feat(frontend): add jest

This commit is contained in:
Sergey Krylov 2025-09-03 06:16:12 +03:00
parent 10c0e5cf7c
commit 9cb8c376dd
11 changed files with 7078 additions and 5 deletions

View File

@ -0,0 +1 @@
module.exports = 'test-file-stub';

View File

@ -0,0 +1,3 @@
import { setupServer } from 'msw/node';
export const server = setupServer();

View File

@ -0,0 +1,19 @@
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import type { PropsWithChildren } from 'react';
export const createReactQueryWrapper = () => {
const queryClient = new QueryClient({
defaultOptions: {
queries: {
retry: false,
},
},
});
return ({ children }: PropsWithChildren) => (
<QueryClientProvider client={queryClient}>
{children}
</QueryClientProvider>
);
};

View File

@ -0,0 +1 @@
export { createReactQueryWrapper } from './ReactQueryWrapper';

View File

@ -0,0 +1,30 @@
// eslint-disable-next-line import/no-import-module-exports
import JSDOMEnvironment from 'jest-environment-jsdom';
class FixedJSDOMEnvironment extends JSDOMEnvironment {
constructor(...args: unknown[]) {
// @ts-ignore
super(...args);
this.global.TextDecoder = TextDecoder;
this.global.TextEncoder = TextEncoder;
this.global.TextDecoderStream = TextDecoderStream;
this.global.TextEncoderStream = TextEncoderStream;
this.global.ReadableStream = ReadableStream;
this.global.Blob = Blob;
this.global.Headers = Headers;
// this.global.FormData = FormData;
this.global.Request = Request;
this.global.Response = Response;
this.global.fetch = fetch;
this.global.structuredClone = structuredClone;
this.global.URL = URL;
this.global.URLSearchParams = URLSearchParams;
this.global.BroadcastChannel = BroadcastChannel;
this.global.TransformStream = TransformStream;
}
}
module.exports = FixedJSDOMEnvironment;

View File

@ -0,0 +1,6 @@
import '@testing-library/jest-dom';
import { server } from '@mocks/jest/server';
beforeAll(() => server.listen());
afterEach(() => server.resetHandlers());
afterAll(() => server.close());

View File

@ -9,7 +9,7 @@ export default [
{
rules: {
'import/no-extraneous-dependencies': ['error', {
devDependencies: ['eslint.config.ts', 'rsbuild.config.ts'],
devDependencies: ['eslint.config.ts', 'rsbuild.config.ts', 'configs/**/*'],
}],
'import/no-anonymous-default-export': 'off',
'import/order': [
@ -80,6 +80,7 @@ export default [
'@typescript-eslint/no-unnecessary-condition': 'off',
'jsx-a11y/click-events-have-key-events': 'off',
'jsx-a11y/no-static-element-interactions': 'off',
'jsx-a11y/no-noninteractive-element-interactions': 'off',
'@stylistic/indent': 'off',
'@stylistic/jsx-one-expression-per-line': 'off',
},
@ -87,4 +88,22 @@ export default [
{
ignores: ['./src/shared/api/schema.ts'],
},
{
files: [
'**/*.test.js',
'**/*.test.jsx',
'**/*.test.ts',
'**/*.test.tsx',
'**/__tests__/**',
'**/tests/**',
],
rules: {
'import/no-extraneous-dependencies': [
'error',
{ devDependencies: true }, // в тестах можно
],
'@typescript-eslint/no-unsafe-call': 'off',
'@typescript-eslint/no-unsafe-member-access': 'off',
},
},
];

23
frontend/jest.config.ts Normal file
View File

@ -0,0 +1,23 @@
import type { Config } from 'jest';
export default {
transform: {
'^.+\\.(t|j)sx?$': ['@swc/jest', {
jsc: {
transform: {
react: {
runtime: 'automatic',
},
},
},
}],
},
testEnvironment: '<rootDir>/configs/jest/jest-fixed-jsdom.ts',
setupFilesAfterEnv: ['<rootDir>/configs/jest/setupTests.ts'],
moduleNameMapper: {
'@/(.*)': '<rootDir>/src/$1',
'@mocks/(.*)': '<rootDir>/__mocks__/$1',
'\\.(css|scss|sass|less)$': 'identity-obj-proxy',
'\\.(jpg|jpeg|png|gif|webp|svg)$': '<rootDir>/__mocks__/jest/fileMock.js',
},
} as Config;

File diff suppressed because it is too large Load Diff

View File

@ -8,6 +8,7 @@
"dev": "rsbuild dev",
"preview": "rsbuild preview",
"lint": "eslint",
"test:unit": "jest",
"typecheck": "tsc --noEmit",
"openapi:gen": "npx openapi-typescript http://localhost:3000/docs/swagger.json -o src/shared/api/schema.ts"
},
@ -23,13 +24,25 @@
"@rsbuild/plugin-eslint": "1.1.2",
"@rsbuild/plugin-react": "1.3.5",
"@rsbuild/plugin-type-check": "1.2.4",
"@swc/core": "1.13.5",
"@swc/jest": "0.2.39",
"@tanstack/eslint-plugin-query": "5.83.1",
"@testing-library/dom": "10.4.1",
"@testing-library/jest-dom": "6.8.0",
"@testing-library/react": "16.3.0",
"@testing-library/user-event": "14.6.1",
"@types/jest": "30.0.0",
"@types/react": "19.1.9",
"@types/react-dom": "19.1.7",
"@typescript-eslint/parser": "8.39.0",
"eslint": "9.34.0",
"eslint-config-ksv741": "0.2.0",
"identity-obj-proxy": "3.0.0",
"jest": "30.1.1",
"jest-environment-jsdom": "30.1.1",
"msw": "2.10.5",
"openapi-typescript": "7.9.1",
"ts-node": "10.9.2",
"typescript": "5.9.2"
}
}

View File

@ -11,7 +11,7 @@
"module": "ESNext",
"moduleDetection": "force",
"moduleResolution": "bundler",
"verbatimModuleSyntax": true,
"verbatimModuleSyntax": false,
"resolveJsonModule": true,
"allowImportingTsExtensions": true,
"noUncheckedSideEffectImports": true,
@ -21,12 +21,17 @@
"noUnusedLocals": true,
"noUnusedParameters": true,
"paths": {
"@/*": ["./src/*"]
}
"@/*": ["./src/*"],
"@mocks/*": ["./__mocks__/*"]
},
"types": ["jest", "@testing-library/jest-dom"]
},
"include": [
"src",
"__mocks__",
"configs",
"eslint.config.ts",
"rsbuild.config.ts"
"rsbuild.config.ts",
"jest.config.ts"
]
}