feat(editor): a tap opens a device's menu in the simulation; undo and redo drawn
In the simulation a tap on a device chooses it and opens its menu where the finger was; the three-dot button is gone there, the long press stays. The context menu moves in from the surface's edge instead of being cut off. Undo and redo show drawn arrows: the characters took whatever font the device had and looked squashed on an iPad (the buttons measured 44 x 44 at every width; the size was not the cause). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -208,51 +208,70 @@ test("shows a card's frames as Java's data exchange window does, with their deta
|
||||
await expect(window).toHaveCount(0);
|
||||
});
|
||||
|
||||
test('chooses a device with a tap in the simulation, its three-dot button as in the design, and opens nothing by itself', async ({ page }) => {
|
||||
test('opens a device\'s menu with a tap in the simulation, chooses it, and opens nothing else by itself', async ({ page }) => {
|
||||
await openPages(page);
|
||||
await start(page);
|
||||
const button = page.locator('.device-menu-button');
|
||||
const menu = page.getByRole('menu');
|
||||
const sheet = page.locator('aside[aria-label="Einstellungen"]');
|
||||
// A router: the button opens the same menu as the long press.
|
||||
// A router: the tap chooses it and opens the same menu as the long press, where the finger was; no three-dot button.
|
||||
const router = await onDevice(page, await idOf(page, 'Router'));
|
||||
await page.mouse.click(router.x, router.y);
|
||||
await expect(page.locator(`g.device[data-node="${await idOf(page, 'Router')}"]`)).toHaveAttribute('data-selected', 'true');
|
||||
await button.click();
|
||||
await expect(page.getByRole('menuitem')).toHaveText(['Datenaustausch anzeigen (192.168.0.1)', 'Datenaustausch anzeigen (10.0.0.1)']);
|
||||
const opened = (await menu.boundingBox())!;
|
||||
expect([opened.x, opened.y]).toEqual([router.x, router.y]);
|
||||
await expect(page.locator('.device-menu-button')).toHaveCount(0);
|
||||
await page.getByRole('menuitem', { name: 'Datenaustausch anzeigen (10.0.0.1)' }).click();
|
||||
await expect(page.locator('section[data-capture]').getByRole('tab', { selected: true })).toHaveText('Router - 10.0.0.1');
|
||||
await page.locator('section[data-capture] .simulation-sheet__close').click();
|
||||
// A computer: the tap opens no desktop (Java's click does), it only chooses; its settings stay closed, the design is locked.
|
||||
// A computer: the tap opens its menu, no desktop by itself (Java's click does); its settings stay closed, the design is locked.
|
||||
const browser = await idOf(page, 'Browser');
|
||||
const at = await onDevice(page, browser);
|
||||
await page.mouse.click(at.x, at.y);
|
||||
await expect(button).toBeVisible();
|
||||
await expect(page.getByRole('menuitem')).toHaveText(['Desktop anzeigen', 'Datenaustausch anzeigen (192.168.0.10)']);
|
||||
await expect(page.locator('section[data-desktop]')).toHaveCount(0);
|
||||
await expect(sheet).toHaveCount(0);
|
||||
await button.click();
|
||||
await expect(page.getByRole('menuitem')).toHaveText(['Desktop anzeigen', 'Datenaustausch anzeigen (192.168.0.10)']);
|
||||
// A tap on another device beside the open menu: that one's menu (the menu lies over what is below it on the right).
|
||||
await page.mouse.click(router.x, router.y);
|
||||
await expect(page.getByRole('menuitem')).toHaveText(['Datenaustausch anzeigen (192.168.0.1)', 'Datenaustausch anzeigen (10.0.0.1)']);
|
||||
await page.keyboard.press('Escape');
|
||||
// A switch: the tap opens no table either; its menu does.
|
||||
const lanSwitch = (await drawing(page)).nodes.find((node) => node.kind === 'networkSwitch')!.id;
|
||||
const hub = await onDevice(page, lanSwitch);
|
||||
await page.mouse.click(hub.x, hub.y);
|
||||
await expect(page.locator(`g.device[data-node="${lanSwitch}"]`)).toHaveAttribute('data-selected', 'true');
|
||||
await expect(page.locator('section[data-viewer]')).toHaveCount(0);
|
||||
await button.click();
|
||||
await expect(page.getByRole('menuitem')).toHaveText(['SAT Tabelle anzeigen']);
|
||||
await expect(page.locator('section[data-viewer]')).toHaveCount(0);
|
||||
await page.getByRole('menuitem', { name: 'SAT Tabelle anzeigen' }).click();
|
||||
await expect(page.locator(`section[data-viewer="${lanSwitch}"]`)).toBeVisible();
|
||||
await page.locator('.simulation-sheet__close').click();
|
||||
// A tap beside lets go.
|
||||
// A tap beside closes the menu and lets go.
|
||||
await page.mouse.click(at.x, at.y);
|
||||
await expect(button).toBeVisible();
|
||||
await expect(menu).toBeVisible();
|
||||
const surface = (await page.locator('svg.filius-canvas').boundingBox())!;
|
||||
await page.mouse.click(surface.x + surface.width - 30, surface.y + surface.height - 80);
|
||||
await expect(button).toHaveCount(0);
|
||||
// Back in the design nothing stays chosen.
|
||||
await expect(menu).toHaveCount(0);
|
||||
await expect(page.locator(`g.device[data-node="${browser}"]`)).not.toHaveAttribute('data-selected', 'true');
|
||||
// A device at the surface's edge: its menu moves in, whole on the surface.
|
||||
await page.mouse.click(at.x, at.y);
|
||||
await page.keyboard.press('Escape');
|
||||
const area = (await page.locator('.editor-area').boundingBox())!;
|
||||
// The wheel moves the surface (a drag on a device in the simulation moves nothing).
|
||||
await page.mouse.move(at.x, at.y);
|
||||
await page.mouse.wheel(-(area.x + area.width - 12 - at.x), -(area.y + area.height - 12 - at.y));
|
||||
await expect.poll(async () => (await onDevice(page, browser)).x).toBeGreaterThan(area.x + area.width - 40);
|
||||
const edge = await onDevice(page, browser);
|
||||
await page.mouse.click(edge.x, edge.y);
|
||||
const moved = (await menu.boundingBox())!;
|
||||
expect(moved.x + moved.width).toBeLessThanOrEqual(area.x + area.width + 0.5);
|
||||
expect(moved.y + moved.height).toBeLessThanOrEqual(area.y + area.height + 0.5);
|
||||
expect(moved.x).toBeLessThan(edge.x);
|
||||
expect(moved.y).toBeLessThan(edge.y);
|
||||
await page.keyboard.press('Escape');
|
||||
// Back in the design nothing stays chosen.
|
||||
await page.mouse.click(edge.x, edge.y);
|
||||
await page.keyboard.press('Escape');
|
||||
await page.getByRole('button', { name: 'Wechselt in den Entwurfsmodus' }).click();
|
||||
await expect(button).toHaveCount(0);
|
||||
await expect(page.locator('.device-menu-button')).toHaveCount(0);
|
||||
await expect(sheet).toHaveCount(0);
|
||||
});
|
||||
|
||||
|
||||
@@ -78,9 +78,8 @@ export async function showFromMenu(page: Page, id: string, item: string | RegExp
|
||||
const open = page.locator('.simulation-sheet__close');
|
||||
if ((await open.count()) > 0) await (touch ? open.tap() : open.click());
|
||||
const at = await onDevice(page, id);
|
||||
// In the simulation a tap opens the device's menu.
|
||||
await (touch ? page.touchscreen.tap(at.x, at.y) : page.mouse.click(at.x, at.y));
|
||||
const button = page.locator('.device-menu-button');
|
||||
await (touch ? button.tap() : button.click());
|
||||
const entry = page.getByRole('menuitem', { name: item, exact: true });
|
||||
await (touch ? entry.tap() : entry.click());
|
||||
}
|
||||
|
||||
@@ -95,10 +95,12 @@ test("opens a computer's desktop from its menu: Java's title, its programs in Ja
|
||||
const id = await deviceNamed(page, 'DNS-Server 2.10');
|
||||
expect((await desktopOf(page, id))!.programs).toHaveLength(3);
|
||||
await start(page);
|
||||
// A tap only chooses the computer (Java's click opens its desktop): its three-dot button is there, no desktop.
|
||||
// A tap opens the computer's menu (Java's click opens its desktop, its menu holds it), no desktop by itself, no three-dot button.
|
||||
await tap(page, id);
|
||||
await expect(page.locator('.device-menu-button')).toBeVisible();
|
||||
await expect(page.getByRole('menuitem')).toHaveText(['Desktop anzeigen', 'Datenaustausch anzeigen (141.99.2.10)']);
|
||||
await expect(page.locator('section[data-desktop]')).toHaveCount(0);
|
||||
await expect(page.locator('.device-menu-button')).toHaveCount(0);
|
||||
await page.keyboard.press('Escape');
|
||||
const window = await showDesktop(page, id);
|
||||
await expect(window.getByRole('heading')).toHaveText('DNS-Server 2.10 - 141.99.2.10');
|
||||
await expect(window.locator('.desktop-icon span')).toHaveText(['Software-Installation', 'Datei-Explorer', 'DNS-Server', 'Webserver']);
|
||||
@@ -117,7 +119,6 @@ test("opens a computer's desktop from its menu: Java's title, its programs in Ja
|
||||
await window.getByRole('button', { name: 'Schließen' }).click();
|
||||
await expect(page.locator('section[data-desktop]')).toHaveCount(0);
|
||||
await tap(page, await deviceNamed(page, 'Switch 1'));
|
||||
await page.locator('.device-menu-button').click();
|
||||
await expect(page.getByRole('menuitem')).toHaveText(['SAT Tabelle anzeigen']);
|
||||
await page.keyboard.press('Escape');
|
||||
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
// anew, set up and pinged across, without a mouse —; two fingers zoom the
|
||||
// surface and never the page (M7); every action without a right click
|
||||
// (long press, the three-dot button, the documentation's menu); every
|
||||
// target at least 44 px, nothing beyond the screen's edge.
|
||||
// target at least 44 px, nothing beyond the screen's edge; in the simulation
|
||||
// a tap opens a device's menu.
|
||||
|
||||
import { expect, test, type Page } from '@playwright/test';
|
||||
import { drawing, onDevice, openEditor, scaleOf, serveEditor } from './editorPage.js';
|
||||
@@ -104,9 +105,8 @@ test('builds FILIUS\' „zwei Rechnernetze“ by finger and pings across (the ac
|
||||
// The simulation; the command line installed on the first computer; a ping across the router.
|
||||
await page.getByRole('button', { name: 'Wechselt in den Aktionsmodus' }).tap();
|
||||
await expect(page.locator('svg.filius-canvas')).toHaveAttribute('data-mode', 'simulation');
|
||||
// A tap chooses the computer; its three-dot button opens its menu, „Desktop anzeigen“ its desktop as the sheet.
|
||||
// A tap opens the computer's menu, „Desktop anzeigen“ its desktop as the sheet.
|
||||
await finger.tap(await onDevice(page, pcA));
|
||||
await page.getByRole('button', { name: 'Aktionen' }).tap();
|
||||
await page.getByRole('menuitem', { name: 'Desktop anzeigen' }).tap();
|
||||
const desktop = page.locator(`section[data-desktop="${pcA}"]`);
|
||||
await desktop.locator('[data-program="installation"]').tap();
|
||||
@@ -332,3 +332,19 @@ test('gives every target 44 px at least and keeps the editor within the screen',
|
||||
expect(await fits()).toBe(true);
|
||||
expect(await small(targets)).toEqual([]);
|
||||
});
|
||||
|
||||
test('draws undo and redo as arrows of their own, in the middle of their buttons, not as a character of whatever font the device has', async ({ page }) => {
|
||||
await openEditor(page, server.base, 'zwei_rechnernetze_komplett.fls');
|
||||
for (const name of ['Rückgängig', 'Wiederholen']) {
|
||||
const button = page.getByRole('button', { name, exact: true });
|
||||
await expect(button).toHaveText('');
|
||||
const [outer, arrow] = [(await button.boundingBox())!, (await button.locator('svg').boundingBox())!];
|
||||
expect([arrow.width, arrow.height]).toEqual([20, 20]);
|
||||
expect(Math.abs(arrow.x + arrow.width / 2 - (outer.x + outer.width / 2))).toBeLessThanOrEqual(0.5);
|
||||
expect(Math.abs(arrow.y + arrow.height / 2 - (outer.y + outer.height / 2))).toBeLessThanOrEqual(0.5);
|
||||
expect(Math.min(outer.width, outer.height)).toBeGreaterThanOrEqual(44);
|
||||
}
|
||||
// Redo is undo's mirror image.
|
||||
const paths = await page.locator('.editor-toolbar svg g').evaluateAll((groups) => groups.map((group) => group.getAttribute('transform')));
|
||||
expect(paths).toEqual([null, 'matrix(-1 0 0 1 24 0)']);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user