From 23e699b61c7d5f3918a6e8d22efc57e0a8487ab2 Mon Sep 17 00:00:00 2001 From: Baozier Date: Tue, 8 Oct 2024 22:50:07 -0400 Subject: [PATCH] Add basic tests for admin panel mange role pages (#179) --- .github/workflows/pr-check.yml | 1 + .../app/[lang]/roles/[id]/page.test.tsx | 110 + admin-panel/app/[lang]/roles/[id]/page.tsx | 2 + .../app/[lang]/roles/new/page.test.tsx | 72 + admin-panel/app/[lang]/roles/new/page.tsx | 5 +- admin-panel/app/[lang]/roles/page.test.tsx | 47 + admin-panel/app/[lang]/roles/page.tsx | 4 +- admin-panel/app/api/v1/roles/[id]/route.ts | 1 - admin-panel/components/ConfirmModal.tsx | 1 + admin-panel/components/CreateButton.tsx | 1 + admin-panel/components/DeleteButton.tsx | 1 + admin-panel/components/EditLink.tsx | 4 +- admin-panel/components/SaveButton.tsx | 1 + admin-panel/package-lock.json | 2423 ++++++++++++++++- admin-panel/package.json | 7 +- admin-panel/tests/roleMock.ts | 16 + admin-panel/vitest.config.mts | 14 + admin-panel/vitest.setup.tsx | 24 + 18 files changed, 2653 insertions(+), 81 deletions(-) create mode 100644 admin-panel/app/[lang]/roles/[id]/page.test.tsx create mode 100644 admin-panel/app/[lang]/roles/new/page.test.tsx create mode 100644 admin-panel/app/[lang]/roles/page.test.tsx create mode 100644 admin-panel/tests/roleMock.ts create mode 100644 admin-panel/vitest.config.mts create mode 100644 admin-panel/vitest.setup.tsx diff --git a/.github/workflows/pr-check.yml b/.github/workflows/pr-check.yml index fd3512da..0b9d230b 100644 --- a/.github/workflows/pr-check.yml +++ b/.github/workflows/pr-check.yml @@ -30,3 +30,4 @@ jobs: - run: cd ./server && npm run test:check:node-key-rotate - run: cd ./server && npm run node:build - run: cd ./admin-panel && npm run build + - run: cd ./admin-panel && npm run test:check diff --git a/admin-panel/app/[lang]/roles/[id]/page.test.tsx b/admin-panel/app/[lang]/roles/[id]/page.test.tsx new file mode 100644 index 00000000..f358d281 --- /dev/null +++ b/admin-panel/app/[lang]/roles/[id]/page.test.tsx @@ -0,0 +1,110 @@ +import { + fireEvent, screen, +} from '@testing-library/react' +import { + describe, it, expect, vi, beforeEach, Mock, +} from 'vitest' +import Page from 'app/[lang]/roles/[id]/page' +import { roles } from 'tests/roleMock' +import { render } from 'vitest.setup' +import { + useGetApiV1RolesByIdQuery, + usePutApiV1RolesByIdMutation, + useDeleteApiV1RolesByIdMutation, +} from 'services/auth/api' + +vi.mock( + 'next/navigation', + () => ({ + useParams: vi.fn().mockReturnValue({ id: '2' }), + useRouter: vi.fn().mockReturnValue({ push: () => {} }), + }), +) + +vi.mock( + 'services/auth/api', + () => ({ + useGetApiV1RolesByIdQuery: vi.fn(), + usePutApiV1RolesByIdMutation: vi.fn(), + useDeleteApiV1RolesByIdMutation: vi.fn(), + }), +) + +const mockUpdate = vi.fn() +const mockDelete = vi.fn() +describe( + 'Page Component', + () => { + beforeEach(() => { + (useGetApiV1RolesByIdQuery as Mock).mockReturnValue({ data: { role: roles[1] } }); + (usePutApiV1RolesByIdMutation as Mock).mockReturnValue([mockUpdate, { isLoading: false }]); + (useDeleteApiV1RolesByIdMutation as Mock).mockReturnValue([mockDelete, { isLoading: false }]) + }) + + it( + 'render role', + async () => { + render() + + const nameInput = screen.queryByTestId('nameInput') as HTMLInputElement + const noteInput = screen.queryByTestId('noteInput') as HTMLInputElement + const saveBtn = screen.queryByTestId('saveButton') as HTMLButtonElement + const deleteBtn = screen.queryByTestId('deleteButton') + expect(nameInput?.value).toBe(roles[1].name) + expect(noteInput?.value).toBe(roles[1].note) + expect(saveBtn?.disabled).toBeTruthy() + expect(deleteBtn).toBeInTheDocument() + }, + ) + + it( + 'update role', + async () => { + render() + + const nameInput = screen.queryByTestId('nameInput') as HTMLInputElement + const noteInput = screen.queryByTestId('noteInput') as HTMLInputElement + const saveBtn = screen.queryByTestId('saveButton') as HTMLButtonElement + + fireEvent.change( + nameInput, + { target: { value: 'new name' } }, + ) + fireEvent.change( + noteInput, + { target: { value: 'new note' } }, + ) + + expect(nameInput?.value).toBe('new name') + expect(noteInput?.value).toBe('new note') + expect(saveBtn?.disabled).toBeFalsy() + fireEvent.click(saveBtn) + + expect(mockUpdate).toHaveBeenLastCalledWith({ + id: 2, + putRoleReq: { + name: 'new name', + note: 'new note', + }, + }) + }, + ) + + it( + 'delete role', + async () => { + render() + + const deleteBtn = screen.queryByTestId('deleteButton') as HTMLButtonElement + expect(screen.queryByRole('dialog')).not.toBeInTheDocument() + + fireEvent.click(deleteBtn) + expect(screen.queryByRole('dialog')).toBeInTheDocument() + + fireEvent.click(screen.queryByTestId('confirmButton') as HTMLButtonElement) + + expect(mockDelete).toHaveBeenLastCalledWith({ id: 2 }) + }, + ) + }, +) diff --git a/admin-panel/app/[lang]/roles/[id]/page.tsx b/admin-panel/app/[lang]/roles/[id]/page.tsx index ceed11c6..b49ea4b6 100644 --- a/admin-panel/app/[lang]/roles/[id]/page.tsx +++ b/admin-panel/app/[lang]/roles/[id]/page.tsx @@ -73,6 +73,7 @@ const Page = () => { {t('roles.name')} onChange( 'name', e.target.value, @@ -85,6 +86,7 @@ const Page = () => { {t('common.note')} onChange( 'note', e.target.value, diff --git a/admin-panel/app/[lang]/roles/new/page.test.tsx b/admin-panel/app/[lang]/roles/new/page.test.tsx new file mode 100644 index 00000000..9f6b484d --- /dev/null +++ b/admin-panel/app/[lang]/roles/new/page.test.tsx @@ -0,0 +1,72 @@ +import { + fireEvent, screen, +} from '@testing-library/react' +import { + describe, it, expect, vi, beforeEach, Mock, +} from 'vitest' +import Page from 'app/[lang]/roles/new/page' +import { render } from 'vitest.setup' +import { usePostApiV1RolesMutation } from 'services/auth/api' + +vi.mock( + 'next/navigation', + () => ({ useRouter: vi.fn().mockReturnValue({ push: () => {} }) }), +) + +vi.mock( + 'services/auth/api', + () => ({ usePostApiV1RolesMutation: vi.fn() }), +) + +const mockCreate = vi.fn().mockReturnValue({ data: { role: { id: 1 } } }) +describe( + 'Page Component', + () => { + beforeEach(() => { + (usePostApiV1RolesMutation as Mock).mockReturnValue([mockCreate, { isLoading: false }]) + }) + + it( + 'render page', + async () => { + render() + + const nameInput = screen.queryByTestId('nameInput') as HTMLInputElement + const noteInput = screen.queryByTestId('noteInput') as HTMLInputElement + const saveBtn = screen.queryByTestId('saveButton') as HTMLButtonElement + expect(nameInput?.value).toBe('') + expect(noteInput?.value).toBe('') + expect(saveBtn).toBeInTheDocument() + }, + ) + + it( + 'create role', + async () => { + render() + + const nameInput = screen.queryByTestId('nameInput') as HTMLInputElement + const noteInput = screen.queryByTestId('noteInput') as HTMLInputElement + const saveBtn = screen.queryByTestId('saveButton') as HTMLButtonElement + + fireEvent.change( + nameInput, + { target: { value: 'new name' } }, + ) + fireEvent.change( + noteInput, + { target: { value: 'new note' } }, + ) + + fireEvent.click(saveBtn) + + expect(mockCreate).toHaveBeenLastCalledWith({ + postRoleReq: { + name: 'new name', + note: 'new note', + }, + }) + }, + ) + }, +) diff --git a/admin-panel/app/[lang]/roles/new/page.tsx b/admin-panel/app/[lang]/roles/new/page.tsx index c694f04b..480ec824 100644 --- a/admin-panel/app/[lang]/roles/new/page.tsx +++ b/admin-panel/app/[lang]/roles/new/page.tsx @@ -55,11 +55,13 @@ const Page = () => { {t('roles.name')} onChange( 'name', e.target.value, )} - value={values.name} /> + value={values.name} + /> {showErrors && } @@ -67,6 +69,7 @@ const Page = () => { {t('common.note')} onChange( 'note', e.target.value, diff --git a/admin-panel/app/[lang]/roles/page.test.tsx b/admin-panel/app/[lang]/roles/page.test.tsx new file mode 100644 index 00000000..4ee184c0 --- /dev/null +++ b/admin-panel/app/[lang]/roles/page.test.tsx @@ -0,0 +1,47 @@ +import { + describe, it, expect, vi, beforeEach, Mock, +} from 'vitest' +import { + waitFor, screen, +} from '@testing-library/react' +import { render } from '../../../vitest.setup' +import Page from 'app/[lang]/roles/page' +import { roles } from 'tests/roleMock' +import { useGetApiV1RolesQuery } from 'services/auth/api' + +vi.mock( + 'services/auth/api', + () => ({ useGetApiV1RolesQuery: vi.fn() }), +) + +describe( + 'Page Component', + () => { + beforeEach(() => { + (useGetApiV1RolesQuery as Mock).mockReturnValue({ data: { roles } }) + }) + + it( + 'render roles', + async () => { + render() + + await waitFor(() => { + const rows = screen.queryAllByTestId('roleRow') + expect(rows.length).toBe(2) + expect(rows[0].querySelector('td')?.innerHTML).toContain(roles[0].name) + const editLinks = rows[0].querySelector('td')?.getElementsByTagName('a') + expect(editLinks?.length).toBe(0) + + expect(rows[1].querySelector('td')?.innerHTML).toContain(roles[1].name) + const editLinks1 = rows[1].querySelector('td')?.getElementsByTagName('a') + expect(editLinks1?.length).toBe(1) + expect(editLinks1?.[0].getAttribute('href')).toBe('/en/roles/2') + + const createButton = screen.getByTestId('createButton') + expect(createButton.getAttribute('href')).toBe('/en/roles/new') + }) + }, + ) + }, +) diff --git a/admin-panel/app/[lang]/roles/page.tsx b/admin-panel/app/[lang]/roles/page.tsx index 15997df3..cf225fd1 100644 --- a/admin-panel/app/[lang]/roles/page.tsx +++ b/admin-panel/app/[lang]/roles/page.tsx @@ -52,7 +52,9 @@ const Page = () => { {roles.map((role) => ( - +
diff --git a/admin-panel/app/api/v1/roles/[id]/route.ts b/admin-panel/app/api/v1/roles/[id]/route.ts index 4e360414..5775e330 100644 --- a/admin-panel/app/api/v1/roles/[id]/route.ts +++ b/admin-panel/app/api/v1/roles/[id]/route.ts @@ -24,7 +24,6 @@ export async function PUT ( const id = context.params.id const reqBody = await request.json() - console.log(reqBody) if (!reqBody) return throwForbiddenError() return sendS2SRequest({ diff --git a/admin-panel/components/ConfirmModal.tsx b/admin-panel/components/ConfirmModal.tsx index aeaf1158..77ec26db 100644 --- a/admin-panel/components/ConfirmModal.tsx +++ b/admin-panel/components/ConfirmModal.tsx @@ -25,6 +25,7 @@ const ConfirmModal = ({ {title} ) diff --git a/admin-panel/components/SaveButton.tsx b/admin-panel/components/SaveButton.tsx index b2fe8068..8b33e733 100644 --- a/admin-panel/components/SaveButton.tsx +++ b/admin-panel/components/SaveButton.tsx @@ -18,6 +18,7 @@ const SaveButton = ({ return (