Skip to content

Commit 45dd6a4

Browse files
committed
fix(ci): pin buf-action to 1.65.0 and seed topics via gRPC in add-topic-step test
- buf.yml: buf-action defaults to the latest buf, whose formatter collapses single-field messages and flags ~40 already-formatted protos. Pin to 1.65.0 (the repo's canonical version from taskfiles/proto.yaml) so CI matches `task proto:generate`. - add-topic-step.test.tsx: topics now load via the gRPC ListTopics query over the test's router transport, not config.fetch. Register a listTopics handler (with a topicNames override) and drop the dead mockFetch-based seeding and the `expect(mockFetch).toHaveBeenCalled()` assertions that could never pass.
1 parent 28a3046 commit 45dd6a4

2 files changed

Lines changed: 27 additions & 52 deletions

File tree

.github/workflows/buf.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@ jobs:
4747
- name: Buf – lint, format & breaking
4848
uses: bufbuild/buf-action@v1
4949
with:
50+
# Pin to the repo's canonical buf version (see taskfiles/proto.yaml install-buf)
51+
# so CI formatting matches `task proto:generate`; buf-action defaults to latest,
52+
# whose formatter reformats single-field messages and produces spurious diffs.
53+
version: 1.65.0
5054
lint: true
5155
format: true
5256
breaking: ${{ github.event_name == 'pull_request' && !contains(github.event.pull_request.labels.*.name, 'Buf Skip Breaking') }}
@@ -79,6 +83,7 @@ jobs:
7983
- name: Buf – push to registry
8084
uses: bufbuild/buf-action@v1
8185
with:
86+
version: 1.65.0
8287
# No validation - already done in validate job
8388
lint: false
8489
format: false
@@ -112,6 +117,7 @@ jobs:
112117
- name: Buf – archive label (ignore if not found)
113118
uses: bufbuild/buf-action@v1
114119
with:
120+
version: 1.65.0
115121
# Only archive - no other operations
116122
push: true
117123
token: ${{ env.BUF_TOKEN }}

frontend/src/components/pages/rp-connect/onboarding/add-topic-step.test.tsx

Lines changed: 21 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@
1212
import { create } from '@bufbuild/protobuf';
1313
import { ConnectError, createRouterTransport } from '@connectrpc/connect';
1414
import userEvent from '@testing-library/user-event';
15-
import { CreateTopicResponseSchema } from 'protogen/redpanda/api/dataplane/v1/topic_pb';
16-
import { createTopic } from 'protogen/redpanda/api/dataplane/v1/topic-TopicService_connectquery';
15+
import { CreateTopicResponseSchema, ListTopicsResponseSchema } from 'protogen/redpanda/api/dataplane/v1/topic_pb';
16+
import { createTopic, listTopics } from 'protogen/redpanda/api/dataplane/v1/topic-TopicService_connectquery';
1717
import type { ComponentProps } from 'react';
1818
import { useRef } from 'react';
1919
import { render, screen, waitFor } from 'test-utils';
@@ -60,21 +60,7 @@ import { AddTopicStep } from './add-topic-step';
6060

6161
// ── Helpers ────────────────────────────────────────────────────────────
6262

63-
/** gRPC ListTopicsResponse (proto JSON shape) for useListTopicsQuery */
64-
function createTopicsResponse(topicNames: string[]) {
65-
return {
66-
topics: topicNames.map((name) => ({
67-
name,
68-
internal: false,
69-
partitionCount: 1,
70-
replicationFactor: 3,
71-
cleanupPolicy: 'delete',
72-
logDirSummary: { totalSizeBytes: 0, replicaErrors: [], hint: '' },
73-
})),
74-
};
75-
}
76-
77-
function createTransport(overrides?: { createTopicMock?: ReturnType<typeof vi.fn> }) {
63+
function createTransport(overrides?: { createTopicMock?: ReturnType<typeof vi.fn>; topicNames?: string[] }) {
7864
return createRouterTransport(({ rpc }) => {
7965
rpc(
8066
createTopic,
@@ -87,6 +73,20 @@ function createTransport(overrides?: { createTopicMock?: ReturnType<typeof vi.fn
8773
})
8874
)
8975
);
76+
// useListTopicsQuery resolves topics over the gRPC transport, so seed them here.
77+
rpc(listTopics, () =>
78+
create(ListTopicsResponseSchema, {
79+
topics: (overrides?.topicNames ?? []).map((name) => ({
80+
name,
81+
internal: false,
82+
partitionCount: 1,
83+
replicationFactor: 3,
84+
cleanupPolicy: 'delete',
85+
logDirSummary: { totalSizeBytes: 0n, replicaErrors: [], hint: '' },
86+
})),
87+
nextPageToken: '',
88+
})
89+
);
9090
});
9191
}
9292

@@ -111,22 +111,13 @@ function TestHarness({ onResult, ...props }: HarnessProps) {
111111
describe('AddTopicStep', () => {
112112
beforeEach(() => {
113113
mockFetch.mockReset();
114-
// Default: return empty topic list
115-
mockFetch.mockResolvedValue({
116-
ok: true,
117-
json: () => Promise.resolve(createTopicsResponse([])),
118-
});
119114
});
120115

121116
it('existing topic returns name via triggerSubmit', async () => {
122117
const user = userEvent.setup();
123-
mockFetch.mockResolvedValue({
124-
ok: true,
125-
json: () => Promise.resolve(createTopicsResponse(['my-topic', 'other-topic'])),
126-
});
127118

128119
let result: unknown;
129-
const transport = createTransport();
120+
const transport = createTransport({ topicNames: ['my-topic', 'other-topic'] });
130121

131122
render(
132123
<TestHarness
@@ -138,11 +129,6 @@ describe('AddTopicStep', () => {
138129
{ transport }
139130
);
140131

141-
// Wait for topics to load so the combobox has options
142-
await waitFor(() => {
143-
expect(mockFetch).toHaveBeenCalled();
144-
});
145-
146132
// The component starts in "Existing" mode when topics exist.
147133
// Open the combobox, type to filter, then click the matching option.
148134
// (Pressing Enter races cmdk's highlighted-value bookkeeping in CI under
@@ -283,11 +269,7 @@ describe('AddTopicStep', () => {
283269
});
284270

285271
it('selectionMode=existing shows combobox', async () => {
286-
mockFetch.mockResolvedValue({
287-
ok: true,
288-
json: () => Promise.resolve(createTopicsResponse(['topic-a'])),
289-
});
290-
const transport = createTransport();
272+
const transport = createTransport({ topicNames: ['topic-a'] });
291273

292274
render(<TestHarness onResult={() => {}} selectionMode="existing" />, { transport });
293275

@@ -297,19 +279,10 @@ describe('AddTopicStep', () => {
297279

298280
it('existing topic alert shown in create mode when name matches', async () => {
299281
const user = userEvent.setup();
300-
mockFetch.mockResolvedValue({
301-
ok: true,
302-
json: () => Promise.resolve(createTopicsResponse(['existing-topic'])),
303-
});
304-
const transport = createTransport();
282+
const transport = createTransport({ topicNames: ['existing-topic'] });
305283

306284
render(<TestHarness onResult={() => {}} selectionMode="both" />, { transport });
307285

308-
// Wait for topics to load
309-
await waitFor(() => {
310-
expect(mockFetch).toHaveBeenCalled();
311-
});
312-
313286
// Switch to "New" tab (single-select ToggleGroupItem renders as role="radio")
314287
const newButton = await screen.findByRole('radio', { name: 'New' });
315288
await user.click(newButton);
@@ -357,11 +330,7 @@ describe('AddTopicStep', () => {
357330
});
358331

359332
it('selectionMode=both renders toggle group', async () => {
360-
mockFetch.mockResolvedValue({
361-
ok: true,
362-
json: () => Promise.resolve(createTopicsResponse(['t1'])),
363-
});
364-
const transport = createTransport();
333+
const transport = createTransport({ topicNames: ['t1'] });
365334

366335
render(<TestHarness onResult={() => {}} selectionMode="both" />, { transport });
367336

0 commit comments

Comments
 (0)