Files
AppFlowy-Web/cypress/e2e/page/delete-page-verify-trash.cy.ts
2025-11-17 15:10:05 +08:00

316 lines
14 KiB
TypeScript

import { AuthTestUtils } from '../../support/auth-utils';
import { TestTool } from '../../support/page-utils';
import { ModalSelectors, PageSelectors, SidebarSelectors, TrashSelectors, waitForReactUpdate } from '../../support/selectors';
import { generateRandomEmail, logAppFlowyEnvironment } from '../../support/test-config';
import { testLog } from '../../support/test-helpers';
describe('Delete Page, Verify in Trash, and Restore Tests', () => {
let testEmail: string;
let testPageName: string;
before(() => {
// Log environment configuration for debugging
logAppFlowyEnvironment();
});
beforeEach(() => {
// Generate unique test data for each test
testEmail = generateRandomEmail();
testPageName = `test-page-${Date.now()}`;
});
describe('Delete Page, Verify in Trash, and Restore', () => {
it('should create a page, delete it, verify in trash, restore it, and verify it is back in sidebar', () => {
// Handle uncaught exceptions during workspace creation
cy.on('uncaught:exception', (err: Error) => {
if (err.message.includes('No workspace or service found')) {
return false;
}
return true;
});
// Step 1: Login
testLog.info('=== Step 1: Login ===');
cy.visit('/login', { failOnStatusCode: false });
cy.wait(2000);
const authUtils = new AuthTestUtils();
authUtils.signInWithTestUrl(testEmail).then(() => {
cy.url().should('include', '/app');
// Wait for the app to fully load
testLog.info('Waiting for app to fully load...');
// Wait for the loading screen to disappear and main app to appear
cy.get('body', { timeout: 30000 }).should('not.contain', 'Welcome!');
// Wait for the sidebar to be visible (indicates app is loaded)
SidebarSelectors.pageHeader().should('be.visible', { timeout: 30000 });
// Wait for at least one page to exist in the sidebar
PageSelectors.names().should('exist', { timeout: 30000 });
// Additional wait for stability
cy.wait(2000);
// Now wait for the new page button to be available
testLog.info('Looking for new page button...');
PageSelectors.newPageButton()
.should('exist', { timeout: 20000 })
.then(() => {
testLog.info('New page button found!');
});
// Step 2: Create a new page
testLog.info(`=== Step 2: Creating page with title: ${testPageName} ===`);
// Click new page button
PageSelectors.newPageButton().click();
waitForReactUpdate(1000);
// Handle the new page modal
ModalSelectors.newPageModal().should('be.visible').within(() => {
// Select the first available space
ModalSelectors.spaceItemInModal().first().click();
waitForReactUpdate(500);
// Click Add button
cy.contains('button', 'Add').click();
});
// Wait for navigation to the new page
cy.wait(3000);
// Close any share/modal dialogs that might be open
cy.get('body').then(($body: JQuery<HTMLBodyElement>) => {
if ($body.find('[role="dialog"]').length > 0 || $body.find('.MuiDialog-container').length > 0) {
testLog.info('Closing modal dialog');
cy.get('body').type('{esc}');
cy.wait(1000);
}
});
// Set the page title
PageSelectors.titleInput().should('exist');
cy.wait(1000);
PageSelectors.titleInput()
.first()
.should('be.visible')
.click({ force: true })
.then($el => {
if ($el && $el.length > 0) {
cy.wrap($el)
.clear({ force: true })
.type(testPageName, { force: true })
.type('{enter}');
testLog.info(`Set page title to: ${testPageName}`);
}
});
// Wait for the title to be saved
cy.wait(2000);
// Step 3: Verify the page exists in sidebar
testLog.info('=== Step 3: Verifying page exists in sidebar ===');
// Expand the first space to see its pages
TestTool.expandSpace();
cy.wait(1000);
// Verify the page exists
PageSelectors.names().then($pages => {
const pageNames = Array.from($pages).map((el: Element) => el.textContent?.trim());
testLog.info(`Found pages: ${pageNames.join(', ')}`);
// Check if our page exists
const pageExists = pageNames.some(name =>
name === testPageName || name === 'Untitled'
);
if (pageExists) {
testLog.info(`✓ Page created successfully`);
} else {
throw new Error(`Could not find created page. Expected "${testPageName}", found: ${pageNames.join(', ')}`);
}
});
// Step 4: Delete the page
testLog.info(`=== Step 4: Deleting page: ${testPageName} ===`);
// Find the page we want to delete
PageSelectors.names().then($pages => {
const pageNames = Array.from($pages).map((el: Element) => el.textContent?.trim());
// Determine the actual name of the page to delete
let pageToDelete = testPageName;
if (!pageNames.includes(testPageName)) {
// If our custom name didn't save, it might be "Untitled"
const untitledPages = pageNames.filter(name => name === 'Untitled');
if (untitledPages.length > 0) {
pageToDelete = 'Untitled';
testLog.info(`Warning: Page title didn't save. Deleting "Untitled" page instead`);
}
}
// Delete the page
TestTool.deletePageByName(pageToDelete);
testLog.info(`✓ Deleted page: ${pageToDelete}`);
});
// Wait for deletion to complete
cy.wait(2000);
// Step 5: Navigate to trash page
testLog.info('=== Step 5: Navigating to trash page ===');
// Click on the trash button in the sidebar
TrashSelectors.sidebarTrashButton().click();
// Wait for navigation
cy.wait(2000);
// Verify we're on the trash page
cy.url().should('include', '/app/trash');
testLog.info('✓ Successfully navigated to trash page');
// Step 6: Verify the deleted page exists in trash
testLog.info('=== Step 6: Verifying deleted page exists in trash ===');
// Wait for trash table to load
TrashSelectors.table().should('be.visible');
// Look for our deleted page in the trash table
TrashSelectors.rows().then($rows => {
let foundPage = false;
// Check each row for our page name
$rows.each((index, row) => {
const rowText = Cypress.$(row).text();
testLog.info(`Trash row ${index + 1}: ${rowText}`);
// Check if this row contains our page (might be named as testPageName or "Untitled")
if (rowText.includes(testPageName) || rowText.includes('Untitled')) {
foundPage = true;
testLog.info(`✓ Found deleted page in trash: ${rowText}`);
}
});
// Verify we found the page
if (foundPage) {
testLog.info('✓✓✓ Test Passed: Deleted page was found in trash');
} else {
throw new Error(`Deleted page not found in trash. Expected to find "${testPageName}" or "Untitled"`);
}
});
// Step 7: Verify restore and permanent delete buttons are present
testLog.info('=== Step 7: Verifying trash actions are available ===');
TrashSelectors.rows().first().within(() => {
// Check for restore button
TrashSelectors.restoreButton().should('exist');
testLog.info('✓ Restore button found');
// Check for permanent delete button
TrashSelectors.deleteButton().should('exist');
testLog.info('✓ Permanent delete button found');
});
// Step 8: Restore the deleted page
testLog.info('=== Step 8: Restoring the deleted page ===');
// Store the actual page name we'll be restoring
let restoredPageName = 'Untitled'; // Default to Untitled since that's what usually gets created
// Click the restore button on the first row (our deleted page)
TrashSelectors.rows().first().within(() => {
// Get the page name before restoring
cy.get('td').first().invoke('text').then((text) => {
restoredPageName = text.trim() || 'Untitled';
testLog.info(`Restoring page: ${restoredPageName}`);
});
// Click restore button
TrashSelectors.restoreButton().click();
});
// Wait for restore to complete
cy.wait(2000);
testLog.info('✓ Restore button clicked');
// Step 9: Verify the page is removed from trash
testLog.info('=== Step 9: Verifying page is removed from trash ===');
// Wait a bit for the UI to update after restore
cy.wait(2000);
// Check if trash is now empty or doesn't contain our page
// Use a more defensive approach - check if rows exist first
cy.get('body').then($body => {
// Check if trash table rows exist
const rowsExist = $body.find('[data-testid="trash-table-row"]').length > 0;
if (!rowsExist) {
testLog.info('✓ Trash is now empty - page successfully removed from trash');
} else {
// Rows still exist, check if our page is among them
TrashSelectors.rows().then($rows => {
let pageStillInTrash = false;
$rows.each((index, row) => {
const rowText = Cypress.$(row).text();
if (rowText.includes(restoredPageName)) {
pageStillInTrash = true;
}
});
if (pageStillInTrash) {
throw new Error(`Page "${restoredPageName}" is still in trash after restore`);
} else {
testLog.info(`✓ Page "${restoredPageName}" successfully removed from trash`);
}
});
}
});
// Step 10: Navigate back to the main workspace
testLog.info('=== Step 10: Navigating back to workspace ===');
// Click on the workspace/home to go back
cy.visit(`/app`);
cy.wait(3000);
// Wait for the sidebar to load
SidebarSelectors.pageHeader().should('be.visible', { timeout: 10000 });
testLog.info('✓ Navigated back to workspace');
// Step 11: Verify the restored page exists in sidebar
testLog.info('=== Step 11: Verifying restored page exists in sidebar ===');
// Expand the space to see all pages
TestTool.expandSpace();
cy.wait(1000);
// Verify the restored page exists in the sidebar
PageSelectors.names().then($pages => {
const pageNames = Array.from($pages).map((el: Element) => el.textContent?.trim());
testLog.info(`Pages in sidebar after restore: ${pageNames.join(', ')}`);
// Check if our restored page exists
const pageRestored = pageNames.some(name =>
name === restoredPageName || name === testPageName || name === 'Untitled'
);
if (pageRestored) {
testLog.info(`✓✓✓ SUCCESS: Page "${restoredPageName}" has been successfully restored to the sidebar!`);
} else {
throw new Error(`Restored page not found in sidebar. Expected to find "${restoredPageName}", found: ${pageNames.join(', ')}`);
}
});
testLog.info('=== Test completed successfully! Page was deleted, verified in trash, and successfully restored! ===');
});
});
});
});