Skip to content
This repository was archived by the owner on Jul 4, 2023. It is now read-only.

build(deps): bump ajv from 6.12.6 to 7.0.3 #633

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 74 additions & 13 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@
},
"dependencies": {
"@hapi/joi": "^17.1.1",
"ajv": "^6.10.2",
"ajv": "^7.0.3",
"bottleneck": "^2.19.5",
"chalk": "^4.0.0",
"chokidar": "^3.4.0",
Expand Down
3 changes: 3 additions & 0 deletions src/test-helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ type MockFn<T extends (...args: any[]) => ReturnType<T>> = (
) &
MockExtensions<T>

export type MockedFn<T extends (...args: any[]) => ReturnType<T>> = jest.Mock<ReturnType<T>, Parameters<T>> &
MockExtensions<T>

export function mockFn<T extends (...args: any[]) => ReturnType<T>>(): jest.Mock<
ReturnType<T>,
Parameters<T>
Expand Down
11 changes: 6 additions & 5 deletions src/validation/errors.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
import ajv from 'ajv'
import { ErrorObject } from 'ajv'
import { blue } from 'chalk'
import { inspect } from 'util'

export class TypeValidationMismatchError extends Error {
constructor(errors: ajv.ErrorObject[]) {
constructor(errors: ErrorObject[]) {
super(errors.map(TypeValidationMismatchError.mapErrorMessage).join('\n'))
this.name = 'TypeValidationError'
Object.setPrototypeOf(this, TypeValidationMismatchError.prototype)
}

private static mapErrorMessage(err: ajv.ErrorObject): string {
const baseMessage = `${blue.bold('<root>' + err.dataPath)} ${err.message?.replace(/'(.*)'/, blue('$&'))}`
private static mapErrorMessage(err: ErrorObject): string {
const dataPath = err.dataPath.replace(/\//g, '.')
const baseMessage = `${blue.bold('<root>' + dataPath)} ${err.message?.replace(/'(.*)'/, blue('$&'))}`

if (err.keyword === 'enum' && 'allowedValues' in err.params) {
return `${baseMessage} ${TypeValidationMismatchError.formatData(
Expand All @@ -31,7 +32,7 @@ export class TypeValidationMismatchError extends Error {
return typeof data
}

private static formatData(data: Data): string {
private static formatData(data: Data | unknown): string {
return inspect(data, false, 1, true)
}
}
24 changes: 12 additions & 12 deletions src/validation/type-validator.integration.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,6 @@ import '../jest-extensions'
import { TypeBuilder } from '~config/resource/builders'

describe('error messages', () => {
function createTestDeps() {
const ajv = new Ajv({ allErrors: true, verbose: true })
const mockSchemaRetriever = mockObj<SchemaRetriever>({ load: jest.fn() })
const typeValidator = new TypeValidator(ajv, mockSchemaRetriever)

return {
mockSchemaRetriever,
typeValidator,
type: TypeBuilder.random(),
}
}

test('missing required properties', async () => {
const { mockSchemaRetriever, typeValidator, type } = createTestDeps()
mockSchemaRetriever.load.mockResolvedValue({
Expand Down Expand Up @@ -126,3 +114,15 @@ describe('error messages', () => {
)
})
})

function createTestDeps() {
const ajv = new Ajv({ allErrors: true, verbose: true })
const mockSchemaRetriever = mockObj<SchemaRetriever>({ load: jest.fn() })
const typeValidator = new TypeValidator(ajv, mockSchemaRetriever)

return {
mockSchemaRetriever,
typeValidator,
type: TypeBuilder.random(),
}
}
52 changes: 12 additions & 40 deletions src/validation/type-validator.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import TypeValidator from './type-validator'
import { Ajv, ValidateFunction, ErrorObject } from 'ajv'
import Ajv, { ValidateFunction } from 'ajv'
import { SchemaRetriever } from '~schema'
import { mockObj, randomString, mockFn } from '~test-helpers'
import { mockObj, randomString } from '~test-helpers'
import '../jest-extensions'
import { TypeBuilder } from '~config/resource/builders'

Expand All @@ -10,77 +10,49 @@ jest.disableAutomock()
describe('validate', () => {
function createTestDeps() {
const stubValidator = mockObj<Ajv>({ compile: jest.fn() })
const stubValidateFn = mockObj<ValidateFunction>({})
const stubSchemaRetriever = mockObj<SchemaRetriever>({ load: jest.fn() })
const typeValidator = new TypeValidator(stubValidator, stubSchemaRetriever)

return {
stubValidator,
stubSchemaRetriever,
typeValidator,
stubValidateFn,
spyValidateFn: stubValidateFn,
}
}

afterEach(() => jest.resetAllMocks())

it('calls the schema retriver with the correct args', async () => {
const { stubSchemaRetriever, typeValidator, stubValidator } = createTestDeps()
const { stubSchemaRetriever, typeValidator, stubValidator, stubValidateFn } = createTestDeps()
const expectedType = TypeBuilder.random()
stubValidator.compile.mockReturnValue(jest.fn())
stubValidator.compile.mockReturnValue(stubValidateFn)

await typeValidator.assert(randomString('body'), expectedType)

expect(stubSchemaRetriever.load).toBeCalledWith(expectedType)
})

it('creates a validator function using the correct args', async () => {
const { stubSchemaRetriever, typeValidator, stubValidator } = createTestDeps()
const { stubSchemaRetriever, typeValidator, stubValidator, stubValidateFn } = createTestDeps()
const schema = { [randomString('key')]: randomString('value') }
stubSchemaRetriever.load.mockResolvedValue(schema)
stubValidator.compile.mockReturnValue(jest.fn())
stubValidator.compile.mockReturnValue(stubValidateFn)

await typeValidator.assert(randomString('body'), TypeBuilder.random())

expect(stubValidator.compile).toBeCalledWith(schema)
})

it('calls the validator func with the correct args', async () => {
const { typeValidator, stubValidator } = createTestDeps()
const validateFn = mockFn<ValidateFunction>()
stubValidator.compile.mockReturnValue(validateFn)
const { typeValidator, stubValidator, stubValidateFn } = createTestDeps()
stubValidator.compile.mockReturnValue(stubValidateFn)
const expectedBody = randomString('body')

await typeValidator.assert(expectedBody, TypeBuilder.random())

expect(validateFn).toBeCalledWith(expectedBody)
})

it('does not throw if the data does match the type', async () => {
const { typeValidator, stubValidator } = createTestDeps()
stubValidator.compile.mockReturnValue(mockFn<ValidateFunction>().mockReturnValue(true))

await typeValidator.assert(randomString('body'), TypeBuilder.random())
})

it('returns validation messages if the data does not match the type', async () => {
const { typeValidator, stubValidator } = createTestDeps()
const error1: Partial<ErrorObject> = {
dataPath: randomString('.datapath1'),
message: randomString('error-message1'),
}
const error2: Partial<ErrorObject> = {
dataPath: '',
message: randomString('error-message2'),
}

const validatorFn: ValidateFunction = mockFn<ValidateFunction>().mockReturnValue(false)
validatorFn.errors = [error1, error2] as ErrorObject[]
stubValidator.compile.mockReturnValue(validatorFn)

const body = randomString('body')
const type = TypeBuilder.random()

await expect(typeValidator.assert(body, type)).rejects.toThrowColouredError(
`<root>${error1.dataPath} ${error1.message}\n<root> ${error2.message}`,
)
expect(stubValidateFn).toBeCalledWith(expectedBody)
})
})
2 changes: 1 addition & 1 deletion src/validation/type-validator.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Ajv } from 'ajv'
import Ajv from 'ajv'
import { Type } from '~config/resource/type'
import { SchemaRetriever } from '~schema'
import { TypeValidationMismatchError } from './errors'
Expand Down