Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

$effect not working in tests, but $derived does #15051

Closed
rChaoz opened this issue Jan 18, 2025 · 7 comments
Closed

$effect not working in tests, but $derived does #15051

rChaoz opened this issue Jan 18, 2025 · 7 comments

Comments

@rChaoz
Copy link
Contributor

rChaoz commented Jan 18, 2025

Describe the bug

I'm having this weird issue where $effect is not working in tests. Interestingly, $derived does work, which means Svelte is not compiling in SSR mode. For example, in this test:

let num = $state(0)
let doubled = $derived(num * 2)
num = 5
expect(doubled).toBe(10)

$effect.root(() => {
    let a = 0
    $effect(() => {
        a = 5
    })
    flushSync()
    expect(a).toBe(5)
})

it errors at the very end: expected +0 to be 5, but it should work. Here's my Vite config:

export default defineConfig({
    plugins: [
        enhancedImages(),
        sveltekit(),
        ...
    ],
    test: {
        include: ["src/**/*.test.{js,ts}"],
        coverage: { ... },
        environmentMatchGlobs: [["src/**/*.svelte.test.{js,ts}", "jsdom"]],
        setupFiles: "src/vitest.setup.ts",
    },
    build: { ... },
})

I also have this mock in my global setup as I use if (browser) in other places in my tests:

vi.mock(import("esm-env"), async (importOriginal): Promise<typeof import("esm-env")> => {
    const module = await importOriginal()
    if (typeof window == "object")
        return {
            ...module,
            BROWSER: true,
        }
    else return module
})

I tried removing it, but without success. I'm not quite sure how to reproduce this yet. Is there something obviously wrong with my config, or something I can try?

@rChaoz rChaoz changed the title $effect not working in tests $effect not working in tests, but $derived does Jan 18, 2025
@7nik
Copy link
Contributor

7nik commented Jan 18, 2025

$derived does work, which means Svelte is not compiling in SSR mode

It means nothing - $derived works for both client and server, though it isn't reactive on the server.

Did you read the docs about testing?

@rChaoz
Copy link
Contributor Author

rChaoz commented Jan 18, 2025

though it isn't reactive on the server

Yes, that's what I meant. Isn't it reactive in my example above?

@paoloricciuti
Copy link
Member

though it isn't reactive on the server

This could be fixed by #14977 but I think you should change your resolve conditions to browser if you also want to test $effect

@rChaoz
Copy link
Contributor Author

rChaoz commented Jan 18, 2025

This could be fixed by #14977

I don't need that, as I mentioned it is reactive for me.

I think you should change your resolve conditions to browser

I tried doing that, but I'm getting blasted with various errors, like

Error [ERR_REQUIRE_ESM]: require() of ES Module [...]\node_modules\@asamuzakjp\css-color\dist\esm\css-color.min.js from [...]\node_modules\cssstyle\lib\parsers.js not supported.
Instead change the require of css-color.min.js in [...]\node_modules\cssstyle\lib\parsers.js to a dynamic import() which is available in all CommonJS modules.

also, this makes every server test to fail.

@paoloricciuti
Copy link
Member

Do you have other tests other than those? You need to run the svelte ones with condition browser and the others with condition node...take a look at this repo

https://github.com/dominikg/vitest-example-svelte5

@rChaoz
Copy link
Contributor Author

rChaoz commented Jan 18, 2025

I will take a look at that repo, although not sure if it will help, running just a single file with the test in my original post fails with the errors I mentioned. Also, I managed to get the transformed module, which looks good I think:

let num = __vite_ssr_import_0__.state(0);
let doubled = __vite_ssr_import_0__.derived(() => __vite_ssr_import_0__.get(num) * 2);

__vite_ssr_import_0__.set(num, 5);
__vite_ssr_import_1__.expect(__vite_ssr_import_0__.get(doubled)).toBe(10);

__vite_ssr_import_0__.effect_root(() => {
	let a = 0;

	__vite_ssr_import_0__.user_effect(() => {
		a = 5;
	});

	__vite_ssr_import_3__.flushSync();
	__vite_ssr_import_1__.expect(a).toBe(5);
});

Update: actually, I think I figured it out. Looking at the top of the generated module, I see this:

const __vite_ssr_import_0__ = await __vite_ssr_import__("/node_modules/svelte/src/internal/client/index.js");
const __vite_ssr_import_1__ = await __vite_ssr_import__("/node_modules/vitest/dist/index.js", {"importedNames":["vi","expect","it","describe"]});
const __vite_ssr_import_3__ = await __vite_ssr_import__("/node_modules/svelte/src/index-server.js", {"importedNames":["flushSync"]});

so, runes are transformed correctly, but flushSync() is imported from the server module, which is actually a no-op. I'll keep looking into this.

@rChaoz
Copy link
Contributor Author

rChaoz commented Jan 19, 2025

After upgrading to Vitest 3, I finally managed to get this working, using the example repo from above, with the workspace config.

@rChaoz rChaoz closed this as completed Jan 19, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants