From 1a27c0a8bd8147b3398462eabf8f06e980540fb1 Mon Sep 17 00:00:00 2001 From: Tim Lai Date: Tue, 1 Sep 2020 10:41:01 -0700 Subject: [PATCH] feat: migrate unit tests to Jest (#6353) * config(jest): updated setup * config(jest): update testMatch to include jsx files * config(jest): add transformIgnorePatterns * config(jest): update ignore files that do not work in jest yet * config: add test:unit-jest to test script * fix(jest): lint with eslint-plugin-jest * refactor(jest): move unit test directory * refactor(mocha): restore mocha tests that fail in jest * docs(jest): update helpful scripts with test:unit-jest --- .eslintrc | 2 + config/jest/jest.unit.config.js | 24 + docs/development/scripts.md | 1 + package-lock.json | 236 +++- package.json | 4 +- test/.eslintrc | 2 +- test/mocha/.eslinrc | 7 + test/mocha/components/live-response.jsx | 14 +- .../components/online-validator-badge.jsx | 2 +- test/mocha/core/oauth2-authorize.js | 74 - test/mocha/core/plugins/spec/selectors.js | 1214 ----------------- .../online-validator-badge.jsx | 2 +- test/unit/.eslintrc | 0 .../bugs/3199-sanitization-escaping.jsx | 2 - .../bugs/3279-empty-markdown-source.jsx | 2 - .../bugs/4557-default-parameter-values.jsx | 8 +- test/{mocha => unit}/components/filter.jsx | 3 - .../components/info-wrapper.jsx | 3 - .../components/json-schema-form.jsx | 2 - test/unit/components/live-response.jsx | 101 ++ test/{mocha => unit}/components/markdown.jsx | 2 - .../components/model-example.jsx | 2 - test/{mocha => unit}/components/models.jsx | 4 +- .../components/object-model.jsx | 7 +- .../components/online-validator-badge.jsx | 76 ++ test/{mocha => unit}/components/operation.jsx | 4 +- .../{mocha => unit}/components/operations.jsx | 2 - .../components/parameter-row.jsx | 2 - .../components/primitive-model.jsx | 2 - .../components/response-body.jsx | 1 - test/{mocha => unit}/components/response.jsx | 1 - .../components/schemes-wrapper.jsx | 5 +- test/{mocha => unit}/components/schemes.jsx | 11 +- .../components/version-pragma-filter.jsx | 3 - test/{mocha => unit}/core/curlify.js | 61 +- .../core/helpers/get-parameter-schema.js | 1 - test/unit/core/oauth2-authorize.js | 77 ++ .../core/plugins/auth/actions.js | 32 +- .../core/plugins/auth/preauthorize.js | 3 +- .../core/plugins/auth/selectors.js | 3 +- .../core/plugins/auth/wrap-spec-actions.js | 13 +- .../core/plugins/configs/actions.js | 5 +- .../plugins/err/transformers/not-of-type.js | 1 - .../err/transformers/parameter-oneof.js | 1 - .../core/plugins/filter/opsFilter.js | 1 - .../core/plugins/oas3/helpers.js | 1 - .../core/plugins/oas3/reducers.js | 3 +- .../core/plugins/oas3/servers-wrapper.jsx | 2 - .../core/plugins/oas3/state-integration.js | 1 - .../core/plugins/oas3/wrap-auth-selectors.js | 5 +- .../core/plugins/oas3/wrap-spec-selectors.js | 5 +- .../core/plugins/samples/fn.js | 43 +- .../core/plugins/spec/actions.js | 70 +- .../core/plugins/spec/assets/petstore.json | 0 .../core/plugins/spec/reducer.js | 3 +- test/unit/core/plugins/spec/selectors.js | 1213 ++++++++++++++++ .../plugins/swagger-js/withCredentials.js | 31 +- test/{mocha => unit}/core/system/system.jsx | 24 +- .../core/system/wrapComponent.jsx | 2 +- test/{mocha => unit}/core/utils.js | 297 ++-- test/{mocha => unit}/docker/oauth.js | 1 - test/{mocha => unit}/docker/translator.js | 5 +- test/unit/setup.js | 19 + .../swagger-ui-dist-package/absolute-path.js | 3 +- .../xss/anchor-target-rel/info.jsx | 22 +- .../xss/anchor-target-rel/link.jsx | 11 +- .../xss/anchor-target-rel/markdown.jsx | 18 +- .../online-validator-badge.jsx | 29 + .../{mocha => unit}/xss/info-sanitization.jsx | 2 - .../xss/markdown-script-sanitization.jsx | 2 - 70 files changed, 2131 insertions(+), 1704 deletions(-) create mode 100644 config/jest/jest.unit.config.js create mode 100644 test/mocha/.eslinrc delete mode 100644 test/mocha/core/oauth2-authorize.js delete mode 100644 test/mocha/core/plugins/spec/selectors.js create mode 100644 test/unit/.eslintrc rename test/{mocha => unit}/bugs/3199-sanitization-escaping.jsx (92%) rename test/{mocha => unit}/bugs/3279-empty-markdown-source.jsx (94%) rename test/{mocha => unit}/bugs/4557-default-parameter-values.jsx (94%) rename test/{mocha => unit}/components/filter.jsx (97%) rename test/{mocha => unit}/components/info-wrapper.jsx (97%) rename test/{mocha => unit}/components/json-schema-form.jsx (99%) create mode 100644 test/unit/components/live-response.jsx rename test/{mocha => unit}/components/markdown.jsx (99%) rename test/{mocha => unit}/components/model-example.jsx (98%) rename test/{mocha => unit}/components/models.jsx (93%) rename test/{mocha => unit}/components/object-model.jsx (95%) create mode 100644 test/unit/components/online-validator-badge.jsx rename test/{mocha => unit}/components/operation.jsx (89%) rename test/{mocha => unit}/components/operations.jsx (98%) rename test/{mocha => unit}/components/parameter-row.jsx (97%) rename test/{mocha => unit}/components/primitive-model.jsx (96%) rename test/{mocha => unit}/components/response-body.jsx (98%) rename test/{mocha => unit}/components/response.jsx (98%) rename test/{mocha => unit}/components/schemes-wrapper.jsx (96%) rename test/{mocha => unit}/components/schemes.jsx (87%) rename test/{mocha => unit}/components/version-pragma-filter.jsx (94%) rename test/{mocha => unit}/core/curlify.js (84%) rename test/{mocha => unit}/core/helpers/get-parameter-schema.js (99%) create mode 100644 test/unit/core/oauth2-authorize.js rename test/{mocha => unit}/core/plugins/auth/actions.js (82%) rename test/{mocha => unit}/core/plugins/auth/preauthorize.js (98%) rename test/{mocha => unit}/core/plugins/auth/selectors.js (98%) rename test/{mocha => unit}/core/plugins/auth/wrap-spec-actions.js (68%) rename test/{mocha => unit}/core/plugins/configs/actions.js (80%) rename test/{mocha => unit}/core/plugins/err/transformers/not-of-type.js (97%) rename test/{mocha => unit}/core/plugins/err/transformers/parameter-oneof.js (99%) rename test/{mocha => unit}/core/plugins/filter/opsFilter.js (96%) rename test/{mocha => unit}/core/plugins/oas3/helpers.js (98%) rename test/{mocha => unit}/core/plugins/oas3/reducers.js (99%) rename test/{mocha => unit}/core/plugins/oas3/servers-wrapper.jsx (97%) rename test/{mocha => unit}/core/plugins/oas3/state-integration.js (99%) rename test/{mocha => unit}/core/plugins/oas3/wrap-auth-selectors.js (96%) rename test/{mocha => unit}/core/plugins/oas3/wrap-spec-selectors.js (94%) rename test/{mocha => unit}/core/plugins/samples/fn.js (96%) rename test/{mocha => unit}/core/plugins/spec/actions.js (70%) rename test/{mocha => unit}/core/plugins/spec/assets/petstore.json (100%) rename test/{mocha => unit}/core/plugins/spec/reducer.js (99%) create mode 100644 test/unit/core/plugins/spec/selectors.js rename test/{mocha => unit}/core/plugins/swagger-js/withCredentials.js (69%) rename test/{mocha => unit}/core/system/system.jsx (98%) rename test/{mocha => unit}/core/system/wrapComponent.jsx (99%) rename test/{mocha => unit}/core/utils.js (84%) rename test/{mocha => unit}/docker/oauth.js (98%) rename test/{mocha => unit}/docker/translator.js (98%) create mode 100644 test/unit/setup.js rename test/{mocha => unit}/swagger-ui-dist-package/absolute-path.js (88%) rename test/{mocha => unit}/xss/anchor-target-rel/info.jsx (79%) rename test/{mocha => unit}/xss/anchor-target-rel/link.jsx (75%) rename test/{mocha => unit}/xss/anchor-target-rel/markdown.jsx (76%) create mode 100644 test/unit/xss/anchor-target-rel/online-validator-badge.jsx rename test/{mocha => unit}/xss/info-sanitization.jsx (95%) rename test/{mocha => unit}/xss/markdown-script-sanitization.jsx (96%) diff --git a/.eslintrc b/.eslintrc index 34099ecd..b7b01640 100644 --- a/.eslintrc +++ b/.eslintrc @@ -4,6 +4,7 @@ env: node: true es6: true jest: true + jest/globals: true parserOptions: ecmaFeatures: jsx: true @@ -14,6 +15,7 @@ plugins: - react - mocha - import + - jest settings: react: pragma: React diff --git a/config/jest/jest.unit.config.js b/config/jest/jest.unit.config.js new file mode 100644 index 00000000..7c5305c2 --- /dev/null +++ b/config/jest/jest.unit.config.js @@ -0,0 +1,24 @@ +const path = require('path'); + +module.exports = { + rootDir: path.join(__dirname, '..', '..'), + testEnvironment: 'jsdom', + testMatch: [ + '**/test/unit/*.js?(x)', + '**/test/unit/**/*.js?(x)', + ], + // testMatch: ['**/test/unit/core/plugins/auth/actions.js'], + setupFilesAfterEnv: ['/test/unit/setup.js'], + testPathIgnorePatterns: [ + '/node_modules/', + '/test/build-artifacts/', + '/test/mocha', + '/test/unit/setup.js', + '/test/unit/xss/anchor-target-rel/online-validator-badge.jsx', + '/test/unit/components/online-validator-badge.jsx', + '/test/unit/components/live-response.jsx', + ], + transformIgnorePatterns: [ + '/node_modules/(?!(react-syntax-highlighter)/)' + ] +}; diff --git a/docs/development/scripts.md b/docs/development/scripts.md index b74472fc..b08b391c 100644 --- a/docs/development/scripts.md +++ b/docs/development/scripts.md @@ -28,6 +28,7 @@ Script name | Description --- | --- `test` | Run unit tests in Node, run Cypress end-to-end tests, and run ESLint in errors-only mode. `just-test-in-node` | Run Mocha unit tests in Node. +`test:unit-jest` | Run Jest unit tests in Node. `e2e` | Run end-to-end tests (requires JDK and Selenium). `e2e-cypress` | Run end-to-end browser tests with Cypress. `dev-e2e-cypress` | Dev mode, open Cypress runner and manually select tests to run. diff --git a/package-lock.json b/package-lock.json index ef40d07e..3ffeeac3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4320,6 +4320,88 @@ "@types/node": "*" } }, + "@typescript-eslint/experimental-utils": { + "version": "2.34.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-2.34.0.tgz", + "integrity": "sha512-eS6FTkq+wuMJ+sgtuNTtcqavWXqsflWcfBnlYhg/nS4aZ1leewkXGbvBhaapn1q6qf4M71bsR1tez5JTRMuqwA==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.3", + "@typescript-eslint/typescript-estree": "2.34.0", + "eslint-scope": "^5.0.0", + "eslint-utils": "^2.0.0" + }, + "dependencies": { + "eslint-scope": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.0.tgz", + "integrity": "sha512-iiGRvtxWqgtx5m8EyQUJihBloE4EnYeGE/bz1wSPwJE6tZuJUtHlhqDM4Xj2ukE8Dyy1+HCZ4hE0fzIVMzb58w==", + "dev": true, + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + } + } + }, + "@typescript-eslint/typescript-estree": { + "version": "2.34.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-2.34.0.tgz", + "integrity": "sha512-OMAr+nJWKdlVM9LOqCqh3pQQPwxHAN7Du8DR6dmwCrAmxtiXQnhHJ6tBNtf+cggqfo51SG/FCwnKhXCIM7hnVg==", + "dev": true, + "requires": { + "debug": "^4.1.1", + "eslint-visitor-keys": "^1.1.0", + "glob": "^7.1.6", + "is-glob": "^4.0.1", + "lodash": "^4.17.15", + "semver": "^7.3.2", + "tsutils": "^3.17.1" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "semver": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", + "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", + "dev": true + } + } + }, "@webassemblyjs/ast": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.9.0.tgz", @@ -10506,6 +10588,15 @@ } } }, + "eslint-plugin-jest": { + "version": "23.20.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-23.20.0.tgz", + "integrity": "sha512-+6BGQt85OREevBDWCvhqj1yYA4+BFK4XnRZSGJionuEYmcglMZYLNNBBemwzbqUAckURaHdJSBcjHPyrtypZOw==", + "dev": true, + "requires": { + "@typescript-eslint/experimental-utils": "^2.5.0" + } + }, "eslint-plugin-mocha": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/eslint-plugin-mocha/-/eslint-plugin-mocha-6.3.0.tgz", @@ -12400,14 +12491,67 @@ "dev": true }, "function.prototype.name": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.0.tgz", - "integrity": "sha512-Bs0VRrTz4ghD8pTmbJQD1mZ8A/mN0ur/jGz+A6FBxPDUPkm1tNfF6bhTYPA7i7aF4lZJVr+OXTNNrnnIl58Wfg==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.2.tgz", + "integrity": "sha512-C8A+LlHBJjB2AdcRPorc5JvJ5VUoWlXdEHLOJdCI7kjHEtGTpHQUiqMvCIKUwIsGwZX2jZJy761AXsn356bJQg==", "dev": true, "requires": { - "define-properties": "^1.1.2", - "function-bind": "^1.1.1", - "is-callable": "^1.1.3" + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1", + "functions-have-names": "^1.2.0" + }, + "dependencies": { + "es-abstract": { + "version": "1.17.6", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", + "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.0", + "is-regex": "^1.1.0", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", + "dev": true + }, + "is-callable": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.0.tgz", + "integrity": "sha512-pyVD9AaGLxtg6srb2Ng6ynWJqkHU9bEM087AKck0w8QwDarTfNcpIYoU8x8Hv2Icm8u6kFJM18Dag8lyqGkviw==", + "dev": true + }, + "is-regex": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz", + "integrity": "sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==", + "dev": true, + "requires": { + "has-symbols": "^1.0.1" + } + } } }, "functional-red-black-tree": { @@ -13399,9 +13543,9 @@ }, "dependencies": { "readable-stream": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.3.0.tgz", - "integrity": "sha512-EsI+s3k3XsW+fU8fQACLN59ky34AZ14LoeVZpYwmZvldCFo0r0gnelwF2TcMjLor/BTL5aDJVBMkss0dthToPw==", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", "dev": true, "requires": { "inherits": "^2.0.3", @@ -22021,10 +22165,67 @@ "dev": true }, "object-is": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.0.1.tgz", - "integrity": "sha1-CqYOyZiaCz7Xlc9NBvYs8a1lObY=", - "dev": true + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.2.tgz", + "integrity": "sha512-5lHCz+0uufF6wZ7CRFWJN3hp8Jqblpgve06U5CMQ3f//6iDjPr2PEo9MWCjEssDsa+UZEL4PkFpr+BMop6aKzQ==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + }, + "dependencies": { + "es-abstract": { + "version": "1.17.6", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", + "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.0", + "is-regex": "^1.1.0", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", + "dev": true + }, + "is-callable": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.0.tgz", + "integrity": "sha512-pyVD9AaGLxtg6srb2Ng6ynWJqkHU9bEM087AKck0w8QwDarTfNcpIYoU8x8Hv2Icm8u6kFJM18Dag8lyqGkviw==", + "dev": true + }, + "is-regex": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz", + "integrity": "sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==", + "dev": true, + "requires": { + "has-symbols": "^1.0.1" + } + } + } }, "object-keys": { "version": "1.1.1", @@ -28420,6 +28621,15 @@ "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==" }, + "tsutils": { + "version": "3.17.1", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.17.1.tgz", + "integrity": "sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + } + }, "tty-browserify": { "version": "0.0.0", "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", diff --git a/package.json b/package.json index 1d0b44f3..60ec45be 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "lint": "eslint --cache --ext \".js,.jsx\" src test", "lint-errors": "eslint --cache --quiet --ext \".js,.jsx\" src test", "lint-fix": "eslint --cache --ext \".js,.jsx\" src test --fix", - "test": "run-s just-test-in-node e2e-cypress lint-errors", + "test": "run-s just-test-in-node test:unit-jest e2e-cypress lint-errors", "test-in-node": "run-s lint-errors just-test-in-node", "just-test-in-node": "cross-env BABEL_ENV=test mocha \"test/mocha/**/*.{js,jsx}\"", "test-e2e-cypress": "cypress run", @@ -41,6 +41,7 @@ "test:artifact:umd:bundle": "npm run build-bundle && cross-env BABEL_ENV=commonjs jest --config ./config/jest/jest.artifact-umd-bundle.config.js", "test:artifact:es:bundle": "npm run build:es:bundle && cross-env BABEL_ENV=commonjs jest --config ./config/jest/jest.artifact-es-bundle.config.js", "test:artifact:es:bundle:core": "npm run build:es:bundle:core && cross-env BABEL_ENV=commonjs jest --config ./config/jest/jest.artifact-es-bundle-core.config.js", + "test:unit-jest": "cross-env BABEL_ENV=test jest --config ./config/jest/jest.unit.config.js", "e2e-initial-render": "nightwatch test/e2e-selenium/scenarios/ --config test/e2e-selenium/nightwatch.json --group initial-render", "mock-api": "json-server --watch test/e2e-selenium/db.json --port 3204", "hot-e2e-cypress-server": "webpack-dev-server --config webpack/dev-e2e.babel.js --content-base test/e2e-cypress/static", @@ -128,6 +129,7 @@ "enzyme": "^2.7.1", "eslint": "^4.1.1", "eslint-plugin-import": "^2.21.1", + "eslint-plugin-jest": "=23.20.0", "eslint-plugin-mocha": "^6.3.0", "eslint-plugin-react": "^7.20.0", "esm": "=3.2.25", diff --git a/test/.eslintrc b/test/.eslintrc index b08be1b9..0c15d61a 100644 --- a/test/.eslintrc +++ b/test/.eslintrc @@ -4,4 +4,4 @@ rules: "react/prop-types": 1 # bah humbug "react/require-render-return": 1 "no-unused-vars": 1 # unused vars in tests can be useful for indicating a full signature - "no-global-assign": 1 + "no-global-assign": 1 \ No newline at end of file diff --git a/test/mocha/.eslinrc b/test/mocha/.eslinrc new file mode 100644 index 00000000..b08be1b9 --- /dev/null +++ b/test/mocha/.eslinrc @@ -0,0 +1,7 @@ +env: + mocha: true +rules: + "react/prop-types": 1 # bah humbug + "react/require-render-return": 1 + "no-unused-vars": 1 # unused vars in tests can be useful for indicating a full signature + "no-global-assign": 1 diff --git a/test/mocha/components/live-response.jsx b/test/mocha/components/live-response.jsx index 9d7b6da1..0beef9fc 100644 --- a/test/mocha/components/live-response.jsx +++ b/test/mocha/components/live-response.jsx @@ -7,7 +7,7 @@ import Curl from "components/curl" import LiveResponse from "components/live-response" import ResponseBody from "components/response-body" -describe("", function(){ +describe("", function () { let request = fromJSOrdered({ credentials: "same-origin", headers: { @@ -35,8 +35,8 @@ describe("", function(){ { showMutatedRequest: false, expected: { request: "request", requestForCalls: 1, mutatedRequestForCalls: 0 } } ] - tests.forEach(function(test) { - it("passes " + test.expected.request + " to Curl when showMutatedRequest = " + test.showMutatedRequest, function() { + tests.forEach(function (test) { + it("passes " + test.expected.request + " to Curl when showMutatedRequest = " + test.showMutatedRequest, function () { // Given @@ -51,7 +51,7 @@ describe("", function(){ }) let mutatedRequestForSpy = createSpy().andReturn(mutatedRequest) - let requestForSpy = createSpy().andReturn(request) + let requestForSpy = createSpy().andReturn(request) let components = { curl: Curl, @@ -59,12 +59,12 @@ describe("", function(){ } let props = { - response: response, + response: response, specSelectors: { mutatedRequestFor: mutatedRequestForSpy, requestFor: requestForSpy, }, - pathMethod: [ "/one", "get" ], + pathMethod: ["/one", "get"], getComponent: (c) => { return components[c] }, @@ -73,7 +73,7 @@ describe("", function(){ } // When - let wrapper = shallow() + let wrapper = shallow() // Then expect(mutatedRequestForSpy.calls.length).toEqual(test.expected.mutatedRequestForCalls) diff --git a/test/mocha/components/online-validator-badge.jsx b/test/mocha/components/online-validator-badge.jsx index 3d947b66..98d14ad3 100644 --- a/test/mocha/components/online-validator-badge.jsx +++ b/test/mocha/components/online-validator-badge.jsx @@ -16,7 +16,7 @@ describe("", function () { } } const wrapper = mount( - + ) // Then diff --git a/test/mocha/core/oauth2-authorize.js b/test/mocha/core/oauth2-authorize.js deleted file mode 100644 index 064b7fd0..00000000 --- a/test/mocha/core/oauth2-authorize.js +++ /dev/null @@ -1,74 +0,0 @@ -/* eslint-env mocha */ -import expect, { spyOn } from "expect" -import win from "core/window" -import oauth2Authorize from "core/oauth2-authorize" -import * as utils from "core/utils" - -describe("oauth2", function () { - - let mockSchema = { - flow: "accessCode", - authorizationUrl: "https://testAuthorizationUrl" - } - - let authConfig = { - auth: { schema: { get: (key)=> mockSchema[key] } }, - authActions: {}, - errActions: {}, - configs: { oauth2RedirectUrl: "" }, - authConfigs: {} - } - - describe("authorize redirect", function () { - it("should build authorize url", function() { - const windowOpenSpy = spyOn(win, "open") - oauth2Authorize(authConfig) - expect(windowOpenSpy.calls.length).toEqual(1) - expect(windowOpenSpy.calls[0].arguments[0]).toMatch("https://testAuthorizationUrl?response_type=code&redirect_uri=&state=") - - windowOpenSpy.restore() - }) - - it("should append query parameters to authorizeUrl with query parameters", function() { - const windowOpenSpy = spyOn(win, "open") - mockSchema.authorizationUrl = "https://testAuthorizationUrl?param=1" - oauth2Authorize(authConfig) - expect(windowOpenSpy.calls.length).toEqual(1) - expect(windowOpenSpy.calls[0].arguments[0]).toMatch("https://testAuthorizationUrl?param=1&response_type=code&redirect_uri=&state=") - - windowOpenSpy.restore() - }) - - it("should send code_challenge when using authorizationCode flow with usePkceWithAuthorizationCodeGrant enabled", function () { - const windowOpenSpy = spyOn(win, "open") - mockSchema.flow = "authorizationCode" - - const expectedCodeVerifier = "mock_code_verifier" - const expectedCodeChallenge = "mock_code_challenge" - - const generateCodeVerifierSpy = spyOn(utils, "generateCodeVerifier").andReturn(expectedCodeVerifier) - const createCodeChallengeSpy = spyOn(utils, "createCodeChallenge").andReturn(expectedCodeChallenge) - - authConfig.authConfigs.usePkceWithAuthorizationCodeGrant = true - - oauth2Authorize(authConfig) - expect(win.open.calls.length).toEqual(1) - - const actualUrl = new URLSearchParams(win.open.calls[0].arguments[0]) - expect(actualUrl.get("code_challenge")).toBe(expectedCodeChallenge) - expect(actualUrl.get("code_challenge_method")).toBe("S256") - - expect(createCodeChallengeSpy.calls.length).toEqual(1) - expect(createCodeChallengeSpy.calls[0].arguments[0]).toBe(expectedCodeVerifier) - - // The code_verifier should be stored to be able to send in - // on the TokenUrl call - expect(authConfig.auth.codeVerifier).toBe(expectedCodeVerifier) - - // Restore spies - windowOpenSpy.restore() - generateCodeVerifierSpy.restore() - createCodeChallengeSpy.restore() - }) - }) -}) diff --git a/test/mocha/core/plugins/spec/selectors.js b/test/mocha/core/plugins/spec/selectors.js deleted file mode 100644 index 6a563ba5..00000000 --- a/test/mocha/core/plugins/spec/selectors.js +++ /dev/null @@ -1,1214 +0,0 @@ -/* eslint-env mocha */ -import expect from "expect" -import { fromJS } from "immutable" -import { fromJSOrdered } from "core/utils" -import { - definitions, - parameterValues, - contentTypeValues, - operationScheme, - specJsonWithResolvedSubtrees, - producesOptionsFor, - operationWithMeta, - parameterWithMeta, - parameterWithMetaByIdentity, - parameterInclusionSettingFor, - consumesOptionsFor, - taggedOperations -} from "corePlugins/spec/selectors" - -import Petstore from "./assets/petstore.json" - - describe("definitions", function(){ - it("should return definitions by default", function(){ - - // Given - const spec = fromJS({ - json: { - swagger: "2.0", - definitions: { - a: { - type: "string" - }, - b: { - type: "string" - } - } - } - }) - - // When - let res = definitions(spec) - - // Then - expect(res.toJS()).toEqual({ - a: { - type: "string" - }, - b: { - type: "string" - } - }) - }) - it("should return an empty Map when missing definitions", function(){ - - // Given - const spec = fromJS({ - json: { - swagger: "2.0" - } - }) - - // When - let res = definitions(spec) - - // Then - expect(res.toJS()).toEqual({}) - }) - it("should return an empty Map when given non-object definitions", function(){ - - // Given - const spec = fromJS({ - json: { - swagger: "2.0", - definitions: "..." - } - }) - - // When - let res = definitions(spec) - - // Then - expect(res.toJS()).toEqual({}) - }) - }) - - describe("parameterValue", function(){ - - it("should return Map({}) if no path found", function(){ - - // Given - const spec = fromJS({ }) - - // When - let paramValues = parameterValues(spec, ["/one", "get"]) - - // Then - expect(paramValues.toJS()).toEqual({}) - - }) - - it("should return a hash of [parameterName]: value", function(){ - - // Given - const spec = fromJS({ - json: { - paths: { - "/one": { - get: { - parameters: [ - { name: "one", in: "query", value: 1}, - { name: "two", in: "query", value: "duos"} - ] - } - } - } - } - }) - - // When - let paramValues = parameterValues(spec, ["/one", "get"]) - - // Then - expect(paramValues.toJS()).toEqual({ - "query.one": 1, - "query.two": "duos" - }) - - }) - - }) - - describe("contentTypeValues", function(){ - it("should return { requestContentType, responseContentType } from an operation", function(){ - // Given - let state = fromJS({ - json: { - paths: { - "/one": { - get: {} - } - } - }, - meta: { - paths: { - "/one": { - get: { - "consumes_value": "one", - "produces_value": "two" - } - } - } - } - }) - - // When - let contentTypes = contentTypeValues(state, [ "/one", "get" ]) - // Then - expect(contentTypes.toJS()).toEqual({ - requestContentType: "one", - responseContentType: "two" - }) - }) - - it("should default to the first `produces` array value if current is not set", function(){ - // Given - let state = fromJS({ - json: { - paths: { - "/one": { - get: { - produces: [ - "application/xml", - "application/whatever" - ] - } - } - } - }, - meta: { - paths: { - "/one": { - get: { - "consumes_value": "one" - } - } - } - } - }) - - // When - let contentTypes = contentTypeValues(state, [ "/one", "get" ]) - // Then - expect(contentTypes.toJS()).toEqual({ - requestContentType: "one", - responseContentType: "application/xml" - }) - }) - - it("should default to `application/json` if a default produces value is not available", function(){ - // Given - let state = fromJS({ - json: { - paths: { - "/one": { - get: {} - } - } - }, - meta: { - paths: { - "/one": { - get: { - "consumes_value": "one" - } - } - } - } - }) - - // When - let contentTypes = contentTypeValues(state, [ "/one", "get" ]) - // Then - expect(contentTypes.toJS()).toEqual({ - requestContentType: "one", - responseContentType: "application/json" - }) - }) - - it("should prioritize consumes value first from an operation", function(){ - // Given - let state = fromJS({ - json: { - paths: { - "/one": { - get: { - "parameters": [{ - "type": "file" - }], - } - } - } - }, - meta: { - paths: { - "/one": { - get: { - "consumes_value": "one", - } - } - } - } - }) - - // When - let contentTypes = contentTypeValues(state, [ "/one", "get" ]) - // Then - expect(contentTypes.toJS().requestContentType).toEqual("one") - }) - - it("should fallback to multipart/form-data if there is no consumes value but there is a file parameter", function(){ - // Given - let state = fromJS({ - json: { - paths: { - "/one": { - get: { - "parameters": [{ - "type": "file" - }], - } - } - } - } - }) - - // When - let contentTypes = contentTypeValues(state, [ "/one", "get" ]) - // Then - expect(contentTypes.toJS().requestContentType).toEqual("multipart/form-data") - }) - - it("should fallback to application/x-www-form-urlencoded if there is no consumes value, no file parameter, but there is a formData parameter", function(){ - // Given - let state = fromJS({ - json: { - paths: { - "/one": { - get: { - "parameters": [{ - "type": "formData" - }], - } - } - } - } - }) - - // When - let contentTypes = contentTypeValues(state, [ "/one", "get" ]) - // Then - expect(contentTypes.toJS().requestContentType).toEqual("application/x-www-form-urlencoded") - }) - - it("should return nothing, if the operation does not exist", function(){ - // Given - let state = fromJS({ }) - - // When - let contentTypes = contentTypeValues(state, [ "/one", "get" ]) - // Then - expect(contentTypes.toJS()).toEqual({ - requestContentType: undefined, - responseContentType: undefined - }) - }) - - }) - - describe("operationScheme", function(){ - - it("should return the correct scheme for a remote spec that doesn't specify a scheme", function(){ - // Given - let state = fromJS({ - url: "https://generator.swagger.io/api/swagger.json", - json: { - paths: { - "/one": { - get: { - "consumes_value": "one", - "produces_value": "two" - } - } - } - } - }) - - // When - let scheme = operationScheme(state, ["/one"], "get") - // Then - expect(scheme).toEqual("https") - }) - - // it("should be ok, if no operation found", function(){ - // // Given - // let state = fromJS({ }) - // - // // When - // let contentTypes = contentTypeValues(state, [ "/one", "get" ]) - // // Then - // expect(contentTypes.toJS()).toEqual({ - // requestContentType: undefined, - // responseContentType: undefined - // }) - // }) - - }) - - describe("specJsonWithResolvedSubtrees", function(){ - - it("should return a correctly merged tree", function(){ - // Given - let state = fromJS({ - json: { - definitions: { - Asdf: { - $ref: "#/some/path", - randomKey: "this should be removed b/c siblings of $refs must be removed, per the specification", - description: "same for this key" - }, - Fgsfds: { - $ref: "#/another/path" - }, - OtherDef: { - description: "has no refs" - } - } - }, - resolvedSubtrees: { - definitions: { - Asdf: { - type: "object", - $$ref: "#/some/path" - } - } - } - }) - - // When - let result = specJsonWithResolvedSubtrees(state) - // Then - expect(result.toJS()).toEqual({ - definitions: { - Asdf: { - type: "object", - $$ref: "#/some/path" - }, - Fgsfds: { - $ref: "#/another/path" - }, - OtherDef: { - description: "has no refs" - } - } - }) - }) - it("should preserve initial map key ordering", function(){ - // Given - let state = fromJSOrdered({ - json: Petstore, - resolvedSubtrees: { - paths: { - "/pet/{petId}": { - post: { - tags: [ - "pet" - ], - summary: "Updates a pet in the store with form data", - description: "", - operationId: "updatePetWithForm", - consumes: [ - "application/x-www-form-urlencoded" - ], - produces: [ - "application/xml", - "application/json" - ], - parameters: [ - { - name: "petId", - "in": "path", - description: "ID of pet that needs to be updated", - required: true, - type: "integer", - format: "int64" - }, - { - name: "name", - "in": "formData", - description: "Updated name of the pet", - required: false, - type: "string" - }, - { - name: "status", - "in": "formData", - description: "Updated status of the pet", - required: false, - type: "string" - } - ], - responses: { - "405": { - description: "Invalid input" - } - }, - security: [ - { - petstore_auth: [ - "write:pets", - "read:pets" - ] - } - ], - __originalOperationId: "updatePetWithForm" - } - } - } - } - }) - - // When - let result = specJsonWithResolvedSubtrees(state) - - // Then - const correctOrder = [ - "/pet", - "/pet/findByStatus", - "/pet/findByTags", - "/pet/{petId}", - "/pet/{petId}/uploadImage", - "/store/inventory", - "/store/order", - "/store/order/{orderId}", - "/user", - "/user/createWithArray", - "/user/createWithList", - "/user/login", - "/user/logout", - "/user/{username}" - ] - expect(state.getIn(["json", "paths"]).keySeq().toJS()).toEqual(correctOrder) - expect(result.getIn(["paths"]).keySeq().toJS()).toEqual(correctOrder) - }) - }) - - describe("operationWithMeta", function() { - it("should support merging in {in}.{name} keyed param metadata", function () { - const state = fromJS({ - json: { - paths: { - "/": { - "get": { - parameters: [ - { - name: "myBody", - in: "body" - } - ] - } - } - } - }, - meta: { - paths: { - "/": { - "get": { - parameters: { - "body.myBody": { - value: "abc123" - } - } - } - } - } - } - }) - - const result = operationWithMeta(state, "/", "get") - - expect(result.toJS()).toEqual({ - parameters: [ - { - name: "myBody", - in: "body", - value: "abc123" - } - ] - }) - }) - it("should support merging in hash-keyed param metadata", function () { - const bodyParam = fromJS({ - name: "myBody", - in: "body" - }) - - const state = fromJS({ - json: { - paths: { - "/": { - "get": { - parameters: [ - bodyParam - ] - } - } - } - }, - meta: { - paths: { - "/": { - "get": { - parameters: { - [`body.myBody.hash-${bodyParam.hashCode()}`]: { - value: "abc123" - } - } - } - } - } - } - }) - - const result = operationWithMeta(state, "/", "get") - - expect(result.toJS()).toEqual({ - parameters: [ - { - name: "myBody", - in: "body", - value: "abc123" - } - ] - }) - }) - }) - describe("parameterWithMeta", function() { - it("should support merging in {in}.{name} keyed param metadata", function () { - const state = fromJS({ - json: { - paths: { - "/": { - "get": { - parameters: [ - { - name: "myBody", - in: "body" - } - ] - } - } - } - }, - meta: { - paths: { - "/": { - "get": { - parameters: { - "body.myBody": { - value: "abc123" - } - } - } - } - } - } - }) - - const result = parameterWithMeta(state, ["/", "get"], "myBody", "body") - - expect(result.toJS()).toEqual({ - name: "myBody", - in: "body", - value: "abc123" - }) - }) - it("should give best-effort when encountering hash-keyed param metadata", function () { - const bodyParam = fromJS({ - name: "myBody", - in: "body" - }) - - const state = fromJS({ - json: { - paths: { - "/": { - "get": { - parameters: [ - bodyParam - ] - } - } - } - }, - meta: { - paths: { - "/": { - "get": { - parameters: { - [`body.myBody.hash-${bodyParam.hashCode()}`]: { - value: "abc123" - } - } - } - } - } - } - }) - - const result = parameterWithMeta(state, ["/", "get"], "myBody", "body") - - expect(result.toJS()).toEqual({ - name: "myBody", - in: "body", - value: "abc123" - }) - }) - - }) - describe("parameterWithMetaByIdentity", function() { - it("should support merging in {in}.{name} keyed param metadata", function () { - const bodyParam = fromJS({ - name: "myBody", - in: "body" - }) - - const state = fromJS({ - json: { - paths: { - "/": { - "get": { - parameters: [bodyParam] - } - } - } - }, - meta: { - paths: { - "/": { - "get": { - parameters: { - "body.myBody": { - value: "abc123" - } - } - } - } - } - } - }) - - const result = parameterWithMetaByIdentity(state, ["/", "get"], bodyParam) - - expect(result.toJS()).toEqual({ - name: "myBody", - in: "body", - value: "abc123" - }) - }) - it("should support merging in hash-keyed param metadata", function () { - const bodyParam = fromJS({ - name: "myBody", - in: "body" - }) - - const state = fromJS({ - json: { - paths: { - "/": { - "get": { - parameters: [ - bodyParam - ] - } - } - } - }, - meta: { - paths: { - "/": { - "get": { - parameters: { - [`body.myBody.hash-${bodyParam.hashCode()}`]: { - value: "abc123" - } - } - } - } - } - } - }) - - const result = parameterWithMetaByIdentity(state, ["/", "get"], bodyParam) - - expect(result.toJS()).toEqual({ - name: "myBody", - in: "body", - value: "abc123" - }) - }) - }) - describe("parameterInclusionSettingFor", function() { - it("should support getting {in}.{name} param inclusion settings", function () { - const param = fromJS({ - name: "param", - in: "query", - allowEmptyValue: true - }) - - const state = fromJS({ - json: { - paths: { - "/": { - "get": { - parameters: [ - param - ] - } - } - } - }, - meta: { - paths: { - "/": { - "get": { - "parameter_inclusions": { - [`query.param`]: true - } - } - } - } - } - }) - - const result = parameterInclusionSettingFor(state, ["/", "get"], "param", "query") - - expect(result).toEqual(true) - }) - }) - describe("producesOptionsFor", function() { - it("should return an operation produces value", function () { - const state = fromJS({ - json: { - paths: { - "/": { - "get": { - description: "my operation", - produces: [ - "operation/one", - "operation/two", - ] - } - } - } - } - }) - - const result = producesOptionsFor(state, ["/", "get"]) - - expect(result.toJS()).toEqual([ - "operation/one", - "operation/two", - ]) - }) - it("should return a path item produces value", function () { - const state = fromJS({ - json: { - paths: { - "/": { - "get": { - description: "my operation", - produces: [ - "path-item/one", - "path-item/two", - ] - } - } - } - } - }) - - const result = producesOptionsFor(state, ["/", "get"]) - - expect(result.toJS()).toEqual([ - "path-item/one", - "path-item/two", - ]) - }) - it("should return a global produces value", function () { - const state = fromJS({ - json: { - produces: [ - "global/one", - "global/two", - ], - paths: { - "/": { - "get": { - description: "my operation" - } - } - } - } - }) - - const result = producesOptionsFor(state, ["/", "get"]) - - expect(result.toJS()).toEqual([ - "global/one", - "global/two", - ]) - }) - it("should favor an operation produces value over a path-item value", function () { - const state = fromJS({ - json: { - paths: { - "/": { - produces: [ - "path-item/one", - "path-item/two", - ], - "get": { - description: "my operation", - produces: [ - "operation/one", - "operation/two", - ] - } - } - } - } - }) - - const result = producesOptionsFor(state, ["/", "get"]) - - expect(result.toJS()).toEqual([ - "operation/one", - "operation/two", - ]) - }) - it("should favor a path-item produces value over a global value", function () { - const state = fromJS({ - json: { - produces: [ - "global/one", - "global/two", - ], - paths: { - "/": { - produces: [ - "path-item/one", - "path-item/two", - ], - "get": { - description: "my operation" - } - } - } - } - }) - - const result = producesOptionsFor(state, ["/", "get"]) - - expect(result.toJS()).toEqual([ - "path-item/one", - "path-item/two", - ]) - }) - }) - describe("consumesOptionsFor", function() { - it("should return an operation consumes value", function () { - const state = fromJS({ - json: { - paths: { - "/": { - "get": { - description: "my operation", - consumes: [ - "operation/one", - "operation/two", - ] - } - } - } - } - }) - - const result = consumesOptionsFor(state, ["/", "get"]) - - expect(result.toJS()).toEqual([ - "operation/one", - "operation/two", - ]) - }) - it("should return a path item consumes value", function () { - const state = fromJS({ - json: { - paths: { - "/": { - "get": { - description: "my operation", - consumes: [ - "path-item/one", - "path-item/two", - ] - } - } - } - } - }) - - const result = consumesOptionsFor(state, ["/", "get"]) - - expect(result.toJS()).toEqual([ - "path-item/one", - "path-item/two", - ]) - }) - it("should return a global consumes value", function () { - const state = fromJS({ - json: { - consumes: [ - "global/one", - "global/two", - ], - paths: { - "/": { - "get": { - description: "my operation" - } - } - } - } - }) - - const result = consumesOptionsFor(state, ["/", "get"]) - - expect(result.toJS()).toEqual([ - "global/one", - "global/two", - ]) - }) - it("should favor an operation consumes value over a path-item value", function () { - const state = fromJS({ - json: { - paths: { - "/": { - consumes: [ - "path-item/one", - "path-item/two", - ], - "get": { - description: "my operation", - consumes: [ - "operation/one", - "operation/two", - ] - } - } - } - } - }) - - const result = consumesOptionsFor(state, ["/", "get"]) - - expect(result.toJS()).toEqual([ - "operation/one", - "operation/two", - ]) - }) - it("should favor a path-item consumes value over a global value", function () { - const state = fromJS({ - json: { - consumes: [ - "global/one", - "global/two", - ], - paths: { - "/": { - consumes: [ - "path-item/one", - "path-item/two", - ], - "get": { - description: "my operation" - } - } - } - } - }) - - const result = consumesOptionsFor(state, ["/", "get"]) - - expect(result.toJS()).toEqual([ - "path-item/one", - "path-item/two", - ]) - }) - }) - describe("taggedOperations", function () { - it("should return a List of ad-hoc tagged operations", function () { - const system = { - getConfigs: () => ({}) - } - const state = fromJS({ - json: { - // tags: [ - // "myTag" - // ], - paths: { - "/": { - "get": { - produces: [], - tags: ["myTag"], - description: "my operation", - consumes: [ - "operation/one", - "operation/two", - ] - } - } - } - } - }) - - const result = taggedOperations(state)(system) - - const op = state.getIn(["json", "paths", "/", "get"]).toJS() - - expect(result.toJS()).toEqual({ - myTag: { - tagDetails: undefined, - operations: [{ - id: "get-/", - method: "get", - path: "/", - operation: op - }] - } - }) - }) - it("should return a List of defined tagged operations", function () { - const system = { - getConfigs: () => ({}) - } - const state = fromJS({ - json: { - tags: [ - { - name: "myTag" - } - ], - paths: { - "/": { - "get": { - produces: [], - tags: ["myTag"], - description: "my operation", - consumes: [ - "operation/one", - "operation/two", - ] - } - } - } - } - }) - - const result = taggedOperations(state)(system) - - const op = state.getIn(["json", "paths", "/", "get"]).toJS() - - expect(result.toJS()).toEqual({ - myTag: { - tagDetails: { - name: "myTag" - }, - operations: [{ - id: "get-/", - method: "get", - path: "/", - operation: op - }] - } - }) - }) - it("should gracefully handle a malformed global tags array", function () { - const system = { - getConfigs: () => ({}) - } - const state = fromJS({ - json: { - tags: [null], - paths: { - "/": { - "get": { - produces: [], - tags: ["myTag"], - description: "my operation", - consumes: [ - "operation/one", - "operation/two", - ] - } - } - } - } - }) - - const result = taggedOperations(state)(system) - - const op = state.getIn(["json", "paths", "/", "get"]).toJS() - - expect(result.toJS()).toEqual({ - myTag: { - tagDetails: undefined, - operations: [{ - id: "get-/", - method: "get", - path: "/", - operation: op - }] - } - }) - }) - it("should gracefully handle a non-array global tags entry", function () { - const system = { - getConfigs: () => ({}) - } - const state = fromJS({ - json: { - tags: "asdf", - paths: { - "/": { - "get": { - produces: [], - tags: ["myTag"], - description: "my operation", - consumes: [ - "operation/one", - "operation/two", - ] - } - } - } - } - }) - - const result = taggedOperations(state)(system) - - const op = state.getIn(["json", "paths", "/", "get"]).toJS() - - expect(result.toJS()).toEqual({ - myTag: { - tagDetails: undefined, - operations: [{ - id: "get-/", - method: "get", - path: "/", - operation: op - }] - } - }) - }) - }) diff --git a/test/mocha/xss/anchor-target-rel/online-validator-badge.jsx b/test/mocha/xss/anchor-target-rel/online-validator-badge.jsx index 4445df8a..47a48761 100644 --- a/test/mocha/xss/anchor-target-rel/online-validator-badge.jsx +++ b/test/mocha/xss/anchor-target-rel/online-validator-badge.jsx @@ -16,7 +16,7 @@ describe(" Anchor Target Safety", function () { } } const wrapper = mount( - + ) const anchor = wrapper.find("a") diff --git a/test/unit/.eslintrc b/test/unit/.eslintrc new file mode 100644 index 00000000..e69de29b diff --git a/test/mocha/bugs/3199-sanitization-escaping.jsx b/test/unit/bugs/3199-sanitization-escaping.jsx similarity index 92% rename from test/mocha/bugs/3199-sanitization-escaping.jsx rename to test/unit/bugs/3199-sanitization-escaping.jsx index 5db9568e..2840f900 100644 --- a/test/mocha/bugs/3199-sanitization-escaping.jsx +++ b/test/unit/bugs/3199-sanitization-escaping.jsx @@ -1,6 +1,4 @@ -/* eslint-env mocha */ import React from "react" -import expect from "expect" import { render } from "enzyme" import Markdown from "components/providers/markdown" diff --git a/test/mocha/bugs/3279-empty-markdown-source.jsx b/test/unit/bugs/3279-empty-markdown-source.jsx similarity index 94% rename from test/mocha/bugs/3279-empty-markdown-source.jsx rename to test/unit/bugs/3279-empty-markdown-source.jsx index 276c87d1..33be60fd 100644 --- a/test/mocha/bugs/3279-empty-markdown-source.jsx +++ b/test/unit/bugs/3279-empty-markdown-source.jsx @@ -1,6 +1,4 @@ -/* eslint-env mocha */ import React from "react" -import expect from "expect" import { render } from "enzyme" import Markdown from "components/providers/markdown" diff --git a/test/mocha/bugs/4557-default-parameter-values.jsx b/test/unit/bugs/4557-default-parameter-values.jsx similarity index 94% rename from test/mocha/bugs/4557-default-parameter-values.jsx rename to test/unit/bugs/4557-default-parameter-values.jsx index b8223de3..05f96d47 100644 --- a/test/mocha/bugs/4557-default-parameter-values.jsx +++ b/test/unit/bugs/4557-default-parameter-values.jsx @@ -1,7 +1,7 @@ -/* eslint-env mocha */ + import React from "react" import { List, fromJS } from "immutable" -import expect, { createSpy } from "expect" + import { render } from "enzyme" import ParameterRow from "components/parameter-row" @@ -24,7 +24,7 @@ describe("bug #4557: default parameter values", function(){ }, fn: {}, operation: {get: ()=>{}}, - onChange: createSpy(), + onChange: jest.fn(), param: paramValue, rawParam: paramValue, onChangeConsumes: () => {}, @@ -61,7 +61,7 @@ describe("bug #4557: default parameter values", function(){ }, fn: {}, operation: {get: ()=>{}}, - onChange: createSpy(), + onChange: jest.fn(), param: paramValue, rawParam: paramValue, onChangeConsumes: () => {}, diff --git a/test/mocha/components/filter.jsx b/test/unit/components/filter.jsx similarity index 97% rename from test/mocha/components/filter.jsx rename to test/unit/components/filter.jsx index 6a7ef1ac..6be672df 100644 --- a/test/mocha/components/filter.jsx +++ b/test/unit/components/filter.jsx @@ -1,7 +1,4 @@ - -/* eslint-env mocha */ import React from "react" -import expect from "expect" import { mount } from "enzyme" import FilterContainer from "containers/filter" import { Col } from "components/layout-utils" diff --git a/test/mocha/components/info-wrapper.jsx b/test/unit/components/info-wrapper.jsx similarity index 97% rename from test/mocha/components/info-wrapper.jsx rename to test/unit/components/info-wrapper.jsx index ba8be696..256ee1d3 100644 --- a/test/mocha/components/info-wrapper.jsx +++ b/test/unit/components/info-wrapper.jsx @@ -1,7 +1,4 @@ - -/* eslint-env mocha */ import React from "react" -import expect from "expect" import { mount } from "enzyme" import { fromJS } from "immutable" import InfoContainer from "containers/info" diff --git a/test/mocha/components/json-schema-form.jsx b/test/unit/components/json-schema-form.jsx similarity index 99% rename from test/mocha/components/json-schema-form.jsx rename to test/unit/components/json-schema-form.jsx index 895a1994..e4c928d9 100644 --- a/test/mocha/components/json-schema-form.jsx +++ b/test/unit/components/json-schema-form.jsx @@ -1,7 +1,5 @@ -/* eslint-env mocha */ import React from "react" import Immutable, { List } from "immutable" -import expect, { createSpy } from "expect" import { Select, Input, TextArea } from "components/layout-utils" import { mount, render } from "enzyme" import * as JsonSchemaComponents from "core/json-schema-components" diff --git a/test/unit/components/live-response.jsx b/test/unit/components/live-response.jsx new file mode 100644 index 00000000..ce7702fa --- /dev/null +++ b/test/unit/components/live-response.jsx @@ -0,0 +1,101 @@ +import React from "react" +import { fromJSOrdered } from "core/utils" +import { shallow } from "enzyme" +import Curl from "components/curl" +import LiveResponse from "components/live-response" +import ResponseBody from "components/response-body" + +describe("", function(){ + let request = fromJSOrdered({ + credentials: "same-origin", + headers: { + accept: "application/xml" + }, + url: "http://petstore.swagger.io/v2/pet/1" + }) + + let mutatedRequest = fromJSOrdered({ + credentials: "same-origin", + headers: { + accept: "application/xml", + mutated: "header" + }, + url: "http://mutated.petstore.swagger.io/v2/pet/1" + }) + + let requests = { + request: request, + mutatedRequest: mutatedRequest + } + + const tests = [ + { showMutatedRequest: true, expected: { request: "mutatedRequest", requestForCalls: 0, mutatedRequestForCalls: 1 } }, + { showMutatedRequest: false, expected: { request: "request", requestForCalls: 1, mutatedRequestForCalls: 0 } } + ] + + tests.forEach(function(test) { + it("passes " + test.expected.request + " to Curl when showMutatedRequest = " + test.showMutatedRequest, function() { + + // Given + + let response = fromJSOrdered({ + status: 200, + url: "http://petstore.swagger.io/v2/pet/1", + headers: { + "content-type": "application/xml" + }, + text: "", + duration: 50 + }) + + let mutatedRequestForSpy = jest.fn().mockImplementation(function(mutatedRequest) { return mutatedRequest }) + let requestForSpy = jest.fn().mockImplementation(function(request) { return request }) + + let components = { + curl: Curl, + responseBody: ResponseBody + } + + let props = { + response: response, + specSelectors: { + mutatedRequestFor: mutatedRequestForSpy, + requestFor: requestForSpy, + }, + pathMethod: [ "/one", "get" ], + getComponent: (c) => { + return components[c] + }, + displayRequestDuration: true, + getConfigs: () => ({ showMutatedRequest: test.showMutatedRequest }) + } + + // When + let wrapper = shallow() + + // Then + expect(mutatedRequestForSpy.calls.length).toEqual(test.expected.mutatedRequestForCalls) + expect(requestForSpy.calls.length).toEqual(test.expected.requestForCalls) + + const curl = wrapper.find(Curl) + expect(curl.length).toEqual(1) + expect(curl.props().request).toBe(requests[test.expected.request]) + + const expectedUrl = requests[test.expected.request].get("url") + expect(wrapper.find("div.request-url pre.microlight").text()).toEqual(expectedUrl) + + let duration = wrapper.find("Duration") + expect(duration.length).toEqual(1) + expect(duration.props().duration).toEqual(50) + expect(duration.html()) + .toEqual("
Request duration
50 ms
") + + let responseHeaders = wrapper.find("Headers") + expect(duration.length).toEqual(1) + expect(responseHeaders.props().headers.length).toEqual(1) + expect(responseHeaders.props().headers[0].key).toEqual("content-type") + expect(responseHeaders.html()) + .toEqual("
Response headers
 content-type: application/xml 
") + }) + }) +}) diff --git a/test/mocha/components/markdown.jsx b/test/unit/components/markdown.jsx similarity index 99% rename from test/mocha/components/markdown.jsx rename to test/unit/components/markdown.jsx index 3fc9c75a..521f03d2 100644 --- a/test/mocha/components/markdown.jsx +++ b/test/unit/components/markdown.jsx @@ -1,6 +1,4 @@ -/* eslint-env mocha */ import React from "react" -import expect from "expect" import { render } from "enzyme" import Markdown from "components/providers/markdown" import { Markdown as OAS3Markdown } from "corePlugins/oas3/wrap-components/markdown.jsx" diff --git a/test/mocha/components/model-example.jsx b/test/unit/components/model-example.jsx similarity index 98% rename from test/mocha/components/model-example.jsx rename to test/unit/components/model-example.jsx index 7c2ad54f..c45ce466 100644 --- a/test/mocha/components/model-example.jsx +++ b/test/unit/components/model-example.jsx @@ -1,6 +1,4 @@ -/* eslint-env mocha */ import React from "react" -import expect, { createSpy } from "expect" import { shallow } from "enzyme" import ModelExample from "components/model-example" import ModelComponent from "components/model-wrapper" diff --git a/test/mocha/components/models.jsx b/test/unit/components/models.jsx similarity index 93% rename from test/mocha/components/models.jsx rename to test/unit/components/models.jsx index 1deb1e8b..b9b315f7 100644 --- a/test/mocha/components/models.jsx +++ b/test/unit/components/models.jsx @@ -1,6 +1,4 @@ -/* eslint-env mocha */ import React from "react" -import expect, { createSpy } from "expect" import { shallow } from "enzyme" import { fromJS, Map } from "immutable" import Models from "components/models" @@ -29,7 +27,7 @@ describe("", function(){ specResolvedSubtree: () => {} }, layoutSelectors: { - isShown: createSpy() + isShown: jest.fn() }, layoutActions: {}, getConfigs: () => ({ diff --git a/test/mocha/components/object-model.jsx b/test/unit/components/object-model.jsx similarity index 95% rename from test/mocha/components/object-model.jsx rename to test/unit/components/object-model.jsx index 5a67d718..3367bac3 100644 --- a/test/mocha/components/object-model.jsx +++ b/test/unit/components/object-model.jsx @@ -1,14 +1,13 @@ import React from "react" -import expect from "expect" import { shallow } from "enzyme" -import { fromJS, List } from "immutable" +import { List } from "immutable" import ObjectModel from "components/object-model" -import ModelExample from "components/model-example" +// import ModelExample from "components/model-example" import Immutable from "immutable" import Model from "components/model" import ModelCollapse from "components/model-collapse" import Property from "components/property" -import { inferSchema } from "corePlugins/samples/fn" +// import { inferSchema } from "corePlugins/samples/fn" describe("", function() { const dummyComponent = () => null diff --git a/test/unit/components/online-validator-badge.jsx b/test/unit/components/online-validator-badge.jsx new file mode 100644 index 00000000..f3a77552 --- /dev/null +++ b/test/unit/components/online-validator-badge.jsx @@ -0,0 +1,76 @@ +import React from "react" +import { mount } from "enzyme" +import OnlineValidatorBadge from "components/online-validator-badge" + +describe("", function () { + it("should render a validator link and image correctly for the default validator", function () { + // When + const props = { + getConfigs: () => ({}), + getComponent: () => null, + specSelectors: { + url: () => "swagger.json" + } + } + const wrapper = mount( + + ) + + // Then + expect(wrapper.find("a").props().href).toEqual( + "https://validator.swagger.io/validator/debug?url=swagger.json" + ) + expect(wrapper.find("ValidatorImage").length).toEqual(1) + expect(wrapper.find("ValidatorImage").props().src).toEqual( + "https://validator.swagger.io/validator?url=swagger.json" + ) + }) + it("should encode a definition URL correctly", function () { + // When + const props = { + getConfigs: () => ({}), + getComponent: () => null, + specSelectors: { + url: () => "http://google.com/swagger.json" + } + } + const wrapper = mount( + + ) + + // Then + expect(wrapper.find("a").props().href).toEqual( + "https://validator.swagger.io/validator/debug?url=http%3A%2F%2Fgoogle.com%2Fswagger.json" + ) + expect(wrapper.find("ValidatorImage").length).toEqual(1) + expect(wrapper.find("ValidatorImage").props().src).toEqual( + "https://validator.swagger.io/validator?url=http%3A%2F%2Fgoogle.com%2Fswagger.json" + ) + }) + it.skip("should resolve a definition URL against the browser's location", function () { + // TODO: mock `window` + // When + + const props = { + getConfigs: () => ({}), + getComponent: () => null, + specSelectors: { + url: () => "http://google.com/swagger.json" + } + } + const wrapper = mount( + + ) + + // Then + expect(wrapper.find("a").props().href).toEqual( + "https://validator.swagger.io/validator/debug?url=http%3A%2F%2Fgoogle.com%2Fswagger.json" + ) + expect(wrapper.find("ValidatorImage").length).toEqual(1) + expect(wrapper.find("ValidatorImage").props().src).toEqual( + "https://validator.swagger.io/validator?url=http%3A%2F%2Fgoogle.com%2Fswagger.json" + ) + }) + // should resolve a definition URL against the browser's location + +}) diff --git a/test/mocha/components/operation.jsx b/test/unit/components/operation.jsx similarity index 89% rename from test/mocha/components/operation.jsx rename to test/unit/components/operation.jsx index 46af6fed..161d5673 100644 --- a/test/mocha/components/operation.jsx +++ b/test/unit/components/operation.jsx @@ -1,6 +1,4 @@ -/* eslint-env mocha */ import React from "react" -import expect, { createSpy } from "expect" import { shallow } from "enzyme" import Operation from "components/operation" @@ -16,7 +14,7 @@ describe("", function(){ shown: true, showOpId: "", showOpIdPrefix: "", - toggleCollapse: createSpy() + toggleCollapse: jest.fn() } let wrapper = shallow() diff --git a/test/mocha/components/operations.jsx b/test/unit/components/operations.jsx similarity index 98% rename from test/mocha/components/operations.jsx rename to test/unit/components/operations.jsx index 4da89427..d8295aa3 100644 --- a/test/mocha/components/operations.jsx +++ b/test/unit/components/operations.jsx @@ -1,6 +1,4 @@ -/* eslint-env mocha */ import React from "react" -import expect from "expect" import { render } from "enzyme" import { fromJS } from "immutable" import DeepLink from "components/deep-link" diff --git a/test/mocha/components/parameter-row.jsx b/test/unit/components/parameter-row.jsx similarity index 97% rename from test/mocha/components/parameter-row.jsx rename to test/unit/components/parameter-row.jsx index a9c1b076..7c44cfe9 100644 --- a/test/mocha/components/parameter-row.jsx +++ b/test/unit/components/parameter-row.jsx @@ -1,7 +1,5 @@ -/* eslint-env mocha */ import React from "react" import { fromJS } from "immutable" -import expect from "expect" import { render } from "enzyme" import ParameterRow from "components/parameter-row" diff --git a/test/mocha/components/primitive-model.jsx b/test/unit/components/primitive-model.jsx similarity index 96% rename from test/mocha/components/primitive-model.jsx rename to test/unit/components/primitive-model.jsx index 8560f7bd..75a0feb6 100644 --- a/test/mocha/components/primitive-model.jsx +++ b/test/unit/components/primitive-model.jsx @@ -1,6 +1,4 @@ -/* eslint-env mocha */ import React from "react" -import expect from "expect" import { shallow } from "enzyme" import { fromJS } from "immutable" import PrimitiveModel from "components/primitive-model" diff --git a/test/mocha/components/response-body.jsx b/test/unit/components/response-body.jsx similarity index 98% rename from test/mocha/components/response-body.jsx rename to test/unit/components/response-body.jsx index 01c48712..654ef954 100644 --- a/test/mocha/components/response-body.jsx +++ b/test/unit/components/response-body.jsx @@ -1,5 +1,4 @@ import React from "react" -import expect from "expect" import { shallow } from "enzyme" import ResponseBody from "components/response-body" diff --git a/test/mocha/components/response.jsx b/test/unit/components/response.jsx similarity index 98% rename from test/mocha/components/response.jsx rename to test/unit/components/response.jsx index 0cbde9ec..b39cb530 100644 --- a/test/mocha/components/response.jsx +++ b/test/unit/components/response.jsx @@ -1,5 +1,4 @@ import React from "react" -import expect from "expect" import { shallow } from "enzyme" import { fromJS, List } from "immutable" import Response from "components/response" diff --git a/test/mocha/components/schemes-wrapper.jsx b/test/unit/components/schemes-wrapper.jsx similarity index 96% rename from test/mocha/components/schemes-wrapper.jsx rename to test/unit/components/schemes-wrapper.jsx index d08412c3..b23aa8cf 100644 --- a/test/mocha/components/schemes-wrapper.jsx +++ b/test/unit/components/schemes-wrapper.jsx @@ -1,8 +1,5 @@ - -/* eslint-env mocha */ import React from "react" -import expect from "expect" -import { mount, render } from "enzyme" +import { mount } from "enzyme" import { fromJS } from "immutable" import SchemesContainer from "containers/schemes" import Schemes from "components/schemes" diff --git a/test/mocha/components/schemes.jsx b/test/unit/components/schemes.jsx similarity index 87% rename from test/mocha/components/schemes.jsx rename to test/unit/components/schemes.jsx index f8f5730c..2cbaf336 100644 --- a/test/mocha/components/schemes.jsx +++ b/test/unit/components/schemes.jsx @@ -1,7 +1,4 @@ - -/* eslint-env mocha */ import React from "react" -import expect, { createSpy } from "expect" import { shallow } from "enzyme" import { fromJS } from "immutable" import Schemes from "components/schemes" @@ -9,7 +6,7 @@ import Schemes from "components/schemes" describe("", function(){ it("calls props.specActions.setScheme() when no currentScheme is selected", function(){ - let setSchemeSpy = createSpy() + let setSchemeSpy = jest.fn() // Given let props = { @@ -43,7 +40,7 @@ describe("", function(){ it("doesn't call props.specActions.setScheme() when schemes hasn't changed", function(){ - let setSchemeSpy = createSpy() + let setSchemeSpy = jest.fn() // Given let props = { @@ -61,12 +58,12 @@ describe("", function(){ let wrapper = shallow() // Should be called initially, to set the global state - expect(setSchemeSpy.calls.length).toEqual(1) + expect(setSchemeSpy.mock.calls.length).toEqual(1) // After an update wrapper.instance().componentWillReceiveProps(props) // Should not be called again, since `currentScheme` is in schemes - expect(setSchemeSpy.calls.length).toEqual(1) + expect(setSchemeSpy.mock.calls.length).toEqual(1) }) }) diff --git a/test/mocha/components/version-pragma-filter.jsx b/test/unit/components/version-pragma-filter.jsx similarity index 94% rename from test/mocha/components/version-pragma-filter.jsx rename to test/unit/components/version-pragma-filter.jsx index c7d653fe..8571916f 100644 --- a/test/mocha/components/version-pragma-filter.jsx +++ b/test/unit/components/version-pragma-filter.jsx @@ -1,8 +1,5 @@ -/* eslint-env mocha */ import React from "react" -import expect, { createSpy } from "expect" import { shallow } from "enzyme" -import { fromJS, Map } from "immutable" import VersionPragmaFilter from "components/version-pragma-filter" describe("", function(){ diff --git a/test/mocha/core/curlify.js b/test/unit/core/curlify.js similarity index 84% rename from test/mocha/core/curlify.js rename to test/unit/core/curlify.js index fd83cea6..a5e24999 100644 --- a/test/mocha/core/curlify.js +++ b/test/unit/core/curlify.js @@ -1,4 +1,3 @@ -import expect from "expect" import Im from "immutable" import curl from "core/curlify" import win from "core/window" @@ -175,9 +174,9 @@ describe("curlify", function () { }) it("should print a curl with formData and file", function () { - let file = new win.File() - file.name = "file.txt" - file.type = "text/plain" + let file = new win.File([""], "file.txt", { type: "text/plain" }) + // file.name = "file.txt" + // file.type = "text/plain" let req = { url: "http://example.com", @@ -195,9 +194,9 @@ describe("curlify", function () { }) it("should print a curl without form data type if type is unknown", function () { - let file = new win.File() - file.name = "file.txt" - file.type = "" + let file = new win.File([""], "file.txt", { type: "" }) + // file.name = "file.txt" + // file.type = "" let req = { url: "http://example.com", @@ -246,12 +245,12 @@ describe("curlify", function () { expect(curlified).toEqual("curl -X POST \"http://example.com\" -H \"accept: application/json\" -d \"{\\\"id\\\":\\\"foo'bar\\\"}\"") }) - context("given multiple entries with file", function () { - context("and with leading custom header", function () { + describe("given multiple entries with file", function () { + describe("and with leading custom header", function () { it("should print a proper curl -F", function () { - let file = new win.File() - file.name = "file.txt" - file.type = "text/plain" + let file = new win.File([""], "file.txt", { type: "text/plain" }) + // file.name = "file.txt" + // file.type = "text/plain" let req = { url: "http://example.com", @@ -272,11 +271,11 @@ describe("curlify", function () { }) }) - context("and with trailing custom header; e.g. from requestInterceptor appending req.headers", function () { + describe("and with trailing custom header; e.g. from requestInterceptor appending req.headers", function () { it("should print a proper curl -F", function () { - let file = new win.File() - file.name = "file.txt" - file.type = "text/plain" + let file = new win.File([""], "file.txt", { type: "text/plain" }) + // file.name = "file.txt" + // file.type = "text/plain" let req = { url: "http://example.com", @@ -298,11 +297,11 @@ describe("curlify", function () { }) }) - context("POST when header value is 'multipart/form-data' but header name is not 'content-type'", function () { - it("shoud print a proper curl as -d ", function () { - let file = new win.File() - file.name = "file.txt" - file.type = "text/plain" + describe("POST when header value is 'multipart/form-data' but header name is not 'content-type'", function () { + it("shoud print a proper curl as -d , when file type is provided", function () { + let file = new win.File([""], "file.txt", { type: "text/plain" }) + // file.name = "file.txt" + // file.type = "text/plain" let req = { url: "http://example.com", @@ -318,6 +317,26 @@ describe("curlify", function () { expect(curlified).toEqual("curl -X POST \"http://example.com\" -H \"x-custom-name: multipart/form-data\" -d {\"id\":\"123\",\"file\":{\"name\":\"file.txt\",\"type\":\"text/plain\"}}") }) + + it("shoud print a proper curl as -d , no file type provided", function () { + let file = new win.File([""], "file.txt") + // file.name = "file.txt" + // file.type = "text/plain" + + let req = { + url: "http://example.com", + method: "POST", + headers: { "x-custom-name": "multipart/form-data" }, + body: { + id: "123", + file + } + } + + let curlified = curl(Im.fromJS(req)) + + expect(curlified).toEqual("curl -X POST \"http://example.com\" -H \"x-custom-name: multipart/form-data\" -d {\"id\":\"123\",\"file\":{\"name\":\"file.txt\"}}") + }) }) it("should escape dollar signs in headers and request body", function () { diff --git a/test/mocha/core/helpers/get-parameter-schema.js b/test/unit/core/helpers/get-parameter-schema.js similarity index 99% rename from test/mocha/core/helpers/get-parameter-schema.js rename to test/unit/core/helpers/get-parameter-schema.js index 132be918..47da1b31 100644 --- a/test/mocha/core/helpers/get-parameter-schema.js +++ b/test/unit/core/helpers/get-parameter-schema.js @@ -2,7 +2,6 @@ * @prettier */ -import expect from "expect" import { fromJS } from "immutable" import getParameterSchema from "../../../../src/helpers/get-parameter-schema" diff --git a/test/unit/core/oauth2-authorize.js b/test/unit/core/oauth2-authorize.js new file mode 100644 index 00000000..335f7571 --- /dev/null +++ b/test/unit/core/oauth2-authorize.js @@ -0,0 +1,77 @@ + +import win from "core/window" +import oauth2Authorize from "core/oauth2-authorize" +import * as utils from "core/utils" + +describe("oauth2", () => { + + let mockSchema = { + flow: "accessCode", + authorizationUrl: "https://testAuthorizationUrl" + } + + let authConfig = { + auth: { schema: { get: (key)=> mockSchema[key] } }, + authActions: {}, + errActions: {}, + configs: { oauth2RedirectUrl: "" }, + authConfigs: {} + } + + beforeEach(() => { + win.open = jest.fn() + }) + + describe("authorize redirect", () => { + it("should build authorize url", () => { + const windowOpenSpy = jest.spyOn(win, "open") + oauth2Authorize(authConfig) + expect(windowOpenSpy.mock.calls.length).toEqual(1) + expect(windowOpenSpy.mock.calls[0][0]).toMatch("https://testAuthorizationUrl?response_type=code&redirect_uri=&state=") + + windowOpenSpy.mockReset() + }) + + it("should append query parameters to authorizeUrl with query parameters", () => { + const windowOpenSpy = jest.spyOn(win, "open") + mockSchema.authorizationUrl = "https://testAuthorizationUrl?param=1" + oauth2Authorize(authConfig) + expect(windowOpenSpy.mock.calls.length).toEqual(1) + expect(windowOpenSpy.mock.calls[0][0]).toMatch("https://testAuthorizationUrl?param=1&response_type=code&redirect_uri=&state=") + + windowOpenSpy.mockReset() + }) + + it("should send code_challenge when using authorizationCode flow with usePkceWithAuthorizationCodeGrant enabled", () => { + const windowOpenSpy = jest.spyOn(win, "open") + mockSchema.flow = "authorizationCode" + + const expectedCodeVerifier = "mock_code_verifier" + const expectedCodeChallenge = "mock_code_challenge" + + const generateCodeVerifierSpy = jest.spyOn(utils, "generateCodeVerifier").mockImplementation(() => expectedCodeVerifier) + const createCodeChallengeSpy = jest.spyOn(utils, "createCodeChallenge").mockImplementation(() => expectedCodeChallenge) + + authConfig.authConfigs.usePkceWithAuthorizationCodeGrant = true + + oauth2Authorize(authConfig) + expect(win.open.mock.calls.length).toEqual(1) + + const actualUrl = new URLSearchParams(win.open.mock.calls[0][0]) + expect(actualUrl.get("code_challenge")).toBe(expectedCodeChallenge) + expect(actualUrl.get("code_challenge_method")).toBe("S256") + + expect(createCodeChallengeSpy.mock.calls.length).toEqual(1) + expect(createCodeChallengeSpy.mock.calls[0][0]).toBe(expectedCodeVerifier) + + // The code_verifier should be stored to be able to send in + // on the TokenUrl call + expect(authConfig.auth.codeVerifier).toBe(expectedCodeVerifier) + + // Restore spies + windowOpenSpy.mockReset() + generateCodeVerifierSpy.mockReset() + createCodeChallengeSpy.mockReset() + }) + }) +}) diff --git a/test/mocha/core/plugins/auth/actions.js b/test/unit/core/plugins/auth/actions.js similarity index 82% rename from test/mocha/core/plugins/auth/actions.js rename to test/unit/core/plugins/auth/actions.js index 017cb5de..9e29e010 100644 --- a/test/mocha/core/plugins/auth/actions.js +++ b/test/unit/core/plugins/auth/actions.js @@ -1,9 +1,5 @@ -/* eslint-env mocha */ -import expect, { createSpy } from "expect" -import { - authorizeRequest, - authorizeAccessCodeWithFormParams, -} from "corePlugins/auth/actions" + +import { authorizeRequest, authorizeAccessCodeWithFormParams } from "corePlugins/auth/actions" describe("auth plugin - actions", () => { @@ -63,7 +59,7 @@ describe("auth plugin - actions", () => { } const system = { fn: { - fetch: createSpy().andReturn(Promise.resolve()) + fetch: jest.fn().mockImplementation(() => Promise.resolve()) }, getConfigs: () => ({}), authSelectors: { @@ -85,8 +81,8 @@ describe("auth plugin - actions", () => { authorizeRequest(data)(system) // Then - expect(system.fn.fetch.calls.length).toEqual(1) - expect(system.fn.fetch.calls[0].arguments[0]).toInclude({url: expectedFetchUrl}) + expect(system.fn.fetch.mock.calls.length).toEqual(1) + expect(system.fn.fetch.mock.calls[0][0]).toEqual(expect.objectContaining({url: expectedFetchUrl})) }) }) @@ -98,7 +94,7 @@ describe("auth plugin - actions", () => { } const system = { fn: { - fetch: createSpy().andReturn(Promise.resolve()) + fetch: jest.fn().mockImplementation(() => Promise.resolve()) }, getConfigs: () => ({}), authSelectors: { @@ -120,9 +116,9 @@ describe("auth plugin - actions", () => { authorizeRequest(data)(system) // Then - expect(system.fn.fetch.calls.length).toEqual(1) + expect(system.fn.fetch.mock.calls.length).toEqual(1) - expect(system.fn.fetch.calls[0].arguments[0].url) + expect(system.fn.fetch.mock.calls[0][0].url) .toEqual("http://google.com/authorize?q=1&myCustomParam=abc123") }) @@ -134,7 +130,7 @@ describe("auth plugin - actions", () => { } const system = { fn: { - fetch: createSpy().andReturn(Promise.resolve()) + fetch: jest.fn().mockImplementation(() => Promise.resolve()) }, getConfigs: () => ({}), authSelectors: { @@ -157,9 +153,9 @@ describe("auth plugin - actions", () => { authorizeRequest(data)(system) // Then - expect(system.fn.fetch.calls.length).toEqual(1) + expect(system.fn.fetch.mock.calls.length).toEqual(1) - expect(system.fn.fetch.calls[0].arguments[0].url) + expect(system.fn.fetch.mock.calls[0][0].url) .toEqual("http://google.com/authorize?q=1&myCustomParam=abc123") }) }) @@ -177,13 +173,13 @@ describe("auth plugin - actions", () => { } const authActions = { - authorizeRequest: createSpy() + authorizeRequest: jest.fn() } authorizeAccessCodeWithFormParams(data)({ authActions }) - expect(authActions.authorizeRequest.calls.length).toEqual(1) - const actualArgument = authActions.authorizeRequest.calls[0].arguments[0] + expect(authActions.authorizeRequest.mock.calls.length).toEqual(1) + const actualArgument = authActions.authorizeRequest.mock.calls[0][0] expect(actualArgument.body).toContain("code_verifier=" + data.auth.codeVerifier) expect(actualArgument.body).toContain("grant_type=authorization_code") }) diff --git a/test/mocha/core/plugins/auth/preauthorize.js b/test/unit/core/plugins/auth/preauthorize.js similarity index 98% rename from test/mocha/core/plugins/auth/preauthorize.js rename to test/unit/core/plugins/auth/preauthorize.js index 3149c8d7..a42f1c4f 100644 --- a/test/mocha/core/plugins/auth/preauthorize.js +++ b/test/unit/core/plugins/auth/preauthorize.js @@ -1,5 +1,4 @@ -/* eslint-env mocha */ -import expect from "expect" + import { fromJS } from "immutable" import { preauthorizeBasic, preauthorizeApiKey } from "corePlugins/auth" import { authorize } from "corePlugins/auth/actions" diff --git a/test/mocha/core/plugins/auth/selectors.js b/test/unit/core/plugins/auth/selectors.js similarity index 98% rename from test/mocha/core/plugins/auth/selectors.js rename to test/unit/core/plugins/auth/selectors.js index a8234a19..bb8e5eac 100644 --- a/test/mocha/core/plugins/auth/selectors.js +++ b/test/unit/core/plugins/auth/selectors.js @@ -1,5 +1,4 @@ -/* eslint-env mocha */ -import expect from "expect" + import { fromJS } from "immutable" import { definitionsToAuthorize, definitionsForRequirements } from "corePlugins/auth/selectors" diff --git a/test/mocha/core/plugins/auth/wrap-spec-actions.js b/test/unit/core/plugins/auth/wrap-spec-actions.js similarity index 68% rename from test/mocha/core/plugins/auth/wrap-spec-actions.js rename to test/unit/core/plugins/auth/wrap-spec-actions.js index d8a967ec..889423d2 100644 --- a/test/mocha/core/plugins/auth/wrap-spec-actions.js +++ b/test/unit/core/plugins/auth/wrap-spec-actions.js @@ -1,5 +1,4 @@ -/* eslint-env mocha */ -import expect, { createSpy } from "expect" + import { execute } from "corePlugins/auth/spec-wrap-actions" describe("spec plugin - actions", function(){ @@ -10,18 +9,20 @@ describe("spec plugin - actions", function(){ // Given const system = { authSelectors: { - authorized: createSpy().andReturn({some: "security"}) + authorized: jest.fn().mockImplementation(() => ({ + some: "security" + })) } } - const oriExecute = createSpy() + const oriExecute = jest.fn() // When let executeFn = execute(oriExecute, system) executeFn({}) // Then - expect(oriExecute.calls.length).toEqual(1) - expect(oriExecute.calls[0].arguments[0]).toEqual({ + expect(oriExecute.mock.calls.length).toEqual(1) + expect(oriExecute.mock.calls[0][0]).toEqual({ extras: { security: { some: "security" diff --git a/test/mocha/core/plugins/configs/actions.js b/test/unit/core/plugins/configs/actions.js similarity index 80% rename from test/mocha/core/plugins/configs/actions.js rename to test/unit/core/plugins/configs/actions.js index 99fc78fc..b47d29fd 100644 --- a/test/mocha/core/plugins/configs/actions.js +++ b/test/unit/core/plugins/configs/actions.js @@ -1,12 +1,11 @@ -/* eslint-env mocha */ -import expect, { createSpy } from "expect" + import { downloadConfig } from "corePlugins/configs/spec-actions" describe("configs plugin - actions", () => { describe("downloadConfig", () => { it("should call the system fetch helper with a provided request", () => { - const fetchSpy = createSpy(async () => {}).andCallThrough() + const fetchSpy = jest.fn(async () => {}) const system = { fn: { fetch: fetchSpy diff --git a/test/mocha/core/plugins/err/transformers/not-of-type.js b/test/unit/core/plugins/err/transformers/not-of-type.js similarity index 97% rename from test/mocha/core/plugins/err/transformers/not-of-type.js rename to test/unit/core/plugins/err/transformers/not-of-type.js index cd84eca3..682c641b 100644 --- a/test/mocha/core/plugins/err/transformers/not-of-type.js +++ b/test/unit/core/plugins/err/transformers/not-of-type.js @@ -1,4 +1,3 @@ -import expect from "expect" import { Map, List } from "immutable" import { transform } from "corePlugins/err/error-transformers/transformers/not-of-type" diff --git a/test/mocha/core/plugins/err/transformers/parameter-oneof.js b/test/unit/core/plugins/err/transformers/parameter-oneof.js similarity index 99% rename from test/mocha/core/plugins/err/transformers/parameter-oneof.js rename to test/unit/core/plugins/err/transformers/parameter-oneof.js index 604ab42d..1ff41019 100644 --- a/test/mocha/core/plugins/err/transformers/parameter-oneof.js +++ b/test/unit/core/plugins/err/transformers/parameter-oneof.js @@ -1,5 +1,4 @@ /* eslint-disable no-useless-escape */ -import expect from "expect" import { fromJS } from "immutable" import { transform } from "corePlugins/err/error-transformers/transformers/parameter-oneof" diff --git a/test/mocha/core/plugins/filter/opsFilter.js b/test/unit/core/plugins/filter/opsFilter.js similarity index 96% rename from test/mocha/core/plugins/filter/opsFilter.js rename to test/unit/core/plugins/filter/opsFilter.js index ef15468c..d64ce609 100644 --- a/test/mocha/core/plugins/filter/opsFilter.js +++ b/test/unit/core/plugins/filter/opsFilter.js @@ -1,6 +1,5 @@ import { Map } from "immutable" import opsFilter from "corePlugins/filter/opsFilter" -import expect from "expect" describe("opsFilter", function() { const taggedOps = Map([["pet"], ["store"], ["user"]]) diff --git a/test/mocha/core/plugins/oas3/helpers.js b/test/unit/core/plugins/oas3/helpers.js similarity index 98% rename from test/mocha/core/plugins/oas3/helpers.js rename to test/unit/core/plugins/oas3/helpers.js index 5af7b9b8..14e31c97 100644 --- a/test/mocha/core/plugins/oas3/helpers.js +++ b/test/unit/core/plugins/oas3/helpers.js @@ -1,6 +1,5 @@ import { fromJS } from "immutable" import { isOAS3, isSwagger2 } from "corePlugins/oas3/helpers" -import expect from "expect" const isOAS3Shorthand = (version) => isOAS3(fromJS({ openapi: version diff --git a/test/mocha/core/plugins/oas3/reducers.js b/test/unit/core/plugins/oas3/reducers.js similarity index 99% rename from test/mocha/core/plugins/oas3/reducers.js rename to test/unit/core/plugins/oas3/reducers.js index c192ba44..102b25e3 100644 --- a/test/mocha/core/plugins/oas3/reducers.js +++ b/test/unit/core/plugins/oas3/reducers.js @@ -1,5 +1,4 @@ -/* eslint-env mocha */ -import expect from "expect" + import { fromJS } from "immutable" import reducer from "corePlugins/oas3/reducers" diff --git a/test/mocha/core/plugins/oas3/servers-wrapper.jsx b/test/unit/core/plugins/oas3/servers-wrapper.jsx similarity index 97% rename from test/mocha/core/plugins/oas3/servers-wrapper.jsx rename to test/unit/core/plugins/oas3/servers-wrapper.jsx index aeece8c1..31bdff84 100644 --- a/test/mocha/core/plugins/oas3/servers-wrapper.jsx +++ b/test/unit/core/plugins/oas3/servers-wrapper.jsx @@ -1,7 +1,5 @@ -/* eslint-env mocha */ import React from "react" -import expect from "expect" import { mount } from "enzyme" import { fromJS } from "immutable" import ServersContainer from "core/plugins/oas3/components/servers-container" diff --git a/test/mocha/core/plugins/oas3/state-integration.js b/test/unit/core/plugins/oas3/state-integration.js similarity index 99% rename from test/mocha/core/plugins/oas3/state-integration.js rename to test/unit/core/plugins/oas3/state-integration.js index 6ce69da5..e80918d9 100644 --- a/test/mocha/core/plugins/oas3/state-integration.js +++ b/test/unit/core/plugins/oas3/state-integration.js @@ -1,4 +1,3 @@ -import expect from "expect" import { fromJS, OrderedMap } from "immutable" import { diff --git a/test/mocha/core/plugins/oas3/wrap-auth-selectors.js b/test/unit/core/plugins/oas3/wrap-auth-selectors.js similarity index 96% rename from test/mocha/core/plugins/oas3/wrap-auth-selectors.js rename to test/unit/core/plugins/oas3/wrap-auth-selectors.js index 5c94417f..578f42b2 100644 --- a/test/mocha/core/plugins/oas3/wrap-auth-selectors.js +++ b/test/unit/core/plugins/oas3/wrap-auth-selectors.js @@ -1,6 +1,5 @@ -/* eslint-env mocha */ -import expect, { createSpy } from "expect" -import { Map, fromJS } from "immutable" + +import { fromJS } from "immutable" import { definitionsToAuthorize } from "corePlugins/oas3/auth-extensions/wrap-selectors" diff --git a/test/mocha/core/plugins/oas3/wrap-spec-selectors.js b/test/unit/core/plugins/oas3/wrap-spec-selectors.js similarity index 94% rename from test/mocha/core/plugins/oas3/wrap-spec-selectors.js rename to test/unit/core/plugins/oas3/wrap-spec-selectors.js index 24cc3db1..55b196e9 100644 --- a/test/mocha/core/plugins/oas3/wrap-spec-selectors.js +++ b/test/unit/core/plugins/oas3/wrap-spec-selectors.js @@ -1,6 +1,5 @@ -/* eslint-env mocha */ -import expect, { createSpy } from "expect" -import { Map, fromJS } from "immutable" + +import { fromJS } from "immutable" import { definitions } from "corePlugins/oas3/spec-extensions/wrap-selectors" diff --git a/test/mocha/core/plugins/samples/fn.js b/test/unit/core/plugins/samples/fn.js similarity index 96% rename from test/mocha/core/plugins/samples/fn.js rename to test/unit/core/plugins/samples/fn.js index 496adafd..dc439c72 100644 --- a/test/mocha/core/plugins/samples/fn.js +++ b/test/unit/core/plugins/samples/fn.js @@ -1,8 +1,7 @@ import { fromJS } from "immutable" import { createXMLExample, sampleFromSchema } from "corePlugins/samples/fn" -import expect from "expect" -describe("sampleFromSchema", function() { +describe("sampleFromSchema", () => { it("handles Immutable.js objects for nested schemas", function () { let definition = fromJS({ "type": "object", @@ -238,7 +237,7 @@ describe("sampleFromSchema", function() { expect(sampleFromSchema(definition, { includeWriteOnly: true })).toEqual(expected) }) - it("returns example value for date-time property", function() { + it("returns example value for date-time property", () => { let definition = { type: "string", format: "date-time" @@ -249,10 +248,10 @@ describe("sampleFromSchema", function() { // it would be better to mock Date globally and expect a string - KS 11/18 let expected = new Date().toISOString().substring(0, 20) - expect(sampleFromSchema(definition)).toInclude(expected) + expect(sampleFromSchema(definition)).toContain(expected) }) - it("returns example value for date property", function() { + it("returns example value for date property", () => { let definition = { type: "string", format: "date" @@ -263,7 +262,7 @@ describe("sampleFromSchema", function() { expect(sampleFromSchema(definition)).toEqual(expected) }) - it("returns a UUID for a string with format=uuid", function() { + it("returns a UUID for a string with format=uuid", () => { let definition = { type: "string", format: "uuid" @@ -274,7 +273,7 @@ describe("sampleFromSchema", function() { expect(sampleFromSchema(definition)).toEqual(expected) }) - it("returns a hostname for a string with format=hostname", function() { + it("returns a hostname for a string with format=hostname", () => { let definition = { type: "string", format: "hostname" @@ -285,7 +284,7 @@ describe("sampleFromSchema", function() { expect(sampleFromSchema(definition)).toEqual(expected) }) - it("returns an IPv4 address for a string with format=ipv4", function() { + it("returns an IPv4 address for a string with format=ipv4", () => { let definition = { type: "string", format: "ipv4" @@ -296,7 +295,7 @@ describe("sampleFromSchema", function() { expect(sampleFromSchema(definition)).toEqual(expected) }) - it("returns an IPv6 address for a string with format=ipv6", function() { + it("returns an IPv6 address for a string with format=ipv6", () => { let definition = { type: "string", format: "ipv6" @@ -307,8 +306,8 @@ describe("sampleFromSchema", function() { expect(sampleFromSchema(definition)).toEqual(expected) }) - describe("for array type", function() { - it("returns array with sample of array type", function() { + describe("for array type", () => { + it("returns array with sample of array type", () => { let definition = { type: "array", items: { @@ -321,7 +320,7 @@ describe("sampleFromSchema", function() { expect(sampleFromSchema(definition)).toEqual(expected) }) - it("returns array of examples for array that has example", function() { + it("returns string for example for array that has example of type string", () => { let definition = { type: "array", items: { @@ -330,12 +329,12 @@ describe("sampleFromSchema", function() { example: "dog" } - let expected = [ "dog" ] + let expected = "dog" expect(sampleFromSchema(definition)).toEqual(expected) }) - it("returns array of examples for array that has examples", function() { + it("returns array of examples for array that has examples", () => { let definition = { type: "array", items: { @@ -349,7 +348,7 @@ describe("sampleFromSchema", function() { expect(sampleFromSchema(definition)).toEqual(expected) }) - it("returns array of samples for oneOf type", function() { + it("returns array of samples for oneOf type", () => { let definition = { type: "array", items: { @@ -367,7 +366,7 @@ describe("sampleFromSchema", function() { expect(sampleFromSchema(definition)).toEqual(expected) }) - it("returns array of samples for oneOf types", function() { + it("returns array of samples for oneOf types", () => { let definition = { type: "array", items: { @@ -388,7 +387,7 @@ describe("sampleFromSchema", function() { expect(sampleFromSchema(definition)).toEqual(expected) }) - it("returns array of samples for oneOf examples", function() { + it("returns array of samples for oneOf examples", () => { let definition = { type: "array", items: { @@ -411,7 +410,7 @@ describe("sampleFromSchema", function() { expect(sampleFromSchema(definition)).toEqual(expected) }) - it("returns array of samples for anyOf type", function() { + it("returns array of samples for anyOf type", () => { let definition = { type: "array", items: { @@ -429,7 +428,7 @@ describe("sampleFromSchema", function() { expect(sampleFromSchema(definition)).toEqual(expected) }) - it("returns array of samples for anyOf types", function() { + it("returns array of samples for anyOf types", () => { let definition = { type: "array", items: { @@ -450,7 +449,7 @@ describe("sampleFromSchema", function() { expect(sampleFromSchema(definition)).toEqual(expected) }) - it("returns array of samples for anyOf examples", function() { + it("returns array of samples for anyOf examples", () => { let definition = { type: "array", items: { @@ -473,7 +472,7 @@ describe("sampleFromSchema", function() { expect(sampleFromSchema(definition)).toEqual(expected) }) - it("returns null for a null example", function() { + it("returns null for a null example", () => { let definition = { "type": "object", "properties": { @@ -492,7 +491,7 @@ describe("sampleFromSchema", function() { expect(sampleFromSchema(definition)).toEqual(expected) }) - it("returns null for a null object-level example", function() { + it("returns null for a null object-level example", () => { let definition = { "type": "object", "properties": { diff --git a/test/mocha/core/plugins/spec/actions.js b/test/unit/core/plugins/spec/actions.js similarity index 70% rename from test/mocha/core/plugins/spec/actions.js rename to test/unit/core/plugins/spec/actions.js index 8010e617..d2a68034 100644 --- a/test/mocha/core/plugins/spec/actions.js +++ b/test/unit/core/plugins/spec/actions.js @@ -1,5 +1,4 @@ -/* eslint-env mocha */ -import expect, { createSpy } from "expect" + import { fromJS } from "immutable" import { execute, executeRequest, changeParamByIdentity, updateEmptyParamInclusion } from "corePlugins/spec/actions" @@ -14,7 +13,7 @@ describe("spec plugin - actions", function(){ fetch: 1 }, specActions: { - executeRequest: createSpy() + executeRequest: jest.fn() }, specSelectors: { spec: () => fromJS({spec: 1}), @@ -28,7 +27,7 @@ describe("spec plugin - actions", function(){ executeFn(system) // Then - expect(system.specActions.executeRequest.calls[0].arguments[0]).toEqual({ + expect(system.specActions.executeRequest.calls[0][0]).toEqual({ fetch: 1, method: "get", pathName: "/one", @@ -49,7 +48,7 @@ describe("spec plugin - actions", function(){ const system = { fn: {}, specActions: { - executeRequest: createSpy() + executeRequest: jest.fn() }, specSelectors: { spec: () => fromJS({}), @@ -63,7 +62,7 @@ describe("spec plugin - actions", function(){ executeFn(system) // Then - expect(system.specActions.executeRequest.calls[0].arguments[0]).toInclude({hi: "hello"}) + expect(system.specActions.executeRequest.calls[0][0]).toContain({hi: "hello"}) }) }) @@ -74,10 +73,10 @@ describe("spec plugin - actions", function(){ const system = { fn: { - execute: createSpy().andReturn(Promise.resolve()) + execute: jest.fn().mockImplementation(() => Promise.resolve({})) }, specActions: { - setResponse: createSpy() + setResponse: jest.fn() } } @@ -86,9 +85,9 @@ describe("spec plugin - actions", function(){ let res = executeFn(system) // Then - expect(res).toBeA(Promise) - expect(system.fn.execute.calls.length).toEqual(1) - expect(system.fn.execute.calls[0].arguments[0]).toEqual({ + expect(res).toBeInstanceOf(Promise) + expect(system.fn.execute.mock.calls.length).toEqual(1) + expect(system.fn.execute.mock.calls[0][0]).toEqual({ one: 1 }) }) @@ -96,19 +95,19 @@ describe("spec plugin - actions", function(){ it("should pass requestInterceptor/responseInterceptor to fn.execute", async () => { // Given let configs = { - requestInterceptor: createSpy(), - responseInterceptor: createSpy() + requestInterceptor: jest.fn(), + responseInterceptor: jest.fn() } const system = { fn: { - buildRequest: createSpy(), - execute: createSpy().andReturn(Promise.resolve()) + buildRequest: jest.fn(), + execute: jest.fn().mockImplementation(() => Promise.resolve({})) }, specActions: { - executeRequest: createSpy(), - setMutatedRequest: createSpy(), - setRequest: createSpy(), - setResponse: createSpy() + executeRequest: jest.fn(), + setMutatedRequest: jest.fn(), + setRequest: jest.fn(), + setResponse: jest.fn() }, specSelectors: { spec: () => fromJS({}), @@ -128,20 +127,20 @@ describe("spec plugin - actions", function(){ await executeFn(system) // Then - expect(system.fn.execute.calls.length).toEqual(1) - expect(system.fn.execute.calls[0].arguments[0]).toIncludeKey("requestInterceptor") - expect(system.fn.execute.calls[0].arguments[0]).toInclude({ + expect(system.fn.execute.mock.calls.length).toEqual(1) + expect(Object.keys(system.fn.execute.mock.calls[0][0])).toContain("requestInterceptor") + expect(system.fn.execute.mock.calls[0][0]).toEqual(expect.objectContaining({ responseInterceptor: configs.responseInterceptor - }) - expect(system.specActions.setMutatedRequest.calls.length).toEqual(0) - expect(system.specActions.setRequest.calls.length).toEqual(1) + })) + expect(system.specActions.setMutatedRequest.mock.calls.length).toEqual(0) + expect(system.specActions.setRequest.mock.calls.length).toEqual(1) - let wrappedRequestInterceptor = system.fn.execute.calls[0].arguments[0].requestInterceptor - await wrappedRequestInterceptor(system.fn.execute.calls[0].arguments[0]) - expect(configs.requestInterceptor.calls.length).toEqual(1) - expect(system.specActions.setMutatedRequest.calls.length).toEqual(1) - expect(system.specActions.setRequest.calls.length).toEqual(1) + let wrappedRequestInterceptor = system.fn.execute.mock.calls[0][0].requestInterceptor + await wrappedRequestInterceptor(system.fn.execute.mock.calls[0][0]) + expect(configs.requestInterceptor.mock.calls.length).toEqual(1) + expect(system.specActions.setMutatedRequest.mock.calls.length).toEqual(1) + expect(system.specActions.setRequest.mock.calls.length).toEqual(1) }) }) @@ -150,13 +149,13 @@ describe("spec plugin - actions", function(){ const response = {serverResponse: true} const system = { fn: { - execute: createSpy().andReturn(Promise.resolve(response)) + execute: jest.fn().mockImplementation(() => Promise.resolve(response)) }, specActions: { - setResponse: createSpy() + setResponse: jest.fn() }, errActions: { - newSpecErr: createSpy() + newSpecErr: jest.fn() } } @@ -178,8 +177,9 @@ describe("spec plugin - actions", function(){ }) }) - describe("requestResolvedSubtree", () => { - it("should return a promise ") + describe.skip("requestResolvedSubtree", () => { + it("should return a promise ", function() { + }) }) it.skip("should call errActions.newErr, if the fn.execute rejects", function(){ diff --git a/test/mocha/core/plugins/spec/assets/petstore.json b/test/unit/core/plugins/spec/assets/petstore.json similarity index 100% rename from test/mocha/core/plugins/spec/assets/petstore.json rename to test/unit/core/plugins/spec/assets/petstore.json diff --git a/test/mocha/core/plugins/spec/reducer.js b/test/unit/core/plugins/spec/reducer.js similarity index 99% rename from test/mocha/core/plugins/spec/reducer.js rename to test/unit/core/plugins/spec/reducer.js index b6098f09..9c56a4a7 100644 --- a/test/mocha/core/plugins/spec/reducer.js +++ b/test/unit/core/plugins/spec/reducer.js @@ -1,5 +1,4 @@ -/* eslint-env mocha */ -import expect from "expect" + import { fromJS } from "immutable" import reducer from "corePlugins/spec/reducers" diff --git a/test/unit/core/plugins/spec/selectors.js b/test/unit/core/plugins/spec/selectors.js new file mode 100644 index 00000000..c032e426 --- /dev/null +++ b/test/unit/core/plugins/spec/selectors.js @@ -0,0 +1,1213 @@ + +import { fromJS } from "immutable" +import { fromJSOrdered } from "core/utils" +import { + definitions, + parameterValues, + contentTypeValues, + operationScheme, + specJsonWithResolvedSubtrees, + producesOptionsFor, + operationWithMeta, + parameterWithMeta, + parameterWithMetaByIdentity, + parameterInclusionSettingFor, + consumesOptionsFor, + taggedOperations +} from "corePlugins/spec/selectors" + +import Petstore from "./assets/petstore.json" + +describe("definitions", function(){ + it("should return definitions by default", function(){ + + // Given + const spec = fromJS({ + json: { + swagger: "2.0", + definitions: { + a: { + type: "string" + }, + b: { + type: "string" + } + } + } + }) + + // When + let res = definitions(spec) + + // Then + expect(res.toJS()).toEqual({ + a: { + type: "string" + }, + b: { + type: "string" + } + }) + }) + it("should return an empty Map when missing definitions", function(){ + + // Given + const spec = fromJS({ + json: { + swagger: "2.0" + } + }) + + // When + let res = definitions(spec) + + // Then + expect(res.toJS()).toEqual({}) + }) + it("should return an empty Map when given non-object definitions", function(){ + + // Given + const spec = fromJS({ + json: { + swagger: "2.0", + definitions: "..." + } + }) + + // When + let res = definitions(spec) + + // Then + expect(res.toJS()).toEqual({}) + }) +}) + +describe("parameterValue", function(){ + + it("should return Map({}) if no path found", function(){ + + // Given + const spec = fromJS({ }) + + // When + let paramValues = parameterValues(spec, ["/one", "get"]) + + // Then + expect(paramValues.toJS()).toEqual({}) + + }) + + it("should return a hash of [parameterName]: value", function(){ + + // Given + const spec = fromJS({ + json: { + paths: { + "/one": { + get: { + parameters: [ + { name: "one", in: "query", value: 1}, + { name: "two", in: "query", value: "duos"} + ] + } + } + } + } + }) + + // When + let paramValues = parameterValues(spec, ["/one", "get"]) + + // Then + expect(paramValues.toJS()).toEqual({ + "query.one": 1, + "query.two": "duos" + }) + + }) + +}) + +describe("contentTypeValues", function(){ + it("should return { requestContentType, responseContentType } from an operation", function(){ + // Given + let state = fromJS({ + json: { + paths: { + "/one": { + get: {} + } + } + }, + meta: { + paths: { + "/one": { + get: { + "consumes_value": "one", + "produces_value": "two" + } + } + } + } + }) + + // When + let contentTypes = contentTypeValues(state, [ "/one", "get" ]) + // Then + expect(contentTypes.toJS()).toEqual({ + requestContentType: "one", + responseContentType: "two" + }) + }) + + it("should default to the first `produces` array value if current is not set", function(){ + // Given + let state = fromJS({ + json: { + paths: { + "/one": { + get: { + produces: [ + "application/xml", + "application/whatever" + ] + } + } + } + }, + meta: { + paths: { + "/one": { + get: { + "consumes_value": "one" + } + } + } + } + }) + + // When + let contentTypes = contentTypeValues(state, [ "/one", "get" ]) + // Then + expect(contentTypes.toJS()).toEqual({ + requestContentType: "one", + responseContentType: "application/xml" + }) + }) + + it("should default to `application/json` if a default produces value is not available", function(){ + // Given + let state = fromJS({ + json: { + paths: { + "/one": { + get: {} + } + } + }, + meta: { + paths: { + "/one": { + get: { + "consumes_value": "one" + } + } + } + } + }) + + // When + let contentTypes = contentTypeValues(state, [ "/one", "get" ]) + // Then + expect(contentTypes.toJS()).toEqual({ + requestContentType: "one", + responseContentType: "application/json" + }) + }) + + it("should prioritize consumes value first from an operation", function(){ + // Given + let state = fromJS({ + json: { + paths: { + "/one": { + get: { + "parameters": [{ + "type": "file" + }], + } + } + } + }, + meta: { + paths: { + "/one": { + get: { + "consumes_value": "one", + } + } + } + } + }) + + // When + let contentTypes = contentTypeValues(state, [ "/one", "get" ]) + // Then + expect(contentTypes.toJS().requestContentType).toEqual("one") + }) + + it("should fallback to multipart/form-data if there is no consumes value but there is a file parameter", function(){ + // Given + let state = fromJS({ + json: { + paths: { + "/one": { + get: { + "parameters": [{ + "type": "file" + }], + } + } + } + } + }) + + // When + let contentTypes = contentTypeValues(state, [ "/one", "get" ]) + // Then + expect(contentTypes.toJS().requestContentType).toEqual("multipart/form-data") + }) + + it("should fallback to application/x-www-form-urlencoded if there is no consumes value, no file parameter, but there is a formData parameter", function(){ + // Given + let state = fromJS({ + json: { + paths: { + "/one": { + get: { + "parameters": [{ + "type": "formData" + }], + } + } + } + } + }) + + // When + let contentTypes = contentTypeValues(state, [ "/one", "get" ]) + // Then + expect(contentTypes.toJS().requestContentType).toEqual("application/x-www-form-urlencoded") + }) + + it("should return nothing, if the operation does not exist", function(){ + // Given + let state = fromJS({ }) + + // When + let contentTypes = contentTypeValues(state, [ "/one", "get" ]) + // Then + expect(contentTypes.toJS()).toEqual({ + requestContentType: undefined, + responseContentType: undefined + }) + }) + +}) + +describe("operationScheme", function(){ + + it("should return the correct scheme for a remote spec that doesn't specify a scheme", function(){ + // Given + let state = fromJS({ + url: "https://generator.swagger.io/api/swagger.json", + json: { + paths: { + "/one": { + get: { + "consumes_value": "one", + "produces_value": "two" + } + } + } + } + }) + + // When + let scheme = operationScheme(state, ["/one"], "get") + // Then + expect(scheme).toEqual("https") + }) + + // it("should be ok, if no operation found", function(){ + // // Given + // let state = fromJS({ }) + // + // // When + // let contentTypes = contentTypeValues(state, [ "/one", "get" ]) + // // Then + // expect(contentTypes.toJS()).toEqual({ + // requestContentType: undefined, + // responseContentType: undefined + // }) + // }) + +}) + +describe("specJsonWithResolvedSubtrees", function(){ + + it("should return a correctly merged tree", function(){ + // Given + let state = fromJS({ + json: { + definitions: { + Asdf: { + $ref: "#/some/path", + randomKey: "this should be removed b/c siblings of $refs must be removed, per the specification", + description: "same for this key" + }, + Fgsfds: { + $ref: "#/another/path" + }, + OtherDef: { + description: "has no refs" + } + } + }, + resolvedSubtrees: { + definitions: { + Asdf: { + type: "object", + $$ref: "#/some/path" + } + } + } + }) + + // When + let result = specJsonWithResolvedSubtrees(state) + // Then + expect(result.toJS()).toEqual({ + definitions: { + Asdf: { + type: "object", + $$ref: "#/some/path" + }, + Fgsfds: { + $ref: "#/another/path" + }, + OtherDef: { + description: "has no refs" + } + } + }) + }) + it("should preserve initial map key ordering", function(){ + // Given + let state = fromJSOrdered({ + json: Petstore, + resolvedSubtrees: { + paths: { + "/pet/{petId}": { + post: { + tags: [ + "pet" + ], + summary: "Updates a pet in the store with form data", + description: "", + operationId: "updatePetWithForm", + consumes: [ + "application/x-www-form-urlencoded" + ], + produces: [ + "application/xml", + "application/json" + ], + parameters: [ + { + name: "petId", + "in": "path", + description: "ID of pet that needs to be updated", + required: true, + type: "integer", + format: "int64" + }, + { + name: "name", + "in": "formData", + description: "Updated name of the pet", + required: false, + type: "string" + }, + { + name: "status", + "in": "formData", + description: "Updated status of the pet", + required: false, + type: "string" + } + ], + responses: { + "405": { + description: "Invalid input" + } + }, + security: [ + { + petstore_auth: [ + "write:pets", + "read:pets" + ] + } + ], + __originalOperationId: "updatePetWithForm" + } + } + } + } + }) + + // When + let result = specJsonWithResolvedSubtrees(state) + + // Then + const correctOrder = [ + "/pet", + "/pet/findByStatus", + "/pet/findByTags", + "/pet/{petId}", + "/pet/{petId}/uploadImage", + "/store/inventory", + "/store/order", + "/store/order/{orderId}", + "/user", + "/user/createWithArray", + "/user/createWithList", + "/user/login", + "/user/logout", + "/user/{username}" + ] + expect(state.getIn(["json", "paths"]).keySeq().toJS()).toEqual(correctOrder) + expect(result.getIn(["paths"]).keySeq().toJS()).toEqual(correctOrder) + }) +}) + +describe("operationWithMeta", function() { + it("should support merging in {in}.{name} keyed param metadata", function () { + const state = fromJS({ + json: { + paths: { + "/": { + "get": { + parameters: [ + { + name: "myBody", + in: "body" + } + ] + } + } + } + }, + meta: { + paths: { + "/": { + "get": { + parameters: { + "body.myBody": { + value: "abc123" + } + } + } + } + } + } + }) + + const result = operationWithMeta(state, "/", "get") + + expect(result.toJS()).toEqual({ + parameters: [ + { + name: "myBody", + in: "body", + value: "abc123" + } + ] + }) + }) + it("should support merging in hash-keyed param metadata", function () { + const bodyParam = fromJS({ + name: "myBody", + in: "body" + }) + + const state = fromJS({ + json: { + paths: { + "/": { + "get": { + parameters: [ + bodyParam + ] + } + } + } + }, + meta: { + paths: { + "/": { + "get": { + parameters: { + [`body.myBody.hash-${bodyParam.hashCode()}`]: { + value: "abc123" + } + } + } + } + } + } + }) + + const result = operationWithMeta(state, "/", "get") + + expect(result.toJS()).toEqual({ + parameters: [ + { + name: "myBody", + in: "body", + value: "abc123" + } + ] + }) + }) +}) +describe("parameterWithMeta", function() { + it("should support merging in {in}.{name} keyed param metadata", function () { + const state = fromJS({ + json: { + paths: { + "/": { + "get": { + parameters: [ + { + name: "myBody", + in: "body" + } + ] + } + } + } + }, + meta: { + paths: { + "/": { + "get": { + parameters: { + "body.myBody": { + value: "abc123" + } + } + } + } + } + } + }) + + const result = parameterWithMeta(state, ["/", "get"], "myBody", "body") + + expect(result.toJS()).toEqual({ + name: "myBody", + in: "body", + value: "abc123" + }) + }) + it("should give best-effort when encountering hash-keyed param metadata", function () { + const bodyParam = fromJS({ + name: "myBody", + in: "body" + }) + + const state = fromJS({ + json: { + paths: { + "/": { + "get": { + parameters: [ + bodyParam + ] + } + } + } + }, + meta: { + paths: { + "/": { + "get": { + parameters: { + [`body.myBody.hash-${bodyParam.hashCode()}`]: { + value: "abc123" + } + } + } + } + } + } + }) + + const result = parameterWithMeta(state, ["/", "get"], "myBody", "body") + + expect(result.toJS()).toEqual({ + name: "myBody", + in: "body", + value: "abc123" + }) + }) + +}) +describe("parameterWithMetaByIdentity", function() { + it("should support merging in {in}.{name} keyed param metadata", function () { + const bodyParam = fromJS({ + name: "myBody", + in: "body" + }) + + const state = fromJS({ + json: { + paths: { + "/": { + "get": { + parameters: [bodyParam] + } + } + } + }, + meta: { + paths: { + "/": { + "get": { + parameters: { + "body.myBody": { + value: "abc123" + } + } + } + } + } + } + }) + + const result = parameterWithMetaByIdentity(state, ["/", "get"], bodyParam) + + expect(result.toJS()).toEqual({ + name: "myBody", + in: "body", + value: "abc123" + }) + }) + it("should support merging in hash-keyed param metadata", function () { + const bodyParam = fromJS({ + name: "myBody", + in: "body" + }) + + const state = fromJS({ + json: { + paths: { + "/": { + "get": { + parameters: [ + bodyParam + ] + } + } + } + }, + meta: { + paths: { + "/": { + "get": { + parameters: { + [`body.myBody.hash-${bodyParam.hashCode()}`]: { + value: "abc123" + } + } + } + } + } + } + }) + + const result = parameterWithMetaByIdentity(state, ["/", "get"], bodyParam) + + expect(result.toJS()).toEqual({ + name: "myBody", + in: "body", + value: "abc123" + }) + }) +}) +describe("parameterInclusionSettingFor", function() { + it("should support getting {in}.{name} param inclusion settings", function () { + const param = fromJS({ + name: "param", + in: "query", + allowEmptyValue: true + }) + + const state = fromJS({ + json: { + paths: { + "/": { + "get": { + parameters: [ + param + ] + } + } + } + }, + meta: { + paths: { + "/": { + "get": { + "parameter_inclusions": { + [`query.param`]: true + } + } + } + } + } + }) + + const result = parameterInclusionSettingFor(state, ["/", "get"], "param", "query") + + expect(result).toEqual(true) + }) +}) +describe("producesOptionsFor", function() { + it("should return an operation produces value", function () { + const state = fromJS({ + json: { + paths: { + "/": { + "get": { + description: "my operation", + produces: [ + "operation/one", + "operation/two", + ] + } + } + } + } + }) + + const result = producesOptionsFor(state, ["/", "get"]) + + expect(result.toJS()).toEqual([ + "operation/one", + "operation/two", + ]) + }) + it("should return a path item produces value", function () { + const state = fromJS({ + json: { + paths: { + "/": { + "get": { + description: "my operation", + produces: [ + "path-item/one", + "path-item/two", + ] + } + } + } + } + }) + + const result = producesOptionsFor(state, ["/", "get"]) + + expect(result.toJS()).toEqual([ + "path-item/one", + "path-item/two", + ]) + }) + it("should return a global produces value", function () { + const state = fromJS({ + json: { + produces: [ + "global/one", + "global/two", + ], + paths: { + "/": { + "get": { + description: "my operation" + } + } + } + } + }) + + const result = producesOptionsFor(state, ["/", "get"]) + + expect(result.toJS()).toEqual([ + "global/one", + "global/two", + ]) + }) + it("should favor an operation produces value over a path-item value", function () { + const state = fromJS({ + json: { + paths: { + "/": { + produces: [ + "path-item/one", + "path-item/two", + ], + "get": { + description: "my operation", + produces: [ + "operation/one", + "operation/two", + ] + } + } + } + } + }) + + const result = producesOptionsFor(state, ["/", "get"]) + + expect(result.toJS()).toEqual([ + "operation/one", + "operation/two", + ]) + }) + it("should favor a path-item produces value over a global value", function () { + const state = fromJS({ + json: { + produces: [ + "global/one", + "global/two", + ], + paths: { + "/": { + produces: [ + "path-item/one", + "path-item/two", + ], + "get": { + description: "my operation" + } + } + } + } + }) + + const result = producesOptionsFor(state, ["/", "get"]) + + expect(result.toJS()).toEqual([ + "path-item/one", + "path-item/two", + ]) + }) +}) +describe("consumesOptionsFor", function() { + it("should return an operation consumes value", function () { + const state = fromJS({ + json: { + paths: { + "/": { + "get": { + description: "my operation", + consumes: [ + "operation/one", + "operation/two", + ] + } + } + } + } + }) + + const result = consumesOptionsFor(state, ["/", "get"]) + + expect(result.toJS()).toEqual([ + "operation/one", + "operation/two", + ]) + }) + it("should return a path item consumes value", function () { + const state = fromJS({ + json: { + paths: { + "/": { + "get": { + description: "my operation", + consumes: [ + "path-item/one", + "path-item/two", + ] + } + } + } + } + }) + + const result = consumesOptionsFor(state, ["/", "get"]) + + expect(result.toJS()).toEqual([ + "path-item/one", + "path-item/two", + ]) + }) + it("should return a global consumes value", function () { + const state = fromJS({ + json: { + consumes: [ + "global/one", + "global/two", + ], + paths: { + "/": { + "get": { + description: "my operation" + } + } + } + } + }) + + const result = consumesOptionsFor(state, ["/", "get"]) + + expect(result.toJS()).toEqual([ + "global/one", + "global/two", + ]) + }) + it("should favor an operation consumes value over a path-item value", function () { + const state = fromJS({ + json: { + paths: { + "/": { + consumes: [ + "path-item/one", + "path-item/two", + ], + "get": { + description: "my operation", + consumes: [ + "operation/one", + "operation/two", + ] + } + } + } + } + }) + + const result = consumesOptionsFor(state, ["/", "get"]) + + expect(result.toJS()).toEqual([ + "operation/one", + "operation/two", + ]) + }) + it("should favor a path-item consumes value over a global value", function () { + const state = fromJS({ + json: { + consumes: [ + "global/one", + "global/two", + ], + paths: { + "/": { + consumes: [ + "path-item/one", + "path-item/two", + ], + "get": { + description: "my operation" + } + } + } + } + }) + + const result = consumesOptionsFor(state, ["/", "get"]) + + expect(result.toJS()).toEqual([ + "path-item/one", + "path-item/two", + ]) + }) +}) +describe("taggedOperations", function () { + it("should return a List of ad-hoc tagged operations", function () { + const system = { + getConfigs: () => ({}) + } + const state = fromJS({ + json: { + // tags: [ + // "myTag" + // ], + paths: { + "/": { + "get": { + produces: [], + tags: ["myTag"], + description: "my operation", + consumes: [ + "operation/one", + "operation/two", + ] + } + } + } + } + }) + + const result = taggedOperations(state)(system) + + const op = state.getIn(["json", "paths", "/", "get"]).toJS() + + expect(result.toJS()).toEqual({ + myTag: { + tagDetails: undefined, + operations: [{ + id: "get-/", + method: "get", + path: "/", + operation: op + }] + } + }) + }) + it("should return a List of defined tagged operations", function () { + const system = { + getConfigs: () => ({}) + } + const state = fromJS({ + json: { + tags: [ + { + name: "myTag" + } + ], + paths: { + "/": { + "get": { + produces: [], + tags: ["myTag"], + description: "my operation", + consumes: [ + "operation/one", + "operation/two", + ] + } + } + } + } + }) + + const result = taggedOperations(state)(system) + + const op = state.getIn(["json", "paths", "/", "get"]).toJS() + + expect(result.toJS()).toEqual({ + myTag: { + tagDetails: { + name: "myTag" + }, + operations: [{ + id: "get-/", + method: "get", + path: "/", + operation: op + }] + } + }) + }) + it("should gracefully handle a malformed global tags array", function () { + const system = { + getConfigs: () => ({}) + } + const state = fromJS({ + json: { + tags: [null], + paths: { + "/": { + "get": { + produces: [], + tags: ["myTag"], + description: "my operation", + consumes: [ + "operation/one", + "operation/two", + ] + } + } + } + } + }) + + const result = taggedOperations(state)(system) + + const op = state.getIn(["json", "paths", "/", "get"]).toJS() + + expect(result.toJS()).toEqual({ + myTag: { + tagDetails: undefined, + operations: [{ + id: "get-/", + method: "get", + path: "/", + operation: op + }] + } + }) + }) + it("should gracefully handle a non-array global tags entry", function () { + const system = { + getConfigs: () => ({}) + } + const state = fromJS({ + json: { + tags: "asdf", + paths: { + "/": { + "get": { + produces: [], + tags: ["myTag"], + description: "my operation", + consumes: [ + "operation/one", + "operation/two", + ] + } + } + } + } + }) + + const result = taggedOperations(state)(system) + + const op = state.getIn(["json", "paths", "/", "get"]).toJS() + + expect(result.toJS()).toEqual({ + myTag: { + tagDetails: undefined, + operations: [{ + id: "get-/", + method: "get", + path: "/", + operation: op + }] + } + }) + }) +}) diff --git a/test/mocha/core/plugins/swagger-js/withCredentials.js b/test/unit/core/plugins/swagger-js/withCredentials.js similarity index 69% rename from test/mocha/core/plugins/swagger-js/withCredentials.js rename to test/unit/core/plugins/swagger-js/withCredentials.js index ca98065d..f0be4ef7 100644 --- a/test/mocha/core/plugins/swagger-js/withCredentials.js +++ b/test/unit/core/plugins/swagger-js/withCredentials.js @@ -1,56 +1,55 @@ -import expect, { createSpy } from "expect" import { loaded } from "corePlugins/swagger-js/configs-wrap-actions" describe("swagger-js plugin - withCredentials", () => { it("should have no effect by default", () => { const system = { fn: { - fetch: createSpy().andReturn(Promise.resolve()) + fetch: jest.fn().mockImplementation(() => Promise.resolve()) }, getConfigs: () => ({}) } - const oriExecute = createSpy() + const oriExecute = jest.fn() const loadedFn = loaded(oriExecute, system) loadedFn() - expect(oriExecute.calls.length).toBe(1) + expect(oriExecute.mock.calls.length).toBe(1) expect(system.fn.fetch.withCredentials).toBe(undefined) }) it("should allow setting flag to true via config", () => { const system = { fn: { - fetch: createSpy().andReturn(Promise.resolve()) + fetch: jest.fn().mockImplementation(() => Promise.resolve()) }, getConfigs: () => ({ withCredentials: true }) } - const oriExecute = createSpy() + const oriExecute = jest.fn() const loadedFn = loaded(oriExecute, system) loadedFn() - expect(oriExecute.calls.length).toBe(1) + expect(oriExecute.mock.calls.length).toBe(1) expect(system.fn.fetch.withCredentials).toBe(true) }) it("should allow setting flag to false via config", () => { const system = { fn: { - fetch: createSpy().andReturn(Promise.resolve()) + fetch: jest.fn().mockImplementation(() => Promise.resolve()) }, getConfigs: () => ({ withCredentials: false }) } - const oriExecute = createSpy() + const oriExecute = jest.fn() const loadedFn = loaded(oriExecute, system) loadedFn() - expect(oriExecute.calls.length).toBe(1) + expect(oriExecute.mock.calls.length).toBe(1) expect(system.fn.fetch.withCredentials).toBe(false) }) @@ -58,18 +57,18 @@ describe("swagger-js plugin - withCredentials", () => { // for query string config const system = { fn: { - fetch: createSpy().andReturn(Promise.resolve()) + fetch: jest.fn().mockImplementation(() => Promise.resolve()) }, getConfigs: () => ({ withCredentials: "true" }) } - const oriExecute = createSpy() + const oriExecute = jest.fn() const loadedFn = loaded(oriExecute, system) loadedFn() - expect(oriExecute.calls.length).toBe(1) + expect(oriExecute.mock.calls.length).toBe(1) expect(system.fn.fetch.withCredentials).toBe(true) }) @@ -77,18 +76,18 @@ describe("swagger-js plugin - withCredentials", () => { // for query string config const system = { fn: { - fetch: createSpy().andReturn(Promise.resolve()) + fetch: jest.fn().mockImplementation(() => Promise.resolve()) }, getConfigs: () => ({ withCredentials: "false" }) } - const oriExecute = createSpy() + const oriExecute = jest.fn() const loadedFn = loaded(oriExecute, system) loadedFn() - expect(oriExecute.calls.length).toBe(1) + expect(oriExecute.mock.calls.length).toBe(1) expect(system.fn.fetch.withCredentials).toBe(false) }) }) diff --git a/test/mocha/core/system/system.jsx b/test/unit/core/system/system.jsx similarity index 98% rename from test/mocha/core/system/system.jsx rename to test/unit/core/system/system.jsx index 9837a328..e5082726 100644 --- a/test/mocha/core/system/system.jsx +++ b/test/unit/core/system/system.jsx @@ -1,6 +1,6 @@ -/* eslint-env mocha */ + import React, { PureComponent } from "react" -import expect from "expect" + import System from "core/system" import { fromJS } from "immutable" import { render } from "enzyme" @@ -755,10 +755,10 @@ describe("bound system", function(){ // When - expect(function() { + expect(() => { system.register([ThrowyPlugin]) // let resSystem = system.getSystem() - }).toNotThrow() + }).not.toThrow() }) it("should encapsulate thrown errors in an action creator", function(){ @@ -779,10 +779,10 @@ describe("bound system", function(){ }) - expect(function() { + expect(() => { // TODO: fix existing action error catcher that creates THROWN ERR actions system.getSystem().throwActions.func() - }).toNotThrow() + }).not.toThrow() }) it("should encapsulate thrown errors in a reducer", function(){ @@ -811,9 +811,9 @@ describe("bound system", function(){ }) - expect(function() { + expect(() => { system.getSystem().throwActions.func() - }).toNotThrow() + }).not.toThrow() }) it("should encapsulate thrown errors in a selector", function(){ @@ -834,7 +834,7 @@ describe("bound system", function(){ }) - expect(system.getSystem().throwSelectors.func).toNotThrow() + expect(system.getSystem().throwSelectors.func).not.toThrow() }) it("should encapsulate thrown errors in a complex selector", function(){ @@ -855,7 +855,7 @@ describe("bound system", function(){ }) - expect(system.getSystem().throwSelectors.func).toNotThrow() + expect(system.getSystem().throwSelectors.func).not.toThrow() }) it("should encapsulate thrown errors in a wrapAction", function(){ @@ -884,7 +884,7 @@ describe("bound system", function(){ }) - expect(system.getSystem().throwActions.func).toNotThrow() + expect(system.getSystem().throwActions.func).not.toThrow() }) it("should encapsulate thrown errors in a wrapSelector", function(){ @@ -910,7 +910,7 @@ describe("bound system", function(){ }) - expect(system.getSystem().throwSelectors.func).toNotThrow() + expect(system.getSystem().throwSelectors.func).not.toThrow() }) describe("components", function() { diff --git a/test/mocha/core/system/wrapComponent.jsx b/test/unit/core/system/wrapComponent.jsx similarity index 99% rename from test/mocha/core/system/wrapComponent.jsx rename to test/unit/core/system/wrapComponent.jsx index f051a819..0605b0d5 100644 --- a/test/mocha/core/system/wrapComponent.jsx +++ b/test/unit/core/system/wrapComponent.jsx @@ -1,5 +1,5 @@ import React from "react" -import expect from "expect" + import { render } from "enzyme" import System from "core/system" diff --git a/test/mocha/core/utils.js b/test/unit/core/utils.js similarity index 84% rename from test/mocha/core/utils.js rename to test/unit/core/utils.js index e55c4cbb..3b7b53af 100644 --- a/test/mocha/core/utils.js +++ b/test/unit/core/utils.js @@ -1,6 +1,5 @@ -/* eslint-env mocha */ -import expect from "expect" -import { Map, fromJS, OrderedMap } from "immutable" + +import { Map, fromJS } from "immutable" import { mapToList, parseSearch, @@ -41,11 +40,11 @@ import { import win from "core/window" -describe("utils", function() { +describe("utils", () => { - describe("mapToList", function(){ + describe("mapToList", () =>{ - it("should convert a map to a list, setting `key`", function(){ + it("should convert a map to a list, setting `key`", () =>{ // With const aMap = fromJS({ a: { @@ -66,7 +65,7 @@ describe("utils", function() { ]) }) - it("should flatten an arbitrarily deep map", function(){ + it("should flatten an arbitrarily deep map", () =>{ // With const aMap = fromJS({ a: { @@ -96,7 +95,7 @@ describe("utils", function() { }) - it("should handle an empty map", function(){ + it("should handle an empty map", () =>{ // With const aMap = fromJS({}) @@ -109,68 +108,68 @@ describe("utils", function() { }) - describe("extractFileNameFromContentDispositionHeader", function(){ - it("should extract quoted filename", function(){ + describe("extractFileNameFromContentDispositionHeader", () =>{ + it("should extract quoted filename", () =>{ let cdHeader = "attachment; filename=\"file name.jpg\"" let expectedResult = "file name.jpg" expect(extractFileNameFromContentDispositionHeader(cdHeader)).toEqual(expectedResult) }) - it("should extract filename", function(){ + it("should extract filename", () =>{ let cdHeader = "attachment; filename=filename.jpg" let expectedResult = "filename.jpg" expect(extractFileNameFromContentDispositionHeader(cdHeader)).toEqual(expectedResult) }) - it("should extract quoted filename in utf-8", function(){ + it("should extract quoted filename in utf-8", () =>{ let cdHeader = "attachment; filename*=UTF-8''\"%D1%84%D0%B0%D0%B9%D0%BB.txt\"" let expectedResult = "файл.txt" expect(extractFileNameFromContentDispositionHeader(cdHeader)).toEqual(expectedResult) }) - it("should extract filename in utf-8", function(){ + it("should extract filename in utf-8", () =>{ let cdHeader = "attachment; filename*=utf-8'ru'%D1%84%D0%B0%D0%B9%D0%BB.txt" let expectedResult = "файл.txt" expect(extractFileNameFromContentDispositionHeader(cdHeader)).toEqual(expectedResult) }) - it("should not extract filename and return null", function(){ + it("should not extract filename and return null", () =>{ let cdHeader = "attachment; no file name provided" let expectedResult = null expect(extractFileNameFromContentDispositionHeader(cdHeader)).toEqual(expectedResult) }) }) - describe("validateMaximum", function() { - it("doesn't return for valid input", function() { + describe("validateMaximum", () => { + it("doesn't return for valid input", () => { expect(validateMaximum(9, 10)).toBeFalsy() expect(validateMaximum(19, 20)).toBeFalsy() }) - it("returns a message for invalid input", function() { + it("returns a message for invalid input", () => { expect(validateMaximum(1, 0)).toEqual("Value must be less than 0") expect(validateMaximum(10, 9)).toEqual("Value must be less than 9") expect(validateMaximum(20, 19)).toEqual("Value must be less than 19") }) }) - describe("validateMinimum", function() { - it("doesn't return for valid input", function() { + describe("validateMinimum", () => { + it("doesn't return for valid input", () => { expect(validateMinimum(2, 1)).toBeFalsy() expect(validateMinimum(20, 10)).toBeFalsy() }) - it("returns a message for invalid input", function() { + it("returns a message for invalid input", () => { expect(validateMinimum(-1, 0)).toEqual("Value must be greater than 0") expect(validateMinimum(1, 2)).toEqual("Value must be greater than 2") expect(validateMinimum(10, 20)).toEqual("Value must be greater than 20") }) }) - describe("validateNumber", function() { + describe("validateNumber", () => { let errorMessage = "Value must be a number" - it("doesn't return for whole numbers", function() { + it("doesn't return for whole numbers", () => { expect(validateNumber(0)).toBeFalsy() expect(validateNumber(1)).toBeFalsy() expect(validateNumber(20)).toBeFalsy() @@ -182,25 +181,25 @@ describe("utils", function() { expect(validateNumber(-5000000)).toBeFalsy() }) - it("doesn't return for negative numbers", function() { + it("doesn't return for negative numbers", () => { expect(validateNumber(-1)).toBeFalsy() expect(validateNumber(-20)).toBeFalsy() expect(validateNumber(-5000000)).toBeFalsy() }) - it("doesn't return for decimal numbers", function() { + it("doesn't return for decimal numbers", () => { expect(validateNumber(1.1)).toBeFalsy() expect(validateNumber(2.5)).toBeFalsy() expect(validateNumber(-30.99)).toBeFalsy() }) - it("returns a message for strings", function() { + it("returns a message for strings", () => { expect(validateNumber("")).toEqual(errorMessage) expect(validateNumber(" ")).toEqual(errorMessage) expect(validateNumber("test")).toEqual(errorMessage) }) - it("returns a message for invalid input", function() { + it("returns a message for invalid input", () => { expect(validateNumber(undefined)).toEqual(errorMessage) expect(validateNumber(null)).toEqual(errorMessage) expect(validateNumber({})).toEqual(errorMessage) @@ -210,10 +209,10 @@ describe("utils", function() { }) }) - describe("validateInteger", function() { + describe("validateInteger", () => { let errorMessage = "Value must be an integer" - it("doesn't return for positive integers", function() { + it("doesn't return for positive integers", () => { expect(validateInteger(0)).toBeFalsy() expect(validateInteger(1)).toBeFalsy() expect(validateInteger(20)).toBeFalsy() @@ -225,25 +224,25 @@ describe("utils", function() { expect(validateInteger(-5000000)).toBeFalsy() }) - it("doesn't return for negative integers", function() { + it("doesn't return for negative integers", () => { expect(validateInteger(-1)).toBeFalsy() expect(validateInteger(-20)).toBeFalsy() expect(validateInteger(-5000000)).toBeFalsy() }) - it("returns a message for decimal values", function() { + it("returns a message for decimal values", () => { 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() { + it("returns a message for strings", () => { expect(validateInteger("")).toEqual(errorMessage) expect(validateInteger(" ")).toEqual(errorMessage) expect(validateInteger("test")).toEqual(errorMessage) }) - it("returns a message for invalid input", function() { + it("returns a message for invalid input", () => { expect(validateInteger(undefined)).toEqual(errorMessage) expect(validateInteger(null)).toEqual(errorMessage) expect(validateInteger({})).toEqual(errorMessage) @@ -253,10 +252,10 @@ describe("utils", function() { }) }) - describe("validateFile", function() { + describe("validateFile", () => { let errorMessage = "Value must be a file" - it("validates against objects which are instances of 'File'", function() { + it("validates against objects which are instances of 'File'", () => { let fileObj = new win.File([], "Test File") expect(validateFile(fileObj)).toBeFalsy() expect(validateFile(null)).toBeFalsy() @@ -266,23 +265,23 @@ describe("utils", function() { }) }) - describe("validateDateTime", function() { + describe("validateDateTime", () => { let errorMessage = "Value must be a DateTime" - it("doesn't return for valid dates", function() { + it("doesn't return for valid dates", () => { expect(validateDateTime("Mon, 25 Dec 1995 13:30:00 +0430")).toBeFalsy() }) - it("returns a message for invalid input'", function() { + it("returns a message for invalid input'", () => { expect(validateDateTime(null)).toEqual(errorMessage) expect(validateDateTime("string")).toEqual(errorMessage) }) }) - describe("validateGuid", function() { + describe("validateGuid", () => { let errorMessage = "Value must be a Guid" - it("doesn't return for valid guid", function() { + it("doesn't return for valid guid", () => { expect(validateGuid("8ce4811e-cec5-4a29-891a-15d1917153c1")).toBeFalsy() expect(validateGuid("{8ce4811e-cec5-4a29-891a-15d1917153c1}")).toBeFalsy() expect(validateGuid("8CE4811E-CEC5-4A29-891A-15D1917153C1")).toBeFalsy() @@ -291,61 +290,61 @@ describe("utils", function() { expect(validateGuid("00000000-0000-0000-0000-000000000000")).toBeFalsy() }) - it("returns a message for invalid input'", function() { + it("returns a message for invalid input'", () => { expect(validateGuid(1)).toEqual(errorMessage) expect(validateGuid("string")).toEqual(errorMessage) }) }) - describe("validateMaxLength", function() { - it("doesn't return for valid input", function() { + describe("validateMaxLength", () => { + it("doesn't return for valid input", () => { expect(validateMaxLength("a", 1)).toBeFalsy() expect(validateMaxLength("abc", 5)).toBeFalsy() }) - it("returns a message for invalid input'", function() { + it("returns a message for invalid input'", () => { expect(validateMaxLength("abc", 0)).toEqual("Value must be no longer than 0 characters") expect(validateMaxLength("abc", 1)).toEqual("Value must be no longer than 1 character") expect(validateMaxLength("abc", 2)).toEqual("Value must be no longer than 2 characters") }) }) - describe("validateMinLength", function() { - it("doesn't return for valid input", function() { + describe("validateMinLength", () => { + it("doesn't return for valid input", () => { expect(validateMinLength("a", 1)).toBeFalsy() expect(validateMinLength("abc", 2)).toBeFalsy() }) - it("returns a message for invalid input'", function() { + it("returns a message for invalid input'", () => { expect(validateMinLength("", 1)).toEqual("Value must be at least 1 character") expect(validateMinLength("abc", 5)).toEqual("Value must be at least 5 characters") expect(validateMinLength("abc", 8)).toEqual("Value must be at least 8 characters") }) }) - describe("validatePattern", function() { + describe("validatePattern", () => { let rxPattern = "^(red|blue)" let errorMessage = "Value must follow pattern " + rxPattern - it("doesn't return for a match", function() { + it("doesn't return for a match", () => { expect(validatePattern("red", rxPattern)).toBeFalsy() expect(validatePattern("blue", rxPattern)).toBeFalsy() }) - it("returns a message for invalid pattern", function() { + it("returns a message for invalid pattern", () => { expect(validatePattern("pink", rxPattern)).toEqual(errorMessage) expect(validatePattern("123", rxPattern)).toEqual(errorMessage) }) - it("fails gracefully when an invalid regex value is passed", function() { - expect(() => validatePattern("aValue", "---")).toNotThrow() - expect(() => validatePattern("aValue", 1234)).toNotThrow() - expect(() => validatePattern("aValue", null)).toNotThrow() - expect(() => validatePattern("aValue", [])).toNotThrow() + it("fails gracefully when an invalid regex value is passed", () => { + expect(() => validatePattern("aValue", "---")).not.toThrow() + expect(() => validatePattern("aValue", 1234)).not.toThrow() + expect(() => validatePattern("aValue", null)).not.toThrow() + expect(() => validatePattern("aValue", [])).not.toThrow() }) }) - describe("validateParam", function() { + describe("validateParam", () => { let param = null let value = null let result = null @@ -377,7 +376,7 @@ describe("utils", function() { expect( result ).toEqual( expectedError ) } - it("should check the isOAS3 flag when validating parameters", function() { + it("should check the isOAS3 flag when validating parameters", () => { // This should "skip" validation because there is no `schema` property // and we are telling `validateParam` this is an OAS3 spec param = fromJS({ @@ -390,7 +389,7 @@ describe("utils", function() { expect( result ).toEqual( [] ) }) - it("validates required OAS3 objects", function() { + it("validates required OAS3 objects", () => { // valid object param = { required: true, @@ -436,7 +435,7 @@ describe("utils", function() { assertValidateOas3Param(param, value, ["Required field is not provided"]) }) - it("validates optional OAS3 objects", function() { + it("validates optional OAS3 objects", () => { // valid object param = { schema: { @@ -478,7 +477,7 @@ describe("utils", function() { assertValidateOas3Param(param, value, []) }) - it("validates required strings", function() { + it("validates required strings", () => { // invalid string param = { required: true, @@ -506,7 +505,7 @@ describe("utils", function() { assertValidateParam(param, value, []) }) - it("handles OAS3 `Parameter.content`", function() { + it("handles OAS3 `Parameter.content`", () => { // invalid string param = { content: { @@ -608,7 +607,7 @@ describe("utils", function() { assertValidateOas3Param(param, value, []) }) - it("validates required strings with min and max length", function() { + it("validates required strings with min and max length", () => { // invalid string with max length param = { required: true, @@ -637,7 +636,7 @@ describe("utils", function() { assertValidateParam(param, value, ["Value must be at least 50 characters"]) }) - it("validates optional strings", function() { + it("validates optional strings", () => { // valid (empty) string param = { required: false, @@ -655,7 +654,7 @@ describe("utils", function() { assertValidateParam(param, value, []) }) - it("validates required files", function() { + it("validates required files", () => { // invalid file param = { required: true, @@ -669,11 +668,11 @@ describe("utils", function() { required: true, type: "file" } - value = new win.File() + value = new win.File([""], "file.txt") assertValidateParam(param, value, []) }) - it("validates optional files", function() { + it("validates optional files", () => { // invalid file param = { required: false, @@ -695,11 +694,11 @@ describe("utils", function() { required: false, type: "file" } - value = new win.File() + value = new win.File([""], "file.txt") assertValidateParam(param, value, []) }) - it("validates required arrays", function() { + it("validates required arrays", () => { // invalid (empty) array param = { required: true, @@ -763,7 +762,7 @@ describe("utils", function() { assertValidateParam(param, value, []) }) - it("validates optional arrays", function() { + it("validates optional arrays", () => { // valid, empty array param = { required: false, @@ -795,7 +794,7 @@ describe("utils", function() { assertValidateParam(param, value, []) }) - it("validates required booleans", function() { + it("validates required booleans", () => { // invalid boolean value param = { required: true, @@ -829,7 +828,7 @@ describe("utils", function() { assertValidateParam(param, value, []) }) - it("validates optional booleans", function() { + it("validates optional booleans", () => { // valid (empty) boolean value param = { required: false, @@ -863,7 +862,7 @@ describe("utils", function() { assertValidateParam(param, value, []) }) - it("validates required numbers", function() { + it("validates required numbers", () => { // invalid number, string instead of a number param = { required: true, @@ -920,7 +919,7 @@ describe("utils", function() { assertValidateParam(param, value, ["Value must be greater than 0"]) }) - it("validates optional numbers", function() { + it("validates optional numbers", () => { // invalid number, string instead of a number param = { required: false, @@ -946,7 +945,7 @@ describe("utils", function() { assertValidateParam(param, value, []) }) - it("validates required integers", function() { + it("validates required integers", () => { // invalid integer, string instead of an integer param = { required: true, @@ -980,7 +979,7 @@ describe("utils", function() { assertValidateParam(param, value, []) }) - it("validates optional integers", function() { + it("validates optional integers", () => { // invalid integer, string instead of an integer param = { required: false, @@ -1131,13 +1130,13 @@ describe("utils", function() { }) }) - describe("createDeepLinkPath", function() { - it("creates a deep link path replacing spaces with underscores", function() { + describe("createDeepLinkPath", () => { + it("creates a deep link path replacing spaces with underscores", () => { const result = createDeepLinkPath("tag id with spaces") expect(result).toEqual("tag%20id%20with%20spaces") }) - it("trims input when creating a deep link path", function() { + it("trims input when creating a deep link path", () => { let result = createDeepLinkPath(" spaces before and after ") expect(result).toEqual("spaces%20before%20and%20after") @@ -1145,12 +1144,12 @@ describe("utils", function() { expect(result).toEqual("") }) - it("creates a deep link path with special characters", function() { + it("creates a deep link path with special characters", () => { const result = createDeepLinkPath("!@#$%^&*(){}[]") expect(result).toEqual("!@#$%^&*(){}[]") }) - it("returns an empty string for invalid input", function() { + it("returns an empty string for invalid input", () => { expect( createDeepLinkPath(null) ).toEqual("") expect( createDeepLinkPath(undefined) ).toEqual("") expect( createDeepLinkPath(1) ).toEqual("") @@ -1159,58 +1158,58 @@ describe("utils", function() { }) }) - describe("escapeDeepLinkPath", function() { - it("creates and escapes a deep link path", function() { + describe("escapeDeepLinkPath", () => { + it("creates and escapes a deep link path", () => { 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() { + it("escapes a deep link path that starts with a number", () => { const result = escapeDeepLinkPath("123") expect(result).toEqual("\\31 23") }) - it("escapes a deep link path with a class selector", function() { + it("escapes a deep link path with a class selector", () => { const result = escapeDeepLinkPath("hello.world") expect(result).toEqual("hello\\.world") }) - it("escapes a deep link path with an id selector", function() { + it("escapes a deep link path with an id selector", () => { const result = escapeDeepLinkPath("hello#world") expect(result).toEqual("hello\\#world") }) - it("escapes a deep link path with a space", function() { + it("escapes a deep link path with a space", () => { const result = escapeDeepLinkPath("hello world") expect(result).toEqual("hello_world") }) - it("escapes a deep link path with a percent-encoded space", function() { + it("escapes a deep link path with a percent-encoded space", () => { const result = escapeDeepLinkPath("hello%20world") expect(result).toEqual("hello_world") }) }) - describe("getExtensions", function() { + describe("getExtensions", () => { const objTest = Map([[ "x-test", "a"], ["minimum", "b"]]) - it("does not error on empty array", function() { + it("does not error on empty array", () => { const result1 = getExtensions([]) expect(result1).toEqual([]) const result2 = getCommonExtensions([]) expect(result2).toEqual([]) }) - it("gets only the x- keys", function() { + it("gets only the x- keys", () => { const result = getExtensions(objTest) expect(result).toEqual(Map([[ "x-test", "a"]])) }) - it("gets the common keys", function() { + it("gets the common keys", () => { const result = getCommonExtensions(objTest, true) expect(result).toEqual(Map([[ "minimum", "b"]])) }) }) - describe("deeplyStripKey", function() { - it("should filter out a specified key", function() { + describe("deeplyStripKey", () => { + it("should filter out a specified key", () => { const input = { $$ref: "#/this/is/my/ref", a: { @@ -1226,7 +1225,7 @@ describe("utils", function() { }) }) - it("should filter out a specified key by predicate", function() { + it("should filter out a specified key by predicate", () => { const input = { $$ref: "#/this/is/my/ref", a: { @@ -1243,7 +1242,7 @@ describe("utils", function() { }) }) - it("should only call the predicate when the key matches", function() { + it("should only call the predicate when the key matches", () => { const input = { $$ref: "#/this/is/my/ref", a: { @@ -1261,78 +1260,86 @@ describe("utils", function() { }) }) - describe("parse and serialize search", function() { - afterEach(function() { + describe("parse and serialize search", () => { + beforeEach(() => { + // jsdom in Jest 25+ prevents modifying window.location, + // so we replace with a stubbed version + delete win.location + win.location = { + search: "" + } + }) + afterEach(() => { win.location.search = "" }) - describe("parsing", function() { - it("works with empty search", function() { + describe("parsing", () => { + it("works with empty search", () => { win.location.search = "" expect(parseSearch()).toEqual({}) }) - it("works with only one key", function() { + it("works with only one key", () => { win.location.search = "?foo" expect(parseSearch()).toEqual({foo: ""}) }) - it("works with keys and values", function() { + it("works with keys and values", () => { win.location.search = "?foo=fooval&bar&baz=bazval" expect(parseSearch()).toEqual({foo: "fooval", bar: "", baz: "bazval"}) }) - it("decode url encoded components", function() { + it("decode url encoded components", () => { win.location.search = "?foo=foo%20bar" expect(parseSearch()).toEqual({foo: "foo bar"}) }) }) - describe("serializing", function() { - it("works with empty map", function() { + describe("serializing", () => { + it("works with empty map", () => { expect(serializeSearch({})).toEqual("") }) - it("works with multiple keys with and without values", function() { + it("works with multiple keys with and without values", () => { expect(serializeSearch({foo: "", bar: "barval"})).toEqual("foo=&bar=barval") }) - it("encode url components", function() { + it("encode url components", () => { expect(serializeSearch({foo: "foo bar"})).toEqual("foo=foo%20bar") }) }) }) - describe("sanitizeUrl", function() { - it("should sanitize a `javascript:` url", function() { + describe("sanitizeUrl", () => { + it("should sanitize a `javascript:` url", () => { const res = sanitizeUrl("javascript:alert('bam!')") expect(res).toEqual("about:blank") }) - it("should sanitize a `data:` url", function() { + it("should sanitize a `data:` url", () => { const res = sanitizeUrl(`data:text/html;base64,PHNjcmlwdD5hbGVydCgiSGVsbG8iKTs8L3NjcmlwdD4=`) expect(res).toEqual("about:blank") }) - it("should not modify a `http:` url", function() { + it("should not modify a `http:` url", () => { const res = sanitizeUrl(`http://swagger.io/`) expect(res).toEqual("http://swagger.io/") }) - it("should not modify a `https:` url", function() { + it("should not modify a `https:` url", () => { const res = sanitizeUrl(`https://swagger.io/`) expect(res).toEqual("https://swagger.io/") }) - it("should gracefully handle empty strings", function() { + it("should gracefully handle empty strings", () => { expect(sanitizeUrl("")).toEqual("") }) - it("should gracefully handle non-string values", function() { + it("should gracefully handle non-string values", () => { expect(sanitizeUrl(123)).toEqual("") expect(sanitizeUrl(null)).toEqual("") expect(sanitizeUrl(undefined)).toEqual("") @@ -1341,9 +1348,9 @@ describe("utils", function() { }) }) - describe("isAbsoluteUrl", function() { + describe("isAbsoluteUrl", () => { - it("check if url is absolute", function() { + it("check if url is absolute", () => { expect(!!isAbsoluteUrl("http://example.com")).toEqual(true) expect(!!isAbsoluteUrl("https://secure-example.com")).toEqual(true) expect(!!isAbsoluteUrl("HTTP://uppercase-example.com")).toEqual(true) @@ -1353,13 +1360,13 @@ describe("utils", function() { expect(!!isAbsoluteUrl("//no-protocol.com")).toEqual(true) }) - it("check if url is not absolute", function() { + it("check if url is not absolute", () => { expect(!!isAbsoluteUrl("/url-relative-to-host/base-path/path")).toEqual(false) expect(!!isAbsoluteUrl("url-relative-to-base/base-path/path")).toEqual(false) }) }) - describe("buildBaseUrl", function() { + describe("buildBaseUrl", () => { const specUrl = "https://petstore.swagger.io/v2/swagger.json" const noServerSelected = "" @@ -1367,21 +1374,21 @@ describe("utils", function() { const serverUrlRelativeToBase = "server-example/base-path/path" const serverUrlRelativeToHost = "/server-example/base-path/path" - it("build base url with no server selected", function() { + it("build base url with no server selected", () => { expect(buildBaseUrl(noServerSelected, specUrl)).toBe("https://petstore.swagger.io/v2/swagger.json") }) - it("build base url from absolute server url", function() { + it("build base url from absolute server url", () => { expect(buildBaseUrl(absoluteServerUrl, specUrl)).toBe("https://server-example.com/base-path/path") }) - it("build base url from relative server url", function() { + it("build base url from relative server url", () => { expect(buildBaseUrl(serverUrlRelativeToBase, specUrl)).toBe("https://petstore.swagger.io/v2/server-example/base-path/path") expect(buildBaseUrl(serverUrlRelativeToHost, specUrl)).toBe("https://petstore.swagger.io/server-example/base-path/path") }) }) - describe("buildUrl", function() { + describe("buildUrl", () => { const specUrl = "https://petstore.swagger.io/v2/swagger.json" const noUrl = "" @@ -1394,77 +1401,77 @@ describe("utils", function() { const serverUrlRelativeToBase = "server-example/base-path/path" const serverUrlRelativeToHost = "/server-example/base-path/path" - it("build no url", function() { + it("build no url", () => { expect(buildUrl(noUrl, specUrl, { selectedServer: absoluteServerUrl })).toBe(undefined) expect(buildUrl(noUrl, specUrl, { selectedServer: serverUrlRelativeToBase })).toBe(undefined) expect(buildUrl(noUrl, specUrl, { selectedServer: serverUrlRelativeToHost })).toBe(undefined) }) - it("build absolute url", function() { + it("build absolute url", () => { expect(buildUrl(absoluteUrl, specUrl, { selectedServer: absoluteServerUrl })).toBe("https://example.com/base-path/path") expect(buildUrl(absoluteUrl, specUrl, { selectedServer: serverUrlRelativeToBase })).toBe("https://example.com/base-path/path") expect(buildUrl(absoluteUrl, specUrl, { selectedServer: serverUrlRelativeToHost })).toBe("https://example.com/base-path/path") }) - it("build relative url with no server selected", function() { + it("build relative url with no server selected", () => { expect(buildUrl(urlRelativeToBase, specUrl, { selectedServer: noServerSelected })).toBe("https://petstore.swagger.io/v2/relative-url/base-path/path") expect(buildUrl(urlRelativeToHost, specUrl, { selectedServer: noServerSelected })).toBe("https://petstore.swagger.io/relative-url/base-path/path") }) - it("build relative url with absolute server url", function() { + it("build relative url with absolute server url", () => { expect(buildUrl(urlRelativeToBase, specUrl, { selectedServer: absoluteServerUrl })).toBe("https://server-example.com/base-path/relative-url/base-path/path") expect(buildUrl(urlRelativeToHost, specUrl, { selectedServer: absoluteServerUrl })).toBe("https://server-example.com/relative-url/base-path/path") }) - it("build relative url with server url relative to base", function() { + it("build relative url with server url relative to base", () => { expect(buildUrl(urlRelativeToBase, specUrl, { selectedServer: serverUrlRelativeToBase })).toBe("https://petstore.swagger.io/v2/server-example/base-path/relative-url/base-path/path") expect(buildUrl(urlRelativeToHost, specUrl, { selectedServer: serverUrlRelativeToBase })).toBe("https://petstore.swagger.io/relative-url/base-path/path") }) - it("build relative url with server url relative to host", function() { + it("build relative url with server url relative to host", () => { expect(buildUrl(urlRelativeToBase, specUrl, { selectedServer: serverUrlRelativeToHost })).toBe("https://petstore.swagger.io/server-example/base-path/relative-url/base-path/path") expect(buildUrl(urlRelativeToHost, specUrl, { selectedServer: serverUrlRelativeToHost })).toBe("https://petstore.swagger.io/relative-url/base-path/path") }) }) - describe("requiresValidationURL", function() { - it("Should tell us if we require a ValidationURL", function() { + describe("requiresValidationURL", () => { + it("Should tell us if we require a ValidationURL", () => { const res = requiresValidationURL("https://example.com") expect(res).toBe(true) }) - it(".. and localhost is not", function() { + it(".. and localhost is not", () => { const res = requiresValidationURL("http://localhost") expect(res).toBe(false) }) - it(".. and neither does 127.0.0.1", function() { + it(".. and neither does 127.0.0.1", () => { const res = requiresValidationURL("http://127.0.0.1") expect(res).toBe(false) }) - it(".. even without the proto", function() { + it(".. even without the proto", () => { const res = requiresValidationURL("127.0.0.1") expect(res).toBe(false) }) - it(".. and also not with 'none'", function() { + it(".. and also not with 'none'", () => { const res = requiresValidationURL("none") expect(res).toBe(false) }) - it(".. and also not with 'none'", function() { + it(".. and also not with 'none'", () => { const res = requiresValidationURL("none") expect(res).toBe(false) }) - it(".. and also not with ''", function() { + it(".. and also not with ''", () => { const res = requiresValidationURL("") expect(res).toBe(false) @@ -1472,10 +1479,10 @@ describe("utils", function() { }) - describe("getSampleSchema", function() { + describe("getSampleSchema", () => { const oriDate = Date - before(function() { + beforeEach(() => { Date = function () { this.toISOString = function () { return "2018-07-07T07:07:05.189Z" @@ -1483,11 +1490,11 @@ describe("utils", function() { } }) - after(function() { + afterEach(() => { Date = oriDate }) - it("should not unnecessarily stringify non-object values", function() { + it("should not unnecessarily stringify non-object values", () => { // Given const res = getSampleSchema({ type: "string", @@ -1499,7 +1506,7 @@ describe("utils", function() { }) }) - describe("paramToIdentifier", function() { + describe("paramToIdentifier", () => { it("should convert an Immutable parameter map to an identifier", () => { const param = fromJS({ name: "id", @@ -1586,13 +1593,13 @@ describe("utils", function() { error = e } - expect(error).toBeA(Error) - expect(error.message).toInclude("received a non-Im.Map parameter as input") + expect(error).toBeInstanceOf(Error) + expect(error.message).toContain("received a non-Im.Map parameter as input") expect(res).toEqual(null) }) }) - describe("paramToValue", function() { + describe("paramToValue", () => { it("should identify a hash-keyed value", () => { const param = fromJS({ name: "id", @@ -1639,16 +1646,16 @@ describe("utils", function() { }) }) - describe("generateCodeVerifier", function() { + describe("generateCodeVerifier", () => { it("should generate a value of at least 43 characters", () => { const codeVerifier = generateCodeVerifier() // Source: https://tools.ietf.org/html/rfc7636#section-4.1 - expect(codeVerifier.length).toBeGreaterThanOrEqualTo(43) + expect(codeVerifier.length).toBeGreaterThanOrEqual(43) }) }) - describe("createCodeChallenge", function() { + describe("createCodeChallenge", () => { it("should hash the input using SHA256 and output the base64 url encoded value", () => { // The `codeVerifier` has been randomly generated const codeVerifier = "cY8OJ9MKvZ7hxQeIyRYD7KFmKA5znSFJ2rELysvy2UI" diff --git a/test/mocha/docker/oauth.js b/test/unit/docker/oauth.js similarity index 98% rename from test/mocha/docker/oauth.js rename to test/unit/docker/oauth.js index 8ffae207..a251bdb8 100644 --- a/test/mocha/docker/oauth.js +++ b/test/unit/docker/oauth.js @@ -1,4 +1,3 @@ -const expect = require("expect") const oauthBlockBuilder = require("../../../docker/configurator/oauth") const dedent = require("dedent") diff --git a/test/mocha/docker/translator.js b/test/unit/docker/translator.js similarity index 98% rename from test/mocha/docker/translator.js rename to test/unit/docker/translator.js index 8b49ba95..33d1a45a 100644 --- a/test/mocha/docker/translator.js +++ b/test/unit/docker/translator.js @@ -1,4 +1,3 @@ -const expect = require("expect") const translator = require("../../../docker/configurator/translator") const dedent = require("dedent") @@ -15,7 +14,7 @@ describe("docker: env translator", function() { MY_THING: "hey" } - const onFoundSpy = expect.createSpy() + const onFoundSpy = jest.fn() const schema = { MY_THING: { @@ -29,7 +28,7 @@ describe("docker: env translator", function() { schema }) expect(res).toEqual(`myThing: "hey",`) - expect(onFoundSpy.calls.length).toEqual(1) + expect(onFoundSpy.mock.calls.length).toEqual(1) }) diff --git a/test/unit/setup.js b/test/unit/setup.js new file mode 100644 index 00000000..75bcdf50 --- /dev/null +++ b/test/unit/setup.js @@ -0,0 +1,19 @@ +import win from "../../src/core/window" + +function copyProps(src, target) { + const props = Object.getOwnPropertyNames(src) + .filter(prop => typeof target[prop] === "undefined") + .reduce((result, prop) => ({ + ...result, + [prop]: Object.getOwnPropertyDescriptor(src, prop), + }), {}) + Object.defineProperties(target, props) +} + +global.window = window +global.document = window.document +global.navigator = { + userAgent: "node.js", +} +copyProps(win, window) // use UI's built-in window wrapper +copyProps(window, global) diff --git a/test/mocha/swagger-ui-dist-package/absolute-path.js b/test/unit/swagger-ui-dist-package/absolute-path.js similarity index 88% rename from test/mocha/swagger-ui-dist-package/absolute-path.js rename to test/unit/swagger-ui-dist-package/absolute-path.js index 473f60ae..8967c894 100644 --- a/test/mocha/swagger-ui-dist-package/absolute-path.js +++ b/test/unit/swagger-ui-dist-package/absolute-path.js @@ -1,5 +1,4 @@ -/* eslint-env mocha */ -import expect from "expect" + import path from "path" import getAbsoluteFSPath from "../../../swagger-ui-dist-package/absolute-path" diff --git a/test/mocha/xss/anchor-target-rel/info.jsx b/test/unit/xss/anchor-target-rel/info.jsx similarity index 79% rename from test/mocha/xss/anchor-target-rel/info.jsx rename to test/unit/xss/anchor-target-rel/info.jsx index 6a685a86..085b9f07 100644 --- a/test/mocha/xss/anchor-target-rel/info.jsx +++ b/test/unit/xss/anchor-target-rel/info.jsx @@ -1,6 +1,4 @@ -/* eslint-env mocha */ import React from "react" -import expect from "expect" import { render } from "enzyme" import { fromJS } from "immutable" import Info, { InfoUrl } from "components/info" @@ -35,8 +33,8 @@ describe(" Anchor Target Safety", function(){ expect(anchor.html()).toEqual("http://google.com/") expect(anchor.attr("target")).toEqual("_blank") - expect(anchor.attr("rel") || "").toInclude("noopener") - expect(anchor.attr("rel") || "").toInclude("noreferrer") + expect(anchor.attr("rel") || "").toMatch("noopener") + expect(anchor.attr("rel") || "").toMatch("noreferrer") }) it("renders Contact links with safe `rel` attributes", function () { @@ -54,8 +52,8 @@ describe(" Anchor Target Safety", function(){ expect(anchor.attr("href")).toEqual("http://google.com/") expect(anchor.attr("target")).toEqual("_blank") - expect(anchor.attr("rel") || "").toInclude("noopener") - expect(anchor.attr("rel") || "").toInclude("noreferrer") + expect(anchor.attr("rel") || "").toMatch("noopener") + expect(anchor.attr("rel") || "").toMatch("noreferrer") }) it("renders License links with safe `rel` attributes", function () { @@ -72,8 +70,8 @@ describe(" Anchor Target Safety", function(){ expect(anchor.attr("href")).toEqual("http://mit.edu/") expect(anchor.attr("target")).toEqual("_blank") - expect(anchor.attr("rel") || "").toInclude("noopener") - expect(anchor.attr("rel") || "").toInclude("noreferrer") + expect(anchor.attr("rel") || "").toMatch("noopener") + expect(anchor.attr("rel") || "").toMatch("noreferrer") }) it("renders termsOfService links with safe `rel` attributes", function () { @@ -88,8 +86,8 @@ describe(" Anchor Target Safety", function(){ expect(anchor.attr("href")).toEqual("http://smartbear.com/") expect(anchor.attr("target")).toEqual("_blank") - expect(anchor.attr("rel") || "").toInclude("noopener") - expect(anchor.attr("rel") || "").toInclude("noreferrer") + expect(anchor.attr("rel") || "").toMatch("noopener") + expect(anchor.attr("rel") || "").toMatch("noreferrer") }) it("renders definition URL links with safe `rel` attributes", function () { @@ -102,7 +100,7 @@ describe(" Anchor Target Safety", function(){ expect(anchor.attr("href")).toEqual("http://petstore.swagger.io/v2/petstore.json") expect(anchor.attr("target")).toEqual("_blank") - expect(anchor.attr("rel") || "").toInclude("noopener") - expect(anchor.attr("rel") || "").toInclude("noreferrer") + expect(anchor.attr("rel") || "").toMatch("noopener") + expect(anchor.attr("rel") || "").toMatch("noreferrer") }) }) diff --git a/test/mocha/xss/anchor-target-rel/link.jsx b/test/unit/xss/anchor-target-rel/link.jsx similarity index 75% rename from test/mocha/xss/anchor-target-rel/link.jsx rename to test/unit/xss/anchor-target-rel/link.jsx index bc082f20..8f8a7518 100644 --- a/test/mocha/xss/anchor-target-rel/link.jsx +++ b/test/unit/xss/anchor-target-rel/link.jsx @@ -1,8 +1,5 @@ -/* eslint-env mocha */ import React from "react" -import expect from "expect" import { render } from "enzyme" -import { fromJS } from "immutable" import { Link } from "components/layout-utils" describe(" Anchor Target Safety", function () { @@ -23,8 +20,8 @@ describe(" Anchor Target Safety", function () { const anchor = wrapper.find("a") expect(anchor.attr("href")).toEqual("http://google.com/") - expect(anchor.attr("rel") || "").toInclude("noopener") - expect(anchor.attr("rel") || "").toInclude("noreferrer") + expect(anchor.attr("rel") || "").toMatch("noopener") + expect(anchor.attr("rel") || "").toMatch("noreferrer") }) it("enforces `noreferrer` and `noopener` on target=_blank links", function () { @@ -38,7 +35,7 @@ describe(" Anchor Target Safety", function () { expect(anchor.attr("href")).toEqual("http://google.com/") expect(anchor.attr("target")).toEqual("_blank") - expect(anchor.attr("rel") || "").toInclude("noopener") - expect(anchor.attr("rel") || "").toInclude("noreferrer") + expect(anchor.attr("rel") || "").toMatch("noopener") + expect(anchor.attr("rel") || "").toMatch("noreferrer") }) }) diff --git a/test/mocha/xss/anchor-target-rel/markdown.jsx b/test/unit/xss/anchor-target-rel/markdown.jsx similarity index 76% rename from test/mocha/xss/anchor-target-rel/markdown.jsx rename to test/unit/xss/anchor-target-rel/markdown.jsx index aade97d3..a247a142 100644 --- a/test/mocha/xss/anchor-target-rel/markdown.jsx +++ b/test/unit/xss/anchor-target-rel/markdown.jsx @@ -1,6 +1,4 @@ -/* eslint-env mocha */ import React from "react" -import expect from "expect" import { render } from "enzyme" import Markdown from "components/providers/markdown" import { Markdown as OAS3Markdown } from "corePlugins/oas3/wrap-components/markdown.jsx" @@ -15,8 +13,8 @@ describe("Markdown Link Anchor Safety", function () { expect(anchor.attr("href")).toEqual("http://google.com/") expect(anchor.attr("target")).toEqual("_blank") - expect(anchor.attr("rel") || "").toInclude("noopener") - expect(anchor.attr("rel") || "").toInclude("noreferrer") + expect(anchor.attr("rel") || "").toMatch("noopener") + expect(anchor.attr("rel") || "").toMatch("noreferrer") }) it("sanitizes raw HTML links", function () { @@ -26,8 +24,8 @@ describe("Markdown Link Anchor Safety", function () { const anchor = wrapper.find("a") expect(anchor.attr("href")).toEqual("http://google.com/") - expect(anchor.attr("rel") || "").toInclude("noopener") - expect(anchor.attr("rel") || "").toInclude("noreferrer") + expect(anchor.attr("rel") || "").toMatch("noopener") + expect(anchor.attr("rel") || "").toMatch("noreferrer") }) }) @@ -40,8 +38,8 @@ describe("Markdown Link Anchor Safety", function () { expect(anchor.attr("href")).toEqual("http://google.com/") expect(anchor.attr("target")).toEqual("_blank") - expect(anchor.attr("rel") || "").toInclude("noopener") - expect(anchor.attr("rel") || "").toInclude("noreferrer") + expect(anchor.attr("rel") || "").toMatch("noopener") + expect(anchor.attr("rel") || "").toMatch("noreferrer") }) it("sanitizes raw HTML links", function () { @@ -51,8 +49,8 @@ describe("Markdown Link Anchor Safety", function () { const anchor = wrapper.find("a") expect(anchor.attr("href")).toEqual("http://google.com/") - expect(anchor.attr("rel") || "").toInclude("noopener") - expect(anchor.attr("rel") || "").toInclude("noreferrer") + expect(anchor.attr("rel") || "").toMatch("noopener") + expect(anchor.attr("rel") || "").toMatch("noreferrer") }) }) }) diff --git a/test/unit/xss/anchor-target-rel/online-validator-badge.jsx b/test/unit/xss/anchor-target-rel/online-validator-badge.jsx new file mode 100644 index 00000000..ecce983a --- /dev/null +++ b/test/unit/xss/anchor-target-rel/online-validator-badge.jsx @@ -0,0 +1,29 @@ +import React from "react" +import { mount } from "enzyme" +import OnlineValidatorBadge from "components/online-validator-badge" + +describe(" Anchor Target Safety", function () { + it("should render a validator link with safe `rel` attributes", function () { + // When + const props = { + getConfigs: () => ({}), + getComponent: () => null, + specSelectors: { + url: () => "swagger.json" + } + } + const wrapper = mount( + + ) + + const anchor = wrapper.find("a") + + // Then + expect(anchor.props().href).toEqual( + "https://validator.swagger.io/validator/debug?url=swagger.json" + ) + expect(anchor.props().target).toEqual("_blank") + expect(anchor.props().rel || "").toInclude("noopener") + expect(anchor.props().rel || "").toInclude("noreferrer") + }) +}) diff --git a/test/mocha/xss/info-sanitization.jsx b/test/unit/xss/info-sanitization.jsx similarity index 95% rename from test/mocha/xss/info-sanitization.jsx rename to test/unit/xss/info-sanitization.jsx index f73b770a..1ce595e0 100644 --- a/test/mocha/xss/info-sanitization.jsx +++ b/test/unit/xss/info-sanitization.jsx @@ -1,6 +1,4 @@ -/* eslint-env mocha */ import React from "react" -import expect from "expect" import { render } from "enzyme" import { fromJS } from "immutable" import Info from "components/info" diff --git a/test/mocha/xss/markdown-script-sanitization.jsx b/test/unit/xss/markdown-script-sanitization.jsx similarity index 96% rename from test/mocha/xss/markdown-script-sanitization.jsx rename to test/unit/xss/markdown-script-sanitization.jsx index 4c433dc3..72a96414 100644 --- a/test/mocha/xss/markdown-script-sanitization.jsx +++ b/test/unit/xss/markdown-script-sanitization.jsx @@ -1,6 +1,4 @@ -/* eslint-env mocha */ import React from "react" -import expect from "expect" import { render } from "enzyme" import Markdown from "components/providers/markdown" import { Markdown as OAS3Markdown } from "corePlugins/oas3/wrap-components/markdown.jsx"