diff --git a/next-ui/src/mocks/api/handlers.ts b/next-ui/src/mocks/api/handlers.ts index 567965c3..6292f56e 100644 --- a/next-ui/src/mocks/api/handlers.ts +++ b/next-ui/src/mocks/api/handlers.ts @@ -19,3 +19,6 @@ export const handlers = [ export const response401Unauthorized = () => HttpResponse.json({ error: 'Unauthorized' }, { status: 401 }) + +export const response502BadGateway = () => + HttpResponse.json({ error: 'Bad gateway' }, { status: 502 }) diff --git a/next-ui/src/pages/login.stories.ts b/next-ui/src/pages/login.stories.ts new file mode 100644 index 00000000..39ab81da --- /dev/null +++ b/next-ui/src/pages/login.stories.ts @@ -0,0 +1,98 @@ +import type { Meta, StoryObj } from '@storybook/vue3-vite' + +import login from './login.vue' +import { http, delay } from 'msw' + +import { response401Unauthorized, response502BadGateway } from '@/mocks/api/handlers' +import { expect, waitFor } from 'storybook/test' +import { useMessagesStore } from '@/stores/messages' + +const meta = { + component: login, + render: (args: object) => ({ + components: { login }, + setup() { + return { args } + }, + template: '', + }), + parameters: { + // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout + }, + args: {}, +} satisfies Meta + +export default meta +type Story = StoryObj + +export const Default: Story = { + args: {}, +} + +export const Invalid: Story = { + parameters: { + msw: { + handlers: [http.get('*/api/v2/users/me', response401Unauthorized)], + }, + }, + play: async ({ canvas, userEvent }) => { + const login = canvas.getByLabelText(/email/i, { + selector: 'input', + }) + await userEvent.type(login, 'test@example.org') + + const password = canvas.getByLabelText(/password/i, { + selector: 'input', + }) + await userEvent.type(password, 'abc') + + await userEvent.click(canvas.getByRole('button', { name: /sign in/i })) + + await waitFor(() => expect(canvas.getByText(/invalid login/i)).toBeVisible()) + }, +} + +export const Loading: Story = { + parameters: { + msw: { + handlers: [http.all('*', async () => await delay(5_000))], + }, + }, + play: async ({ canvas, userEvent }) => { + const login = canvas.getByLabelText(/email/i, { + selector: 'input', + }) + await userEvent.type(login, 'test@example.org') + + const password = canvas.getByLabelText(/password/i, { + selector: 'input', + }) + await userEvent.type(password, 'abc') + + await userEvent.click(canvas.getByRole('button', { name: /sign in/i })) + }, +} + +export const Error: Story = { + parameters: { + msw: { + handlers: [http.all('*', response502BadGateway)], + }, + }, + play: async ({ canvas, userEvent }) => { + const login = canvas.getByLabelText(/email/i, { + selector: 'input', + }) + await userEvent.type(login, 'test@example.org') + + const password = canvas.getByLabelText(/password/i, { + selector: 'input', + }) + await userEvent.type(password, 'abc') + + await userEvent.click(canvas.getByRole('button', { name: /sign in/i })) + + const messagesStore = useMessagesStore() + await waitFor(() => expect(messagesStore.messages.length).toBe(1)) + }, +}