beacon / frontend /src /lib /citations.test.js
kiyer's picture
feat: in-text citations — visual styling, per-unit splitting, ADS search fallback
6ac1f78
Raw
History Blame Contribute Delete
2.37 kB
import { describe, it, expect } from 'vitest';
import { splitCitations } from './citations';
const REFS = [
{ id: 'r1', short: 'Carnall 2018', year: 2018, corpusMatch: true },
{ id: 'r2', short: 'Behroozi 2019', year: 2019, corpusMatch: false },
{ id: 'r3', short: 'Stark 2016', year: 2016, corpusMatch: true },
];
const IDX = {
'carnall:2018': ['r1'],
'behroozi:2019': ['r2'],
'stark:2016': ['r3'],
};
describe('splitCitations', () => {
it('narrative cite: Carnall et al. (2018)', () => {
const segs = splitCitations('From Carnall et al. (2018) we know this.', IDX, REFS);
const cite = segs.find((s) => s.t === 'cite');
expect(cite).toBeTruthy();
expect(cite.refs[0].id).toBe('r1');
expect(cite.refs[0].corpusMatch).toBe(true);
});
it('parenthetical multi-cite: each unit is its own cite segment', () => {
const segs = splitCitations('Results (Behroozi et al. 2019; Stark 2016) agree.', IDX, REFS);
const cites = segs.filter((s) => s.t === 'cite');
// Two separate cite segments, not one combined
expect(cites).toHaveLength(2);
expect(cites[0].refs[0].id).toBe('r2');
expect(cites[1].refs[0].id).toBe('r3');
// Surrounding punctuation preserved as text
const texts = segs.filter((s) => s.t === 'text').map((s) => s.s);
expect(texts.some((s) => s.includes('('))).toBe(true);
expect(texts.some((s) => s.includes(')'))).toBe(true);
expect(texts.some((s) => s.includes(';'))).toBe(true);
});
it('unmatched cite gets a cite span with empty refs (for visual styling)', () => {
const segs = splitCitations('See Hubble (1929) for early evidence.', IDX, REFS);
const cite = segs.find((s) => s.t === 'cite');
expect(cite).toBeTruthy();
expect(cite.s).toContain('Hubble');
expect(cite.refs).toHaveLength(0);
});
it('no citations → single text segment', () => {
const segs = splitCitations('No references here at all.', IDX, REFS);
expect(segs).toHaveLength(1);
expect(segs[0].t).toBe('text');
});
it('surname & Other (year) narrative form', () => {
const segs = splitCitations('Carnall & McLure (2018) showed this.', IDX, REFS);
const cite = segs.find((s) => s.t === 'cite');
expect(cite?.refs[0].id).toBe('r1');
});
it('empty string returns empty array', () => {
expect(splitCitations('', IDX, REFS)).toEqual([]);
});
});