forked from yvv/decision
Une version retenue par une objection le dit sous l'article, à chacun selon son rôle : la personne qui vote voit qu'elle ne se vote plus (les votes faits restent) ; l'auteur, quoi faire (« Modifier l'article visé » pour une redite, « Reformuler » pour une contradiction) ; la personne qui objecte, lever ou réitérer avant l'échéance. Le panier la montre sans choix et ne l'envoie jamais. « Détails » : faire une objection (redit / contredit), les objections et où elles en sont, les coquilles proposées par d'autres avec leur diff resserré, valider / refuser / revenir, l'historique dit qui a validé. Une coquille se propose sur toute version ouverte ou en vigueur. Boîte « Messages » dans le menu, avec le nombre de non-lus (pastille sur le bouton du menu en mobile) : objet, texte, gestes, échéance ; un message traité n'a plus de geste. Répondre à une objection lit son message. Trilingue (fr, en, es). C6 suit la règle : la coquille d'un administrateur sur un texte du seed passe tout de suite ; C28–C31 couvrent le reste. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
38 lines
2.0 KiB
TypeScript
38 lines
2.0 KiB
TypeScript
import { describe, expect, it } from 'vitest';
|
||
import { answerPanel, holding } from '../../src/lib/objections';
|
||
import type { Objection, VersionRef } from '../../src/lib/types';
|
||
|
||
const ref = (id: string, over: Partial<VersionRef> = {}): VersionRef => ({
|
||
id, title: id, status: 'open', unitId: `u-${id}`, code: id.toUpperCase(), author: null, authorId: null, ...over,
|
||
});
|
||
|
||
function objection(over: Partial<Objection> = {}): Objection {
|
||
return {
|
||
id: 'o1', kind: 'redit', reason: 'Ces deux textes disent la même chose.', objector: 'Yvv', objectorInvited: false,
|
||
mine: false, at: '', phase: 'author', cycle: 1, dueAt: null, answer: null, answerId: null, answeredAt: null,
|
||
lift: null, liftedAt: null, heldVersion: ref('k1', { author: 'Chiara', authorId: 'dev:chiara' }),
|
||
other: ref('e2', { status: 'in_force' }), iAnswer: true, canLift: false, canReiterate: false, held: true, ...over,
|
||
};
|
||
}
|
||
|
||
describe('answering an objection', () => {
|
||
it('a repetition: a proposal linked to it, on the article repeated, from its text', () => {
|
||
expect(answerPanel(objection(), 'dev:chiara')).toEqual({ tab: 'propose', unitId: 'u-e2', proposalId: 'e2', objectionId: 'o1' });
|
||
});
|
||
|
||
it('a contradiction: one rewords one’s own version in place', () => {
|
||
expect(answerPanel(objection({ kind: 'contredit' }), 'dev:chiara')).toEqual({ tab: 'details', unitId: 'u-k1', proposalId: 'k1', edit: true });
|
||
});
|
||
|
||
it('a contradiction on a seeded version: a linked proposal on its article', () => {
|
||
const o = objection({ kind: 'contredit', heldVersion: ref('k1') });
|
||
expect(answerPanel(o, 'dev:chiara')).toEqual({ tab: 'propose', unitId: 'u-k1', proposalId: 'k1', objectionId: 'o1' });
|
||
});
|
||
|
||
it('nothing held back, nothing to answer; a lifted objection holds nothing', () => {
|
||
expect(answerPanel(objection({ heldVersion: null }), 'dev:chiara')).toBeNull();
|
||
const list = [objection(), objection({ id: 'o2', phase: 'lifted' }), objection({ id: 'o3', held: false })];
|
||
expect(holding(list).map((o) => o.id)).toEqual(['o1']);
|
||
});
|
||
});
|