From 17addf8d9f7913c5080f7a4e02d1a9840f551498 Mon Sep 17 00:00:00 2001 From: Yvv Date: Tue, 3 Nov 2026 05:15:18 +0100 Subject: [PATCH] Lot S, phase 2 : le quorum dans l'interface (fr, en, es), e2e 35 / 35 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - types.ts : evaluation.quorum / yesNeeded / noNeeded, levels[].quorum, l'unité quorum / quorumDefault / canSetQuorum, doc.quorums (optionnels) ; publication « suspended » (ADR 0011) ; - Réglages de la formule : la colonne « Quorum » des cinq crans et sa note, la participation de référence « deux fois 50, le quorum de référence » ; plus de ligne C ; sur téléphone, les six colonnes tiennent dans la feuille ; - La formule du seuil : T' = max(T, Q), R = B^W + ratio(T')·T', la ligne Q (le quorum de la version) au lieu de C ; - textes : deep.note, formula.reading, settings.* parlent du quorum, plus de C (test vu rouge puis vert, tests/unit/inertia.test.ts) ; - e2e : Seuil 9 (cran 2) et 39 (cran 3) dans Monnaie libre, les quorums 12 · 12 · 50 · 50 · 50, voix pour à 100 votants 60 · 67 · 75 · 83 · 90, à 0 votant 8 · 9 · 39 · 43 · 46. Co-Authored-By: Claude Opus 5.5 --- web/e2e/mobile.spec.ts | 2 +- web/e2e/modules.spec.ts | 2 +- web/e2e/reader.spec.ts | 22 ++++++++++------- web/e2e/vote.spec.ts | 3 ++- web/src/lib/components/Formula.svelte | 14 +++++++---- web/src/lib/components/FormulaSettings.svelte | 24 +++++++++++++++---- web/src/lib/i18n/en.ts | 18 +++++++------- web/src/lib/i18n/es.ts | 18 +++++++------- web/src/lib/i18n/fr.ts | 18 +++++++------- web/src/lib/types.ts | 24 ++++++++++++++++--- web/tests/unit/inertia.test.ts | 14 +++++++++++ 11 files changed, 112 insertions(+), 47 deletions(-) diff --git a/web/e2e/mobile.spec.ts b/web/e2e/mobile.spec.ts index 5470d5d..0d914fd 100644 --- a/web/e2e/mobile.spec.ts +++ b/web/e2e/mobile.spec.ts @@ -83,7 +83,7 @@ test('M1 — mobile : logo dans la barre, l’accueil sous la voûte, menu en ti // in force at the start, its vote unfolds in the list of proposals). await page.locator('ul.deep button.row').first().click(); const fold = page.locator('ul.deep section.fold'); - await expect(fold.getByText('Seuil : 50 voix pour')).toBeVisible(); + await expect(fold.getByText('Seuil : 9 voix pour')).toBeVisible(); // The settings of the formula read on a phone: the table of the five levels holds in the sheet. await fold.getByRole('button', { name: 'Réglages de la formule' }).click(); const panel = page.locator('aside.panel'); diff --git a/web/e2e/modules.spec.ts b/web/e2e/modules.spec.ts index eb15fd6..cab972a 100644 --- a/web/e2e/modules.spec.ts +++ b/web/e2e/modules.spec.ts @@ -190,7 +190,7 @@ test('C27 — la participation ramenée dans ses bornes : la mesure, puis ce que await expect(panel.getByText(/^3 votants sur 4 \(62,5\s%\) : la médiane des 12 propositions votées depuis un an\.$/)).toBeVisible(); // Then what the group asks, the group as subject. await expect(panel.getByText(/^Ramenée entre 5\s% et 50\s% de l'électorat : le groupe demande ses voix pour comme si 2 personnes votaient \(50\s%\)\.$/)).toBeVisible(); - await expect(panel.getByText("Part exigée : les « pour » demandés au-delà de C, à 2 votants comme d'habitude.")).toBeVisible(); + await expect(panel.getByText("Part exigée : la part de « pour » demandée, à 2 votants comme d'habitude.")).toBeVisible(); await shot(page, 'c27-participation-bornee'); }); diff --git a/web/e2e/reader.spec.ts b/web/e2e/reader.spec.ts index 55ec01a..7f0d737 100644 --- a/web/e2e/reader.spec.ts +++ b/web/e2e/reader.spec.ts @@ -283,7 +283,8 @@ test('C19 — un article, une ligne : ses versions se déplient', async ({ page // A version unfolds its vote below it, as any proposal. await versions.nth(1).click(); await expect(versions.nth(1)).toHaveAttribute('aria-expanded', 'true'); - await expect(page.locator('section.fold').getByText('Seuil : 50 voix pour')).toBeVisible(); + // Level 3, the quorum 50 (ADR 0013): 39 « pour » at no vote, the voters missing counted as « non ». + await expect(page.locator('section.fold').getByText('Seuil : 39 voix pour')).toBeVisible(); await expect(page).toHaveURL(/vote=/); await e3.click(); await expect(e3).toHaveAttribute('aria-expanded', 'false'); @@ -299,19 +300,22 @@ test('C20 — réglages de la formule et cinq crans', async ({ page }) => { const panel = page.locator('aside.panel'); await expect(panel.getByRole('heading', { name: 'Réglages de la formule' })).toBeVisible(); await expect(panel.getByText(/W — électorat : 5\s745/)).toBeVisible(); - await expect(panel.getByText('C — minimum de voix pour : 50')).toBeVisible(); - // No vote yet: the reference, twice C. - await expect(panel.getByText(/100 votants sur 5\s745 \(1,74 %\), deux fois C : la participation de référence/)).toBeVisible(); + // No vote yet: the reference, twice the reference quorum (ADR 0013). + await expect(panel.getByText(/100 votants sur 5\s745 \(1,74 %\), deux fois 50, le quorum de référence : la participation de référence/)).toBeVisible(); const rows = panel.locator('table tbody tr'); await expect(rows).toHaveCount(5); await expect(rows.locator('th')).toHaveText([/1\s*très basse/, /2\s*basse/, /3\s*moyenne/, /4\s*haute/, /5\s*très haute/]); await expect(rows.locator('td:nth-child(2)')).toHaveText(['50 %', '50 %', '55 %', '60 %', '66 %']); await expect(rows.locator('td:nth-child(4)')).toHaveText(['60 %', '67 %', '75 %', '83 %', '90 %']); - // At 100 voters: C plus each level's share of the 50 votes beyond C. + // The quorum of each level (Yvv: « 12 · 12 · 50 · 50 · 50 »). + const quorums = rows.locator('td:nth-child(5)'); + await expect(quorums).toHaveText(['12', '12', '50', '50', '50']); + // 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(['80', '84', '88', '92', '95']); + 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 : les « pour » demandés au-delà de C, à 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(); + await expect(panel.getByText(/^Quorum : en dessous, les votants qui manquent comptent comme « non »\./)).toBeVisible(); await page.keyboard.press('Escape'); // From the vote of an article: Unicité du compte, a seed proposal, is at 2 / 5, its row is marked. @@ -322,7 +326,9 @@ test('C20 — réglages de la formule et cinq crans', async ({ page }) => { await expect(panel.locator('tr.current')).toHaveCount(1); await expect(panel.locator('tr.current th')).toContainText('2'); await expect(panel.locator('tr.current th')).toContainText('cet article'); - await expect(required).toHaveText(['50', '50', '50', '50', '50']); + // 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 page.keyboard.press('Escape'); diff --git a/web/e2e/vote.spec.ts b/web/e2e/vote.spec.ts index db7c70b..5b66089 100644 --- a/web/e2e/vote.spec.ts +++ b/web/e2e/vote.spec.ts @@ -195,7 +195,8 @@ test('C24 — sans compte de vote, le vote par la chaîne est fermé et le dit ; await expect(fold.getByText("Le vote par la chaîne Ğ1 n'est pas encore ouvert : le compte qui reçoit les votes reste à créer.", { exact: false })).toBeVisible(); await expect(fold.getByRole('button', { name: 'Pour', exact: true })).toHaveCount(0); // The totals and the threshold stay in sight. - await expect(fold.getByText('Seuil : 50 voix pour')).toBeVisible(); + // Raison d'être, level 2, the quorum 12 (ADR 0013). + await expect(fold.getByText('Seuil : 9 voix pour')).toBeVisible(); await fold.getByText('Ton vote ne se montre à personne', { exact: false }).scrollIntoViewIfNeeded(); await shot(page, '6-vote-ferme'); // The basket, opened by its address, says the vote is closed — never « Tes votes comptent dès l'envoi ». diff --git a/web/src/lib/components/Formula.svelte b/web/src/lib/components/Formula.svelte index 321d5b0..0e51fdc 100644 --- a/web/src/lib/components/Formula.svelte +++ b/web/src/lib/components/Formula.svelte @@ -33,12 +33,18 @@
{t('formula.title')}

{t('formula.intro')}

+ - R=C+BW+ + T′=max(T,Q) + + + + + R=BW+ (M+(1−M)(1− - (TW)G)) - ·max(0,T−C) + (T′W)G)) + ·T′
    @@ -49,7 +55,7 @@
  • {t('formula.G', { n: i18n.number(Math.round(p.gradient * 1000) / 1000) })}
  • {/if}
  • {t('formula.B', { n: i18n.number(base) })}
  • -
  • {t('formula.C', { n: i18n.number(floor) })}
  • +
  • {t('formula.Q', { n: i18n.number(evaluation?.quorum ?? p?.quorum ?? floor) })}
  • {#if evaluation}
  • {t('formula.R', { n: evaluation.required })}
  • {/if}

{t('formula.reading')}

diff --git a/web/src/lib/components/FormulaSettings.svelte b/web/src/lib/components/FormulaSettings.svelte index ddcd9bc..dce07a8 100644 --- a/web/src/lib/components/FormulaSettings.svelte +++ b/web/src/lib/components/FormulaSettings.svelte @@ -1,8 +1,9 @@