// 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
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 { 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
but its summary. */ function read(html: string): string { return html .replace(//g, '') .replace(/(]*\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'); }); });