fuzzyworld

when-am-i / files / src / data / index.test.ts

index.test.ts

3.2 KB · history · blame

1import { describe, it, expect } from 'vitest';
2import { regions } from './index';
3import { convert } from '../utils/calendars';
4import { parseGregorianDate } from '../utils/julianDay';
5
6// Smoke test: the data loader must validate and expose the calendar files.
7// As more regions are added this also acts as a basic data sanity check.
8describe('calendar data loader', () => {
9 it('loads at least one region', () => {
10 expect(regions.length).toBeGreaterThan(0);
11 });
12
13 it('loads the Massachusett region with named eras and Polygon geometry', () => {
14 const massachusett = regions.find((r) => r.region.name === 'Massachusett homeland');
15 expect(massachusett).toBeDefined();
16 expect(massachusett!.region.geo.type).toBe('Polygon');
17 expect(massachusett!.sourceFile).toBe('src/data/calendars/massachusett.json');
18 expect(massachusett!.eras.length).toBeGreaterThan(0);
19 for (const era of massachusett!.eras) {
20 expect(era.name).toBeTruthy();
21 expect(era.calendar).toBeTruthy();
22 }
23 });
24
25 it('every era has string|null start/end and a calendar', () => {
26 for (const { eras } of regions) {
27 for (const era of eras) {
28 expect(['string', 'object']).toContain(typeof era.start); // string or null
29 expect(['string', 'object']).toContain(typeof era.end);
30 expect(typeof era.calendar).toBe('string');
31 }
32 }
33 });
34
35 // Regression guard: validate:data does not whitelist calendar names, so a
36 // typo (e.g. "Persain") would pass validation but silently make a region
37 // descriptive-only. These regions are meant to convert to a numeric year, so
38 // pin that here. The date is the midpoint of each era's covered range.
39 it.each([
40 ['Iran (historic Persia)', 'Lunar Hijri era', 'Islamic (Umm al-Qura)'],
41 ['Iran (historic Persia)', 'Solar Hijri era', 'Persian (Solar Hijri)'],
42 ['Russian America (Alaska)', 'Russian America (Old Style)', 'Julian'],
43 ['Russian America (Alaska)', 'Alaska (United States)', 'Gregorian'],
44 ['Oregon Country', 'Joint occupation (Hudson\'s Bay Company)', 'Gregorian'],
45 ])('%s / %s converts to a numeric year (%s)', (regionName, eraName, system) => {
46 const region = regions.find((r) => r.region.name === regionName);
47 expect(region, `region "${regionName}" not loaded`).toBeDefined();
48 const era = region!.eras.find((e) => e.name === eraName);
49 expect(era, `era "${eraName}" not found`).toBeDefined();
50
51 // Pick a date inside the era's range (midpoint, or near a null bound).
52 const startJd = era!.start ? parseGregorianDate(era!.start) : null;
53 const endJd = era!.end ? parseGregorianDate(era!.end) : null;
54 const year = startJd && endJd
55 ? Math.floor((startJd.year + endJd.year) / 2)
56 : startJd ? startJd.year + 10
57 : endJd ? endJd.year - 10
58 : 1850;
59
60 const conversion = convert({ year, month: 7, day: 1 }, era!.calendar);
61 expect(conversion.convertible, `${regionName}/${eraName} should be convertible`).toBe(true);
62 expect(conversion.system).toBe(system);
63 });
64});