You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
It still doesn't print anything for me even after adding await tick(), if I add a top level console.log that does print, it's purely the onMount function...
I'm using Vitest, I don't know if that would make a difference
I am hitting this bug as well. This seems like a bug, not WAD?
I understand you should not test internal lifecycle events, but thats not what we are trying to do here. Even if you are just trying to test the user-facing surface area of a component, if your component internally uses onMount, then you need that to run in order for the user to see the right thing so you can test the output.
Also, I've had no success using vitest with either jest or happy-dom. In both environments, onMount never runs
Okay, that's, as Spock would say, fascinating. As soon as I'll have a real connection back, I'll check what import stuff is happening under the blanket there. Thanks for the info!
On Mon, 12 Jun 2023, at 12:53 PM, Speros Kokenes wrote:
I am hitting this bug as well. This seems like a bug, not WAD?
I understand you should not test internal lifecycle events, but thats not what we are trying to do here. Even if you are just trying to test the user-facing surface area of a component, if your component internally uses `onMount`, then you need that to run in order for the user to see the right thing so you can test the output.
—
Reply to this email directly, view it on GitHub <#222 (comment)>, or unsubscribe <https://github.com/notifications/unsubscribe-auth/AAAE34RZYNUDA7IQ4CH6FCLXK5CSPANCNFSM6AAAAAAY75IQUM>.
You are receiving this because you were mentioned.Message ID: ***@***.***>
Just for info: svelte/internal got removed in svelte 4 so I think despite the workaround this should be fixed...if you have any suggestion on where to start to look I can see If I can craft a PR
@yanick I think we're good to officially close this one out 🧹
The docs now have setup instructions to ensure Vitest is properly configured to load Svelte's browser bundler
The docs now have an onMount FAQ entry
onMount tests have been added to our suite here
@dominikg if you have a minute, could you check over my work above? I compared the resolve.conditions: ['browser'] approach with the suggested plugin + unshift approach and got identical results - a resolve.conditions array with browser prepended to the conditions added by VPS and Vitest. I'd be really curious to know if I'm misunderstanding something here!
I have an existing test suite with some components that use onMount.
Adding the example from the FAQ to vite.config.js breaks the tests on any components that import modules using require().
Error: require() of ES Module ... is not supported.
Is there a way to selectively ignore the resolve option on a case-by-case basis?
@hardingjam no, the Vite configuration is all or nothing. You could try one of the other options listed above rather than the plugin.
Using require in Svelte modules seems suspicious, though. Are you able to use import instead and configure Vite to prebundle your CJS dependencies into ESM?
This is still an issue when testing functions that call onMount which are intended to be used inside components. Even with the first solution provided by @mcous.
The motivation for testing functions that contain onMount is because they can contain runes and lifecycle calls all encapsulated and then be used in any components - exactly like React hooks.
From what I recall, @testing-library provides ways to test React hooks in isolation and I'm trying to do exactly that with Svelte 5.
Hey @karbica, onMount cannot be used outside a .svelte component. This is not a Svelte Testing Library thing, this is just a Svelte thing. onMount relies on the implicit environment brought along by the Svelte component to function. It is inherently not encapsulated.
The way React Testing Library's hooks testing works is by wrapping the hook under test up in a fixture component. You can do the same to test things that require a component environment to function:
<!-- use-mouse-coords.test.svelte (or whatever name you want) -->
<scriptlang="ts">
import { useMouseCoords } from'../src/lib/use-mouse-coords.svelte.ts';exportconst mouseCoords =useMouseCoords()
</script>
import{it,expect}from'vitest';import{render,screen}from'@testing-library/svelte';importWithUseMouseCoordsfrom'./use-mouse-coords.test.svelte';it('runs correctly when rendering a component',()=>{const{ component }=render(WithUseMouseCoords);expect(component.mouseCoords.x).toBe(0);expect(component.mouseCoords.y).toBe(0);});
Personally, I find these fixture components annoying in my own tests. It's not really unit testing, and instead is integration testing the whole stack of my logic, the Svelte compiler, the Svelte runtime, and whichever DOM library the test suite is using (or the browser). If I find myself in a situation where I "need" to use a fixture component, I try to restructure my code so the logic I care about is more directly testable and avoid coupling to the view library/framework.
(One final bit of housekeeping: I see that you've added both the svelteTesting plugin to your Vitest config as well as the resolve.conditions customization from earlier in this thread. You do not need both, because the svelteTesting plugin sets the resolve conditions for you. See #359 if you're curious!)
This is not a Svelte Testing Library thing, this is just a Svelte thing. onMount relies on the implicit environment brought along by the Svelte component to function. It is inherently not encapsulated.
I agree and follow this entirely. This isn't for Testing Library to solve, it's a consequence of the framework. I was curious if there was any remedy this library could provide. The fixture component (which is also performed for React hooks) is exactly what came to mind for these kinds of functions in Svelte. I'm not a fan of the ceremony involved and it breaks away from the concept of unit testing, as you mentioned. Thanks for clearing that up and confirming that.
One final bit of housekeeping: I see that you've added both the svelteTesting plugin to your Vitest config as well as the resolve.conditions customization from earlier in this thread. You do not need both, because the svelteTesting plugin sets the resolve conditions for you. See #359 if you're curious!
Thanks for calling this out. I really didn't like how the escape hatch was leaking into the configuration file. Good to know this library is handling that for us.
Manually force Vitest to load the browser version of with a resolve alias
Not very future proof; locks your config to the internals of the Svelte package
More targeted than option (1)
If you're considering this option because the browser condition breaks some other dependency, consider swapping that dependency with an alias instead, because it's probably less important than your Svelte dependency
@mcous Thanks for your great research and writeup! You suggest swapping dependencies broken by the browser condition with an alias. I'm experiencing this with @auth/sveltekit. How can I swap it using an alias?
note that this uses vitest.workspace.ts instead of .config.ts and extends the vite config. For global vitest settings like coverage, i do recommend using test in vite.config.ts to not have too many files.
A setup like this is going to be added to sv soonish and hopefully resolves all issues around this problem. Feedback welcome
@dominikg that setup looks great! Let me know if there's anything on the testing-library side that could be updated to help the effort of getting this sort of thing into sv
@Stadly see Dominik's suggestion above; my comment about aliases predates Vitest's workspace configuration option. To throw my extra 2 cents into the mix, I also recommend that you explore structuring your application code such that auth and other framework concerns don't leak down to the level of component tests, and instead are tested at much higher levels, like E2E tests in playwright. You may be able to bypass this Vitest problem entirely with more separation between your own interesting logic that you want to test and framework stuff that you wire into
@dominikg that setup looks great! Let me know if there's anything on the testing-library side that could be updated to help the effort of getting this sort of thing into sv
@Stadly see Dominik's suggestion above; my comment about aliases predates Vitest's workspace configuration option. To throw my extra 2 cents into the mix, I also recommend that you explore structuring your application code such that auth and other framework concerns don't leak down to the level of component tests, and instead are tested at much higher levels, like E2E tests in playwright. You may be able to bypass this Vitest problem entirely with more separation between your own interesting logic that you want to test and framework stuff that you wire into
Thanks for the suggestion! I'm actually unit testing my handle hook using Vitest, so then the auth stuff is needed :)
note that this uses vitest.workspace.ts instead of .config.ts and extends the vite config. For global vitest settings like coverage, i do recommend using test in vite.config.ts to not have too many files.
A setup like this is going to be added to sv soonish and hopefully resolves all issues around this problem. Feedback welcome
Activity
yanick commentedon Jun 8, 2023
It does for me.
You might have to add a
await tick()
after the render, as the onMount is called after the component is rendered, according to the docs.connerdassen commentedon Jun 9, 2023
@yanick
It still doesn't print anything for me even after adding
await tick()
, if I add a top levelconsole.log
that does print, it's purely the onMount function...I'm using Vitest, I don't know if that would make a difference
yanick commentedon Jun 9, 2023
[Vitest] It shouldn't affect anything.
Hmmm... It still works for me. Can you create a repo with the minimal amount of code that reproduce the problem?
yanick commentedon Jun 9, 2023
(also, I'll drop offline for a few days starting tomorrow. If I don't answer, I'm not ghosting, I'm just without Internet. :-) )
connerdassen commentedon Jun 9, 2023
@yanick
I've uploaded an example to https://github.com/connerdassen/svelte-test-example
I asked in the official svelte discord server and was told
So now I wonder why it works for you...
yanick commentedon Jun 9, 2023
Oooh, I'm using happydom, which might be why. I'll try to, uh, try with jsdom later on to see if it makes a difference.
yanick commentedon Jun 9, 2023
So with vitest, no console print, with jest, I get one. As for why, I haven't the foggiest. O.o
connerdassen commentedon Jun 11, 2023
@yanick I have discovered something, when importing onMount from "svelte" it does not run, but when importing from "svelte/internal" it does...
skokenes commentedon Jun 12, 2023
I am hitting this bug as well. This seems like a bug, not WAD?
I understand you should not test internal lifecycle events, but thats not what we are trying to do here. Even if you are just trying to test the user-facing surface area of a component, if your component internally uses
onMount
, then you need that to run in order for the user to see the right thing so you can test the output.Also, I've had no success using vitest with either jest or happy-dom. In both environments,
onMount
never runsyanick commentedon Jun 13, 2023
yanick commentedon Jun 13, 2023
connerdassen commentedon Jun 13, 2023
@skokenes seems to have figured it out in the svelte server, I'll reiterate:
Since the test is running in a Node environment instead of a browser environment, it uses the "node" exports from svelte which points to the ssr import path: https://github.com/sveltejs/svelte/blob/master/package.json
For SSR, life cycle methods do not run and are exported as a noop: https://github.com/sveltejs/svelte/blob/3bc791bcba97f0810165c7a2e215563993a0989b/src/runtime/ssr.ts#L1
Importing from "svelte/internal" bypasses this.
Solutions are either mocking onMount in every test:
Or a custom alias in vite.config.ts:
yanick commentedon Jun 13, 2023
paoloricciuti commentedon Jun 27, 2023
Just for info: svelte/internal got removed in svelte 4 so I think despite the workaround this should be fixed...if you have any suggestion on where to start to look I can see If I can craft a PR
26 remaining items
hardingjam commentedon Jul 16, 2024
I have an existing test suite with some components that use onMount.
Adding the example from the FAQ to vite.config.js breaks the tests on any components that import modules using require().
Is there a way to selectively ignore the resolve option on a case-by-case basis?
mcous commentedon Jul 16, 2024
@hardingjam no, the Vite configuration is all or nothing. You could try one of the other options listed above rather than the plugin.
Using
require
in Svelte modules seems suspicious, though. Are you able to useimport
instead and configure Vite to prebundle your CJS dependencies into ESM?karbica commentedon Sep 5, 2024
This is still an issue when testing functions that call
onMount
which are intended to be used inside components. Even with the first solution provided by @mcous.sveltejs/svelte#13136 (comment)
The motivation for testing functions that contain
onMount
is because they can contain runes and lifecycle calls all encapsulated and then be used in any components - exactly like React hooks.From what I recall,
@testing-library
provides ways to test React hooks in isolation and I'm trying to do exactly that with Svelte 5.The issue is reproduced here: https://stackblitz.com/edit/vitejs-vite-2fltxz?file=vite.config.ts
mcous commentedon Sep 5, 2024
Hey @karbica,
onMount
cannot be used outside a.svelte
component. This is not a Svelte Testing Library thing, this is just a Svelte thing.onMount
relies on the implicit environment brought along by the Svelte component to function. It is inherently not encapsulated.The way React Testing Library's hooks testing works is by wrapping the hook under test up in a fixture component. You can do the same to test things that require a component environment to function:
Personally, I find these fixture components annoying in my own tests. It's not really unit testing, and instead is integration testing the whole stack of my logic, the Svelte compiler, the Svelte runtime, and whichever DOM library the test suite is using (or the browser). If I find myself in a situation where I "need" to use a fixture component, I try to restructure my code so the logic I care about is more directly testable and avoid coupling to the view library/framework.
(One final bit of housekeeping: I see that you've added both the
svelteTesting
plugin to your Vitest config as well as theresolve.conditions
customization from earlier in this thread. You do not need both, because thesvelteTesting
plugin sets the resolve conditions for you. See #359 if you're curious!)karbica commentedon Sep 5, 2024
Thank you @mcous for the great write up.
I agree and follow this entirely. This isn't for Testing Library to solve, it's a consequence of the framework. I was curious if there was any remedy this library could provide. The fixture component (which is also performed for React hooks) is exactly what came to mind for these kinds of functions in Svelte. I'm not a fan of the ceremony involved and it breaks away from the concept of unit testing, as you mentioned. Thanks for clearing that up and confirming that.
Thanks for calling this out. I really didn't like how the escape hatch was leaking into the configuration file. Good to know this library is handling that for us.
I appreciate you taking a look into my concern.
SvelteSet
does not behave correctly in Vitest sveltejs/svelte#13961Stadly commentedon Nov 25, 2024
@mcous Thanks for your great research and writeup! You suggest swapping dependencies broken by the
browser
condition with an alias. I'm experiencing this with@auth/sveltekit
. How can I swap it using an alias?dominikg commentedon Nov 25, 2024
for svelte5, i made an example using vitests workspace feature here: https://github.com/dominikg/vitest-example-svelte5
note that this uses
vitest.workspace.ts
instead of .config.ts and extends the vite config. For global vitest settings like coverage, i do recommend usingtest
invite.config.ts
to not have too many files.A setup like this is going to be added to
sv
soonish and hopefully resolves all issues around this problem. Feedback welcomemcous commentedon Nov 25, 2024
@dominikg that setup looks great! Let me know if there's anything on the testing-library side that could be updated to help the effort of getting this sort of thing into
sv
@Stadly see Dominik's suggestion above; my comment about aliases predates Vitest's workspace configuration option. To throw my extra 2 cents into the mix, I also recommend that you explore structuring your application code such that auth and other framework concerns don't leak down to the level of component tests, and instead are tested at much higher levels, like E2E tests in playwright. You may be able to bypass this Vitest problem entirely with more separation between your own interesting logic that you want to test and framework stuff that you wire into
Stadly commentedon Nov 27, 2024
Thanks for the suggestion! I'm actually unit testing my
handle
hook using Vitest, so then the auth stuff is needed :)Stadly commentedon Jan 21, 2025
@dominikg It seems workspaces can now be defined without a separate file: vitest-dev/vitest#6923