@defra-fish/sales-api-service
Version:
Rod Licensing Sales API
403 lines (368 loc) • 18.6 kB
JavaScript
import TestEntity from '@defra-fish/dynamics-lib/src/__mocks__/TestEntity.js'
import { PermitConcession } from '@defra-fish/dynamics-lib'
import { BaseEntity, EntityDefinition } from '@defra-fish/dynamics-lib/src/entities/base.entity.js'
import {
buildJoiOptionSetValidator,
createAlternateKeyValidator,
createOptionSetValidator,
createEntityIdValidator,
createPermitConcessionValidator,
createReferenceDataEntityValidator
} from '../validators.js'
const referenceData = jest.requireActual('../../../services/reference-data.service.js')
const entityManager = jest.requireActual('@defra-fish/dynamics-lib/src/client/entity-manager.js')
describe('validators', () => {
beforeEach(jest.resetAllMocks)
describe('buildJoiOptionSetValidator', () => {
it('returns a Joi validator returning undefined when an optionset is successfully resolved', async () => {
const spy = jest.spyOn(referenceData, 'getGlobalOptionSetValue').mockImplementation(async () => 'success')
const schema = buildJoiOptionSetValidator('testOptionSet', 'Test Example')
await expect(schema.validateAsync('testValue')).resolves.toEqual('testValue')
expect(spy).toHaveBeenCalledWith('testOptionSet', 'testValue')
})
it('returns a Joi validator that requires a value to be present', async () => {
const spy = jest.spyOn(referenceData, 'getGlobalOptionSetValue')
const schema = buildJoiOptionSetValidator('testOptionSet', 'Test Example')
await expect(schema.validateAsync(undefined)).rejects.toThrow('"value" is required')
expect(spy).not.toHaveBeenCalled()
})
it('returns a Joi validator throwing an error when no optionset found', async () => {
const spy = jest.spyOn(referenceData, 'getGlobalOptionSetValue').mockImplementation(async () => null)
const schema = buildJoiOptionSetValidator('testOptionSet', 'Test Example')
await expect(schema.validateAsync('testValue')).rejects.toThrow('Value provided is not a recognised testOptionSet')
expect(spy).toHaveBeenCalledWith('testOptionSet', 'testValue')
})
})
describe('createOptionSetValidator', () => {
it('returns a validation function returning undefined when an optionset is successfully resolved', async () => {
const spy = jest.spyOn(referenceData, 'getGlobalOptionSetValue').mockImplementation(async () => 'success')
const validationFunction = createOptionSetValidator('testOptionSet')
await expect(validationFunction('testValue')).resolves.toEqual(undefined)
expect(spy).toHaveBeenCalledWith('testOptionSet', 'testValue')
})
it('returns a validation function which skips validation if the input value is undefined', async () => {
const spy = jest.spyOn(referenceData, 'getGlobalOptionSetValue').mockImplementation(async () => 'success')
const validationFunction = createOptionSetValidator('testOptionSet')
await expect(validationFunction(undefined)).resolves.toEqual(undefined)
expect(spy).not.toHaveBeenCalled()
})
it('returns a validation function throwing an error when no optionset found', async () => {
const spy = jest.spyOn(referenceData, 'getGlobalOptionSetValue').mockImplementation(async () => null)
const validationFunction = createOptionSetValidator('testOptionSet')
await expect(validationFunction('testValue')).rejects.toThrow('Value provided is not a recognised testOptionSet')
expect(spy).toHaveBeenCalledWith('testOptionSet', 'testValue')
})
})
describe('createReferenceDataEntityValidator', () => {
it('returns a validation function returning undefined when a cached reference data entity is successfully resolved', async () => {
const spy = jest.spyOn(referenceData, 'getReferenceDataForEntityAndId').mockImplementation(async () => 'success')
const validationFunction = createReferenceDataEntityValidator(TestEntity)
await expect(validationFunction('testValue')).resolves.toEqual(undefined)
expect(spy).toHaveBeenCalledWith(TestEntity, 'testValue')
})
it('returns a validation function which skips validation if the input value is undefined', async () => {
const spy = jest.spyOn(referenceData, 'getReferenceDataForEntityAndId')
const validationFunction = createReferenceDataEntityValidator(TestEntity)
await expect(validationFunction(undefined)).resolves.toEqual(undefined)
expect(spy).not.toHaveBeenCalled()
})
it('returns a validation function throwing an error when no reference data entity found', async () => {
const spy = jest.spyOn(referenceData, 'getReferenceDataForEntityAndId').mockImplementation(async () => null)
const validationFunction = createReferenceDataEntityValidator(TestEntity)
await expect(validationFunction('testValue')).rejects.toThrow('Unrecognised entityTest identifier')
expect(spy).toHaveBeenCalledWith(TestEntity, 'testValue')
})
})
describe('createEntityIdValidator', () => {
it('returns a validation function returning undefined when an entity is successfully resolved', async () => {
const spy = jest.spyOn(entityManager, 'findById').mockImplementation(async () => 'success')
const validationFunction = createEntityIdValidator(TestEntity)
await expect(validationFunction('testValue')).resolves.toEqual(undefined)
expect(spy).toHaveBeenCalledWith(TestEntity, 'testValue')
})
it('allows the validation result to be cached', async () => {
const spy = jest.spyOn(entityManager, 'findById').mockImplementation(async () => 'success')
const validationFunction = createEntityIdValidator(TestEntity, { cache: 1 })
await expect(validationFunction('testValue')).resolves.toEqual(undefined)
expect(spy).toHaveBeenCalledWith(TestEntity, 'testValue')
})
it('returns a validation function which skips validation if the input value is undefined', async () => {
const spy = jest.spyOn(entityManager, 'findById')
const validationFunction = createEntityIdValidator(TestEntity, { negate: true })
await expect(validationFunction(undefined)).resolves.toEqual(undefined)
expect(spy).not.toHaveBeenCalled()
})
it('returns a validation function returning undefined when an entity is not resolved and negate is set', async () => {
const spy = jest.spyOn(entityManager, 'findById').mockImplementation(async () => null)
const validationFunction = createEntityIdValidator(TestEntity, { negate: true })
await expect(validationFunction('testValue')).resolves.toEqual(undefined)
expect(spy).toHaveBeenCalledWith(TestEntity, 'testValue')
})
it('returns a validation function throwing an error when no entity is found', async () => {
const spy = jest.spyOn(entityManager, 'findById').mockImplementation(async () => null)
const validationFunction = createEntityIdValidator(TestEntity)
await expect(validationFunction('testValue')).rejects.toThrow('Unrecognised entityTest identifier')
expect(spy).toHaveBeenCalledWith(TestEntity, 'testValue')
})
it('returns a validation function throwing an error when an entity is found and negate is set', async () => {
const spy = jest.spyOn(entityManager, 'findById').mockImplementation(async () => 'success')
const validationFunction = createEntityIdValidator(TestEntity, { negate: true })
await expect(validationFunction('testValue')).rejects.toThrow('Entity for entityTest identifier already exists')
expect(spy).toHaveBeenCalledWith(TestEntity, 'testValue')
})
})
describe('createAlternateKeyValidator', () => {
it('returns a validation function returning undefined when an entity is successfully resolved', async () => {
const spy = jest.spyOn(entityManager, 'findByAlternateKey').mockImplementation(async () => 'success')
const validationFunction = createAlternateKeyValidator(TestEntity)
await expect(validationFunction('testValue')).resolves.toEqual(undefined)
expect(spy).toHaveBeenCalledWith(TestEntity, 'testValue')
})
it('allows the validation result to be cached', async () => {
const spy = jest.spyOn(entityManager, 'findByAlternateKey').mockImplementation(async () => 'success')
const validationFunction = createAlternateKeyValidator(TestEntity, { cache: 1 })
await expect(validationFunction('testValue')).resolves.toEqual(undefined)
expect(spy).toHaveBeenCalledWith(TestEntity, 'testValue')
})
it('returns a validation function which skips validation if the input value is undefined', async () => {
const spy = jest.spyOn(entityManager, 'findByAlternateKey')
const validationFunction = createAlternateKeyValidator(TestEntity, { negate: true })
await expect(validationFunction(undefined)).resolves.toEqual(undefined)
expect(spy).not.toHaveBeenCalled()
})
it('returns a validation function returning undefined when an entity is not resolved and negate is set', async () => {
const spy = jest.spyOn(entityManager, 'findByAlternateKey').mockImplementation(async () => null)
const validationFunction = createAlternateKeyValidator(TestEntity, { negate: true })
await expect(validationFunction('testValue')).resolves.toEqual(undefined)
expect(spy).toHaveBeenCalledWith(TestEntity, 'testValue')
})
it('returns a validation function throwing an error when no entity is found', async () => {
const spy = jest.spyOn(entityManager, 'findByAlternateKey').mockImplementation(async () => null)
const validationFunction = createAlternateKeyValidator(TestEntity)
await expect(validationFunction('testValue')).rejects.toThrow('Unrecognised entityTest identifier')
expect(spy).toHaveBeenCalledWith(TestEntity, 'testValue')
})
it('returns a validation function throwing an error when an entity is found and negate is set', async () => {
const spy = jest.spyOn(entityManager, 'findByAlternateKey').mockImplementation(async () => 'success')
const validationFunction = createAlternateKeyValidator(TestEntity, { negate: true })
await expect(validationFunction('testValue')).rejects.toThrow('Entity for entityTest identifier already exists')
expect(spy).toHaveBeenCalledWith(TestEntity, 'testValue')
})
it('throws if attempting to create an alternate key validator using an object which does not support it', async () => {
class TestNonAlternateKeyEntity extends BaseEntity {
static get definition () {
return new EntityDefinition(() => ({
localName: 'TestNonAlternateKeyEntity',
dynamicsCollection: 'TestNonAlternateKeyEntity',
mappings: { id: { field: 'idval', type: 'string' } }
}))
}
}
expect(() => createAlternateKeyValidator(TestNonAlternateKeyEntity, true)).toThrow(
/The entity TestNonAlternateKeyEntity does not support alternate key lookups/
)
})
})
describe('createPermitConcessionValidator', () => {
it('returns a validation function returning undefined when the permit and concession are successfully resolved', async () => {
const spy = jest.spyOn(referenceData, 'getReferenceDataForEntity').mockImplementation(async () => [
{
permitId: 'test-1',
concessionId: 'test-1'
}
])
const validationFunction = createPermitConcessionValidator()
await expect(
validationFunction({
dataSource: 'Web Sales',
permissions: [
{
permitId: 'test-1',
concessions: [
{
id: 'test-1'
}
]
}
]
})
).resolves.toEqual(undefined)
expect(spy).toHaveBeenCalledWith(PermitConcession)
})
it('returns a validation function throwing an error if the permit and concession are not successfully resolved', async () => {
const spy = jest.spyOn(referenceData, 'getReferenceDataForEntity').mockImplementation(async () => [
{
permitId: 'test-1',
concessionId: 'test-1'
}
])
const validationFunction = createPermitConcessionValidator()
await expect(
validationFunction({
dataSource: 'Web Sales',
permissions: [
{
permitId: 'test-1',
concessions: [
{
id: 'test-2'
}
]
}
]
})
).rejects.toThrow("The concession 'test-2' is not valid with respect to the permit 'test-1'")
expect(spy).toHaveBeenCalledWith(PermitConcession)
})
it('returns a validation function throwing an error if the permit does not allow concessions but they are supplied', async () => {
const spy = jest.spyOn(referenceData, 'getReferenceDataForEntity').mockImplementation(async () => [{}])
const validationFunction = createPermitConcessionValidator()
await expect(
validationFunction({
dataSource: 'Web Sales',
permissions: [
{
permitId: 'test-1',
concessions: [
{
id: 'test-2'
}
]
}
]
})
).rejects.toThrow("The permit 'test-1' does not allow concessions but concession proofs were supplied")
expect(spy).toHaveBeenCalledWith(PermitConcession)
})
it('returns a validation function throwing an error if the permission contains duplicate concession proofs', async () => {
const spy = jest.spyOn(referenceData, 'getReferenceDataForEntity').mockImplementation(async () => [
{ permitId: 'test-1', concessionId: 'test-1' },
{ permitId: 'test-1', concessionId: 'test-2' }
])
const validationFunction = createPermitConcessionValidator()
await expect(
validationFunction({
dataSource: 'Web Sales',
permissions: [
{
permitId: 'test-1',
concessions: [{ id: 'test-1' }, { id: 'test-1' }, { id: 'test-2' }, { id: 'test-2' }]
}
]
})
).rejects.toThrow("The concession ids 'test-1,test-2' appear more than once, duplicates are not permitted")
expect(spy).toHaveBeenCalledWith(PermitConcession)
})
it('returns a validation function which skips concession list validation if no concessions are supplied and none are required', async () => {
const spy = jest.spyOn(referenceData, 'getReferenceDataForEntity').mockImplementation(async () => [])
const validationFunction = createPermitConcessionValidator()
await expect(
validationFunction({
dataSource: 'Web Sales',
permissions: [
{
permitId: 'test-1'
}
]
})
).resolves.toEqual(undefined)
expect(spy).toHaveBeenCalledWith(PermitConcession)
})
it('returns a validation function which skips validation if the input value is undefined', async () => {
const spy = jest.spyOn(referenceData, 'getReferenceDataForEntity').mockImplementation(async () => [
{
dataSource: 'Web Sales',
permissions: [
{
permitId: 'test-1',
concessionId: 'test-1'
}
]
}
])
const validationFunction = createPermitConcessionValidator()
await expect(validationFunction(undefined)).resolves.toEqual(undefined)
expect(spy).not.toHaveBeenCalled()
})
it('returns a validation function throwing an error if the permit requires a concession and none is supplied', async () => {
const spy = jest.spyOn(referenceData, 'getReferenceDataForEntity').mockImplementation(async () => [
{
permitId: 'test-1',
concessionId: 'test-1'
}
])
const validationFunction = createPermitConcessionValidator()
await expect(
validationFunction({
dataSource: 'Web Sales',
permissions: [
{
permitId: 'test-1'
}
]
})
).rejects.toThrow("The permit 'test-1' requires proof of concession however none were supplied")
expect(spy).toHaveBeenCalledWith(PermitConcession)
})
it('returns a validation function which does not throw an error for Post Office Sales even if the permit requires a concession and none is supplied', async () => {
const spy = jest.spyOn(referenceData, 'getReferenceDataForEntity').mockImplementation(async () => [
{
permitId: 'test-1',
concessionId: 'test-1'
}
])
const validationFunction = createPermitConcessionValidator()
await expect(
validationFunction({
dataSource: 'Post Office Sales',
permissions: [
{
permitId: 'test-1'
}
]
})
).resolves.toEqual(undefined)
expect(spy).toHaveBeenCalledWith(PermitConcession)
})
it('returns a validation function which does not throw an error for DDE File even if the permit requires a concession and none is supplied', async () => {
const spy = jest.spyOn(referenceData, 'getReferenceDataForEntity').mockImplementation(async () => [
{
permitId: 'test-1',
concessionId: 'test-1'
}
])
const validationFunction = createPermitConcessionValidator()
await expect(
validationFunction({
dataSource: 'DDE File',
permissions: [
{
permitId: 'test-1'
}
]
})
).resolves.toEqual(undefined)
expect(spy).toHaveBeenCalledWith(PermitConcession)
})
it('returns a validation function which does not throw an error for Postal Order Sales even if the permit requires a concession and none is supplied', async () => {
const spy = jest.spyOn(referenceData, 'getReferenceDataForEntity').mockImplementation(async () => [
{
permitId: 'test-1',
concessionId: 'test-1'
}
])
const validationFunction = createPermitConcessionValidator()
await expect(
validationFunction({
dataSource: 'Postal Order Sales',
permissions: [
{
permitId: 'test-1'
}
]
})
).resolves.toEqual(undefined)
expect(spy).toHaveBeenCalledWith(PermitConcession)
})
})
})