v3 : inertie à cinq crans — interface (L10)

L'inertie se lit en crans, « 3 / 5 · moyenne » (très basse, basse,
moyenne, haute, très haute ; fr, en, es). Le sélecteur offre les cinq
crans, l'actuel marqué ; le changement se vote au cran de l'article.
L'article dit le passé de son inertie (vote ou réglage de départ).

« Réglages de la formule », en lecture seule, depuis l'en-tête du doc et
depuis le vote d'un article (onglet « Réglages » du panneau, dans
l'URL) : W et sa source, C, B, la participation habituelle (médiane ou
référence, sur combien de propositions, quand), et les cinq crans : M,
G, part exigée, voix pour exigées à la participation de la version
regardée (ou habituelle depuis l'en-tête).

Composants à part (InertiaPicker, FormulaSettings), branchés par
quelques lignes dans VoteView. La formule dépliée ne fait plus déborder
le panneau. e2e : C4 (cran de l'article dans la formule), C20 (réglages
et cinq crans), M1 (réglages lisibles sur mobile).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Yvv
2026-10-30 16:42:11 +01:00
co-authored by Claude Opus 5.5
parent d762301706
commit db64405e1e
17 changed files with 671 additions and 109 deletions
+57
View File
@@ -60,6 +60,9 @@ test('C4 — les actions sont contextuelles, le vote s’ouvre en panneau', asyn
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 level of the article sets M and G: the Raison d'être is at 3 / 5.
await expect(panel.getByText('M — majorité à pleine participation : 55 % — inertie 3 / 5 · moyenne')).toBeVisible();
await expect(panel.getByRole('button', { name: 'Réglages de la formule' })).toBeVisible();
// The panel lives in the URL.
await expect(page).toHaveURL(/onglet=vote/);
await page.keyboard.press('Escape');
@@ -242,3 +245,57 @@ test('C19 — un article, une ligne : ses versions se déplient', async ({ page
await expect(e3).toHaveAttribute('aria-expanded', 'false');
await expect(versions).toHaveCount(0);
});
test('C20 — réglages de la formule et cinq crans', async ({ page }) => {
await signIn(page, 'Chiara');
await page.goto(DOC);
// From the head of the document: the scale of the group, at its usual turnout.
await page.getByRole('button', { name: 'Réglages de la formule' }).click();
await expect(page).toHaveURL(/onglet=reglages/);
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();
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.
const required = panel.locator('table tbody td.required');
await expect(required).toHaveText(['80', '84', '88', '92', '95']);
await expect(panel.getByText('celles exigées à la participation habituelle, 100 votants')).toBeVisible();
await page.keyboard.press('Escape');
// From the vote of an article: Unicité du compte is at 4 / 5, its row is marked.
const e1 = page.locator('section.text article.unit', { hasText: 'Unicité du compte' });
await e1.hover();
await e1.getByRole('button', { name: 'Le vote' }).click();
await expect(panel.getByRole('heading', { name: 'Inertie · 4 / 5 · haute' })).toBeVisible();
await panel.getByRole('button', { name: 'Réglages de la formule' }).click();
await expect(panel.locator('tr.current')).toHaveCount(1);
await expect(panel.locator('tr.current th')).toContainText('4');
await expect(panel.locator('tr.current th')).toContainText('cet article');
await expect(required).toHaveText(['50', '50', '50', '50', '50']);
await expect(panel.getByText('celles exigées à la participation de cette version, 0 votant.')).toBeVisible();
await page.keyboard.press('Escape');
// The five levels to choose from, in the test group; the change is voted at the article's level.
await page.goto(TEST_DOC);
const e2 = page.locator('section.text article.unit', { hasText: 'Réciprocité' });
await e2.hover();
await e2.getByRole('button', { name: 'Le vote' }).click();
await panel.getByText("Proposer un changement d'inertie").click();
const levels = panel.getByRole('radiogroup', { name: 'Nouvelle inertie' }).getByRole('radio');
await expect(levels).toHaveCount(5);
await expect(levels.nth(3)).toBeDisabled();
await expect(levels.nth(3)).toContainText('actuelle');
await expect(panel.getByText("Un changement d'inertie se vote lui-même à l'inertie de l'article : 4 / 5 · haute.")).toBeVisible();
await levels.nth(4).click();
await expect(levels.nth(4)).toHaveAttribute('aria-checked', 'true');
await panel.getByRole('button', { name: 'Soumettre au vote' }).click();
await expect(panel.getByRole('heading', { name: 'inertie vers 5 / 5 · très haute' })).toBeVisible();
await expect(panel.getByText('inertie 4 / 5 · haute', { exact: true })).toBeVisible();
});