updating a value in a svelte writable store using cypress

Inside my Svelte application, I am working with a boolean variable.

import { writable } from 'svelte/store'
export const authorised = writable(false)

This variable is imported into App.svelte and other Svelte files, where it can be accessed and updated using $authorised.

However, the $ syntax cannot be used in Cypress, so instead I have utilized the following:

import { authorised } from '../../src/stores'
describe( etc etc
        authorised.set(true)
        cy.visit(`/`)

In App.svelte, there is a console.log displaying the value of $authorised.

Despite setting values in the Svelte store during testing, the output in the Cypress browser's dev tools shows that authorised is still false.

The backend API successfully logs in and provides the necessary data. This data is used to update various values in the Svelte store, including authorised, with the expectation that the app will show the authorized screen upon visit rather than the login screen.

But why does the authorised value not get properly set in the Svelte store?

An update was made by incorporating Fody's approach at the beginning of App.svelte, outside of the script tags,

declare global {
  interface Window {
    Cypress?: Cypress.Cypress;
  }
}

Moving this declaration inside the script led to an error related to the use of 'interface,' while placing it as shown above caused an issue regarding the keyword itself.

The keyword 'interface' is reserved

After referring to Parsing error: The keyword 'interface' is reserved and attempting to install ts-standard for resolution, the lengthy installation process has commenced.

Is installing ts-standard mandatory in this context?

A further modification involved adding the following code to main.ts:

import type { Writable } from 'svelte/store';    
declare global {
        interface Window {
          Cypress?: Cypress.Cypress
          authorised?: Writable<boolean>
        }
    }

This was then utilized in App.svelte as follows:

if (window.Cypress) {
    window.authorised.set($authorised)          
}

Lastly, in the test.js file:

.its('body').then((body) => {
        cy.log(body)
        cy.visit(`/`)
        cy.window().then(win => win.authorised.set(true))

Running the test resulted in an error stating "window.authorised is undefined" along with the log message: Uncaught TypeError: window.authorised is undefined instance App.svelte:16 init index.mjs:1891 App bundle.js:4033 app main.ts:14 bundle.js:4050

The line causing the error is mentioned as "window.authorised.set($authorised)" on line 16 of App.svelte.

Answer №1

When importing the writable store directly, it does not utilize the same instance as the one in the application.

However, you can make it accessible to Cypress by attaching it as a property of window.

An example to demonstrate this:

Svelte app

<script>
  import { writable } from 'svelte/store'

  export const authorized = writable(false)

  if (window.Cypress) {
    window.authorized = authorized;          // only if Cypress is running
  }

  let authorizedValue;
  authorized.subscribe(value => {
    authorizedValue = value;
  });
</script>

<main>
  <div id="app-container" class="app-container">
    <div id="authorized-display-value">{authorizedValue}</div>
  </div>
</main>

Testing

it('passes', () => {
  cy.visit('http://localhost:8080/')
  cy.get('#authorized-display-value').should('contain', 'false')    // passes
  cy.window().then(win => win.authorized.set(true))
  cy.get('#authorized-display-value').should('contain', 'true')     // passes
})

Typescript support

If the project is typescript-based, referencing window.Cypress and window.authorized may pose an issue.

To address this, define these references in main.ts.

In my minimal app example:

import type { Writable } from 'svelte/store';
import App from './App.svelte';

declare global {
  interface Window {
    Cypress?: Cypress.Cypress;
    authorized?: Writable<Boolean>;
  }
}

const app = new App({
    target: document.body
});

export default app;

It is recommended to add a generic parameter to the writable store for better practice.

In App.svelte:

<script lang="ts">
  import { writable } from 'svelte/store'
  export const authorized = writable<Boolean>(false)
  ...

Lastly, define the global type imports in global.d.ts:

/// <reference types="svelte" />
/// <reference types="cypress" />

Answer №2

After some trial and error, I managed to combine elements from @fody's solution with my own insights. I made modifications in main.ts by extending the Window interface to facilitate communication between Cypress and the application. Within App.svelte, I incorporated svelte store variables (indicated by $) along with additional changes.

 if (window.Cypress) {
    console.log("entering Cypress selection")
    authorised = window.authorised
    $emailName = window.emailName
    $authToken = window.authToken
    $userId = window.userId
  }

In the test script:

  cy.request('POST', Cypress.env('api')+'users/login', {
    email: "[email protected]",
    password: "12345678"
  }).its('body').then((body) => {
            cy.log(body)

            cy.visit(`/`, {
              onBeforeLoad(win) {
                win.authorised = true
                win.emailName = "[email protected]"
                win.authToken = body.token
                win.userId = body.userId
              },
            })
                                    
          cy.get('h1').should('contain', 'Svelte To-Do List')       

The crucial aspect here is the onBeforeLoad function, which ensures that the new app window receives the authentication details. This step is essential for seamlessly passing information between the two window objects.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Tips for avoiding a form reload on onSubmit during unit testing with jasmine

I'm currently working on a unit test to ensure that a user can't submit a form until all fields have been filled out. The test itself is functioning correctly and passes, but the problem arises when the default behavior of form submission causes ...

Using a try block inside another try block to handle various errors is a common practice in JavaScript

In an effort to efficiently debug my code and identify the location of errors, I have implemented a try-catch within a try block. Here is a snippet of the code: for (const searchUrl of savedSearchUrls) { console.log("here"); // function will get ...

What could be causing my React Redux state to not trigger a re-render?

Having trouble with my redux state not triggering a re-render when using a selector. I'm new to react-redux and typescript, and despite following advice online about returning a new object from the reducer, my object is still not re-rendering even tho ...

Encountering issues in Angular 2 when attempting to pass data into root component through ng-content and binding. Objective: Creating a reusable form component

I currently have a .NET MVC application and I'm looking to integrate Angular 2 into it. The structure of my page is as follows: <html> <head>css imports and jquery imports</head> <body> <div> a bunch of table ...

Error during Webpack Compilation: Module 'jQuery' not found in Travis CI with Mocha Test

I've been struggling to automate tests for my repository using mocha-webpack and Travis CI. The local machine runs the tests smoothly, but Travis CI hasn't been able to complete them yet due to an unresolved error: WEBPACK Failed to compile wit ...

What is the process for sending an http get request that provides a JSON array to populate an ngFor directive?

I'm trying to figure out how to make an http get request in order to retrieve a json array of data that I can use within an ngFor loop. The list that needs to be looped through is stored in this.list. Currently, the json file for testing purposes is l ...

Develop a TypeScript class that includes only a single calculated attribute

Is it advisable to create a class solely for one computed property as a key in order to manage the JSON response? I am faced with an issue where I need to create a blog post. There are 3 variations to choose from: A) Blog Post EN B) Blog Post GER C) Bl ...

Typescript error: Undefined reference to 'DhImportKeyParams'

Working on a project, I encountered an issue with a third-party library written in Typescript 3.7. The outdated library depended on the 'lib' that contained an interface called DhImportKeyParams. However, my current project uses Typescript 4.6 wh ...

Injecting AngularJS together with TypeScript and Restangular to optimize application performance

Encountering an issue while trying to configure my angularjs + typescript application with the restangular plugin Here are the steps I have taken: Ran bower install --save restangular (now I have in index.html <script src="bower_components/restang ...

Customizing tsconfig.json: Enhancing an existing object by adding new keys in TypeScript

Is it possible to achieve the following functionality by default? let j = {a:1}; j.b = 2; I am aware that there are alternative solutions, but I am curious if this specific task can be accomplished by solely modifying tsconfig.json? ...

What are the reasons for deprecating bindToController in Typescript?

When I am creating an AngularJS directive using TypeScript, I typically use the bindToController property to bind parameters to the controller for easy access. export class MyDirective implements IDirective { controller = MyController; controllerA ...

ANGULAR: Issue with filtering an array by clicking a button is not functioning

I've been attempting to apply a filter to my array by using modulo on the id when clicking multiple buttons. I initially tried using pipe but was advised to stick with .filter(). Despite watching numerous online tutorials, I keep encountering errors o ...

The function's overloading is not compatible with its implementation

Currently, I am puzzled by the lack of functionality in some code that I am reviewing. The structure resembles this: function getValidity(x: "v1"): boolean; function getValidity(x: "v2"): { a: number; b: number }; function getValidity(x: any) { if (x == ...

Develop a flexible axios client

I have a basic axios client setup like this: import axios from "axios"; const httpClient = axios.create({ baseURL: "https://localhost:7254/test", }); httpClient.interceptors.request.use( (config) => config, (error) => Prom ...

Top Recommendations: Comparing Standalone Components and Modules in Angular Version 14

I'm in need of some clarification on the most effective practices when it comes to utilizing standalone components and modules within Angular 14. With the introduction of standalone components as a new concept in Angular, I am seeking factual guidance ...

I'm encountering an issue in my node application where it is unable to access the push

I am a beginner in the world of node.js and express. Whenever I try to start my application using the command npm start, I encounter an error message saying Cannot Read property push of undefined from my index.js file. The problematic code snippet looks l ...

Getting the first nested object within an object in Angular 8: A comprehensive guide

Looking to extract the first object from a JSON data set? In this case, we want to retrieve {"test": {"id":1, "name":"cat"}} from the following object: { "3": {"test": {"id":1, "name":"cat"}}, "4": {"test": {"id":2, "name":"dog"}}}. Keep in mind that the ...

Improprove the performance of an array of objects using JavaScript

Hello there, I am currently in the process of creating an array. this.data = [{ label: 'Total', count: details.request.length, }, { label: 'In-Progress', count: details.request.filter((obj) => obj.statusId === 0 || ob ...

Having trouble getting @types/express-session to function properly. Any suggestions on how to fix it?

My web-app backend is built with TypeScript and I've integrated express-session. Despite having @types/express and @types/express-session, I continue to encounter type errors that say: Property 'session' does not exist on type 'Request ...

In need of secure HTML, received a dose of Style instead

I am currently developing a component that loads html content dynamically and validates the loaded styles to prevent any mixing of app styles with the dynamic template's styles. This is the structure of my HTML component: <div class="modal-header ...