From 4efc891dfe9545d06c4db32316eb6633caa0bbca Mon Sep 17 00:00:00 2001 From: "javier.brea" Date: Sun, 14 Feb 2021 20:29:00 +0100 Subject: [PATCH] test(e2e): Add v2 e2e tests --- .github/workflows/build.yml | 6 +- .gitignore | 2 + jest.e2e.config.js | 2 +- package-lock.json | 86 +++++++ package.json | 9 +- sonar-project.properties | 2 +- test/e2e/main/v1/cli-no-behaviors.spec.js | 9 - test/e2e/main/v1/interactive-cli.spec.js | 4 - test/e2e/main/v2/arguments.spec.js | 101 ++++++++ test/e2e/main/v2/disabled.spec.js | 75 ++++++ test/e2e/main/v2/files-watch.spec.js | 233 ++++++++++++++++++ .../v2/fixtures/files-error-mock/db/users.js | 24 ++ .../v2/fixtures/files-error-mock/mocks.js | 11 + .../fixtures/files-error-mock/routes/user.js | 51 ++++ .../fixtures/files-error-mock/routes/users.js | 37 +++ test/e2e/main/v2/fixtures/no-mocks/.gitkeep | 0 test/e2e/main/v2/fixtures/starter | 24 ++ .../web-tutorial-modified/db/users.js | 24 ++ .../fixtures/web-tutorial-modified/mocks.js | 31 +++ .../web-tutorial-modified/routes/user.js | 51 ++++ .../web-tutorial-modified/routes/users.js | 61 +++++ .../main/v2/fixtures/web-tutorial/db/users.js | 24 ++ .../main/v2/fixtures/web-tutorial/mocks.js | 26 ++ .../v2/fixtures/web-tutorial/routes/user.js | 51 ++++ .../v2/fixtures/web-tutorial/routes/users.js | 37 +++ test/e2e/main/v2/interactive-cli.spec.js | 147 +++++++++++ test/e2e/main/v2/no-mocks.spec.js | 44 ++++ test/e2e/main/v2/support/helpers.js | 114 +++++++++ test/e2e/main/v2/web-tutorial.spec.js | 179 ++++++++++++++ 29 files changed, 1444 insertions(+), 21 deletions(-) create mode 100644 test/e2e/main/v2/arguments.spec.js create mode 100644 test/e2e/main/v2/disabled.spec.js create mode 100644 test/e2e/main/v2/files-watch.spec.js create mode 100644 test/e2e/main/v2/fixtures/files-error-mock/db/users.js create mode 100644 test/e2e/main/v2/fixtures/files-error-mock/mocks.js create mode 100644 test/e2e/main/v2/fixtures/files-error-mock/routes/user.js create mode 100644 test/e2e/main/v2/fixtures/files-error-mock/routes/users.js create mode 100644 test/e2e/main/v2/fixtures/no-mocks/.gitkeep create mode 100755 test/e2e/main/v2/fixtures/starter create mode 100644 test/e2e/main/v2/fixtures/web-tutorial-modified/db/users.js create mode 100644 test/e2e/main/v2/fixtures/web-tutorial-modified/mocks.js create mode 100644 test/e2e/main/v2/fixtures/web-tutorial-modified/routes/user.js create mode 100644 test/e2e/main/v2/fixtures/web-tutorial-modified/routes/users.js create mode 100644 test/e2e/main/v2/fixtures/web-tutorial/db/users.js create mode 100644 test/e2e/main/v2/fixtures/web-tutorial/mocks.js create mode 100644 test/e2e/main/v2/fixtures/web-tutorial/routes/user.js create mode 100644 test/e2e/main/v2/fixtures/web-tutorial/routes/users.js create mode 100644 test/e2e/main/v2/interactive-cli.spec.js create mode 100644 test/e2e/main/v2/no-mocks.spec.js create mode 100644 test/e2e/main/v2/support/helpers.js create mode 100644 test/e2e/main/v2/web-tutorial.spec.js diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index bdcabc8..fe6f5d0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -41,9 +41,9 @@ jobs: run: npm run lint - name: Test unit run: npm run test:unit - #- name: Test E2E - #run: npm run test:e2e - #id: test-e2e + - name: Test E2E + run: npm run test:e2e + id: test-e2e - name: Upload test results uses: actions/upload-artifact@v2 with: diff --git a/.gitignore b/.gitignore index 51b8af7..13738df 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,8 @@ /mocks /test/e2e/main/v1/fixtures/files-watch /test/e2e/main/v1/fixtures/mocks.config.js +/test/e2e/main/v2/fixtures/temp +/test/e2e/main/v2/fixtures/mocks.config.js # misc .DS_Store diff --git a/jest.e2e.config.js b/jest.e2e.config.js index 35aae60..e029628 100644 --- a/jest.e2e.config.js +++ b/jest.e2e.config.js @@ -6,7 +6,7 @@ module.exports = { clearMocks: true, testMatch: ["/test/e2e/**/*.spec.js"], - // testMatch: ["/test/e2e/main/v1/web-tutorial-files-watch.spec.js"], + // testMatch: ["/test/e2e/main/v2/files-watch.spec.js"], // Indicates whether the coverage information should be collected while executing the test collectCoverage: false, diff --git a/package-lock.json b/package-lock.json index 1042caf..c8920d3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -547,6 +547,15 @@ "integrity": "sha512-CAEbWH7OIur6jEOzaai83jq3FmKmv4PmX1JYfs9IrYcGEVI/lyL1EXJGCj7eFVJ0bg5QR8LMxBlEtA+xKiLpFw==", "dev": true }, + "@hapi/topo": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.0.0.tgz", + "integrity": "sha512-tFJlT47db0kMqVm3H4nQYgn6Pwg10GTZHb1pwmSiv1K4ks6drQOtfEF5ZnPjkvC+y4/bUPHK+bc87QvLcL+WMw==", + "dev": true, + "requires": { + "@hapi/hoek": "^9.0.0" + } + }, "@istanbuljs/load-nyc-config": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", @@ -827,6 +836,27 @@ } } }, + "@sideway/address": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.1.tgz", + "integrity": "sha512-+I5aaQr3m0OAmMr7RQ3fR9zx55sejEYR2BFJaxL+zT3VM2611X0SHvPWIbAUBZVTn/YzYKbV8gJ2oT/QELknfQ==", + "dev": true, + "requires": { + "@hapi/hoek": "^9.0.0" + } + }, + "@sideway/formula": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.0.tgz", + "integrity": "sha512-vHe7wZ4NOXVfkoRb8T5otiENVlT7a3IAiw7H5M2+GO+9CDgcVUUsX1zalAztCmwyOr2RUTGJdgB+ZvSVqmdHmg==", + "dev": true + }, + "@sideway/pinpoint": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz", + "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==", + "dev": true + }, "@sinonjs/commons": { "version": "1.7.2", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.7.2.tgz", @@ -1210,6 +1240,15 @@ "integrity": "sha512-wMHVg2EOHaMRxbzgFJ9gtjOOCrI80OHLG14rxi28XwOW8ux6IiEbRCGGGqCtdAIg4FQCbW20k9RsT4y3gJlFug==", "dev": true }, + "axios": { + "version": "0.21.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz", + "integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==", + "dev": true, + "requires": { + "follow-redirects": "^1.10.0" + } + }, "babel-jest": { "version": "26.6.3", "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-26.6.3.tgz", @@ -1846,6 +1885,15 @@ "yaml": "^1.10.0" } }, + "cross-fetch": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.0.6.tgz", + "integrity": "sha512-KBPUbqgFjzWlVcURG+Svp9TlhA5uliYtiNx/0r8nv0pdypeQCRJ9IaSIc3q/x3q8t3F75cHuwxVql1HFGHCNJQ==", + "dev": true, + "requires": { + "node-fetch": "2.6.1" + } + }, "cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -2855,6 +2903,12 @@ "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==", "dev": true }, + "follow-redirects": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.2.tgz", + "integrity": "sha512-6mPTgLxYm3r6Bkkg0vNM0HTjfGrOEtsfbhagQvbxDEsEkpNhw582upBaoRZylzen6krEmxXJgt9Ju6HiI4O7BA==", + "dev": true + }, "for-in": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", @@ -4129,6 +4183,19 @@ } } }, + "joi": { + "version": "17.4.0", + "resolved": "https://registry.npmjs.org/joi/-/joi-17.4.0.tgz", + "integrity": "sha512-F4WiW2xaV6wc1jxete70Rw4V/VuMd6IN+a5ilZsxG4uYtUXWu2kq9W5P2dz30e7Gmw8RCbY/u/uk+dMPma9tAg==", + "dev": true, + "requires": { + "@hapi/hoek": "^9.0.0", + "@hapi/topo": "^5.0.0", + "@sideway/address": "^4.1.0", + "@sideway/formula": "^3.0.0", + "@sideway/pinpoint": "^2.0.0" + } + }, "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -4750,6 +4817,12 @@ "lodash.toarray": "^4.4.0" } }, + "node-fetch": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", + "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==", + "dev": true + }, "node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", @@ -6780,6 +6853,19 @@ "xml-name-validator": "^3.0.0" } }, + "wait-on": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/wait-on/-/wait-on-5.2.1.tgz", + "integrity": "sha512-H2F986kNWMU9hKlI9l/ppO6tN8ZSJd35yBljMLa1/vjzWP++Qh6aXyt77/u7ySJFZQqBtQxnvm/xgG48AObXcw==", + "dev": true, + "requires": { + "axios": "^0.21.1", + "joi": "^17.3.0", + "lodash": "^4.17.20", + "minimist": "^1.2.5", + "rxjs": "^6.6.3" + } + }, "walker": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz", diff --git a/package.json b/package.json index 575e547..8bc7a99 100644 --- a/package.json +++ b/package.json @@ -1,14 +1,15 @@ { "name": "@mocks-server/plugin-inquirer-cli", "version": "1.4.1", - "description": "Plugin for Mocks server. Displays an interactive CLI", + "description": "Mocks server plugin providing an interactive CLI", "keywords": [ "mocks-server-plugin", "interactive", "cli", "inquirer", + "settings", "administration", - "testing", + "options", "development" ], "author": "Javier Brea", @@ -42,6 +43,7 @@ }, "devDependencies": { "@mocks-server/core": "2.0.0-beta.1", + "cross-fetch": "3.0.6", "cross-spawn": "7.0.3", "eslint": "7.15.0", "eslint-plugin-no-only-tests": "2.4.0", @@ -57,7 +59,8 @@ "request-promise": "4.2.6", "sinon": "9.2.2", "strip-ansi": "6.0.0", - "tree-kill": "1.2.2" + "tree-kill": "1.2.2", + "wait-on": "5.2.1" }, "lint-staged": { "src/**/*.js": "eslint", diff --git a/sonar-project.properties b/sonar-project.properties index f860a1c..207da59 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -4,7 +4,7 @@ sonar.projectVersion=1.4.1 sonar.javascript.file.suffixes=.js sonar.sourceEncoding=UTF-8 -sonar.exclusions=node_modules/**,*.config.js +sonar.exclusions=node_modules/**,*.config.js,test/**/fixtures/** sonar.test.exclusions=test/**/* sonar.coverage.exclusions=test/**/* sonar.cpd.exclusions=test/** diff --git a/test/e2e/main/v1/cli-no-behaviors.spec.js b/test/e2e/main/v1/cli-no-behaviors.spec.js index 8eb21e0..db46f4d 100644 --- a/test/e2e/main/v1/cli-no-behaviors.spec.js +++ b/test/e2e/main/v1/cli-no-behaviors.spec.js @@ -20,15 +20,6 @@ describe("with no behaviors", () => { await cli.kill(); }); - it.skip("should display alerts", async () => { - cli = new CliRunner([BINARY_PATH, "--behavior=foo", "--pathLegacy=no-behaviors"], { - cwd: cwdPath, - }); - await wait(); - expect(cli.currentScreen).toEqual(expect.stringContaining("ALERTS")); - expect(cli.currentScreen).toEqual(expect.stringContaining("Warning: No behaviors found")); - }); - it("should print a dash as current behavior", async () => { cli = new CliRunner([BINARY_PATH, "--pathLegacy=no-behaviors"], { cwd: cwdPath, diff --git a/test/e2e/main/v1/interactive-cli.spec.js b/test/e2e/main/v1/interactive-cli.spec.js index 8ad6f97..862bf90 100644 --- a/test/e2e/main/v1/interactive-cli.spec.js +++ b/test/e2e/main/v1/interactive-cli.spec.js @@ -72,10 +72,6 @@ describe("interactive CLI", () => { expect(newScreen).toEqual(expect.stringContaining("Current behavior: dynamic")); }); - it.skip("should have removed alert", async () => { - expect(cli.currentScreen).toEqual(expect.not.stringContaining("ALERTS")); - }); - it("should serve users collection mock under the /api/users path", async () => { const users = await request("/api/users"); expect(users).toEqual([ diff --git a/test/e2e/main/v2/arguments.spec.js b/test/e2e/main/v2/arguments.spec.js new file mode 100644 index 0000000..3b5de40 --- /dev/null +++ b/test/e2e/main/v2/arguments.spec.js @@ -0,0 +1,101 @@ +/* +Copyright 2019 Javier Brea + +Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. +*/ + +const { mocksRunner, fetch, waitForServerAndCli, TimeCounter } = require("./support/helpers"); + +describe("command line arguments", () => { + let mocks; + + afterEach(async () => { + await mocks.kill(); + }); + + describe("path option", () => { + it("should set mocks folder", async () => { + expect.assertions(2); + mocks = mocksRunner(["--path=web-tutorial"]); + await waitForServerAndCli(); + const users = await fetch("/api/users"); + expect(users.body).toEqual([ + { id: 1, name: "John Doe" }, + { id: 2, name: "Jane Doe" }, + ]); + expect(mocks.currentScreen).toEqual(expect.stringContaining("Mocks: 3")); + }); + }); + + describe("mock option", () => { + describe("when not provided", () => { + it("should set as current mock the first one found", async () => { + expect.assertions(2); + mocks = mocksRunner(["--path=web-tutorial"]); + await waitForServerAndCli(); + const users = await fetch("/api/users/2"); + expect(users.body).toEqual({ id: 1, name: "John Doe" }); + expect(mocks.currentScreen).toEqual(expect.stringContaining("Current mock: base")); + }); + }); + + describe("when provided and exists", () => { + it("should set current mock", async () => { + expect.assertions(2); + mocks = mocksRunner(["--path=web-tutorial", "--mock=user-2"]); + await waitForServerAndCli(); + const users = await fetch("/api/users/2"); + expect(users.body).toEqual({ id: 2, name: "Jane Doe" }); + expect(mocks.currentScreen).toEqual(expect.stringContaining("Current mock: user-2")); + }); + }); + + describe("when provided and does not exist", () => { + it("should display an alert", async () => { + mocks = mocksRunner(["--path=web-tutorial", "--mock=foo"]); + await waitForServerAndCli(); + expect(mocks.currentScreen).toEqual(expect.stringContaining("ALERTS")); + expect(mocks.currentScreen).toEqual(expect.stringContaining('Mock "foo" was not found')); + }); + + it("should set as current behavior the first one found", async () => { + expect.assertions(3); + mocks = mocksRunner(["--path=web-tutorial", "--mock=foo"]); + await waitForServerAndCli(); + const users = await fetch("/api/users/2"); + expect(users.body).toEqual({ id: 1, name: "John Doe" }); + expect(mocks.currentScreen).toEqual(expect.stringContaining("Using the first one found")); + expect(mocks.currentScreen).toEqual(expect.stringContaining("Current mock: base")); + }); + }); + }); + + describe("delay option", () => { + it("should set delay", async () => { + expect.assertions(3); + mocks = mocksRunner(["--path=web-tutorial", "--delay=2000"]); + await waitForServerAndCli(); + const timeCounter = new TimeCounter(); + const users = await fetch("/api/users"); + timeCounter.stop(); + expect(users.body).toEqual([ + { id: 1, name: "John Doe" }, + { id: 2, name: "Jane Doe" }, + ]); + expect(mocks.currentScreen).toEqual(expect.stringContaining("Delay: 2000")); + expect(timeCounter.total).toBeGreaterThan(1999); + }); + }); + + describe("log option", () => { + it("should set log level", async () => { + mocks = mocksRunner(["--path=web-tutorial", "--log=debug"]); + await waitForServerAndCli(); + expect(mocks.currentScreen).toEqual(expect.stringContaining("Log level: debug")); + }); + }); +}); diff --git a/test/e2e/main/v2/disabled.spec.js b/test/e2e/main/v2/disabled.spec.js new file mode 100644 index 0000000..fa09ec1 --- /dev/null +++ b/test/e2e/main/v2/disabled.spec.js @@ -0,0 +1,75 @@ +/* +Copyright 2019 Javier Brea + +Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. +*/ + +const { mocksRunner, fetch, waitForServer, wait, TimeCounter } = require("./support/helpers"); + +describe("command line arguments with cli disabled", () => { + let mocks; + + afterEach(async () => { + await mocks.kill(); + }); + + describe("interactive cli", () => { + it("should not be started", async () => { + mocks = mocksRunner(["--path=web-tutorial", "--no-cli"]); + await wait(3000); + expect(mocks.logs).toEqual(expect.not.stringContaining("Select action")); + }); + }); + + describe("path option", () => { + it("should set mocks folder", async () => { + mocks = mocksRunner(["--path=web-tutorial", "--no-cli"]); + await wait(); + const users = await fetch("/api/users"); + expect(users.body).toEqual([ + { id: 1, name: "John Doe" }, + { id: 2, name: "Jane Doe" }, + ]); + }); + }); + + describe("behavior option", () => { + describe("when not provided", () => { + it("should set as current behavior the first one found", async () => { + mocks = mocksRunner(["--path=web-tutorial", "--no-cli"]); + await wait(); + const users = await fetch("/api/users/2"); + expect(users.body).toEqual({ id: 1, name: "John Doe" }); + }); + }); + + describe("when provided and exists", () => { + it("should set current behavior", async () => { + mocks = mocksRunner(["--path=web-tutorial", "--no-cli", "--mock=user-2"]); + await wait(); + const users = await fetch("/api/users/2"); + expect(users.body).toEqual({ id: 2, name: "Jane Doe" }); + }); + }); + }); + + describe("delay option", () => { + it("should set delay", async () => { + expect.assertions(2); + mocks = mocksRunner(["--path=web-tutorial", "--no-cli", "--delay=2000"]); + await waitForServer(); + const timeCounter = new TimeCounter(); + const users = await fetch("/api/users"); + timeCounter.stop(); + expect(users.body).toEqual([ + { id: 1, name: "John Doe" }, + { id: 2, name: "Jane Doe" }, + ]); + expect(timeCounter.total).toBeGreaterThan(1999); + }); + }); +}); diff --git a/test/e2e/main/v2/files-watch.spec.js b/test/e2e/main/v2/files-watch.spec.js new file mode 100644 index 0000000..d24202f --- /dev/null +++ b/test/e2e/main/v2/files-watch.spec.js @@ -0,0 +1,233 @@ +/* +Copyright 2019 Javier Brea + +Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. +*/ + +const fsExtra = require("fs-extra"); +const { + mocksRunner, + fetch, + waitForServerAndCli, + wait, + fixturesFolder, +} = require("./support/helpers"); + +describe("files watcher", () => { + jest.setTimeout(15000); + let mocks; + + beforeAll(async () => { + fsExtra.removeSync(fixturesFolder("temp")); + fsExtra.copySync(fixturesFolder("web-tutorial"), fixturesFolder("temp")); + mocks = mocksRunner(["--path=temp"]); + await waitForServerAndCli(); + }); + + afterAll(async () => { + await mocks.kill(); + }); + + describe("When started", () => { + it("should display available mocks in CLI", async () => { + expect(mocks.currentScreen).toEqual(expect.stringContaining("Mocks: 3")); + }); + + it("should display current mock in CLI", async () => { + expect(mocks.logs).toEqual(expect.stringContaining("Current mock: base")); + }); + + it("should serve users collection mock under the /api/users path", async () => { + const users = await fetch("/api/users"); + expect(users.body).toEqual([ + { id: 1, name: "John Doe" }, + { id: 2, name: "Jane Doe" }, + ]); + }); + + it("should serve user 1 under the /api/users/1 path", async () => { + const users = await fetch("/api/users/1"); + expect(users.body).toEqual({ id: 1, name: "John Doe" }); + }); + + it("should serve user 1 under the /api/users/2 path", async () => { + const users = await fetch("/api/users/2"); + expect(users.body).toEqual({ id: 1, name: "John Doe" }); + }); + }); + + describe("When files are modified", () => { + beforeAll(async () => { + fsExtra.copySync(fixturesFolder("web-tutorial-modified"), fixturesFolder("temp")); + await wait(5000); + }); + + describe("without changing current mock", () => { + it("should display available mocks in CLI", async () => { + expect(mocks.currentScreen).toEqual(expect.stringContaining("Mocks: 4")); + }); + + it("should serve users collection mock under the /api/users path", async () => { + const users = await fetch("/api/users"); + expect(users.body).toEqual([ + { id: 1, name: "John Doe modified" }, + { id: 2, name: "Jane Doe modified" }, + ]); + }); + + it("should serve user 1 under the /api/users/1 path", async () => { + const users = await fetch("/api/users/1"); + expect(users.body).toEqual({ id: 1, name: "John Doe modified" }); + }); + + it("should serve user 1 under the /api/users/2 path", async () => { + const users = await fetch("/api/users/2"); + expect(users.body).toEqual({ id: 1, name: "John Doe modified" }); + }); + }); + + describe('When changing current mock to "user-2"', () => { + beforeAll(async () => { + await mocks.pressEnter(); + await mocks.cursorDown(); + await mocks.pressEnter(); + }); + + it("should display current mock in CLI", async () => { + await wait(500); + expect(mocks.logs).toEqual(expect.stringContaining("Current mock: user-2")); + }); + + it("should serve users collection mock under the /api/users path", async () => { + const users = await fetch("/api/users"); + expect(users.body).toEqual([ + { id: 1, name: "John Doe modified" }, + { id: 2, name: "Jane Doe modified" }, + ]); + }); + + it("should serve user 2 under the /api/users/1 path", async () => { + const users = await fetch("/api/users/1"); + expect(users.body).toEqual({ id: 2, name: "Jane Doe modified" }); + }); + + it("should serve user 2 under the /api/users/2 path", async () => { + const users = await fetch("/api/users/2"); + expect(users.body).toEqual({ id: 2, name: "Jane Doe modified" }); + }); + }); + + describe('When changing current mock to "user-real"', () => { + beforeAll(async () => { + await mocks.pressEnter(); + await mocks.cursorDown(2); + await mocks.pressEnter(); + }); + + it("should display current behavior in CLI", async () => { + await wait(500); + expect(mocks.logs).toEqual(expect.stringContaining("Current mock: user-real")); + }); + + it("should serve users collection mock under the /api/users path", async () => { + const users = await fetch("/api/users"); + expect(users.body).toEqual([ + { id: 1, name: "John Doe modified" }, + { id: 2, name: "Jane Doe modified" }, + ]); + }); + + it("should serve user 1 under the /api/users/1 path", async () => { + const users = await fetch("/api/users/1"); + expect(users.body).toEqual({ id: 1, name: "John Doe modified" }); + }); + + it("should serve user 2 under the /api/users/2 path", async () => { + const users = await fetch("/api/users/2"); + expect(users.body).toEqual({ id: 2, name: "Jane Doe modified" }); + }); + }); + }); + + describe("When files are modified and contain an error", () => { + beforeAll(async () => { + fsExtra.copySync(fixturesFolder("files-error-mock"), fixturesFolder("temp")); + await wait(2000); + }); + + it("should display an error", async () => { + expect(mocks.currentScreen).toEqual( + expect.stringContaining("Error: Error loading mocks from file") + ); + expect(mocks.currentScreen).toEqual( + expect.stringContaining("main/v2/fixtures/temp/mocks.js: foo is not defined") + ); + expect(mocks.currentScreen).toEqual( + expect.stringContaining("main/v2/fixtures/temp/mocks.js:11:18") + ); + }); + + it("should have no mocks available", async () => { + expect(mocks.currentScreen).toEqual(expect.stringContaining("Mocks: 0")); + }); + + it("should not serve users collection mock under the /api/users path", async () => { + const users = await fetch("/api/users"); + expect(users.status).toEqual(404); + }); + + it("should remove alerts when error is fixed", async () => { + fsExtra.copySync(fixturesFolder("web-tutorial-modified"), fixturesFolder("temp")); + await wait(2000); + expect(mocks.currentScreen).toEqual(expect.not.stringContaining("ALERTS")); + }); + }); + + describe("When files are modified while displaying logs", () => { + it("should display logs", async () => { + await mocks.cursorDown(7); + await mocks.pressEnter(); + await wait(1000); + expect(mocks.currentScreen).toEqual(expect.stringContaining("Displaying logs")); + }); + + it("should not display alerts when files are modified and contain an error", async () => { + expect.assertions(2); + fsExtra.copySync(fixturesFolder("files-error-mock"), fixturesFolder("temp")); + await wait(3000); + expect(mocks.currentScreen).toEqual(expect.stringContaining("Displaying logs")); + expect(mocks.currentScreen).toEqual(expect.not.stringContaining("ALERTS")); + }); + + it("should have displayed error in logs", async () => { + expect.assertions(2); + expect(mocks.currentScreen).toEqual(expect.not.stringContaining("ALERTS")); + expect(mocks.currentScreen).toEqual( + expect.stringContaining("Error loading mocks from file") + ); + }); + + it("should display alerts when exit logs mode", async () => { + expect.assertions(3); + await mocks.pressEnter(); + await wait(2000); + expect(mocks.currentScreen).toEqual(expect.not.stringContaining("Displaying logs")); + expect(mocks.currentScreen).toEqual( + expect.stringContaining("Error: Error loading mocks from file") + ); + expect(mocks.currentScreen).toEqual(expect.stringContaining("ALERTS")); + }); + + it("should remove alerts when error is fixed", async () => { + expect.assertions(2); + fsExtra.copySync(fixturesFolder("web-tutorial-modified"), fixturesFolder("temp")); + await wait(2000); + expect(mocks.currentScreen).toEqual(expect.not.stringContaining("ALERTS")); + expect(mocks.currentScreen).toEqual(expect.stringContaining("CURRENT SETTINGS")); + }); + }); +}); diff --git a/test/e2e/main/v2/fixtures/files-error-mock/db/users.js b/test/e2e/main/v2/fixtures/files-error-mock/db/users.js new file mode 100644 index 0000000..f05a501 --- /dev/null +++ b/test/e2e/main/v2/fixtures/files-error-mock/db/users.js @@ -0,0 +1,24 @@ +/* +Copyright 2021 Javier Brea + +Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. +*/ + +const USERS = [ + { + id: 1, + name: "John Doe", + }, + { + id: 2, + name: "Jane Doe", + }, +]; + +module.exports = { + USERS, +}; diff --git a/test/e2e/main/v2/fixtures/files-error-mock/mocks.js b/test/e2e/main/v2/fixtures/files-error-mock/mocks.js new file mode 100644 index 0000000..fe754cc --- /dev/null +++ b/test/e2e/main/v2/fixtures/files-error-mock/mocks.js @@ -0,0 +1,11 @@ +/* +Copyright 2021 Javier Brea + +Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. +*/ +/* eslint-disable */ +module.exports = foo; diff --git a/test/e2e/main/v2/fixtures/files-error-mock/routes/user.js b/test/e2e/main/v2/fixtures/files-error-mock/routes/user.js new file mode 100644 index 0000000..ac18756 --- /dev/null +++ b/test/e2e/main/v2/fixtures/files-error-mock/routes/user.js @@ -0,0 +1,51 @@ +/* +Copyright 2021 Javier Brea + +Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. +*/ + +const { USERS } = require("../db/users"); + +module.exports = [ + { + id: "get-user", + url: "/api/users/:id", + method: "GET", + variants: [ + { + id: "1", + response: { + status: 200, + body: USERS[0], + }, + }, + { + id: "2", + response: { + status: 200, + body: USERS[1], + }, + }, + { + id: "real", + response: (req, res) => { + const userId = req.params.id; + const user = USERS.find((userData) => userData.id === Number(userId)); + if (user) { + res.status(200); + res.send(user); + } else { + res.status(404); + res.send({ + message: "User not found", + }); + } + }, + }, + ], + }, +]; diff --git a/test/e2e/main/v2/fixtures/files-error-mock/routes/users.js b/test/e2e/main/v2/fixtures/files-error-mock/routes/users.js new file mode 100644 index 0000000..6c1d2ae --- /dev/null +++ b/test/e2e/main/v2/fixtures/files-error-mock/routes/users.js @@ -0,0 +1,37 @@ +/* +Copyright 2021 Javier Brea + +Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. +*/ + +const { USERS } = require("../db/users"); + +module.exports = [ + { + id: "get-users", + url: "/api/users", + method: "GET", + variants: [ + { + id: "success", + response: { + status: 200, + body: USERS, + }, + }, + { + id: "error", + response: { + status: 403, + body: { + message: "Bad data", + }, + }, + }, + ], + }, +]; diff --git a/test/e2e/main/v2/fixtures/no-mocks/.gitkeep b/test/e2e/main/v2/fixtures/no-mocks/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/test/e2e/main/v2/fixtures/starter b/test/e2e/main/v2/fixtures/starter new file mode 100755 index 0000000..f57fadd --- /dev/null +++ b/test/e2e/main/v2/fixtures/starter @@ -0,0 +1,24 @@ +#!/usr/bin/env node +"use strict"; + +const { Core } = require("@mocks-server/core"); +const InquirerCli = require("../../../../../index"); + +const handleError = (error) => { + console.error(`Error: ${error.message}`); + process.exitCode = 1; +}; + +const start = () => { + try { + const mocksServer = new Core({ + plugins: [InquirerCli], + }); + + return mocksServer.start().catch(handleError); + } catch (error) { + return handleError(error); + } +}; + +start(); diff --git a/test/e2e/main/v2/fixtures/web-tutorial-modified/db/users.js b/test/e2e/main/v2/fixtures/web-tutorial-modified/db/users.js new file mode 100644 index 0000000..627c6a7 --- /dev/null +++ b/test/e2e/main/v2/fixtures/web-tutorial-modified/db/users.js @@ -0,0 +1,24 @@ +/* +Copyright 2021 Javier Brea + +Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. +*/ + +const USERS = [ + { + id: 1, + name: "John Doe modified", + }, + { + id: 2, + name: "Jane Doe modified", + }, +]; + +module.exports = { + USERS, +}; diff --git a/test/e2e/main/v2/fixtures/web-tutorial-modified/mocks.js b/test/e2e/main/v2/fixtures/web-tutorial-modified/mocks.js new file mode 100644 index 0000000..0141b77 --- /dev/null +++ b/test/e2e/main/v2/fixtures/web-tutorial-modified/mocks.js @@ -0,0 +1,31 @@ +/* +Copyright 2021 Javier Brea + +Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. +*/ + +module.exports = [ + { + id: "base", + routesVariants: ["get-users:success", "get-user:1", "get-users-new:success"], + }, + { + id: "user-2", + from: "base", + routesVariants: ["get-user:2"], + }, + { + id: "user-real", + from: "base", + routesVariants: ["get-user:real"], + }, + { + id: "users-error", + from: "base", + routesVariants: ["get-users:error"], + }, +]; diff --git a/test/e2e/main/v2/fixtures/web-tutorial-modified/routes/user.js b/test/e2e/main/v2/fixtures/web-tutorial-modified/routes/user.js new file mode 100644 index 0000000..ac18756 --- /dev/null +++ b/test/e2e/main/v2/fixtures/web-tutorial-modified/routes/user.js @@ -0,0 +1,51 @@ +/* +Copyright 2021 Javier Brea + +Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. +*/ + +const { USERS } = require("../db/users"); + +module.exports = [ + { + id: "get-user", + url: "/api/users/:id", + method: "GET", + variants: [ + { + id: "1", + response: { + status: 200, + body: USERS[0], + }, + }, + { + id: "2", + response: { + status: 200, + body: USERS[1], + }, + }, + { + id: "real", + response: (req, res) => { + const userId = req.params.id; + const user = USERS.find((userData) => userData.id === Number(userId)); + if (user) { + res.status(200); + res.send(user); + } else { + res.status(404); + res.send({ + message: "User not found", + }); + } + }, + }, + ], + }, +]; diff --git a/test/e2e/main/v2/fixtures/web-tutorial-modified/routes/users.js b/test/e2e/main/v2/fixtures/web-tutorial-modified/routes/users.js new file mode 100644 index 0000000..afedb5f --- /dev/null +++ b/test/e2e/main/v2/fixtures/web-tutorial-modified/routes/users.js @@ -0,0 +1,61 @@ +/* +Copyright 2021 Javier Brea + +Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. +*/ + +const { USERS } = require("../db/users"); + +module.exports = [ + { + id: "get-users", + url: "/api/users", + method: "GET", + variants: [ + { + id: "success", + response: { + headers: { + "x-custom-header": "foo-header", + "x-another-header": "another-header", + }, + status: 200, + body: USERS, + }, + }, + { + id: "error", + response: { + status: 403, + body: { + message: "Bad data", + }, + }, + }, + ], + }, + { + id: "get-users-new", + url: "/api/new-users", + method: "GET", + variants: [ + { + id: "success", + response: { + status: 200, + body: [ + ...USERS, + { + id: 3, + name: "Brand new user", + }, + ], + }, + }, + ], + }, +]; diff --git a/test/e2e/main/v2/fixtures/web-tutorial/db/users.js b/test/e2e/main/v2/fixtures/web-tutorial/db/users.js new file mode 100644 index 0000000..f05a501 --- /dev/null +++ b/test/e2e/main/v2/fixtures/web-tutorial/db/users.js @@ -0,0 +1,24 @@ +/* +Copyright 2021 Javier Brea + +Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. +*/ + +const USERS = [ + { + id: 1, + name: "John Doe", + }, + { + id: 2, + name: "Jane Doe", + }, +]; + +module.exports = { + USERS, +}; diff --git a/test/e2e/main/v2/fixtures/web-tutorial/mocks.js b/test/e2e/main/v2/fixtures/web-tutorial/mocks.js new file mode 100644 index 0000000..82511e6 --- /dev/null +++ b/test/e2e/main/v2/fixtures/web-tutorial/mocks.js @@ -0,0 +1,26 @@ +/* +Copyright 2021 Javier Brea + +Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. +*/ + +module.exports = [ + { + id: "base", + routesVariants: ["get-users:success", "get-user:1"], + }, + { + id: "user-2", + from: "base", + routesVariants: ["get-user:2"], + }, + { + id: "user-real", + from: "base", + routesVariants: ["get-user:real"], + }, +]; diff --git a/test/e2e/main/v2/fixtures/web-tutorial/routes/user.js b/test/e2e/main/v2/fixtures/web-tutorial/routes/user.js new file mode 100644 index 0000000..ac18756 --- /dev/null +++ b/test/e2e/main/v2/fixtures/web-tutorial/routes/user.js @@ -0,0 +1,51 @@ +/* +Copyright 2021 Javier Brea + +Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. +*/ + +const { USERS } = require("../db/users"); + +module.exports = [ + { + id: "get-user", + url: "/api/users/:id", + method: "GET", + variants: [ + { + id: "1", + response: { + status: 200, + body: USERS[0], + }, + }, + { + id: "2", + response: { + status: 200, + body: USERS[1], + }, + }, + { + id: "real", + response: (req, res) => { + const userId = req.params.id; + const user = USERS.find((userData) => userData.id === Number(userId)); + if (user) { + res.status(200); + res.send(user); + } else { + res.status(404); + res.send({ + message: "User not found", + }); + } + }, + }, + ], + }, +]; diff --git a/test/e2e/main/v2/fixtures/web-tutorial/routes/users.js b/test/e2e/main/v2/fixtures/web-tutorial/routes/users.js new file mode 100644 index 0000000..6c1d2ae --- /dev/null +++ b/test/e2e/main/v2/fixtures/web-tutorial/routes/users.js @@ -0,0 +1,37 @@ +/* +Copyright 2021 Javier Brea + +Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. +*/ + +const { USERS } = require("../db/users"); + +module.exports = [ + { + id: "get-users", + url: "/api/users", + method: "GET", + variants: [ + { + id: "success", + response: { + status: 200, + body: USERS, + }, + }, + { + id: "error", + response: { + status: 403, + body: { + message: "Bad data", + }, + }, + }, + ], + }, +]; diff --git a/test/e2e/main/v2/interactive-cli.spec.js b/test/e2e/main/v2/interactive-cli.spec.js new file mode 100644 index 0000000..29ce9d6 --- /dev/null +++ b/test/e2e/main/v2/interactive-cli.spec.js @@ -0,0 +1,147 @@ +/* +Copyright 2019 Javier Brea + +Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. +*/ + +const { + mocksRunner, + fetch, + waitForServerAndCli, + wait, + TimeCounter, +} = require("./support/helpers"); + +describe("interactive CLI", () => { + jest.setTimeout(15000); + let mocks; + + beforeAll(async () => { + mocks = mocksRunner(["--path=web-tutorial", "--mock=foo"]); + await waitForServerAndCli(); + }); + + afterAll(async () => { + await mocks.kill(); + }); + + describe("When started", () => { + it("should display an alert because chosen mock does not exist", async () => { + expect(mocks.currentScreen).toEqual(expect.stringContaining('Mock "foo" was not found.')); + expect(mocks.currentScreen).toEqual(expect.stringContaining("ALERTS")); + }); + + it("should have loaded first mock", async () => { + expect(mocks.currentScreen).toEqual(expect.stringContaining("Current mock: base")); + }); + + it("should have 3 mocks available", async () => { + expect(mocks.currentScreen).toEqual(expect.stringContaining("Mocks: 3")); + }); + + it("should serve users collection mock under the /api/users path", async () => { + const users = await fetch("/api/users"); + expect(users.body).toEqual([ + { id: 1, name: "John Doe" }, + { id: 2, name: "Jane Doe" }, + ]); + }); + + it("should serve user 1 under the /api/users/1 path", async () => { + const users = await fetch("/api/users/1"); + expect(users.body).toEqual({ id: 1, name: "John Doe" }); + }); + + it("should serve user 1 under the /api/users/2 path", async () => { + const users = await fetch("/api/users/2"); + expect(users.body).toEqual({ id: 1, name: "John Doe" }); + }); + }); + + describe('When changing current mock to "user-real"', () => { + it("should display new selected mock", async () => { + await mocks.pressEnter(); + await mocks.cursorDown(2); + const newScreen = await mocks.pressEnter(); + expect(newScreen).toEqual(expect.stringContaining("Current mock: user-real")); + }); + + it("should have removed alert", async () => { + expect(mocks.currentScreen).toEqual(expect.not.stringContaining("ALERTS")); + }); + + it("should serve users collection mock under the /api/users path", async () => { + const users = await fetch("/api/users"); + expect(users.body).toEqual([ + { id: 1, name: "John Doe" }, + { id: 2, name: "Jane Doe" }, + ]); + }); + + it("should serve user 1 under the /api/users/1 path", async () => { + const users = await fetch("/api/users/1"); + expect(users.body).toEqual({ id: 1, name: "John Doe" }); + }); + + it("should serve user 2 under the /api/users/2 path", async () => { + const users = await fetch("/api/users/2"); + expect(users.body).toEqual({ id: 2, name: "Jane Doe" }); + }); + + it("should return not found for /api/users/3 path", async () => { + const usersResponse = await fetch("/api/users/3"); + expect(usersResponse.status).toEqual(404); + }); + }); + + describe("When changing logs level", () => { + it("should display new selected log level", async () => { + await mocks.cursorDown(5); + await mocks.pressEnter(); + await mocks.cursorDown(2); + const newScreen = await mocks.pressEnter(); + expect(newScreen).toEqual(expect.stringContaining("Log level: verbose")); + }); + }); + + describe("When displaying logs", () => { + it("should log requests", async () => { + expect.assertions(2); + await mocks.cursorDown(7); + await mocks.pressEnter(); + await fetch("/api/users"); + await wait(1000); + expect(mocks.currentScreen).toEqual(expect.stringContaining("Displaying logs")); + expect(mocks.currentScreen).toEqual( + expect.stringContaining("[Mocks verbose] Request received") + ); + await mocks.pressEnter(); + }); + }); + + describe("When changing delay time", () => { + it("should display new selected delay time", async () => { + await mocks.cursorDown(3); + await mocks.pressEnter(); + await mocks.write(2000); + const newScreen = await mocks.pressEnter(); + expect(newScreen).toEqual(expect.stringContaining("Delay: 2000")); + }); + + it("should respond after defined delay", async () => { + expect.assertions(2); + const timeCounter = new TimeCounter(); + const users = await fetch("/api/users"); + timeCounter.stop(); + expect(timeCounter.total).toBeGreaterThan(1999); + expect(users.body).toEqual([ + { id: 1, name: "John Doe" }, + { id: 2, name: "Jane Doe" }, + ]); + }); + }); +}); diff --git a/test/e2e/main/v2/no-mocks.spec.js b/test/e2e/main/v2/no-mocks.spec.js new file mode 100644 index 0000000..24c67af --- /dev/null +++ b/test/e2e/main/v2/no-mocks.spec.js @@ -0,0 +1,44 @@ +/* +Copyright 2019 Javier Brea + +Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. +*/ + +const { mocksRunner, waitForServerAndCli } = require("./support/helpers"); + +describe("with no behaviors", () => { + let mocks; + + afterEach(async () => { + await mocks.kill(); + }); + + it("should display alerts", async () => { + mocks = mocksRunner(["--path=no-mocks", "mock=foo"]); + await waitForServerAndCli(); + expect(mocks.currentScreen).toEqual(expect.stringContaining("ALERTS")); + expect(mocks.currentScreen).toEqual(expect.stringContaining("Warning: No mocks found")); + }); + + it("should print a dash as current behavior", async () => { + mocks = mocksRunner(["--path=no-mocks"]); + await waitForServerAndCli(); + expect(mocks.currentScreen).toEqual(expect.stringContaining("Current mock: -")); + }); + + it("should print mocks as 0", async () => { + mocks = mocksRunner(["--path=no-mocks"]); + await waitForServerAndCli(); + expect(mocks.currentScreen).toEqual(expect.stringContaining("Mocks: 0")); + }); + + it("should print current routes as 0", async () => { + mocks = mocksRunner(["--path=no-mocks"]); + await waitForServerAndCli(); + expect(mocks.logs).toEqual(expect.stringContaining("Routes: 0")); + }); +}); diff --git a/test/e2e/main/v2/support/helpers.js b/test/e2e/main/v2/support/helpers.js new file mode 100644 index 0000000..affec37 --- /dev/null +++ b/test/e2e/main/v2/support/helpers.js @@ -0,0 +1,114 @@ +/* +Copyright 2019 Javier Brea + +Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. +*/ + +const path = require("path"); + +const crossFetch = require("cross-fetch"); +const waitOn = require("wait-on"); + +const InteractiveCliRunner = require("../../../inquirer/support/InteractiveCliRunner"); + +const DEFAULT_BINARY_PATH = "./starter"; + +const SERVER_PORT = 3100; + +const defaultRequestOptions = { + method: "GET", + headers: { + "Content-Type": "application/json", + }, +}; + +const defaultMocksRunnerOptions = { + cwd: path.resolve(__dirname, "..", "fixtures"), +}; + +const fixturesFolder = (folderName) => { + return path.resolve(__dirname, "..", "fixtures", folderName); +}; + +const serverUrl = (port) => { + return `http://localhost:${port || SERVER_PORT}`; +}; + +const fetch = (uri, options = {}) => { + const requestOptions = { + ...defaultRequestOptions, + ...options, + }; + + return crossFetch(`${serverUrl(options.port)}${uri}`, { + ...requestOptions, + }).then((res) => { + return res + .json() + .then((processedRes) => ({ body: processedRes, status: res.status, headers: res.headers })); + }); +}; + +class TimeCounter { + constructor() { + this._startTime = new Date(); + } + + _getMiliseconds() { + this._miliseconds = this._endTime - this._startTime; + } + + get total() { + return this._miliseconds; + } + + stop() { + this._endTime = new Date(); + this._getMiliseconds(); + } +} + +const wait = (time = 1000) => { + return new Promise((resolve) => { + setTimeout(() => { + resolve(); + }, time); + }); +}; + +const waitForServer = (port) => { + return waitOn({ resources: [`tcp:localhost:${port || SERVER_PORT}`] }); +}; + +const waitForServerUrl = (url) => { + return waitOn({ resources: [`${serverUrl()}${url}`] }); +}; + +const waitForServerAndCli = async (port) => { + await waitForServer(port); + await wait(); +}; + +const mocksRunner = (args = [], options = {}) => { + const argsToSend = [...args]; + argsToSend.unshift(DEFAULT_BINARY_PATH); + return new InteractiveCliRunner(argsToSend, { + ...defaultMocksRunnerOptions, + ...options, + }); +}; + +module.exports = { + fetch, + TimeCounter, + mocksRunner, + wait, + waitForServer, + waitForServerUrl, + waitForServerAndCli, + fixturesFolder, +}; diff --git a/test/e2e/main/v2/web-tutorial.spec.js b/test/e2e/main/v2/web-tutorial.spec.js new file mode 100644 index 0000000..5178cf4 --- /dev/null +++ b/test/e2e/main/v2/web-tutorial.spec.js @@ -0,0 +1,179 @@ +/* +Copyright 2019 Javier Brea + +Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. +*/ + +const { mocksRunner, fetch, waitForServerAndCli } = require("./support/helpers"); + +describe("web tutorial", () => { + jest.setTimeout(15000); + let mocks; + + beforeAll(async () => { + mocks = mocksRunner(["--path=web-tutorial"]); + await waitForServerAndCli(); + }); + + afterAll(async () => { + await mocks.kill(); + }); + + describe("When started", () => { + it("should have 3 mocks available", async () => { + expect(mocks.currentScreen).toEqual(expect.stringContaining("Mocks: 3")); + }); + + it("should not display behaviors", async () => { + expect(mocks.currentScreen).toEqual(expect.not.stringContaining("behaviors")); + }); + + it("should serve users collection mock under the /api/users path", async () => { + const users = await fetch("/api/users"); + expect(users.body).toEqual([ + { id: 1, name: "John Doe" }, + { id: 2, name: "Jane Doe" }, + ]); + }); + + it("should serve user 1 under the /api/users/1 path", async () => { + const users = await fetch("/api/users/1"); + expect(users.body).toEqual({ id: 1, name: "John Doe" }); + }); + + it("should serve user 1 under the /api/users/2 path", async () => { + const users = await fetch("/api/users/2"); + expect(users.body).toEqual({ id: 1, name: "John Doe" }); + }); + }); + + describe('When changing current mock to "user-2"', () => { + it("should display new selected mock", async () => { + await mocks.pressEnter(); + await mocks.cursorDown(); + const newScreen = await mocks.pressEnter(); + expect(newScreen).toEqual(expect.stringContaining("Current mock: user-2")); + }); + + it("should serve users collection mock under the /api/users path", async () => { + const users = await fetch("/api/users"); + expect(users.body).toEqual([ + { id: 1, name: "John Doe" }, + { id: 2, name: "Jane Doe" }, + ]); + }); + + it("should serve user 2 under the /api/users/1 path", async () => { + const users = await fetch("/api/users/1"); + expect(users.body).toEqual({ id: 2, name: "Jane Doe" }); + }); + + it("should serve user 2 under the /api/users/2 path", async () => { + const users = await fetch("/api/users/2"); + expect(users.body).toEqual({ id: 2, name: "Jane Doe" }); + }); + }); + + describe('When changing current mock to "user-real"', () => { + it("should display new selected mock", async () => { + await mocks.pressEnter(); + await mocks.cursorDown(2); + const newScreen = await mocks.pressEnter(); + expect(newScreen).toEqual(expect.stringContaining("Current mock: user-real")); + }); + + it("should serve users collection mock under the /api/users path", async () => { + const users = await fetch("/api/users"); + expect(users.body).toEqual([ + { id: 1, name: "John Doe" }, + { id: 2, name: "Jane Doe" }, + ]); + }); + + it("should serve user 1 under the /api/users/1 path", async () => { + const users = await fetch("/api/users/1"); + expect(users.body).toEqual({ id: 1, name: "John Doe" }); + }); + + it("should serve user 2 under the /api/users/2 path", async () => { + const users = await fetch("/api/users/2"); + expect(users.body).toEqual({ id: 2, name: "Jane Doe" }); + }); + + it("should return not found for /api/users/3 path", async () => { + const usersResponse = await fetch("/api/users/3"); + expect(usersResponse.status).toEqual(404); + }); + }); + + describe("When setting custom route variant", () => { + it("should display custom route variant", async () => { + await mocks.cursorDown(); + await mocks.pressEnter(); + await mocks.cursorDown(); + const newScreen = await mocks.pressEnter(); + expect(newScreen).toEqual( + expect.stringContaining("Current mock: user-real (custom variants: get-user:2)") + ); + }); + + it("should serve users collection mock under the /api/users path", async () => { + const users = await fetch("/api/users"); + expect(users.body).toEqual([ + { id: 1, name: "John Doe" }, + { id: 2, name: "Jane Doe" }, + ]); + }); + + it("should serve user 2 under the /api/users/1 path", async () => { + const users = await fetch("/api/users/1"); + expect(users.body).toEqual({ id: 2, name: "Jane Doe" }); + }); + + it("should serve user 2 under the /api/users/2 path", async () => { + const users = await fetch("/api/users/2"); + expect(users.body).toEqual({ id: 2, name: "Jane Doe" }); + }); + + it("should return user 2 for /api/users/3 path", async () => { + const users = await fetch("/api/users/3"); + expect(users.body).toEqual({ id: 2, name: "Jane Doe" }); + }); + }); + + describe("When restoring route variants", () => { + it("should display mock", async () => { + await mocks.cursorDown(2); + await mocks.pressEnter(); + const newScreen = await mocks.pressEnter(); + expect(newScreen).toEqual(expect.stringContaining("Current mock: user-real")); + }); + + it("should serve users collection mock under the /api/users path", async () => { + const users = await fetch("/api/users"); + expect(users.body).toEqual([ + { id: 1, name: "John Doe" }, + { id: 2, name: "Jane Doe" }, + ]); + }); + + it("should serve user 1 under the /api/users/1 path", async () => { + const users = await fetch("/api/users/1"); + expect(users.body).toEqual({ id: 1, name: "John Doe" }); + }); + + it("should serve user 2 under the /api/users/2 path", async () => { + const users = await fetch("/api/users/2"); + expect(users.body).toEqual({ id: 2, name: "Jane Doe" }); + }); + + it("should return not found for /api/users/3 path", async () => { + const usersResponse = await fetch("/api/users/3"); + expect(usersResponse.status).toEqual(404); + }); + }); +});