import React from 'react';
import { fireEvent, render } from '@testing-library/react-native';
import DatePickerRangeView from '../date-picker-range-view';
jest.mock('@xrnjs/ui', () => ({
Button: ({ children, onPress }: any) => {
const React = require('react');
const { Text } = require('react-native');
return React.createElement(Text, { onPress }, children);
},
Fill: {
weak: 'weak',
outline: 'outline',
},
}));
jest.mock('../../date-picker-view', () => {
return function MockDatePickerView() {
return null;
};
});
jest.mock('../../date-picker-view/helper', () => ({
formatDate: (_mode: string, day: Date) =>
`${day.getFullYear()}-${day.getMonth() + 1}-${day.getDate()}`,
}));
jest.mock('../../../components/Locale/locale', () => ({
useLocale: () => ({
DatePickerRangeView: {
labelStartTime: '开始时间',
labelEndTime: '结束时间',
placeholder: ['请选择开始时间', '请选择结束时间'],
resetButtonText: '重置',
confirmButtonText: '确认',
clearButtonText: '清空',
},
}),
useLangType: () => 'zh_CN',
}));
jest.mock('../../picker/style', () => ({
varCreator: () => ({
picker_action_gap: 0,
}),
styleCreator: () => ({
data_range: {},
data_range_item: {},
data_range_text: {},
data_range_day: {},
data_range_day_active: {},
}),
}));
jest.mock('../../button/style', () => ({
varCreator: () => ({
button_active_opacity: 1,
}),
}));
jest.mock('../../row', () => {
return function MockRow({ children }: any) {
const React = require('react');
const { View } = require('react-native');
return {children};
};
});
jest.mock('../../col', () => {
return function MockCol({ children }: any) {
const React = require('react');
const { View } = require('react-native');
return {children};
};
});
jest.mock('../../theme', () => ({
__esModule: true,
default: {
useThemeTokens: () => ({}),
createVar: (_tokens: any, creator: any) => creator(),
createStyle: (_vars: any, creator: any) => creator(),
},
}));
jest.mock('../../hooks', () => ({
usePersistFn: (fn: any) => {
const React = require('react');
return React.useCallback(fn, []);
},
}));
describe('DatePickerRangeView', () => {
test('does not auto emit partial range on mount', () => {
const onChange = jest.fn();
render(
);
expect(onChange).not.toHaveBeenCalled();
});
test('reset keeps empty range instead of auto filling start date', () => {
const onChange = jest.fn();
const { getByText } = render(
);
fireEvent.press(getByText('重置'));
expect(onChange).toHaveBeenLastCalledWith([null, null]);
});
test('invalid end date falls back to placeholder instead of NaN text', () => {
const { queryByText, getByText } = render(
);
expect(queryByText('NaN-NaN')).toBeNull();
expect(getByText('请选择结束时间')).toBeTruthy();
});
test('switching to end date does not auto fill end value', () => {
const onChange = jest.fn();
const { getByText } = render(
);
fireEvent.press(getByText('结束时间'));
expect(onChange).not.toHaveBeenCalled();
});
test('reset then switch to end date shows correct placeholders', () => {
const onChange = jest.fn();
const Wrapper = () => {
const [val, setVal] = React.useState<[Date | null, Date | null]>([
new Date('2026-03-27'),
new Date('2026-03-28'),
]);
return (
{
setVal(v);
onChange(v);
}}
/>
);
};
const { getByText } = render();
// Reset to initialValue [null, null]
fireEvent.press(getByText('重置'));
expect(onChange).toHaveBeenLastCalledWith([null, null]);
// Switch to end date tab — should not crash or auto-fill
fireEvent.press(getByText('结束时间'));
// Both placeholders should appear since value is [null, null]
expect(getByText('请选择开始时间')).toBeTruthy();
expect(getByText('请选择结束时间')).toBeTruthy();
});
test('reset with non-null initialValue restores original dates', () => {
const initStart = new Date('2025-06-01');
const initEnd = new Date('2025-06-15');
const onChange = jest.fn();
const { getByText } = render(
);
fireEvent.press(getByText('重置'));
const lastCall = onChange.mock.calls[onChange.mock.calls.length - 1][0];
expect(lastCall[0].getTime()).toBe(initStart.getTime());
expect(lastCall[1].getTime()).toBe(initEnd.getTime());
});
test('confirm fills both values when only start is set', () => {
const onConfirm = jest.fn();
const onChange = jest.fn();
const start = new Date('2026-05-10');
const { getByText } = render(
);
fireEvent.press(getByText('确认'));
// ensureCompleteRangeValue should fill end = start when end is null
if (onConfirm.mock.calls.length > 0) {
const confirmed = onConfirm.mock.calls[0][0];
expect(confirmed[0]).toBeInstanceOf(Date);
expect(confirmed[1]).toBeInstanceOf(Date);
// end should be >= start
expect(confirmed[1].getTime()).toBeGreaterThanOrEqual(
confirmed[0].getTime()
);
}
});
test('switching start→end→start does not lose dates', () => {
const onChange = jest.fn();
const start = new Date('2026-04-01');
const end = new Date('2026-04-15');
const { getByText } = render(
);
fireEvent.press(getByText('结束时间'));
fireEvent.press(getByText('开始时间'));
// Dates should still be displayed, not replaced by placeholders
expect(getByText('2026-4-1')).toBeTruthy();
expect(getByText('2026-4-15')).toBeTruthy();
});
});