93 lines
3.6 KiB
TypeScript
93 lines
3.6 KiB
TypeScript
|
|
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
||
|
|
import { render, screen, waitFor } from '@testing-library/react'
|
||
|
|
import userEvent from '@testing-library/user-event'
|
||
|
|
import { MemoryRouter } from 'react-router-dom'
|
||
|
|
import AddPage from '../src/pages/AddPage.js'
|
||
|
|
import { api, ApiError } from '../src/api.js'
|
||
|
|
import type { Candidate, ReleasePreview } from '../src/types.js'
|
||
|
|
|
||
|
|
vi.mock('../src/api.js', async (importOriginal) => {
|
||
|
|
const actual = await importOriginal<typeof import('../src/api.js')>()
|
||
|
|
return { ...actual, api: { ...actual.api, lookupSearch: vi.fn(), getReleasePreview: vi.fn(), addToCollection: vi.fn() } }
|
||
|
|
})
|
||
|
|
|
||
|
|
const candidate: Candidate = {
|
||
|
|
id: 1001,
|
||
|
|
artist: 'The Cinematic Orchestra',
|
||
|
|
title: 'Motion',
|
||
|
|
year: 1999,
|
||
|
|
formats: ['Vinyl'],
|
||
|
|
labels: ['Ninja Tune'],
|
||
|
|
country: 'UK',
|
||
|
|
catno: 'ZEN012',
|
||
|
|
thumbUrl: null,
|
||
|
|
}
|
||
|
|
|
||
|
|
const preview: ReleasePreview = {
|
||
|
|
release: { ...candidate, genres: [], tracklist: [], coverUrl: null, barcodes: [] },
|
||
|
|
duplicate: false,
|
||
|
|
ripMatch: 'not_ripped',
|
||
|
|
matchCandidates: [],
|
||
|
|
}
|
||
|
|
|
||
|
|
// The api module is mocked directly, so mocks resolve with parsed bodies.
|
||
|
|
function jsonOk(body: unknown) {
|
||
|
|
return Promise.resolve(body)
|
||
|
|
}
|
||
|
|
|
||
|
|
beforeEach(() => {
|
||
|
|
vi.mocked(api.lookupSearch).mockReset()
|
||
|
|
vi.mocked(api.getReleasePreview).mockReset()
|
||
|
|
vi.mocked(api.addToCollection).mockReset()
|
||
|
|
})
|
||
|
|
|
||
|
|
function renderAdd(initialEntry = '/add') {
|
||
|
|
return render(
|
||
|
|
<MemoryRouter initialEntries={[initialEntry]}>
|
||
|
|
<AddPage />
|
||
|
|
</MemoryRouter>
|
||
|
|
)
|
||
|
|
}
|
||
|
|
|
||
|
|
describe('AddPage', () => {
|
||
|
|
it('searches discogs and shows candidate cards', async () => {
|
||
|
|
vi.mocked(api.lookupSearch).mockResolvedValue(jsonOk({ candidates: [candidate] }) as never)
|
||
|
|
renderAdd()
|
||
|
|
await userEvent.type(screen.getByPlaceholderText(/artist and title/i), 'cinematic orchestra motion{Enter}')
|
||
|
|
await waitFor(() =>
|
||
|
|
expect(api.lookupSearch).toHaveBeenCalledWith('cinematic orchestra motion', undefined)
|
||
|
|
)
|
||
|
|
expect(await screen.findByRole('button', { name: /motion/i })).toBeTruthy()
|
||
|
|
})
|
||
|
|
|
||
|
|
it('passes the format filter and pre-filled query from the URL', async () => {
|
||
|
|
vi.mocked(api.lookupSearch).mockResolvedValue(jsonOk({ candidates: [] }) as never)
|
||
|
|
renderAdd('/add?q=5021592210629')
|
||
|
|
expect((screen.getByPlaceholderText(/artist and title/i) as HTMLInputElement).value).toBe(
|
||
|
|
'5021592210629'
|
||
|
|
)
|
||
|
|
await userEvent.selectOptions(screen.getByLabelText(/format/i), 'Vinyl')
|
||
|
|
await userEvent.click(screen.getByRole('button', { name: /^search$/i }))
|
||
|
|
await waitFor(() => expect(api.lookupSearch).toHaveBeenCalledWith('5021592210629', 'Vinyl'))
|
||
|
|
})
|
||
|
|
|
||
|
|
it('shows a not-found message', async () => {
|
||
|
|
vi.mocked(api.lookupSearch).mockRejectedValue(new ApiError(404, 'not_found'))
|
||
|
|
renderAdd()
|
||
|
|
await userEvent.type(screen.getByPlaceholderText(/artist and title/i), 'zzz{Enter}')
|
||
|
|
await waitFor(() => expect(screen.getByText(/nothing found/i)).toBeTruthy())
|
||
|
|
})
|
||
|
|
|
||
|
|
it('selecting a candidate loads the confirm view and adds', async () => {
|
||
|
|
vi.mocked(api.lookupSearch).mockResolvedValue(jsonOk({ candidates: [candidate] }) as never)
|
||
|
|
vi.mocked(api.getReleasePreview).mockResolvedValue(jsonOk(preview) as never)
|
||
|
|
vi.mocked(api.addToCollection).mockResolvedValue(jsonOk({}) as never)
|
||
|
|
renderAdd()
|
||
|
|
await userEvent.type(screen.getByPlaceholderText(/artist and title/i), 'motion{Enter}')
|
||
|
|
await userEvent.click(await screen.findByRole('button', { name: /motion/i }))
|
||
|
|
await waitFor(() => expect(screen.getByText('Not ripped yet')).toBeTruthy())
|
||
|
|
await userEvent.click(screen.getByRole('button', { name: /add to collection/i }))
|
||
|
|
await waitFor(() => expect(api.addToCollection).toHaveBeenCalledWith({ releaseId: 1001 }))
|
||
|
|
})
|
||
|
|
})
|