Skip to content

Commit 264a819

Browse files
[16472] Added the usual ResourceTabs for Bundle (#17049)
Added some snapshots test for the new changes
1 parent 5a9e74d commit 264a819

5 files changed

Lines changed: 261 additions & 35 deletions

File tree

cypress/e2e/po/pages/fleet/fleet.cattle.io.bundle.po.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import ProductNavPo from '@/cypress/e2e/po/side-bars/product-side-nav.po';
33
import { BaseListPagePo } from '@/cypress/e2e/po/pages/base/base-list-page.po';
44
import { BaseDetailPagePo } from '@/cypress/e2e/po/pages/base/base-detail-page.po';
55
import ResourceTablePo from '@/cypress/e2e/po/components/resource-table.po';
6+
import TabbedPo from '@/cypress/e2e/po/components/tabbed.po';
67

78
export class FleetBundlesListPagePo extends BaseListPagePo {
89
static url = `/c/_/fleet/fleet.cattle.io.bundle`
@@ -57,7 +58,19 @@ export class FleetBundleDetailsPo extends BaseDetailPagePo {
5758
super(FleetBundleDetailsPo.createPath(fleetWorkspace, bundleName));
5859
}
5960

61+
tabs(): TabbedPo {
62+
return new TabbedPo();
63+
}
64+
6065
resourcesList() {
61-
return new ResourceTablePo(this.self());
66+
return new ResourceTablePo('#resources [data-testid="sortable-table-list-container"]');
67+
}
68+
69+
conditionsList() {
70+
return new ResourceTablePo('#conditions [data-testid="sortable-table-list-container"]');
71+
}
72+
73+
eventsList() {
74+
return new ResourceTablePo('#events [data-testid="sortable-table-list-container"]');
6275
}
6376
}

cypress/e2e/tests/pages/fleet/resources/bundles.spec.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@ describe('Bundles', { testIsolation: 'off', tags: ['@fleet', '@adminUser'] }, ()
6060

6161
fleetBundlesDetailsPage.waitForPage();
6262

63+
// click on the Resources tab
64+
fleetBundlesDetailsPage.tabs().clickTabWithName('resources');
65+
6366
// check table headers
6467
const expectedHeadersDetailsViewEvents = ['State', 'Name', 'Kind', 'Cluster', 'Namespace', 'API Version'];
6568

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`view: fleet.cattle.io.bundle should render resources when bundle deployments exist 1`] = `
4+
<div class="tabbed-container resource-tabs view" data-testid="tabbed">
5+
<ul role="tablist" class="tabs clearfix horizontal" data-testid="tabbed-block" tabindex="0">
6+
<!-- This is the tabs link... tabs appear here because they are injected from the "Tab" component -->
7+
<li id="resources" data-testid="resources" class="tab active"><a id="tab-resources" data-testid="btn-resources" aria-controls="resources" aria-selected="true" aria-label="Resources" role="tab" tabindex="0">
8+
<!--v-if--><span>Resources</span>
9+
<!--v-if-->
10+
<!--v-if-->
11+
</a></li>
12+
<!--v-if-->
13+
<!--v-if-->
14+
</ul>
15+
<div class="tab-container">
16+
<!-- This is where "normal" tab content goes... -->
17+
<section id="resources" aria-hidden="false" role="tabpanel" aria-labelledby="tab-resources" style="">
18+
<!--v-if-->
19+
<resource-table-stub rows="[object Object],[object Object]" loading="false" altloading="false" keyfield="tableKey" headers="[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]" search="true" tableactions="false" paginglabel="sortableTable.paging.resource" rowactions="false" groupoptions="[object Object],[object Object]" groupdefault="namespace" grouptooltip="resourceTable.groupBy.namespace" overflowx="false" overflowy="false" ignorefilter="false" hasadvancedfiltering="false" advfilterhidelabelsascols="false" advfilterpreventfilteringlabels="false" usequeryparamsforsimplefiltering="false" forceupdateliveanddelayed="0" externalpaginationenabled="false" default-sort-by="state"></resource-table-stub>
20+
</section>
21+
<!--v-if-->
22+
<!--v-if-->
23+
<!--v-if-->
24+
<!-- Extension tabs content goes here... -->
25+
</div>
26+
</div>
27+
`;
28+
29+
exports[`view: fleet.cattle.io.bundle should render the bundle detail page 1`] = `<resource-tabs-stub mode="view" needconditions="true" needevents="true" needrelated="false" usehash="true" value="[object Object]"></resource-tabs-stub>`;
30+
31+
exports[`view: fleet.cattle.io.bundle should render the bundle detail page with full mount 1`] = `
32+
<div class="tabbed-container resource-tabs view" data-testid="tabbed">
33+
<ul role="tablist" class="tabs clearfix horizontal" data-testid="tabbed-block" tabindex="0">
34+
<!-- This is the tabs link... tabs appear here because they are injected from the "Tab" component -->
35+
<!--v-if-->
36+
<!--v-if-->
37+
</ul>
38+
<div class="">
39+
<!-- This is where "normal" tab content goes... -->
40+
<section id="resources" aria-hidden="true" role="tabpanel" aria-labelledby="tab-resources" style="display: none;">
41+
<!--v-if-->
42+
<resource-table-stub rows="" loading="false" altloading="false" keyfield="tableKey" headers="[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]" search="true" tableactions="false" paginglabel="sortableTable.paging.resource" rowactions="false" groupoptions="[object Object],[object Object]" groupdefault="namespace" grouptooltip="resourceTable.groupBy.namespace" overflowx="false" overflowy="false" ignorefilter="false" hasadvancedfiltering="false" advfilterhidelabelsascols="false" advfilterpreventfilteringlabels="false" usequeryparamsforsimplefiltering="false" forceupdateliveanddelayed="0" externalpaginationenabled="false" default-sort-by="state"></resource-table-stub>
43+
</section>
44+
<!--v-if-->
45+
<!--v-if-->
46+
<!--v-if-->
47+
<!-- Extension tabs content goes here... -->
48+
</div>
49+
</div>
50+
`;
51+
52+
exports[`view: fleet.cattle.io.bundle should show Loading when fetch is pending 1`] = `<loading-stub loading="true" mode="content" nodelay="false"></loading-stub>`;
Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
import { shallowMount, mount } from '@vue/test-utils';
2+
import BundleDetail from '@shell/detail/fleet.cattle.io.bundle.vue';
3+
4+
describe('view: fleet.cattle.io.bundle', () => {
5+
const mockStore = {
6+
getters: {
7+
'i18n/t': (text: string) => text,
8+
'i18n/exists': jest.fn(),
9+
currentStore: () => 'management',
10+
'management/schemaFor': jest.fn(),
11+
'management/all': () => [],
12+
'management/pathExistsInSchema': () => false,
13+
'type-map/optionsFor': () => ({}),
14+
'type-map/headersFor': () => [],
15+
'cluster/schemaFor': jest.fn(),
16+
'resource-fetch/refreshFlag': () => false,
17+
},
18+
dispatch: jest.fn(),
19+
};
20+
21+
const mockValue = {
22+
id: 'fleet-default/test-bundle',
23+
type: 'fleet.cattle.io.bundle',
24+
metadata: {
25+
name: 'test-bundle',
26+
namespace: 'fleet-default',
27+
labels: {},
28+
},
29+
spec: { targets: [] },
30+
status: { conditions: [] },
31+
targetClusters: [],
32+
};
33+
34+
const mockValueWithResources = {
35+
id: 'fleet-default/test-bundle',
36+
type: 'fleet.cattle.io.bundle',
37+
metadata: {
38+
name: 'test-bundle',
39+
namespace: 'fleet-default',
40+
labels: {},
41+
},
42+
spec: { targets: [] },
43+
status: {
44+
conditions: [
45+
{
46+
type: 'Ready',
47+
status: 'True',
48+
}
49+
]
50+
},
51+
targetClusters: [
52+
{
53+
id: 'fleet-default/cluster-1',
54+
nameDisplay: 'cluster-1',
55+
metadata: { labels: { 'management.cattle.io/cluster-name': 'c-m-abc123' } },
56+
},
57+
],
58+
};
59+
60+
const mockBundleDeployments = [
61+
{
62+
metadata: {
63+
labels: {
64+
'fleet.cattle.io/bundle-namespace': 'fleet-default',
65+
'fleet.cattle.io/bundle-name': 'test-bundle',
66+
'fleet.cattle.io/cluster-namespace': 'fleet-default',
67+
'fleet.cattle.io/cluster': 'cluster-1',
68+
},
69+
},
70+
status: {
71+
resources: [
72+
{
73+
kind: 'Deployment',
74+
apiVersion: 'apps/v1',
75+
namespace: 'default',
76+
name: 'nginx',
77+
},
78+
{
79+
kind: 'Service',
80+
apiVersion: 'v1',
81+
namespace: 'default',
82+
name: 'nginx-svc',
83+
},
84+
],
85+
},
86+
},
87+
];
88+
89+
const fullMountGlobal = {
90+
mocks: {
91+
$store: mockStore,
92+
$fetchState: { pending: false },
93+
$route: { query: {}, hash: '' },
94+
$router: {
95+
applyQuery: jest.fn(),
96+
replace: jest.fn(),
97+
currentRoute: { _value: { hash: '' } },
98+
},
99+
},
100+
stubs: {
101+
ResourceTable: true,
102+
teleport: true,
103+
},
104+
};
105+
106+
const createWrapper = (props = {}) => {
107+
return shallowMount(BundleDetail, {
108+
props: {
109+
value: mockValue,
110+
...props,
111+
},
112+
global: {
113+
mocks: {
114+
$store: mockStore,
115+
$fetchState: { pending: false },
116+
$route: { query: {} },
117+
$router: { applyQuery: jest.fn() },
118+
},
119+
},
120+
});
121+
};
122+
123+
it('should render the bundle detail page', () => {
124+
const wrapper = createWrapper();
125+
126+
expect(wrapper.html()).toMatchSnapshot();
127+
});
128+
129+
it('should render the bundle detail page with full mount', () => {
130+
const wrapper = mount(BundleDetail, {
131+
props: { value: mockValue },
132+
global: fullMountGlobal,
133+
});
134+
135+
expect(wrapper.html()).toMatchSnapshot();
136+
});
137+
138+
it('should show Loading when fetch is pending', () => {
139+
const wrapper = shallowMount(BundleDetail, {
140+
props: { value: mockValue },
141+
global: {
142+
mocks: {
143+
$store: mockStore,
144+
$fetchState: { pending: true },
145+
$route: { query: {} },
146+
$router: { applyQuery: jest.fn() },
147+
},
148+
},
149+
});
150+
151+
expect(wrapper.html()).toMatchSnapshot();
152+
});
153+
154+
it('should render resources when bundle deployments exist', async() => {
155+
const wrapper = mount(BundleDetail, {
156+
props: { value: mockValueWithResources },
157+
global: fullMountGlobal,
158+
});
159+
160+
// Simulate fetch completion by setting allBundleDeployments
161+
(wrapper.vm as any).allBundleDeployments = mockBundleDeployments;
162+
await wrapper.vm.$nextTick();
163+
164+
expect(wrapper.html()).toMatchSnapshot();
165+
166+
// Verify computed bundleResources are populated
167+
expect((wrapper.vm as any).bundleResources).toHaveLength(2);
168+
expect((wrapper.vm as any).bundleResources[0].name).toBe('nginx');
169+
expect((wrapper.vm as any).bundleResources[1].name).toBe('nginx-svc');
170+
});
171+
});

shell/detail/fleet.cattle.io.bundle.vue

Lines changed: 21 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,16 @@ import FleetUtils from '@shell/utils/fleet';
55
import { checkSchemasForFindAllHash } from '@shell/utils/auth';
66
import Loading from '@shell/components/Loading.vue';
77
import { FLEET as FLEET_ANNOTATIONS } from '@shell/config/labels-annotations';
8+
import ResourceTabs from '@shell/components/form/ResourceTabs';
9+
import Tab from '@shell/components/Tabbed/Tab';
810
911
export default {
1012
name: 'FleetBundleDetail',
1113
12-
components: { Loading, FleetResources },
13-
props: {
14+
components: {
15+
Loading, FleetResources, ResourceTabs, Tab
16+
},
17+
props: {
1418
value: {
1519
type: Object,
1620
required: true,
@@ -82,42 +86,25 @@ export default {
8286
return res;
8387
}, []);
8488
},
85-
resourceCount() {
86-
return this.bundleResources.length;
87-
},
8889
}
8990
};
9091
9192
</script>
9293
9394
<template>
94-
<div>
95-
<div class="bundle-title mt-20 mb-20">
96-
<h2>{{ t('fleet.bundles.resources') }}</h2>
97-
<span>{{ resourceCount }}</span>
98-
</div>
99-
<Loading v-if="$fetchState.pending" />
100-
<FleetResources
101-
v-else
102-
:rows="bundleResources"
103-
/>
104-
</div>
95+
<Loading v-if="$fetchState.pending" />
96+
<ResourceTabs
97+
v-else
98+
:value="value"
99+
mode="view"
100+
:need-related="false"
101+
>
102+
<Tab
103+
label="Resources"
104+
name="resources"
105+
:weight="20"
106+
>
107+
<FleetResources :rows="bundleResources" />
108+
</Tab>
109+
</ResourceTabs>
105110
</template>
106-
107-
<style lang="scss" scoped>
108-
.bundle-title {
109-
display: flex;
110-
align-items: center;
111-
112-
h2 {
113-
margin: 0 10px 0 0;
114-
}
115-
116-
span {
117-
background-color: var(--darker);
118-
color: var(--default);
119-
padding: 5px 10px;
120-
border-radius: 15px;
121-
}
122-
}
123-
</style>

0 commit comments

Comments
 (0)