Show an added idea's true status and let Find ideas search typed text
CI / ci (push) Successful in 5m41s
CI / ci (pull_request) Successful in 5m43s

F-02: adding an idea to the Quest log answers an existing dinner as it is,
so it can come back as a Regular. useAddIdeaToQuestLog now resolves with
the dinner and its status (quest_log or regular, anything else an error),
and Cook from what I have and Quick dinners show "In the Quest log" or
"Already a Regular" from it; Quick dinners keeps the status per idea for
the session.

F-03: Find ideas is enabled by a chip or by nonblank text typed and not
yet added, which the search already lists.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-09 10:56:14 -04:00
co-authored by Claude Opus 5.5
parent 47a5b5cb89
commit 2b96dea5d8
5 changed files with 146 additions and 30 deletions
+49
View File
@@ -203,6 +203,22 @@ describe('CookFromPantryPage', () => {
expect(chips()).toHaveLength(4)
})
it('enables Find ideas for text typed and not yet added, and searches it', async () => {
const { fetchMock } = stubServer({ [FIND]: () => jsonResponse(202, { jobId: 'j1' }) })
await renderPage()
fireEvent.change(input(), { target: { value: ' ' } })
expect(findButton()).toBeDisabled()
fireEvent.change(input(), { target: { value: 'Chicken thighs' } })
expect(chips()).toEqual([])
expect(findButton()).toBeEnabled()
fireEvent.click(findButton())
await waitFor(() => expect(calls(fetchMock, FIND)).toHaveLength(1))
expect(bodyOf(calls(fetchMock, FIND)[0]!)).toEqual({ ingredients: ['Chicken thighs'], quick_only: false })
expect(chips()).toEqual(['Chicken thighs'])
})
it('removes a chip with its cross, or the last one with Backspace in the empty input', async () => {
stubServer({})
await renderPage()
@@ -348,6 +364,39 @@ describe('CookFromPantryPage', () => {
expect(within(card(CURRY.name)).getByRole('button', { name: 'Add to Quest log' })).toBeEnabled()
})
it('says an idea that came back as an existing Regular is already a Regular, not in the Quest log', async () => {
const { fetchMock, jobs } = stubServer({
[FIND]: () => jsonResponse(202, { jobId: 'j1' }),
'POST /api/v1/ideas/j1/items/0/quest-log': () =>
jsonResponse(200, dinnerBody('dn-reg', 'Coconut Chicken Curry', { status: 'regular' })),
})
jobs.j1 = state('succeeded', 'done', [CURRY])
await renderPage()
await searched(fetchMock)
const curry = within(await screen.findByRole('article', { name: CURRY.name }))
fireEvent.click(curry.getByRole('button', { name: 'Add to Quest log' }))
expect(await curry.findByRole('status')).toHaveTextContent('Already a Regular')
expect(curry.queryByText('In the Quest log')).toBeNull()
})
it('fails on a dinner whose status is neither quest_log nor regular', async () => {
const { fetchMock, jobs } = stubServer({
[FIND]: () => jsonResponse(202, { jobId: 'j1' }),
'POST /api/v1/ideas/j1/items/0/quest-log': () => jsonResponse(200, dinnerBody('dn-1', CURRY.name, { status: 'suggested' })),
})
jobs.j1 = state('succeeded', 'done', [CURRY])
await renderPage()
await searched(fetchMock)
const curry = within(await screen.findByRole('article', { name: CURRY.name }))
fireEvent.click(curry.getByRole('button', { name: 'Add to Quest log' }))
expect(await curry.findByRole('alert')).toHaveTextContent(
'POST /api/v1/ideas/j1/items/0/quest-log: status "suggested" is not one of quest_log, regular',
)
expect(curry.queryByRole('status')).toBeNull()
})
it('shows its failure on its card and lets it be pressed again', async () => {
let fail = true
const { fetchMock, jobs } = stubServer({