Skip to content

Commit a6e4f88

Browse files
authored
Merge pull request #1483 from kravciak/nav2
2nd level navigation
2 parents 3e61dfb + 91c4ea4 commit a6e4f88

2 files changed

Lines changed: 65 additions & 53 deletions

File tree

tests/e2e/components/navigation.ts

Lines changed: 60 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,40 @@
1-
import { expect, Page, test } from '@playwright/test'
1+
import { expect, Page, Locator, test } from '@playwright/test'
22
import { step } from '../rancher/rancher-test'
33
import { RancherUI } from './rancher-ui'
44
import { RancherCommonPage } from '../rancher/rancher-common.page'
55

6-
type ExpGroup = 'Cluster' | 'Workloads' | 'Apps' | 'Storage' | 'Admission Policy Management' | 'SBOMScanner'
7-
type ExpItemMap = {
6+
// Explorer navigation
7+
type ENav = 'Cluster' | 'Workloads' | 'Apps' | 'Storage' | 'Admission Policy Management' | 'SBOMScanner'
8+
type ENavMap = {
89
'Cluster' : 'Projects/Namespaces' | 'Nodes' | 'Cluster and Project Members' | 'Events'
910
'Workloads' : 'CronJobs' | 'DaemonSets' | 'Deployments' | 'Jobs' | 'StatefulSets' | 'Pods'
1011
'Apps' : 'Charts' | 'Installed Apps' | 'Repositories' | 'Recent Operations'
1112
'Storage' : 'PersistentVolumes' | 'StorageClasses' | 'ConfigMaps' | 'PersistentVolumeClaims' | 'Secrets'
1213
'Admission Policy Management': 'Policy Servers' | 'Cluster Admission Policies' | 'Admission Policies' | 'Policy Reporter'
13-
'SBOMScanner' : 'Images' | 'Workloads Scan' | 'Registries configuration' | 'VEX Management'
14+
'SBOMScanner' : 'Images' | 'Advanced'
1415
}
15-
16+
// Expandable items in ENavMap that have a third navigation level
17+
type ENavSubMap = {
18+
SBOMScanner: {
19+
Advanced: 'Workloads Scan' | 'VEX Management' | 'Registries configuration'
20+
}
21+
}
22+
// Returns valid sub-items for a given group and child
23+
type ENavChild<T extends ENav, C extends ENavMap[T]> =
24+
T extends keyof ENavSubMap
25+
? C extends keyof ENavSubMap[T]
26+
? ENavSubMap[T][C]
27+
: never
28+
: never
29+
30+
// Fleet navigation
1631
// Rancher v2.12 renamed Advanced to Resources
17-
type FleetGroup = '' | 'Advanced' | 'Resources'
18-
type FleetItemMap = {
19-
'' : 'Dashboard' | 'Git Repos' | 'App Bundles' | 'Clusters' | 'Cluster Groups' | 'Workspaces'
20-
'Advanced' : 'Workspaces' | 'BundleNamespaceMappings' | 'Bundles' | 'Cluster Registration Tokens' | 'GitRepoRestrictions'
21-
'Resources': 'Git Repos' | 'Helm Ops' | 'BundleNamespaceMappings' | 'Bundles' | 'Cluster Registration Tokens' | 'GitRepoRestrictions'
32+
type FNav = 'Dashboard' | 'Git Repos' | 'App Bundles' | 'Clusters' | 'Cluster Groups' | 'Workspaces' | 'Advanced' | 'Resources'
33+
type FNavMap = {
34+
Advanced : 'Workspaces' | 'BundleNamespaceMappings' | 'Bundles' | 'Cluster Registration Tokens' | 'GitRepoRestrictions'
35+
Resources: 'Git Repos' | 'Helm Ops' | 'BundleNamespaceMappings' | 'Bundles' | 'Cluster Registration Tokens' | 'GitRepoRestrictions'
2236
}
37+
type FNavChild<T extends FNav> = T extends keyof FNavMap ? FNavMap[T] : never
2338

2439
export interface Cluster {
2540
id : string
@@ -55,42 +70,46 @@ export class Navigation {
5570
}, 'User menu occasionally does not open', { reload: false })
5671
}
5772

58-
private async sideNavHandler(groupName: string, childName?: string) {
59-
const groupHeader = this.page.getByRole('heading', { name: groupName, exact: true })
60-
let groupBlock = this.page.locator('nav.side-nav').locator('.accordion')
61-
if (groupName) groupBlock = groupBlock.filter({ has: groupHeader })
62-
63-
// Expand group if needed
64-
if (groupName && childName) {
65-
const expandBtn = groupBlock.locator('i.icon-chevron-down,i.icon-chevron-right')
66-
// Can't detect with expandBtn.isVisible, conflict in: icon-down = closed (2.7) = open (2.8)
67-
await expect(groupBlock).toBeVisible()
68-
if (!await groupBlock.getByRole('list').first().isVisible()) {
69-
await expandBtn.click()
73+
private async sideNavHandler(groupName: string, childName?: string, subChildName?: string) {
74+
const expand = async(block: Locator) => {
75+
await expect(block).toBeVisible()
76+
if (!await block.getByRole('list').first().isVisible()) {
77+
await block.locator('i.icon-chevron-right').click()
7078
}
7179
}
72-
// Click menu item
73-
if (childName) {
74-
await groupBlock.getByText(childName, { exact: true }).click()
75-
} else {
76-
await groupBlock.locator(groupHeader).click()
80+
const groupBlock = this.page.locator('nav.side-nav .accordion', { has: this.page.getByText(groupName, { exact: true }) })
81+
82+
if (!childName) {
83+
await groupBlock.getByText(groupName, { exact: true }).click()
84+
return
7785
}
7886

79-
// 2nd level children not implemented
87+
await expand(groupBlock)
88+
const childBlock = groupBlock.getByRole('listitem').filter({ has: this.page.getByText(childName, { exact: true }) })
89+
90+
if (subChildName) await expand(childBlock)
91+
await childBlock.getByText(subChildName || childName, { exact: true }).click()
8092
}
8193

8294
@step
83-
async fleet<T extends FleetGroup>(groupName?: T, childName?: FleetItemMap[T]) {
95+
async fleet<T extends FNav>(groupName?: T, childName?: FNavChild<T>) {
8496
await this.mainNav('Continuous Delivery')
85-
if (groupName !== undefined) await this.sideNavHandler(groupName, childName)
97+
if (!groupName) return
98+
99+
// Backwards compatibility overrides
100+
if (RancherUI.isVersion('<=2.11')) {
101+
if (childName == 'Git Repos') return await this.sideNavHandler('Git Repos')
102+
if (groupName == 'Resources') return await this.sideNavHandler('Advanced', childName)
103+
}
104+
await this.sideNavHandler(groupName, childName)
86105
}
87106

88107
@step
89-
async explorer<T extends ExpGroup>(groupName: T, childName?: ExpItemMap[T]) {
108+
async explorer<T extends ENav, C extends ENavMap[T]>(groupName: T, childName?: C, subChildName?: ENavChild<T, C>) {
90109
if (this.isblank()) await this.cluster()
91-
await this.sideNavHandler(groupName, childName)
110+
await this.sideNavHandler(groupName, childName, subChildName)
92111

93-
// Handle known cases of empty tables
112+
// Handle empty tables - https://github.com/rancher/rancher/issues/54281
94113
if (childName === 'Installed Apps' || childName === 'CronJobs') {
95114
const row = this.ui.tableRow(/^(rancher|audit-scanner)$/).row
96115
await expect(row).toBeVisible().catch(async() => {
@@ -136,8 +155,8 @@ export class Navigation {
136155
// ==================================================================================================
137156
// Kubewarden specific helpers
138157

139-
@step // Overview
140-
async kubewarden(childName?: ExpItemMap['Admission Policy Management']) {
158+
@step // Dashboard
159+
async kubewarden(childName?: ENavMap['Admission Policy Management']) {
141160
await this.explorer('Admission Policy Management', childName)
142161
}
143162

@@ -169,16 +188,13 @@ export class Navigation {
169188
// SBOMScanner specific helpers
170189

171190
@step
172-
async sbomScanner(childName?: ExpItemMap['SBOMScanner']) {
173-
// Navigation does not support 2nd level items (Advanced > Registries)
174-
if (childName === 'VEX Management')
175-
await this.goto(`dashboard/c/local/imageScanner/sbomscanner.kubewarden.io.vexhub`)
176-
else if (childName === 'Workloads Scan')
177-
await this.goto(`dashboard/c/local/imageScanner/sbomscanner.kubewarden.io.workloadscanconfiguration`)
178-
else if (childName === 'Registries configuration')
179-
await this.goto(`dashboard/c/local/imageScanner/sbomscanner.kubewarden.io.registry`)
180-
else
191+
async sbomScanner(childName?: ENavMap['SBOMScanner'] | ENavChild<'SBOMScanner', ENavMap['SBOMScanner']>) {
192+
// Shortcut to Advanced sub-items
193+
if (childName === 'VEX Management' || childName === 'Workloads Scan' || childName === 'Registries configuration') {
194+
await this.explorer('SBOMScanner', 'Advanced', childName)
195+
} else {
181196
await this.explorer('SBOMScanner', childName)
197+
}
182198

183199
const heading = childName || /^(Dashboard|Install SBOMScanner)/
184200
await expect(this.page.locator('div.title').getByText(heading)).toBeVisible()

tests/e2e/rancher/rancher-fleet.page.ts

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { Locator, Page } from '@playwright/test'
2-
import { RancherUI, type YAMLPatch } from '../components/rancher-ui'
2+
import { type YAMLPatch } from '../components/rancher-ui'
33
import { test, step, expect } from './rancher-test'
44
import { BasePage } from './basepage'
55

@@ -39,13 +39,9 @@ export class RancherFleetPage extends BasePage {
3939
this.updateBtn = this.ui.button('Update')
4040
}
4141

42-
get navGroup() {
43-
return RancherUI.isVersion('>=2.12') ? 'Resources' : ''
44-
}
45-
4642
async goto(): Promise<void> {
47-
// await this.nav.fleet('', 'Dashboard')
48-
await this.nav.goto('dashboard/c/local/fleet')
43+
await this.nav.fleet()
44+
// await this.nav.goto('dashboard/c/local/fleet')
4945
}
5046

5147
async selectWorkspace(workspace: string) {
@@ -139,7 +135,7 @@ export class RancherFleetPage extends BasePage {
139135
}
140136

141137
async addGitRepo(repo: GitRepo, options?: { timeout?: number }) {
142-
await this.nav.fleet(this.navGroup, 'Git Repos')
138+
await this.nav.fleet('Resources', 'Git Repos')
143139
await this.ui.button('Add Repository').first().click()
144140

145141
await this.addBundle(repo, async() => {
@@ -164,7 +160,7 @@ export class RancherFleetPage extends BasePage {
164160

165161
@step
166162
async deleteGitRepo(name: string) {
167-
await this.nav.fleet(this.navGroup, 'Git Repos')
163+
await this.nav.fleet('Resources', 'Git Repos')
168164
await this.ui.tableRow(name).delete()
169165
}
170166
}

0 commit comments

Comments
 (0)