Reputation: 1773
Within a Svelte app, I have a boolean variable.
import { writable } from 'svelte/store'
export const authorised = writable(false)
This is imported into App.svelte and other svelte files and accessed and updated using $authorised.
I can't use the $ syntax in Cypress so I used
import { authorised } from '../../src/stores'
describe( etc etc
authorised.set(true)
cy.visit(`/`)
Within App.svelte, I have a console.log showing value of $authorised.
Using dev tools in the cypress browser output, authorised is showing false.
The test logs in via the backend api, receiving the token and user id in the body response. With this data I set various values in svelte store (including authorised) so that when visit the app, it should show the authorised screen rather than the login screen.
So why is authorised not being set in svelte store?
Updated:
Using Fody's approach, I added to the start of App.svelte, outside of script,
declare global {
interface Window {
Cypress?: Cypress.Cypress;
}
}
Putting this within script gives an error on declare. But the above code, gives an error on interface.
The keyword 'interface' is reserved
I have looked at Parsing error: The keyword 'interface' is reserved and am installing ts-standard and updating the package.json. But the install is taking a long time.
Am I supposed to be installing ts-standard?
Further update:
In main.ts, I added
import type { Writable } from 'svelte/store';
declare global {
interface Window {
Cypress?: Cypress.Cypress
authorised?: Writable<boolean>
}
}
And in App.svelte.
if (window.Cypress) {
window.authorised.set($authorised)
}
and finally 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 shows an error of "windows.authorised is undefined" with a console log of 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
where App.svelte:16 is "window.authorised.set($authorised) "
Upvotes: 1
Views: 831
Reputation: 1773
What I got working was a mixture of @fody's answer and mine. So in main.ts - I added the additions to the Window interface so that cypress and the app can communicate via this. In App.svelte - I added (the variables preceeded by $ are svelte store variables)
if (window.Cypress) {
console.log("entering Cypress selection")
authorised = window.authorised
$emailName = window.emailName
$authToken = window.authToken
$userId = window.userId
}
And in the test
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')
So the key bit is the onBeforeLoad as that updates the new app window with the auth information. Without this, there are two different window objects and information is not passed across.
Upvotes: 0
Reputation: 32080
If you import the writable store directly, it's not using the same instance as the one in the app.
But you can attach it as a property of window
to allow Cypress access to the same instance.
A minimal example:
Svelte app
<script>
import { writable } from 'svelte/store'
export const authorised = writable(false)
if (window.Cypress) {
window.authorised = authorised; // only if Cypress is running
}
let authorisedValue;
authorised.subscribe(value => {
authorisedValue = value;
});
</script>
<main>
<div id="app-container" class="app-container">
<div id="authorised-display-value">{authorisedValue}</div>
</div>
</main>
Test
it('passes', () => {
cy.visit('http://localhost:8080/')
cy.get('#authorised-display-value').should('contain', 'false') // passes
cy.window().then(win => win.authorised.set(true))
cy.get('#authorised-display-value').should('contain', 'true') // passes
})
If the project is typescript-based, the window.Cypress
and window.authorised
references will give a problem.
Define these in main.ts
.
For my minimal app:
import type { Writable } from 'svelte/store';
import App from './App.svelte';
declare global {
interface Window {
Cypress?: Cypress.Cypress;
authorised?: Writable<Boolean>;
}
}
const app = new App({
target: document.body
});
export default app;
It's also good practice to add a generic parameter to the writable store.
In App.svelte
:
<script lang="ts">
import { writable } from 'svelte/store'
export const authorised = writable<Boolean>(false)
...
Finally, define the global type imports in global.d.ts
:
/// <reference types="svelte" />
/// <reference types="cypress" />
Upvotes: 1