diff --git a/test/browser/documents/2.0/swagger.yaml b/test/browser/documents/2.0/swagger.yaml index c62c88b..7a2361c 100644 --- a/test/browser/documents/2.0/swagger.yaml +++ b/test/browser/documents/2.0/swagger.yaml @@ -80,6 +80,57 @@ paths: description: "Pet not found" 405: description: "Validation exception" + /toy: + post: + tags: + - "toy" + summary: "Add a new Toy to the store" + description: "" + operationId: "addToy" + consumes: + - "application/json" + - "application/xml" + produces: + - "application/xml" + - "application/json" + parameters: + - in: "body" + name: "body" + description: "Toy object that needs to be added to the store" + required: true + schema: + $ref: "#/definitions/Toy" + responses: + 200: + description: "OK" + 405: + description: "Invalid input" + put: + tags: + - "toy" + summary: "Update an existing toy" + description: "" + operationId: "updateToy" + consumes: + - "application/json" + - "application/xml" + produces: + - "application/xml" + - "application/json" + parameters: + - in: "body" + name: "body" + description: "Toy object that needs to be added to the store" + required: true + schema: + $ref: "#/definitions/Toy" + responses: + 400: + description: "Invalid ID supplied" + 404: + description: "Toy not found" + 405: + description: "Validation exception" /pet/findByStatus: get: tags: @@ -218,6 +269,82 @@ paths: responses: 400: description: "Invalid pet value" + /toy/{toyId}: + parameters: + - name: "toyId" + in: "path" + description: "ID of toy to return" + required: true + type: "integer" + format: "int64" + get: + tags: + - "toy" + summary: "Find toy by ID" + description: "Returns a single petoyt" + operationId: "getToyById" + produces: + - "application/xml" + - "application/json" + responses: + 200: + description: "successful operation" + schema: + $ref: "#/definitions/Toy" + 400: + description: "Invalid ID supplied" + 404: + description: "Toy not found" + post: + tags: + - "toy" + summary: "Updates a toy in the store with form data" + description: "" + operationId: "updateToyWithForm" + consumes: + - "application/x-www-form-urlencoded" + produces: + - "application/xml" + - "application/json" + parameters: + - name: "name" + in: "formData" + description: "Updated name of the toy" + required: true + type: "string" + - name: "status" + in: "formData" + description: "Updated status of the toy" + required: false + type: "string" + responses: + 405: + description: "Invalid input" + delete: + tags: + - "toy" + summary: "Deletes a toy" + description: "" + operationId: "deleteToy" + produces: + - "application/xml" + - "application/json" + parameters: + - name: "api_key" + in: "header" + description: "" + required: true + type: "string" + default: "" + - name: "optional_header" + in: "header" + description: "" + required: false + type: "string" + default: "" + responses: + 400: + description: "Invalid toy value" /pet/{petId}/uploadImage: post: tags: @@ -728,6 +855,74 @@ definitions: type: "object" xml: name: "Pet" + Toy: + required: + - "name" + - "photoUrls" + properties: + id: + type: "integer" + format: "int64" + category: + $ref: "#/definitions/Category" + name: + type: "string" + example: "doggie" + x-ms-secret: "true" + age: + readOnly: true + type: "number" + price: + readOnly: true + type: "string" + title: "{\"path\":[\"toy\"]}" + photoUrls: + type: "array" + title: "{\"path\":[\"toy\"]}" + x-ms-mutability: ["create", "update"] + xml: + name: "photoUrl" + wrapped: true + items: + type: "string" + x-ms-secret: "true" + tags: + type: "array" + xml: + name: "tag" + wrapped: true + items: + $ref: "#/definitions/Tag" + status: + type: "string" + description: "pet status in the store" + enum: + - "available" + - "pending" + - "sold" + secret: + type: "string" + title: "{\"path\":[\"toy\"]}" + x-ms-secret: "true" + nonSecret: + type: "string" + x-ms-secret: "false" + writeOnly: + type: "string" + x-ms-mutability: ["create", "update"] + createOnly: + type: "string" + x-ms-mutability: ["create"] + updateOnly: + type: "string" + x-ms-mutability: ["update"] + readOnlyProperty: + type: "string" + title: "{\"path\":[\"toy\"]}" + x-ms-mutability: ["read"] + type: "object" + xml: + name: "Pet" ApiResponse: properties: code: diff --git a/test/test-operation.js b/test/test-operation.js index b04904f..bec4746 100644 --- a/test/test-operation.js +++ b/test/test-operation.js @@ -833,8 +833,171 @@ describe('Operation', function () { ] ); }); + + it('should return an error for expected type string but found type object', function () { + var request = { + url: '/pet', + body: { + name: 'Test Pet', + photoUrls: [], + readOnlyProperty: {} + } + }; + + request.headers = { + 'content-type': 'application/json' + }; + + var results = operation.validateRequest(request); + + assert.equal(results.warnings.length, 0); + assert.equal(results.errors.length, 1); + assert.deepEqual(results.errors[0].errors[0], { + code: 'INVALID_TYPE', + message: 'Expected type string but found type object', + params: ['string', 'object'], + path: ['readOnlyProperty'] + } + ); + }); + + it('should return an error for readOnly property "toy": "readonly property", cannot be sent in the request.', function () { + var myOperation = swaggerApi.getOperation('/toy', 'post'); + + var request = { + url: '/toy', + body: { + name: 'Test toy', + photoUrls: [], + readOnlyProperty: 'readonly property' + } + }; + + request.headers = { + 'content-type': 'application/json' + }; + + var results = myOperation.validateRequest(request); + + assert.equal(results.warnings.length, 0); + assert.equal(results.errors.length, 1); + assert.deepEqual(results.errors[0].errors[0], { + code: 'READONLY_PROPERTY_NOT_ALLOWED_IN_REQUEST', + params: ['toy', 'readonly property'], + message: 'ReadOnly property `\"toy\": \"readonly property\"`, cannot be sent in the request.', + path: ['readOnlyProperty'], + title: '{\"path\":[\"toy\"]}' + }); + }); + + it('should return 0 warnings 0 errors', function () { + var myOperation = swaggerApi.getOperation('/toy', 'post'); + + var request = { + url: '/toy', + body: { + name: 'Test toy', + photoUrls: [], + secret: 'secret' + } + }; + + request.headers = { + 'content-type': 'application/json' + }; + + var results = myOperation.validateRequest(request); + + assert.equal(results.warnings.length, 0); + assert.equal(results.errors.length, 0); + }); + + it('should return a errors for readOnly property "age": 12, cannot be sent in the request.', function () { + var myOperation = swaggerApi.getOperation('/toy', 'post'); + + var request = { + url: '/toy', + body: { + name: 'Test toy', + photoUrls: [], + age: 12, + } + }; + + request.headers = { + 'content-type': 'application/json' + }; + + var results = myOperation.validateRequest(request); + + assert.equal(results.warnings.length, 0); + assert.deepEqual(results.errors[0].errors[0], + { + code: 'READONLY_PROPERTY_NOT_ALLOWED_IN_REQUEST', + params: ['','12'], + message: 'ReadOnly property `\"\": 12`, cannot be sent in the request.', + path: ['age'], + }); }); + it('should return a errors for expected type number but found type not-a-number', function () { + var myOperation = swaggerApi.getOperation('/toy', 'post'); + + var request = { + url: '/toy', + body: { + name: 'Test toy', + photoUrls: [], + age: NaN, + } + }; + + request.headers = { + 'content-type': 'application/json' + }; + + var results = myOperation.validateRequest(request); + + assert.equal(results.warnings.length, 0); + assert.deepEqual(results.errors[0].errors[0], + { + code: 'INVALID_TYPE', + params: ['number','not-a-number'], + message: 'Expected type number but found type not-a-number', + path: ['age'], + }); + }); + + it('should return a errors for readOnly property "toy": "price", cannot be sent in the request.', function () { + var myOperation = swaggerApi.getOperation('/toy', 'post'); + + var request = { + url: '/toy', + body: { + name: 'Test toy', + photoUrls: [], + price: 'price', + } + }; + + request.headers = { + 'content-type': 'application/json' + }; + + var results = myOperation.validateRequest(request); + + assert.equal(results.warnings.length, 0); + assert.deepEqual(results.errors[0].errors[0], + { + code: 'READONLY_PROPERTY_NOT_ALLOWED_IN_REQUEST', + params: ['toy','price'], + message: 'ReadOnly property `\"toy\": \"price\"`, cannot be sent in the request.', + path: ['price'], + title: '{\"path\":[\"toy\"]}' + }); + }); + }); + // We only need one test to make sure that we're using the global consumes it('should handle global level consumes', function (done) { diff --git a/test/test-response.js b/test/test-response.js index 3dc98ad..6e10efa 100644 --- a/test/test-response.js +++ b/test/test-response.js @@ -129,6 +129,12 @@ describe('Response', function () { photoUrls: [] }; + var validToy = { + name: 'Test Toy', + photoUrls: [], + age: 12, + }; + var writeOnlyPet = { name: 'Test Pet', photoUrls: [], @@ -310,6 +316,54 @@ describe('Response', function () { // We only need one test to make sure that we're using the global produces + it('should not return errors for WRITEONLY_PROPERTY_NOT_ALLOWED_IN_RESPONSE and SECRET_PROPERTY', function (done) { + + var cSwaggerDoc = _.cloneDeep(helpers.swaggerDoc); + + cSwaggerDoc.produces = [ + 'application/json', + 'application/xml' + ]; + + delete cSwaggerDoc.paths['/toy/{toyId}'].get.produces; + + Sway.create({ + definition: cSwaggerDoc + }) + .then(function (api) { + var results = api.getOperation('/toy/{toyId}', 'get').validateResponse({ + body: validToy, + headers: { + 'content-type': 'application/json' + }, + statusCode: 200 + }); + + assert.equal(results.warnings.length, 0); + assert.deepEqual(results.errors[0].errors, [ + { + code: 'WRITEONLY_PROPERTY_NOT_ALLOWED_IN_RESPONSE', + message: 'Write-only property `"toy": `, is not allowed in the response.', + params: ['toy', []], + path: ['photoUrls'], + title: '{\"path\":[\"toy\"]}' + }, { + code: 'SECRET_PROPERTY', + message: 'Secret property `"toy": `, cannot be sent in the response.', + params: ['toy', []], + path: ['photoUrls'], + title: '{\"path\":[\"toy\"]}' + }, { + code: 'SECRET_PROPERTY', + message: 'Secret property `"": "Test Toy"`, cannot be sent in the response.', + params: ['', 'Test Toy'], + path: ['name'], + }, + ]); + }) + .then(done, done); + }); + it('should handle global level produces', function (done) { var cSwaggerDoc = _.cloneDeep(helpers.swaggerDoc);