fix: handle empty candidate trait lists
Return empty JSON arrays from the API and normalize nullable values from older servers before rendering candidate match counts. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
parent
6969f79015
commit
fd06fbbb5d
4 changed files with 36 additions and 3 deletions
|
|
@ -66,9 +66,17 @@ func ParticipantToWeb(value servicemodel.Participant) webmodel.ParticipantRespon
|
||||||
}
|
}
|
||||||
|
|
||||||
func CandidateToWeb(value servicemodel.CandidateMatch) webmodel.CandidateResponse {
|
func CandidateToWeb(value servicemodel.CandidateMatch) webmodel.CandidateResponse {
|
||||||
|
matched := value.Matched
|
||||||
|
if matched == nil {
|
||||||
|
matched = []string{}
|
||||||
|
}
|
||||||
|
missing := value.Missing
|
||||||
|
if missing == nil {
|
||||||
|
missing = []string{}
|
||||||
|
}
|
||||||
return webmodel.CandidateResponse{
|
return webmodel.CandidateResponse{
|
||||||
Participant: ParticipantToWeb(value.Participant), Score: value.Score,
|
Participant: ParticipantToWeb(value.Participant), Score: value.Score,
|
||||||
Matched: value.Matched, Missing: value.Missing,
|
Matched: matched, Missing: missing,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,3 +19,10 @@ func TestInterviewOmitsReferenceAnswer(t *testing.T) {
|
||||||
t.Fatalf("expected participant-safe code question, got %#v", response)
|
t.Fatalf("expected participant-safe code question, got %#v", response)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCandidateAlwaysUsesJSONArrays(t *testing.T) {
|
||||||
|
response := CandidateToWeb(servicemodel.CandidateMatch{})
|
||||||
|
if response.Matched == nil || response.Missing == nil {
|
||||||
|
t.Fatalf("candidate trait collections must not be nil: %#v", response)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,7 @@ function mockApi() {
|
||||||
participant,
|
participant,
|
||||||
score: 90,
|
score: 90,
|
||||||
matchedTraits: ['Go'],
|
matchedTraits: ['Go'],
|
||||||
missingTraits: [],
|
missingTraits: null,
|
||||||
},
|
},
|
||||||
])
|
])
|
||||||
if (path === '/api/jobs/7/invitations' && method === 'GET') return response([])
|
if (path === '/api/jobs/7/invitations' && method === 'GET') return response([])
|
||||||
|
|
@ -129,6 +129,17 @@ describe('Go Guess frontend', () => {
|
||||||
mockApi()
|
mockApi()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('renders candidate matches when an older API returns null trait arrays', async () => {
|
||||||
|
authenticate()
|
||||||
|
const user = userEvent.setup()
|
||||||
|
renderApp('/jobs/7')
|
||||||
|
|
||||||
|
await user.click(await screen.findByRole('tab', { name: /candidate match/i }))
|
||||||
|
|
||||||
|
expect(await screen.findByText('90%')).toBeInTheDocument()
|
||||||
|
expect(screen.getByText('Missing').nextElementSibling).toHaveTextContent('0')
|
||||||
|
})
|
||||||
|
|
||||||
it('persists login, navigates from the login URL, and shows API jobs', async () => {
|
it('persists login, navigates from the login URL, and shows API jobs', async () => {
|
||||||
const user = userEvent.setup()
|
const user = userEvent.setup()
|
||||||
window.history.replaceState({}, '', '/login')
|
window.history.replaceState({}, '', '/login')
|
||||||
|
|
|
||||||
|
|
@ -115,7 +115,14 @@ export const api = {
|
||||||
}),
|
}),
|
||||||
detachQuestion: (jobId: number, questionId: number) =>
|
detachQuestion: (jobId: number, questionId: number) =>
|
||||||
request<void>(`/jobs/${jobId}/questions/${questionId}`, { method: 'DELETE' }),
|
request<void>(`/jobs/${jobId}/questions/${questionId}`, { method: 'DELETE' }),
|
||||||
candidates: (jobId: number) => request<CandidateMatch[]>(`/jobs/${jobId}/candidates`),
|
candidates: async (jobId: number) => {
|
||||||
|
const matches = await request<CandidateMatch[]>(`/jobs/${jobId}/candidates`)
|
||||||
|
return matches.map((match) => ({
|
||||||
|
...match,
|
||||||
|
matchedTraits: match.matchedTraits ?? [],
|
||||||
|
missingTraits: match.missingTraits ?? [],
|
||||||
|
}))
|
||||||
|
},
|
||||||
invitations: (jobId: number) => request<Invitation[]>(`/jobs/${jobId}/invitations`),
|
invitations: (jobId: number) => request<Invitation[]>(`/jobs/${jobId}/invitations`),
|
||||||
invitation: (jobId: number, invitationId: number) =>
|
invitation: (jobId: number, invitationId: number) =>
|
||||||
request<Interview>(`/jobs/${jobId}/invitations/${invitationId}`),
|
request<Interview>(`/jobs/${jobId}/invitations/${invitationId}`),
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue