mirror of
https://github.com/nextcloud/server.git
synced 2026-05-21 17:45:40 -04:00
fix(cypress): adapt NavigationHeader and theming specs to waffle launcher
Signed-off-by: Peter Ringelmann <peter.ringelmann@nextcloud.com>
This commit is contained in:
parent
831989b770
commit
c36d64d06a
4 changed files with 123 additions and 29 deletions
|
|
@ -175,9 +175,15 @@ describe('Remove the default background with a bright color', function() {
|
|||
})
|
||||
|
||||
it('See the header being inverted', function() {
|
||||
// Probe the Nextcloud logo: it carries the same
|
||||
// `var(--background-image-invert-if-bright)` filter and is always
|
||||
// present in the header. The waffle launcher's current-app icon only
|
||||
// renders when an app is active, which isn't the case on settings,
|
||||
// and the in-popover tiles use a fixed brightness/invert filter
|
||||
// regardless of theme so they're not a valid inversion probe.
|
||||
cy.waitUntil(() => navigationHeader
|
||||
.getNavigationEntries()
|
||||
.find('img')
|
||||
.logo()
|
||||
.find('.logo')
|
||||
.then((el) => {
|
||||
let ret = true
|
||||
el.each(function() {
|
||||
|
|
|
|||
|
|
@ -35,9 +35,14 @@ describe('User theming set app order', () => {
|
|||
const appOrder = ['Dashboard', 'Files']
|
||||
appOrderList.assertAppOrder(appOrder)
|
||||
|
||||
// Check the top app menu order
|
||||
navigationHeader.getNavigationEntries()
|
||||
.each((entry, index) => expect(entry).contain.text(appOrder[index]!))
|
||||
// Check the top app menu order. The launcher grid appends a synthetic
|
||||
// "More apps" / "App store" tile to the user's apps, so iterate
|
||||
// positionally only over the real-app prefix.
|
||||
navigationHeader.getNavigationEntries().then(($entries) => {
|
||||
appOrder.forEach((name, index) => {
|
||||
expect($entries.eq(index)).to.contain.text(name)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('Change the app order', () => {
|
||||
|
|
@ -59,9 +64,14 @@ describe('User theming set app order', () => {
|
|||
.scrollIntoView()
|
||||
appOrderList.assertAppOrder(appOrder)
|
||||
|
||||
// Check the top app menu order
|
||||
navigationHeader.getNavigationEntries()
|
||||
.each((entry, index) => expect(entry).contain.text(appOrder[index]!))
|
||||
// Check the top app menu order. Idempotent open in the page object
|
||||
// re-opens the popover after the reload above. The synthetic trailing
|
||||
// tile is ignored by iterating only over the expected app names.
|
||||
navigationHeader.getNavigationEntries().then(($entries) => {
|
||||
appOrder.forEach((name, index) => {
|
||||
expect($entries.eq(index)).to.contain.text(name)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
|
|
@ -140,9 +150,13 @@ describe('User theming set app order with default app', () => {
|
|||
cy.reload()
|
||||
|
||||
const appOrder = ['Files', 'Test App', 'Dashboard', 'Test App 2']
|
||||
// Check the top app menu order
|
||||
navigationHeader.getNavigationEntries()
|
||||
.each((entry, index) => expect(entry).contain.text(appOrder[index]!))
|
||||
// Check the top app menu order. See note above: the launcher appends
|
||||
// a synthetic tile that we skip by iterating positionally.
|
||||
navigationHeader.getNavigationEntries().then(($entries) => {
|
||||
appOrder.forEach((name, index) => {
|
||||
expect($entries.eq(index)).to.contain.text(name)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
|
|
@ -219,9 +233,12 @@ describe('User theming reset app order', () => {
|
|||
const appOrder = ['Dashboard', 'Files']
|
||||
appOrderList.assertAppOrder(appOrder)
|
||||
|
||||
// Check the top app menu order
|
||||
navigationHeader.getNavigationEntries()
|
||||
.each((entry, index) => expect(entry).contain.text(appOrder[index]!))
|
||||
// Check the top app menu order. See note above on the synthetic tile.
|
||||
navigationHeader.getNavigationEntries().then(($entries) => {
|
||||
appOrder.forEach((name, index) => {
|
||||
expect($entries.eq(index)).to.contain.text(name)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('See the reset button is disabled', () => {
|
||||
|
|
@ -263,9 +280,12 @@ describe('User theming reset app order', () => {
|
|||
it('See the app order is restored', () => {
|
||||
const appOrder = ['Dashboard', 'Files']
|
||||
appOrderList.assertAppOrder(appOrder)
|
||||
// Check the top app menu order
|
||||
navigationHeader.getNavigationEntries()
|
||||
.each((entry, index) => expect(entry).contain.text(appOrder[index]!))
|
||||
// Check the top app menu order. See note above on the synthetic tile.
|
||||
navigationHeader.getNavigationEntries().then(($entries) => {
|
||||
appOrder.forEach((name, index) => {
|
||||
expect($entries.eq(index)).to.contain.text(name)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('See the reset button is disabled again', () => {
|
||||
|
|
|
|||
|
|
@ -131,7 +131,13 @@ describe('User select a bright custom color and remove background', function() {
|
|||
})
|
||||
|
||||
it('See the header being inverted', function() {
|
||||
cy.waitUntil(() => navigationHeader.getNavigationEntries().find('img').then((el) => {
|
||||
// Probe the Nextcloud logo: it carries the same
|
||||
// `var(--background-image-invert-if-bright)` filter and is always
|
||||
// present in the header. The waffle launcher's current-app icon only
|
||||
// renders when an app is active, which isn't the case on settings,
|
||||
// and the in-popover tiles use a fixed brightness/invert filter
|
||||
// regardless of theme so they're not a valid inversion probe.
|
||||
cy.waitUntil(() => navigationHeader.logo().find('.logo').then((el) => {
|
||||
let ret = true
|
||||
el.each(function() {
|
||||
ret = ret && window.getComputedStyle(this).filter === 'invert(1)'
|
||||
|
|
@ -157,7 +163,9 @@ describe('User select a bright custom color and remove background', function() {
|
|||
})
|
||||
|
||||
it('See the header NOT being inverted this time', function() {
|
||||
cy.waitUntil(() => navigationHeader.getNavigationEntries().find('img').then((el) => {
|
||||
// Probe the Nextcloud logo: see the inverted-header test above for
|
||||
// why we don't probe the menu icons.
|
||||
cy.waitUntil(() => navigationHeader.logo().find('.logo').then((el) => {
|
||||
let ret = true
|
||||
el.each(function() {
|
||||
ret = ret && window.getComputedStyle(this).filter === 'none'
|
||||
|
|
|
|||
|
|
@ -4,7 +4,11 @@
|
|||
*/
|
||||
|
||||
/**
|
||||
* Page object model for the Nextcloud navigation header
|
||||
* Page object model for the Nextcloud navigation header.
|
||||
*
|
||||
* The app launcher (waffle menu) is an NcPopover whose content is teleported
|
||||
* to <body>, so the menu items do not live inside the <nav> element. Selectors
|
||||
* for the menu entries scope to the popover rather than the nav.
|
||||
*/
|
||||
export class NavigationHeader {
|
||||
/**
|
||||
|
|
@ -23,35 +27,91 @@ export class NavigationHeader {
|
|||
}
|
||||
|
||||
/**
|
||||
* Locator of the app navigation bar
|
||||
* Locator of the app navigation bar.
|
||||
*
|
||||
* The accessible name is just "Applications" since the waffle redesign;
|
||||
* the previous label "Applications menu" is gone.
|
||||
*/
|
||||
navigation() {
|
||||
return this.header()
|
||||
.findByRole('navigation', { name: 'Applications menu' })
|
||||
.findByRole('navigation', { name: 'Applications' })
|
||||
}
|
||||
|
||||
/**
|
||||
* The toggle for the navigation overflow menu
|
||||
* Open the waffle launcher popover.
|
||||
*
|
||||
* Idempotent: if the popover is already open the click is skipped, so
|
||||
* callers can invoke this defensively at the start of any helper that
|
||||
* needs the menu items in the DOM.
|
||||
*/
|
||||
openMenu() {
|
||||
this.navigation()
|
||||
.find('.app-menu__waffle')
|
||||
.then(($trigger) => {
|
||||
if ($trigger.attr('aria-expanded') !== 'true') {
|
||||
cy.wrap($trigger).click()
|
||||
}
|
||||
})
|
||||
// Popover is teleported to <body>, so query from the document root.
|
||||
cy.get('.app-menu__popover').should('be.visible')
|
||||
return this.popover()
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the waffle launcher popover.
|
||||
*
|
||||
* Sends Escape rather than clicking outside: NcPopover's focus trap is
|
||||
* active while the menu is open, so a stray click can land on a tile.
|
||||
*/
|
||||
closeMenu() {
|
||||
cy.get('body').type('{esc}')
|
||||
cy.get('.app-menu__popover').should('not.exist')
|
||||
}
|
||||
|
||||
/**
|
||||
* Locator for the popover content (the teleported grid wrapper).
|
||||
*
|
||||
* Scoping menu-item queries here is mandatory: the popover is rendered
|
||||
* outside the <nav>, so `.within(navigation())` would find nothing.
|
||||
*/
|
||||
popover() {
|
||||
return cy.get('[role="menu"][aria-label="Apps"]')
|
||||
}
|
||||
|
||||
/**
|
||||
* The waffle trigger that toggles the launcher.
|
||||
*
|
||||
* @deprecated The old "overflow" affordance is gone; this now points at
|
||||
* the waffle button so existing call sites keep compiling. Prefer
|
||||
* {@link openMenu} / {@link closeMenu} in new code.
|
||||
*/
|
||||
overflowNavigationToggle() {
|
||||
return this.navigation()
|
||||
.find('.app-menu__waffle')
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all navigation entries
|
||||
* Get all navigation entries in the launcher.
|
||||
*
|
||||
* Opens the popover first if it is not already open; the entries do not
|
||||
* exist in the DOM otherwise. Each entry is rendered as an `<a role="menuitem">`.
|
||||
*/
|
||||
getNavigationEntries() {
|
||||
return this.navigation()
|
||||
.findAllByRole('listitem')
|
||||
this.openMenu()
|
||||
return this.popover().findAllByRole('menuitem')
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the navigation entry for a given app
|
||||
* Get the navigation entry for a given app.
|
||||
*
|
||||
* Each tile's accessible name comes from the `<a title="...">` attribute
|
||||
* and the inner `.app-item__label`, so `findByRole('menuitem', { name })`
|
||||
* matches reliably.
|
||||
*
|
||||
* @param name The app name
|
||||
*/
|
||||
getNavigationEntry(name: string) {
|
||||
return this.navigation()
|
||||
.findByRole('listitem', { name })
|
||||
this.openMenu()
|
||||
return this.popover().findByRole('menuitem', { name })
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue