mirror of
https://github.com/mayswind/ezbookkeeping.git
synced 2026-05-13 22:47:33 +08:00
replace Jest with Vitest
This commit is contained in:
@@ -1,21 +0,0 @@
|
||||
import { type JestConfigWithTsJest, createDefaultEsmPreset } from 'ts-jest';
|
||||
|
||||
const presetConfig = createDefaultEsmPreset({
|
||||
tsconfig: '<rootDir>/tsconfig.jest.json'
|
||||
});
|
||||
|
||||
const config: JestConfigWithTsJest = {
|
||||
...presetConfig,
|
||||
clearMocks: true,
|
||||
collectCoverage: false,
|
||||
moduleNameMapper: {
|
||||
"^@/(.*)$": "<rootDir>/src/$1"
|
||||
},
|
||||
testEnvironment: "node",
|
||||
testMatch: [
|
||||
"**/__tests__/**/*.[jt]s?(x)",
|
||||
"!**/__tests__/*_gen.[jt]s?(x)"
|
||||
]
|
||||
};
|
||||
|
||||
export default config;
|
||||
Generated
+497
-2548
File diff suppressed because it is too large
Load Diff
+2
-4
@@ -16,7 +16,7 @@
|
||||
"build": "cross-env NODE_ENV=production vite build",
|
||||
"serve:dist": "vite preview",
|
||||
"lint": "vue-tsc --noEmit && eslint . --fix",
|
||||
"test": "cross-env TS_NODE_PROJECT=\"./tsconfig.jest.json\" jest"
|
||||
"test": "vitest run"
|
||||
},
|
||||
"dependencies": {
|
||||
"@mdi/js": "7.4.47",
|
||||
@@ -56,7 +56,6 @@
|
||||
"@types/crypto-js": "4.2.2",
|
||||
"@types/git-rev-sync": "2.0.2",
|
||||
"@types/jalaali-js": "1.2.0",
|
||||
"@types/jest": "30.0.0",
|
||||
"@types/node": "25.6.0",
|
||||
"@types/ua-parser-js": "0.7.39",
|
||||
"@vitejs/plugin-vue": "6.0.6",
|
||||
@@ -66,16 +65,15 @@
|
||||
"eslint": "10.2.1",
|
||||
"eslint-plugin-vue": "10.9.0",
|
||||
"git-rev-sync": "3.0.2",
|
||||
"jest": "30.3.0",
|
||||
"postcss-preset-env": "11.2.1",
|
||||
"sass": "1.99.0",
|
||||
"ts-jest": "29.4.9",
|
||||
"ts-node": "10.9.2",
|
||||
"typescript": "6.0.3",
|
||||
"vite": "7.3.2",
|
||||
"vite-plugin-checker": "0.13.0",
|
||||
"vite-plugin-pwa": "1.2.0",
|
||||
"vite-plugin-vuetify": "2.1.3",
|
||||
"vitest": "4.1.5",
|
||||
"vue-tsc": "3.2.7"
|
||||
},
|
||||
"browserslist": [
|
||||
|
||||
@@ -0,0 +1,225 @@
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { describe, expect, it, beforeAll } from 'vitest';
|
||||
import moment from 'moment-timezone';
|
||||
|
||||
import type { TextualYearMonth } from '@/core/datetime.ts';
|
||||
import { FiscalYearStart, FiscalYearUnixTime } from '@/core/fiscalyear.ts';
|
||||
|
||||
import {
|
||||
getFiscalYearFromUnixTime,
|
||||
getFiscalYearStartUnixTime,
|
||||
getFiscalYearEndUnixTime,
|
||||
getFiscalYearTimeRangeFromUnixTime,
|
||||
getAllFiscalYearsStartAndEndUnixTimes,
|
||||
getFiscalYearTimeRangeFromYear
|
||||
} from '@/lib/datetime.ts';
|
||||
|
||||
// Set test environment timezone to UTC, since the test data constants are in UTC
|
||||
beforeAll(() => {
|
||||
moment.tz.setDefault('UTC');
|
||||
});
|
||||
|
||||
function importTestData(datasetName: string): unknown[] {
|
||||
const data = JSON.parse(
|
||||
fs.readFileSync(path.join(__dirname, 'fiscal_year.data.json'), 'utf8')
|
||||
);
|
||||
if (!data || typeof data[datasetName] === 'undefined') {
|
||||
throw new Error(`${datasetName} is undefined or missing in the data object.`);
|
||||
}
|
||||
return data[datasetName];
|
||||
}
|
||||
|
||||
function formatUnixTimeISO(unixTime: number): string {
|
||||
return moment.unix(unixTime).format('YYYY-MM-DDTHH:mm:ssZ');
|
||||
}
|
||||
|
||||
function withISO(data: FiscalYearUnixTime) {
|
||||
return {
|
||||
...data,
|
||||
minUnixTimeISO: formatUnixTimeISO(data.minUnixTime),
|
||||
maxUnixTimeISO: formatUnixTimeISO(data.maxUnixTime),
|
||||
};
|
||||
}
|
||||
|
||||
type FiscalYearStartConfig = {
|
||||
id: string;
|
||||
monthDateString: string;
|
||||
value: number;
|
||||
};
|
||||
|
||||
const FISCAL_YEAR_START_PRESETS: Record<string, FiscalYearStartConfig> = {
|
||||
'January 1': { id: 'January 1', monthDateString: '01-01', value: 0x0101 },
|
||||
'April 1': { id: 'April 1', monthDateString: '04-01', value: 0x0401 },
|
||||
'October 1': { id: 'October 1', monthDateString: '10-01', value: 0x0A01 },
|
||||
};
|
||||
|
||||
describe('validateFiscalYearStart', () => {
|
||||
Object.values(FISCAL_YEAR_START_PRESETS).forEach(({ id, value, monthDateString }) => {
|
||||
it(`should return a fiscal year start object for valid value 0x${value.toString(16)} (${id})`, () => {
|
||||
expect(FiscalYearStart.valueOf(value)).toBeDefined();
|
||||
});
|
||||
|
||||
it(`should return the correct month-date string for valid value 0x${value.toString(16)} (${id})`, () => {
|
||||
expect(FiscalYearStart.valueOf(value)?.toMonthDashDayString()).toStrictEqual(monthDateString);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
const INVALID_FISCAL_YEAR_VALUES = [
|
||||
0x0000, // Invalid: L0/0
|
||||
0x0D01, // Invalid: Month 13
|
||||
0x0100, // Invalid: Day 0
|
||||
0x0120, // Invalid: January 32
|
||||
0x021D, // Invalid: February 29 (not permitted)
|
||||
0x021E, // Invalid: February 30
|
||||
0x041F, // Invalid: April 31
|
||||
0x061F, // Invalid: June 31
|
||||
0x091F, // Invalid: September 31
|
||||
0x0B20, // Invalid: November 32
|
||||
0xFFFF, // Invalid: Largest uint16
|
||||
];
|
||||
|
||||
describe('validateFiscalYearStartInvalidValues', () => {
|
||||
INVALID_FISCAL_YEAR_VALUES.forEach((value) => {
|
||||
it(`should return undefined for invalid fiscal year start value 0x${value.toString(16)}`, () => {
|
||||
expect(FiscalYearStart.valueOf(value)).not.toBeDefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('validateFiscalYearStartLeapDay', () => {
|
||||
it('should return undefined for February 29 value (0x021D)', () => {
|
||||
expect(FiscalYearStart.valueOf(0x021D)).not.toBeDefined();
|
||||
});
|
||||
|
||||
it('should return undefined when parsing month-day string "02-29"', () => {
|
||||
expect(FiscalYearStart.parse('02-29')).not.toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
type FiscalYearFromUnixTimeCase = {
|
||||
date: string;
|
||||
unixTime: number;
|
||||
expected: { [fiscalYearStartId: string]: number };
|
||||
};
|
||||
|
||||
const TEST_CASES_GET_FISCAL_YEAR_FROM_UNIX_TIME =
|
||||
importTestData('test_cases_getFiscalYearFromUnixTime') as FiscalYearFromUnixTimeCase[];
|
||||
|
||||
describe('getFiscalYearFromUnixTime', () => {
|
||||
Object.values(FISCAL_YEAR_START_PRESETS).forEach(({ id, value }) => {
|
||||
TEST_CASES_GET_FISCAL_YEAR_FROM_UNIX_TIME.forEach((testCase) => {
|
||||
it(`should return correct fiscal year for FY_START ${id}, date ${moment(testCase.date).format('MMMM D, YYYY')}`, () => {
|
||||
expect(getFiscalYearFromUnixTime(moment(testCase.date).unix(), value)).toBe(testCase.expected[id]);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
type FiscalYearStartUnixTimeCase = {
|
||||
date: string;
|
||||
expected: {
|
||||
[fiscalYearStart: string]: { unixTime: number; unixTimeISO: string };
|
||||
};
|
||||
};
|
||||
|
||||
const TEST_CASES_GET_FISCAL_YEAR_START_UNIX_TIME =
|
||||
importTestData('test_cases_getFiscalYearStartUnixTime') as FiscalYearStartUnixTimeCase[];
|
||||
|
||||
describe('getFiscalYearStartUnixTime', () => {
|
||||
Object.values(FISCAL_YEAR_START_PRESETS).forEach(({ id, value }) => {
|
||||
TEST_CASES_GET_FISCAL_YEAR_START_UNIX_TIME.forEach((testCase) => {
|
||||
it(`should return correct start unix time for FY_START ${id}, date ${moment(testCase.date).format('MMMM D, YYYY')}`, () => {
|
||||
const startUnixTime = getFiscalYearStartUnixTime(moment(testCase.date).unix(), value);
|
||||
const expected = testCase.expected[id];
|
||||
expect({ unixTime: startUnixTime, ISO: formatUnixTimeISO(startUnixTime) })
|
||||
.toStrictEqual({ unixTime: expected!.unixTime, ISO: expected!.unixTimeISO });
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
type FiscalYearEndUnixTimeCase = {
|
||||
date: string;
|
||||
expected: {
|
||||
[fiscalYearStart: string]: { unixTime: number; unixTimeISO: string };
|
||||
};
|
||||
};
|
||||
|
||||
const TEST_CASES_GET_FISCAL_YEAR_END_UNIX_TIME =
|
||||
importTestData('test_cases_getFiscalYearEndUnixTime') as FiscalYearEndUnixTimeCase[];
|
||||
|
||||
describe('getFiscalYearEndUnixTime', () => {
|
||||
Object.values(FISCAL_YEAR_START_PRESETS).forEach(({ id, value }) => {
|
||||
TEST_CASES_GET_FISCAL_YEAR_END_UNIX_TIME.forEach((testCase) => {
|
||||
it(`should return correct end unix time for FY_START ${id}, date ${moment(testCase.date).format('MMMM D, YYYY')}`, () => {
|
||||
const endUnixTime = getFiscalYearEndUnixTime(moment(testCase.date).unix(), value);
|
||||
const expected = testCase.expected[id];
|
||||
expect({ unixTime: endUnixTime, ISO: formatUnixTimeISO(endUnixTime) })
|
||||
.toStrictEqual({ unixTime: expected!.unixTime, ISO: expected!.unixTimeISO });
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
type FiscalYearTimeRangeFromUnixTimeCase = {
|
||||
date: string;
|
||||
expected: { [fiscalYearStart: string]: FiscalYearUnixTime[] };
|
||||
};
|
||||
|
||||
const TEST_CASES_GET_FISCAL_YEAR_UNIX_TIME_RANGE =
|
||||
importTestData('test_cases_getFiscalYearTimeRangeFromUnixTime') as FiscalYearTimeRangeFromUnixTimeCase[];
|
||||
|
||||
describe('getFiscalYearTimeRangeFromUnixTime', () => {
|
||||
Object.values(FISCAL_YEAR_START_PRESETS).forEach(({ id, value }) => {
|
||||
TEST_CASES_GET_FISCAL_YEAR_UNIX_TIME_RANGE.forEach((testCase) => {
|
||||
it(`should return correct fiscal year unix time range for FY_START ${id}, date ${moment(testCase.date).format('MMMM D, YYYY')}`, () => {
|
||||
expect(getFiscalYearTimeRangeFromUnixTime(moment(testCase.date).unix(), value))
|
||||
.toStrictEqual(testCase.expected[id]);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
type AllFiscalYearsStartAndEndUnixTimesCase = {
|
||||
startYearMonth: TextualYearMonth;
|
||||
endYearMonth: TextualYearMonth;
|
||||
fiscalYearStart: string;
|
||||
fiscalYearStartId: string;
|
||||
expected: FiscalYearUnixTime[];
|
||||
};
|
||||
|
||||
const TEST_CASES_GET_ALL_FISCAL_YEARS_START_AND_END_UNIX_TIMES =
|
||||
importTestData('test_cases_getAllFiscalYearsStartAndEndUnixTimes') as AllFiscalYearsStartAndEndUnixTimesCase[];
|
||||
|
||||
describe('getAllFiscalYearsStartAndEndUnixTimes', () => {
|
||||
TEST_CASES_GET_ALL_FISCAL_YEARS_START_AND_END_UNIX_TIMES.forEach((testCase) => {
|
||||
it(`should return correct fiscal year start and end unix times for FY_START ${testCase.fiscalYearStartId}, range ${testCase.startYearMonth} to ${testCase.endYearMonth}`, () => {
|
||||
const fiscalYearStart = FiscalYearStart.parse(testCase.fiscalYearStart);
|
||||
expect(fiscalYearStart).toBeDefined();
|
||||
expect(getAllFiscalYearsStartAndEndUnixTimes(testCase.startYearMonth, testCase.endYearMonth, fiscalYearStart?.value || 0).map(withISO))
|
||||
.toStrictEqual(testCase.expected.map(withISO));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
type FiscalYearTimeRangeFromYearCase = {
|
||||
year: number;
|
||||
fiscalYearStart: string;
|
||||
expected: FiscalYearUnixTime;
|
||||
};
|
||||
|
||||
const TEST_CASES_GET_FISCAL_YEAR_RANGE_FROM_YEAR =
|
||||
importTestData('test_cases_getFiscalYearTimeRangeFromYear') as FiscalYearTimeRangeFromYearCase[];
|
||||
|
||||
describe('getFiscalYearTimeRangeFromYear', () => {
|
||||
TEST_CASES_GET_FISCAL_YEAR_RANGE_FROM_YEAR.forEach((testCase) => {
|
||||
it(`should return correct fiscal year unix time range for year ${testCase.year} and FY_START ${testCase.fiscalYearStart}`, () => {
|
||||
const fiscalYearStart = FiscalYearStart.parse(testCase.fiscalYearStart);
|
||||
expect(fiscalYearStart).toBeDefined();
|
||||
expect(getFiscalYearTimeRangeFromYear(testCase.year, fiscalYearStart?.value || 0))
|
||||
.toStrictEqual(testCase.expected);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,289 +0,0 @@
|
||||
// Unit tests for fiscal year functions
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { describe, expect, test, beforeAll } from '@jest/globals';
|
||||
import moment from 'moment-timezone';
|
||||
|
||||
// Import all the fiscal year functions from the lib
|
||||
import type { TextualYearMonth } from '@/core/datetime.ts';
|
||||
import { FiscalYearStart, FiscalYearUnixTime } from '@/core/fiscalyear.ts';
|
||||
|
||||
import {
|
||||
getFiscalYearFromUnixTime,
|
||||
getFiscalYearStartUnixTime,
|
||||
getFiscalYearEndUnixTime,
|
||||
getFiscalYearTimeRangeFromUnixTime,
|
||||
getAllFiscalYearsStartAndEndUnixTimes,
|
||||
getFiscalYearTimeRangeFromYear
|
||||
} from '@/lib/datetime.ts';
|
||||
|
||||
// Set test environment timezone to UTC, since the test data constants are in UTC
|
||||
beforeAll(() => {
|
||||
moment.tz.setDefault('UTC');
|
||||
});
|
||||
|
||||
// UTILITIES
|
||||
function importTestData(datasetName: string): unknown[] {
|
||||
const data = JSON.parse(
|
||||
fs.readFileSync(path.join(__dirname, 'fiscal_year.data.json'), 'utf8')
|
||||
);
|
||||
if (!data || typeof data[datasetName] === 'undefined') {
|
||||
throw new Error(`${datasetName} is undefined or missing in the data object.`);
|
||||
}
|
||||
return data[datasetName];
|
||||
}
|
||||
|
||||
function formatUnixTimeISO(unixTime: number): string {
|
||||
return moment.unix(unixTime).format('YYYY-MM-DDTHH:mm:ssZ');
|
||||
}
|
||||
|
||||
function getTestTitleFormatDate(testFiscalYearStartId: string, testCaseDateString: string): string {
|
||||
return `FY_START: ${testFiscalYearStartId.padStart(10, ' ')}; DATE: ${moment(testCaseDateString).format('MMMM D, YYYY')}`;
|
||||
}
|
||||
|
||||
function getTestTitleFormatString(testFiscalYearStartId: string, testCaseString: string): string {
|
||||
return `FY_START: ${testFiscalYearStartId.padStart(10, ' ')}; ${testCaseString}`;
|
||||
}
|
||||
|
||||
// FISCAL YEAR START CONFIGURATION
|
||||
type FiscalYearStartConfig = {
|
||||
id: string;
|
||||
monthDateString: string;
|
||||
value: number;
|
||||
};
|
||||
|
||||
const TEST_FISCAL_YEAR_START_PRESETS: Record<string, FiscalYearStartConfig> = {
|
||||
'January 1': {
|
||||
id: 'January 1',
|
||||
monthDateString: '01-01',
|
||||
value: 0x0101,
|
||||
},
|
||||
'April 1': {
|
||||
id: 'April 1',
|
||||
monthDateString: '04-01',
|
||||
value: 0x0401,
|
||||
},
|
||||
'October 1': {
|
||||
id: 'October 1',
|
||||
monthDateString: '10-01',
|
||||
value: 0x0A01,
|
||||
},
|
||||
};
|
||||
|
||||
// VALIDATE FISCAL YEAR START PRESETS
|
||||
describe('validateFiscalYearStart', () => {
|
||||
Object.values(TEST_FISCAL_YEAR_START_PRESETS).forEach((testFiscalYearStart) => {
|
||||
test(`should return fiscal year start object if fiscal year start value (uint16) is valid: id: ${testFiscalYearStart.id}; value: 0x${testFiscalYearStart.value.toString(16)}`, () => {
|
||||
expect(FiscalYearStart.valueOf(testFiscalYearStart.value)).toBeDefined();
|
||||
});
|
||||
|
||||
test(`returns same month-date string for valid fiscal year start value: id: ${testFiscalYearStart.id}; value: 0x${testFiscalYearStart.value.toString(16)}`, () => {
|
||||
const fiscalYearStart = FiscalYearStart.valueOf(testFiscalYearStart.value);
|
||||
expect(fiscalYearStart?.toMonthDashDayString()).toStrictEqual(testFiscalYearStart.monthDateString);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// VALIDATE INVALID FISCAL YEAR START VALUES
|
||||
const TestCase_invalidFiscalYearValues = [
|
||||
0x0000, // Invalid: L0/0
|
||||
0x0D01, // Invalid: Month 13
|
||||
0x0100, // Invalid: Day 0
|
||||
0x0120, // Invalid: January 32
|
||||
0x021D, // Invalid: February 29 (not permitted)
|
||||
0x021E, // Invalid: February 30
|
||||
0x041F, // Invalid: April 31
|
||||
0x061F, // Invalid: June 31
|
||||
0x091F, // Invalid: September 31
|
||||
0x0B20, // Invalid: November 32
|
||||
0xFFFF, // Invalid: Largest uint16
|
||||
]
|
||||
|
||||
describe('validateFiscalYearStartInvalidValues', () => {
|
||||
TestCase_invalidFiscalYearValues.forEach((testCase) => {
|
||||
test(`should return undefined if fiscal year start value (uint16) is invalid: value: 0x${testCase.toString(16)}`, () => {
|
||||
expect(FiscalYearStart.valueOf(testCase)).not.toBeDefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// VALIDATE LEAP DAY FEBRUARY 29 IS NOT VALID
|
||||
describe('validateFiscalYearStartLeapDay', () => {
|
||||
test(`should return undefined if fiscal year start value (uint16) for February 29 is invalid: value: 0x0229}`, () => {
|
||||
expect(FiscalYearStart.valueOf(0x021D)).not.toBeDefined();
|
||||
});
|
||||
|
||||
test(`should return undefined if fiscal year month-day string "02-29" is used to create fiscal year start object`, () => {
|
||||
expect(FiscalYearStart.parse('02-29')).not.toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
// FISCAL YEAR FROM UNIX TIME
|
||||
type TestCase_getFiscalYearFromUnixTime = {
|
||||
date: string;
|
||||
unixTime: number;
|
||||
expected: {
|
||||
[fiscalYearStartId: string]: number;
|
||||
};
|
||||
};
|
||||
|
||||
const TEST_CASES_GET_FISCAL_YEAR_FROM_UNIX_TIME: TestCase_getFiscalYearFromUnixTime[] =
|
||||
importTestData('test_cases_getFiscalYearFromUnixTime') as TestCase_getFiscalYearFromUnixTime[];
|
||||
|
||||
describe('getFiscalYearFromUnixTime', () => {
|
||||
Object.values(TEST_FISCAL_YEAR_START_PRESETS).forEach((testFiscalYearStart) => {
|
||||
TEST_CASES_GET_FISCAL_YEAR_FROM_UNIX_TIME.forEach((testCase) => {
|
||||
test(`returns correct fiscal year for ${getTestTitleFormatDate(testFiscalYearStart.id, testCase.date)}`, () => {
|
||||
const testCaseUnixTime = moment(testCase.date).unix();
|
||||
const fiscalYear = getFiscalYearFromUnixTime(testCaseUnixTime, testFiscalYearStart.value);
|
||||
const expected = testCase.expected[testFiscalYearStart.id];
|
||||
expect(fiscalYear).toBe(expected);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// FISCAL YEAR START UNIX TIME
|
||||
type TestCase_getFiscalYearStartUnixTime = {
|
||||
date: string;
|
||||
expected: {
|
||||
[fiscalYearStart: string]: {
|
||||
unixTime: number;
|
||||
unixTimeISO: string;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
const TEST_CASES_GET_FISCAL_YEAR_START_UNIX_TIME: TestCase_getFiscalYearStartUnixTime[] =
|
||||
importTestData('test_cases_getFiscalYearStartUnixTime') as TestCase_getFiscalYearStartUnixTime[];
|
||||
|
||||
describe('getFiscalYearStartUnixTime', () => {
|
||||
Object.values(TEST_FISCAL_YEAR_START_PRESETS).forEach((testFiscalYearStart) => {
|
||||
TEST_CASES_GET_FISCAL_YEAR_START_UNIX_TIME.forEach((testCase) => {
|
||||
test(`returns correct start unix time for ${getTestTitleFormatDate(testFiscalYearStart.id, testCase.date)}`, () => {
|
||||
const testCaseUnixTime = moment(testCase.date).unix();
|
||||
const startUnixTime = getFiscalYearStartUnixTime(testCaseUnixTime, testFiscalYearStart.value);
|
||||
const expected = testCase.expected[testFiscalYearStart.id];
|
||||
const unixTimeISO = formatUnixTimeISO(startUnixTime);
|
||||
|
||||
expect({ unixTime: startUnixTime, ISO: unixTimeISO }).toStrictEqual({ unixTime: expected!.unixTime, ISO: expected!.unixTimeISO });
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// FISCAL YEAR END UNIX TIME
|
||||
type TestCase_getFiscalYearEndUnixTime = {
|
||||
date: string;
|
||||
expected: {
|
||||
[fiscalYearStart: string]: {
|
||||
unixTime: number;
|
||||
unixTimeISO: string;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
const TEST_CASES_GET_FISCAL_YEAR_END_UNIX_TIME: TestCase_getFiscalYearEndUnixTime[] =
|
||||
importTestData('test_cases_getFiscalYearEndUnixTime') as TestCase_getFiscalYearEndUnixTime[];
|
||||
|
||||
describe('getFiscalYearEndUnixTime', () => {
|
||||
Object.values(TEST_FISCAL_YEAR_START_PRESETS).forEach((testFiscalYearStart) => {
|
||||
TEST_CASES_GET_FISCAL_YEAR_END_UNIX_TIME.forEach((testCase) => {
|
||||
test(`returns correct end unix time for ${getTestTitleFormatDate(testFiscalYearStart.id, testCase.date)}`, () => {
|
||||
const testCaseUnixTime = moment(testCase.date).unix();
|
||||
const endUnixTime = getFiscalYearEndUnixTime(testCaseUnixTime, testFiscalYearStart.value);
|
||||
const expected = testCase.expected[testFiscalYearStart.id];
|
||||
const unixTimeISO = formatUnixTimeISO(endUnixTime);
|
||||
|
||||
expect({ unixTime: endUnixTime, ISO: unixTimeISO }).toStrictEqual({ unixTime: expected!.unixTime, ISO: expected!.unixTimeISO });
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// GET FISCAL YEAR UNIX TIME RANGE
|
||||
type TestCase_getFiscalYearTimeRangeFromUnixTime = {
|
||||
date: string;
|
||||
expected: {
|
||||
[fiscalYearStart: string]: FiscalYearUnixTime[]
|
||||
}
|
||||
}
|
||||
|
||||
const TEST_CASES_GET_FISCAL_YEAR_UNIX_TIME_RANGE: TestCase_getFiscalYearTimeRangeFromUnixTime[] =
|
||||
importTestData('test_cases_getFiscalYearTimeRangeFromUnixTime') as TestCase_getFiscalYearTimeRangeFromUnixTime[];
|
||||
|
||||
describe('getFiscalYearTimeRangeFromUnixTime', () => {
|
||||
Object.values(TEST_FISCAL_YEAR_START_PRESETS).forEach((testFiscalYearStart) => {
|
||||
TEST_CASES_GET_FISCAL_YEAR_UNIX_TIME_RANGE.forEach((testCase) => {
|
||||
test(`returns correct fiscal year unix time range for ${getTestTitleFormatDate(testFiscalYearStart.id, testCase.date)}`, () => {
|
||||
const testCaseUnixTime = moment(testCase.date).unix();
|
||||
const fiscalYearUnixTimeRange = getFiscalYearTimeRangeFromUnixTime(testCaseUnixTime, testFiscalYearStart.value);
|
||||
expect(fiscalYearUnixTimeRange).toStrictEqual(testCase.expected[testFiscalYearStart.id]);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// GET ALL FISCAL YEAR START AND END UNIX TIMES
|
||||
type TestCase_getAllFiscalYearsStartAndEndUnixTimes = {
|
||||
startYearMonth: TextualYearMonth;
|
||||
endYearMonth: TextualYearMonth;
|
||||
fiscalYearStart: string;
|
||||
fiscalYearStartId: string;
|
||||
expected: FiscalYearUnixTime[]
|
||||
}
|
||||
|
||||
const TEST_CASES_GET_ALL_FISCAL_YEARS_START_AND_END_UNIX_TIMES: TestCase_getAllFiscalYearsStartAndEndUnixTimes[] =
|
||||
importTestData('test_cases_getAllFiscalYearsStartAndEndUnixTimes') as TestCase_getAllFiscalYearsStartAndEndUnixTimes[];
|
||||
|
||||
describe('getAllFiscalYearsStartAndEndUnixTimes', () => {
|
||||
TEST_CASES_GET_ALL_FISCAL_YEARS_START_AND_END_UNIX_TIMES.forEach((testCase) => {
|
||||
const fiscalYearStart = FiscalYearStart.parse(testCase.fiscalYearStart);
|
||||
test(`returns correct fiscal year start and end unix times for ${getTestTitleFormatString(testCase.fiscalYearStartId, `${testCase.startYearMonth} to ${testCase.endYearMonth}`)}`, () => {
|
||||
expect(fiscalYearStart).toBeDefined();
|
||||
|
||||
const fiscalYearStartAndEndUnixTimes = getAllFiscalYearsStartAndEndUnixTimes(testCase.startYearMonth, testCase.endYearMonth, fiscalYearStart?.value || 0);
|
||||
|
||||
// Convert results to include ISO strings for better test output
|
||||
const resultWithISO = fiscalYearStartAndEndUnixTimes.map(data => ({
|
||||
...data,
|
||||
minUnixTimeISO: formatUnixTimeISO(data.minUnixTime),
|
||||
maxUnixTimeISO: formatUnixTimeISO(data.maxUnixTime)
|
||||
}));
|
||||
|
||||
// Convert expected to include ISO strings
|
||||
const expectedWithISO = testCase.expected.map(data => ({
|
||||
...data,
|
||||
minUnixTimeISO: formatUnixTimeISO(data.minUnixTime),
|
||||
maxUnixTimeISO: formatUnixTimeISO(data.maxUnixTime)
|
||||
}));
|
||||
|
||||
expect(resultWithISO).toStrictEqual(expectedWithISO);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// GET FISCAL YEAR RANGE FROM YEAR
|
||||
type TestCase_getFiscalYearTimeRangeFromYear = {
|
||||
year: number;
|
||||
fiscalYearStart: string;
|
||||
expected: FiscalYearUnixTime;
|
||||
}
|
||||
|
||||
const TEST_CASES_GET_FISCAL_YEAR_RANGE_FROM_YEAR: TestCase_getFiscalYearTimeRangeFromYear[] =
|
||||
importTestData('test_cases_getFiscalYearTimeRangeFromYear') as TestCase_getFiscalYearTimeRangeFromYear[];
|
||||
|
||||
describe('getFiscalYearTimeRangeFromYear', () => {
|
||||
TEST_CASES_GET_FISCAL_YEAR_RANGE_FROM_YEAR.forEach((testCase) => {
|
||||
const fiscalYearStart = FiscalYearStart.parse(testCase.fiscalYearStart);
|
||||
test(`returns correct fiscal year unix time range for input year integer ${testCase.year} and FY_START: ${testCase.fiscalYearStart}`, () => {
|
||||
expect(fiscalYearStart).toBeDefined();
|
||||
const fiscalYearRange = getFiscalYearTimeRangeFromYear(testCase.year, fiscalYearStart?.value || 0);
|
||||
expect(fiscalYearRange).toStrictEqual(testCase.expected);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,79 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
import { mean, median, percentile, sumMaxN } from '@/lib/math.ts';
|
||||
|
||||
describe('mean', () => {
|
||||
it('should return zero for empty array', () => {
|
||||
expect(mean([], item => item)).toBeCloseTo(0);
|
||||
});
|
||||
|
||||
it('should return the average for positive values', () => {
|
||||
expect(mean([1, 2, 3, 4], item => item)).toBeCloseTo(2.5);
|
||||
});
|
||||
|
||||
it('should return the average for negative and positive values', () => {
|
||||
expect(mean([-10, 0, 20], item => item)).toBeCloseTo(10 / 3);
|
||||
});
|
||||
});
|
||||
|
||||
describe('median', () => {
|
||||
it('should return zero for empty sorted array', () => {
|
||||
expect(median([], item => item)).toBeCloseTo(0);
|
||||
});
|
||||
|
||||
it('should return the middle value for odd-length sorted array', () => {
|
||||
expect(median([1, 3, 5], item => item)).toBeCloseTo(3);
|
||||
});
|
||||
|
||||
it('should return the average of the two middle values for even-length sorted array', () => {
|
||||
expect(median([1, 3, 5, 7], item => item)).toBeCloseTo(4);
|
||||
});
|
||||
});
|
||||
|
||||
describe('percentile', () => {
|
||||
it('should return zero for empty sorted array', () => {
|
||||
expect(percentile([], 0.5, item => item)).toBeCloseTo(0);
|
||||
});
|
||||
|
||||
it('should return zero when percentile is smaller than zero', () => {
|
||||
expect(percentile([1, 2, 3], -0.1, item => item)).toBeCloseTo(0);
|
||||
});
|
||||
|
||||
it('should return zero when percentile is larger than one', () => {
|
||||
expect(percentile([1, 2, 3], 1.1, item => item)).toBeCloseTo(0);
|
||||
});
|
||||
|
||||
it('should return the minimum value for zero percentile', () => {
|
||||
expect(percentile([5, 10, 15, 20], 0, item => item)).toBeCloseTo(5);
|
||||
});
|
||||
|
||||
it('should return the maximum value for one percentile', () => {
|
||||
expect(percentile([5, 10, 15, 20], 1, item => item)).toBeCloseTo(20);
|
||||
});
|
||||
|
||||
it('should return the exact indexed value when percentile maps to an integer index', () => {
|
||||
expect(percentile([10, 20, 30, 40, 50], 0.25, item => item)).toBeCloseTo(20);
|
||||
});
|
||||
|
||||
it('should interpolate between neighboring values when percentile maps to a fractional index', () => {
|
||||
expect(percentile([10, 20, 30, 40, 50, 60, 70, 80], 0.25, item => item)).toBeCloseTo(27.5);
|
||||
});
|
||||
});
|
||||
|
||||
describe('sumMaxN', () => {
|
||||
it('should return zero for empty sorted array', () => {
|
||||
expect(sumMaxN([], 3, item => item)).toBe(0);
|
||||
});
|
||||
|
||||
it('should return zero when n is zero', () => {
|
||||
expect(sumMaxN([1, 2, 3], 0, item => item)).toBe(0);
|
||||
});
|
||||
|
||||
it('should return the sum of the largest n values', () => {
|
||||
expect(sumMaxN([1, 2, 3, 4, 5], 2, item => item)).toBe(9);
|
||||
});
|
||||
|
||||
it('should return the sum of all values when n is larger than array length', () => {
|
||||
expect(sumMaxN([1, 2, 3, 4], 10, item => item)).toBe(10);
|
||||
});
|
||||
});
|
||||
@@ -1,190 +0,0 @@
|
||||
import { describe, expect, test } from '@jest/globals';
|
||||
|
||||
import { mean, median, percentile, sumMaxN } from '@/lib/math.ts';
|
||||
|
||||
type TestNumberItem = {
|
||||
value: number;
|
||||
};
|
||||
|
||||
function createNumberItems(values: number[]): TestNumberItem[] {
|
||||
return values.map(value => ({ value }));
|
||||
}
|
||||
|
||||
function getTestTitle(functionName: string, title: string): string {
|
||||
return `${functionName}: ${title}`;
|
||||
}
|
||||
|
||||
type MeanTestCase = {
|
||||
title: string;
|
||||
values: number[];
|
||||
expected: number;
|
||||
};
|
||||
|
||||
const TEST_CASES_MEAN: MeanTestCase[] = [
|
||||
{
|
||||
title: 'returns zero for empty array',
|
||||
values: [],
|
||||
expected: 0,
|
||||
},
|
||||
{
|
||||
title: 'returns the average for positive values',
|
||||
values: [1, 2, 3, 4],
|
||||
expected: 2.5,
|
||||
},
|
||||
{
|
||||
title: 'returns the average for negative and positive values',
|
||||
values: [-10, 0, 20],
|
||||
expected: 10 / 3,
|
||||
},
|
||||
];
|
||||
|
||||
describe('mean', () => {
|
||||
TEST_CASES_MEAN.forEach((testCase) => {
|
||||
test(getTestTitle('mean', testCase.title), () => {
|
||||
const result = mean(createNumberItems(testCase.values), item => item.value);
|
||||
expect(result).toBeCloseTo(testCase.expected);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
type MedianTestCase = {
|
||||
title: string;
|
||||
values: number[];
|
||||
expected: number;
|
||||
};
|
||||
|
||||
const TEST_CASES_MEDIAN: MedianTestCase[] = [
|
||||
{
|
||||
title: 'returns zero for empty sorted array',
|
||||
values: [],
|
||||
expected: 0,
|
||||
},
|
||||
{
|
||||
title: 'returns the middle value for odd-length sorted array',
|
||||
values: [1, 3, 5],
|
||||
expected: 3,
|
||||
},
|
||||
{
|
||||
title: 'returns the average of the two middle values for even-length sorted array',
|
||||
values: [1, 3, 5, 7],
|
||||
expected: 4,
|
||||
},
|
||||
];
|
||||
|
||||
describe('median', () => {
|
||||
TEST_CASES_MEDIAN.forEach((testCase) => {
|
||||
test(getTestTitle('median', testCase.title), () => {
|
||||
const result = median(createNumberItems(testCase.values), item => item.value);
|
||||
expect(result).toBeCloseTo(testCase.expected);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
type PercentileTestCase = {
|
||||
title: string;
|
||||
values: number[];
|
||||
percentileValue: number;
|
||||
expected: number;
|
||||
};
|
||||
|
||||
const TEST_CASES_PERCENTILE: PercentileTestCase[] = [
|
||||
{
|
||||
title: 'returns zero for empty sorted array',
|
||||
values: [],
|
||||
percentileValue: 0.5,
|
||||
expected: 0,
|
||||
},
|
||||
{
|
||||
title: 'returns zero when percentile is smaller than zero',
|
||||
values: [1, 2, 3],
|
||||
percentileValue: -0.1,
|
||||
expected: 0,
|
||||
},
|
||||
{
|
||||
title: 'returns zero when percentile is larger than one',
|
||||
values: [1, 2, 3],
|
||||
percentileValue: 1.1,
|
||||
expected: 0,
|
||||
},
|
||||
{
|
||||
title: 'returns the minimum value for zero percentile',
|
||||
values: [5, 10, 15, 20],
|
||||
percentileValue: 0,
|
||||
expected: 5,
|
||||
},
|
||||
{
|
||||
title: 'returns the maximum value for one percentile',
|
||||
values: [5, 10, 15, 20],
|
||||
percentileValue: 1,
|
||||
expected: 20,
|
||||
},
|
||||
{
|
||||
title: 'returns the exact indexed value when percentile maps to an integer index',
|
||||
values: [10, 20, 30, 40, 50],
|
||||
percentileValue: 0.25,
|
||||
expected: 20,
|
||||
},
|
||||
{
|
||||
title: 'interpolates between neighboring values when percentile maps to a fractional index',
|
||||
values: [10, 20, 30, 40, 50, 60, 70, 80],
|
||||
percentileValue: 0.25,
|
||||
expected: 27.5,
|
||||
},
|
||||
];
|
||||
|
||||
describe('percentile', () => {
|
||||
TEST_CASES_PERCENTILE.forEach((testCase) => {
|
||||
test(getTestTitle('percentile', testCase.title), () => {
|
||||
const result = percentile(
|
||||
createNumberItems(testCase.values),
|
||||
testCase.percentileValue,
|
||||
item => item.value
|
||||
);
|
||||
|
||||
expect(result).toBeCloseTo(testCase.expected);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
type SumMaxNTestCase = {
|
||||
title: string;
|
||||
values: number[];
|
||||
n: number;
|
||||
expected: number;
|
||||
};
|
||||
|
||||
const TEST_CASES_SUM_MAX_N: SumMaxNTestCase[] = [
|
||||
{
|
||||
title: 'returns zero for empty sorted array',
|
||||
values: [],
|
||||
n: 3,
|
||||
expected: 0,
|
||||
},
|
||||
{
|
||||
title: 'returns zero when n is zero',
|
||||
values: [1, 2, 3],
|
||||
n: 0,
|
||||
expected: 0,
|
||||
},
|
||||
{
|
||||
title: 'returns the sum of the largest n values',
|
||||
values: [1, 2, 3, 4, 5],
|
||||
n: 2,
|
||||
expected: 9,
|
||||
},
|
||||
{
|
||||
title: 'returns the sum of all values when n is larger than array length',
|
||||
values: [1, 2, 3, 4],
|
||||
n: 10,
|
||||
expected: 10,
|
||||
},
|
||||
];
|
||||
|
||||
describe('sumMaxN', () => {
|
||||
TEST_CASES_SUM_MAX_N.forEach((testCase) => {
|
||||
test(getTestTitle('sumMaxN', testCase.title), () => {
|
||||
const result = sumMaxN(createNumberItems(testCase.values), testCase.n, item => item.value);
|
||||
expect(result).toBe(testCase.expected);
|
||||
});
|
||||
});
|
||||
});
|
||||
+40
-39
@@ -1,13 +1,12 @@
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { describe, expect, test } from '@jest/globals';
|
||||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
import { DEFAULT_CONTENT } from '@/locales/calendar/chinese/index.ts';
|
||||
|
||||
import { itemAndIndex, entries } from '@/core/base.ts';
|
||||
import type { ChineseCalendarLocaleData } from '@/core/calendar.ts';
|
||||
import {
|
||||
type ChineseYearMonthDayInfo,
|
||||
getChineseYearMonthAllDayInfos,
|
||||
getChineseYearMonthDayInfo
|
||||
} from '@/lib/calendar/chinese_calendar.ts';
|
||||
@@ -45,12 +44,33 @@ const localeData: ChineseCalendarLocaleData = {
|
||||
'Winter Solstice'
|
||||
]
|
||||
};
|
||||
|
||||
const ordinalSuffix = ['st', 'nd', 'rd'];
|
||||
|
||||
describe('getChineseYearMonthAllDayInfos', () => {
|
||||
const lines: string[] = fs.readFileSync(path.join(__dirname, 'chinese_calendar_all_data.txt'), 'utf8').replace(/\r/g, '').split('\n');
|
||||
function lunarMonthOrDayLabel(month: number, day: number): string {
|
||||
return day === 1
|
||||
? `${month}${ordinalSuffix[month - 1] ?? 'th'} Lunar Month`.toLowerCase()
|
||||
: day.toString();
|
||||
}
|
||||
|
||||
type PerDayEntry = {
|
||||
gregorianDate: string;
|
||||
gregorianYear: number;
|
||||
gregorianMonth: number;
|
||||
gregorianDay: number;
|
||||
expectedChineseMonthOrDay: string;
|
||||
expectedSolarTermName: string;
|
||||
};
|
||||
|
||||
function parseCalendarDataFile(): {
|
||||
allMonthChineseDays: Record<string, string[]>;
|
||||
allMonthSolarTermNames: Record<string, string[]>;
|
||||
perDayEntries: PerDayEntry[];
|
||||
} {
|
||||
const lines = fs.readFileSync(path.join(__dirname, 'chinese_calendar_all_data.txt'), 'utf8').replace(/\r/g, '').split('\n');
|
||||
const allMonthChineseDays: Record<string, string[]> = {};
|
||||
const allMonthSolarTermNames: Record<string, string[]> = {};
|
||||
const perDayEntries: PerDayEntry[] = [];
|
||||
let currentMonthChineseDays: string[] = [];
|
||||
let currentMonthSolarTermNames: string[] = [];
|
||||
let currentYear: number = 0;
|
||||
@@ -66,16 +86,17 @@ describe('getChineseYearMonthAllDayInfos', () => {
|
||||
const gregorianDateItems = gregorianDate.split('/');
|
||||
const gregorianYear = parseInt(gregorianDateItems[0] as string, 10);
|
||||
const gregorianMonth = parseInt(gregorianDateItems[1] as string, 10);
|
||||
const gregorianDay = parseInt(gregorianDateItems[2] as string, 10);
|
||||
const chineseDay = items[1] as string;
|
||||
const solarTermName = items.length > 3 ? items[3] as string : '';
|
||||
|
||||
perDayEntries.push({ gregorianDate, gregorianYear, gregorianMonth, gregorianDay, expectedChineseMonthOrDay: chineseDay, expectedSolarTermName: solarTermName });
|
||||
|
||||
if (currentYear > 0 && currentMonth > 0 && (gregorianYear !== currentYear || gregorianMonth !== currentMonth)) {
|
||||
allMonthChineseDays[`${currentYear}-${currentMonth}`] = currentMonthChineseDays;
|
||||
allMonthSolarTermNames[`${currentYear}-${currentMonth}`] = currentMonthSolarTermNames;
|
||||
|
||||
currentMonthChineseDays = [];
|
||||
currentMonthSolarTermNames = [];
|
||||
|
||||
currentYear = gregorianYear;
|
||||
currentMonth = gregorianMonth;
|
||||
} else if (currentYear === 0 && currentMonth === 0) {
|
||||
@@ -92,27 +113,27 @@ describe('getChineseYearMonthAllDayInfos', () => {
|
||||
allMonthChineseDays[`${currentYear}-${currentMonth}`] = currentMonthChineseDays;
|
||||
allMonthSolarTermNames[`${currentYear}-${currentMonth}`] = currentMonthSolarTermNames;
|
||||
|
||||
return { allMonthChineseDays, allMonthSolarTermNames, perDayEntries };
|
||||
}
|
||||
|
||||
const { allMonthChineseDays, allMonthSolarTermNames, perDayEntries } = parseCalendarDataFile();
|
||||
|
||||
describe('getChineseYearMonthAllDayInfos', () => {
|
||||
for (const [yearMonth, monthChineseDays] of entries(allMonthChineseDays)) {
|
||||
test(`returns correct chinese all dates in month for ${yearMonth}`, () => {
|
||||
it(`should return correct chinese dates for all days in ${yearMonth}`, () => {
|
||||
const [yearStr, monthStr] = yearMonth.split('-');
|
||||
const year = parseInt(yearStr as string);
|
||||
const month = parseInt(monthStr as string);
|
||||
const expectedChineseMonthOrDays = monthChineseDays;
|
||||
const expectedSolarTermNames = allMonthSolarTermNames[yearMonth] as string[];
|
||||
|
||||
const actualChineseDates: ChineseYearMonthDayInfo[] | undefined = getChineseYearMonthAllDayInfos({
|
||||
year: year,
|
||||
month1base: month
|
||||
}, localeData);
|
||||
const actualChineseDates = getChineseYearMonthAllDayInfos({ year, month1base: month }, localeData);
|
||||
|
||||
expect(actualChineseDates).toBeDefined();
|
||||
|
||||
if (actualChineseDates) {
|
||||
for (const [actualChineseDate, index] of itemAndIndex(actualChineseDates)) {
|
||||
const chineseMonthOrDay: string | undefined = actualChineseDate?.day === 1 ? `${actualChineseDate?.month}${ordinalSuffix[actualChineseDate?.month - 1] ?? 'th'} Lunar Month`.toLowerCase() : actualChineseDate?.day.toString();
|
||||
|
||||
expect(actualChineseDate).toBeDefined();
|
||||
expect(chineseMonthOrDay).toBe(expectedChineseMonthOrDays[index]);
|
||||
expect(lunarMonthOrDayLabel(actualChineseDate!.month, actualChineseDate!.day)).toBe(monthChineseDays[index]);
|
||||
expect(actualChineseDate?.solarTermName).toBe(expectedSolarTermNames[index]);
|
||||
}
|
||||
}
|
||||
@@ -121,32 +142,12 @@ describe('getChineseYearMonthAllDayInfos', () => {
|
||||
});
|
||||
|
||||
describe('getChineseYearMonthDayInfo', () => {
|
||||
const lines: string[] = fs.readFileSync(path.join(__dirname, 'chinese_calendar_all_data.txt'), 'utf8').replace(/\r/g, '').split('\n');
|
||||
|
||||
for (const line of lines) {
|
||||
if (!line.trim() || line.startsWith('#')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const items = line.split('\t');
|
||||
const gregorianDate = items[0] as string;
|
||||
const gregorianDateItems = gregorianDate.split('/');
|
||||
const gregorianYear = parseInt(gregorianDateItems[0] as string);
|
||||
const gregorianMonth = parseInt(gregorianDateItems[1] as string);
|
||||
const gregorianDay = parseInt(gregorianDateItems[2] as string);
|
||||
const expectedChineseMonthOrDay = items[1] as string;
|
||||
const expectedSolarTermName = items.length > 3 ? items[3] as string : '';
|
||||
|
||||
test(`returns correct chinese date for ${gregorianDate}`, () => {
|
||||
const actualChineseDate: ChineseYearMonthDayInfo | undefined = getChineseYearMonthDayInfo({
|
||||
year: gregorianYear,
|
||||
month: gregorianMonth,
|
||||
day: gregorianDay
|
||||
}, localeData);
|
||||
const actualChineseMonthOrDay: string | undefined = actualChineseDate?.day === 1 ? `${actualChineseDate?.month}${ordinalSuffix[actualChineseDate?.month - 1] ?? 'th'} Lunar Month`.toLowerCase() : actualChineseDate?.day.toString();
|
||||
for (const { gregorianDate, gregorianYear, gregorianMonth, gregorianDay, expectedChineseMonthOrDay, expectedSolarTermName } of perDayEntries) {
|
||||
it(`should return correct chinese date for ${gregorianDate}`, () => {
|
||||
const actualChineseDate = getChineseYearMonthDayInfo({ year: gregorianYear, month: gregorianMonth, day: gregorianDay }, localeData);
|
||||
|
||||
expect(actualChineseDate).toBeDefined();
|
||||
expect(actualChineseMonthOrDay).toBe(expectedChineseMonthOrDay.toLowerCase());
|
||||
expect(lunarMonthOrDayLabel(actualChineseDate!.month, actualChineseDate!.day)).toBe(expectedChineseMonthOrDay.toLowerCase());
|
||||
expect(actualChineseDate?.solarTermName).toBe(expectedSolarTermName);
|
||||
});
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"verbatimModuleSyntax": false
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -18,6 +18,6 @@
|
||||
"include": [
|
||||
"src/**/*",
|
||||
"vite.config.ts",
|
||||
"jest.config.ts"
|
||||
"vitest.config.ts"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
import { defineConfig } from 'vitest/config';
|
||||
import vue from '@vitejs/plugin-vue';
|
||||
import path from 'node:path';
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [vue()],
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': path.resolve(__dirname, './src')
|
||||
}
|
||||
},
|
||||
test: {
|
||||
environment: 'node',
|
||||
clearMocks: true,
|
||||
restoreMocks: true,
|
||||
mockReset: true,
|
||||
isolate: true,
|
||||
coverage: {
|
||||
provider: 'v8',
|
||||
reporter: ['text', 'html']
|
||||
}
|
||||
}
|
||||
})
|
||||
Reference in New Issue
Block a user