ajout de l'export des votes dans un fichier ODS avec toutes les données (anonymisées par défaut - réglable dans les paramètres)

This commit is contained in:
Yannick Le Duc
2025-08-27 18:38:20 +02:00
parent c94c8038f3
commit b7ce1145e3
10 changed files with 979 additions and 23 deletions

View File

@@ -0,0 +1,164 @@
import { generateVoteExportODS, formatFilename, anonymizeParticipantName, ExportData, AnonymizationLevel } from '@/lib/export-utils';
// Mock data pour les tests
const mockExportData: ExportData = {
campaignTitle: 'Test Campaign',
propositions: [
{ id: 'prop1', title: 'Proposition 1', description: 'Description 1', campaign_id: 'camp1', author_first_name: 'John', author_last_name: 'Doe', author_email: 'john@example.com', created_at: '2024-01-01' },
{ id: 'prop2', title: 'Proposition 2', description: 'Description 2', campaign_id: 'camp1', author_first_name: 'Jane', author_last_name: 'Smith', author_email: 'jane@example.com', created_at: '2024-01-02' }
],
participants: [
{ id: 'part1', first_name: 'Alice', last_name: 'Johnson', email: 'alice@example.com', campaign_id: 'camp1', short_id: 'abc123', created_at: '2024-01-01' },
{ id: 'part2', first_name: 'Bob', last_name: 'Brown', email: 'bob@example.com', campaign_id: 'camp1', short_id: 'def456', created_at: '2024-01-02' }
],
votes: [
{ id: 'vote1', participant_id: 'part1', proposition_id: 'prop1', amount: 50, created_at: '2024-01-01', updated_at: '2024-01-01' },
{ id: 'vote2', participant_id: 'part1', proposition_id: 'prop2', amount: 30, created_at: '2024-01-01', updated_at: '2024-01-01' },
{ id: 'vote3', participant_id: 'part2', proposition_id: 'prop1', amount: 40, created_at: '2024-01-02', updated_at: '2024-01-02' }
],
budgetPerUser: 100,
propositionStats: [
{
proposition: { id: 'prop1', title: 'Proposition 1', description: 'Description 1', campaign_id: 'camp1', author_first_name: 'John', author_last_name: 'Doe', author_email: 'john@example.com', created_at: '2024-01-01' },
voteCount: 2,
averageAmount: 45,
minAmount: 40,
maxAmount: 50,
totalAmount: 90,
participationRate: 100,
voteDistribution: 2,
consensusScore: 5
},
{
proposition: { id: 'prop2', title: 'Proposition 2', description: 'Description 2', campaign_id: 'camp1', author_first_name: 'Jane', author_last_name: 'Smith', author_email: 'jane@example.com', created_at: '2024-01-02' },
voteCount: 1,
averageAmount: 30,
minAmount: 30,
maxAmount: 30,
totalAmount: 30,
participationRate: 50,
voteDistribution: 1,
consensusScore: 0
}
]
};
describe('Export Utils', () => {
describe('generateVoteExportODS', () => {
it('should generate ODS data with correct structure', () => {
const odsData = generateVoteExportODS(mockExportData);
expect(odsData).toBeInstanceOf(Uint8Array);
expect(odsData.length).toBeGreaterThan(0);
});
it('should include campaign title in the export', () => {
const odsData = generateVoteExportODS(mockExportData);
// Vérifier que les données sont générées
expect(odsData).toBeInstanceOf(Uint8Array);
expect(odsData.length).toBeGreaterThan(0);
});
it('should handle empty votes', () => {
const dataWithNoVotes: ExportData = {
...mockExportData,
votes: []
};
const odsData = generateVoteExportODS(dataWithNoVotes);
expect(odsData).toBeInstanceOf(Uint8Array);
expect(odsData.length).toBeGreaterThan(0);
});
it('should handle empty participants', () => {
const dataWithNoParticipants: ExportData = {
...mockExportData,
participants: []
};
const odsData = generateVoteExportODS(dataWithNoParticipants);
expect(odsData).toBeInstanceOf(Uint8Array);
expect(odsData.length).toBeGreaterThan(0);
});
it('should generate additional tabs when propositionStats are provided', () => {
const odsData = generateVoteExportODS(mockExportData);
expect(odsData).toBeInstanceOf(Uint8Array);
expect(odsData.length).toBeGreaterThan(0);
});
it('should handle anonymization levels', () => {
const odsData = generateVoteExportODS({
...mockExportData,
anonymizationLevel: 'initials'
});
expect(odsData).toBeInstanceOf(Uint8Array);
expect(odsData.length).toBeGreaterThan(0);
});
it('should include campaign title in sort tab headers', () => {
const odsData = generateVoteExportODS(mockExportData);
expect(odsData).toBeInstanceOf(Uint8Array);
expect(odsData.length).toBeGreaterThan(0);
// Vérifier que le titre de la campagne est inclus dans les en-têtes des onglets de tri
// Note: Cette vérification est basée sur la structure attendue du fichier ODS
});
});
describe('anonymizeParticipantName', () => {
const mockParticipant = {
id: 'test',
first_name: 'John',
last_name: 'Doe',
email: 'john@example.com',
campaign_id: 'camp1',
short_id: 'abc123',
created_at: '2024-01-01'
};
it('should anonymize fully', () => {
const result = anonymizeParticipantName(mockParticipant, 'full');
expect(result).toBe('XXXX');
});
it('should show initials', () => {
const result = anonymizeParticipantName(mockParticipant, 'initials');
expect(result).toBe('J.D.');
});
it('should show full name', () => {
const result = anonymizeParticipantName(mockParticipant, 'none');
expect(result).toBe('John Doe');
});
it('should default to full anonymization', () => {
const result = anonymizeParticipantName(mockParticipant, 'invalid' as AnonymizationLevel);
expect(result).toBe('XXXX');
});
});
describe('formatFilename', () => {
it('should format filename correctly', () => {
const filename = formatFilename('Test Campaign 2024!');
expect(filename).toMatch(/^statistiques_vote_test_campaign_2024_\d{4}-\d{2}-\d{2}\.ods$/);
});
it('should handle special characters', () => {
const filename = formatFilename('Campagne avec des caractères spéciaux @#$%');
expect(filename).toMatch(/^statistiques_vote_campagne_avec_des_caractres_spciaux_\d{4}-\d{2}-\d{2}\.ods$/);
expect(filename).toContain('2025-08-27');
expect(filename).not.toContain('__'); // Pas d'underscores doubles
});
it('should handle empty title', () => {
const filename = formatFilename('');
expect(filename).toMatch(/^statistiques_vote_\d{4}-\d{2}-\d{2}\.ods$/);
expect(filename).toContain('2025-08-27');
});
});
});