feat(editor): F4.6e the e-mail program and e-mail server on a computer's desktop
The oracle MailWindowRun uses Java's e-mail windows as a person does and answers their dialogs. The core sets and saves the program's account, deletes a mail, checks a form as Java's window does, and gives the server its domain, new and removed accounts and the window's own line; the room sends both programs' views and takes their actions; the editor has both windows. Better than Java: a name field for a new account, a user name the server has is refused, deleting hits the folder shown, a new domain goes into the accounts file at once. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,196 @@
|
||||
// The e-mail program and the e-mail server on a computer's desktop in
|
||||
// Chromium (F4.6e), on FILIUS' example email_komplett: a mail written with
|
||||
// Java's checks and sent, the server's accounts and lines, the mail fetched,
|
||||
// chosen, answered and deleted, the account dialog; the server's new account,
|
||||
// its question before it removes one, its domain only while it is off.
|
||||
|
||||
import { expect, test, type Page } from '@playwright/test';
|
||||
import { drawing, onDevice, openEditor, serveEditor } from './editorPage.js';
|
||||
|
||||
let server: { readonly base: string; readonly close: () => Promise<void> };
|
||||
|
||||
test.beforeAll(async () => {
|
||||
server = await serveEditor();
|
||||
});
|
||||
|
||||
test.afterAll(async () => {
|
||||
await server.close();
|
||||
});
|
||||
|
||||
async function start(page: Page): Promise<void> {
|
||||
await page.getByRole('button', { name: 'Wechselt in den Aktionsmodus' }).click();
|
||||
await expect(page.locator('svg.filius-canvas')).toHaveAttribute('data-mode', 'simulation');
|
||||
}
|
||||
|
||||
/** Opens a computer's desktop with a tap and a program's window on it. */
|
||||
async function openProgram(page: Page, name: string, program: string) {
|
||||
const id = (await drawing(page)).nodes.find((node) => node.name === name)!.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="${program}"]`).click();
|
||||
return { desktop, window: desktop.locator(`[data-program-window="${program}"]`) };
|
||||
}
|
||||
|
||||
test("writes, sends, fetches, answers and deletes mails as Java's e-mail program does", async ({ page }) => {
|
||||
test.setTimeout(120_000);
|
||||
await openEditor(page, server.base, 'email_komplett.fls');
|
||||
await start(page);
|
||||
const one = await openProgram(page, 'Rechner 1', 'emailClient');
|
||||
const window = one.window;
|
||||
await expect(window.locator('.mail-welcome')).toHaveText('Willkommen in der E-Mail-Anwendung!');
|
||||
await expect(window.getByRole('tab', { name: 'Posteingang' })).toHaveAttribute('aria-selected', 'true');
|
||||
|
||||
// The account dialog shows the account, as Java's does.
|
||||
await window.getByRole('button', { name: 'Konto einrichten' }).click();
|
||||
const dialog = window.getByRole('form', { name: 'E-Mail-Konto verwalten' });
|
||||
await expect(dialog.getByRole('textbox', { name: 'Name:', exact: true })).toHaveValue('Rechner 1');
|
||||
await expect(dialog.getByRole('textbox', { name: 'E-Mail-Adresse:' })).toHaveValue('rechner1@filius.de');
|
||||
await dialog.getByRole('textbox', { name: 'SMTP-Port:' }).fill('25x');
|
||||
await dialog.getByRole('button', { name: 'Speichern' }).click();
|
||||
await expect(window.getByRole('alertdialog')).toHaveText(/Die Angaben sind entweder fehlerhaft oder unvollständig!/);
|
||||
await window.getByRole('alertdialog').getByRole('button', { name: 'OK' }).click();
|
||||
await dialog.getByRole('button', { name: 'Abbrechen' }).click();
|
||||
await expect(dialog).toHaveCount(0);
|
||||
|
||||
// Writing: Java's checks, then sent; the window shows the sent mails.
|
||||
await window.getByRole('button', { name: 'Neue E-Mail verfassen' }).click();
|
||||
const compose = window.getByRole('form', { name: 'E-Mail verfassen' });
|
||||
await compose.getByRole('textbox', { name: 'An:' }).fill('rechner2@filius.de, kein');
|
||||
await expect(compose.getByRole('textbox', { name: 'An:' })).toHaveAttribute('aria-invalid', 'true');
|
||||
await compose.getByRole('button', { name: 'Senden' }).click();
|
||||
await expect(window.getByRole('alertdialog')).toHaveText(/Mindestens eine eingegebene E-Mail-Adresse ist nicht korrekt!/);
|
||||
await window.getByRole('alertdialog').getByRole('button', { name: 'OK' }).click();
|
||||
await compose.getByRole('textbox', { name: 'An:' }).fill('');
|
||||
await compose.getByRole('button', { name: 'Senden' }).click();
|
||||
await expect(window.getByRole('alertdialog')).toHaveText(/Sie müssen mindestens eine Empfänger-Adresse eingeben!/);
|
||||
await window.getByRole('alertdialog').getByRole('button', { name: 'OK' }).click();
|
||||
await compose.getByRole('textbox', { name: 'An:' }).fill('rechner2@filius.de');
|
||||
await compose.getByRole('textbox', { name: 'Betreff:' }).fill('Hallo Zwei');
|
||||
await compose.getByRole('textbox', { name: 'Text der E-Mail' }).fill('Erste Zeile\nZweite Zeile');
|
||||
await compose.getByRole('button', { name: 'Senden' }).click();
|
||||
await expect(compose).toHaveCount(0);
|
||||
await expect(window.getByRole('tab', { name: 'Gesendete' })).toHaveAttribute('aria-selected', 'true');
|
||||
await expect(window.getByRole('tabpanel').locator('tbody tr').last()).toHaveText(/<rechner2@filius\.de>\s*Hallo Zwei/, { timeout: 30_000 });
|
||||
await one.desktop.getByRole('button', { name: 'Schließen' }).click();
|
||||
|
||||
// The server holds it; its lines show the dialogue.
|
||||
const mailServer = await openProgram(page, 'Mail-Server (filius.de)', 'emailServer');
|
||||
await mailServer.window.getByRole('tab', { name: 'Konten-Liste' }).click();
|
||||
await expect(mailServer.window.getByRole('tabpanel').locator('tbody tr')).toHaveText([/rechner1@filius\.de/, /rechner2@filius\.de\s*\d+/]);
|
||||
await mailServer.window.getByRole('tab', { name: 'Log Fenster' }).click();
|
||||
await expect(mailServer.window.getByRole('tabpanel')).toContainText('E-Mail für rechner2 im Postfach gespeichert.');
|
||||
await mailServer.desktop.getByRole('button', { name: 'Schließen' }).click();
|
||||
|
||||
// Fetched, chosen, answered, deleted.
|
||||
const two = await openProgram(page, 'Rechner 2', 'emailClient');
|
||||
// Fetching shows the inbox, from any folder.
|
||||
await two.window.getByRole('tab', { name: 'Gesendete' }).click();
|
||||
await two.window.getByRole('button', { name: 'E-Mails abrufen' }).click();
|
||||
await expect(two.window.getByRole('tab', { name: 'Posteingang' })).toHaveAttribute('aria-selected', 'true');
|
||||
const rows = two.window.getByRole('tabpanel').locator('tbody tr');
|
||||
await expect(rows.filter({ hasText: 'Hallo Zwei' })).toHaveCount(1, { timeout: 30_000 });
|
||||
await expect(rows.filter({ hasText: 'Hallo Zwei' })).toHaveText(/Rechner 1\s*Hallo Zwei/);
|
||||
await rows.filter({ hasText: 'Hallo Zwei' }).click();
|
||||
await expect(two.window.locator('.mail-preview pre')).toHaveText(/Erste Zeile\nZweite Zeile/);
|
||||
await two.window.getByRole('button', { name: 'E-Mail beantworten' }).click();
|
||||
const reply = two.window.getByRole('form', { name: 'E-Mail verfassen' });
|
||||
await expect(reply.getByRole('textbox', { name: 'An:' })).toHaveValue('Rechner 1 <rechner1@filius.de>');
|
||||
await expect(reply.getByRole('textbox', { name: 'Betreff:' })).toHaveValue('RE: Hallo Zwei');
|
||||
await expect(reply.getByRole('textbox', { name: 'Text der E-Mail' })).toHaveValue(/^\n\nRechner 1 <rechner1@filius\.de> schrieb:\n> Erste Zeile\n> Zweite Zeile/);
|
||||
// Sent: the window shows the sent mails, the answer among them.
|
||||
await reply.getByRole('button', { name: 'Senden' }).click();
|
||||
await expect(two.window.getByRole('tab', { name: 'Gesendete' })).toHaveAttribute('aria-selected', 'true');
|
||||
await expect(rows.filter({ hasText: 'RE: Hallo Zwei' })).toHaveCount(1, { timeout: 30_000 });
|
||||
// The mail chosen belongs to its folder: chosen here, nothing is chosen in the inbox, and deleting deletes nothing there (Java's deleted one).
|
||||
await rows.filter({ hasText: 'RE: Hallo Zwei' }).click();
|
||||
await expect(two.window.locator('.mail-preview pre')).toHaveText(/schrieb:/);
|
||||
await two.window.getByRole('tab', { name: 'Posteingang' }).click();
|
||||
const inboxBefore = await rows.count();
|
||||
await expect(two.window.locator('.mail-welcome')).toBeVisible();
|
||||
await two.window.getByRole('button', { name: 'E-Mail löschen' }).click();
|
||||
await expect(rows).toHaveCount(inboxBefore);
|
||||
const before = await rows.count();
|
||||
await rows.filter({ hasText: 'Hallo Zwei' }).click();
|
||||
await two.window.getByRole('button', { name: 'E-Mail löschen' }).click();
|
||||
await expect(rows).toHaveCount(before - 1);
|
||||
await expect(rows.filter({ hasText: 'Hallo Zwei' })).toHaveCount(0);
|
||||
await expect(two.window.locator('.mail-welcome')).toBeVisible();
|
||||
});
|
||||
|
||||
test("makes and removes accounts and sets the domain as Java's e-mail server window does", async ({ page }) => {
|
||||
test.setTimeout(120_000);
|
||||
await openEditor(page, server.base, 'email_komplett.fls');
|
||||
await start(page);
|
||||
const { window } = await openProgram(page, 'Mail-Server (filius.de)', 'emailServer');
|
||||
const domain = window.getByRole('textbox', { name: 'Maildomain:' });
|
||||
await expect(domain).toHaveValue('filius.de');
|
||||
await expect(domain).toBeDisabled();
|
||||
|
||||
// A new account: Java's checks, one the server has already, then made.
|
||||
const form = window.getByRole('tabpanel', { name: 'Neues Konto' });
|
||||
const create = form.getByRole('button', { name: 'Konto erstellen' });
|
||||
await create.click();
|
||||
await expect(form.getByRole('status')).toHaveText('Geben Sie einen Benutzernamen und ein Passwort ein!');
|
||||
await form.getByRole('textbox', { name: 'Benutzername:' }).fill('carl os');
|
||||
await form.getByLabel('Passwort:').fill('x');
|
||||
await create.click();
|
||||
await expect(form.getByRole('status')).toHaveText('Der Benutzername darf keine Leerzeichen enthalten!');
|
||||
await form.getByRole('textbox', { name: 'Benutzername:' }).fill('RECHNER1');
|
||||
await create.click();
|
||||
await expect(form.getByRole('status')).toHaveText('Das Benutzerkonto RECHNER1 gibt es schon.');
|
||||
await form.getByRole('textbox', { name: 'Benutzername:' }).fill('neu');
|
||||
await form.getByRole('textbox', { name: 'Vorname und Nachname:' }).fill('Neue Nutzerin');
|
||||
await create.click();
|
||||
await expect(form.getByRole('status')).toHaveText('Das Benutzerkonto neu wurde angelegt.');
|
||||
await expect(form.getByRole('textbox', { name: 'Benutzername:' })).toHaveValue('');
|
||||
|
||||
// The list: chosen, asked, removed.
|
||||
await window.getByRole('tab', { name: 'Konten-Liste' }).click();
|
||||
const list = window.getByRole('tabpanel', { name: 'Konten-Liste' });
|
||||
await expect(list.locator('tbody tr')).toHaveText([/rechner1@filius\.de/, /rechner2@filius\.de/, /neu@filius\.de\s*0/]);
|
||||
await expect(list.getByRole('button', { name: 'Markiertes Konto entfernen' })).toBeDisabled();
|
||||
await list.locator('tbody tr').filter({ hasText: 'neu@' }).click();
|
||||
await list.getByRole('button', { name: 'Markiertes Konto entfernen' }).click();
|
||||
const question = list.getByRole('alertdialog', { name: 'Sicherheitsabfrage!' });
|
||||
await expect(question).toContainText("Wollen Sie das Konto 'neu' wirklich entfernen?");
|
||||
await question.getByRole('button', { name: 'Abbrechen' }).click();
|
||||
await expect(list.locator('tbody tr')).toHaveCount(3);
|
||||
await list.getByRole('button', { name: 'Markiertes Konto entfernen' }).click();
|
||||
await list.getByRole('alertdialog').getByRole('button', { name: 'Ja' }).click();
|
||||
await expect(list.locator('tbody tr')).toHaveCount(2);
|
||||
|
||||
// Stopped: the domain can be set, red where Java's pattern does not take it.
|
||||
await window.getByRole('button', { name: 'Anhalten' }).click();
|
||||
await expect(window.getByRole('button', { name: 'Starten' })).toBeVisible();
|
||||
await expect(domain).toBeEnabled();
|
||||
await domain.fill('kein domain!');
|
||||
await expect(domain).toHaveAttribute('aria-invalid', 'true');
|
||||
await domain.fill('schule.de');
|
||||
await domain.press('Enter');
|
||||
await expect(list.locator('tbody tr')).toHaveText([/rechner1@schule\.de/, /rechner2@schule\.de/]);
|
||||
await window.getByRole('tab', { name: 'Log Fenster' }).click();
|
||||
await expect(window.getByRole('tabpanel')).toContainText('POP3- und SMTP-Server wurden angehalten.');
|
||||
});
|
||||
|
||||
test("shows the program's failure as Java's dialog does, and saves a new account", async ({ page }) => {
|
||||
test.setTimeout(120_000);
|
||||
await openEditor(page, server.base, 'email_komplett.fls');
|
||||
await start(page);
|
||||
const { window } = await openProgram(page, 'Rechner 1', 'emailClient');
|
||||
await window.getByRole('button', { name: 'Konto einrichten' }).click();
|
||||
const dialog = window.getByRole('form', { name: 'E-Mail-Konto verwalten' });
|
||||
await dialog.getByRole('textbox', { name: 'SMTP-Server:' }).fill('niemand.filius.de');
|
||||
await dialog.getByRole('textbox', { name: 'Name:', exact: true }).fill('Anna Maria Muster');
|
||||
await dialog.getByRole('button', { name: 'Speichern' }).click();
|
||||
await expect(dialog).toHaveCount(0);
|
||||
await window.getByRole('button', { name: 'Konto einrichten' }).click();
|
||||
await expect(dialog.getByRole('textbox', { name: 'Name:', exact: true })).toHaveValue('Anna Maria Muster');
|
||||
await expect(dialog.getByRole('textbox', { name: 'SMTP-Server:' })).toHaveValue('niemand.filius.de');
|
||||
await dialog.getByRole('button', { name: 'Abbrechen' }).click();
|
||||
await window.getByRole('button', { name: 'Neue E-Mail verfassen' }).click();
|
||||
const compose = window.getByRole('form', { name: 'E-Mail verfassen' });
|
||||
await compose.getByRole('textbox', { name: 'An:' }).fill('rechner2@filius.de');
|
||||
await compose.getByRole('button', { name: 'Senden' }).click();
|
||||
await expect(window.getByRole('alertdialog')).toHaveText(/Ziel konnte nicht bestimmt werden!/, { timeout: 60_000 });
|
||||
});
|
||||
Reference in New Issue
Block a user