Files
decision/web/e2e/reader.spec.ts
T
YvvandClaude Opus 5.5 7a022dd35e v3 : interface Svelte — accueil, groupes, lecteur du texte en vigueur, panneau contextuel, éditeur à assistant, trustinWallet
- Accueil sobre, menu complet à gauche (Décisions, Docs de référence, Mandats,
  Protocoles), intro demandée, quatre sections, connexion Ğ1.
- Lecteur : texte en vigueur en Literata, actions contextuelles par article
  (le vote, propositions, proposer), propositions en cours sous la « surface »
  avec leur niveau d'eau, aperçus « si les bien cotées passent » / « si tout
  passe », langue du texte fr/en/es (traductions éditoriales).
- Panneau : vote pour/contre, seuil et formule (MathML), inertie et son
  changement (voté en inertie +), coquille sans vote, traduction, signalement
  de contradiction, historique des corrections.
- trustinWallet (/acces) : groupes et membres, invitations à usage unique,
  administrateurs, retours d'usage.
- Contrôles : vitest (markdown, catalogues, anti-lexique), Playwright C1–C10 + M1.
- Sections du seed portées jusqu'à l'écran.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 02:58:34 +02:00

136 lines
7.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { expect, test } from '@playwright/test';
import { DOC, person, signIn, TEST_DOC } from './helpers';
test('C1 — l’accueil : l’intro, les quatre sections, le menu complet', async ({ page }) => {
await page.goto('/');
await expect(page.getByRole('heading', { level: 1 })).toHaveText('Rendre possible la décision collective');
await expect(page.getByText('en fonction du contexte, processus et modalités, boîte à outils')).toBeVisible();
const nav = page.getByRole('navigation', { name: 'Boîte à outils' });
for (const item of ['Décisions', 'Docs de référence', 'Mandats', 'Protocoles']) {
await expect(nav.locator('.tool', { hasText: item })).toBeVisible();
}
await expect(nav.locator('.tool.disabled')).toHaveCount(3);
await expect(page.getByRole('link', { name: 'Se connecter avec sa clé Ğ1' })).toBeVisible();
});
test('C2 — les groupes de la même clé ; pas l’Atelier du canal', async ({ page }) => {
await signIn(page, 'Chiara');
await page.goto('/groupes');
for (const g of ['Monnaie libre', 'Axiom', 'Librodrome', 'Groupe local Vallée Drôme Crestois']) {
await expect(page.getByText(g, { exact: true })).toBeVisible();
}
await expect(page.getByText('Atelier du canal')).toHaveCount(0);
});
test('C3 — le texte en vigueur : préambule et deux engagements, seed a minima', async ({ page }) => {
await signIn(page, 'Chiara');
await page.goto(DOC);
await expect(page.getByRole('heading', { level: 1 })).toHaveText("Acte d'engagement Certification");
const units = page.locator('section.text article.unit');
await expect(units).toHaveCount(3);
await expect(units.nth(0).locator('h2')).toHaveText('Préambule');
await expect(units.nth(1).locator('h2')).toHaveText('Unicité du compte');
await expect(units.nth(2).locator('h2')).toHaveText('Réciprocité');
await expect(page.getByText('seed a minima · 0 vote')).toHaveCount(3);
await expect(page.getByRole('heading', { name: 'Propositions en cours' })).toBeVisible();
await expect(page.locator('ul.deep button.row')).toHaveCount(32);
});
test('C4 — les actions sont contextuelles, le vote s’ouvre en panneau', async ({ page }) => {
await signIn(page, 'Chiara');
await page.goto(DOC);
const first = page.locator('section.text article.unit').first();
await first.hover();
await first.getByRole('button', { name: 'Le vote' }).click();
const panel = page.locator('aside.panel');
await expect(panel.getByText('Seuil : 50 voix pour')).toBeVisible();
await expect(panel.getByText('Il manque 50 voix pour.')).toBeVisible();
await panel.getByText('La formule du seuil').click();
await expect(panel.getByText(/W — électorat/)).toBeVisible();
// The panel lives in the URL.
await expect(page).toHaveURL(/onglet=vote/);
await page.keyboard.press('Escape');
await expect(panel).toHaveCount(0);
});
test('C5 — une proposition remonte en vigueur quand elle atteint son seuil (groupe d’essai)', async ({ browser }) => {
const yvv = await person(browser, 'Yvv');
const chiara = await person(browser, 'Chiara');
for (const p of [yvv, chiara]) {
await p.goto(TEST_DOC);
await p.locator('ul.deep button.row', { hasText: 'Les deux garanties réciproques' }).click();
await p.locator('aside.panel').getByRole('button', { name: 'Pour', exact: true }).click();
await expect(p.getByText('Vote enregistré.')).toBeVisible();
}
await expect(chiara.getByText('« Les deux garanties réciproques » est entré en vigueur.')).toBeVisible();
await chiara.keyboard.press('Escape');
await expect(chiara.locator('section.text article.unit')).toHaveCount(4);
});
test('C6 — une coquille se corrige sans vote', async ({ page }) => {
await signIn(page, 'Chiara');
await page.goto(TEST_DOC);
const preamble = page.locator('section.text article.unit').first();
await preamble.hover();
await preamble.getByRole('button', { name: 'Le vote' }).click();
const panel = page.locator('aside.panel');
await panel.getByText('Corriger une coquille').click();
const body = panel.getByLabel('Texte', { exact: true });
await body.fill((await body.inputValue()).replace('latransmission', 'la transmission'));
await panel.getByRole('button', { name: 'Enregistrer la correction' }).click();
await expect(page.getByText('Coquille corrigée, sans toucher aux votes.')).toBeVisible();
await expect(preamble).toContainText('la transmission de ce document');
// A change of meaning is turned away.
await panel.getByText('Corriger une coquille').click();
await body.fill('Tout autre chose, qui change le sens du préambule.');
await panel.getByRole('button', { name: 'Enregistrer la correction' }).click();
await expect(panel.getByText('Ce changement touche au sens : propose-le comme modification.')).toBeVisible();
});
test('C7 — l’assistant propose de découper deux décisions', async ({ page }) => {
await signIn(page, 'Chiara');
await page.goto(TEST_DOC);
await page.getByRole('button', { name: 'Proposer un nouvel article' }).click();
const panel = page.locator('aside.panel');
await panel.getByLabel('Titre').fill('Joignabilité et vérification');
await panel.getByLabel('Texte').fill(
"Je m'engage à rester joignable par mes certifieurs.\n\nJe m'engage à vérifier la clé publique avec la personne.",
);
await expect(panel.getByText('Ce texte semble porter 2 décisions.', { exact: false })).toBeVisible();
await panel.getByRole('button', { name: 'Découper en 2 brouillons' }).click();
await expect(page.getByText('Découpé en 2 brouillons.')).toBeVisible();
await expect(page.getByRole('heading', { name: 'Tes brouillons' })).toBeVisible();
});
test('C8 — multilingue : le texte et l’interface en anglais et en espagnol', async ({ page }) => {
await signIn(page, 'Chiara');
await page.goto(DOC);
await page.getByRole('radiogroup', { name: 'Langue du texte' }).getByRole('radio', { name: 'EN' }).click();
await expect(page.getByRole('heading', { level: 1 })).toHaveText('Certification Commitment Act');
await expect(page.getByText('Open proposals', { exact: false }).first()).toBeVisible();
await page.getByRole('radiogroup', { name: 'Text language' }).getByRole('radio', { name: 'ES' }).click();
await expect(page.getByRole('heading', { level: 1 })).toHaveText('Acta de compromiso de Certificación');
});
test('C9 — les aperçus : bien cotées, et tout', async ({ page }) => {
await signIn(page, 'Chiara');
await page.goto(DOC);
await page.getByRole('radio', { name: 'Si tout passe' }).click();
await expect(page.getByText("Aperçu : le texte tel qu'il serait si toutes les propositions", { exact: false })).toBeVisible();
await expect(page.locator('section.text article.unit')).toHaveCount(33);
await page.getByRole('radio', { name: 'Si les bien cotées passent' }).click();
await expect(page.locator('section.text article.unit')).toHaveCount(3);
});
test('C10 — trustinWallet : la gestion des accès est réservée', async ({ browser }) => {
const chiara = await person(browser, 'Chiara');
await chiara.goto('/acces');
await expect(chiara.getByText('La gestion des accès est réservée aux administrateurs de trustinWallet.')).toBeVisible();
const yvv = await person(browser, 'Yvv', true);
await yvv.goto('/acces');
await expect(yvv.getByRole('heading', { name: 'trustinWallet — accès' })).toBeVisible();
await yvv.getByLabel('Pour qui').fill('Invitée');
await yvv.getByRole('button', { name: "Créer le lien d'invitation" }).click();
await expect(yvv.locator('.link code')).toContainText('/invitation#');
});