fix(ui): fix warnings in client-side tests [BE-12351] (#1342)

This commit is contained in:
Chaim Lev-Ari
2025-11-04 14:23:11 +02:00
committed by GitHub
parent 34a7d75e10
commit 3f1bd8e290
16 changed files with 152 additions and 32 deletions

View File

@@ -291,12 +291,12 @@ const mockRow = mockTable.getRow('1');
describe('defaultGlobalFilterFn', () => {
it('should return true when filterValue is null', () => {
const result = defaultGlobalFilterFn(mockRow, 'Name', null);
const result = defaultGlobalFilterFn(mockRow, 'name', null);
expect(result).toBe(true);
});
it('should return true when filterValue.search is empty', () => {
const result = defaultGlobalFilterFn(mockRow, 'Name', {
const result = defaultGlobalFilterFn(mockRow, 'name', {
search: '',
});
expect(result).toBe(true);

View File

@@ -64,8 +64,6 @@ test('renders AppTemplateFieldset component', async () => {
<Wrapped templateId={template.id} values={values} onChange={onChange} />
);
screen.debug();
await expect(
screen.findByText('This is a template note')
).resolves.toBeInTheDocument();

View File

@@ -19,6 +19,11 @@ vi.mock('@uirouter/react', async (importOriginal: () => Promise<object>) => ({
useCurrentStateAndParams: vi.fn(() => ({
params: { templateId: mockTemplateId, templateType: mockTemplateType },
})),
useRouter: vi.fn(() => ({
stateService: {
go: vi.fn(),
},
})),
}));
mockCodeMirror();

View File

@@ -19,6 +19,11 @@ vi.mock('@uirouter/react', async (importOriginal: () => Promise<object>) => ({
useCurrentStateAndParams: vi.fn(() => ({
params: { templateId: mockTemplateId, templateType: mockTemplateType },
})),
useRouter: vi.fn(() => ({
stateService: {
go: vi.fn(),
},
})),
}));
mockCodeMirror();
@@ -75,7 +80,7 @@ test('The form should submit the correct request body for a given custom templat
setMockCreateStackUrlParams(8, 'custom');
let requestBody: DefaultBodyType;
server.use(
http.post('/api/edge_stacks/create/repository', async ({ request }) => {
http.post('/api/edge_stacks/create/:method', async ({ request }) => {
requestBody = await request.json();
return HttpResponse.json({});
})

View File

@@ -1,10 +1,13 @@
import { render, screen } from '@testing-library/react';
import { vi } from 'vitest';
import { HttpResponse } from 'msw';
import { withTestQueryProvider } from '@/react/test-utils/withTestQuery';
import { withTestRouter } from '@/react/test-utils/withRouter';
import { UserViewModel } from '@/portainer/models/user';
import { withUserProvider } from '@/react/test-utils/withUserProvider';
import { http, server } from '@/setup-tests/server';
import { createMockEnvironment } from '@/react-tools/test-mocks';
import { PodKubernetesInstanceLabel, PodManagedByLabel } from '../../constants';
@@ -108,6 +111,12 @@ vi.mock('@/react/kubernetes/components/CreateFromManifestButton', () => ({
}));
function renderComponent() {
server.use(
http.get('/api/endpoints/:endpointId', () =>
HttpResponse.json(createMockEnvironment())
)
);
const user = new UserViewModel({ Username: 'user' });
const Wrapped = withTestQueryProvider(

View File

@@ -1,7 +1,7 @@
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { http, HttpResponse } from 'msw';
import { vi, describe, it, expect, beforeEach, afterEach } from 'vitest';
import { vi, describe, it, expect, beforeEach } from 'vitest';
import { withTestQueryProvider } from '@/react/test-utils/withTestQuery';
import { withTestRouter } from '@/react/test-utils/withRouter';
@@ -16,12 +16,15 @@ import { confirmUpdateNode } from '../ConfirmUpdateNode';
import { NodeDetails } from './NodeDetails';
// Mocks
vi.mock('../ConfirmUpdateNode', () => ({
confirmUpdateNode: vi.fn(),
}));
vi.mock('@/portainer/services/notifications', () => ({
notifySuccess: vi.fn(),
}));
vi.mock(
'@/react/hooks/useUser',
async (importOriginal: () => Promise<object>) => {
@@ -32,11 +35,19 @@ vi.mock(
};
}
);
vi.mock('@uirouter/react', async (importOriginal: () => Promise<object>) => ({
...(await importOriginal()),
useCurrentStateAndParams: vi.fn(() => ({
params: { endpointId: 1, name: 'test-node' },
})),
useRouter: vi.fn(() => ({
stateService: {
reload: vi.fn(),
},
})),
}));
// Sample test data
@@ -171,10 +182,6 @@ describe('NodeDetails', () => {
setupMocks();
});
afterEach(() => {
server.resetHandlers();
});
it('shows drain warning when selecting Drain availability', async () => {
renderComponent();

View File

@@ -145,6 +145,7 @@ function useEnvironmentTagNames(tagIds?: TagId[]) {
.map((tag) => tag?.Name)
);
},
enabled: !!tagIds && tagIds.length > 0,
});
const { data: tags, isLoading } = tagsQuery;

View File

@@ -9,13 +9,16 @@ import { EnvironmentGroup } from '@/react/portainer/environments/environment-gro
import { Tag } from '@/portainer/tags/types';
import { StatusResponse } from '@/react/portainer/system/useSystemStatus';
import { createMockTeams } from '@/react-tools/test-mocks';
import { PublicSettingsResponse } from '@/react/portainer/settings/types';
import { UserId } from '@/portainer/users/types';
import { VersionResponse } from '@/react/portainer/system/useSystemVersion';
import { azureHandlers } from './setup-handlers/azure';
import { dockerHandlers } from './setup-handlers/docker';
import { userHandlers } from './setup-handlers/users';
import { kubernetesHandlers } from './setup-handlers/kubernetes';
import { endpointsHandlers } from './setup-handlers/endpoints';
import { settingsHandlers } from './setup-handlers/settings';
import { templatesHandlers } from './setup-handlers/templates';
const tags: Tag[] = [
{ ID: 1, Name: 'tag1', Endpoints: {} },
@@ -44,9 +47,13 @@ export const handlers = [
http.post<never, { userId: UserId }>('/api/team_memberships', () =>
HttpResponse.json(null, { status: 204 })
),
...endpointsHandlers,
...settingsHandlers,
...templatesHandlers,
...azureHandlers,
...dockerHandlers,
...userHandlers,
...kubernetesHandlers,
http.get('/api/licenses/info', () => HttpResponse.json(licenseInfo)),
http.get('/api/status/nodes', () => HttpResponse.json({ nodes: 3 })),
http.get('/api/backup/s3/status', () => HttpResponse.json({ Failed: false })),
@@ -70,19 +77,7 @@ export const handlers = [
tags.push(tag);
return HttpResponse.json(tag);
}),
http.get<never, never, Partial<PublicSettingsResponse>>(
'/api/settings/public',
() =>
HttpResponse.json({
Edge: {
AsyncMode: false,
CheckinInterval: 60,
CommandInterval: 60,
PingInterval: 60,
SnapshotInterval: 60,
},
})
),
http.get<never, never, Partial<StatusResponse>>('/api/status', () =>
HttpResponse.json({})
),
@@ -90,5 +85,12 @@ export const handlers = [
HttpResponse.json({ ServerVersion: 'v2.10.0' })
),
http.get('/api/teams/:id/memberships', () => HttpResponse.json([])),
http.get('/api/endpoints/agent_versions', () => HttpResponse.json([])),
http.get('/api/observability/alerting/settings', () => HttpResponse.json([])),
http.get('/observability/alerting/rules', () => HttpResponse.json([])),
http.get('/api/omni/:id/machines', () => HttpResponse.json([])),
http.get('/api/registries', () => HttpResponse.json([])),
http.get('/api/registries/:id', () => HttpResponse.json({})),
http.get('/api/system/info', () => HttpResponse.json({})),
];

View File

@@ -48,7 +48,15 @@ export const azureHandlers = [
})
),
http.get(
'/api/endpoints/:endpointId/azure/subscriptions/:subsriptionId/resourcegroups',
'/api/endpoints/:endpointId/azure/subscriptions/:subscriptionId/providers/Microsoft.ContainerInstance/containerGroups',
() => HttpResponse.json({ value: [] })
),
http.get(
'/api/endpoints/:endpointId/azure/subscriptions/:subscriptionId/providers/Microsoft.Network/virtualNetworks',
() => HttpResponse.json({ value: [] })
),
http.get(
'/api/endpoints/:endpointId/azure/subscriptions/:subscriptionId/resourcegroups',
({ params }) =>
HttpResponse.json({
value: [

View File

@@ -0,0 +1,12 @@
import { http, HttpResponse } from 'msw';
export const endpointsHandlers = [
http.get('/api/endpoints/agent_versions', () => HttpResponse.json([])),
http.get('/api/endpoints/:endpointId', () => HttpResponse.json({})),
http.get('/api/endpoints/:endpointId/registries', () =>
HttpResponse.json([])
),
http.get('/api/endpoints/:endpointId/registries/:id', () =>
HttpResponse.json({})
),
];

View File

@@ -0,0 +1,26 @@
import { http, HttpResponse } from 'msw';
export const kubernetesHandlers = [
http.get(
'/api/kubernetes/:endpointId/metrics/pods/namespace/:namespace',
() => HttpResponse.json({})
),
http.get('/api/kubernetes/:endpointId/namespaces/:namespace/events', () =>
HttpResponse.json([])
),
http.get('/api/kubernetes/:endpointId/namespaces/:namespace', () =>
HttpResponse.json({})
),
http.get('/api/kubernetes/:endpointId/ingresses', () =>
HttpResponse.json({})
),
http.get('/api/kubernetes/:endpointId/namespaces', () =>
HttpResponse.json([])
),
http.get('/api/kubernetes/:endpointId/customresourcedefinitions', () =>
HttpResponse.json({})
),
http.get('/api/kubernetes/:endpointId/customresourcedefinitions/:name', () =>
HttpResponse.json({})
),
];

View File

@@ -0,0 +1,33 @@
import { http, HttpResponse } from 'msw';
import { PublicSettingsResponse } from '@/react/portainer/settings/types';
export const settingsHandlers = [
http.get('/api/ssl', () => HttpResponse.json({})),
http.get('/api/settings', () => HttpResponse.json({})),
http.get('/api/settings/additional_functionality', () =>
HttpResponse.json({})
),
http.get<never, never, Partial<PublicSettingsResponse>>(
'/api/settings/public',
() =>
HttpResponse.json({
Edge: {
AsyncMode: false,
CheckinInterval: 60,
CommandInterval: 60,
PingInterval: 60,
SnapshotInterval: 60,
},
GlobalDeploymentOptions: {
perEnvOverride: false,
hideAddWithForm: false,
hideFileUpload: false,
hideStacksFunctionality: false,
hideWebEditor: false,
requireNoteOnApplications: false,
minApplicationNoteLength: 0,
},
} satisfies Partial<PublicSettingsResponse>)
),
];

View File

@@ -0,0 +1,8 @@
import { http, HttpResponse } from 'msw';
export const templatesHandlers = [
http.put('/api/custom_templates/:id/git_fetch', () =>
HttpResponse.json({ FileContent: '' })
),
http.get('/api/templates/helm/values', () => HttpResponse.json({})),
];

View File

@@ -12,4 +12,5 @@ export const userHandlers = [
'/api/users/:userId/memberships',
() => HttpResponse.json([])
),
http.get('/api/users/:userId/gitcredentials', () => HttpResponse.json([])),
];

View File

@@ -8,11 +8,11 @@ export default defineConfig({
globals: true,
environment: 'jsdom',
setupFiles: [
'./app/setup-tests/setup-rtl.ts',
'./app/setup-tests/setup-msw.ts',
'./app/setup-tests/stub-modules.ts',
'./app/setup-tests/setup.ts',
'./app/setup-tests/setup-codemirror.ts',
'./app/setup-tests/setup-rtl.ts',
],
coverage: {
provider: 'v8',
@@ -24,8 +24,13 @@ export default defineConfig({
env: {
PORTAINER_EDITION: 'CE',
},
deps: {
inline: [/@radix-ui/, /codemirror-json-schema/], // https://github.com/radix-ui/primitives/issues/2974#issuecomment-2186808459
server: {
deps: {
inline: [/@radix-ui/, /codemirror-json-schema/], // https://github.com/radix-ui/primitives/issues/2974#issuecomment-2186808459
},
},
onConsoleLog(log) {
return !/Can't perform a React state update on an unmounted component/.test(log);
},
},
plugins: [svgr({ include: /\?c$/ }), tsconfigPaths()],

View File

@@ -8348,9 +8348,9 @@ caniuse-api@^3.0.0:
lodash.uniq "^4.5.0"
caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001181, caniuse-lite@^1.0.30001449, caniuse-lite@^1.0.30001503, caniuse-lite@^1.0.30001538, caniuse-lite@^1.0.30001541, caniuse-lite@^1.0.30001565:
version "1.0.30001579"
resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001579.tgz"
integrity sha512-u5AUVkixruKHJjw/pj9wISlcMpgFWzSrczLZbrqBSxukQixmg0SJ5sZTpvaFvxU0HoQKd4yoyAogyrAz9pzJnA==
version "1.0.30001751"
resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001751.tgz"
integrity sha512-A0QJhug0Ly64Ii3eIqHu5X51ebln3k4yTUkY1j8drqpWHVreg/VLijN48cZ1bYPiqOQuqpkIKnzr/Ul8V+p6Cw==
capital-case@^1.0.4:
version "1.0.4"