Lot T4 : l'ADR 0014, le fichier de relecture textes-amorce.md, les contrôles e2e au document de T4

ADR 0014 « Les informations de fonctionnement ne se votent pas » : ce qui sort
(F1, F1.1, F1.2, F1.3, N1, N1.1, O1 et l'ordre de leurs sections), comment (rien
d'effacé, units.retired_at), la garde et ses refus, aucun vote futur (404 / 400),
ce que dira l'interface (U3), la file de publication, le retour arrière (prouvé
avec l'image de de1b7eb), les limites. textes-amorce.md : chaque texte avant /
après en fr, en, es, E12, ce qui sort, les choix à confirmer par Yvv.

e2e (aucun changement de web/src) : C3, C9 (27 articles, cinq sections, quatre
Propositions seed), C17 (33 modules à voter), C18 et C31 (le texte d'I1 de
T4), C25 (cinq lignes d'ordre, E12 dans l'ordre de « fondamental »), C35 (E12
entre E1 et E2 ; le glisser d'une place), C38 (4 Propositions seed).
CONTROLES.md suit ; CLAUDE.md : article_amend.rs, retire.rs, amorce.rs,
fixtures/seed-m8, le seed de 27 articles, l'invariant.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Yvv
2026-11-03 21:45:27 +01:00
co-authored by Claude Opus 5.5
parent 093d1ca471
commit 3996f6f99d
11 changed files with 512 additions and 53 deletions
+21 -17
View File
@@ -10,6 +10,8 @@ test.beforeAll(async ({ browser }) => seedsInForce(browser));
const EF = 'Engagements fondamentaux';
const E1 = 'Unicité du compte';
// Lot T4 (Yvv, 2026-11-03): between the two, a seed proposal, left open by `seedsInForce`.
const EC = 'Responsabilité civique';
const E2 = 'Réciprocité';
const ORDER = `Ordre des articles · ${EF}`;
const CSRF = { 'x-requested-with': 'libredecision' };
@@ -41,11 +43,11 @@ test('C35 — réordonner une section : les poignées sur ses articles, au gliss
await expect(page.locator('aside.panel')).toHaveCount(0);
const list = page.locator('section.text').getByRole('list', { name: 'Nouvel ordre des articles' });
const names = list.locator('button.item .name');
await expect(names).toHaveText([EF, E1, E2]);
await expect(names).toHaveText([EF, E1, EC, E2]);
// The articles in force of the section are in the list now, not twice; the one only proposed says so.
await expect(page.locator('section.text article.unit', { hasText: E1 })).toHaveCount(0);
await expect(list.locator('li', { hasText: EF })).toContainText('proposé');
await expect(list.locator('.grip')).toHaveCount(3);
await expect(list.locator('.grip')).toHaveCount(4);
const submit = page.getByRole('button', { name: 'Proposer cet ordre' });
await expect(submit).toBeDisabled();
// Off, and it says why (UX-lecteur.md: « le bouton reste éteint et le dit » — lot U2).
@@ -54,43 +56,45 @@ test('C35 — réordonner une section : les poignées sur ses articles, au gliss
await expect(submit).toHaveAccessibleDescription(why);
await shot(page, 'c35-2-poignees');
// By dragging its handle: Réciprocité onto the place of Unicité du compte.
await list.locator('li', { hasText: E2 }).locator('.grip').dragTo(list.locator('li', { hasText: E1 }));
await expect(names).toHaveText([EF, E2, E1]);
await expect(page.getByText(`« ${E2} » en place 2 sur 3.`)).toBeAttached();
// By dragging its handle: Réciprocité onto the place of the article above it, Responsabilité
// civique (lot T4; a drag over two rows is not announced, see the report of lot T4 for U3).
await list.locator('li', { hasText: E2 }).locator('.grip').dragTo(list.locator('li', { hasText: EC }));
await expect(names).toHaveText([EF, E1, E2, EC]);
await expect(page.getByText(`« ${E2} » en place 3 sur 4.`)).toBeAttached();
await expect(submit).toBeEnabled();
await expect(page.getByText(why)).toHaveCount(0);
// With the keyboard: the article keeps the focus, the arrows move it.
const items = list.locator('button.item');
await items.nth(1).focus();
await items.nth(2).focus();
await page.keyboard.press('ArrowUp');
await expect(names).toHaveText([E2, EF, E1]);
await expect(items.nth(0)).toBeFocused();
await expect(names).toHaveText([EF, E2, E1, EC]);
await expect(items.nth(1)).toBeFocused();
await page.keyboard.press('ArrowDown');
await expect(names).toHaveText([EF, E2, E1]);
await expect(names).toHaveText([EF, E1, E2, EC]);
// Without dragging: its arrows, or an article then its new place.
await list.getByRole('button', { name: `Descendre « ${E2} »` }).click();
await expect(names).toHaveText([EF, E1, E2]);
await expect(names).toHaveText([EF, E1, EC, E2]);
await expect(submit).toBeDisabled();
await expect(page.getByText(why)).toBeVisible();
await items.nth(2).click();
await expect(items.nth(2)).toHaveAttribute('aria-pressed', 'true');
await items.nth(3).click();
await expect(items.nth(3)).toHaveAttribute('aria-pressed', 'true');
await items.nth(1).click();
await expect(names).toHaveText([EF, E2, E1]);
await expect(names).toHaveText([EF, E2, E1, EC]);
// « Annuler » gives the section back as it read.
await page.getByRole('button', { name: 'Annuler' }).click();
await expect(list).toHaveCount(0);
await expect(page.locator('section.text article.unit', { hasText: E1 })).toHaveCount(1);
await line.getByRole('button', { name: 'Réordonner' }).click();
await list.getByRole('button', { name: `Monter « ${E2} »` }).click();
await expect(names).toHaveText([EF, E2, E1]);
await list.getByRole('button', { name: `Monter « ${E2} »` }).click();
await expect(names).toHaveText([EF, E2, E1, EC]);
// Then the vote: the order goes to the vote, and its vote unfolds at once, in the same place.
await submit.click();
await expect(page.getByText('Ordre proposé au vote.')).toBeVisible();
const fold = line.locator('section.fold');
await expect(fold).toHaveAttribute('aria-label', `Le vote de « ${ORDER} »`);
await expect(fold.getByRole('list', { name: 'Ordre proposé' }).locator('li')).toHaveText([EF, E2, E1]);
await expect(fold.getByRole('list', { name: 'Ordre proposé' }).locator('li')).toHaveText([EF, E2, E1, EC]);
await expect(line).toContainText('1 ordre proposé');
const pid = ((await fold.getAttribute('id')) ?? '').replace(/^vote-/, '');
await fold.getByRole('button', { name: 'Pour', exact: true }).click();
@@ -257,7 +261,7 @@ test('C38 — l’en-tête compte ce que montre la liste ; un changement d’ine
await page.goto(DOC);
await unfold(page);
const facts = page.locator('.facts');
await expect.soft(facts).toContainText('0 article en vigueur · 3 Propositions seed · ');
await expect.soft(facts).toContainText('0 article en vigueur · 4 Propositions seed · ');
await expect.soft(facts).toContainText(new RegExp(`· ${await listed()} propositions en cours`));
// A change of inertia on the order of a section and on the title (test group): each is found at