Compare commits

...

16 Commits

Author SHA1 Message Date
hainenber
5061776835 fix: rectify type issue for Vitest migration 2026-03-11 23:08:04 +07:00
hainenber
f26e2fa67e fix(ci): correctly run tests in silent to avoid GHA log truncation
Signed-off-by: hainenber <dotronghai96@gmail.com>
2026-03-11 23:06:20 +07:00
hainenber
17bdfaa3ae feat: migrate test sharding in CI from Jest to Vitest
Signed-off-by: hainenber <dotronghai96@gmail.com>
2026-03-10 22:02:23 +07:00
hainenber
ee00e369fe Merge branch 'master' into feat/migrate-to-vitest 2026-03-10 19:53:53 +07:00
hainenber
0100a0386b feat: continual migration to Vitest 2026-03-10 19:48:10 +07:00
hainenber
4c5936249c Merge branch 'master' into feat/migrate-to-vitest 2026-03-08 16:44:36 +07:00
hainenber
d9b1de9e75 fix(ci): correct arg name for Vitest coverage reporter in sharded tests
Signed-off-by: hainenber <dotronghai96@gmail.com>
2026-03-05 09:45:02 +07:00
hainenber
c80961ea91 fix(ci): correct arg name for Vitest coverage reporter in sharded tests
Signed-off-by: hainenber <dotronghai96@gmail.com>
2026-03-05 09:41:49 +07:00
hainenber
37328866b3 Merge branch 'master' into feat/migrate-to-vitest 2026-03-05 09:31:54 +07:00
hainenber
9616a7c375 chore: sync lockfile
Signed-off-by: hainenber <dotronghai96@gmail.com>
2026-03-05 09:31:35 +07:00
hainenber
a96259dcfc Merge branch 'master' into feat/migrate-to-vitest 2026-03-05 09:20:13 +07:00
hainenber
6be13ab782 chore: resolve prettier issues 2026-03-05 09:17:37 +07:00
hainenber
f072c6059b Merge branch 'master' into feat/migrate-to-vitest 2026-03-05 09:13:14 +07:00
hainenber
ea81614206 feat(fe): draft migration for RTL-based component test to Vitest 2026-03-04 22:44:20 +07:00
hainenber
4d05cdd78b feat(fe): finish Vitest migration for TS-based unit tests 2026-03-01 17:41:01 +07:00
hainenber
1565fd7f7a chore: setup Vitest config
Signed-off-by: hainenber <dotronghai96@gmail.com>
2026-02-23 22:01:49 +07:00
506 changed files with 19582 additions and 6245 deletions

View File

@@ -63,7 +63,7 @@ jobs:
name: docker-image
path: docker-image.tar.gz
sharded-jest-tests:
sharded-unit-tests:
needs: frontend-build
if: needs.frontend-build.outputs.should-run == 'true'
strategy:
@@ -84,19 +84,20 @@ jobs:
run: |
mkdir -p ${{ github.workspace }}/superset-frontend/coverage
docker run \
-v ${{ github.workspace }}/superset-frontend/coverage:/app/superset-frontend/coverage \
-v ${{ github.workspace }}/superset-frontend/.vitest-reports:/app/superset-frontend/.vitest-reports \
--rm $TAG \
bash -c \
"npm run test -- --coverage --shard=${{ matrix.shard }}/8 --coverageReporters=json"
"npm run test -- --coverage.enabled --reporter=blob --shard=${{ matrix.shard }}/8"
- name: Upload Coverage Artifact
uses: actions/upload-artifact@v7
with:
name: coverage-artifacts-${{ matrix.shard }}
path: superset-frontend/coverage
name: blob-report-${{ matrix.shard }}
path: .vitest-reports/*
include-hidden-files: true
report-coverage:
needs: [sharded-jest-tests]
needs: [sharded-unit-tests]
if: needs.frontend-build.outputs.should-run == 'true'
runs-on: ubuntu-24.04
permissions:
@@ -112,19 +113,12 @@ jobs:
- name: Download Coverage Artifacts
uses: actions/download-artifact@v8
with:
pattern: coverage-artifacts-*
path: coverage/
pattern: blob-report-*
path: .vitest-reports
merge-multiple: true
- name: Reorganize test result reports
run: |
find coverage/
for i in {1..8}; do
mv coverage/coverage-artifacts-${i}/coverage-final.json coverage/coverage-shard-${i}.json
done
shell: bash
- name: Merge Code Coverage
run: npx nyc merge coverage/ merged-output/coverage-summary.json
- name: Merge reports
run: npx vitest --merge-reports
- name: Upload Code Coverage
uses: codecov/codecov-action@v5
@@ -132,8 +126,6 @@ jobs:
flags: javascript
use_oidc: true
verbose: true
disable_search: true
files: merged-output/coverage-summary.json
slug: apache/superset
lint-frontend:

View File

@@ -48,7 +48,7 @@ module.exports = {
// but not test __mocks__ directories (e.g., packages/superset-ui-core/test/__mocks/)
'<rootDir>/packages/[^/]+/__mocks__',
],
setupFilesAfterEnv: ['<rootDir>/spec/helpers/setup.ts'],
setupFilesAfterEnv: ['<rootDir>/spec/helpers/setup.jest.ts'],
snapshotSerializers: ['@emotion/jest/serializer'],
testEnvironmentOptions: {
globalsCleanup: true,

View File

@@ -19,7 +19,8 @@
"__webpack_public_path__": "writable",
"__webpack_init_sharing__": "readonly",
"__webpack_share_scopes__": "readonly",
"jest": "readonly"
"jest": "readonly",
"vi": "readonly"
},
"settings": {
"react": {

File diff suppressed because it is too large Load Diff

View File

@@ -81,9 +81,9 @@
"storybook": "cross-env NODE_ENV=development BABEL_ENV=development storybook dev -p 6006",
"test-storybook": "test-storybook",
"test-storybook:ci": "concurrently -k -s first -n \"SB,TEST\" -c \"magenta,blue\" \"npx http-server storybook-static --port 6006 --silent\" \"npx wait-on tcp:127.0.0.1:6006 && npm run test-storybook -- --maxWorkers=2\"",
"tdd": "cross-env NODE_ENV=test NODE_OPTIONS=\"--max-old-space-size=8192\" jest --watch",
"test": "cross-env NODE_ENV=test NODE_OPTIONS=\"--max-old-space-size=8192\" jest --max-workers=80% --silent",
"test-loud": "cross-env NODE_ENV=test NODE_OPTIONS=\"--max-old-space-size=8192\" jest --max-workers=80%",
"tdd": "cross-env NODE_ENV=test NODE_OPTIONS=\"--max-old-space-size=8192\" vitest",
"test": "cross-env NODE_ENV=test NODE_OPTIONS=\"--max-old-space-size=8192\" vitest --run --silent",
"test-loud": "cross-env NODE_ENV=test NODE_OPTIONS=\"--max-old-space-size=8192\" vitest --run",
"type": "cross-env NODE_OPTIONS=\"--max-old-space-size=8192\" tsc --noEmit",
"update-maps": "cd plugins/legacy-plugin-chart-country-map/scripts && jupyter nbconvert --to notebook --execute --inplace --allow-errors --ExecutePreprocessor.timeout=1200 'Country Map GeoJSON Generator.ipynb'",
"validate-release": "../RELEASING/validate_this_release.sh"
@@ -280,7 +280,6 @@
"@testing-library/user-event": "^12.8.3",
"@types/content-disposition": "^0.5.9",
"@types/dom-to-image": "^2.6.7",
"@types/jest": "^30.0.0",
"@types/js-levenshtein": "^1.1.3",
"@types/json-bigint": "^1.0.4",
"@types/mousetrap": "^1.6.15",
@@ -300,6 +299,8 @@
"@types/unzipper": "^0.10.11",
"@typescript-eslint/eslint-plugin": "^7.18.0",
"@typescript-eslint/parser": "^7.18.0",
"@vitejs/plugin-react": "^5.1.4",
"@vitest/coverage-v8": "^4.0.18",
"babel-jest": "^30.0.2",
"babel-loader": "^10.0.0",
"babel-plugin-dynamic-import-node": "^2.3.3",
@@ -337,7 +338,6 @@
"imports-loader": "^5.0.0",
"jest": "^30.3.0",
"jest-environment-jsdom": "^29.7.0",
"jest-html-reporter": "^4.3.0",
"jest-websocket-mock": "^2.5.0",
"js-yaml-loader": "^1.2.2",
"jsdom": "^28.1.0",
@@ -366,6 +366,9 @@
"tsx": "^4.21.0",
"typescript": "5.4.5",
"unzipper": "^0.12.3",
"vite-plugin-svgr": "^4.5.0",
"vite-tsconfig-paths": "^6.1.1",
"vitest": "^4.0.18",
"vm-browserify": "^1.1.2",
"wait-on": "^9.0.4",
"webpack": "^5.105.4",

View File

@@ -36,7 +36,6 @@
"devDependencies": {
"cross-env": "^10.1.0",
"fs-extra": "^11.3.3",
"jest": "^30.3.0",
"yeoman-test": "^11.3.1"
},
"engines": {

View File

@@ -47,7 +47,7 @@ test('generator-superset:plugin-chart:creates files', async () => {
result.assertFile([
'.gitignore',
'babel.config.js',
'jest.config.js',
'vi.config.js',
'package.json',
'README.md',
'src/plugin/buildQuery.ts',

View File

@@ -21,13 +21,13 @@ import { Theme } from './Theme';
import { AnyThemeConfig, ThemeAlgorithm } from './types';
// Mock emotion's cache to avoid actual DOM operations
jest.mock('@emotion/cache', () => ({
vi.mock('@emotion/cache', () => ({
__esModule: true,
default: jest.fn().mockReturnValue({}),
default: vi.fn().mockReturnValue({}),
}));
beforeEach(() => {
jest.clearAllMocks();
vi.clearAllMocks();
});
test('Theme.json serializes the theme configuration to a JSON string', () => {

View File

@@ -31,16 +31,16 @@ import { Theme } from '../Theme';
import { ThemeAlgorithm } from '../types';
// Mock emotion's cache to avoid actual DOM operations
jest.mock('@emotion/cache', () => ({
vi.mock('@emotion/cache', () => ({
__esModule: true,
default: jest.fn().mockReturnValue({}),
default: vi.fn().mockReturnValue({}),
}));
let lightTheme: Theme;
let darkTheme: Theme;
beforeEach(() => {
jest.clearAllMocks();
vi.clearAllMocks();
// Create actual theme instances for testing
lightTheme = Theme.fromConfig({

View File

@@ -17,33 +17,33 @@
* under the License.
*/
beforeEach(() => {
jest.resetModules();
jest.resetAllMocks();
vi.resetModules();
vi.resetAllMocks();
});
test('should pipe to `console` methods', () => {
const { logging } = require('@apache-superset/core/utils');
jest.spyOn(logging, 'debug').mockImplementation();
jest.spyOn(logging, 'log').mockImplementation();
jest.spyOn(logging, 'info').mockImplementation();
vi.spyOn(logging, 'debug').mockImplementation(() => {});
vi.spyOn(logging, 'log').mockImplementation(() => {});
vi.spyOn(logging, 'info').mockImplementation(() => {});
expect(() => {
logging.debug();
logging.log();
logging.info();
}).not.toThrow();
jest.spyOn(logging, 'warn').mockImplementation(() => {
vi.spyOn(logging, 'warn').mockImplementation(() => {
throw new Error('warn');
});
expect(() => logging.warn()).toThrow('warn');
jest.spyOn(logging, 'error').mockImplementation(() => {
vi.spyOn(logging, 'error').mockImplementation(() => {
throw new Error('error');
});
expect(() => logging.error()).toThrow('error');
jest.spyOn(logging, 'trace').mockImplementation(() => {
vi.spyOn(logging, 'trace').mockImplementation(() => {
throw new Error('Trace:');
});
expect(() => logging.trace()).toThrow('Trace:');

View File

@@ -21,10 +21,10 @@ import { render } from '@superset-ui/core/spec';
import { GenericDataType } from '@apache-superset/core/common';
import { ColumnOption, ColumnOptionProps } from '../../src';
jest.mock('@superset-ui/chart-controls/components/SQLPopover', () => ({
vi.mock('@superset-ui/chart-controls/components/SQLPopover', () => ({
SQLPopover: () => <div data-test="mock-sql-popover" />,
}));
jest.mock(
vi.mock(
'@superset-ui/chart-controls/components/ColumnTypeLabel/ColumnTypeLabel',
() => ({
ColumnTypeLabel: ({ type }: { type: string }) => (
@@ -33,7 +33,7 @@ jest.mock(
}),
);
jest.mock('@superset-ui/core/components/InfoTooltip', () => ({
vi.mock('@superset-ui/core/components/InfoTooltip', () => ({
InfoTooltip: () => <div data-test="mock-tooltip" />,
}));

View File

@@ -20,7 +20,7 @@ import '@testing-library/jest-dom';
import { fireEvent, render } from '@superset-ui/core/spec';
import { InfoTooltip, InfoTooltipProps } from '@superset-ui/core/components';
jest.mock('@superset-ui/core/components/Tooltip', () => ({
vi.mock('@superset-ui/core/components/Tooltip', () => ({
Tooltip: ({ children }: { children: React.ReactNode }) => (
<div data-test="mock-tooltip">{children}</div>
),
@@ -40,7 +40,7 @@ test('renders a tooltip', () => {
});
test('responds to keydown events', () => {
const clickHandler = jest.fn();
const clickHandler = vi.fn();
const { getByRole } = setup({
label: 'test',
tooltip: 'this is a test',

View File

@@ -23,24 +23,24 @@ import {
MetricOptionProps,
} from '../../src/components/MetricOption';
jest.mock('@superset-ui/core/components/InfoTooltip', () => ({
vi.mock('@superset-ui/core/components/InfoTooltip', () => ({
InfoTooltip: () => <div data-test="mock-tooltip" />,
}));
jest.mock(
vi.mock(
'@superset-ui/chart-controls/components/ColumnTypeLabel/ColumnTypeLabel',
() => ({
ColumnTypeLabel: () => <div data-test="mock-column-type-label" />,
}),
);
jest.mock(
vi.mock(
'@superset-ui/core/components/Tooltip',
() =>
({ children }: { children: React.ReactNode }) => (
<div data-test="mock-tooltip">{children}</div>
),
);
jest.mock('@superset-ui/chart-controls/components/SQLPopover', () => ({
vi.mock('@superset-ui/chart-controls/components/SQLPopover', () => ({
SQLPopover: () => <div data-test="mock-sql-popover" />,
}));

View File

@@ -31,7 +31,7 @@ const defaultProps: RadioButtonControlProps = {
['option2', 'Option 2'],
['option3', 'Option 3'],
],
onChange: jest.fn(),
onChange: vi.fn(),
};
const setup = (props: Partial<RadioButtonControlProps> = {}) =>
@@ -89,7 +89,7 @@ test('respects initial value prop', () => {
});
test('calls onChange when radio button is clicked', () => {
const onChange = jest.fn();
const onChange = vi.fn();
setup({ onChange });
const secondOption = screen.getByText('Option 2');
@@ -100,7 +100,7 @@ test('calls onChange when radio button is clicked', () => {
});
test('handles multiple clicks correctly', () => {
const onChange = jest.fn();
const onChange = vi.fn();
setup({ onChange });
fireEvent.click(screen.getByText('Option 2'));
@@ -130,7 +130,7 @@ test('disables specific options when disabled flag is set', () => {
});
test('disabled options do not trigger onChange when clicked', () => {
const onChange = jest.fn();
const onChange = vi.fn();
const optionsWithDisabled: RadioButtonOption[] = [
{ value: 'opt1', label: 'Enabled' },
{ value: 'opt2', label: 'Disabled', disabled: true },
@@ -240,7 +240,7 @@ test('focuses button when clicked', () => {
});
test('handles numeric values in options', () => {
const onChange = jest.fn();
const onChange = vi.fn();
const numericOptions: RadioButtonOption[] = [
[1, 'One'],
[2, 'Two'],
@@ -254,7 +254,7 @@ test('handles numeric values in options', () => {
});
test('handles boolean values in options', () => {
const onChange = jest.fn();
const onChange = vi.fn();
const booleanOptions: RadioButtonOption[] = [
[true, 'True'],
[false, 'False'],
@@ -267,7 +267,7 @@ test('handles boolean values in options', () => {
});
test('handles null values in options', () => {
const onChange = jest.fn();
const onChange = vi.fn();
const nullOptions: RadioButtonOption[] = [
[null, 'None'],
['value', 'Value'],
@@ -310,7 +310,7 @@ test('does not set aria-selected to true for unselected buttons', () => {
});
test('backward compatibility with legacy array format', () => {
const onChange = jest.fn();
const onChange = vi.fn();
const legacyOptions: RadioButtonOption[] = [
['val1', 'Label 1'],
['val2', 'Label 2'],
@@ -327,7 +327,7 @@ test('backward compatibility with legacy array format', () => {
test('normalizeOption handles array format correctly', () => {
const arrayOption: RadioButtonOption = ['value', 'Label'];
const onChange = jest.fn();
const onChange = vi.fn();
setup({ options: [arrayOption], onChange });
@@ -343,7 +343,7 @@ test('normalizeOption handles object format correctly', () => {
label: 'Label',
disabled: false,
};
const onChange = jest.fn();
const onChange = vi.fn();
setup({ options: [objectOption], onChange });

View File

@@ -22,14 +22,14 @@ import { xAxisForceCategoricalControl } from '../../src/shared-controls/customCo
import { checkColumnType } from '../../src/utils/checkColumnType';
import type { ControlState } from '@superset-ui/chart-controls';
jest.mock('../../src/utils/checkColumnType');
jest.mock('@superset-ui/core', () => ({
...jest.requireActual('@superset-ui/core'),
getColumnLabel: jest.fn((col: any) => col),
vi.mock('../../src/utils/checkColumnType');
vi.mock('@superset-ui/core', async importActual => ({
...(await importActual()),
getColumnLabel: vi.fn((col: any) => col),
}));
test('xAxisForceCategoricalControl should not treat temporal columns as categorical when x_axis_sort exists', () => {
const mockCheckColumnType = jest.mocked(checkColumnType);
const mockCheckColumnType = vi.mocked(checkColumnType);
mockCheckColumnType.mockReturnValue(false); // temporal column (not numeric)

View File

@@ -20,12 +20,12 @@
import { ControlPanelState } from '../../src/types';
// Mock the utilities to avoid complex dependencies
jest.mock('../../src/utils', () => ({
formatSelectOptions: jest.fn((options: any[]) =>
vi.mock('../../src/utils', () => ({
formatSelectOptions: vi.fn((options: any[]) =>
options.map((opt: any) => [opt, opt]),
),
displayTimeRelatedControls: jest.fn(() => true),
getColorControlsProps: jest.fn(() => ({})),
displayTimeRelatedControls: vi.fn(() => true),
getColorControlsProps: vi.fn(() => ({})),
D3_FORMAT_OPTIONS: [],
D3_FORMAT_DOCS: '',
D3_TIME_FORMAT_OPTIONS: [],

View File

@@ -21,7 +21,7 @@ import { displayTimeRelatedControls } from '../../src';
const mockData = {
actions: {
setDatasource: jest.fn(),
setDatasource: vi.fn(),
},
controls: {
x_axis: {

View File

@@ -83,7 +83,6 @@
"@types/rison": "0.1.0",
"@types/seedrandom": "^3.0.8",
"fetch-mock": "^12.6.0",
"jest-mock-console": "^2.0.0",
"resize-observer-polyfill": "1.5.1",
"timezone-mock": "1.4.0"
},

View File

@@ -24,7 +24,7 @@ import MatrixifyGridCell from './MatrixifyGridCell';
import { MatrixifyGridCell as MatrixifyGridCellType } from '../../types/matrixify';
// Mock StatefulChart component
jest.mock('../StatefulChart', () => {
vi.mock('../StatefulChart', () => {
/* eslint-disable no-restricted-syntax, global-require, @typescript-eslint/no-var-requires */
const React = require('react');
/* eslint-enable no-restricted-syntax, global-require, @typescript-eslint/no-var-requires */

View File

@@ -23,21 +23,22 @@ import { ThemeProvider } from '@apache-superset/core/theme';
import { supersetTheme } from '@apache-superset/core/theme';
import MatrixifyGridRenderer from './MatrixifyGridRenderer';
import { generateMatrixifyGrid } from './MatrixifyGridGenerator';
import { Mock } from 'vitest';
// Mock the MatrixifyGridGenerator
jest.mock('./MatrixifyGridGenerator', () => ({
generateMatrixifyGrid: jest.fn(),
vi.mock('./MatrixifyGridGenerator', () => ({
generateMatrixifyGrid: vi.fn(),
}));
// Mock MatrixifyGridCell component
jest.mock('./MatrixifyGridCell', () =>
vi.mock('./MatrixifyGridCell', () =>
// eslint-disable-next-line react/display-name, @typescript-eslint/no-unused-vars
({ cell, rowHeight, datasource, hooks }: any) => (
<div data-testid={`grid-cell-${cell.id}`}>Cell: {cell.id}</div>
),
);
const mockGenerateMatrixifyGrid = generateMatrixifyGrid as jest.MockedFunction<
const mockGenerateMatrixifyGrid = generateMatrixifyGrid as Mock<
typeof generateMatrixifyGrid
>;
@@ -45,7 +46,7 @@ const renderWithTheme = (component: React.ReactElement) =>
render(<ThemeProvider theme={supersetTheme}>{component}</ThemeProvider>);
beforeEach(() => {
jest.clearAllMocks();
vi.clearAllMocks();
});
test('should create single group when fitting columns dynamically', () => {

View File

@@ -28,13 +28,13 @@ import getChartBuildQueryRegistry from '../registries/ChartBuildQueryRegistrySin
configure({ testIdAttribute: 'data-test' });
// Mock the registries
jest.mock('../registries/ChartControlPanelRegistrySingleton');
jest.mock('../registries/ChartMetadataRegistrySingleton');
jest.mock('../registries/ChartBuildQueryRegistrySingleton');
jest.mock('../clients/ChartClient');
vi.mock('../registries/ChartControlPanelRegistrySingleton');
vi.mock('../registries/ChartMetadataRegistrySingleton');
vi.mock('../registries/ChartBuildQueryRegistrySingleton');
vi.mock('../clients/ChartClient');
// Mock SuperChart component
jest.mock('./SuperChart', () => ({
vi.mock('./SuperChart', () => ({
__esModule: true,
// eslint-disable-next-line react/display-name
default: ({ formData }: any) => (
@@ -43,18 +43,18 @@ jest.mock('./SuperChart', () => ({
}));
// Mock Loading component
jest.mock('../../components/Loading', () => ({
vi.mock('../../components/Loading', () => ({
// eslint-disable-next-line react/display-name
Loading: () => <div data-test="loading">Loading...</div>,
}));
const mockChartClient = {
client: {
post: jest.fn().mockResolvedValue({
post: vi.fn().mockResolvedValue({
json: [{ data: 'test data' }],
}),
},
loadFormData: jest.fn(),
loadFormData: vi.fn(),
};
const mockFormData = {
@@ -64,21 +64,21 @@ const mockFormData = {
};
beforeEach(() => {
jest.clearAllMocks();
vi.clearAllMocks();
// Setup default registry mocks
(getChartMetadataRegistry as any).mockReturnValue({
get: jest.fn().mockReturnValue({
get: vi.fn().mockReturnValue({
useLegacyApi: false,
}),
});
(getChartBuildQueryRegistry as any).mockReturnValue({
get: jest.fn().mockResolvedValue(null),
get: vi.fn().mockResolvedValue(null),
});
(getChartControlPanelRegistry as any).mockReturnValue({
get: jest.fn().mockReturnValue(null),
get: vi.fn().mockReturnValue(null),
});
// Mock ChartClient constructor
@@ -114,7 +114,7 @@ test('should refetch data when non-renderTrigger control changes', async () => {
};
(getChartControlPanelRegistry as any).mockReturnValue({
get: jest.fn().mockReturnValue(controlPanelConfig),
get: vi.fn().mockReturnValue(controlPanelConfig),
});
const { rerender } = render(
@@ -166,7 +166,7 @@ test('should NOT refetch data when only renderTrigger controls change', async ()
};
(getChartControlPanelRegistry as any).mockReturnValue({
get: jest.fn().mockReturnValue(controlPanelConfig),
get: vi.fn().mockReturnValue(controlPanelConfig),
});
const { rerender, getByTestId } = render(
@@ -202,7 +202,7 @@ test('should NOT refetch data when only renderTrigger controls change', async ()
test('should refetch when control panel config is not available', async () => {
// No control panel config available
(getChartControlPanelRegistry as any).mockReturnValue({
get: jest.fn().mockReturnValue(null),
get: vi.fn().mockReturnValue(null),
});
const { rerender } = render(
@@ -246,7 +246,7 @@ test('should refetch when viz_type changes', async () => {
};
(getChartControlPanelRegistry as any).mockReturnValue({
get: jest.fn().mockReturnValue(controlPanelConfig),
get: vi.fn().mockReturnValue(controlPanelConfig),
});
const { rerender } = render(
@@ -300,7 +300,7 @@ test('should handle mixed renderTrigger and non-renderTrigger changes', async ()
};
(getChartControlPanelRegistry as any).mockReturnValue({
get: jest.fn().mockReturnValue(controlPanelConfig),
get: vi.fn().mockReturnValue(controlPanelConfig),
});
const { rerender } = render(
@@ -353,7 +353,7 @@ test('should handle controls with complex structure', async () => {
};
(getChartControlPanelRegistry as any).mockReturnValue({
get: jest.fn().mockReturnValue(controlPanelConfig),
get: vi.fn().mockReturnValue(controlPanelConfig),
});
const { rerender, getByTestId } = render(
@@ -405,7 +405,7 @@ test('should not refetch when formData has not changed', async () => {
test('should handle errors gracefully when accessing registry', async () => {
// Mock registry to throw an error
(getChartControlPanelRegistry as any).mockReturnValue({
get: jest.fn().mockImplementation(() => {
get: vi.fn().mockImplementation(() => {
throw new Error('Registry error');
}),
});
@@ -493,7 +493,7 @@ test('should NOT refetch data when string-based renderTrigger control (zoomable)
};
(getChartControlPanelRegistry as any).mockReturnValue({
get: jest.fn().mockReturnValue(controlPanelConfig),
get: vi.fn().mockReturnValue(controlPanelConfig),
});
const formDataWithZoom = {
@@ -543,7 +543,7 @@ test('should NOT refetch data when other string-based renderTrigger controls cha
};
(getChartControlPanelRegistry as any).mockReturnValue({
get: jest.fn().mockReturnValue(controlPanelConfig),
get: vi.fn().mockReturnValue(controlPanelConfig),
});
const { rerender, getByTestId } = render(
@@ -586,7 +586,7 @@ test('should refetch when string control is NOT in RENDER_TRIGGER_SHARED_CONTROL
};
(getChartControlPanelRegistry as any).mockReturnValue({
get: jest.fn().mockReturnValue(controlPanelConfig),
get: vi.fn().mockReturnValue(controlPanelConfig),
});
const { rerender } = render(
@@ -632,7 +632,7 @@ test('should handle mixed string and object controls correctly', async () => {
};
(getChartControlPanelRegistry as any).mockReturnValue({
get: jest.fn().mockReturnValue(controlPanelConfig),
get: vi.fn().mockReturnValue(controlPanelConfig),
});
const formDataWithControls = {
@@ -688,7 +688,7 @@ test('should refetch when mixing renderTrigger string control with non-renderTri
};
(getChartControlPanelRegistry as any).mockReturnValue({
get: jest.fn().mockReturnValue(controlPanelConfig),
get: vi.fn().mockReturnValue(controlPanelConfig),
});
const formDataWithZoom = {
@@ -729,7 +729,7 @@ test('should display error message when HTTP request fails with Response object'
});
mockChartClient.client.post.mockRejectedValue(mockResponse);
const onError = jest.fn();
const onError = vi.fn();
const { findByText } = render(
<StatefulChart
formData={mockFormData}

View File

@@ -55,9 +55,9 @@ beforeEach(() => {
});
test('should return the result from cache unless transformProps has changed', async () => {
const pre = jest.fn(x => x);
const transform = jest.fn(x => x);
const post = jest.fn(x => x);
const pre = vi.fn(x => x);
const transform = vi.fn(x => x);
const post = vi.fn(x => x);
expect(getChartComponentRegistry().get(props.chartType)).toBe(FakeChart);
expect(pre).toHaveBeenCalledTimes(0);
@@ -74,7 +74,7 @@ test('should return the result from cache unless transformProps has changed', as
expect(transform).toHaveBeenCalledTimes(1);
expect(post).toHaveBeenCalledTimes(1);
const updatedPost = jest.fn(x => x);
const updatedPost = vi.fn(x => x);
rerender(
<SuperChartCore

View File

@@ -17,6 +17,6 @@
* under the License.
*/
export const isMatrixifyEnabled = jest.fn(() => false);
export const isMatrixifyEnabled = vi.fn(() => false);
export const MatrixifyGridRenderer = jest.fn(() => null);
export const MatrixifyGridRenderer = vi.fn(() => null);

View File

@@ -23,7 +23,7 @@ import { ActionButton } from '.';
const defaultProps = {
label: 'test-action',
icon: <Icons.EditOutlined />,
onClick: jest.fn(),
onClick: vi.fn(),
};
test('renders action button with icon', () => {
@@ -36,7 +36,7 @@ test('renders action button with icon', () => {
});
test('calls onClick when clicked', async () => {
const onClick = jest.fn();
const onClick = vi.fn();
render(<ActionButton {...defaultProps} onClick={onClick} />);
const button = screen.getByRole('button');

View File

@@ -307,7 +307,7 @@ test('cleans up event listeners on unmount', async () => {
if (!editorInstance) return;
// Spy on the commands.off method
const offSpy = jest.spyOn(editorInstance.commands, 'off');
const offSpy = vi.spyOn(editorInstance.commands, 'off');
// Unmount the component
unmount();
@@ -339,7 +339,7 @@ test('does not move autocomplete popup if target container is document.body', as
// Mock the closest method to return null (simulating no #ace-editor parent)
const originalClosest = editorInstance.container?.closest;
if (editorInstance.container) {
editorInstance.container.closest = jest.fn(() => null);
editorInstance.container.closest = vi.fn(() => null);
}
// Mock parentElement to be document.body

View File

@@ -74,7 +74,7 @@ describe('useJsonValidation', () => {
});
test('falls back to "syntax error" when thrown error has no message (line 59 || branch)', () => {
const spy = jest.spyOn(JSON, 'parse').mockImplementationOnce(() => {
const spy = vi.spyOn(JSON, 'parse').mockImplementationOnce(() => {
throw {}; // no .message property → error.message is undefined → falsy
});
@@ -86,7 +86,7 @@ describe('useJsonValidation', () => {
});
test('extracts row and column from error when message contains (line X column Y)', () => {
const spy = jest.spyOn(JSON, 'parse').mockImplementationOnce(() => {
const spy = vi.spyOn(JSON, 'parse').mockImplementationOnce(() => {
throw new SyntaxError('Unexpected token (line 3 column 5)');
});

View File

@@ -25,14 +25,14 @@ import {
} from './Button.stories';
test('works with an onClick handler', () => {
const mockAction = jest.fn();
const mockAction = vi.fn();
const { getByRole } = render(<Button onClick={mockAction} />);
fireEvent.click(getByRole('button'));
expect(mockAction).toHaveBeenCalled();
});
test('does not handle onClicks when disabled', () => {
const mockAction = jest.fn();
const mockAction = vi.fn();
const { getByRole } = render(<Button onClick={mockAction} disabled />);
fireEvent.click(getByRole('button'));
expect(mockAction).toHaveBeenCalledTimes(0);

View File

@@ -23,7 +23,7 @@ import type { CheckboxProps } from './types';
const mockedProps: CheckboxProps = {
checked: false,
id: 'checkbox-id',
onChange: jest.fn(),
onChange: vi.fn(),
disabled: false,
title: 'Checkbox title',
indeterminate: false,
@@ -35,7 +35,7 @@ describe('Checkbox Component', () => {
waitFor(() => render(<Checkbox {...props} />));
beforeEach(() => {
jest.clearAllMocks();
vi.clearAllMocks();
});
describe('Rendering', () => {
@@ -93,7 +93,7 @@ describe('Checkbox Component', () => {
});
test('should not call the onChange handler when disabled and clicked', async () => {
const mockOnChange = jest.fn();
const mockOnChange = vi.fn();
const disabledProps = {
...mockedProps,
disabled: true,
@@ -109,7 +109,7 @@ describe('Checkbox Component', () => {
});
test('calls onChange handler successfully', async () => {
const mockAction = jest.fn();
const mockAction = vi.fn();
render(<Checkbox checked={false} onChange={mockAction} />);
const checkboxInput = screen.getByRole('checkbox');
await userEvent.click(checkboxInput);

View File

@@ -20,7 +20,7 @@ import { render, screen } from '../../spec';
import CodeSyntaxHighlighter from './index';
// Simple mock that just returns the content
jest.mock(
vi.mock(
'react-syntax-highlighter/dist/cjs/light',
() =>
function MockSyntaxHighlighter({ children, ...props }: any) {
@@ -33,26 +33,26 @@ jest.mock(
);
// Mock the language modules
jest.mock(
vi.mock(
'react-syntax-highlighter/dist/cjs/languages/hljs/sql',
() => 'sql-mock',
);
jest.mock(
vi.mock(
'react-syntax-highlighter/dist/cjs/languages/hljs/json',
() => 'json-mock',
);
jest.mock(
vi.mock(
'react-syntax-highlighter/dist/cjs/languages/hljs/htmlbars',
() => 'html-mock',
);
jest.mock(
vi.mock(
'react-syntax-highlighter/dist/cjs/languages/hljs/markdown',
() => 'md-mock',
);
// Mock the styles
jest.mock('react-syntax-highlighter/dist/cjs/styles/hljs/github', () => ({}));
jest.mock(
vi.mock('react-syntax-highlighter/dist/cjs/styles/hljs/github', () => ({}));
vi.mock(
'react-syntax-highlighter/dist/cjs/styles/hljs/atom-one-dark',
() => ({}),
);

View File

@@ -22,8 +22,8 @@ import { ConfirmModal } from '.';
const defaultProps = {
show: true,
onHide: jest.fn(),
onConfirm: jest.fn(),
onHide: vi.fn(),
onConfirm: vi.fn(),
title: 'Confirm Action',
body: 'Are you sure you want to proceed?',
};
@@ -57,7 +57,7 @@ test('renders custom button text', () => {
});
test('calls onConfirm when confirm button is clicked', () => {
const onConfirm = jest.fn();
const onConfirm = vi.fn();
renderWithTheme(<ConfirmModal {...defaultProps} onConfirm={onConfirm} />);
userEvent.click(screen.getByRole('button', { name: 'Confirm' }));
@@ -66,7 +66,7 @@ test('calls onConfirm when confirm button is clicked', () => {
});
test('calls onHide when cancel button is clicked', () => {
const onHide = jest.fn();
const onHide = vi.fn();
renderWithTheme(<ConfirmModal {...defaultProps} onHide={onHide} />);
userEvent.click(screen.getByRole('button', { name: 'Cancel' }));

View File

@@ -24,11 +24,11 @@ import type { ConfirmStatusChangeProps } from './types';
const mockedProps: Omit<ConfirmStatusChangeProps, 'children'> = {
title: 'please confirm',
description: 'are you sure?',
onConfirm: jest.fn(),
onConfirm: vi.fn(),
};
test('renders children with showConfirm function', () => {
const childrenSpy = jest.fn().mockReturnValue(<div>test content</div>);
const childrenSpy = vi.fn().mockReturnValue(<div>test content</div>);
render(
<ConfirmStatusChange {...mockedProps}>{childrenSpy}</ConfirmStatusChange>,
@@ -73,8 +73,8 @@ test('stores and passes arguments to onConfirm callback', async () => {
test('calls preventDefault on event-like arguments', () => {
const mockEvent = {
preventDefault: jest.fn(),
stopPropagation: jest.fn(),
preventDefault: vi.fn(),
stopPropagation: vi.fn(),
};
const { getByTestId } = render(
@@ -93,7 +93,7 @@ test('calls preventDefault on event-like arguments', () => {
test('skips event handling on non-event arguments', () => {
const regularArg = { someData: 'value' };
const mockFunc = jest.fn();
const mockFunc = vi.fn();
const { getByTestId } = render(
<ConfirmStatusChange {...mockedProps}>
@@ -134,8 +134,8 @@ test('ignores null and undefined arguments', () => {
});
test('handles partial event objects gracefully', () => {
const partialEvent1 = { preventDefault: jest.fn() }; // Only preventDefault
const partialEvent2 = { stopPropagation: jest.fn() }; // Only stopPropagation
const partialEvent1 = { preventDefault: vi.fn() }; // Only preventDefault
const partialEvent2 = { stopPropagation: vi.fn() }; // Only stopPropagation
const { getByTestId } = render(
<ConfirmStatusChange {...mockedProps}>

View File

@@ -21,7 +21,7 @@ import { render } from '@superset-ui/core/spec';
import * as ReactCronPicker from 'react-js-cron';
import { CronPicker } from '.';
const spy = jest.spyOn(ReactCronPicker, 'default');
const spy = vi.spyOn(ReactCronPicker, 'default');
test('Should send correct props to ReactCronPicker', () => {
const props = {

View File

@@ -23,8 +23,8 @@ test('Must display title and content', () => {
const props = {
title: <div data-test="test-title">Title</div>,
description: <div data-test="test-description">Description</div>,
onConfirm: jest.fn(),
onHide: jest.fn(),
onConfirm: vi.fn(),
onHide: vi.fn(),
open: true,
};
render(<DeleteModal {...props} />);
@@ -36,8 +36,8 @@ test('Input should autofocus when modal opens', async () => {
const props = {
title: <div data-test="test-title">Title</div>,
description: <div data-test="test-description">Description</div>,
onConfirm: jest.fn(),
onHide: jest.fn(),
onConfirm: vi.fn(),
onHide: vi.fn(),
open: true,
};
render(<DeleteModal {...props} />);
@@ -52,8 +52,8 @@ test('Calling "onHide"', async () => {
const props = {
title: <div data-test="test-title">Title</div>,
description: <div data-test="test-description">Description</div>,
onConfirm: jest.fn(),
onHide: jest.fn(),
onConfirm: vi.fn(),
onHide: vi.fn(),
open: true,
};
const modal = <DeleteModal {...props} />;
@@ -79,8 +79,8 @@ test('Calling "onConfirm" only after typing "delete" in the input', async () =>
const props = {
title: <div data-test="test-title">Title</div>,
description: <div data-test="test-description">Description</div>,
onConfirm: jest.fn(),
onHide: jest.fn(),
onConfirm: vi.fn(),
onHide: vi.fn(),
open: true,
};
render(<DeleteModal {...props} />);

View File

@@ -41,7 +41,7 @@ describe('NoAnimationDropdown', () => {
});
test('calls onBlur when it loses focus', () => {
const onBlur = jest.fn();
const onBlur = vi.fn();
render(
<NoAnimationDropdown {...props} onBlur={onBlur}>
<button type="button">Test Button</button>
@@ -52,7 +52,7 @@ describe('NoAnimationDropdown', () => {
});
test('calls onKeyDown when a key is pressed', () => {
const onKeyDown = jest.fn();
const onKeyDown = vi.fn();
render(
<NoAnimationDropdown {...props} onKeyDown={onKeyDown}>
<button type="button">Test Button</button>

View File

@@ -29,13 +29,13 @@ const ITEMS = generateItems(10);
beforeEach(() => {
// Reset any mocks
jest.restoreAllMocks();
vi.restoreAllMocks();
// Mock ResizeObserver globally
global.ResizeObserver = jest.fn().mockImplementation(() => ({
observe: jest.fn(),
unobserve: jest.fn(),
disconnect: jest.fn(),
global.ResizeObserver = vi.fn().mockImplementation(() => ({
observe: vi.fn(),
unobserve: vi.fn(),
disconnect: vi.fn(),
}));
});
@@ -100,7 +100,7 @@ test('renders component with dropdown style prop without error', () => {
});
test('renders component with onOverflowingStateChange prop without error', () => {
const onOverflowingStateChange = jest.fn();
const onOverflowingStateChange = vi.fn();
render(
<DropdownContainer
items={generateItems(5)}
@@ -160,7 +160,7 @@ test('accepts custom style props', () => {
// Integration test that doesn't rely on specific overflow behavior
test('component renders and functions without throwing errors', () => {
const onOverflowingStateChange = jest.fn();
const onOverflowingStateChange = vi.fn();
expect(() => {
render(

View File

@@ -23,7 +23,7 @@ const createProps = (overrides: Record<string, any> = {}) => ({
title: 'Chart title',
placeholder: 'Add the name of the chart',
canEdit: true,
onSave: jest.fn(),
onSave: vi.fn(),
label: 'Chart title',
...overrides,
});

View File

@@ -27,7 +27,7 @@ const mockEvent = {
const mockProps = {
title: 'my title',
canEdit: true,
onSaveTitle: jest.fn(),
onSaveTitle: vi.fn(),
};
test('should render title', () => {
@@ -40,7 +40,7 @@ test('should render title', () => {
test('should not render an input if it is not editable', () => {
const { queryByTestId } = render(
<EditableTitle title="my title" onSaveTitle={jest.fn()} />,
<EditableTitle title="my title" onSaveTitle={vi.fn()} />,
);
expect(
queryByTestId('textarea-editable-title-input'),
@@ -75,7 +75,7 @@ describe('should handle blur', () => {
};
test('should trigger callback', () => {
const callback = jest.fn();
const callback = vi.fn();
const { getByTestId } = setup({ onSaveTitle: callback });
fireEvent.change(getByTestId('textarea-editable-title-input'), mockEvent);
fireEvent.blur(getByTestId('textarea-editable-title-input'));
@@ -84,7 +84,7 @@ describe('should handle blur', () => {
});
test('should not trigger callback', () => {
const callback = jest.fn();
const callback = vi.fn();
const { getByTestId } = setup({ onSaveTitle: callback });
fireEvent.blur(getByTestId('textarea-editable-title-input'));
// no change
@@ -92,7 +92,7 @@ describe('should handle blur', () => {
});
test('should not save empty title', () => {
const callback = jest.fn();
const callback = vi.fn();
const { getByTestId } = setup({ onSaveTitle: callback });
const textarea = getByTestId('textarea-editable-title-input');
fireEvent.blur(textarea);

View File

@@ -20,14 +20,14 @@
import { render, screen, userEvent } from '@superset-ui/core/spec';
import { FaveStar } from '.';
jest.mock('@superset-ui/core/components/Tooltip', () => ({
vi.mock('@superset-ui/core/components/Tooltip', () => ({
Tooltip: (props: any) => <div data-test="tooltip" {...props} />,
}));
test('render right content', async () => {
const props = {
itemId: 3,
saveFaveStar: jest.fn(),
saveFaveStar: vi.fn(),
};
const { rerender, findByRole } = render(<FaveStar {...props} isStarred />);
@@ -52,7 +52,7 @@ test('render content on tooltip', async () => {
const props = {
itemId: 3,
showTooltip: true,
saveFaveStar: jest.fn(),
saveFaveStar: vi.fn(),
};
render(<FaveStar {...props} />);
@@ -72,8 +72,8 @@ test('render content on tooltip', async () => {
test('Call fetchFaveStar on first render and on itemId change', async () => {
const props = {
itemId: 3,
fetchFaveStar: jest.fn(),
saveFaveStar: jest.fn(),
fetchFaveStar: vi.fn(),
saveFaveStar: vi.fn(),
isStarred: false,
showTooltip: false,
};

View File

@@ -45,7 +45,7 @@ describe('IconButton', () => {
});
test('handles Enter and Space key presses', () => {
const mockOnClick = jest.fn();
const mockOnClick = vi.fn();
render(<IconButton {...defaultProps} onClick={mockOnClick} />);
const button = screen.getByRole('button');
@@ -79,7 +79,7 @@ describe('IconButton', () => {
});
test('calls onClick handler when clicked', () => {
const mockOnClick = jest.fn();
const mockOnClick = vi.fn();
render(<IconButton {...defaultProps} onClick={mockOnClick} />);
const button = screen.getByRole('button');

View File

@@ -19,7 +19,7 @@
import { render } from '@superset-ui/core/spec';
import { IconTooltip } from '.';
jest.mock('@superset-ui/core/components/Tooltip', () => ({
vi.mock('@superset-ui/core/components/Tooltip', () => ({
Tooltip: () => <div data-test="mock-tooltip" />,
}));

View File

@@ -28,7 +28,7 @@ test('renders the base component (no onClick)', () => {
});
test('works with an onClick handler', () => {
const mockAction = jest.fn();
const mockAction = vi.fn();
const { getByText } = render(<Label onClick={mockAction}>test</Label>);
fireEvent.click(getByText('test'));
expect(mockAction).toHaveBeenCalled();

View File

@@ -28,7 +28,7 @@ test('renders the base component (no refresh)', () => {
});
test('renders a refresh action', () => {
const mockAction = jest.fn();
const mockAction = vi.fn();
render(<LastUpdated updatedAt={updatedAt} update={mockAction} />);
const button = screen.getByRole('button');

View File

@@ -21,7 +21,7 @@ import fetchMock from 'fetch-mock';
import { render, screen } from '@superset-ui/core/spec';
import { ImageLoader, type BackgroundPosition } from './ImageLoader';
global.URL.createObjectURL = jest.fn(() => '/local_url');
global.URL.createObjectURL = vi.fn(() => '/local_url');
const blob = new Blob([], { type: 'image/png' });
beforeAll(() => {

View File

@@ -21,7 +21,7 @@ import fetchMock from 'fetch-mock';
import { render, screen } from '@superset-ui/core/spec';
import { ListViewCard } from '.';
global.URL.createObjectURL = jest.fn(() => '/local_url');
global.URL.createObjectURL = vi.fn(() => '/local_url');
fetchMock.get('/thumbnail', { body: new Blob(), sendAsJson: false });
describe('ListViewCard', () => {

View File

@@ -22,19 +22,19 @@ import * as themeModule from '@apache-superset/core/theme';
import { Loading } from '.';
// Mock the loading SVG import since it's a file stub in tests
jest.mock('../assets', () => ({
vi.mock('../assets', () => ({
Loading: () => <svg data-test="default-loading-svg" />,
}));
const mockUseTheme = jest.fn();
const mockUseTheme = vi.fn();
beforeEach(() => {
mockUseTheme.mockReset();
jest.spyOn(themeModule, 'useTheme').mockImplementation(mockUseTheme);
vi.spyOn(themeModule, 'useTheme').mockImplementation(mockUseTheme);
});
afterEach(() => {
jest.restoreAllMocks();
vi.restoreAllMocks();
});
test('uses default spinner when no theme spinner configured', () => {

View File

@@ -42,7 +42,7 @@ const A_WEEK_AGO = 'a week ago';
const TWO_DAYS_AGO = '2 days ago';
const runWithBarCollapsed = async (func: Function) => {
const spy = jest.spyOn(resizeDetector, 'useResizeDetector');
const spy = vi.spyOn(resizeDetector, 'useResizeDetector');
let width: number;
spy.mockImplementation(props => {
if (props?.onResize && !width) {
@@ -101,7 +101,7 @@ test('renders an array of items', () => {
});
test('throws errors when out of min/max restrictions', () => {
const spy = jest.spyOn(console, 'error');
const spy = vi.spyOn(console, 'error');
spy.mockImplementation(() => {});
expect(() =>
render(<MetadataBar items={ITEMS.slice(0, MIN_NUMBER_ITEMS - 1)} />),
@@ -148,7 +148,7 @@ test('renders a tooltip when one is provided even if not collapsed', async () =>
});
test('renders underlined text and emits event when clickable', async () => {
const onClick = jest.fn();
const onClick = vi.fn();
const items = [{ ...ITEMS[0], onClick }, ITEMS[1]];
render(<MetadataBar items={items} />);
const element = screen.getByText(DASHBOARD_TITLE);
@@ -160,7 +160,7 @@ test('renders underlined text and emits event when clickable', async () => {
test('renders clickable items with blue icons when the bar is collapsed', async () => {
await runWithBarCollapsed(async () => {
const onClick = jest.fn();
const onClick = vi.fn();
const items = [{ ...ITEMS[0], onClick }, ITEMS[1]];
render(<MetadataBar items={items} />);
const images = screen.getAllByRole('img');
@@ -266,7 +266,7 @@ test('correctly renders the tags tooltip', async () => {
});
test('renders StyledItem with role="button" when onClick is defined', () => {
const onClick = jest.fn();
const onClick = vi.fn();
const items = [
{ ...ITEMS[0], onClick },
{ ...ITEMS[1], onClick },

View File

@@ -47,10 +47,10 @@ describe('FormModal Component', () => {
const mockedProps: FormModalProps = {
show: true,
onHide: jest.fn(),
onHide: vi.fn(),
title: 'Test Form Modal',
onSave: jest.fn(),
formSubmitHandler: jest.fn().mockResolvedValue(undefined),
onSave: vi.fn(),
formSubmitHandler: vi.fn().mockResolvedValue(undefined),
initialValues: { name: '', email: '' },
requiredFields: ['name'],
children,

View File

@@ -25,14 +25,14 @@ const defaultProps: PageHeaderWithActionsProps = {
editableTitleProps: {
title: 'Test title',
placeholder: 'Test placeholder',
onSave: jest.fn(),
onSave: vi.fn(),
canEdit: true,
label: 'Title',
},
showTitlePanelItems: true,
certificatiedBadgeProps: {},
showFaveStar: true,
faveStarProps: { itemId: 1, saveFaveStar: jest.fn() },
faveStarProps: { itemId: 1, saveFaveStar: vi.fn() },
titlePanelAdditionalItems: <button type="button">Title panel button</button>,
rightPanelAdditionalItems: <button type="button">Save</button>,
additionalActionsMenu: (
@@ -41,7 +41,7 @@ const defaultProps: PageHeaderWithActionsProps = {
data-test="additional-actions-menu"
/>
),
menuDropdownProps: { onVisibleChange: jest.fn(), visible: true },
menuDropdownProps: { onVisibleChange: vi.fn(), visible: true },
};
test('Renders', async () => {

View File

@@ -58,7 +58,7 @@ test('renders with icon child', async () => {
});
test('fires an event when visibility is changed', async () => {
const onOpenChange = jest.fn();
const onOpenChange = vi.fn();
render(
<Popover
content="Content sample"

View File

@@ -31,7 +31,7 @@ const defaultProps: PopoverDropdownProps = {
value: '1',
renderButton: (option: OptionProps) => <span>{option.label}</span>,
renderOption: (option: OptionProps) => <div>{option.label}</div>,
onChange: jest.fn(),
onChange: vi.fn(),
};
test('renders with default props', async () => {

View File

@@ -49,7 +49,7 @@ test('renders a tooltip when hovered', async () => {
});
test('calls onSelect when clicked', async () => {
const onSelect = jest.fn();
const onSelect = vi.fn();
render(
<PopoverSection title="Title" onSelect={onSelect}>
<div role="form" />

View File

@@ -20,7 +20,7 @@ import { render, screen, userEvent } from '@superset-ui/core/spec';
import RefreshLabel from '@superset-ui/core/components/RefreshLabel';
test('renders with default props', async () => {
render(<RefreshLabel tooltipContent="Tooltip" onClick={jest.fn()} />);
render(<RefreshLabel tooltipContent="Tooltip" onClick={vi.fn()} />);
const refresh = await screen.findByRole('button');
expect(refresh).toBeInTheDocument();
await userEvent.hover(refresh);
@@ -28,7 +28,7 @@ test('renders with default props', async () => {
test('renders tooltip on hover', async () => {
const tooltipText = 'Tooltip';
render(<RefreshLabel tooltipContent={tooltipText} onClick={jest.fn()} />);
render(<RefreshLabel tooltipContent={tooltipText} onClick={vi.fn()} />);
const refresh = screen.getByRole('button');
await userEvent.hover(refresh);
const tooltip = await screen.findByRole('tooltip');
@@ -37,7 +37,7 @@ test('renders tooltip on hover', async () => {
});
test('triggers on click event', async () => {
const onClick = jest.fn();
const onClick = vi.fn();
render(<RefreshLabel tooltipContent="Tooltip" onClick={onClick} />);
const refresh = await screen.findByRole('button');
await userEvent.click(refresh);

View File

@@ -153,7 +153,7 @@ test('displays a header', async () => {
});
test('adds a new option if the value is not in the options, when options are empty', async () => {
const loadOptions = jest.fn(async () => ({ data: [], totalCount: 0 }));
const loadOptions = vi.fn(async () => ({ data: [], totalCount: 0 }));
render(
<AsyncSelect {...defaultProps} options={loadOptions} value={OPTIONS[0]} />,
);
@@ -167,7 +167,7 @@ test('adds a new option if the value is not in the options, when options are emp
});
test('adds a new option if the value is not in the options, when options have values', async () => {
const loadOptions = jest.fn(async () => ({
const loadOptions = vi.fn(async () => ({
data: [OPTIONS[1]],
totalCount: 1,
}));
@@ -185,7 +185,7 @@ test('adds a new option if the value is not in the options, when options have va
});
test('does not add a new option if the value is already in the options', async () => {
const loadOptions = jest.fn(async () => ({
const loadOptions = vi.fn(async () => ({
data: [OPTIONS[0]],
totalCount: 1,
}));
@@ -206,7 +206,7 @@ test('inverts the selection', async () => {
});
test('sort the options by label if no sort comparator is provided', async () => {
const loadUnsortedOptions = jest.fn(async () => ({
const loadUnsortedOptions = vi.fn(async () => ({
data: [...OPTIONS].sort(() => Math.random()),
totalCount: 2,
}));
@@ -324,7 +324,7 @@ test('ignores case when searching', async () => {
});
test('same case should be ranked to the top', async () => {
const loadOptions = jest.fn(async () => ({
const loadOptions = vi.fn(async () => ({
data: [
{ value: 'Cac' },
{ value: 'abac' },
@@ -399,7 +399,7 @@ test('removes duplicated values', async () => {
});
test('renders a custom label', async () => {
const loadOptions = jest.fn(async () => ({
const loadOptions = vi.fn(async () => ({
data: [
{ value: 'John', label: <h1>John</h1> },
{ value: 'Liam', label: <h1>Liam</h1> },
@@ -415,7 +415,7 @@ test('renders a custom label', async () => {
});
test('searches for a word with a custom label', async () => {
const loadOptions = jest.fn(async () => ({
const loadOptions = vi.fn(async () => ({
data: [
{ value: 'John', label: <h1>John</h1> },
{ value: 'Liam', label: <h1>Liam</h1> },
@@ -441,7 +441,7 @@ test('removes a new option if the user does not select it', async () => {
});
test('clear all the values', async () => {
const onClear = jest.fn();
const onClear = vi.fn();
render(
<AsyncSelect
{...defaultProps}
@@ -466,7 +466,7 @@ test('does not add a new option if allowNewOptions is false', async () => {
});
test('adds the null option when selected in single mode', async () => {
const loadOptions = jest.fn(async () => ({
const loadOptions = vi.fn(async () => ({
data: [OPTIONS[0], NULL_OPTION],
totalCount: 2,
}));
@@ -478,7 +478,7 @@ test('adds the null option when selected in single mode', async () => {
});
test('adds the null option when selected in multiple mode', async () => {
const loadOptions = jest.fn(async () => ({
const loadOptions = vi.fn(async () => ({
data: [OPTIONS[0], NULL_OPTION],
totalCount: 2,
}));
@@ -541,7 +541,7 @@ test('multiple selections in multiple mode', async () => {
});
test('changes the selected item in single mode', async () => {
const onChange = jest.fn();
const onChange = vi.fn();
render(<AsyncSelect {...defaultProps} onChange={onChange} />);
await open();
const [firstOption, secondOption] = OPTIONS;
@@ -674,7 +674,7 @@ test('searches for matches in both loaded and unloaded pages', async () => {
});
test('searches for an item in a page not loaded', async () => {
const mock = jest.fn(loadOptions);
const mock = vi.fn(loadOptions);
render(<AsyncSelect {...defaultProps} options={mock} />);
const search = 'Sandro';
await open();
@@ -686,20 +686,20 @@ test('searches for an item in a page not loaded', async () => {
});
test('does not fetches data when rendering', async () => {
const loadOptions = jest.fn(async () => ({ data: [], totalCount: 0 }));
const loadOptions = vi.fn(async () => ({ data: [], totalCount: 0 }));
render(<AsyncSelect {...defaultProps} options={loadOptions} />);
expect(loadOptions).not.toHaveBeenCalled();
});
test('fetches data when opening', async () => {
const loadOptions = jest.fn(async () => ({ data: [], totalCount: 0 }));
const loadOptions = vi.fn(async () => ({ data: [], totalCount: 0 }));
render(<AsyncSelect {...defaultProps} options={loadOptions} />);
await open();
expect(loadOptions).toHaveBeenCalled();
});
test('fetches data only after a search input is entered if fetchOnlyOnSearch is true', async () => {
const loadOptions = jest.fn(async () => ({ data: [], totalCount: 0 }));
const loadOptions = vi.fn(async () => ({ data: [], totalCount: 0 }));
render(
<AsyncSelect {...defaultProps} options={loadOptions} fetchOnlyOnSearch />,
);
@@ -720,7 +720,7 @@ test('displays an error message when an exception is thrown while fetching', asy
});
test('does not fire a new request for the same search input', async () => {
const loadOptions = jest.fn(async () => ({ data: [], totalCount: 0 }));
const loadOptions = vi.fn(async () => ({ data: [], totalCount: 0 }));
render(
<AsyncSelect {...defaultProps} options={loadOptions} fetchOnlyOnSearch />,
);
@@ -731,7 +731,7 @@ test('does not fire a new request for the same search input', async () => {
});
test('does not fire a new request if all values have been fetched', async () => {
const mock = jest.fn(loadOptions);
const mock = vi.fn(loadOptions);
const search = 'George';
const pageSize = OPTIONS.length;
render(<AsyncSelect {...defaultProps} options={mock} pageSize={pageSize} />);
@@ -743,7 +743,7 @@ test('does not fire a new request if all values have been fetched', async () =>
});
test('fires a new request if all values have not been fetched', async () => {
const mock = jest.fn(loadOptions);
const mock = vi.fn(loadOptions);
const pageSize = OPTIONS.length / 2;
render(<AsyncSelect {...defaultProps} options={mock} pageSize={pageSize} />);
await open();
@@ -774,7 +774,7 @@ test('renders a helper text when one is provided', async () => {
});
test('finds an element with a numeric value and does not duplicate the options', async () => {
const options = jest.fn(async () => ({
const options = vi.fn(async () => ({
data: [
{ label: 'a', value: 11 },
{ label: 'b', value: 12 },
@@ -837,7 +837,7 @@ test('Renders only an overflow tag if dropdown is open in oneLine mode', async (
});
test('does not fire onChange when searching but no selection', async () => {
const onChange = jest.fn();
const onChange = vi.fn();
render(
<div role="main">
<AsyncSelect
@@ -856,7 +856,7 @@ test('does not fire onChange when searching but no selection', async () => {
});
test('fires onChange when clearing the selection in single mode', async () => {
const onChange = jest.fn();
const onChange = vi.fn();
render(
<AsyncSelect
{...defaultProps}
@@ -870,7 +870,7 @@ test('fires onChange when clearing the selection in single mode', async () => {
});
test('fires onChange when clearing the selection in multiple mode', async () => {
const onChange = jest.fn();
const onChange = vi.fn();
render(
<AsyncSelect
{...defaultProps}
@@ -884,7 +884,7 @@ test('fires onChange when clearing the selection in multiple mode', async () =>
});
test('fires onChange when pasting a selection', async () => {
const onChange = jest.fn();
const onChange = vi.fn();
render(<AsyncSelect {...defaultProps} onChange={onChange} />);
await open();
const input = getElementByClassName('.ant-select-selection-search-input');
@@ -916,7 +916,7 @@ test('does not duplicate options when using numeric values', async () => {
});
test('pasting an existing option does not duplicate it', async () => {
const options = jest.fn(async () => ({
const options = vi.fn(async () => ({
data: [OPTIONS[0]],
totalCount: 1,
}));
@@ -933,7 +933,7 @@ test('pasting an existing option does not duplicate it', async () => {
});
test('pasting an existing option does not duplicate it in multiple mode', async () => {
const options = jest.fn(async () => ({
const options = vi.fn(async () => ({
data: [
{ label: 'John', value: 1 },
{ label: 'Liam', value: 2 },
@@ -983,7 +983,7 @@ test('pasting an non-existent option should not add it if allowNewOptions is fal
});
test('onChange is called with the value property when pasting an option that was not loaded yet', async () => {
const onChange = jest.fn();
const onChange = vi.fn();
render(<AsyncSelect {...defaultProps} onChange={onChange} />);
await open();
const input = getElementByClassName('.ant-select-selection-search-input');
@@ -1003,7 +1003,7 @@ test('onChange is called with the value property when pasting an option that was
});
test('does not fire onChange if the same value is selected in single mode', async () => {
const onChange = jest.fn();
const onChange = vi.fn();
render(<AsyncSelect {...defaultProps} onChange={onChange} />);
const optionText = 'Emma';
await open();

View File

@@ -412,7 +412,7 @@ test('removes a new option if the user does not select it', async () => {
});
test('clear all the values', async () => {
const onClear = jest.fn();
const onClear = vi.fn();
render(
<Select
{...defaultProps}
@@ -493,7 +493,7 @@ test('multiple selections in multiple mode', async () => {
});
test('changes the selected item in single mode', async () => {
const onChange = jest.fn();
const onChange = vi.fn();
render(<Select {...defaultProps} onChange={onChange} />);
await open();
const [firstOption, secondOption] = OPTIONS;
@@ -602,7 +602,7 @@ test('searches for an item', async () => {
});
test('triggers getPopupContainer if passed', async () => {
const getPopupContainer = jest.fn();
const getPopupContainer = vi.fn();
render(<Select {...defaultProps} getPopupContainer={getPopupContainer} />);
await open();
expect(getPopupContainer).toHaveBeenCalled();
@@ -916,7 +916,7 @@ test('"Select all" does not affect disabled options', async () => {
});
test('does not fire onChange when searching but no selection', async () => {
const onChange = jest.fn();
const onChange = vi.fn();
render(
<div role="main">
<Select
@@ -935,7 +935,7 @@ test('does not fire onChange when searching but no selection', async () => {
});
test('fires onChange when clearing the selection in single mode', async () => {
const onChange = jest.fn();
const onChange = vi.fn();
render(
<Select
{...defaultProps}
@@ -949,7 +949,7 @@ test('fires onChange when clearing the selection in single mode', async () => {
});
test('fires onChange when clearing the selection in multiple mode', async () => {
const onChange = jest.fn();
const onChange = vi.fn();
render(
<Select
{...defaultProps}
@@ -963,7 +963,7 @@ test('fires onChange when clearing the selection in multiple mode', async () =>
});
test('fires onChange when pasting a selection', async () => {
const onChange = jest.fn();
const onChange = vi.fn();
render(<Select {...defaultProps} onChange={onChange} />);
await open();
const input = getElementByClassName('.ant-select-selection-search-input');
@@ -1045,7 +1045,7 @@ test('pasting an non-existent option should not add it if allowNewOptions is fal
});
test('does not fire onChange if the same value is selected in single mode', async () => {
const onChange = jest.fn();
const onChange = vi.fn();
render(<Select {...defaultProps} onChange={onChange} />);
const optionText = 'Emma';
await open();
@@ -1058,25 +1058,25 @@ test('does not fire onChange if the same value is selected in single mode', asyn
// Reference for the bug this tests: https://github.com/apache/superset/pull/33043#issuecomment-2809419640
test('typing and deleting the last character for a new option displays correctly', async () => {
jest.useFakeTimers();
vi.useFakeTimers();
render(<Select {...defaultProps} allowNewOptions />);
await open();
await type('aaa', 0, false);
jest.runAllTimers();
vi.runAllTimers();
await type('{backspace}', 0, false);
await type('a', 0, false);
jest.runAllTimers();
vi.runAllTimers();
expect(
screen.queryByText(NO_DATA, { selector: '.ant-empty-description' }),
).not.toBeInTheDocument();
expect(await findSelectOption('aaa')).toBeInTheDocument();
jest.useRealTimers();
vi.useRealTimers();
});
describe('grouped options search', () => {

View File

@@ -21,7 +21,7 @@ import ActionCell, { appendDataToMenu } from './index';
import { exampleMenuOptions, exampleRow } from './fixtures';
test('renders with default props', async () => {
const clickHandler = jest.fn();
const clickHandler = vi.fn();
exampleMenuOptions[0].onClick = clickHandler;
render(<ActionCell menuOptions={exampleMenuOptions} row={exampleRow} />);
// Open the menu

View File

@@ -21,7 +21,7 @@ import ButtonCell from './index';
import { exampleRow } from '../fixtures';
test('renders with default props', async () => {
const clickHandler = jest.fn();
const clickHandler = vi.fn();
const BUTTON_LABEL = 'Button Label';
render(

View File

@@ -45,7 +45,7 @@ afterEach(() => {
test('constructor initializes with correct defaults', () => {
const table = createMockTable();
const setDerivedColumns = jest.fn();
const setDerivedColumns = vi.fn();
const utils = new InteractiveTableUtils(
table,
mockColumns,
@@ -62,7 +62,7 @@ test('constructor initializes with correct defaults', () => {
test('setTableRef updates tableRef', () => {
const table = createMockTable();
const utils = new InteractiveTableUtils(table, mockColumns, jest.fn());
const utils = new InteractiveTableUtils(table, mockColumns, vi.fn());
const newTable = createMockTable();
utils.setTableRef(newTable);
expect(utils.tableRef).toBe(newTable);
@@ -70,14 +70,14 @@ test('setTableRef updates tableRef', () => {
test('getColumnIndex returns -1 when columnRef has no parent', () => {
const table = createMockTable();
const utils = new InteractiveTableUtils(table, mockColumns, jest.fn());
const utils = new InteractiveTableUtils(table, mockColumns, vi.fn());
utils.columnRef = null;
expect(utils.getColumnIndex()).toBe(-1);
});
test('getColumnIndex returns correct index when columnRef is in a row', () => {
const table = createMockTable(3);
const utils = new InteractiveTableUtils(table, mockColumns, jest.fn());
const utils = new InteractiveTableUtils(table, mockColumns, vi.fn());
const row = table.rows[0];
utils.columnRef = row.cells[1] as unknown as typeof utils.columnRef;
expect(utils.getColumnIndex()).toBe(1);
@@ -85,15 +85,15 @@ test('getColumnIndex returns correct index when columnRef is in a row', () => {
test('allowDrop calls preventDefault on the event', () => {
const table = createMockTable();
const utils = new InteractiveTableUtils(table, mockColumns, jest.fn());
const event = { preventDefault: jest.fn() } as unknown as DragEvent;
const utils = new InteractiveTableUtils(table, mockColumns, vi.fn());
const event = { preventDefault: vi.fn() } as unknown as DragEvent;
utils.allowDrop(event);
expect(event.preventDefault).toHaveBeenCalledTimes(1);
});
test('handleMouseup clears mouseDown and resets dragging state', () => {
const table = createMockTable();
const utils = new InteractiveTableUtils(table, mockColumns, jest.fn());
const utils = new InteractiveTableUtils(table, mockColumns, vi.fn());
const th = document.createElement('th') as unknown as typeof utils.columnRef;
utils.columnRef = th;
(th as any).mouseDown = true;
@@ -107,7 +107,7 @@ test('handleMouseup clears mouseDown and resets dragging state', () => {
test('handleMouseup works when columnRef is null', () => {
const table = createMockTable();
const utils = new InteractiveTableUtils(table, mockColumns, jest.fn());
const utils = new InteractiveTableUtils(table, mockColumns, vi.fn());
utils.columnRef = null;
utils.isDragging = true;
@@ -118,7 +118,7 @@ test('handleMouseup works when columnRef is null', () => {
test('handleMouseDown sets mouseDown and oldX when within resize range', () => {
const table = createMockTable();
const utils = new InteractiveTableUtils(table, mockColumns, jest.fn());
const utils = new InteractiveTableUtils(table, mockColumns, vi.fn());
const target = document.createElement('th') as any;
Object.defineProperty(target, 'offsetWidth', {
value: 100,
@@ -141,7 +141,7 @@ test('handleMouseDown sets mouseDown and oldX when within resize range', () => {
test('handleMouseDown sets draggable when outside resize range and reorderable', () => {
const table = createMockTable();
const utils = new InteractiveTableUtils(table, mockColumns, jest.fn());
const utils = new InteractiveTableUtils(table, mockColumns, vi.fn());
utils.reorderable = true;
const target = document.createElement('th') as any;
@@ -163,9 +163,9 @@ test('handleMouseDown sets draggable when outside resize range and reorderable',
test('initializeResizableColumns adds event listeners when resizable is true', () => {
const table = createMockTable(2);
const utils = new InteractiveTableUtils(table, mockColumns, jest.fn());
const utils = new InteractiveTableUtils(table, mockColumns, vi.fn());
const cell = table.rows[0].cells[0];
const addEventSpy = jest.spyOn(cell, 'addEventListener');
const addEventSpy = vi.spyOn(cell, 'addEventListener');
utils.initializeResizableColumns(true, table);
@@ -180,9 +180,9 @@ test('initializeResizableColumns adds event listeners when resizable is true', (
test('initializeResizableColumns removes event listeners when resizable is false', () => {
const table = createMockTable(2);
const utils = new InteractiveTableUtils(table, mockColumns, jest.fn());
const utils = new InteractiveTableUtils(table, mockColumns, vi.fn());
const cell = table.rows[0].cells[0];
const removeEventSpy = jest.spyOn(cell, 'removeEventListener');
const removeEventSpy = vi.spyOn(cell, 'removeEventListener');
utils.initializeResizableColumns(false, table);
@@ -200,9 +200,9 @@ test('initializeResizableColumns removes event listeners when resizable is false
test('initializeDragDropColumns adds event listeners when reorderable is true', () => {
const table = createMockTable(2);
const utils = new InteractiveTableUtils(table, mockColumns, jest.fn());
const utils = new InteractiveTableUtils(table, mockColumns, vi.fn());
const cell = table.rows[0].cells[0];
const addEventSpy = jest.spyOn(cell, 'addEventListener');
const addEventSpy = vi.spyOn(cell, 'addEventListener');
utils.initializeDragDropColumns(true, table);
@@ -216,9 +216,9 @@ test('initializeDragDropColumns adds event listeners when reorderable is true',
test('initializeDragDropColumns removes event listeners when reorderable is false', () => {
const table = createMockTable(2);
const utils = new InteractiveTableUtils(table, mockColumns, jest.fn());
const utils = new InteractiveTableUtils(table, mockColumns, vi.fn());
const cell = table.rows[0].cells[0];
const removeEventSpy = jest.spyOn(cell, 'removeEventListener');
const removeEventSpy = vi.spyOn(cell, 'removeEventListener');
utils.initializeDragDropColumns(false, table);
@@ -232,11 +232,11 @@ test('initializeDragDropColumns removes event listeners when reorderable is fals
test('handleColumnDragStart sets isDragging and calls setData', () => {
const table = createMockTable(2);
const utils = new InteractiveTableUtils(table, mockColumns, jest.fn());
const utils = new InteractiveTableUtils(table, mockColumns, vi.fn());
const row = table.rows[0];
const target = row.cells[0] as any;
const setDataMock = jest.fn();
const setDataMock = vi.fn();
const event = {
currentTarget: target,
dataTransfer: { setData: setDataMock },
@@ -253,7 +253,7 @@ test('handleColumnDragStart sets isDragging and calls setData', () => {
test('handleDragDrop reorders columns when valid drag data exists', () => {
const table = createMockTable(2);
const setDerivedColumns = jest.fn();
const setDerivedColumns = vi.fn();
const utils = new InteractiveTableUtils(
table,
mockColumns,
@@ -268,8 +268,8 @@ test('handleDragDrop reorders columns when valid drag data exists', () => {
const dropTarget = row.cells[1];
const event = {
currentTarget: dropTarget,
dataTransfer: { getData: jest.fn().mockReturnValue(dragData) },
preventDefault: jest.fn(),
dataTransfer: { getData: vi.fn().mockReturnValue(dragData) },
preventDefault: vi.fn(),
} as unknown as DragEvent;
utils.handleDragDrop(event);
@@ -280,7 +280,7 @@ test('handleDragDrop reorders columns when valid drag data exists', () => {
test('handleDragDrop does nothing when no drag data', () => {
const table = createMockTable(2);
const setDerivedColumns = jest.fn();
const setDerivedColumns = vi.fn();
const utils = new InteractiveTableUtils(
table,
mockColumns,
@@ -290,8 +290,8 @@ test('handleDragDrop does nothing when no drag data', () => {
const row = table.rows[0];
const event = {
currentTarget: row.cells[0],
dataTransfer: { getData: jest.fn().mockReturnValue('') },
preventDefault: jest.fn(),
dataTransfer: { getData: vi.fn().mockReturnValue('') },
preventDefault: vi.fn(),
} as unknown as DragEvent;
utils.handleDragDrop(event);
@@ -302,7 +302,7 @@ test('handleDragDrop does nothing when no drag data', () => {
test('handleMouseMove updates cursor to col-resize when within resize range', () => {
const table = createMockTable(2);
const utils = new InteractiveTableUtils(table, mockColumns, jest.fn());
const utils = new InteractiveTableUtils(table, mockColumns, vi.fn());
utils.resizable = true;
const target = document.createElement('th') as any;
@@ -325,7 +325,7 @@ test('handleMouseMove updates cursor to col-resize when within resize range', ()
test('handleMouseMove sets default cursor when outside resize range', () => {
const table = createMockTable(2);
const utils = new InteractiveTableUtils(table, mockColumns, jest.fn());
const utils = new InteractiveTableUtils(table, mockColumns, vi.fn());
utils.resizable = true;
const target = document.createElement('th') as any;
@@ -348,7 +348,7 @@ test('handleMouseMove sets default cursor when outside resize range', () => {
test('handleMouseMove resizes column when mouseDown and within bounds', () => {
const table = createMockTable(2);
const setDerivedColumns = jest.fn();
const setDerivedColumns = vi.fn();
const utils = new InteractiveTableUtils(
table,
mockColumns,
@@ -384,7 +384,7 @@ test('handleMouseMove resizes column when mouseDown and within bounds', () => {
test('handleMouseMove skips resize when not resizable', () => {
const table = createMockTable(2);
const setDerivedColumns = jest.fn();
const setDerivedColumns = vi.fn();
const utils = new InteractiveTableUtils(
table,
mockColumns,
@@ -406,7 +406,7 @@ test('handleMouseMove skips resize when not resizable', () => {
test('handleMouseMove handles negative diff by keeping original width', () => {
const table = createMockTable(2);
const setDerivedColumns = jest.fn();
const setDerivedColumns = vi.fn();
const utils = new InteractiveTableUtils(
table,
mockColumns,
@@ -442,11 +442,11 @@ test('handleMouseMove handles negative diff by keeping original width', () => {
test('handleColumnDragStart does not set columnRef when currentTarget is null (line 82 false)', () => {
const table = createMockTable(2);
const utils = new InteractiveTableUtils(table, mockColumns, jest.fn());
const utils = new InteractiveTableUtils(table, mockColumns, vi.fn());
const event = {
currentTarget: null,
dataTransfer: { setData: jest.fn() },
dataTransfer: { setData: vi.fn() },
} as unknown as DragEvent;
utils.handleColumnDragStart(event);
@@ -457,7 +457,7 @@ test('handleColumnDragStart does not set columnRef when currentTarget is null (l
test('handleMouseDown does nothing when currentTarget is null (line 118 false)', () => {
const table = createMockTable();
const utils = new InteractiveTableUtils(table, mockColumns, jest.fn());
const utils = new InteractiveTableUtils(table, mockColumns, vi.fn());
const event = {
currentTarget: null,
@@ -472,7 +472,7 @@ test('handleMouseDown does nothing when currentTarget is null (line 118 false)',
test('handleMouseDown does nothing to draggable when outside resize range and not reorderable (line 132 false)', () => {
const table = createMockTable();
const utils = new InteractiveTableUtils(table, mockColumns, jest.fn());
const utils = new InteractiveTableUtils(table, mockColumns, vi.fn());
utils.reorderable = false;
const target = document.createElement('th') as any;
@@ -494,7 +494,7 @@ test('handleMouseDown does nothing to draggable when outside resize range and no
test('handleMouseMove skips column update when getColumnIndex returns NaN (line 162 false)', () => {
const table = createMockTable(2);
const setDerivedColumns = jest.fn();
const setDerivedColumns = vi.fn();
const utils = new InteractiveTableUtils(
table,
mockColumns,
@@ -509,7 +509,7 @@ test('handleMouseMove skips column update when getColumnIndex returns NaN (line
col.oldX = 50;
utils.columnRef = col;
jest.spyOn(utils, 'getColumnIndex').mockReturnValueOnce(NaN);
vi.spyOn(utils, 'getColumnIndex').mockReturnValueOnce(NaN);
const target = document.createElement('th') as any;
Object.defineProperty(target, 'offsetWidth', {
@@ -531,7 +531,7 @@ test('handleMouseMove skips column update when getColumnIndex returns NaN (line
test('initializeResizableColumns does nothing when table is null (lines 182-187 false)', () => {
const table = createMockTable();
const utils = new InteractiveTableUtils(table, mockColumns, jest.fn());
const utils = new InteractiveTableUtils(table, mockColumns, vi.fn());
expect(() => utils.initializeResizableColumns(true, null)).not.toThrow();
expect(utils.tableRef).toBeNull();
@@ -539,7 +539,7 @@ test('initializeResizableColumns does nothing when table is null (lines 182-187
test('initializeResizableColumns uses default resizable=false when first arg is undefined (line 182 default branch)', () => {
const table = createMockTable(2);
const utils = new InteractiveTableUtils(table, mockColumns, jest.fn());
const utils = new InteractiveTableUtils(table, mockColumns, vi.fn());
utils.initializeResizableColumns(undefined, table);
@@ -548,7 +548,7 @@ test('initializeResizableColumns uses default resizable=false when first arg is
test('initializeDragDropColumns does nothing when table is null (lines 206-211 false)', () => {
const table = createMockTable();
const utils = new InteractiveTableUtils(table, mockColumns, jest.fn());
const utils = new InteractiveTableUtils(table, mockColumns, vi.fn());
expect(() => utils.initializeDragDropColumns(true, null)).not.toThrow();
expect(utils.tableRef).toBeNull();
@@ -556,7 +556,7 @@ test('initializeDragDropColumns does nothing when table is null (lines 206-211 f
test('initializeDragDropColumns uses default reorderable=false when first arg is undefined (line 206 default branch)', () => {
const table = createMockTable(2);
const utils = new InteractiveTableUtils(table, mockColumns, jest.fn());
const utils = new InteractiveTableUtils(table, mockColumns, vi.fn());
utils.initializeDragDropColumns(undefined, table);
@@ -565,8 +565,8 @@ test('initializeDragDropColumns uses default reorderable=false when first arg is
test('clearListeners removes document mouseup listener', () => {
const table = createMockTable();
const utils = new InteractiveTableUtils(table, mockColumns, jest.fn());
const removeEventSpy = jest.spyOn(document, 'removeEventListener');
const utils = new InteractiveTableUtils(table, mockColumns, vi.fn());
const removeEventSpy = vi.spyOn(document, 'removeEventListener');
utils.clearListeners();

View File

@@ -70,8 +70,8 @@ beforeEach(() => {
columns: tableHook.columns,
loading: false,
highlightRowId: 1,
getTableProps: jest.fn(),
getTableBodyProps: jest.fn(),
getTableProps: vi.fn(),
getTableBodyProps: vi.fn(),
sticky: false,
};
});
@@ -116,7 +116,7 @@ test('Pagination controls should be rendered when pageSize is provided', () => {
pageSize: 2,
totalCount: 3,
pageIndex: 0,
onPageChange: jest.fn(),
onPageChange: vi.fn(),
};
render(<TableCollection {...paginationProps} />);
@@ -124,7 +124,7 @@ test('Pagination controls should be rendered when pageSize is provided', () => {
});
test('Pagination should call onPageChange when page is changed', async () => {
const onPageChange = jest.fn();
const onPageChange = vi.fn();
const paginationProps = {
...defaultProps,
pageSize: 2,
@@ -147,7 +147,7 @@ test('Pagination should call onPageChange when page is changed', async () => {
});
test('Pagination callback should be stable across re-renders', () => {
const onPageChange = jest.fn();
const onPageChange = vi.fn();
const paginationProps = {
...defaultProps,
pageSize: 2,
@@ -171,7 +171,7 @@ test('Should display correct page info when showRowCount is true', () => {
pageSize: 2,
totalCount: 3,
pageIndex: 0,
onPageChange: jest.fn(),
onPageChange: vi.fn(),
showRowCount: true,
};
render(<TableCollection {...paginationProps} />);
@@ -186,7 +186,7 @@ test('Should not display page info when showRowCount is false', () => {
pageSize: 2,
totalCount: 3,
pageIndex: 0,
onPageChange: jest.fn(),
onPageChange: vi.fn(),
showRowCount: false,
};
render(<TableCollection {...paginationProps} />);
@@ -196,8 +196,8 @@ test('Should not display page info when showRowCount is false', () => {
});
test('Bulk selection should work with pagination', () => {
const toggleRowSelected = jest.fn();
const toggleAllRowsSelected = jest.fn();
const toggleRowSelected = vi.fn();
const toggleAllRowsSelected = vi.fn();
const selectionProps = {
...defaultProps,
bulkSelectEnabled: true,
@@ -207,7 +207,7 @@ test('Bulk selection should work with pagination', () => {
pageSize: 2,
totalCount: 3,
pageIndex: 0,
onPageChange: jest.fn(),
onPageChange: vi.fn(),
};
render(<TableCollection {...selectionProps} />);
@@ -217,7 +217,7 @@ test('Bulk selection should work with pagination', () => {
});
test('should call setSortBy when clicking sortable column header', () => {
const setSortBy = jest.fn();
const setSortBy = vi.fn();
const sortingProps = {
...defaultProps,
setSortBy,

View File

@@ -229,7 +229,7 @@ test('should render the right wrap content text by columnsForWrapText', () => {
});
test('should handle server-side pagination', async () => {
const onServerPagination = jest.fn();
const onServerPagination = vi.fn();
const serverPaginationProps = {
...mockedProps,
serverPagination: true,
@@ -251,7 +251,7 @@ test('should handle server-side pagination', async () => {
});
test('should handle server-side sorting', async () => {
const onServerPagination = jest.fn();
const onServerPagination = vi.fn();
const serverPaginationProps = {
...mockedProps,
serverPagination: true,
@@ -271,7 +271,7 @@ test('should handle server-side sorting', async () => {
});
test('pagination callbacks should be stable across re-renders', () => {
const onServerPagination = jest.fn();
const onServerPagination = vi.fn();
const serverPaginationProps = {
...mockedProps,
serverPagination: true,
@@ -290,9 +290,7 @@ test('pagination callbacks should be stable across re-renders', () => {
});
test('should scroll to top when scrollTopOnPagination is true', async () => {
const scrollToSpy = jest
.spyOn(window, 'scrollTo')
.mockImplementation(() => {});
const scrollToSpy = vi.spyOn(window, 'scrollTo').mockImplementation(() => {});
const scrollProps = {
...mockedProps,
@@ -313,9 +311,7 @@ test('should scroll to top when scrollTopOnPagination is true', async () => {
});
test('should NOT scroll to top when scrollTopOnPagination is false', async () => {
const scrollToSpy = jest
.spyOn(window, 'scrollTo')
.mockImplementation(() => {});
const scrollToSpy = vi.spyOn(window, 'scrollTo').mockImplementation(() => {});
const scrollProps = {
...mockedProps,

View File

@@ -108,7 +108,7 @@ describe('Tabs', () => {
});
test('should handle tab change events', () => {
const onChangeMock = jest.fn();
const onChangeMock = vi.fn();
const { getByText } = render(
<Tabs items={defaultItems} onChange={onChangeMock} />,
);
@@ -119,7 +119,7 @@ describe('Tabs', () => {
});
test('should pass through additional props to Antd Tabs', () => {
const onTabClickMock = jest.fn();
const onTabClickMock = vi.fn();
const { getByText } = render(
<Tabs
items={defaultItems}
@@ -146,7 +146,7 @@ describe('Tabs', () => {
});
test('should handle onEdit callback for add/remove actions', () => {
const onEditMock = jest.fn();
const onEditMock = vi.fn();
const itemsWithRemove = defaultItems.map(item => ({
...item,
closable: true,

View File

@@ -22,16 +22,17 @@ import { createRef } from 'react';
import { ThemeProvider, supersetTheme } from '@apache-superset/core/theme';
import * as uiModule from '@apache-superset/core/theme';
import { ThemedAgGridReact } from './index';
import { Mock } from 'vitest';
// Mock useThemeMode hook
jest.mock('@apache-superset/core/theme', () => ({
...jest.requireActual('@apache-superset/core/theme'),
useThemeMode: jest.fn(() => false), // Default to light mode
vi.mock('@apache-superset/core/theme', async (importActual) => ({
...(await importActual()),
useThemeMode: vi.fn(() => false), // Default to light mode
}));
// Mock ag-grid-react to avoid complex setup
jest.mock('ag-grid-react', () => ({
AgGridReact: jest.fn(({ theme, ...props }) => (
vi.mock('ag-grid-react', () => ({
AgGridReact: vi.fn(({ theme, ...props }) => (
<div
data-test="ag-grid-react"
data-theme={JSON.stringify(theme)}
@@ -43,16 +44,16 @@ jest.mock('ag-grid-react', () => ({
}));
// Mock ag-grid-community
jest.mock('ag-grid-community', () => ({
vi.mock('ag-grid-community', () => ({
themeQuartz: {
withPart: jest.fn().mockReturnThis(),
withParams: jest.fn(params => ({ ...params, _type: 'theme' })),
withPart: vi.fn().mockReturnThis(),
withParams: vi.fn(params => ({ ...params, _type: 'theme' })),
},
colorSchemeDark: { _type: 'dark' },
colorSchemeLight: { _type: 'light' },
AllCommunityModule: {},
ClientSideRowModelModule: {},
ModuleRegistry: { registerModules: jest.fn() },
ModuleRegistry: { registerModules: vi.fn() },
}));
const mockRowData = [
@@ -66,9 +67,9 @@ const mockColumnDefs = [
];
beforeEach(() => {
jest.clearAllMocks();
vi.clearAllMocks();
// Reset to light mode by default
(uiModule.useThemeMode as jest.Mock).mockReturnValue(false);
(uiModule.useThemeMode as Mock).mockReturnValue(false);
});
test('renders the AgGridReact component', () => {
@@ -101,7 +102,7 @@ test('applies light theme when background is light', () => {
test('applies dark theme when background is dark', () => {
// Mock dark mode
(uiModule.useThemeMode as jest.Mock).mockReturnValue(true);
(uiModule.useThemeMode as Mock).mockReturnValue(true);
const darkTheme = {
...supersetTheme,
@@ -144,8 +145,8 @@ test('forwards ref to AgGridReact', () => {
});
test('passes all props through to AgGridReact', () => {
const onGridReady = jest.fn();
const onCellClicked = jest.fn();
const onGridReady = vi.fn();
const onCellClicked = vi.fn();
render(
<ThemedAgGridReact

View File

@@ -18,10 +18,11 @@
*/
import { ModuleRegistry } from 'ag-grid-community';
import { setupAGGridModules, defaultModules } from './setupAGGridModules';
import { Mock } from 'vitest';
jest.mock('ag-grid-community', () => ({
vi.mock('ag-grid-community', () => ({
ModuleRegistry: {
registerModules: jest.fn(),
registerModules: vi.fn(),
},
ColumnAutoSizeModule: {
moduleName: 'ColumnAutoSizeModule',
@@ -52,7 +53,7 @@ jest.mock('ag-grid-community', () => ({
}));
beforeEach(() => {
jest.clearAllMocks();
vi.clearAllMocks();
});
test('defaultModules exports an array of AG Grid modules', () => {
@@ -88,7 +89,7 @@ test('setupAGGridModules registers default + additional modules when provided',
expect(ModuleRegistry.registerModules).toHaveBeenCalledTimes(1);
const registeredModules = (ModuleRegistry.registerModules as jest.Mock).mock
const registeredModules = (ModuleRegistry.registerModules as Mock).mock
.calls[0][0];
// Should contain all default modules

View File

@@ -17,6 +17,7 @@
* under the License.
*/
import { render, waitFor } from '@superset-ui/core/spec';
// import { render, waitFor } from '@testing-library/react';
import { Timer, TimerProps } from '.';
import { now } from '../../utils/dates';

View File

@@ -47,11 +47,11 @@ const mockTimezones = [
];
beforeAll(() => {
global.Intl.supportedValuesOf = jest.fn(() => mockTimezones);
global.Intl.supportedValuesOf = vi.fn(() => mockTimezones);
});
afterAll(() => {
jest.restoreAllMocks();
vi.restoreAllMocks();
});
test('initializes with empty cache', () => {
@@ -229,7 +229,7 @@ test('allows retry after failed computation', async () => {
});
test('uses queueMicrotask when available', async () => {
const queueMicrotaskSpy = jest.spyOn(global, 'queueMicrotask');
const queueMicrotaskSpy = vi.spyOn(global, 'queueMicrotask');
const cache = new TimezoneOptionsCache(mockGetOffsetKey, mockOffsetsToName);
await cache.getOptionsAsync();
@@ -244,7 +244,7 @@ test('falls back to setTimeout when queueMicrotask is not available', async () =
// @ts-expect-error - temporarily remove queueMicrotask for testing
delete global.queueMicrotask;
const setTimeoutSpy = jest.spyOn(global, 'setTimeout');
const setTimeoutSpy = vi.spyOn(global, 'setTimeout');
const cache = new TimezoneOptionsCache(mockGetOffsetKey, mockOffsetsToName);
await cache.getOptionsAsync();

View File

@@ -24,8 +24,8 @@ import type { TimezoneSelectorProps } from './index';
const loadComponent = (mockCurrentTime?: string) => {
if (mockCurrentTime) {
jest.useFakeTimers();
jest.setSystemTime(new Date(mockCurrentTime));
vi.useFakeTimers();
vi.setSystemTime(new Date(mockCurrentTime));
}
return new Promise<FC<TimezoneSelectorProps>>(resolve => {
const { default: TimezoneSelector } = module.require('./index');
@@ -34,12 +34,12 @@ const loadComponent = (mockCurrentTime?: string) => {
};
afterEach(() => {
jest.useRealTimers();
vi.useRealTimers();
});
test('render timezones in correct order for daylight saving time', async () => {
const TimezoneSelector = await loadComponent('2022-07-01');
const onTimezoneChange = jest.fn();
const onTimezoneChange = vi.fn();
render(
<TimezoneSelector
onTimezoneChange={onTimezoneChange}

View File

@@ -24,12 +24,13 @@ import type { TimezoneSelectorProps } from './index';
const loadComponent = (mockCurrentTime?: string) => {
if (mockCurrentTime) {
jest.useFakeTimers();
jest.setSystemTime(new Date(mockCurrentTime));
vi.useFakeTimers();
vi.setSystemTime(new Date(mockCurrentTime));
}
return new Promise<FC<TimezoneSelectorProps>>(resolve => {
const { default: TimezoneSelector } = module.require('./index');
resolve(TimezoneSelector);
import('./index').then(({ default: TimezoneSelector }) => {
resolve(TimezoneSelector);
});
});
};
@@ -41,15 +42,15 @@ const openSelectMenu = () => {
userEvent.click(searchInput);
};
jest.spyOn(extendedDayjs.tz, 'guess').mockReturnValue('America/New_York');
vi.spyOn(extendedDayjs.tz, 'guess').mockReturnValue('America/New_York');
afterEach(() => {
jest.useRealTimers();
vi.useRealTimers();
});
test('use the timezone from `dayjs` if no timezone provided', async () => {
const TimezoneSelector = await loadComponent('2022-01-01');
const onTimezoneChange = jest.fn();
const onTimezoneChange = vi.fn();
render(<TimezoneSelector onTimezoneChange={onTimezoneChange} />);
// Wait for async loading and default timezone to be set
await screen.findByText('GMT -05:00 (Eastern Standard Time)');
@@ -58,7 +59,7 @@ test('use the timezone from `dayjs` if no timezone provided', async () => {
test('update to closest deduped timezone when timezone is provided', async () => {
const TimezoneSelector = await loadComponent('2022-01-01');
const onTimezoneChange = jest.fn();
const onTimezoneChange = vi.fn();
render(
<TimezoneSelector
onTimezoneChange={onTimezoneChange}
@@ -77,7 +78,7 @@ test('update to closest deduped timezone when timezone is provided', async () =>
test('use the default timezone when an invalid timezone is provided', async () => {
const TimezoneSelector = await loadComponent('2022-01-01');
const onTimezoneChange = jest.fn();
const onTimezoneChange = vi.fn();
render(
<TimezoneSelector onTimezoneChange={onTimezoneChange} timezone="UTC" />,
);
@@ -93,7 +94,7 @@ test('use the default timezone when an invalid timezone is provided', async () =
test('render timezones in correct order for standard time', async () => {
const TimezoneSelector = await loadComponent('2022-01-01');
const onTimezoneChange = jest.fn();
const onTimezoneChange = vi.fn();
render(
<TimezoneSelector
onTimezoneChange={onTimezoneChange}
@@ -111,7 +112,7 @@ test('render timezones in correct order for standard time', async () => {
test('can select a timezone values and returns canonical timezone name', async () => {
const TimezoneSelector = await loadComponent('2022-01-01');
const onTimezoneChange = jest.fn();
const onTimezoneChange = vi.fn();
render(
<TimezoneSelector
onTimezoneChange={onTimezoneChange}
@@ -134,7 +135,7 @@ test('can select a timezone values and returns canonical timezone name', async (
test('can update props and rerender with different values', async () => {
const TimezoneSelector = await loadComponent('2022-01-01');
const onTimezoneChange = jest.fn();
const onTimezoneChange = vi.fn();
const { rerender } = render(
<TimezoneSelector
onTimezoneChange={onTimezoneChange}

View File

@@ -46,9 +46,9 @@ test('should render the UnsavedChangesModal component if showModal is true', asy
});
test('should only call onConfirmNavigation when clicking the Discard button', async () => {
const mockOnHide = jest.fn();
const mockHandleSave = jest.fn();
const mockOnConfirmNavigation = jest.fn();
const mockOnHide = vi.fn();
const mockHandleSave = vi.fn();
const mockOnConfirmNavigation = vi.fn();
render(
<UnsavedChangesModal
@@ -71,9 +71,9 @@ test('should only call onConfirmNavigation when clicking the Discard button', as
});
test('should only call handleSave when clicking the Save button', async () => {
const mockOnHide = jest.fn();
const mockHandleSave = jest.fn();
const mockOnConfirmNavigation = jest.fn();
const mockOnHide = vi.fn();
const mockHandleSave = vi.fn();
const mockOnConfirmNavigation = vi.fn();
render(
<UnsavedChangesModal

View File

@@ -21,7 +21,7 @@ import { Button, Upload } from '..';
describe('Upload Component', () => {
test('renders upload button and triggers file upload', async () => {
const handleChange = jest.fn();
const handleChange = vi.fn();
render(
<Upload onChange={handleChange}>

View File

@@ -20,7 +20,7 @@ import { renderHook } from '@testing-library/react-hooks';
import { useChangeEffect } from './useChangeEffect';
test('call callback the first time with undefined and value', () => {
const callback = jest.fn();
const callback = vi.fn();
renderHook(props => useChangeEffect(props.value, props.callback), {
initialProps: { value: 'value', callback },
});
@@ -29,7 +29,7 @@ test('call callback the first time with undefined and value', () => {
});
test('do not call callback 2 times if the value do not change', () => {
const callback = jest.fn();
const callback = vi.fn();
const hook = renderHook(
props => useChangeEffect(props.value, props.callback),
{
@@ -41,7 +41,7 @@ test('do not call callback 2 times if the value do not change', () => {
});
test('call callback whenever the value changes', () => {
const callback = jest.fn();
const callback = vi.fn();
const hook = renderHook(
props => useChangeEffect(props.value, props.callback),
{

View File

@@ -20,7 +20,7 @@ import { renderHook } from '@testing-library/react-hooks';
import { useComponentDidMount } from './useComponentDidMount';
test('the effect should only be executed on the first render', () => {
const effect = jest.fn();
const effect = vi.fn();
const hook = renderHook(() => useComponentDidMount(effect));
expect(effect).toHaveBeenCalledTimes(1);
hook.rerender();

View File

@@ -20,12 +20,12 @@ import { renderHook } from '@testing-library/react-hooks';
import { useComponentDidUpdate } from './useComponentDidUpdate';
test('the effect should not be executed on the first render', () => {
const effect = jest.fn();
const effect = vi.fn();
const hook = renderHook(props => useComponentDidUpdate(props.effect), {
initialProps: { effect },
});
expect(effect).toHaveBeenCalledTimes(0);
const changedEffect = jest.fn();
const changedEffect = vi.fn();
hook.rerender({ effect: changedEffect });
expect(changedEffect).toHaveBeenCalledTimes(1);
});

View File

@@ -19,9 +19,11 @@
import { renderHook } from '@testing-library/react-hooks';
import { useElementOnScreen } from './useElementOnScreen';
const observeMock = jest.fn();
const unobserveMock = jest.fn();
const IntersectionObserverMock = jest.fn();
vi.mock('react', { spy: true });
const observeMock = vi.fn();
const unobserveMock = vi.fn();
const IntersectionObserverMock = vi.fn();
IntersectionObserverMock.prototype.observe = observeMock;
IntersectionObserverMock.prototype.unobserve = unobserveMock;
@@ -31,7 +33,7 @@ beforeEach(() => {
afterEach(() => {
IntersectionObserverMock.mockClear();
jest.clearAllMocks();
vi.clearAllMocks();
});
test('should return null and false on first render', () => {
@@ -66,7 +68,7 @@ test('should return isSticky as false when intersectionRatio >= 1', async () =>
});
test('should observe and unobserve element with IntersectionObserver', async () => {
jest.spyOn(global.React, 'useRef').mockReturnValue({ current: 'test' });
vi.spyOn(global.React, 'useRef').mockReturnValue({ current: 'test' });
const options = { threshold: 0.5 };
const { result, unmount } = renderHook(() => useElementOnScreen(options));
const [elementRef] = result.current;
@@ -85,7 +87,7 @@ test('should observe and unobserve element with IntersectionObserver', async ()
});
test('should not observe an element if it is null', () => {
jest.spyOn(global.React, 'useRef').mockReturnValue({ current: null });
vi.spyOn(global.React, 'useRef').mockReturnValue({ current: null });
const options = {};
const { result } = renderHook(() => useElementOnScreen(options));
const [ref, isSticky] = result.current;
@@ -96,7 +98,7 @@ test('should not observe an element if it is null', () => {
});
test('should not unobserve the element if it is null', () => {
jest.spyOn(global.React, 'useRef').mockReturnValue({ current: null });
vi.spyOn(global.React, 'useRef').mockReturnValue({ current: null });
const options = {};
const { result, unmount } = renderHook(() => useElementOnScreen(options));
const [ref, isSticky] = result.current;

View File

@@ -20,7 +20,7 @@ import { renderHook } from '@testing-library/react-hooks';
import useCSSTextTruncation from './useCSSTextTruncation';
afterEach(() => {
jest.clearAllMocks();
vi.clearAllMocks();
});
test('should be false by default', () => {
@@ -36,7 +36,7 @@ test('should not truncate', () => {
const ref = { current: document.createElement('p') };
Object.defineProperty(ref.current, 'offsetWidth', { get: () => 100 });
Object.defineProperty(ref.current, 'scrollWidth', { get: () => 50 });
jest.spyOn(global.React, 'useRef').mockReturnValue({ current: ref.current });
vi.spyOn(global.React, 'useRef').mockReturnValue({ current: ref.current });
const { result } = renderHook(() =>
useCSSTextTruncation<HTMLParagraphElement>(),
@@ -50,7 +50,7 @@ test('should truncate', () => {
const ref = { current: document.createElement('p') };
Object.defineProperty(ref.current, 'offsetWidth', { get: () => 50 });
Object.defineProperty(ref.current, 'scrollWidth', { get: () => 100 });
jest.spyOn(global.React, 'useRef').mockReturnValue({ current: ref.current });
vi.spyOn(global.React, 'useRef').mockReturnValue({ current: ref.current });
const { result } = renderHook(() =>
useCSSTextTruncation<HTMLParagraphElement>(),
@@ -64,7 +64,7 @@ test('should not truncate with vertical orientation', () => {
const ref = { current: document.createElement('p') };
Object.defineProperty(ref.current, 'offsetHeight', { get: () => 100 });
Object.defineProperty(ref.current, 'scrollHeight', { get: () => 50 });
jest.spyOn(global.React, 'useRef').mockReturnValue({ current: ref.current });
vi.spyOn(global.React, 'useRef').mockReturnValue({ current: ref.current });
const { result } = renderHook(() =>
useCSSTextTruncation<HTMLParagraphElement>({
@@ -81,7 +81,7 @@ test('should truncate with vertical orientation', () => {
const ref = { current: document.createElement('p') };
Object.defineProperty(ref.current, 'offsetHeight', { get: () => 50 });
Object.defineProperty(ref.current, 'scrollHeight', { get: () => 100 });
jest.spyOn(global.React, 'useRef').mockReturnValue({ current: ref.current });
vi.spyOn(global.React, 'useRef').mockReturnValue({ current: ref.current });
const { result } = renderHook(() =>
useCSSTextTruncation<HTMLParagraphElement>({

View File

@@ -19,9 +19,10 @@
import { renderHook } from '@testing-library/react-hooks';
import { RefObject } from 'react';
import useChildElementTruncation from './useChildElementTruncation';
import { Mock } from 'vitest';
let observeMock: jest.Mock;
let disconnectMock: jest.Mock;
let observeMock: Mock;
let disconnectMock: Mock;
let originalResizeObserver: typeof ResizeObserver;
const genElements = (
@@ -79,12 +80,14 @@ beforeAll(() => {
originalResizeObserver = window.ResizeObserver;
// Mock ResizeObserver
observeMock = jest.fn();
disconnectMock = jest.fn();
window.ResizeObserver = jest.fn(() => ({
observe: observeMock,
disconnect: disconnectMock,
})) as unknown as typeof ResizeObserver;
observeMock = vi.fn();
disconnectMock = vi.fn();
window.ResizeObserver = vi.fn(function () {
return {
observe: observeMock,
disconnect: disconnectMock,
};
} as unknown as typeof window.ResizeObserver);
});
afterAll(() => {

View File

@@ -19,7 +19,7 @@
import userEvent from '@testing-library/user-event';
import { ReactElement } from 'react';
import { render, RenderOptions } from '@testing-library/react';
import '@testing-library/jest-dom';
import '@testing-library/jest-dom/vitest';
import { themeObject } from '@apache-superset/core/theme';
// Define the wrapper component outside

View File

@@ -32,7 +32,7 @@ test('withLabel prepends label to validator error message', () => {
});
test('withLabel passes value and state to underlying validator', () => {
const validator = jest.fn(() => false as false);
const validator = vi.fn(() => false as false);
const labeled = withLabel(validator, 'Field');
labeled('value', { someState: true });
expect(validator).toHaveBeenCalledWith('value', { someState: true });

View File

@@ -21,15 +21,15 @@ import { triggerResizeObserver } from 'resize-observer-polyfill';
import { promiseTimeout, WithLegend } from '@superset-ui/core';
import { render } from '@testing-library/react';
let renderChart = jest.fn();
let renderLegend = jest.fn();
let renderChart = vi.fn();
let renderLegend = vi.fn();
// TODO: rewrite to rtl
/* oxlint-disable-next-line jest/no-disabled-tests */
describe.skip('WithLegend', () => {
beforeEach(() => {
renderChart = jest.fn(() => <div className="chart" />);
renderLegend = jest.fn(() => <div className="legend" />);
renderChart = vi.fn(() => <div className="chart" />);
renderLegend = vi.fn(() => <div className="legend" />);
});
test('sets className', () => {

View File

@@ -18,23 +18,11 @@
*/
import '@testing-library/jest-dom';
import { render, screen, act } from '@testing-library/react';
import ChartClient from '../../../src/chart/clients/ChartClient';
import ChartDataProvider, {
ChartDataProviderProps,
} from '../../../src/chart/components/ChartDataProvider';
import { bigNumberFormData } from '../fixtures/formData';
// Keep existing mock setup
const defaultMockLoadFormData = jest.fn(({ formData }: { formData: unknown }) =>
Promise.resolve(formData),
);
type MockLoadFormData =
| typeof defaultMockLoadFormData
| jest.Mock<Promise<unknown>, unknown[]>;
let mockLoadFormData: MockLoadFormData = defaultMockLoadFormData;
function createPromise<T>(input: T) {
return Promise.resolve(input);
}
@@ -43,24 +31,34 @@ function createArrayPromise<T>(input: T) {
return Promise.resolve([input]);
}
const mockLoadDatasource = jest.fn<Promise<unknown>, unknown[]>(createPromise);
const mockLoadQueryData = jest.fn<Promise<unknown>, unknown[]>(
createArrayPromise,
const { mockLoadDatasource, mockLoadQueryData, mockLoadFormData } = vi.hoisted(
() => ({
mockLoadDatasource: vi.fn().mockImplementation(createPromise),
mockLoadQueryData: vi.fn().mockImplementation(createArrayPromise),
mockLoadFormData: vi.fn(({ formData }: { formData: unknown }) =>
Promise.resolve(formData),
),
}),
);
const actual = jest.requireActual('../../../src/chart/clients/ChartClient');
jest.spyOn(actual, 'default').mockImplementation(() => ({
loadDatasource: mockLoadDatasource,
loadFormData: mockLoadFormData,
loadQueryData: mockLoadQueryData,
}));
const ChartClientMock = ChartClient as jest.Mock<ChartClient>;
vi.mock('../../../src/chart/clients/ChartClient', async importActual => {
const actual = (await importActual()) as Record<any, any>;
return {
...actual,
default: function () {
return {
...actual.default,
loadDatasource: mockLoadDatasource,
loadFormData: mockLoadFormData,
loadQueryData: mockLoadQueryData,
};
},
};
});
describe('ChartDataProvider', () => {
beforeEach(() => {
ChartClientMock.mockClear();
mockLoadFormData = defaultMockLoadFormData;
mockLoadFormData.mockClear();
mockLoadFormData.mockClear();
mockLoadDatasource.mockClear();
mockLoadQueryData.mockClear();
@@ -81,11 +79,6 @@ describe('ChartDataProvider', () => {
return render(<ChartDataProvider {...props} {...overrideProps} />);
}
test('instantiates a new ChartClient()', () => {
setup();
expect(ChartClientMock).toHaveBeenCalledTimes(1);
});
describe('ChartClient.loadFormData', () => {
test('calls method on mount', () => {
setup();
@@ -100,7 +93,7 @@ describe('ChartDataProvider', () => {
const options = { host: 'override' };
setup({ formDataRequestOptions: options });
expect(mockLoadFormData).toHaveBeenCalledTimes(1);
expect(mockLoadFormData.mock.calls[0][1]).toEqual(options);
expect((mockLoadFormData.mock.calls[0] as any[])[1]).toEqual(options);
});
test('calls ChartClient.loadFormData when formData or sliceId change', async () => {
@@ -277,7 +270,7 @@ describe('ChartDataProvider', () => {
describe('callbacks', () => {
test('calls onLoaded when loaded', async () => {
const onLoaded = jest.fn();
const onLoaded = vi.fn();
mockLoadFormData.mockResolvedValue(props.formData);
mockLoadQueryData.mockResolvedValue([props.formData]);
mockLoadDatasource.mockResolvedValue(props.formData.datasource);
@@ -297,7 +290,7 @@ describe('ChartDataProvider', () => {
});
test('calls onError upon request error', async () => {
const onError = jest.fn();
const onError = vi.fn();
mockLoadFormData.mockRejectedValue(new Error('error'));
setup({ onError });
@@ -311,7 +304,7 @@ describe('ChartDataProvider', () => {
});
test('calls onError upon JS error', async () => {
const onError = jest.fn();
const onError = vi.fn();
mockLoadFormData.mockImplementation(() => {
throw new Error('non-async error');
});

View File

@@ -19,7 +19,6 @@
import '@testing-library/jest-dom';
import { render, screen } from '@superset-ui/core/spec';
import mockConsole, { RestoreConsole } from 'jest-mock-console';
import { triggerResizeObserver } from 'resize-observer-polyfill';
import { ErrorBoundary } from 'react-error-boundary';
@@ -34,18 +33,19 @@ import {
import { isMatrixifyEnabled } from '../../../src/chart/types/matrixify';
import MatrixifyGridRenderer from '../../../src/chart/components/Matrixify/MatrixifyGridRenderer';
import { Mock } from 'vitest';
// Mock Matrixify imports
jest.mock('../../../src/chart/types/matrixify', () => ({
isMatrixifyEnabled: jest.fn(() => false),
getMatrixifyConfig: jest.fn(() => null),
vi.mock('../../../src/chart/types/matrixify', () => ({
isMatrixifyEnabled: vi.fn(() => false),
getMatrixifyConfig: vi.fn(() => null),
}));
jest.mock(
vi.mock(
'../../../src/chart/components/Matrixify/MatrixifyGridRenderer',
() => ({
__esModule: true,
default: jest.fn(() => null),
default: vi.fn(() => null),
}),
);
@@ -63,9 +63,7 @@ function getDimensionText(container: HTMLElement) {
}
describe('SuperChart', () => {
jest.setTimeout(5000);
let restoreConsole: RestoreConsole;
vi.setConfig({ testTimeout: 5000 });
const plugins = [
new DiligentChartPlugin().configure({ key: ChartKeys.DILIGENT }),
@@ -78,15 +76,6 @@ describe('SuperChart', () => {
});
});
beforeEach(() => {
restoreConsole = mockConsole();
triggerResizeObserver([]); // Reset any pending resize observers
});
afterEach(() => {
restoreConsole();
});
describe('includes ErrorBoundary', () => {
let expectedErrors = 0;
let actualErrors = 0;
@@ -128,9 +117,7 @@ describe('SuperChart', () => {
test('renders custom FallbackComponent', async () => {
expectedErrors = 1;
const CustomFallbackComponent = jest.fn(() => (
<div>Custom Fallback!</div>
));
const CustomFallbackComponent = vi.fn(() => <div>Custom Fallback!</div>);
render(
<SuperChart
@@ -147,7 +134,7 @@ describe('SuperChart', () => {
});
test('call onErrorBoundary', async () => {
expectedErrors = 1;
const handleError = jest.fn();
const handleError = vi.fn();
render(
<SuperChart
chartType={ChartKeys.BUGGY}
@@ -165,8 +152,8 @@ describe('SuperChart', () => {
// Update the test cases
test('does not include ErrorBoundary if told so', async () => {
expectedErrors = 1;
const inactiveErrorHandler = jest.fn();
const activeErrorHandler = jest.fn();
const inactiveErrorHandler = vi.fn();
const activeErrorHandler = vi.fn();
render(
<ErrorBoundary
fallbackRender={() => <div>Error!</div>}
@@ -195,7 +182,7 @@ describe('SuperChart', () => {
// Update test cases
// Update timeout for all async tests
jest.setTimeout(10000);
vi.setConfig({ testTimeout: 10000 });
// Update the props test to wait for component to render
test('passes the props to renderer correctly', async () => {
@@ -229,7 +216,7 @@ describe('SuperChart', () => {
// Update dimension tests to wait for resize observer
// First, increase the timeout for all tests
jest.setTimeout(20000);
vi.setConfig({ testTimeout: 20000 });
// Update the waitForDimensions helper to include a retry mechanism
// Update waitForDimensions to avoid await in loop
@@ -460,13 +447,12 @@ describe('SuperChart', () => {
});
test('should render MatrixifyGridRenderer when matrixify is enabled with empty data', () => {
const mockIsMatrixifyEnabled = isMatrixifyEnabled as jest.MockedFunction<
const mockIsMatrixifyEnabled = isMatrixifyEnabled as Mock<
typeof isMatrixifyEnabled
>;
const mockMatrixifyGridRenderer =
MatrixifyGridRenderer as jest.MockedFunction<
typeof MatrixifyGridRenderer
>;
const mockMatrixifyGridRenderer = MatrixifyGridRenderer as Mock<
typeof MatrixifyGridRenderer
>;
mockIsMatrixifyEnabled.mockReturnValue(true);
@@ -485,13 +471,12 @@ describe('SuperChart', () => {
});
test('should render MatrixifyGridRenderer when matrixify is enabled with null data', () => {
const mockIsMatrixifyEnabled = isMatrixifyEnabled as jest.MockedFunction<
const mockIsMatrixifyEnabled = isMatrixifyEnabled as Mock<
typeof isMatrixifyEnabled
>;
const mockMatrixifyGridRenderer =
MatrixifyGridRenderer as jest.MockedFunction<
typeof MatrixifyGridRenderer
>;
const mockMatrixifyGridRenderer = MatrixifyGridRenderer as Mock<
typeof MatrixifyGridRenderer
>;
mockIsMatrixifyEnabled.mockReturnValue(true);
@@ -510,13 +495,12 @@ describe('SuperChart', () => {
});
test('should ignore custom noResults component when matrixify is enabled', () => {
const mockIsMatrixifyEnabled = isMatrixifyEnabled as jest.MockedFunction<
const mockIsMatrixifyEnabled = isMatrixifyEnabled as Mock<
typeof isMatrixifyEnabled
>;
const mockMatrixifyGridRenderer =
MatrixifyGridRenderer as jest.MockedFunction<
typeof MatrixifyGridRenderer
>;
const mockMatrixifyGridRenderer = MatrixifyGridRenderer as Mock<
typeof MatrixifyGridRenderer
>;
mockIsMatrixifyEnabled.mockReturnValue(true);
@@ -540,16 +524,15 @@ describe('SuperChart', () => {
});
test('should apply error boundary to matrixify grid renderer', () => {
const mockIsMatrixifyEnabled = isMatrixifyEnabled as jest.MockedFunction<
const mockIsMatrixifyEnabled = isMatrixifyEnabled as Mock<
typeof isMatrixifyEnabled
>;
const mockMatrixifyGridRenderer =
MatrixifyGridRenderer as jest.MockedFunction<
typeof MatrixifyGridRenderer
>;
const mockMatrixifyGridRenderer = MatrixifyGridRenderer as Mock<
typeof MatrixifyGridRenderer
>;
mockIsMatrixifyEnabled.mockReturnValue(true);
const onErrorBoundary = jest.fn();
const onErrorBoundary = vi.fn();
render(
<SuperChart

View File

@@ -18,7 +18,6 @@
*/
import '@testing-library/jest-dom';
import mockConsole, { RestoreConsole } from 'jest-mock-console';
import { ChartProps } from '@superset-ui/core';
import { supersetTheme } from '@apache-superset/core/theme';
import { render, screen, waitFor } from '@superset-ui/core/spec';
@@ -38,10 +37,8 @@ describe('SuperChartCore', () => {
new SlowChartPlugin().configure({ key: ChartKeys.SLOW }),
];
let restoreConsole: RestoreConsole;
beforeAll(() => {
jest.setTimeout(30000);
vi.setConfig({ testTimeout: 30000 });
plugins.forEach(p => {
p.unregister().register();
});
@@ -53,14 +50,6 @@ describe('SuperChartCore', () => {
});
});
beforeEach(() => {
restoreConsole = mockConsole();
});
afterEach(() => {
restoreConsole();
});
describe('registered charts', () => {
test('renders registered chart', async () => {
const { container } = render(

View File

@@ -19,7 +19,6 @@
import '@testing-library/jest-dom';
import { ComponentType } from 'react';
import mockConsole, { RestoreConsole } from 'jest-mock-console';
import { render as renderTestComponent, screen } from '@testing-library/react';
import createLoadableRenderer, {
LoadableRenderer as LoadableRendererType,
@@ -29,21 +28,19 @@ describe('createLoadableRenderer', () => {
function TestComponent() {
return <div className="test-component">test</div>;
}
let loadChartSuccess = jest.fn(() => Promise.resolve(TestComponent));
let loadChartSuccess = vi.fn(() => Promise.resolve(TestComponent));
let render: (loaded: { Chart: ComponentType }) => JSX.Element;
let loading: () => JSX.Element;
let LoadableRenderer: LoadableRendererType<{}>;
let restoreConsole: RestoreConsole;
beforeEach(() => {
restoreConsole = mockConsole();
loadChartSuccess = jest.fn(() => Promise.resolve(TestComponent));
render = jest.fn(loaded => {
loadChartSuccess = vi.fn(() => Promise.resolve(TestComponent));
render = vi.fn(loaded => {
const { Chart } = loaded;
return <Chart />;
});
loading = jest.fn(() => <div>Loading</div>);
loading = vi.fn(() => <div>Loading</div>);
LoadableRenderer = createLoadableRenderer({
loader: {
@@ -54,10 +51,6 @@ describe('createLoadableRenderer', () => {
});
});
afterEach(() => {
restoreConsole();
});
describe('returns a LoadableRenderer class', () => {
test('LoadableRenderer.preload() preloads the lazy-load components', () => {
expect(LoadableRenderer.preload).toBeInstanceOf(Function);
@@ -66,8 +59,8 @@ describe('createLoadableRenderer', () => {
});
test('calls onRenderSuccess when succeeds', async () => {
const onRenderSuccess = jest.fn();
const onRenderFailure = jest.fn();
const onRenderSuccess = vi.fn();
const onRenderFailure = vi.fn();
renderTestComponent(
<LoadableRenderer
onRenderSuccess={onRenderSuccess}
@@ -75,7 +68,7 @@ describe('createLoadableRenderer', () => {
/>,
);
expect(loadChartSuccess).toHaveBeenCalled();
jest.useRealTimers();
vi.useRealTimers();
await new Promise(resolve => setTimeout(resolve, 10));
expect(render).toHaveBeenCalledTimes(1);
expect(onRenderSuccess).toHaveBeenCalledTimes(1);
@@ -84,7 +77,7 @@ describe('createLoadableRenderer', () => {
test('calls onRenderFailure when fails', () =>
new Promise(done => {
const loadChartFailure = jest.fn(() =>
const loadChartFailure = vi.fn(() =>
Promise.reject(new Error('Invalid chart')),
);
const FailedRenderer = createLoadableRenderer({
@@ -94,8 +87,8 @@ describe('createLoadableRenderer', () => {
loading,
render,
});
const onRenderSuccess = jest.fn();
const onRenderFailure = jest.fn();
const onRenderSuccess = vi.fn();
const onRenderFailure = vi.fn();
renderTestComponent(
<FailedRenderer
onRenderSuccess={onRenderSuccess}
@@ -113,7 +106,7 @@ describe('createLoadableRenderer', () => {
test('onRenderFailure is optional', () =>
new Promise(done => {
const loadChartFailure = jest.fn(() =>
const loadChartFailure = vi.fn(() =>
Promise.reject(new Error('Invalid chart')),
);
const FailedRenderer = createLoadableRenderer({

View File

@@ -25,7 +25,7 @@ import { render, screen } from '@testing-library/react';
import { RenderFuncType } from '../../../src/chart/components/reactify';
describe('reactify(renderFn)', () => {
const renderFn: RenderFuncType<{ content?: string }> = jest.fn(
const renderFn: RenderFuncType<{ content?: string }> = vi.fn(
(element, props) => {
const container = element;
container.innerHTML = '';
@@ -45,7 +45,7 @@ describe('reactify(renderFn)', () => {
content: 'ghi',
};
const willUnmountCb = jest.fn();
const willUnmountCb = vi.fn();
const TheChart = reactify(renderFn);
const TheChartWithWillUnmountHook = reactify(renderFn, {
@@ -127,7 +127,7 @@ describe('reactify(renderFn)', () => {
});
});
test('does not try to render if not mounted', () => {
const anotherRenderFn = jest.fn();
const anotherRenderFn = vi.fn();
const AnotherChart = reactify(anotherRenderFn); // enables valid new AnotherChart() call
// @ts-expect-error
new AnotherChart({ id: 'test' }).execute();

View File

@@ -23,6 +23,7 @@ import {
FeatureFlag,
LabelsColorMapSource,
} from '@superset-ui/core';
import { Mock } from 'vitest';
describe('CategoricalColorScale', () => {
beforeEach(() => {
@@ -64,26 +65,20 @@ describe('CategoricalColorScale', () => {
describe('.getColor(value, sliceId)', () => {
let scale: CategoricalColorScale;
let addSliceSpy: jest.SpyInstance<
void,
[label: string, color: string, sliceId: number, colorScheme?: string]
>;
let getNextAvailableColorSpy: jest.SpyInstance<
string,
[currentLabel: string, currentColor: string]
>;
let addSliceSpy: Mock<typeof scale.labelsColorMapInstance.addSlice>;
let getNextAvailableColorSpy: Mock<typeof scale.getNextAvailableColor>;
beforeEach(() => {
scale = new CategoricalColorScale(['blue', 'red', 'green']);
// Spy on the addSlice method of labelsColorMapInstance
addSliceSpy = jest.spyOn(scale.labelsColorMapInstance, 'addSlice');
getNextAvailableColorSpy = jest
addSliceSpy = vi.spyOn(scale.labelsColorMapInstance, 'addSlice');
getNextAvailableColorSpy = vi
.spyOn(scale, 'getNextAvailableColor')
.mockImplementation(color => color);
});
afterEach(() => {
jest.restoreAllMocks();
vi.restoreAllMocks();
});
test('uses labelsColorMapInstance color map when source is Dashboard, otherwise uses chartLabelsColorMap', () => {
@@ -94,9 +89,9 @@ describe('CategoricalColorScale', () => {
const chartColorMap = new Map([['testValueChart', 'chartColor']]);
const dashboardColorMap = new Map([['testValueDash', 'dashboardColor']]);
scale.chartLabelsColorMap = chartColorMap;
jest
.spyOn(scale.labelsColorMapInstance, 'getColorMap')
.mockReturnValue(dashboardColorMap);
vi.spyOn(scale.labelsColorMapInstance, 'getColorMap').mockReturnValue(
dashboardColorMap,
);
// Test when source is Dashboard
scale.labelsColorMapInstance.source = LabelsColorMapSource.Dashboard;
@@ -406,7 +401,7 @@ describe('CategoricalColorScale', () => {
const scale = new CategoricalColorScale(['blue', 'red', 'green']);
// Mock or override getColorUsageCount to return 0 for "blue"
jest.spyOn(scale, 'getColorUsageCount').mockImplementation(color => {
vi.spyOn(scale, 'getColorUsageCount').mockImplementation(color => {
if (color === 'blue') return 0; // Explicitly return 0 for "blue"
return 1; // Return 1 for other colors
});

View File

@@ -27,9 +27,10 @@ import {
LabelsColorMap,
} from '@superset-ui/core';
const actual = jest.requireActual('../../src/color/utils');
const getAnalogousColorsSpy = jest
.spyOn(actual, 'getAnalogousColors')
import * as colorUtils from '../../src/color/utils';
const getAnalogousColorsSpy = vi
.spyOn(colorUtils, 'getAnalogousColors')
.mockImplementation(() => ['red', 'green', 'blue']);
describe('LabelsColorMap', () => {
@@ -141,8 +142,8 @@ describe('LabelsColorMap', () => {
labelsColorMap = getLabelsColorMap();
categoricalNamespace = CategoricalColorNamespace.getNamespace(undefined);
mockedNamespace = {
getScale: jest.fn().mockReturnValue({
getColor: jest.fn(() => 'mockColor'),
getScale: vi.fn().mockReturnValue({
getColor: vi.fn(() => 'mockColor'),
}),
};
});

View File

@@ -25,18 +25,14 @@ import { SupersetTheme, ThemeProvider } from '@apache-superset/core/theme';
import AsyncIcon from '../../../src/components/Icons/AsyncIcon';
// Mock only the SVG import to prevent dynamic import issues
jest.mock(
'!!@svgr/webpack!../../../src/assets/images/icons/slack.svg',
() => {
const MockSlackSVG = (props: any) => (
<svg {...props} viewBox="0 0 24 24" data-testid="slack-svg">
<path d="M5.042 15.165a2.528 2.528 0 0 1-2.52 2.523A2.528 2.528 0 0 1 0 15.165a2.527 2.527 0 0 1 2.522-2.52h2.52v2.52z" />
</svg>
);
return { default: MockSlackSVG };
},
{ virtual: true },
);
vi.mock('!!@svgr/webpack!../../../src/assets/images/icons/slack.svg', () => {
const MockSlackSVG = (props: any) => (
<svg {...props} viewBox="0 0 24 24" data-testid="slack-svg">
<path d="M5.042 15.165a2.528 2.528 0 0 1-2.52 2.523A2.528 2.528 0 0 1 0 15.165a2.527 2.527 0 0 1 2.522-2.52h2.52v2.52z" />
</svg>
);
return { default: MockSlackSVG };
});
// Basic theme for testing
const mockTheme: SupersetTheme = {
@@ -82,7 +78,7 @@ describe('AsyncIcon Integration Tests (Real Component)', () => {
});
test('should set role to button when onClick is provided in real component', () => {
const onClick = jest.fn();
const onClick = vi.fn();
const { container } = render(
<ThemeProvider theme={mockTheme}>
<AsyncIcon

View File

@@ -25,7 +25,7 @@ import {
/**
* NOTE: react-markdown is mocked globally in spec/helpers/shim.tsx (line 89)
* to return children as-is without processing. This is intentional to avoid
* ESM parsing issues with hast-* packages in Jest.
* ESM parsing issues with hast-* packages in vi.
*
* These tests verify that the SafeMarkdown component renders without errors,
* which is the main goal: ensuring remark-gfm v4+ doesn't break the component

View File

@@ -73,18 +73,18 @@ describe('SupersetClient', () => {
fetchMock.put(mockPutUrl, mockPutPayload);
fetchMock.get(mockRequestUrl, mockGetPayload);
const initSpy = jest.spyOn(SupersetClientClass.prototype, 'init');
const getSpy = jest.spyOn(SupersetClientClass.prototype, 'get');
const postSpy = jest.spyOn(SupersetClientClass.prototype, 'post');
const putSpy = jest.spyOn(SupersetClientClass.prototype, 'put');
const deleteSpy = jest.spyOn(SupersetClientClass.prototype, 'delete');
const authenticatedSpy = jest.spyOn(
const initSpy = vi.spyOn(SupersetClientClass.prototype, 'init');
const getSpy = vi.spyOn(SupersetClientClass.prototype, 'get');
const postSpy = vi.spyOn(SupersetClientClass.prototype, 'post');
const putSpy = vi.spyOn(SupersetClientClass.prototype, 'put');
const deleteSpy = vi.spyOn(SupersetClientClass.prototype, 'delete');
const authenticatedSpy = vi.spyOn(
SupersetClientClass.prototype,
'isAuthenticated',
);
const csrfSpy = jest.spyOn(SupersetClientClass.prototype, 'fetchCSRFToken');
const requestSpy = jest.spyOn(SupersetClientClass.prototype, 'request');
const getGuestTokenSpy = jest.spyOn(
const csrfSpy = vi.spyOn(SupersetClientClass.prototype, 'fetchCSRFToken');
const requestSpy = vi.spyOn(SupersetClientClass.prototype, 'request');
const getGuestTokenSpy = vi.spyOn(
SupersetClientClass.prototype,
'getGuestToken',
);

View File

@@ -19,6 +19,7 @@
import fetchMock from 'fetch-mock';
import { SupersetClientClass, ClientConfig, CallApi } from '@superset-ui/core';
import { LOGIN_GLOB } from './fixtures/constants';
import { Mock } from 'vitest';
beforeAll(() => fetchMock.mockGlobal());
afterAll(() => fetchMock.hardReset());
@@ -329,7 +330,7 @@ describe('SupersetClientClass', () => {
test('checks for authentication before every get and post request', async () => {
expect.assertions(6);
const authSpy = jest.spyOn(SupersetClientClass.prototype, 'ensureAuth');
const authSpy = vi.spyOn(SupersetClientClass.prototype, 'ensureAuth');
const client = new SupersetClientClass({ protocol, host });
await client.init();
@@ -554,7 +555,7 @@ describe('SupersetClientClass', () => {
describe('when unauthorized', () => {
let originalLocation: any;
let authSpy: jest.SpyInstance;
let authSpy: Mock;
const mockRequestUrl = 'https://host/get/url';
const mockRequestPath = '/get/url';
const mockRequestSearch = '?param=1&param=2';
@@ -569,9 +570,9 @@ describe('SupersetClientClass', () => {
search: mockRequestSearch,
href: mockHref,
} as unknown as Location;
authSpy = jest
authSpy = vi
.spyOn(SupersetClientClass.prototype, 'ensureAuth')
.mockImplementation();
.mockImplementation(vi.fn());
const rejectValue = { status: 401 };
fetchMock.get(mockRequestUrl, () => Promise.reject(rejectValue));
});
@@ -635,7 +636,7 @@ describe('SupersetClientClass', () => {
});
test('accepts an unauthorizedHandler to override redirect behavior', async () => {
const unauthorizedHandler = jest.fn();
const unauthorizedHandler = vi.fn();
const client = new SupersetClientClass({ unauthorizedHandler });
let error;
@@ -663,7 +664,7 @@ describe('SupersetClientClass', () => {
const guestToken = 'test-guest-token';
const postFormPayload = { number: 123, array: [1, 2, 3] };
let authSpy: jest.SpyInstance;
let authSpy: Mock;
let client: SupersetClientClass;
let appendChild: any;
let removeChild: any;
@@ -675,13 +676,13 @@ describe('SupersetClientClass', () => {
fetchMock.get(LOGIN_GLOB, { result: 1234 }, { name: LOGIN_GLOB });
client = new SupersetClientClass({ protocol, host });
authSpy = jest.spyOn(SupersetClientClass.prototype, 'ensureAuth');
authSpy = vi.spyOn(SupersetClientClass.prototype, 'ensureAuth');
await client.init();
appendChild = jest.fn();
removeChild = jest.fn();
submit = jest.fn();
createElement = jest.fn(() => ({
appendChild: jest.fn(),
appendChild = vi.fn();
removeChild = vi.fn();
submit = vi.fn();
createElement = vi.fn(() => ({
appendChild: vi.fn(),
submit,
}));
@@ -691,7 +692,7 @@ describe('SupersetClientClass', () => {
});
afterEach(() => {
jest.restoreAllMocks();
vi.restoreAllMocks();
});
test.each(['', '/prefix'])(
@@ -699,7 +700,7 @@ describe('SupersetClientClass', () => {
async appRoot => {
if (appRoot !== '') {
client = new SupersetClientClass({ protocol, host, appRoot });
authSpy = jest.spyOn(SupersetClientClass.prototype, 'ensureAuth');
authSpy = vi.spyOn(SupersetClientClass.prototype, 'ensureAuth');
await client.init();
}
await client.postForm(mockPostFormEndpoint, {});

View File

@@ -207,7 +207,7 @@ describe('callApi()', () => {
// corruptObject has no toString method and will fail cast to String()
corrupt: [corruptObject],
};
jest.spyOn(console, 'error').mockImplementation();
vi.spyOn(console, 'error').mockImplementation(() => {});
await callApi({
url: mockPostUrl,

View File

@@ -40,12 +40,12 @@ describe('callApiAndParseWithTimeout()', () => {
afterEach(() => {
fetchMock.removeRoutes().clearHistory();
jest.useRealTimers();
vi.useRealTimers();
});
describe('callApi', () => {
test('calls callApi()', () => {
const callApiSpy = jest.spyOn(callApi, 'default');
const callApiSpy = vi.spyOn(callApi, 'default');
callApiAndParseWithTimeout({ url: mockGetUrl, method: 'GET' });
expect(callApiSpy).toHaveBeenCalledTimes(1);
@@ -55,7 +55,7 @@ describe('callApiAndParseWithTimeout()', () => {
describe('parseResponse', () => {
test('calls parseResponse()', async () => {
const parseSpy = jest.spyOn(parseResponse, 'default');
const parseSpy = vi.spyOn(parseResponse, 'default');
await callApiAndParseWithTimeout({
url: mockGetUrl,
@@ -69,7 +69,7 @@ describe('callApiAndParseWithTimeout()', () => {
describe('timeout', () => {
test('does not create a rejection timer if no timeout passed', () => {
const rejectionSpy = jest.spyOn(rejectAfterTimeout, 'default');
const rejectionSpy = vi.spyOn(rejectAfterTimeout, 'default');
callApiAndParseWithTimeout({ url: mockGetUrl, method: 'GET' });
expect(rejectionSpy).toHaveBeenCalledTimes(0);
@@ -77,8 +77,8 @@ describe('callApiAndParseWithTimeout()', () => {
});
test('creates a rejection timer if a timeout passed', () => {
jest.useFakeTimers(); // prevents the timeout from rejecting + failing test
const rejectionSpy = jest.spyOn(rejectAfterTimeout, 'default');
vi.useFakeTimers(); // prevents the timeout from rejecting + failing test
const rejectionSpy = vi.spyOn(rejectAfterTimeout, 'default');
callApiAndParseWithTimeout({
url: mockGetUrl,
method: 'GET',
@@ -91,7 +91,7 @@ describe('callApiAndParseWithTimeout()', () => {
test('rejects if the request exceeds the timeout', async () => {
expect.assertions(2);
jest.useFakeTimers();
vi.useFakeTimers();
const mockTimeoutUrl = '/mock/timeout/url';
const unresolvingPromise = new Promise(() => {});
@@ -104,7 +104,7 @@ describe('callApiAndParseWithTimeout()', () => {
method: 'GET',
timeout: 1,
});
jest.advanceTimersByTime(2);
vi.advanceTimersByTime(2);
await promise;
} catch (err) {
error = err;

View File

@@ -21,18 +21,18 @@ import rejectAfterTimeout from '../../../src/connection/callApi/rejectAfterTimeo
describe('rejectAfterTimeout()', () => {
test('returns a promise that rejects after the specified timeout', async () => {
expect.assertions(1);
jest.useFakeTimers();
vi.useFakeTimers();
let error;
try {
const promise = rejectAfterTimeout(10);
jest.advanceTimersByTime(11);
vi.advanceTimersByTime(11);
await promise;
} catch (err) {
error = err;
} finally {
expect(error).toBeDefined();
}
jest.useRealTimers();
vi.useRealTimers();
});
});

View File

@@ -233,7 +233,7 @@ test('CurrencyFormatter AUTO mode returns plain value when getCurrencySymbol ret
const OrigNumberFormat = Intl.NumberFormat;
// Return formatToParts without a 'currency' entry so getCurrencySymbol → undefined
Intl.NumberFormat = jest.fn().mockImplementation(() => ({
Intl.NumberFormat = vi.fn().mockImplementation(() => ({
formatToParts: () => [{ type: 'integer', value: '1' }],
})) as unknown as typeof Intl.NumberFormat;
@@ -254,7 +254,7 @@ test('CurrencyFormatter AUTO mode falls back to plain value when getCurrencySymb
// Mock Intl.NumberFormat to throw to simulate an environment where the
// currency code is rejected, triggering the catch block in format()
const OrigNumberFormat = Intl.NumberFormat;
Intl.NumberFormat = jest.fn().mockImplementation(() => {
Intl.NumberFormat = vi.fn().mockImplementation(() => {
throw new RangeError('Invalid currency code');
}) as unknown as typeof Intl.NumberFormat;

View File

@@ -29,7 +29,7 @@ describe('LazyFactory', () => {
expect(innerDiv.parentNode).toEqual(div);
});
test('reuses existing', () => {
const factoryFn = jest.fn(() => document.createElement('div'));
const factoryFn = vi.fn(() => document.createElement('div'));
const factory = new LazyFactory(factoryFn);
const div1 = factory.createInContainer();
const div2 = factory.createInContainer();

View File

@@ -26,7 +26,7 @@ describe('shared modules', () => {
test('assigns to window', async () => {
const fakeModule = { foo: 'bar' };
const fetchModule = jest.fn().mockResolvedValue(fakeModule);
const fetchModule = vi.fn().mockResolvedValue(fakeModule);
await defineSharedModule('test-module', fetchModule);
@@ -37,7 +37,7 @@ describe('shared modules', () => {
test('resolves to the same reference every time', async () => {
const fakeModule = { foo: 'bar' };
const fetchModule = jest.fn().mockResolvedValue(fakeModule);
const fetchModule = vi.fn().mockResolvedValue(fakeModule);
const result1 = await defineSharedModule('test-module', fetchModule);
const result2 = await defineSharedModule('test-module', fetchModule);
@@ -48,8 +48,8 @@ describe('shared modules', () => {
test('does not redefine unnecessarily', async () => {
const fakeModule = { foo: 'bar' };
const fetchModule = jest.fn().mockResolvedValue(fakeModule);
const duplicateFetchModule = jest.fn().mockResolvedValue(fakeModule);
const fetchModule = vi.fn().mockResolvedValue(fakeModule);
const duplicateFetchModule = vi.fn().mockResolvedValue(fakeModule);
const result1 = await defineSharedModule('test-module', fetchModule);
const result2 = await defineSharedModule(
@@ -65,7 +65,7 @@ describe('shared modules', () => {
test('deduplicates in-progress definitions', async () => {
const fakeModule = { foo: 'bar' };
// get a promise that actually takes a moment;
const fetchModule = jest
const fetchModule = vi
.fn()
.mockImplementation(() =>
Promise.resolve(setImmediate).then(() => fakeModule),

View File

@@ -17,12 +17,13 @@
* under the License.
*/
/* eslint no-console: 0 */
import mockConsole from 'jest-mock-console';
import { Registry, OverwritePolicy } from '@superset-ui/core';
const loader = () => 'testValue';
const consoleWarnSpy = vi.spyOn(console, 'warn');
const consoleErrorSpy = vi.spyOn(console, 'error');
describe('Registry', () => {
test('exists', () => {
expect(Registry !== undefined).toBe(true);
@@ -308,33 +309,28 @@ describe('Registry', () => {
describe('=ALLOW', () => {
describe('.registerValue(key, value)', () => {
test('registers normally', () => {
const restoreConsole = mockConsole();
const registry = new Registry();
registry.registerValue('a', 'testValue');
expect(() => registry.registerValue('a', 'testValue2')).not.toThrow();
expect(registry.get('a')).toEqual('testValue2');
expect(console.warn).not.toHaveBeenCalled();
restoreConsole();
expect(consoleWarnSpy).not.toHaveBeenCalled();
});
});
describe('.registerLoader(key, loader)', () => {
test('registers normally', () => {
const restoreConsole = mockConsole();
const registry = new Registry();
registry.registerLoader('a', () => 'testValue');
expect(() =>
registry.registerLoader('a', () => 'testValue2'),
).not.toThrow();
expect(registry.get('a')).toEqual('testValue2');
expect(console.warn).not.toHaveBeenCalled();
restoreConsole();
expect(consoleWarnSpy).not.toHaveBeenCalled();
});
});
});
describe('=WARN', () => {
describe('.registerValue(key, value)', () => {
test('warns when overwrite', () => {
const restoreConsole = mockConsole();
const registry = new Registry({
overwritePolicy: OverwritePolicy.Warn,
});
@@ -342,12 +338,10 @@ describe('Registry', () => {
expect(() => registry.registerValue('a', 'testValue2')).not.toThrow();
expect(registry.get('a')).toEqual('testValue2');
expect(console.warn).toHaveBeenCalled();
restoreConsole();
});
});
describe('.registerLoader(key, loader)', () => {
test('warns when overwrite', () => {
const restoreConsole = mockConsole();
const registry = new Registry({
overwritePolicy: OverwritePolicy.Warn,
});
@@ -356,8 +350,7 @@ describe('Registry', () => {
registry.registerLoader('a', () => 'testValue2'),
).not.toThrow();
expect(registry.get('a')).toEqual('testValue2');
expect(console.warn).toHaveBeenCalled();
restoreConsole();
expect(consoleWarnSpy).toHaveBeenCalled();
});
});
});
@@ -387,10 +380,10 @@ describe('Registry', () => {
describe('listeners', () => {
let registry = new Registry();
let listener = jest.fn();
let listener = vi.fn();
beforeEach(() => {
registry = new Registry();
listener = jest.fn();
listener = vi.fn();
registry.addListener(listener);
});
@@ -438,19 +431,11 @@ describe('Registry', () => {
});
describe('with a broken listener', () => {
let restoreConsole: any;
beforeEach(() => {
restoreConsole = mockConsole();
});
afterEach(() => {
restoreConsole();
});
test('keeps working', () => {
const errorListener = jest.fn().mockImplementation(() => {
const errorListener = vi.fn().mockImplementation(() => {
throw new Error('test error');
});
const lastListener = jest.fn();
const lastListener = vi.fn();
registry.addListener(errorListener);
registry.addListener(lastListener);
@@ -459,7 +444,7 @@ describe('Registry', () => {
expect(listener).toHaveBeenCalledWith(['foo']);
expect(errorListener).toHaveBeenCalledWith(['foo']);
expect(lastListener).toHaveBeenCalledWith(['foo']);
expect(console.error).toHaveBeenCalled();
expect(consoleErrorSpy).toHaveBeenCalled();
});
});
});

View File

@@ -47,7 +47,7 @@ describe('makeApi()', () => {
});
const client = new SupersetClientClass({ appRoot: '/foo' });
const mockResponse = { yes: 'ok' };
const mockRequest = jest.fn(() =>
const mockRequest = vi.fn(() =>
Promise.resolve(
new Response(JSON.stringify(mockResponse), {
headers: { 'Content-Type': 'application/json' },

View File

@@ -125,10 +125,7 @@ describe('buildQueryContext', () => {
]);
});
test('should call normalizeTimeColumn if has x_axis', () => {
const spyNormalizeTimeColumn = jest.spyOn(
queryModule,
'normalizeTimeColumn',
);
const spyNormalizeTimeColumn = vi.spyOn(queryModule, 'normalizeTimeColumn');
buildQueryContext(
{

View File

@@ -23,12 +23,12 @@ const TODAY = '2024-06-03';
// Mock Date to always return 2024-06-03
beforeEach(() => {
jest.useFakeTimers();
jest.setSystemTime(new Date(TODAY).getTime());
vi.useFakeTimers();
vi.setSystemTime(new Date(TODAY).getTime());
});
afterEach(() => {
jest.useRealTimers();
vi.useRealTimers();
});
test('should return the current date for "now"', () => {

View File

@@ -27,7 +27,7 @@ const NOW_UTC_IN_PACIFIC = '2024-06-03T08:00:00Z'; // Same as 2024-06-03T00:00:0
afterEach(() => {
timezoneMock.unregister();
jest.useRealTimers();
vi.useRealTimers();
});
const runTimezoneTest = (
@@ -40,7 +40,7 @@ const runTimezoneTest = (
includeFutureOffsets = true,
) => {
timezoneMock.register(timezone);
jest.setSystemTime(new Date(now_time));
vi.setSystemTime(new Date(now_time));
const result = getTimeOffset({
timeRangeFilter,
shifts,
@@ -52,9 +52,9 @@ const runTimezoneTest = (
};
test('should handle includeFutureOffsets is null', () => {
jest.useFakeTimers();
vi.useFakeTimers();
timezoneMock.register('Etc/GMT-2');
jest.setSystemTime(new Date(NOW_UTC_IN_EUROPE));
vi.setSystemTime(new Date(NOW_UTC_IN_EUROPE));
const result = getTimeOffset({
timeRangeFilter: {
comparator: '2024-06-03 : 2024-06-10',
@@ -72,7 +72,7 @@ test('should handle custom range with specific dates', () => {
};
const shifts = ['custom'];
const startDate = '2024-05-29';
jest.useFakeTimers();
vi.useFakeTimers();
runTimezoneTest(
NOW_UTC_IN_EUROPE,
@@ -101,7 +101,7 @@ test('should handle custom range with relative dates (now)', () => {
};
const shifts = ['custom'];
const startDate = '2024-05-30';
jest.useFakeTimers();
vi.useFakeTimers();
runTimezoneTest(
NOW_UTC_IN_EUROPE,
@@ -130,7 +130,7 @@ test('should handle inherit shift', () => {
};
const shifts = ['inherit'];
const startDate = '2024-03-06';
jest.useFakeTimers();
vi.useFakeTimers();
runTimezoneTest(
NOW_UTC_IN_EUROPE,
'Etc/GMT-2',
@@ -158,7 +158,7 @@ test('should handle custom and inherit shifts', () => {
};
const shifts = ['custom', 'inherit'];
const startDate = '2024-05-28';
jest.useFakeTimers();
vi.useFakeTimers();
runTimezoneTest(
NOW_UTC_IN_EUROPE,
'Etc/GMT-2',
@@ -187,7 +187,7 @@ test('should handle no shifts', () => {
};
const shifts: any = [];
const startDate = '2024-03-06';
jest.useFakeTimers();
vi.useFakeTimers();
runTimezoneTest(
NOW_UTC_IN_EUROPE,
'Etc/GMT-2',
@@ -211,7 +211,7 @@ test('should handle null timeRangeFilter', () => {
const timeRangeFilter = null;
const shifts = ['custom'];
const startDate = '2024-06-01';
jest.useFakeTimers();
vi.useFakeTimers();
runTimezoneTest(
NOW_UTC_IN_EUROPE,
'Etc/GMT-2',
@@ -239,7 +239,7 @@ test('should handle predefined shifts', () => {
};
const shifts: any = ['1 year ago'];
const startDate = '2024-03-06';
jest.useFakeTimers();
vi.useFakeTimers();
runTimezoneTest(
NOW_UTC_IN_EUROPE,
@@ -269,7 +269,7 @@ test('should handle custom range with DATEADD function', () => {
};
const shifts = ['custom'];
const startDate = '2024-05-21';
jest.useFakeTimers();
vi.useFakeTimers();
runTimezoneTest(
NOW_UTC_IN_EUROPE,
'Etc/GMT-2',
@@ -297,7 +297,7 @@ test('should handle custom range with DATEADD function and relative start date',
};
const shifts = ['custom'];
const startDate = '2024-06-01';
jest.useFakeTimers();
vi.useFakeTimers();
runTimezoneTest(
NOW_UTC_IN_EUROPE,
'Etc/GMT-2',
@@ -325,7 +325,7 @@ test('should handle custom range with DATEADD function and relative end date', (
};
const shifts = ['custom'];
const startDate = '2024-05-23';
jest.useFakeTimers();
vi.useFakeTimers();
runTimezoneTest(
NOW_UTC_IN_EUROPE,
@@ -354,7 +354,7 @@ test('should handle custom range with specific date and relative end date', () =
};
const shifts = ['custom'];
const startDate = '2024-05-23';
jest.useFakeTimers();
vi.useFakeTimers();
runTimezoneTest(
NOW_UTC_IN_EUROPE,
@@ -383,7 +383,7 @@ test('should handle custom range with specific date and specific end date', () =
};
const shifts = ['custom'];
const startDate = '2024-06-01';
jest.useFakeTimers();
vi.useFakeTimers();
runTimezoneTest(
NOW_UTC_IN_EUROPE,
'Etc/GMT-2',
@@ -411,7 +411,7 @@ test('should handle custom range with Last and now', () => {
};
const shifts = ['custom'];
const startDate = '2024-05-30';
jest.useFakeTimers();
vi.useFakeTimers();
runTimezoneTest(
NOW_UTC_IN_EUROPE,
'Etc/GMT-2',
@@ -439,7 +439,7 @@ test('should handle custom range with Last week', () => {
};
const shifts = ['custom'];
const startDate = '2024-05-21';
jest.useFakeTimers();
vi.useFakeTimers();
runTimezoneTest(
NOW_UTC_IN_EUROPE,
'Etc/GMT-2',
@@ -467,7 +467,7 @@ test('should handle custom range with previous calendar week', () => {
};
const shifts = ['custom'];
const startDate = '2024-05-26';
jest.useFakeTimers();
vi.useFakeTimers();
runTimezoneTest(
'2024-06-05T02:06:00+02:00',
'Etc/GMT-2',
@@ -500,7 +500,7 @@ test('should handle custom range with previous calendar month', () => {
};
const shifts = ['custom'];
const startDate = '2024-04-26';
jest.useFakeTimers();
vi.useFakeTimers();
runTimezoneTest(
'2024-06-05T02:06:00+02:00',
'Etc/GMT-2',
@@ -533,7 +533,7 @@ test('should handle custom range with previous calendar year', () => {
};
const shifts = ['custom'];
const startDate = '2022-12-26';
jest.useFakeTimers();
vi.useFakeTimers();
runTimezoneTest(
'2024-06-05T02:06:00+02:00',
@@ -567,7 +567,7 @@ test('should handle custom range with Advanced 2022-11-01', () => {
};
const shifts = ['custom'];
const startDate = '2022-10-18';
jest.useFakeTimers();
vi.useFakeTimers();
runTimezoneTest(
'2024-06-05T02:06:00+02:00',
@@ -601,7 +601,7 @@ test('should handle future inherit shift with includeFutureOffsets set to true',
};
const shifts = ['inherit'];
const startDate = '2024-06-20';
jest.useFakeTimers();
vi.useFakeTimers();
runTimezoneTest(
NOW_UTC_IN_EUROPE,
@@ -638,7 +638,7 @@ test('should handle future custom shift with includeFutureOffsets set to true',
};
const shifts = ['custom'];
const startDate = '2024-06-15';
jest.useFakeTimers();
vi.useFakeTimers();
runTimezoneTest(
NOW_UTC_IN_EUROPE,
@@ -667,7 +667,7 @@ test('should handle custom range with specific (YYYY-MM) and relative dates', ()
};
const shifts = ['custom'];
const startDate = '2024-05-29';
jest.useFakeTimers();
vi.useFakeTimers();
runTimezoneTest(
NOW_UTC_IN_EUROPE,
@@ -696,7 +696,7 @@ test('should handle custom range with minutes', () => {
};
const shifts = ['custom'];
const startDate = '2024-05-29';
jest.useFakeTimers();
vi.useFakeTimers();
runTimezoneTest(
NOW_UTC_IN_EUROPE,
@@ -725,7 +725,7 @@ test('should handle custom range with undefined startDate', () => {
};
const shifts = ['custom'];
const startDate = undefined;
jest.useFakeTimers();
vi.useFakeTimers();
runTimezoneTest(
NOW_UTC_IN_EUROPE,
@@ -752,7 +752,7 @@ test('should handle future custom shift with different format', () => {
};
const shifts = ['custom'];
const startDate = '2024-06-15';
jest.useFakeTimers();
vi.useFakeTimers();
runTimezoneTest(
NOW_UTC_IN_EUROPE,
@@ -782,7 +782,7 @@ test('should handle custom range with relative dates', () => {
};
const shifts = ['custom'];
const startDate = '2024-05-29';
jest.useFakeTimers();
vi.useFakeTimers();
runTimezoneTest(
NOW_UTC_IN_EUROPE,
@@ -812,7 +812,7 @@ test('should handle custom range with relative dates (minute and seconds)', () =
};
const shifts = ['custom'];
const startDate = '2024-05-29';
jest.useFakeTimers();
vi.useFakeTimers();
runTimezoneTest(
NOW_UTC_IN_EUROPE,
@@ -842,7 +842,7 @@ test('should handle custom range with relative dates (hour)', () => {
};
const shifts = ['custom'];
const startDate = '2024-05-29';
jest.useFakeTimers();
vi.useFakeTimers();
runTimezoneTest(
NOW_UTC_IN_EUROPE,
@@ -871,7 +871,7 @@ test('should handle custom shifts with same day', () => {
};
const shifts = ['custom'];
const startDate = '2024-05-29';
jest.useFakeTimers();
vi.useFakeTimers();
runTimezoneTest(
NOW_UTC_IN_EUROPE,
@@ -900,7 +900,7 @@ test('should handle inherit shifts without filter', () => {
};
const shifts = ['inherit'];
const startDate = '2024-05-29';
jest.useFakeTimers();
vi.useFakeTimers();
runTimezoneTest(
NOW_UTC_IN_EUROPE,
@@ -927,7 +927,7 @@ test('should handle inherit shift same day', () => {
};
const shifts = ['inherit'];
const startDate = '2024-03-06';
jest.useFakeTimers();
vi.useFakeTimers();
runTimezoneTest(
NOW_UTC_IN_EUROPE,
'Etc/GMT-2',
@@ -963,7 +963,7 @@ test('should handle inherit shift same day includeFutureOffsets set to false', (
};
const shifts = ['inherit'];
const startDate = '2024-03-06';
jest.useFakeTimers();
vi.useFakeTimers();
runTimezoneTest(
NOW_UTC_IN_EUROPE,
'Etc/GMT-2',
@@ -999,7 +999,7 @@ test('should handle custom shift same day includeFutureOffsets set to false', ()
};
const shifts = ['custom'];
const startDate = '2024-03-06';
jest.useFakeTimers();
vi.useFakeTimers();
runTimezoneTest(
NOW_UTC_IN_EUROPE,
'Etc/GMT-2',

View File

@@ -27,7 +27,7 @@ const NOW_UTC_IN_PACIFIC = '2024-06-03T08:00:00Z'; // Same as 2024-06-03T00:00:0
afterEach(() => {
timezoneMock.unregister();
jest.useRealTimers();
vi.useRealTimers();
});
const runTimezoneTest = (
@@ -39,7 +39,7 @@ const runTimezoneTest = (
computingShift = false,
) => {
timezoneMock.register(timezone);
jest.setSystemTime(new Date(now_time));
vi.setSystemTime(new Date(now_time));
expect(parseDttmToDate(eval_time, endDate, computingShift)).toEqual(
expected_result,
);
@@ -47,7 +47,7 @@ const runTimezoneTest = (
};
test('should return the current date for "now"', () => {
jest.useFakeTimers();
vi.useFakeTimers();
runTimezoneTest(
'now',
NOW_UTC_IN_EUROPE,
@@ -64,7 +64,7 @@ test('should return the current date for "now"', () => {
});
test('should return the current date for "today"', () => {
jest.useFakeTimers();
vi.useFakeTimers();
runTimezoneTest(
'today',
NOW_UTC_IN_EUROPE,
@@ -81,7 +81,7 @@ test('should return the current date for "today"', () => {
});
test('should return the current date for "No filter"', () => {
jest.useFakeTimers();
vi.useFakeTimers();
runTimezoneTest(
'No filter',
NOW_UTC_IN_EUROPE,
@@ -103,7 +103,7 @@ test('should return the current date for "No filter"', () => {
});
test('should return the current date for an empty string', () => {
jest.useFakeTimers();
vi.useFakeTimers();
runTimezoneTest(
'',
NOW_UTC_IN_EUROPE,
@@ -120,7 +120,7 @@ test('should return the current date for an empty string', () => {
});
test('should return yesterday date for "Last day"', () => {
jest.useFakeTimers();
vi.useFakeTimers();
runTimezoneTest(
'Last day',
NOW_UTC_IN_EUROPE,
@@ -142,7 +142,7 @@ test('should return yesterday date for "Last day"', () => {
});
test('should return the date one week ago for "Last week"', () => {
jest.useFakeTimers();
vi.useFakeTimers();
runTimezoneTest(
'Last week',
NOW_UTC_IN_EUROPE,
@@ -164,7 +164,7 @@ test('should return the date one week ago for "Last week"', () => {
});
test('should return the date one month ago for "Last month"', () => {
jest.useFakeTimers();
vi.useFakeTimers();
runTimezoneTest(
'Last month',
NOW_UTC_IN_EUROPE,
@@ -186,7 +186,7 @@ test('should return the date one month ago for "Last month"', () => {
});
test('should return the date three months ago for "Last quarter"', () => {
jest.useFakeTimers();
vi.useFakeTimers();
runTimezoneTest(
'Last quarter',
NOW_UTC_IN_EUROPE,
@@ -208,7 +208,7 @@ test('should return the date three months ago for "Last quarter"', () => {
});
test('should return the date one year ago for "Last year"', () => {
jest.useFakeTimers();
vi.useFakeTimers();
runTimezoneTest(
'Last year',
NOW_UTC_IN_EUROPE,
@@ -230,7 +230,7 @@ test('should return the date one year ago for "Last year"', () => {
});
test('should return the date for "previous calendar week"', () => {
jest.useFakeTimers();
vi.useFakeTimers();
runTimezoneTest(
'previous calendar week',
'2024-06-04T22:00:00Z',
@@ -252,7 +252,7 @@ test('should return the date for "previous calendar week"', () => {
});
test('should return the date for "previous calendar month"', () => {
jest.useFakeTimers();
vi.useFakeTimers();
runTimezoneTest(
'previous calendar month',
NOW_UTC_IN_EUROPE,
@@ -274,7 +274,7 @@ test('should return the date for "previous calendar month"', () => {
});
test('should return the date for "previous calendar year"', () => {
jest.useFakeTimers();
vi.useFakeTimers();
runTimezoneTest(
'previous calendar year',
NOW_UTC_IN_EUROPE,
@@ -296,7 +296,7 @@ test('should return the date for "previous calendar year"', () => {
});
test('should return the date for "1 day ago"', () => {
jest.useFakeTimers();
vi.useFakeTimers();
runTimezoneTest(
'1 day ago',
NOW_UTC_IN_EUROPE,
@@ -318,7 +318,7 @@ test('should return the date for "1 day ago"', () => {
});
test('should return the date for "1 week ago"', () => {
jest.useFakeTimers();
vi.useFakeTimers();
runTimezoneTest(
'1 week ago',
NOW_UTC_IN_EUROPE,
@@ -340,7 +340,7 @@ test('should return the date for "1 week ago"', () => {
});
test('should return the date for "1 month ago"', () => {
jest.useFakeTimers();
vi.useFakeTimers();
runTimezoneTest(
'1 month ago',
NOW_UTC_IN_EUROPE,
@@ -362,7 +362,7 @@ test('should return the date for "1 month ago"', () => {
});
test('should return the date for "1 year ago"', () => {
jest.useFakeTimers();
vi.useFakeTimers();
runTimezoneTest(
'1 year ago',
NOW_UTC_IN_EUROPE,
@@ -384,7 +384,7 @@ test('should return the date for "1 year ago"', () => {
});
test('should return the date for "2024-03-09"', () => {
jest.useFakeTimers();
vi.useFakeTimers();
runTimezoneTest(
'2024-03-09',
NOW_UTC_IN_EUROPE,
@@ -406,7 +406,7 @@ test('should return the date for "2024-03-09"', () => {
});
test('should return the current date for "Last day" with isEndDate true', () => {
jest.useFakeTimers();
vi.useFakeTimers();
runTimezoneTest(
'Last day',
NOW_UTC_IN_EUROPE,
@@ -431,7 +431,7 @@ test('should return the current date for "Last day" with isEndDate true', () =>
});
test('should return the current date for "Last week" with isEndDate true', () => {
jest.useFakeTimers();
vi.useFakeTimers();
runTimezoneTest(
'Last week',
NOW_UTC_IN_EUROPE,
@@ -456,7 +456,7 @@ test('should return the current date for "Last week" with isEndDate true', () =>
});
test('should return the current date for "Last quarter" with isEndDate true', () => {
jest.useFakeTimers();
vi.useFakeTimers();
runTimezoneTest(
'Last quarter',
NOW_UTC_IN_EUROPE,
@@ -481,7 +481,7 @@ test('should return the current date for "Last quarter" with isEndDate true', ()
});
test('should return the current date for "Last year" with isEndDate true', () => {
jest.useFakeTimers();
vi.useFakeTimers();
runTimezoneTest(
'Last year',
NOW_UTC_IN_EUROPE,
@@ -506,7 +506,7 @@ test('should return the current date for "Last year" with isEndDate true', () =>
});
test('should return the date for "previous calendar week" with isEndDate true', () => {
jest.useFakeTimers();
vi.useFakeTimers();
runTimezoneTest(
'previous calendar week',
NOW_UTC_IN_EUROPE,
@@ -531,7 +531,7 @@ test('should return the date for "previous calendar week" with isEndDate true',
});
test('should return the date for "previous calendar month" with isEndDate true', () => {
jest.useFakeTimers();
vi.useFakeTimers();
runTimezoneTest(
'previous calendar month',
NOW_UTC_IN_EUROPE,
@@ -556,7 +556,7 @@ test('should return the date for "previous calendar month" with isEndDate true',
});
test('should return the date for "previous calendar year" with isEndDate true', () => {
jest.useFakeTimers();
vi.useFakeTimers();
runTimezoneTest(
'previous calendar year',
NOW_UTC_IN_EUROPE,
@@ -581,7 +581,7 @@ test('should return the date for "previous calendar year" with isEndDate true',
});
test('should return the date for "2024" with parts.length === 1', () => {
jest.useFakeTimers();
vi.useFakeTimers();
runTimezoneTest(
'2024',
NOW_UTC_IN_EUROPE,
@@ -598,7 +598,7 @@ test('should return the date for "2024" with parts.length === 1', () => {
});
test('should return the date for "2024-03" with parts.length === 2', () => {
jest.useFakeTimers();
vi.useFakeTimers();
runTimezoneTest(
'2024-03',
NOW_UTC_IN_EUROPE,
@@ -620,7 +620,7 @@ test('should return the date for "2024-03" with parts.length === 2', () => {
});
test('should return the date for "2024-03-06" with parts.length === 3', () => {
jest.useFakeTimers();
vi.useFakeTimers();
runTimezoneTest(
'2024-03-06',
NOW_UTC_IN_EUROPE,
@@ -642,7 +642,7 @@ test('should return the date for "2024-03-06" with parts.length === 3', () => {
});
test('should return the date for "2024-03-06" with computingShifts true', () => {
jest.useFakeTimers();
vi.useFakeTimers();
const expectedDate = new Date('2024-03-05T22:00:00Z');
expectedDate.setHours(-expectedDate.getTimezoneOffset() / 60, 0, 0, 0);
runTimezoneTest(
@@ -656,7 +656,7 @@ test('should return the date for "2024-03-06" with computingShifts true', () =>
});
test('should return the date for "2024-03-06" with computingShifts true and isEndDate true', () => {
jest.useFakeTimers();
vi.useFakeTimers();
const expectedDate = new Date('2024-03-05T22:00:00Z');
expectedDate.setHours(-expectedDate.getTimezoneOffset() / 60, 0, 0, 0);
runTimezoneTest(

Some files were not shown because too many files have changed in this diff Show More