diff --git a/code/e2e-tests/framework-svelte.spec.ts b/code/e2e-tests/framework-svelte.spec.ts index ceffacc525d7..40d2b7f817dd 100644 --- a/code/e2e-tests/framework-svelte.spec.ts +++ b/code/e2e-tests/framework-svelte.spec.ts @@ -91,4 +91,36 @@ test.describe('SvelteKit', () => { }); await expect(complexLogItem).toBeVisible(); }); + + test('goto are logged in Actions panel', async ({ page }) => { + const sbPage = new SbPage(page); + + await sbPage.navigateToStory('stories/sveltekit/modules/navigation', 'default-actions'); + const root = sbPage.previewRoot(); + await sbPage.viewAddonPanel('Actions'); + + const goto = root.locator('button', { hasText: 'goto' }); + await goto.click(); + + const gotoLogItem = page.locator('#storybook-panel-root #panel-tab-content', { + hasText: `/storybook-goto`, + }); + await expect(gotoLogItem).toBeVisible(); + + const invalidate = root.getByRole('button', { name: 'invalidate', exact: true }); + await invalidate.click(); + + const invalidateLogItem = page.locator('#storybook-panel-root #panel-tab-content', { + hasText: `/storybook-invalidate`, + }); + await expect(invalidateLogItem).toBeVisible(); + + const invalidateAll = root.getByRole('button', { name: 'invalidateAll' }); + await invalidateAll.click(); + + const invalidateAllLogItem = page.locator('#storybook-panel-root #panel-tab-content', { + hasText: `"invalidateAll"`, + }); + await expect(invalidateAllLogItem).toBeVisible(); + }); }); diff --git a/code/frameworks/sveltekit/README.md b/code/frameworks/sveltekit/README.md index d9242efcdbf1..20248ce0d3f3 100644 --- a/code/frameworks/sveltekit/README.md +++ b/code/frameworks/sveltekit/README.md @@ -130,16 +130,16 @@ export const MyStory = { You can add the name of the module you want to mock to `parameters.sveltekit_experimental` (in the example above we are mocking the `stores` module which correspond to `$app/stores`) and then pass the following kind of objects: -| Module | Path in parameters | Kind of objects | -| ------------------------------------------------- | ------------------------------------------------------------ | -------------------------------------------------------------------------------------------------- | -| `import { page } from "$app/stores"` | `parameters.sveltekit_experimental.stores.page` | A Partial of the page store | -| `import { navigating } from "$app/stores"` | `parameters.sveltekit_experimental.stores.navigating` | A Partial of the navigating store | -| `import { updated } from "$app/stores"` | `parameters.sveltekit_experimental.stores.updated` | A boolean representing the value of updated (you can also access `check()` which will be a noop) | -| `import { goto } from "$app/navigation"` | `parameters.sveltekit_experimental.navigation.goto` | A callback that will be called whenever goto is called | -| `import { invalidate } from "$app/navigation"` | `parameters.sveltekit_experimental.navigation.invalidate` | A callback that will be called whenever invalidate is called | -| `import { invalidateAll } from "$app/navigation"` | `parameters.sveltekit_experimental.navigation.invalidateAll` | A callback that will be called whenever invalidateAll is called | -| `import { afterNavigate } from "$app/navigation"` | `parameters.sveltekit_experimental.navigation.afterNavigate` | An object that will be passed to the afterNavigate function (which will be invoked onMount) called | -| `import { enhance } from "$app/forms"` | `parameters.sveltekit_experimental.forms.enhance` | A callback that will called when a form with `use:enhance` is submitted | +| Module | Path in parameters | Kind of objects | +| ------------------------------------------------- | ------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------- | +| `import { page } from "$app/stores"` | `parameters.sveltekit_experimental.stores.page` | A Partial of the page store | +| `import { navigating } from "$app/stores"` | `parameters.sveltekit_experimental.stores.navigating` | A Partial of the navigating store | +| `import { updated } from "$app/stores"` | `parameters.sveltekit_experimental.stores.updated` | A boolean representing the value of updated (you can also access `check()` which will be a noop) | +| `import { goto } from "$app/navigation"` | `parameters.sveltekit_experimental.navigation.goto` | A callback that will be called whenever goto is called, in no function is provided an action will be logged to the Actions panel | +| `import { invalidate } from "$app/navigation"` | `parameters.sveltekit_experimental.navigation.invalidate` | A callback that will be called whenever invalidate is called, in no function is provided an action will be logged to the Actions panel | +| `import { invalidateAll } from "$app/navigation"` | `parameters.sveltekit_experimental.navigation.invalidateAll` | A callback that will be called whenever invalidateAll is called, in no function is provided an action will be logged to the Actions panel | +| `import { afterNavigate } from "$app/navigation"` | `parameters.sveltekit_experimental.navigation.afterNavigate` | An object that will be passed to the afterNavigate function (which will be invoked onMount) called | +| `import { enhance } from "$app/forms"` | `parameters.sveltekit_experimental.forms.enhance` | A callback that will called when a form with `use:enhance` is submitted | All the other functions are still exported as `noop` from the mocked modules so that your application will still work. diff --git a/code/frameworks/sveltekit/src/preview.ts b/code/frameworks/sveltekit/src/preview.ts index a43431b5103d..10affca46fc4 100644 --- a/code/frameworks/sveltekit/src/preview.ts +++ b/code/frameworks/sveltekit/src/preview.ts @@ -63,9 +63,14 @@ export const decorators: Decorator[] = [ * eg. storybook:goto, storybook:invalidateAll * @param baseModule the base module where the function lives (navigation|forms) * @param functions the list of functions in that module that emit events + * @param {boolean} [defaultToAction] the list of functions in that module that emit events * @returns a function to remove all the listener added */ - function createListeners(baseModule: keyof SvelteKitParameters, functions: string[]) { + function createListeners( + baseModule: keyof SvelteKitParameters, + functions: string[], + defaultToAction?: boolean + ) { // the array of every added listener, we can use this in the return function // to clean them const toRemove: Array<{ @@ -75,10 +80,11 @@ export const decorators: Decorator[] = [ functions.forEach((func) => { // we loop over every function and check if the user actually passed // a function in sveltekit_experimental[baseModule][func] eg. sveltekit_experimental.navigation.goto - if ( + const hasFunction = (svelteKitParameters as any)[baseModule]?.[func] && - (svelteKitParameters as any)[baseModule][func] instanceof Function - ) { + (svelteKitParameters as any)[baseModule][func] instanceof Function; + // if we default to an action we still add the listener (this will be the case for goto, invalidate, invalidateAll) + if (hasFunction || defaultToAction) { // we create the listener that will just get the detail array from the custom element // and call the user provided function spreading this args in...this will basically call // the function that the user provide with the same arguments the function is invoked to @@ -87,7 +93,12 @@ export const decorators: Decorator[] = [ // it provided to storybook will be called with "/my-route" const listener = ({ detail = [] as any[] }) => { const args = Array.isArray(detail) ? detail : []; - (svelteKitParameters as any)[baseModule][func](...args); + // if it has a function in the parameters we call that function + // otherwise we invoke the action + const fnToCall = hasFunction + ? (svelteKitParameters as any)[baseModule][func] + : action(func); + fnToCall(...args); }; const eventType = `storybook:${func}`; toRemove.push({ eventType, listener }); @@ -104,11 +115,11 @@ export const decorators: Decorator[] = [ }; } - const removeNavigationListeners = createListeners('navigation', [ - 'goto', - 'invalidate', - 'invalidateAll', - ]); + const removeNavigationListeners = createListeners( + 'navigation', + ['goto', 'invalidate', 'invalidateAll'], + true + ); const removeFormsListeners = createListeners('forms', ['enhance']); window.addEventListener('click', globalClickListener); diff --git a/code/frameworks/sveltekit/template/stories_svelte-kit-skeleton-js/Navigation.svelte b/code/frameworks/sveltekit/template/stories_svelte-kit-skeleton-js/Navigation.svelte index f857ae36a843..b923b8ee78d8 100644 --- a/code/frameworks/sveltekit/template/stories_svelte-kit-skeleton-js/Navigation.svelte +++ b/code/frameworks/sveltekit/template/stories_svelte-kit-skeleton-js/Navigation.svelte @@ -9,13 +9,13 @@ diff --git a/code/frameworks/sveltekit/template/stories_svelte-kit-skeleton-js/navigation.stories.js b/code/frameworks/sveltekit/template/stories_svelte-kit-skeleton-js/navigation.stories.js index 529997126f7c..ded12268e03c 100644 --- a/code/frameworks/sveltekit/template/stories_svelte-kit-skeleton-js/navigation.stories.js +++ b/code/frameworks/sveltekit/template/stories_svelte-kit-skeleton-js/navigation.stories.js @@ -14,7 +14,7 @@ export const Goto = { const canvas = within(canvasElement); const button = canvas.getByText('goto'); button.click(); - expect(goto).toHaveBeenCalledWith('/storybook'); + expect(goto).toHaveBeenCalledWith('/storybook-goto'); }, parameters: { sveltekit_experimental: { @@ -25,6 +25,8 @@ export const Goto = { }, }; +export const DefaultActions = {}; + const invalidate = fn(); export const Invalidate = { @@ -32,7 +34,7 @@ export const Invalidate = { const canvas = within(canvasElement); const button = canvas.getByText('invalidate', { exact: true }); button.click(); - expect(invalidate).toHaveBeenCalledWith('/storybook'); + expect(invalidate).toHaveBeenCalledWith('/storybook-invalidate'); }, parameters: { sveltekit_experimental: { diff --git a/code/frameworks/sveltekit/template/stories_svelte-kit-skeleton-ts/Navigation.svelte b/code/frameworks/sveltekit/template/stories_svelte-kit-skeleton-ts/Navigation.svelte index d97b6fe8a2df..4bcb7d0e6fc9 100644 --- a/code/frameworks/sveltekit/template/stories_svelte-kit-skeleton-ts/Navigation.svelte +++ b/code/frameworks/sveltekit/template/stories_svelte-kit-skeleton-ts/Navigation.svelte @@ -8,13 +8,13 @@ diff --git a/code/frameworks/sveltekit/template/stories_svelte-kit-skeleton-ts/navigation.stories.js b/code/frameworks/sveltekit/template/stories_svelte-kit-skeleton-ts/navigation.stories.js index 529997126f7c..ded12268e03c 100644 --- a/code/frameworks/sveltekit/template/stories_svelte-kit-skeleton-ts/navigation.stories.js +++ b/code/frameworks/sveltekit/template/stories_svelte-kit-skeleton-ts/navigation.stories.js @@ -14,7 +14,7 @@ export const Goto = { const canvas = within(canvasElement); const button = canvas.getByText('goto'); button.click(); - expect(goto).toHaveBeenCalledWith('/storybook'); + expect(goto).toHaveBeenCalledWith('/storybook-goto'); }, parameters: { sveltekit_experimental: { @@ -25,6 +25,8 @@ export const Goto = { }, }; +export const DefaultActions = {}; + const invalidate = fn(); export const Invalidate = { @@ -32,7 +34,7 @@ export const Invalidate = { const canvas = within(canvasElement); const button = canvas.getByText('invalidate', { exact: true }); button.click(); - expect(invalidate).toHaveBeenCalledWith('/storybook'); + expect(invalidate).toHaveBeenCalledWith('/storybook-invalidate'); }, parameters: { sveltekit_experimental: {