forked from yvv/decision
Lot U2 : les contrôles d'abord, vus rouges sur l'interface d'avant — cibles de 44 px sur téléphone et les trois lectures entières (M2), « Proposer cet ordre » dit pourquoi il est éteint (C35), une information à un seul endroit dans le vote déplié (onceonly, C19, C36), l'en-tête compte ce que montre la liste et un changement d'inertie d'un module se trouve à sa ligne (C38), settings.reading et l'anglais (lexicon)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -55,3 +55,25 @@ describe('anti-lexicon', () => {
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Lot U2 (reviews of M6c and M7): the same words for the same things.
|
||||
describe('the reading of the formula', () => {
|
||||
it('the settings say, like N1.1 and the formula, that the share falls beyond the quorum', () => {
|
||||
expect(fr['formula.reading']).toContain('Au-delà');
|
||||
expect(fr['settings.reading']).toContain('au-delà du quorum');
|
||||
expect(en['settings.reading']).toContain('beyond the quorum');
|
||||
expect(es['settings.reading']).toContain('más allá del quórum');
|
||||
});
|
||||
});
|
||||
|
||||
describe('English: one vocabulary', () => {
|
||||
it('« Pour » and « Contre » are for and against, never yes and no', () => {
|
||||
for (const [k, v] of Object.entries(en)) {
|
||||
expect(v, k).not.toMatch(/\byes\b/i);
|
||||
expect(v, k).not.toMatch(/“no”|\{no\} no\b/);
|
||||
}
|
||||
});
|
||||
it('one spelling, the one that dominates: favour', () => {
|
||||
for (const [k, v] of Object.entries(en)) expect(v, k).not.toMatch(/\bfavor\b/i);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
// Lot U2 (review of M7): in the vote unfolded, one piece of information in one place. Rendered as
|
||||
// the server would (svelte/server), and read as a person reads it: the tags left out, and what a
|
||||
// closed <details> holds left out too (only its summary shows).
|
||||
import { render } from 'svelte/server';
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import UnitBlock from '../../src/lib/components/UnitBlock.svelte';
|
||||
import VoteFold from '../../src/lib/components/VoteFold.svelte';
|
||||
import type { DocState } from '../../src/lib/doc.svelte';
|
||||
import type { Inertia, Proposal, Unit } from '../../src/lib/types';
|
||||
|
||||
function version(id: string, over: Partial<Proposal> = {}): Proposal {
|
||||
return {
|
||||
id,
|
||||
unitId: 'u1',
|
||||
kind: 'text',
|
||||
inertiaTarget: null,
|
||||
title: 'Connaissance suffisante',
|
||||
body: 'Je connais suffisamment la personne.',
|
||||
status: 'open',
|
||||
origin: 'seed',
|
||||
label: null,
|
||||
author: null,
|
||||
mine: false,
|
||||
revision: 1,
|
||||
createdAt: '2026-11-03T00:00:00Z',
|
||||
updatedAt: '2026-11-03T00:00:00Z',
|
||||
submittedAt: null,
|
||||
enteredAt: null,
|
||||
confirmedAt: null,
|
||||
seedMinimal: false,
|
||||
tally: { for: 0, against: 0 },
|
||||
tallyPending: { for: 0, against: 0 },
|
||||
tallySimulated: { for: 0, against: 0 },
|
||||
evaluation: { cast: 0, required: 9, reached: false, missing: 9, requiredRatio: 0.75, wellRated: false, quorum: 12, yesNeeded: 9, noNeeded: 0 },
|
||||
votedAtInertia: 2,
|
||||
blocked: false,
|
||||
votable: true,
|
||||
objections: 0,
|
||||
myVote: null,
|
||||
myVoteState: null,
|
||||
myVoteStale: false,
|
||||
myVoteChain: false,
|
||||
myBallot: null,
|
||||
translations: {},
|
||||
...over,
|
||||
};
|
||||
}
|
||||
|
||||
function unitOf(proposals: Proposal[], inertia: Inertia = 2): Unit {
|
||||
return { id: 'u1', code: 'E3', section: 'technique', position: 1, inertia, inertiaChanges: [], inForce: null, proposals };
|
||||
}
|
||||
|
||||
/** The text a person reads: no tags, no server markers, nothing inside a closed <details> but its summary. */
|
||||
function read(html: string): string {
|
||||
return html
|
||||
.replace(/<!--[\s\S]*?-->/g, '')
|
||||
.replace(/(<details(?![^>]*\sopen)[^>]*>[\s\S]*?<\/summary>)[\s\S]*?<\/details>/g, '$1')
|
||||
.replace(/<[^>]+>/g, ' ')
|
||||
.replace(/\s+/g, ' ');
|
||||
}
|
||||
|
||||
const noop = () => {};
|
||||
const doc = { view: null, original: false, articleTitle: () => '', unit: () => undefined } as unknown as DocState;
|
||||
|
||||
function fold(p: Proposal, unit: Unit, besides?: string[]): string {
|
||||
const { body } = render(VoteFold, {
|
||||
props: { doc, proposal: p, unit, besides, onopen: noop, onsettings: noop, ondetails: noop, onanswer: noop, onsign: noop },
|
||||
});
|
||||
return read(body);
|
||||
}
|
||||
|
||||
const count = (text: string, part: string) => text.split(part).length - 1;
|
||||
|
||||
describe('the vote unfolded says each thing once', () => {
|
||||
it('the inertia of the article, once (its notches with it)', () => {
|
||||
const p = version('p1');
|
||||
const text = fold(p, unitOf([p]));
|
||||
expect(count(text, '2 / 5 · basse'), text).toBe(1);
|
||||
});
|
||||
it('the inertia a change of inertia is voted at, once', () => {
|
||||
const p = version('p2', { kind: 'inertia', inertiaTarget: 4, title: 'inertia:4' });
|
||||
const text = fold(p, unitOf([p]));
|
||||
expect(count(text, '2 / 5 · basse'), text).toBe(1);
|
||||
});
|
||||
it('the other versions already listed beside the vote are not listed again', () => {
|
||||
const a = version('p1', { label: '1.0.0' });
|
||||
const b = version('p2', { label: '0.4.0-draft' });
|
||||
const unit = unitOf([a, b]);
|
||||
// Alone (in the text, say), it names its other version …
|
||||
expect(fold(a, unit)).toContain('Autres versions (1)');
|
||||
// … but in the list of the versions of its article, the other one is right there.
|
||||
expect(fold(a, unit, ['p1', 'p2'])).not.toContain('Autres versions');
|
||||
});
|
||||
it('an other version not in sight is still named (the text in force, above)', () => {
|
||||
const inForce = version('p0', { status: 'in_force', title: 'Connaissance suffisante' });
|
||||
const a = version('p1', { label: '1.0.0' });
|
||||
const b = version('p2', { label: '0.4.0-draft' });
|
||||
const unit = { ...unitOf([a, b]), inForce };
|
||||
expect(fold(a, unit, ['p1', 'p2'])).toContain('Autres versions (1)');
|
||||
});
|
||||
});
|
||||
|
||||
function block(seed: Proposal, voteOpen: boolean, rivals = 0): string {
|
||||
const { body } = render(UnitBlock, {
|
||||
props: {
|
||||
text: { title: seed.title, body: seed.body, translated: false, stale: false, missing: false },
|
||||
seed,
|
||||
rivals,
|
||||
voteFor: seed.id,
|
||||
voteOpen,
|
||||
onaction: noop,
|
||||
},
|
||||
});
|
||||
return read(body);
|
||||
}
|
||||
|
||||
describe('a seed proposal at the head, its vote unfolded', () => {
|
||||
const seed = version('p1', { seedProposal: true, title: "Raison d'être" });
|
||||
it('folded: its line says how far it is from passing', () => {
|
||||
const text = block(seed, false, 1);
|
||||
expect(text).toContain('0 pour · 0 contre · 9 oui sur 12');
|
||||
expect(text).toContain('1 autre version');
|
||||
});
|
||||
it('unfolded: the vote below says it, the line does not say it again', () => {
|
||||
const text = block(seed, true, 1);
|
||||
expect(text).not.toContain('0 pour · 0 contre');
|
||||
expect(text).not.toContain('9 oui sur 12');
|
||||
expect(text).not.toContain('basse');
|
||||
expect(text).not.toContain('autre version');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user