diff --git a/.eslintignore b/.eslintignore index fabaa79cbfcf..6fbfa158dcec 100644 --- a/.eslintignore +++ b/.eslintignore @@ -21,3 +21,4 @@ coverage **/*.d.ts # Scripts scripts/previewEditor/**/* +jest-stare diff --git a/.eslintrc.js b/.eslintrc.js index a23e6df7c692..5e0141096839 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -3,7 +3,7 @@ module.exports = { 'airbnb', 'prettier', 'plugin:compat/recommended', - 'plugin:vitest/recommended', + 'plugin:jest/recommended', 'plugin:react/recommended', 'plugin:import/typescript', 'plugin:markdown/recommended', @@ -12,6 +12,7 @@ module.exports = { browser: true, node: true, jasmine: true, + jest: true, es6: true, }, settings: { @@ -24,15 +25,7 @@ module.exports = { }, }, parser: '@typescript-eslint/parser', - plugins: [ - 'react', - '@babel', - 'vitest', - '@typescript-eslint', - 'react-hooks', - 'unicorn', - 'markdown', - ], + plugins: ['react', '@babel', 'jest', '@typescript-eslint', 'react-hooks', 'unicorn', 'markdown'], // https://github.com/typescript-eslint/typescript-eslint/issues/46#issuecomment-470486034 overrides: [ { @@ -159,10 +152,8 @@ module.exports = { 'scripts/**', '**/*.test.js', '**/__tests__/*', - '__mocks__/**', '*.config.js', '**/*.md', - 'vitest*config.ts', ], }, ], @@ -188,12 +179,12 @@ module.exports = { 'no-restricted-globals': 0, 'max-classes-per-file': 0, - 'vitest/prefer-to-be': 0, - 'vitest/expect-expect': 0, - 'vitest/no-done-callback': 0, - 'vitest/valid-title': 0, - 'vitest/no-conditional-expect': 0, - 'vitest/no-standalone-expect': 0, + 'jest/no-test-callback': 0, + 'jest/expect-expect': 0, + 'jest/no-done-callback': 0, + 'jest/valid-title': 0, + 'jest/no-conditional-expect': 0, + 'jest/no-standalone-expect': 0, 'unicorn/better-regex': 2, 'unicorn/prefer-string-trim-start-end': 2, diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 767a1e34a762..3eb5482b89f2 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -191,7 +191,7 @@ jobs: # dom test - name: dom test if: ${{ matrix.module == 'dom' }} - run: npm test -- --shard=${{matrix.shard}} --coverage + run: npm test -- --maxWorkers=2 --shard=${{matrix.shard}} --coverage - name: persist coverages if: ${{ matrix.module == 'dom' && matrix.react == '17' }} @@ -347,7 +347,7 @@ jobs: - name: test # lib only run in master branch not in pull request if: ${{ github.event_name != 'pull_request' || matrix.module != 'lib' }} - run: npm test -- --shard=${{matrix.shard}} + run: npm test -- --maxWorkers=2 --shard=${{matrix.shard}} env: LIB_DIR: ${{ matrix.module }} needs: compile diff --git a/.gitignore b/.gitignore index 16cbdf182205..7693ccc26972 100644 --- a/.gitignore +++ b/.gitignore @@ -58,6 +58,7 @@ components/version/token-meta.json # Image snapshot diff __diff_output__/ __image_snapshots__/ +/jest-stare /imageSnapshots /imageDiffSnapshots diff --git a/.jest.image.js b/.jest.image.js new file mode 100644 index 000000000000..fb42545326b8 --- /dev/null +++ b/.jest.image.js @@ -0,0 +1,23 @@ +const { moduleNameMapper, transformIgnorePatterns } = require('./.jest'); + +// jest config for image snapshots +module.exports = { + setupFiles: ['./tests/setup.js'], + moduleFileExtensions: ['ts', 'tsx', 'js', 'md'], + moduleNameMapper, + transform: { + '\\.tsx?$': './node_modules/@ant-design/tools/lib/jest/codePreprocessor', + '\\.js$': './node_modules/@ant-design/tools/lib/jest/codePreprocessor', + '\\.md$': './node_modules/@ant-design/tools/lib/jest/demoPreprocessor', + '\\.(jpg|png|gif|svg)$': './node_modules/@ant-design/tools/lib/jest/imagePreprocessor', + }, + testRegex: 'image\\.test\\.(j|t)s$', + transformIgnorePatterns, + globals: { + 'ts-jest': { + tsConfigFile: './tsconfig.test.json', + }, + }, + preset: 'jest-puppeteer', + testTimeout: 10000, +}; diff --git a/.jest.js b/.jest.js new file mode 100644 index 000000000000..08ff43ec46eb --- /dev/null +++ b/.jest.js @@ -0,0 +1,68 @@ +const compileModules = ['react-sticky-box', 'rc-tween-one', '@babel', '@ant-design', 'countup.js']; + +const ignoreList = []; + +// cnpm use `_` as prefix +['', '_'].forEach((prefix) => { + compileModules.forEach((module) => { + ignoreList.push(`${prefix}${module}`); + }); +}); + +const transformIgnorePatterns = [ + // Ignore modules without es dir. + // Update: @babel/runtime should also be transformed + `/node_modules/(?!${ignoreList.join('|')})[^/]+?/(?!(es)/)`, +]; + +function getTestRegex(libDir) { + if (['dist', 'lib', 'es'].includes(libDir)) { + return 'demo\\.test\\.(j|t)sx?$'; + } + return '.*\\.test\\.(j|t)sx?$'; +} + +module.exports = { + verbose: true, + testEnvironment: 'jsdom', + setupFiles: ['./tests/setup.js', 'jest-canvas-mock'], + setupFilesAfterEnv: ['./tests/setupAfterEnv.ts'], + moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'md'], + modulePathIgnorePatterns: ['/_site/'], + moduleNameMapper: { + '/\\.(css|less)$/': 'identity-obj-proxy', + '^antd$': '/components/index', + '^antd/es/(.*)$': '/components/$1', + }, + testPathIgnorePatterns: ['/node_modules/', 'dekko', 'node', 'image.test.js', 'image.test.ts'], + transform: { + '\\.tsx?$': './node_modules/@ant-design/tools/lib/jest/codePreprocessor', + '\\.(m?)js$': './node_modules/@ant-design/tools/lib/jest/codePreprocessor', + '\\.md$': './node_modules/@ant-design/tools/lib/jest/demoPreprocessor', + '\\.(jpg|png|gif|svg)$': './node_modules/@ant-design/tools/lib/jest/imagePreprocessor', + }, + testRegex: getTestRegex(process.env.LIB_DIR), + collectCoverageFrom: [ + 'components/**/*.{ts,tsx}', + '!components/*/style/index.tsx', + '!components/style/index.tsx', + '!components/*/locale/index.tsx', + '!components/*/__tests__/type.test.tsx', + '!components/**/*/interface.{ts,tsx}', + '!components/*/__tests__/image.test.{ts,tsx}', + '!components/__tests__/node.test.tsx', + '!components/*/demo/*.tsx', + '!components/*/design/**', + ], + transformIgnorePatterns, + globals: { + 'ts-jest': { + tsConfig: './tsconfig.test.json', + }, + }, + testEnvironmentOptions: { + url: 'http://localhost', + }, + // bail: true, + maxWorkers: '50%', +}; diff --git a/.jest.node.js b/.jest.node.js new file mode 100644 index 000000000000..54d6fb852d79 --- /dev/null +++ b/.jest.node.js @@ -0,0 +1,19 @@ +const { moduleNameMapper, transformIgnorePatterns } = require('./.jest'); + +// jest config for server render environment +module.exports = { + setupFiles: ['./tests/setup.js'], + setupFilesAfterEnv: ['./tests/setupAfterEnv.ts'], + moduleFileExtensions: ['ts', 'tsx', 'js', 'md'], + moduleNameMapper, + transform: { + '\\.tsx?$': './node_modules/@ant-design/tools/lib/jest/codePreprocessor', + '\\.js$': './node_modules/@ant-design/tools/lib/jest/codePreprocessor', + '\\.md$': './node_modules/@ant-design/tools/lib/jest/demoPreprocessor', + '\\.(jpg|png|gif|svg)$': './node_modules/@ant-design/tools/lib/jest/imagePreprocessor', + }, + testRegex: 'node\\.test\\.(j|t)sx$', + testEnvironment: 'node', + transformIgnorePatterns, + // bail: true, +}; diff --git a/.jest.site.js b/.jest.site.js new file mode 100644 index 000000000000..a1f19aee581b --- /dev/null +++ b/.jest.site.js @@ -0,0 +1,21 @@ +const { moduleNameMapper, transformIgnorePatterns } = require('./.jest'); + +// jest config for server render environment +module.exports = { + moduleFileExtensions: ['ts', 'tsx', 'js', 'md'], + moduleNameMapper, + transform: { + '\\.tsx?$': './node_modules/@ant-design/tools/lib/jest/codePreprocessor', + '\\.js$': './node_modules/@ant-design/tools/lib/jest/codePreprocessor', + '\\.md$': './node_modules/@ant-design/tools/lib/jest/demoPreprocessor', + '\\.(jpg|png|gif|svg)$': './node_modules/@ant-design/tools/lib/jest/imagePreprocessor', + }, + testRegex: 'check-site\\.(j|t)s$', + testEnvironment: 'node', + transformIgnorePatterns, + globals: { + 'ts-jest': { + tsConfigFile: './tsconfig.test.json', + }, + }, +}; diff --git a/__mocks__/rc-virtual-list.ts b/__mocks__/rc-virtual-list.ts deleted file mode 100644 index e99eeb9b9f4e..000000000000 --- a/__mocks__/rc-virtual-list.ts +++ /dev/null @@ -1,3 +0,0 @@ -import Mock from 'rc-virtual-list/es/mock'; - -export default Mock; diff --git a/components/__tests__/__snapshots__/index.test.ts.snap b/components/__tests__/__snapshots__/index.test.ts.snap index a6f6d0399c22..8572ab796ffb 100644 --- a/components/__tests__/__snapshots__/index.test.ts.snap +++ b/components/__tests__/__snapshots__/index.test.ts.snap @@ -1,6 +1,6 @@ -// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html +// Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`antd > exports modules correctly 1`] = ` +exports[`antd exports modules correctly 1`] = ` [ "Affix", "Alert", @@ -37,9 +37,7 @@ exports[`antd > exports modules correctly 1`] = ` "List", "Mentions", "Menu", - "message", "Modal", - "notification", "Pagination", "Popconfirm", "Popover", @@ -61,7 +59,6 @@ exports[`antd > exports modules correctly 1`] = ` "Table", "Tabs", "Tag", - "theme", "TimePicker", "Timeline", "Tooltip", @@ -71,7 +68,10 @@ exports[`antd > exports modules correctly 1`] = ` "TreeSelect", "Typography", "Upload", - "version", "Watermark", + "message", + "notification", + "theme", + "version", ] `; diff --git a/components/__tests__/__snapshots__/setup.test.tsx.snap b/components/__tests__/__snapshots__/setup.test.tsx.snap index c3c40d4094ec..f2e4db6141ac 100644 --- a/components/__tests__/__snapshots__/setup.test.tsx.snap +++ b/components/__tests__/__snapshots__/setup.test.tsx.snap @@ -1,6 +1,6 @@ -// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html +// Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`SetUp.Test > diff of React 18 & React 17 1`] = ` +exports[`SetUp.Test diff of React 18 & React 17 1`] = ` NodeList [
bamboo diff --git a/components/__tests__/index.test.ts b/components/__tests__/index.test.ts index 8364ed2743f9..9ab8d246ba51 100644 --- a/components/__tests__/index.test.ts +++ b/components/__tests__/index.test.ts @@ -1,7 +1,6 @@ -import * as antd from '..'; - const OLD_NODE_ENV = process.env.NODE_ENV; process.env.NODE_ENV = 'development'; +const antd = require('..'); describe('antd', () => { afterAll(() => { diff --git a/components/__tests__/node.test.tsx b/components/__tests__/node.test.tsx index 452abf2f25c5..cc63dd37e41d 100644 --- a/components/__tests__/node.test.tsx +++ b/components/__tests__/node.test.tsx @@ -3,24 +3,21 @@ import * as React from 'react'; import { renderToString } from 'react-dom/server'; import type { Options } from '../../tests/shared/demoTest'; -globalThis.testConfig = {}; +(global as any).testConfig = {}; -vi.mock('../../tests/shared/demoTest', () => { +jest.mock('../../tests/shared/demoTest', () => { function fakeDemoTest(name: string, option: Options = {}) { - globalThis.testConfig[name] = option; + (global as any).testConfig[name] = option; } fakeDemoTest.rootPropsTest = () => {}; - return { - default: fakeDemoTest, - rootPropsTest: () => {}, - }; + return fakeDemoTest; }); describe('node', () => { beforeAll(() => { - vi.useFakeTimers().setSystemTime(new Date('2016-11-22')); + jest.useFakeTimers().setSystemTime(new Date('2016-11-22')); }); // Find the component exist demo test file @@ -30,27 +27,23 @@ describe('node', () => { const componentName = componentTestFile.match(/components\/([^/]*)\//)![1]; // Test for ssr - // eslint-disable-next-line vitest/valid-describe-callback - describe(componentName, async () => { + describe(componentName, () => { const demoList = globSync(`./components/${componentName}/demo/*.tsx`); // Use mock to get config - await import(`../../${componentTestFile}`); + require(`../../${componentTestFile}`); // eslint-disable-line global-require, import/no-dynamic-require + const option = (global as any).testConfig?.[componentName]; + demoList.forEach((demoFile) => { - const option = globalThis.testConfig?.[componentName]; const skip: string[] = option?.skip || []; const test = skip.some((skipMarkdown) => demoFile.includes(skipMarkdown)) ? it.skip : it; - test( - demoFile, - async () => { - const Demo = (await import(`../../${demoFile}`)).default; - expect(() => { - renderToString(); - }).not.toThrow(); - }, - 120000, - ); + test(demoFile, () => { + const Demo = require(`../../${demoFile}`).default; // eslint-disable-line global-require, import/no-dynamic-require + expect(() => { + renderToString(); + }).not.toThrow(); + }); }); }); }); diff --git a/components/_util/PurePanel.tsx b/components/_util/PurePanel.tsx index 39e5e2e991d1..49e8b2c16ead 100644 --- a/components/_util/PurePanel.tsx +++ b/components/_util/PurePanel.tsx @@ -7,7 +7,7 @@ export interface BaseProps { style?: React.CSSProperties; } -/* c8 ignore start */ +/* istanbul ignore next */ export default function genPurePanel( Component: any, defaultPrefixCls?: string, @@ -96,4 +96,3 @@ export default function genPurePanel( ); } as typeof Component; } -/* c8 ignore stop */ diff --git a/components/_util/__tests__/getScroll.test.ts b/components/_util/__tests__/getScroll.test.ts index 0eb77443ad93..8cb737ff1a40 100644 --- a/components/_util/__tests__/getScroll.test.ts +++ b/components/_util/__tests__/getScroll.test.ts @@ -7,7 +7,7 @@ describe('getScroll', () => { }); it('getScroll window', async () => { - const scrollToSpy = vi.spyOn(window, 'scrollTo').mockImplementation((x, y) => { + const scrollToSpy = jest.spyOn(window, 'scrollTo').mockImplementation((x, y) => { window.pageXOffset = x; window.pageYOffset = y; }); @@ -18,7 +18,7 @@ describe('getScroll', () => { }); it('getScroll document', async () => { - const scrollToSpy = vi.spyOn(window, 'scrollTo').mockImplementation((x, y) => { + const scrollToSpy = jest.spyOn(window, 'scrollTo').mockImplementation((x, y) => { document.documentElement.scrollLeft = x; document.documentElement.scrollTop = y; }); @@ -30,7 +30,7 @@ describe('getScroll', () => { it('getScroll div', async () => { const div = document.createElement('div'); - const scrollToSpy = vi.spyOn(window, 'scrollTo').mockImplementation((x, y) => { + const scrollToSpy = jest.spyOn(window, 'scrollTo').mockImplementation((x, y) => { div.scrollLeft = x; div.scrollTop = y; }); @@ -42,7 +42,7 @@ describe('getScroll', () => { it('getScroll documentElement', async () => { const div: any = {}; - const scrollToSpy = vi.spyOn(window, 'scrollTo').mockImplementation((x, y) => { + const scrollToSpy = jest.spyOn(window, 'scrollTo').mockImplementation((x, y) => { div.scrollLeft = null; div.scrollTop = null; div.documentElement = {}; diff --git a/components/_util/__tests__/responsiveObserve.test.tsx b/components/_util/__tests__/responsiveObserve.test.tsx index b47595d4cdc0..d88c5ea6066c 100644 --- a/components/_util/__tests__/responsiveObserve.test.tsx +++ b/components/_util/__tests__/responsiveObserve.test.tsx @@ -11,7 +11,7 @@ describe('Test ResponsiveObserve', () => { return null; }; render(); - const subscribeFunc = vi.fn(); + const subscribeFunc = jest.fn(); const token = responsiveObserveRef.subscribe(subscribeFunc); expect( responsiveObserveRef.matchHandlers[responsiveObserveRef.responsiveMap.xs].mql.matches, diff --git a/components/_util/__tests__/scrollTo.test.ts b/components/_util/__tests__/scrollTo.test.ts index a6e7533c1cac..5fe2e09502c0 100644 --- a/components/_util/__tests__/scrollTo.test.ts +++ b/components/_util/__tests__/scrollTo.test.ts @@ -2,10 +2,10 @@ import { waitFakeTimer } from '../../../tests/utils'; import scrollTo from '../scrollTo'; describe('Test ScrollTo function', () => { - const dateNowMock = vi.spyOn(Date, 'now'); + const dateNowMock = jest.spyOn(Date, 'now'); beforeAll(() => { - vi.useFakeTimers(); + jest.useFakeTimers(); }); beforeEach(() => { @@ -13,16 +13,16 @@ describe('Test ScrollTo function', () => { }); afterAll(() => { - vi.useRealTimers(); + jest.useRealTimers(); }); afterEach(() => { - vi.clearAllTimers(); + jest.clearAllTimers(); dateNowMock.mockClear(); }); it('test scrollTo', async () => { - const scrollToSpy = vi.spyOn(window, 'scrollTo').mockImplementation((_, y) => { + const scrollToSpy = jest.spyOn(window, 'scrollTo').mockImplementation((_, y) => { window.scrollY = y; window.pageYOffset = y; }); @@ -36,7 +36,7 @@ describe('Test ScrollTo function', () => { }); it('test callback - option', async () => { - const cbMock = vi.fn(); + const cbMock = jest.fn(); scrollTo(1000, { callback: cbMock, }); diff --git a/components/_util/__tests__/util.test.tsx b/components/_util/__tests__/util.test.tsx index 7e806a606f19..6b80428474e7 100644 --- a/components/_util/__tests__/util.test.tsx +++ b/components/_util/__tests__/util.test.tsx @@ -9,19 +9,19 @@ import TransButton from '../transButton'; describe('Test utils function', () => { describe('throttle', () => { beforeAll(() => { - vi.useFakeTimers(); + jest.useFakeTimers(); }); afterAll(() => { - vi.useRealTimers(); + jest.useRealTimers(); }); afterEach(() => { - vi.clearAllTimers(); + jest.clearAllTimers(); }); it('throttle function should work', async () => { - const callback = vi.fn(); + const callback = jest.fn(); const throttled = throttleByAnimationFrame(callback); expect(callback).not.toHaveBeenCalled(); @@ -34,7 +34,7 @@ describe('Test utils function', () => { }); it('throttle function should be canceled', async () => { - const callback = vi.fn(); + const callback = jest.fn(); const throttled = throttleByAnimationFrame(callback); throttled(); @@ -54,7 +54,7 @@ describe('Test utils function', () => { }); it('should trigger onClick when press enter', () => { - const onClick = vi.fn(); + const onClick = jest.fn(); const { container } = render(TransButton); @@ -75,7 +75,7 @@ describe('Test utils function', () => { }); it('isStyleSupport return false in service side', () => { - const spy = vi + const spy = jest .spyOn(window.document, 'documentElement', 'get') .mockImplementation(() => undefined as unknown as HTMLElement); expect(isStyleSupport('color')).toBe(false); diff --git a/components/_util/__tests__/warning.test.ts b/components/_util/__tests__/warning.test.ts index 377d3eaf69a2..00a952bd49d8 100644 --- a/components/_util/__tests__/warning.test.ts +++ b/components/_util/__tests__/warning.test.ts @@ -1,10 +1,8 @@ -import type { SpyInstance } from 'vitest'; - describe('Test warning', () => { - let spy: SpyInstance; + let spy: jest.SpyInstance; beforeAll(() => { - spy = vi.spyOn(console, 'error').mockImplementation(() => {}); + spy = jest.spyOn(console, 'error').mockImplementation(() => {}); }); afterAll(() => { @@ -12,7 +10,7 @@ describe('Test warning', () => { }); beforeEach(() => { - vi.resetModules(); + jest.resetModules(); }); afterEach(() => { diff --git a/components/_util/__tests__/wave.test.tsx b/components/_util/__tests__/wave.test.tsx index 4ad0abe81ece..1311db982926 100644 --- a/components/_util/__tests__/wave.test.tsx +++ b/components/_util/__tests__/wave.test.tsx @@ -3,13 +3,11 @@ import mountTest from '../../../tests/shared/mountTest'; import { act, fireEvent, getByText, render, waitFakeTimer } from '../../../tests/utils'; import Wave from '../wave'; -let isVisible = vi.hoisted(() => true); +(global as any).isVisible = true; -vi.mock('rc-util/es/Dom/isVisible', () => { - const mockFn = () => isVisible; - return { - default: mockFn, - }; +jest.mock('rc-util/lib/Dom/isVisible', () => { + const mockFn = () => (global as any).isVisible; + return mockFn; }); describe('Wave component', () => { @@ -31,37 +29,44 @@ describe('Wave component', () => { } (window as any).ResizeObserver = FakeResizeObserver; - vi.useFakeTimers(); + jest.useFakeTimers(); }); afterAll(() => { - vi.useRealTimers(); + jest.useRealTimers(); expect(obCnt).not.toBe(0); expect(disCnt).not.toBe(0); }); beforeEach(() => { - isVisible = true; + (global as any).isVisible = true; document.body.innerHTML = ''; }); - afterEach(async () => { - await vi.runAllTimersAsync(); - vi.clearAllTimers(); + afterEach(() => { + jest.clearAllTimers(); const styles = document.getElementsByTagName('style'); for (let i = 0; i < styles.length; i += 1) { styles[i].remove(); } }); - function getWaveColor() { + function getWaveStyle() { + const styleObj: Record = {}; const { style } = document.querySelector('.ant-wave')!; - return style.getPropertyValue('--wave-color'); + style.cssText.split(';').forEach((kv) => { + if (kv.trim()) { + const cells = kv.split(':'); + styleObj[cells[0].trim()] = cells[1].trim(); + } + }); + + return styleObj; } function waitRaf() { act(() => { - vi.advanceTimersByTime(100); + jest.advanceTimersByTime(100); }); } @@ -85,7 +90,7 @@ describe('Wave component', () => { }); it('invisible in screen', () => { - isVisible = false; + (global as any).isVisible = false; const { container, unmount } = render( @@ -114,7 +119,9 @@ describe('Wave component', () => { fireEvent.click(container.querySelector('button')!); waitRaf(); - expect(getWaveColor()).toBeFalsy(); + const style = getWaveStyle(); + + expect(style['--wave-color']).toBeFalsy(); unmount(); }); @@ -122,7 +129,7 @@ describe('Wave component', () => { it('wave color is not grey', () => { const { container, unmount } = render( - , @@ -131,7 +138,8 @@ describe('Wave component', () => { fireEvent.click(container.querySelector('button')!); waitRaf(); - expect(getWaveColor()).toEqual('rgb(255, 0, 0)'); + const style = getWaveStyle(); + expect(style['--wave-color']).toEqual('red'); unmount(); }); @@ -139,14 +147,15 @@ describe('Wave component', () => { it('read wave color from border-top-color', () => { const { container, unmount } = render( -
button
+
button
, ); fireEvent.click(getByText(container, 'button')!); waitRaf(); - expect(getWaveColor()).toEqual('rgb(0, 0, 255)'); + const style = getWaveStyle(); + expect(style['--wave-color']).toEqual('blue'); unmount(); }); @@ -154,14 +163,15 @@ describe('Wave component', () => { it('read wave color from background color', () => { const { container, unmount } = render( -
button
+
button
, ); fireEvent.click(getByText(container, 'button')!); waitRaf(); - expect(getWaveColor()).toEqual('rgb(0, 128, 0)'); + const style = getWaveStyle(); + expect(style['--wave-color']).toEqual('green'); unmount(); }); @@ -169,14 +179,15 @@ describe('Wave component', () => { it('read wave color from border firstly', () => { const { container, unmount } = render( -
button
+
button
, ); fireEvent.click(getByText(container, 'button')!); waitRaf(); - expect(getWaveColor()).toEqual('rgb(255, 0, 0)'); + const style = getWaveStyle(); + expect(style['--wave-color']).toEqual('yellow'); unmount(); }); @@ -211,7 +222,7 @@ describe('Wave component', () => { }); it('not show when hidden', () => { - isVisible = false; + (global as any).isVisible = false; const { container } = render( @@ -260,7 +271,7 @@ describe('Wave component', () => { it('wave color should inferred if border is transparent and background is not', () => { const { container, unmount } = render( - , @@ -268,7 +279,8 @@ describe('Wave component', () => { fireEvent.click(container.querySelector('button')!); waitRaf(); - expect(getWaveColor()).toEqual('rgb(255, 0, 0)'); + const style = getWaveStyle(); + expect(style['--wave-color']).toEqual('red'); unmount(); }); @@ -285,7 +297,8 @@ describe('Wave component', () => { fireEvent.click(container.querySelector('button')!); waitRaf(); - expect(getWaveColor()).toEqual('red'); + const style = getWaveStyle(); + expect(style['--wave-color']).toEqual('red'); unmount(); }); diff --git a/components/affix/__tests__/Affix.test.tsx b/components/affix/__tests__/Affix.test.tsx index 7d2552e6fb5a..cbe9b44815e0 100644 --- a/components/affix/__tests__/Affix.test.tsx +++ b/components/affix/__tests__/Affix.test.tsx @@ -22,7 +22,7 @@ const AffixMounter: React.FC = ({ getInstance, ...restProps }) => { const container = useRef(null); useEffect(() => { if (container.current) { - container.current.addEventListener = vi + container.current.addEventListener = jest .fn() .mockImplementation((event: keyof HTMLElementEventMap, cb: (ev: Event) => void) => { events[event] = cb; @@ -42,12 +42,12 @@ describe('Affix Render', () => { rtlTest(Affix); accessibilityTest(Affix); - const domMock = vi.spyOn(HTMLElement.prototype, 'getBoundingClientRect'); + const domMock = jest.spyOn(HTMLElement.prototype, 'getBoundingClientRect'); const classRect: Record = { container: { top: 0, bottom: 100 } as DOMRect }; beforeEach(() => { - vi.useFakeTimers(); + jest.useFakeTimers(); }); beforeAll(() => { @@ -57,8 +57,8 @@ describe('Affix Render', () => { }); afterEach(() => { - vi.useRealTimers(); - vi.clearAllTimers(); + jest.useRealTimers(); + jest.clearAllTimers(); }); afterAll(() => { @@ -89,11 +89,7 @@ describe('Affix Render', () => { }); it('Anchor correct render when target is null', async () => { - render( - null}> - test - , - ); + render( null}>test); await waitFakeTimer(); }); @@ -113,7 +109,7 @@ describe('Affix Render', () => { }); it('updatePosition when offsetTop changed', async () => { - const onChange = vi.fn(); + const onChange = jest.fn(); const { container, rerender } = render(); await waitFakeTimer(); @@ -232,7 +228,7 @@ describe('Affix Render', () => { '.fixed', // outer ].forEach((selector) => { it(`trigger listener when size change: ${selector}`, async () => { - const updateCalled = vi.fn(); + const updateCalled = jest.fn(); const { container } = render( , { diff --git a/components/affix/__tests__/__snapshots__/Affix.test.tsx.snap b/components/affix/__tests__/__snapshots__/Affix.test.tsx.snap index 1d68a8068ffa..bd230c7ac40d 100644 --- a/components/affix/__tests__/__snapshots__/Affix.test.tsx.snap +++ b/components/affix/__tests__/__snapshots__/Affix.test.tsx.snap @@ -1,6 +1,6 @@ -// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html +// Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`Affix Render > rtl render > component should be rendered correctly in RTL direction 1`] = ` +exports[`Affix Render rtl render component should be rendered correctly in RTL direction 1`] = `
custom action 1`] = ` +exports[`Alert custom action 1`] = `
custom action 1`] = `
`; -exports[`Alert > rtl render > component should be rendered correctly in RTL direction 1`] = ` +exports[`Alert rtl render component should be rendered correctly in RTL direction 1`] = `
{ accessibilityTest(Alert); beforeAll(() => { - vi.useFakeTimers(); + jest.useFakeTimers(); }); afterAll(() => { - vi.useRealTimers(); + jest.useRealTimers(); }); it('should show close button and could be closed', async () => { - const onClose = vi.fn(); + const onClose = jest.fn(); render( { await userEvent.click(screen.getByRole('button', { name: /close/i })); + act(() => { + jest.runAllTimers(); + }); + expect(onClose).toHaveBeenCalledTimes(1); }); @@ -72,7 +76,7 @@ describe('Alert', () => { }); it('should show error as ErrorBoundary when children have error', () => { - const warnSpy = vi.spyOn(console, 'error').mockImplementation(() => {}); + const warnSpy = jest.spyOn(console, 'error').mockImplementation(() => {}); expect(warnSpy).toHaveBeenCalledTimes(0); // @ts-expect-error // eslint-disable-next-line react/jsx-no-undef @@ -101,9 +105,11 @@ describe('Alert', () => { await userEvent.hover(screen.getByRole('alert')); - await waitFor(() => { - expect(screen.getByRole('tooltip')).toBeInTheDocument(); + act(() => { + jest.runAllTimers(); }); + + expect(screen.getByRole('tooltip')).toBeInTheDocument(); }); it('could be used with Popconfirm', async () => { @@ -117,6 +123,10 @@ describe('Alert', () => { ); await userEvent.click(screen.getByRole('alert')); + act(() => { + jest.runAllTimers(); + }); + expect(screen.getByRole('tooltip')).toBeInTheDocument(); }); diff --git a/components/anchor/__tests__/Anchor.test.tsx b/components/anchor/__tests__/Anchor.test.tsx index bd253574f6d7..51cf8972649d 100644 --- a/components/anchor/__tests__/Anchor.test.tsx +++ b/components/anchor/__tests__/Anchor.test.tsx @@ -2,7 +2,6 @@ import { resetWarned } from 'rc-util/lib/warning'; import React, { useState } from 'react'; import scrollIntoView from 'scroll-into-view-if-needed'; -import type { SpyInstance } from 'vitest'; import Anchor from '..'; import { act, fireEvent, render, waitFakeTimer } from '../../../tests/utils'; import Button from '../../button'; @@ -10,9 +9,8 @@ import type { AnchorDirection } from '../Anchor'; const { Link } = Anchor; -function createRootDiv() { +function createDiv() { const root = document.createElement('div'); - root.className = 'root'; document.body.appendChild(root); return root; } @@ -20,16 +18,18 @@ function createRootDiv() { let idCounter = 0; const getHashUrl = () => `Anchor-API-${idCounter++}`; -vi.mock('scroll-into-view-if-needed', () => ({ - default: vi.fn(), -})); +jest.mock('scroll-into-view-if-needed', () => jest.fn()); describe('Anchor Render', () => { - const getBoundingClientRectMock = vi.spyOn(HTMLHeadingElement.prototype, 'getBoundingClientRect'); - const getClientRectsMock = vi.spyOn(HTMLHeadingElement.prototype, 'getClientRects'); + const getBoundingClientRectMock = jest.spyOn( + HTMLHeadingElement.prototype, + 'getBoundingClientRect', + ); + const getClientRectsMock = jest.spyOn(HTMLHeadingElement.prototype, 'getClientRects'); + const scrollIntoViewMock = jest.createMockFromModule('scroll-into-view-if-needed'); beforeAll(() => { - vi.useFakeTimers(); + jest.useFakeTimers(); getBoundingClientRectMock.mockReturnValue({ width: 100, height: 100, @@ -39,18 +39,18 @@ describe('Anchor Render', () => { }); beforeEach(() => { - vi.useFakeTimers(); - vi.mocked(scrollIntoView).mockReset(); + jest.useFakeTimers(); + scrollIntoViewMock.mockReset(); }); afterEach(() => { - vi.clearAllTimers(); - vi.useRealTimers(); + jest.clearAllTimers(); + jest.useRealTimers(); }); afterAll(() => { - vi.clearAllTimers(); - vi.useRealTimers(); + jest.clearAllTimers(); + jest.useRealTimers(); getBoundingClientRectMock.mockRestore(); getClientRectsMock.mockRestore(); }); @@ -186,12 +186,12 @@ describe('Anchor Render', () => { const link = container.querySelector(`a[href="http://www.example.com/#${hash}"]`)!; fireEvent.click(link); await waitFakeTimer(); - expect(link.classList.contains('ant-anchor-link-title-active')).toBeTruthy(); + expect(link.classList).toContain('ant-anchor-link-title-active'); }); it('scrolls the page when clicking a link', async () => { - const root = createRootDiv(); - const scrollToSpy = vi.spyOn(window, 'scrollTo'); + const root = createDiv(); + const scrollToSpy = jest.spyOn(window, 'scrollTo'); render(
Q1
, { container: root }); const { container } = render( , @@ -200,14 +200,13 @@ describe('Anchor Render', () => { fireEvent.click(link); await waitFakeTimer(); expect(scrollToSpy).toHaveBeenCalled(); - scrollToSpy.mockRestore(); }); it('handleScroll should not be triggered when scrolling caused by clicking a link', async () => { const hash1 = getHashUrl(); const hash2 = getHashUrl(); - const root = createRootDiv(); - const onChange = vi.fn(); + const root = createDiv(); + const onChange = jest.fn(); render(
Hello
@@ -266,8 +265,8 @@ describe('Anchor Render', () => { it('targetOffset prop', async () => { const hash = getHashUrl(); - const scrollToSpy = vi.spyOn(window, 'scrollTo'); - const root = createRootDiv(); + const scrollToSpy = jest.spyOn(window, 'scrollTo'); + const root = createDiv(); render(

Hello

, { container: root }); const { container, rerender } = render( , @@ -291,16 +290,14 @@ describe('Anchor Render', () => { fireEvent.click(container.querySelector(`a[href="#${hash}"]`)!); await waitFakeTimer(); expect(scrollToSpy).toHaveBeenLastCalledWith(0, 800); - - scrollToSpy.mockRestore(); }); // https://github.com/ant-design/ant-design/issues/31941 it('targetOffset prop when contain spaces', async () => { const hash = `${getHashUrl()} s p a c e s`; - const scrollToSpy = vi.spyOn(window, 'scrollTo'); - const root = createRootDiv(); + const scrollToSpy = jest.spyOn(window, 'scrollTo'); + const root = createDiv(); render(

Hello

, { container: root }); const { container, rerender } = render( , @@ -322,8 +319,6 @@ describe('Anchor Render', () => { fireEvent.click(container.querySelector(`a[href="#${hash}"]`)!); await waitFakeTimer(); expect(scrollToSpy).toHaveBeenLastCalledWith(0, 800); - - scrollToSpy.mockRestore(); }); it('onClick event', () => { @@ -352,7 +347,7 @@ describe('Anchor Render', () => { it('onChange event', () => { const hash1 = getHashUrl(); const hash2 = getHashUrl(); - const onChange = vi.fn(); + const onChange = jest.fn(); const { container } = render( { const hash1 = getHashUrl(); const hash2 = getHashUrl(); - const beforeFn = vi.fn(); - const afterFn = vi.fn(); + const beforeFn = jest.fn(); + const afterFn = jest.fn(); const Demo: React.FC = () => { const [trigger, setTrigger] = useState(false); @@ -440,8 +435,8 @@ describe('Anchor Render', () => { getBoundingClientRectMock.mockReturnValue({ width: 0, height: 0, top: 1000 } as DOMRect); const hash = getHashUrl(); - const scrollToSpy = vi.spyOn(window, 'scrollTo'); - const root = createRootDiv(); + const scrollToSpy = jest.spyOn(window, 'scrollTo'); + const root = createDiv(); render(

Hello

, { container: root }); const { container, rerender } = render( @@ -475,14 +470,13 @@ describe('Anchor Render', () => { height: 100, top: 1000, } as DOMRect); - - scrollToSpy.mockRestore(); }); it('test edge case when container is not windows', async () => { const hash = getHashUrl(); - const root = createRootDiv(); + const scrollToSpy = jest.spyOn(window, 'scrollTo'); + const root = createDiv(); render(

Hello

, { container: root }); const { container, rerender } = render( @@ -498,23 +492,19 @@ describe('Anchor Render', () => {
, ); - // Since it's mock rect pos here. We need always reset the `scrollTop` for test - document.body.scrollTop = 0; fireEvent.click(container.querySelector(`a[href="#${hash}"]`)!); await waitFakeTimer(); - expect(document.body.scrollTop).toEqual(1000); + expect(scrollToSpy).toHaveBeenLastCalledWith(0, 800); - document.body.scrollTop = 0; setProps({ offsetTop: 100 }); fireEvent.click(container.querySelector(`a[href="#${hash}"]`)!); await waitFakeTimer(); - expect(document.body.scrollTop).toEqual(900); + expect(scrollToSpy).toHaveBeenLastCalledWith(0, 800); - document.body.scrollTop = 0; setProps({ targetOffset: 200 }); fireEvent.click(container.querySelector(`a[href="#${hash}"]`)!); await waitFakeTimer(); - expect(document.body.scrollTop).toEqual(800); + expect(scrollToSpy).toHaveBeenLastCalledWith(0, 800); }); describe('getCurrentAnchor', () => { @@ -539,7 +529,7 @@ describe('Anchor Render', () => { it('should trigger onChange when have getCurrentAnchor', () => { const hash1 = getHashUrl(); const hash2 = getHashUrl(); - const onChange = vi.fn(); + const onChange = jest.fn(); const { container } = render( { it('getCurrentAnchor have default link as argument', () => { const hash1 = getHashUrl(); const hash2 = getHashUrl(); - const getCurrentAnchor = vi.fn(); + const getCurrentAnchor = jest.fn(); const { container } = render( { describe('scroll x', () => { it('targetOffset horizontal', async () => { const hash = getHashUrl(); - const scrollToSpy = vi.spyOn(window, 'scrollTo'); - const root = createRootDiv(); + const scrollToSpy = jest.spyOn(window, 'scrollTo'); + const root = createDiv(); render(

Hello

, { container: root }); const { container, rerender } = render( { fireEvent.click(container.querySelector(`a[href="#${hash}"]`)!); await waitFakeTimer(); expect(scrollToSpy).toHaveBeenLastCalledWith(0, 800); - - scrollToSpy.mockRestore(); }); }); @@ -768,12 +756,12 @@ describe('Anchor Render', () => { const link = container.querySelector(`a[href="http://www.example.com/#${hash}"]`)!; fireEvent.click(link); await waitFakeTimer(); - expect(link.classList.contains('ant-anchor-link-title-active')).toBeTruthy(); + expect(link.classList).toContain('ant-anchor-link-title-active'); }); it('scrolls the page when clicking a link', async () => { - const root = createRootDiv(); - const scrollToSpy = vi.spyOn(window, 'scrollTo'); + const root = createDiv(); + const scrollToSpy = jest.spyOn(window, 'scrollTo'); render(
Q1
, { container: root }); const { container } = render( @@ -784,15 +772,13 @@ describe('Anchor Render', () => { fireEvent.click(link); await waitFakeTimer(); expect(scrollToSpy).toHaveBeenCalled(); - - scrollToSpy.mockRestore(); }); it('handleScroll should not be triggered when scrolling caused by clicking a link', async () => { const hash1 = getHashUrl(); const hash2 = getHashUrl(); - const root = createRootDiv(); - const onChange = vi.fn(); + const root = createDiv(); + const onChange = jest.fn(); render(
Hello
@@ -865,10 +851,10 @@ describe('Anchor Render', () => { }); describe('warning', () => { - let errSpy: SpyInstance; + let errSpy: jest.SpyInstance; beforeEach(() => { resetWarned(); - errSpy = vi.spyOn(console, 'error').mockImplementation(() => {}); + errSpy = jest.spyOn(console, 'error').mockImplementation(() => {}); }); afterEach(() => { @@ -985,14 +971,14 @@ describe('Anchor Render', () => { const toggleButton = wrapper.container.querySelector('button')!; fireEvent.click(toggleButton); - act(() => vi.runAllTimers()); + act(() => jest.runAllTimers()); expect(!!ink.style.left).toBe(true); expect(!!ink.style.width).toBe(true); expect(ink.style.top).toBe(''); expect(ink.style.height).toBe(''); fireEvent.click(toggleButton); - act(() => vi.runAllTimers()); + act(() => jest.runAllTimers()); expect(!!ink.style.top).toBe(true); expect(!!ink.style.height).toBe(true); expect(ink.style.left).toBe(''); diff --git a/components/anchor/__tests__/__snapshots__/Anchor.test.tsx.snap b/components/anchor/__tests__/__snapshots__/Anchor.test.tsx.snap index 0a030f440b25..aa6da33ae783 100644 --- a/components/anchor/__tests__/__snapshots__/Anchor.test.tsx.snap +++ b/components/anchor/__tests__/__snapshots__/Anchor.test.tsx.snap @@ -1,6 +1,6 @@ -// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html +// Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`Anchor Render > render items and ignore jsx children 1`] = ` +exports[`Anchor Render render items and ignore jsx children 1`] = `
render items and ignore jsx children 1`] = `
`; -exports[`Anchor Render > renders items correctly 1`] = ` +exports[`Anchor Render renders items correctly 1`] = `
renders items correctly 1`] = `
`; -exports[`Anchor Render > renders items correctly#horizontal 1`] = ` +exports[`Anchor Render renders items correctly#horizontal 1`] = `
rtl render > component should be rendered correctly in RTL direction 1`] = ` +exports[`App rtl render component should be rendered correctly in RTL direction 1`] = `
`; -exports[`App > single 1`] = ` +exports[`App single 1`] = `
diff --git a/components/app/__tests__/index.test.tsx b/components/app/__tests__/index.test.tsx index cf58ca84b3cf..c738a60a203d 100644 --- a/components/app/__tests__/index.test.tsx +++ b/components/app/__tests__/index.test.tsx @@ -11,12 +11,12 @@ describe('App', () => { rtlTest(App); beforeEach(() => { - vi.useFakeTimers(); + jest.useFakeTimers(); }); afterEach(() => { - vi.clearAllTimers(); - vi.useRealTimers(); + jest.clearAllTimers(); + jest.useRealTimers(); }); it('single', () => { @@ -134,12 +134,10 @@ describe('App', () => { it('support style', () => { const { container } = render( - +
test
, ); - expect(container.querySelector('.ant-app')).toHaveStyle( - 'color: rgb(255, 0, 0);', - ); + expect(container.querySelector('.ant-app')).toHaveStyle('color: blue;'); }); }); diff --git a/components/auto-complete/__tests__/__snapshots__/demo-extend.test.ts.snap b/components/auto-complete/__tests__/__snapshots__/demo-extend.test.ts.snap index f4a2dc307a07..18443f634903 100644 --- a/components/auto-complete/__tests__/__snapshots__/demo-extend.test.ts.snap +++ b/components/auto-complete/__tests__/__snapshots__/demo-extend.test.ts.snap @@ -1,4 +1,4 @@ -// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html +// Jest Snapshot v1, https://goo.gl/fbAQLP exports[`renders components/auto-complete/demo/basic.tsx extend context correctly 1`] = ` Array [ @@ -235,7 +235,7 @@ exports[`renders components/auto-complete/demo/certain-category.tsx extend conte >
rtl render > component should be rendered correctly in RTL direction 1`] = ` +exports[`AutoComplete rtl render component should be rendered correctly in RTL direction 1`] = `