From 338cb9543cd7e7f8a58223bd399828ac93f66d96 Mon Sep 17 00:00:00 2001 From: Ivan <8611739+IRBorisov@users.noreply.github.com> Date: Sun, 2 Mar 2025 19:28:32 +0300 Subject: [PATCH] M: Setup testing mocks --- README.md | 1 + rsconcept/backend/apps/users/serializers.py | 12 ---- rsconcept/frontend/eslint.config.js | 8 ++- rsconcept/frontend/package-lock.json | 49 +++++++++++++ rsconcept/frontend/package.json | 1 + rsconcept/frontend/tests/app.spec.ts | 3 +- rsconcept/frontend/tests/mocks/auth.ts | 36 +++++++++- rsconcept/frontend/tests/mocks/users.ts | 72 +++++++++++++++++++ rsconcept/frontend/tsconfig.json | 2 +- rsconcept/frontend/tsconfig.test.json | 8 +++ ...{tsconfig.node.json => tsconfig.vite.json} | 2 +- 11 files changed, 176 insertions(+), 18 deletions(-) create mode 100644 rsconcept/frontend/tests/mocks/users.ts create mode 100644 rsconcept/frontend/tsconfig.test.json rename rsconcept/frontend/{tsconfig.node.json => tsconfig.vite.json} (92%) diff --git a/README.md b/README.md index 5fb8fb12..1487e40d 100644 --- a/README.md +++ b/README.md @@ -66,6 +66,7 @@ This readme file is used mostly to document project dependencies and conventions - eslint-plugin-simple-import-sort - eslint-plugin-react-hooks - eslint-plugin-tsdoc + - eslint-plugin-playwright - babel-plugin-react-compiler - vite - jest diff --git a/rsconcept/backend/apps/users/serializers.py b/rsconcept/backend/apps/users/serializers.py index 071f058c..1c546be3 100644 --- a/rsconcept/backend/apps/users/serializers.py +++ b/rsconcept/backend/apps/users/serializers.py @@ -77,18 +77,6 @@ class AuthSerializer(serializers.Serializer): } -class UserInfoSerializer(serializers.ModelSerializer): - ''' Serializer: User data. ''' - class Meta: - ''' serializer metadata. ''' - model = models.User - fields = [ - 'id', - 'first_name', - 'last_name', - ] - - class UserSerializer(serializers.ModelSerializer): ''' Serializer: User data. ''' id = serializers.IntegerField(read_only=True) diff --git a/rsconcept/frontend/eslint.config.js b/rsconcept/frontend/eslint.config.js index 7c9a475d..8cb311aa 100644 --- a/rsconcept/frontend/eslint.config.js +++ b/rsconcept/frontend/eslint.config.js @@ -6,6 +6,7 @@ import reactCompilerPlugin from 'eslint-plugin-react-compiler'; import reactHooksPlugin from 'eslint-plugin-react-hooks'; import importPlugin from 'eslint-plugin-import'; import simpleImportSort from 'eslint-plugin-simple-import-sort'; +import playwright from 'eslint-plugin-playwright'; export default [ ...typescriptPlugin.configs.recommendedTypeChecked, @@ -20,11 +21,16 @@ export default [ ecmaVersion: 'latest', sourceType: 'module', globals: { ...globals.browser, ...globals.es2020, ...globals.jest }, - project: ['./tsconfig.json', './tsconfig.node.json'], + project: ['./tsconfig.json', './tsconfig.vite.json', './tsconfig.test.json'], projectService: true } } }, + { + ...playwright.configs['flat/recommended'], + files: ['tests/**'], + rules: { ...playwright.configs['flat/recommended'].rules } + }, { plugins: { 'react': reactPlugin, diff --git a/rsconcept/frontend/package-lock.json b/rsconcept/frontend/package-lock.json index c39b3a1b..98a83bee 100644 --- a/rsconcept/frontend/package-lock.json +++ b/rsconcept/frontend/package-lock.json @@ -53,6 +53,7 @@ "babel-plugin-react-compiler": "^19.0.0-beta-21e868a-20250216", "eslint": "^9.21.0", "eslint-plugin-import": "^2.31.0", + "eslint-plugin-playwright": "^2.2.0", "eslint-plugin-react": "^7.37.4", "eslint-plugin-react-compiler": "^19.0.0-beta-21e868a-20250216", "eslint-plugin-react-hooks": "^5.1.0", @@ -5738,6 +5739,54 @@ "semver": "bin/semver.js" } }, + "node_modules/eslint-plugin-playwright": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-playwright/-/eslint-plugin-playwright-2.2.0.tgz", + "integrity": "sha512-qSQpAw7RcSzE3zPp8FMGkthaCWovHZ/BsXtpmnGax9vQLIovlh1bsZHEa2+j2lv9DWhnyeLM/qZmp7ffQZfQvg==", + "dev": true, + "license": "MIT", + "workspaces": [ + "examples" + ], + "dependencies": { + "globals": "^13.23.0" + }, + "engines": { + "node": ">=16.6.0" + }, + "peerDependencies": { + "eslint": ">=8.40.0" + } + }, + "node_modules/eslint-plugin-playwright/node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint-plugin-playwright/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/eslint-plugin-react": { "version": "7.37.4", "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.4.tgz", diff --git a/rsconcept/frontend/package.json b/rsconcept/frontend/package.json index 793b28a3..9c438a7c 100644 --- a/rsconcept/frontend/package.json +++ b/rsconcept/frontend/package.json @@ -59,6 +59,7 @@ "babel-plugin-react-compiler": "^19.0.0-beta-21e868a-20250216", "eslint": "^9.21.0", "eslint-plugin-import": "^2.31.0", + "eslint-plugin-playwright": "^2.2.0", "eslint-plugin-react": "^7.37.4", "eslint-plugin-react-compiler": "^19.0.0-beta-21e868a-20250216", "eslint-plugin-react-hooks": "^5.1.0", diff --git a/rsconcept/frontend/tests/app.spec.ts b/rsconcept/frontend/tests/app.spec.ts index a29b9162..7ec14360 100644 --- a/rsconcept/frontend/tests/app.spec.ts +++ b/rsconcept/frontend/tests/app.spec.ts @@ -6,9 +6,8 @@ test('should load the homepage and display login button', async ({ page }) => { await authAnonymous(page); await page.goto('/'); - await page.waitForSelector('.h-full > .mr-1'); await expect(page).toHaveTitle('Концепт Портал'); - await page.click('.h-full > .mr-1'); + await page.locator('.h-full > .mr-1').click(); await expect(page.getByText('Логин или email')).toBeVisible(); }); diff --git a/rsconcept/frontend/tests/mocks/auth.ts b/rsconcept/frontend/tests/mocks/auth.ts index 433047bd..9839cf1e 100644 --- a/rsconcept/frontend/tests/mocks/auth.ts +++ b/rsconcept/frontend/tests/mocks/auth.ts @@ -1,9 +1,43 @@ import { type Page } from '@playwright/test'; +import { type ICurrentUser } from '../../src/features/auth/backend/types'; import { BACKEND_URL } from '../constants'; +const dataAnonymousAuth: ICurrentUser = { + id: null, + username: '', + is_staff: false, + editor: [] +}; + +const dataAdminAuth: ICurrentUser = { + id: 1, + username: 'admin', + is_staff: true, + editor: [] +}; + +const dataUserAuth: ICurrentUser = { + id: 2, + username: 'user', + is_staff: false, + editor: [2] +}; + export async function authAnonymous(page: Page) { await page.route(`${BACKEND_URL}/users/api/auth`, async route => { - await route.fulfill({ json: { id: null } }); + await route.fulfill({ json: dataAnonymousAuth }); + }); +} + +export async function authAdmin(page: Page) { + await page.route(`${BACKEND_URL}/users/api/auth`, async route => { + await route.fulfill({ json: dataAdminAuth }); + }); +} + +export async function authUser(page: Page) { + await page.route(`${BACKEND_URL}/users/api/auth`, async route => { + await route.fulfill({ json: dataUserAuth }); }); } diff --git a/rsconcept/frontend/tests/mocks/users.ts b/rsconcept/frontend/tests/mocks/users.ts new file mode 100644 index 00000000..371f2f23 --- /dev/null +++ b/rsconcept/frontend/tests/mocks/users.ts @@ -0,0 +1,72 @@ +import { type Page } from '@playwright/test'; + +import { + type IUpdateProfileDTO, + type IUserInfo, + type IUserProfile, + type IUserSignupDTO +} from '../../src/features/users/backend/types'; +import { BACKEND_URL } from '../constants'; + +const dataActiveUsers: IUserInfo[] = [ + { + id: 1, + first_name: 'Admin', + last_name: 'User' + }, + { + id: 2, + first_name: 'User', + last_name: 'User' + } +]; + +let dataUserProfile: IUserProfile = { + id: 1, + username: 'user', + email: 'user@example.com', + first_name: 'User', + last_name: 'User' +}; + +export async function setupUsers(page: Page) { + await page.route(`${BACKEND_URL}/users/api/active-users`, async route => { + await route.fulfill({ json: dataActiveUsers }); + }); +} + +export async function setupUserProfile(page: Page) { + await page.route(`${BACKEND_URL}/users/api/profile`, async route => { + await route.fulfill({ json: dataUserProfile }); + }); +} + +export async function setupUserSignup(page: Page) { + await page.route(`${BACKEND_URL}/users/api/signup`, async route => { + const data = route.request().postDataJSON() as IUserSignupDTO; + const newID = dataActiveUsers.length + 1; + dataActiveUsers.push({ + id: newID, + first_name: data.first_name, + last_name: data.last_name + }); + dataUserProfile = { + id: newID, + username: data.username, + email: data.email, + first_name: data.first_name, + last_name: data.last_name + }; + await route.fulfill({ json: dataUserProfile }); + }); +} + +export async function setupUserProfileUpdate(page: Page) { + await page.route(`${BACKEND_URL}/users/api/profile`, async route => { + dataUserProfile = { + ...dataUserProfile, + ...(route.request().postDataJSON() as IUpdateProfileDTO) + }; + await route.fulfill({ json: dataUserProfile }); + }); +} diff --git a/rsconcept/frontend/tsconfig.json b/rsconcept/frontend/tsconfig.json index 3ace1996..6a2810eb 100644 --- a/rsconcept/frontend/tsconfig.json +++ b/rsconcept/frontend/tsconfig.json @@ -28,5 +28,5 @@ }, "types": ["vite/client"], "include": ["src"], - "references": [{ "path": "./tsconfig.node.json" }] + "references": [{ "path": "./tsconfig.vite.json" }] } diff --git a/rsconcept/frontend/tsconfig.test.json b/rsconcept/frontend/tsconfig.test.json new file mode 100644 index 00000000..a236604b --- /dev/null +++ b/rsconcept/frontend/tsconfig.test.json @@ -0,0 +1,8 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "types": ["playwright/test"], + "isolatedModules": false + }, + "include": ["src", "tests"] +} diff --git a/rsconcept/frontend/tsconfig.node.json b/rsconcept/frontend/tsconfig.vite.json similarity index 92% rename from rsconcept/frontend/tsconfig.node.json rename to rsconcept/frontend/tsconfig.vite.json index 1febc5ec..3fe47bf3 100644 --- a/rsconcept/frontend/tsconfig.node.json +++ b/rsconcept/frontend/tsconfig.vite.json @@ -11,5 +11,5 @@ "@/*": ["*"] } }, - "include": ["vite.config.ts", "package.json", "playwright.config.ts", "tests", "src"] + "include": ["vite.config.ts", "package.json", "playwright.config.ts"] }