mirror of https://github.com/portainer/portainer
feat(ci): replace jest with vitest [EE-6504] (#10997)
parent
4a19871fcc
commit
69c06bc756
|
@ -116,10 +116,9 @@ overrides:
|
||||||
- files:
|
- files:
|
||||||
- app/**/*.test.*
|
- app/**/*.test.*
|
||||||
extends:
|
extends:
|
||||||
- 'plugin:jest/recommended'
|
- 'plugin:vitest/recommended'
|
||||||
- 'plugin:jest/style'
|
|
||||||
env:
|
env:
|
||||||
'jest/globals': true
|
'vitest/env': true
|
||||||
rules:
|
rules:
|
||||||
'react/jsx-no-constructed-context-values': off
|
'react/jsx-no-constructed-context-values': off
|
||||||
- files:
|
- files:
|
||||||
|
|
|
@ -27,7 +27,7 @@ jobs:
|
||||||
- run: yarn --frozen-lockfile
|
- run: yarn --frozen-lockfile
|
||||||
|
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
run: make test-client ARGS="--maxWorkers=2"
|
run: make test-client ARGS="--maxWorkers=2 --minWorkers=1"
|
||||||
test-server:
|
test-server:
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
|
|
|
@ -27,10 +27,9 @@ export function mockT(i18nKey: string, args?: Record<string, string>) {
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
const i18next: Record<string, unknown> = jest.createMockFromModule('i18next');
|
export default {
|
||||||
i18next.t = mockT;
|
t: mockT,
|
||||||
i18next.language = 'en';
|
language: 'en',
|
||||||
i18next.changeLanguage = () => new Promise(() => {});
|
changeLanguage: () => new Promise(() => {}),
|
||||||
i18next.use = () => i18next;
|
use: () => this,
|
||||||
|
};
|
||||||
export default i18next;
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ describe('promiseSequence', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('provided two promise functions, the second should run after the first', async () => {
|
it('provided two promise functions, the second should run after the first', async () => {
|
||||||
const callback = jest.fn();
|
const callback = vi.fn();
|
||||||
|
|
||||||
function first() {
|
function first() {
|
||||||
return Promise.resolve(callback(1));
|
return Promise.resolve(callback(1));
|
||||||
|
|
|
@ -2,10 +2,11 @@ import toastr from 'toastr';
|
||||||
|
|
||||||
import { notifyError, notifySuccess, notifyWarning } from './notifications';
|
import { notifyError, notifySuccess, notifyWarning } from './notifications';
|
||||||
|
|
||||||
jest.mock('toastr');
|
vi.mock('toastr');
|
||||||
|
vi.spyOn(console, 'error').mockImplementation(() => vi.fn());
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
jest.resetAllMocks();
|
vi.resetAllMocks();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('calling success should show success message', () => {
|
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', () => {
|
it('calling error with Error should show error message', () => {
|
||||||
const consoleErrorFn = jest
|
const consoleErrorFn = vi
|
||||||
.spyOn(console, 'error')
|
.spyOn(console, 'error')
|
||||||
.mockImplementation(() => jest.fn());
|
.mockImplementation(() => vi.fn());
|
||||||
const title = 'title';
|
const title = 'title';
|
||||||
const errorMessage = 'message';
|
const errorMessage = 'message';
|
||||||
const fallback = 'fallback';
|
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', () => {
|
it('calling error without Error should show fallback message', () => {
|
||||||
const consoleErrorFn = jest
|
const consoleErrorFn = vi
|
||||||
.spyOn(console, 'error')
|
.spyOn(console, 'error')
|
||||||
.mockImplementation(() => jest.fn());
|
.mockImplementation(() => vi.fn());
|
||||||
const title = 'title';
|
const title = 'title';
|
||||||
|
|
||||||
const fallback = 'fallback';
|
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 { render, RenderOptions } from '@testing-library/react';
|
||||||
import { UIRouter, pushStateLocationPlugin } from '@uirouter/react';
|
import { UIRouter, pushStateLocationPlugin } from '@uirouter/react';
|
||||||
import { PropsWithChildren, ReactElement } from 'react';
|
import { PropsWithChildren, ReactElement } from 'react';
|
||||||
|
|
|
@ -11,9 +11,9 @@ import {
|
||||||
|
|
||||||
import { DashboardView } from './DashboardView';
|
import { DashboardView } from './DashboardView';
|
||||||
|
|
||||||
jest.mock('@uirouter/react', () => ({
|
vi.mock('@uirouter/react', async (importOriginal: () => Promise<object>) => ({
|
||||||
...jest.requireActual('@uirouter/react'),
|
...(await importOriginal()),
|
||||||
useCurrentStateAndParams: jest.fn(() => ({
|
useCurrentStateAndParams: vi.fn(() => ({
|
||||||
params: { endpointId: 1 },
|
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 () => {
|
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(
|
const { queryByLabelText } = await renderComponent(
|
||||||
1,
|
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 () => {
|
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(
|
const { queryByLabelText, findByLabelText } = await renderComponent(
|
||||||
1,
|
1,
|
||||||
|
|
|
@ -6,9 +6,9 @@ import { renderWithQueryClient } from '@/react-tools/test-utils';
|
||||||
|
|
||||||
import { CreateContainerInstanceForm } from './CreateContainerInstanceForm';
|
import { CreateContainerInstanceForm } from './CreateContainerInstanceForm';
|
||||||
|
|
||||||
jest.mock('@uirouter/react', () => ({
|
vi.mock('@uirouter/react', async (importOriginal: () => Promise<object>) => ({
|
||||||
...jest.requireActual('@uirouter/react'),
|
...(await importOriginal()),
|
||||||
useCurrentStateAndParams: jest.fn(() => ({
|
useCurrentStateAndParams: vi.fn(() => ({
|
||||||
params: { endpointId: 5 },
|
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({
|
const { getByLabelText } = renderDefault({
|
||||||
options,
|
options,
|
||||||
onChange,
|
onChange,
|
||||||
|
|
|
@ -37,7 +37,7 @@ test('should call onSelect when clicked with id', async () => {
|
||||||
{ children: 'Content 2', id: 'option2', label: 'Option 2' },
|
{ children: 'Content 2', id: 'option2', label: 'Option 2' },
|
||||||
];
|
];
|
||||||
|
|
||||||
const onSelect = jest.fn();
|
const onSelect = vi.fn();
|
||||||
|
|
||||||
const { findByText } = renderComponent(options, options[1].id, onSelect);
|
const { findByText } = renderComponent(options, options[1].id, onSelect);
|
||||||
|
|
||||||
|
|
|
@ -6,9 +6,9 @@ import { HeaderContainer } from './HeaderContainer';
|
||||||
import { HeaderTitle } from './HeaderTitle';
|
import { HeaderTitle } from './HeaderTitle';
|
||||||
|
|
||||||
test('should not render without a wrapping HeaderContainer', async () => {
|
test('should not render without a wrapping HeaderContainer', async () => {
|
||||||
const consoleErrorFn = jest
|
const consoleErrorFn = vi
|
||||||
.spyOn(console, 'error')
|
.spyOn(console, 'error')
|
||||||
.mockImplementation(() => jest.fn());
|
.mockImplementation(() => vi.fn());
|
||||||
|
|
||||||
const title = 'title';
|
const title = 'title';
|
||||||
function renderComponent() {
|
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 { http, HttpResponse } from 'msw';
|
||||||
|
import { Mock } from 'vitest';
|
||||||
|
|
||||||
import { Tag, TagId } from '@/portainer/tags/types';
|
import { Tag, TagId } from '@/portainer/tags/types';
|
||||||
import { renderWithQueryClient } from '@/react-tools/test-utils';
|
import { renderWithQueryClient } from '@/react-tools/test-utils';
|
||||||
|
@ -43,11 +44,11 @@ async function renderComponent(
|
||||||
{
|
{
|
||||||
value = [],
|
value = [],
|
||||||
allowCreate = false,
|
allowCreate = false,
|
||||||
onChange = jest.fn(),
|
onChange = vi.fn(),
|
||||||
}: {
|
}: {
|
||||||
value?: TagId[];
|
value?: TagId[];
|
||||||
allowCreate?: boolean;
|
allowCreate?: boolean;
|
||||||
onChange?: jest.Mock;
|
onChange?: Mock;
|
||||||
} = {},
|
} = {},
|
||||||
tags: Tag[] = []
|
tags: Tag[] = []
|
||||||
) {
|
) {
|
||||||
|
|
|
@ -26,7 +26,7 @@ function renderDefault({
|
||||||
|
|
||||||
test('should display a Button component and allow onClick', async () => {
|
test('should display a Button component and allow onClick', async () => {
|
||||||
const children = 'test label';
|
const children = 'test label';
|
||||||
const onClick = jest.fn();
|
const onClick = vi.fn();
|
||||||
const { findByText } = renderDefault({ children, onClick });
|
const { findByText } = renderDefault({ children, onClick });
|
||||||
|
|
||||||
const buttonLabel = await findByText(children);
|
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 () => {
|
test('CopyButton should copy text to clipboard', async () => {
|
||||||
// override navigator.clipboard.writeText (to test copy to clipboard functionality)
|
// override navigator.clipboard.writeText (to test copy to clipboard functionality)
|
||||||
let clipboardText = '';
|
let clipboardText = '';
|
||||||
const writeText = jest.fn((text) => {
|
const writeText = vi.fn((text) => {
|
||||||
clipboardText = text;
|
clipboardText = text;
|
||||||
});
|
});
|
||||||
Object.assign(navigator, {
|
Object.assign(navigator, {
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { fireEvent, render } from '@/react-tools/test-utils';
|
||||||
import { FileUploadField } from './FileUploadField';
|
import { FileUploadField } from './FileUploadField';
|
||||||
|
|
||||||
test('render should make the file button clickable and fire onChange event after click', async () => {
|
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(
|
const { findByText, findByLabelText } = render(
|
||||||
<FileUploadField
|
<FileUploadField
|
||||||
title="test button"
|
title="test button"
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { render } from '@/react-tools/test-utils';
|
||||||
import { FileUploadForm } from './FileUploadForm';
|
import { FileUploadForm } from './FileUploadForm';
|
||||||
|
|
||||||
test('render should include description', async () => {
|
test('render should include description', async () => {
|
||||||
const onClick = jest.fn();
|
const onClick = vi.fn();
|
||||||
const { findByText } = render(
|
const { findByText } = render(
|
||||||
<FileUploadForm
|
<FileUploadForm
|
||||||
title="test button"
|
title="test button"
|
||||||
|
|
|
@ -6,7 +6,7 @@ function renderDefault({
|
||||||
name = 'default name',
|
name = 'default name',
|
||||||
checked = false,
|
checked = false,
|
||||||
label = 'label',
|
label = 'label',
|
||||||
onChange = jest.fn(),
|
onChange = vi.fn(),
|
||||||
index,
|
index,
|
||||||
}: Partial<Props> = {}) {
|
}: Partial<Props> = {}) {
|
||||||
return render(
|
return render(
|
||||||
|
@ -28,7 +28,7 @@ test('should display a Switch component', async () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('clicking should emit on-change with the opposite value', async () => {
|
test('clicking should emit on-change with the opposite value', async () => {
|
||||||
const onChange = jest.fn();
|
const onChange = vi.fn();
|
||||||
const checked = true;
|
const checked = true;
|
||||||
const { findByRole } = renderDefault({ onChange, checked });
|
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 () => {
|
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 checked = true;
|
||||||
const index = 3;
|
const index = 3;
|
||||||
const { findByRole } = renderDefault({ onChange, checked, index });
|
const { findByRole } = renderDefault({ onChange, checked, index });
|
||||||
|
|
|
@ -18,9 +18,9 @@ const networkContainers: NetworkContainer[] = [
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
jest.mock('@uirouter/react', () => ({
|
vi.mock('@uirouter/react', async (importOriginal: () => Promise<object>) => ({
|
||||||
...jest.requireActual('@uirouter/react'),
|
...(await importOriginal()),
|
||||||
useCurrentStateAndParams: jest.fn(() => ({
|
useCurrentStateAndParams: vi.fn(() => ({
|
||||||
params: { endpointId: 1 },
|
params: { endpointId: 1 },
|
||||||
})),
|
})),
|
||||||
}));
|
}));
|
||||||
|
|
|
@ -6,9 +6,9 @@ import { DockerNetwork } from '../types';
|
||||||
|
|
||||||
import { NetworkDetailsTable } from './NetworkDetailsTable';
|
import { NetworkDetailsTable } from './NetworkDetailsTable';
|
||||||
|
|
||||||
jest.mock('@uirouter/react', () => ({
|
vi.mock('@uirouter/react', async (importOriginal: () => Promise<object>) => ({
|
||||||
...jest.requireActual('@uirouter/react'),
|
...(await importOriginal()),
|
||||||
useCurrentStateAndParams: jest.fn(() => ({
|
useCurrentStateAndParams: vi.fn(() => ({
|
||||||
params: { endpointId: 1 },
|
params: { endpointId: 1 },
|
||||||
})),
|
})),
|
||||||
}));
|
}));
|
||||||
|
|
|
@ -32,7 +32,7 @@ describe('getValidEditorTypes', () => {
|
||||||
];
|
];
|
||||||
|
|
||||||
tests.forEach((test) => {
|
tests.forEach((test) => {
|
||||||
// eslint-disable-next-line jest/valid-title
|
// eslint-disable-next-line vitest/valid-title
|
||||||
it(test.title, () => {
|
it(test.title, () => {
|
||||||
expect(getValidEditorTypes(test.endpointTypes)).toEqual(test.expected);
|
expect(getValidEditorTypes(test.endpointTypes)).toEqual(test.expected);
|
||||||
});
|
});
|
||||||
|
|
|
@ -431,7 +431,7 @@ describe('getCreateAppSummaries', () => {
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
tests.forEach((test) => {
|
tests.forEach((test) => {
|
||||||
// eslint-disable-next-line jest/valid-title
|
// eslint-disable-next-line vitest/valid-title
|
||||||
it(test.title, () => {
|
it(test.title, () => {
|
||||||
expect(
|
expect(
|
||||||
getAppResourceSummaries(test.newFormValues, test.oldFormValues)
|
getAppResourceSummaries(test.newFormValues, test.oldFormValues)
|
||||||
|
@ -507,7 +507,7 @@ describe('getUpdateAppSummaries', () => {
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
tests.forEach((test) => {
|
tests.forEach((test) => {
|
||||||
// eslint-disable-next-line jest/valid-title
|
// eslint-disable-next-line vitest/valid-title
|
||||||
it(test.title, () => {
|
it(test.title, () => {
|
||||||
expect(
|
expect(
|
||||||
getAppResourceSummaries(test.newFormValues, test.oldFormValues)
|
getAppResourceSummaries(test.newFormValues, test.oldFormValues)
|
||||||
|
|
|
@ -51,7 +51,7 @@ async function renderComponent(
|
||||||
|
|
||||||
const queries = renderWithQueryClient(
|
const queries = renderWithQueryClient(
|
||||||
<UserContext.Provider value={{ user }}>
|
<UserContext.Provider value={{ user }}>
|
||||||
<EnvironmentList onClickBrowse={jest.fn()} onRefresh={jest.fn()} />
|
<EnvironmentList onClickBrowse={vi.fn()} onRefresh={vi.fn()} />
|
||||||
</UserContext.Provider>
|
</UserContext.Provider>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -48,7 +48,7 @@ test.each([
|
||||||
async (ownership) => {
|
async (ownership) => {
|
||||||
const values = buildFormData(ownership);
|
const values = buildFormData(ownership);
|
||||||
|
|
||||||
const { findByRole } = await renderComponent(values, jest.fn(), {
|
const { findByRole } = await renderComponent(values, vi.fn(), {
|
||||||
isAdmin: true,
|
isAdmin: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -76,7 +76,7 @@ test.each([
|
||||||
async (ownership) => {
|
async (ownership) => {
|
||||||
const values = buildFormData(ownership);
|
const values = buildFormData(ownership);
|
||||||
|
|
||||||
const { findByRole } = await renderComponent(values, jest.fn(), {
|
const { findByRole } = await renderComponent(values, vi.fn(), {
|
||||||
teams: [],
|
teams: [],
|
||||||
isAdmin: false,
|
isAdmin: false,
|
||||||
});
|
});
|
||||||
|
@ -99,7 +99,7 @@ test.each([
|
||||||
async (ownership) => {
|
async (ownership) => {
|
||||||
const values = buildFormData(ownership);
|
const values = buildFormData(ownership);
|
||||||
|
|
||||||
const { findByRole } = await renderComponent(values, jest.fn(), {
|
const { findByRole } = await renderComponent(values, vi.fn(), {
|
||||||
teams: createMockTeams(1),
|
teams: createMockTeams(1),
|
||||||
isAdmin: false,
|
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 () => {
|
test('when hideTitle is true, title should be hidden', async () => {
|
||||||
const values = buildFormData();
|
const values = buildFormData();
|
||||||
|
|
||||||
const { queryByRole } = await renderComponent(values, jest.fn(), {
|
const { queryByRole } = await renderComponent(values, vi.fn(), {
|
||||||
hideTitle: true,
|
hideTitle: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -136,7 +136,7 @@ test('when isAdmin and admin ownership is selected, no extra options are visible
|
||||||
|
|
||||||
const { findByRole, queryByLabelText } = await renderComponent(
|
const { findByRole, queryByLabelText } = await renderComponent(
|
||||||
values,
|
values,
|
||||||
jest.fn(),
|
vi.fn(),
|
||||||
{
|
{
|
||||||
isAdmin: true,
|
isAdmin: true,
|
||||||
}
|
}
|
||||||
|
@ -162,7 +162,7 @@ test('when isAdmin and restricted ownership is selected, show team and users sel
|
||||||
|
|
||||||
const { findByRole, findByLabelText } = await renderComponent(
|
const { findByRole, findByLabelText } = await renderComponent(
|
||||||
values,
|
values,
|
||||||
jest.fn(),
|
vi.fn(),
|
||||||
{
|
{
|
||||||
isAdmin: true,
|
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(
|
const { findByRole, findByLabelText } = await renderComponent(
|
||||||
values,
|
values,
|
||||||
jest.fn()
|
vi.fn()
|
||||||
);
|
);
|
||||||
|
|
||||||
const ownershipSelector = await findByRole('radiogroup');
|
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(
|
const { findByRole, findByLabelText } = await renderComponent(
|
||||||
values,
|
values,
|
||||||
jest.fn(),
|
vi.fn(),
|
||||||
{
|
{
|
||||||
teams: createMockTeams(1),
|
teams: createMockTeams(1),
|
||||||
isAdmin: false,
|
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(
|
const { findByRole, findByLabelText } = await renderComponent(
|
||||||
values,
|
values,
|
||||||
jest.fn(),
|
vi.fn(),
|
||||||
{
|
{
|
||||||
isAdmin: false,
|
isAdmin: false,
|
||||||
}
|
}
|
||||||
|
@ -300,7 +300,7 @@ interface AdditionalProps {
|
||||||
|
|
||||||
async function renderComponent(
|
async function renderComponent(
|
||||||
values: AccessControlFormData,
|
values: AccessControlFormData,
|
||||||
onChange = jest.fn(),
|
onChange = vi.fn(),
|
||||||
{ isAdmin = false, hideTitle = false, teams, users }: AdditionalProps = {}
|
{ isAdmin = false, hideTitle = false, teams, users }: AdditionalProps = {}
|
||||||
) {
|
) {
|
||||||
const user = new UserViewModel({ Username: 'user', Role: isAdmin ? 1 : 2 });
|
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', () => {
|
describe('getLicenses', () => {
|
||||||
it('on success should return the server body', async () => {
|
it('on success should return the server body', async () => {
|
||||||
const catchFn = jest.fn();
|
const catchFn = vi.fn();
|
||||||
const thenFn = jest.fn();
|
const thenFn = vi.fn();
|
||||||
|
|
||||||
const data: License[] = [];
|
const data: License[] = [];
|
||||||
server.use(http.get('/api/licenses', () => HttpResponse.json(data)));
|
server.use(http.get('/api/licenses', () => HttpResponse.json(data)));
|
||||||
|
@ -22,8 +22,8 @@ describe('getLicenses', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('on failure should return the server message', async () => {
|
it('on failure should return the server message', async () => {
|
||||||
const catchFn = jest.fn();
|
const catchFn = vi.fn();
|
||||||
const thenFn = jest.fn();
|
const thenFn = vi.fn();
|
||||||
|
|
||||||
const message = 'message';
|
const message = 'message';
|
||||||
const details = 'details';
|
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';
|
import { server } from './server';
|
||||||
|
|
||||||
beforeAll(() => server.listen());
|
beforeAll(() => server.listen());
|
||||||
|
|
203
jest.config.js
203
jest.config.js
|
@ -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": {
|
"compilerOptions": {
|
||||||
"target": "es2017",
|
"target": "es2017",
|
||||||
"allowSyntheticDefaultImports": false,
|
"allowSyntheticDefaultImports": false,
|
||||||
"baseUrl": "app",
|
"module": "commonjs"
|
||||||
"module": "commonjs",
|
|
||||||
"paths": {
|
|
||||||
"Agent/*": ["agent/*"],
|
|
||||||
"Azure/*": ["azure/*"],
|
|
||||||
"Docker/*": ["docker/*"],
|
|
||||||
"Kubernetes/*": ["kubernetes/*"],
|
|
||||||
"Portainer/*": ["portainer/*"],
|
|
||||||
"@/*": ["../app/*"]
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"exclude": ["api", "build", "dist", "distribution", "node_modules", "test", "webpack"],
|
|
||||||
"typeAcquisition": {
|
"extends": "./tsconfig.json"
|
||||||
"include": ["jest"]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
18
package.json
18
package.json
|
@ -22,7 +22,7 @@
|
||||||
"build": "webpack",
|
"build": "webpack",
|
||||||
"format": "prettier --log-level warn --write \"**/*.{js,css,html,jsx,tsx,ts,json}\"",
|
"format": "prettier --log-level warn --write \"**/*.{js,css,html,jsx,tsx,ts,json}\"",
|
||||||
"lint": "eslint --cache --fix './**/*.{js,jsx,ts,tsx}'",
|
"lint": "eslint --cache --fix './**/*.{js,jsx,ts,tsx}'",
|
||||||
"test": "jest",
|
"test": "vitest",
|
||||||
"sb": "yarn storybook",
|
"sb": "yarn storybook",
|
||||||
"storybook": "storybook dev -p 6006",
|
"storybook": "storybook dev -p 6006",
|
||||||
"storybook:build": "storybook build -o ./dist/storybook",
|
"storybook:build": "storybook build -o ./dist/storybook",
|
||||||
|
@ -79,6 +79,7 @@
|
||||||
"babel-plugin-angularjs-annotate": "^0.10.0",
|
"babel-plugin-angularjs-annotate": "^0.10.0",
|
||||||
"bootstrap": "^3.4.0",
|
"bootstrap": "^3.4.0",
|
||||||
"buffer": "^6.0.3",
|
"buffer": "^6.0.3",
|
||||||
|
"c8": "^9.1.0",
|
||||||
"chardet": "^1.4.0",
|
"chardet": "^1.4.0",
|
||||||
"chart.js": "^2.7.0",
|
"chart.js": "^2.7.0",
|
||||||
"clsx": "^1.1.1",
|
"clsx": "^1.1.1",
|
||||||
|
@ -97,6 +98,7 @@
|
||||||
"jquery": "^3.6.0",
|
"jquery": "^3.6.0",
|
||||||
"js-base64": "^3.7.2",
|
"js-base64": "^3.7.2",
|
||||||
"js-yaml": "^3.14.0",
|
"js-yaml": "^3.14.0",
|
||||||
|
"jsdom": "^24.0.0",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"lucide-react": "^0.101.0",
|
"lucide-react": "^0.101.0",
|
||||||
"moment": "^2.29.1",
|
"moment": "^2.29.1",
|
||||||
|
@ -139,13 +141,12 @@
|
||||||
"@storybook/react": "^7.0.18",
|
"@storybook/react": "^7.0.18",
|
||||||
"@storybook/react-webpack5": "^7.0.18",
|
"@storybook/react-webpack5": "^7.0.18",
|
||||||
"@svgr/webpack": "^8.1.0",
|
"@svgr/webpack": "^8.1.0",
|
||||||
"@testing-library/jest-dom": "^5.16.1",
|
"@testing-library/dom": "^9.3.4",
|
||||||
"@testing-library/react": "^12.1.2",
|
"@testing-library/react": "^12",
|
||||||
"@testing-library/user-event": "^13.5.0",
|
"@testing-library/user-event": "^13.5.0",
|
||||||
"@types/angular": "^1.8.3",
|
"@types/angular": "^1.8.3",
|
||||||
"@types/file-saver": "^2.0.4",
|
"@types/file-saver": "^2.0.4",
|
||||||
"@types/filesize-parser": "^1.5.1",
|
"@types/filesize-parser": "^1.5.1",
|
||||||
"@types/jest": "^27.0.3",
|
|
||||||
"@types/jquery": "^3.5.10",
|
"@types/jquery": "^3.5.10",
|
||||||
"@types/mustache": "^4.1.2",
|
"@types/mustache": "^4.1.2",
|
||||||
"@types/nprogress": "^0.2.0",
|
"@types/nprogress": "^0.2.0",
|
||||||
|
@ -160,7 +161,6 @@
|
||||||
"@typescript-eslint/parser": "^6.7.4",
|
"@typescript-eslint/parser": "^6.7.4",
|
||||||
"auto-ngtemplate-loader": "^3.1.2",
|
"auto-ngtemplate-loader": "^3.1.2",
|
||||||
"autoprefixer": "^10.4.16",
|
"autoprefixer": "^10.4.16",
|
||||||
"babel-jest": "^29.5.0",
|
|
||||||
"babel-loader": "^9.1.3",
|
"babel-loader": "^9.1.3",
|
||||||
"babel-plugin-i18next-extract": "^0.9.0",
|
"babel-plugin-i18next-extract": "^0.9.0",
|
||||||
"babel-plugin-lodash": "^3.3.4",
|
"babel-plugin-lodash": "^3.3.4",
|
||||||
|
@ -176,17 +176,16 @@
|
||||||
"eslint-import-resolver-alias": "^1.1.2",
|
"eslint-import-resolver-alias": "^1.1.2",
|
||||||
"eslint-plugin-eslint-comments": "^3.2.0",
|
"eslint-plugin-eslint-comments": "^3.2.0",
|
||||||
"eslint-plugin-import": "^2.28.1",
|
"eslint-plugin-import": "^2.28.1",
|
||||||
"eslint-plugin-jest": "^27.4.2",
|
|
||||||
"eslint-plugin-jsx-a11y": "^6.7.1",
|
"eslint-plugin-jsx-a11y": "^6.7.1",
|
||||||
"eslint-plugin-promise": "^6.1.1",
|
"eslint-plugin-promise": "^6.1.1",
|
||||||
"eslint-plugin-react": "^7.33.2",
|
"eslint-plugin-react": "^7.33.2",
|
||||||
"eslint-plugin-react-hooks": "^4.6.0",
|
"eslint-plugin-react-hooks": "^4.6.0",
|
||||||
"eslint-plugin-regex": "^1.10.0",
|
"eslint-plugin-regex": "^1.10.0",
|
||||||
"eslint-plugin-storybook": "^0.6.14",
|
"eslint-plugin-storybook": "^0.6.14",
|
||||||
|
"eslint-plugin-vitest": "^0.3.20",
|
||||||
"html-loader": "^0.5.5",
|
"html-loader": "^0.5.5",
|
||||||
"html-webpack-plugin": "^5.5.3",
|
"html-webpack-plugin": "^5.5.3",
|
||||||
"husky": "^8.0.0",
|
"husky": "^8.0.0",
|
||||||
"jest": "^27.4.3",
|
|
||||||
"kubernetes-types": "^1.26.0",
|
"kubernetes-types": "^1.26.0",
|
||||||
"lint-staged": "^14.0.1",
|
"lint-staged": "^14.0.1",
|
||||||
"lodash-webpack-plugin": "^0.11.6",
|
"lodash-webpack-plugin": "^0.11.6",
|
||||||
|
@ -199,7 +198,6 @@
|
||||||
"prettier": "^3.0.3",
|
"prettier": "^3.0.3",
|
||||||
"prettier-plugin-tailwindcss": "^0.5.4",
|
"prettier-plugin-tailwindcss": "^0.5.4",
|
||||||
"react-docgen-typescript-plugin": "^1.0.5",
|
"react-docgen-typescript-plugin": "^1.0.5",
|
||||||
"react-test-renderer": "^17.0.2",
|
|
||||||
"source-map-loader": "^4.0.1",
|
"source-map-loader": "^4.0.1",
|
||||||
"speed-measure-webpack-plugin": "^1.5.0",
|
"speed-measure-webpack-plugin": "^1.5.0",
|
||||||
"storybook": "^7.0.18",
|
"storybook": "^7.0.18",
|
||||||
|
@ -210,6 +208,10 @@
|
||||||
"tsconfig-paths-webpack-plugin": "^4.1.0",
|
"tsconfig-paths-webpack-plugin": "^4.1.0",
|
||||||
"typescript": "^5.2.2",
|
"typescript": "^5.2.2",
|
||||||
"undici": "^6.2.1",
|
"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": "^5.88.2",
|
||||||
"webpack-build-notifier": "^2.3.0",
|
"webpack-build-notifier": "^2.3.0",
|
||||||
"webpack-bundle-analyzer": "^4.9.1",
|
"webpack-bundle-analyzer": "^4.9.1",
|
||||||
|
|
|
@ -37,11 +37,9 @@
|
||||||
"Docker/*": ["docker/*"],
|
"Docker/*": ["docker/*"],
|
||||||
"Kubernetes/*": ["kubernetes/*"],
|
"Kubernetes/*": ["kubernetes/*"],
|
||||||
"Portainer/*": ["portainer/*"]
|
"Portainer/*": ["portainer/*"]
|
||||||
}
|
},
|
||||||
|
"types": ["vitest/globals"]
|
||||||
},
|
},
|
||||||
"exclude": ["api", "build", "dist", "distribution", "node_modules", "test", "webpack"],
|
"exclude": ["api", "build", "dist", "distribution", "node_modules", "test", "webpack"],
|
||||||
"include": ["app"],
|
"include": ["app"]
|
||||||
"typeAcquisition": {
|
|
||||||
"include": ["jest"]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()],
|
||||||
|
});
|
Loading…
Reference in New Issue