ajv: Cannot read property 'test' of undefined

What version of Ajv are you using? Does the issue happen if you use the latest version?

7.0.2

Ajv options object

const ajv = new Ajv.default({ code: { source: true } });

JSON Schema

Sample data

Your code

import * as schemas from "validate.js";

const validator = schemas[MyRef];

const valid = validator(data);

Validation result, data AFTER validation, error messages

On Karma:

TypeError: Cannot read property 'test' of undefined

At Runtime:

TypeError: You provided 'null' where a stream was expected. You can provide an Observable, Promise, Array, or Iterable.

Both errors are raised by validator(data);

What results did you expect?

On 7.0.1 I have no errors at runtime, so this is a regression introduced with the latest version. Karma fails also with 7.0.1 but due to a different error (duplicated functions fixed with 7.0.2)

Are you going to resolve the issue?

The runtime error is pretty obscure but I tried to work around the error provided by karma.

the only ‘test’ property that I found in the validation functions is:

if(!(formats2.test(data0))

where formats2 is:

const formats2 = {"_items":["require(\"ajv-formats/dist/formats\").",{"str":"fullFormats"},""]}.email;

I verified with a console.log that formats2 is undefined

On the 7.0.1 this part works well and I noticed that formats2 is created with a different syntax:

const formats2 = require("ajv-formats/dist/formats").fullFormats.email;

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Comments: 17 (10 by maintainers)

Commits related to this issue

Most upvoted comments

Hope that this can be enough:

const Ajv = require("/app/node_modules/ajv");
const addFormats = require("/app/node_modules/ajv-formats");
const standaloneCode = require("/app/node_modules/ajv/dist/standalone");

const schema = {
  "$schema": "http://json-schema.org/draft-07/schema#",
  "definitions": {
    "User": {
      "additionalProperties": false,
      "properties": {
        "email": {
          "format": "email",
          "type": "string"
        }
      },
      "required": [
        "email"
      ],
      "type": "object"
    }
  }
}

const ajv = new Ajv.default({ code: { source: true } });
addFormats(ajv);

const validate = ajv.compile(schema);

for (let definition in schema["definitions"]) {
  const def = schema["definitions"][definition];
  const ref = "#/definitions/" + definition;

  ajv.addSchema(def, ref);
}

let moduleCode = standaloneCode.default(ajv);

console.log(moduleCode);

With 7.0.2 the output is:

"use strict";exports["#/definitions/User"] = validate11;const schema12 = {"additionalProperties":false,"properties":{"email":{"format":"email","type":"string"}},"required":["email"],"type":"object"};const formats0 = {"_items":["require(\"ajv-formats/dist/formats\").",{"str":"fullFormats"},""]}.email;function validate11(data, {dataPath="", parentData, parentDataProperty, rootData=data}={}){let vErrors = null;let errors = 0;if(data && typeof data == "object" && !Array.isArray(data)){let missing0;if(data.email === undefined && (missing0 = "email")){validate11.errors = [{keyword:"required",dataPath,schemaPath:"#/required",params:{missingProperty: missing0},message:"should have required property '"+missing0+"'"}];return false;}else {const _errs0 = errors;for(const key0 in data){if(!(key0 === "email")){validate11.errors = [{keyword:"additionalProperties",dataPath,schemaPath:"#/additionalProperties",params:{additionalProperty: key0},message:"should NOT have additional properties"}];return false;break;}}if(_errs0 === errors){if(data.email !== undefined){let data0 = data.email;const _errs1 = errors;if(errors === _errs1){if(typeof data0 === "string"){if(!(formats0.test(data0))){validate11.errors = [{keyword:"format",dataPath:dataPath+"/email",schemaPath:"#/properties/email/format",params:{format: "email"},message:"should match format \""+"email"+"\""}];return false;}}else {validate11.errors = [{keyword:"type",dataPath:dataPath+"/email",schemaPath:"#/properties/email/type",params:{type: "string"},message:"should be string"}];return false;}}}}}}else {validate11.errors = [{keyword:"type",dataPath,schemaPath:"#/type",params:{type: "object"},message:"should be object"}];return false;}validate11.errors = vErrors;return errors === 0;}

With 7.0.1 the output is:

"use strict";exports["#/definitions/User"] = validate11;const schema12 = {"additionalProperties":false,"properties":{"email":{"format":"email","type":"string"}},"required":["email"],"type":"object"};const formats0 = require("ajv-formats/dist/formats").fullFormats.email;function validate11(data, {dataPath="", parentData, parentDataProperty, rootData=data}={}){let vErrors = null;let errors = 0;if(data && typeof data == "object" && !Array.isArray(data)){let missing0;if(data.email === undefined && (missing0 = "email")){validate11.errors = [{keyword:"required",dataPath,schemaPath:"#/required",params:{missingProperty: missing0},message:"should have required property '"+missing0+"'"}];return false;}else {const _errs0 = errors;for(const key0 in data){if(!(key0 === "email")){validate11.errors = [{keyword:"additionalProperties",dataPath,schemaPath:"#/additionalProperties",params:{additionalProperty: key0},message:"should NOT have additional properties"}];return false;break;}}if(_errs0 === errors){if(data.email !== undefined){let data0 = data.email;const _errs1 = errors;if(errors === _errs1){if(typeof data0 === "string"){if(!(formats0.test(data0))){validate11.errors = [{keyword:"format",dataPath:dataPath+"/email",schemaPath:"#/properties/email/format",params:{format: "email"},message:"should match format \""+"email"+"\""}];return false;}}else {validate11.errors = [{keyword:"type",dataPath:dataPath+"/email",schemaPath:"#/properties/email/type",params:{type: "string"},message:"should be string"}];return false;}}}}}}else {validate11.errors = [{keyword:"type",dataPath,schemaPath:"#/type",params:{type: "object"},message:"should be object"}];return false;}validate11.errors = vErrors;return errors === 0;}

The difference is the formats0

7.0.2: const formats0 = {"_items":["require(\"ajv-formats/dist/formats\").",{"str":"fullFormats"},""]}.email; 7.0.1: const formats0 = require("ajv-formats/dist/formats").fullFormats.email;

If I edit the validation code by adding a console.log(formats0) I obtain an undefined with 7.0.2 and valid value with 7.0.1 (i.e. /^[a-z0-9!#$%&'*+/=?^_{|}~-]+(?:.[a-z0-9!#$%&'*+/=?^_{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/i)

The same happens with others validation formats, e.g. date-time

undefined on 7.0.2 and an Object with 7.0.1

{validate: ƒ, compare: ƒ}
compare: ƒ compareDateTime(dt1, dt2)
arguments: (...)
caller: (...)
length: 2
name: "compareDateTime"
prototype: {constructor: ƒ}
__proto__: ƒ ()
[[FunctionLocation]]: formats.js:113
[[Scopes]]: Scopes[2]
validate: ƒ date_time(str)
arguments: (...)
caller: (...)
length: 1
name: "date_time"
prototype: {constructor: ƒ}
__proto__: ƒ ()
[[FunctionLocation]]: formats.js:108
[[Scopes]]: Scopes[2]
0: Closure (XnP8) {DATE: /^(\d\d\d\d)-(\d\d)-(\d\d)$/, DAYS: Array(13), isLeapYear: ƒ, date: ƒ, compareDate: ƒ, …}
1: Global {window: Window, self: Window, document: document, name: "", location: Location, …}
__proto__: Object