// The file explorer and the image viewer on a computer's desktop in // Chromium (F4.6f3), on browser/fixtures/web-pages.fls // (test/webPagesFixture.test.ts): installed while the simulation runs; a // folder made, an entry copied and pasted through Java's right-click menu, // renamed and deleted through the buttons (after Java's questions), what the // command line makes shown at once, a local file imported; a picture // imported and opened in the viewer, a text file refused there. import { dirname, join } from 'node:path'; import { fileURLToPath } from 'node:url'; import { expect, test, type Page } from '@playwright/test'; import { drawing, onDevice, serveEditor } from './editorPage.js'; let server: { readonly base: string; readonly close: () => Promise }; test.beforeAll(async () => { server = await serveEditor(); }); test.afterAll(async () => { await server.close(); }); const here = dirname(fileURLToPath(import.meta.url)); const FIXTURE = join(here, 'fixtures/web-pages.fls'); const PICTURE = join(here, '../src/assets/desktop/ordner.png'); async function openPages(page: Page): Promise { await page.goto(`${server.base}?example=new`); await page.waitForSelector('svg.filius-canvas'); await page.locator('input[type="file"]').first().setInputFiles(FIXTURE); await expect.poll(async () => (await drawing(page).catch(() => ({ nodes: [] }))).nodes.length).toBe(4); await page.getByRole('button', { name: 'Wechselt in den Aktionsmodus' }).click(); await expect(page.locator('svg.filius-canvas')).toHaveAttribute('data-mode', 'simulation'); } test('makes, copies, pastes, renames, deletes and imports as Java’s explorer does, and shows a picture in the viewer', async ({ page }) => { test.setTimeout(120_000); await openPages(page); const id = (await drawing(page)).nodes.find((node) => node.name === 'Server')!.id; const at = await onDevice(page, id); await page.mouse.click(at.x, at.y); const desktop = page.locator(`section[data-desktop="${id}"]`); await desktop.locator('[data-program="installation"]').click(); const installation = desktop.locator('[data-program-window="installation"]'); const available = installation.locator('[data-list="available"] [role="option"]'); for (const program of ['Datei-Explorer', 'Bildbetrachter', 'Befehlszeile']) await available.filter({ hasText: program }).click(); await installation.getByRole('button', { name: 'Installieren' }).click(); await installation.getByRole('button', { name: 'Änderungen annehmen' }).click(); await desktop.locator('[data-program="fileExplorer"]').click(); const window = desktop.locator('[data-program-window="fileExplorer"]'); await expect(window.locator('.program-titlebar h3')).toHaveText('Datei-Explorer'); const bar = window.getByRole('toolbar', { name: 'Aktionen' }); await expect(bar.getByRole('button')).toHaveText(['Importieren', 'Neuer Ordner', 'Löschen', 'Ausschneiden', 'Kopieren', 'Einfügen', 'Umbenennen']); await expect(bar.getByRole('button', { name: 'Löschen' })).toBeDisabled(); await expect(bar.getByRole('button', { name: 'Einfügen' })).toBeDisabled(); const tree = window.getByRole('list', { name: 'Ordner und Dateien' }).getByRole('button'); const entries = window.getByRole('list', { name: 'Inhalt des Ordners' }).getByRole('button'); await expect(entries).toHaveText(['webserver']); await expect(tree.first()).toHaveText('/'); // A new folder, named in Java's question. await bar.getByRole('button', { name: 'Neuer Ordner' }).click(); const naming = window.getByRole('dialog', { name: 'Neuer Ordner' }); await naming.getByRole('textbox', { name: 'Neuer Name:' }).fill('ordner'); await naming.getByRole('button', { name: 'OK' }).click(); await expect(entries).toHaveText(['webserver', 'ordner']); // Java's right-click menu: on an entry, then on the free space with something copied. await entries.filter({ hasText: 'webserver' }).click({ button: 'right' }); await expect(window.getByRole('menuitem')).toHaveText(['Löschen', 'Ausschneiden', 'Kopieren', 'Umbenennen']); await window.getByRole('menuitem', { name: 'Kopieren' }).click(); await window.locator('.file-explorer-tree [data-path="/ordner"]').click(); await expect(entries).toHaveCount(0); await window.getByRole('list', { name: 'Inhalt des Ordners' }).click({ button: 'right', position: { x: 20, y: 20 } }); await expect(window.getByRole('menuitem')).toHaveText(['Neuer Ordner', 'Einfügen']); await window.getByRole('menuitem', { name: 'Einfügen' }).click(); await expect(entries).toHaveText(['webserver']); // A folder of the list opens with a double click; into the copied folder itself: Java's message. await entries.filter({ hasText: 'webserver' }).dblclick(); await expect(window.locator('.file-explorer-tree [data-path="/ordner/webserver"]')).toHaveAttribute('aria-current', 'true'); await window.locator('.file-explorer-tree [data-path="/webserver"]').click(); await bar.getByRole('button', { name: 'Einfügen' }).click(); await expect(window.getByRole('alert')).toHaveText('Unzulässiger Zielordner!'); // Renamed through the button: the old name first, a name there already is said. await window.locator('.file-explorer-tree [data-path="/"]').click(); await entries.filter({ hasText: 'ordner' }).click(); await bar.getByRole('button', { name: 'Umbenennen' }).click(); const renaming = window.getByRole('dialog', { name: 'Umbenennen' }); await expect(renaming.getByRole('textbox', { name: 'Neuer Name:' })).toHaveValue('ordner'); await renaming.getByRole('textbox', { name: 'Neuer Name:' }).fill('webserver'); await renaming.getByRole('button', { name: 'OK' }).click(); await expect(renaming.getByRole('alert')).toHaveText('Den Namen „webserver“ gibt es in diesem Ordner schon.'); await renaming.getByRole('textbox', { name: 'Neuer Name:' }).fill('Kopie'); await renaming.getByRole('button', { name: 'OK' }).click(); await expect(entries).toHaveText(['webserver', 'Kopie']); // Deleted after Java's "Sicher?": no, then yes. await bar.getByRole('button', { name: 'Löschen' }).click(); await window.getByRole('alertdialog', { name: 'Sicher?' }).getByRole('button', { name: 'Nein' }).click(); await expect(entries).toHaveText(['webserver', 'Kopie']); await bar.getByRole('button', { name: 'Löschen' }).click(); await window.getByRole('alertdialog', { name: 'Sicher?' }).getByRole('button', { name: 'Ja' }).click(); await expect(entries).toHaveText(['webserver']); // What the command line makes is there at once. await desktop.locator('.desktop-home').click(); await desktop.locator('[data-program="commandPrompt"]').click(); const input = desktop.locator('input[name="terminalInput"]'); await input.fill('mkdir extern'); await input.press('Enter'); await desktop.locator('.desktop-home').click(); await desktop.locator('[data-program="fileExplorer"]').click(); await expect(entries).toHaveText(['webserver', 'extern']); // A local picture imported: the new name is the local file's at first. await bar.getByRole('button', { name: 'Importieren' }).click(); const importing = window.getByRole('dialog', { name: 'Datei importieren' }); await importing.getByRole('button', { name: 'Datei importieren' }).click(); await expect(importing.getByRole('status')).toHaveText('Eingabe- und Ausgabedatei müssen angegeben werden!'); await importing.locator('input[type="file"]').setInputFiles(PICTURE); await expect(importing.getByRole('textbox', { name: 'Neuer Name:' })).toHaveValue('ordner.png'); await importing.getByRole('textbox', { name: 'Neuer Name:' }).fill('bild.png'); await importing.getByRole('button', { name: 'Datei importieren' }).click(); await expect(importing.getByRole('status')).toHaveText('Datei erfolgreich importiert!'); await importing.getByRole('button', { name: 'Schließen' }).click(); await expect(entries).toHaveText(['webserver', 'extern', 'bild.png']); // The viewer: the picture, its name as the title; a text file is said. await desktop.locator('.desktop-home').click(); await desktop.locator('[data-program="imageViewer"]').click(); const viewer = desktop.locator('[data-program-window="imageViewer"]'); await expect(viewer.locator('.program-titlebar h3')).toHaveText('Bildbetrachter'); await viewer.getByRole('button', { name: 'Öffnen' }).click(); const dialog = viewer.getByRole('dialog', { name: 'Datei Öffnen' }); await dialog.locator('.file-dialog-entries button', { hasText: 'bild.png' }).click(); await dialog.getByRole('button', { name: 'Öffnen' }).click(); await expect(viewer.locator('.program-titlebar h3')).toHaveText('bild.png'); await expect.poll(() => viewer.getByRole('img', { name: 'Bild' }).evaluate((image: HTMLImageElement) => image.naturalWidth)).toBe(16); await viewer.getByRole('button', { name: 'Öffnen' }).click(); await dialog.locator('.file-dialog-entries button', { hasText: 'webserver' }).click(); await dialog.locator('.file-dialog-entries button', { hasText: 'index.html' }).click(); await dialog.getByRole('button', { name: 'Öffnen' }).click(); await expect(dialog.getByRole('alert')).toHaveText('„index.html“ ist keine Bilddatei.'); });