// The share link has to survive a chat client, a recipient whose saved settings // differ from the sender's, and a version of the page older than the link. import { describe, it, expect } from 'vitest' import { buildFragment, readFragment, coerce } from './sharelink' const DEFAULTS = { codetype: 'qr', errorcorrection: 'M', preset: 'zebra1x05', labelwidth: 1.0, labelheight: 0.5, dpi: 203, layout: 'side', } function state (extra = {}) { return { source: 'single', content: 'WJ-3204', ...DEFAULTS, ...extra } } describe('buildFragment', () => { it('carries what was typed', () => { const params = new URLSearchParams(buildFragment(state(), DEFAULTS).slice(1)) expect(params.get('c')).toBe('WJ-3204') expect(params.get('s')).toBe('single') }) it('leaves out layout values the sender never changed', () => { const fragment = buildFragment(state(), DEFAULTS) expect(fragment).not.toContain('labelwidth') expect(fragment).not.toContain('dpi') }) it('carries a layout value the sender did change', () => { const fragment = buildFragment(state({ labelwidth: 2.0, dpi: 300 }), DEFAULTS) const params = new URLSearchParams(fragment.slice(1)) expect(params.get('labelwidth')).toBe('2') expect(params.get('dpi')).toBe('300') }) it('says nothing about one copy, which is what everybody has', () => { expect(buildFragment(state({ copies: 1 }), DEFAULTS)).not.toContain('n=') expect(buildFragment(state({ copies: 4 }), DEFAULTS)).toContain('n=4') }) it('is empty when there is nothing to share', () => { // So the caller can disable its button rather than emit a bare '#'. expect(buildFragment({}, DEFAULTS)).toBe('') }) it('never carries the picture', () => { // A data URL runs to megabytes; the link would not survive a chat box. const fragment = buildFragment(state({ pictureUrl: 'data:image/png;base64,AAAA' }), DEFAULTS) expect(fragment).not.toContain('data:image') expect(fragment).not.toContain('pictureUrl') }) }) describe('readFragment', () => { it('reads back what buildFragment wrote', () => { const sent = state({ content: 'Bay 310 / press 2', label: 'Press', copies: 3, labelwidth: 2.0, layout: 'stack' }) const back = readFragment(buildFragment(sent, DEFAULTS)) expect(back.content).toBe('Bay 310 / press 2') expect(back.label).toBe('Press') expect(back.copies).toBe('3') expect(back.labelwidth).toBe('2') expect(back.layout).toBe('stack') }) it('survives the characters people actually put in a label', () => { const awkward = 'CNC #4 & 5 - 50% duty, "spare"' const back = readFragment(buildFragment(state({ content: awkward }), DEFAULTS)) expect(back.content).toBe(awkward) }) it('ignores a key it does not know', () => { // A link made by a newer version must still open here, minus the parts // this version cannot use. const back = readFragment('#c=X&somethingnew=1') expect(back.content).toBe('X') expect(back.somethingnew).toBeUndefined() }) it('is empty for an empty or absent fragment', () => { expect(readFragment('')).toEqual({}) expect(readFragment('#')).toEqual({}) expect(readFragment(undefined)).toEqual({}) }) }) describe('coerce', () => { it('keeps a number a number', () => { // '0' + '2' is '02'; 0 + 2 is 2. The nudge fields are arithmetic. expect(coerce('2', 0)).toBe(2) expect(coerce('0.4286', 0.5)).toBeCloseTo(0.4286) }) it('falls back to the current value when the link is nonsense', () => { expect(coerce('not-a-number', 203)).toBe(203) }) it('reads a boolean back as a boolean', () => { expect(coerce('true', false)).toBe(true) expect(coerce('false', true)).toBe(false) }) it('leaves a string alone', () => { expect(coerce('stack', 'side')).toBe('stack') }) })