/* eslint-env mocha */ import expect from "expect" import { fromJS, OrderedMap } from "immutable" import { mapToList, validateMinLength, validateMaxLength, validateDateTime, validateGuid, validateNumber, validateInteger, validateParam, validateFile, validateMaximum, validateMinimum, fromJSOrdered, getAcceptControllingResponse, createDeepLinkPath, escapeDeepLinkPath } from "core/utils" import win from "core/window" describe("utils", function() { describe("mapToList", function(){ it("should convert a map to a list, setting `key`", function(){ // With const aMap = fromJS({ a: { one: 1, }, b: { two: 2, } }) // When const aList = mapToList(aMap, "someKey") // Then expect(aList.toJS()).toEqual([ { someKey: "a", one: 1 }, { someKey: "b", two: 2 }, ]) }) it("should flatten an arbitrarily deep map", function(){ // With const aMap = fromJS({ a: { one: { alpha: true } }, b: { two: { bravo: true }, three: { charlie: true } } }) // When const aList = mapToList(aMap, ["levelA", "levelB"]) // Then expect(aList.toJS()).toEqual([ { levelA: "a", levelB: "one", alpha: true }, { levelA: "b", levelB: "two", bravo: true }, { levelA: "b", levelB: "three", charlie: true }, ]) }) it("should handle an empty map", function(){ // With const aMap = fromJS({}) // When const aList = mapToList(aMap, ["levelA", "levelB"]) // Then expect(aList.toJS()).toEqual([]) }) }) describe("validateMaximum", function() { let errorMessage = "Value must be less than Maximum" it("doesn't return for valid input", function() { expect(validateMaximum(9, 10)).toBeFalsy() expect(validateMaximum(19, 20)).toBeFalsy() }) it("returns a message for invalid input", function() { expect(validateMaximum(1, 0)).toEqual(errorMessage) expect(validateMaximum(10, 9)).toEqual(errorMessage) expect(validateMaximum(20, 19)).toEqual(errorMessage) }) }) describe("validateMinimum", function() { let errorMessage = "Value must be greater than Minimum" it("doesn't return for valid input", function() { expect(validateMinimum(2, 1)).toBeFalsy() expect(validateMinimum(20, 10)).toBeFalsy() }) it("returns a message for invalid input", function() { expect(validateMinimum(-1, 0)).toEqual(errorMessage) expect(validateMinimum(1, 2)).toEqual(errorMessage) expect(validateMinimum(10, 20)).toEqual(errorMessage) }) }) describe("validateNumber", function() { let errorMessage = "Value must be a number" it("doesn't return for whole numbers", function() { expect(validateNumber(0)).toBeFalsy() expect(validateNumber(1)).toBeFalsy() expect(validateNumber(20)).toBeFalsy() expect(validateNumber(5000000)).toBeFalsy() expect(validateNumber("1")).toBeFalsy() expect(validateNumber("2")).toBeFalsy() expect(validateNumber(-1)).toBeFalsy() expect(validateNumber(-20)).toBeFalsy() expect(validateNumber(-5000000)).toBeFalsy() }) it("doesn't return for negative numbers", function() { expect(validateNumber(-1)).toBeFalsy() expect(validateNumber(-20)).toBeFalsy() expect(validateNumber(-5000000)).toBeFalsy() }) it("doesn't return for decimal numbers", function() { expect(validateNumber(1.1)).toBeFalsy() expect(validateNumber(2.5)).toBeFalsy() expect(validateNumber(-30.99)).toBeFalsy() }) it("returns a message for strings", function() { expect(validateNumber("")).toEqual(errorMessage) expect(validateNumber(" ")).toEqual(errorMessage) expect(validateNumber("test")).toEqual(errorMessage) }) it("returns a message for invalid input", function() { expect(validateNumber(undefined)).toEqual(errorMessage) expect(validateNumber(null)).toEqual(errorMessage) expect(validateNumber({})).toEqual(errorMessage) expect(validateNumber([])).toEqual(errorMessage) expect(validateNumber(true)).toEqual(errorMessage) expect(validateNumber(false)).toEqual(errorMessage) }) }) describe("validateInteger", function() { let errorMessage = "Value must be an integer" it("doesn't return for positive integers", function() { expect(validateInteger(0)).toBeFalsy() expect(validateInteger(1)).toBeFalsy() expect(validateInteger(20)).toBeFalsy() expect(validateInteger(5000000)).toBeFalsy() expect(validateInteger("1")).toBeFalsy() expect(validateInteger("2")).toBeFalsy() expect(validateInteger(-1)).toBeFalsy() expect(validateInteger(-20)).toBeFalsy() expect(validateInteger(-5000000)).toBeFalsy() }) it("doesn't return for negative integers", function() { expect(validateInteger(-1)).toBeFalsy() expect(validateInteger(-20)).toBeFalsy() expect(validateInteger(-5000000)).toBeFalsy() }) it("returns a message for decimal values", function() { expect(validateInteger(1.1)).toEqual(errorMessage) expect(validateInteger(2.5)).toEqual(errorMessage) expect(validateInteger(-30.99)).toEqual(errorMessage) }) it("returns a message for strings", function() { expect(validateInteger("")).toEqual(errorMessage) expect(validateInteger(" ")).toEqual(errorMessage) expect(validateInteger("test")).toEqual(errorMessage) }) it("returns a message for invalid input", function() { expect(validateInteger(undefined)).toEqual(errorMessage) expect(validateInteger(null)).toEqual(errorMessage) expect(validateInteger({})).toEqual(errorMessage) expect(validateInteger([])).toEqual(errorMessage) expect(validateInteger(true)).toEqual(errorMessage) expect(validateInteger(false)).toEqual(errorMessage) }) }) describe("validateFile", function() { let errorMessage = "Value must be a file" it("validates against objects which are instances of 'File'", function() { let fileObj = new win.File([], "Test File") expect(validateFile(fileObj)).toBeFalsy() expect(validateFile(null)).toBeFalsy() expect(validateFile(undefined)).toBeFalsy() expect(validateFile(1)).toEqual(errorMessage) expect(validateFile("string")).toEqual(errorMessage) }) }) describe("validateDateTime", function() { let errorMessage = "Value must be a DateTime" it("doesn't return for valid dates", function() { expect(validateDateTime("Mon, 25 Dec 1995 13:30:00 +0430")).toBeFalsy() }) it("returns a message for invalid input'", function() { expect(validateDateTime(null)).toEqual(errorMessage) expect(validateDateTime("string")).toEqual(errorMessage) }) }) describe("validateGuid", function() { let errorMessage = "Value must be a Guid" it("doesn't return for valid guid", function() { expect(validateGuid("8ce4811e-cec5-4a29-891a-15d1917153c1")).toBeFalsy() expect(validateGuid("{8ce4811e-cec5-4a29-891a-15d1917153c1}")).toBeFalsy() }) it("returns a message for invalid input'", function() { expect(validateGuid(1)).toEqual(errorMessage) expect(validateGuid("string")).toEqual(errorMessage) }) }) describe("validateMaxLength", function() { let errorMessage = "Value must be less than MaxLength" it("doesn't return for valid guid", function() { expect(validateMaxLength("a", 1)).toBeFalsy() expect(validateMaxLength("abc", 5)).toBeFalsy() }) it("returns a message for invalid input'", function() { expect(validateMaxLength("abc", 0)).toEqual(errorMessage) expect(validateMaxLength("abc", 1)).toEqual(errorMessage) expect(validateMaxLength("abc", 2)).toEqual(errorMessage) }) }) describe("validateMinLength", function() { let errorMessage = "Value must be greater than MinLength" it("doesn't return for valid guid", function() { expect(validateMinLength("a", 1)).toBeFalsy() expect(validateMinLength("abc", 2)).toBeFalsy() }) it("returns a message for invalid input'", function() { expect(validateMinLength("abc", 5)).toEqual(errorMessage) expect(validateMinLength("abc", 8)).toEqual(errorMessage) }) }) describe("validateParam", function() { let param = null let result = null const assertValidateParam = (param, expectedError) => { // Swagger 2.0 version result = validateParam( fromJS(param), false ) expect( result ).toEqual( expectedError ) // OAS3 version, using `schema` sub-object let oas3Param = { value: param.value, required: param.required, schema: { ...param, value: undefined, required: undefined } } result = validateParam( fromJS(oas3Param), false, true ) expect( result ).toEqual( expectedError ) } it("should check the isOAS3 flag when validating parameters", function() { // This should "skip" validation because there is no `schema.type` property // and we are telling `validateParam` this is an OAS3 spec param = fromJS({ value: "", required: true, schema: { notTheTypeProperty: "string" } }) result = validateParam( param, false, true ) expect( result ).toEqual( [] ) }) it("validates required strings", function() { // invalid string param = { required: true, type: "string", value: "" } assertValidateParam(param, ["Required field is not provided"]) // valid string param = { required: true, type: "string", value: "test string" } assertValidateParam(param, []) // valid string with min and max length param = { required: true, type: "string", value: "test string", maxLength: 50, minLength: 1 } assertValidateParam(param, []) }) it("validates required strings with min and max length", function() { // invalid string with max length param = { required: true, type: "string", value: "test string", maxLength: 5 } assertValidateParam(param, ["Value must be less than MaxLength"]) // invalid string with max length 0 param = { required: true, type: "string", value: "test string", maxLength: 0 } assertValidateParam(param, ["Value must be less than MaxLength"]) // invalid string with min length param = { required: true, type: "string", value: "test string", minLength: 50 } assertValidateParam(param, ["Value must be greater than MinLength"]) }) it("validates optional strings", function() { // valid (empty) string param = { required: false, type: "string", value: "" } assertValidateParam(param, []) // valid string param = { required: false, type: "string", value: "test" } assertValidateParam(param, []) }) it("validates required files", function() { // invalid file param = { required: true, type: "file", value: undefined } assertValidateParam(param, ["Required field is not provided"]) // valid file param = { required: true, type: "file", value: new win.File() } assertValidateParam(param, []) }) it("validates optional files", function() { // invalid file param = { required: false, type: "file", value: "not a file" } assertValidateParam(param, ["Value must be a file"]) // valid (empty) file param = { required: false, type: "file", value: undefined } assertValidateParam(param, []) // valid file param = { required: false, type: "file", value: new win.File() } assertValidateParam(param, []) }) it("validates required arrays", function() { // invalid (empty) array param = { required: true, type: "array", value: [] } assertValidateParam(param, ["Required field is not provided"]) // invalid (not an array) param = { required: true, type: "array", value: undefined } assertValidateParam(param, ["Required field is not provided"]) // invalid array, items do not match correct type param = { required: true, type: "array", value: [1], items: { type: "string" } } assertValidateParam(param, [{index: 0, error: "Value must be a string"}]) // valid array, with no 'type' for items param = { required: true, type: "array", value: ["1"] } assertValidateParam(param, []) // valid array, items match type param = { required: true, type: "array", value: ["1"], items: { type: "string" } } assertValidateParam(param, []) }) it("validates optional arrays", function() { // valid, empty array param = { required: false, type: "array", value: [] } assertValidateParam(param, []) // invalid, items do not match correct type param = { required: false, type: "array", value: ["number"], items: { type: "number" } } assertValidateParam(param, [{index: 0, error: "Value must be a number"}]) // valid param = { required: false, type: "array", value: ["test"], items: { type: "string" } } assertValidateParam(param, []) }) it("validates required booleans", function() { // invalid boolean value param = { required: true, type: "boolean", value: undefined } assertValidateParam(param, ["Required field is not provided"]) // invalid boolean value (not a boolean) param = { required: true, type: "boolean", value: "test string" } assertValidateParam(param, ["Required field is not provided"]) // valid boolean value param = { required: true, type: "boolean", value: "true" } assertValidateParam(param, []) // valid boolean value param = { required: true, type: "boolean", value: false } assertValidateParam(param, []) }) it("validates optional booleans", function() { // valid (empty) boolean value param = { required: false, type: "boolean", value: undefined } assertValidateParam(param, []) // invalid boolean value (not a boolean) param = { required: false, type: "boolean", value: "test string" } assertValidateParam(param, ["Value must be a boolean"]) // valid boolean value param = { required: false, type: "boolean", value: "true" } assertValidateParam(param, []) // valid boolean value param = { required: false, type: "boolean", value: false } assertValidateParam(param, []) }) it("validates required numbers", function() { // invalid number, string instead of a number param = { required: true, type: "number", value: "test" } assertValidateParam(param, ["Required field is not provided"]) // invalid number, undefined value param = { required: true, type: "number", value: undefined } assertValidateParam(param, ["Required field is not provided"]) // valid number with min and max param = { required: true, type: "number", value: 10, minimum: 5, maximum: 99 } assertValidateParam(param, []) // valid negative number with min and max param = { required: true, type: "number", value: -10, minimum: -50, maximum: -5 } assertValidateParam(param, []) // invalid number with maximum:0 param = { required: true, type: "number", value: 1, maximum: 0 } assertValidateParam(param, ["Value must be less than Maximum"]) // invalid number with minimum:0 param = { required: true, type: "number", value: -10, minimum: 0 } assertValidateParam(param, ["Value must be greater than Minimum"]) }) it("validates optional numbers", function() { // invalid number, string instead of a number param = { required: false, type: "number", value: "test" } assertValidateParam(param, ["Value must be a number"]) // valid (empty) number param = { required: false, type: "number", value: undefined } assertValidateParam(param, []) // valid number param = { required: false, type: "number", value: 10 } assertValidateParam(param, []) }) it("validates required integers", function() { // invalid integer, string instead of an integer param = { required: true, type: "integer", value: "test" } assertValidateParam(param, ["Required field is not provided"]) // invalid integer, undefined value param = { required: true, type: "integer", value: undefined } assertValidateParam(param, ["Required field is not provided"]) // valid integer param = { required: true, type: "integer", value: 10 } assertValidateParam(param, []) }) it("validates optional integers", function() { // invalid integer, string instead of an integer param = { required: false, type: "integer", value: "test" } assertValidateParam(param, ["Value must be an integer"]) // valid (empty) integer param = { required: false, type: "integer", value: undefined } assertValidateParam(param, []) // integers param = { required: false, type: "integer", value: 10 } assertValidateParam(param, []) }) }) describe("fromJSOrdered", () => { it("should create an OrderedMap from an object", () => { const param = { value: "test" } const result = fromJSOrdered(param).toJS() expect( result ).toEqual( { value: "test" } ) }) it("should not use an object's length property for Map size", () => { const param = { length: 5 } const result = fromJSOrdered(param).toJS() expect( result ).toEqual( { length: 5 } ) }) it("should create an OrderedMap from an array", () => { const param = [1, 1, 2, 3, 5, 8] const result = fromJSOrdered(param).toJS() expect( result ).toEqual( [1, 1, 2, 3, 5, 8] ) }) }) describe("getAcceptControllingResponse", () => { it("should return the first 2xx response with a media type", () => { const responses = fromJSOrdered({ "200": { content: { "application/json": { schema: { type: "object" } } } }, "201": { content: { "application/json": { schema: { type: "object" } } } } }) expect(getAcceptControllingResponse(responses)).toEqual(responses.get("200")) }) it("should skip 2xx responses without defined media types", () => { const responses = fromJSOrdered({ "200": { content: { "application/json": { schema: { type: "object" } } } }, "201": { content: { "application/json": { schema: { type: "object" } } } } }) expect(getAcceptControllingResponse(responses)).toEqual(responses.get("201")) }) it("should default to the `default` response if it has defined media types", () => { const responses = fromJSOrdered({ "200": { description: "quite empty" }, "201": { description: "quite empty" }, default: { content: { "application/json": { schema: { type: "object" } } } } }) expect(getAcceptControllingResponse(responses)).toEqual(responses.get("default")) }) it("should return null if there are no suitable controlling responses", () => { const responses = fromJSOrdered({ "200": { description: "quite empty" }, "201": { description: "quite empty" }, "default": { description: "also empty.." } }) expect(getAcceptControllingResponse(responses)).toBe(null) }) it("should return null if an empty OrderedMap is passed", () => { const responses = fromJSOrdered() expect(getAcceptControllingResponse(responses)).toBe(null) }) it("should return null if anything except an OrderedMap is passed", () => { const responses = {} expect(getAcceptControllingResponse(responses)).toBe(null) }) }) describe("createDeepLinkPath", function() { it("creates a deep link path replacing spaces with underscores", function() { const result = createDeepLinkPath("tag id with spaces") expect(result).toEqual("tag_id_with_spaces") }) it("trims input when creating a deep link path", function() { let result = createDeepLinkPath(" spaces before and after ") expect(result).toEqual("spaces_before_and_after") result = createDeepLinkPath(" ") expect(result).toEqual("") }) it("creates a deep link path with special characters", function() { const result = createDeepLinkPath("!@#$%^&*(){}[]") expect(result).toEqual("!@#$%^&*(){}[]") }) it("returns an empty string for invalid input", function() { expect( createDeepLinkPath(null) ).toEqual("") expect( createDeepLinkPath(undefined) ).toEqual("") expect( createDeepLinkPath(1) ).toEqual("") expect( createDeepLinkPath([]) ).toEqual("") expect( createDeepLinkPath({}) ).toEqual("") }) }) describe("escapeDeepLinkPath", function() { it("creates and escapes a deep link path", function() { const result = escapeDeepLinkPath("tag id with spaces?") expect(result).toEqual("tag_id_with_spaces\\?") }) it("escapes a deep link path that starts with a number", function() { const result = escapeDeepLinkPath("123") expect(result).toEqual("\\31 23") }) it("escapes a deep link path with a class selector", function() { const result = escapeDeepLinkPath("hello.world") expect(result).toEqual("hello\\.world") }) it("escapes a deep link path with an id selector", function() { const result = escapeDeepLinkPath("hello#world") expect(result).toEqual("hello\\#world") }) }) })