-
-
Notifications
You must be signed in to change notification settings - Fork 6.6k
Description
Version
29.7.0, 30.0.4
Steps to reproduce
its react app, react version is 18.2.0, bundler is vite
jest config
module.exports = {
setupFilesAfterEnv: ['<rootDir>/testconfig/setupTest.tsx'],
testEnvironment: 'jest-fixed-jsdom',
testEnvironmentOptions: {
customExportConditions: ['browsers']
},
modulePaths: ['<rootDir>src'],
testMatch: ['<rootDir>src/**/*(*.)@(spec|test).[tj]s?(x)'],
rootDir: '.',
transform: {
'^.+\\.(ts|tsx|js)$': 'babel-jest'
},
transformIgnorePatterns: ['/node_modules/(?!4game-ui)'],
moduleDirectories: ['node_modules'],
clearMocks: true,
moduleNameMapper: {
'^.+\\.module\\.(css|sass|scss)$': 'identity-obj-proxy',
'^@/(.*)$': '<rootDir>src/$1'
},
globals: {
__IS_DEV__: true,
__ENV__: 'development',
__AREA__: 'ru',
__IS_TESTING__: true,
TextEncoder: TextEncoder,
TextDecoder: TextDecoder,
Response: Response
}
};
setup tests
import '@testing-library/react';
import '@testing-library/jest-dom';
import { fetch, Headers, Request, Response } from 'cross-fetch';
import dayjs from 'dayjs';
import localeRu from 'dayjs/locale/ru';
import { setupServer } from 'msw/node';
import { store } from '@/app/store';
import { baseApi } from '@/shared/api';
dayjs.locale(localeRu);
global.fetch = fetch;
global.Headers = Headers;
global.Request = Request;
global.Response = Response;
export const server = setupServer();
beforeAll(() => {
// Enable API mocking before tests.
server.listen();
// Disable act warning
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
//@ts-expect-error
global.IS_REACT_ACT_ENVIRONMENT = false;
});
// Clear query cache
beforeEach(() => {
store.dispatch(baseApi.util.resetApiState());
});
// Reset any runtime request handlers we may add during the tests.
afterEach(() => {
server.resetHandlers();
});
// Disable API mocking after the tests are done.
afterAll(() => server.close());
jest.mock('@tanstack/react-router', () => ({
...jest.requireActual('@tanstack/react-router'),
useSearch: jest.fn(),
useNavigate: jest.fn(),
useRouterState: jest.fn(),
useBlocker: jest.fn(),
useParams: jest.fn(),
useLocation: jest.fn()
}));
jest.mock('@ckeditor/ckeditor5-react', () => ({
CKEditor: jest.fn()
}));
jest.mock('@ckeditor/ckeditor5-editor-balloon', () => ({
BalloonEditor: jest.fn()
}));
jest.mock('@ckeditor/ckeditor5-essentials', () => ({
Essentials: jest.fn()
}));
jest.mock('@ckeditor/ckeditor5-link', () => ({
Link: jest.fn(),
AutoLink: jest.fn()
}));
jest.mock('@ckeditor/ckeditor5-markdown-gfm', () => ({
Markdown: jest.fn()
}));
jest.mock('@ckeditor/ckeditor5-paragraph', () => ({
Paragraph: jest.fn()
}));
jest.mock('@/shared/ui/DoughnutChart', () => ({
__esModule: true,
default: () => <div>DoughnutChart</div>
}));
jest.mock('@/shared/ui/DoughnutChart/ui/DoughnutChartSkeleton', () => ({
__esModule: true,
default: () => <div>DoughnutChartSkeleton</div>
}));
jest.mock('@/shared/lib/components/ClassicEditor', () => ({
__esModule: true,
default: ({ value }: { value: string }) => (
<div data-testid="ClassicEditor">{value}</div>
)
}));
class DataTransfer {
items: Set<File> & {
remove: typeof Set.prototype.delete;
};
files: Set<File>;
data: Map<string, unknown>;
constructor() {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
this.items = new Set();
this.items.remove = this.items.delete;
this.files = this.items;
this.data = new Map();
}
setData(format: string, data: unknown) {
this.data.set(format, data);
}
}
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
global.DataTransfer = DataTransfer;
component test
import { screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { useFields } from '@/shared/lib/form';
import { componentRender } from '@/shared/lib/test/componentRender';
import { testIds } from '../../model/testIds/articleFormHeaderTestIds';
import { ArticleFormHeader } from './ArticleFormHeader';
const testId = 'ArticleFormHeader';
const toggleOpenTemplatesList = jest.fn();
const updateEditor = jest.fn();
const props = {
toggleOpenTemplatesList,
isTemplatesListOpen: true,
isNew: false,
createTemplate: <div>createTemplate</div>,
updateEditor,
['data-testid']: testId
};
const reset = jest.fn();
const setValue = jest.fn();
const isActive = true;
jest.mock('@/shared/lib/form', () => ({
...jest.requireActual('@/shared/lib/form'),
useFields: jest.fn()
}));
const mockUseFields = jest.mocked<Mocked<Partial<typeof useFields>>>(useFields);
beforeEach(() => {
mockUseFields.mockReturnValue({
value: () => isActive,
formState: {
isSubmitting: false,
isValid: true,
isDirty: true
},
reset,
setValue
});
});
describe('ArticleFormHeader', () => {
test('component renders', async () => {
componentRender(<ArticleFormHeader {...props} />);
expect(await screen.findByTestId(testId)).toBeInTheDocument();
});
test('toggleOpenTemplatesList to be called on template open icon click', async () => {
componentRender(<ArticleFormHeader {...props} />);
await userEvent.click(await screen.findByTestId(testIds.TemplateIcon));
expect(toggleOpenTemplatesList).toHaveBeenCalled();
});
test('resets form on cancel btn click', async () => {
componentRender(<ArticleFormHeader {...props} />);
await userEvent.click(await screen.findByTestId(testIds.Cancel));
expect(reset).toHaveBeenCalled();
expect(updateEditor).toHaveBeenCalled();
});
test('sets new value on visibility change', async () => {
componentRender(<ArticleFormHeader {...props} />);
await userEvent.click(
await screen.findByTestId(testIds.VisibilitySwitcher)
);
expect(setValue).toHaveBeenCalledWith('isActive', !isActive);
});
test('submit btn is not disabled when form is valid, not submittin and is dirty', async () => {
componentRender(<ArticleFormHeader {...props} />);
expect(await screen.findByTestId(testIds.Submit)).not.toBeDisabled();
});
test('submit btn is disabled when form is not valid', async () => {
mockUseFields.mockReturnValue({
value: () => isActive,
formState: {
isSubmitting: false,
isValid: false,
isDirty: true
},
reset,
setValue
});
componentRender(<ArticleFormHeader {...props} />);
expect(await screen.findByTestId(testIds.Submit)).toBeDisabled();
});
test('submit btn is disabled when form is submitting', async () => {
mockUseFields.mockReturnValue({
value: () => isActive,
formState: {
isSubmitting: true,
isValid: true,
isDirty: true
},
reset,
setValue
});
componentRender(<ArticleFormHeader {...props} />);
expect(await screen.findByTestId(testIds.Submit)).toBeDisabled();
});
test('submit btn is disabled when form is not dirty', async () => {
mockUseFields.mockReturnValue({
value: () => isActive,
formState: {
isSubmitting: false,
isValid: true,
isDirty: false
},
reset,
setValue
});
componentRender(<ArticleFormHeader {...props} />);
expect(await screen.findByTestId(testIds.Submit)).toBeDisabled();
});
});
versions, same with 29.7.0
"jest": "^30.0.4",
"babel-jest": "^30.0.4",
"@types/jest": "^30.0.0",
"@testing-library/jest-dom": "^6.6.3",
"@testing-library/react": "^16.3.0",
"@testing-library/user-event": "^14.6.1",
Expected behavior
jest.mock is mocking
Actual behavior
jest.mock is not mocking when it called in test file, but working when called in setupTests file
before all mocks was working fine, but last month I wrote a lot of new code and just now started to cover it with tests, and I discovered that old tests with mocks are failing if mock is in setupTests file and in test file I rewrite the same mock(it started to take mock from setupTests, not from file)
I fixed all this tests, removed mocks from setupTests
But in new tests I just created mocks in test file not working at all, only works if I put mock in setupTests, but I need to make different mocks for each component
maybe its because of a lot of tests in the app
Additional context
No response
Environment
System:
OS: macOS 15.5
CPU: (8) arm64 Apple M1 Pro
Binaries:
Node: 22.14.0 - /usr/local/bin/node
Yarn: 1.22.22 - /usr/local/bin/yarn
npm: 10.9.2 - /usr/local/bin/npm
pnpm: 10.13.1 - /usr/local/bin/pnpm
npmPackages:
jest: ^30.0.4 => 30.0.4