Skip to content

Commit 4143e4a

Browse files
[17563] Fixed and added unit test to capture this bug next time (#17599)
1 parent 476226c commit 4143e4a

2 files changed

Lines changed: 216 additions & 3 deletions

File tree

shell/components/formatter/FleetSummaryGraph.vue

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,6 @@ export default {
2626
if (this.clusterId) {
2727
return this.row.statusResourceCountsForCluster(this.clusterId);
2828
}
29-
if (this.row.statusResourceCountsForCluster) {
30-
return this.row.statusResourceCountsForCluster;
31-
}
3229
3330
return this.row.status?.resourceCounts || {};
3431
},
Lines changed: 216 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
1+
import { shallowMount } from '@vue/test-utils';
2+
import FleetSummaryGraph from '@shell/components/formatter/FleetSummaryGraph.vue';
3+
import { FLEET } from '@shell/config/types';
4+
import { ExtendedVue, Vue } from 'vue/types/vue';
5+
import { DefaultProps } from 'vue/types/options';
6+
7+
const FleetSummaryGraphComponent = FleetSummaryGraph as unknown as ExtendedVue<Vue, {}, {}, {}, DefaultProps>;
8+
9+
function makeRow({
10+
type = FLEET.GIT_REPO,
11+
resourceCounts = {},
12+
targetClusters = [],
13+
statusResourceCountsForCluster = undefined,
14+
}: {
15+
type?: string;
16+
resourceCounts?: Record<string, number>;
17+
targetClusters?: any[];
18+
statusResourceCountsForCluster?: any;
19+
} = {}) {
20+
const row: Record<string, any> = {
21+
id: 'test-ns/test-row',
22+
type,
23+
status: { resourceCounts },
24+
targetClusters,
25+
};
26+
27+
if (statusResourceCountsForCluster !== undefined) {
28+
row.statusResourceCountsForCluster = statusResourceCountsForCluster;
29+
}
30+
31+
return row;
32+
}
33+
34+
describe('component: FleetSummaryGraph', () => {
35+
describe('summary', () => {
36+
it('returns status.resourceCounts for GitRepo rows', () => {
37+
const resourceCounts = {
38+
desiredReady: 7,
39+
ready: 7,
40+
};
41+
const wrapper = shallowMount(FleetSummaryGraphComponent, {
42+
propsData: {
43+
row: makeRow({
44+
resourceCounts,
45+
targetClusters: [{ id: 'cluster-1' }],
46+
}),
47+
},
48+
});
49+
50+
expect((wrapper.vm as any).summary).toStrictEqual(resourceCounts);
51+
});
52+
53+
it('returns status.resourceCounts for HelmOp rows', () => {
54+
const resourceCounts = {
55+
desiredReady: 3,
56+
ready: 2,
57+
modified: 1,
58+
};
59+
const wrapper = shallowMount(FleetSummaryGraphComponent, {
60+
propsData: {
61+
row: makeRow({
62+
type: FLEET.HELM_OP,
63+
resourceCounts,
64+
targetClusters: [{ id: 'cluster-1' }],
65+
}),
66+
},
67+
});
68+
69+
expect((wrapper.vm as any).summary).toStrictEqual(resourceCounts);
70+
});
71+
72+
it('does not return function when row has statusResourceCountsForCluster as a method', () => {
73+
const resourceCounts = {
74+
desiredReady: 5,
75+
ready: 5,
76+
};
77+
const wrapper = shallowMount(FleetSummaryGraphComponent, {
78+
propsData: {
79+
row: makeRow({
80+
resourceCounts,
81+
targetClusters: [{ id: 'cluster-1' }],
82+
// Simulate a class method — the bug was that a truthy function
83+
// caused summary to return the function itself instead of resourceCounts
84+
statusResourceCountsForCluster: (clusterId: string) => ({ desiredReady: 0 }),
85+
}),
86+
},
87+
});
88+
89+
const summary = (wrapper.vm as any).summary;
90+
91+
expect(typeof summary).not.toBe('function');
92+
expect(summary).toStrictEqual(resourceCounts);
93+
});
94+
95+
it('calls statusResourceCountsForCluster with clusterId when clusterId prop is set', () => {
96+
const perClusterData = {
97+
desiredReady: 2,
98+
ready: 1,
99+
};
100+
const mockFn = jest.fn().mockReturnValue(perClusterData);
101+
102+
const wrapper = shallowMount(FleetSummaryGraphComponent, {
103+
propsData: {
104+
row: makeRow({ statusResourceCountsForCluster: mockFn }),
105+
clusterId: 'cluster-1',
106+
},
107+
});
108+
109+
expect((wrapper.vm as any).summary).toStrictEqual(perClusterData);
110+
expect(mockFn).toHaveBeenCalledWith('cluster-1');
111+
});
112+
113+
it('returns empty object when status.resourceCounts is undefined', () => {
114+
const wrapper = shallowMount(FleetSummaryGraphComponent, { propsData: { row: makeRow() } });
115+
116+
expect((wrapper.vm as any).summary).toStrictEqual({});
117+
});
118+
});
119+
120+
describe('show', () => {
121+
it('returns true when stateParts exist and row has targetClusters', () => {
122+
const wrapper = shallowMount(FleetSummaryGraphComponent, {
123+
propsData: {
124+
row: makeRow({
125+
resourceCounts: {
126+
desiredReady: 5,
127+
ready: 5,
128+
},
129+
targetClusters: [{ id: 'cluster-1' }],
130+
}),
131+
},
132+
});
133+
134+
expect((wrapper.vm as any).show).toBeTruthy();
135+
});
136+
137+
it('returns false when stateParts exist but targetClusters is empty', () => {
138+
const wrapper = shallowMount(FleetSummaryGraphComponent, {
139+
propsData: {
140+
row: makeRow({
141+
resourceCounts: {
142+
desiredReady: 5,
143+
ready: 5,
144+
},
145+
targetClusters: [],
146+
}),
147+
},
148+
});
149+
150+
expect((wrapper.vm as any).show).toBeFalsy();
151+
});
152+
153+
it('returns true for FLEET.CLUSTER type even without targetClusters', () => {
154+
const wrapper = shallowMount(FleetSummaryGraphComponent, {
155+
propsData: {
156+
row: makeRow({
157+
type: FLEET.CLUSTER,
158+
resourceCounts: {
159+
desiredReady: 3,
160+
ready: 3,
161+
},
162+
}),
163+
},
164+
});
165+
166+
expect((wrapper.vm as any).show).toBeTruthy();
167+
});
168+
169+
it('returns false when resourceCounts is empty', () => {
170+
const wrapper = shallowMount(FleetSummaryGraphComponent, { propsData: { row: makeRow({ targetClusters: [{ id: 'cluster-1' }] }) } });
171+
172+
expect((wrapper.vm as any).show).toBeFalsy();
173+
});
174+
});
175+
176+
describe('stateParts', () => {
177+
it('filters out keys starting with "desired"', () => {
178+
const wrapper = shallowMount(FleetSummaryGraphComponent, {
179+
propsData: {
180+
row: makeRow({
181+
resourceCounts: {
182+
desiredReady: 5,
183+
ready: 5,
184+
},
185+
targetClusters: [{ id: 'cluster-1' }],
186+
}),
187+
},
188+
});
189+
190+
const parts = (wrapper.vm as any).stateParts;
191+
192+
expect(parts.every((p: any) => !p.label.startsWith('Desired'))).toBe(true);
193+
});
194+
195+
it('filters out entries with value 0', () => {
196+
const wrapper = shallowMount(FleetSummaryGraphComponent, {
197+
propsData: {
198+
row: makeRow({
199+
resourceCounts: {
200+
desiredReady: 5,
201+
ready: 5,
202+
notReady: 0,
203+
},
204+
targetClusters: [{ id: 'cluster-1' }],
205+
}),
206+
},
207+
});
208+
209+
const parts = (wrapper.vm as any).stateParts;
210+
const labels = parts.map((p: any) => p.label);
211+
212+
expect(labels).toContain('Ready');
213+
expect(labels).not.toContain('NotReady');
214+
});
215+
});
216+
});

0 commit comments

Comments
 (0)