feat(app): retain workspace screens on sidebar switch

This commit is contained in:
Mohamed Boudra
2026-04-20 12:55:58 +07:00
parent f8411d121e
commit 403fb03c97
11 changed files with 265 additions and 48 deletions
+6 -4
View File
@@ -210,13 +210,15 @@ export async function openWorkspaceWithAgents(
}
export async function expectWorkspaceTabVisible(page: Page, agentId: string): Promise<void> {
await expect(page.getByTestId(`workspace-tab-agent_${agentId}`).first()).toBeVisible({
timeout: 30_000,
});
await expect(
page.getByTestId(`workspace-tab-agent_${agentId}`).filter({ visible: true }).first(),
).toBeVisible({ timeout: 30_000 });
}
export async function expectWorkspaceTabHidden(page: Page, agentId: string): Promise<void> {
await expect(page.getByTestId(`workspace-tab-agent_${agentId}`)).toHaveCount(0, {
await expect(
page.getByTestId(`workspace-tab-agent_${agentId}`).filter({ visible: true }),
).toHaveCount(0, {
timeout: 30_000,
});
}
+19 -11
View File
@@ -23,16 +23,18 @@ export async function gotoWorkspace(page: Page, cwd: string): Promise<void> {
/** Wait for the workspace tab bar to be visible. */
export async function waitForTabBar(page: Page): Promise<void> {
await expect(page.getByTestId("workspace-tabs-row").first()).toBeVisible({
await expect(
page.getByTestId("workspace-tabs-row").filter({ visible: true }).first(),
).toBeVisible({
timeout: 30_000,
});
}
/** Return all tab test IDs currently in the tab bar. */
export async function getTabTestIds(page: Page): Promise<string[]> {
const tabs = page.locator(
'[data-testid^="workspace-tab-"]:not([data-testid^="workspace-tab-context-"])',
);
const tabs = page
.locator('[data-testid^="workspace-tab-"]:not([data-testid^="workspace-tab-context-"])')
.filter({ visible: true });
const count = await tabs.count();
const ids: string[] = [];
for (let i = 0; i < count; i++) {
@@ -55,6 +57,7 @@ export async function getActiveTabTestId(page: Page): Promise<string | null> {
.locator(
'[data-testid^="workspace-tab-"]:not([data-testid^="workspace-tab-context-"])[aria-selected="true"]',
)
.filter({ visible: true })
.first();
if (await activeTab.isVisible().catch(() => false)) {
return activeTab.getAttribute("data-testid");
@@ -67,14 +70,14 @@ export async function getActiveTabTestId(page: Page): Promise<string | null> {
/** Click the new agent tab button in the tab bar. Creates a draft/chat tab directly. */
export async function clickNewTabButton(page: Page): Promise<void> {
const button = page.getByTestId("workspace-new-agent-tab");
const button = page.getByTestId("workspace-new-agent-tab").filter({ visible: true }).first();
await expect(button).toBeVisible({ timeout: 10_000 });
await button.click();
}
/** Click the new terminal button in the workspace tab bar. Creates a terminal tab directly. */
export async function clickNewTerminalButton(page: Page): Promise<void> {
const button = page.getByTestId("workspace-new-terminal");
const button = page.getByTestId("workspace-new-terminal").filter({ visible: true }).first();
await expect(button).toBeVisible({ timeout: 10_000 });
await button.click();
}
@@ -94,26 +97,30 @@ export async function waitForLauncherPanel(page: Page): Promise<void> {
/** Assert the new agent tab button is visible in the tab bar. */
export async function assertNewChatTileVisible(page: Page): Promise<void> {
await expect(page.getByTestId("workspace-new-agent-tab").first()).toBeVisible();
await expect(
page.getByTestId("workspace-new-agent-tab").filter({ visible: true }).first(),
).toBeVisible();
}
/** Assert the new terminal button is visible in the tab bar. */
export async function assertTerminalTileVisible(page: Page): Promise<void> {
await expect(page.getByTestId("workspace-new-terminal").first()).toBeVisible();
await expect(
page.getByTestId("workspace-new-terminal").filter({ visible: true }).first(),
).toBeVisible();
}
// ─── Tab creation actions ─────────────────────────────────────────────────
/** Click the new agent tab button to create a draft/chat tab. */
export async function clickNewChat(page: Page): Promise<void> {
const button = page.getByTestId("workspace-new-agent-tab");
const button = page.getByTestId("workspace-new-agent-tab").filter({ visible: true }).first();
await expect(button).toBeVisible({ timeout: 10_000 });
await button.click();
}
/** Click the new terminal button to create a terminal tab. */
export async function clickTerminal(page: Page): Promise<void> {
const button = page.getByTestId("workspace-new-terminal");
const button = page.getByTestId("workspace-new-terminal").filter({ visible: true }).first();
await expect(button).toBeVisible({ timeout: 10_000 });
await button.click();
}
@@ -131,13 +138,14 @@ export async function waitForTabWithTitle(
page
.locator('[data-testid^="workspace-tab-"]:not([data-testid^="workspace-tab-context-"])')
.filter({ hasText: matcher })
.filter({ visible: true })
.first(),
).toBeVisible({ timeout });
}
/** Assert the new agent tab button is visible in the tab bar. */
export async function assertSingleNewTabButton(page: Page): Promise<void> {
const buttons = page.getByTestId("workspace-new-agent-tab");
const buttons = page.getByTestId("workspace-new-agent-tab").filter({ visible: true });
const count = await buttons.count();
expect(count).toBeGreaterThanOrEqual(1);
}
+17 -5
View File
@@ -13,18 +13,30 @@ export async function getWorkspaceTabTestIds(page: Page): Promise<string[]> {
return ids;
}
function visibleTestId(page: Page, testId: string) {
return page.getByTestId(testId).filter({ visible: true });
}
export async function waitForWorkspaceTabsVisible(page: Page): Promise<void> {
await expect(page.getByTestId("workspace-tabs-row").first()).toBeVisible({
await expect(visibleTestId(page, "workspace-tabs-row").first()).toBeVisible({
timeout: 30_000,
});
await expect(page.getByTestId("workspace-new-agent-tab").first()).toBeVisible({
await expect(visibleTestId(page, "workspace-new-agent-tab").first()).toBeVisible({
timeout: 30_000,
});
}
export async function getVisibleWorkspaceAgentTabIds(page: Page): Promise<string[]> {
const allTabIds = await getWorkspaceTabTestIds(page);
return allTabIds.filter((id) => id.startsWith("workspace-tab-agent_"));
const tabs = page.locator('[data-testid^="workspace-tab-agent_"]').filter({ visible: true });
const count = await tabs.count();
const ids: string[] = [];
for (let index = 0; index < count; index += 1) {
const testId = await tabs.nth(index).getAttribute("data-testid");
if (testId && !ids.includes(testId)) {
ids.push(testId);
}
}
return ids;
}
export async function expectOnlyWorkspaceAgentTabsVisible(
@@ -38,7 +50,7 @@ export async function expectOnlyWorkspaceAgentTabsVisible(
expect(unexpected).toEqual([]);
expect(visible.length).toBe(expected.size);
for (const expectedId of expectedAgentIds) {
await expect(page.getByTestId(`workspace-tab-agent_${expectedId}`)).toBeVisible({
await expect(visibleTestId(page, `workspace-tab-agent_${expectedId}`).first()).toBeVisible({
timeout: 30_000,
});
}
+2 -2
View File
@@ -103,8 +103,8 @@ export async function expectWorkspaceHeader(
page: Page,
input: { title: string; subtitle: string },
): Promise<void> {
const titleLocator = page.getByTestId("workspace-header-title");
const subtitleLocator = page.getByTestId("workspace-header-subtitle");
const titleLocator = page.getByTestId("workspace-header-title").filter({ visible: true });
const subtitleLocator = page.getByTestId("workspace-header-subtitle").filter({ visible: true });
await expect(titleLocator.first()).toHaveText(input.title, {
timeout: 30_000,