Search code examples
javascriptarraystestingautomated-testspostman

Unable to validate complete JSON schema using tv4


I'm wondering if someone can help because I'm at a loss! I'm trying to assert that the response from a GET API Call meets this monster schema set - Using console.log() it looks like each of the properties is accessed successfully and if I change the object type the test will fail as I'd expect.

Working down the schema - If I try and change a property in the data array i.e. from string to boolean the test will still pass although it doesn't meet the required schema I've defined,

Any guidance is massively appreciated!

//Test the schema is valid
const schema = {
    "type": "object",
    "properties": {
        "current_page": {
            "type": "integer"
        },
        "data": {
            "type": "array",
            "properties": {
                "id": {
                    "type": "integer"
                },
                "first_name": {
                    "type": "string"
                },
                "last_name": {
                    "type": "string"
                },
                "telephone": {
                    "type": "string"
                },
                "postcode": {
                    "type": "string"
                },
                "date_of_birth": {
                    "type": "string"
                },
                "profession": {
                    "type": "string"
                },
                "time_served": {
                    "type": "integer"
                },
                "national_insurance_number": {
                    "type": "string"
                },
                "employer": {
                    "type": "string"
                },
                "lco_id": {
                    "type": "integer"
                },
                "company_employed": {
                    "type": "null"
                },
                "company_employed_email": {
                    "type": "null"
                },
                "company_employed_telephone": {
                    "type": "string"
                },
                "company_employed_address": {
                    "type": "null"
                },
                "apprentice": {
                    "type": "boolean"
                },
                "apprentice_trade": {
                    "type": "string"
                },
                "apprentice_course": {
                    "type": "string"
                },
                "apprentice_started_at": {
                    "type": "string"
                },
                "apprentice_ended_at": {
                    "type": "string"
                },
                "work_experience": {
                    "type": "boolean"
                },
                "work_experience_trade": {
                    "type": "null"
                },
                "work_experience_education": {
                    "type": "null"
                },
                "work_experience_started_at": {
                    "type": "null"
                },
                "work_experience_ended_at": {
                    "type": "null"
                },
                "nvq": {
                    "type": "boolean"
                },
                "nvq_trade": {
                    "type": "string"
                },
                "nvq_education": {
                    "type": "string"
                },
                "nvq_started_at": {
                    "type": "string"
                },
                "nvq_ended_at": {
                    "type": "string"
                },
                "unemployed": {
                    "type": "boolean"
                },
                "unemployed_months": {
                    "type": "null"
                },
                "company_employed_postcode": {
                    "type": "string"
                },
                "partner_relationship": {
                    "type": "null"
                },
                "self_partner_relationship": {
                    "type": "null"
                },
                "emergency_contact_first_name": {
                    "type": "string"
                },
                "emergency_contact_last_name": {
                    "type": "string"
                },
                "emergency_contact_telephone": {
                    "type": "string"
                },
                "enrollment_id": {
                    "type": "integer"
                },
                "created_at": {
                    "type": "string"
                },
                "updated_at": {
                    "type": "string"
                },
                "mode_of_travel": {
                    "type": "string"
                },
                "driver_or_passenger": {
                    "type": "string"
                },
                "fuel_type": {
                    "type": "string"
                },
                "engine_capacity": {
                    "type": "string"
                },
                "rtw_declaration": {
                    "type": "boolean"
                },
                "rtw_proof1_upload_id": {
                    "type": "null"
                },
                "rtw_proof2_upload_id": {
                    "type": "null"
                },
                "card_type": {
                    "type": "string"
                },
                "gender": {
                    "type": "string"
                },
                "self_gender": {
                    "type": "null"
                },
                "marital_status": {
                    "type": "string"
                },
                "disability_act": {
                    "type": "string"
                },
                "disability_description": {
                    "type": "null"
                },
                "ethnic_origin": {
                    "type": "string"
                },
                "religion": {
                    "type": "string"
                },
                "nationality": {
                    "type": "string"
                },
                "sexual_orient": {
                    "type": "string"
                },
                "checked_membership": {
                    "type": "integer"
                },
                "training_checked": {
                    "type": "integer"
                },
                "enrollment": {
                    "type": "object",
                    "properties": {
                        "id": {
                            "type": "integer"
                        },
                        "inducted": {
                            "type": "boolean"
                        },
                        "user_id": {
                            "type": "integer"
                        },
                        "created_at": {
                            "type": "string"
                        },
                        "updated_at": {
                            "type": "string"
                        },
                        "expiry_date": {
                            "type": "string"
                        },
                        "user": {
                            "type": "object",
                            "properties": {
                                "id": {
                                    "type": "integer"
                                },
                                "email": {
                                    "type": "string"
                                },
                                "role": {
                                    "type": "integer"
                                },
                                "created_at": {
                                    "type": "string"
                                },
                                "updated_at": {
                                    "type": "string"
                                },
                                "state": {
                                    "type": "integer"
                                },
                                "last_login_at": {
                                    "type": "null"
                                }
                            },
                            "required": [
                                "id",
                                "email",
                                "role",
                                "created_at",
                                "updated_at",
                                "state",
                                "last_login_at"
                            ]
                        }
                    },
                    "required": [
                        "id",
                        "inducted",
                        "user_id",
                        "created_at",
                        "updated_at",
                        "expiry_date",
                        "user"
                    ]
                }
            },
            "required": [
                "id",
                "first_name",
                "last_name",
                "telephone",
                "postcode",
                "date_of_birth",
                "profession",
                "time_served",
                "national_insurance_number",
                "employer",
                "lco_id",
                "company_employed",
                "company_employed_email",
                "company_employed_telephone",
                "company_employed_address",
                "apprentice",
                "apprentice_trade",
                "apprentice_course",
                "apprentice_started_at",
                "apprentice_ended_at",
                "work_experience",
                "work_experience_trade",
                "work_experience_education",
                "work_experience_started_at",
                "work_experience_ended_at",
                "nvq",
                "nvq_trade",
                "nvq_education",
                "nvq_started_at",
                "nvq_ended_at",
                "unemployed",
                "unemployed_months",
                "company_employed_postcode",
                "partner_relationship",
                "self_partner_relationship",
                "emergency_contact_first_name",
                "emergency_contact_last_name",
                "emergency_contact_telephone",
                "enrollment_id",
                "created_at",
                "updated_at",
                "mode_of_travel",
                "driver_or_passenger",
                "fuel_type",
                "engine_capacity",
                "rtw_declaration",
                "rtw_proof1_upload_id",
                "rtw_proof2_upload_id",
                "card_type",
                "gender",
                "self_gender",
                "marital_status",
                "disability_act",
                "disability_description",
                "ethnic_origin",
                "religion",
                "nationality",
                "sexual_orient",
                "checked_membership",
                "training_checked",
                "enrollment",
            ]
        },
    }
}

// Use tiny validator to validate the results - Error if there are additional properties, and check recursion.

pm.test("Validate schema contains the relevant details", () => {
    tv4.validateMultiple(jsonData, schema, true, true);
    var jsonData = JSON.parse(responseBody);

    // Log all errors to the console 
    var validationResult = tv4.validateMultiple(jsonData, schema, true, true);
    for (var i = 0; i < validationResult.errors.length; i++) {
        console.log("path :" + validationResult.errors[i].dataPath + " message :" + validationResult.errors[i].message);
    }

});

Solution

  • const schema = {
        "type": "object",
        "properties": {
            "current_page": {
                "type": "boolean"
            }
    
        }
    }
    
    
    pm.test("Validate schema contains the relevant details", () => {
    
        var jsonData = { "current_page": 2 }
    
        // Log all errors to the console 
        var validationResult = tv4.validateMultiple(jsonData, schema, true, true);
        validationResult.valid ? null : console.log(JSON.stringify(validationResult, null, 2))
        pm.expect(validationResult.valid, JSON.stringify(validationResult, null, 2)).to.be.true
    
    
    });
    

    you don't have expect to assert it that's why it passes always , also as Danny mentioned use

    const schema = {
        "type": "object",
        "properties": {
            "current_page": {
                "type": "boolean"
            }
    
        }
    }
    
    
    pm.test("Validate schema contains the relevant details", () => {
    
    var jsonData = { "current_page": 2 }
    
    pm.response.to.have.jsonSchema(schema)
    
    });
    

    And for array you should use items instead of property:

    const schema = {
        "type": "object",
        "properties": {
            "data": {
                "type": "array",
                "items": {
                    "properties": {
                        "id": {
                            "type": "integer"
                        },
                         "name": {
                            "type": "string"
                        }
                    },
                    "required":["id","name"]
                }
            }
        }
    }
    pm.test("Validate schema contains the relevant details", () => {
    
        var jsonData = { "data": [{ "id": 2,"name":"test" }] }
        // Log all errors to the console 
        var validationResult = tv4.validateMultiple(jsonData, schema, true, true);
        validationResult.valid ? null : console.log(JSON.stringify(validationResult, null, 2))
        pm.expect(validationResult.valid, JSON.stringify(validationResult, null, 2)).to.be.true
    
    
    });
    

    you can create schema with so much ease using :

    https://www.jsonschema.net/login