const test = require('node:test') const assert = require('node:assert/strict') const fs = require('node:fs') const path = require('node:path') const vm = require('node:vm') const ts = require('typescript') const exports_ = {} vm.runInNewContext(ts.transpileModule(fs.readFileSync(path.join(__dirname, '../src/utils/birthdayCalendar.ts'), 'utf8'), { compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2019 } }).outputText, { exports: exports_, require }) const { solarToLunarBirthday, lunarBirthdayToSolar, lunarBirthdayModel, changeLunarBirthdayColumn, formatLunarBirthday } = exports_ const max = '2026-10-18' test('阳历农历准确往返,闰月单列而不是重复普通月份', () => { for (const solar of ['1900-01-01', '1998-06-18', '2000-02-05', '2023-03-22', '2024-02-29', max]) { assert.equal(lunarBirthdayToSolar(solarToLunarBirthday(solar)), solar) } const leap = solarToLunarBirthday('2023-03-22') assert.equal(leap.year, 2023); assert.equal(leap.month, -2); assert.equal(leap.day, 1) assert.match(formatLunarBirthday('2023-03-22'), /闰二月初一/) const model = lunarBirthdayModel(leap, max) assert.ok(model.months.some(month => month.value === 2)) assert.ok(model.months.some(month => month.value === -2 && month.label === '闰二月')) }) test('小月天数、无闰月年份联动纠正,不生成无效生日', () => { const original = lunarBirthdayModel({ year: 2023, month: 2, day: 30 }, max) const leapIndex = original.months.findIndex(month => month.value === -2) const leap = changeLunarBirthdayColumn(original, 1, leapIndex, max) assert.equal(leap.month, -2); assert.equal(leap.day, 29) const leapModel = lunarBirthdayModel(leap, max) const next = changeLunarBirthdayColumn(leapModel, 0, leapModel.years.indexOf(2024), max) assert.equal(next.month, 2) assert.ok(lunarBirthdayToSolar(next)) assert.equal(lunarBirthdayToSolar({ year: 2023, month: -2, day: 30 }), null) assert.equal(lunarBirthdayToSolar({ year: 2024, month: -2, day: 1 }), null) }) test('边界年月日只包含1900至今天,农历跨年仍正确', () => { for (const solar of ['1900-01-01', max]) { const model = lunarBirthdayModel(solarToLunarBirthday(solar), max) for (const month of model.months) for (const day of month.days) { const candidate = lunarBirthdayToSolar({ year: model.selection.year, month: month.value, day }) assert.ok(candidate >= '1900-01-01' && candidate <= max) } } const current = lunarBirthdayModel({ year: 2026, month: 12, day: 30 }, max) assert.ok(lunarBirthdayToSolar(current.selection) <= max) assert.equal(solarToLunarBirthday('2026-02-30'), null) assert.equal(solarToLunarBirthday('2026-2-1'), null) }) test('同一生日两种输入不改变生肖与日主计算日期', () => { for (const solar of ['2000-02-04', '2000-02-05', '2023-03-22']) { const lunar = solarToLunarBirthday(solar) const input = lunarBirthdayModel(lunar, max) assert.equal(lunarBirthdayToSolar(input.selection), solar) } }) test('微信头像选择仅接收系统结果,不会再次调用媒体选择', () => { const source = fs.readFileSync(path.join(__dirname, '../src/pages/profile-edit/index.tsx'), 'utf8') assert.equal((source.match(/\? 'chooseAvatar' : undefined/g) || []).length, 1) const callback = source.match(/const handleWechatAvatar = [\s\S]*?\n }/)[0] assert.match(callback, /useAvatar\(event.detail.avatarUrl\)/) assert.doesNotMatch(callback, /chooseMedia|chooseFrom|chooseImage/) assert.doesNotMatch(source, /微信头像选择|wechat-avatar-action/) }) test('日期控件回显农历偏好,切换历法不修改实际生日或触发保存', () => { const component = {} const file = fs.readFileSync(path.join(__dirname, '../src/components/BirthdayPicker.tsx'), 'utf8') vm.runInNewContext(ts.transpileModule(file, { compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2019, jsx: ts.JsxEmit.ReactJSX } }).outputText, { exports: component, require: id => { if (id === 'react') return { useState: initial => [initial(), () => {}], useEffect: () => {}, useMemo: fn => fn() } if (id.endsWith('/birthdayCalendar')) return exports_ if (id === '@tarojs/components') return { View: 'View', Text: 'Text', Button: 'Button', Picker: 'Picker' } return require(id) } }) const modes = [], dates = [] const tree = component.BirthdayPicker({ value: '2023-03-22', calendar: 'lunar', onChange: value => dates.push(value), onCalendarChange: mode => modes.push(mode) }) const collect = node => { if (!node || typeof node !== 'object') return [] if (Array.isArray(node)) return node.flatMap(collect) return [node, ...collect(node.props?.children)] } const nodes = collect(tree) const lunar = nodes.find(node => node.props?.['aria-label'] === '选择农历') assert.match(lunar.props.className, /active/) nodes.find(node => node.props?.['aria-label'] === '选择阳历').props.onClick() assert.deepEqual(modes, ['solar']); assert.deepEqual(dates, []) const picker = nodes.find(node => node.type === 'Picker') assert.equal(picker.props.mode, 'multiSelector') assert.ok(picker.props.range[1].includes('闰二月')) picker.props.onCancel() assert.deepEqual(dates, []) })