Skip to content

Commit 7bac1c4

Browse files
committed
Improved e2e tests for quotas
1 parent e104821 commit 7bac1c4

File tree

4 files changed

+20
-181
lines changed

4 files changed

+20
-181
lines changed

frontend/src/components/pages/quotas/quotas-list.tsx

Lines changed: 5 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -9,21 +9,19 @@
99
* by the Apache License, Version 2.0
1010
*/
1111

12-
import { createConnectQueryKey } from '@connectrpc/connect-query';
1312
import { Alert, AlertIcon, Button, DataTable, Result, Skeleton } from '@redpanda-data/ui';
14-
import { useQuery } from '@tanstack/react-query';
1513
import { useNavigate, useSearch } from '@tanstack/react-router';
1614
import { SkipIcon } from 'components/icons';
17-
import { config } from 'config';
15+
import { Link } from 'components/redpanda-ui/components/typography';
16+
import { useQuotasQuery } from 'hooks/use-quotas-query';
1817
import { useMemo } from 'react';
1918

2019
import {
2120
Quota_EntityType,
2221
type Quota_Value,
2322
Quota_ValueType,
2423
} from '../../../protogen/redpanda/api/dataplane/v1/quota_pb';
25-
import { listQuotas } from '../../../protogen/redpanda/api/dataplane/v1/quota-QuotaService_connectquery';
26-
import type { QuotaResponse, QuotaResponseSetting } from '../../../state/rest-interfaces';
24+
import type { QuotaResponseSetting } from '../../../state/rest-interfaces';
2725
import { InfoText } from '../../../utils/tsx-utils';
2826
import { prettyBytes, prettyNumber } from '../../../utils/utils';
2927
import PageContent from '../../misc/page-content';
@@ -63,39 +61,6 @@ const mapEntityTypeToProto = (entityType: string): Quota_EntityType => {
6361
}
6462
};
6563

66-
/**
67-
* Custom hook to fetch quotas from REST API until protobuf endpoint is available
68-
*/
69-
const useQuotasQuery = () => {
70-
// Create a query key compatible with Connect Query for future migration
71-
const queryKey = createConnectQueryKey({
72-
schema: listQuotas,
73-
input: {},
74-
cardinality: 'finite',
75-
});
76-
77-
return useQuery<QuotaResponse | null>({
78-
queryKey,
79-
queryFn: async () => {
80-
const response = await config.fetch(`${config.restBasePath}/quotas`, {
81-
method: 'GET',
82-
headers: {},
83-
});
84-
85-
if (!response.ok) {
86-
if (response.status === 403 || response.status === 401) {
87-
throw new Error('You do not have permission to view quotas');
88-
}
89-
throw new Error(`Failed to fetch quotas: ${response.statusText}`);
90-
}
91-
92-
const data: QuotaResponse = await response.json();
93-
return data;
94-
},
95-
refetchOnMount: 'always',
96-
});
97-
};
98-
9964
const QuotasList = () => {
10065
const navigate = useNavigate({ from: '/quotas' });
10166
const search = useSearch({ from: '/quotas' });
@@ -179,9 +144,9 @@ const QuotasList = () => {
179144
<Section>
180145
<Result
181146
extra={
182-
<a href="https://docs.redpanda.com/docs/manage/console/" rel="noopener noreferrer" target="_blank">
147+
<Link href="https://docs.redpanda.com/docs/manage/console/" target="_blank">
183148
<Button variant="solid">Redpanda Console documentation for roles and permissions</Button>
184-
</a>
149+
</Link>
185150
}
186151
status={403}
187152
title="Forbidden"

frontend/src/routes/quotas.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
*/
1111

1212
import { createFileRoute } from '@tanstack/react-router';
13+
import { fallback, zodValidator } from '@tanstack/zod-adapter';
1314
import { ScaleIcon } from 'components/icons';
1415
import { useLayoutEffect } from 'react';
1516
import { z } from 'zod';
@@ -18,16 +19,16 @@ import QuotasList from '../components/pages/quotas/quotas-list';
1819
import { uiState } from '../state/ui-state';
1920

2021
const quotasSearchSchema = z.object({
21-
page: z.number().int().min(0).catch(0).optional(),
22-
pageSize: z.number().int().min(10).max(100).catch(50).optional(),
22+
page: fallback(z.number().int().min(0).optional(), 0),
23+
pageSize: fallback(z.number().int().min(10).max(100).optional(), 50),
2324
});
2425

2526
export const Route = createFileRoute('/quotas')({
2627
staticData: {
2728
title: 'Quotas',
2829
icon: ScaleIcon,
2930
},
30-
validateSearch: quotasSearchSchema,
31+
validateSearch: zodValidator(quotasSearchSchema),
3132
component: QuotasWrapper,
3233
});
3334

frontend/tests/test-variant-console-enterprise/playwright/.auth/user.json

Lines changed: 0 additions & 129 deletions
This file was deleted.

frontend/tests/test-variant-console/quotas/quota-pagination.spec.ts

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@ import { QuotaPage } from '../utils/quota-page';
55

66
const DEFAULT_PAGE_SIZE = 50;
77

8+
// Regex patterns for pagination tests
9+
const ENTITY_TYPE_REGEX = /client-id|user|ip/;
10+
const PAGE_0_REGEX = /page=0/;
11+
const PAGE_1_REGEX = /page=1/;
12+
813
test.describe('Quotas - Pagination', () => {
914
test('should not show pagination controls when quotas count is less than page size', async ({ page }) => {
1015
await test.step('Navigate to quotas page', async () => {
@@ -13,10 +18,7 @@ test.describe('Quotas - Pagination', () => {
1318

1419
await test.step('Verify pagination is not visible for small datasets', async () => {
1520
// Check if table has rows but pagination is not present
16-
const rowCount = await page
17-
.locator('tr')
18-
.filter({ hasText: /client-id|user|ip/ })
19-
.count();
21+
const rowCount = await page.locator('tr').filter({ hasText: ENTITY_TYPE_REGEX }).count();
2022

2123
// If there are less than 50 items, pagination should not be visible
2224
if (rowCount < DEFAULT_PAGE_SIZE) {
@@ -77,7 +79,7 @@ test.describe('Quotas - Pagination', () => {
7779
await quotaPage.clickNextPage();
7880

7981
// Wait for page navigation to complete
80-
await page.waitForURL(/page=1/, { timeout: 5000 });
82+
await page.waitForURL(PAGE_1_REGEX, { timeout: 5000 });
8183
});
8284

8385
await test.step('Verify page 1 quotas are no longer visible on page 2', async () => {
@@ -149,7 +151,7 @@ test.describe('Quotas - Pagination', () => {
149151

150152
await test.step('Navigate to page 2', async () => {
151153
await quotaPage.clickNextPage();
152-
await page.waitForURL(/page=1/, { timeout: 5000 });
154+
await page.waitForURL(PAGE_1_REGEX, { timeout: 5000 });
153155
});
154156

155157
await test.step('Capture page 2 quotas', async () => {
@@ -171,7 +173,7 @@ test.describe('Quotas - Pagination', () => {
171173

172174
await test.step('Navigate back to page 1', async () => {
173175
await quotaPage.clickPreviousPage();
174-
await page.waitForURL(/page=0/, { timeout: 5000 });
176+
await page.waitForURL(PAGE_0_REGEX, { timeout: 5000 });
175177
});
176178

177179
await test.step('Verify page 1 quotas are visible again', async () => {
@@ -239,10 +241,10 @@ test.describe('Quotas - Pagination', () => {
239241

240242
await test.step('Navigate to page 2', async () => {
241243
await quotaPage.clickNextPage();
242-
await page.waitForURL(/page=1/, { timeout: 5000 });
244+
await page.waitForURL(PAGE_1_REGEX, { timeout: 5000 });
243245
});
244246

245-
await test.step('Verify URL contains pagination state', async () => {
247+
await test.step('Verify URL contains pagination state', () => {
246248
const url = page.url();
247249
expect(url).toContain('page=1');
248250
expect(url).toContain(`pageSize=${PAGE_SIZE}`);

0 commit comments

Comments
 (0)