feat(editor): F4.5b the device sheet for routers and home routers
Measured first: SheetRun now types into FILIUS' router and home router
panels, records five forwarding tables (holeTabelle) and steps in the
panel's table. Java turns a card address that passes the pattern but not
IP.ipCheck (".0.0.1") into null and the router panel throws; an empty
gateway is marked red yet taken; a refused table cell is stored as null;
a home router's DHCP client leaves its DHCP server running. None of the
nulls is adopted. The core's routeTableRows matches all five tables.
- doc: card addresses (the first card mirrored in the device's settings),
router gateway, RIP, manual routes (a new row once all four cells pass,
a cell, removal); the sheet reads cards with what their cable joins and
the whole table
- editor: Java's tabs (general, each card titled by its address, the
forwarding table greyed out under RIP; general, LAN, WAN on a home
router); the open card's cable drawn active in Java's green
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
// beside the surface on a wide screen, below it on a phone.
|
||||
|
||||
import { expect, test, type Page } from '@playwright/test';
|
||||
import type { HostSheet } from '@mdg-filius/doc';
|
||||
import type { HostSheet, RouterSheet } from '@mdg-filius/doc';
|
||||
import { drawing, onDevice, openEditor, serveEditor, sheetOf } from './editorPage.js';
|
||||
|
||||
let server: { readonly base: string; readonly close: () => Promise<void> };
|
||||
@@ -156,6 +156,100 @@ test("joins a notebook to a switch's wireless network, drawn as wireless", async
|
||||
await expect.poll(async () => (await drawing(page)).links).toEqual([]);
|
||||
});
|
||||
|
||||
test("shows a router's cards in Java's tabs, draws the open card's cable active, and renames a tab by its address", async ({ page }) => {
|
||||
await openEditor(page, server.base, 'zwei_rechnernetze_komplett.fls');
|
||||
const id = (await drawing(page)).nodes.find((node) => node.kind === 'router')!.id;
|
||||
await choose(page, id);
|
||||
const values = (await sheetOf(page, id)) as RouterSheet;
|
||||
const tabs = sheet(page).getByRole('tab');
|
||||
await expect(tabs).toHaveText(['Allgemein', ...values.interfaces.map((card) => card.ipAddress), 'Weiterleitungstabelle']);
|
||||
await expect(field(page, 'name')).toHaveValue(values.name);
|
||||
await expect(sheet(page).getByLabel('IP-Weiterleitung aktivieren')).toBeDisabled();
|
||||
await expect(sheet(page).getByLabel('IP-Weiterleitung aktivieren')).toBeChecked();
|
||||
const card = values.interfaces[0]!;
|
||||
await tabs.nth(1).click();
|
||||
await expect(sheet(page).locator('.sheet-connected')).toHaveText(`Verbunden mit ${card.connected!.device}`);
|
||||
await expect(page.locator(`path[data-link="${card.connected!.link}"]`)).toHaveAttribute('data-active', 'true');
|
||||
// Java's active cable is green (JCablePanel.farbeBlinken).
|
||||
await expect(page.locator(`path[data-link="${card.connected!.link}"]`)).toHaveCSS('stroke', 'rgb(0, 255, 64)');
|
||||
await field(page, 'ipAddress').fill('192.168.0.1');
|
||||
await field(page, 'ipAddress').press('Enter');
|
||||
await expect(tabs.nth(1)).toHaveText('192.168.0.1');
|
||||
await tabs.first().click();
|
||||
await expect(page.locator('path[data-active]')).toHaveCount(0);
|
||||
await tabs.nth(1).click();
|
||||
await sheet(page).getByRole('button', { name: 'Schließen' }).click();
|
||||
await expect(page.locator('path[data-active]')).toHaveCount(0);
|
||||
});
|
||||
|
||||
test("edits a router's forwarding table: a new row once its four cells pass, a cell, the row removed; RIP greys it out", async ({ page }) => {
|
||||
await openEditor(page, server.base, 'new');
|
||||
await page.locator('[data-palette="router"]').click();
|
||||
await page.getByRole('dialog').getByRole('button', { name: '2', exact: true }).click();
|
||||
const id = (await drawing(page)).nodes[0]!.id;
|
||||
const tabs = sheet(page).getByRole('tab');
|
||||
await tabs.last().click();
|
||||
const rows = sheet(page).locator('.route-table tbody tr');
|
||||
// Java's own rows: two addresses, two networks (the same twice: both cards are new), localhost.
|
||||
await expect(rows).toHaveCount(5);
|
||||
await sheet(page).getByRole('button', { name: 'Neuer Eintrag' }).click();
|
||||
await expect(sheet(page).getByText('Die Zeile wird übernommen, sobald alle vier Felder gültig sind.')).toBeVisible();
|
||||
await expect(field(page, 'route-destinationNetwork')).toHaveAttribute('aria-invalid', 'false');
|
||||
for (const [column, text] of [
|
||||
['destinationNetwork', '10.0.0.0'],
|
||||
['subnetMask', '255.0.0.0'],
|
||||
['gateway', '192.168.0.1'],
|
||||
] as const) {
|
||||
await field(page, `route-${column}`).fill(text);
|
||||
await field(page, `route-${column}`).press('Enter');
|
||||
}
|
||||
expect(((await sheetOf(page, id)) as RouterSheet).routes).toEqual([]);
|
||||
await field(page, 'route-interfaceIPAddress').fill('192.168.0.10');
|
||||
await field(page, 'route-interfaceIPAddress').press('Enter');
|
||||
await expect.poll(async () => ((await sheetOf(page, id)) as RouterSheet).routes).toEqual([{ destinationNetwork: '10.0.0.0', subnetMask: '255.0.0.0', gateway: '192.168.0.1', interfaceIPAddress: '192.168.0.10' }]);
|
||||
await expect(sheet(page).locator('tr[data-manual="0"]')).toHaveAttribute('aria-selected', 'true');
|
||||
await field(page, 'route-gateway').fill('192.168.0.2');
|
||||
await field(page, 'route-gateway').press('Enter');
|
||||
await expect(sheet(page).locator('tr[data-manual="0"] td').nth(2)).toHaveText('192.168.0.2');
|
||||
await sheet(page).getByLabel('Alle Einträge anzeigen').uncheck();
|
||||
await expect(rows).toHaveCount(1);
|
||||
await sheet(page).getByLabel('Alle Einträge anzeigen').check();
|
||||
await sheet(page).locator('tr[data-manual="0"]').click();
|
||||
await sheet(page).getByRole('button', { name: 'Eintrag löschen' }).click();
|
||||
await expect.poll(async () => ((await sheetOf(page, id)) as RouterSheet).routes).toEqual([]);
|
||||
await expect(rows).toHaveCount(5);
|
||||
await tabs.first().click();
|
||||
await sheet(page).getByLabel('Automatisches Routing').check();
|
||||
await expect(tabs.last()).toBeDisabled();
|
||||
await sheet(page).getByLabel('Automatisches Routing').uncheck();
|
||||
await expect(tabs.last()).toBeEnabled();
|
||||
// RIP switched on while the table is open (here: taken back by undo) closes it.
|
||||
await tabs.last().click();
|
||||
await expect(sheet(page).locator('.route-table')).toBeVisible();
|
||||
await page.getByRole('button', { name: 'Rückgängig' }).click();
|
||||
await expect(tabs.last()).toBeDisabled();
|
||||
await expect(tabs.first()).toHaveAttribute('aria-selected', 'true');
|
||||
await expect(sheet(page).getByLabel('Automatisches Routing')).toBeChecked();
|
||||
});
|
||||
|
||||
test("shows a home router's LAN and WAN tabs, DHCP closing the WAN card's address", async ({ page }) => {
|
||||
await openEditor(page, server.base, 'new');
|
||||
await page.locator('[data-palette="gateway"]').click();
|
||||
const tabs = sheet(page).getByRole('tab');
|
||||
await expect(tabs).toHaveText(['Allgemein', 'LAN: 192.168.0.10', 'WAN: 42.0.0.10']);
|
||||
await expect(sheet(page).locator('.sheet-connected')).toHaveCount(0);
|
||||
await tabs.nth(2).click();
|
||||
await expect(sheet(page).locator('.sheet-connected')).toHaveText('Keine Verbindung');
|
||||
await sheet(page).getByLabel('DHCP zur Konfiguration verwenden').check();
|
||||
await expect(field(page, 'ipAddress')).toBeDisabled();
|
||||
await expect(field(page, 'subnetMask')).toBeDisabled();
|
||||
await tabs.nth(1).click();
|
||||
await expect(field(page, 'ipAddress')).toBeEnabled();
|
||||
await field(page, 'ipAddress').fill('192.168.7.1');
|
||||
await field(page, 'ipAddress').press('Enter');
|
||||
await expect(tabs.nth(1)).toHaveText('LAN: 192.168.7.1');
|
||||
});
|
||||
|
||||
test.describe('on a phone', () => {
|
||||
test.use({ viewport: { width: 390, height: 844 }, hasTouch: true });
|
||||
|
||||
|
||||
Reference in New Issue
Block a user