Skip to content

Commit b919362

Browse files
committed
Clean up podlog tests
Signed-off-by: Adameska <[email protected]>
1 parent 0c8b7ef commit b919362

File tree

1 file changed

+179
-111
lines changed

1 file changed

+179
-111
lines changed

packages/webview/src/component/pods/PodLogs.spec.ts

Lines changed: 179 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,17 @@
1616
* SPDX-License-Identifier: Apache-2.0
1717
***********************************************************************/
1818

19-
import { render } from '@testing-library/svelte';
20-
import { RemoteMocks } from '/@/tests/remote-mocks';
21-
import { API_POD_LOGS, type PodLogsChunk, type PodLogsApi } from '@kubernetes-dashboard/channels';
22-
import { StreamsMocks } from '/@/tests/stream-mocks';
23-
import { FakeStreamObject } from '/@/stream/util/fake-stream-object.svelte';
24-
import PodLogs from './PodLogs.svelte';
19+
import { API_POD_LOGS, type PodLogsApi, type PodLogsChunk } from '@kubernetes-dashboard/channels';
2520
import type { V1Pod } from '@kubernetes/client-node';
26-
import TerminalWindow from '/@/component/terminal/TerminalWindow.svelte';
27-
import type { Terminal } from '@xterm/xterm';
2821
import { EmptyScreen } from '@podman-desktop/ui-svelte';
22+
import { render } from '@testing-library/svelte';
23+
import type { Terminal } from '@xterm/xterm';
2924
import { beforeEach, describe, expect, test, vi } from 'vitest';
25+
import PodLogs from './PodLogs.svelte';
26+
import TerminalWindow from '/@/component/terminal/TerminalWindow.svelte';
27+
import { FakeStreamObject } from '/@/stream/util/fake-stream-object.svelte';
28+
import { RemoteMocks } from '/@/tests/remote-mocks';
29+
import { StreamsMocks } from '/@/tests/stream-mocks';
3030

3131
vi.mock(import('../terminal/TerminalWindow.svelte'));
3232
vi.mock(import('@podman-desktop/ui-svelte'));
@@ -36,6 +36,36 @@ const streamMocks = new StreamsMocks();
3636

3737
const streamPodLogsMock = new FakeStreamObject<PodLogsChunk>();
3838

39+
// Helper to create a mock terminal
40+
function createMockTerminal(): Terminal {
41+
return {
42+
write: vi.fn(),
43+
dispose: vi.fn(),
44+
clear: vi.fn(),
45+
} as unknown as Terminal;
46+
}
47+
48+
// Helper to create a pod with the specified containers
49+
function createPod(containerNames: string[]): V1Pod {
50+
return {
51+
metadata: {
52+
name: 'podName',
53+
namespace: 'namespace',
54+
},
55+
spec: {
56+
containers: containerNames.map(name => ({ name })),
57+
},
58+
} as V1Pod;
59+
}
60+
61+
// Helper to setup terminal mock with binding
62+
function setupTerminalMock(terminal: Terminal): void {
63+
vi.mocked(TerminalWindow).mockImplementation((_, props) => {
64+
props.terminal = terminal;
65+
return {};
66+
});
67+
}
68+
3969
beforeEach(() => {
4070
vi.resetAllMocks();
4171
streamMocks.reset();
@@ -45,123 +75,161 @@ beforeEach(() => {
4575
remoteMocks.mock(API_POD_LOGS, {} as unknown as PodLogsApi);
4676
});
4777

48-
describe('pod with one container', async () => {
49-
let pod: V1Pod;
50-
beforeEach(() => {
51-
pod = {
52-
metadata: {
53-
name: 'podName',
78+
describe('PodLogs', () => {
79+
describe('EmptyScreen display', () => {
80+
test.each([
81+
{ containerCount: 1, containers: ['containerName'] },
82+
{ containerCount: 2, containers: ['cnt1', 'containerName2'] },
83+
])('should display "No Log" with $containerCount container(s) when no logs received', ({ containers }) => {
84+
const pod = createPod(containers);
85+
render(PodLogs, { object: pod });
86+
87+
expect(EmptyScreen).toHaveBeenCalledWith(
88+
expect.anything(),
89+
expect.objectContaining({
90+
hidden: false,
91+
}),
92+
);
93+
});
94+
95+
test('should hide EmptyScreen when logs are received', () => {
96+
const pod = createPod(['containerName']);
97+
const mockedTerminal = createMockTerminal();
98+
setupTerminalMock(mockedTerminal);
99+
100+
render(PodLogs, { object: pod });
101+
102+
streamPodLogsMock.sendData({
103+
podName: 'podName',
54104
namespace: 'namespace',
55-
},
56-
spec: {
57-
containers: [
58-
{
59-
name: 'containerName',
60-
},
61-
],
62-
},
63-
} as V1Pod;
64-
});
105+
containerName: 'containerName',
106+
data: 'some logs',
107+
});
65108

66-
test('display No Logwith no logs', async () => {
67-
render(PodLogs, { object: pod });
68-
expect(EmptyScreen).toHaveBeenCalledWith(
69-
expect.anything(),
70-
expect.objectContaining({
71-
hidden: false,
72-
}),
73-
);
109+
expect(EmptyScreen).toHaveBeenLastCalledWith(
110+
expect.anything(),
111+
expect.objectContaining({
112+
hidden: true,
113+
}),
114+
);
115+
});
74116
});
75117

76-
test('write received logs to the terminal', async () => {
77-
const mockedTerminal: Terminal = {
78-
write: vi.fn(),
79-
dispose: vi.fn(),
80-
clear: vi.fn(),
81-
} as unknown as Terminal;
82-
vi.mocked(TerminalWindow).mockImplementation((_, props) => {
83-
props.terminal = mockedTerminal;
84-
return {};
118+
describe('log output formatting', () => {
119+
test('should format single container logs without prefix', () => {
120+
const pod = createPod(['containerName']);
121+
const mockedTerminal = createMockTerminal();
122+
setupTerminalMock(mockedTerminal);
123+
124+
render(PodLogs, { object: pod });
125+
126+
streamPodLogsMock.sendData({
127+
podName: 'podName',
128+
namespace: 'namespace',
129+
containerName: 'containerName',
130+
data: 'simple log line',
131+
});
132+
133+
expect(mockedTerminal.write).toHaveBeenCalled();
134+
const writtenLog = vi.mocked(mockedTerminal.write).mock.calls[0][0] as string;
135+
expect(writtenLog).toContain('simple log line\r');
136+
expect(writtenLog).not.toContain('|');
85137
});
86-
render(PodLogs, { object: pod });
87-
expect(mockedTerminal.write).not.toHaveBeenCalledWith();
88-
expect(mockedTerminal.clear).toHaveBeenCalled();
89-
expect(TerminalWindow).toHaveBeenCalled();
90138

91-
streamPodLogsMock.sendData({
92-
podName: 'podName',
93-
namespace: 'namespace',
94-
containerName: 'containerName',
95-
data: 'some logs',
139+
test('should format multi-container logs with colored prefix and padding', () => {
140+
const pod = createPod(['cnt1', 'containerName2']);
141+
const mockedTerminal = createMockTerminal();
142+
setupTerminalMock(mockedTerminal);
143+
144+
render(PodLogs, { object: pod });
145+
146+
streamPodLogsMock.sendData({
147+
podName: 'podName',
148+
namespace: 'namespace',
149+
containerName: 'cnt1',
150+
data: 'log from cnt1',
151+
});
152+
153+
expect(mockedTerminal.write).toHaveBeenCalled();
154+
const writtenLog = vi.mocked(mockedTerminal.write).mock.calls[0][0] as string;
155+
expect(writtenLog).toContain('\u001b[36mcnt1\u001b[0m|log from cnt1');
96156
});
97-
expect(mockedTerminal.write).toHaveBeenCalledWith('some logs\r');
98-
expect(EmptyScreen).toHaveBeenCalledWith(
99-
expect.anything(),
100-
expect.objectContaining({
101-
hidden: true,
102-
}),
103-
);
104-
});
105-
});
106157

107-
describe('pod with two containers', async () => {
108-
let pod: V1Pod;
109-
beforeEach(() => {
110-
pod = {
111-
metadata: {
112-
name: 'podName',
158+
test('should apply log level colorization', () => {
159+
const pod = createPod(['containerName']);
160+
const mockedTerminal = createMockTerminal();
161+
setupTerminalMock(mockedTerminal);
162+
163+
render(PodLogs, { object: pod });
164+
165+
streamPodLogsMock.sendData({
166+
podName: 'podName',
113167
namespace: 'namespace',
114-
},
115-
spec: {
116-
containers: [
117-
{
118-
name: 'cnt1',
119-
},
120-
{
121-
name: 'containerName2',
122-
},
123-
],
124-
},
125-
} as V1Pod;
126-
});
168+
containerName: 'containerName',
169+
data: 'info: Application started',
170+
});
171+
172+
const writtenLog = vi.mocked(mockedTerminal.write).mock.calls[0][0] as string;
173+
// Should contain ANSI color code for info: (cyan)
174+
expect(writtenLog).toContain('\u001b[36m');
175+
expect(writtenLog).toContain('\u001b[0m');
176+
expect(writtenLog).toContain('Application started');
177+
});
127178

128-
test('display No Logwith no logs', async () => {
129-
render(PodLogs, { object: pod });
130-
expect(EmptyScreen).toHaveBeenCalledWith(
131-
expect.anything(),
132-
expect.objectContaining({
133-
hidden: false,
134-
}),
135-
);
179+
test('should apply JSON colorization when JSON logs detected', () => {
180+
const pod = createPod(['containerName']);
181+
const mockedTerminal = createMockTerminal();
182+
setupTerminalMock(mockedTerminal);
183+
184+
render(PodLogs, { object: pod });
185+
186+
// Send JSON log data
187+
streamPodLogsMock.sendData({
188+
podName: 'podName',
189+
namespace: 'namespace',
190+
containerName: 'containerName',
191+
data: '{"level":"info","message":"test","count":42}',
192+
});
193+
194+
const writtenLog = vi.mocked(mockedTerminal.write).mock.calls[0][0] as string;
195+
// Should contain ANSI color codes for JSON elements (braces in yellow, numbers in green)
196+
expect(writtenLog).toContain('\u001b[33m{\u001b[0m'); // yellow brace
197+
expect(writtenLog).toContain('\u001b[32m42\u001b[0m'); // green number
198+
});
136199
});
137200

138-
test('write received logs to the terminal v2', async () => {
139-
const mockedTerminal: Terminal = {
140-
write: vi.fn(),
141-
dispose: vi.fn(),
142-
clear: vi.fn(),
143-
} as unknown as Terminal;
144-
vi.mocked(TerminalWindow).mockImplementation((_, props) => {
145-
props.terminal = mockedTerminal;
146-
return {};
201+
describe('terminal initialization', () => {
202+
test('should clear terminal and create TerminalWindow on mount', () => {
203+
const pod = createPod(['containerName']);
204+
const mockedTerminal = createMockTerminal();
205+
setupTerminalMock(mockedTerminal);
206+
207+
render(PodLogs, { object: pod });
208+
209+
expect(mockedTerminal.clear).toHaveBeenCalled();
210+
expect(TerminalWindow).toHaveBeenCalled();
147211
});
148-
render(PodLogs, { object: pod });
149-
expect(mockedTerminal.write).not.toHaveBeenCalledWith();
150-
expect(mockedTerminal.clear).toHaveBeenCalled();
151-
expect(TerminalWindow).toHaveBeenCalled();
212+
});
152213

153-
streamPodLogsMock.sendData({
154-
podName: 'podName',
155-
namespace: 'namespace',
156-
containerName: 'cnt1',
157-
data: 'some logs',
214+
describe('multi-container prefix colors', () => {
215+
test('should apply colored prefixes for each container', () => {
216+
const pod = createPod(['container1', 'container2', 'container3']);
217+
const mockedTerminal = createMockTerminal();
218+
setupTerminalMock(mockedTerminal);
219+
220+
render(PodLogs, { object: pod });
221+
222+
// Send log from first container
223+
streamPodLogsMock.sendData({
224+
podName: 'podName',
225+
namespace: 'namespace',
226+
containerName: 'container1',
227+
data: 'log message',
228+
});
229+
230+
const calls = vi.mocked(mockedTerminal.write).mock.calls;
231+
// First container should have cyan prefix
232+
expect(calls[0][0]).toContain('\u001b[36mcontainer1\u001b[0m|');
158233
});
159-
expect(mockedTerminal.write).toHaveBeenCalledWith(' \u001b[36mcnt1\u001b[0m|some logs\r');
160-
expect(EmptyScreen).toHaveBeenCalledWith(
161-
expect.anything(),
162-
expect.objectContaining({
163-
hidden: true,
164-
}),
165-
);
166234
});
167235
});

0 commit comments

Comments
 (0)