Full document, spreadsheet, slideshow, and diagram tooling
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at main 90 lines 2.7 kB view raw
1/** 2 * Tests for form response export (CSV generation). 3 */ 4import { describe, it, expect } from 'vitest'; 5import { 6 createPipelineConfig, 7 pipelineHeaders, 8 responseToRow, 9 type FormResponse, 10} from '../src/forms/responses.js'; 11import { escapeField } from '../src/sheets/csv-export.js'; 12 13function makeResponse(answers: Record<string, unknown>, submittedAt = Date.now()): FormResponse { 14 return { 15 id: `resp-${submittedAt}`, 16 formId: 'form-1', 17 answers: new Map(Object.entries(answers)), 18 submittedAt, 19 submitterId: '', 20 }; 21} 22 23describe('response export pipeline', () => { 24 const config = createPipelineConfig( 25 'form-1', 26 '', 27 ['q1', 'q2', 'q3'], 28 ['Name', 'Email', 'Rating'], 29 ); 30 31 it('generates correct headers including timestamp', () => { 32 const headers = pipelineHeaders(config); 33 expect(headers).toEqual(['Name', 'Email', 'Rating', 'Submitted At']); 34 }); 35 36 it('generates headers without timestamp when disabled', () => { 37 const noTs = createPipelineConfig('f', '', ['q1'], ['Name'], false); 38 expect(pipelineHeaders(noTs)).toEqual(['Name']); 39 }); 40 41 it('converts response to row array', () => { 42 const resp = makeResponse({ q1: 'Alice', q2: 'alice@example.com', q3: 5 }, 1700000000000); 43 const row = responseToRow(resp, config); 44 expect(row[0]).toBe('Alice'); 45 expect(row[1]).toBe('alice@example.com'); 46 expect(row[2]).toBe(5); 47 expect(row[3]).toBe(new Date(1700000000000).toISOString()); 48 }); 49 50 it('handles missing answers as empty string', () => { 51 const resp = makeResponse({ q1: 'Bob' }); 52 const row = responseToRow(resp, config); 53 expect(row[0]).toBe('Bob'); 54 expect(row[1]).toBe(''); 55 expect(row[2]).toBe(''); 56 }); 57 58 it('handles array answers (multiple choice)', () => { 59 const resp = makeResponse({ q1: ['opt-a', 'opt-b'] }); 60 const row = responseToRow(resp, config); 61 expect(row[0]).toEqual(['opt-a', 'opt-b']); 62 }); 63}); 64 65describe('CSV escaping', () => { 66 it('escapes fields with commas', () => { 67 expect(escapeField('hello, world', ',')).toBe('"hello, world"'); 68 }); 69 70 it('escapes fields with double quotes', () => { 71 expect(escapeField('say "hi"', ',')).toBe('"say ""hi"""'); 72 }); 73 74 it('escapes fields with newlines', () => { 75 expect(escapeField('line1\nline2', ',')).toBe('"line1\nline2"'); 76 }); 77 78 it('returns empty string as empty', () => { 79 expect(escapeField('', ',')).toBe(''); 80 }); 81 82 it('does not escape plain values', () => { 83 expect(escapeField('hello', ',')).toBe('hello'); 84 }); 85 86 it('uses tab delimiter correctly', () => { 87 expect(escapeField('hello\tworld', '\t')).toBe('"hello\tworld"'); 88 expect(escapeField('hello, world', '\t')).toBe('hello, world'); 89 }); 90});