Feature/fix external subscription client expiry (#6333)

* fix(sub): honor client expiry for external links

* fix(ui): show client expiry on external links

* fix(sub): address external expiry review
This commit is contained in:
duqigit
2026-09-04 04:32:05 +08:00
committed by GitHub
parent 13e87a18c8
commit 2ddcf53020
16 changed files with 332 additions and 61 deletions
@@ -0,0 +1,17 @@
import { describe, expect, it } from 'vitest';
import { resolveExternalLinkExpiry } from '@/lib/clients/external-link';
describe('resolveExternalLinkExpiry', () => {
it('uses the client expiry when the external link has no specific expiry', () => {
expect(resolveExternalLinkExpiry(0, 1_800_000_000_000)).toBe(1_800_000_000_000);
});
it('keeps an explicit external-link expiry', () => {
expect(resolveExternalLinkExpiry(1_700_000_000_000, 1_800_000_000_000)).toBe(1_700_000_000_000);
});
it('stays empty when neither expiry is set', () => {
expect(resolveExternalLinkExpiry(0, 0)).toBe(0);
});
});
+53 -2
View File
@@ -1,11 +1,32 @@
import { fireEvent } from '@testing-library/react';
import { fireEvent, screen } from '@testing-library/react';
import dayjs from 'dayjs';
import type { Dayjs } from 'dayjs';
import { describe, expect, it, vi } from 'vitest';
import { afterEach, describe, expect, it, vi } from 'vitest';
import DateTimePicker from '@/components/form/DateTimePicker';
import { setDatepicker } from '@/hooks/useDatepicker';
import { renderWithProviders } from './test-utils';
vi.mock('persian-calendar-suite', () => ({
PersianDateTimePicker: ({
maxDate,
onChange,
}: {
maxDate?: Date;
onChange?: (value: number) => void;
}) => (
<button
type="button"
aria-label="Persian date time picker"
data-testid="persian-date-time-picker"
data-max-date={maxDate?.toISOString()}
onClick={() => onChange?.((maxDate?.getTime() ?? 0) + 1)}
/>
),
}));
afterEach(() => setDatepicker('gregorian'));
function openPicker(): void {
const input = document.querySelector('.ant-picker input');
if (!input) throw new Error('picker input not rendered');
@@ -40,4 +61,34 @@ describe('DateTimePicker', () => {
expect(document.querySelector('.ant-picker-ok')).toBeNull();
});
it('hides the Gregorian clear control and disables dates after maxDate', () => {
const maxDate = dayjs().add(1, 'day').startOf('day');
renderWithProviders(
<DateTimePicker value={maxDate} onChange={vi.fn()} allowClear={false} maxDate={maxDate} />,
);
expect(document.querySelector('.ant-picker-clear')).toBeNull();
openPicker();
const blockedCell = document.querySelector(
`.ant-picker-cell[title="${maxDate.add(1, 'day').format('YYYY-MM-DD')}"]`,
);
expect(blockedCell?.classList.contains('ant-picker-cell-disabled')).toBe(true);
});
it('applies clear and max-date constraints to the Jalali picker', () => {
setDatepicker('jalalian');
const maxDate = dayjs('2030-01-02T03:04:05');
const onChange = vi.fn();
renderWithProviders(
<DateTimePicker value={maxDate} onChange={onChange} allowClear={false} maxDate={maxDate} />,
);
expect(document.querySelector('.jdp-clear')).toBeNull();
expect(screen.getByTestId('persian-date-time-picker').dataset.maxDate).toBe(
maxDate.toDate().toISOString(),
);
fireEvent.click(screen.getByTestId('persian-date-time-picker'));
expect(onChange).not.toHaveBeenCalled();
});
});