Skip to content

Commit

Permalink
Merge pull request #29592 from storybookjs/yann/fix-next-13-sandboxes
Browse files Browse the repository at this point in the history
Build: Exclude server action stories to run in next 13
  • Loading branch information
yannbf authored Nov 12, 2024
2 parents fa138f6 + 12be898 commit 0676c9c
Show file tree
Hide file tree
Showing 4 changed files with 146 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import React from 'react';

import { revalidatePath } from '@storybook/nextjs/cache.mock';
import { cookies } from '@storybook/nextjs/headers.mock';
import { getRouter, redirect } from '@storybook/nextjs/navigation.mock';
import type { Meta, StoryObj } from '@storybook/react';
import { expect, userEvent, waitFor, within } from '@storybook/test';

import { accessRoute, login, logout } from './server-actions';

function Component() {
return (
<div style={{ display: 'flex', gap: 8 }}>
<form>
<button type="submit" formAction={login}>
Login
</button>
</form>
<form>
<button type="submit" formAction={logout}>
Logout
</button>
</form>
<form>
<button type="submit" formAction={accessRoute}>
Access protected route
</button>
</form>
</div>
);
}

export default {
component: Component,
tags: ['!test'],
parameters: {
nextjs: {
appDirectory: true,
navigation: {
pathname: '/',
},
},
test: {
// This is needed until Next will update to the React 19 beta: https://github.com/vercel/next.js/pull/65058
// In the React 19 beta ErrorBoundary errors (such as redirect) are only logged, and not thrown.
// We will also suspress console.error logs for re the console.error logs for redirect in the next framework.
// Using the onCaughtError react root option:
// react: {
// rootOptions: {
// onCaughtError(error: unknown) {
// if (isNextRouterError(error)) return;
// console.error(error);
// },
// },
// See: code/frameworks/nextjs/src/preview.tsx
dangerouslyIgnoreUnhandledErrors: true,
},
},
} as Meta<typeof Component>;

type Story = StoryObj<typeof Component>;

export const ProtectedWhileLoggedOut: Story = {
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
await userEvent.click(canvas.getByText('Access protected route'));

await expect(cookies().get).toHaveBeenCalledWith('user');
await expect(redirect).toHaveBeenCalledWith('/');

await waitFor(() => expect(getRouter().push).toHaveBeenCalled());
},
};

export const ProtectedWhileLoggedIn: Story = {
beforeEach() {
cookies().set('user', 'storybookjs');
},
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
await userEvent.click(canvas.getByText('Access protected route'));

await expect(cookies().get).toHaveBeenLastCalledWith('user');
await expect(revalidatePath).toHaveBeenLastCalledWith('/');
await expect(redirect).toHaveBeenLastCalledWith('/protected');

await waitFor(() => expect(getRouter().push).toHaveBeenCalled());
},
};

export const Logout: Story = {
beforeEach() {
cookies().set('user', 'storybookjs');
},
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);

await userEvent.click(canvas.getByText('Logout'));
await expect(cookies().delete).toHaveBeenCalled();
await expect(revalidatePath).toHaveBeenCalledWith('/');
await expect(redirect).toHaveBeenCalledWith('/');

await waitFor(() => expect(getRouter().push).toHaveBeenCalled());
},
};

export const Login: Story = {
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
await userEvent.click(canvas.getByText('Login'));

await expect(cookies().set).toHaveBeenCalledWith('user', 'storybookjs');
await expect(revalidatePath).toHaveBeenCalledWith('/');
await expect(redirect).toHaveBeenCalledWith('/');

await waitFor(() => expect(getRouter().push).toHaveBeenCalled());
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
'use server';

import { revalidatePath } from 'next/cache';
import { cookies } from 'next/headers';
import { redirect } from 'next/navigation';

export async function accessRoute() {
const user = (await cookies()).get('user');

if (!user) {
redirect('/');
}

revalidatePath('/');
redirect(`/protected`);
}

export async function logout() {
(await cookies()).delete('user');
revalidatePath('/');
redirect('/');
}

export async function login() {
(await cookies()).set('user', 'storybookjs');
revalidatePath('/');
redirect('/');
}

0 comments on commit 0676c9c

Please sign in to comment.