mirror of
https://github.com/Dispatcharr/Dispatcharr.git
synced 2026-07-18 00:55:50 +00:00
Merge branch 'dev' of https://github.com/Dispatcharr/Dispatcharr into dev
This commit is contained in:
commit
44d86ebfc0
2 changed files with 104 additions and 29 deletions
|
|
@ -114,6 +114,7 @@ export default function TVChannelGuide({ startDate, endDate }) {
|
|||
const [recordingForProgram, setRecordingForProgram] = useState(null);
|
||||
const [recordChoiceOpen, setRecordChoiceOpen] = useState(false);
|
||||
const [recordChoiceProgram, setRecordChoiceProgram] = useState(null);
|
||||
const [recordChoiceChannel, setRecordChoiceChannel] = useState(null);
|
||||
const [existingRuleMode, setExistingRuleMode] = useState(null);
|
||||
const [rulesOpen, setRulesOpen] = useState(false);
|
||||
const [rules, setRules] = useState([]);
|
||||
|
|
@ -709,8 +710,9 @@ export default function TVChannelGuide({ startDate, endDate }) {
|
|||
);
|
||||
|
||||
const openRecordChoice = useCallback(
|
||||
async (program) => {
|
||||
async (program, channel) => {
|
||||
setRecordChoiceProgram(program);
|
||||
setRecordChoiceChannel(channel);
|
||||
setRecordChoiceOpen(true);
|
||||
try {
|
||||
const rules = await fetchRules();
|
||||
|
|
@ -726,8 +728,7 @@ export default function TVChannelGuide({ startDate, endDate }) {
|
|||
);
|
||||
|
||||
const recordOne = useCallback(
|
||||
async (program) => {
|
||||
const channel = findChannelByTvgId(program.tvg_id);
|
||||
async (program, channel) => {
|
||||
if (!channel) {
|
||||
showNotification({
|
||||
title: 'Unable to schedule recording',
|
||||
|
|
@ -740,7 +741,7 @@ export default function TVChannelGuide({ startDate, endDate }) {
|
|||
await createRecording(channel, program);
|
||||
showNotification({ title: 'Recording scheduled' });
|
||||
},
|
||||
[findChannelByTvgId]
|
||||
[]
|
||||
);
|
||||
|
||||
const saveSeriesRule = useCallback(async (program, mode) => {
|
||||
|
|
@ -1463,7 +1464,7 @@ export default function TVChannelGuide({ startDate, endDate }) {
|
|||
program={recordChoiceProgram}
|
||||
recording={recordingForProgram}
|
||||
existingRuleMode={existingRuleMode}
|
||||
onRecordOne={() => recordOne(recordChoiceProgram)}
|
||||
onRecordOne={() => recordOne(recordChoiceProgram, recordChoiceChannel)}
|
||||
onRecordSeriesAll={() =>
|
||||
saveSeriesRule(recordChoiceProgram, 'all')
|
||||
}
|
||||
|
|
@ -1500,7 +1501,7 @@ export default function TVChannelGuide({ startDate, endDate }) {
|
|||
recording={recordingForProgram}
|
||||
opened={!!selectedProgram}
|
||||
onClose={handleCloseModal}
|
||||
onRecord={openRecordChoice}
|
||||
onRecord={(program) => openRecordChoice(program, selectedChannel)}
|
||||
/>
|
||||
</Suspense>
|
||||
</ErrorBoundary>
|
||||
|
|
|
|||
|
|
@ -158,7 +158,7 @@ vi.mock('react-window', () => ({
|
|||
{children({
|
||||
index: i,
|
||||
style: {},
|
||||
data: itemData.filteredChannels[i],
|
||||
data: itemData,
|
||||
})}
|
||||
</div>
|
||||
))}
|
||||
|
|
@ -167,10 +167,42 @@ vi.mock('react-window', () => ({
|
|||
}));
|
||||
|
||||
vi.mock('../../components/GuideRow', () => ({
|
||||
default: ({ data }) => (
|
||||
<div data-testid="guide-row">GuideRow for {data?.name}</div>
|
||||
),
|
||||
default: ({ index, data }) => {
|
||||
const channel = data?.filteredChannels?.[index];
|
||||
const channelPrograms = data?.programsByChannelId?.get(channel?.id) || [];
|
||||
const program = channelPrograms[0] || {
|
||||
id: 'prog-1',
|
||||
tvg_id: 'tvg-1',
|
||||
title: 'Test Program 1',
|
||||
channel_id: channel?.id,
|
||||
start_time: '2024-01-15T12:00:00Z',
|
||||
end_time: '2024-01-15T13:00:00Z',
|
||||
programStart: dayjs('2024-01-15T12:00:00Z'),
|
||||
programEnd: dayjs('2024-01-15T13:00:00Z'),
|
||||
startMs: dayjs('2024-01-15T12:00:00Z').valueOf(),
|
||||
endMs: dayjs('2024-01-15T13:00:00Z').valueOf(),
|
||||
};
|
||||
|
||||
return (
|
||||
<div data-testid="guide-row">
|
||||
GuideRow for {channel?.name}
|
||||
<button
|
||||
data-testid="guide-row-select"
|
||||
onClick={() => {
|
||||
// renderProgram embeds the click handler — call it directly
|
||||
const fakeEvent = { stopPropagation: () => {}, preventDefault: () => {} };
|
||||
// renderProgram returns a Box with onClick — extract and call it
|
||||
const rendered = data?.renderProgram?.(program, undefined, channel);
|
||||
rendered?.props?.onClick?.(fakeEvent);
|
||||
}}
|
||||
>
|
||||
Select program
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
}));
|
||||
|
||||
vi.mock('../../components/HourTimeline', () => ({
|
||||
default: ({ hourTimeline }) => (
|
||||
<div data-testid="hour-timeline">
|
||||
|
|
@ -559,43 +591,85 @@ describe('Guide', () => {
|
|||
});
|
||||
|
||||
describe('Recording Functionality', () => {
|
||||
it('opens Series Rules modal when button is clicked', async () => {
|
||||
it('opens Program Recording modal when Record One is clicked', async () => {
|
||||
vi.useRealTimers();
|
||||
|
||||
const user = userEvent.setup();
|
||||
render(<Guide />);
|
||||
|
||||
const rulesButton = await screen.findByText('Series Rules');
|
||||
await user.click(rulesButton);
|
||||
const selectButtons = await screen.findAllByTestId('guide-row-select');
|
||||
await user.click(selectButtons[0]);
|
||||
|
||||
await waitFor(() =>
|
||||
expect(screen.getByTestId('program-detail-modal')).toBeInTheDocument()
|
||||
);
|
||||
|
||||
fireEvent.click(screen.getByText('Record'));
|
||||
|
||||
await waitFor(() =>
|
||||
expect(screen.getByTestId('program-recording-modal')).toBeInTheDocument()
|
||||
);
|
||||
|
||||
fireEvent.click(screen.getByText('Record One'));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(
|
||||
screen.getByTestId('series-recording-modal')
|
||||
).toBeInTheDocument();
|
||||
expect(guideUtils.createRecording).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
vi.useFakeTimers();
|
||||
vi.setSystemTime(new Date('2024-01-15T12:00:00Z'));
|
||||
});
|
||||
|
||||
it('fetches rules when opening Series Rules modal', async () => {
|
||||
it('uses selected channel for recordOne instead of tvg_id fallback', async () => {
|
||||
vi.useRealTimers();
|
||||
|
||||
const mockRules = [{ id: 1, title: 'Test Rule' }];
|
||||
guideUtils.fetchRules.mockResolvedValue(mockRules);
|
||||
API.getAllChannelIds.mockResolvedValue(['channel-1']);
|
||||
API.getChannelsSummary.mockResolvedValue([mockChannelsState.channels['channel-1']]);
|
||||
guideUtils.filterGuideChannels.mockImplementation((channels) =>
|
||||
Array.isArray(channels) ? channels : Object.values(channels)
|
||||
);
|
||||
|
||||
const program = {
|
||||
id: 'prog-1',
|
||||
tvg_id: 'tvg-1',
|
||||
title: 'Test Program 1',
|
||||
channel_id: 'channel-1',
|
||||
start_time: now.toISOString(),
|
||||
end_time: now.add(1, 'hour').toISOString(),
|
||||
programStart: now,
|
||||
programEnd: now.add(1, 'hour'),
|
||||
startMs: now.valueOf(),
|
||||
endMs: now.add(1, 'hour').valueOf(),
|
||||
};
|
||||
|
||||
guideUtils.fetchPrograms.mockResolvedValue([program]);
|
||||
|
||||
const user = userEvent.setup();
|
||||
render(<Guide />);
|
||||
|
||||
const rulesButton = await screen.findByText('Series Rules');
|
||||
await user.click(rulesButton);
|
||||
await waitFor(() =>
|
||||
expect(screen.getAllByTestId('guide-row').length).toBeGreaterThan(0)
|
||||
);
|
||||
|
||||
// Use userEvent instead of fireEvent so microtasks (Suspense lazy resolution) are flushed
|
||||
const user = userEvent.setup({ delay: null });
|
||||
|
||||
await user.click(screen.getByTestId('guide-row-select'));
|
||||
|
||||
await waitFor(() =>
|
||||
expect(screen.getByTestId('program-detail-modal')).toBeInTheDocument()
|
||||
);
|
||||
|
||||
await user.click(screen.getByText('Record'));
|
||||
|
||||
await waitFor(() =>
|
||||
expect(screen.getByTestId('program-recording-modal')).toBeInTheDocument()
|
||||
);
|
||||
|
||||
await user.click(screen.getByText('Record One'));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(guideUtils.fetchRules).toHaveBeenCalled();
|
||||
expect(guideUtils.createRecording).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ id: 'channel-1' }),
|
||||
expect.objectContaining({ id: 'prog-1' })
|
||||
);
|
||||
});
|
||||
|
||||
vi.useFakeTimers();
|
||||
vi.setSystemTime(new Date('2024-01-15T12:00:00Z'));
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue