Lot U3 : l'interface de l'Acte d'engagement (Yvv, 03/11) — avant le texte, hors vote, « Info ouverture doc de réf. » (OpeningInfo, lib/opening.ts) : le paragraphe d'Yvv mot pour mot à la place de doc.empty.seeds (sa première phrase tant qu'aucun article n'est en vigueur, puis « entrent en vigueur » où « y » n'avait plus rien à reprendre), le cran d'ouverture des Propositions d'amorce, du titre, de l'ordre de chaque section et des autres articles (avant tout changement voté) et le quorum de chaque cran, lus dans l'API ; une séparation (un filet de la couleur de la clé de voûte, jamais une bordure) ; plus les titres « Introduction » et « Engagements fondamentaux » dans le texte. Les informations de F1, F1.1, F1.2, N1, N1.1 et O1 là où elles servent : vote.permanent, vote.rival, vote.others.rule, formula.Tprime, formula.round, formula.B.wot, formula.G, settings.share.note, settings.usual.quorum, settings.gradient, order.edit.effect ; les termes définis de T3c (« à la participation habituelle », « quorum de l'article », « part exigée », « repose sur moins de N propositions votées depuis un an »), plus de « comme d'habitude ». « Proposition d'amorce » (Starter proposal, Propuesta de arranque). Le mot d'Yvv pour qui n'est pas invité, à l'accueil sans session (à la place du bouton Ğ1 tant que la connexion Ğ1 n'est pas active) et sur « Se connecter » (signin.g1.pending sans redite). Réordonner : la ligne sous le pointeur lue dans la mise en page (offsetTop), pas là où animate:flip la montre — une poignée tirée sur plusieurs lignes ne revient plus en arrière ; le pointeur capturé par la liste. API : seedFeatured sur chaque version (seul changement sous crates/). C1, C3, C20, C27, C35, C38 suivent les mots

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Yvv
2026-11-03 22:28:41 +01:00
co-authored by Claude Opus 5.5
parent 9d478d668a
commit 8528a269fc
20 changed files with 434 additions and 88 deletions
+13 -8
View File
@@ -13,7 +13,10 @@ test('C1 — l’accueil sans session : la voûte abrite les trois points, le ti
await expect(nav.locator('.tool', { hasText: item })).toBeVisible();
}
await expect(nav.locator('.tool.off')).toHaveCount(3);
await expect(page.getByRole('link', { name: 'Se connecter avec sa clé Ğ1' })).toBeVisible();
// The Ğ1 sign-in not active (as in production): Yvv's word for whoever is not invited yet,
// in place of the button (lot U3, C41).
await expect(page.getByText("Pour rentrer dans un groupe de décisions, il faut pour l'instant demander un lien d'invitation à Chiara ou à Yvv.", { exact: false })).toBeVisible();
await expect(page.getByRole('link', { name: 'Se connecter avec sa clé Ğ1' })).toHaveCount(0);
// The four pillars live on the page of a group, no longer here.
await expect(page.locator('.pillars')).toHaveCount(0);
await expect(page.getByText('Monnaie libre', { exact: true })).toHaveCount(0);
@@ -37,17 +40,18 @@ test('C2 — l’accueil avec session : le choix du groupe, ceux de la même cl
await expect(page).toHaveURL((u) => u.pathname === '/');
});
test('C3 — au départ, aucun texte en vigueur : la raison d’être et les trois engagements, Propositions seed, ouvrent le texte', async ({ page }) => {
test('C3 — au départ, aucun texte en vigueur : la raison d’être et les trois engagements, Propositions d’amorce, ouvrent le texte', async ({ page }) => {
await signIn(page, 'Chiara');
await page.goto(DOC);
await expect(page.getByRole('heading', { level: 1 })).toHaveText("Acte d'engagement Certification");
// Nothing in force (Yvv, 2026-11-02): the page says where to begin, once — the seed proposals,
// read whole at the head of the text (lot U), each marked: never the bare page of a text in force.
await expect(page.getByText("Aucun article n'est encore en vigueur. Commence par les Propositions seed : elles y entrent par le vote, comme toute proposition.")).toBeVisible();
// Lot U3 (Yvv, 2026-11-03): said by « Info ouverture doc de réf. », in her words (C39).
await expect(page.getByRole('region', { name: 'Info ouverture doc de réf.' }).getByText("Aucun article n'est encore en vigueur. Les Propositions d'amorce y entrent par le vote")).toBeVisible();
const seeds = page.locator('section.text article.unit');
// Lot T4 (Yvv, 2026-11-03): « Responsabilité civique » between the two engagements.
await expect(seeds.locator('h2')).toHaveText(["Raison d'être", 'Unicité du compte', 'Responsabilité civique', 'Réciprocité']);
await expect(seeds.locator('.tag', { hasText: 'Proposition seed' })).toHaveCount(4);
await expect(seeds.locator('.tag', { hasText: "Proposition d'amorce" })).toHaveCount(4);
await expect(seeds.getByTitle("Texte de départ mis en avant pour lancer le vote. Il n'est pas en vigueur : il y entre par le vote, comme toute proposition.")).toHaveCount(4);
// At the low level they start at, how far each is from passing.
for (const seed of await seeds.all()) await expect(seed).toContainText('0 pour · 0 contre · 9 oui sur 12');
@@ -61,7 +65,7 @@ test('C3 — au départ, aucun texte en vigueur : la raison d’être et les tro
await unfold(page);
// One line per article: the 27 less the 4 at the head, E3 and E7 holding their two variants inside.
await expect(page.locator('ul.deep button.row')).toHaveCount(23);
await expect(page.locator('ul.deep .tag', { hasText: 'Proposition seed' })).toHaveCount(0);
await expect(page.locator('ul.deep .tag', { hasText: "Proposition d'amorce" })).toHaveCount(0);
});
test('C4 — les actions sont contextuelles, le vote se déplie sous l’article', async ({ page }) => {
@@ -331,8 +335,9 @@ test('C20 — réglages de la formule et cinq crans', async ({ page }) => {
// At 100 voters, above every quorum: each level's share of the 100.
const required = panel.locator('table tbody td.required');
await expect(required).toHaveText(['60', '67', '75', '83', '90']);
await expect(panel.getByText("Voix pour : à 100 votants, comme d'habitude.")).toBeVisible();
await expect(panel.getByText("Part exigée : la part de « pour » demandée, à 100 votants comme d'habitude.")).toBeVisible();
// Lot U3: the defined terms of lot T3c, never « comme d'habitude ».
await expect(panel.getByText("Voix pour : à 100 votants, la participation habituelle arrondie, ou au quorum s'il est plus haut.")).toBeVisible();
await expect(panel.getByText("Part exigée : celle que le cran demande au-delà du quorum de l'article, à la participation habituelle.")).toBeVisible();
await expect(panel.getByText(/^Quorum : en dessous, les votants qui manquent comptent comme « non »\./)).toBeVisible();
await page.keyboard.press('Escape');
@@ -349,7 +354,7 @@ test('C20 — réglages de la formule et cinq crans', async ({ page }) => {
// No vote: each level on its quorum, the voters missing counted as « non ».
await expect(quorums).toHaveText(['12', '12', '50', '50', '50']);
await expect(required).toHaveText(['8', '9', '39', '43', '46']);
await expect(panel.getByText('Voix pour : à 0 votant, la participation de cette version.')).toBeVisible();
await expect(panel.getByText("Voix pour : à 0 votant, la participation de cette version, ou au quorum s'il est plus haut.")).toBeVisible();
await page.keyboard.press('Escape');
// The five levels to choose from, in the test group (Réciprocité voted into force there,