diff --git a/src/frontend/apps/e2e/__tests__/app-drive/file-preview-actions.spec.ts b/src/frontend/apps/e2e/__tests__/app-drive/file-preview-actions.spec.ts deleted file mode 100644 index 84656846..00000000 --- a/src/frontend/apps/e2e/__tests__/app-drive/file-preview-actions.spec.ts +++ /dev/null @@ -1,124 +0,0 @@ -import path from "path"; - -import test, { expect } from "@playwright/test"; - -import { clearDb, login } from "./utils-common"; -import { clickToMyFiles } from "./utils-navigate"; -import { uploadFile } from "./utils/upload-utils"; - -const PDF_FILE_PATH = path.join(__dirname, "/assets/pv_cm.pdf"); -const DOCX_FILE_PATH = path.join(__dirname, "/assets/empty_doc.docx"); - -test.describe("File Preview Actions Menu", () => { - test.beforeEach(async ({ page }) => { - await clearDb(); - await login(page, "drive@example.com"); - await page.goto("/"); - await clickToMyFiles(page); - - await uploadFile(page, PDF_FILE_PATH); - await expect( - page.getByRole("cell", { name: "pv_cm", exact: true }), - ).toBeVisible({ timeout: 10000 }); - - await page.getByRole("cell", { name: "pv_cm", exact: true }).dblclick(); - await expect(page.getByTestId("file-preview")).toBeVisible({ - timeout: 10000, - }); - }); - - test("Shows the actions dropdown with download and print options", async ({ - page, - }) => { - const filePreview = page.getByTestId("file-preview"); - const moreButton = filePreview.locator( - ".file-preview__header__content__right button:has(.material-icons)", - ); - - // Find the "..." button (more_vert icon) - const moreVertButton = filePreview.getByText("more_vert").locator(".."); - await expect(moreVertButton).toBeVisible(); - await moreVertButton.click(); - - // Verify both menu items appear - await expect( - page.getByRole("menuitem", { name: "Download" }), - ).toBeVisible(); - await expect(page.getByRole("menuitem", { name: "Print" })).toBeVisible(); - }); - - test("Download action in dropdown triggers file download", async ({ - page, - }) => { - const filePreview = page.getByTestId("file-preview"); - const moreVertButton = filePreview.getByText("more_vert").locator(".."); - await moreVertButton.click(); - - const downloadPromise = page.waitForEvent("download"); - await page.getByRole("menuitem", { name: "Download" }).click(); - const download = await downloadPromise; - - expect(download.suggestedFilename()).toContain("pv_cm"); - }); - - test("Updates the browser tab title when preview is open", async ({ - page, - }) => { - // The title should include the file name while preview is open - await expect(page).toHaveTitle(/pv_cm\.pdf/); - - // Close the preview - const filePreview = page.getByTestId("file-preview"); - const closeButton = filePreview.locator( - ".file-preview__header__content__left button", - ); - await closeButton.click(); - - // The title should no longer contain the file name - await expect(page).not.toHaveTitle(/pv_cm\.pdf/); - }); - - test("Print action in dropdown opens the file in a new tab", async ({ - page, - context, - }) => { - const filePreview = page.getByTestId("file-preview"); - const moreVertButton = filePreview.getByText("more_vert").locator(".."); - await moreVertButton.click(); - - const [newPage] = await Promise.all([ - context.waitForEvent("page"), - page.getByRole("menuitem", { name: "Print" }).click(), - ]); - - // A new tab was opened with the file for printing - expect(newPage).toBeTruthy(); - await newPage.close(); - }); -}); - -test.describe("File Preview Actions Menu - Non-printable file", () => { - test("Hides the actions menu for non-PDF/non-image files", async ({ - page, - }) => { - await clearDb(); - await login(page, "drive@example.com"); - await page.goto("/"); - await clickToMyFiles(page); - - await uploadFile(page, DOCX_FILE_PATH); - await expect( - page.getByRole("cell", { name: "empty_doc", exact: true }), - ).toBeVisible({ timeout: 10000 }); - - await page.getByRole("cell", { name: "empty_doc", exact: true }).dblclick(); - await expect(page.getByTestId("file-preview")).toBeVisible({ - timeout: 10000, - }); - - const filePreview = page.getByTestId("file-preview"); - await expect( - filePreview.getByText("more_vert"), - ).not.toBeVisible(); - }); -}); diff --git a/src/frontend/apps/e2e/__tests__/app-drive/file-preview/file-preview-actions.spec.ts b/src/frontend/apps/e2e/__tests__/app-drive/file-preview/file-preview-actions.spec.ts new file mode 100644 index 00000000..18ba22b0 --- /dev/null +++ b/src/frontend/apps/e2e/__tests__/app-drive/file-preview/file-preview-actions.spec.ts @@ -0,0 +1,283 @@ +import path from "path"; + +import test, { expect } from "@playwright/test"; + +import { clearDb, login } from "../utils-common"; +import { clickToMyFiles } from "../utils-navigate"; +import { uploadFile } from "../utils/upload-utils"; + +const PDF_FILE_PATH = path.join(__dirname, "../assets/pv_cm.pdf"); +const DOCX_FILE_PATH = path.join(__dirname, "../assets/empty_doc.docx"); + +test.describe("File Preview Actions Menu", () => { + test.beforeEach(async ({ page }) => { + await clearDb(); + await login(page, "drive@example.com"); + await page.goto("/"); + await clickToMyFiles(page); + + await uploadFile(page, PDF_FILE_PATH); + await expect( + page.getByRole("cell", { name: "pv_cm", exact: true }), + ).toBeVisible({ timeout: 10000 }); + + await page.getByRole("cell", { name: "pv_cm", exact: true }).dblclick(); + await expect(page.getByTestId("file-preview")).toBeVisible({ + timeout: 10000, + }); + }); + + test("Shows the actions dropdown with download and print options", async ({ + page, + }) => { + const filePreview = page.getByTestId("file-preview"); + const moreButton = filePreview.locator( + ".file-preview__header__content__right button:has(.material-icons)", + ); + + // Find the "..." button (more_vert icon) + const moreVertButton = filePreview.getByText("more_vert").locator(".."); + await expect(moreVertButton).toBeVisible(); + await moreVertButton.click(); + + // Verify both menu items appear + await expect( + page.getByRole("menuitem", { name: "Download" }), + ).toBeVisible(); + await expect(page.getByRole("menuitem", { name: "Print" })).toBeVisible(); + }); + + test("Download action in dropdown triggers file download", async ({ + page, + }) => { + const filePreview = page.getByTestId("file-preview"); + const moreVertButton = filePreview.getByText("more_vert").locator(".."); + await moreVertButton.click(); + + const downloadPromise = page.waitForEvent("download"); + await page.getByRole("menuitem", { name: "Download" }).click(); + const download = await downloadPromise; + + expect(download.suggestedFilename()).toContain("pv_cm"); + }); + + test("Updates the browser tab title when preview is open", async ({ + page, + }) => { + // The title should include the file name while preview is open + await expect(page).toHaveTitle(/pv_cm\.pdf/); + + // Close the preview + const filePreview = page.getByTestId("file-preview"); + const closeButton = filePreview.locator( + ".file-preview__header__content__left button", + ); + await closeButton.click(); + + // The title should no longer contain the file name + await expect(page).not.toHaveTitle(/pv_cm\.pdf/); + }); + + test("Print action in dropdown opens the file in a new tab", async ({ + page, + context, + }) => { + const filePreview = page.getByTestId("file-preview"); + const moreVertButton = filePreview.getByText("more_vert").locator(".."); + await moreVertButton.click(); + + const [newPage] = await Promise.all([ + context.waitForEvent("page"), + page.getByRole("menuitem", { name: "Print" }).click(), + ]); + + // A new tab was opened with the file for printing + expect(newPage).toBeTruthy(); + await newPage.close(); + }); +}); + +test.describe("File Preview Actions Menu - Non-printable file", () => { + test("Hides the actions menu for non-PDF/non-image files", async ({ + page, + }) => { + await clearDb(); + await login(page, "drive@example.com"); + await page.goto("/"); + await clickToMyFiles(page); + + await uploadFile(page, DOCX_FILE_PATH); + await expect( + page.getByRole("cell", { name: "empty_doc", exact: true }), + ).toBeVisible({ timeout: 10000 }); + + await page.getByRole("cell", { name: "empty_doc", exact: true }).dblclick(); + await expect(page.getByTestId("file-preview")).toBeVisible({ + timeout: 10000, + }); + + const filePreview = page.getByTestId("file-preview"); + await expect( + filePreview.getByText("more_vert"), + ).not.toBeVisible(); + }); +}); + +test.describe("File Preview Header", () => { + test.beforeEach(async ({ page }) => { + await clearDb(); + await login(page, "drive@example.com"); + await page.goto("/"); + await clickToMyFiles(page); + + await uploadFile(page, PDF_FILE_PATH); + await expect( + page.getByRole("cell", { name: "pv_cm", exact: true }), + ).toBeVisible({ timeout: 10000 }); + + await page.getByRole("cell", { name: "pv_cm", exact: true }).dblclick(); + await expect(page.getByTestId("file-preview")).toBeVisible({ + timeout: 10000, + }); + }); + + test("Closes the preview when the close button is clicked", async ({ + page, + }) => { + const filePreview = page.getByTestId("file-preview"); + await expect(filePreview).toBeVisible(); + + const closeButton = filePreview.locator( + ".file-preview__header__content__left button", + ); + await closeButton.click(); + + await expect(page.getByTestId("file-preview")).not.toBeAttached({ + timeout: 5000, + }); + }); + + test("Toggles the info sidebar on and off", async ({ page }) => { + const container = page.locator(".file-preview__container"); + const sidebar = page.locator(".file-preview-sidebar"); + + await expect(container).not.toHaveClass( + /file-preview__container--sidebar-open/, + ); + await expect(sidebar).not.toHaveClass(/(^|\s)open(\s|$)/); + + const filePreview = page.getByTestId("file-preview"); + const infoButton = filePreview.getByText("info_outline").locator(".."); + await infoButton.click(); + + await expect(container).toHaveClass( + /file-preview__container--sidebar-open/, + { timeout: 5000 }, + ); + await expect(sidebar).toHaveClass(/(^|\s)open(\s|$)/); + + await infoButton.click(); + + await expect(container).not.toHaveClass( + /file-preview__container--sidebar-open/, + { timeout: 5000 }, + ); + await expect(sidebar).not.toHaveClass(/(^|\s)open(\s|$)/); + }); +}); + +test.describe("File Preview Navigation", () => { + test.beforeEach(async ({ page }) => { + await clearDb(); + await login(page, "drive@example.com"); + await page.goto("/"); + await clickToMyFiles(page); + + await uploadFile(page, PDF_FILE_PATH); + await expect( + page.getByRole("cell", { name: "pv_cm", exact: true }), + ).toBeVisible({ timeout: 10000 }); + + await uploadFile(page, DOCX_FILE_PATH); + await expect( + page.getByRole("cell", { name: "empty_doc", exact: true }), + ).toBeVisible({ timeout: 10000 }); + + await page.getByRole("cell", { name: "pv_cm", exact: true }).dblclick(); + await expect(page.getByTestId("file-preview")).toBeVisible({ + timeout: 10000, + }); + }); + + test("Navigates between files with the prev/next buttons", async ({ + page, + }) => { + const filePreview = page.getByTestId("file-preview"); + const title = filePreview.locator("h1.file-preview__title"); + const nextButton = page.locator(".file-preview__next-button button"); + const prevButton = page.locator(".file-preview__previous-button button"); + + await expect(title).toHaveText("pv_cm"); + + // With 2 files and pv_cm at a boundary, exactly one of prev/next is disabled. + const nextDisabled = await nextButton.isDisabled(); + const prevDisabled = await prevButton.isDisabled(); + expect(nextDisabled).not.toBe(prevDisabled); + + // Click whichever is enabled — we should land on empty_doc. + if (!nextDisabled) { + await nextButton.click(); + } else { + await prevButton.click(); + } + await expect(title).toHaveText("empty_doc"); + + // Boundary flipped: previously enabled is now disabled, vice versa. + if (!nextDisabled) { + await expect(nextButton).toBeDisabled(); + await expect(prevButton).toBeEnabled(); + } else { + await expect(prevButton).toBeDisabled(); + await expect(nextButton).toBeEnabled(); + } + }); + + test("Navigates between files with ArrowLeft/ArrowRight keys", async ({ + page, + }) => { + const filePreview = page.getByTestId("file-preview"); + const title = filePreview.locator("h1.file-preview__title"); + const nextButton = page.locator(".file-preview__next-button button"); + + await expect(title).toHaveText("pv_cm"); + + const nextDisabled = await nextButton.isDisabled(); + const forwardKey = nextDisabled ? "ArrowLeft" : "ArrowRight"; + const backwardKey = nextDisabled ? "ArrowRight" : "ArrowLeft"; + + await page.keyboard.press(forwardKey); + await expect(title).toHaveText("empty_doc"); + + await page.keyboard.press(backwardKey); + await expect(title).toHaveText("pv_cm"); + }); + + test("Does not navigate files when arrow keys are pressed inside the PDF page input", async ({ + page, + }) => { + const filePreview = page.getByTestId("file-preview"); + const title = filePreview.locator("h1.file-preview__title"); + + await expect(title).toHaveText("pv_cm"); + + const pageInput = page.locator('input[aria-label="Current page"]'); + await expect(pageInput).toBeVisible({ timeout: 10000 }); + await pageInput.focus(); + + await page.keyboard.press("ArrowRight"); + await expect(title).toHaveText("pv_cm"); + + await page.keyboard.press("ArrowLeft"); + await expect(title).toHaveText("pv_cm"); + }); +}); diff --git a/src/frontend/apps/e2e/__tests__/app-drive/heic-file-preview.spec.ts b/src/frontend/apps/e2e/__tests__/app-drive/file-preview/heic-file-preview.spec.ts similarity index 59% rename from src/frontend/apps/e2e/__tests__/app-drive/heic-file-preview.spec.ts rename to src/frontend/apps/e2e/__tests__/app-drive/file-preview/heic-file-preview.spec.ts index a6af93ae..5f9f81ee 100644 --- a/src/frontend/apps/e2e/__tests__/app-drive/heic-file-preview.spec.ts +++ b/src/frontend/apps/e2e/__tests__/app-drive/file-preview/heic-file-preview.spec.ts @@ -1,9 +1,8 @@ import test, { expect } from "@playwright/test"; -import { clearDb, login } from "./utils-common"; +import { clearDb, login } from "../utils-common"; import path from "path"; -import { clickToMyFiles } from "./utils-navigate"; -import { getRowItem } from "./utils-embedded-grid"; -import { uploadFile } from "./utils/upload-utils"; +import { clickToMyFiles } from "../utils-navigate"; +import { uploadFile } from "../utils/upload-utils"; test("Display HEIC not supported message when opening a HEIC file", async ({ page, @@ -15,21 +14,22 @@ test("Display HEIC not supported message when opening a HEIC file", async ({ await expect(page.getByText("This tab is empty")).toBeVisible(); // Use the real HEIC file from assets - const heicFilePath = path.join(__dirname, "/assets/test-image.heic"); + const heicFilePath = path.join(__dirname, "../assets/test-image.heic"); // Upload the HEIC file await uploadFile(page, heicFilePath); // Wait for the file to be uploaded and visible in the list - await expect(page.getByText("Drop your files here")).not.toBeVisible(); + await expect( + page.getByRole("cell", { name: "test-image", exact: true }), + ).toBeVisible({ timeout: 10000 }); - // Click on the HEIC file to open the preview - const row = await getRowItem(page, "test-image"); - await row.dblclick(); + // Double-click the cell to open the preview + await page.getByRole("cell", { name: "test-image", exact: true }).dblclick(); // Check that the file preview is visible const filePreview = page.getByTestId("file-preview"); - await expect(filePreview).toBeVisible(); + await expect(filePreview).toBeVisible({ timeout: 10000 }); // Check that the HEIC-specific message is displayed await expect( diff --git a/src/frontend/apps/e2e/__tests__/app-drive/pdf-preview.spec.ts b/src/frontend/apps/e2e/__tests__/app-drive/file-preview/pdf-preview.spec.ts similarity index 94% rename from src/frontend/apps/e2e/__tests__/app-drive/pdf-preview.spec.ts rename to src/frontend/apps/e2e/__tests__/app-drive/file-preview/pdf-preview.spec.ts index 999534b5..6c134ee9 100644 --- a/src/frontend/apps/e2e/__tests__/app-drive/pdf-preview.spec.ts +++ b/src/frontend/apps/e2e/__tests__/app-drive/file-preview/pdf-preview.spec.ts @@ -2,20 +2,23 @@ import path from "path"; import test, { expect } from "@playwright/test"; -import { clearDb, login } from "./utils-common"; -import { clickToMyFiles } from "./utils-navigate"; -import { uploadFile } from "./utils/upload-utils"; +import { clearDb, login } from "../utils-common"; +import { clickToMyFiles } from "../utils-navigate"; +import { uploadFile } from "../utils/upload-utils"; -const PDF_FILE_PATH = path.join(__dirname, "/assets/pv_cm.pdf"); -const PDF_LINKS_FILE_PATH = path.join(__dirname, "/assets/pdf_with_links.pdf"); -const PDF_JS_FILE_PATH = path.join(__dirname, "/assets/pdf_with_js.pdf"); +const PDF_FILE_PATH = path.join(__dirname, "../assets/pv_cm.pdf"); +const PDF_LINKS_FILE_PATH = path.join( + __dirname, + "../assets/pdf_with_links.pdf", +); +const PDF_JS_FILE_PATH = path.join(__dirname, "../assets/pdf_with_js.pdf"); const PDF_JS_LINK_FILE_PATH = path.join( __dirname, - "/assets/pdf_with_js_link.pdf", + "../assets/pdf_with_js_link.pdf", ); const PDF_CORRUPTED_FILE_PATH = path.join( __dirname, - "/assets/pdf_corrupted.pdf", + "../assets/pdf_corrupted.pdf", ); import type { Page, Locator } from "@playwright/test"; @@ -255,6 +258,31 @@ test.describe("PDF Preview", () => { }); }); + test("Applies pdf-sidebar-open class on the container when the thumbnail sidebar is opened", async ({ + page, + }) => { + const container = page.locator(".file-preview__container"); + + await expect(container).not.toHaveClass( + /file-preview__container--pdf-sidebar-open/, + ); + + await openSidebar(page); + + await expect(container).toHaveClass( + /file-preview__container--pdf-sidebar-open/, + { timeout: 5000 }, + ); + + const toggle = page.locator('button[aria-label="Toggle sidebar"]'); + await toggle.dispatchEvent("click"); + + await expect(container).not.toHaveClass( + /file-preview__container--pdf-sidebar-open/, + { timeout: 5000 }, + ); + }); + test("Marks the current page thumbnail as active", async ({ page }) => { await openSidebar(page);