feat(editor): the simulation's properties in a sheet of their own, with a restart for everyone
Who started the simulation, "Pakete verwerfen" and the dropped packets move from the toolbar into a properties sheet beside the surface. New in it: restart the simulation, after asking. The room learns a restart message: stopped as by stop, every capture, dropped frame and program window emptied, started anew and named after who restarted; refused for readers and frozen projects, logged, and waiting for asked blobs like a start. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
// its address; the browser's card while it fetches a page — a row per frame
|
||||
// in its layer's colour, the chosen frame's details, the table as a text
|
||||
// file named after the tab —, a router's two cards beside it, "Tabellen
|
||||
// löschen", "Automatisches Scrollen" off, a tab closed, the window gone with
|
||||
// löschen", "Automatisches Scrollen" off, a restart emptying it, a tab closed, the window gone with
|
||||
// the design and back with the next start without the tab of a computer
|
||||
// removed; and on a phone.
|
||||
|
||||
@@ -164,6 +164,27 @@ test("shows a card's frames as Java's data exchange window does, with their deta
|
||||
await expect(window.locator('tbody tr[aria-selected="true"]')).toHaveCount(0);
|
||||
expect(await scrolled()).toMatchObject({ overflows: true, top: 0 });
|
||||
|
||||
// Started anew from „Eigenschaften“: the table begins empty, and the frame chosen before is chosen in none of the new ones.
|
||||
await rows.nth(2).click();
|
||||
await expect(rows.nth(2)).toHaveAttribute('aria-selected', 'true');
|
||||
await page.getByRole('button', { name: 'Eigenschaften' }).click();
|
||||
const properties = page.getByRole('complementary', { name: 'Eigenschaften' });
|
||||
await properties.getByRole('button', { name: 'Simulation neu starten' }).click();
|
||||
await properties.getByRole('button', { name: 'Neu starten' }).click();
|
||||
await expect(rows).toHaveCount(0);
|
||||
await properties.getByRole('button', { name: 'Schließen' }).click();
|
||||
await window.locator('.simulation-sheet__close').click();
|
||||
await showDesktop(page, await idOf(page, 'Browser'));
|
||||
await desktop.locator('[data-program="webBrowser"]').click();
|
||||
await address.fill('192.168.0.20');
|
||||
await address.press('Enter');
|
||||
await page.waitForTimeout(6_000);
|
||||
await desktop.locator('.simulation-sheet__close').click();
|
||||
await (await menuOf(page, 'Browser')).filter({ hasText: 'Datenaustausch' }).click();
|
||||
await expect.poll(() => rows.count()).toBeGreaterThan(3);
|
||||
await expect(rows.first().locator('td').first()).toHaveText('1');
|
||||
await expect(window.locator('tbody tr[aria-selected="true"]')).toHaveCount(0);
|
||||
|
||||
// A third tab; a tab closed beside the chosen one leaves it chosen.
|
||||
await window.locator('.simulation-sheet__close').click();
|
||||
await (await menuOf(page, 'Server')).filter({ hasText: 'Datenaustausch' }).click();
|
||||
|
||||
@@ -49,6 +49,7 @@ test('the editor from F itself: two people, one simulation, the bundle packed',
|
||||
await expect(ben.page.locator('g.device')).toHaveCount(await mia.page.locator('g.device').count());
|
||||
await mia.page.locator('button[name="simulationMode"]').click();
|
||||
await expect(ben.page.locator('svg.filius-canvas')).toHaveAttribute('data-mode', 'simulation');
|
||||
await ben.page.getByRole('button', { name: 'Eigenschaften' }).click();
|
||||
await expect(ben.page.locator('[data-note="startedBy"]')).toHaveText('Simulation gestartet von Mia');
|
||||
expect([...mia.encodings.values()]).toEqual(['br']);
|
||||
});
|
||||
|
||||
@@ -46,6 +46,7 @@ const box = (page: Page, id: string) => page.locator(`g.device[data-node="${id}"
|
||||
const canvas = (page: Page) => page.locator('svg.filius-canvas');
|
||||
const desktop = (page: Page, id: string) => page.locator(`section[data-desktop="${id}"]`);
|
||||
const note = (page: Page, kind: string) => page.locator(`[data-note="${kind}"]`);
|
||||
const properties = (page: Page) => page.getByRole('complementary', { name: 'Eigenschaften' });
|
||||
|
||||
async function commandLine(page: Page, id: string) {
|
||||
await showDesktop(page, id);
|
||||
@@ -117,8 +118,12 @@ test('three people in one project of F: moving, reading only, one simulation for
|
||||
await mia.locator('button[name="simulationMode"]').click();
|
||||
for (const page of [mia, ben, rita]) {
|
||||
await expect(canvas(page)).toHaveAttribute('data-mode', 'simulation');
|
||||
await expect(note(page, 'startedBy')).toHaveText('Simulation gestartet von Mia');
|
||||
await page.getByRole('button', { name: 'Eigenschaften' }).click();
|
||||
await expect(properties(page).locator('[data-note="startedBy"]')).toHaveText('Simulation gestartet von Mia');
|
||||
}
|
||||
// Rita may look: neither start anew nor drop.
|
||||
await expect(properties(rita).getByRole('button')).toHaveText(['×']);
|
||||
for (const page of [mia, ben, rita]) await properties(page).getByRole('button', { name: 'Schließen' }).click();
|
||||
|
||||
// Ben pings from the notebook's command line; Mia's command line of it shows the same.
|
||||
const bens = await commandLine(ben, notebook);
|
||||
@@ -141,6 +146,16 @@ test('three people in one project of F: moving, reading only, one simulation for
|
||||
await ritas.input.press('Enter');
|
||||
await expect(rita.getByText('Hier können Sie nur zuschauen.')).toBeVisible();
|
||||
|
||||
// Ben starts it anew, for everyone: the command line begins anew in each, named after him.
|
||||
await ben.getByRole('button', { name: 'Eigenschaften' }).click();
|
||||
await properties(ben).getByRole('button', { name: 'Simulation neu starten' }).click();
|
||||
await properties(ben).getByRole('button', { name: 'Neu starten' }).click();
|
||||
for (const each of [bens, mias, ritas]) await expect(each.text).not.toContainText('ping 141.99.5.10');
|
||||
await expect(properties(ben).locator('[data-note="startedBy"]')).toHaveText('Simulation gestartet von Ben');
|
||||
await mia.getByRole('button', { name: 'Eigenschaften' }).click();
|
||||
await expect(properties(mia).locator('[data-note="startedBy"]')).toHaveText('Simulation gestartet von Ben');
|
||||
await expect(properties(mia).getByText('Noch keine verworfenen Pakete.')).toBeVisible();
|
||||
|
||||
// Ben stops it, for everyone.
|
||||
await ben.locator('button[name="designMode"]').click();
|
||||
for (const page of [mia, ben, rita]) await expect(canvas(page)).toHaveAttribute('data-mode', 'design');
|
||||
|
||||
@@ -2,8 +2,10 @@
|
||||
// (F4.6g5), on FILIUS' example nat_with_mapped_port: a tap on a home router
|
||||
// shows its NAT table (the port forwarding's entry, then a ping's), a tap on
|
||||
// a switch its table (the addresses a ping taught it), each reset; and
|
||||
// "Pakete verwerfen" held while a ping runs: the ping loses answers, the
|
||||
// list shows the dropped frames in Java's words.
|
||||
// "Pakete verwerfen" held while a ping runs, in the simulation's
|
||||
// „Eigenschaften“: the ping loses answers, the list shows the dropped frames
|
||||
// in Java's words; „Simulation neu starten“ empties the command line and the
|
||||
// list and keeps the server's file.
|
||||
|
||||
import { expect, test, type Locator, type Page } from '@playwright/test';
|
||||
import { drawing, openEditor, serveEditor, showDesktop, showFromMenu } from './editorPage.js';
|
||||
@@ -80,7 +82,10 @@ test('shows the tables of a home router and a switch, and drops while “Pakete
|
||||
await desktop.locator('[data-program="commandPrompt"]').click();
|
||||
await input.fill('ping 141.99.4.10');
|
||||
await input.press('Enter');
|
||||
const hold = page.getByRole('button', { name: 'Pakete verwerfen' });
|
||||
await page.getByRole('button', { name: 'Eigenschaften' }).click();
|
||||
const properties = page.getByRole('complementary', { name: 'Eigenschaften' });
|
||||
await expect(properties.getByText('Noch keine verworfenen Pakete.')).toBeVisible();
|
||||
const hold = properties.getByRole('button', { name: 'Pakete verwerfen' });
|
||||
const box = (await hold.boundingBox())!;
|
||||
await page.mouse.move(box.x + box.width / 2, box.y + box.height / 2);
|
||||
await page.mouse.down();
|
||||
@@ -91,19 +96,40 @@ test('shows the tables of a home router and a switch, and drops while “Pakete
|
||||
// The second ping's statistics: an answer lost.
|
||||
await expect(desktop.locator('.terminal-text')).toContainText(/Paketstatistik ---[^]*Paketstatistik ---\n4 Paket\(e\) gesendet, [0-3] Paket\(e\) empfangen/, { timeout: 30_000 });
|
||||
await expect(desktop.locator('.terminal-text')).toContainText('-- Timeout!');
|
||||
const toggle = page.getByRole('button', { name: /^Verworfen: [1-9]/ });
|
||||
await toggle.click();
|
||||
await expect(page.getByLabel('Verworfene Pakete')).toContainText(/\d\d:\d\d:\d\d\.\d\d\d : \[src=[0-9A-F:]+, dest=[0-9A-F:]+, type=0x8/);
|
||||
await expect(properties.getByRole('heading', { name: /^Verworfene Pakete \([1-9]\d*\)$/ })).toBeVisible();
|
||||
await expect(properties.getByLabel('Verworfene Pakete', { exact: true })).toContainText(/\d\d:\d\d:\d\d\.\d\d\d : \[src=[0-9A-F:]+, dest=[0-9A-F:]+, type=0x8/);
|
||||
|
||||
// „Simulation neu starten“: asked first — cancelled, nothing happens; confirmed, the command line and the
|
||||
// dropped frames begin anew, the simulation runs, and what the server saved is still there.
|
||||
await input.fill('touch bleibt.txt');
|
||||
await input.press('Enter');
|
||||
await properties.getByRole('button', { name: 'Simulation neu starten' }).click();
|
||||
await expect(properties.getByText('Die Simulation für alle neu starten? Alle Protokolle und Datenpakete gehen verloren.')).toBeVisible();
|
||||
await properties.getByRole('button', { name: 'Abbrechen' }).click();
|
||||
await expect(properties.getByLabel('Verworfene Pakete', { exact: true })).toBeVisible();
|
||||
await expect(desktop.locator('.terminal-text')).toContainText('ping 141.99.4.10');
|
||||
await properties.getByRole('button', { name: 'Simulation neu starten' }).click();
|
||||
await properties.getByRole('button', { name: 'Neu starten' }).click();
|
||||
await expect(desktop.locator('.terminal-text')).not.toContainText('ping 141.99.4.10');
|
||||
await expect(properties.getByText('Noch keine verworfenen Pakete.')).toBeVisible();
|
||||
await expect(properties.getByRole('heading', { name: 'Verworfene Pakete (0)' })).toBeVisible();
|
||||
await expect(page.locator('svg.filius-canvas')).toHaveAttribute('data-mode', 'simulation');
|
||||
await input.fill('ls');
|
||||
await input.press('Enter');
|
||||
await expect(desktop.locator('.terminal-text')).toContainText('bleibt.txt');
|
||||
});
|
||||
|
||||
test('keeps “Pakete verwerfen” in reach on a phone', async ({ page }) => {
|
||||
test('keeps “Pakete verwerfen” in reach on a phone, in „Eigenschaften“ over the whole editor', async ({ page }) => {
|
||||
await page.setViewportSize({ width: 360, height: 740 });
|
||||
await openEditor(page, server.base, 'nat_with_mapped_port.fls');
|
||||
await page.getByRole('button', { name: 'Wechselt in den Aktionsmodus' }).click();
|
||||
await expect(page.locator('svg.filius-canvas')).toHaveAttribute('data-mode', 'simulation');
|
||||
await expect(page.getByRole('button', { name: 'Pakete verwerfen' })).toBeInViewport({ ratio: 1 });
|
||||
await expect(page.getByRole('button', { name: /^Verworfen: / })).toBeInViewport({ ratio: 1 });
|
||||
// Every part of the toolbar within the screen (the dev page's own fields above the editor are wider; they are not the editor's).
|
||||
const rights = await page.locator('.editor-toolbar > *').evaluateAll((parts) => parts.map((part) => part.getBoundingClientRect().right));
|
||||
expect(Math.max(...rights)).toBeLessThanOrEqual(360);
|
||||
await page.getByRole('button', { name: 'Eigenschaften' }).click();
|
||||
const properties = page.getByRole('complementary', { name: 'Eigenschaften' });
|
||||
expect(await properties.boundingBox()).toEqual(await page.locator('.editor-root').boundingBox());
|
||||
await expect(properties.getByRole('button', { name: 'Pakete verwerfen' })).toBeInViewport({ ratio: 1 });
|
||||
await expect(properties.getByRole('button', { name: 'Simulation neu starten' })).toBeInViewport({ ratio: 1 });
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user