Skip to content

Commit

Permalink
Merge pull request #24955 from paoloricciuti/default-actions-for-goto
Browse files Browse the repository at this point in the history
SvelteKit: Default to log an action for `goto`, `invalidate` and `invalidateAll`
  • Loading branch information
JReinhold authored Nov 24, 2023
2 parents 574bb87 + 3546b45 commit 306c510
Show file tree
Hide file tree
Showing 7 changed files with 75 additions and 28 deletions.
32 changes: 32 additions & 0 deletions code/e2e-tests/framework-svelte.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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();
});
});
20 changes: 10 additions & 10 deletions code/frameworks/sveltekit/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down
31 changes: 21 additions & 10 deletions code/frameworks/sveltekit/src/preview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<{
Expand All @@ -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
Expand All @@ -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 });
Expand All @@ -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);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@

<button
on:click={() => {
goto('/storybook');
goto('/storybook-goto');
}}>goto</button
>

<button
on:click={() => {
invalidate('/storybook');
invalidate('/storybook-invalidate');
}}>invalidate</button
>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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: {
Expand All @@ -25,14 +25,16 @@ export const Goto = {
},
};

export const DefaultActions = {};

const invalidate = fn();

export const Invalidate = {
async play({ canvasElement }) {
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: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@

<button
on:click={() => {
goto('/storybook');
goto('/storybook-goto');
}}>goto</button
>

<button
on:click={() => {
invalidate('/storybook');
invalidate('/storybook-invalidate');
}}>invalidate</button
>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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: {
Expand All @@ -25,14 +25,16 @@ export const Goto = {
},
};

export const DefaultActions = {};

const invalidate = fn();

export const Invalidate = {
async play({ canvasElement }) {
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: {
Expand Down

0 comments on commit 306c510

Please sign in to comment.