mirror of
https://github.com/bookorbit/bookorbit.git
synced 2026-11-03 08:21:39 -06:00
test(books): cover same-day reading completion
Protect equal manual start and finish dates through the client and status API. Closes #1097
This commit is contained in:
@@ -358,6 +358,54 @@ describe('DetailsTab - present state', () => {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('allows the finished date to match the started date', async () => {
|
||||||
|
vi.mocked(api).mockImplementation(async (input, init) => {
|
||||||
|
if (input === '/api/v1/books/1/status' && init?.method === 'PATCH') {
|
||||||
|
return makeApiResponse({
|
||||||
|
status: 'read',
|
||||||
|
source: 'manual',
|
||||||
|
startedAt: '2026-04-10',
|
||||||
|
finishedAt: '2026-04-10',
|
||||||
|
updatedAt: '2026-04-10T00:00:00.000Z',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if (input === '/api/v1/collections/membership') return makeApiResponse([])
|
||||||
|
return makeApiResponse({}, false)
|
||||||
|
})
|
||||||
|
|
||||||
|
const wrapper = mount(DetailsTab, {
|
||||||
|
props: {
|
||||||
|
book: makeBook({
|
||||||
|
readStatus: {
|
||||||
|
status: 'reading',
|
||||||
|
source: 'manual',
|
||||||
|
startedAt: '2026-04-10',
|
||||||
|
finishedAt: null,
|
||||||
|
updatedAt: '2026-04-10T00:00:00.000Z',
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
global: globalStubs,
|
||||||
|
})
|
||||||
|
|
||||||
|
await wrapper.find('button[title="Edit date finished"]').trigger('click')
|
||||||
|
await wrapper.find('input[type="date"]').setValue('2026-04-10')
|
||||||
|
|
||||||
|
const saveButton = wrapper.findAll('button').find((button) => button.text() === 'Save')
|
||||||
|
expect(saveButton?.exists()).toBe(true)
|
||||||
|
await saveButton!.trigger('click')
|
||||||
|
await flushPromises()
|
||||||
|
|
||||||
|
expect(wrapper.text()).not.toContain('Date Finished must be on or after Date Started')
|
||||||
|
expect(vi.mocked(api)).toHaveBeenCalledWith(
|
||||||
|
'/api/v1/books/1/status',
|
||||||
|
expect.objectContaining({
|
||||||
|
method: 'PATCH',
|
||||||
|
body: JSON.stringify({ finishedAt: '2026-04-10' }),
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
it('shows validation for finished date earlier than started date and blocks save', async () => {
|
it('shows validation for finished date earlier than started date and blocks save', async () => {
|
||||||
vi.mocked(api).mockImplementation(async (input) => {
|
vi.mocked(api).mockImplementation(async (input) => {
|
||||||
if (input === '/api/v1/collections/membership') return makeApiResponse([])
|
if (input === '/api/v1/collections/membership') return makeApiResponse([])
|
||||||
|
|||||||
@@ -644,6 +644,14 @@ describe('Reading attempts main-flow simulation (docker e2e)', { timeout: TIMEOU
|
|||||||
expect((await listAttempts(bothDates.bookId)).items).toEqual([
|
expect((await listAttempts(bothDates.bookId)).items).toEqual([
|
||||||
expect.objectContaining({ startedOn: '2026-02-01', endedOn: '2026-02-10', outcome: 'completed', origin: 'manual' }),
|
expect.objectContaining({ startedOn: '2026-02-01', endedOn: '2026-02-10', outcome: 'completed', origin: 'manual' }),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
const sameDay = await createBook();
|
||||||
|
const sameDayResponse = await patchStatus(sameDay.bookId, { startedAt: '2026-02-15', finishedAt: '2026-02-15' });
|
||||||
|
expect(sameDayResponse.statusCode).toBe(200);
|
||||||
|
expect(sameDayResponse.json()).toMatchObject({ status: 'read', startedAt: '2026-02-15', finishedAt: '2026-02-15' });
|
||||||
|
expect((await listAttempts(sameDay.bookId)).items).toEqual([
|
||||||
|
expect.objectContaining({ startedOn: '2026-02-15', endedOn: '2026-02-15', outcome: 'completed', origin: 'manual' }),
|
||||||
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('27. closes active lifecycle states with a date-only finish patch', async () => {
|
it('27. closes active lifecycle states with a date-only finish patch', async () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user