forked from yvv/decision
Lot U3 : les tests d'abord, rouges sur 590ccd7 — e2e C39 à C43 (5 / 5 rouges : le chapitre « Info ouverture doc de réf. » absent, « Proposition seed », le mot pour qui n'est pas invité absent, une poignée tirée sur trois lignes s'arrête en place 2, les informations de fonctionnement absentes) ; vitest opening.test.ts (lib/opening absent) et rules.test.ts (25 rouges : les mots d'Yvv, « Proposition d'amorce », le terme défini « participation habituelle », chaque phrase de règle épinglée avec le test qui la prouve) ; Rust the_view_keeps_which_versions_the_seed_put_forward_once_they_enter_into_force (seedFeatured absent de la vue)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,130 @@
|
||||
// Lot U3 — « Info ouverture doc de réf. » (Yvv, 2026-11-03: « un petit chapitre qui explicite les
|
||||
// réglages initiaux de l'auteur, notamment Quorum et Inertie »): what the chapter says is read in
|
||||
// the data of the document, never written in. The level a module opened at is the one before any
|
||||
// change voted (a change of the seed's settings, an amendment, is the author's); a Proposition
|
||||
// d'amorce stays one once it has entered into force (`seedFeatured`).
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { isAmorce, openedAt, openingLevels, quorumsOf } from '../../src/lib/opening';
|
||||
import type { DocView, Inertia, InertiaChange, Proposal, Unit } from '../../src/lib/types';
|
||||
|
||||
function version(over: Partial<Proposal> = {}): Proposal {
|
||||
return {
|
||||
id: 'p',
|
||||
unitId: 'u',
|
||||
kind: 'text',
|
||||
inertiaTarget: null,
|
||||
title: 'Un article',
|
||||
body: '',
|
||||
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,
|
||||
seedProposal: false,
|
||||
seedFeatured: false,
|
||||
tally: { for: 0, against: 0 },
|
||||
tallyPending: { for: 0, against: 0 },
|
||||
tallySimulated: { for: 0, against: 0 },
|
||||
evaluation: null,
|
||||
votedAtInertia: 3,
|
||||
blocked: false,
|
||||
votable: true,
|
||||
objections: 0,
|
||||
myVote: null,
|
||||
myVoteState: null,
|
||||
myVoteStale: false,
|
||||
myVoteChain: false,
|
||||
myBallot: null,
|
||||
translations: {},
|
||||
...over,
|
||||
};
|
||||
}
|
||||
|
||||
let n = 0;
|
||||
function unit(inertia: Inertia, over: Partial<Unit> = {}, versions: Partial<Proposal>[] = [{}]): Unit {
|
||||
n += 1;
|
||||
return {
|
||||
id: `u${n}`,
|
||||
code: `X${n}`,
|
||||
section: 'technique',
|
||||
position: n,
|
||||
inertia,
|
||||
inertiaChanges: [],
|
||||
inForce: null,
|
||||
proposals: versions.map((v) => version({ id: `p${n}`, ...v })),
|
||||
...over,
|
||||
};
|
||||
}
|
||||
|
||||
const change = (from: Inertia, to: Inertia, cause: InertiaChange['cause']): InertiaChange => ({ from, to, cause, at: '2026-11-03T00:00:00Z' });
|
||||
|
||||
describe('the level a module opened at', () => {
|
||||
it('is its level when nothing changed it', () => {
|
||||
expect(openedAt(unit(3))).toBe(3);
|
||||
});
|
||||
it('is the author’s: a change of the seed’s settings (an amendment) is part of the opening', () => {
|
||||
expect(openedAt(unit(2, { inertiaChanges: [change(3, 2, 'amendment')] }))).toBe(2);
|
||||
});
|
||||
it('is the one before the first change voted, whatever came after', () => {
|
||||
expect(openedAt(unit(4, { inertiaChanges: [change(2, 4, 'vote')] }))).toBe(2);
|
||||
expect(openedAt(unit(5, { inertiaChanges: [change(3, 2, 'amendment'), change(2, 4, 'vote'), change(4, 5, 'vote')] }))).toBe(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('a Proposition d’amorce', () => {
|
||||
it('is the article the seed put forward, open or in force since', () => {
|
||||
expect(isAmorce(unit(2, {}, [{ seedProposal: true, seedFeatured: true }]))).toBe(true);
|
||||
expect(isAmorce(unit(2, { inForce: version({ status: 'in_force', seedFeatured: true, enteredAt: '2026-11-03T00:00:00Z' }) }, []))).toBe(true);
|
||||
expect(isAmorce(unit(3))).toBe(false);
|
||||
});
|
||||
it('a server that does not say it yet makes no article an amorce', () => {
|
||||
const old = version();
|
||||
delete (old as Partial<Proposal>).seedFeatured;
|
||||
expect(isAmorce(unit(3, { proposals: [old] }))).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('the levels at the opening, by kind of module', () => {
|
||||
function view(units: Unit[], title: Unit | null, orders: Unit[]): Pick<DocView, 'units' | 'modules'> {
|
||||
return { units, modules: { title, orders } };
|
||||
}
|
||||
it('the amorces, the title, the order of each section, the other articles of the seed', () => {
|
||||
const v = view(
|
||||
[
|
||||
unit(2, {}, [{ seedProposal: true, seedFeatured: true }]),
|
||||
unit(3, { inertiaChanges: [change(2, 3, 'vote')], inForce: version({ status: 'in_force', seedFeatured: true }) }, []),
|
||||
unit(3),
|
||||
unit(4, { inertiaChanges: [change(3, 4, 'vote')] }),
|
||||
// A member's article is not a setting of the author.
|
||||
unit(5, {}, [{ origin: 'member' }]),
|
||||
],
|
||||
unit(4, { kind: 'title' }),
|
||||
[unit(2, { kind: 'order', section: 'introduction' }), unit(3, { kind: 'order', section: 'technique', inertiaChanges: [change(2, 3, 'vote')] })],
|
||||
);
|
||||
expect(openingLevels(v)).toEqual({ amorce: [2], title: [4], orders: [2], others: [3] });
|
||||
});
|
||||
it('several levels in one kind are all said, lowest first; a kind that is absent says none', () => {
|
||||
const v = view([unit(4), unit(3), unit(4)], null, []);
|
||||
expect(openingLevels(v)).toEqual({ amorce: [], title: [], orders: [], others: [3, 4] });
|
||||
});
|
||||
});
|
||||
|
||||
describe('the quorum of each level', () => {
|
||||
it('said once when every level has the same', () => {
|
||||
expect(quorumsOf([1, 1, 1, 1, 1])).toEqual({ same: 1, list: [1, 1, 1, 1, 1] });
|
||||
});
|
||||
it('listed from level 1 to level 5 otherwise', () => {
|
||||
expect(quorumsOf([12, 12, 50, 50, 50])).toEqual({ same: null, list: [12, 12, 50, 50, 50] });
|
||||
});
|
||||
it('nothing when the server does not say them', () => {
|
||||
expect(quorumsOf(undefined)).toBeNull();
|
||||
expect(quorumsOf([])).toBeNull();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user