Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ import {
import { FormFieldComponent } from '@lucca-front/ng/form-field';
import { LuSimpleSelectInputComponent } from '@lucca-front/ng/simple-select';
import { Meta, StoryObj, applicationConfig } from '@storybook/angular-vite';
import { expect, screen, userEvent, waitFor, within } from 'storybook/test';

import { createTestStory } from '@/helpers/stories';
import { sleep, waitForAngular } from '@/helpers/test';

@Component({
selector: 'sb-dialog-content',
Expand Down Expand Up @@ -150,3 +154,84 @@ openDialog(): void {
},
},
};

const openDialog = async (trigger: HTMLElement) => {
await userEvent.click(trigger);
await waitForAngular();
return screen.findByRole('dialog');
};

const expectClosed = () => waitFor(() => expect(screen.queryByRole('dialog')).not.toBeInTheDocument());

/** Gives the close attempt time to go through before asserting the dialog is still there. */
const expectStillOpen = async () => {
await sleep(100);
await expect(screen.getByRole('dialog')).toBeVisible();
};

export const BasicTEST = createTestStory(Basic, async ({ canvasElement, step }) => {
await waitForAngular();

const canvas = within(canvasElement);
const trigger = canvas.getByRole('button', { name: 'Open dialog' });

await step('Escape closes the dialog when canClose allows it', async () => {
const dialog = await openDialog(trigger);
await expect(dialog).toBeVisible();
await userEvent.keyboard('{Escape}');
await expectClosed();
});

await step('Cancel closes the dialog when canClose allows it', async () => {
await openDialog(trigger);
await userEvent.click(within(screen.getByRole('dialog')).getByRole('button', { name: 'Cancel' }));
await expectClosed();
});

await step('Confirm closes the dialog through the injected LuDialogRef', async () => {
await openDialog(trigger);
await userEvent.click(within(screen.getByRole('dialog')).getByRole('button', { name: 'Confirm' }));
await expectClosed();
});
});

export const CannotCloseTEST = createTestStory({ ...Basic, args: { ...Basic.args, canClose: false } }, async ({ canvasElement, step }) => {
await waitForAngular();

const canvas = within(canvasElement);
const trigger = canvas.getByRole('button', { name: 'Open dialog' });
await openDialog(trigger);

await step('Escape does not close a dialog denied by canClose', async () => {
await userEvent.keyboard('{Escape}');
await expectStillOpen();
});

await step('Cancel does not close a dialog denied by canClose', async () => {
await userEvent.click(within(screen.getByRole('dialog')).getByRole('button', { name: 'Cancel' }));
await expectStillOpen();
});

await step('Confirm still closes it, as LuDialogRef.close bypasses canClose', async () => {
await userEvent.click(within(screen.getByRole('dialog')).getByRole('button', { name: 'Confirm' }));
await expectClosed();
});
});

export const CannotCloseWithBackdropTEST = createTestStory({ ...Basic, args: { ...Basic.args, canCloseWithBackdrop: false } }, async ({ canvasElement, step }) => {
await waitForAngular();

const canvas = within(canvasElement);
const trigger = canvas.getByRole('button', { name: 'Open dialog' });
await openDialog(trigger);

await step('Escape is ignored, as it goes through the same stream as the backdrop click', async () => {
await userEvent.keyboard('{Escape}');
await expectStillOpen();
});
Comment on lines +228 to +231

await step('Cancel still closes the dialog', async () => {
await userEvent.click(within(screen.getByRole('dialog')).getByRole('button', { name: 'Cancel' }));
await expectClosed();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,11 @@ import { FormFieldComponent } from '@lucca-front/ng/form-field';
import { CheckboxInputComponent, TextInputComponent } from '@lucca-front/ng/forms';
import { IconComponent } from '@lucca-front/ng/icon';
import { Meta, StoryObj } from '@storybook/angular-vite';
import { expect, screen, userEvent, waitFor, within } from 'storybook/test';

import { HiddenArgType } from '@/helpers/common-arg-types';
import { createTestStory } from '@/helpers/stories';
import { waitForAngular } from '@/helpers/test';

@Component({
selector: 'dialog-confirmation-story',
Expand Down Expand Up @@ -138,3 +141,42 @@ export const Basic: StoryObj<DialogConfirmationStory> = {
},
render: template,
};

export const BasicTEST = createTestStory(Basic, async ({ canvasElement, step }) => {
await waitForAngular();

const canvas = within(canvasElement);
const trigger = canvas.getByRole('button', { name: 'Open Dialog with confirmation on dismiss' });

await step('The first dialog opens on click', async () => {
await userEvent.click(trigger);
await waitForAngular();
const dialog = await screen.findByRole('dialog');
await expect(within(dialog).getByRole('heading', { name: 'Dialog' })).toBeVisible();
});

await step('Dismissing stacks a confirmation dialog on top of the first one', async () => {
await userEvent.click(screen.getByRole('button', { name: 'Cancel with confirmation' }));
await waitForAngular();
await waitFor(() => expect(screen.getAllByRole('dialog')).toHaveLength(2));
await expect(screen.getByRole('heading', { name: 'Confirmation' })).toBeVisible();
});

await step('Confirming closes the confirmation dialog and leaves the first one open', async () => {
const confirmation = screen.getAllByRole('dialog')[1];
await userEvent.click(within(confirmation).getByRole('button', { name: 'Confirm' }));
await waitFor(() => expect(screen.getAllByRole('dialog')).toHaveLength(1));
await expect(screen.getByRole('heading', { name: 'Dialog' })).toBeVisible();
});

await step('Escape closes the topmost dialog only, then the last one', async () => {
await userEvent.click(screen.getByRole('button', { name: 'Cancel with confirmation' }));
await waitFor(() => expect(screen.getAllByRole('dialog')).toHaveLength(2));

await userEvent.keyboard('{Escape}');
await waitFor(() => expect(screen.getAllByRole('dialog')).toHaveLength(1));

await userEvent.keyboard('{Escape}');
await waitFor(() => expect(screen.queryByRole('dialog')).not.toBeInTheDocument());
});
});
49 changes: 49 additions & 0 deletions stories/documentation/overlays/dialog/dialog-routing.stories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ import { LinkComponent } from '@lucca-front/ng/link';
import { applicationConfig, Meta, StoryObj } from '@storybook/angular-vite';
import { map } from 'rxjs';
import { StoryModelDisplayComponent } from '@/helpers/story-model-display.component';
import { createTestStory } from '@/helpers/stories';
import { waitForAngular } from '@/helpers/test';
import { expect, screen, userEvent, waitFor, within } from 'storybook/test';
@Injectable()
class DataProvider {
dummy = signal(42);
Expand Down Expand Up @@ -371,3 +374,49 @@ Basic.parameters = {
},
},
};

export const BasicTEST = createTestStory(Basic, async ({ canvasElement, step }) => {
await waitForAngular();

const canvas = within(canvasElement);
const trigger = canvas.getByRole('button', { name: 'Navigate to /dialog/12' });
const openRoutedDialog = async () => {
await userEvent.click(trigger);
await waitForAngular();
return screen.findByRole('dialog');
};

await step('Navigating to the dialog route opens it with the data from its factory', async () => {
const dialog = await openRoutedDialog();
await expect(within(dialog).getByRole('heading', { name: 'Dialog opened by route' })).toBeVisible();
await expect(within(dialog).getByLabelText('Data received by dialog')).toHaveValue(42);
});

await step('Submitting closes the dialog and hands the form value to onClosed', async () => {
const dialog = screen.getByRole('dialog');
await userEvent.type(within(dialog).getByLabelText('Additionnal data to submit'), 'lucca');
await userEvent.click(within(dialog).getByRole('button', { name: 'Submit' }));
await waitFor(() => expect(screen.queryByRole('dialog')).not.toBeInTheDocument());
await expect(await canvas.findByText('dialog onClosed() called')).toBeVisible();
await expect(canvas.getByText(/"dataString": "lucca"/)).toBeVisible();
});

await step('Dismissing routes to the onDismissed destination', async () => {
await openRoutedDialog();
await userEvent.click(within(screen.getByRole('dialog')).getByRole('button', { name: 'Dismiss' }));
await waitFor(() => expect(screen.queryByRole('dialog')).not.toBeInTheDocument());
await expect(await canvas.findByText('dialog onDismissed() called')).toBeVisible();
});

await step('Escape dismisses the routed dialog as well', async () => {
trigger.focus();
await expect(trigger).toHaveFocus();
await userEvent.keyboard('{Enter}');
await waitForAngular();
await expect(await screen.findByRole('dialog')).toBeVisible();

await userEvent.keyboard('{Escape}');
await waitFor(() => expect(screen.queryByRole('dialog')).not.toBeInTheDocument());
await expect(await canvas.findByText('dialog onDismissed() called')).toBeVisible();
});
});
52 changes: 52 additions & 0 deletions stories/documentation/overlays/dialog/dialog-service.stories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ import {
import { FormFieldComponent } from '@lucca-front/ng/form-field';
import { LuSimpleSelectInputComponent } from '@lucca-front/ng/simple-select';
import { Meta, StoryObj, applicationConfig } from '@storybook/angular-vite';
import { expect, screen, userEvent, waitFor, within } from 'storybook/test';

import { createTestStory } from '@/helpers/stories';
import { waitForAngular } from '@/helpers/test';

@Component({
selector: 'sb-dialog-content',
Expand Down Expand Up @@ -110,3 +114,51 @@ export const Basic: StoryObj = {
mode: 'default',
},
};

export const BasicTEST = createTestStory(Basic, async ({ canvasElement, step }) => {
await waitForAngular();

const canvas = within(canvasElement);
const trigger = canvas.getByRole('button', { name: 'Open dialog' });
const expectClosed = () => waitFor(() => expect(screen.queryByRole('dialog')).not.toBeInTheDocument());
const openDialog = async () => {
await userEvent.click(trigger);
await waitForAngular();
return screen.findByRole('dialog');
};

await step('Opening through LuDialogService renders the dialog content component', async () => {
const dialog = await openDialog();
await expect(dialog).toBeVisible();
await expect(within(dialog).getByText('Header')).toBeVisible();
await expect(within(dialog).getAllByRole('combobox')).toHaveLength(4);
});

await step('Confirm closes the dialog through the injected LuDialogRef', async () => {
await userEvent.click(within(screen.getByRole('dialog')).getByRole('button', { name: 'Confirm' }));
await expectClosed();
});

await step('Cancel closes the dialog through luDialogDismiss', async () => {
await openDialog();
await userEvent.click(within(screen.getByRole('dialog')).getByRole('button', { name: 'Cancel' }));
await expectClosed();
});

await step('The header close button closes the dialog', async () => {
await openDialog();
await userEvent.click(within(screen.getByRole('dialog')).getByRole('button', { name: 'Fermer' }));
await expectClosed();
});

await step('The dialog opens with Enter and closes with Escape', async () => {
trigger.focus();
await expect(trigger).toHaveFocus();
await userEvent.keyboard('{Enter}');
await waitForAngular();
await expect(await screen.findByRole('dialog')).toBeVisible();

await userEvent.keyboard('{Escape}');
await expectClosed();
});
});
Loading