82 lines
3.2 KiB
JavaScript
82 lines
3.2 KiB
JavaScript
// Typing a name in full must reach the same employee as picking it off the list.
|
|
//
|
|
// Both pickers turned a typed name straight into `NAME:<text>` - a free-text
|
|
// label linked to nothing. On screen the chip is identical to a real
|
|
// selection, so the difference only shows up later: no photo, no directory
|
|
// record, and a recognition that cannot be found by the person it is about.
|
|
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
|
|
|
vi.mock('../api', () => ({
|
|
employeesApi: { search: vi.fn() }
|
|
}))
|
|
|
|
import { employeesApi } from '../api'
|
|
import { resolveEmployeeName } from './employeeResolve'
|
|
|
|
const DANA = { SSO: 270015376, First_Name: 'Dana', Last_Name: 'Reyes' }
|
|
const DANA_HYPHEN = { SSO: 270099999, First_Name: 'Dana', Last_Name: 'Reyes-Smith' }
|
|
const SAM = { SSO: 270000001, First_Name: 'Sam', Last_Name: 'Reyes' }
|
|
|
|
function found(rows) {
|
|
employeesApi.search.mockResolvedValue({ data: { data: rows } })
|
|
}
|
|
|
|
describe('resolveEmployeeName', () => {
|
|
beforeEach(() => employeesApi.search.mockReset())
|
|
|
|
it('resolves a full name to the employee', async () => {
|
|
found([DANA])
|
|
const { match } = await resolveEmployeeName('Dana Reyes')
|
|
expect(match.SSO).toBe(270015376)
|
|
})
|
|
|
|
it('prefers an exact full-name match over a longer partial one', async () => {
|
|
// Searching "Dana Reyes" also returns "Dana Reyes-Smith"; the person who
|
|
// typed the shorter name meant the shorter name.
|
|
found([DANA, DANA_HYPHEN])
|
|
const { match, matches } = await resolveEmployeeName('Dana Reyes')
|
|
expect(matches).toBeUndefined()
|
|
expect(match.SSO).toBe(270015376)
|
|
})
|
|
|
|
it('refuses to guess between genuinely ambiguous matches', async () => {
|
|
found([DANA, SAM])
|
|
const { match, matches } = await resolveEmployeeName('Reyes')
|
|
expect(match).toBeUndefined()
|
|
expect(matches).toHaveLength(2)
|
|
})
|
|
|
|
it('reports nothing found, so the caller may fall back to a label', async () => {
|
|
found([])
|
|
const result = await resolveEmployeeName('Somebody External')
|
|
expect(result.match).toBeUndefined()
|
|
expect(result.matches).toBeUndefined()
|
|
expect(result.failed).toBeUndefined()
|
|
})
|
|
|
|
it('says the lookup FAILED rather than reporting nobody', async () => {
|
|
// The difference matters: "not in the directory" may become a custom
|
|
// label, "could not ask" must not.
|
|
// A THENABLE that calls its reject callback, rather than a mock returning
|
|
// a rejected promise. The await sees the same failure, but no rejected
|
|
// promise object exists for the runner to collect as an unhandled error -
|
|
// which it does even when the code under test catches it, failing the very
|
|
// test that proves the catch works.
|
|
employeesApi.search.mockImplementationOnce(() => {
|
|
const failure = new Error('network down')
|
|
return { then: (_ok, fail) => fail(failure) }
|
|
})
|
|
// resolves.toEqual, so the runner sees the rejection consumed by an
|
|
// assertion rather than as an unhandled error of its own.
|
|
await expect(resolveEmployeeName('Dana Reyes')).resolves.toEqual({
|
|
failed: true
|
|
})
|
|
})
|
|
|
|
it('does not call the directory for an empty box', async () => {
|
|
const result = await resolveEmployeeName(' ')
|
|
expect(employeesApi.search).not.toHaveBeenCalled()
|
|
expect(result).toEqual({})
|
|
})
|
|
})
|