mirror of
https://github.com/usebruno/bruno.git
synced 2026-06-25 21:55:49 +00:00
* feat: add JSON Schema validation support with custom chai assertion - Introduced a new custom assertion for JSON Schema validation in chai, allowing users to validate response bodies against defined schemas. - Updated the postman translation logic to translate `pm.response.to.have.jsonSchema` to the new assertion format. - Enhanced tests to cover various scenarios for JSON Schema validation, ensuring accurate translations and functionality. - Updated package dependencies to include the latest versions of relevant libraries. * refactor: enhance JSON Schema validation assertion and add comprehensive test cases * chore: add @rollup/plugin-json dependency and enhance JSON Schema validation tests - Added @rollup/plugin-json as a development dependency in package.json and package-lock.json. - Introduced new test cases for JSON Schema validation, covering various scenarios including valid schema matching, type mismatches, and required field checks. - Updated existing assertions to utilize the new validation capabilities. * refactor: streamline JSON Schema validation with default Ajv instance - Updated the custom chai assertion for JSON Schema validation to utilize a default Ajv instance, improving consistency and reducing redundancy in the code. - Enhanced the error messages in the assertion to include the actual data being validated, providing clearer feedback during validation failures. * refactor: improve error messaging in JSON Schema validation assertion - Enhanced the custom chai assertion for JSON Schema validation to provide clearer error messages by including a stringified version of the data being validated, improving feedback during validation failures. * refactor: simplify Ajv instance creation in JSON Schema validation - Removed the default Ajv instance and streamlined the creation of Ajv instances in the custom chai assertion for JSON Schema validation, ensuring consistent handling of ajvOptions across the codebase. * feat: add support for negated JSON Schema assertions in Postman translations - Introduced translations for `pm.response.to.not.have.jsonSchema`, `pm.response.not.to.have.jsonSchema`, and `pm.response.to.have.not.jsonSchema` to the new assertion format using `expect`. - Enhanced the translation logic to handle these new patterns and added corresponding test cases to ensure accurate functionality. - Updated existing tests to cover various scenarios for negated assertions, improving overall test coverage for JSON Schema validation. * fix: improve error handling in JSON Schema validation assertions - Added error handling for JSON schema compilation in the custom chai assertion, ensuring that any compilation errors are caught and reported with a clear message. - Updated tests to verify that malformed schemas correctly trigger assertion errors, enhancing the robustness of JSON Schema validation.
350 lines
8.0 KiB
Plaintext
350 lines
8.0 KiB
Plaintext
meta {
|
|
name: jsonSchema
|
|
type: http
|
|
seq: 9
|
|
}
|
|
|
|
post {
|
|
url: {{host}}/api/echo/json
|
|
body: json
|
|
auth: none
|
|
}
|
|
|
|
body:json {
|
|
{
|
|
"name": "John",
|
|
"age": 30,
|
|
"email": "john@example.com",
|
|
"status": "active",
|
|
"score": 95.5,
|
|
"isVerified": true,
|
|
"tags": ["developer", "tester"],
|
|
"address": {
|
|
"street": "123 Main St",
|
|
"city": "Springfield",
|
|
"zip": "62701"
|
|
}
|
|
}
|
|
}
|
|
|
|
tests {
|
|
// --- Passing validations ---
|
|
|
|
test("Basic object with properties and required", function() {
|
|
const schema = {
|
|
type: 'object',
|
|
properties: {
|
|
name: { type: 'string' },
|
|
age: { type: 'number' },
|
|
email: { type: 'string' },
|
|
status: { type: 'string' },
|
|
score: { type: 'number' },
|
|
isVerified: { type: 'boolean' },
|
|
tags: { type: 'array' },
|
|
address: { type: 'object' }
|
|
},
|
|
required: ['name', 'age', 'email']
|
|
};
|
|
expect(res.getBody()).to.have.jsonSchema(schema);
|
|
});
|
|
|
|
test("Nested object validation", function() {
|
|
const schema = {
|
|
type: 'object',
|
|
properties: {
|
|
address: {
|
|
type: 'object',
|
|
properties: {
|
|
street: { type: 'string' },
|
|
city: { type: 'string' },
|
|
zip: { type: 'string' }
|
|
},
|
|
required: ['street', 'city', 'zip']
|
|
}
|
|
}
|
|
};
|
|
expect(res.getBody()).to.have.jsonSchema(schema);
|
|
});
|
|
|
|
test("Array items validation", function() {
|
|
const schema = {
|
|
type: 'object',
|
|
properties: {
|
|
tags: {
|
|
type: 'array',
|
|
items: { type: 'string' }
|
|
}
|
|
}
|
|
};
|
|
expect(res.getBody()).to.have.jsonSchema(schema);
|
|
});
|
|
|
|
test("String pattern (regex)", function() {
|
|
const schema = {
|
|
type: 'object',
|
|
properties: {
|
|
email: {
|
|
type: 'string',
|
|
pattern: '^[^@]+@[^@]+\\.[^@]+$'
|
|
}
|
|
}
|
|
};
|
|
expect(res.getBody()).to.have.jsonSchema(schema);
|
|
});
|
|
|
|
test("Enum validation", function() {
|
|
const schema = {
|
|
type: 'object',
|
|
properties: {
|
|
status: {
|
|
type: 'string',
|
|
enum: ['active', 'inactive', 'pending']
|
|
}
|
|
}
|
|
};
|
|
expect(res.getBody()).to.have.jsonSchema(schema);
|
|
});
|
|
|
|
test("Number range (minimum/maximum)", function() {
|
|
const schema = {
|
|
type: 'object',
|
|
properties: {
|
|
age: {
|
|
type: 'number',
|
|
minimum: 0,
|
|
maximum: 150
|
|
}
|
|
}
|
|
};
|
|
expect(res.getBody()).to.have.jsonSchema(schema);
|
|
});
|
|
|
|
test("String length constraints (minLength/maxLength)", function() {
|
|
const schema = {
|
|
type: 'object',
|
|
properties: {
|
|
name: {
|
|
type: 'string',
|
|
minLength: 1,
|
|
maxLength: 100
|
|
}
|
|
}
|
|
};
|
|
expect(res.getBody()).to.have.jsonSchema(schema);
|
|
});
|
|
|
|
test("allOf composition", function() {
|
|
const schema = {
|
|
allOf: [
|
|
{
|
|
type: 'object',
|
|
properties: { name: { type: 'string' } },
|
|
required: ['name']
|
|
},
|
|
{
|
|
type: 'object',
|
|
properties: { age: { type: 'number' } },
|
|
required: ['age']
|
|
}
|
|
]
|
|
};
|
|
expect(res.getBody()).to.have.jsonSchema(schema);
|
|
});
|
|
|
|
test("anyOf composition", function() {
|
|
const schema = {
|
|
type: 'object',
|
|
properties: {
|
|
score: {
|
|
anyOf: [
|
|
{ type: 'number' },
|
|
{ type: 'string' }
|
|
]
|
|
}
|
|
}
|
|
};
|
|
expect(res.getBody()).to.have.jsonSchema(schema);
|
|
});
|
|
|
|
test("jsonSchema with ajvOptions", function() {
|
|
const schema = {
|
|
type: 'object',
|
|
properties: {
|
|
name: { type: 'string' },
|
|
age: { type: 'number' }
|
|
},
|
|
required: ['name', 'age']
|
|
};
|
|
expect(res.getBody()).to.have.jsonSchema(schema, { allErrors: true });
|
|
});
|
|
|
|
// --- Failure validations ---
|
|
|
|
test("Type mismatch - schema expects array, response is object", function() {
|
|
const schema = { type: 'array' };
|
|
let failed = false;
|
|
try {
|
|
expect(res.getBody()).to.have.jsonSchema(schema);
|
|
} catch (e) {
|
|
failed = true;
|
|
}
|
|
expect(failed).to.be.true;
|
|
});
|
|
|
|
test("Missing required field", function() {
|
|
const schema = {
|
|
type: 'object',
|
|
required: ['nonExistentField']
|
|
};
|
|
let failed = false;
|
|
try {
|
|
expect(res.getBody()).to.have.jsonSchema(schema);
|
|
} catch (e) {
|
|
failed = true;
|
|
}
|
|
expect(failed).to.be.true;
|
|
});
|
|
|
|
test("additionalProperties false rejects extra fields", function() {
|
|
const schema = {
|
|
type: 'object',
|
|
properties: {
|
|
name: { type: 'string' }
|
|
},
|
|
additionalProperties: false
|
|
};
|
|
let failed = false;
|
|
try {
|
|
expect(res.getBody()).to.have.jsonSchema(schema);
|
|
} catch (e) {
|
|
failed = true;
|
|
}
|
|
expect(failed).to.be.true;
|
|
});
|
|
|
|
test("Enum mismatch", function() {
|
|
const schema = {
|
|
type: 'object',
|
|
properties: {
|
|
status: {
|
|
type: 'string',
|
|
enum: ['deleted', 'archived']
|
|
}
|
|
},
|
|
required: ['status']
|
|
};
|
|
let failed = false;
|
|
try {
|
|
expect(res.getBody()).to.have.jsonSchema(schema);
|
|
} catch (e) {
|
|
failed = true;
|
|
}
|
|
expect(failed).to.be.true;
|
|
});
|
|
|
|
test("Pattern mismatch - name does not match digits-only", function() {
|
|
const schema = {
|
|
type: 'object',
|
|
properties: {
|
|
name: {
|
|
type: 'string',
|
|
pattern: '^[0-9]+$'
|
|
}
|
|
},
|
|
required: ['name']
|
|
};
|
|
let failed = false;
|
|
try {
|
|
expect(res.getBody()).to.have.jsonSchema(schema);
|
|
} catch (e) {
|
|
failed = true;
|
|
}
|
|
expect(failed).to.be.true;
|
|
});
|
|
|
|
// --- Malformed schema (ajv.compile error) ---
|
|
|
|
test("Malformed schema - invalid type throws assertion error", function() {
|
|
const schema = { type: 'invalidType' };
|
|
expect(() => expect(res.getBody()).to.have.jsonSchema(schema)).to.throw('JSON schema compile error');
|
|
});
|
|
|
|
// --- .not (negation) validations ---
|
|
|
|
test(".not with mismatched type - body is object, not array", function() {
|
|
const schema = { type: 'array' };
|
|
expect(res.getBody()).to.not.have.jsonSchema(schema);
|
|
});
|
|
|
|
test(".not with missing required field", function() {
|
|
const schema = {
|
|
type: 'object',
|
|
required: ['nonExistent']
|
|
};
|
|
expect(res.getBody()).to.not.have.jsonSchema(schema);
|
|
});
|
|
|
|
test(".not fails when schema actually matches", function() {
|
|
const schema = { type: 'object' };
|
|
let failed = false;
|
|
try {
|
|
expect(res.getBody()).to.not.have.jsonSchema(schema);
|
|
} catch (e) {
|
|
failed = true;
|
|
}
|
|
expect(failed).to.be.true;
|
|
});
|
|
|
|
// --- not.to.have (negation) validations ---
|
|
|
|
test("not.to.have with mismatched type - body is object, not array", function() {
|
|
const schema = { type: 'array' };
|
|
expect(res.getBody()).not.to.have.jsonSchema(schema);
|
|
});
|
|
|
|
test("not.to.have with missing required field", function() {
|
|
const schema = {
|
|
type: 'object',
|
|
required: ['nonExistent']
|
|
};
|
|
expect(res.getBody()).not.to.have.jsonSchema(schema);
|
|
});
|
|
|
|
test("not.to.have fails when schema actually matches", function() {
|
|
const schema = { type: 'object' };
|
|
let failed = false;
|
|
try {
|
|
expect(res.getBody()).not.to.have.jsonSchema(schema);
|
|
} catch (e) {
|
|
failed = true;
|
|
}
|
|
expect(failed).to.be.true;
|
|
});
|
|
|
|
// --- to.have.not (negation) validations ---
|
|
|
|
test("to.have.not with mismatched type - body is object, not array", function() {
|
|
const schema = { type: 'array' };
|
|
expect(res.getBody()).to.have.not.jsonSchema(schema);
|
|
});
|
|
|
|
test("to.have.not with missing required field", function() {
|
|
const schema = {
|
|
type: 'object',
|
|
required: ['nonExistent']
|
|
};
|
|
expect(res.getBody()).to.have.not.jsonSchema(schema);
|
|
});
|
|
|
|
test("to.have.not fails when schema actually matches", function() {
|
|
const schema = { type: 'object' };
|
|
let failed = false;
|
|
try {
|
|
expect(res.getBody()).to.have.not.jsonSchema(schema);
|
|
} catch (e) {
|
|
failed = true;
|
|
}
|
|
expect(failed).to.be.true;
|
|
});
|
|
}
|