storybookjs/storybook

[Feature Request]: SvelteKit mocks

benmccann opened this issue ยท 9 comments

Is your feature request related to a problem? Please describe

SvelteKit's $app/navigation and $app/forms don't work today because they rely on the SvelteKit client singleton, which isn't initialized since there's no application and just individual components. We wouldn't really want to make them work anyway because we don't want to actually do navigations and so we should mock these components.

Describe the solution you'd like

Implement a Vite plugin (probably in sveltekit/src/plugins) that overrides Kit's goto, and either calls the action() from addon-actions or sends an event over the channel.

If we wanted to get real fancy we'd let users map URLs to stories, and then use that map when intercepting goto and friends, to navigate stories instead. Like:

import * as OtherPageStories from './OtherPage.stories';
import ThisPage from '../pages/xyz';

export default {
  component: ThisPage,
  parameters: {
    goto: {
      ['/some/url/that/usually/displays/other-page']: OtherPageStories.DefaultPage
    }
  }
}

export const DefaultPage = {};

Describe alternatives you've considered

Intercept all navigations, ignores them, and logs them to the Actions panel similar to the NextJS integration

Are you able to assist to bring the feature to reality?

I can advise from the SvelteKit side, but not implement. PRs would be very welcome!

Additional context

No response

@benmccann does SvelteKit's handling of <a> tags as described here use goto internally, or do they work differently?
https://kit.svelte.dev/docs/link-options

In other words, if we create mocks for goto would that automatically make <a> tags work too, or do we need something separate to handle that?

I was able to come up with a workaround so I can test my forms that have use:enhance. With the storybook-addon-manual-mocks addon, you can make a wrapper for the enhance function to be able to mock it.

  1. Follow the getting started guide for the addon.
  2. Create a wrapper for your sveltekit function that uses $app/form (or potentially $app/navigate, haven't tested).

$lib/form.js

import { enhance } from "$app/forms";

export default enhance

Use the function as normal inside your svelte component and import the wrapper:

$lib/Component.svelte

<script>
	import enhance from "$lib/form";
</script>

<form use:enhance method="post">
...
</form>

Now create the mocked enhance function. The mocked folder needs to be in the same parent folder as the wrapper.
$lib/__ mocks __/form.js

export default function () {}

Directory:
Wrapper Function: $lib/form.js Mocked Function: $lib/__mocks__/form.js

It's a bit less than ideal needing to have a wrapper for the function, but at least I can run my tests without errors.

Oh wow, that's great inspiration for how we could bake this in, in the future.

great job on the addon @gebeto!

Is there any update on this issue? The proposed workaround by @eugenepentland only works when $app/forms is installed in the app itself. If you use a third party library that uses the forms module (for example, sveltekit-superforms) you cannot mock the function.

Sveltekit recently did an update which fixes the disable_scroll_handling issue in storybook. I was interested in mocks just so this error would quietly fail, this might help you as well.

sveltejs/kit#9808

this feature is needed to use components with superforms because it uses beforeNavigate inside

import { superForm } from "sveltekit-superforms/client";

hi, generally like SB but this issue is starting to make it impossible to actually use it for tests. Any goto anywhere breaks the entire test used to break pretty much all of Storybook, these days it only seems to break in CI mode

I've on occasion tried a variety of things over the past few months but can't get anything to ever work. Is there any way to currently test a component which calls or imports goto at any point of the lifetime of the component?

If someone encounters this weird error when using superForms:

Uncaught (in promise) TypeError: Invalid value used as weak map key
    at WeakMap.set (<anonymous>)
    at superForm (sveltekit-superforms_client.js?v=49a9ffcb:2100:15)

you have to mock the page store inside your story to fix this:

export const Default: Story = {
  parameters: {
    sveltekit_experimental: {
      stores: {
        page: {},
      },
    },
  },
};