114 lines
4.6 KiB
JavaScript
114 lines
4.6 KiB
JavaScript
// Page order is the one thing here that costs money to get wrong: a run of
|
|
// badge cards with the backs one card out looks perfect until someone reads
|
|
// one. These tests pin the order and the CSV contract.
|
|
|
|
import { describe, it, expect } from 'vitest'
|
|
|
|
import { parseCsv, splitCsvLine, buildPages, MAX_LABELS } from './labelPages'
|
|
|
|
const sides = pages => pages.map(page => page.side).join(' ')
|
|
const contents = pages => pages.map(page => page.content || '-').join(' ')
|
|
|
|
describe('splitCsvLine', () => {
|
|
it('keeps a comma that is inside quotes', () => {
|
|
expect(splitCsvLine('WJ-0001,"Bay 12, press",2')).toEqual(['WJ-0001', 'Bay 12, press', '2'])
|
|
})
|
|
|
|
it('unescapes a doubled quote', () => {
|
|
expect(splitCsvLine('x,"the ""big"" one"')).toEqual(['x', 'the "big" one'])
|
|
})
|
|
})
|
|
|
|
describe('parseCsv', () => {
|
|
it('reads a named header in any column order', () => {
|
|
const rows = parseCsv('copies,label,content\n3,Line 1,WJ-0001')
|
|
expect(rows).toEqual([
|
|
{ content: 'WJ-0001', label: 'Line 1', copies: 3, back: '', backlabel: '' },
|
|
])
|
|
})
|
|
|
|
it('falls back to positional columns with no header', () => {
|
|
const rows = parseCsv('WJ-0001,Line 1,2,WJ-0001-B,Reverse')
|
|
expect(rows[0]).toEqual({
|
|
content: 'WJ-0001', label: 'Line 1', copies: 2,
|
|
back: 'WJ-0001-B', backlabel: 'Reverse',
|
|
})
|
|
})
|
|
|
|
it('skips a row with no content rather than printing a blank sticker', () => {
|
|
expect(parseCsv('content,label\n,orphan\nWJ-0002,real')).toHaveLength(1)
|
|
})
|
|
|
|
it('defaults copies to 1 when it is missing or junk', () => {
|
|
expect(parseCsv('content,copies\nA,\nB,zero')[0].copies).toBe(1)
|
|
expect(parseCsv('content,copies\nA,\nB,zero')[1].copies).toBe(1)
|
|
})
|
|
})
|
|
|
|
describe('buildPages without a back side', () => {
|
|
it('expands copies and emits fronts only', () => {
|
|
const { pages, backs } = buildPages([{ content: 'A', label: 'a', copies: 3 }])
|
|
expect(sides(pages)).toBe('front front front')
|
|
expect(backs).toHaveLength(0)
|
|
})
|
|
|
|
it('caps cards, not pages, and says how many it dropped', () => {
|
|
const { fronts, dropped } = buildPages([{ content: 'A', copies: MAX_LABELS + 5 }])
|
|
expect(fronts).toHaveLength(MAX_LABELS)
|
|
expect(dropped).toBe(5)
|
|
})
|
|
})
|
|
|
|
describe('buildPages with a back side', () => {
|
|
const rows = [
|
|
{ content: 'A', label: 'a', copies: 2, back: 'A2', backlabel: 'a2' },
|
|
{ content: 'B', label: 'b', copies: 1, back: 'B2', backlabel: 'b2' },
|
|
]
|
|
|
|
it('interleaves front and back, which is what a duplex driver takes', () => {
|
|
const { pages } = buildPages(rows, { back: { enabled: true, source: 'column', order: 'interleave' } })
|
|
expect(sides(pages)).toBe('front back front back front back')
|
|
expect(contents(pages)).toBe('A A2 A A2 B B2')
|
|
})
|
|
|
|
it('groups every front then every back, for a flip-and-reload printer', () => {
|
|
const { pages } = buildPages(rows, { back: { enabled: true, source: 'column', order: 'grouped' } })
|
|
expect(sides(pages)).toBe('front front front back back back')
|
|
// Same card order in both halves, or the flipped stack pairs up wrong.
|
|
expect(contents(pages)).toBe('A A B A2 A2 B2')
|
|
})
|
|
|
|
it('still emits a back for a row that left the back column empty', () => {
|
|
const { pages } = buildPages(
|
|
[{ content: 'A', copies: 1 }, { content: 'B', copies: 1, back: 'B2' }],
|
|
{ back: { enabled: true, source: 'column', order: 'interleave' } })
|
|
// A page count that changes per row would shift every later back onto the
|
|
// wrong front.
|
|
expect(sides(pages)).toBe('front back front back')
|
|
expect(contents(pages)).toBe('A - B B2')
|
|
})
|
|
|
|
it('repeats the front payload when the back is the same code', () => {
|
|
const { backs } = buildPages(rows, { back: { enabled: true, source: 'code' } })
|
|
expect(contents(backs)).toBe('A A B')
|
|
})
|
|
|
|
it('puts the same fixed text on every back and no code', () => {
|
|
const { backs } = buildPages(rows, { back: { enabled: true, source: 'text', text: 'Property of GE' } })
|
|
expect(backs.every(page => page.content === '')).toBe(true)
|
|
expect(backs.every(page => page.label === 'Property of GE')).toBe(true)
|
|
})
|
|
|
|
it('leaves a blank back entirely empty but still counted', () => {
|
|
const { pages, backs } = buildPages(rows, { back: { enabled: true, source: 'blank' } })
|
|
expect(pages).toHaveLength(6)
|
|
expect(backs.every(page => !page.content && !page.label)).toBe(true)
|
|
})
|
|
|
|
it('falls back to the fixed text when a row has no back label', () => {
|
|
const { backs } = buildPages([{ content: 'A', copies: 1, back: 'A2' }],
|
|
{ back: { enabled: true, source: 'column', text: 'Return to IT' } })
|
|
expect(backs[0].label).toBe('Return to IT')
|
|
})
|
|
})
|