Skip to content

Commit

Permalink
Merge pull request #109 from kitcc-org/102-rewrite-login-test
Browse files Browse the repository at this point in the history
ログインページのテストを書き直した
  • Loading branch information
kimurash authored Oct 31, 2024
2 parents c1992c9 + e0b9bf4 commit c1bb2f7
Show file tree
Hide file tree
Showing 8 changed files with 460 additions and 52 deletions.
2 changes: 1 addition & 1 deletion frontend/app/components/login/LoginEmailForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const LoginEmailForm = ({ form }: LoginEmailFormProps) => {
withAsterisk
autoComplete="email"
key={form.key('email')}
data-testid="email-input"
aria-label="メールアドレス"
{...form.getInputProps('email')}
/>
);
Expand Down
2 changes: 1 addition & 1 deletion frontend/app/components/login/LoginPasswordForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const LoginPasswordForm = ({ form }: LoginPasswordFormProps) => {
withAsterisk
autoComplete="current-password"
key={form.key('password')}
data-testid="password-input"
aria-label="パスワード"
{...form.getInputProps('password')}
/>
);
Expand Down
1 change: 1 addition & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
"@cloudflare/workers-types": "^4.20241004.0",
"@faker-js/faker": "^9.0.3",
"@remix-run/dev": "2.12.0",
"@remix-run/testing": "2.12.0",
"@testing-library/jest-dom": "^6.6.2",
"@testing-library/react": "^16.0.1",
"@testing-library/user-event": "^14.5.2",
Expand Down
301 changes: 299 additions & 2 deletions frontend/pnpm-lock.yaml

Large diffs are not rendered by default.

30 changes: 19 additions & 11 deletions frontend/test/helpers/wrapper.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { MantineProvider } from '@mantine/core';
import { Notifications } from '@mantine/notifications';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { render } from '@testing-library/react';
import { render, RenderOptions } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { ReactElement } from 'react';
import { ReactElement, ReactNode } from 'react';

export const renderWithWrapper = (children: ReactElement) => {
const wrappper = ({ children }: { children: ReactNode }) => {
const queryClient = new QueryClient({
defaultOptions: {
queries: {
Expand All @@ -15,15 +15,23 @@ export const renderWithWrapper = (children: ReactElement) => {
},
},
});

return (
<QueryClientProvider client={queryClient}>
<MantineProvider>
<Notifications />
{children}
</MantineProvider>
</QueryClientProvider>
);
};

export const customRender = (
ui: ReactElement,
options?: Omit<RenderOptions, 'wrapper'>,
) => {
return {
user: userEvent.setup(),
...render(
<QueryClientProvider client={queryClient}>
<MantineProvider>
<Notifications />
{children}
</MantineProvider>
</QueryClientProvider>,
),
...render(ui, { wrapper: wrappper, ...options }),
};
};
5 changes: 5 additions & 0 deletions frontend/test/mocks/@remix-run/cloudflare.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export const redirect = vi
.fn()
.mockImplementation((url: string, init?: number | ResponseInit) => {
return null;
});
99 changes: 98 additions & 1 deletion frontend/test/routes/auth.login.test.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,123 @@
import type * as remixruncloudflare from '@remix-run/cloudflare';
import { ActionFunctionArgs, LoaderFunctionArgs } from '@remix-run/cloudflare';
import { createRemixStub } from '@remix-run/testing';
import { screen } from '@testing-library/react';
import LoginPage, { action, loader } from '~/routes/auth.login';
import { customRender } from '../helpers/wrapper';
import { redirect } from '../mocks/@remix-run/cloudflare';

vi.mock('@remix-run/cloudflare', async (importOriginal) => {
const actual = await importOriginal<typeof remixruncloudflare>();
return {
...actual,
redirect: (url: string, init?: number | ResponseInit) => {
return redirect(url, init);
},
};
});

const LoginPageStub = createRemixStub([
{
path: '/login',
Component: LoginPage,
async loader({ request }) {
return await loader({ request } as LoaderFunctionArgs);
},
async action({ request }) {
return await action({ request } as ActionFunctionArgs);
},
},
]);

describe('Login page', () => {
it('should login successfully', async () => {
const { user } = customRender(
<LoginPageStub initialEntries={['/login']} />,
);

// メールアドレスを入力
const emailForm = await screen.findByLabelText('メールアドレス');
await user.type(emailForm, 'user@example.com');
expect(emailForm).toHaveValue('user@example.com');

// パスワードを入力
const passwordForm = await screen.findByLabelText('パスワード');
await user.type(passwordForm, 'passw0rd');
expect(passwordForm).toHaveValue('passw0rd');

// ログインボタンをクリック
// ログイン成功の通知が表示される
// prettier-ignore
const submitButton = await screen.findByRole('button', { name: 'ログイン' });
await user.click(submitButton);

// マイページへリダイレクトされる
// prettier-ignore
expect(redirect).toHaveBeenCalledWith(
'/home/mypage',
{
headers: {
'Set-Cookie': expect.any(String),
},
}
);
});

it('should fail to pass when email is invalid', async () => {
const { user } = customRender(
<LoginPageStub initialEntries={['/login']} />,
);

// メールアドレスを入力
const emailForm = await screen.findByLabelText('メールアドレス');
await user.type(emailForm, 'user@invalid');

// ログインボタンをクリック
// prettier-ignore
const submitButton = await screen.findByRole('button', { name: 'ログイン' });
await user.click(submitButton);

// エラーメッセージが表示される
const message = await screen.findByText('有効でないメールアドレスです');
expect(message).toBeInTheDocument();
});

it('should fail to pass when password length is less than 8', async () => {
const { user } = customRender(
<LoginPageStub initialEntries={['/login']} />,
);

// パスワードを入力
const passwordForm = await screen.findByLabelText('パスワード');
await user.type(passwordForm, 'hoge');

// ログインボタンをクリック
// prettier-ignore
const submitButton = await screen.findByRole('button', { name: 'ログイン' });
await user.click(submitButton);

// エラーメッセージが表示される
// prettier-ignore
const message = await screen.findByText('パスワードは8文字以上で入力してください');
expect(message).toBeInTheDocument();
});

it('should fail to pass when password is not alphanumeric', async () => {
const { user } = customRender(
<LoginPageStub initialEntries={['/login']} />,
);

// パスワードを入力
const passwordForm = await screen.findByLabelText('パスワード');
await user.type(passwordForm, 'password');

// ログインボタンをクリック
// prettier-ignore
const submitButton = await screen.findByRole('button', { name: 'ログイン' });
await user.click(submitButton);

// エラーメッセージが表示される
// prettier-ignore
const message = await screen.findByText('パスワードにはアルファベットと数字を含めてください');
expect(message).toBeInTheDocument();
});
});
72 changes: 36 additions & 36 deletions frontend/vite.config.ts
Original file line number Diff line number Diff line change
@@ -1,41 +1,41 @@
/// <reference types="vitest" />
import {
vitePlugin as remix,
cloudflareDevProxyVitePlugin as remixCloudflareDevProxy,
} from "@remix-run/dev";
import { defineConfig } from "vite";
import tsconfigPaths from "vite-tsconfig-paths";
vitePlugin as remix,
cloudflareDevProxyVitePlugin as remixCloudflareDevProxy,
} from '@remix-run/dev';
import { defineConfig } from 'vite';
import tsconfigPaths from 'vite-tsconfig-paths';

export default defineConfig({
plugins: [
remixCloudflareDevProxy(),
!process.env.VITEST
? remix({
future: {
v3_fetcherPersist: true,
v3_relativeSplatPath: true,
v3_throwAbortReason: true,
},
})
: null,
tsconfigPaths(),
],
server: {
proxy: {},
https: {
key: "./certs/key.pem",
cert: "./certs/cert.pem",
},
},
test: {
alias: {
"~/*": "./app/*",
},
env: {
NODE_TLS_REJECT_UNAUTHORIZED: "0",
},
environment: "happy-dom",
globals: true,
setupFiles: ["./test/setup.ts"],
},
plugins: [
remixCloudflareDevProxy(),
!process.env.VITEST
? remix({
future: {
v3_fetcherPersist: true,
v3_relativeSplatPath: true,
v3_throwAbortReason: true,
},
})
: null,
tsconfigPaths(),
],
server: {
proxy: {},
https: {
key: './certs/key.pem',
cert: './certs/cert.pem',
},
},
test: {
alias: {
'~/*': './app/*',
},
env: {
NODE_TLS_REJECT_UNAUTHORIZED: '0',
},
environment: 'happy-dom',
globals: true,
setupFiles: ['./test/setup.ts'],
},
});

0 comments on commit c1bb2f7

Please sign in to comment.