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 {
|
||||
matched := value.Matched
|
||||
if matched == nil {
|
||||
matched = []string{}
|
||||
}
|
||||
missing := value.Missing
|
||||
if missing == nil {
|
||||
missing = []string{}
|
||||
}
|
||||
return webmodel.CandidateResponse{
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
score: 90,
|
||||
matchedTraits: ['Go'],
|
||||
missingTraits: [],
|
||||
missingTraits: null,
|
||||
},
|
||||
])
|
||||
if (path === '/api/jobs/7/invitations' && method === 'GET') return response([])
|
||||
|
|
@ -129,6 +129,17 @@ describe('Go Guess frontend', () => {
|
|||
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 () => {
|
||||
const user = userEvent.setup()
|
||||
window.history.replaceState({}, '', '/login')
|
||||
|
|
|
|||
|
|
@ -115,7 +115,14 @@ export const api = {
|
|||
}),
|
||||
detachQuestion: (jobId: number, questionId: number) =>
|
||||
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`),
|
||||
invitation: (jobId: number, invitationId: number) =>
|
||||
request<Interview>(`/jobs/${jobId}/invitations/${invitationId}`),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue