feat(ci): replace jest with vitest [EE-6504] (#10997)

pull/11004/head
Chaim Lev-Ari 10 months ago committed by GitHub
parent 4a19871fcc
commit 69c06bc756
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -116,10 +116,9 @@ overrides:
- files:
- app/**/*.test.*
extends:
- 'plugin:jest/recommended'
- 'plugin:jest/style'
- 'plugin:vitest/recommended'
env:
'jest/globals': true
'vitest/env': true
rules:
'react/jsx-no-constructed-context-values': off
- files:

@ -12,7 +12,7 @@ on:
- synchronize
- ready_for_review
push:
jobs:
test-client:
runs-on: ubuntu-latest
@ -27,7 +27,7 @@ jobs:
- run: yarn --frozen-lockfile
- name: Run tests
run: make test-client ARGS="--maxWorkers=2"
run: make test-client ARGS="--maxWorkers=2 --minWorkers=1"
test-server:
strategy:
matrix:

@ -27,10 +27,9 @@ export function mockT(i18nKey: string, args?: Record<string, string>) {
return key;
}
const i18next: Record<string, unknown> = jest.createMockFromModule('i18next');
i18next.t = mockT;
i18next.language = 'en';
i18next.changeLanguage = () => new Promise(() => {});
i18next.use = () => i18next;
export default i18next;
export default {
t: mockT,
language: 'en',
changeLanguage: () => new Promise(() => {}),
use: () => this,
};

@ -6,7 +6,7 @@ describe('promiseSequence', () => {
});
it('provided two promise functions, the second should run after the first', async () => {
const callback = jest.fn();
const callback = vi.fn();
function first() {
return Promise.resolve(callback(1));

@ -2,10 +2,11 @@ import toastr from 'toastr';
import { notifyError, notifySuccess, notifyWarning } from './notifications';
jest.mock('toastr');
vi.mock('toastr');
vi.spyOn(console, 'error').mockImplementation(() => vi.fn());
afterEach(() => {
jest.resetAllMocks();
vi.resetAllMocks();
});
it('calling success should show success message', () => {
@ -18,9 +19,9 @@ it('calling success should show success message', () => {
});
it('calling error with Error should show error message', () => {
const consoleErrorFn = jest
const consoleErrorFn = vi
.spyOn(console, 'error')
.mockImplementation(() => jest.fn());
.mockImplementation(() => vi.fn());
const title = 'title';
const errorMessage = 'message';
const fallback = 'fallback';
@ -37,9 +38,9 @@ it('calling error with Error should show error message', () => {
});
it('calling error without Error should show fallback message', () => {
const consoleErrorFn = jest
const consoleErrorFn = vi
.spyOn(console, 'error')
.mockImplementation(() => jest.fn());
.mockImplementation(() => vi.fn());
const title = 'title';
const fallback = 'fallback';

@ -1,5 +1,4 @@
import '@testing-library/jest-dom';
import 'vitest-dom/extend-expect';
import { render, RenderOptions } from '@testing-library/react';
import { UIRouter, pushStateLocationPlugin } from '@uirouter/react';
import { PropsWithChildren, ReactElement } from 'react';

@ -11,9 +11,9 @@ import {
import { DashboardView } from './DashboardView';
jest.mock('@uirouter/react', () => ({
...jest.requireActual('@uirouter/react'),
useCurrentStateAndParams: jest.fn(() => ({
vi.mock('@uirouter/react', async (importOriginal: () => Promise<object>) => ({
...(await importOriginal()),
useCurrentStateAndParams: vi.fn(() => ({
params: { endpointId: 1 },
})),
}));
@ -73,7 +73,7 @@ test('should correctly show total number of resource groups across multiple subs
});
test("when only subscriptions fail to load, don't show the dashboard", async () => {
jest.spyOn(console, 'error').mockImplementation(() => {});
vi.spyOn(console, 'error').mockImplementation(() => {});
const { queryByLabelText } = await renderComponent(
1,
@ -86,7 +86,7 @@ test("when only subscriptions fail to load, don't show the dashboard", async ()
});
test('when only resource groups fail to load, still show the subscriptions', async () => {
jest.spyOn(console, 'error').mockImplementation(() => {});
vi.spyOn(console, 'error').mockImplementation(() => {});
const { queryByLabelText, findByLabelText } = await renderComponent(
1,

@ -6,9 +6,9 @@ import { renderWithQueryClient } from '@/react-tools/test-utils';
import { CreateContainerInstanceForm } from './CreateContainerInstanceForm';
jest.mock('@uirouter/react', () => ({
...jest.requireActual('@uirouter/react'),
useCurrentStateAndParams: jest.fn(() => ({
vi.mock('@uirouter/react', async (importOriginal: () => Promise<object>) => ({
...(await importOriginal()),
useCurrentStateAndParams: vi.fn(() => ({
params: { endpointId: 5 },
})),
}));

@ -44,7 +44,7 @@ test('should render with the initial value selected and call onChange when click
},
];
const onChange = jest.fn();
const onChange = vi.fn();
const { getByLabelText } = renderDefault({
options,
onChange,

@ -37,7 +37,7 @@ test('should call onSelect when clicked with id', async () => {
{ children: 'Content 2', id: 'option2', label: 'Option 2' },
];
const onSelect = jest.fn();
const onSelect = vi.fn();
const { findByText } = renderComponent(options, options[1].id, onSelect);

@ -6,9 +6,9 @@ import { HeaderContainer } from './HeaderContainer';
import { HeaderTitle } from './HeaderTitle';
test('should not render without a wrapping HeaderContainer', async () => {
const consoleErrorFn = jest
const consoleErrorFn = vi
.spyOn(console, 'error')
.mockImplementation(() => jest.fn());
.mockImplementation(() => vi.fn());
const title = 'title';
function renderComponent() {

@ -1,3 +1,3 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
exports[`should not render without a wrapping HeaderContainer 1`] = `"Should be nested inside a HeaderContainer component"`;
exports[`should not render without a wrapping HeaderContainer 1`] = `[Error: Should be nested inside a HeaderContainer component]`;

@ -1,4 +1,5 @@
import { http, HttpResponse } from 'msw';
import { Mock } from 'vitest';
import { Tag, TagId } from '@/portainer/tags/types';
import { renderWithQueryClient } from '@/react-tools/test-utils';
@ -43,11 +44,11 @@ async function renderComponent(
{
value = [],
allowCreate = false,
onChange = jest.fn(),
onChange = vi.fn(),
}: {
value?: TagId[];
allowCreate?: boolean;
onChange?: jest.Mock;
onChange?: Mock;
} = {},
tags: Tag[] = []
) {

@ -26,7 +26,7 @@ function renderDefault({
test('should display a Button component and allow onClick', async () => {
const children = 'test label';
const onClick = jest.fn();
const onClick = vi.fn();
const { findByText } = renderDefault({ children, onClick });
const buttonLabel = await findByText(children);

@ -15,7 +15,7 @@ test('should display a CopyButton with children', async () => {
test('CopyButton should copy text to clipboard', async () => {
// override navigator.clipboard.writeText (to test copy to clipboard functionality)
let clipboardText = '';
const writeText = jest.fn((text) => {
const writeText = vi.fn((text) => {
clipboardText = text;
});
Object.assign(navigator, {

@ -3,7 +3,7 @@ import { fireEvent, render } from '@/react-tools/test-utils';
import { FileUploadField } from './FileUploadField';
test('render should make the file button clickable and fire onChange event after click', async () => {
const onClick = jest.fn();
const onClick = vi.fn();
const { findByText, findByLabelText } = render(
<FileUploadField
title="test button"

@ -3,7 +3,7 @@ import { render } from '@/react-tools/test-utils';
import { FileUploadForm } from './FileUploadForm';
test('render should include description', async () => {
const onClick = jest.fn();
const onClick = vi.fn();
const { findByText } = render(
<FileUploadForm
title="test button"

@ -6,7 +6,7 @@ function renderDefault({
name = 'default name',
checked = false,
label = 'label',
onChange = jest.fn(),
onChange = vi.fn(),
index,
}: Partial<Props> = {}) {
return render(
@ -28,7 +28,7 @@ test('should display a Switch component', async () => {
});
test('clicking should emit on-change with the opposite value', async () => {
const onChange = jest.fn();
const onChange = vi.fn();
const checked = true;
const { findByRole } = renderDefault({ onChange, checked });
@ -39,7 +39,7 @@ test('clicking should emit on-change with the opposite value', async () => {
});
test('clicking should emit on-change with the opposite value and index', async () => {
const onChange = jest.fn();
const onChange = vi.fn();
const checked = true;
const index = 3;
const { findByRole } = renderDefault({ onChange, checked, index });

@ -18,9 +18,9 @@ const networkContainers: NetworkContainer[] = [
},
];
jest.mock('@uirouter/react', () => ({
...jest.requireActual('@uirouter/react'),
useCurrentStateAndParams: jest.fn(() => ({
vi.mock('@uirouter/react', async (importOriginal: () => Promise<object>) => ({
...(await importOriginal()),
useCurrentStateAndParams: vi.fn(() => ({
params: { endpointId: 1 },
})),
}));

@ -6,9 +6,9 @@ import { DockerNetwork } from '../types';
import { NetworkDetailsTable } from './NetworkDetailsTable';
jest.mock('@uirouter/react', () => ({
...jest.requireActual('@uirouter/react'),
useCurrentStateAndParams: jest.fn(() => ({
vi.mock('@uirouter/react', async (importOriginal: () => Promise<object>) => ({
...(await importOriginal()),
useCurrentStateAndParams: vi.fn(() => ({
params: { endpointId: 1 },
})),
}));

@ -32,7 +32,7 @@ describe('getValidEditorTypes', () => {
];
tests.forEach((test) => {
// eslint-disable-next-line jest/valid-title
// eslint-disable-next-line vitest/valid-title
it(test.title, () => {
expect(getValidEditorTypes(test.endpointTypes)).toEqual(test.expected);
});

@ -431,7 +431,7 @@ describe('getCreateAppSummaries', () => {
},
];
tests.forEach((test) => {
// eslint-disable-next-line jest/valid-title
// eslint-disable-next-line vitest/valid-title
it(test.title, () => {
expect(
getAppResourceSummaries(test.newFormValues, test.oldFormValues)
@ -507,7 +507,7 @@ describe('getUpdateAppSummaries', () => {
},
];
tests.forEach((test) => {
// eslint-disable-next-line jest/valid-title
// eslint-disable-next-line vitest/valid-title
it(test.title, () => {
expect(
getAppResourceSummaries(test.newFormValues, test.oldFormValues)

@ -51,7 +51,7 @@ async function renderComponent(
const queries = renderWithQueryClient(
<UserContext.Provider value={{ user }}>
<EnvironmentList onClickBrowse={jest.fn()} onRefresh={jest.fn()} />
<EnvironmentList onClickBrowse={vi.fn()} onRefresh={vi.fn()} />
</UserContext.Provider>
);

@ -48,7 +48,7 @@ test.each([
async (ownership) => {
const values = buildFormData(ownership);
const { findByRole } = await renderComponent(values, jest.fn(), {
const { findByRole } = await renderComponent(values, vi.fn(), {
isAdmin: true,
});
@ -76,7 +76,7 @@ test.each([
async (ownership) => {
const values = buildFormData(ownership);
const { findByRole } = await renderComponent(values, jest.fn(), {
const { findByRole } = await renderComponent(values, vi.fn(), {
teams: [],
isAdmin: false,
});
@ -99,7 +99,7 @@ test.each([
async (ownership) => {
const values = buildFormData(ownership);
const { findByRole } = await renderComponent(values, jest.fn(), {
const { findByRole } = await renderComponent(values, vi.fn(), {
teams: createMockTeams(1),
isAdmin: false,
});
@ -124,7 +124,7 @@ test('when ownership is public, ownership selector should be hidden', async () =
test('when hideTitle is true, title should be hidden', async () => {
const values = buildFormData();
const { queryByRole } = await renderComponent(values, jest.fn(), {
const { queryByRole } = await renderComponent(values, vi.fn(), {
hideTitle: true,
});
@ -136,7 +136,7 @@ test('when isAdmin and admin ownership is selected, no extra options are visible
const { findByRole, queryByLabelText } = await renderComponent(
values,
jest.fn(),
vi.fn(),
{
isAdmin: true,
}
@ -162,7 +162,7 @@ test('when isAdmin and restricted ownership is selected, show team and users sel
const { findByRole, findByLabelText } = await renderComponent(
values,
jest.fn(),
vi.fn(),
{
isAdmin: true,
}
@ -200,7 +200,7 @@ test('when user is not an admin, there are more then 1 team and ownership is res
const { findByRole, findByLabelText } = await renderComponent(
values,
jest.fn()
vi.fn()
);
const ownershipSelector = await findByRole('radiogroup');
@ -231,7 +231,7 @@ test('when user is not an admin, there is 1 team and ownership is restricted, te
const { findByRole, findByLabelText } = await renderComponent(
values,
jest.fn(),
vi.fn(),
{
teams: createMockTeams(1),
isAdmin: false,
@ -266,7 +266,7 @@ test('when user is not an admin, and ownership is restricted, user selector not
const { findByRole, findByLabelText } = await renderComponent(
values,
jest.fn(),
vi.fn(),
{
isAdmin: false,
}
@ -300,7 +300,7 @@ interface AdditionalProps {
async function renderComponent(
values: AccessControlFormData,
onChange = jest.fn(),
onChange = vi.fn(),
{ isAdmin = false, hideTitle = false, teams, users }: AdditionalProps = {}
) {
const user = new UserViewModel({ Username: 'user', Role: isAdmin ? 1 : 2 });

@ -1,5 +1,5 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
exports[`when ownership is restricted and no teams or users, should be invalid 1`] = `"You must specify at least one team or user."`;
exports[`when ownership is restricted and no teams or users, should be invalid 1`] = `[ValidationError: You must specify at least one team or user.]`;
exports[`when ownership is restricted and no teams or users, should be invalid 2`] = `"You must specify at least one team."`;
exports[`when ownership is restricted and no teams or users, should be invalid 2`] = `[ValidationError: You must specify at least one team.]`;

@ -7,8 +7,8 @@ import type { License } from './types';
describe('getLicenses', () => {
it('on success should return the server body', async () => {
const catchFn = jest.fn();
const thenFn = jest.fn();
const catchFn = vi.fn();
const thenFn = vi.fn();
const data: License[] = [];
server.use(http.get('/api/licenses', () => HttpResponse.json(data)));
@ -22,8 +22,8 @@ describe('getLicenses', () => {
});
it('on failure should return the server message', async () => {
const catchFn = jest.fn();
const thenFn = jest.fn();
const catchFn = vi.fn();
const thenFn = vi.fn();
const message = 'message';
const details = 'details';

@ -1,42 +0,0 @@
/* eslint-disable import/order */
/* eslint-disable @typescript-eslint/no-var-requires */
/**
* @note The block below contains polyfills for Node.js globals
* required for Jest to function when running JSDOM tests.
* These HAVE to be require's and HAVE to be in this exact
* order, since "undici" depends on the "TextEncoder" global API.
*
* Consider migrating to a more modern test runner if
* you don't want to deal with this.
*/
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
const { TextDecoder, TextEncoder } = require('node:util');
Object.defineProperties(globalThis, {
TextDecoder: { value: TextDecoder },
TextEncoder: { value: TextEncoder },
});
const { ReadableStream } = require('node:stream/web');
Object.defineProperties(globalThis, {
ReadableStream: { value: ReadableStream },
});
const { Blob, File } = require('node:buffer');
const { fetch, Headers, FormData, Request, Response } = require('undici');
Object.defineProperties(globalThis, {
fetch: { value: fetch, writable: true },
Blob: { value: Blob },
File: { value: File },
Headers: { value: Headers },
FormData: { value: FormData },
Request: { value: Request },
Response: { value: Response },
});
/* eslint-enable @typescript-eslint/no-var-requires */
/* eslint-enable import/order */

@ -1,5 +1,3 @@
// test/setup-env.js
// add this to your setupFilesAfterEnv config in jest so it's imported for every test file
import { server } from './server';
beforeAll(() => server.listen());

@ -1,203 +0,0 @@
/*
* For a detailed explanation regarding each configuration property, visit:
* https://jestjs.io/docs/configuration
*/
module.exports = {
// All imported modules in your tests should be mocked automatically
// automock: false,
// Stop running tests after `n` failures
// bail: 0,
// The directory where Jest should store its cached dependency information
// cacheDirectory: "/tmp/jest_rs",
// Automatically clear mock calls and instances between every test
clearMocks: true,
// Indicates whether the coverage information should be collected while executing the test
// collectCoverage: false,
// An array of glob patterns indicating a set of files for which coverage information should be collected
// collectCoverageFrom: undefined,
// The directory where Jest should output its coverage files
// coverageDirectory: undefined,
// An array of regexp pattern strings used to skip coverage collection
// coveragePathIgnorePatterns: [
// "/node_modules/"
// ],
// Indicates which provider should be used to instrument code for coverage
coverageProvider: 'v8',
// A list of reporter names that Jest uses when writing coverage reports
// coverageReporters: [
// "json",
// "text",
// "lcov",
// "clover"
// ],
// An object that configures minimum threshold enforcement for coverage results
// coverageThreshold: undefined,
// A path to a custom dependency extractor
// dependencyExtractor: undefined,
// Make calling deprecated APIs throw helpful error messages
// errorOnDeprecated: false,
// Force coverage collection from ignored files using an array of glob patterns
// forceCoverageMatch: [],
// A path to a module which exports an async function that is triggered once before all test suites
globalSetup: `<rootDir>/app/setup-tests/global-setup.js`,
// A path to a module which exports an async function that is triggered once after all test suites
// globalTeardown: undefined,
// A set of global variables that need to be available in all test environments
// globals: {},
// The maximum amount of workers used to run your tests. Can be specified as % or a number. E.g. maxWorkers: 10% will use 10% of your CPU amount + 1 as the maximum worker number. maxWorkers: 2 will use a maximum of 2 workers.
// maxWorkers: "50%",
// An array of directory names to be searched recursively up from the requiring module's location
// moduleDirectories: [
// "node_modules"
// ],
// An array of file extensions your modules use
// moduleFileExtensions: [
// "js",
// "jsx",
// "ts",
// "tsx",
// "json",
// "node"
// ],
// A map from regular expressions to module names or to arrays of module names that allow to stub out resources with a single module
moduleNameMapper: {
'\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': '<rootDir>/app/__mocks__/fileMock.js',
'\\.svg\\?c$': '<rootDir>/app/__mocks__/svg.tsx',
'\\.(css|less)$': '<rootDir>/app/__mocks__/styleMock.js',
'^@@/(.*)$': '<rootDir>/app/react/components/$1',
'^@/(.*)$': '<rootDir>/app/$1',
'^Agent/(.*)?': '<rootDir>/app/agent/$1',
'^Azure/(.*)$': '<rootDir>/app/azure/$1',
'^Docker/(.*)$': '<rootDir>/app/docker/$1',
'^Kubernetes/(.*)$': '<rootDir>/app/kubernetes/$1',
'^Portainer/(.*)$': '<rootDir>/app/portainer/$1',
},
// An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader
// modulePathIgnorePatterns: [],
// Activates notifications for test results
// notify: false,
// An enum that specifies notification mode. Requires { notify: true }
// notifyMode: "failure-change",
// A preset that is used as a base for Jest's configuration
// preset: undefined,
// Run tests from one or more projects
// projects: undefined,
// Use this configuration option to add custom reporters to Jest
// reporters: undefined,
// Automatically reset mock state between every test
// resetMocks: false,
// Reset the module registry before running each individual test
// resetModules: false,
// A path to a custom resolver
// resolver: undefined,
// Automatically restore mock state between every test
// restoreMocks: false,
// The root directory that Jest should scan for tests and modules within
// rootDir: undefined,
// A list of paths to directories that Jest should use to search for files in
roots: ['<rootDir>/app'],
// Allows you to use a custom runner instead of Jest's default test runner
// runner: "jest-runner",
// The paths to modules that run some code to configure or set up the testing environment before each test
setupFiles: ['<rootDir>/app/setup-tests/jest-polyfills.ts'],
// A list of paths to modules that run some code to configure or set up the testing framework before each test
setupFilesAfterEnv: ['<rootDir>/app/setup-tests/setup-msw.ts'],
// The number of seconds after which a test is considered as slow and reported as such in the results.
// slowTestThreshold: 5,
// A list of paths to snapshot serializer modules Jest should use for snapshot testing
// snapshotSerializers: [],
// The test environment that will be used for testing
testEnvironment: 'jsdom', //"jest-environment-node",
// Options that will be passed to the testEnvironment
// testEnvironmentOptions: {},
// Adds a location field to test results
// testLocationInResults: false,
// The glob patterns Jest uses to detect test files
// testMatch: [
// "**/__tests__/**/*.[jt]s?(x)",
// "**/?(*.)+(spec|test).[tj]s?(x)"
// ],
// An array of regexp pattern strings that are matched against all test paths, matched tests are skipped
// testPathIgnorePatterns: [
// "/node_modules/"
// ],
// The regexp pattern or array of patterns that Jest uses to detect test files
// testRegex: [],
// This option allows the use of a custom results processor
// testResultsProcessor: undefined,
// This option allows use of a custom test runner
// testRunner: "jest-circus/runner",
// This option sets the URL for the jsdom environment. It is reflected in properties such as location.href
// testURL: "http://localhost",
// Setting this value to "fake" allows the use of fake timers for functions such as "setTimeout"
// timers: "real",
// A map from regular expressions to paths to transformers
// transform: undefined,
// An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation
transformIgnorePatterns: [],
// "/node_modules/",
// "\\.pnp\\.[^\\/]+$"
// ],
// An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them
// unmockedModulePathPatterns: undefined,
// Indicates whether each individual test should be reported during the run
// verbose: undefined,
// An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode
// watchPathIgnorePatterns: [],
// Whether to use watchman for file crawling
// watchman: true,
};

@ -2,19 +2,8 @@
"compilerOptions": {
"target": "es2017",
"allowSyntheticDefaultImports": false,
"baseUrl": "app",
"module": "commonjs",
"paths": {
"Agent/*": ["agent/*"],
"Azure/*": ["azure/*"],
"Docker/*": ["docker/*"],
"Kubernetes/*": ["kubernetes/*"],
"Portainer/*": ["portainer/*"],
"@/*": ["../app/*"]
}
"module": "commonjs"
},
"exclude": ["api", "build", "dist", "distribution", "node_modules", "test", "webpack"],
"typeAcquisition": {
"include": ["jest"]
}
"extends": "./tsconfig.json"
}

@ -22,7 +22,7 @@
"build": "webpack",
"format": "prettier --log-level warn --write \"**/*.{js,css,html,jsx,tsx,ts,json}\"",
"lint": "eslint --cache --fix './**/*.{js,jsx,ts,tsx}'",
"test": "jest",
"test": "vitest",
"sb": "yarn storybook",
"storybook": "storybook dev -p 6006",
"storybook:build": "storybook build -o ./dist/storybook",
@ -79,6 +79,7 @@
"babel-plugin-angularjs-annotate": "^0.10.0",
"bootstrap": "^3.4.0",
"buffer": "^6.0.3",
"c8": "^9.1.0",
"chardet": "^1.4.0",
"chart.js": "^2.7.0",
"clsx": "^1.1.1",
@ -97,6 +98,7 @@
"jquery": "^3.6.0",
"js-base64": "^3.7.2",
"js-yaml": "^3.14.0",
"jsdom": "^24.0.0",
"lodash": "^4.17.21",
"lucide-react": "^0.101.0",
"moment": "^2.29.1",
@ -139,13 +141,12 @@
"@storybook/react": "^7.0.18",
"@storybook/react-webpack5": "^7.0.18",
"@svgr/webpack": "^8.1.0",
"@testing-library/jest-dom": "^5.16.1",
"@testing-library/react": "^12.1.2",
"@testing-library/dom": "^9.3.4",
"@testing-library/react": "^12",
"@testing-library/user-event": "^13.5.0",
"@types/angular": "^1.8.3",
"@types/file-saver": "^2.0.4",
"@types/filesize-parser": "^1.5.1",
"@types/jest": "^27.0.3",
"@types/jquery": "^3.5.10",
"@types/mustache": "^4.1.2",
"@types/nprogress": "^0.2.0",
@ -160,7 +161,6 @@
"@typescript-eslint/parser": "^6.7.4",
"auto-ngtemplate-loader": "^3.1.2",
"autoprefixer": "^10.4.16",
"babel-jest": "^29.5.0",
"babel-loader": "^9.1.3",
"babel-plugin-i18next-extract": "^0.9.0",
"babel-plugin-lodash": "^3.3.4",
@ -176,17 +176,16 @@
"eslint-import-resolver-alias": "^1.1.2",
"eslint-plugin-eslint-comments": "^3.2.0",
"eslint-plugin-import": "^2.28.1",
"eslint-plugin-jest": "^27.4.2",
"eslint-plugin-jsx-a11y": "^6.7.1",
"eslint-plugin-promise": "^6.1.1",
"eslint-plugin-react": "^7.33.2",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-regex": "^1.10.0",
"eslint-plugin-storybook": "^0.6.14",
"eslint-plugin-vitest": "^0.3.20",
"html-loader": "^0.5.5",
"html-webpack-plugin": "^5.5.3",
"husky": "^8.0.0",
"jest": "^27.4.3",
"kubernetes-types": "^1.26.0",
"lint-staged": "^14.0.1",
"lodash-webpack-plugin": "^0.11.6",
@ -199,7 +198,6 @@
"prettier": "^3.0.3",
"prettier-plugin-tailwindcss": "^0.5.4",
"react-docgen-typescript-plugin": "^1.0.5",
"react-test-renderer": "^17.0.2",
"source-map-loader": "^4.0.1",
"speed-measure-webpack-plugin": "^1.5.0",
"storybook": "^7.0.18",
@ -210,6 +208,10 @@
"tsconfig-paths-webpack-plugin": "^4.1.0",
"typescript": "^5.2.2",
"undici": "^6.2.1",
"vite-plugin-svgr": "^4.2.0",
"vite-tsconfig-paths": "^4.3.1",
"vitest": "^1.2.1",
"vitest-dom": "^0.1.1",
"webpack": "^5.88.2",
"webpack-build-notifier": "^2.3.0",
"webpack-bundle-analyzer": "^4.9.1",

@ -37,11 +37,9 @@
"Docker/*": ["docker/*"],
"Kubernetes/*": ["kubernetes/*"],
"Portainer/*": ["portainer/*"]
}
},
"types": ["vitest/globals"]
},
"exclude": ["api", "build", "dist", "distribution", "node_modules", "test", "webpack"],
"include": ["app"],
"typeAcquisition": {
"include": ["jest"]
}
"include": ["app"]
}

@ -0,0 +1,22 @@
/// <reference types="vitest" />
import { defineConfig } from 'vite';
import tsconfigPaths from 'vite-tsconfig-paths';
import svgr from 'vite-plugin-svgr';
export default defineConfig({
test: {
globals: true,
environment: 'jsdom',
setupFiles: [
'./app/setup-tests/global-setup.js',
'./app/setup-tests/setup-msw.ts',
],
coverage: {
reporter: ['text', 'html'],
exclude: ['node_modules/', 'app/setup-tests/global-setup.js'],
},
bail: 2,
include: ['./app/**/*.test.ts', './app/**/*.test.tsx'],
},
plugins: [svgr({ include: /\?c$/ }), tsconfigPaths()],
});

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save