fix: fix storybook build cache not being used by tests in CI (#5451)

TL;DR:
- removed `--configuration={args.scope}` from `storybook:static:test`
for the `storybook:static` part, as it was making `front-sb-test` jobs
in CI not reuse the cache from the `front-sb-build` job and re-build
storybook every time.
- replaced it with a new `test` configuration which optimizes storybook
build for tests and builds storybook 2x faster.

## Fix storybook:build cache usage in CI

`storybook:static:test` executes two scripts in parallel:
1. `storybook:static`, which depends on `storybook:build`
1.a. it builds storybook first with `storybook:build`, the output
directory is `storybook-static`.
1.b. then it launches an `http-server`, using what has been built in
`storybook-static`
2. `storybook:test` to execute tests (needs the storybook http-server to
be running)

When passing `--configuration=pages` or `--configuration=modules` to
`storybook:static` from step 1, those configurations are passed to the
`storybook:build` script from step 1.a as well.

But for Nx `storybook:build` and `storybook:build --configuration=pages`
(or `modules`) are not the same command, therefore one does not reuse
the cache of the other because they could output completely different
things.

As `front-sb-test` jobs are passing `--configuration={args.scope}` to
`storybook:static`, the cache of the previously executed
`storybook:build` (from `front-sb-build`) is not reused and therefore
each job re-builds Storybook with its own scope, which increases CI
time.

### Solution

- Removed scope configurations from `storybook:static` and
`storybook:build` scripts to avoid confusion.
- `storybook:test` and `storybook:dev` can keep scope configurations as
they can be useful and this doesn't impact storybook build cache in CI.

### Improve Storybook build time for testing

Added the `test` configuration to `storybook:build` and
`storybook:static` which makes Storybook build time 2x faster. It
disables addons that slow down build time and are not used in tests.
This commit is contained in:
Thaïs
2024-05-17 16:05:31 +02:00
committed by GitHub
parent 36e54119a3
commit 992602b307
9 changed files with 98 additions and 54 deletions

View File

@ -18,7 +18,7 @@ import { IconButton, IconButtonVariant } from '../button/components/IconButton';
import { LightIconButton } from '../button/components/LightIconButton';
import { IconPickerHotkeyScope } from '../types/IconPickerHotkeyScope';
type IconPickerProps = {
export type IconPickerProps = {
disabled?: boolean;
dropdownId?: string;
onChange: (params: { iconKey: string; Icon: IconComponent }) => void;
@ -154,6 +154,11 @@ export const IconPicker = ({
dropdownHotkeyScope={{ scope: IconPickerHotkeyScope.IconPicker }}
clickableComponent={
<IconButton
ariaLabel={`Click to select icon ${
selectedIconKey
? `(selected: ${selectedIconKey})`
: `(no icon selected)`
}`}
disabled={disabled}
Icon={selectedIconKey ? getIcon(selectedIconKey) : IconApps}
variant={variant}

View File

@ -1,3 +1,4 @@
import { useArgs } from '@storybook/preview-api';
import { Meta, StoryObj } from '@storybook/react';
import { expect, userEvent, within } from '@storybook/test';
import { ComponentDecorator } from 'twenty-ui';
@ -5,12 +6,29 @@ import { ComponentDecorator } from 'twenty-ui';
import { IconsProviderDecorator } from '~/testing/decorators/IconsProviderDecorator';
import { sleep } from '~/testing/sleep';
import { IconPicker } from '../IconPicker';
import { IconPicker, IconPickerProps } from '../IconPicker';
type RenderProps = IconPickerProps;
const Render = (args: RenderProps) => {
const [{ selectedIconKey }, updateArgs] = useArgs();
return (
<IconPicker
// eslint-disable-next-line react/jsx-props-no-spreading
{...args}
onChange={({ iconKey }) => {
updateArgs({ selectedIconKey: iconKey });
}}
selectedIconKey={selectedIconKey}
/>
);
};
const meta: Meta<typeof IconPicker> = {
title: 'UI/Input/IconPicker/IconPicker',
component: IconPicker,
decorators: [IconsProviderDecorator, ComponentDecorator],
render: Render,
};
export default meta;
@ -18,39 +36,45 @@ type Story = StoryObj<typeof IconPicker>;
export const Default: Story = {};
export const WithSelectedIcon: Story = {
args: { selectedIconKey: 'IconCalendarEvent' },
};
export const WithOpen: Story = {
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
const iconPickerButton = await canvas.findByRole('button');
const iconPickerButton = await canvas.findByRole('button', {
name: 'Click to select icon (no icon selected)',
});
userEvent.click(iconPickerButton);
await userEvent.click(iconPickerButton);
},
};
export const WithOpenAndSelectedIcon: Story = {
export const WithSelectedIcon: Story = {
args: { selectedIconKey: 'IconCalendarEvent' },
};
export const WithOpenAndSelectedIcon: Story = {
...WithSelectedIcon,
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
const iconPickerButton = await canvas.findByRole('button');
const iconPickerButton = await canvas.findByRole('button', {
name: 'Click to select icon (selected: IconCalendarEvent)',
});
userEvent.click(iconPickerButton);
await userEvent.click(iconPickerButton);
},
};
export const WithSearch: Story = {
args: { selectedIconKey: 'IconBuildingSkyscraper' },
...WithSelectedIcon,
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
const iconPickerButton = await canvas.findByRole('button');
const iconPickerButton = await canvas.findByRole('button', {
name: 'Click to select icon (selected: IconCalendarEvent)',
});
userEvent.click(iconPickerButton);
await userEvent.click(iconPickerButton);
const searchInput = await canvas.findByRole('textbox');
@ -67,13 +91,15 @@ export const WithSearch: Story = {
};
export const WithSearchAndClose: Story = {
args: { selectedIconKey: 'IconBuildingSkyscraper' },
...WithSelectedIcon,
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
const iconPickerButton = await canvas.findByRole('button');
let iconPickerButton = await canvas.findByRole('button', {
name: 'Click to select icon (selected: IconCalendarEvent)',
});
userEvent.click(iconPickerButton);
await userEvent.click(iconPickerButton);
let searchInput = await canvas.findByRole('textbox');
@ -87,13 +113,19 @@ export const WithSearchAndClose: Story = {
expect(searchedIcon).toBeInTheDocument();
userEvent.click(searchedIcon);
await userEvent.click(searchedIcon);
await sleep(100);
await sleep(500);
expect(searchedIcon).not.toBeInTheDocument();
iconPickerButton = await canvas.findByRole('button', {
name: 'Click to select icon (selected: IconBuildingSkyscraper)',
});
userEvent.click(iconPickerButton);
await sleep(100);
await sleep(500);
searchInput = await canvas.findByRole('textbox');