Files
AppFlowy-Web/cypress/e2e/page/breadcrumb-navigation.cy.ts
2025-11-17 13:58:29 +08:00

883 lines
44 KiB
TypeScript

import { AuthTestUtils } from '../../support/auth-utils';
import { TestTool } from '../../support/page-utils';
import {
BreadcrumbSelectors,
PageSelectors,
SidebarSelectors,
SpaceSelectors
} from '../../support/selectors';
import { generateRandomEmail, logAppFlowyEnvironment } from '../../support/test-config';
import { testLog } from '../../support/test-helpers';
describe('Breadcrumb Navigation Complete Tests', () => {
let testEmail: string;
before(() => {
// Log environment configuration for debugging
logAppFlowyEnvironment();
});
beforeEach(() => {
// Generate unique test data for each test
testEmail = generateRandomEmail();
// Handle uncaught exceptions
cy.on('uncaught:exception', (err: Error) => {
if (err.message.includes('No workspace or service found')) {
return false;
}
// Handle View not found errors
if (err.message.includes('View not found')) {
return false;
}
return true;
});
});
describe('Basic Navigation Tests', () => {
it('should navigate through space and check for breadcrumb availability', () => {
// // Login
testLog.info('=== Step 1: Login ===');
cy.visit('/login', { failOnStatusCode: false });
cy.get('body').should('be.visible');
const authUtils = new AuthTestUtils();
authUtils.signInWithTestUrl(testEmail).then(() => {
cy.url().should('include', '/app');
// Wait for app to load
testLog.info('Waiting for app to fully load...');
cy.get('body', { timeout: 30000 }).should('not.contain', 'Welcome!');
SidebarSelectors.pageHeader().should('be.visible', { timeout: 30000 });
PageSelectors.names().should('exist', { timeout: 30000 });
// Wait for pages to be ready
PageSelectors.names().should('have.length.at.least', 1);
testLog.info('App loaded successfully');
// Step 2: Expand first space
testLog.info('=== Step 2: Expanding first space ===');
TestTool.expandSpace(0);
// Wait for space to expand and pages to be visible
PageSelectors.names().should('be.visible', { timeout: 10000 });
testLog.info('Expanded first space');
// Step 3: Navigate to first page
testLog.info('=== Step 3: Navigating to first page ===');
PageSelectors.names().first().then($page => {
const pageName = $page.text();
testLog.info(`Navigating to: ${pageName}`);
cy.wrap($page).click();
});
// Wait for page to load
cy.url().should('include', '/app/', { timeout: 10000 });
// Step 4: Check for breadcrumb navigation
testLog.info('=== Step 4: Checking for breadcrumb navigation ===');
BreadcrumbSelectors.navigation().then($nav => {
if ($nav.length > 0) {
testLog.info('✓ Breadcrumb navigation found on this page');
BreadcrumbSelectors.items().then($items => {
testLog.info(`✓ Found ${$items.length} breadcrumb items`);
});
} else {
testLog.info('No breadcrumb navigation on this page (normal for top-level pages)');
}
});
// Verify no errors
cy.get('body').then($body => {
const hasError = $body.text().includes('Error') ||
$body.text().includes('Failed');
if (!hasError) {
testLog.info('✓ Navigation completed without errors');
}
});
testLog.info('=== Basic navigation test completed ===');
});
});
it('should navigate to nested pages and use breadcrumb to go back', () => {
// Login
cy.visit('/login', { failOnStatusCode: false });
cy.get('body').should('be.visible');
const authUtils = new AuthTestUtils();
authUtils.signInWithTestUrl(testEmail).then(() => {
cy.url().should('include', '/app');
// Wait for app to load
cy.get('body', { timeout: 30000 }).should('not.contain', 'Welcome!');
SidebarSelectors.pageHeader().should('be.visible', { timeout: 30000 });
PageSelectors.names().should('exist', { timeout: 30000 });
// Wait for pages to be ready
PageSelectors.names().should('have.length.at.least', 1);
testLog.info('=== Step 1: Expand first space ===');
TestTool.expandSpace(0);
// Wait for space to expand and pages to be visible
PageSelectors.names().should('be.visible', { timeout: 10000 });
testLog.info('=== Step 2: Navigate to first page ===');
PageSelectors.names().first().click();
// Wait for page to load
cy.url().should('include', '/app/', { timeout: 10000 });
cy.wait(2000); // Wait for sidebar to update
testLog.info('=== Step 3: Check for nested pages ===');
PageSelectors.names().then($pages => {
testLog.info(`Found ${$pages.length} pages in sidebar`);
// Find child pages by name
const childPageNames = ['Desktop guide', 'Mobile guide', 'Web guide'];
let childPageFound = false;
for (let i = 0; i < $pages.length; i++) {
const pageName = Cypress.$($pages[i]).text().trim();
if (childPageNames.includes(pageName)) {
testLog.info(`Found child page: ${pageName}`);
cy.wrap($pages[i]).click({ force: true });
childPageFound = true;
break;
}
}
if (!childPageFound && $pages.length > 1) {
// Fallback: navigate to second page
testLog.info('No known child page found, clicking second page as fallback');
cy.wrap($pages[1]).click({ force: true });
}
// Wait for page to load
cy.url().should('include', '/app/', { timeout: 10000 });
cy.wait(2000);
// Check for breadcrumb navigation
testLog.info('=== Step 4: Testing breadcrumb navigation ===');
BreadcrumbSelectors.navigation().then($nav => {
if ($nav.length > 0) {
testLog.info('✓ Breadcrumb navigation is visible');
BreadcrumbSelectors.items().should('have.length.at.least', 1);
BreadcrumbSelectors.items().then($items => {
if ($items.length > 1) {
cy.wrap($items).first().click({ force: true });
testLog.info('✓ Clicked breadcrumb item to navigate back');
// Wait for navigation to complete
cy.url().should('include', '/app/', { timeout: 10000 });
testLog.info('✓ Successfully used breadcrumb navigation');
} else {
testLog.info('Only one breadcrumb item found');
}
});
} else {
testLog.info('No breadcrumb navigation on nested page');
}
});
});
testLog.info('=== Nested navigation test completed ===');
});
});
});
describe('Full Breadcrumb Flow Test', () => {
it('should navigate through General > Get Started > Desktop Guide flow (if available)', () => {
// Login
cy.visit('/login', { failOnStatusCode: false });
cy.get('body').should('be.visible');
const authUtils = new AuthTestUtils();
authUtils.signInWithTestUrl(testEmail).then(() => {
cy.url().should('include', '/app');
// Wait for app to load
cy.get('body', { timeout: 30000 }).should('not.contain', 'Welcome!');
SidebarSelectors.pageHeader().should('be.visible', { timeout: 30000 });
PageSelectors.names().should('exist', { timeout: 30000 });
// Wait for pages to be ready
PageSelectors.names().should('have.length.at.least', 1);
// Step 1: Find and expand General space or first space
testLog.info('=== Step 1: Looking for General space ===');
SpaceSelectors.names().then($spaces => {
const spaceNames = Array.from($spaces).map((el: Element) => el.textContent?.trim());
testLog.info(`Available spaces: ${spaceNames.join(', ')}`);
// Find General space or use first
const generalIndex = spaceNames.findIndex(name =>
name?.toLowerCase().includes('general')
);
if (generalIndex !== -1) {
testLog.info(`Found General space at index ${generalIndex}`);
TestTool.expandSpace(generalIndex);
} else {
testLog.info('Using first available space');
TestTool.expandSpace(0);
}
});
// Wait for space to expand and pages to be visible
PageSelectors.names().should('be.visible', { timeout: 10000 });
// Step 2: Look for Get Started page or use first page
testLog.info('=== Step 2: Looking for Get Started page ===');
PageSelectors.names().then($pages => {
const pageNames = Array.from($pages).map((el: Element) => el.textContent?.trim());
testLog.info(`Available pages: ${pageNames.join(', ')}`);
// Find Get Started or similar page
const getStartedPage = Array.from($pages).find((el: Element) => {
const text = el.textContent?.trim().toLowerCase();
return text?.includes('get') || text?.includes('start') ||
text?.includes('welcome') || text?.includes('guide');
});
if (getStartedPage) {
cy.wrap(getStartedPage).click();
testLog.info(`Clicked on: ${getStartedPage.textContent?.trim()}`);
} else {
PageSelectors.names().first().click();
testLog.info('Clicked first available page');
}
});
// Wait for page to load
cy.url().should('include', '/app/', { timeout: 10000 });
cy.wait(2000); // Wait for sidebar to update
// Step 3: Look for Desktop Guide or sub-page
testLog.info('=== Step 3: Looking for Desktop Guide or sub-pages ===');
PageSelectors.names().then($subPages => {
const subPageNames = Array.from($subPages).map((el: Element) => el.textContent?.trim());
testLog.info(`Found pages: ${subPageNames.join(', ')}`);
// Look for Desktop Guide or any guide
const childPageNames = ['Desktop guide', 'Mobile guide', 'Web guide'];
let guidePage = null;
for (let i = 0; i < $subPages.length; i++) {
const el = $subPages[i];
const text = el.textContent?.trim().toLowerCase();
if (text?.includes('desktop') || childPageNames.some(name => text.includes(name.toLowerCase()))) {
guidePage = el;
break;
}
}
if (guidePage) {
cy.wrap(guidePage).click({ force: true });
testLog.info(`Navigated to: ${guidePage.textContent?.trim()}`);
} else if ($subPages.length > 1) {
// Try to find a child page by name
let childFound = false;
for (let i = 0; i < $subPages.length; i++) {
const pageName = Cypress.$($subPages[i]).text().trim();
if (childPageNames.includes(pageName)) {
cy.wrap($subPages[i]).click({ force: true });
testLog.info(`Navigated to: ${pageName}`);
childFound = true;
break;
}
}
if (!childFound) {
cy.wrap($subPages[1]).click({ force: true });
testLog.info('Navigated to second page');
}
}
// Wait for page to load
cy.url().should('include', '/app/', { timeout: 10000 });
cy.wait(2000);
// Step 4: Test breadcrumb navigation
testLog.info('=== Step 4: Testing breadcrumb navigation ===');
BreadcrumbSelectors.navigation().then($nav => {
if ($nav.length > 0) {
testLog.info('✓ Breadcrumb navigation is visible');
BreadcrumbSelectors.items().should('have.length.at.least', 1);
BreadcrumbSelectors.items().then($items => {
testLog.info(`Found ${$items.length} breadcrumb items`);
if ($items.length > 1) {
const targetIndex = Math.max(0, $items.length - 2);
cy.wrap($items[targetIndex]).click({ force: true });
testLog.info(`✓ Clicked breadcrumb at index ${targetIndex} to go back`);
// Wait for navigation to complete
cy.url().should('include', '/app/', { timeout: 10000 });
testLog.info('✓ Successfully navigated back using breadcrumb');
}
});
} else {
testLog.info('Breadcrumb navigation not available on this page');
}
});
});
// Final verification
cy.get('body').then($body => {
const hasError = $body.text().includes('Error') ||
$body.text().includes('Failed') ||
$body.find('[role="alert"]').length > 0;
if (!hasError) {
testLog.info('✓ Test completed without errors');
}
});
testLog.info('=== Full breadcrumb flow test completed ===');
});
});
});
describe('Breadcrumb Item Verification Tests', () => {
it('should verify breadcrumb items display correct names and are clickable', () => {
cy.visit('/login', { failOnStatusCode: false });
cy.get('body').should('be.visible');
const authUtils = new AuthTestUtils();
authUtils.signInWithTestUrl(testEmail).then(() => {
cy.url().should('include', '/app');
// Wait for app to load
cy.get('body', { timeout: 30000 }).should('not.contain', 'Welcome!');
SidebarSelectors.pageHeader().should('be.visible', { timeout: 30000 });
PageSelectors.names().should('exist', { timeout: 30000 });
PageSelectors.names().should('have.length.at.least', 1);
testLog.info('=== Step 1: Navigate to nested page ===');
TestTool.expandSpace(0);
PageSelectors.names().should('be.visible', { timeout: 10000 });
// Navigate to first page
PageSelectors.names().first().click();
cy.url().should('include', '/app/', { timeout: 10000 });
cy.wait(2000); // Wait for sidebar to update
// Navigate to nested page if available
PageSelectors.names().then($pages => {
// Find child pages by name
const childPageNames = ['Desktop guide', 'Mobile guide', 'Web guide'];
let childPageFound = false;
for (let i = 0; i < $pages.length; i++) {
const pageName = Cypress.$($pages[i]).text().trim();
if (childPageNames.includes(pageName)) {
testLog.info(`Found child page: ${pageName}`);
cy.wrap($pages[i]).click({ force: true });
childPageFound = true;
break;
}
}
if (!childPageFound && $pages.length > 1) {
cy.wrap($pages[1]).click({ force: true });
}
cy.url().should('include', '/app/', { timeout: 10000 });
cy.wait(2000);
testLog.info('=== Step 2: Verify breadcrumb items ===');
BreadcrumbSelectors.navigation().then($nav => {
if ($nav.length > 0) {
BreadcrumbSelectors.items().then($items => {
testLog.info(`Found ${$items.length} breadcrumb items`);
// Verify each breadcrumb item has text
$items.each((index, item) => {
const $item = Cypress.$(item);
const itemText = $item.text().trim();
testLog.info(`Breadcrumb ${index}: "${itemText}"`);
expect(itemText).to.not.be.empty;
});
// Verify last item is not clickable (should be disabled)
if ($items.length > 0) {
const lastItem = $items.last();
cy.wrap(lastItem).should('exist');
testLog.info('✓ Verified breadcrumb items structure');
}
});
} else {
testLog.info('No breadcrumb navigation available');
}
});
});
});
});
it('should verify breadcrumb navigation updates correctly when navigating', () => {
cy.visit('/login', { failOnStatusCode: false });
cy.get('body').should('be.visible');
const authUtils = new AuthTestUtils();
authUtils.signInWithTestUrl(testEmail).then(() => {
cy.url().should('include', '/app');
// Wait for app to load
cy.get('body', { timeout: 30000 }).should('not.contain', 'Welcome!');
SidebarSelectors.pageHeader().should('be.visible', { timeout: 30000 });
PageSelectors.names().should('exist', { timeout: 30000 });
PageSelectors.names().should('have.length.at.least', 1);
testLog.info('=== Step 1: Navigate to parent page ===');
TestTool.expandSpace(0);
PageSelectors.names().should('be.visible', { timeout: 10000 });
let parentPageName: string;
PageSelectors.names().first().then($page => {
parentPageName = $page.text().trim();
testLog.info(`Parent page: ${parentPageName}`);
cy.wrap($page).click();
});
cy.url().should('include', '/app/', { timeout: 10000 });
cy.wait(2000); // Wait for sidebar to update
testLog.info('=== Step 2: Navigate to nested page ===');
PageSelectors.names().then($pages => {
// Find child pages by name
const childPageNames = ['Desktop guide', 'Mobile guide', 'Web guide'];
let childPageFound = false;
for (let i = 0; i < $pages.length; i++) {
const pageName = Cypress.$($pages[i]).text().trim();
if (childPageNames.includes(pageName)) {
testLog.info(`Found child page: ${pageName}`);
cy.wrap($pages[i]).click({ force: true });
childPageFound = true;
break;
}
}
if (!childPageFound && $pages.length > 1) {
cy.wrap($pages[1]).click({ force: true });
}
cy.url().should('include', '/app/', { timeout: 10000 });
cy.wait(2000);
testLog.info('=== Step 3: Verify breadcrumb shows parent ===');
BreadcrumbSelectors.navigation().then($nav => {
if ($nav.length > 0) {
BreadcrumbSelectors.items().then($items => {
if ($items.length > 1) {
// Verify parent page appears in breadcrumb
const breadcrumbTexts = Array.from($items).map(el => Cypress.$(el).text().trim());
const hasParent = breadcrumbTexts.some(text => text.includes(parentPageName));
if (hasParent) {
testLog.info('✓ Parent page found in breadcrumb');
}
}
});
}
});
testLog.info('=== Step 4: Navigate back via breadcrumb ===');
BreadcrumbSelectors.items().then($items => {
if ($items.length > 1) {
// Click first breadcrumb (parent)
cy.wrap($items).first().click({ force: true });
cy.url().should('include', '/app/', { timeout: 10000 });
testLog.info('✓ Successfully navigated back via breadcrumb');
}
});
});
});
});
});
describe('Deep Navigation Tests', () => {
it('should handle breadcrumb navigation for 3+ level deep pages', () => {
cy.visit('/login', { failOnStatusCode: false });
cy.get('body').should('be.visible');
const authUtils = new AuthTestUtils();
authUtils.signInWithTestUrl(testEmail).then(() => {
cy.url().should('include', '/app');
// Wait for app to load
cy.get('body', { timeout: 30000 }).should('not.contain', 'Welcome!');
SidebarSelectors.pageHeader().should('be.visible', { timeout: 30000 });
PageSelectors.names().should('exist', { timeout: 30000 });
PageSelectors.names().should('have.length.at.least', 1);
testLog.info('=== Step 1: Navigate to first level ===');
TestTool.expandSpace(0);
PageSelectors.names().should('be.visible', { timeout: 10000 });
// Get initial page count
let initialPageCount = 0;
PageSelectors.names().then($pages => {
initialPageCount = $pages.length;
testLog.info(`Initial pages in sidebar: ${initialPageCount}`);
});
// Click first page and wait for navigation
PageSelectors.names().first().then($firstPage => {
const firstPageName = $firstPage.text().trim();
testLog.info(`Clicking on first page: ${firstPageName}`);
cy.wrap($firstPage).click();
});
cy.url().should('include', '/app/', { timeout: 10000 });
// Wait for page to load and sidebar to potentially update
cy.wait(2000);
testLog.info('Waiting for sidebar to update with nested pages...');
testLog.info('=== Step 2: Navigate to second level ===');
// Look for nested pages - they should be children of the first page
// In the sidebar, nested pages appear after their parent when expanded
PageSelectors.names().then($pages => {
testLog.info(`Pages in sidebar after navigation: ${$pages.length}`);
const pageNames = Array.from($pages).map((el: Element) => el.textContent?.trim());
testLog.info(`Available pages: ${pageNames.join(', ')}`);
// Find "Desktop guide" or another child page (usually appears after "Getting started")
// Children of "Getting started" are: Desktop guide, Mobile guide, Web guide
const childPageNames = ['Desktop guide', 'Mobile guide', 'Web guide'];
let childPageFound = false;
for (let i = 0; i < $pages.length; i++) {
const pageName = Cypress.$($pages[i]).text().trim();
if (childPageNames.includes(pageName)) {
testLog.info(`Found child page: ${pageName} at index ${i}`);
cy.wrap($pages[i]).click({ force: true });
childPageFound = true;
break;
}
}
if (!childPageFound && $pages.length > 1) {
// Fallback: click second page if no known child found
testLog.info('No known child page found, clicking second page as fallback');
cy.wrap($pages[1]).click({ force: true });
}
cy.url().should('include', '/app/', { timeout: 10000 });
// Wait for sidebar to update again
cy.wait(2000);
testLog.info('Waiting for sidebar to update with third level pages...');
testLog.info('=== Step 3: Navigate to third level if available ===');
// Wait for third level pages to appear
PageSelectors.names().should('exist', { timeout: 10000 });
PageSelectors.names().then($subPages => {
testLog.info(`Pages in sidebar after second navigation: ${$subPages.length}`);
const subPageNames = Array.from($subPages).map((el: Element) => el.textContent?.trim());
testLog.info(`Available sub-pages: ${subPageNames.join(', ')}`);
// Try to find another nested page or click a different page
if ($subPages.length > 2) {
// Click a page that's different from what we've already clicked
// Skip first two (Getting started and Desktop guide) and try third
cy.wrap($subPages[2]).click({ force: true });
cy.url().should('include', '/app/', { timeout: 10000 });
cy.wait(2000); // Wait for page to fully load
testLog.info('=== Step 4: Verify breadcrumb shows all levels ===');
// Wait a bit more for breadcrumb to render
cy.wait(1000);
BreadcrumbSelectors.navigation().should('exist', { timeout: 10000 }).then($nav => {
if ($nav.length > 0) {
BreadcrumbSelectors.items().should('have.length.at.least', 1);
BreadcrumbSelectors.items().then($items => {
testLog.info(`Found ${$items.length} breadcrumb items (3+ levels deep)`);
// Log breadcrumb item texts for debugging
const breadcrumbTexts = Array.from($items).map(el => Cypress.$(el).text().trim());
testLog.info(`Breadcrumb items: ${breadcrumbTexts.join(' > ')}`);
expect($items.length).to.be.at.least(2);
// Verify we can navigate back through breadcrumbs
if ($items.length > 2) {
// Click second-to-last breadcrumb
const targetIndex = $items.length - 2;
testLog.info(`Clicking breadcrumb at index ${targetIndex} (${breadcrumbTexts[targetIndex]})`);
cy.wrap($items[targetIndex]).click({ force: true });
cy.url().should('include', '/app/', { timeout: 10000 });
cy.wait(1000);
testLog.info('✓ Successfully navigated back from deep level');
} else {
testLog.info(`Only ${$items.length} breadcrumb items found, expected at least 3 for deep navigation`);
}
});
} else {
testLog.info('Breadcrumb not available for deep navigation');
}
});
} else {
testLog.info(`No third level pages available (found ${$subPages.length} pages)`);
}
});
});
});
});
});
describe('Breadcrumb After Page Creation Tests', () => {
it('should show breadcrumb after creating a new nested page', () => {
cy.visit('/login', { failOnStatusCode: false });
cy.get('body').should('be.visible');
const authUtils = new AuthTestUtils();
authUtils.signInWithTestUrl(testEmail).then(() => {
cy.url().should('include', '/app');
// Wait for app to load
cy.get('body', { timeout: 30000 }).should('not.contain', 'Welcome!');
SidebarSelectors.pageHeader().should('be.visible', { timeout: 30000 });
PageSelectors.names().should('exist', { timeout: 30000 });
PageSelectors.names().should('have.length.at.least', 1);
testLog.info('=== Step 1: Navigate to a page ===');
TestTool.expandSpace(0);
PageSelectors.names().should('be.visible', { timeout: 10000 });
PageSelectors.names().first().click();
cy.url().should('include', '/app/', { timeout: 10000 });
cy.wait(2000); // Wait for page to load
testLog.info('=== Step 2: Create a new nested page ===');
const newPageName = `Test Page ${Date.now()}`;
// Create page using the new page button
PageSelectors.newPageButton().should('be.visible').click();
cy.wait(1000);
// Close any modals that might appear
cy.get('body').then($body => {
if ($body.find('[role="dialog"]').length > 0) {
cy.get('body').type('{esc}');
cy.wait(500);
}
});
// Wait for page to be created and navigate to it
cy.url().should('include', '/app/', { timeout: 10000 });
cy.wait(2000); // Wait for page to fully load
// Set page title if title input is available (use force to bypass modal backdrop)
PageSelectors.titleInput().then($titleInput => {
if ($titleInput.length > 0) {
cy.wrap($titleInput).first().click({ force: true });
cy.wait(500);
cy.wrap($titleInput).first().type('{selectall}', { force: true });
cy.wrap($titleInput).first().type(newPageName, { force: true });
cy.wrap($titleInput).first().type('{enter}', { force: true });
cy.wait(1000);
}
});
testLog.info('=== Step 3: Verify breadcrumb appears for new page ===');
BreadcrumbSelectors.navigation().then($nav => {
if ($nav.length > 0) {
testLog.info('✓ Breadcrumb navigation found after page creation');
BreadcrumbSelectors.items().should('have.length.at.least', 1);
BreadcrumbSelectors.items().then($items => {
testLog.info(`Found ${$items.length} breadcrumb items for new page`);
// Verify we can navigate back
if ($items.length > 1) {
cy.wrap($items).first().click({ force: true });
cy.url().should('include', '/app/', { timeout: 10000 });
testLog.info('✓ Successfully navigated back from newly created page');
}
});
} else {
testLog.info('No breadcrumb navigation (page may be top-level)');
}
});
});
});
});
describe('Breadcrumb Text Content Tests', () => {
it('should verify breadcrumb items contain correct page names', () => {
cy.visit('/login', { failOnStatusCode: false });
cy.get('body').should('be.visible');
const authUtils = new AuthTestUtils();
authUtils.signInWithTestUrl(testEmail).then(() => {
cy.url().should('include', '/app');
// Wait for app to load
cy.get('body', { timeout: 30000 }).should('not.contain', 'Welcome!');
SidebarSelectors.pageHeader().should('be.visible', { timeout: 30000 });
PageSelectors.names().should('exist', { timeout: 30000 });
PageSelectors.names().should('have.length.at.least', 1);
testLog.info('=== Step 1: Navigate through pages and collect names ===');
TestTool.expandSpace(0);
PageSelectors.names().should('be.visible', { timeout: 10000 });
const pageNames: string[] = [];
PageSelectors.names().then($pages => {
// Collect first 3 page names
const maxPages = Math.min($pages.length, 3);
for (let i = 0; i < maxPages; i++) {
const pageName = Cypress.$($pages[i]).text().trim();
pageNames.push(pageName);
}
testLog.info(`Collected page names: ${pageNames.join(', ')}`);
// Navigate to first page
if (pageNames.length > 0) {
cy.wrap($pages[0]).click();
cy.url().should('include', '/app/', { timeout: 10000 });
cy.wait(2000); // Wait for sidebar to update
// Find and navigate to nested page
const childPageNames = ['Desktop guide', 'Mobile guide', 'Web guide'];
let childFound = false;
PageSelectors.names().then($subPages => {
for (let i = 0; i < $subPages.length; i++) {
const pageName = Cypress.$($subPages[i]).text().trim();
if (childPageNames.includes(pageName)) {
cy.wrap($subPages[i]).click({ force: true });
childFound = true;
break;
}
}
if (!childFound && $subPages.length > 1) {
cy.wrap($subPages[1]).click({ force: true });
}
cy.url().should('include', '/app/', { timeout: 10000 });
cy.wait(2000);
testLog.info('=== Step 2: Verify breadcrumb contains page names ===');
BreadcrumbSelectors.navigation().then($nav => {
if ($nav.length > 0) {
BreadcrumbSelectors.items().then($items => {
const breadcrumbTexts = Array.from($items).map(el =>
Cypress.$(el).text().trim()
);
testLog.info(`Breadcrumb texts: ${breadcrumbTexts.join(' > ')}`);
// Verify parent page name appears in breadcrumb
if (pageNames.length > 0 && breadcrumbTexts.length > 0) {
const hasParentName = breadcrumbTexts.some(text =>
text.includes(pageNames[0])
);
if (hasParentName) {
testLog.info('✓ Parent page name found in breadcrumb');
}
}
});
}
});
});
}
});
});
});
});
describe('Breadcrumb Edge Cases', () => {
it('should handle breadcrumb when navigating between different spaces', () => {
cy.visit('/login', { failOnStatusCode: false });
cy.get('body').should('be.visible');
const authUtils = new AuthTestUtils();
authUtils.signInWithTestUrl(testEmail).then(() => {
cy.url().should('include', '/app');
// Wait for app to load
cy.get('body', { timeout: 30000 }).should('not.contain', 'Welcome!');
SidebarSelectors.pageHeader().should('be.visible', { timeout: 30000 });
PageSelectors.names().should('exist', { timeout: 30000 });
PageSelectors.names().should('have.length.at.least', 1);
testLog.info('=== Step 1: Navigate to first space ===');
TestTool.expandSpace(0);
PageSelectors.names().should('be.visible', { timeout: 10000 });
PageSelectors.names().first().click();
cy.url().should('include', '/app/', { timeout: 10000 });
cy.wait(2000); // Wait for sidebar to update
testLog.info('=== Step 2: Check breadcrumb state ===');
BreadcrumbSelectors.navigation().then($nav => {
if ($nav.length > 0) {
BreadcrumbSelectors.items().then($items => {
testLog.info(`Breadcrumb items before navigation: ${$items.length}`);
// Navigate to nested page
PageSelectors.names().then($pages => {
// Find child pages by name
const childPageNames = ['Desktop guide', 'Mobile guide', 'Web guide'];
let childFound = false;
for (let i = 0; i < $pages.length; i++) {
const pageName = Cypress.$($pages[i]).text().trim();
if (childPageNames.includes(pageName)) {
cy.wrap($pages[i]).click({ force: true });
childFound = true;
break;
}
}
if (!childFound && $pages.length > 1) {
cy.wrap($pages[1]).click({ force: true });
}
cy.url().should('include', '/app/', { timeout: 10000 });
cy.wait(2000);
// Verify breadcrumb updates
BreadcrumbSelectors.items().then($newItems => {
testLog.info(`Breadcrumb items after navigation: ${$newItems.length}`);
if ($newItems.length > $items.length) {
testLog.info('✓ Breadcrumb updated correctly after navigation');
}
});
});
});
}
});
});
});
it('should verify breadcrumb does not appear on top-level pages', () => {
cy.visit('/login', { failOnStatusCode: false });
cy.get('body').should('be.visible');
const authUtils = new AuthTestUtils();
authUtils.signInWithTestUrl(testEmail).then(() => {
cy.url().should('include', '/app');
// Wait for app to load
cy.get('body', { timeout: 30000 }).should('not.contain', 'Welcome!');
SidebarSelectors.pageHeader().should('be.visible', { timeout: 30000 });
PageSelectors.names().should('exist', { timeout: 30000 });
PageSelectors.names().should('have.length.at.least', 1);
testLog.info('=== Step 1: Navigate to top-level page ===');
TestTool.expandSpace(0);
PageSelectors.names().should('be.visible', { timeout: 10000 });
// Click first page (likely top-level)
PageSelectors.names().first().click();
cy.url().should('include', '/app/', { timeout: 10000 });
cy.wait(2000); // Wait for page to load
testLog.info('=== Step 2: Verify breadcrumb behavior on top-level page ===');
BreadcrumbSelectors.navigation().then($nav => {
if ($nav.length === 0) {
testLog.info('✓ No breadcrumb on top-level page (expected behavior)');
} else {
BreadcrumbSelectors.items().then($items => {
testLog.info(`Found ${$items.length} breadcrumb items on top-level page`);
// Top-level pages may or may not have breadcrumbs depending on structure
});
}
});
});
});
});
});