Skip to content

Commit c946bc1

Browse files
committed
Merge pull request #29593 from storybookjs/yann/fix-next-13-sandboxes-again
Build: Move more stories out of next 13 sandbox (cherry picked from commit 22df58c)
1 parent b8c7ccf commit c946bc1

File tree

10 files changed

+182
-0
lines changed

10 files changed

+182
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import React from 'react';
2+
3+
import type { Meta, StoryObj } from '@storybook/react';
4+
5+
import { getImageProps } from 'next/image';
6+
7+
import Accessibility from '../../assets/accessibility.svg';
8+
import Testing from '../../assets/testing.png';
9+
10+
// referenced from https://nextjs.org/docs/pages/api-reference/components/image#theme-detection-picture
11+
const Component = (props: any) => {
12+
const {
13+
props: { srcSet: dark },
14+
} = getImageProps({ src: Accessibility, ...props });
15+
const {
16+
// capture rest on one to spread to img as default; it doesn't matter which barring art direction
17+
props: { srcSet: light, ...rest },
18+
} = getImageProps({ src: Testing, ...props });
19+
20+
return (
21+
<picture>
22+
<source media="(prefers-color-scheme: dark)" srcSet={dark} />
23+
<source media="(prefers-color-scheme: light)" srcSet={light} />
24+
<img {...rest} />
25+
</picture>
26+
);
27+
};
28+
29+
export default {
30+
component: Component,
31+
args: {
32+
alt: 'getImageProps Example',
33+
},
34+
} as Meta<typeof Component>;
35+
36+
export const Default: StoryObj<typeof Component> = {};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import { cookies, headers } from '@storybook/nextjs/headers.mock';
2+
import type { Meta, StoryObj } from '@storybook/react';
3+
import { expect, userEvent, within } from '@storybook/test';
4+
5+
import NextHeader from './NextHeader';
6+
7+
export default {
8+
component: NextHeader,
9+
parameters: {
10+
react: {
11+
rsc: true,
12+
},
13+
},
14+
} as Meta<typeof NextHeader>;
15+
16+
type Story = StoryObj<typeof NextHeader>;
17+
18+
export const Default: Story = {
19+
loaders: async () => {
20+
cookies().set('firstName', 'Jane');
21+
cookies().set({
22+
name: 'lastName',
23+
value: 'Doe',
24+
});
25+
headers().set('timezone', 'Central European Summer Time');
26+
},
27+
play: async ({ canvasElement, step }) => {
28+
const canvas = within(canvasElement);
29+
const headersMock = headers();
30+
const cookiesMock = cookies();
31+
await step('Cookie and header store apis are called upon rendering', async () => {
32+
await expect(cookiesMock.getAll).toHaveBeenCalled();
33+
await expect(headersMock.entries).toHaveBeenCalled();
34+
});
35+
36+
await step('Upon clicking on submit, the user-id cookie is set', async () => {
37+
const submitButton = await canvas.findByRole('button');
38+
await userEvent.click(submitButton);
39+
40+
await expect(cookiesMock.set).toHaveBeenCalledWith('user-id', 'encrypted-id');
41+
});
42+
43+
await step('The user-id cookie is available in cookie and header stores', async () => {
44+
await expect(headersMock.get('cookie')).toContain('user-id=encrypted-id');
45+
await expect(cookiesMock.get('user-id')).toEqual({
46+
name: 'user-id',
47+
value: 'encrypted-id',
48+
});
49+
});
50+
},
51+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import React from 'react';
2+
3+
import { cookies, headers } from 'next/headers';
4+
5+
export default async function Component() {
6+
async function handleClick() {
7+
'use server';
8+
(await cookies()).set('user-id', 'encrypted-id');
9+
}
10+
11+
return (
12+
<>
13+
<h3>Cookies:</h3>
14+
{(await cookies()).getAll().map(({ name, value }) => {
15+
return (
16+
<p key={name} style={{ display: 'flex', flexDirection: 'row', gap: 8 }}>
17+
<strong>Name:</strong> <span>{name}</span>
18+
<strong>Value:</strong> <span>{value}</span>
19+
</p>
20+
);
21+
})}
22+
23+
<h3>Headers:</h3>
24+
{Array.from((await headers()).entries()).map(([name, value]: [string, string]) => {
25+
return (
26+
<p key={name} style={{ display: 'flex', flexDirection: 'row', gap: 8 }}>
27+
<strong>Name:</strong> <span>{name}</span>
28+
<strong>Value:</strong> <span>{value}</span>
29+
</p>
30+
);
31+
})}
32+
33+
<form action={handleClick}>
34+
<button>add user-id cookie</button>
35+
</form>
36+
</>
37+
);
38+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import React from 'react';
2+
3+
import type { Meta, StoryObj } from '@storybook/react';
4+
import { userEvent, within } from '@storybook/test';
5+
6+
import { redirect } from 'next/navigation';
7+
8+
let state = 'Bug! Not invalidated';
9+
10+
export default {
11+
render() {
12+
return (
13+
<div>
14+
<div>{state}</div>
15+
<form
16+
action={() => {
17+
state = 'State is invalidated successfully.';
18+
redirect('/');
19+
}}
20+
>
21+
<button>Submit</button>
22+
</form>
23+
</div>
24+
);
25+
},
26+
parameters: {
27+
test: {
28+
// This is needed until Next will update to the React 19 beta: https://github.com/vercel/next.js/pull/65058
29+
// In the React 19 beta ErrorBoundary errors (such as redirect) are only logged, and not thrown.
30+
// We will also suspress console.error logs for re the console.error logs for redirect in the next framework.
31+
// Using the onCaughtError react root option:
32+
// react: {
33+
// rootOptions: {
34+
// onCaughtError(error: unknown) {
35+
// if (isNextRouterError(error)) return;
36+
// console.error(error);
37+
// },
38+
// },
39+
// See: code/frameworks/nextjs/src/preview.tsx
40+
dangerouslyIgnoreUnhandledErrors: true,
41+
},
42+
nextjs: {
43+
appDirectory: true,
44+
navigation: {
45+
pathname: '/',
46+
},
47+
},
48+
},
49+
tags: ['!test'],
50+
} as Meta;
51+
52+
export const SingletonStateGetsInvalidatedAfterRedirecting: StoryObj = {
53+
play: async ({ canvasElement, step }) => {
54+
const canvas = within(canvasElement);
55+
await userEvent.click(canvas.getByRole('button'));
56+
},
57+
};

0 commit comments

Comments
 (0)