From 5981af71866717b24705fe5bf0807c79c564b4d9 Mon Sep 17 00:00:00 2001 From: linonetwo Date: Wed, 29 Apr 2026 08:55:02 +0800 Subject: [PATCH] fix(e2e): consolidate workspace drag scenarios and remove fixed waits --- features/stepDefinitions/ui.ts | 5 +- features/stepDefinitions/workspaceGroup.ts | 95 ++++++---------- features/workspaceConfig.feature | 3 - features/workspaceGroup.feature | 124 +++------------------ 4 files changed, 50 insertions(+), 177 deletions(-) diff --git a/features/stepDefinitions/ui.ts b/features/stepDefinitions/ui.ts index bcceb068..e5881252 100644 --- a/features/stepDefinitions/ui.ts +++ b/features/stepDefinitions/ui.ts @@ -542,11 +542,8 @@ When('I select {string} from MUI Select with test id {string}', async function(t throw new Error(`Failed to click: ${JSON.stringify(clicked)}`); } - // Wait a bit for the menu to appear - await currentWindow.waitForTimeout(500); - // Wait for the menu to appear - await currentWindow.waitForSelector('[role="listbox"]', { timeout: PLAYWRIGHT_SHORT_TIMEOUT }); + await currentWindow.waitForSelector('[role="listbox"]', { state: 'visible', timeout: PLAYWRIGHT_SHORT_TIMEOUT }); // Try to click on the option with the specified value (data-value attribute) // If not found, try to find by text content diff --git a/features/stepDefinitions/workspaceGroup.ts b/features/stepDefinitions/workspaceGroup.ts index d26c18ed..5de2e2ad 100644 --- a/features/stepDefinitions/workspaceGroup.ts +++ b/features/stepDefinitions/workspaceGroup.ts @@ -57,6 +57,11 @@ async function getGroups(world: ApplicationWorld): Promise { return await world.currentWindow.evaluate(async () => window.service.workspace.getGroupsAsList()); } +async function getGroupWorkspaces(world: ApplicationWorld, groupId: string): Promise { + const workspaces = await getAllWikiWorkspaces(world); + return workspaces.filter(workspace => workspace.groupId === groupId); +} + async function getSidebarOrderEntries(world: ApplicationWorld): Promise { const [workspaces, groups] = await Promise.all([getAllWikiWorkspaces(world), getGroups(world)]); return [ @@ -73,13 +78,6 @@ async function getSidebarOrderEntries(world: ApplicationWorld): Promise left.order - right.order); } -async function getGroupById(world: ApplicationWorld, groupId: string): Promise { - if (!world.currentWindow) { - throw new Error('Current window not set'); - } - return await world.currentWindow.evaluate(async (id) => window.service.workspace.getGroup(id), groupId); -} - async function createGroup(world: ApplicationWorld, groupName: string): Promise { const groups = await getGroups(world); const newGroup: IWorkspaceGroup = { @@ -131,6 +129,29 @@ async function waitForGroupVisibility(world: ApplicationWorld, groupId: string): }, BACKOFF_OPTIONS); } +async function waitForGroupedWorkspaceDomState(world: ApplicationWorld, groupId: string, shouldBeVisible: boolean): Promise { + await backOff(async () => { + if (!world.currentWindow) { + throw new Error('Current window not set'); + } + + const groupedWorkspaces = await getGroupWorkspaces(world, groupId); + + for (const workspace of groupedWorkspaces) { + const itemCount = await world.currentWindow.locator(`[data-testid="workspace-item-${workspace.id}"]`).count(); + const topDropZoneCount = await world.currentWindow.locator(`[data-testid="workspace-drop-zone-${workspace.id}-top"]`).count(); + + if (shouldBeVisible && (itemCount === 0 || topDropZoneCount === 0)) { + throw new Error(`Grouped workspace "${workspace.name}" is not fully visible yet`); + } + + if (!shouldBeVisible && (itemCount !== 0 || topDropZoneCount !== 0)) { + throw new Error(`Grouped workspace "${workspace.name}" is still visible`); + } + } + }, BACKOFF_OPTIONS); +} + async function dragLocatorToCoordinates( world: ApplicationWorld, sourceSelector: string, @@ -278,10 +299,6 @@ Given('workspace group {string} contains workspaces:', async function(this: Appl } }, BACKOFF_OPTIONS); } - - // Allow any deferred async side-effects (e.g. tidgi.config.json writes) - // to finish so that React state stabilises before the drag step starts. - await this.currentWindow?.waitForTimeout(3000); }); When('I drag workspace {string} onto workspace {string}', async function(this: ApplicationWorld, sourceWorkspaceName: string, targetWorkspaceName: string) { @@ -382,15 +399,6 @@ When('I drag workspace {string} onto the header of its current group', async fun ); }); -When('I remove workspace {string} from its group without auto-disband', async function(this: ApplicationWorld, workspaceName: string) { - const workspace = await getWorkspaceByName(this, workspaceName); - if (!workspace.groupId) { - throw new Error(`Workspace "${workspaceName}" is not currently grouped`); - } - - await moveWorkspaceToGroup(this, workspace.id, null, false); -}); - Then('workspaces {string} and {string} should share a group', async function(this: ApplicationWorld, firstWorkspaceName: string, secondWorkspaceName: string) { await backOff(async () => { const [firstWorkspace, secondWorkspace] = await Promise.all([ @@ -417,20 +425,6 @@ Then('workspace {string} should be in a group', async function(this: Application }, BACKOFF_OPTIONS); }); -Then('the group containing workspace {string} should contain {int} workspaces', async function(this: ApplicationWorld, workspaceName: string, expectedCount: number) { - await backOff(async () => { - const workspace = await getWorkspaceByName(this, workspaceName); - if (!workspace.groupId) { - throw new Error(`Workspace "${workspaceName}" is not in a group`); - } - - const groupedWorkspaces = (await getAllWikiWorkspaces(this)).filter(candidate => candidate.groupId === workspace.groupId); - if (groupedWorkspaces.length !== expectedCount) { - throw new Error(`Expected ${expectedCount} workspaces in group ${workspace.groupId}, found ${groupedWorkspaces.length}`); - } - }, BACKOFF_OPTIONS); -}); - Then('there should be {int} workspace groups', async function(this: ApplicationWorld, expectedCount: number) { await backOff(async () => { const groups = await getGroups(this); @@ -440,20 +434,6 @@ Then('there should be {int} workspace groups', async function(this: ApplicationW }, BACKOFF_OPTIONS); }); -Then('the group containing workspace {string} should still exist', async function(this: ApplicationWorld, workspaceName: string) { - await backOff(async () => { - const workspace = await getWorkspaceByName(this, workspaceName); - if (!workspace.groupId) { - throw new Error(`Workspace "${workspaceName}" is not in a group`); - } - - const group = await getGroupById(this, workspace.groupId); - if (!group) { - throw new Error(`Group ${workspace.groupId} no longer exists`); - } - }, BACKOFF_OPTIONS); -}); - Then('workspace {string} should appear before workspace {string}', async function(this: ApplicationWorld, firstWorkspaceName: string, secondWorkspaceName: string) { await backOff(async () => { const [firstWorkspace, secondWorkspace] = await Promise.all([ @@ -502,15 +482,6 @@ Then('workspace {string} should show {string} drag intent', async function(this: }, BACKOFF_OPTIONS); }); -When('I press the Escape key', async function(this: ApplicationWorld) { - if (!this.currentWindow) { - throw new Error('Current window not set'); - } - - await this.currentWindow.keyboard.press('Escape'); - await this.currentWindow.waitForTimeout(100); -}); - When('I collapse workspace group {string}', async function(this: ApplicationWorld, groupName: string) { const groups = await getGroups(this); const group = groups.find(g => g.name === groupName); @@ -525,8 +496,7 @@ When('I collapse workspace group {string}', async function(this: ApplicationWorl await window.service.workspace.setGroup(g.id, { ...g, collapsed: true }); }, group); - // Wait for Collapse unmountOnExit to fully remove children from DOM - await this.currentWindow?.waitForTimeout(400); + await waitForGroupedWorkspaceDomState(this, group.id, false); }); When('I expand workspace group {string}', async function(this: ApplicationWorld, groupName: string) { @@ -543,11 +513,8 @@ When('I expand workspace group {string}', async function(this: ApplicationWorld, await window.service.workspace.setGroup(g.id, { ...g, collapsed: false }); }, group); - // Wait for the MUI Collapse animation to finish so that - // overflow:hidden no longer clips pointer events on child elements. - // timeout='auto' can take 300-500ms for small lists; 2000ms ensures completion - // even on slower CI runners. - await this.currentWindow?.waitForTimeout(2000); + await waitForGroupVisibility(this, group.id); + await waitForGroupedWorkspaceDomState(this, group.id, true); }); When('I drag group header {string} onto group header {string}', async function(this: ApplicationWorld, sourceGroupName: string, targetGroupName: string) { diff --git a/features/workspaceConfig.feature b/features/workspaceConfig.feature index 144fb951..97f3dfd2 100644 --- a/features/workspaceConfig.feature +++ b/features/workspaceConfig.feature @@ -95,7 +95,6 @@ Feature: Workspace Configuration Sync When I update workspace "wiki" settings: | property | value | | name | LocalWiki | - When I wait for 2 seconds for "potential config write" # Step 4: Verify tidgi.config.json was NOT overwritten by the local-only workspace Then file "wiki/tidgi.config.json" should contain JSON with: @@ -109,7 +108,6 @@ Feature: Workspace Configuration Sync When I update workspace "LocalWiki" settings: | property | value | | readOnlyMode | true | - When I wait for 2 seconds for "potential config write" # Step 7: Verify read-only config did NOT leak into tidgi.config.json Then file "wiki/tidgi.config.json" should contain JSON with: @@ -159,7 +157,6 @@ Feature: Workspace Configuration Sync | property | value | | name | BlogDeploy | | readOnlyMode | true | - When I wait for 2 seconds for "potential config write" # Step 3: Verify tidgi.config.json does NOT contain the readOnlyMode from the non-synced workspace # (Default wiki may have created tidgi.config.json, but the non-synced workspace must not modify it) diff --git a/features/workspaceGroup.feature b/features/workspaceGroup.feature index b341de63..ab6c8df9 100644 --- a/features/workspaceGroup.feature +++ b/features/workspaceGroup.feature @@ -10,14 +10,6 @@ Feature: Workspace Grouping And I wait for the page to load completely And the browser view should be loaded and visible - Scenario: Create a group by dragging one ungrouped workspace onto another - When I create a new wiki workspace with name "Group Drag Alpha" - And I create a new wiki workspace with name "Group Drag Beta" - And I drag workspace "Group Drag Alpha" onto workspace "Group Drag Beta" - Then workspaces "Group Drag Alpha" and "Group Drag Beta" should share a group - And the group containing workspace "Group Drag Alpha" should contain 2 workspaces - And there should be 1 workspace groups - Scenario: Dragging a workspace onto its own group header removes it from the group When I create a new wiki workspace with name "Ungroup Drag Beta" And I create a new wiki workspace with name "Ungroup Drag Gamma" @@ -27,20 +19,6 @@ Feature: Workspace Grouping When I drag workspace "Ungroup Drag Beta" onto the header of its current group Then workspace "Ungroup Drag Beta" should be ungrouped And workspace "Ungroup Drag Gamma" should be in a group - And the group containing workspace "Ungroup Drag Gamma" should contain 1 workspaces - And there should be 1 workspace groups - - Scenario: Removing one workspace without auto-disband keeps a two-item group alive - When I create a new wiki workspace with name "Context Path Beta" - And I create a new wiki workspace with name "Context Path Gamma" - Given workspace group "Context Path Group" contains workspaces: - | Context Path Beta | - | Context Path Gamma | - When I remove workspace "Context Path Beta" from its group without auto-disband - Then workspace "Context Path Beta" should be ungrouped - And workspace "Context Path Gamma" should be in a group - And the group containing workspace "Context Path Gamma" should contain 1 workspaces - And there should be 1 workspace groups Scenario: Removing the last workspace deletes the empty group When I create a new wiki workspace with name "Last Workspace Gamma" @@ -50,116 +28,56 @@ Feature: Workspace Grouping Then workspace "Last Workspace Gamma" should be ungrouped And there should be 0 workspace groups - Scenario: Dragging to top zone reorders before without grouping + Scenario: Dragging across top, bottom, and center zones covers grouped and ungrouped targets When I create a new wiki workspace with name "Zone Test Alpha" And I create a new wiki workspace with name "Zone Test Beta" And I create a new wiki workspace with name "Zone Test Gamma" + And I create a new wiki workspace with name "Zone Test Delta" When I drag workspace "Zone Test Gamma" to the top zone of workspace "Zone Test Alpha" - Then workspace "Zone Test Gamma" should be ungrouped - And workspace "Zone Test Alpha" should be ungrouped And workspace "Zone Test Gamma" should appear before workspace "Zone Test Alpha" - - Scenario: Dragging to bottom zone reorders after without grouping - When I create a new wiki workspace with name "Zone Bottom Alpha" - And I create a new wiki workspace with name "Zone Bottom Beta" - And I create a new wiki workspace with name "Zone Bottom Gamma" - When I drag workspace "Zone Bottom Alpha" to the bottom zone of workspace "Zone Bottom Gamma" - Then workspace "Zone Bottom Alpha" should be ungrouped - And workspace "Zone Bottom Gamma" should be ungrouped - And workspace "Zone Bottom Alpha" should appear after workspace "Zone Bottom Gamma" - - Scenario: Dragging to center zone creates a group - When I create a new wiki workspace with name "Zone Center Alpha" - And I create a new wiki workspace with name "Zone Center Beta" - When I drag workspace "Zone Center Alpha" onto workspace "Zone Center Beta" - Then workspaces "Zone Center Alpha" and "Zone Center Beta" should share a group - And the group containing workspace "Zone Center Alpha" should contain 2 workspaces + When I drag workspace "Zone Test Gamma" to the bottom zone of workspace "Zone Test Beta" + Then workspace "Zone Test Gamma" should appear after workspace "Zone Test Beta" + When I drag workspace "Zone Test Alpha" onto workspace "Zone Test Beta" + Then workspaces "Zone Test Alpha" and "Zone Test Beta" should share a group + When I drag workspace "Zone Test Delta" to the top zone of workspace "Zone Test Alpha" + Then workspace "Zone Test Delta" should appear before workspace "Zone Test Alpha" + And workspaces "Zone Test Alpha" and "Zone Test Beta" should share a group Scenario: Canceling a drag with Escape key leaves workspaces unchanged When I create a new wiki workspace with name "Cancel Drag Alpha" And I create a new wiki workspace with name "Cancel Drag Beta" And I hover workspace "Cancel Drag Alpha" over workspace "Cancel Drag Beta" - And I press the Escape key + And I press "Escape" key Then workspace "Cancel Drag Alpha" should be ungrouped And workspace "Cancel Drag Beta" should be ungrouped - Scenario: Dragging a workspace from a collapsed group - When I create a new wiki workspace with name "Collapsed Group Alpha" - And I create a new wiki workspace with name "Collapsed Group Beta" - And I create a new wiki workspace with name "Collapsed Group Gamma" - Given workspace group "Collapsed Test Group" contains workspaces: - | Collapsed Group Alpha | - | Collapsed Group Beta | - When I collapse workspace group "Collapsed Test Group" - And I expand workspace group "Collapsed Test Group" - And I drag workspace "Collapsed Group Alpha" onto workspace "Collapsed Group Gamma" - Then workspaces "Collapsed Group Alpha" and "Collapsed Group Gamma" should share a group - And workspace "Collapsed Group Beta" should be in a group - - Scenario: Dragging workspace between different groups + Scenario: Dragging workspace between different groups after collapsing and re-expanding the source group When I create a new wiki workspace with name "Cross Group Alpha" And I create a new wiki workspace with name "Cross Group Beta" And I create a new wiki workspace with name "Cross Group Gamma" - And I create a new wiki workspace with name "Cross Group Delta" Given workspace group "Cross Group A" contains workspaces: | Cross Group Alpha | | Cross Group Beta | Given workspace group "Cross Group B" contains workspaces: | Cross Group Gamma | - | Cross Group Delta | - When I drag workspace "Cross Group Alpha" onto workspace "Cross Group Gamma" + When I collapse workspace group "Cross Group A" + And I expand workspace group "Cross Group A" + And I drag workspace "Cross Group Alpha" onto workspace "Cross Group Gamma" Then workspaces "Cross Group Alpha" and "Cross Group Gamma" should share a group And workspace "Cross Group Beta" should be in a group - And the group containing workspace "Cross Group Beta" should contain 1 workspaces - And the group containing workspace "Cross Group Gamma" should contain 3 workspaces - Scenario: Reordering workspaces within the same group - When I create a new wiki workspace with name "Same Group Alpha" - And I create a new wiki workspace with name "Same Group Beta" - And I create a new wiki workspace with name "Same Group Gamma" - Given workspace group "Same Group Test" contains workspaces: - | Same Group Alpha | - | Same Group Beta | - | Same Group Gamma | - When I drag workspace "Same Group Gamma" to the top zone of workspace "Same Group Alpha" - Then workspace "Same Group Gamma" should appear before workspace "Same Group Alpha" - And workspace "Same Group Alpha" should appear before workspace "Same Group Beta" - And workspaces "Same Group Alpha" and "Same Group Gamma" should share a group - - Scenario: Reordering group headers + Scenario: Reordering group headers and positioning before ungrouped workspaces When I create a new wiki workspace with name "Group Order Alpha" And I create a new wiki workspace with name "Group Order Beta" And I create a new wiki workspace with name "Group Order Gamma" - And I create a new wiki workspace with name "Group Order Delta" Given workspace group "Group Order A" contains workspaces: | Group Order Alpha | - | Group Order Beta | Given workspace group "Group Order B" contains workspaces: - | Group Order Gamma | - | Group Order Delta | + | Group Order Beta | When I drag group header "Group Order B" onto group header "Group Order A" Then group "Group Order B" should appear before group "Group Order A" - - Scenario: Reordering group header before an ungrouped workspace - When I create a new wiki workspace with name "Mixed Order Alpha" - And I create a new wiki workspace with name "Mixed Order Beta" - And I create a new wiki workspace with name "Mixed Order Gamma" - Given workspace group "Mixed Order Group" contains workspaces: - | Mixed Order Gamma | - When I drag group header "Mixed Order Group" onto workspace "Mixed Order Alpha" - Then group "Mixed Order Group" should appear before workspace "Mixed Order Alpha" - - Scenario: Dragging ungrouped workspace to zone of grouped workspace - When I create a new wiki workspace with name "Zone Grouped Alpha" - And I create a new wiki workspace with name "Zone Grouped Beta" - And I create a new wiki workspace with name "Zone Grouped Gamma" - Given workspace group "Zone Grouped Test" contains workspaces: - | Zone Grouped Alpha | - | Zone Grouped Beta | - When I drag workspace "Zone Grouped Gamma" to the top zone of workspace "Zone Grouped Alpha" - Then workspace "Zone Grouped Gamma" should be ungrouped - And workspace "Zone Grouped Gamma" should appear before workspace "Zone Grouped Alpha" - And workspaces "Zone Grouped Alpha" and "Zone Grouped Beta" should share a group + When I drag group header "Group Order A" onto workspace "Group Order Gamma" + Then group "Group Order A" should appear before workspace "Group Order Gamma" Scenario: Hovering a workspace over another shows combine intent on the target When I create a new wiki workspace with name "Hover Highlight Alpha" @@ -167,9 +85,3 @@ Feature: Workspace Grouping And I hover workspace "Hover Highlight Alpha" over workspace "Hover Highlight Beta" Then workspace "Hover Highlight Beta" should show "group" drag intent And I release the mouse - - Scenario: Preferences search finds workspace group management - When I click on a "settings button" element with selector "#open-preferences-button" - And I switch to "preferences" window - And I type "workspace group" in "search input" element with selector "[data-testid='preferences-search-input'] input" - Then I should see a "workspace group management" element with selector "[data-testid='create-group-button']"