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
Describe the bug
As far as I can tell there's no way to use sveltekit runtime imports (eg: $app/navigation) outside of sveltekit dev/build. Which makes testing virtually impossible. If there is a way to shim these imports outside of the main sveltekit context I haven't found it, so perhaps documentation is needed.
My particular use-case is with Storybook, where UI components that rely on any sveltekit modules break the whole setup. I tried aliasing them with webpack (pointing to .svelte-kit/dev/...) but that didn't work either.
Another use-case is publishing components for sveltekit that would need to rely on those imports.
To Reproduce
Setup storybook with Sveltekit
Create a component that imports a runtime module (eg: $app/env)
Run storybook and see if fail (cannot resolve module $app/env)
Severity
Not blocking, but makes building a component library with Storybook or other development/testing frameworks impossible. So, severe annoyance?
Yep that would solve the second use case (distributing components/actions that rely on sveltekit), but I don’t think it would address the first? Testing etc components of a sveltekit app outside the main sveltekit dev/build runtime? Storybook being a very common use case
TBH I am hitting this issue trying to just do basic testing with uvu and typescript. I have ts files that import $app/env and uvu fails to resolve this using ts-node but I know you guys have set testing as a post 1.0. But any hacks or workarounds would be greatly appreciated. #19
Yeah this isn't to do with your own custom aliases, but the runtime modules of sveltekit. There needs to be a way to consume or shim them in non-sveltekit contexts like testing. Updated issue title to be clearer on the issue
Reacted by Joseph Spurrier, Huseyin Atasoy, DylanStandridge and Bae Junehyeon
changed the title [-]Shimming sveltekit runtime import aliases in other contexts[/-][+]Shimming sveltekit runtime modules in other contexts[/+]on May 19, 2021
I'd like to voice my support for a feature that would allow libraries to neatly get access to the $app/navigation, $app/stores, and $app/env modules.
As the creator and maintainer of SvelteKitAuth we're trying to provide a way for users to augment the SvelteKit session with authentication data using the getSession() hook, and upon changes in the session it would be nice to reset it internally instead of expecting users to do something like signOut().then(session.set), and a similar story for routing. Since signIn() either generates a redirect URL or sends a direct fetch() request depending on the payload provided, currently we're returning the URL and expect users to route themselves with goto() as such:
signIn().then(goto);
Letting libraries handle these things internally means less boilerplate for our users, so getting access to the SvelteKit router in a global module, instead of a scoped one would be useful. This is how other frameworks and libraries such as the Vue Router and React Router handle this, as they make use of the global React instance SvelteKit might have to work around the fact that Svelte doesn't provide such a thing, but create its own global context or a singleton.
Reacted by Alex Thomsen, vhscom, Joël Charles, James Moynihan and AllNamesRTaken
With the caveat being that you have to have run sveltekit dev first to generate those runtime modules. I think this is worth documenting (the path to the alias if nothing else) for others that need to shim these modules until Svelte comes up with an official workaround
Reacted by Joseph Spurrier, AJ Caldwell and basluta
Author of comment of the said person who had to mock this stuff. I don't mind mocking - fine as a workaround for unit testing anyway. It wasn't exactly simple to figure out the correct mocks though.
Error: Cannot subscribe to 'page' store on the server outside of a Svelte component, as it is bound to the current request via component context. This prevents state from leaking between users.For more information, see https://kit.svelte.dev/docs/state-management#avoid-shared-state-on-the-server
❯ get_store node_modules/@sveltejs/kit/src/runtime/app/stores.js:96:9
❯ Object.subscribe node_modules/@sveltejs/kit/src/runtime/app/stores.js:39:37
❯ subscribe node_modules/svelte/src/runtime/internal/utils.js:139:22
❯ Module.component_subscribe node_modules/svelte/src/runtime/internal/utils.js:159:31
❯ instance src/Demo.svelte:69:24
I believe that is related to this issue. I had a minimal repro set up for a new issue before realizing it's probably the same as this issue. Run
$ yarn
$ yarn test run
to reproduce. On commit 388142a, it works. After this commit, the test breaks in the manner mentioned above.
We found some solution to work around not being able to mock those modules. In case it can help someone in the same situation, and in order to gather some feedback about what we found, I write below the whole story: our context and our solution.
Some context
Just to explain how this “shimming” this is crucial to us, and how we really tried to avoid is… in vain :-(
For our project, we are using TDD, SvelteKit and Superforms. So, be able to test is crucial for us. That being said, we ran into this “mocking” problem before with $env and resolved it easily, but when trying to implement Superforms we had a real blocker.
We spent a lot of time on the Internet, browsing issues, testing solutions. But as there seem to be no way to correctly shim the $app modules (especially $app/forms and $app/navigation, which both contain some complex logic methods such as beforeNavigate, enhance or applyAction), we had to choose between these solutions:
Abandon Superforms: we could try to mock some $app modules, but this would fail when using libraries that also use these modules. So, a solution would be to abandon thoses librairies. Problem is that there is not always a good alternative not using thoses Svelte modules, and it is most certain that at some point we run into another library using thoses modules.
Abandon TDD: no way! We are a 2-person team, so we cannot afford to take the risk to not have the safety net and peace of mind TDD gives us. Plus the other benefits, of course, but these two are important for us.
Abandon SvelteKit: we choose SK over React when we started, but it is still an option, although we do not want because we love this framework so much!
Our workaround solution
As no solution was valid, we tried to change a bit our way of doing things. Currently, we do component testing with Playwright experimental component testing feature. But in the end, component testing is just end-to-end testing with a specific page containing only one component. This seems to be indeed how SvelteKit seems to be tested: small “apps” exposing only a specific feature to be tested.
So we implemented this:
Have a route for each component to test, leading to a page which would only contain this component. We put those in src/routes/tests and have some conventions for the folders beneath:
Mimic the folder structure of the component to test. For example, when testing a src/routes/(auth)/signup/+page.svelte, we need to create a src/routes/tests/(auth)/signup/+page.svelte. When testing a src/lib/components/form-input/form-input.svelte, we need to create a src/routes/tests/lib/components/form-input/+page.svelte.
If multiple “forms” of the component have to be tested (same as using multiple mount in a Playwright component test), then we create a subfolder with a _ prefix and a name explaining how this feature is different. For example, if we need to test a the FormInput component mentioned above in a situation that it would receive a value parameter, then we create src/routes/tests/lib/components/form-input/_has-initial-value/+page.svelte.
Have a Playwright test for each of these routes, same way we would do for our components. We colocate these tests with our components, as before, but they can be put anywhere in src.
Have a Playwright configuration dedicated to this component testing that targets only these tests.
This solution will need to have a dev server running (with npm run dev for example) so that we can run our tests and most importantly benefit from HMR.
Reading test results in the Playwright test
To be able to make this work, we also had to find a way to retrieve some result value from the tested component. For example, how to test that a button component correctly calls a callback when it is submitted? In e2e testing, this can be tricky because we only browse as a user do, we do not have access to the code. For this purpose, we created a utility component and method to help displaying and retrieving data:
// test-result.svelte<scriptlang="ts">
export let id = 'test-result'
export let value: unknown
</script><spandata-testid={id}class="hidden">{JSON.stringify(value)}</span>// test-result.util.tsimporttype{ Page }from'playwright-core'exportconstgetTestResult=async<T>(page: Page,id: string='test-result'): Promise<T>=>{constresultText=awaitpage.getByTestId(id).innerText()returnJSON.parse(resultText)asT}
We then use it like this:
// src/routes/tests/lib/components/form-input/_has-initial-value/+page.svelte<scriptlang="ts">
import FormInput from '$lib/components/form-input/form-input.svelte'
import TestResult from '$routes/tests/test-result.svelte'
import {generateRandomUsername} from '$tests/unit/utils/string-generator.util'
const initialUsername = generateRandomUsername()
</script><FormInputvalue={initialUsername}/><TestResultvalue={initialUsername}/>// $lib/components/form-input/form-input.spec.tstest('has the passed value by default',async({ page,pom: { username }})=>{awaitexpect(username).toHaveValue(awaitgetTestResult(page))})
What’s cool
We are just begining to use this, so maybe I’ll come back in a few days/weeks and tell it’s totally lame to do that 😅 But what we see in this solution are the following perks:
It’s really close to what we would do with Playwright component testing, except that Playwright is not dynamically mounting our component in a template page.
We use the component in a way that is even closer to its real usage: we create a real page with real code similar to how our component would be used, passing attributes the same way, using callbacks and bindings the same way etc.
We use the real runtime:
no need to mock anything in SvelteKit, so everything works, and of course Superforms does also.
we can use and therefore test everything that is proposed by SvelteKit, and also things that could not be tested correctly in Playwright component testing (such as <svelte:head> to change the title of the page, or goto)
the correct layout is used, so we can really benefit (and test) from anything done at this level
it’s possible to see and interact with what’s really rendered, if we want, by just browsing to the URL (because we have a dev server running, which is used by our tests)
HMR: as we have a dev server running background, we benefit from HMR, which is faster that the building/server executed by Playwright component testing when we run a test from VSCode
We do not need to do this little hack in some component tests to mount the component even if we do not use it, just to make sure the component is rendered (for example when running accessibility tests).
What’s not so great
There are some downsides to this technique:
As explained before, if the component has to be tested in different configurations (which would correspond to a new call to mount in Playwright component testing), then we need to create 1 route (which means 1 subfolder and 1 +page.svelte) for each of these configurations. Fortunately, we should not have a lot of different configurations for our components.
The bigger one: we need to find a way to remove testing routes from the final bundle. Or course, we do not want to ship those tests routes, so we want to tell Vite to just ignore what is in src/routes/tests. Unfortunately, it does not seem to be possible. I spent a good amount of time on the Internet, tried some things (vite configuration, Rollup configuration, creating a vite plugin) but nothing worked. The only solution that I found is to use renamer to change the name of the files before and after build. Our NPM script becomes:
The caveat with this being that some strange thing could occur if you edit or rename the file elsewhere during this process.
I would love to have a simpler way to do this (just like “hey vite, completely ignore this folder please”), so if anyone has an idea, please send me a message 😬
What I would love from SvelteKit
I hope this will help someone, but I would love to have some things from SK out-of-the-box:
An official and neat way to mock thoses runtime modules
A way to strip some routes from the bundle (this can also be used to strip some admin or dev-only routes, as I saw in some discussions)
Please feel free to tell me what you think about this solution, and if I missed something. We will continue on this path and I will come back here and edit if we found something interesting, especially if everything turned out to be garbage in the end 😅 (but I hope not 😉)
Hi! As promised, here's some feedback after using this technique for 2 weeks. It's working rather well regarding the initial problem of not having a way to mock $app modules.
However, we are having some issues:
👎 having test routes is not ideal because it's not easy to strip them from the bundle, and they cannot be near the components they tests, which make it hard to maintain tests
👎 tests are rather slow and Playwright as a test runner lacks the ability to rerun a test when corresponding code has changed, which is even more of a problem with this technique, so it's not really fluid to develop like that
⛔ last but not least: we are having lots of flaky tests with Playwright these days, and it's getting hard to continue. We are considering leaving Playwright and going back to Vitest (+ Testing Library). However, we would still have this $app modules problem with nos solution (as Vitest has no mean to go to a URL to perform tests, nor can it launch a headless browser as Playwright does).
@benmccann I know you're all very busy and that there's a lot of work to be done on this framework that we all love. Nevertheless, in the absence of any feedback from the team on this subject, I can't help but wonder how this work is being prioritized.
Indeed, it is (in my opinion) crucial to the widespread adoption of SvelteKit, given that if it's impossible to properly test our applications (which is unfortunately the case today) then SvelteKit (and therefore Svelte) will probably not be chosen in many contexts.
In any case, that's the conclusion we've reached. Today, we'd like to have some feedback on the implementation of a solution to this problem, as well as a possible delivery target. I'm well aware that the notion of a deadline on such a project is a very complicated one, but we need to know whether we can expect to wait a few weeks, or whether we're talking months or years, in which case we'll have to turn to another framework.
I'm not sure I'll be able to help more directly by contributing code, but if possible please feel free to give some general lines on what needs to be done, in case I or someone passing by can lend a hand on the subject 😉
Thanks again for your work, really, and I hope this topic can move forward! 🙏
Reacted by Emre Şafak, Josh Forbes, Alpha Intelligence and Yuki Ishii
Aside from $env/* which will soon be importable, can folks here share which APIs they would like to be able to easily mock or run into errors when importing? I'll look into making the $app/* modules importable too
Reacted by Eli, frederikhors and Houssam Elbadissi
@teemingc That would be wonderful. Besides the $env and $app imports, aliases and also $lib import does not work. It can be solved with relative imports, but it's very annoying.
I'm going to close this issue because the original post (unable to import Kit modules in Storybook) and the comments (shimming Kit modules) are very old and deviated from the original post. In SvelteKit 3, the $env and $app modules are written to disk. The $lib alias is also removed in favour of Node subpath imports. Therefore, the issue of errors from SvelteKit imports not being resolvable is probably resolved. If anyone still faces this issue, please open a new issue specifying the exact import/API that errors.
Activity
benmccann commentedon May 18, 2021
This sounds loosely related to allowing SvelteKit to build components as suggested in #518
madeleineostoja commentedon May 18, 2021
Yep that would solve the second use case (distributing components/actions that rely on sveltekit), but I don’t think it would address the first? Testing etc components of a sveltekit app outside the main sveltekit dev/build runtime? Storybook being a very common use case
alexkornitzer commentedon May 19, 2021
TBH I am hitting this issue trying to just do basic testing with
uvuand typescript. I have ts files that import$app/envanduvufails to resolve this usingts-nodebut I know you guys have set testing as a post 1.0. But any hacks or workarounds would be greatly appreciated. #19josephspurrier commentedon May 19, 2021
Are we able to use something like https://github.com/eirslett/storybook-builder-vite to help with this - or is this a problem outside of Vite?
josephspurrier commentedon May 19, 2021
@madeleineostoja for Storybook, in the .storybook/main.js/cjs, can you try using
preprocess.replacelike this for each of your aliases (https://github.com/sveltejs/svelte-preprocess#replace-values):josephspurrier commentedon May 19, 2021
Ah, I see the challenge - the modules like
$app/envare the problem, not just aliases. My workaround won't help there.madeleineostoja commentedon May 19, 2021
Yeah this isn't to do with your own custom aliases, but the runtime modules of sveltekit. There needs to be a way to consume or shim them in non-sveltekit contexts like testing. Updated issue title to be clearer on the issue
[-]Shimming sveltekit runtime import aliases in other contexts[/-][+]Shimming sveltekit runtime modules in other contexts[/+]Dan6erbond commentedon May 31, 2021
I'd like to voice my support for a feature that would allow libraries to neatly get access to the
$app/navigation,$app/stores, and$app/envmodules.As the creator and maintainer of SvelteKitAuth we're trying to provide a way for users to augment the SvelteKit session with authentication data using the
getSession()hook, and upon changes in the session it would be nice to reset it internally instead of expecting users to do something likesignOut().then(session.set), and a similar story for routing. SincesignIn()either generates a redirect URL or sends a directfetch()request depending on the payload provided, currently we're returning the URL and expect users to route themselves withgoto()as such:Letting libraries handle these things internally means less boilerplate for our users, so getting access to the SvelteKit router in a global module, instead of a scoped one would be useful. This is how other frameworks and libraries such as the Vue Router and React Router handle this, as they make use of the global React instance SvelteKit might have to work around the fact that Svelte doesn't provide such a thing, but create its own global context or a singleton.
madeleineostoja commentedon Jun 16, 2021
I've fixed this in storybook by using their new vite-builder and adding manual aliases to sveltekit's
$appruntime moduleWith the caveat being that you have to have run
sveltekit devfirst to generate those runtime modules. I think this is worth documenting (the path to the alias if nothing else) for others that need to shim these modules until Svelte comes up with an official workaroundbenmccann commentedon Aug 2, 2021
Here's an example of someone having to mock this stuff out for testing: rossyman/svelte-add-jest#14 (comment)
patrickleet commentedon Aug 2, 2021
Author of comment of the said person who had to mock this stuff. I don't mind mocking - fine as a workaround for unit testing anyway. It wasn't exactly simple to figure out the correct mocks though.
benmccann commentedon Aug 20, 2021
It looks like
import.meta.envalso might need to be mocked: #2210 (comment)32 remaining items
dskloetd commentedon Sep 4, 2023
amosjyng commentedon Oct 10, 2023
For anyone else that gets the error
I believe that is related to this issue. I had a minimal repro set up for a new issue before realizing it's probably the same as this issue. Run
to reproduce. On commit
388142a, it works. After this commit, the test breaks in the manner mentioned above.opack commentedon Oct 31, 2023
We found some solution to work around not being able to mock those modules. In case it can help someone in the same situation, and in order to gather some feedback about what we found, I write below the whole story: our context and our solution.
Some context
Just to explain how this “shimming” this is crucial to us, and how we really tried to avoid is… in vain :-(
For our project, we are using TDD, SvelteKit and Superforms. So, be able to test is crucial for us. That being said, we ran into this “mocking” problem before with
$envand resolved it easily, but when trying to implement Superforms we had a real blocker.We spent a lot of time on the Internet, browsing issues, testing solutions. But as there seem to be no way to correctly shim the
$appmodules (especially$app/formsand$app/navigation, which both contain some complex logic methods such asbeforeNavigate,enhanceorapplyAction), we had to choose between these solutions:$appmodules, but this would fail when using libraries that also use these modules. So, a solution would be to abandon thoses librairies. Problem is that there is not always a good alternative not using thoses Svelte modules, and it is most certain that at some point we run into another library using thoses modules.Our workaround solution
As no solution was valid, we tried to change a bit our way of doing things. Currently, we do component testing with Playwright experimental component testing feature. But in the end, component testing is just end-to-end testing with a specific page containing only one component. This seems to be indeed how SvelteKit seems to be tested: small “apps” exposing only a specific feature to be tested.
So we implemented this:
src/routes/testsand have some conventions for the folders beneath:src/routes/(auth)/signup/+page.svelte, we need to create asrc/routes/tests/(auth)/signup/+page.svelte. When testing asrc/lib/components/form-input/form-input.svelte, we need to create asrc/routes/tests/lib/components/form-input/+page.svelte.mountin a Playwright component test), then we create a subfolder with a_prefix and a name explaining how this feature is different. For example, if we need to test a theFormInputcomponent mentioned above in a situation that it would receive avalueparameter, then we createsrc/routes/tests/lib/components/form-input/_has-initial-value/+page.svelte.src.npm run devfor example) so that we can run our tests and most importantly benefit from HMR.Reading test results in the Playwright test
To be able to make this work, we also had to find a way to retrieve some result value from the tested component. For example, how to test that a button component correctly calls a callback when it is submitted? In e2e testing, this can be tricky because we only browse as a user do, we do not have access to the code. For this purpose, we created a utility component and method to help displaying and retrieving data:
We then use it like this:
What’s cool
We are just begining to use this, so maybe I’ll come back in a few days/weeks and tell it’s totally lame to do that 😅 But what we see in this solution are the following perks:
<svelte:head>to change the title of the page, orgoto)What’s not so great
There are some downsides to this technique:
As explained before, if the component has to be tested in different configurations (which would correspond to a new call to
mountin Playwright component testing), then we need to create 1 route (which means 1 subfolder and 1+page.svelte) for each of these configurations. Fortunately, we should not have a lot of different configurations for our components.The bigger one: we need to find a way to remove testing routes from the final bundle. Or course, we do not want to ship those tests routes, so we want to tell Vite to just ignore what is in
src/routes/tests. Unfortunately, it does not seem to be possible. I spent a good amount of time on the Internet, tried some things (vite configuration, Rollup configuration, creating a vite plugin) but nothing worked. The only solution that I found is to use renamer to change the name of the files before and after build. Our NPM script becomes:The caveat with this being that some strange thing could occur if you edit or rename the file elsewhere during this process.
I would love to have a simpler way to do this (just like “hey vite, completely ignore this folder please”), so if anyone has an idea, please send me a message 😬
What I would love from SvelteKit
I hope this will help someone, but I would love to have some things from SK out-of-the-box:
Please feel free to tell me what you think about this solution, and if I missed something. We will continue on this path and I will come back here and edit if we found something interesting, especially if everything turned out to be garbage in the end 😅 (but I hope not 😉)
opack commentedon Nov 13, 2023
Hi! As promised, here's some feedback after using this technique for 2 weeks. It's working rather well regarding the initial problem of not having a way to mock
$appmodules.However, we are having some issues:
$appmodules problem with nos solution (as Vitest has no mean to go to a URL to perform tests, nor can it launch a headless browser as Playwright does).@benmccann I know you're all very busy and that there's a lot of work to be done on this framework that we all love. Nevertheless, in the absence of any feedback from the team on this subject, I can't help but wonder how this work is being prioritized.
Indeed, it is (in my opinion) crucial to the widespread adoption of SvelteKit, given that if it's impossible to properly test our applications (which is unfortunately the case today) then SvelteKit (and therefore Svelte) will probably not be chosen in many contexts.
In any case, that's the conclusion we've reached. Today, we'd like to have some feedback on the implementation of a solution to this problem, as well as a possible delivery target. I'm well aware that the notion of a deadline on such a project is a very complicated one, but we need to know whether we can expect to wait a few weeks, or whether we're talking months or years, in which case we'll have to turn to another framework.
I'm not sure I'll be able to help more directly by contributing code, but if possible please feel free to give some general lines on what needs to be done, in case I or someone passing by can lend a hand on the subject 😉
Thanks again for your work, really, and I hope this topic can move forward! 🙏
benmccann commentedon Nov 22, 2023
Storybook now has built-in mocks for SvelteKit: storybookjs/storybook#24795
opack commentedon Nov 22, 2023
ogulcan-north commentedon Sep 9, 2025
Kattenelvis commentedon Oct 2, 2025
teemingc commentedon Feb 4, 2026
Aside from
$env/*which will soon be importable, can folks here share which APIs they would like to be able to easily mock or run into errors when importing? I'll look into making the$app/*modules importable tooogulcan-north commentedon Feb 5, 2026
@teemingc That would be wonderful. Besides the
$envand$appimports, aliases and also$libimport does not work. It can be solved with relative imports, but it's very annoying.breaking: overhaul tsconfig (#16458)
teemingc commentedon Aug 20, 2026
I'm going to close this issue because the original post (unable to import Kit modules in Storybook) and the comments (shimming Kit modules) are very old and deviated from the original post. In SvelteKit 3, the
$envand$appmodules are written to disk. The$libalias is also removed in favour of Node subpath imports. Therefore, the issue of errors from SvelteKit imports not being resolvable is probably resolved. If anyone still faces this issue, please open a new issue specifying the exact import/API that errors.