diff --git a/desktop/tests/e2e/channel-controls-screenshots.spec.ts b/desktop/tests/e2e/channel-controls-screenshots.spec.ts index ed6c8126cc..6a8e741c9b 100644 --- a/desktop/tests/e2e/channel-controls-screenshots.spec.ts +++ b/desktop/tests/e2e/channel-controls-screenshots.spec.ts @@ -14,6 +14,13 @@ async function openManagementSheet(page: import("@playwright/test").Page) { await expect(page.getByTestId("channel-management-sheet")).toBeVisible(); } +async function openEditDialog(page: import("@playwright/test").Page) { + await page.getByTestId("channel-management-edit").click(); + await expect( + page.getByRole("dialog", { name: "Edit channel" }), + ).toBeVisible(); +} + async function settle(page: import("@playwright/test").Page) { await page.evaluate(() => Promise.all(document.getAnimations().map((a) => a.finished)), @@ -26,6 +33,7 @@ test.describe("channel controls screenshots", () => { }) => { await installMockBridge(page); await openManagementSheet(page); + await openEditDialog(page); const lifecycle = page.getByTestId("channel-management-lifecycle"); await lifecycle.scrollIntoViewIfNeeded(); @@ -43,6 +51,7 @@ test.describe("channel controls screenshots", () => { test("02 — Private toggled on", async ({ page }) => { await installMockBridge(page); await openManagementSheet(page); + await openEditDialog(page); const lifecycle = page.getByTestId("channel-management-lifecycle"); await lifecycle.scrollIntoViewIfNeeded(); @@ -52,7 +61,7 @@ test.describe("channel controls screenshots", () => { ).toBeChecked(); // Save button enables once the visibility actually changed. await expect( - page.getByTestId("channel-management-save-lifecycle"), + page.getByTestId("channel-management-save-changes"), ).toBeEnabled(); await settle(page); @@ -62,6 +71,7 @@ test.describe("channel controls screenshots", () => { test("03 — Ephemeral on with friendly timeout field", async ({ page }) => { await installMockBridge(page); await openManagementSheet(page); + await openEditDialog(page); const lifecycle = page.getByTestId("channel-management-lifecycle"); await lifecycle.scrollIntoViewIfNeeded(); @@ -71,7 +81,7 @@ test.describe("channel controls screenshots", () => { await expect(ttl).toBeVisible(); await ttl.fill("1d12h"); await expect( - page.getByTestId("channel-management-save-lifecycle"), + page.getByTestId("channel-management-save-changes"), ).toBeEnabled(); await settle(page); @@ -83,6 +93,7 @@ test.describe("channel controls screenshots", () => { }) => { await installMockBridge(page); await openManagementSheet(page); + await openEditDialog(page); const lifecycle = page.getByTestId("channel-management-lifecycle"); await lifecycle.scrollIntoViewIfNeeded(); @@ -92,7 +103,7 @@ test.describe("channel controls screenshots", () => { await ttl.fill("soon"); await expect(ttl).toHaveAttribute("aria-invalid", "true"); await expect( - page.getByTestId("channel-management-save-lifecycle"), + page.getByTestId("channel-management-save-changes"), ).toBeDisabled(); await settle(page); @@ -122,30 +133,28 @@ test.describe("channel controls screenshots", () => { await sheet.screenshot({ path: `${SHOTS}/06-management-sheet.png` }); }); - test("07 — saving lifecycle leaves details save idle", async ({ page }) => { + test("07 — saving lifecycle uses unified save", async ({ page }) => { await installMockBridge(page, { updateChannelDelayMs: 500 }); await openManagementSheet(page); + await openEditDialog(page); const sheet = page.getByTestId("channel-management-sheet"); await page.getByTestId("channel-management-ephemeral-toggle").click(); await expect( - page.getByTestId("channel-management-save-lifecycle"), + page.getByTestId("channel-management-save-changes"), ).toBeEnabled(); - await page.getByTestId("channel-management-save-lifecycle").click(); + await page.getByTestId("channel-management-save-changes").click(); await expect( - page.getByTestId("channel-management-save-lifecycle"), + page.getByTestId("channel-management-save-changes"), ).toHaveText("Saving..."); - await expect( - page.getByTestId("channel-management-save-details"), - ).toHaveText("Save details"); await sheet.screenshot({ - path: `${SHOTS}/07-lifecycle-saving-details-idle.png`, + path: `${SHOTS}/07-lifecycle-saving-unified-save.png`, }); await expect( - page.getByTestId("channel-management-save-lifecycle"), - ).toHaveText("Save visibility"); + page.getByRole("dialog", { name: "Edit channel" }), + ).toHaveCount(0); }); test("08 — saved ephemeral lifecycle is reflected after reopen", async ({ @@ -153,19 +162,21 @@ test.describe("channel controls screenshots", () => { }) => { await installMockBridge(page); await openManagementSheet(page); + await openEditDialog(page); await page.getByTestId("channel-management-private-toggle").click(); await page.getByTestId("channel-management-ephemeral-toggle").click(); - await page.getByTestId("channel-management-save-lifecycle").click(); + await page.getByTestId("channel-management-save-changes").click(); await expect( - page.getByTestId("channel-management-save-lifecycle"), - ).toHaveText("Save visibility"); + page.getByRole("dialog", { name: "Edit channel" }), + ).toHaveCount(0); await page.keyboard.press("Escape"); await expect( page.getByTestId("channel-management-sheet"), ).not.toBeVisible(); await page.getByTestId("channel-management-trigger").click(); + await openEditDialog(page); const lifecycle = page.getByTestId("channel-management-lifecycle"); await lifecycle.scrollIntoViewIfNeeded(); diff --git a/desktop/tests/e2e/channels.spec.ts b/desktop/tests/e2e/channels.spec.ts index 6f4f533274..86d6231607 100644 --- a/desktop/tests/e2e/channels.spec.ts +++ b/desktop/tests/e2e/channels.spec.ts @@ -20,6 +20,13 @@ async function closeChannelManagement(page: import("@playwright/test").Page) { await expect(page.getByTestId("channel-management-sheet")).not.toBeVisible(); } +async function openChannelEditDialog(page: import("@playwright/test").Page) { + await page.getByTestId("channel-management-edit").click(); + await expect( + page.getByRole("dialog", { name: "Edit channel" }), + ).toBeVisible(); +} + async function openMembersSidebar( page: import("@playwright/test").Page, channelName: string, @@ -983,28 +990,30 @@ test("manage channel updates details and context", async ({ page }) => { await page.goto("/"); await openChannelManagement(page, "general"); + await openChannelEditDialog(page); + const editDialog = page.getByRole("dialog", { name: "Edit channel" }); - await page.getByTestId("channel-management-name").fill(newName); - await page.getByTestId("channel-management-description").fill(newDescription); - await page.getByTestId("channel-management-save-details").click(); + await editDialog.getByTestId("channel-management-name").fill(newName); + await editDialog + .getByTestId("channel-management-description") + .fill(newDescription); + await editDialog.getByTestId("channel-management-topic").fill(newTopic); + await editDialog.getByTestId("channel-management-purpose").fill(newPurpose); + await editDialog.getByTestId("channel-management-save-changes").click(); + await expect(editDialog).toHaveCount(0); await expect(page.getByTestId("chat-title")).toHaveText(newName); await expect(page.getByTestId("stream-list")).toContainText(newName); - - const saveTopicButton = page.getByTestId("channel-management-save-topic"); - const savePurposeButton = page.getByTestId("channel-management-save-purpose"); - - await page.getByTestId("channel-management-topic").fill(newTopic); - await saveTopicButton.click(); - await expect(saveTopicButton).toHaveText("Save topic"); - await expect(page.getByTestId("channel-management-topic")).toHaveValue( + await expect(page.getByTestId("channel-management-name-row")).toContainText( + newName, + ); + await expect( + page.getByTestId("channel-management-description"), + ).toContainText(newDescription); + await expect(page.getByTestId("channel-management-topic")).toContainText( newTopic, ); - - await page.getByTestId("channel-management-purpose").fill(newPurpose); - await savePurposeButton.click(); - await expect(savePurposeButton).toHaveText("Save purpose"); - await expect(page.getByTestId("channel-management-purpose")).toHaveValue( + await expect(page.getByTestId("channel-management-purpose")).toContainText( newPurpose, ); @@ -1017,19 +1026,23 @@ test("manage channel updates details and context", async ({ page }) => { await expect(page.getByTestId("chat-title")).toHaveText(newName); await page.getByTestId("channel-management-trigger").click(); await expect(page.getByTestId("channel-management-sheet")).toBeVisible(); + await openChannelEditDialog(page); + const reopenedEditDialog = page.getByRole("dialog", { + name: "Edit channel", + }); - await expect(page.getByTestId("channel-management-name")).toHaveValue( - newName, - ); - await expect(page.getByTestId("channel-management-description")).toHaveValue( - newDescription, - ); - await expect(page.getByTestId("channel-management-topic")).toHaveValue( - newTopic, - ); - await expect(page.getByTestId("channel-management-purpose")).toHaveValue( - newPurpose, - ); + await expect( + reopenedEditDialog.getByTestId("channel-management-name"), + ).toHaveValue(newName); + await expect( + reopenedEditDialog.getByTestId("channel-management-description"), + ).toHaveValue(newDescription); + await expect( + reopenedEditDialog.getByTestId("channel-management-topic"), + ).toHaveValue(newTopic); + await expect( + reopenedEditDialog.getByTestId("channel-management-purpose"), + ).toHaveValue(newPurpose); }); test("manage channel updates visibility and ephemeral lifecycle independently", async ({ @@ -1037,21 +1050,19 @@ test("manage channel updates visibility and ephemeral lifecycle independently", }) => { await page.goto("/"); await openChannelManagement(page, "general"); + await openChannelEditDialog(page); - const saveDetailsButton = page.getByTestId("channel-management-save-details"); - const saveLifecycleButton = page.getByTestId( - "channel-management-save-lifecycle", - ); + let saveChangesButton = page.getByTestId("channel-management-save-changes"); - await expect(saveLifecycleButton).toBeDisabled(); + await expect(saveChangesButton).toBeDisabled(); await page.getByTestId("channel-management-private-toggle").click(); await page.getByTestId("channel-management-ephemeral-toggle").click(); await expect(page.getByTestId("channel-management-ttl")).toBeVisible(); - await expect(saveLifecycleButton).toBeEnabled(); + await expect(saveChangesButton).toBeEnabled(); const commandCountBeforeEnable = (await readCommandPayloadLog(page)).length; - await saveLifecycleButton.click(); + await saveChangesButton.click(); await expect .poll(async () => (await readCommandPayloadLog(page)).slice(commandCountBeforeEnable), @@ -1064,8 +1075,9 @@ test("manage channel updates visibility and ephemeral lifecycle independently", }), }), ); - await expect(saveLifecycleButton).toHaveText("Save visibility"); - await expect(saveDetailsButton).toHaveText("Save details"); + await expect(page.getByRole("dialog", { name: "Edit channel" })).toHaveCount( + 0, + ); const channelAfterEnable = await invokeMockCommand<{ ttl_seconds: number | null; @@ -1080,6 +1092,8 @@ test("manage channel updates visibility and ephemeral lifecycle independently", await closeChannelManagement(page); await openChannelManagement(page, "general"); + await openChannelEditDialog(page); + saveChangesButton = page.getByTestId("channel-management-save-changes"); await expect( page.getByTestId("channel-management-private-toggle"), @@ -1091,10 +1105,10 @@ test("manage channel updates visibility and ephemeral lifecycle independently", await page.getByTestId("channel-management-private-toggle").click(); await page.getByTestId("channel-management-ephemeral-toggle").click(); - await expect(saveLifecycleButton).toBeEnabled(); + await expect(saveChangesButton).toBeEnabled(); const commandCountBeforeDisable = (await readCommandPayloadLog(page)).length; - await saveLifecycleButton.click(); + await saveChangesButton.click(); await expect .poll(async () => (await readCommandPayloadLog(page)).slice(commandCountBeforeDisable), @@ -1107,9 +1121,9 @@ test("manage channel updates visibility and ephemeral lifecycle independently", }), }), ); - await expect(saveLifecycleButton).toHaveText("Save visibility"); - await expect(saveDetailsButton).toHaveText("Save details"); - await expect(page.getByTestId("channel-management-ttl")).toHaveCount(0); + await expect(page.getByRole("dialog", { name: "Edit channel" })).toHaveCount( + 0, + ); const channelAfterDisable = await invokeMockCommand<{ ttl_seconds: number | null; @@ -1124,6 +1138,7 @@ test("manage channel updates visibility and ephemeral lifecycle independently", await closeChannelManagement(page); await openChannelManagement(page, "general"); + await openChannelEditDialog(page); await expect( page.getByTestId("channel-management-private-toggle"), @@ -1142,12 +1157,12 @@ test("manage channel keeps canvas near the top of the sheet", async ({ const sheet = page.getByTestId("channel-management-sheet"); - // Canvas section should appear before the name input in the DOM. + // Canvas ingress should appear before the channel metadata rows in the DOM. const canvasBox = await sheet - .getByTestId("channel-canvas-section") + .getByTestId("channel-canvas-ingress") .boundingBox(); const nameBox = await sheet - .getByTestId("channel-management-name") + .getByTestId("channel-management-name-row") .boundingBox(); expect(canvasBox).not.toBeNull(); diff --git a/desktop/tests/e2e/integration.spec.ts b/desktop/tests/e2e/integration.spec.ts index 63d019e326..ef54f1941d 100644 --- a/desktop/tests/e2e/integration.spec.ts +++ b/desktop/tests/e2e/integration.spec.ts @@ -28,6 +28,13 @@ async function openChannelManagement(page: import("@playwright/test").Page) { await expect(page.getByTestId("channel-management-sheet")).toBeVisible(); } +async function openChannelEditDialog(page: import("@playwright/test").Page) { + await page.getByTestId("channel-management-edit").click(); + await expect( + page.getByRole("dialog", { name: "Edit channel" }), + ).toBeVisible(); +} + async function closeChannelManagement(page: import("@playwright/test").Page) { await page.keyboard.press("Escape"); await expect(page.getByTestId("channel-management-sheet")).not.toBeVisible(); @@ -455,32 +462,23 @@ test("manage sheet updates channel details and context through the relay", async await createStream(page, initialName, initialDescription); await openChannelManagement(page); - await page.getByTestId("channel-management-name").fill(renamedChannel); - await page + await openChannelEditDialog(page); + const editDialog = page.getByRole("dialog", { name: "Edit channel" }); + + await editDialog.getByTestId("channel-management-name").fill(renamedChannel); + await editDialog .getByTestId("channel-management-description") .fill(updatedDescription); - await page.getByTestId("channel-management-save-details").click(); + await editDialog.getByTestId("channel-management-topic").fill(updatedTopic); + await editDialog + .getByTestId("channel-management-purpose") + .fill(updatedPurpose); + await editDialog.getByTestId("channel-management-save-changes").click(); + await expect(editDialog).toHaveCount(0); await expect(page.getByTestId("chat-title")).toHaveText(renamedChannel); await expect(page.getByTestId("stream-list")).toContainText(renamedChannel); - const saveTopicButton = page.getByTestId("channel-management-save-topic"); - const savePurposeButton = page.getByTestId("channel-management-save-purpose"); - - await page.getByTestId("channel-management-topic").fill(updatedTopic); - await saveTopicButton.click(); - await expect(saveTopicButton).toHaveText("Save topic"); - await expect(page.getByTestId("channel-management-topic")).toHaveValue( - updatedTopic, - ); - - await page.getByTestId("channel-management-purpose").fill(updatedPurpose); - await savePurposeButton.click(); - await expect(savePurposeButton).toHaveText("Save purpose"); - await expect(page.getByTestId("channel-management-purpose")).toHaveValue( - updatedPurpose, - ); - await closeChannelManagement(page); await page.reload(); @@ -493,18 +491,23 @@ test("manage sheet updates channel details and context through the relay", async ); await openChannelManagement(page); - await expect(page.getByTestId("channel-management-name")).toHaveValue( - renamedChannel, - ); - await expect(page.getByTestId("channel-management-description")).toHaveValue( - updatedDescription, - ); - await expect(page.getByTestId("channel-management-topic")).toHaveValue( - updatedTopic, - ); - await expect(page.getByTestId("channel-management-purpose")).toHaveValue( - updatedPurpose, - ); + await openChannelEditDialog(page); + const reopenedEditDialog = page.getByRole("dialog", { + name: "Edit channel", + }); + + await expect( + reopenedEditDialog.getByTestId("channel-management-name"), + ).toHaveValue(renamedChannel); + await expect( + reopenedEditDialog.getByTestId("channel-management-description"), + ).toHaveValue(updatedDescription); + await expect( + reopenedEditDialog.getByTestId("channel-management-topic"), + ).toHaveValue(updatedTopic); + await expect( + reopenedEditDialog.getByTestId("channel-management-purpose"), + ).toHaveValue(updatedPurpose); }); test("manage sheet archive and unarchive survives a reload through the relay", async ({ diff --git a/desktop/tests/e2e/relay-connectivity-screenshots.spec.ts b/desktop/tests/e2e/relay-connectivity-screenshots.spec.ts index ee42430d76..2385a34d27 100644 --- a/desktop/tests/e2e/relay-connectivity-screenshots.spec.ts +++ b/desktop/tests/e2e/relay-connectivity-screenshots.spec.ts @@ -113,8 +113,10 @@ test.describe("relay connectivity screenshots", () => { await expect(page.getByTestId("chat-title")).toHaveText("general"); await page.getByTestId("channel-management-trigger").click(); await expect(page.getByTestId("channel-management-sheet")).toBeVisible(); + await page.getByTestId("channel-canvas-ingress").click(); - // ChannelCanvas shows the destructive error paragraph when the query fails. + // ChannelCanvas shows the destructive error paragraph in the drill-in view + // when the query fails. const canvasSection = page.getByTestId("channel-canvas-section"); await canvasSection.scrollIntoViewIfNeeded(); await expect(