diff --git a/.eslintignore b/.eslintignore index f89d1d0f27ff..7dd7fe603e53 100644 --- a/.eslintignore +++ b/.eslintignore @@ -26,7 +26,7 @@ packages/server/lib/scaffold/plugins/index.js packages/server/lib/scaffold/support/index.js packages/server/lib/scaffold/support/commands.js packages/server/test/support/fixtures/projects/e2e/cypress/integration/stdout_exit_early_failing_spec.js -packages/server/test/support/fixtures/projects/e2e/cypress/integration/browserify_typescript_failing_spec.ts +packages/server/test/support/fixtures/projects/e2e/cypress/integration/typescript_syntax_error_spec.ts **/.projects **/*.d.ts diff --git a/.eslintrc.json b/.eslintrc.json index 5da4255366f5..4d6129e600ad 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -6,7 +6,8 @@ "plugin:@cypress/dev/general" ], "rules": { - "prefer-spread": "off" + "prefer-spread": "off", + "prefer-rest-params": "off" }, "settings": { "react": { diff --git a/.node-version b/.node-version index e56b2006c570..5c088ddb94af 100644 --- a/.node-version +++ b/.node-version @@ -1 +1 @@ -12.8.1 +12.14.1 diff --git a/appveyor.yml b/appveyor.yml index 462b9f83ee2a..14abce2131d2 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -7,7 +7,7 @@ branches: # https://www.appveyor.com/docs/lang/nodejs-iojs/ environment: # use matching version of Node.js - nodejs_version: "12.8.1" + nodejs_version: "12.14.1" # encode secure variables which will NOT be used # in pull requests # https://www.appveyor.com/docs/build-configuration/#secure-variables diff --git a/circle.yml b/circle.yml index e0bf57391f0b..83722ddfad3f 100644 --- a/circle.yml +++ b/circle.yml @@ -8,7 +8,8 @@ macBuildFilters: &macBuildFilters branches: only: - develop - - investigate-spec-on-mac + - v5.0-release + - install-node-on-circleci-mac defaults: &defaults parallelism: 1 @@ -43,14 +44,14 @@ executors: # the Docker image with Cypress dependencies and Chrome browser cy-doc: docker: - - image: cypress/browsers:node12.13.0-chrome80-ff74 + - image: cypress/browsers:node12.14.1-chrome83-ff77 environment: PLATFORM: linux # Docker image with non-root "node" user non-root-docker-user: docker: - - image: cypress/browsers:node12.13.0-chrome80-ff74 + - image: cypress/browsers:node12.14.1-chrome83-ff77 user: node environment: PLATFORM: linux @@ -60,12 +61,37 @@ executors: # https://circleci.com/docs/2.0/testing-ios/#supported-xcode-versions mac: macos: - ## Node 12.10.0 (yarn 1.17.3) - xcode: "11.0.0" + # Executor should have Node >= required version + xcode: "11.2.1" environment: PLATFORM: mac commands: + install-required-node: + # https://discuss.circleci.com/t/switch-nodejs-version-on-machine-executor-solved/26675/2 + description: Install Node version matching .node-version + steps: + - run: + name: Install NVM + # TODO: determine why we get the missing .nvmrc file error + command: | + export NODE_VERSION=$(cat .node-version) + echo "Installing Node $NODE_VERSION" + cp .node-version .nvmrc + curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.35.3/install.sh | bash + - run: + # https://github.com/nvm-sh/nvm#nvmrc + name: Install Node + command: | + . ./scripts/load-nvm.sh + echo "before nvm install" + nvm install + echo "before nvm use" + nvm use + echo "before nvm alias default" + nvm alias default + node --version + install-latest-chrome: description: Install latest Google Chrome (stable) parameters: @@ -77,14 +103,14 @@ commands: - run: name: Install latest Google Chrome (stable) command: | - if [ << parameters.browser >> == "chrome" ]; then + if [ <> == "chrome" ]; then echo "**** Running Chrome tests. Installing latest stable version of Google Chrome. ****" apt-get update apt-get install google-chrome-stable -y echo "**** Location of Google Chrome Installation: "`which google-chrome`" ****" echo "**** Google Chrome Version: "`google-chrome --version`" ****" else - echo "**** Not updating Chrome. Running tests in '<< parameters.browser >>' ****" + echo "**** Not updating Chrome. Running tests in '<>' ****" fi run-driver-integration-tests: @@ -105,7 +131,7 @@ commands: if [[ -v PACKAGES_RECORD_KEY ]]; then # internal PR CYPRESS_RECORD_KEY=$PACKAGES_RECORD_KEY \ - yarn cypress:run --record --parallel --group 5x-driver-<< parameters.browser >> --browser << parameters.browser >> + yarn cypress:run --record --parallel --group 5x-driver-<> --browser <> else # external PR TESTFILES=$(circleci tests glob "cypress/integration/**/*_spec.*" | circleci tests split --total=$CIRCLE_NODE_TOTAL) @@ -114,7 +140,7 @@ commands: if [[ -z "$TESTFILES" ]]; then echo "Empty list of test files" fi - yarn cypress:run --browser << parameters.browser >> --spec $TESTFILES + yarn cypress:run --browser <> --spec $TESTFILES fi working_directory: packages/driver - verify-mocha-results @@ -129,14 +155,22 @@ commands: browser: description: browser shortname to target type: string + percy: + description: enable percy + type: boolean + default: false steps: - attach_workspace: at: ~/ - run: command: | + cmd=$([[ <> == 'true' ]] && echo 'yarn percy exec --') || true + CYPRESS_KONFIG_ENV=production \ CYPRESS_RECORD_KEY=$PACKAGES_RECORD_KEY \ - yarn workspace @packages/runner cypress:run --record --parallel --group runner-integration-<< parameters.browser >> --browser <> + PERCY_PARALLEL_NONCE=$CIRCLE_WORKFLOW_ID \ + PERCY_PARALLEL_TOTAL=-1 \ + $cmd yarn workspace @packages/runner cypress:run --record --parallel --group runner-integration-<> --browser <> - store_test_results: path: /tmp/cypress - store_artifacts: @@ -156,7 +190,7 @@ commands: - attach_workspace: at: ~/ - run: - command: yarn workspace @packages/server test ./test/e2e/<< parameters.chunk >>*spec* --browser << parameters.browser >> + command: yarn workspace @packages/server test ./test/e2e/<>*spec* --browser <> - verify-mocha-results - store_test_results: path: /tmp/cypress @@ -194,7 +228,23 @@ commands: ## by default, assert that at least 1 test ran default: 0 steps: - - run: yarn verify:mocha:results << parameters.expectedResultCount >> + - run: yarn verify:mocha:results <> + + clone-repo-and-checkout-release-branch: + description: | + Clones an external repo and then checks out the branch that matches NEXT_DEV_VERSION otherwise uses 'master' branch. + parameters: + repo: + description: "Name of the github repo to clone like: cypress-example-kitchensink" + type: string + steps: + - attach_workspace: + at: ~/ + - run: + name: "Cloning test project: <>" + command: | + git clone --depth 1 --no-single-branch https://github.com/cypress-io/<>.git /tmp/<> + cd /tmp/<> && (git checkout $NEXT_DEV_VERSION || true) test-binary-against-repo: description: | @@ -202,7 +252,7 @@ commands: and runs the new version of Cypress against it. parameters: repo: - description: Name of the repo like "cypress-example-kitchensink" + description: "Name of the github repo to clone like: cypress-example-kitchensink" type: string browser: description: Name of the browser to use, like "electron", "chrome", "firefox" @@ -230,24 +280,27 @@ commands: description: Whether to use wait-on to wait on a server to be booted type: string default: "" + server-start-command: + description: Server start command for repo + type: string + default: "npm start --if-present" steps: - attach_workspace: at: ~/ # make sure the binary and NPM package files are present - run: ls -l - run: ls -l cypress.zip cypress.tgz - - run: - name: Cloning project <> - command: git clone --depth 1 https://github.com/cypress-io/<>.git /tmp/<> + - clone-repo-and-checkout-release-branch: + repo: <> - when: - condition: << parameters.pull_request_id >> + condition: <> steps: - run: - name: Check out PR << parameters.pull_request_id >> + name: Check out PR <> working_directory: /tmp/<> command: | - git fetch origin pull/<< parameters.pull_request_id >>/head:pr-<< parameters.pull_request_id >> - git checkout pr-<< parameters.pull_request_id >> + git fetch origin pull/<>/head:pr-<> + git checkout pr-<> git log -n 2 - run: command: npm install @@ -267,49 +320,49 @@ commands: command: npm run build --if-present - run: working_directory: /tmp/<> - command: npm start --if-present + command: <> background: true - run: condition: <> name: "Waiting on server to boot: <>" command: "npx wait-on <> --timeout 120000" - when: - condition: << parameters.folder >> + condition: <> steps: - when: - condition: << parameters.browser >> + condition: <> steps: - run: - name: Run tests using browser "<< parameters.browser >>" - working_directory: /tmp/<>/<< parameters.folder >> + name: Run tests using browser "<>" + working_directory: /tmp/<>/<> command: | <> -- --browser <> - unless: - condition: << parameters.browser >> + condition: <> steps: - run: name: Run tests using command - working_directory: /tmp/<>/<< parameters.folder >> + working_directory: /tmp/<>/<> command: <> - store_artifacts: name: screenshots - path: /tmp/<>/<< parameters.folder >>/cypress/screenshots + path: /tmp/<>/<>/cypress/screenshots - store_artifacts: name: videos - path: /tmp/<>/<< parameters.folder >>/cypress/videos + path: /tmp/<>/<>/cypress/videos - unless: - condition: << parameters.folder >> + condition: <> steps: - when: - condition: << parameters.browser >> + condition: <> steps: - run: - name: Run tests using browser "<< parameters.browser >>" + name: Run tests using browser "<>" working_directory: /tmp/<> command: <> -- --browser <> - unless: - condition: << parameters.browser >> + condition: <> steps: - run: name: Run tests using command @@ -323,12 +376,24 @@ commands: path: /tmp/<>/cypress/videos - store-npm-logs + wait-on-circle-jobs: + description: Polls certain Circle CI jobs until they finish + parameters: + job-names: + description: comma separated list of circle ci job names to wait for + type: string + steps: + - run: + name: "Waiting on Circle CI jobs: <>" + command: node ./scripts/wait-on-circle-jobs.js --job-names="<>" + jobs: ## code checkout and yarn installs build: <<: *defaults steps: - checkout + - install-required-node - run: name: Print working folder command: echo $PWD @@ -337,20 +402,36 @@ jobs: command: echo $(yarn global bin) - run: name: print Node version - command: node -v + command: | + . ./scripts/load-nvm.sh + echo "nvm use default" + nvm use default + node -v - run: name: print yarn version command: yarn -v - - run: yarn check-node-version + - run: + name: check Node version + command: | + . ./scripts/load-nvm.sh + yarn check-node-version ## make sure the TERM is set to 'xterm' in node (Linux only) ## else colors (and tests) will fail ## See the following information ## * http://andykdocs.de/development/Docker/Fixing+the+Docker+TERM+variable+issue ## * https://unix.stackexchange.com/questions/43945/whats-the-difference-between-various-term-variables - - run: yarn check-terminal + - run: + name: Check terminal + command: | + . ./scripts/load-nvm.sh + yarn check-terminal - - run: yarn stop-only-all + - run: + name: Stop .only + command: | + . ./scripts/load-nvm.sh + yarn stop-only-all - restore_cache: name: Restore yarn cache @@ -361,7 +442,11 @@ jobs: - run: ls $(yarn global bin)/../lib/node_modules # try several times, because flaky NPM installs ... - - run: yarn --frozen-lockfile || yarn --frozen-lockfile + - run: + name: install and build + command: | + . ./scripts/load-nvm.sh + yarn --frozen-lockfile || yarn --frozen-lockfile - run: name: Top level packages command: yarn list --depth=0 || true @@ -379,13 +464,49 @@ jobs: steps: - attach_workspace: at: ~/ - ## this will catch .only's in js/coffee as well - - run: yarn lint + - install-required-node + ## this will catch ".only"s in js/coffee as well + - run: + name: Linting ๐Ÿงน + command: | + . ./scripts/load-nvm.sh + yarn lint - run: name: cypress info (dev) command: node cli/bin/cypress info --dev - store-npm-logs + # a special job that keeps polling Circle and when all + # individual jobs are finished, it closes the Percy build + percy-finalize: + <<: *defaults + executor: cy-doc + parameters: + required_env_var: + type: env_var_name + steps: + - attach_workspace: + at: ~/ + - run: + # if this is an external pull request, the environment variables + # are NOT set for security reasons, thus no need to poll - + # and no need to finalize Percy, since there will be no visual tests + name: Check if <> is set + command: | + if [[ -v <> ]]; then + echo "Internal PR, good to go" + else + echo "This is an external PR, cannot access other services" + circleci-agent step halt + fi + - wait-on-circle-jobs: + job-names: > + desktop-gui-integration-tests-2x, + desktop-gui-component-tests, + cli-visual-tests, + runner-integration-tests-chrome, + - run: npx percy finalize --all + cli-visual-tests: <<: *defaults parallelism: 1 @@ -406,7 +527,8 @@ jobs: - run: name: Upload CLI snapshots for diffing command: | - PERCY_TOKEN=$PERCY_TOKEN_CLI \ + PERCY_PARALLEL_NONCE=$CIRCLE_WORKFLOW_ID \ + PERCY_PARALLEL_TOTAL=-1 \ yarn percy snapshot ./cli/visual-snapshots unit-tests: @@ -460,12 +582,20 @@ jobs: steps: - attach_workspace: at: ~/ - # make sure mocha runs - - run: yarn test-mocha + - install-required-node + - run: + name: Mocha tests + command: | + . ./scripts/load-nvm.sh + yarn test-mocha # test binary build code - - run: yarn test-scripts + - run: + name: Test scripts + command: | + . ./scripts/load-nvm.sh + yarn test-scripts - "server-unit-tests": + server-unit-tests: <<: *defaults parallelism: 2 steps: @@ -478,7 +608,7 @@ jobs: path: /tmp/cypress - store-npm-logs - "server-integration-tests": + server-integration-tests: <<: *defaults parallelism: 2 steps: @@ -491,7 +621,7 @@ jobs: path: /tmp/cypress - store-npm-logs - "server-performance-tests": + server-performance-tests: <<: *defaults steps: - attach_workspace: @@ -506,216 +636,217 @@ jobs: path: /tmp/artifacts - store-npm-logs - "server-e2e-tests-chrome-1": + server-e2e-tests-chrome-1: <<: *defaults steps: - run-e2e-tests: browser: chrome chunk: "1" - "server-e2e-tests-chrome-2": + server-e2e-tests-chrome-2: <<: *defaults steps: - run-e2e-tests: browser: chrome chunk: "2" - "server-e2e-tests-chrome-3": + server-e2e-tests-chrome-3: <<: *defaults steps: - run-e2e-tests: browser: chrome chunk: "3" - "server-e2e-tests-chrome-4": + server-e2e-tests-chrome-4: <<: *defaults steps: - run-e2e-tests: browser: chrome chunk: "4" - "server-e2e-tests-chrome-5": + server-e2e-tests-chrome-5: <<: *defaults steps: - run-e2e-tests: browser: chrome chunk: "5" - "server-e2e-tests-chrome-6": + server-e2e-tests-chrome-6: <<: *defaults steps: - run-e2e-tests: browser: chrome chunk: "6" - "server-e2e-tests-chrome-7": + server-e2e-tests-chrome-7: <<: *defaults steps: - run-e2e-tests: browser: chrome chunk: "7" - "server-e2e-tests-chrome-8": + server-e2e-tests-chrome-8: <<: *defaults steps: - run-e2e-tests: browser: chrome chunk: "8" - "server-e2e-tests-electron-1": + server-e2e-tests-electron-1: <<: *defaults steps: - run-e2e-tests: browser: electron chunk: "1" - "server-e2e-tests-electron-2": + server-e2e-tests-electron-2: <<: *defaults steps: - run-e2e-tests: browser: electron chunk: "2" - "server-e2e-tests-electron-3": + server-e2e-tests-electron-3: <<: *defaults steps: - run-e2e-tests: browser: electron chunk: "3" - "server-e2e-tests-electron-4": + server-e2e-tests-electron-4: <<: *defaults steps: - run-e2e-tests: browser: electron chunk: "4" - "server-e2e-tests-electron-5": + server-e2e-tests-electron-5: <<: *defaults steps: - run-e2e-tests: browser: electron chunk: "5" - "server-e2e-tests-electron-6": + server-e2e-tests-electron-6: <<: *defaults steps: - run-e2e-tests: browser: electron chunk: "6" - "server-e2e-tests-electron-7": + server-e2e-tests-electron-7: <<: *defaults steps: - run-e2e-tests: browser: electron chunk: "7" - "server-e2e-tests-electron-8": + server-e2e-tests-electron-8: <<: *defaults steps: - run-e2e-tests: browser: electron chunk: "8" - "server-e2e-tests-non-root": + server-e2e-tests-non-root: <<: *defaults steps: - run-e2e-tests: chunk: non_root - "server-e2e-tests-firefox-1": + server-e2e-tests-firefox-1: <<: *defaults steps: - run-e2e-tests: browser: firefox chunk: "1" - "server-e2e-tests-firefox-2": + server-e2e-tests-firefox-2: <<: *defaults steps: - run-e2e-tests: browser: firefox chunk: "2" - "server-e2e-tests-firefox-3": + server-e2e-tests-firefox-3: <<: *defaults steps: - run-e2e-tests: browser: firefox chunk: "3" - "server-e2e-tests-firefox-4": + server-e2e-tests-firefox-4: <<: *defaults steps: - run-e2e-tests: browser: firefox chunk: "4" - "server-e2e-tests-firefox-5": + server-e2e-tests-firefox-5: <<: *defaults steps: - run-e2e-tests: browser: firefox chunk: "5" - "server-e2e-tests-firefox-6": + server-e2e-tests-firefox-6: <<: *defaults steps: - run-e2e-tests: browser: firefox chunk: "6" - "server-e2e-tests-firefox-7": + server-e2e-tests-firefox-7: <<: *defaults steps: - run-e2e-tests: browser: firefox chunk: "7" - "server-e2e-tests-firefox-8": + server-e2e-tests-firefox-8: <<: *defaults steps: - run-e2e-tests: browser: firefox chunk: "8" - "runner-integration-tests-chrome": + runner-integration-tests-chrome: <<: *defaults parallelism: 2 steps: - run-runner-integration-tests: browser: chrome + percy: true - "runner-integration-tests-firefox": + runner-integration-tests-firefox: <<: *defaults parallelism: 2 steps: - run-runner-integration-tests: browser: firefox - "driver-integration-tests-chrome": + driver-integration-tests-chrome: <<: *defaults parallelism: 5 steps: - run-driver-integration-tests: browser: chrome - # "driver-integration-tests-electron": + # driver-integration-tests-electron: # <<: *defaults # parallelism: 5 # steps: # - run-driver-integration-tests: # browser: electron - "driver-integration-tests-firefox": + driver-integration-tests-firefox: <<: *defaults parallelism: 5 steps: - run-driver-integration-tests: browser: firefox - "desktop-gui-integration-tests-2x": + desktop-gui-integration-tests-2x: <<: *defaults parallelism: 2 steps: @@ -733,6 +864,9 @@ jobs: command: | CYPRESS_KONFIG_ENV=production \ CYPRESS_RECORD_KEY=$PACKAGES_RECORD_KEY \ + PERCY_PARALLEL_NONCE=$CIRCLE_WORKFLOW_ID \ + PERCY_PARALLEL_TOTAL=-1 \ + yarn percy exec -- \ yarn cypress:run --record --parallel --group 2x-desktop-gui working_directory: packages/desktop-gui - verify-mocha-results @@ -802,7 +936,7 @@ jobs: command: | CYPRESS_KONFIG_ENV=production \ PERCY_PARALLEL_NONCE=$CIRCLE_WORKFLOW_ID \ - PERCY_PARALLEL_TOTAL=1 \ + PERCY_PARALLEL_TOTAL=-1 \ yarn percy exec -- \ yarn cypress:run --spec 'src/**/*_spec.jsx' working_directory: packages/desktop-gui @@ -810,7 +944,7 @@ jobs: # we don't really need any artifacts - we are only interested in visual screenshots - store-npm-logs - "reporter-integration-tests": + reporter-integration-tests: <<: *defaults steps: - attach_workspace: @@ -831,7 +965,7 @@ jobs: path: /tmp/artifacts - store-npm-logs - "ui-components-integration-tests": + ui-components-integration-tests: <<: *defaults steps: - attach_workspace: @@ -852,7 +986,7 @@ jobs: path: /tmp/artifacts - store-npm-logs - "run-launcher": + run-launcher: <<: *defaults steps: - attach_workspace: @@ -895,6 +1029,7 @@ jobs: - attach_workspace: at: ~/ - run: $(yarn bin)/print-arch + - install-required-node - run: environment: DEBUG: electron-builder,electron-osx-sign* @@ -903,8 +1038,15 @@ jobs: # if this is a forked pull request, the NEXT_DEV_VERSION environment variable # won't be set and we will use default version, since we are not going to # upload the dev binary build anywhere - command: yarn binary-build --platform $PLATFORM --version ${NEXT_DEV_VERSION:-0.0.0-development} - - run: yarn binary-zip --platform $PLATFORM + command: | + . ./scripts/load-nvm.sh + node --version + yarn binary-build --platform $PLATFORM --version ${NEXT_DEV_VERSION:-0.0.0-development} + - run: + name: Zip the binary + command: | + . ./scripts/load-nvm.sh + yarn binary-zip --platform $PLATFORM # Cypress binary file should be zipped to cypress.zip - run: ls -l *.zip - store-npm-logs @@ -935,45 +1077,42 @@ jobs: test-kitchensink: <<: *defaults steps: - - attach_workspace: - at: ~/ - - run: - name: Cloning test project - command: git clone https://github.com/cypress-io/cypress-example-kitchensink.git /tmp/repo + - clone-repo-and-checkout-release-branch: + repo: cypress-example-kitchensink + - install-required-node - run: name: Install prod dependencies command: yarn --production - working_directory: /tmp/repo + working_directory: /tmp/cypress-example-kitchensink - run: name: Example server command: yarn start - working_directory: /tmp/repo + working_directory: /tmp/cypress-example-kitchensink background: true - run: name: Run Kitchensink example project - command: yarn cypress:run --project /tmp/repo + command: | + . ./scripts/load-nvm.sh + yarn cypress:run --project /tmp/cypress-example-kitchensink - store_artifacts: - path: /tmp/repo/cypress/screenshots + path: /tmp/cypress-example-kitchensink/cypress/screenshots - store_artifacts: - path: /tmp/repo/cypress/videos + path: /tmp/cypress-example-kitchensink/cypress/videos - store-npm-logs "test-kitchensink-against-staging": <<: *defaults steps: - - attach_workspace: - at: ~/ - - run: - name: Cloning test project - command: git clone https://github.com/cypress-io/cypress-example-kitchensink.git /tmp/repo + - clone-repo-and-checkout-release-branch: + repo: cypress-example-kitchensink - run: name: Install prod dependencies command: yarn --production - working_directory: /tmp/repo + working_directory: /tmp/cypress-example-kitchensink - run: name: Example server command: yarn start - working_directory: /tmp/repo + working_directory: /tmp/cypress-example-kitchensink background: true - run: name: Run Kitchensink example project @@ -982,24 +1121,21 @@ jobs: CYPRESS_RECORD_KEY=$TEST_KITCHENSINK_RECORD_KEY \ CYPRESS_INTERNAL_ENV=staging \ CYPRESS_video=false \ - yarn cypress:run --project /tmp/repo --record + yarn cypress:run --project /tmp/cypress-example-kitchensink --record - store-npm-logs "test-against-staging": <<: *defaults steps: - - attach_workspace: - at: ~/ - - run: - name: Cloning test project - command: git clone https://github.com/cypress-io/cypress-test-tiny.git /tmp/repo + - clone-repo-and-checkout-release-branch: + repo: cypress-test-tiny - run: name: Run test project command: | CYPRESS_PROJECT_ID=$TEST_TINY_PROJECT_ID \ CYPRESS_RECORD_KEY=$TEST_TINY_RECORD_KEY \ CYPRESS_INTERNAL_ENV=staging \ - yarn cypress:run --project /tmp/repo --record + yarn cypress:run --project /tmp/cypress-example-kitchensink --record - store-npm-logs build-npm-package: @@ -1007,13 +1143,20 @@ jobs: steps: - attach_workspace: at: ~/ - - run: yarn check-next-dev-version + - install-required-node + - run: + name: Check next dev version + command: | + . ./scripts/load-nvm.sh + yarn check-next-dev-version - run: name: bump NPM version command: yarn version --no-git-tag-version --new-version ${NEXT_DEV_VERSION:-0.0.0-development} - run: name: build NPM package - command: yarn build --scope cypress + command: | + . ./scripts/load-nvm.sh + yarn build --scope cypress - run: command: ls -la types working_directory: cli/build @@ -1144,7 +1287,7 @@ jobs: test-npm-module-on-minimum-node-version: <<: *defaults docker: - - image: cypress/base:8.0.0 + - image: cypress/base:10.0.0 steps: - attach_workspace: at: ~/ @@ -1192,16 +1335,16 @@ jobs: # make sure we have cypress.zip received - run: ls -l - run: ls -l cypress.zip cypress.tgz - - run: mkdir << parameters.wd >> + - run: mkdir <> - run: node --version - run: npm --version - run: name: Create new NPM package โš—๏ธ - working_directory: << parameters.wd >> + working_directory: <> command: npm init -y - run: name: Install dependencies ๐Ÿ“ฆ - working_directory: << parameters.wd >> + working_directory: <> environment: CYPRESS_INSTALL_BINARY: /root/cypress/cypress.zip # let's install Cypress, Jest and any other package that might conflict @@ -1211,7 +1354,7 @@ jobs: typescript jest @types/jest enzyme @types/enzyme - run: name: Test types clash โš”๏ธ - working_directory: << parameters.wd >> + working_directory: <> command: | echo "console.log('hello world')" > hello.ts npx tsc hello.ts --noEmit @@ -1235,16 +1378,16 @@ jobs: # make sure we have cypress.zip received - run: ls -l - run: ls -l cypress.zip cypress.tgz - - run: mkdir << parameters.wd >> + - run: mkdir <> - run: node --version - run: npm --version - run: name: Create new NPM package โš—๏ธ - working_directory: << parameters.wd >> + working_directory: <> command: npm init -y - run: name: Install dependencies ๐Ÿ“ฆ - working_directory: << parameters.wd >> + working_directory: <> environment: CYPRESS_INSTALL_BINARY: /root/cypress/cypress.zip # let's install Cypress, Jest and any other package that might conflict @@ -1254,7 +1397,7 @@ jobs: typescript jest @types/jest enzyme @types/enzyme - run: name: Scaffold and test examples ๐Ÿ— - working_directory: << parameters.wd >> + working_directory: <> environment: CYPRESS_INTERNAL_FORCE_SCAFFOLD: "1" command: | @@ -1278,27 +1421,27 @@ jobs: # make sure we have cypress.zip received - run: ls -l - run: ls -l cypress.zip cypress.tgz - - run: mkdir << parameters.wd >> + - run: mkdir <> - run: node --version - run: npm --version - run: name: Create new NPM package โš—๏ธ - working_directory: << parameters.wd >> + working_directory: <> command: npm init -y - run: name: Install dependencies ๐Ÿ“ฆ - working_directory: << parameters.wd >> + working_directory: <> environment: CYPRESS_INSTALL_BINARY: /root/cypress/cypress.zip command: | npm install /root/cypress/cypress.tgz typescript - run: name: Scaffold full TypeScript project ๐Ÿ— - working_directory: << parameters.wd >> + working_directory: <> command: npx @bahmutov/cly@1 init --typescript - run: name: Run project tests ๐Ÿ—ณ - working_directory: << parameters.wd >> + working_directory: <> command: npx cypress run # install NPM + binary zip and run against staging API @@ -1310,9 +1453,8 @@ jobs: - run: ls -l # make sure we have the binary and NPM package - run: ls -l cypress.zip cypress.tgz - - run: - name: Cloning test project - command: git clone https://github.com/cypress-io/cypress-test-tiny.git /tmp/cypress-test-tiny + - clone-repo-and-checkout-release-branch: + repo: cypress-test-tiny - run: name: Install Cypress working_directory: /tmp/cypress-test-tiny @@ -1348,6 +1490,12 @@ jobs: test-binary-against-recipe-pull-request: <<: *defaults steps: + # test a specific pull request by number from cypress-example-recipes + - test-binary-against-repo: + repo: cypress-example-recipes + command: npm run test:ci + pull_request_id: 515 + folder: examples/fundamentals__typescript - test-binary-against-repo: repo: cypress-example-recipes command: npm test @@ -1422,6 +1570,16 @@ jobs: browser: firefox command: "npm run cypress:run" + "test-binary-against-cypress-realworld-app": + <<: *defaults + steps: + - test-binary-against-repo: + repo: cypress-realworld-app + browser: chrome + server-start-command: "npm run start:ci" + command: "npm run cypress:run" + wait-on: http://localhost:3000 + test-binary-as-specific-user: <<: *defaults steps: @@ -1477,6 +1635,11 @@ linux-workflow: &linux-workflow name: Linux lint requires: - build + - percy-finalize: + context: test-runner:poll-circle-workflow + required_env_var: PERCY_TOKEN # skips job if not defined (external PR) + requires: + - build - lint-types: requires: - build @@ -1595,9 +1758,6 @@ linux-workflow: &linux-workflow - desktop-gui-integration-tests-2x: requires: - build - - desktop-gui-visual-tests: - requires: - - build - desktop-gui-component-tests: requires: - build @@ -1610,6 +1770,7 @@ linux-workflow: &linux-workflow - run-launcher: requires: - build + # various testing scenarios, like building full binary # and testing it on a real project - test-against-staging: @@ -1623,6 +1784,12 @@ linux-workflow: &linux-workflow - test-kitchensink: requires: - build + filters: + branches: + ignore: + ## TODO: remove this upon merging the PR + - rename-blacklisthosts + - pull/7622 - test-kitchensink-against-staging: context: test-runner:record-tests filters: @@ -1640,6 +1807,7 @@ linux-workflow: &linux-workflow branches: only: - develop + - v5.0-release requires: - build-npm-package - build-binary: @@ -1651,6 +1819,7 @@ linux-workflow: &linux-workflow branches: only: - develop + - v5.0-release requires: - build-binary - test-npm-module-on-minimum-node-version: @@ -1673,6 +1842,12 @@ linux-workflow: &linux-workflow requires: - build-binary - build-npm-package + filters: + branches: + ignore: + ## TODO: remove this upon merging the PR + - rename-blacklisthosts + - pull/7622 # when working on a feature or a fix, # you are probably working in a branch # and you want to run a specific PR in the cypress-example-recipes @@ -1701,6 +1876,7 @@ linux-workflow: &linux-workflow branches: only: - develop + - v5.0-release requires: - upload-npm-package - upload-binary @@ -1747,6 +1923,16 @@ linux-workflow: &linux-workflow <<: *testBinaryFirefox - test-binary-against-piechopper-firefox: <<: *testBinaryFirefox + - test-binary-against-cypress-realworld-app: + filters: + branches: + only: + - develop + - kevin-v5.0-release-rwa + - v5.0-release + requires: + - build-npm-package + - build-binary - test-binary-as-specific-user: name: "test binary as a non-root user" diff --git a/cli/package.json b/cli/package.json index 37afdebc23d6..e294ad3104ad 100644 --- a/cli/package.json +++ b/cli/package.json @@ -26,26 +26,27 @@ "@types/sinonjs__fake-timers": "^6.0.1", "@types/sizzle": "^2.3.2", "arch": "^2.1.2", + "blob-util": "2.0.2", "bluebird": "^3.7.2", "cachedir": "^2.3.0", - "chalk": "^2.4.2", + "chalk": "^4.1.0", "check-more-types": "^2.24.0", - "cli-table3": "~0.5.1", + "cli-table3": "~0.6.0", "commander": "^4.1.1", "common-tags": "^1.8.0", "debug": "^4.1.1", "eventemitter2": "^6.4.2", - "execa": "^1.0.0", + "execa": "^4.0.2", "executable": "^4.1.1", "extract-zip": "^1.7.0", - "fs-extra": "^8.1.0", + "fs-extra": "^9.0.1", "getos": "^3.2.1", "is-ci": "^2.0.0", "is-installed-globally": "^0.3.2", "lazy-ass": "^1.6.0", "listr": "^0.14.3", "lodash": "^4.17.19", - "log-symbols": "^3.0.0", + "log-symbols": "^4.0.0", "minimist": "^1.2.5", "moment": "^2.27.0", "ospath": "^1.2.2", @@ -53,7 +54,7 @@ "ramda": "~0.26.1", "request-progress": "^3.0.0", "supports-color": "^7.1.0", - "tmp": "~0.1.0", + "tmp": "~0.2.1", "untildify": "^4.0.0", "url": "^0.11.0", "yauzl": "^2.10.0" @@ -63,7 +64,6 @@ "@babel/preset-env": "7.9.5", "@cypress/sinon-chai": "1.1.0", "@packages/root": "*", - "@types/blob-util": "1.3.3", "@types/bluebird": "3.5.29", "@types/chai": "4.2.7", "@types/chai-jquery": "1.1.40", @@ -82,7 +82,7 @@ "execa-wrap": "1.4.0", "hasha": "5.0.0", "mocha": "6.2.2", - "mock-fs": "4.9.0", + "mock-fs": "4.12.0", "mocked-env": "1.2.4", "nock": "12.0.2", "postinstall-postinstall": "2.0.0", @@ -104,7 +104,7 @@ "cypress": "bin/cypress" }, "engines": { - "node": ">=8.0.0" + "node": ">=10.0.0" }, "types": "types" } diff --git a/cli/schema/cypress.schema.json b/cli/schema/cypress.schema.json index 5b964c63df85..12b7c37052e3 100644 --- a/cli/schema/cypress.schema.json +++ b/cli/schema/cypress.schema.json @@ -180,7 +180,7 @@ "default": null, "description": "Enables you to override the default user agent the browser sends in all request headers. User agent values are typically used by servers to help identify the operating system, browser, and browser version. See User-Agent MDN Documentation for example user agent values here: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/User-Agent" }, - "blacklistHosts": { + "blockHosts": { "type": [ "string", "array" @@ -189,7 +189,7 @@ "type": "string" }, "default": null, - "description": "A String or Array of hosts that you wish to block traffic for. Please read the notes for examples on using this https://on.cypress.io/configuration#blacklistHosts" + "description": "A String or Array of hosts that you wish to block traffic for. Please read the notes for examples on using this https://on.cypress.io/configuration#blockHosts" }, "modifyObstructiveCode": { "type": "boolean", @@ -229,11 +229,6 @@ "default": "bundled", "description": "If set to 'system', Cypress will try to find a Node.js executable on your path to use when executing your plugins. Otherwise, Cypress will use the Node version bundled with Cypress." }, - "experimentalGetCookiesSameSite": { - "type": "boolean", - "default": false, - "description": "If `true`, Cypress will add `sameSite` values to the objects yielded from `cy.setCookie()`, `cy.getCookie()`, and `cy.getCookies()`. This will become the default behavior in Cypress 5.0." - }, "experimentalSourceRewriting": { "type": "boolean", "default": false, @@ -248,6 +243,18 @@ "type": "boolean", "default": false, "description": "Polyfills `window.fetch` to enable Network spying and stubbing" + }, + "retries": { + "type": [ + "object", + "number", + "null" + ], + "default": { + "runMode": 0, + "openMode": 0 + }, + "description": "The number of times to retry a failing. Can be configured to apply only in runMode or openMode" } } } diff --git a/cli/scripts/utils.js b/cli/scripts/utils.js index 8c215081d438..87389ed9826e 100644 --- a/cli/scripts/utils.js +++ b/cli/scripts/utils.js @@ -4,7 +4,6 @@ * definition files that we will need to include with our NPM package. */ const includeTypes = [ - 'blob-util', 'bluebird', 'lodash', 'mocha', diff --git a/cli/types/cy-blob-util.d.ts b/cli/types/cy-blob-util.d.ts index a70481fa30fc..e8fc61702f86 100644 --- a/cli/types/cy-blob-util.d.ts +++ b/cli/types/cy-blob-util.d.ts @@ -3,7 +3,7 @@ // so that Cypress can get and use the Blob type // tslint:disable-next-line:no-implicit-dependencies -import * as blobUtil from './blob-util' +import * as blobUtil from 'blob-util' export = BlobUtil export as namespace BlobUtil diff --git a/cli/types/cypress-npm-api.d.ts b/cli/types/cypress-npm-api.d.ts index 40721b8fc0c9..d3b29eccd58e 100644 --- a/cli/types/cypress-npm-api.d.ts +++ b/cli/types/cypress-npm-api.d.ts @@ -7,6 +7,12 @@ // but for now describe it as an ambient module declare namespace CypressCommandLine { + type HookName = 'before' | 'beforeEach' | 'afterEach' | 'after' + interface TestError { + name: string + message: string + stack: string + } /** * All options that one can pass to "cypress.run" * @see https://on.cypress.io/module-api#cypress-run @@ -154,39 +160,36 @@ declare namespace CypressCommandLine { // small utility types to better express meaning of other types type dateTimeISO = string type ms = number - type hookId = string - type testId = string type pixels = number /** * Cypress single test result */ interface TestResult { - testId: testId title: string[] state: string body: string - /** - * Error stack string if there is an error - */ - stack: string | null - /** - * Error message if there is an error + /** + * Error string as it's presented in console if the test fails */ - error: string | null - timings: any - failedFromHookId: hookId | null - wallClockStartedAt: dateTimeISO - wallClockDuration: ms + displayError: string | null + attempts: AttemptResult[] + } + + interface AttemptResult { + state: string + error: TestError | null + startedAt: dateTimeISO + duration: ms videoTimestamp: ms + screenshots: ScreenshotInformation[] } /** * Information about a single "before", "beforeEach", "afterEach" and "after" hook. */ interface HookInformation { - hookId: hookId - hookName: 'before' | 'beforeEach' | 'afterEach' | 'after' + hookName: HookName title: string[] body: string } @@ -195,9 +198,7 @@ declare namespace CypressCommandLine { * Information about a single screenshot. */ interface ScreenshotInformation { - screenshotId: string name: string - testId: testId takenAt: dateTimeISO /** * Absolute path to the saved image @@ -221,9 +222,9 @@ declare namespace CypressCommandLine { pending: number skipped: number failures: number - wallClockStartedAt: dateTimeISO - wallClockEndedAt: dateTimeISO - wallClockDuration: ms + startedAt: dateTimeISO + endedAt: dateTimeISO + duration: ms }, /** * Reporter name like "spec" @@ -238,7 +239,6 @@ declare namespace CypressCommandLine { tests: TestResult[] error: string | null video: string | null - screenshots: ScreenshotInformation[] /** * information about the spec test file. */ diff --git a/cli/types/cypress.d.ts b/cli/types/cypress.d.ts index 4a6424ee12fe..a37ca35278f2 100644 --- a/cli/types/cypress.d.ts +++ b/cli/types/cypress.d.ts @@ -107,6 +107,16 @@ declare namespace Cypress { fromAutWindow: WindowPosition & { x: number, y: number } } + /** + * Window type for Application Under Test(AUT) + */ + type AUTWindow = Window & typeof globalThis & ApplicationWindow + + /** + * The interface for user-defined properties in Window object under test. + */ + interface ApplicationWindow {} // tslint:disable-line + /** * Several libraries are bundled with Cypress by default. * @@ -324,6 +334,11 @@ declare namespace Cypress { */ getFirefoxGcInterval(): number | null | undefined + /** + * @returns the number of test retries currently enabled for the run + */ + getTestRetries(): number | null + /** * Checks if a variable is a valid instance of `cy` or a `cy` chainable. * @@ -1062,7 +1077,7 @@ declare namespace Cypress { * * @see https://on.cypress.io/go */ - go(direction: HistoryDirection | number, options?: Partial): Chainable + go(direction: HistoryDirection | number, options?: Partial): Chainable /** * Get the current URL hash of the page that is currently active. @@ -1399,7 +1414,7 @@ declare namespace Cypress { * @example * cy.reload() */ - reload(options?: Partial): Chainable + reload(options?: Partial): Chainable /** * Reload the page without cache * @@ -1410,7 +1425,7 @@ declare namespace Cypress { * cy.visit('http://localhost:3000/admin') * cy.reload(true) */ - reload(forceReload: boolean): Chainable + reload(forceReload: boolean): Chainable /** * Make an HTTP GET request. @@ -1976,8 +1991,8 @@ declare namespace Cypress { * }) * */ - visit(url: string, options?: Partial): Chainable - visit(options: Partial & { url: string }): Chainable + visit(url: string, options?: Partial): Chainable + visit(options: Partial & { url: string }): Chainable /** * Wait for a number of milliseconds. @@ -2048,7 +2063,7 @@ declare namespace Cypress { }) ``` */ - window(options?: Partial): Chainable + window(options?: Partial): Chainable /** * Scopes all subsequent cy commands to within this element. @@ -2177,7 +2192,7 @@ declare namespace Cypress { type Agent = SinonSpyAgent & T interface CookieDefaults { - whitelist: string | string[] | RegExp | ((cookie: any) => boolean) + preserve: string | string[] | RegExp | ((cookie: any) => boolean) } interface Failable { @@ -2542,12 +2557,6 @@ declare namespace Cypress { * @default { runMode: 1, openMode: null } */ firefoxGcInterval: Nullable, openMode: Nullable }> - /** - * If `true`, Cypress will add `sameSite` values to the objects yielded from `cy.setCookie()`, - * `cy.getCookie()`, and `cy.getCookies()`. This will become the default behavior in Cypress 5.0. - * @default false - */ - experimentalGetCookiesSameSite: boolean /** * Enables AST-based JS/HTML rewriting. This may fix issues caused by the existing regex-based JS/HTML replacement * algorithm. @@ -2559,6 +2568,13 @@ declare namespace Cypress { * the `includeShadowDom` option to some DOM commands. */ experimentalShadowDomSupport: boolean + /** + * Number of times to retry a failed test. + * If a number is set, tests will retry in both runMode and openMode. + * To enable test retries only in runMode, set e.g. `{ openMode: null, runMode: 2 }` + * @default null + */ + retries: Nullable, openMode: Nullable}> } interface TestConfigOverrides extends Partial> { @@ -2732,7 +2748,7 @@ declare namespace Cypress { enable: boolean force404: boolean urlMatchingOptions: object - whitelist(xhr: Request): void + ignore(xhr: Request): void onAnyRequest(route: RouteOptions, proxy: any): void onAnyResponse(route: RouteOptions, proxy: any): void onAnyAbort(route: RouteOptions, proxy: any): void @@ -2831,16 +2847,16 @@ declare namespace Cypress { /** * Called before your page has loaded all of its resources. * - * @param {Window} contentWindow the remote page's window object + * @param {AUTWindow} contentWindow the remote page's window object */ - onBeforeLoad(win: Window): void + onBeforeLoad(win: AUTWindow): void /** * Called once your page has fired its load event. * - * @param {Window} contentWindow the remote page's window object + * @param {AUTWindow} contentWindow the remote page's window object */ - onLoad(win: Window): void + onLoad(win: AUTWindow): void /** * Cypress will automatically apply the right authorization headers @@ -5031,12 +5047,12 @@ declare namespace Cypress { * Fires as the page begins to load, but before any of your applications JavaScript has executed. This fires at the exact same time as `cy.visit()` `onBeforeLoad` callback. Useful to modify the window on a page transition. * @see https://on.cypress.io/catalog-of-events#App-Events */ - (action: 'window:before:load', fn: (win: Window) => void): void + (action: 'window:before:load', fn: (win: AUTWindow) => void): void /** * Fires after all your resources have finished loading after a page transition. This fires at the exact same time as a `cy.visit()` `onLoad` callback. * @see https://on.cypress.io/catalog-of-events#App-Events */ - (action: 'window:load', fn: (win: Window) => void): void + (action: 'window:load', fn: (win: AUTWindow) => void): void /** * Fires when your application is about to navigate away. The real event object is provided to you. Your app may have set a `returnValue` on the event, which is useful to assert on. * @see https://on.cypress.io/catalog-of-events#App-Events @@ -5217,7 +5233,7 @@ declare namespace Cypress { interface Server extends RouteOptions { enable: boolean - whitelist: (xhr: any) => boolean + ignore: (xhr: any) => boolean } interface Viewport { diff --git a/cli/types/index.d.ts b/cli/types/index.d.ts index 8da316edd19d..64600eb51430 100644 --- a/cli/types/index.d.ts +++ b/cli/types/index.d.ts @@ -4,7 +4,7 @@ // Mike Woudenberg // Robbert van Markus // Nicholas Boll -// TypeScript Version: 3.0 +// TypeScript Version: 3.4 // Updated by the Cypress team: https://www.cypress.io/about/ /// diff --git a/cli/types/tests/actions.ts b/cli/types/tests/actions.ts index ae407691ce85..b022c1a8af6a 100644 --- a/cli/types/tests/actions.ts +++ b/cli/types/tests/actions.ts @@ -12,11 +12,11 @@ Cypress.on('window:alert', (text) => { }) Cypress.on('window:before:load', (win) => { - win // $ExpectType Window + win // $ExpectType AUTWindow }) Cypress.on('window:load', (win) => { - win // $ExpectType Window + win // $ExpectType AUTWindow }) Cypress.on('window:before:unload', (event) => { diff --git a/cli/types/tests/cypress-tests.ts b/cli/types/tests/cypress-tests.ts index bd3f194e0862..a7e6fa40d503 100644 --- a/cli/types/tests/cypress-tests.ts +++ b/cli/types/tests/cypress-tests.ts @@ -306,6 +306,24 @@ cy subject // $ExpectType undefined }) +namespace CypressAUTWindowTests { + cy.go(2).then((win) => { + win // $ExpectType AUTWindow + }) + + cy.reload().then((win) => { + win // $ExpectType AUTWindow + }) + + cy.visit('https://google.com').then(win => { + win // $ExpectType AUTWindow + }) + + cy.window().then(win => { + win // $ExpectType AUTWindow + }) +} + namespace CypressOnTests { Cypress.on('uncaught:exception', (error, runnable) => { error // $ExpectType Error diff --git a/cli/types/tests/kitchen-sink.ts b/cli/types/tests/kitchen-sink.ts index 8df9c1ea1d61..af59141f74f0 100644 --- a/cli/types/tests/kitchen-sink.ts +++ b/cli/types/tests/kitchen-sink.ts @@ -35,7 +35,7 @@ cy.visit('https://www.acme.com/', { const serverOptions: Partial = { delay: 100, - whitelist: () => true + ignore: () => true } cy.server(serverOptions) @@ -143,3 +143,9 @@ namespace BlobTests { dateUrl // $ExpectType string }) } + +cy.window().then(window => { + window // $ExpectType AUTWindow + + window.eval('1') +}) diff --git a/electron-builder.json b/electron-builder.json index 75b5402687ae..7f57dd04e93a 100644 --- a/electron-builder.json +++ b/electron-builder.json @@ -11,15 +11,16 @@ "entitlementsInherit": "./scripts/entitlements.mac.inherit.plist", "type": "distribution", "binaries": [ + "./build/mac/Cypress.app/Contents/Resources/app/packages/server/node_modules/watchpack-chokidar2/node_modules/fsevents/build/Release/.node", + "./build/mac/Cypress.app/Contents/Resources/app/packages/server/node_modules/watchpack-chokidar2/node_modules/fsevents/build/Release/fse.node", "./build/mac/Cypress.app/Contents/Resources/app/packages/server/node_modules/@ffmpeg-installer/darwin-x64/ffmpeg", - "./build/mac/Cypress.app/Contents/Resources/app/packages/server/node_modules/watchify/node_modules/fsevents/build/Release/.node", - "./build/mac/Cypress.app/Contents/Resources/app/packages/server/node_modules/watchify/node_modules/fsevents/build/Release/fse.node", "./build/mac/Cypress.app/Contents/Resources/app/packages/server/node_modules/registry-js/build/Release/registry.node", "./build/mac/Cypress.app/Contents/Resources/app/packages/server/node_modules/term-size/vendor/macos/term-size", "./build/mac/Cypress.app/Contents/Resources/app/packages/server/node_modules/trash/lib/macos-trash", "./build/mac/Cypress.app/Contents/Resources/app/packages/server/node_modules/babel-plugin-add-module-exports/node_modules/fsevents/build/Release/.node", "./build/mac/Cypress.app/Contents/Resources/app/packages/server/node_modules/babel-plugin-add-module-exports/node_modules/fsevents/build/Release/fse.node", - "./build/mac/Cypress.app/Contents/Resources/app/packages/server/node_modules/fsevents/fsevents.node" + "./build/mac/Cypress.app/Contents/Resources/app/packages/server/node_modules/fsevents/fsevents.node", + "./build/mac/Cypress.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Helpers/chrome_crashpad_handler" ] }, "linux": { diff --git a/package.json b/package.json index 9df2a027333f..51e3951dcc4c 100644 --- a/package.json +++ b/package.json @@ -121,8 +121,8 @@ "debug": "4.1.1", "decaffeinate": "6.0.9", "del": "3.0.0", - "electron-builder": "22.6.1", - "electron-notarize": "0.2.1", + "electron-builder": "22.8.0", + "electron-notarize": "1.0.0", "enzyme-adapter-react-16": "1.12.1", "eslint": "6.8.0", "eslint-plugin-cypress": "2.11.1", @@ -136,6 +136,7 @@ "fs-extra": "8.1.0", "gift": "0.10.2", "globby": "10.0.1", + "got": "11.5.1", "gulp": "4.0.2", "gulp-awspublish": "4.0.0", "gulp-debug": "4.0.0", @@ -163,7 +164,7 @@ "mocha-multi-reporters": "1.1.7", "mock-fs": "4.9.0", "parse-github-repo-url": "1.4.1", - "patch-package": "6.2.0", + "patch-package": "6.2.2", "percy": "0.26.9", "plist": "3.0.1", "pluralize": "8.0.0", @@ -187,7 +188,7 @@ "typescript": "3.7.4" }, "engines": { - "node": ">=12.8.1", + "node": ">=12.14.1", "yarn": ">=1.17.3" }, "productName": "Cypress", diff --git a/packages/desktop-gui/cypress/fixtures/config.json b/packages/desktop-gui/cypress/fixtures/config.json index f55c7483b7df..5da0c8d3e099 100644 --- a/packages/desktop-gui/cypress/fixtures/config.json +++ b/packages/desktop-gui/cypress/fixtures/config.json @@ -109,7 +109,7 @@ "cypressHostUrl": "http://localhost:2020", "cypressEnv": "development", "env": {}, - "blacklistHosts": [ + "blockHosts": [ "www.google-analytics.com", "hotjar.com" ], @@ -376,7 +376,7 @@ "from": "default", "value": true }, - "blacklistHosts": { + "blockHosts": { "from": "config", "value": [ "www.google-analytics.com", diff --git a/packages/desktop-gui/cypress/integration/settings_spec.js b/packages/desktop-gui/cypress/integration/settings_spec.js index 85eaf91711cd..c12317dd0ebe 100644 --- a/packages/desktop-gui/cypress/integration/settings_spec.js +++ b/packages/desktop-gui/cypress/integration/settings_spec.js @@ -116,9 +116,17 @@ describe('Settings', () => { .should('not.contain', '0:Chrome') cy.contains('span', 'browsers').parents('div').first().find('span').first().click() + cy.get('.config-vars').invoke('text') .should('contain', '0:Chrome') + // make sure the main collapsible content + // has finished animating and that it has + // an empty inline style attribute + cy.get('.rc-collapse-content') + .should('not.have.class', 'rc-collapse-anim') + .should('have.attr', 'style', '') + cy.percySnapshot() }) @@ -154,7 +162,7 @@ describe('Settings', () => { cy.get('@config-vars') .contains('span', 'Electron').parent('span').should('have.class', 'plugin') - cy.contains('span', 'blacklistHosts').parents('div').first().find('span').first().click() + cy.contains('span', 'blockHosts').parents('div').first().find('span').first().click() cy.get('@config-vars') .contains('span', 'www.google-analytics.com').parent('span').should('have.class', 'config') @@ -207,8 +215,8 @@ describe('Settings', () => { cy.get('.line').contains('*.foobar.com, *.bazqux.com') }) - it('displays "array" values for blacklistHosts', () => { - cy.contains('.line', 'blacklistHosts').contains('www.google-analytics.com, hotjar.com') + it('displays "array" values for blockHosts', () => { + cy.contains('.line', 'blockHosts').contains('www.google-analytics.com, hotjar.com') }) it('opens help link on click', () => { diff --git a/packages/desktop-gui/cypress/support/index.js b/packages/desktop-gui/cypress/support/index.js index f81291bfc71f..026e9b5ba5ed 100644 --- a/packages/desktop-gui/cypress/support/index.js +++ b/packages/desktop-gui/cypress/support/index.js @@ -1,4 +1,4 @@ -require('@percy/cypress') +require('@packages/ui-components/cypress/support/customPercyCommand') require('cypress-react-unit-test/dist/hooks') const BluebirdPromise = require('bluebird') diff --git a/packages/driver/cypress/integration/commands/agents_spec.js b/packages/driver/cypress/integration/commands/agents_spec.js index 0088dfc6c210..bff2ae3ea08f 100644 --- a/packages/driver/cypress/integration/commands/agents_spec.js +++ b/packages/driver/cypress/integration/commands/agents_spec.js @@ -352,11 +352,11 @@ describe('src/cy/commands/agents', () => { }).to.throw('`cy.as()` cannot be passed an empty string.') }) - _.each(['test', 'runnable', 'timeout', 'slow', 'skip', 'inspect'], (blacklist) => { - it(`throws on a blacklisted word: ${blacklist}`, () => { + _.each(['test', 'runnable', 'timeout', 'slow', 'skip', 'inspect'], (reserved) => { + it(`throws on a reserved word: ${reserved}`, () => { expect(() => { - cy.stub().as(blacklist) - }).to.throw(`\`cy.as()\` cannot be aliased as: \`${blacklist}\`. This word is reserved.`) + cy.stub().as(reserved) + }).to.throw(`\`cy.as()\` cannot be aliased as: \`${reserved}\`. This word is reserved.`) }) }) }) @@ -433,11 +433,11 @@ describe('src/cy/commands/agents', () => { }).to.throw('`cy.as()` cannot be passed an empty string.') }) - _.each(['test', 'runnable', 'timeout', 'slow', 'skip', 'inspect'], (blacklist) => { - it(`throws on a blacklisted word: ${blacklist}`, () => { + _.each(['test', 'runnable', 'timeout', 'slow', 'skip', 'inspect'], (reserved) => { + it(`throws on a reserved word: ${reserved}`, () => { expect(() => { - cy.stub().as(blacklist) - }).to.throw(`\`cy.as()\` cannot be aliased as: \`${blacklist}\`. This word is reserved.`) + cy.stub().as(reserved) + }).to.throw(`\`cy.as()\` cannot be aliased as: \`${reserved}\`. This word is reserved.`) }) }) }) diff --git a/packages/driver/cypress/integration/commands/aliasing_spec.js b/packages/driver/cypress/integration/commands/aliasing_spec.js index 3a88ff2d70fb..db17200a01cf 100644 --- a/packages/driver/cypress/integration/commands/aliasing_spec.js +++ b/packages/driver/cypress/integration/commands/aliasing_spec.js @@ -232,16 +232,16 @@ describe('src/cy/commands/aliasing', () => { cy.get('@my@Alias') }) - _.each(['test', 'runnable', 'timeout', 'slow', 'skip', 'inspect'], (blacklist) => { - it(`throws on a blacklisted word: ${blacklist}`, (done) => { + _.each(['test', 'runnable', 'timeout', 'slow', 'skip', 'inspect'], (reserved) => { + it(`throws on a reserved word: ${reserved}`, (done) => { cy.on('fail', (err) => { - expect(err.message).to.eq(`\`cy.as()\` cannot be aliased as: \`${blacklist}\`. This word is reserved.`) + expect(err.message).to.eq(`\`cy.as()\` cannot be aliased as: \`${reserved}\`. This word is reserved.`) expect(err.docsUrl).to.eq('https://on.cypress.io/as') done() }) - cy.get('div:first').as(blacklist) + cy.get('div:first').as(reserved) }) }) }) diff --git a/packages/driver/cypress/integration/commands/cookies_spec.js b/packages/driver/cypress/integration/commands/cookies_spec.js index 896f1fd5bb2e..4cd21b40b484 100644 --- a/packages/driver/cypress/integration/commands/cookies_spec.js +++ b/packages/driver/cypress/integration/commands/cookies_spec.js @@ -474,9 +474,7 @@ describe('src/cy/commands/cookies', () => { }) }) - it('can set cookies with sameSite', { - experimentalGetCookiesSameSite: true, - }, () => { + it('can set cookies with sameSite', () => { Cypress.automation.restore() Cypress.utils.addTwentyYears.restore() @@ -1248,4 +1246,18 @@ describe('src/cy/commands/cookies', () => { }) }) }) + + context('Cypress.cookies.defaults', () => { + it('throws error on use of renamed whitelist option', (done) => { + cy.on('fail', (err) => { + expect(err.message).to.include('`Cypress.Cookies.defaults` `whitelist` option has been renamed to `preserve`. Please rename `whitelist` to `preserve`.') + + done() + }) + + Cypress.Cookies.defaults({ + whitelist: 'session_id', + }) + }) + }) }) diff --git a/packages/driver/cypress/integration/commands/screenshot_spec.js b/packages/driver/cypress/integration/commands/screenshot_spec.js index dcb584a8d9d3..8e65dcd7315e 100644 --- a/packages/driver/cypress/integration/commands/screenshot_spec.js +++ b/packages/driver/cypress/integration/commands/screenshot_spec.js @@ -19,6 +19,7 @@ describe('src/cy/commands/screenshot', () => { takenAt: new Date().toISOString(), name: 'name', blackout: ['.foo'], + testAttemptIndex: 0, duration: 100, } @@ -49,7 +50,7 @@ describe('src/cy/commands/screenshot', () => { Cypress.action('runner:runnable:after:run:async', test, runnable) .then(() => { - expect(Cypress.action).not.to.be.calledWith('cy:test:set:state') + expect(Cypress.action).not.to.be.calledWith('test:set:state') expect(Cypress.automation).not.to.be.called }) .finally(() => { @@ -68,7 +69,7 @@ describe('src/cy/commands/screenshot', () => { Cypress.action('runner:runnable:after:run:async', test, runnable) .then(() => { - expect(Cypress.action).not.to.be.calledWith('cy:test:set:state') + expect(Cypress.action).not.to.be.calledWith('test:set:state') expect(Cypress.automation).not.to.be.called }) }) @@ -89,7 +90,7 @@ describe('src/cy/commands/screenshot', () => { Cypress.action('runner:runnable:after:run:async', test, runnable) .then(() => { - expect(Cypress.action).not.to.be.calledWith('cy:test:set:state') + expect(Cypress.action).not.to.be.calledWith('test:set:state') expect(Cypress.automation).not.to.be.called }) }) @@ -137,6 +138,7 @@ describe('src/cy/commands/screenshot', () => { waitForCommandSynchronization: true, disableTimersAndAnimations: true, blackout: [], + testAttemptIndex: 0, }) expect(Cypress.action).to.be.calledWith('cy:after:screenshot', { @@ -147,6 +149,7 @@ describe('src/cy/commands/screenshot', () => { waitForCommandSynchronization: true, disableTimersAndAnimations: true, blackout: [], + testAttemptIndex: 0, }) }) }) @@ -183,6 +186,7 @@ describe('src/cy/commands/screenshot', () => { testFailure: true, blackout: [], scaled: true, + testAttemptIndex: 0, }) }) }) @@ -225,6 +229,7 @@ describe('src/cy/commands/screenshot', () => { simple: false, scaled: true, blackout: [], + testAttemptIndex: 0, }) }) }) @@ -264,6 +269,7 @@ describe('src/cy/commands/screenshot', () => { testFailure: true, scaled: true, blackout: [], + testAttemptIndex: 0, }) }) }) @@ -406,6 +412,7 @@ describe('src/cy/commands/screenshot', () => { waitForCommandSynchronization: false, disableTimersAndAnimations: true, blackout: ['.foo'], + testAttemptIndex: 0, }) }) }) @@ -425,6 +432,7 @@ describe('src/cy/commands/screenshot', () => { waitForCommandSynchronization: false, disableTimersAndAnimations: true, blackout: ['.foo'], + testAttemptIndex: 0, }) }) }) @@ -446,6 +454,7 @@ describe('src/cy/commands/screenshot', () => { waitForCommandSynchronization: true, disableTimersAndAnimations: true, blackout: [], + testAttemptIndex: 0, }) }) }) @@ -466,6 +475,7 @@ describe('src/cy/commands/screenshot', () => { waitForCommandSynchronization: false, disableTimersAndAnimations: true, blackout: ['.foo'], + testAttemptIndex: 0, }) }) }) diff --git a/packages/driver/cypress/integration/commands/xhr_spec.js b/packages/driver/cypress/integration/commands/xhr_spec.js index a29bec5ccaab..295eb11f67bc 100644 --- a/packages/driver/cypress/integration/commands/xhr_spec.js +++ b/packages/driver/cypress/integration/commands/xhr_spec.js @@ -305,39 +305,6 @@ describe('src/cy/commands/xhr', () => { }) }) - // FIXME: I have no idea why this is skipped, this test is rly old - describe.skip('filtering requests', () => { - beforeEach(() => { - cy.server() - }) - - const extensions = { - html: 'ajax html', - js: '{foo: "bar"}', - css: 'body {}', - } - - _.each(extensions, (val, ext) => { - it(`filters out non ajax requests by default for extension: .${ext}`, (done) => { - cy.state('window').$.get(`/fixtures/app.${ext}`).done((res) => { - expect(res).to.eq(val) - - done() - }) - }) - }) - - it('can disable default filtering', (done) => { - // this should throw since it should return 404 when no - // route matches it - cy.server({ ignore: false }).window().then((w) => { - Promise.resolve(w.$.get('/fixtures/app.html')).catch(() => { - done() - }) - }) - }) - }) - describe('url rewriting', () => { it('has a FQDN absolute-relative url', () => { cy @@ -1167,6 +1134,14 @@ describe('src/cy/commands/xhr', () => { }) }) + it('sets ignore as function by default', () => { + cy.server() + cy.route('*', {}) + .then(() => { + expect(cy.state('server').getRoutes()[0].ignore).to.be.a('function') + }) + }) + it('passes down options.delay to routes', () => { cy .server({ delay: 100 }) @@ -1271,110 +1246,6 @@ describe('src/cy/commands/xhr', () => { }) }) - // FIXME: I have no idea why this is skipped, this test is rly old - context.skip('#server', () => { - beforeEach(function () { - const defaults = { - ignore: true, - respond: true, - delay: 10, - beforeRequest () {}, - afterResponse () {}, - onAbort () {}, - onError () {}, - onFilter () {}, - } - - this.options = (obj) => { - return _.extend(obj, defaults) - } - - this.create = cy.spy(this.Cypress.Server, 'create') - }) - - it('can accept an onRequest and onResponse callback', function (done) { - const onRequest = () => {} - const onResponse = () => {} - - cy.on('end', () => { - expect(this.create.getCall(0).args[1]).to.have.keys(_.keys(this.options({ onRequest, onResponse }))) - - done() - }) - - cy.server(onRequest, onResponse) - }) - - it('can accept onRequest and onRespond through options', function (done) { - const onRequest = () => {} - const onResponse = () => {} - - cy.on('end', () => { - expect(this.create.getCall(0).args[1]).to.have.keys(_.keys(this.options({ onRequest, onResponse }))) - - done() - }) - - cy.server({ onRequest, onResponse }) - }) - - describe('without sinon present', () => { - beforeEach(() => { - // force us to start from blank window - cy.state('$autIframe').prop('src', 'about:blank') - }) - - it('can start server with no errors', () => { - cy - .server() - .visit('http://localhost:3500/fixtures/sinon.html') - }) - - it('can add routes with no errors', () => { - cy - .server() - .route(/foo/, {}) - .visit('http://localhost:3500/fixtures/sinon.html') - }) - - it('routes xhr requests', () => { - cy - .server() - .route(/foo/, { foo: 'bar' }) - .visit('http://localhost:3500/fixtures/sinon.html') - .window().then((w) => { - return w.$.get('/foo') - }) - .then((resp) => { - expect(resp).to.deep.eq({ foo: 'bar' }) - }) - }) - - it('works with aliases', () => { - cy - .server() - .route(/foo/, { foo: 'bar' }).as('getFoo') - .visit('http://localhost:3500/fixtures/sinon.html') - .window().then((w) => { - return w.$.get('/foo') - }) - .wait('@getFoo').then((xhr) => { - expect(xhr.responseText).to.eq(JSON.stringify({ foo: 'bar' })) - }) - }) - - it('prevents XHR\'s from going out from sinon.html', () => { - cy - .server() - .route(/bar/, { bar: 'baz' }).as('getBar') - .visit('http://localhost:3500/fixtures/sinon.html') - .wait('@getBar').then((xhr) => { - expect(xhr.responseText).to.eq(JSON.stringify({ bar: 'baz' })) - }) - }) - }) - }) - context('#route', () => { beforeEach(function () { this.expectOptionsToBe = (opts) => { @@ -1937,6 +1808,16 @@ describe('src/cy/commands/xhr', () => { cy.route() }) + it('throws on use of whitelist option', (done) => { + cy.on('fail', (err) => { + expect(err.message).to.include('The `cy.server()` `whitelist` option has been renamed to `ignore`. Please rename `whitelist` to `ignore`.') + + done() + }) + + cy.server({ whitelist: () => { } }) + }) + it('url must be a string or regexp', (done) => { cy.on('fail', (err) => { expect(err.message).to.include('`cy.route()` was called with an invalid `url`. `url` must be either a string or regular expression.') @@ -2326,8 +2207,8 @@ describe('src/cy/commands/xhr', () => { }) }) - describe('whitelisting', () => { - it('does not send back 404s on whitelisted routes', () => { + describe('ignored routes', () => { + it('does not send back 404s on allowed routes', () => { cy .server() .window().then((win) => { @@ -2339,7 +2220,7 @@ describe('src/cy/commands/xhr', () => { }) // https://github.com/cypress-io/cypress/issues/7280 - it('ignores query params when whitelisting routes', () => { + it('ignores query params when filtering routes', () => { cy.server() cy.route(/url-with-query-param/, { foo: 'bar' }).as('getQueryParam') cy.window().then((win) => { @@ -2353,7 +2234,7 @@ describe('src/cy/commands/xhr', () => { }) // https://github.com/cypress-io/cypress/issues/7280 - it('ignores hashes when whitelisting routes', () => { + it('ignores hashes when filtering routes', () => { cy.server() cy.route(/url-with-hash/, { foo: 'bar' }).as('getHash') cy.window().then((win) => { @@ -2365,6 +2246,30 @@ describe('src/cy/commands/xhr', () => { cy.wait('@getHash').its('response.body') .should('deep.equal', { foo: 'bar' }) }) + + it('overrides ignoring resources when passed as option', () => { + cy.server({ ignore: () => false }) + cy.route('app.js', { foo: 'bar' }).as('getJSResource') + cy.route('index.html', '').as('getHTMLResource') + cy.route('style.css', 'body: {color: red;}').as('getCSSResource') + cy.window().then((win) => { + win.$.get('/fixtures/app.js') + win.$.get('/fixtures/style.css') + + return win.$.get('/fixtures/index.html') + }) + + // normally these resources would be ignored + // but overwriting ignore to return false allows all resources + cy.wait('@getJSResource').its('response.body') + .should('deep.equal', { foo: 'bar' }) + + cy.wait('@getHTMLResource').its('response.body') + .should('deep.equal', '') + + cy.wait('@getCSSResource').its('response.body') + .should('deep.equal', 'body: {color: red;}') + }) }) describe('route setup', () => { diff --git a/packages/driver/cypress/integration/e2e/uncaught_errors_spec.js b/packages/driver/cypress/integration/e2e/uncaught_errors_spec.js index 6651e0aad5ca..bd3b3af01ddf 100644 --- a/packages/driver/cypress/integration/e2e/uncaught_errors_spec.js +++ b/packages/driver/cypress/integration/e2e/uncaught_errors_spec.js @@ -117,7 +117,18 @@ describe('uncaught errors', () => { expect(uncaught).to.be.true expect(err.message).to.include('foo is not defined') expect(click.get('name')).to.eq('click') - expect(click.get('error')).to.eq(err) + + // TODO: when there's an uncaught exception event + // we should log this to the command log so then + // we could update this test to always reference + // that command log + // + // FIXME: in firefox this test sometimes fails + // because the cy.click() command resolves before + // the page navigation event occurs and therefore + // the state('current') command is null'd out and + // firefox does not highlight the click command in read + // expect(click.get('error')).to.eq(err) done() }) @@ -127,7 +138,10 @@ describe('uncaught errors', () => { .window().then((win) => { return win.$('visit') .appendTo(win.document.body) - }).contains('visit').click() + }) + .contains('visit').click() + + cy.url().should('include', 'visit_error.html') }) // https://github.com/cypress-io/cypress/issues/987 diff --git a/packages/driver/cypress/integration/util/breaking_change_warnings_spec.js b/packages/driver/cypress/integration/util/breaking_change_warnings_spec.js new file mode 100644 index 000000000000..5d3acf47228d --- /dev/null +++ b/packages/driver/cypress/integration/util/breaking_change_warnings_spec.js @@ -0,0 +1,45 @@ +describe('blob-util 2.x', () => { + it('arrayBufferToBlob', (done) => { + cy.on('fail', (err) => { + expect(err.message).to.include('no longer returns a `Promise`') + done() + }) + + Cypress.Blob.arrayBufferToBlob('1234').then((blob) => { + // it should fail. + }) + }) + + it('base64StringToBlob', (done) => { + cy.on('fail', (err) => { + expect(err.message).to.include('no longer returns a `Promise`') + done() + }) + + Cypress.Blob.base64StringToBlob('1234').then((blob) => { + // it should fail. + }) + }) + + it('binaryStringToBlob', (done) => { + cy.on('fail', (err) => { + expect(err.message).to.include('no longer returns a `Promise`') + done() + }) + + Cypress.Blob.binaryStringToBlob('0100101').then((blob) => { + // it should fail. + }) + }) + + it('dataURLToBlob', (done) => { + cy.on('fail', (err) => { + expect(err.message).to.include('no longer returns a `Promise`') + done() + }) + + Cypress.Blob.dataURLToBlob('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==').then((blob) => { + // it should fail. + }) + }) +}) diff --git a/packages/driver/package.json b/packages/driver/package.json index b2622310fcf6..4b5d00a0b637 100644 --- a/packages/driver/package.json +++ b/packages/driver/package.json @@ -18,11 +18,16 @@ "@cypress/what-is-circular": "1.0.1", "@packages/network": "*", "@packages/runner": "*", + "@packages/server": "*", "@packages/ts": "*", + "@types/chalk": "^2.2.0", + "@types/common-tags": "^1.8.0", + "@types/lodash": "^4.14.123", + "@types/mocha": "^5.2.6", "angular": "1.8.0", "backbone": "1.4.0", "basic-auth": "2.0.1", - "blob-util": "1.3.0", + "blob-util": "2.0.2", "bluebird": "3.5.3", "body-parser": "1.19.0", "bootstrap": "4.4.1", diff --git a/packages/driver/src/cy/aliases.js b/packages/driver/src/cy/aliases.js index 8bf2dff1c6ab..fe7db54847b8 100644 --- a/packages/driver/src/cy/aliases.js +++ b/packages/driver/src/cy/aliases.js @@ -6,7 +6,7 @@ const aliasRe = /^@.+/ const aliasDisplayRe = /^([@]+)/ const requestXhrRe = /\.request$/ -const blacklist = ['test', 'runnable', 'timeout', 'slow', 'skip', 'inspect'] +const reserved = ['test', 'runnable', 'timeout', 'slow', 'skip', 'inspect'] const aliasDisplayName = (name) => { return name.replace(aliasDisplayRe, '') @@ -38,7 +38,7 @@ const validateAlias = (alias) => { $errUtils.throwErrByPath('as.empty_string') } - if (blacklist.includes(alias)) { + if (reserved.includes(alias)) { return $errUtils.throwErrByPath('as.reserved_word', { args: { alias } }) } } diff --git a/packages/driver/src/cy/commands/cookies.js b/packages/driver/src/cy/commands/cookies.js index b5fda3ad6ac2..85c3170b7b30 100644 --- a/packages/driver/src/cy/commands/cookies.js +++ b/packages/driver/src/cy/commands/cookies.js @@ -58,12 +58,6 @@ const normalizeSameSite = (sameSite) => { } module.exports = function (Commands, Cypress, cy, state, config) { - const maybeStripSameSiteProp = (cookie) => { - if (cookie && !Cypress.config('experimentalGetCookiesSameSite')) { - delete cookie.sameSite - } - } - const automateCookies = function (event, obj = {}, log, timeout) { const automate = () => { return Cypress.automation(event, mergeDefaults(obj)) @@ -101,7 +95,7 @@ module.exports = function (Commands, Cypress, cy, state, config) { return resp } - // iterate over all of these and ensure none are whitelisted + // iterate over all of these and ensure none are allowed // or preserved const cookies = Cypress.Cookies.getClearableCookies(resp) @@ -183,8 +177,6 @@ module.exports = function (Commands, Cypress, cy, state, config) { return automateCookies('get:cookie', { name }, options._log, options.timeout) .then((resp) => { - maybeStripSameSiteProp(resp) - options.cookie = resp return resp @@ -222,10 +214,6 @@ module.exports = function (Commands, Cypress, cy, state, config) { return automateCookies('get:cookies', _.pick(options, 'domain'), options._log, options.timeout) .then((resp) => { - if (Array.isArray(resp)) { - resp.forEach(maybeStripSameSiteProp) - } - options.cookies = resp return resp @@ -299,8 +287,6 @@ module.exports = function (Commands, Cypress, cy, state, config) { return automateCookies('set:cookie', cookie, options._log, options.timeout) .then((resp) => { - maybeStripSameSiteProp(resp) - options.cookie = resp return resp diff --git a/packages/driver/src/cy/commands/navigation.js b/packages/driver/src/cy/commands/navigation.js index 7a234465a514..15f67911e3ec 100644 --- a/packages/driver/src/cy/commands/navigation.js +++ b/packages/driver/src/cy/commands/navigation.js @@ -842,6 +842,9 @@ module.exports = (Commands, Cypress, cy, state, config) => { if (previousDomainVisited && (remote.originPolicy !== existing.originPolicy)) { // if we've already visited a new superDomain // then die else we'd be in a terrible endless loop + // we also need to disable retries to prevent the endless loop + $utils.getTestFromRunnable(state('runnable'))._retries = 0 + return cannotVisitDifferentOrigin(remote.origin, previousDomainVisited, remote, existing, options._log) } diff --git a/packages/driver/src/cy/commands/screenshot.js b/packages/driver/src/cy/commands/screenshot.js index 708383cb6a96..d924bcbae8e2 100644 --- a/packages/driver/src/cy/commands/screenshot.js +++ b/packages/driver/src/cy/commands/screenshot.js @@ -7,6 +7,7 @@ const Promise = require('bluebird') const $Screenshot = require('../../cypress/screenshot') const $dom = require('../../dom') const $errUtils = require('../../cypress/error_utils') +const $utils = require('../../cypress/utils') const getViewportHeight = (state) => { // TODO this doesn't seem correct @@ -54,6 +55,7 @@ const automateScreenshot = (state, options = {}) => { titles, testId: runnable.id, takenPaths: state('screenshotPaths'), + testAttemptIndex: $utils.getTestFromRunnable(runnable)._currentRetry, }, _.omit(options, 'runnable', 'timeout', 'log', 'subject')) const automate = () => { @@ -304,6 +306,7 @@ const takeScreenshot = (Cypress, state, screenshotConfig, options = {}) => { const getOptions = (isOpen) => { return { id: runnable.id, + testAttemptIndex: $utils.getTestFromRunnable(runnable)._currentRetry, isOpen, appOnly: isAppOnly(screenshotConfig), scale: getShouldScale(screenshotConfig), diff --git a/packages/driver/src/cy/keyboard.ts b/packages/driver/src/cy/keyboard.ts index c93d5361a1cd..2152422ff2a6 100644 --- a/packages/driver/src/cy/keyboard.ts +++ b/packages/driver/src/cy/keyboard.ts @@ -263,7 +263,7 @@ const shouldUpdateValue = (el: HTMLElement, key: KeyDetails, options: typeOption if (!(numberRe.test(potentialValue))) { debug('skipping inserting value since number input would be invalid', key.text, potentialValue) - // when typing in a number input, only certain whitelisted chars will insert text + // when typing in a number input, only certain allowed chars will insert text if (!key.text.match(isValidNumberInputChar)) { // https://github.com/cypress-io/cypress/issues/6055 // Should not remove old valid values when a new one is not a valid number char, just dismiss it with return diff --git a/packages/driver/src/cypress.js b/packages/driver/src/cypress.js index 2288e3b56024..280803024402 100644 --- a/packages/driver/src/cypress.js +++ b/packages/driver/src/cypress.js @@ -34,6 +34,7 @@ const $scriptUtils = require('./cypress/script_utils') const browserInfo = require('./cypress/browser') const resolvers = require('./cypress/resolvers') const debug = require('debug')('cypress:driver:cypress') +const { wrapBlobUtil } = require('./util/breaking_change_warning') const jqueryProxyFn = function (...args) { if (!this.cy) { @@ -164,6 +165,19 @@ class $Cypress { this.config = $SetterGetter.create(config) this.env = $SetterGetter.create(env) this.getFirefoxGcInterval = $FirefoxForcedGc.createIntervalGetter(this.config) + this.getTestRetries = function () { + const testRetries = this.config('retries') + + if (_.isNumber(testRetries)) { + return testRetries + } + + if (_.isObject(testRetries)) { + return testRetries[this.config('isInteractive') ? 'openMode' : 'runMode'] + } + + return null + } this.Cookies = $Cookies.create(config.namespace, d) @@ -268,11 +282,6 @@ class $Cypress { break - case 'runner:set:runnable': - // when there is a hook / test (runnable) that - // is about to be invoked - return this.cy.setRunnable(...args) - case 'runner:suite:start': // mocha runner started processing a suite if (this.config('isTextTerminal')) { @@ -322,6 +331,8 @@ class $Cypress { case 'runner:pass': // mocha runner calculated a pass + // this is delayed from when mocha would normally fire it + // since we fire it after all afterEach hooks have ran if (this.config('isTextTerminal')) { return this.emit('mocha', 'pass', ...args) } @@ -358,6 +369,16 @@ class $Cypress { break } + // retry event only fired in mocha version 6+ + // https://github.com/mochajs/mocha/commit/2a76dd7589e4a1ed14dd2a33ab89f182e4c4a050 + case 'runner:retry': { + // mocha runner calculated a pass + if (this.config('isTextTerminal')) { + this.emit('mocha', 'retry', ...args) + } + + break + } case 'mocha:runnable:run': return this.runner.onRunnableRun(...args) @@ -366,7 +387,14 @@ class $Cypress { // get back to a clean slate this.cy.reset(...args) - return this.emit('test:before:run', ...args) + if (this.config('isTextTerminal')) { + // needed for handling test retries + this.emit('mocha', 'test:before:run', args[0]) + } + + this.emit('test:before:run', ...args) + + break case 'runner:test:before:run:async': // TODO: handle timeouts here? or in the runner? @@ -618,7 +646,7 @@ $Cypress.prototype.SelectorPlayground = $SelectorPlayground $Cypress.prototype.utils = $utils $Cypress.prototype._ = _ $Cypress.prototype.moment = moment -$Cypress.prototype.Blob = blobUtil +$Cypress.prototype.Blob = wrapBlobUtil(blobUtil) $Cypress.prototype.Promise = Promise $Cypress.prototype.minimatch = minimatch $Cypress.prototype.sinon = sinon diff --git a/packages/driver/src/cypress/cookies.js b/packages/driver/src/cypress/cookies.js index 01b92e441743..76d83d4fa1e8 100644 --- a/packages/driver/src/cypress/cookies.js +++ b/packages/driver/src/cypress/cookies.js @@ -9,7 +9,13 @@ let isDebuggingVerbose = false const preserved = {} const defaults = { - whitelist: null, + preserve: null, +} + +const warnOnWhitelistRenamed = (obj, type) => { + if (obj.whitelist) { + return $errUtils.throwErrByPath('cookies.whitelist_renamed', { args: { type } }) + } } const $Cookies = (namespace, domain) => { @@ -17,8 +23,8 @@ const $Cookies = (namespace, domain) => { return _.startsWith(name, namespace) } - const isWhitelisted = (cookie) => { - const w = defaults.whitelist + const isAllowed = (cookie) => { + const w = defaults.preserve if (w) { if (_.isString(w)) { @@ -76,7 +82,7 @@ const $Cookies = (namespace, domain) => { getClearableCookies (cookies = []) { return _.filter(cookies, (cookie) => { - return !isWhitelisted(cookie) && !removePreserved(cookie.name) + return !isAllowed(cookie) && !removePreserved(cookie.name) }) }, @@ -132,6 +138,8 @@ const $Cookies = (namespace, domain) => { }, defaults (obj = {}) { + warnOnWhitelistRenamed(obj, 'Cypress.Cookies.defaults') + // merge obj into defaults return _.extend(defaults, obj) }, diff --git a/packages/driver/src/cypress/cy.js b/packages/driver/src/cypress/cy.js index 3cdbc2052d18..66708bad974e 100644 --- a/packages/driver/src/cypress/cy.js +++ b/packages/driver/src/cypress/cy.js @@ -1282,6 +1282,8 @@ const create = function (specWindow, Cypress, Cookies, state, config, log) { state('runnable', runnable) + state('test', $utils.getTestFromRunnable(runnable)) + state('ctx', runnable.ctx) const { fn } = runnable diff --git a/packages/driver/src/cypress/error_messages.js b/packages/driver/src/cypress/error_messages.js index 1355148a7dd8..1436bc622c31 100644 --- a/packages/driver/src/cypress/error_messages.js +++ b/packages/driver/src/cypress/error_messages.js @@ -153,6 +153,15 @@ module.exports = { }, }, + breaking_change: { + blob_util2 (obj) { + return { + message: `\`${obj.functionName}()\` no longer returns a \`Promise\`. Update the use of \`${obj.functionName}()\` to expect a returned \`Blob\`.`, + docsUrl: 'https://on.cypress.io/migration-guide', + } + }, + }, + browser: { invalid_arg: '{{prefix}} must be passed a string, object, or an array. You passed: `{{obj}}`', }, @@ -301,6 +310,11 @@ module.exports = { - \`cy.clearCookie()\` - \`cy.clearCookies()\``, }, + whitelist_renamed (obj) { + return { + message: `\`${obj.type}\` \`whitelist\` option has been renamed to \`preserve\`. Please rename \`whitelist\` to \`preserve\`.`, + } + }, }, dom: { @@ -870,6 +884,33 @@ module.exports = { {{error}}`, docsUrl: 'https://on.cypress.io/returning-promise-and-invoking-done-callback', }, + manually_set_retries_test: stripIndent`\ + Mocha \`this.retries()\` syntax is not supported. + + To configure retries use the following syntax: + + \`\`\` + it('{{title}}', { retries: {{numRetries}} }, () => { + ... + }) + \`\`\` + + https://on.cypress.io/test-retries + `, + manually_set_retries_suite: stripIndent`\ + Mocha \`this.retries()\` syntax is not supported. + + To configure retries use the following syntax: + + \`\`\` + describe('{{title}}', { retries: {{numRetries}} }, () => { + ... + }) + \`\`\` + + https://on.cypress.io/test-retries + `, + }, navigation: { @@ -1294,6 +1335,7 @@ module.exports = { }, xhrurl_not_set: '`Server.options.xhrUrl` has not been set', unavailable: 'The XHR server is unavailable or missing. This should never happen and likely is a bug. Open an issue if you see this message.', + whitelist_renamed: `The ${cmd('server')} \`whitelist\` option has been renamed to \`ignore\`. Please rename \`whitelist\` to \`ignore\`.`, }, setCookie: { @@ -1580,6 +1622,10 @@ module.exports = { msg += 'all of the remaining tests.' } + if ((obj.hookName === 'after all' || obj.hookName === 'before all') && obj.retries > 0) { + msg += `\n\nAlthough you have test retries enabled, we do not retry tests when \`before all\` or \`after all\` hooks fail` + } + return msg }, error (obj) { diff --git a/packages/driver/src/cypress/log.js b/packages/driver/src/cypress/log.js index 363856aec9b1..0d8a91aab247 100644 --- a/packages/driver/src/cypress/log.js +++ b/packages/driver/src/cypress/log.js @@ -13,7 +13,7 @@ const $errUtils = require('./error_utils') const groupsOrTableRe = /^(groups|table)$/ const parentOrChildRe = /parent|child/ const SNAPSHOT_PROPS = 'id snapshots $el url coords highlightAttr scrollBy viewportWidth viewportHeight'.split(' ') -const DISPLAY_PROPS = 'id alias aliasType callCount displayName end err event functionName hookId instrument isStubbed message method name numElements numResponses referencesAlias renderProps state testId timeout type url visible wallClockStartedAt'.split(' ') +const DISPLAY_PROPS = 'id alias aliasType callCount displayName end err event functionName hookId instrument isStubbed message method name numElements numResponses referencesAlias renderProps state testId timeout type url visible wallClockStartedAt testCurrentRetry'.split(' ') const BLACKLIST_PROPS = 'snapshots'.split(' ') let delay = null @@ -90,10 +90,12 @@ const countLogsByTests = function (tests = {}) { return _ .chain(tests) - .map((test, key) => { - return [].concat(test.agents, test.routes, test.commands) - }).flatten() - .compact() + .flatMap((test) => { + return [test, test.prevAttempts] + }) + .flatMap((tests) => { + return [].concat(tests.agents, tests.routes, tests.commands) + }).compact() .union([{ id: 0 }]) .map('id') .max() @@ -167,6 +169,16 @@ const defaults = function (state, config, obj) { const runnable = state('runnable') + const getTestAttemptFromRunnable = (runnable) => { + if (!runnable) { + return + } + + const t = $utils.getTestFromRunnable(runnable) + + return t._currentRetry || 0 + } + return _.defaults(obj, { id: (counter += 1), state: 'pending', @@ -174,6 +186,7 @@ const defaults = function (state, config, obj) { url: state('url'), hookId: state('hookId'), testId: runnable ? runnable.id : undefined, + testCurrentRetry: getTestAttemptFromRunnable(state('runnable')), viewportWidth: state('viewportWidth'), viewportHeight: state('viewportHeight'), referencesAlias: undefined, diff --git a/packages/driver/src/cypress/mocha.js b/packages/driver/src/cypress/mocha.js index 04a248533ef0..bb44c2ef8313 100644 --- a/packages/driver/src/cypress/mocha.js +++ b/packages/driver/src/cypress/mocha.js @@ -1,5 +1,8 @@ +/* eslint-disable prefer-rest-params */ + const _ = require('lodash') const $errUtils = require('./error_utils') +const { getTestFromRunnable } = require('./utils') const $stackUtils = require('./stack_utils') // in the browser mocha is coming back @@ -7,13 +10,19 @@ const $stackUtils = require('./stack_utils') const mocha = require('mocha') const Mocha = mocha.Mocha != null ? mocha.Mocha : mocha -const { Test, Runner, Runnable } = Mocha +const { Test, Runner, Runnable, Hook, Suite } = Mocha const runnerRun = Runner.prototype.run const runnerFail = Runner.prototype.fail +const runnerRunTests = Runner.prototype.runTests const runnableRun = Runnable.prototype.run const runnableClearTimeout = Runnable.prototype.clearTimeout const runnableResetTimeout = Runnable.prototype.resetTimeout +const testRetries = Test.prototype.retries +const testClone = Test.prototype.clone +const suiteAddTest = Suite.prototype.addTest +const suiteRetries = Suite.prototype.retries +const hookRetries = Hook.prototype.retries // don't let mocha polute the global namespace delete window.mocha @@ -241,6 +250,62 @@ const restoreRunnableRun = () => { Runnable.prototype.run = runnableRun } +const restoreSuiteRetries = () => { + Suite.prototype.retries = suiteRetries +} + +function restoreTestClone () { + Test.prototype.clone = testClone +} + +function restoreRunnerRunTests () { + Runner.prototype.runTests = runnerRunTests +} + +function restoreSuiteAddTest () { + Mocha.Suite.prototype.addTest = suiteAddTest +} +const restoreHookRetries = () => { + Hook.prototype.retries = hookRetries +} + +const patchSuiteRetries = () => { + Suite.prototype.retries = function (...args) { + if (args[0] !== undefined && args[0] > -1) { + const err = $errUtils.cypressErrByPath('mocha.manually_set_retries_suite', { + args: { + title: this.title, + numRetries: args[0] ?? 2, + }, + }) + + throw err + } + + return suiteRetries.apply(this, args) + } +} + +const patchHookRetries = () => { + Hook.prototype.retries = function (...args) { + if (args[0] !== undefined && args[0] > -1) { + const err = $errUtils.cypressErrByPath('mocha.manually_set_retries_suite', { + args: { + title: this.parent.title, + numRetries: args[0] ?? 2, + }, + }) + + // so this error doesn't cause a retry + getTestFromRunnable(this)._retries = -1 + + throw err + } + + return hookRetries.apply(this, args) + } +} + // matching the current Runner.prototype.fail except // changing the logic for determing whether this is a valid err const patchRunnerFail = () => { @@ -274,6 +339,50 @@ const patchRunnableRun = (Cypress) => { } } +function patchTestClone () { + Test.prototype.clone = function () { + if (this._retriesBeforeEachFailedTestFn) { + this.fn = this._retriesBeforeEachFailedTestFn + } + + const ret = testClone.apply(this, arguments) + + // carry over testConfigOverrides + ret.cfg = this.cfg + + // carry over test.id + ret.id = this.id + + return ret + } +} + +function patchRunnerRunTests () { + Runner.prototype.runTests = function () { + const suite = arguments[0] + + const _slice = suite.tests.slice + + // HACK: we need to dynamically enqueue tests to suite.tests during a test run + // however Mocha calls `.slice` on this property and thus we no longer have a reference + // to the internal test queue. So we replace the .slice method + // in a way that we keep a reference to the returned array. we name it suite.testsQueue + suite.tests.slice = function () { + this.slice = _slice + + const ret = _slice.apply(this, arguments) + + suite.testsQueue = ret + + return ret + } + + const ret = runnerRunTests.apply(this, arguments) + + return ret + } +} + const patchRunnableClearTimeout = () => { Runnable.prototype.clearTimeout = function (...args) { // call the original @@ -283,6 +392,34 @@ const patchRunnableClearTimeout = () => { } } +function patchSuiteAddTest (Cypress) { + Mocha.Suite.prototype.addTest = function (...args) { + const test = args[0] + + const ret = suiteAddTest.apply(this, args) + + test.retries = function (...args) { + if (args[0] !== undefined && args[0] > -1) { + const err = $errUtils.cypressErrByPath('mocha.manually_set_retries_test', { + args: { + title: test.title, + numRetries: args[0] ?? 2, + }, + }) + + // so this error doesn't cause a retry + test._retries = -1 + + throw err + } + + return testRetries.apply(this, args) + } + + return ret + } +} + const patchRunnableResetTimeout = () => { Runnable.prototype.resetTimeout = function () { const runnable = this @@ -319,6 +456,11 @@ const restore = () => { restoreRunnableRun() restoreRunnableClearTimeout() restoreRunnableResetTimeout() + restoreSuiteRetries() + restoreHookRetries() + restoreRunnerRunTests() + restoreTestClone() + restoreSuiteAddTest() } const override = (Cypress) => { @@ -326,6 +468,11 @@ const override = (Cypress) => { patchRunnableRun(Cypress) patchRunnableClearTimeout() patchRunnableResetTimeout() + patchSuiteRetries() + patchHookRetries() + patchRunnerRunTests() + patchTestClone() + patchSuiteAddTest(Cypress) } const create = (specWindow, Cypress, config) => { diff --git a/packages/driver/src/cypress/runner.js b/packages/driver/src/cypress/runner.js index ab8f6a6625c8..2f0178aa5919 100644 --- a/packages/driver/src/cypress/runner.js +++ b/packages/driver/src/cypress/runner.js @@ -18,7 +18,7 @@ const TEST_BEFORE_RUN_EVENT = 'runner:test:before:run' const TEST_AFTER_RUN_EVENT = 'runner:test:after:run' const RUNNABLE_LOGS = 'routes agents commands hooks'.split(' ') -const RUNNABLE_PROPS = 'id order title root hookName hookId err state failedFromHookId body speed type duration wallClockStartedAt wallClockDuration timings file originalTitle invocationDetails'.split(' ') +const RUNNABLE_PROPS = 'id order title root hookName hookId err state failedFromHookId body speed type duration wallClockStartedAt wallClockDuration timings file originalTitle invocationDetails final currentRetry retries'.split(' ') const debug = require('debug')('cypress:driver:runner') @@ -54,9 +54,8 @@ const runnableAfterRunAsync = (runnable, Cypress) => { runnable.clearTimeout() return Promise.try(() => { - if (!fired('runner:runnable:after:run:async', runnable)) { - return fire('runner:runnable:after:run:async', runnable, Cypress) - } + // NOTE: other events we do not fire more than once, but this needed to change for test-retries + return fire('runner:runnable:after:run:async', runnable, Cypress) }) } @@ -224,12 +223,14 @@ const findLastTestInSuite = (suite, fn = _.identity) => { const getAllSiblingTests = (suite, getTestById) => { const tests = [] - suite.eachTest((test) => { + suite.eachTest((testRunnable) => { // iterate through each of our suites tests. // this will iterate through all nested tests // as well. and then we add it only if its // in our filtered tests array - if (getTestById(test.id)) { + const test = getTestById(testRunnable.id) + + if (test) { return tests.push(test) } }) @@ -291,7 +292,7 @@ const lastTestThatWillRunInSuite = (test, tests) => { } const isLastTest = (test, tests) => { - return test === _.last(tests) + return test.id === _.get(_.last(tests), 'id') } const isRootSuite = (suite) => { @@ -308,73 +309,94 @@ const overrideRunnerHook = (Cypress, _runner, getTestById, getTest, setTest, get // monkey patch the hook event so we can wrap // 'test:after:run' around all of // the hooks surrounding a test runnable - const _runnerHook = _runner.hook - - _runner.hook = function (name, fn) { - const allTests = getTests() + // const _runnerHook = _runner.hook - const changeFnToRunAfterHooks = () => { - const originalFn = fn - - const test = getTest() - - fn = function () { - setTest(null) - - testAfterRun(test, Cypress) - - // and now invoke next(err) - return originalFn.apply(window, arguments) - } + _runner.hook = $utils.monkeypatchBefore(_runner.hook, function (name, fn) { + if (name !== 'afterAll' && name !== 'afterEach') { + return } - switch (name) { - case 'afterEach': { - const t = getTest() + const test = getTest() + const allTests = getTests() - // find all of the filtered _tests which share - // the same parent suite as our current _test - const tests = getAllSiblingTests(t.parent, getTestById) + let shouldFireTestAfterRun = _.noop - // make sure this test isnt the last test overall but also - // isnt the last test in our filtered parent suite's tests array - if (this.suite.root && (t !== _.last(allTests)) && (t !== _.last(tests))) { - changeFnToRunAfterHooks() + switch (name) { + case 'afterEach': + shouldFireTestAfterRun = () => { + // find all of the grep'd tests which share + // the same parent suite as our current test + const tests = getAllSiblingTests(test.parent, getTestById) + + if (this.suite.root) { + _runner._shouldBufferSuiteEnd = true + + // make sure this test isnt the last test overall but also + // isnt the last test in our filtered parent suite's tests array + if (test.final === false || (test !== _.last(allTests)) && (test !== _.last(tests))) { + return true + } + } } break - } - case 'afterAll': { - // find all of the filtered allTests which share - // the same parent suite as our current _test - const t = getTest() - - if (t) { - const siblings = getAllSiblingTests(t.parent, getTestById) - - // 1. if we're the very last test in the entire allTests - // we wait until the root suite fires - // 2. else if we arent the last nested suite we fire if we're - // the last test that will run - - if ( - (isRootSuite(this.suite) && isLastTest(t, allTests)) || - (!isLastSuite(this.suite, allTests) && lastTestThatWillRunInSuite(t, siblings)) - ) { - changeFnToRunAfterHooks() + case 'afterAll': + shouldFireTestAfterRun = () => { + // find all of the filtered allTests which share + // the same parent suite as our current _test + // const t = getTest() + + if (test) { + const siblings = getAllSiblingTests(test.parent, getTestById) + + // 1. if we're the very last test in the entire allTests + // we wait until the root suite fires + // 2. else if we arent the last nested suite we fire if we're + // the last test that will run + + if ( + (isRootSuite(this.suite) && isLastTest(test, allTests)) || + (!isLastSuite(this.suite, allTests) && lastTestThatWillRunInSuite(test, siblings)) + ) { + return true + } } } break - } default: break } - return _runnerHook.call(this, name, fn) - } + const newArgs = [name, $utils.monkeypatchBefore(fn, + function () { + if (!shouldFireTestAfterRun()) return + + setTest(null) + + if (test.final !== false) { + test.final = true + if (test.state === 'passed') { + Cypress.action('runner:pass', wrap(test)) + } + + Cypress.action('runner:test:end', wrap(test)) + + _runner._shouldBufferSuiteEnd = false + _runner._onTestAfterRun.map((fn) => { + return fn() + }) + + _runner._onTestAfterRun = [] + } + + testAfterRun(test, Cypress) + })] + + return newArgs + }) } const getTestResults = (tests) => { @@ -443,8 +465,6 @@ const normalizeAll = (suite, initialTests = {}, setTestsById, setTests, onRunnab const normalize = (runnable, tests, initialTests, onRunnable, onLogsById, getTestId, getHookId) => { const normalizeRunnable = (runnable) => { - let i - runnable.id = getTestId() // tests have a type of 'test' whereas suites do not have a type property @@ -458,8 +478,27 @@ const normalize = (runnable, tests, initialTests, onRunnable, onLogsById, getTes // if we have a runnable in the initial state // then merge in existing properties into the runnable - i = initialTests[runnable.id] + const i = initialTests[runnable.id] + + let prevAttempts + if (i) { + prevAttempts = [] + + if (i.prevAttempts) { + prevAttempts = _.map(i.prevAttempts, (test) => { + if (test) { + _.each(RUNNABLE_LOGS, (type) => { + return _.each(test[type], onLogsById) + }) + } + + // reduce this runnable down to its props + // and collections + return wrapAll(test) + }) + } + _.each(RUNNABLE_LOGS, (type) => { return _.each(i[type], onLogsById) }) @@ -472,7 +511,13 @@ const normalize = (runnable, tests, initialTests, onRunnable, onLogsById, getTes // reduce this runnable down to its props // and collections - return wrapAll(runnable) + const test = wrapAll(runnable) + + if (prevAttempts) { + test.prevAttempts = prevAttempts + } + + return test } const push = (test) => { @@ -506,7 +551,7 @@ const normalize = (runnable, tests, initialTests, onRunnable, onLogsById, getTes normalizedSuite.tests = _.map(suite._onlyTests, (test) => { const normalizedTest = normalizeRunnable(test, initialTests, onRunnable, onLogsById, getTestId, getHookId) - push(normalizedTest) + push(test) return normalizedTest }) @@ -541,17 +586,13 @@ const normalize = (runnable, tests, initialTests, onRunnable, onLogsById, getTes return normalizedRunnable } -const hookFailed = (hook, err, hookName, getTest, getTestFromHookOrFindTest) => { +const hookFailed = (hook, err, getTest, getTestFromHookOrFindTest) => { // NOTE: sometimes mocha will fail a hook without having emitted on('hook') // event, so this hook might not have currentTest set correctly // in which case we need to lookup the test const test = getTest() || getTestFromHookOrFindTest(hook) - test.err = err - test.state = 'failed' - test.duration = hook.duration // TODO: nope (?) - test.hookName = hookName // TODO: why are we doing this? - test.failedFromHookId = hook.hookId + setHookFailureProps(test, hook, err) if (hook.alreadyEmittedMocha) { test.alreadyEmittedMocha = true @@ -560,6 +601,17 @@ const hookFailed = (hook, err, hookName, getTest, getTestFromHookOrFindTest) => } } +const setHookFailureProps = (test, hook, err) => { + err = $errUtils.wrapErr(err) + const hookName = getHookName(hook) + + test.err = err + test.state = 'failed' + test.duration = hook.duration // TODO: nope (?) + test.hookName = hookName // TODO: why are we doing this? + test.failedFromHookId = hook.hookId +} + function getTestFromRunnable (runnable) { switch (runnable.type) { case 'hook': @@ -594,18 +646,31 @@ const _runnerListeners = (_runner, Cypress, _emissions, getTestById, getTest, se return Cypress.action('runner:suite:start', wrap(suite)) }) + _runner._shouldBufferSuiteEnd = false + _runner._onTestAfterRun = [] + _runner.on('suite end', (suite) => { + const handleSuiteEnd = () => { // cleanup our suite + its hooks - forceGc(suite) - eachHookInSuite(suite, forceGc) + forceGc(suite) + eachHookInSuite(suite, forceGc) - if (_emissions.ended[suite.id]) { - return + if (_emissions.ended[suite.id]) { + return + } + + _emissions.ended[suite.id] = true + + Cypress.action('runner:suite:end', wrap(suite)) } - _emissions.ended[suite.id] = true + if (_runner._shouldBufferSuiteEnd) { + _runner._onTestAfterRun = _runner._onTestAfterRun.concat([handleSuiteEnd]) - return Cypress.action('runner:suite:end', wrap(suite)) + return + } + + return handleSuiteEnd() }) _runner.on('hook', (hook) => { @@ -665,11 +730,22 @@ const _runnerListeners = (_runner, Cypress, _emissions, getTestById, getTest, se _emissions.ended[test.id] = true - return Cypress.action('runner:test:end', wrap(test)) + // NOTE: we wait to send 'test end' until after hooks run + // return Cypress.action('runner:test:end', wrap(test)) }) - _runner.on('pass', (test) => { - return Cypress.action('runner:pass', wrap(test)) + // Ignore the 'pass' event since we emit our own + // _runner.on('pass', (test) => { + // return Cypress.action('runner:pass', wrap(test)) + // }) + + /** + * Mocha retry event is only fired in Mocha version 6+ + * https://github.com/mochajs/mocha/commit/2a76dd7589e4a1ed14dd2a33ab89f182e4c4a050 + */ + _runner.on('retry', (test, err) => { + test.err = $errUtils.wrapErr(err) + Cypress.action('runner:retry', wrap(test), test.err) }) // if a test is pending mocha will only @@ -702,11 +778,13 @@ const _runnerListeners = (_runner, Cypress, _emissions, getTestById, getTest, se const tests = getAllSiblingTests(test.parent, getTestById) if (_.last(tests) !== test) { + test.final = true + return fire(TEST_AFTER_RUN_EVENT, test, Cypress) } }) - return _runner.on('fail', (runnable, err) => { + _runner.on('fail', (runnable, err) => { let hookName const isHook = runnable.type === 'hook' @@ -716,6 +794,7 @@ const _runnerListeners = (_runner, Cypress, _emissions, getTestById, getTest, se const parentTitle = runnable.parent.title hookName = getHookName(runnable) + const test = getTest() || getTestFromHookOrFindTest(runnable) // append a friendly message to the error indicating // we're skipping the remaining tests in this suite @@ -724,6 +803,7 @@ const _runnerListeners = (_runner, Cypress, _emissions, getTestById, getTest, se $errUtils.errByPath('uncaught.error_in_hook', { parentTitle, hookName, + retries: test._retries, }).message, ) } @@ -751,7 +831,7 @@ const _runnerListeners = (_runner, Cypress, _emissions, getTestById, getTest, se // if a hook fails (such as a before) then the test will never // get run and we'll need to make sure we set the test so that // the TEST_AFTER_RUN_EVENT fires correctly - return hookFailed(runnable, runnable.err, hookName, getTest, getTestFromHookOrFindTest) + return hookFailed(runnable, runnable.err, getTest, getTestFromHookOrFindTest) } }) } @@ -779,13 +859,18 @@ const create = (specWindow, mocha, Cypress, cy) => { const suite = hook.parent + let foundTest + if (hook.hookName === 'after all') { - return findLastTestInSuite(suite, isNotAlreadyRunTest) + foundTest = findLastTestInSuite(suite, isNotAlreadyRunTest) + } else if (hook.hookName === 'before all') { + foundTest = findTestInSuite(suite, isNotAlreadyRunTest) } - if (hook.hookName === 'before all') { - return findTestInSuite(suite, isNotAlreadyRunTest) - } + // if test has retried, we getTestById will give us the last attempt + foundTest = foundTest && getTestById(foundTest.id) + + return foundTest } const onScriptError = (err) => { @@ -837,6 +922,7 @@ const create = (specWindow, mocha, Cypress, cy) => { let _testsById = {} const _testsQueue = [] const _testsQueueById = {} + // only used during normalization const _runnables = [] const _logsById = {} let _emissions = { @@ -867,6 +953,7 @@ const create = (specWindow, mocha, Cypress, cy) => { } const onRunnable = (r) => { + // set defualt retries at onRunnable time instead of onRunnableRun return _runnables.push(r) } @@ -891,8 +978,103 @@ const create = (specWindow, mocha, Cypress, cy) => { return _testsById[id] } + const replaceRunnable = (runnable, id) => { + const testsQueueIndex = _.findIndex(_testsQueue, { id }) + + _testsQueue.splice(testsQueueIndex, 1, runnable) + + _testsQueueById[id] = runnable + + const testsIndex = _.findIndex(_tests, { id }) + + _tests.splice(testsIndex, 1, runnable) + + _testsById[id] = runnable + } + overrideRunnerHook(Cypress, _runner, getTestById, getTest, setTest, getTests) + // this forces mocha to enqueue a duplicate test in the case of test retries + const replacePreviousAttemptWith = (test) => { + const prevAttempt = _testsById[test.id] + + const prevAttempts = prevAttempt.prevAttempts || [] + + const newPrevAttempts = prevAttempts.concat([prevAttempt]) + + delete prevAttempt.prevAttempts + + test.prevAttempts = newPrevAttempts + + replaceRunnable(test, test.id) + } + + const maybeHandleRetry = (runnable, err) => { + const r = runnable + const isHook = r.type === 'hook' + const isTest = r.type === 'test' + const test = getTest() || getTestFromHook(runnable, getTestById) + const isBeforeEachHook = isHook && !!r.hookName.match(/before each/) + const isAfterEachHook = isHook && !!r.hookName.match(/after each/) + const retryAbleRunnable = isTest || isBeforeEachHook || isAfterEachHook + const willRetry = (test._currentRetry < test._retries) && retryAbleRunnable + + const fail = function () { + return err + } + const noFail = function () { + return + } + + if (err) { + if (willRetry) { + test.state = 'failed' + test.final = false + } + + if (willRetry && isBeforeEachHook) { + delete runnable.err + test._retriesBeforeEachFailedTestFn = test.fn + + // this prevents afterEach hooks that exist at a deeper level than the failing one from running + // we will always skip remaining beforeEach hooks since they will always be same level or deeper + test._skipHooksWithLevelGreaterThan = runnable.titlePath().length + setHookFailureProps(test, runnable, err) + test.fn = function () { + throw err + } + + return noFail() + } + + if (willRetry && isAfterEachHook) { + // if we've already failed this attempt from an afterEach hook then we've already enqueud another attempt + // so return early + if (test._retriedFromAfterEachHook) { + return noFail() + } + + setHookFailureProps(test, runnable, err) + + const newTest = test.clone() + + newTest._currentRetry = test._currentRetry + 1 + + test.parent.testsQueue.unshift(newTest) + + // this prevents afterEach hooks that exist at a deeper (or same) level than the failing one from running + test._skipHooksWithLevelGreaterThan = runnable.titlePath().length - 1 + test._retriedFromAfterEachHook = true + + Cypress.action('runner:retry', wrap(test), test.err) + + return noFail() + } + } + + return fail() + } + return { onScriptError, @@ -961,6 +1143,12 @@ const create = (specWindow, mocha, Cypress, cy) => { return _next() } + // first time seeing a retried test + // that hasn't already replaced our test + if (test._currentRetry > 0 && _testsById[test.id] !== test) { + replacePreviousAttemptWith(test) + } + // closure for calculating the actual // runtime of a runnables fn exection duration // and also the run of the runnable:after:run:async event @@ -998,6 +1186,27 @@ const create = (specWindow, mocha, Cypress, cy) => { // associated _runnables will share this state if (!fired(TEST_BEFORE_RUN_EVENT, test)) { fire(TEST_BEFORE_RUN_EVENT, test, Cypress) + + // this is the earliest we can set test._retries since test:before:run + // will load in testConfigOverrides (per test configuration) + const retries = Cypress.getTestRetries() ?? -1 + + test._retries = retries + } + + const isHook = runnable.type === 'hook' + + const isAfterEachHook = isHook && runnable.hookName.match(/after each/) + const isBeforeEachHook = isHook && runnable.hookName.match(/before each/) + + // if we've been told to skip hooks at a certain nested level + // this happens if we're handling a runnable that is going to retry due to failing in a hook + const shouldSkipRunnable = test._skipHooksWithLevelGreaterThan != null + && isHook + && (isBeforeEachHook || isAfterEachHook && runnable.titlePath().length > test._skipHooksWithLevelGreaterThan) + + if (shouldSkipRunnable) { + return _next.call(this) } const next = (err) => { @@ -1038,7 +1247,7 @@ const create = (specWindow, mocha, Cypress, cy) => { break } - return _next(err) + return _next.call(runnable, err) } const onNext = (err) => { @@ -1058,6 +1267,8 @@ const create = (specWindow, mocha, Cypress, cy) => { runnable.err = $errUtils.wrapErr(err) } + err = maybeHandleRetry(runnable, err) + return runnableAfterRunAsync(runnable, Cypress) .then(() => { // once we complete callback with the @@ -1163,21 +1374,13 @@ const create = (specWindow, mocha, Cypress, cy) => { // search through all of the tests // until we find the current test // and break then - for (let test of _tests) { - if (test.id === id) { + for (let testRunnable of _tests) { + if (testRunnable.id === id) { break } else { - test = wrapAll(test) + const test = serializeTest(testRunnable) - _.each(RUNNABLE_LOGS, (type) => { - let logs - - logs = test[type] - - if (logs) { - test[type] = _.map(logs, $Log.toSerializedJSON) - } - }) + test.prevAttempts = _.map(testRunnable.prevAttempts, serializeTest) tests[test.id] = test } @@ -1210,9 +1413,7 @@ const create = (specWindow, mocha, Cypress, cy) => { getDisplayPropsForLog: $Log.getDisplayProps, getConsolePropsForLogById (logId) { - let attrs - - attrs = _logsById[logId] + const attrs = _logsById[logId] if (attrs) { return $Log.getConsoleProps(attrs) @@ -1220,25 +1421,13 @@ const create = (specWindow, mocha, Cypress, cy) => { }, getSnapshotPropsForLogById (logId) { - let attrs - - attrs = _logsById[logId] + const attrs = _logsById[logId] if (attrs) { return $Log.getSnapshotProps(attrs) } }, - getErrorByTestId (testId) { - let test - - test = getTestById(testId) - - if (test) { - return $errUtils.wrapErr(test.err) - } - }, - resumeAtTest (id, emissions = {}) { _resumedAtTestIndex = getTestIndexFromId(id) @@ -1287,7 +1476,6 @@ const create = (specWindow, mocha, Cypress, cy) => { // we dont need to hold a log reference // to anything in memory when we're headless // because you cannot inspect any logs - let existing if (!isInteractive) { return @@ -1308,7 +1496,7 @@ const create = (specWindow, mocha, Cypress, cy) => { _testsQueue.push(test) } - existing = _logsById[attrs.id] + const existing = _logsById[attrs.id] if (existing) { // because log:state:changed may @@ -1343,6 +1531,24 @@ const create = (specWindow, mocha, Cypress, cy) => { } } +const mixinLogs = (test) => { + _.each(RUNNABLE_LOGS, (type) => { + const logs = test[type] + + if (logs) { + test[type] = _.map(logs, $Log.toSerializedJSON) + } + }) +} + +const serializeTest = (test) => { + const wrappedTest = wrapAll(test) + + mixinLogs(wrappedTest) + + return wrappedTest +} + module.exports = { create, } diff --git a/packages/driver/src/cypress/server.js b/packages/driver/src/cypress/server.js index 4610d8f91acf..097336edb019 100644 --- a/packages/driver/src/cypress/server.js +++ b/packages/driver/src/cypress/server.js @@ -65,7 +65,13 @@ const warnOnForce404Default = (obj) => { } } -const whitelist = (xhr) => { +const warnOnWhitelistRenamed = (obj, type) => { + if (obj.whitelist) { + return $errUtils.throwErrByPath('server.whitelist_renamed', { args: { type } }) + } +} + +const ignore = (xhr) => { const url = new URL(xhr.url) // https://github.com/cypress-io/cypress/issues/7280 @@ -74,7 +80,7 @@ const whitelist = (xhr) => { url.search = '' url.hash = '' - // whitelist if we're GET + looks like we're fetching regular resources + // allow if we're GET + looks like we're fetching regular resources return xhr.method === 'GET' && regularResourcesRe.test(url.href) } @@ -95,7 +101,7 @@ const serverDefaults = { urlMatchingOptions: { matchBase: true }, stripOrigin: _.identity, getUrlOptions: _.identity, - whitelist, // function whether to allow a request to go out (css/js/html/templates) etc + ignore, // function whether to allow a request to go out (css/js/html/templates) etc onOpen () {}, onSend () {}, onXhrAbort () {}, @@ -209,8 +215,8 @@ const create = (options = {}) => { return routes }, - isWhitelisted (xhr) { - return options.whitelist(xhr) + isIgnored (xhr) { + return options.ignore(xhr) }, shouldApplyStub (route) { @@ -257,9 +263,9 @@ const create = (options = {}) => { // return the 404 stub if we dont have any stubs // but we are stubbed - meaning we havent added any routes // but have started the server - // and this request shouldnt be whitelisted + // and this request shouldnt be allowed if (!routes.length && hasEnabledStubs && - options.force404 !== false && !server.isWhitelisted(xhr)) { + options.force404 !== false && !server.isIgnored(xhr)) { return get404Route() } @@ -268,8 +274,8 @@ const create = (options = {}) => { return nope() } - // bail if this xhr matches our whitelist - if (server.isWhitelisted(xhr)) { + // bail if this xhr matches our ignore list + if (server.isIgnored(xhr)) { return nope() } @@ -414,6 +420,7 @@ const create = (options = {}) => { set (obj) { warnOnStubDeprecation(obj, 'server') warnOnForce404Default(obj) + warnOnWhitelistRenamed(obj, 'server') // handle enable=true|false if (obj.enable != null) { @@ -648,8 +655,8 @@ const create = (options = {}) => { proxy._setRequestBody(requestBody) // log this out now since it's being sent officially - // unless its been whitelisted - if (!server.isWhitelisted(this)) { + // unless its not been ignored + if (!server.isIgnored(this)) { options.onSend(proxy, sendStack, route) } diff --git a/packages/driver/src/cypress/stack_utils.js b/packages/driver/src/cypress/stack_utils.js index ccb7daac37b4..08e9efff4637 100644 --- a/packages/driver/src/cypress/stack_utils.js +++ b/packages/driver/src/cypress/stack_utils.js @@ -3,6 +3,7 @@ const { codeFrameColumns } = require('@babel/code-frame') const errorStackParser = require('error-stack-parser') const path = require('path') +const { getStackLines, replacedStack, stackWithoutMessage, splitStack, unsplitStack } = require('@packages/server/lib/util/stack_utils') const $sourceMapUtils = require('./source_map_utils') const $utils = require('./utils') @@ -11,36 +12,6 @@ const stackLineRegex = /^\s*(at )?.*@?\(?.*\:\d+\:\d+\)?$/ const customProtocolRegex = /^[^:\/]+:\/+/ const STACK_REPLACEMENT_MARKER = '__stackReplacementMarker' -// returns tuple of [message, stack] -const splitStack = (stack) => { - const lines = stack.split('\n') - - return _.reduce(lines, (memo, line) => { - if (memo.messageEnded || stackLineRegex.test(line)) { - memo.messageEnded = true - memo[1].push(line) - } else { - memo[0].push(line) - } - - return memo - }, [[], []]) -} - -const unsplitStack = (messageLines, stackLines) => { - return _.castArray(messageLines).concat(stackLines).join('\n') -} - -const getStackLines = (stack) => { - const [, stackLines] = splitStack(stack) - - return stackLines -} - -const stackWithoutMessage = (stack) => { - return getStackLines(stack).join('\n') -} - const hasCrossFrameStacks = (specWindow) => { // get rid of the top lines since they naturally have different line:column const normalize = (stack) => { @@ -323,17 +294,6 @@ const normalizedUserInvocationStack = (userInvocationStack) => { return normalizeStackIndentation(winnowedStackLines) } -const replacedStack = (err, newStack) => { - // if err already lacks a stack or we've removed the stack - // for some reason, keep it stackless - if (!err.stack) return err.stack - - const errString = err.toString() - const stackLines = getStackLines(newStack) - - return unsplitStack(errString, stackLines) -} - module.exports = { getCodeFrame, getSourceStack, diff --git a/packages/driver/src/cypress/utils.js b/packages/driver/src/cypress/utils.js index 53344c4130af..8c1943d6d4f6 100644 --- a/packages/driver/src/cypress/utils.js +++ b/packages/driver/src/cypress/utils.js @@ -55,6 +55,18 @@ module.exports = { return console.log(...msgs) }, + monkeypatchBefore (origFn, fn) { + return function () { + const newArgs = fn.apply(this, arguments) + + if (newArgs !== undefined) { + return origFn.apply(this, newArgs) + } + + return origFn.apply(this, arguments) + } + }, + unwrapFirst (val) { // this method returns the first item in an array // and if its still a jquery object, then we return @@ -89,7 +101,7 @@ module.exports = { return _.reduce(props, (memo, prop) => { if (_.has(obj, prop) || obj[prop] !== undefined) { - memo[prop] = obj[prop] + memo[prop] = _.result(obj, prop) } return memo @@ -297,6 +309,10 @@ module.exports = { return Math.sqrt((deltaX * deltaX) + (deltaY * deltaY)) }, + getTestFromRunnable (r) { + return r.ctx.currentTest || r + }, + memoize (func, cacheInstance = new Map()) { const memoized = function (...args) { const key = args[0] diff --git a/packages/driver/src/util/breaking_change_warning.ts b/packages/driver/src/util/breaking_change_warning.ts new file mode 100644 index 000000000000..61671c661611 --- /dev/null +++ b/packages/driver/src/util/breaking_change_warning.ts @@ -0,0 +1,34 @@ +import $errUtil from '../cypress/error_utils' + +export function wrapBlobUtil (blobUtil) { + const breakingChanges = [ + 'arrayBufferToBlob', + 'base64StringToBlob', + 'binaryStringToBlob', + 'dataURLToBlob', + ] + + const obj = {} + + Object.keys(blobUtil).forEach((key) => { + if (breakingChanges.includes(key)) { + obj[key] = function (...args) { + const val = blobUtil[key](...args) + + val.then = function () { + $errUtil.throwErrByPath('breaking_change.blob_util2', { + args: { + functionName: key, + }, + }) + } + + return val + } + } else { + obj[key] = blobUtil[key] + } + }) + + return obj +} diff --git a/packages/electron/package.json b/packages/electron/package.json index 1d8736bb4629..8755ad56787b 100644 --- a/packages/electron/package.json +++ b/packages/electron/package.json @@ -24,7 +24,7 @@ "minimist": "1.2.5" }, "devDependencies": { - "electron": "8.3.1", + "electron": "9.2.0", "mocha": "3.5.3" }, "files": [ diff --git a/packages/example/bin/convert.js b/packages/example/bin/convert.js index 9e548350a03c..4936485cd923 100755 --- a/packages/example/bin/convert.js +++ b/packages/example/bin/convert.js @@ -24,6 +24,11 @@ function replaceStringsIn (file) { replace(eslintRe, "") replace("imgSrcToDataURL('/assets", "imgSrcToDataURL('https://example.cypress.io/assets") + // temporary for 5.0.0 + // TODO: remove this + replace("whitelist: 'session_id'", "preserve: 'session_id'") + replace("server.whitelist", "server.ignore") + fs.writeFile(file, str, function (err) { if (err) throw err diff --git a/packages/network/README.md b/packages/network/README.md index df06bbe38812..5263862e391a 100644 --- a/packages/network/README.md +++ b/packages/network/README.md @@ -8,7 +8,7 @@ You can see a list of the modules exported from this package in [./lib/index.ts] * `agent` is a HTTP/HTTPS [agent][1] with support for HTTP/HTTPS proxies and keepalive whenever possible * `allowDestroy` can be used to wrap a `net.Server` to add a `.destroy()` method -* `blacklist` is a utility for matching glob blacklists +* `blocked` is a utility for matching blocked globs * `concatStream` is a wrapper around [`concat-stream@1.6.2`][2] that makes it always yield a `Buffer` * `connect` contains utilities for making network connections, including `createRetryingSocket` * `cors` contains utilities for Cross-Origin Resource Sharing diff --git a/packages/network/lib/blacklist.ts b/packages/network/lib/blocked.ts similarity index 71% rename from packages/network/lib/blacklist.ts rename to packages/network/lib/blocked.ts index 1a6b7021ecba..1e59bbda5b91 100644 --- a/packages/network/lib/blacklist.ts +++ b/packages/network/lib/blocked.ts @@ -2,9 +2,9 @@ import _ from 'lodash' import minimatch from 'minimatch' import { stripProtocolAndDefaultPorts } from './uri' -export function matches (urlToCheck, blacklistHosts) { +export function matches (urlToCheck, blockHosts) { // normalize into flat array - blacklistHosts = [].concat(blacklistHosts) + blockHosts = [].concat(blockHosts) urlToCheck = stripProtocolAndDefaultPorts(urlToCheck) @@ -14,5 +14,5 @@ export function matches (urlToCheck, blacklistHosts) { return minimatch(urlToCheck, hostMatcher) } - return _.find(blacklistHosts, matchUrl) + return _.find(blockHosts, matchUrl) } diff --git a/packages/network/lib/index.ts b/packages/network/lib/index.ts index f40984659a19..e9064ae0b3ab 100644 --- a/packages/network/lib/index.ts +++ b/packages/network/lib/index.ts @@ -1,12 +1,12 @@ import agent from './agent' -import * as blacklist from './blacklist' +import * as blocked from './blocked' import * as connect from './connect' import * as cors from './cors' import * as uri from './uri' export { agent, - blacklist, + blocked, connect, cors, uri, diff --git a/packages/network/test/unit/blacklist_spec.ts b/packages/network/test/unit/blocked_spec.ts similarity index 87% rename from packages/network/test/unit/blacklist_spec.ts rename to packages/network/test/unit/blocked_spec.ts index 81e223b4f915..0e327503d490 100644 --- a/packages/network/test/unit/blacklist_spec.ts +++ b/packages/network/test/unit/blocked_spec.ts @@ -1,4 +1,4 @@ -import { blacklist } from '../..' +import { blocked } from '../..' import { expect } from 'chai' const hosts = [ @@ -10,22 +10,22 @@ const hosts = [ ] const matchesStr = function (url, host, val) { - const m = blacklist.matches(url, host) + const m = blocked.matches(url, host) expect(!!m).to.eq(val, `url: '${url}' did not pass`) } const matchesArray = function (url, val) { - const m = blacklist.matches(url, hosts) + const m = blocked.matches(url, hosts) expect(!!m).to.eq(val, `url: '${url}' did not pass`) } const matchesHost = (url, host) => { - expect(blacklist.matches(url, hosts)).to.eq(host) + expect(blocked.matches(url, hosts)).to.eq(host) } -describe('lib/blacklist', () => { +describe('lib/blocked', () => { it('handles hosts, ports, wildcards', () => { matchesArray('https://mail.google.com/foo', true) matchesArray('https://shop.apple.com/bar', true) diff --git a/packages/proxy/lib/http/request-middleware.ts b/packages/proxy/lib/http/request-middleware.ts index df9819330678..f8ab37cb6c00 100644 --- a/packages/proxy/lib/http/request-middleware.ts +++ b/packages/proxy/lib/http/request-middleware.ts @@ -1,6 +1,6 @@ import _ from 'lodash' import debugModule from 'debug' -import { blacklist, cors } from '@packages/network' +import { blocked, cors } from '@packages/network' import { HttpMiddleware } from './' export type RequestMiddleware = HttpMiddleware<{ @@ -46,15 +46,15 @@ const RedirectToClientRouteIfNotProxied: RequestMiddleware = function () { this.next() } -const EndRequestsToBlacklistedHosts: RequestMiddleware = function () { - const { blacklistHosts } = this.config +const EndRequestsToBlockedHosts: RequestMiddleware = function () { + const { blockHosts } = this.config - if (blacklistHosts) { - const matches = blacklist.matches(this.req.proxiedUrl, blacklistHosts) + if (blockHosts) { + const matches = blocked.matches(this.req.proxiedUrl, blockHosts) if (matches) { - this.res.set('x-cypress-matched-blacklisted-host', matches) - debug('blacklisting request %o', { + this.res.set('x-cypress-matched-blocked-host', matches) + debug('blocking request %o', { url: this.req.proxiedUrl, matches, }) @@ -149,7 +149,7 @@ export default { LogRequest, RedirectToClientRouteIfUnloaded, RedirectToClientRouteIfNotProxied, - EndRequestsToBlacklistedHosts, + EndRequestsToBlockedHosts, MaybeEndRequestWithBufferedResponse, StripUnsupportedAcceptEncoding, MaybeSetBasicAuthHeaders, diff --git a/packages/proxy/test/unit/http/request-middleware.spec.ts b/packages/proxy/test/unit/http/request-middleware.spec.ts index 5fb61b6839e9..07cd117c8754 100644 --- a/packages/proxy/test/unit/http/request-middleware.spec.ts +++ b/packages/proxy/test/unit/http/request-middleware.spec.ts @@ -8,7 +8,7 @@ describe('http/request-middleware', function () { 'LogRequest', 'RedirectToClientRouteIfUnloaded', 'RedirectToClientRouteIfNotProxied', - 'EndRequestsToBlacklistedHosts', + 'EndRequestsToBlockedHosts', 'MaybeEndRequestWithBufferedResponse', 'StripUnsupportedAcceptEncoding', 'MaybeSetBasicAuthHeaders', diff --git a/packages/reporter/cypress/integration/aliases_spec.js b/packages/reporter/cypress/integration/aliases_spec.js index 852860b23275..1eacc6fc0b17 100644 --- a/packages/reporter/cypress/integration/aliases_spec.js +++ b/packages/reporter/cypress/integration/aliases_spec.js @@ -10,6 +10,7 @@ const addLog = function (runner, log) { renderProps: {}, state: 'passed', testId: 'r3', + testCurrentRetry: 0, type: 'parent', url: 'http://example.com', } diff --git a/packages/reporter/cypress/integration/shortcuts_spec.ts b/packages/reporter/cypress/integration/shortcuts_spec.ts index b1de68dd581e..2606d2fef04d 100644 --- a/packages/reporter/cypress/integration/shortcuts_spec.ts +++ b/packages/reporter/cypress/integration/shortcuts_spec.ts @@ -90,7 +90,7 @@ describe('controls', function () { // need to add an input since this environment is isolated $body.append('') }) - .get('#temp-input').type('r') + .get('#temp-input').type('r', { force: true }) .then(() => { expect(runner.emit).not.to.have.been.calledWith('runner:restart') }) diff --git a/packages/reporter/cypress/support/util.js b/packages/reporter/cypress/support/util.js new file mode 100644 index 000000000000..0b5cc710de4f --- /dev/null +++ b/packages/reporter/cypress/support/util.js @@ -0,0 +1,29 @@ +const _ = Cypress._ + +const sendLog = (runner, log, event) => { + const defaultLog = { + event: false, + hookName: 'test', + id: _.uniqueId('l'), + instrument: 'command', + renderProps: {}, + state: 'passed', + testId: 'r3', + type: 'parent', + url: 'http://example.com', + } + + runner.emit(event, _.extend(defaultLog, log)) +} + +export const updateLog = (runner, log) => { + sendLog(runner, log, 'reporter:log:state:changed') +} + +export const addLog = (runner, log) => { + sendLog(runner, log, 'reporter:log:add') +} + +export const addLogs = (runner, logs) => { + _.forEach(logs, addLog.bind(null, runner)) +} diff --git a/packages/reporter/src/attempts/attempt-model.ts b/packages/reporter/src/attempts/attempt-model.ts new file mode 100644 index 000000000000..cb8a9966cbf4 --- /dev/null +++ b/packages/reporter/src/attempts/attempt-model.ts @@ -0,0 +1,201 @@ +import _ from 'lodash' +import { action, computed, observable } from 'mobx' + +import Agent, { AgentProps } from '../agents/agent-model' +import Command, { CommandProps } from '../commands/command-model' +import Err from '../errors/err-model' +import Route, { RouteProps } from '../routes/route-model' +import Test, { UpdatableTestProps, TestProps, TestState } from '../test/test-model' +import Hook, { HookName } from '../hooks/hook-model' +import { FileDetails } from '@packages/ui-components' +import { LogProps } from '../runnables/runnables-store' +import Log from '../instruments/instrument-model' + +export default class Attempt { + @observable agents: Agent[] = [] + @observable commands: Command[] = [] + @observable err = new Err({}) + @observable hooks: Hook[] = [] + // TODO: make this an enum with states: 'QUEUED, ACTIVE, INACTIVE' + @observable isActive: boolean | null = null + @observable routes: Route[] = [] + @observable _state?: TestState | null = null + @observable _invocationCount: number = 0 + @observable invocationDetails?: FileDetails + @observable hookCount: { [name in HookName]: number } = { + 'before all': 0, + 'before each': 0, + 'after all': 0, + 'after each': 0, + 'test body': 0, + } + @observable _isOpen: boolean|null = null + + @observable isOpenWhenLast: boolean | null = null + _callbackAfterUpdate: Function | null = null + testId: string + + @observable id: number + test: Test + + _logs: {[key: string]: Log} = {} + + constructor (props: TestProps, test: Test) { + this.testId = props.id + this.id = props.currentRetry || 0 + this.test = test + this._state = props.state + this.err.update(props.err) + + this.invocationDetails = props.invocationDetails + + this.hooks = _.map(props.hooks, (hook) => new Hook(hook)) + + _.each(props.agents, this.addLog) + _.each(props.commands, this.addLog) + _.each(props.routes, this.addLog) + } + + @computed get hasCommands () { + return !!this.commands.length + } + + @computed get isLongRunning () { + return this.isActive && this._hasLongRunningCommand + } + + @computed get _hasLongRunningCommand () { + return _.some(this.commands, (command) => { + return command.isLongRunning + }) + } + + @computed get state () { + return this._state || (this.isActive ? 'active' : 'processing') + } + + @computed get isLast () { + return this.id === this.test.lastAttempt.id + } + + @computed get isOpen () { + if (this._isOpen !== null) { + return this._isOpen + } + + // prev attempts open by default while test is running, otherwise only the last is open + return this.test.isActive || this.isLast + } + + addLog = (props: LogProps) => { + switch (props.instrument) { + case 'command': { + return this._addCommand(props as CommandProps) + } + case 'agent': { + return this._addAgent(props as AgentProps) + } + case 'route': { + return this._addRoute(props as RouteProps) + } + default: { + throw new Error(`Attempted to add log for unknown instrument: ${props.instrument}`) + } + } + } + + updateLog (props: LogProps) { + const log = this._logs[props.id] + + if (log) { + log.update(props) + } + } + + commandMatchingErr () { + return _(this.hooks) + .map((hook) => { + return hook.commandMatchingErr(this.err) + }) + .compact() + .last() + } + + @action start () { + this.isActive = true + } + + @action update (props: UpdatableTestProps) { + if (props.state) { + this._state = props.state + } + + this.err.update(props.err) + + if (props.hookId) { + const hook = _.find(this.hooks, { hookId: props.hookId }) + + if (hook && props.err) { + hook.failed = true + } + } + + if (props.isOpen != null) { + this.isOpenWhenLast = props.isOpen + } + } + + @action finish (props: UpdatableTestProps) { + this.update(props) + this.isActive = false + } + + _addAgent (props: AgentProps) { + const agent = new Agent(props) + + this._logs[props.id] = agent + this.agents.push(agent) + + return agent + } + + _addRoute (props: RouteProps) { + const route = new Route(props) + + this._logs[props.id] = route + this.routes.push(route) + + return route + } + + _addCommand (props: CommandProps) { + const command = new Command(props) + + this._logs[props.id] = command + + this.commands.push(command) + + const hookIndex = _.findIndex(this.hooks, { hookId: command.hookId }) + + const hook = this.hooks[hookIndex] + + hook.addCommand(command) + + // make sure that hooks are in order of invocation + if (hook.invocationOrder === undefined) { + hook.invocationOrder = this._invocationCount++ + + if (hook.invocationOrder !== hookIndex) { + this.hooks[hookIndex] = this.hooks[hook.invocationOrder] + this.hooks[hook.invocationOrder] = hook + } + } + + // assign number if non existent + if (hook.hookNumber === undefined) { + hook.hookNumber = ++this.hookCount[hook.hookName] + } + + return command + } +} diff --git a/packages/reporter/src/attempts/attempts.scss b/packages/reporter/src/attempts/attempts.scss new file mode 100644 index 000000000000..c6c94e0a116c --- /dev/null +++ b/packages/reporter/src/attempts/attempts.scss @@ -0,0 +1,150 @@ +.reporter { + .attempts { + .attempt-item > .collapsible > .collapsible-header-wrapper { + display: none; + } + + &.has-multiple-attempts .attempt-item > .collapsible > .collapsible-header-wrapper { + display: flex; + } + } + + .attempt-item { + margin-bottom: 7px; + + > .collapsible { + position: relative; + margin-right: 20px; + .collapsible-header-inner { + outline: none; + } + + &:before { + border-left: 1px solid #dcdcdc; + content: ''; + left: 5px; + position: absolute; + top: 22px; + height: 15px; + } + + &.is-open:before { + display: none; + } + } + + &:last-child > .collapsible:before { + display: none; + } + + > .is-open .open-close-indicator { + i.fa-angle-down { + margin-top: 0; + } + + i.fa-angle-up { + order: 1; + margin-top: -4px; + } + } + + .open-close-indicator { + display: flex; + flex-direction: column; + + i { + margin-right: 5px; + + &.fa-angle-down { + margin-top: -4px; + } + } + } + } + + + .attempt-state-active { + .attempt-state { + + @include runnable-state-active; + } + } + .attempt-state-processing { + .attempt-state { + + @include runnable-state-processing; + } + } + .attempt-state-failed { + .attempt-state { + @include runnable-state-failed; + } + + .attempt-name:after { + color: $fail; + } + } + .attempt-state-passed { + .attempt-state { + + @include runnable-state-passed; + } + + + .attempt-name:after { + color: $pass; + } + } + + + .attempt-name { + display: flex; + justify-content: flex-end; + position: relative; + width: 100%; + + &:before { + border-top: 1px solid #dcdcdc; + content: ''; + left: 15px; + position: absolute; + right: 0; + top: 13px; + } + + &:after { + color: #a2a2a2; + content: 'โ€ข'; + left: 3px; + position: absolute; + top: 6px; + } + + .attempt-tag { + align-items: center; + border: 1px solid #d5d5d5; + border-radius: 7px; + box-shadow: 0 1px 1px 0 rgba(0, 0, 0, 0.20); + display: flex; + font-size: 11px; + padding: 2px 5px; + position: relative; + background-color: #fff; + user-select: none; + cursor: pointer; + + &:hover { + background-color: #e8e8e8; + } + } + + .collapsible-indicator, + .collapsible-more { + display: none; + } + + .attempt-state { + margin-left: 3px; + } + } +} diff --git a/packages/reporter/src/attempts/attempts.tsx b/packages/reporter/src/attempts/attempts.tsx new file mode 100644 index 000000000000..f2c13c7d2e0e --- /dev/null +++ b/packages/reporter/src/attempts/attempts.tsx @@ -0,0 +1,102 @@ +import cs from 'classnames' +import _ from 'lodash' +import { observer } from 'mobx-react' +import React, { Component } from 'react' + +import Agents from '../agents/agents' +import Collapsible from '../collapsible/collapsible' +import Hooks from '../hooks/hooks' +import Routes from '../routes/routes' +import TestError from '../errors/test-error' +import TestModel from '../test/test-model' +import AttemptModel from './attempt-model' + +const NoCommands = () => ( +
    +
  • + No commands were issued in this test. +
  • +
+) + +const AttemptHeader = ({ index }:{index: number}) => ( + + + + + + Attempt {index + 1} + + +) + +function renderAttemptContent (model: AttemptModel) { + // performance optimization - don't render contents if not open + + return ( +
+ + +
+ {model.hasCommands ? : } +
+ +
+ +
+
+ ) +} + +@observer +class Attempt extends Component<{model: AttemptModel, scrollIntoView: Function}> { + componentDidUpdate () { + this.props.scrollIntoView() + } + + render () { + const { model } = this.props + + // HACK: causes component update when command log is added + model.commands.length + + return ( +
  • + } + headerClass='attempt-name' + isOpen={model.isOpen} + > + {renderAttemptContent(model)} + +
  • + ) + } +} + +const Attempts = observer(({ test, scrollIntoView }: {test: TestModel, scrollIntoView: Function}) => { + return (
      + {_.map(test.attempts, (attempt) => { + return ( + + ) + })} +
    ) +}) + +export { Attempt, AttemptHeader, NoCommands } + +export default Attempts diff --git a/packages/reporter/src/collapsible/collapsible.spec.tsx b/packages/reporter/src/collapsible/collapsible.spec.tsx index 41996a32b1ad..f9b74eec2bc4 100644 --- a/packages/reporter/src/collapsible/collapsible.spec.tsx +++ b/packages/reporter/src/collapsible/collapsible.spec.tsx @@ -1,6 +1,5 @@ import React from 'react' import { shallow } from 'enzyme' - import Collapsible from './collapsible' describe('', () => { diff --git a/packages/reporter/src/collapsible/collapsible.tsx b/packages/reporter/src/collapsible/collapsible.tsx index e36363db36a5..c9d0533d651a 100644 --- a/packages/reporter/src/collapsible/collapsible.tsx +++ b/packages/reporter/src/collapsible/collapsible.tsx @@ -11,7 +11,6 @@ interface Props { headerExtras?: ReactNode containerRef?: RefObject contentClass?: string - toggleOpen?: (isOpen: boolean) => any } interface State { diff --git a/packages/reporter/src/commands/command-model.ts b/packages/reporter/src/commands/command-model.ts index aacafa18a744..6e4d344b6f05 100644 --- a/packages/reporter/src/commands/command-model.ts +++ b/packages/reporter/src/commands/command-model.ts @@ -110,9 +110,6 @@ export default class Command extends Instrument { if (this._becameNonPending()) { clearTimeout(this._pendingTimeout as TimeoutID) - action('became:inactive', () => { - return this.isLongRunning = false - })() } this._prevState = this.state diff --git a/packages/reporter/src/commands/commands.scss b/packages/reporter/src/commands/commands.scss index 3a5287a6a21a..7694559e58d5 100644 --- a/packages/reporter/src/commands/commands.scss +++ b/packages/reporter/src/commands/commands.scss @@ -222,6 +222,7 @@ .command-state-pending .command-number { i { + line-height: 18px; display: inline-block; } diff --git a/packages/reporter/src/errors/test-error.tsx b/packages/reporter/src/errors/test-error.tsx index ed18a7713b48..b2733676fb11 100644 --- a/packages/reporter/src/errors/test-error.tsx +++ b/packages/reporter/src/errors/test-error.tsx @@ -10,7 +10,7 @@ import ErrorStack from '../errors/error-stack' import events from '../lib/events' import FlashOnClick from '../lib/flash-on-click' import { onEnterOrSpace } from '../lib/util' -import TestModel from '../test/test-model' +import Attempt from '../attempts/attempt-model' interface DocsUrlProps { url: string | string[] @@ -31,7 +31,8 @@ const DocsUrl = ({ url }: DocsUrlProps) => { } interface TestErrorProps { - model: TestModel + model: Attempt + isTestError?: boolean } const TestError = observer((props: TestErrorProps) => { @@ -40,7 +41,7 @@ const TestError = observer((props: TestErrorProps) => { md.enable(['backticks', 'emphasis', 'escape']) const onPrint = () => { - events.emit('show:error', props.model.id) + events.emit('show:error', props.model) } const _onPrintClick = (e: MouseEvent) => { diff --git a/packages/reporter/src/header/stats-store.ts b/packages/reporter/src/header/stats-store.ts index e6b4cdd10fd0..b28446611c49 100644 --- a/packages/reporter/src/header/stats-store.ts +++ b/packages/reporter/src/header/stats-store.ts @@ -65,6 +65,7 @@ class StatsStore { this._currentTime = Date.now() } + @action incrementCount (type: TestState) { const countKey = `num${_.capitalize(type)}` diff --git a/packages/reporter/src/instruments/instrument-model.ts b/packages/reporter/src/instruments/instrument-model.ts index ac6a26fa381d..020e87a15781 100644 --- a/packages/reporter/src/instruments/instrument-model.ts +++ b/packages/reporter/src/instruments/instrument-model.ts @@ -16,10 +16,11 @@ export interface InstrumentProps { name?: string message?: string type?: string + testCurrentRetry: number state?: string | null referencesAlias?: Alias instrument?: 'agent' | 'command' | 'route' - testId: number + testId: string } export default class Log { diff --git a/packages/reporter/src/lib/base.scss b/packages/reporter/src/lib/base.scss index c5faa2e2242c..faa343748095 100644 --- a/packages/reporter/src/lib/base.scss +++ b/packages/reporter/src/lib/base.scss @@ -4,10 +4,15 @@ body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,code,form,fieldset,legend,input .reporter { background-color: #F6F6F6; + bottom: 0; color: #555; display: flex; flex-direction: column; font-size: 12px; + left: 0; + position: absolute; + right: 0; + top: 0; * { box-sizing: border-box; diff --git a/packages/reporter/src/lib/events.spec.ts b/packages/reporter/src/lib/events.spec.ts index c5d6d1b70962..05b95ec857e5 100644 --- a/packages/reporter/src/lib/events.spec.ts +++ b/packages/reporter/src/lib/events.spec.ts @@ -217,11 +217,16 @@ describe('events', () => { expect(runnablesStore.runnableFinished).to.have.been.calledWith('the runnable') }) - it('increments the stats count on test:after:run', () => { - runner.on.withArgs('test:after:run').callArgWith(1, { state: 'passed' }) + it('increments the stats count on test:after:run if final: true', () => { + runner.on.withArgs('test:after:run').callArgWith(1, { state: 'passed', final: true }) expect(statsStore.incrementCount).to.have.been.calledWith('passed') }) + it('does not increment the stats count on test:after:run if not final: true', () => { + runner.on.withArgs('test:after:run').callArgWith(1, { state: 'passed' }) + expect(statsStore.incrementCount).not.to.have.been.called + }) + it('pauses the appState with next command name on paused', () => { runner.on.withArgs('paused').callArgWith(1, 'next command') expect(appState.pause).to.have.been.calledWith('next command') @@ -303,12 +308,12 @@ describe('events', () => { }) it('emits runner:console:error with test id on show:error', () => { - const err = { isCommandErr: false } + const test = { err: { isCommandErr: false } } - runnablesStore.testById.returns({ err }) - events.emit('show:error', 'test id') + runnablesStore.testById.returns(test) + events.emit('show:error', test) expect(runner.emit).to.have.been.calledWith('runner:console:error', { - err, + err: test.err, commandId: undefined, }) }) @@ -319,7 +324,7 @@ describe('events', () => { } } runnablesStore.testById.returns(test) - events.emit('show:error', 'test id') + events.emit('show:error', test) expect(runner.emit).to.have.been.calledWith('runner:console:error', { err: test.err, commandId: 'matching command id', @@ -332,7 +337,7 @@ describe('events', () => { } } runnablesStore.testById.returns(test) - events.emit('show:error', 'test id') + events.emit('show:error', test) expect(runner.emit).to.have.been.calledWith('runner:console:error', { err: test.err, commandId: undefined, diff --git a/packages/reporter/src/lib/events.ts b/packages/reporter/src/lib/events.ts index 156dffe89894..76105016ff78 100644 --- a/packages/reporter/src/lib/events.ts +++ b/packages/reporter/src/lib/events.ts @@ -4,7 +4,7 @@ import appState, { AppState } from './app-state' import runnablesStore, { RunnablesStore, RootRunnable, LogProps } from '../runnables/runnables-store' import statsStore, { StatsStore, StatsStoreStartInfo } from '../header/stats-store' import scroller, { Scroller } from './scroller' -import TestModel, { TestProps, UpdateTestCallback } from '../test/test-model' +import TestModel, { UpdatableTestProps, UpdateTestCallback, TestProps } from '../test/test-model' const localBus = new EventEmitter() @@ -93,17 +93,19 @@ const events: Events = { } })) - runner.on('test:before:run:async', action('test:before:run:async', (runnable: TestModel) => { + runner.on('test:before:run:async', action('test:before:run:async', (runnable: TestProps) => { runnablesStore.runnableStarted(runnable) })) - runner.on('test:after:run', action('test:after:run', (runnable: TestModel) => { + runner.on('test:after:run', action('test:after:run', (runnable: TestProps) => { runnablesStore.runnableFinished(runnable) - statsStore.incrementCount(runnable.state) + if (runnable.final) { + statsStore.incrementCount(runnable.state!) + } })) - runner.on('test:set:state', action('test:set:state', (runnable: TestProps, cb: UpdateTestCallback) => { - runnablesStore.updateTest(runnable, cb) + runner.on('test:set:state', action('test:set:state', (props: UpdatableTestProps, cb: UpdateTestCallback) => { + runnablesStore.updateTest(props, cb) })) runner.on('paused', action('paused', (nextCommandName: string) => { @@ -160,13 +162,12 @@ const events: Events = { runner.emit('runner:console:log', commandId) }) - localBus.on('show:error', (testId: number) => { - const test = runnablesStore.testById(testId) - const command = test.err.isCommandErr && test.commandMatchingErr() + localBus.on('show:error', (test: TestModel) => { + const command = test.err.isCommandErr ? test.commandMatchingErr() : null runner.emit('runner:console:error', { err: test.err, - commandId: command ? command.id : undefined, + commandId: command?.id, }) }) diff --git a/packages/reporter/src/lib/mixins.scss b/packages/reporter/src/lib/mixins.scss new file mode 100644 index 000000000000..98ebbc41e1c9 --- /dev/null +++ b/packages/reporter/src/lib/mixins.scss @@ -0,0 +1,32 @@ +@mixin runnable-state-active { + @extend .#{$fa-css-prefix}-sync-alt; + @extend .#{$fa-css-prefix}-spin; +} + +@mixin runnable-state-processing { + @extend .far; + @extend .#{$fa-css-prefix}-square; + color: #888; + line-height: 18px; // @extend .far overrides line-height, so we need to set it again + +} + +@mixin runnable-state-skipped { + @extend .#{$fa-css-prefix}-ban; + color: #888; +} + +@mixin runnable-state-failed { + @extend .#{$fa-css-prefix}-times; + color: $fail; +} + +@mixin runnable-state-passed { + @extend .#{$fa-css-prefix}-check; + color: $pass; +} + +@mixin runnable-state-pending { + @extend .#{$fa-css-prefix}-circle-notch; + color: lighten($pending, 20%); +} diff --git a/packages/reporter/src/lib/variables.scss b/packages/reporter/src/lib/variables.scss index 40357fc625b3..ef26084a7105 100644 --- a/packages/reporter/src/lib/variables.scss +++ b/packages/reporter/src/lib/variables.scss @@ -5,6 +5,7 @@ $pinned: #9442ca; $yellow-dark: #FFB61C; $yellow-medium: lighten($yellow-dark, 25%); $yellow-lightest: #ffffee; +$retried: #f0ec98; $link-text: #3380FF; diff --git a/packages/reporter/src/main-runner.scss b/packages/reporter/src/main-runner.scss index ada4216e7ec7..aa522c4c6375 100644 --- a/packages/reporter/src/main-runner.scss +++ b/packages/reporter/src/main-runner.scss @@ -1,6 +1,7 @@ // this file is imported by the runner's main.scss // if you update this file, also update main.scss @import 'lib/variables'; +@import 'lib/mixins'; @import 'lib/base'; @import 'lib/tooltip'; @import '../../../node_modules/@reach/dialog/styles.css'; diff --git a/packages/reporter/src/main.scss b/packages/reporter/src/main.scss index bb9459db9c90..22e43c1ec838 100644 --- a/packages/reporter/src/main.scss +++ b/packages/reporter/src/main.scss @@ -1,6 +1,7 @@ // this file is used when developing the reporter in isolation via cypress tests // if you update this file, also update main-runner.scss @import 'lib/variables'; +@import 'lib/mixins'; @import 'lib/fonts'; @import 'lib/base'; @import 'lib/tooltip'; diff --git a/packages/reporter/src/runnables/runnable-and-suite.spec.tsx b/packages/reporter/src/runnables/runnable-and-suite.spec.tsx index 6be4df7ca02d..d6a65f490bac 100644 --- a/packages/reporter/src/runnables/runnable-and-suite.spec.tsx +++ b/packages/reporter/src/runnables/runnable-and-suite.spec.tsx @@ -104,7 +104,7 @@ describe('', () => { }) it('renders a runnable for each child', () => { - const component = shallow() + const component = shallow() expect(component.find(Runnable).length).to.equal(2) }) diff --git a/packages/reporter/src/runnables/runnable-and-suite.tsx b/packages/reporter/src/runnables/runnable-and-suite.tsx index b07d83f667b6..1023d6a969ff 100644 --- a/packages/reporter/src/runnables/runnable-and-suite.tsx +++ b/packages/reporter/src/runnables/runnable-and-suite.tsx @@ -48,6 +48,7 @@ class Runnable extends Component { return (
  • } export default class Runnable { - @observable id: number + @observable id: string @observable shouldRender: boolean = false @observable title?: string @observable level: number diff --git a/packages/reporter/src/runnables/runnables-store.spec.ts b/packages/reporter/src/runnables/runnables-store.spec.ts index 79efbc9da28c..1e5106b29fd8 100644 --- a/packages/reporter/src/runnables/runnables-store.spec.ts +++ b/packages/reporter/src/runnables/runnables-store.spec.ts @@ -33,30 +33,28 @@ const scrollerStub = () => { const createHook = (hookId: string) => { return { hookId, hookName: 'before each' } as HookProps } -const createTest = (id: number) => { - return { id, title: `test ${id}`, hooks: [], state: 'processing' } as TestProps +const createTest = (id: string) => { + return { id, title: `test ${id}`, hooks: [], state: 'processing', currentRetry: 0 } as TestProps } -const createSuite = (id: number, tests: Array, suites: Array) => { +const createSuite = (id: string, tests: Array, suites: Array) => { return { id, title: `suite ${id}`, tests, suites, hooks: [] } as SuiteProps } -const createAgent = (id: number, testId: number) => { - return { id, testId, instrument: 'agent' } as AgentProps +const createAgent = (id: number, testId: string) => { + return { id, testId, instrument: 'agent', callCount: 0, testCurrentRetry: 0, functionName: 'foo' } as AgentProps } -const createCommand = (id: number, testId: number, hookId?: string) => { +const createCommand = (id: number, testId: string, hookId?: string) => { return { id, testId, instrument: 'command', hookId } as CommandProps } -const createRoute = (id: number, testId: number) => { +const createRoute = (id: number, testId: string) => { return { id, testId, instrument: 'route' } as RouteProps } const createRootRunnable = () => { return { - tests: [createTest(1)], + tests: [createTest('1')], suites: [ - createSuite(1, [createTest(2), createTest(3)], [ - createSuite(3, [createTest(4)], []), createSuite(4, [createTest(5)], []), - ]), - createSuite(2, [createTest(6)], []), + createSuite('1', [createTest('2'), createTest('3')], [createSuite('3', [createTest('4')], []), createSuite('4', [createTest('5')], [])]), + createSuite('2', [createTest('6')], []), ], } as RootRunnable } @@ -100,14 +98,14 @@ describe('runnables store', () => { it('adds logs to tests when specified', () => { const rootRunnable = createRootRunnable() - rootRunnable.tests![0].agents = [createAgent(1, 1), createAgent(2, 1), createAgent(3, 1)] - rootRunnable.tests![0].commands = [createCommand(1, 1, 'h1')] - rootRunnable.tests![0].routes = [createRoute(1, 1), createRoute(2, 1)] + rootRunnable.tests![0].agents = [createAgent(1, '1'), createAgent(2, '1'), createAgent(3, '1')] + rootRunnable.tests![0].commands = [createCommand(1, '1', 'h1')] + rootRunnable.tests![0].routes = [createRoute(1, '1'), createRoute(2, '1')] rootRunnable.tests![0].hooks = [createHook('h1')] instance.setRunnables(rootRunnable) - expect((instance.runnables[0] as TestModel).agents.length).to.equal(3) - expect((instance.runnables[0] as TestModel).commands.length).to.equal(1) - expect((instance.runnables[0] as TestModel).routes.length).to.equal(2) + expect((instance.runnables[0] as TestModel).lastAttempt.agents.length).to.equal(3) + expect((instance.runnables[0] as TestModel).lastAttempt.commands.length).to.equal(1) + expect((instance.runnables[0] as TestModel).lastAttempt.routes.length).to.equal(2) }) it('sets the appropriate nesting levels', () => { @@ -142,17 +140,17 @@ describe('runnables store', () => { }) it('sets .hasTests flag to false if there are no tests', () => { - instance.setRunnables({ tests: [], suites: [createSuite(1, [], []), createSuite(2, [], [])] }) + instance.setRunnables({ tests: [], suites: [createSuite('1', [], []), createSuite('2', [], [])] }) expect(instance.hasTests).to.be.false }) it('sets .hasSingleTest flag to true if there is only one test', () => { - instance.setRunnables({ tests: [], suites: [createSuite(1, [], []), createSuite(2, [createTest(1)], [])] }) + instance.setRunnables({ tests: [], suites: [createSuite('1', [], []), createSuite('2', [createTest('1')], [])] }) expect(instance.hasSingleTest).to.be.true }) it('sets .hasSingleTest flag to false if there are no tests', () => { - instance.setRunnables({ tests: [], suites: [createSuite(1, [], []), createSuite(2, [], [])] }) + instance.setRunnables({ tests: [], suites: [createSuite('1', [], []), createSuite('2', [], [])] }) expect(instance.hasSingleTest).to.be.false }) @@ -162,7 +160,7 @@ describe('runnables store', () => { }) it('starts rendering the runnables on requestAnimationFrame', () => { - instance.setRunnables({ tests: [], suites: [createSuite(1, [], []), createSuite(2, [createTest(1)], [])] }) + instance.setRunnables({ tests: [], suites: [createSuite('1', [], []), createSuite('2', [createTest('1')], [])] }) expect(instance.runnables[0].shouldRender).to.be.true expect(instance.runnables[1].shouldRender).to.be.true expect((instance.runnables[1] as SuiteModel).children[0].shouldRender).to.be.true @@ -202,44 +200,44 @@ describe('runnables store', () => { context('#runnableStarted', () => { it('starts the test with the given id', () => { - instance.setRunnables({ tests: [createTest(1)], suites: [] }) - instance.runnableStarted({ id: 1 } as TestModel) + instance.setRunnables({ tests: [createTest('1')], suites: [] }) + instance.runnableStarted({ id: '1' } as TestProps) expect((instance.runnables[0] as TestModel).isActive).to.be.true }) }) context('#runnableFinished', () => { it('finishes the test with the given id', () => { - instance.setRunnables({ tests: [createTest(1)], suites: [] }) - instance.runnableStarted({ id: 1 } as TestModel) - instance.runnableFinished({ id: 1 } as TestModel) + instance.setRunnables({ tests: [createTest('1')], suites: [] }) + instance.runnableStarted({ id: '1' } as TestProps) + instance.runnableFinished({ id: '1' } as TestProps) expect((instance.runnables[0] as TestModel).isActive).to.be.false }) }) context('#testByid', () => { it('returns the test with the given id', () => { - instance.setRunnables({ tests: [createTest(1), createTest(3)], suites: [] }) - expect(instance.testById(3).title).to.be.equal('test 3') + instance.setRunnables({ tests: [createTest('1'), createTest('3')], suites: [] }) + expect(instance.testById('3').title).to.be.equal('test 3') }) }) context('#updateLog', () => { it('updates the log', () => { - const test = createTest(1) + const test = createTest('1') test.hooks = [createHook('h1')] instance.setRunnables({ tests: [test] }) - instance.addLog(createCommand(1, 1, 'h1')) - instance.updateLog({ id: 1, name: 'new name' } as LogProps) - expect(instance.testById(1).commands[0].name).to.equal('new name') + instance.addLog(createCommand(1, '1', 'h1')) + instance.updateLog({ id: 1, testId: '1', name: 'new name' } as LogProps) + expect(instance.testById('1').lastAttempt.commands[0].name).to.equal('new name') }) }) context('#reset', () => { it('resets flags to default values', () => { - instance.setRunnables({ tests: [createTest(1)] }) + instance.setRunnables({ tests: [createTest('1')] }) instance.attemptingShowSnapshot = true instance.showingSnapshot = true instance.reset() @@ -252,15 +250,15 @@ describe('runnables store', () => { }) it('resets runnables', () => { - instance.setRunnables({ tests: [createTest(1)] }) + instance.setRunnables({ tests: [createTest('1')] }) instance.reset() expect(instance.runnables.length).to.equal(0) }) it('resets tests', () => { - instance.setRunnables({ tests: [createTest(1)] }) + instance.setRunnables({ tests: [createTest('1')] }) instance.reset() - expect(instance.testById(1)).to.be.undefined + expect(instance.testById('1')).to.be.undefined }) }) }) diff --git a/packages/reporter/src/runnables/runnables-store.ts b/packages/reporter/src/runnables/runnables-store.ts index 72a03eb382ba..bdb3d1d916e6 100644 --- a/packages/reporter/src/runnables/runnables-store.ts +++ b/packages/reporter/src/runnables/runnables-store.ts @@ -8,7 +8,7 @@ import RouteModel, { RouteProps } from '../routes/route-model' import scroller, { Scroller } from '../lib/scroller' import { HookProps } from '../hooks/hook-model' import SuiteModel, { SuiteProps } from './suite-model' -import TestModel, { TestProps, UpdateTestCallback } from '../test/test-model' +import TestModel, { TestProps, UpdateTestCallback, UpdatableTestProps } from '../test/test-model' import RunnableModel from './runnable-model' const defaults = { @@ -29,7 +29,7 @@ export type LogProps = AgentProps | CommandProps | RouteProps export type RunnableArray = Array -type Log = AgentModel | CommandModel | RouteModel +export type Log = AgentModel | CommandModel | RouteModel export interface RootRunnable { hooks?: Array @@ -102,15 +102,11 @@ class RunnablesStore { } _createTest (props: TestProps, level: number) { - const test = new TestModel(props, level) + const test = new TestModel(props, level, this) this._runnablesQueue.push(test) this._tests[test.id] = test - _.each(props.agents, this.addLog.bind(this)) - _.each(props.commands, this.addLog.bind(this)) - _.each(props.routes, this.addLog.bind(this)) - return test } @@ -151,66 +147,35 @@ class RunnablesStore { this._initialScrollTop = initialScrollTop } - updateTest (props: TestProps, cb: UpdateTestCallback) { + updateTest (props: UpdatableTestProps, cb: UpdateTestCallback) { this._withTest(props.id, (test) => { - return test.update(props, cb) + test.update(props, cb) }) } - runnableStarted ({ id }: TestModel) { - this._withTest(id, (test) => { - return test.start() + runnableStarted (props: TestProps) { + this._withTest(props.id, (test) => { + test.start(props) }) } - runnableFinished (props: TestModel) { + runnableFinished (props: TestProps) { this._withTest(props.id, (test) => { - return test.finish(props) + test.finish(props) }) } - testById (id: number) { + testById (id: string) { return this._tests[id] } addLog (log: LogProps) { - switch (log.instrument) { - case 'command': { - const command = new CommandModel(log as CommandProps) - - this._logs[log.id] = command - this._withTest(log.testId, (test) => { - return test.addCommand(command) - }) - - break - } - case 'agent': { - const agent = new AgentModel(log as AgentProps) - - this._logs[log.id] = agent - this._withTest(log.testId, (test) => { - return test.addAgent(agent) - }) - - break - } - case 'route': { - const route = new RouteModel(log as RouteProps) - - this._logs[log.id] = route - this._withTest(log.testId, (test) => { - return test.addRoute(route) - }) - - break - } - default: - throw new Error(`Attempted to add log for unknown instrument: ${log.instrument}`) - } + this._withTest(log.testId, (test) => { + test.addLog(log) + }) } - _withTest (id: number, cb: ((test: TestModel) => void)) { + _withTest (id: string, cb: ((test: TestModel) => void)) { // we get events for suites and tests, but only tests change during a run, // so if the id isn't found in this._tests, we ignore it b/c it's a suite const test = this._tests[id] @@ -218,13 +183,10 @@ class RunnablesStore { if (test) cb(test) } - updateLog (log: LogProps) { - const found = this._logs[log.id] - - if (found) { - // The type of found is Log (one of Agent, Command, Route). So, we need any here. - found.update(log as any) - } + updateLog (props: LogProps) { + this._withTest(props.testId, (test) => { + test.updateLog(props) + }) } reset () { @@ -234,7 +196,6 @@ class RunnablesStore { this.runnables = [] this._tests = {} - this._logs = {} this._runnablesQueue = [] } } diff --git a/packages/reporter/src/runnables/runnables.scss b/packages/reporter/src/runnables/runnables.scss index e0c445ff6162..2ae964dba666 100644 --- a/packages/reporter/src/runnables/runnables.scss +++ b/packages/reporter/src/runnables/runnables.scss @@ -57,7 +57,7 @@ } } - &.test.hover { + .attempt-item:hover { > .runnable-wrapper .runnable-controls i.fa-redo { visibility: visible !important; } @@ -69,12 +69,11 @@ &.runnable-active { .runnable-state { - @extend .#{$fa-css-prefix}-sync-alt; - @extend .#{$fa-css-prefix}-spin; + @include runnable-state-active; } } - .runnable-state { + .runnable-state,.attempt-state { display: inline-block; line-height: 18px; margin-right: 5px; @@ -90,12 +89,10 @@ color: #bbbcbd; } - &.test.runnable-processing { + + &.test.runnable-processing { .runnable-state { - @extend .far; - line-height: 18px; // @extend .far overrides line-height, so we need to set it again - @extend .#{$fa-css-prefix}-square; - color: #888; + @include runnable-state-processing; } } @@ -119,10 +116,14 @@ border-left: 5px solid $pass; } + .runnable-retried > div > .runnable-wrapper, + .runnable-retried > div > .runnable-instruments { + border-left: 5px solid $retried; + } + &.runnable-skipped > .runnable-wrapper { .runnable-state { - @extend .#{$fa-css-prefix}-ban; - color: #888; + @include runnable-state-skipped; } .runnable-title { @@ -137,8 +138,7 @@ &.test.runnable-failed { .runnable-state { - @extend .#{$fa-css-prefix}-times; - color: $fail; + @include runnable-state-failed; } } @@ -152,21 +152,18 @@ &.test.runnable-passed { .runnable-state { - @extend .#{$fa-css-prefix}-check; - color: $pass; + @include runnable-state-passed; } } &.test.runnable-pending { + .runnable-state { + @include runnable-state-pending; + } .runnable-title { color: lighten($pending, 25%); } - .runnable-state { - @extend .#{$fa-css-prefix}-circle-notch; - color: lighten($pending, 20%); - } - .runnable-commands-region { display: none; } diff --git a/packages/reporter/src/runnables/runnables.spec.tsx b/packages/reporter/src/runnables/runnables.spec.tsx index e545727d0fbc..e92c126e7f19 100644 --- a/packages/reporter/src/runnables/runnables.spec.tsx +++ b/packages/reporter/src/runnables/runnables.spec.tsx @@ -46,7 +46,7 @@ describe('', () => { it('renders when there are runnables', () => { const component = shallow( , @@ -134,7 +134,7 @@ describe('', () => { context('', () => { it('renders a runnable for each runnable in model', () => { - const component = shallow() + const component = shallow() expect(component.find('Runnable').length).to.equal(2) }) diff --git a/packages/reporter/src/runnables/suite-model.spec.ts b/packages/reporter/src/runnables/suite-model.spec.ts index ec10badaee74..82a2523bb0f1 100644 --- a/packages/reporter/src/runnables/suite-model.spec.ts +++ b/packages/reporter/src/runnables/suite-model.spec.ts @@ -2,7 +2,7 @@ import Suite from './suite-model' import TestModel from '../test/test-model' const suiteWithChildren = (children: Array>) => { - const suite = new Suite({ id: 1, title: '', hooks: [] }, 0) + const suite = new Suite({ id: '1', title: '', hooks: [] }, 0) suite.children = children as Array diff --git a/packages/reporter/src/runnables/suite-model.ts b/packages/reporter/src/runnables/suite-model.ts index 47c2a26e009f..f227115071b7 100644 --- a/packages/reporter/src/runnables/suite-model.ts +++ b/packages/reporter/src/runnables/suite-model.ts @@ -32,6 +32,10 @@ export default class Suite extends Runnable { return _.map(this.children, 'state') } + @computed get hasRetried (): boolean { + return _.some(this.children, (v) => v.hasRetried) + } + @computed get _anyChildrenFailed () { return _.some(this._childStates, (state) => { return state === 'failed' diff --git a/packages/reporter/src/test/test-model.spec.ts b/packages/reporter/src/test/test-model.spec.ts index 9c9fb00e6533..bf811b8db008 100644 --- a/packages/reporter/src/test/test-model.spec.ts +++ b/packages/reporter/src/test/test-model.spec.ts @@ -1,37 +1,56 @@ -import { HookProps } from '../hooks/hook-model' -import Command, { CommandProps } from '../commands/command-model' -import Agent from '../agents/agent-model' -import Route from '../routes/route-model' import Err from '../errors/err-model' - -import TestModel, { TestProps } from './test-model' - -const commandHook: (hookId: string) => Partial = (hookId: string) => { - return { - hookId, - isMatchingEvent: () => { - return false - }, - } +import _ from 'lodash' +import TestModel, { TestProps, UpdatableTestProps } from './test-model' +import CommandModel, { CommandProps } from '../commands/command-model' +import { RouteProps } from '../routes/route-model' +import { RunnablesStore } from '../runnables/runnables-store' +import { AgentProps } from '../agents/agent-model' + +const createTest = (props: Partial = {}, store = {}) => { + const defaults = { + currentRetry: 0, + id: 'r3', + prevAttempts: [], + state: null, + hooks: [], + } as TestProps + + return new TestModel(_.defaults(props, defaults), 0, store as RunnablesStore) +} +const createCommand = (props: Partial = {}) => { + const defaults = { + instrument: 'command', + hookName: '', + id: 1, + hookId: 'r3', + numElements: 1, + testCurrentRetry: 0, + testId: 'r3', + timeout: 4000, + wallClockStartedAt: new Date().toString(), + + } as CommandProps + + return _.defaults(props, defaults) } describe('Test model', () => { context('.state', () => { it('is the "state" when it exists', () => { - const test = new TestModel({ id: 1, state: 'passed' } as TestProps, 0) + const test = createTest({ state: 'passed' }) expect(test.state).to.equal('passed') }) it('is active when there is no state and isActive is true', () => { - const test = new TestModel({ id: 1 } as TestProps, 0) + const test = createTest() - test.isActive = true + test.lastAttempt.isActive = true expect(test.state).to.equal('active') }) it('is processing when there is no state and isActive is falsey', () => { - const test = new TestModel({ id: 1 } as TestProps, 0) + const test = createTest() expect(test.state).to.equal('processing') }) @@ -39,201 +58,262 @@ describe('Test model', () => { context('.isLongRunning', () => { it('start out not long running', () => { - const test = new TestModel({ id: 1 } as TestProps, 0) + const test = createTest() expect(test.isLongRunning).to.be.false }) it('is not long running if active but without a long running command', () => { - const test = new TestModel({ id: 1 } as TestProps, 0) + const test = createTest() - test.start() + test.start({} as TestProps) expect(test.isLongRunning).to.be.false }) it('becomes long running if active and has a long running command', () => { - const test = new TestModel({ id: 1, hooks: [{ hookId: 'h1' } as HookProps] } as TestProps, 0) + const test = createTest() + + test.start({} as TestProps) + const command = test.addLog(createCommand()) as CommandModel - test.start() - test.addCommand({ isLongRunning: true, hookId: 'h1' } as Command) + command.isLongRunning = true expect(test.isLongRunning).to.be.true }) it('becomes not long running if it becomes inactive', () => { - const test = new TestModel({ id: 1, hooks: [{ hookId: 'h1' } as HookProps] } as TestProps, 0) + const test = createTest() - test.start() - test.addCommand({ isLongRunning: true, hookId: 'h1' } as Command) - test.finish({}) + test.start({} as TestProps) + const command = test.addLog(createCommand()) as CommandModel + + command.isLongRunning = true + + test.finish({} as UpdatableTestProps) expect(test.isLongRunning).to.be.false }) }) context('#addAgent', () => { it('adds the agent to the agents collection', () => { - const test = new TestModel({ id: 1 } as TestProps, 0) + const test = createTest() - test.addAgent({} as Agent) - expect(test.agents.length).to.equal(1) + test.addLog({ instrument: 'agent' } as AgentProps) + expect(test.lastAttempt.agents.length).to.equal(1) }) }) context('#addRoute', () => { it('adds the route to the routes collection', () => { - const test = new TestModel({ id: 1 } as TestProps, 0) + const test = createTest() - test.addRoute({} as Route) - expect(test.routes.length).to.equal(1) + test.addLog({ instrument: 'route' } as RouteProps) + expect(test.lastAttempt.routes.length).to.equal(1) }) }) context('#addCommand', () => { it('adds the command to the commands collection', () => { - const test = new TestModel({ id: 1, hooks: [{ hookId: 'h1' } as HookProps] } as TestProps, 0) + const test = createTest() + + test.addLog(createCommand()) + expect(test.lastAttempt.commands.length).to.equal(1) + }) - test.addCommand({ hookId: 'h1' } as Command) - expect(test.commands.length).to.equal(1) + it('creates a hook and adds the command to it if it does not exist', () => { + const test = createTest({ hooks: [ + { hookName: 'before each', hookId: 'h1' }, + ] }) + + test.addLog(createCommand({ instrument: 'command', hookId: 'h1' })) + expect(test.lastAttempt.hooks.length).to.equal(2) + expect(test.lastAttempt.hooks[0].hookName).equal('before each') + expect(test.lastAttempt.hooks[0].commands.length).to.equal(1) + }) + + it('adds the command to an existing hook if it already exists', () => { + const test = createTest({ hooks: [{ hookId: 'h1', hookName: 'before each' }] }) + const commandProps = createCommand({ + hookId: 'h1', + }) + + const command = test.addLog(commandProps) as CommandModel + + command.isMatchingEvent = () => false + + expect(test.lastAttempt.hooks.length).to.equal(2) + expect(test.lastAttempt.hooks[0].hookName).to.equal('before each') + expect(test.lastAttempt.hooks[0].commands.length).to.equal(1) + test.addLog(createCommand({ hookId: 'h1' })) + expect(test.lastAttempt.hooks.length).to.equal(2) + expect(test.lastAttempt.hooks[0].commands.length).to.equal(2) }) it('adds the command to the correct hook', () => { - const test = new TestModel({ - id: 1, + const test = createTest({ hooks: [ - { hookId: 'h1' } as HookProps, - { hookId: 'h2' } as HookProps, + { hookId: 'h1', hookName: 'before each' }, + { hookId: 'h2', hookName: 'before each' }, ], - } as TestProps, 0) + }) - test.addCommand(commandHook('h1') as Command) - expect(test.hooks[0].commands.length).to.equal(1) - expect(test.hooks[1].commands.length).to.equal(0) - expect(test.hooks[2].commands.length).to.equal(0) + test.addLog(createCommand({ hookId: 'h1' })) + expect(test.lastAttempt.hooks[0].commands.length).to.equal(1) + expect(test.lastAttempt.hooks[1].commands.length).to.equal(0) + expect(test.lastAttempt.hooks[2].commands.length).to.equal(0) - test.addCommand(commandHook('1') as Command) - expect(test.hooks[0].commands.length).to.equal(1) - expect(test.hooks[1].commands.length).to.equal(1) - expect(test.hooks[2].commands.length).to.equal(0) + test.addLog(createCommand({ hookId: 'h2' })) + expect(test.lastAttempt.hooks[0].commands.length).to.equal(1) + expect(test.lastAttempt.hooks[1].commands.length).to.equal(1) + expect(test.lastAttempt.hooks[2].commands.length).to.equal(0) }) it('moves hooks into the correct order', () => { - const test = new TestModel({ - id: 1, + const test = createTest({ hooks: [ - { hookId: 'h1' } as HookProps, - { hookId: 'h2' } as HookProps, + { hookId: 'h1', hookName: 'before all' }, + { hookId: 'h2', hookName: 'before each' }, ], - } as TestProps, 0) + }) - test.addCommand(commandHook('h2') as Command) - expect(test.hooks[0].hookId).to.equal('h2') - expect(test.hooks[0].invocationOrder).to.equal(0) - expect(test.hooks[0].commands.length).to.equal(1) + test.addLog(createCommand({ hookId: 'h2' })) + expect(test.lastAttempt.hooks[0].hookId).to.equal('h2') + expect(test.lastAttempt.hooks[0].invocationOrder).to.equal(0) + expect(test.lastAttempt.hooks[0].commands.length).to.equal(1) - test.addCommand(commandHook('h1') as Command) - expect(test.hooks[1].hookId).to.equal('h1') - expect(test.hooks[1].invocationOrder).to.equal(1) - expect(test.hooks[1].commands.length).to.equal(1) + test.addLog(createCommand({ hookId: 'h1' })) + expect(test.lastAttempt.hooks[1].hookId).to.equal('h1') + expect(test.lastAttempt.hooks[1].invocationOrder).to.equal(1) + expect(test.lastAttempt.hooks[1].commands.length).to.equal(1) }) it('counts and assigns the number of each hook type', () => { - const test = new TestModel({ - id: 1, + const test = createTest({ hooks: [ - { hookId: 'h1', hookName: 'before each' } as HookProps, - { hookId: 'h2', hookName: 'after each' } as HookProps, - { hookId: 'h3', hookName: 'before each' } as HookProps, + { hookId: 'h1', hookName: 'before each' }, + { hookId: 'h2', hookName: 'after each' }, + { hookId: 'h3', hookName: 'before each' }, ], - } as TestProps, 0) - - test.addCommand(commandHook('h1') as Command) - expect(test.hookCount['before each']).to.equal(1) - expect(test.hookCount['after each']).to.equal(0) - expect(test.hooks[0].hookNumber).to.equal(1) - - test.addCommand(commandHook('h1') as Command) - expect(test.hookCount['before each']).to.equal(1) - expect(test.hookCount['after each']).to.equal(0) - expect(test.hooks[0].hookNumber).to.equal(1) - - test.addCommand(commandHook('h3') as Command) - expect(test.hookCount['before each']).to.equal(2) - expect(test.hookCount['after each']).to.equal(0) - expect(test.hooks[1].hookNumber).to.equal(2) - - test.addCommand(commandHook('h2') as Command) - expect(test.hookCount['before each']).to.equal(2) - expect(test.hookCount['after each']).to.equal(1) - expect(test.hooks[2].hookNumber).to.equal(1) + }) + + test.addLog(createCommand({ hookId: 'h1' })) + expect(test.lastAttempt.hookCount['before each']).to.equal(1) + expect(test.lastAttempt.hookCount['after each']).to.equal(0) + expect(test.lastAttempt.hooks[0].hookNumber).to.equal(1) + + test.addLog(createCommand({ hookId: 'h1' })) + expect(test.lastAttempt.hookCount['before each']).to.equal(1) + expect(test.lastAttempt.hookCount['after each']).to.equal(0) + expect(test.lastAttempt.hooks[0].hookNumber).to.equal(1) + + test.addLog(createCommand({ hookId: 'h3' })) + expect(test.lastAttempt.hookCount['before each']).to.equal(2) + expect(test.lastAttempt.hookCount['after each']).to.equal(0) + expect(test.lastAttempt.hooks[1].hookNumber).to.equal(2) + + test.addLog(createCommand({ hookId: 'h2' })) + expect(test.lastAttempt.hookCount['before each']).to.equal(2) + expect(test.lastAttempt.hookCount['after each']).to.equal(1) + expect(test.lastAttempt.hooks[2].hookNumber).to.equal(1) }) }) context('#start', () => { it('sets the test as active', () => { - const test = new TestModel({ id: 1 } as TestProps, 0) + const test = createTest() - test.start() + test.start({} as TestProps) expect(test.isActive).to.be.true }) }) context('#finish', () => { it('sets the test as inactive', () => { - const test = new TestModel({ id: 1 } as TestProps, 0) + const test = createTest() - test.finish({}) + test.finish({} as UpdatableTestProps) expect(test.isActive).to.be.false }) it('updates the state of the test', () => { - const test = new TestModel({ id: 1 } as TestProps, 0) + const test = createTest() - test.finish({ state: 'failed' }) + test.finish({ state: 'failed' } as UpdatableTestProps) expect(test.state).to.equal('failed') }) it('updates the test err', () => { - const test = new TestModel({ id: 1 } as TestProps, 0) + const test = createTest() - test.finish({ err: { name: 'SomeError' } as Err }) + test.finish({ err: { name: 'SomeError' } as Err } as UpdatableTestProps) expect(test.err.name).to.equal('SomeError') }) it('sets the hook to failed if it exists', () => { - const test = new TestModel({ id: 1, hooks: [{ hookId: 'h1' } as HookProps] } as TestProps, 0) + const test = createTest({ hooks: [{ hookId: 'h1', hookName: 'before each' }] }) - test.addCommand({ hookId: 'h1' } as Command) - test.finish({ hookId: 'h1' }) - expect(test.hooks[0].failed).to.be.true + test.addLog(createCommand({ instrument: 'command' })) + test.finish({ hookId: 'h1', err: { message: 'foo' } as Err } as UpdatableTestProps) + expect(test.lastAttempt.hooks[1].failed).to.be.true }) it('does not throw error if hook does not exist', () => { - const test = new TestModel({ id: 1 } as TestProps, 0) + const test = createTest() expect(() => { - test.finish({ hookId: 'h1' }) + test.finish({ hookId: 'h1' } as UpdatableTestProps) }).not.to.throw() }) }) context('#commandMatchingErr', () => { it('returns last command matching the error', () => { - const test = new TestModel({ id: 1, err: { message: 'SomeError' } as Err, hooks: [{ hookId: 'h1' } as HookProps] } as TestProps, 0) - - test.addCommand(new Command({ err: { message: 'SomeError' } as Err, hookId: 'h1' } as CommandProps)) - test.addCommand(new Command({ err: {} as Err, hookId: 'h1' } as CommandProps)) - test.addCommand(new Command({ err: { message: 'SomeError' } as Err, hookId: 'h1' } as CommandProps)) - test.addCommand(new Command({ err: {} as Err, hookId: 'h1' } as CommandProps)) - test.addCommand(new Command({ name: 'The One', err: { message: 'SomeError' } as Err, hookId: 'h1' } as CommandProps)) + const test = createTest({ err: { message: 'SomeError' } as Err, hooks: [ + { hookId: 'h1', hookName: 'before each' }, + { hookId: 'h2', hookName: 'before each' }, + ] }) + + test.addLog(createCommand({ err: { message: 'SomeError' } as Err, hookId: 'h1' })) + test.addLog(createCommand({ err: {} as Err, hookId: 'h1' })) + test.addLog(createCommand({ err: { message: 'SomeError' } as Err, hookId: 'h1' })) + test.addLog(createCommand({ err: {} as Err, hookId: 'h2' })) + test.addLog(createCommand({ name: 'The One', err: { message: 'SomeError' } as Err, hookId: 'h2' })) expect(test.commandMatchingErr()!.name).to.equal('The One') }) it('returns undefined if there are no commands with errors', () => { - const test = new TestModel({ id: 1, err: { message: 'SomeError' } as Err, hooks: [{ hookId: 'h1' } as HookProps] } as TestProps, 0) + const test = createTest({ err: { message: 'SomeError' } as Err, hooks: [ + { hookId: 'h1', hookName: 'before each' }, + { hookId: 'h2', hookName: 'before each' }, + { hookId: 'h3', hookName: 'before each' }, + ] }) - test.addCommand(new Command({ hookId: 'h1' } as CommandProps)) - test.addCommand(new Command({ hookId: 'h1' } as CommandProps)) - test.addCommand(new Command({ hookId: 'h1' } as CommandProps)) expect(test.commandMatchingErr()).to.be.undefined }) }) + + context('#isOpen', () => { + it('false by default', () => { + const test = createTest() + + test.start({} as TestProps) + + expect(test.isOpen).eq(false) + }) + + it('true when the model is long running', () => { + const test = createTest() + + test.start({} as TestProps) + const command = test.addLog(createCommand()) as CommandModel + + command.isLongRunning = true + expect(test.isOpen).eq(true) + }) + + it('true when there is only one test', () => { + const test = createTest({}, { hasSingleTest: true }) + + expect(test.isOpen).eq(true) + }) + }) }) diff --git a/packages/reporter/src/test/test-model.ts b/packages/reporter/src/test/test-model.ts index 1be6515bf78e..ab60b961bc42 100644 --- a/packages/reporter/src/test/test-model.ts +++ b/packages/reporter/src/test/test-model.ts @@ -1,195 +1,205 @@ import _ from 'lodash' -import { action, autorun, computed, observable, observe } from 'mobx' +import { action, computed, observable } from 'mobx' import { FileDetails } from '@packages/ui-components' +import Attempt from '../attempts/attempt-model' import Err from '../errors/err-model' -import Hook, { HookName } from '../hooks/hook-model' +import { HookProps } from '../hooks/hook-model' import Runnable, { RunnableProps } from '../runnables/runnable-model' -import Command, { CommandProps } from '../commands/command-model' -import Agent, { AgentProps } from '../agents/agent-model' -import Route, { RouteProps } from '../routes/route-model' +import { CommandProps } from '../commands/command-model' +import { AgentProps } from '../agents/agent-model' +import { RouteProps } from '../routes/route-model' +import { RunnablesStore, LogProps } from '../runnables/runnables-store' export type TestState = 'active' | 'failed' | 'pending' | 'passed' | 'processing' export type UpdateTestCallback = () => void export interface TestProps extends RunnableProps { - state: TestState + state: TestState | null err?: Err isOpen?: boolean agents?: Array commands?: Array routes?: Array + hooks: Array + prevAttempts?: Array + currentRetry: number + retries?: number + final?: boolean invocationDetails?: FileDetails } export interface UpdatableTestProps { + id: TestProps['id'] state?: TestProps['state'] err?: TestProps['err'] hookId?: string isOpen?: TestProps['isOpen'] + currentRetry?: TestProps['currentRetry'] + retries?: TestProps['retries'] } export default class Test extends Runnable { - @observable agents: Array = [] - @observable commands: Array = [] - @observable err = new Err({}) - @observable hooks: Array = [] - // TODO: make this an enum with states: 'QUEUED, ACTIVE, INACTIVE' - @observable isActive: boolean | null = null - @observable isLongRunning = false - @observable isOpen = false - @observable routes: Array = [] - @observable _state?: TestState | null = null - @observable _invocationCount: number = 0 - @observable invocationDetails?: FileDetails - @observable hookCount: { [name in HookName]: number } = { - 'before all': 0, - 'before each': 0, - 'after all': 0, - 'after each': 0, - 'test body': 0, - } type = 'test' - callbackAfterUpdate: (() => void) | null = null + _callbackAfterUpdate: UpdateTestCallback | null = null + hooks: HookProps[] + invocationDetails?: FileDetails + + @observable attempts: Attempt[] = [] + @observable _isOpen: boolean | null = null + @observable isOpenWhenActive: Boolean | null = null + @observable _isFinished = false - constructor (props: TestProps, level: number) { + constructor (props: TestProps, level: number, private store: RunnablesStore) { super(props, level) - this._state = props.state - this.err.update(props.err) - this.invocationDetails = props.invocationDetails - this.hooks = _.map(props.hooks, (hook) => new Hook(hook)) - this.hooks.push(new Hook({ - hookId: this.id.toString(), + this.hooks = [...props.hooks, { + hookId: props.id.toString(), hookName: 'test body', - invocationDetails: this.invocationDetails, - })) - - autorun(() => { - // if at any point, a command goes long running, set isLongRunning - // to true until the test becomes inactive - if (!this.isActive) { - action('became:inactive', () => { - return this.isLongRunning = false - })() - } else if (this._hasLongRunningCommand) { - action('became:long:running', () => { - return this.isLongRunning = true - })() - } - }) + invocationDetails: props.invocationDetails, + }] + + _.each(props.prevAttempts || [], (attempt) => this._addAttempt(attempt)) + + this._addAttempt(props) } - @computed get _hasLongRunningCommand () { - return _.some(this.commands, (command) => { - return command.isLongRunning + @computed get isLongRunning () { + return _.some(this.attempts, (attempt: Attempt) => { + return attempt.isLongRunning }) } - @computed get state () { - return this._state || (this.isActive ? 'active' : 'processing') + @computed get isOpen () { + if (this._isOpen === null) { + return Boolean(this.state === 'failed' + || this.isLongRunning + || this.isActive && (this.hasMultipleAttempts || this.isOpenWhenActive) + || this.store.hasSingleTest) + } + + return this._isOpen } - addAgent (agent: Agent) { - this.agents.push(agent) + @computed get state () { + return this.lastAttempt ? this.lastAttempt.state : 'active' } - addRoute (route: Route) { - this.routes.push(route) + @computed get err () { + return this.lastAttempt ? this.lastAttempt.err : new Err({}) } - addCommand (command: Command) { - this.commands.push(command) + @computed get lastAttempt () { + return _.last(this.attempts) as Attempt + } - const hookIndex = _.findIndex(this.hooks, { hookId: command.hookId }) + @computed get hasMultipleAttempts () { + return this.attempts.length > 1 + } - const hook = this.hooks[hookIndex] + @computed get hasRetried () { + return this.state === 'passed' && this.hasMultipleAttempts + } - hook.addCommand(command) + // TODO: make this an enum with states: 'QUEUED, ACTIVE, INACTIVE' + @computed get isActive (): boolean { + return _.some(this.attempts, { isActive: true }) + } - // make sure that hooks are in order of invocation - if (hook.invocationOrder === undefined) { - hook.invocationOrder = this._invocationCount++ + @computed get currentRetry () { + return this.attempts.length - 1 + } - if (hook.invocationOrder !== hookIndex) { - this.hooks[hookIndex] = this.hooks[hook.invocationOrder] - this.hooks[hook.invocationOrder] = hook - } - } + isLastAttempt (attemptModel: Attempt) { + return this.lastAttempt === attemptModel + } - // assign number if non existent - if (hook.hookNumber === undefined) { - hook.hookNumber = ++this.hookCount[hook.hookName] - } + addLog = (props: LogProps) => { + return this._withAttempt(props.testCurrentRetry, (attempt: Attempt) => { + return attempt.addLog(props) + }) } - start () { - this.isActive = true + updateLog (props: LogProps) { + this._withAttempt(props.testCurrentRetry, (attempt: Attempt) => { + attempt.updateLog(props) + }) } - update ({ state, err, hookId, isOpen }: UpdatableTestProps, cb?: UpdateTestCallback) { - let hadChanges = false + @action start (props: TestProps) { + let attempt = this.getAttemptByIndex(props.currentRetry) + + if (!attempt) { + attempt = this._addAttempt(props) + } - const disposer = observe(this, (change) => { - hadChanges = true + attempt.start() + } - disposer() + @action update (props: UpdatableTestProps, cb: UpdateTestCallback) { + if (props.isOpen != null) { + this.setIsOpenWhenActive(props.isOpen) - // apply change as-is - return change - }) + if (this.isOpen !== props.isOpen) { + this._callbackAfterUpdate = cb - if (cb) { - this.callbackAfterUpdate = () => { - this.callbackAfterUpdate = null - cb() + return } } - this._state = state - this.err.update(err) - if (isOpen != null) { - this.isOpen = isOpen - } + cb() + } - if (hookId) { - const hook = _.find(this.hooks, { hookId }) + // this is called to sync up the command log UI for the sake of + // screenshots, so we only ever need to open the last attempt + setIsOpenWhenActive (isOpen: boolean) { + this.isOpenWhenActive = isOpen + } - if (hook) { - hook.failed = true - } + callbackAfterUpdate () { + if (this._callbackAfterUpdate) { + this._callbackAfterUpdate() + this._callbackAfterUpdate = null } + } - // if we had no changes then react will - // never fire componentDidUpdate and - // so we need to manually call our callback - // https://github.com/cypress-io/cypress/issues/674#issuecomment-366495057 - if (!hadChanges) { - // unbind the listener if no changes - disposer() - - // if we had a callback, invoke it - if (this.callbackAfterUpdate) { - this.callbackAfterUpdate() - } - } + @action finish (props: UpdatableTestProps) { + this._isFinished = !(props.retries && props.currentRetry) || props.currentRetry >= props.retries + + this._withAttempt(props.currentRetry || 0, (attempt: Attempt) => { + attempt.finish(props) + }) } - finish (props: UpdatableTestProps) { - this.update(props) - this.isActive = false + getAttemptByIndex (attemptIndex: number) { + if (attemptIndex >= this.attempts.length) return + + return this.attempts[attemptIndex || 0] } commandMatchingErr () { - return _(this.hooks) - .map((hook) => { - return hook.commandMatchingErr(this.err) - }) - .compact() - .last() + return this.lastAttempt.commandMatchingErr() + } + + _addAttempt = (props: TestProps) => { + props.invocationDetails = this.invocationDetails + props.hooks = this.hooks + const attempt = new Attempt(props, this) + + this.attempts.push(attempt) + + return attempt + } + + _withAttempt (attemptIndex: number, cb: (attempt: Attempt) => T) { + const attempt = this.getAttemptByIndex(attemptIndex) + + if (attempt) return cb(attempt) + + return null } } diff --git a/packages/reporter/src/test/test.spec.tsx b/packages/reporter/src/test/test.spec.tsx index f6792086d03a..2bc07054ca41 100644 --- a/packages/reporter/src/test/test.spec.tsx +++ b/packages/reporter/src/test/test.spec.tsx @@ -1,24 +1,22 @@ -import _ from 'lodash' import React from 'react' -import { mount, shallow, ReactWrapper } from 'enzyme' +import { shallow, mount, ReactWrapper } from 'enzyme' import sinon, { SinonSpy } from 'sinon' - -import Hooks from '../hooks/hooks' - -import Test, { NoCommands } from './test' -import TestModel from './test-model' +import _ from 'lodash' +import Test from './test' +import TestModel, { TestState } from './test-model' import { Scroller } from '../lib/scroller' import { AppState } from '../lib/app-state' const appStateStub = (props?: Partial) => { - return _.extend({ + return { autoScrollingEnabled: true, isRunning: true, - }, props) + ...props, + } as AppState } const model = (props?: Partial) => { - return _.extend({ + return { agents: [], commands: [], hooks: [], @@ -30,8 +28,10 @@ const model = (props?: Partial) => { shouldRender: true, state: 'passed', title: 'some title', - type: 'test', - }, props) + callbackAfterUpdate: () => {}, + toggleOpen: sinon.stub(), + ...props, + } as any } type ScrollerStub = Scroller & { @@ -42,6 +42,8 @@ const scrollerStub = () => ({ scrollIntoView: sinon.spy(), } as ScrollerStub) +const setTestState = (test:TestModel, state:TestState) => _.extend(test, { state }) + describe('', () => { it('does not render when it should not render', () => { const component = shallow() @@ -49,88 +51,18 @@ describe('', () => { expect(component).to.be.empty }) - context('open/closed', () => { - it('renders without is-open class by default', () => { - const component = mount() - - expect(component.find('.collapsible').first()).not.to.have.className('is-open') - }) - - it('renders with is-open class when the model state is failed', () => { - const component = mount() - - expect(component.find('.collapsible').first()).to.have.className('is-open') - }) - - it('renders with is-open class when the model is long running', () => { - const component = mount() - - expect(component.find('.collapsible').first()).to.have.className('is-open') - }) - - it('renders with is-open class when there is only one test', () => { - const component = mount() - - expect(component.find('.collapsible').first()).to.have.className('is-open') - }) - - context('toggling', () => { - it('renders without is-open class when already open', () => { - const component = mount() - - component.find('.collapsible-header').first().simulate('click') - expect(component.find('.collapsible').first()).not.to.have.className('is-open') - }) - - it('renders with is-open class when not already open', () => { - const component = mount() - - component.find('.collapsible-header').first().simulate('click') - expect(component.find('.collapsible').first()).to.have.className('is-open') - }) - - it('renders without is-open class when toggled again', () => { - const component = mount() - - component.find('.collapsible-header').first().simulate('click') - component.find('.collapsible-header').first().simulate('click') - expect(component.find('.collapsible').first()).not.to.have.className('is-open') - }) - }) - }) - context('contents', () => { it('does not render the contents if not open', () => { - const component = mount() + const component = mount() expect(component.find('.runnable-instruments')).to.be.empty }) it('renders the contents if open', () => { - const component = mount() + const component = mount() expect(component.find('.runnable-instruments')).not.to.be.empty }) - - it('renders if there are commands', () => { - const component = shallow() - - expect(component.find(Hooks)).to.exist - }) - - it('renders is no commands', () => { - const component = shallow() - - expect(component.find(NoCommands)).to.exist - }) - - it('stops propagation when clicked', () => { - const component = mount() - const e = { stopPropagation: sinon.spy() } - - component.find('.collapsible-header').first().simulate('click', e) - expect(e.stopPropagation).to.have.been.called - }) }) context('scrolling into view', () => { @@ -195,11 +127,11 @@ describe('', () => { expect(scroller.scrollIntoView).not.to.have.been.called }) - it('does not scroll into view if model.isActive is null', () => { + it('does not scroll into view if model.state is processing', () => { mount( , ) @@ -215,30 +147,21 @@ describe('', () => { beforeEach(() => { appState = appStateStub({ autoScrollingEnabled: false, isRunning: false }) - testModel = model({ isActive: null }) + testModel = model({ state: 'processing' }) component = mount() }) - it('scrolls into view if auto-scrolling is enabled, app is running, the model should render, and the model.isActive is null', () => { - appState.id = 'fooo' - appState.autoScrollingEnabled = true - appState.isRunning = true - testModel.isActive = true - testModel.shouldRender = true - component.instance()!.componentDidUpdate!({}, {}) - expect(scroller.scrollIntoView).to.have.been.calledWith((component.instance() as any).containerRef.current) - }) - it('does not scroll into view if auto-scrolling is disabled', () => { appState.isRunning = true - testModel.isActive = true + setTestState(testModel, 'processing') component.instance()!.componentDidUpdate!({}, {}) expect(scroller.scrollIntoView).not.to.have.been.called }) it('does not scroll into view if app is not running', () => { appState.autoScrollingEnabled = true - testModel.isActive = true + setTestState(testModel, 'processing') + component.instance()!.componentDidUpdate!({}, {}) expect(scroller.scrollIntoView).not.to.have.been.called }) diff --git a/packages/reporter/src/test/test.tsx b/packages/reporter/src/test/test.tsx index 07f8550f553e..10556594a68a 100644 --- a/packages/reporter/src/test/test.tsx +++ b/packages/reporter/src/test/test.tsx @@ -1,31 +1,20 @@ -import { action, observable } from 'mobx' import { observer } from 'mobx-react' import React, { Component, createRef, RefObject } from 'react' // @ts-ignore import Tooltip from '@cypress/react-tooltip' +import events, { Events } from '../lib/events' import appState, { AppState } from '../lib/app-state' import Collapsible from '../collapsible/collapsible' import { indent } from '../lib/util' import runnablesStore, { RunnablesStore } from '../runnables/runnables-store' -import scroller, { Scroller } from '../lib/scroller' - -import Hooks from '../hooks/hooks' -import Agents from '../agents/agents' -import Routes from '../routes/routes' -import TestError from '../errors/test-error' - import TestModel from './test-model' +import scroller, { Scroller } from '../lib/scroller' -const NoCommands = observer(() => ( -
      -
    • - No commands were issued in this test. -
    • -
    -)) +import Attempts from '../attempts/attempts' interface Props { + events: Events appState: AppState runnablesStore: RunnablesStore scroller: Scroller @@ -35,13 +24,12 @@ interface Props { @observer class Test extends Component { static defaultProps = { + events, appState, runnablesStore, scroller, } - @observable isOpen: boolean | null = null - containerRef: RefObject constructor (props: Props) { @@ -56,19 +44,14 @@ class Test extends Component { componentDidUpdate () { this._scrollIntoView() - - const cb = this.props.model.callbackAfterUpdate - - if (cb) { - cb() - } + this.props.model.callbackAfterUpdate() } _scrollIntoView () { const { appState, model, scroller } = this.props - const { isActive, shouldRender } = model + const { state, shouldRender } = model - if (appState.autoScrollingEnabled && appState.isRunning && shouldRender && isActive != null) { + if (appState.autoScrollingEnabled && appState.isRunning && shouldRender && state !== 'processing') { window.requestAnimationFrame(() => { // since this executes async in a RAF the ref might be null if (this.containerRef.current) { @@ -90,7 +73,7 @@ class Test extends Component { headerClass='runnable-wrapper' headerStyle={{ paddingLeft: indent(model.level) }} contentClass='runnable-instruments' - isOpen={this._shouldBeOpen()} + isOpen={model.isOpen} > {this._contents()} @@ -119,37 +102,11 @@ class Test extends Component { return (
    - - -
    - {model.commands.length ? : } -
    - + + this._scrollIntoView()} />
    ) } - - _shouldBeOpen () { - // if this.isOpen is non-null, prefer that since the user has - // explicity chosen to open or close the test - if (this.isOpen !== null) return this.isOpen - - // otherwise, look at reasons to auto-open the test - return this.props.model.state === 'failed' - || this.props.model.isOpen - || this.props.model.isLongRunning - || this.props.runnablesStore.hasSingleTest - } - - @action _toggleOpen = () => { - if (this.isOpen === null) { - this.isOpen = !this._shouldBeOpen() - } else { - this.isOpen = !this.isOpen - } - } } -export { NoCommands } - export default Test diff --git a/packages/runner/__snapshots__/retries.mochaEvents.spec.js b/packages/runner/__snapshots__/retries.mochaEvents.spec.js new file mode 100644 index 000000000000..cff75b2f8808 --- /dev/null +++ b/packages/runner/__snapshots__/retries.mochaEvents.spec.js @@ -0,0 +1,6458 @@ +exports['src/cypress/runner retries mochaEvents simple retry #1'] = [ + [ + "mocha", + "start", + { + "start": "match.date" + } + ], + [ + "mocha", + "suite", + { + "id": "r1", + "title": "", + "root": true, + "type": "suite", + "file": "relative/path/to/spec.js", + "retries": -1 + } + ], + [ + "mocha", + "suite", + { + "id": "r2", + "title": "suite 1", + "root": false, + "type": "suite", + "file": null, + "retries": -1 + } + ], + [ + "mocha", + "test", + { + "id": "r3", + "order": 1, + "title": "test 1", + "body": "[body]", + "type": "test", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "test:before:run", + { + "id": "r3", + "order": 1, + "title": "test 1", + "body": "[body]", + "type": "test", + "wallClockStartedAt": "match.date", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "retry", + { + "id": "r3", + "order": 1, + "title": "test 1", + "err": "{Object 9}", + "state": "failed", + "body": "[body]", + "type": "test", + "duration": "match.number", + "wallClockStartedAt": "match.date", + "timings": { + "lifecycle": "match.number", + "test": { + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + }, + "file": null, + "invocationDetails": "{Object 8}", + "final": false, + "currentRetry": 0, + "retries": 1 + }, + { + "message": "[error message]", + "name": "AssertionError", + "stack": "match.string", + "sourceMappedStack": "match.string", + "parsedStack": "match.array", + "actual": null, + "showDiff": false + } + ], + [ + "mocha", + "test:after:run", + { + "id": "r3", + "order": 1, + "title": "test 1", + "err": "{Object 9}", + "state": "failed", + "body": "[body]", + "type": "test", + "duration": "match.number", + "wallClockStartedAt": "match.date", + "wallClockDuration": "match.number", + "timings": { + "lifecycle": "match.number", + "test": { + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + }, + "file": null, + "invocationDetails": "{Object 8}", + "final": false, + "currentRetry": 0, + "retries": 1 + } + ], + [ + "mocha", + "test:before:run", + { + "id": "r3", + "title": "test 1", + "body": "[body]", + "type": "test", + "wallClockStartedAt": "match.date", + "file": null, + "currentRetry": 1, + "retries": 1 + } + ], + [ + "mocha", + "pass", + { + "id": "r3", + "title": "test 1", + "state": "passed", + "body": "[body]", + "type": "test", + "duration": "match.number", + "wallClockStartedAt": "match.date", + "timings": { + "lifecycle": "match.number", + "test": { + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + }, + "file": null, + "final": true, + "currentRetry": 1, + "retries": 1 + } + ], + [ + "mocha", + "test end", + { + "id": "r3", + "title": "test 1", + "state": "passed", + "body": "[body]", + "type": "test", + "duration": "match.number", + "wallClockStartedAt": "match.date", + "timings": { + "lifecycle": "match.number", + "test": { + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + }, + "file": null, + "final": true, + "currentRetry": 1, + "retries": 1 + } + ], + [ + "mocha", + "suite end", + { + "id": "r2", + "title": "suite 1", + "root": false, + "type": "suite", + "file": null, + "retries": -1 + } + ], + [ + "mocha", + "test:after:run", + { + "id": "r3", + "title": "test 1", + "state": "passed", + "body": "[body]", + "type": "test", + "duration": "match.number", + "wallClockStartedAt": "match.date", + "wallClockDuration": "match.number", + "timings": { + "lifecycle": "match.number", + "test": { + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + }, + "file": null, + "final": true, + "currentRetry": 1, + "retries": 1 + } + ], + [ + "mocha", + "suite end", + { + "id": "r1", + "title": "", + "root": true, + "type": "suite", + "file": "relative/path/to/spec.js", + "retries": -1 + } + ], + [ + "mocha", + "end", + { + "end": "match.date" + } + ] +] + +exports['src/cypress/runner retries mochaEvents test retry with hooks #1'] = [ + [ + "mocha", + "start", + { + "start": "match.date" + } + ], + [ + "mocha", + "suite", + { + "id": "r1", + "title": "", + "root": true, + "type": "suite", + "file": "relative/path/to/spec.js", + "retries": -1 + } + ], + [ + "mocha", + "suite", + { + "id": "r2", + "title": "suite 1", + "root": false, + "type": "suite", + "file": null, + "retries": -1 + } + ], + [ + "mocha", + "hook", + { + "id": "r3", + "title": "\"before all\" hook", + "hookName": "before all", + "hookId": "h1", + "body": "[body]", + "type": "hook", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "test:before:run", + { + "id": "r3", + "order": 1, + "title": "test 1", + "body": "[body]", + "type": "test", + "wallClockStartedAt": "match.date", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook end", + { + "id": "r3", + "title": "\"before all\" hook", + "hookName": "before all", + "hookId": "h1", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "test", + { + "id": "r3", + "order": 1, + "title": "test 1", + "body": "[body]", + "type": "test", + "wallClockStartedAt": "match.date", + "timings": { + "lifecycle": "match.number", + "before all": [ + { + "hookId": "h1", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "before each": [ + { + "hookId": "h2", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "test": { + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + "after each": [ + { + "hookId": "h4", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ] + }, + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": 1 + } + ], + [ + "mocha", + "hook", + { + "id": "r3", + "title": "\"before each\" hook", + "hookName": "before each", + "hookId": "h2", + "body": "[body]", + "type": "hook", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook end", + { + "id": "r3", + "title": "\"before each\" hook", + "hookName": "before each", + "hookId": "h2", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "retry", + { + "id": "r3", + "order": 1, + "title": "test 1", + "err": "{Object 9}", + "state": "failed", + "body": "[body]", + "type": "test", + "duration": "match.number", + "wallClockStartedAt": "match.date", + "timings": { + "lifecycle": "match.number", + "before all": [ + { + "hookId": "h1", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "before each": [ + { + "hookId": "h2", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "test": { + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + "after each": [ + { + "hookId": "h4", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ] + }, + "file": null, + "invocationDetails": "{Object 8}", + "final": false, + "currentRetry": 0, + "retries": 1 + }, + { + "message": "[error message]", + "name": "AssertionError", + "stack": "match.string", + "sourceMappedStack": "match.string", + "parsedStack": "match.array", + "actual": null, + "showDiff": false + } + ], + [ + "mocha", + "hook", + { + "id": "r3", + "title": "\"after each\" hook", + "hookName": "after each", + "hookId": "h4", + "body": "[body]", + "type": "hook", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook end", + { + "id": "r3", + "title": "\"after each\" hook", + "hookName": "after each", + "hookId": "h4", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "test:after:run", + { + "id": "r3", + "order": 1, + "title": "test 1", + "err": "{Object 9}", + "state": "failed", + "body": "[body]", + "type": "test", + "duration": "match.number", + "wallClockStartedAt": "match.date", + "wallClockDuration": "match.number", + "timings": { + "lifecycle": "match.number", + "before all": [ + { + "hookId": "h1", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "before each": [ + { + "hookId": "h2", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "test": { + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + "after each": [ + { + "hookId": "h4", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ] + }, + "file": null, + "invocationDetails": "{Object 8}", + "final": false, + "currentRetry": 0, + "retries": 1 + } + ], + [ + "mocha", + "hook", + { + "id": "r3", + "title": "\"before each\" hook", + "hookName": "before each", + "hookId": "h2", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "test:before:run", + { + "id": "r3", + "title": "test 1", + "body": "[body]", + "type": "test", + "wallClockStartedAt": "match.date", + "file": null, + "currentRetry": 1, + "retries": 1 + } + ], + [ + "mocha", + "hook end", + { + "id": "r3", + "title": "\"before each\" hook", + "hookName": "before each", + "hookId": "h2", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook", + { + "id": "r3", + "title": "\"after each\" hook", + "hookName": "after each", + "hookId": "h4", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook end", + { + "id": "r3", + "title": "\"after each\" hook", + "hookName": "after each", + "hookId": "h4", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook", + { + "id": "r3", + "title": "\"after all\" hook", + "hookName": "after all", + "hookId": "h3", + "body": "[body]", + "type": "hook", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook end", + { + "id": "r3", + "title": "\"after all\" hook", + "hookName": "after all", + "hookId": "h3", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "pass", + { + "id": "r3", + "title": "test 1", + "state": "passed", + "body": "[body]", + "type": "test", + "duration": "match.number", + "wallClockStartedAt": "match.date", + "timings": { + "lifecycle": "match.number", + "before each": [ + { + "hookId": "h2", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "test": { + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + "after each": [ + { + "hookId": "h4", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "after all": [ + { + "hookId": "h3", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ] + }, + "file": null, + "final": true, + "currentRetry": 1, + "retries": 1 + } + ], + [ + "mocha", + "test end", + { + "id": "r3", + "title": "test 1", + "state": "passed", + "body": "[body]", + "type": "test", + "duration": "match.number", + "wallClockStartedAt": "match.date", + "timings": { + "lifecycle": "match.number", + "before each": [ + { + "hookId": "h2", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "test": { + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + "after each": [ + { + "hookId": "h4", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "after all": [ + { + "hookId": "h3", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ] + }, + "file": null, + "final": true, + "currentRetry": 1, + "retries": 1 + } + ], + [ + "mocha", + "suite end", + { + "id": "r2", + "title": "suite 1", + "root": false, + "type": "suite", + "file": null, + "retries": -1 + } + ], + [ + "mocha", + "test:after:run", + { + "id": "r3", + "title": "test 1", + "state": "passed", + "body": "[body]", + "type": "test", + "duration": "match.number", + "wallClockStartedAt": "match.date", + "wallClockDuration": "match.number", + "timings": { + "lifecycle": "match.number", + "before each": [ + { + "hookId": "h2", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "test": { + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + "after each": [ + { + "hookId": "h4", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "after all": [ + { + "hookId": "h3", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ] + }, + "file": null, + "final": true, + "currentRetry": 1, + "retries": 1 + } + ], + [ + "mocha", + "suite end", + { + "id": "r1", + "title": "", + "root": true, + "type": "suite", + "file": "relative/path/to/spec.js", + "retries": -1 + } + ], + [ + "mocha", + "end", + { + "end": "match.date" + } + ] +] + +exports['src/cypress/runner retries mochaEvents test retry with [only] #1'] = [ + [ + "mocha", + "start", + { + "start": "match.date" + } + ], + [ + "mocha", + "suite", + { + "id": "r1", + "title": "", + "root": true, + "type": "suite", + "file": "relative/path/to/spec.js", + "retries": -1 + } + ], + [ + "mocha", + "suite", + { + "id": "r4", + "title": "suite 1", + "root": false, + "type": "suite", + "file": null, + "retries": -1 + } + ], + [ + "mocha", + "hook", + { + "id": "r5", + "title": "\"before all\" hook", + "hookName": "before all", + "hookId": "h1", + "body": "[body]", + "type": "hook", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "test:before:run", + { + "id": "r5", + "order": 2, + "title": "test 2", + "body": "[body]", + "type": "test", + "wallClockStartedAt": "match.date", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook end", + { + "id": "r5", + "title": "\"before all\" hook", + "hookName": "before all", + "hookId": "h1", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "test", + { + "id": "r5", + "order": 2, + "title": "test 2", + "body": "[body]", + "type": "test", + "wallClockStartedAt": "match.date", + "timings": { + "lifecycle": "match.number", + "before all": [ + { + "hookId": "h1", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "before each": [ + { + "hookId": "h2", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "test": { + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + "after each": [ + { + "hookId": "h4", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ] + }, + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": 1 + } + ], + [ + "mocha", + "hook", + { + "id": "r5", + "title": "\"before each\" hook", + "hookName": "before each", + "hookId": "h2", + "body": "[body]", + "type": "hook", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook end", + { + "id": "r5", + "title": "\"before each\" hook", + "hookName": "before each", + "hookId": "h2", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "retry", + { + "id": "r5", + "order": 2, + "title": "test 2", + "err": "{Object 9}", + "state": "failed", + "body": "[body]", + "type": "test", + "duration": "match.number", + "wallClockStartedAt": "match.date", + "timings": { + "lifecycle": "match.number", + "before all": [ + { + "hookId": "h1", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "before each": [ + { + "hookId": "h2", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "test": { + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + "after each": [ + { + "hookId": "h4", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ] + }, + "file": null, + "invocationDetails": "{Object 8}", + "final": false, + "currentRetry": 0, + "retries": 1 + }, + { + "message": "[error message]", + "name": "AssertionError", + "stack": "match.string", + "sourceMappedStack": "match.string", + "parsedStack": "match.array", + "actual": null, + "showDiff": false + } + ], + [ + "mocha", + "hook", + { + "id": "r5", + "title": "\"after each\" hook", + "hookName": "after each", + "hookId": "h4", + "body": "[body]", + "type": "hook", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook end", + { + "id": "r5", + "title": "\"after each\" hook", + "hookName": "after each", + "hookId": "h4", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "test:after:run", + { + "id": "r5", + "order": 2, + "title": "test 2", + "err": "{Object 9}", + "state": "failed", + "body": "[body]", + "type": "test", + "duration": "match.number", + "wallClockStartedAt": "match.date", + "wallClockDuration": "match.number", + "timings": { + "lifecycle": "match.number", + "before all": [ + { + "hookId": "h1", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "before each": [ + { + "hookId": "h2", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "test": { + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + "after each": [ + { + "hookId": "h4", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ] + }, + "file": null, + "invocationDetails": "{Object 8}", + "final": false, + "currentRetry": 0, + "retries": 1 + } + ], + [ + "mocha", + "hook", + { + "id": "r5", + "title": "\"before each\" hook", + "hookName": "before each", + "hookId": "h2", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "test:before:run", + { + "id": "r5", + "title": "test 2", + "body": "[body]", + "type": "test", + "wallClockStartedAt": "match.date", + "file": null, + "currentRetry": 1, + "retries": 1 + } + ], + [ + "mocha", + "hook end", + { + "id": "r5", + "title": "\"before each\" hook", + "hookName": "before each", + "hookId": "h2", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook", + { + "id": "r5", + "title": "\"after each\" hook", + "hookName": "after each", + "hookId": "h4", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook end", + { + "id": "r5", + "title": "\"after each\" hook", + "hookName": "after each", + "hookId": "h4", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook", + { + "id": "r5", + "title": "\"after all\" hook", + "hookName": "after all", + "hookId": "h3", + "body": "[body]", + "type": "hook", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook end", + { + "id": "r5", + "title": "\"after all\" hook", + "hookName": "after all", + "hookId": "h3", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "pass", + { + "id": "r5", + "title": "test 2", + "state": "passed", + "body": "[body]", + "type": "test", + "duration": "match.number", + "wallClockStartedAt": "match.date", + "timings": { + "lifecycle": "match.number", + "before each": [ + { + "hookId": "h2", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "test": { + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + "after each": [ + { + "hookId": "h4", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "after all": [ + { + "hookId": "h3", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ] + }, + "file": null, + "final": true, + "currentRetry": 1, + "retries": 1 + } + ], + [ + "mocha", + "test end", + { + "id": "r5", + "title": "test 2", + "state": "passed", + "body": "[body]", + "type": "test", + "duration": "match.number", + "wallClockStartedAt": "match.date", + "timings": { + "lifecycle": "match.number", + "before each": [ + { + "hookId": "h2", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "test": { + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + "after each": [ + { + "hookId": "h4", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "after all": [ + { + "hookId": "h3", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ] + }, + "file": null, + "final": true, + "currentRetry": 1, + "retries": 1 + } + ], + [ + "mocha", + "suite end", + { + "id": "r4", + "title": "suite 1", + "root": false, + "type": "suite", + "file": null, + "retries": -1 + } + ], + [ + "mocha", + "test:after:run", + { + "id": "r5", + "title": "test 2", + "state": "passed", + "body": "[body]", + "type": "test", + "duration": "match.number", + "wallClockStartedAt": "match.date", + "wallClockDuration": "match.number", + "timings": { + "lifecycle": "match.number", + "before each": [ + { + "hookId": "h2", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "test": { + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + "after each": [ + { + "hookId": "h4", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "after all": [ + { + "hookId": "h3", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ] + }, + "file": null, + "final": true, + "currentRetry": 1, + "retries": 1 + } + ], + [ + "mocha", + "suite end", + { + "id": "r1", + "title": "", + "root": true, + "type": "suite", + "file": "relative/path/to/spec.js", + "retries": -1 + } + ], + [ + "mocha", + "end", + { + "end": "match.date" + } + ] +] + +exports['src/cypress/runner retries mochaEvents can retry from [beforeEach] #1'] = [ + [ + "mocha", + "start", + { + "start": "match.date" + } + ], + [ + "mocha", + "suite", + { + "id": "r1", + "title": "", + "root": true, + "type": "suite", + "file": "relative/path/to/spec.js", + "retries": -1 + } + ], + [ + "mocha", + "suite", + { + "id": "r2", + "title": "suite 1", + "root": false, + "type": "suite", + "file": null, + "retries": -1 + } + ], + [ + "mocha", + "hook", + { + "id": "r3", + "title": "\"before all\" hook", + "hookName": "before all", + "hookId": "h1", + "body": "[body]", + "type": "hook", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "test:before:run", + { + "id": "r3", + "order": 1, + "title": "test 1", + "body": "[body]", + "type": "test", + "wallClockStartedAt": "match.date", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook end", + { + "id": "r3", + "title": "\"before all\" hook", + "hookName": "before all", + "hookId": "h1", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "test", + { + "id": "r3", + "order": 1, + "title": "test 1", + "body": "[body]", + "type": "test", + "wallClockStartedAt": "match.date", + "timings": { + "lifecycle": "match.number", + "before all": [ + { + "hookId": "h1", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "before each": [ + { + "hookId": "h2", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + { + "hookId": "h3", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "test": { + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + "after each": [ + { + "hookId": "h6", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ] + }, + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": 1 + } + ], + [ + "mocha", + "hook", + { + "id": "r3", + "title": "\"before each\" hook", + "hookName": "before each", + "hookId": "h2", + "body": "[body]", + "type": "hook", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook end", + { + "id": "r3", + "title": "\"before each\" hook", + "hookName": "before each", + "hookId": "h2", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook", + { + "id": "r3", + "title": "\"before each\" hook", + "hookName": "before each", + "hookId": "h3", + "body": "[body]", + "type": "hook", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook end", + { + "id": "r3", + "title": "\"before each\" hook", + "hookName": "before each", + "hookId": "h3", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook", + { + "id": "r3", + "title": "\"before each\" hook", + "hookName": "before each", + "hookId": "h4", + "body": "[body]", + "type": "hook", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook end", + { + "id": "r3", + "title": "\"before each\" hook", + "hookName": "before each", + "hookId": "h4", + "body": "[body]", + "type": "hook", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "retry", + { + "id": "r3", + "order": 1, + "title": "test 1", + "hookName": "before each", + "err": "{Object 9}", + "state": "failed", + "failedFromHookId": "h3", + "body": "[body]", + "type": "test", + "duration": "match.number", + "wallClockStartedAt": "match.date", + "timings": { + "lifecycle": "match.number", + "before all": [ + { + "hookId": "h1", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "before each": [ + { + "hookId": "h2", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + { + "hookId": "h3", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "test": { + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + "after each": [ + { + "hookId": "h6", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ] + }, + "file": null, + "invocationDetails": "{Object 8}", + "final": false, + "currentRetry": 0, + "retries": 1 + }, + { + "message": "[error message]", + "name": "AssertionError", + "stack": "match.string", + "sourceMappedStack": "match.string", + "parsedStack": "match.array", + "actual": null, + "showDiff": false + } + ], + [ + "mocha", + "hook", + { + "id": "r3", + "title": "\"after each\" hook", + "hookName": "after each", + "hookId": "h6", + "body": "[body]", + "type": "hook", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook end", + { + "id": "r3", + "title": "\"after each\" hook", + "hookName": "after each", + "hookId": "h6", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "test:after:run", + { + "id": "r3", + "order": 1, + "title": "test 1", + "hookName": "before each", + "err": "{Object 9}", + "state": "failed", + "failedFromHookId": "h3", + "body": "[body]", + "type": "test", + "duration": "match.number", + "wallClockStartedAt": "match.date", + "wallClockDuration": "match.number", + "timings": { + "lifecycle": "match.number", + "before all": [ + { + "hookId": "h1", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "before each": [ + { + "hookId": "h2", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + { + "hookId": "h3", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "test": { + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + "after each": [ + { + "hookId": "h6", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ] + }, + "file": null, + "invocationDetails": "{Object 8}", + "final": false, + "currentRetry": 0, + "retries": 1 + } + ], + [ + "mocha", + "hook", + { + "id": "r3", + "title": "\"before each\" hook", + "hookName": "before each", + "hookId": "h2", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "test:before:run", + { + "id": "r3", + "title": "test 1", + "body": "[body]", + "type": "test", + "wallClockStartedAt": "match.date", + "file": null, + "currentRetry": 1, + "retries": 1 + } + ], + [ + "mocha", + "hook end", + { + "id": "r3", + "title": "\"before each\" hook", + "hookName": "before each", + "hookId": "h2", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook", + { + "id": "r3", + "title": "\"before each\" hook", + "hookName": "before each", + "hookId": "h3", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook end", + { + "id": "r3", + "title": "\"before each\" hook", + "hookName": "before each", + "hookId": "h3", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook", + { + "id": "r3", + "title": "\"before each\" hook", + "hookName": "before each", + "hookId": "h4", + "body": "[body]", + "type": "hook", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook end", + { + "id": "r3", + "title": "\"before each\" hook", + "hookName": "before each", + "hookId": "h4", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook", + { + "id": "r3", + "title": "\"after each\" hook", + "hookName": "after each", + "hookId": "h6", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook end", + { + "id": "r3", + "title": "\"after each\" hook", + "hookName": "after each", + "hookId": "h6", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook", + { + "id": "r3", + "title": "\"after all\" hook", + "hookName": "after all", + "hookId": "h5", + "body": "[body]", + "type": "hook", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook end", + { + "id": "r3", + "title": "\"after all\" hook", + "hookName": "after all", + "hookId": "h5", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "pass", + { + "id": "r3", + "title": "test 1", + "state": "passed", + "body": "[body]", + "type": "test", + "duration": "match.number", + "wallClockStartedAt": "match.date", + "timings": { + "lifecycle": "match.number", + "before each": [ + { + "hookId": "h2", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + { + "hookId": "h3", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + { + "hookId": "h4", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "test": { + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + "after each": [ + { + "hookId": "h6", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "after all": [ + { + "hookId": "h5", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ] + }, + "file": null, + "final": true, + "currentRetry": 1, + "retries": 1 + } + ], + [ + "mocha", + "test end", + { + "id": "r3", + "title": "test 1", + "state": "passed", + "body": "[body]", + "type": "test", + "duration": "match.number", + "wallClockStartedAt": "match.date", + "timings": { + "lifecycle": "match.number", + "before each": [ + { + "hookId": "h2", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + { + "hookId": "h3", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + { + "hookId": "h4", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "test": { + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + "after each": [ + { + "hookId": "h6", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "after all": [ + { + "hookId": "h5", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ] + }, + "file": null, + "final": true, + "currentRetry": 1, + "retries": 1 + } + ], + [ + "mocha", + "suite end", + { + "id": "r2", + "title": "suite 1", + "root": false, + "type": "suite", + "file": null, + "retries": -1 + } + ], + [ + "mocha", + "test:after:run", + { + "id": "r3", + "title": "test 1", + "state": "passed", + "body": "[body]", + "type": "test", + "duration": "match.number", + "wallClockStartedAt": "match.date", + "wallClockDuration": "match.number", + "timings": { + "lifecycle": "match.number", + "before each": [ + { + "hookId": "h2", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + { + "hookId": "h3", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + { + "hookId": "h4", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "test": { + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + "after each": [ + { + "hookId": "h6", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "after all": [ + { + "hookId": "h5", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ] + }, + "file": null, + "final": true, + "currentRetry": 1, + "retries": 1 + } + ], + [ + "mocha", + "suite end", + { + "id": "r1", + "title": "", + "root": true, + "type": "suite", + "file": "relative/path/to/spec.js", + "retries": -1 + } + ], + [ + "mocha", + "end", + { + "end": "match.date" + } + ] +] + +exports['src/cypress/runner retries mochaEvents can retry from [afterEach] #1'] = [ + [ + "mocha", + "start", + { + "start": "match.date" + } + ], + [ + "mocha", + "suite", + { + "id": "r1", + "title": "", + "root": true, + "type": "suite", + "file": "relative/path/to/spec.js", + "retries": -1 + } + ], + [ + "mocha", + "suite", + { + "id": "r2", + "title": "suite 1", + "root": false, + "type": "suite", + "file": null, + "retries": -1 + } + ], + [ + "mocha", + "hook", + { + "id": "r3", + "title": "\"before all\" hook", + "hookName": "before all", + "hookId": "h2", + "body": "[body]", + "type": "hook", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "test:before:run", + { + "id": "r3", + "order": 1, + "title": "test 1", + "body": "[body]", + "type": "test", + "wallClockStartedAt": "match.date", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook end", + { + "id": "r3", + "title": "\"before all\" hook", + "hookName": "before all", + "hookId": "h2", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "test", + { + "id": "r3", + "order": 1, + "title": "test 1", + "body": "[body]", + "type": "test", + "wallClockStartedAt": "match.date", + "timings": { + "lifecycle": "match.number", + "before all": [ + { + "hookId": "h2", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "before each": [ + { + "hookId": "h3", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + { + "hookId": "h4", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "test": { + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + "after each": [ + { + "hookId": "h6", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + { + "hookId": "h1", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ] + }, + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": 2 + } + ], + [ + "mocha", + "hook", + { + "id": "r3", + "title": "\"before each\" hook", + "hookName": "before each", + "hookId": "h3", + "body": "[body]", + "type": "hook", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook end", + { + "id": "r3", + "title": "\"before each\" hook", + "hookName": "before each", + "hookId": "h3", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook", + { + "id": "r3", + "title": "\"before each\" hook", + "hookName": "before each", + "hookId": "h4", + "body": "[body]", + "type": "hook", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook end", + { + "id": "r3", + "title": "\"before each\" hook", + "hookName": "before each", + "hookId": "h4", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook", + { + "id": "r3", + "title": "\"after each\" hook", + "hookName": "after each", + "hookId": "h6", + "body": "[body]", + "type": "hook", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook end", + { + "id": "r3", + "title": "\"after each\" hook", + "hookName": "after each", + "hookId": "h6", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook", + { + "id": "r3", + "title": "\"after each\" hook", + "hookName": "after each", + "hookId": "h1", + "body": "[body]", + "type": "hook", + "file": "relative/path/to/spec.js", + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "retry", + { + "id": "r3", + "order": 1, + "title": "test 1", + "hookName": "after each", + "err": "{Object 9}", + "state": "failed", + "failedFromHookId": "h1", + "body": "[body]", + "type": "test", + "duration": "match.number", + "wallClockStartedAt": "match.date", + "timings": { + "lifecycle": "match.number", + "before all": [ + { + "hookId": "h2", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "before each": [ + { + "hookId": "h3", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + { + "hookId": "h4", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "test": { + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + "after each": [ + { + "hookId": "h6", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + { + "hookId": "h1", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ] + }, + "file": null, + "invocationDetails": "{Object 8}", + "final": false, + "currentRetry": 0, + "retries": 2 + }, + { + "message": "[error message]", + "name": "AssertionError", + "stack": "match.string", + "sourceMappedStack": "match.string", + "parsedStack": "match.array", + "actual": null, + "showDiff": false + } + ], + [ + "mocha", + "hook end", + { + "id": "r3", + "title": "\"after each\" hook", + "hookName": "after each", + "hookId": "h1", + "err": "{Object 9}", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": "relative/path/to/spec.js", + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "test:after:run", + { + "id": "r3", + "order": 1, + "title": "test 1", + "hookName": "after each", + "err": "{Object 9}", + "state": "failed", + "failedFromHookId": "h1", + "body": "[body]", + "type": "test", + "duration": "match.number", + "wallClockStartedAt": "match.date", + "wallClockDuration": "match.number", + "timings": { + "lifecycle": "match.number", + "before all": [ + { + "hookId": "h2", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "before each": [ + { + "hookId": "h3", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + { + "hookId": "h4", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "test": { + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + "after each": [ + { + "hookId": "h6", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + { + "hookId": "h1", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ] + }, + "file": null, + "invocationDetails": "{Object 8}", + "final": false, + "currentRetry": 0, + "retries": 2 + } + ], + [ + "mocha", + "hook", + { + "id": "r3", + "title": "\"before each\" hook", + "hookName": "before each", + "hookId": "h3", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "test:before:run", + { + "id": "r3", + "title": "test 1", + "body": "[body]", + "type": "test", + "wallClockStartedAt": "match.date", + "file": null, + "currentRetry": 1, + "retries": 2 + } + ], + [ + "mocha", + "hook end", + { + "id": "r3", + "title": "\"before each\" hook", + "hookName": "before each", + "hookId": "h3", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook", + { + "id": "r3", + "title": "\"before each\" hook", + "hookName": "before each", + "hookId": "h4", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook end", + { + "id": "r3", + "title": "\"before each\" hook", + "hookName": "before each", + "hookId": "h4", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook", + { + "id": "r3", + "title": "\"after each\" hook", + "hookName": "after each", + "hookId": "h6", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook end", + { + "id": "r3", + "title": "\"after each\" hook", + "hookName": "after each", + "hookId": "h6", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook", + { + "id": "r3", + "title": "\"after each\" hook", + "hookName": "after each", + "hookId": "h1", + "err": "{Object 9}", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": "relative/path/to/spec.js", + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook end", + { + "id": "r3", + "title": "\"after each\" hook", + "hookName": "after each", + "hookId": "h1", + "err": "{Object 9}", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": "relative/path/to/spec.js", + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "pass", + { + "id": "r3", + "title": "test 1", + "state": "passed", + "body": "[body]", + "type": "test", + "duration": "match.number", + "wallClockStartedAt": "match.date", + "timings": { + "lifecycle": "match.number", + "before each": [ + { + "hookId": "h3", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + { + "hookId": "h4", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "test": { + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + "after each": [ + { + "hookId": "h6", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + { + "hookId": "h1", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ] + }, + "file": null, + "final": true, + "currentRetry": 1, + "retries": 2 + } + ], + [ + "mocha", + "test end", + { + "id": "r3", + "title": "test 1", + "state": "passed", + "body": "[body]", + "type": "test", + "duration": "match.number", + "wallClockStartedAt": "match.date", + "timings": { + "lifecycle": "match.number", + "before each": [ + { + "hookId": "h3", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + { + "hookId": "h4", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "test": { + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + "after each": [ + { + "hookId": "h6", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + { + "hookId": "h1", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ] + }, + "file": null, + "final": true, + "currentRetry": 1, + "retries": 2 + } + ], + [ + "mocha", + "test:after:run", + { + "id": "r3", + "title": "test 1", + "state": "passed", + "body": "[body]", + "type": "test", + "duration": "match.number", + "wallClockStartedAt": "match.date", + "wallClockDuration": "match.number", + "timings": { + "lifecycle": "match.number", + "before each": [ + { + "hookId": "h3", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + { + "hookId": "h4", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "test": { + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + "after each": [ + { + "hookId": "h6", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + { + "hookId": "h1", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ] + }, + "file": null, + "final": true, + "currentRetry": 1, + "retries": 2 + } + ], + [ + "mocha", + "test", + { + "id": "r4", + "order": 2, + "title": "test 2", + "body": "[body]", + "type": "test", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook", + { + "id": "r4", + "title": "\"before each\" hook", + "hookName": "before each", + "hookId": "h3", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "test:before:run", + { + "id": "r4", + "order": 2, + "title": "test 2", + "body": "[body]", + "type": "test", + "wallClockStartedAt": "match.date", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook end", + { + "id": "r4", + "title": "\"before each\" hook", + "hookName": "before each", + "hookId": "h3", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook", + { + "id": "r4", + "title": "\"before each\" hook", + "hookName": "before each", + "hookId": "h4", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook end", + { + "id": "r4", + "title": "\"before each\" hook", + "hookName": "before each", + "hookId": "h4", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook", + { + "id": "r4", + "title": "\"after each\" hook", + "hookName": "after each", + "hookId": "h6", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook end", + { + "id": "r4", + "title": "\"after each\" hook", + "hookName": "after each", + "hookId": "h6", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook", + { + "id": "r4", + "title": "\"after each\" hook", + "hookName": "after each", + "hookId": "h1", + "err": "{Object 9}", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": "relative/path/to/spec.js", + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook end", + { + "id": "r4", + "title": "\"after each\" hook", + "hookName": "after each", + "hookId": "h1", + "err": "{Object 9}", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": "relative/path/to/spec.js", + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "pass", + { + "id": "r4", + "order": 2, + "title": "test 2", + "state": "passed", + "body": "[body]", + "type": "test", + "duration": "match.number", + "wallClockStartedAt": "match.date", + "timings": { + "lifecycle": "match.number", + "before each": [ + { + "hookId": "h3", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + { + "hookId": "h4", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "test": { + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + "after each": [ + { + "hookId": "h6", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + { + "hookId": "h1", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ] + }, + "file": null, + "invocationDetails": "{Object 8}", + "final": true, + "currentRetry": 0, + "retries": 2 + } + ], + [ + "mocha", + "test end", + { + "id": "r4", + "order": 2, + "title": "test 2", + "state": "passed", + "body": "[body]", + "type": "test", + "duration": "match.number", + "wallClockStartedAt": "match.date", + "timings": { + "lifecycle": "match.number", + "before each": [ + { + "hookId": "h3", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + { + "hookId": "h4", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "test": { + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + "after each": [ + { + "hookId": "h6", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + { + "hookId": "h1", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ] + }, + "file": null, + "invocationDetails": "{Object 8}", + "final": true, + "currentRetry": 0, + "retries": 2 + } + ], + [ + "mocha", + "test:after:run", + { + "id": "r4", + "order": 2, + "title": "test 2", + "state": "passed", + "body": "[body]", + "type": "test", + "duration": "match.number", + "wallClockStartedAt": "match.date", + "wallClockDuration": "match.number", + "timings": { + "lifecycle": "match.number", + "before each": [ + { + "hookId": "h3", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + { + "hookId": "h4", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "test": { + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + "after each": [ + { + "hookId": "h6", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + { + "hookId": "h1", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ] + }, + "file": null, + "invocationDetails": "{Object 8}", + "final": true, + "currentRetry": 0, + "retries": 2 + } + ], + [ + "mocha", + "test", + { + "id": "r5", + "order": 3, + "title": "test 3", + "body": "[body]", + "type": "test", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook", + { + "id": "r5", + "title": "\"before each\" hook", + "hookName": "before each", + "hookId": "h3", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "test:before:run", + { + "id": "r5", + "order": 3, + "title": "test 3", + "body": "[body]", + "type": "test", + "wallClockStartedAt": "match.date", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook end", + { + "id": "r5", + "title": "\"before each\" hook", + "hookName": "before each", + "hookId": "h3", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook", + { + "id": "r5", + "title": "\"before each\" hook", + "hookName": "before each", + "hookId": "h4", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook end", + { + "id": "r5", + "title": "\"before each\" hook", + "hookName": "before each", + "hookId": "h4", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook", + { + "id": "r5", + "title": "\"after each\" hook", + "hookName": "after each", + "hookId": "h6", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook end", + { + "id": "r5", + "title": "\"after each\" hook", + "hookName": "after each", + "hookId": "h6", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook", + { + "id": "r5", + "title": "\"after each\" hook", + "hookName": "after each", + "hookId": "h1", + "err": "{Object 9}", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": "relative/path/to/spec.js", + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook end", + { + "id": "r5", + "title": "\"after each\" hook", + "hookName": "after each", + "hookId": "h1", + "err": "{Object 9}", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": "relative/path/to/spec.js", + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook", + { + "id": "r5", + "title": "\"after all\" hook", + "hookName": "after all", + "hookId": "h5", + "body": "[body]", + "type": "hook", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook end", + { + "id": "r5", + "title": "\"after all\" hook", + "hookName": "after all", + "hookId": "h5", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "pass", + { + "id": "r5", + "order": 3, + "title": "test 3", + "state": "passed", + "body": "[body]", + "type": "test", + "duration": "match.number", + "wallClockStartedAt": "match.date", + "timings": { + "lifecycle": "match.number", + "before each": [ + { + "hookId": "h3", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + { + "hookId": "h4", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "test": { + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + "after each": [ + { + "hookId": "h6", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + { + "hookId": "h1", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "after all": [ + { + "hookId": "h5", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ] + }, + "file": null, + "invocationDetails": "{Object 8}", + "final": true, + "currentRetry": 0, + "retries": 2 + } + ], + [ + "mocha", + "test end", + { + "id": "r5", + "order": 3, + "title": "test 3", + "state": "passed", + "body": "[body]", + "type": "test", + "duration": "match.number", + "wallClockStartedAt": "match.date", + "timings": { + "lifecycle": "match.number", + "before each": [ + { + "hookId": "h3", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + { + "hookId": "h4", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "test": { + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + "after each": [ + { + "hookId": "h6", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + { + "hookId": "h1", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "after all": [ + { + "hookId": "h5", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ] + }, + "file": null, + "invocationDetails": "{Object 8}", + "final": true, + "currentRetry": 0, + "retries": 2 + } + ], + [ + "mocha", + "test:after:run", + { + "id": "r5", + "order": 3, + "title": "test 3", + "state": "passed", + "body": "[body]", + "type": "test", + "duration": "match.number", + "wallClockStartedAt": "match.date", + "wallClockDuration": "match.number", + "timings": { + "lifecycle": "match.number", + "before each": [ + { + "hookId": "h3", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + { + "hookId": "h4", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "test": { + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + "after each": [ + { + "hookId": "h6", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + { + "hookId": "h1", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "after all": [ + { + "hookId": "h5", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ] + }, + "file": null, + "invocationDetails": "{Object 8}", + "final": true, + "currentRetry": 0, + "retries": 2 + } + ], + [ + "mocha", + "suite end", + { + "id": "r2", + "title": "suite 1", + "root": false, + "type": "suite", + "file": null, + "retries": -1 + } + ], + [ + "mocha", + "suite", + { + "id": "r6", + "title": "suite 2", + "root": false, + "type": "suite", + "file": null, + "retries": -1 + } + ], + [ + "mocha", + "test", + { + "id": "r7", + "order": 4, + "title": "test 1", + "body": "[body]", + "type": "test", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "test:before:run", + { + "id": "r7", + "order": 4, + "title": "test 1", + "body": "[body]", + "type": "test", + "wallClockStartedAt": "match.date", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook", + { + "id": "r7", + "title": "\"after each\" hook", + "hookName": "after each", + "hookId": "h7", + "body": "[body]", + "type": "hook", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "retry", + { + "id": "r7", + "order": 4, + "title": "test 1", + "hookName": "after each", + "err": "{Object 9}", + "state": "failed", + "failedFromHookId": "h7", + "body": "[body]", + "type": "test", + "duration": "match.number", + "wallClockStartedAt": "match.date", + "timings": { + "lifecycle": "match.number", + "test": { + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + "after each": [ + { + "hookId": "h7", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + { + "hookId": "h1", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ] + }, + "file": null, + "invocationDetails": "{Object 8}", + "final": false, + "currentRetry": 0, + "retries": 2 + }, + { + "message": "[error message]", + "name": "AssertionError", + "stack": "match.string", + "sourceMappedStack": "match.string", + "parsedStack": "match.array", + "actual": null, + "showDiff": false + } + ], + [ + "mocha", + "hook end", + { + "id": "r7", + "title": "\"after each\" hook", + "hookName": "after each", + "hookId": "h7", + "err": "{Object 9}", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook", + { + "id": "r7", + "title": "\"after each\" hook", + "hookName": "after each", + "hookId": "h1", + "err": "{Object 9}", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": "relative/path/to/spec.js", + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook end", + { + "id": "r7", + "title": "\"after each\" hook", + "hookName": "after each", + "hookId": "h1", + "err": "{Object 9}", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": "relative/path/to/spec.js", + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "test:after:run", + { + "id": "r7", + "order": 4, + "title": "test 1", + "hookName": "after each", + "err": "{Object 9}", + "state": "failed", + "failedFromHookId": "h7", + "body": "[body]", + "type": "test", + "duration": "match.number", + "wallClockStartedAt": "match.date", + "wallClockDuration": "match.number", + "timings": { + "lifecycle": "match.number", + "test": { + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + "after each": [ + { + "hookId": "h7", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + { + "hookId": "h1", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ] + }, + "file": null, + "invocationDetails": "{Object 8}", + "final": false, + "currentRetry": 0, + "retries": 2 + } + ], + [ + "mocha", + "test:before:run", + { + "id": "r7", + "title": "test 1", + "body": "[body]", + "type": "test", + "wallClockStartedAt": "match.date", + "file": null, + "currentRetry": 1, + "retries": 2 + } + ], + [ + "mocha", + "hook", + { + "id": "r7", + "title": "\"after each\" hook", + "hookName": "after each", + "hookId": "h7", + "err": "{Object 9}", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "retry", + { + "id": "r7", + "title": "test 1", + "hookName": "after each", + "err": "{Object 9}", + "state": "failed", + "failedFromHookId": "h7", + "body": "[body]", + "type": "test", + "duration": "match.number", + "wallClockStartedAt": "match.date", + "timings": { + "lifecycle": "match.number", + "test": { + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + "after each": [ + { + "hookId": "h7", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + { + "hookId": "h1", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ] + }, + "file": null, + "final": false, + "currentRetry": 1, + "retries": 2 + }, + { + "message": "[error message]", + "name": "AssertionError", + "stack": "match.string", + "sourceMappedStack": "match.string", + "parsedStack": "match.array", + "actual": null, + "showDiff": false + } + ], + [ + "mocha", + "hook end", + { + "id": "r7", + "title": "\"after each\" hook", + "hookName": "after each", + "hookId": "h7", + "err": "{Object 9}", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook", + { + "id": "r7", + "title": "\"after each\" hook", + "hookName": "after each", + "hookId": "h1", + "err": "{Object 9}", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": "relative/path/to/spec.js", + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook end", + { + "id": "r7", + "title": "\"after each\" hook", + "hookName": "after each", + "hookId": "h1", + "err": "{Object 9}", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": "relative/path/to/spec.js", + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "test:after:run", + { + "id": "r7", + "title": "test 1", + "hookName": "after each", + "err": "{Object 9}", + "state": "failed", + "failedFromHookId": "h7", + "body": "[body]", + "type": "test", + "duration": "match.number", + "wallClockStartedAt": "match.date", + "wallClockDuration": "match.number", + "timings": { + "lifecycle": "match.number", + "test": { + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + "after each": [ + { + "hookId": "h7", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + { + "hookId": "h1", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ] + }, + "file": null, + "final": false, + "currentRetry": 1, + "retries": 2 + } + ], + [ + "mocha", + "test:before:run", + { + "id": "r7", + "title": "test 1", + "body": "[body]", + "type": "test", + "wallClockStartedAt": "match.date", + "file": null, + "currentRetry": 2, + "retries": 2 + } + ], + [ + "mocha", + "hook", + { + "id": "r7", + "title": "\"after each\" hook", + "hookName": "after each", + "hookId": "h7", + "err": "{Object 9}", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook end", + { + "id": "r7", + "title": "\"after each\" hook", + "hookName": "after each", + "hookId": "h7", + "err": "{Object 9}", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook", + { + "id": "r7", + "title": "\"after each\" hook", + "hookName": "after each", + "hookId": "h1", + "err": "{Object 9}", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": "relative/path/to/spec.js", + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook end", + { + "id": "r7", + "title": "\"after each\" hook", + "hookName": "after each", + "hookId": "h1", + "err": "{Object 9}", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": "relative/path/to/spec.js", + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "pass", + { + "id": "r7", + "title": "test 1", + "state": "passed", + "body": "[body]", + "type": "test", + "duration": "match.number", + "wallClockStartedAt": "match.date", + "timings": { + "lifecycle": "match.number", + "test": { + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + "after each": [ + { + "hookId": "h7", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + { + "hookId": "h1", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ] + }, + "file": null, + "final": true, + "currentRetry": 2, + "retries": 2 + } + ], + [ + "mocha", + "test end", + { + "id": "r7", + "title": "test 1", + "state": "passed", + "body": "[body]", + "type": "test", + "duration": "match.number", + "wallClockStartedAt": "match.date", + "timings": { + "lifecycle": "match.number", + "test": { + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + "after each": [ + { + "hookId": "h7", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + { + "hookId": "h1", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ] + }, + "file": null, + "final": true, + "currentRetry": 2, + "retries": 2 + } + ], + [ + "mocha", + "test:after:run", + { + "id": "r7", + "title": "test 1", + "state": "passed", + "body": "[body]", + "type": "test", + "duration": "match.number", + "wallClockStartedAt": "match.date", + "wallClockDuration": "match.number", + "timings": { + "lifecycle": "match.number", + "test": { + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + "after each": [ + { + "hookId": "h7", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + { + "hookId": "h1", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ] + }, + "file": null, + "final": true, + "currentRetry": 2, + "retries": 2 + } + ], + [ + "mocha", + "suite end", + { + "id": "r6", + "title": "suite 2", + "root": false, + "type": "suite", + "file": null, + "retries": -1 + } + ], + [ + "mocha", + "suite", + { + "id": "r8", + "title": "suite 3", + "root": false, + "type": "suite", + "file": null, + "retries": -1 + } + ], + [ + "mocha", + "test", + { + "id": "r9", + "order": 5, + "title": "test 1", + "body": "[body]", + "type": "test", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "test:before:run", + { + "id": "r9", + "order": 5, + "title": "test 1", + "body": "[body]", + "type": "test", + "wallClockStartedAt": "match.date", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook", + { + "id": "r9", + "title": "\"after each\" hook", + "hookName": "after each", + "hookId": "h1", + "err": "{Object 9}", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": "relative/path/to/spec.js", + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook end", + { + "id": "r9", + "title": "\"after each\" hook", + "hookName": "after each", + "hookId": "h1", + "err": "{Object 9}", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": "relative/path/to/spec.js", + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "pass", + { + "id": "r9", + "order": 5, + "title": "test 1", + "state": "passed", + "body": "[body]", + "type": "test", + "duration": "match.number", + "wallClockStartedAt": "match.date", + "timings": { + "lifecycle": "match.number", + "test": { + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + "after each": [ + { + "hookId": "h1", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ] + }, + "file": null, + "invocationDetails": "{Object 8}", + "final": true, + "currentRetry": 0, + "retries": 2 + } + ], + [ + "mocha", + "test end", + { + "id": "r9", + "order": 5, + "title": "test 1", + "state": "passed", + "body": "[body]", + "type": "test", + "duration": "match.number", + "wallClockStartedAt": "match.date", + "timings": { + "lifecycle": "match.number", + "test": { + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + "after each": [ + { + "hookId": "h1", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ] + }, + "file": null, + "invocationDetails": "{Object 8}", + "final": true, + "currentRetry": 0, + "retries": 2 + } + ], + [ + "mocha", + "suite end", + { + "id": "r8", + "title": "suite 3", + "root": false, + "type": "suite", + "file": null, + "retries": -1 + } + ], + [ + "mocha", + "test:after:run", + { + "id": "r9", + "order": 5, + "title": "test 1", + "state": "passed", + "body": "[body]", + "type": "test", + "duration": "match.number", + "wallClockStartedAt": "match.date", + "wallClockDuration": "match.number", + "timings": { + "lifecycle": "match.number", + "test": { + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + "after each": [ + { + "hookId": "h1", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ] + }, + "file": null, + "invocationDetails": "{Object 8}", + "final": true, + "currentRetry": 0, + "retries": 2 + } + ], + [ + "mocha", + "suite end", + { + "id": "r1", + "title": "", + "root": true, + "type": "suite", + "file": "relative/path/to/spec.js", + "retries": -1 + } + ], + [ + "mocha", + "end", + { + "end": "match.date" + } + ] +] + +exports['src/cypress/runner retries mochaEvents cant retry from [before] #1'] = [ + [ + "mocha", + "start", + { + "start": "match.date" + } + ], + [ + "mocha", + "suite", + { + "id": "r1", + "title": "", + "root": true, + "type": "suite", + "file": "relative/path/to/spec.js", + "retries": -1 + } + ], + [ + "mocha", + "suite", + { + "id": "r2", + "title": "suite 1", + "root": false, + "type": "suite", + "file": null, + "retries": -1 + } + ], + [ + "mocha", + "hook", + { + "id": "r3", + "title": "\"before all\" hook", + "hookName": "before all", + "hookId": "h1", + "body": "[body]", + "type": "hook", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "test:before:run", + { + "id": "r3", + "order": 1, + "title": "test 1", + "body": "[body]", + "type": "test", + "wallClockStartedAt": "match.date", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "fail", + { + "id": "r3", + "title": "\"before all\" hook for \"test 1\"", + "hookName": "before all", + "hookId": "h1", + "err": "{Object 9}", + "state": "failed", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "originalTitle": "\"before all\" hook", + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + }, + { + "message": "[error message]", + "name": "AssertionError", + "stack": "match.string", + "sourceMappedStack": "match.string", + "parsedStack": "match.array", + "actual": null, + "showDiff": false + } + ], + [ + "mocha", + "hook", + { + "id": "r3", + "title": "\"after all\" hook", + "hookName": "after all", + "hookId": "h4", + "body": "[body]", + "type": "hook", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook end", + { + "id": "r3", + "title": "\"after all\" hook", + "hookName": "after all", + "hookId": "h4", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "suite end", + { + "id": "r2", + "title": "suite 1", + "root": false, + "type": "suite", + "file": null, + "retries": -1 + } + ], + [ + "mocha", + "test end", + { + "id": "r3", + "order": 1, + "title": "test 1", + "hookName": "before all", + "err": "{Object 9}", + "state": "failed", + "failedFromHookId": "h1", + "body": "[body]", + "type": "test", + "duration": "match.number", + "wallClockStartedAt": "match.date", + "timings": { + "lifecycle": "match.number", + "before all": [ + { + "hookId": "h1", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "after all": [ + { + "hookId": "h4", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ] + }, + "file": null, + "invocationDetails": "{Object 8}", + "final": true, + "currentRetry": 0, + "retries": 1 + } + ], + [ + "mocha", + "test:after:run", + { + "id": "r3", + "order": 1, + "title": "test 1", + "hookName": "before all", + "err": "{Object 9}", + "state": "failed", + "failedFromHookId": "h1", + "body": "[body]", + "type": "test", + "duration": "match.number", + "wallClockStartedAt": "match.date", + "wallClockDuration": "match.number", + "timings": { + "lifecycle": "match.number", + "before all": [ + { + "hookId": "h1", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "after all": [ + { + "hookId": "h4", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ] + }, + "file": null, + "invocationDetails": "{Object 8}", + "final": true, + "currentRetry": 0, + "retries": 1 + } + ], + [ + "mocha", + "suite end", + { + "id": "r1", + "title": "", + "root": true, + "type": "suite", + "file": "relative/path/to/spec.js", + "retries": -1 + } + ], + [ + "mocha", + "end", + { + "end": "match.date" + } + ] +] + +exports['src/cypress/runner retries mochaEvents cant retry from [after] #1'] = [ + [ + "mocha", + "start", + { + "start": "match.date" + } + ], + [ + "mocha", + "suite", + { + "id": "r1", + "title": "", + "root": true, + "type": "suite", + "file": "relative/path/to/spec.js", + "retries": -1 + } + ], + [ + "mocha", + "suite", + { + "id": "r2", + "title": "suite 1", + "root": false, + "type": "suite", + "file": null, + "retries": -1 + } + ], + [ + "mocha", + "hook", + { + "id": "r3", + "title": "\"before all\" hook", + "hookName": "before all", + "hookId": "h1", + "body": "[body]", + "type": "hook", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "test:before:run", + { + "id": "r3", + "order": 1, + "title": "test 1", + "body": "[body]", + "type": "test", + "wallClockStartedAt": "match.date", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook end", + { + "id": "r3", + "title": "\"before all\" hook", + "hookName": "before all", + "hookId": "h1", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "test", + { + "id": "r3", + "order": 1, + "title": "test 1", + "body": "[body]", + "type": "test", + "wallClockStartedAt": "match.date", + "timings": { + "lifecycle": "match.number", + "before all": [ + { + "hookId": "h1", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "before each": [ + { + "hookId": "h2", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + { + "hookId": "h3", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "test": { + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + "after each": [ + { + "hookId": "h5", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + { + "hookId": "h6", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "after all": [ + { + "hookId": "h4", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ] + }, + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": 1 + } + ], + [ + "mocha", + "hook", + { + "id": "r3", + "title": "\"before each\" hook", + "hookName": "before each", + "hookId": "h2", + "body": "[body]", + "type": "hook", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook end", + { + "id": "r3", + "title": "\"before each\" hook", + "hookName": "before each", + "hookId": "h2", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook", + { + "id": "r3", + "title": "\"before each\" hook", + "hookName": "before each", + "hookId": "h3", + "body": "[body]", + "type": "hook", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook end", + { + "id": "r3", + "title": "\"before each\" hook", + "hookName": "before each", + "hookId": "h3", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook", + { + "id": "r3", + "title": "\"after each\" hook", + "hookName": "after each", + "hookId": "h5", + "body": "[body]", + "type": "hook", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook end", + { + "id": "r3", + "title": "\"after each\" hook", + "hookName": "after each", + "hookId": "h5", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook", + { + "id": "r3", + "title": "\"after each\" hook", + "hookName": "after each", + "hookId": "h6", + "body": "[body]", + "type": "hook", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook end", + { + "id": "r3", + "title": "\"after each\" hook", + "hookName": "after each", + "hookId": "h6", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook", + { + "id": "r3", + "title": "\"after all\" hook", + "hookName": "after all", + "hookId": "h4", + "body": "[body]", + "type": "hook", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "fail", + { + "id": "r3", + "title": "\"after all\" hook for \"test 1\"", + "hookName": "after all", + "hookId": "h4", + "err": "{Object 9}", + "state": "failed", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "originalTitle": "\"after all\" hook", + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + }, + { + "message": "[error message]", + "name": "AssertionError", + "stack": "match.string", + "sourceMappedStack": "match.string", + "parsedStack": "match.array", + "actual": null, + "showDiff": false + } + ], + [ + "mocha", + "test end", + { + "id": "r3", + "order": 1, + "title": "test 1", + "hookName": "after all", + "err": "{Object 9}", + "state": "failed", + "failedFromHookId": "h4", + "body": "[body]", + "type": "test", + "duration": "match.number", + "wallClockStartedAt": "match.date", + "timings": { + "lifecycle": "match.number", + "before all": [ + { + "hookId": "h1", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "before each": [ + { + "hookId": "h2", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + { + "hookId": "h3", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "test": { + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + "after each": [ + { + "hookId": "h5", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + { + "hookId": "h6", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "after all": [ + { + "hookId": "h4", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ] + }, + "file": null, + "invocationDetails": "{Object 8}", + "final": true, + "currentRetry": 0, + "retries": 1 + } + ], + [ + "mocha", + "suite end", + { + "id": "r2", + "title": "suite 1", + "root": false, + "type": "suite", + "file": null, + "retries": -1 + } + ], + [ + "mocha", + "test:after:run", + { + "id": "r3", + "order": 1, + "title": "test 1", + "hookName": "after all", + "err": "{Object 9}", + "state": "failed", + "failedFromHookId": "h4", + "body": "[body]", + "type": "test", + "duration": "match.number", + "wallClockStartedAt": "match.date", + "wallClockDuration": "match.number", + "timings": { + "lifecycle": "match.number", + "before all": [ + { + "hookId": "h1", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "before each": [ + { + "hookId": "h2", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + { + "hookId": "h3", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "test": { + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + "after each": [ + { + "hookId": "h5", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + { + "hookId": "h6", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "after all": [ + { + "hookId": "h4", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ] + }, + "file": null, + "invocationDetails": "{Object 8}", + "final": true, + "currentRetry": 0, + "retries": 1 + } + ], + [ + "mocha", + "suite end", + { + "id": "r1", + "title": "", + "root": true, + "type": "suite", + "file": "relative/path/to/spec.js", + "retries": -1 + } + ], + [ + "mocha", + "end", + { + "end": "match.date" + } + ] +] + +exports['src/cypress/runner retries mochaEvents three tests with retry #1'] = [ + [ + "mocha", + "start", + { + "start": "match.date" + } + ], + [ + "mocha", + "suite", + { + "id": "r1", + "title": "", + "root": true, + "type": "suite", + "file": "relative/path/to/spec.js", + "retries": -1 + } + ], + [ + "mocha", + "suite", + { + "id": "r2", + "title": "suite 1", + "root": false, + "type": "suite", + "file": null, + "retries": -1 + } + ], + [ + "mocha", + "hook", + { + "id": "r3", + "title": "\"before all\" hook", + "hookName": "before all", + "hookId": "h1", + "body": "[body]", + "type": "hook", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "test:before:run", + { + "id": "r3", + "order": 1, + "title": "test 1", + "body": "[body]", + "type": "test", + "wallClockStartedAt": "match.date", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook end", + { + "id": "r3", + "title": "\"before all\" hook", + "hookName": "before all", + "hookId": "h1", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "test", + { + "id": "r3", + "order": 1, + "title": "test 1", + "body": "[body]", + "type": "test", + "wallClockStartedAt": "match.date", + "timings": { + "lifecycle": "match.number", + "before all": [ + { + "hookId": "h1", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "before each": [ + { + "hookId": "h2", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "test": { + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + "after each": [ + { + "hookId": "h4", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ] + }, + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": 2 + } + ], + [ + "mocha", + "hook", + { + "id": "r3", + "title": "\"before each\" hook", + "hookName": "before each", + "hookId": "h2", + "body": "[body]", + "type": "hook", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook end", + { + "id": "r3", + "title": "\"before each\" hook", + "hookName": "before each", + "hookId": "h2", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook", + { + "id": "r3", + "title": "\"after each\" hook", + "hookName": "after each", + "hookId": "h4", + "body": "[body]", + "type": "hook", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook end", + { + "id": "r3", + "title": "\"after each\" hook", + "hookName": "after each", + "hookId": "h4", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "pass", + { + "id": "r3", + "order": 1, + "title": "test 1", + "state": "passed", + "body": "[body]", + "type": "test", + "duration": "match.number", + "wallClockStartedAt": "match.date", + "timings": { + "lifecycle": "match.number", + "before all": [ + { + "hookId": "h1", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "before each": [ + { + "hookId": "h2", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "test": { + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + "after each": [ + { + "hookId": "h4", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ] + }, + "file": null, + "invocationDetails": "{Object 8}", + "final": true, + "currentRetry": 0, + "retries": 2 + } + ], + [ + "mocha", + "test end", + { + "id": "r3", + "order": 1, + "title": "test 1", + "state": "passed", + "body": "[body]", + "type": "test", + "duration": "match.number", + "wallClockStartedAt": "match.date", + "timings": { + "lifecycle": "match.number", + "before all": [ + { + "hookId": "h1", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "before each": [ + { + "hookId": "h2", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "test": { + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + "after each": [ + { + "hookId": "h4", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ] + }, + "file": null, + "invocationDetails": "{Object 8}", + "final": true, + "currentRetry": 0, + "retries": 2 + } + ], + [ + "mocha", + "test:after:run", + { + "id": "r3", + "order": 1, + "title": "test 1", + "state": "passed", + "body": "[body]", + "type": "test", + "duration": "match.number", + "wallClockStartedAt": "match.date", + "wallClockDuration": "match.number", + "timings": { + "lifecycle": "match.number", + "before all": [ + { + "hookId": "h1", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "before each": [ + { + "hookId": "h2", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "test": { + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + "after each": [ + { + "hookId": "h4", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ] + }, + "file": null, + "invocationDetails": "{Object 8}", + "final": true, + "currentRetry": 0, + "retries": 2 + } + ], + [ + "mocha", + "test", + { + "id": "r4", + "order": 2, + "title": "test 2", + "body": "[body]", + "type": "test", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook", + { + "id": "r4", + "title": "\"before each\" hook", + "hookName": "before each", + "hookId": "h2", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "test:before:run", + { + "id": "r4", + "order": 2, + "title": "test 2", + "body": "[body]", + "type": "test", + "wallClockStartedAt": "match.date", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook end", + { + "id": "r4", + "title": "\"before each\" hook", + "hookName": "before each", + "hookId": "h2", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "retry", + { + "id": "r4", + "order": 2, + "title": "test 2", + "err": "{Object 9}", + "state": "failed", + "body": "[body]", + "type": "test", + "duration": "match.number", + "wallClockStartedAt": "match.date", + "timings": { + "lifecycle": "match.number", + "before each": [ + { + "hookId": "h2", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "test": { + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + "after each": [ + { + "hookId": "h4", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ] + }, + "file": null, + "invocationDetails": "{Object 8}", + "final": false, + "currentRetry": 0, + "retries": 2 + }, + { + "message": "[error message]", + "name": "AssertionError", + "stack": "match.string", + "sourceMappedStack": "match.string", + "parsedStack": "match.array", + "actual": null, + "showDiff": false + } + ], + [ + "mocha", + "hook", + { + "id": "r4", + "title": "\"after each\" hook", + "hookName": "after each", + "hookId": "h4", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook end", + { + "id": "r4", + "title": "\"after each\" hook", + "hookName": "after each", + "hookId": "h4", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "test:after:run", + { + "id": "r4", + "order": 2, + "title": "test 2", + "err": "{Object 9}", + "state": "failed", + "body": "[body]", + "type": "test", + "duration": "match.number", + "wallClockStartedAt": "match.date", + "wallClockDuration": "match.number", + "timings": { + "lifecycle": "match.number", + "before each": [ + { + "hookId": "h2", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "test": { + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + "after each": [ + { + "hookId": "h4", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ] + }, + "file": null, + "invocationDetails": "{Object 8}", + "final": false, + "currentRetry": 0, + "retries": 2 + } + ], + [ + "mocha", + "hook", + { + "id": "r4", + "title": "\"before each\" hook", + "hookName": "before each", + "hookId": "h2", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "test:before:run", + { + "id": "r4", + "title": "test 2", + "body": "[body]", + "type": "test", + "wallClockStartedAt": "match.date", + "file": null, + "currentRetry": 1, + "retries": 2 + } + ], + [ + "mocha", + "hook end", + { + "id": "r4", + "title": "\"before each\" hook", + "hookName": "before each", + "hookId": "h2", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "retry", + { + "id": "r4", + "title": "test 2", + "err": "{Object 9}", + "state": "failed", + "body": "[body]", + "type": "test", + "duration": "match.number", + "wallClockStartedAt": "match.date", + "timings": { + "lifecycle": "match.number", + "before each": [ + { + "hookId": "h2", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "test": { + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + "after each": [ + { + "hookId": "h4", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ] + }, + "file": null, + "final": false, + "currentRetry": 1, + "retries": 2 + }, + { + "message": "[error message]", + "name": "AssertionError", + "stack": "match.string", + "sourceMappedStack": "match.string", + "parsedStack": "match.array", + "actual": null, + "showDiff": false + } + ], + [ + "mocha", + "hook", + { + "id": "r4", + "title": "\"after each\" hook", + "hookName": "after each", + "hookId": "h4", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook end", + { + "id": "r4", + "title": "\"after each\" hook", + "hookName": "after each", + "hookId": "h4", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "test:after:run", + { + "id": "r4", + "title": "test 2", + "err": "{Object 9}", + "state": "failed", + "body": "[body]", + "type": "test", + "duration": "match.number", + "wallClockStartedAt": "match.date", + "wallClockDuration": "match.number", + "timings": { + "lifecycle": "match.number", + "before each": [ + { + "hookId": "h2", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "test": { + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + "after each": [ + { + "hookId": "h4", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ] + }, + "file": null, + "final": false, + "currentRetry": 1, + "retries": 2 + } + ], + [ + "mocha", + "hook", + { + "id": "r4", + "title": "\"before each\" hook", + "hookName": "before each", + "hookId": "h2", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "test:before:run", + { + "id": "r4", + "title": "test 2", + "body": "[body]", + "type": "test", + "wallClockStartedAt": "match.date", + "file": null, + "currentRetry": 2, + "retries": 2 + } + ], + [ + "mocha", + "hook end", + { + "id": "r4", + "title": "\"before each\" hook", + "hookName": "before each", + "hookId": "h2", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook", + { + "id": "r4", + "title": "\"after each\" hook", + "hookName": "after each", + "hookId": "h4", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook end", + { + "id": "r4", + "title": "\"after each\" hook", + "hookName": "after each", + "hookId": "h4", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "pass", + { + "id": "r4", + "title": "test 2", + "state": "passed", + "body": "[body]", + "type": "test", + "duration": "match.number", + "wallClockStartedAt": "match.date", + "timings": { + "lifecycle": "match.number", + "before each": [ + { + "hookId": "h2", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "test": { + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + "after each": [ + { + "hookId": "h4", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ] + }, + "file": null, + "final": true, + "currentRetry": 2, + "retries": 2 + } + ], + [ + "mocha", + "test end", + { + "id": "r4", + "title": "test 2", + "state": "passed", + "body": "[body]", + "type": "test", + "duration": "match.number", + "wallClockStartedAt": "match.date", + "timings": { + "lifecycle": "match.number", + "before each": [ + { + "hookId": "h2", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "test": { + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + "after each": [ + { + "hookId": "h4", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ] + }, + "file": null, + "final": true, + "currentRetry": 2, + "retries": 2 + } + ], + [ + "mocha", + "test:after:run", + { + "id": "r4", + "title": "test 2", + "state": "passed", + "body": "[body]", + "type": "test", + "duration": "match.number", + "wallClockStartedAt": "match.date", + "wallClockDuration": "match.number", + "timings": { + "lifecycle": "match.number", + "before each": [ + { + "hookId": "h2", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "test": { + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + "after each": [ + { + "hookId": "h4", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ] + }, + "file": null, + "final": true, + "currentRetry": 2, + "retries": 2 + } + ], + [ + "mocha", + "test", + { + "id": "r5", + "order": 3, + "title": "test 3", + "body": "[body]", + "type": "test", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook", + { + "id": "r5", + "title": "\"before each\" hook", + "hookName": "before each", + "hookId": "h2", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "test:before:run", + { + "id": "r5", + "order": 3, + "title": "test 3", + "body": "[body]", + "type": "test", + "wallClockStartedAt": "match.date", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook end", + { + "id": "r5", + "title": "\"before each\" hook", + "hookName": "before each", + "hookId": "h2", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook", + { + "id": "r5", + "title": "\"after each\" hook", + "hookName": "after each", + "hookId": "h4", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook end", + { + "id": "r5", + "title": "\"after each\" hook", + "hookName": "after each", + "hookId": "h4", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook", + { + "id": "r5", + "title": "\"after all\" hook", + "hookName": "after all", + "hookId": "h3", + "body": "[body]", + "type": "hook", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook end", + { + "id": "r5", + "title": "\"after all\" hook", + "hookName": "after all", + "hookId": "h3", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "pass", + { + "id": "r5", + "order": 3, + "title": "test 3", + "state": "passed", + "body": "[body]", + "type": "test", + "duration": "match.number", + "wallClockStartedAt": "match.date", + "timings": { + "lifecycle": "match.number", + "before each": [ + { + "hookId": "h2", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "test": { + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + "after each": [ + { + "hookId": "h4", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "after all": [ + { + "hookId": "h3", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ] + }, + "file": null, + "invocationDetails": "{Object 8}", + "final": true, + "currentRetry": 0, + "retries": 2 + } + ], + [ + "mocha", + "test end", + { + "id": "r5", + "order": 3, + "title": "test 3", + "state": "passed", + "body": "[body]", + "type": "test", + "duration": "match.number", + "wallClockStartedAt": "match.date", + "timings": { + "lifecycle": "match.number", + "before each": [ + { + "hookId": "h2", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "test": { + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + "after each": [ + { + "hookId": "h4", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "after all": [ + { + "hookId": "h3", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ] + }, + "file": null, + "invocationDetails": "{Object 8}", + "final": true, + "currentRetry": 0, + "retries": 2 + } + ], + [ + "mocha", + "suite end", + { + "id": "r2", + "title": "suite 1", + "root": false, + "type": "suite", + "file": null, + "retries": -1 + } + ], + [ + "mocha", + "test:after:run", + { + "id": "r5", + "order": 3, + "title": "test 3", + "state": "passed", + "body": "[body]", + "type": "test", + "duration": "match.number", + "wallClockStartedAt": "match.date", + "wallClockDuration": "match.number", + "timings": { + "lifecycle": "match.number", + "before each": [ + { + "hookId": "h2", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "test": { + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + "after each": [ + { + "hookId": "h4", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "after all": [ + { + "hookId": "h3", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ] + }, + "file": null, + "invocationDetails": "{Object 8}", + "final": true, + "currentRetry": 0, + "retries": 2 + } + ], + [ + "mocha", + "suite end", + { + "id": "r1", + "title": "", + "root": true, + "type": "suite", + "file": "relative/path/to/spec.js", + "retries": -1 + } + ], + [ + "mocha", + "end", + { + "end": "match.date" + } + ] +] + +exports['src/cypress/runner retries mochaEvents screenshots retry screenshot in test body #1'] = [ + "take:screenshot", + { + "titles": [ + "suite 1", + "test 1" + ], + "testId": "r3", + "testAttemptIndex": "match.match(0)", + "capture": "fullPage", + "clip": { + "x": 0, + "y": 0, + "width": 1000, + "height": 660 + }, + "viewport": { + "width": 1000, + "height": 660 + }, + "scaled": false, + "blackout": [], + "startTime": "match.string", + "current": 1, + "total": 1 + } +] + +exports['src/cypress/runner retries mochaEvents screenshots retry screenshot in test body #2'] = { + "id": "r3", + "testAttemptIndex": "match.match(0)", + "isOpen": false, + "appOnly": true, + "scale": false, + "waitForCommandSynchronization": false, + "disableTimersAndAnimations": true, + "blackout": [] +} + +exports['serialize state - retries'] = { + "currentId": "r6", + "tests": { + "r3": { + "id": "r3", + "order": 1, + "title": "test 1", + "state": "passed", + "body": "[body]", + "type": "test", + "duration": 1, + "wallClockStartedAt": "1970-01-01T00:00:00.000Z", + "wallClockDuration": 1, + "timings": { + "lifecycle": 1, + "before all": [ + { + "hookId": "h1", + "fnDuration": 1, + "afterFnDuration": 1 + } + ], + "before each": [ + { + "hookId": "h2", + "fnDuration": 1, + "afterFnDuration": 1 + } + ], + "test": { + "fnDuration": 1, + "afterFnDuration": 1 + }, + "after each": [ + { + "hookId": "h4", + "fnDuration": 1, + "afterFnDuration": 1 + } + ], + "after all": [ + { + "hookId": "h3", + "fnDuration": 1, + "afterFnDuration": 1 + } + ] + }, + "file": null, + "invocationDetails": "{Object 8}", + "final": true, + "currentRetry": 0, + "retries": 1, + "hooks": [], + "prevAttempts": [] + }, + "r5": { + "id": "r5", + "title": "test 1", + "state": "passed", + "body": "[body]", + "type": "test", + "duration": 1, + "wallClockStartedAt": "1970-01-01T00:00:00.000Z", + "wallClockDuration": 1, + "timings": { + "lifecycle": 1, + "test": { + "fnDuration": 1, + "afterFnDuration": 1 + } + }, + "file": null, + "final": true, + "currentRetry": 1, + "retries": 1, + "prevAttempts": [ + { + "id": "r5", + "order": 2, + "title": "test 1", + "err": "{Object 9}", + "state": "failed", + "body": "[body]", + "type": "test", + "duration": 1, + "wallClockStartedAt": "1970-01-01T00:00:00.000Z", + "wallClockDuration": 1, + "timings": { + "lifecycle": 1, + "test": { + "fnDuration": 1, + "afterFnDuration": 1 + } + }, + "file": null, + "invocationDetails": "{Object 8}", + "final": false, + "currentRetry": 0, + "retries": 1, + "hooks": [] + } + ] + } + }, + "startTime": "1970-01-01T00:00:00.000Z", + "emissions": { + "started": { + "r1": true, + "r2": true, + "r3": true, + "r4": true, + "r5": true, + "r6": true + }, + "ended": { + "r3": true, + "r2": true, + "r5": true + } + }, + "passed": 2, + "failed": 0, + "pending": 0, + "numLogs": 0 +} diff --git a/packages/runner/__snapshots__/runner.mochaEvents.spec.js b/packages/runner/__snapshots__/runner.mochaEvents.spec.js index 97daa2d5fa39..b32f5dd5eb04 100644 --- a/packages/runner/__snapshots__/runner.mochaEvents.spec.js +++ b/packages/runner/__snapshots__/runner.mochaEvents.spec.js @@ -14,7 +14,8 @@ exports['src/cypress/runner tests finish with correct state hook failures fail i "title": "", "root": true, "type": "suite", - "file": "relative/path/to/spec.js" + "file": "relative/path/to/spec.js", + "retries": -1 } ], [ @@ -25,7 +26,8 @@ exports['src/cypress/runner tests finish with correct state hook failures fail i "title": "suite 1", "root": false, "type": "suite", - "file": null + "file": null, + "retries": -1 } ], [ @@ -39,7 +41,25 @@ exports['src/cypress/runner tests finish with correct state hook failures fail i "body": "[body]", "type": "hook", "file": null, - "invocationDetails": "{Object 8}" + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "test:before:run", + { + "id": "r3", + "order": 1, + "title": "test 1", + "body": "[body]", + "type": "test", + "wallClockStartedAt": "match.date", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 } ], [ @@ -57,7 +77,9 @@ exports['src/cypress/runner tests finish with correct state hook failures fail i "duration": "match.number", "file": null, "originalTitle": "\"before all\" hook", - "invocationDetails": "{Object 8}" + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 }, { "message": "[error message]", @@ -77,7 +99,40 @@ exports['src/cypress/runner tests finish with correct state hook failures fail i "title": "suite 1", "root": false, "type": "suite", - "file": null + "file": null, + "retries": -1 + } + ], + [ + "mocha", + "test end", + { + "id": "r3", + "order": 1, + "title": "test 1", + "hookName": "before all", + "err": "{Object 9}", + "state": "failed", + "failedFromHookId": "h1", + "body": "[body]", + "type": "test", + "duration": "match.number", + "wallClockStartedAt": "match.date", + "timings": { + "lifecycle": "match.number", + "before all": [ + { + "hookId": "h1", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ] + }, + "file": null, + "invocationDetails": "{Object 8}", + "final": true, + "currentRetry": 0, + "retries": 0 } ], [ @@ -107,7 +162,10 @@ exports['src/cypress/runner tests finish with correct state hook failures fail i ] }, "file": null, - "invocationDetails": "{Object 8}" + "invocationDetails": "{Object 8}", + "final": true, + "currentRetry": 0, + "retries": 0 } ], [ @@ -118,7 +176,8 @@ exports['src/cypress/runner tests finish with correct state hook failures fail i "title": "", "root": true, "type": "suite", - "file": "relative/path/to/spec.js" + "file": "relative/path/to/spec.js", + "retries": -1 } ], [ @@ -146,7 +205,8 @@ exports['src/cypress/runner tests finish with correct state hook failures fail i "title": "", "root": true, "type": "suite", - "file": "relative/path/to/spec.js" + "file": "relative/path/to/spec.js", + "retries": -1 } ], [ @@ -157,7 +217,8 @@ exports['src/cypress/runner tests finish with correct state hook failures fail i "title": "suite 1", "root": false, "type": "suite", - "file": null + "file": null, + "retries": -1 } ], [ @@ -170,7 +231,9 @@ exports['src/cypress/runner tests finish with correct state hook failures fail i "body": "[body]", "type": "test", "file": null, - "invocationDetails": "{Object 8}" + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 } ], [ @@ -184,7 +247,25 @@ exports['src/cypress/runner tests finish with correct state hook failures fail i "body": "[body]", "type": "hook", "file": null, - "invocationDetails": "{Object 8}" + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "test:before:run", + { + "id": "r3", + "order": 1, + "title": "test 1", + "body": "[body]", + "type": "test", + "wallClockStartedAt": "match.date", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 } ], [ @@ -202,7 +283,9 @@ exports['src/cypress/runner tests finish with correct state hook failures fail i "duration": "match.number", "file": null, "originalTitle": "\"before each\" hook", - "invocationDetails": "{Object 8}" + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 }, { "message": "[error message]", @@ -214,6 +297,38 @@ exports['src/cypress/runner tests finish with correct state hook failures fail i "showDiff": false } ], + [ + "mocha", + "test end", + { + "id": "r3", + "order": 1, + "title": "test 1", + "hookName": "before each", + "err": "{Object 9}", + "state": "failed", + "failedFromHookId": "h1", + "body": "[body]", + "type": "test", + "duration": "match.number", + "wallClockStartedAt": "match.date", + "timings": { + "lifecycle": "match.number", + "before each": [ + { + "hookId": "h1", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ] + }, + "file": null, + "invocationDetails": "{Object 8}", + "final": true, + "currentRetry": 0, + "retries": 0 + } + ], [ "mocha", "suite end", @@ -222,7 +337,8 @@ exports['src/cypress/runner tests finish with correct state hook failures fail i "title": "suite 1", "root": false, "type": "suite", - "file": null + "file": null, + "retries": -1 } ], [ @@ -252,7 +368,10 @@ exports['src/cypress/runner tests finish with correct state hook failures fail i ] }, "file": null, - "invocationDetails": "{Object 8}" + "invocationDetails": "{Object 8}", + "final": true, + "currentRetry": 0, + "retries": 0 } ], [ @@ -263,7 +382,8 @@ exports['src/cypress/runner tests finish with correct state hook failures fail i "title": "", "root": true, "type": "suite", - "file": "relative/path/to/spec.js" + "file": "relative/path/to/spec.js", + "retries": -1 } ], [ @@ -291,7 +411,8 @@ exports['src/cypress/runner tests finish with correct state hook failures fail i "title": "", "root": true, "type": "suite", - "file": "relative/path/to/spec.js" + "file": "relative/path/to/spec.js", + "retries": -1 } ], [ @@ -302,80 +423,39 @@ exports['src/cypress/runner tests finish with correct state hook failures fail i "title": "suite 1", "root": false, "type": "suite", - "file": null - } - ], - [ - "mocha", - "test", - { - "id": "r3", - "order": 1, - "title": "test 1", - "body": "[body]", - "type": "test", "file": null, - "invocationDetails": "{Object 8}" + "retries": -1 } ], [ "mocha", - "pass", + "test", { "id": "r3", "order": 1, "title": "test 1", - "state": "passed", "body": "[body]", "type": "test", - "duration": "match.number", - "wallClockStartedAt": "match.date", - "timings": { - "lifecycle": "match.number", - "test": { - "fnDuration": "match.number", - "afterFnDuration": "match.number" - }, - "after each": [ - { - "hookId": "h1", - "fnDuration": "match.number", - "afterFnDuration": "match.number" - } - ] - }, "file": null, - "invocationDetails": "{Object 8}" + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 } ], [ "mocha", - "test end", + "test:before:run", { "id": "r3", "order": 1, "title": "test 1", - "state": "passed", "body": "[body]", "type": "test", - "duration": "match.number", "wallClockStartedAt": "match.date", - "timings": { - "lifecycle": "match.number", - "test": { - "fnDuration": "match.number", - "afterFnDuration": "match.number" - }, - "after each": [ - { - "hookId": "h1", - "fnDuration": "match.number", - "afterFnDuration": "match.number" - } - ] - }, "file": null, - "invocationDetails": "{Object 8}" + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 } ], [ @@ -389,7 +469,9 @@ exports['src/cypress/runner tests finish with correct state hook failures fail i "body": "[body]", "type": "hook", "file": null, - "invocationDetails": "{Object 8}" + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 } ], [ @@ -407,7 +489,9 @@ exports['src/cypress/runner tests finish with correct state hook failures fail i "duration": "match.number", "file": null, "originalTitle": "\"after each\" hook", - "invocationDetails": "{Object 8}" + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 }, { "message": "[error message]", @@ -419,6 +503,42 @@ exports['src/cypress/runner tests finish with correct state hook failures fail i "showDiff": false } ], + [ + "mocha", + "test end", + { + "id": "r3", + "order": 1, + "title": "test 1", + "hookName": "after each", + "err": "{Object 9}", + "state": "failed", + "failedFromHookId": "h1", + "body": "[body]", + "type": "test", + "duration": "match.number", + "wallClockStartedAt": "match.date", + "timings": { + "lifecycle": "match.number", + "test": { + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + "after each": [ + { + "hookId": "h1", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ] + }, + "file": null, + "invocationDetails": "{Object 8}", + "final": true, + "currentRetry": 0, + "retries": 0 + } + ], [ "mocha", "suite end", @@ -427,7 +547,8 @@ exports['src/cypress/runner tests finish with correct state hook failures fail i "title": "suite 1", "root": false, "type": "suite", - "file": null + "file": null, + "retries": -1 } ], [ @@ -461,7 +582,10 @@ exports['src/cypress/runner tests finish with correct state hook failures fail i ] }, "file": null, - "invocationDetails": "{Object 8}" + "invocationDetails": "{Object 8}", + "final": true, + "currentRetry": 0, + "retries": 0 } ], [ @@ -472,7 +596,8 @@ exports['src/cypress/runner tests finish with correct state hook failures fail i "title": "", "root": true, "type": "suite", - "file": "relative/path/to/spec.js" + "file": "relative/path/to/spec.js", + "retries": -1 } ], [ @@ -500,7 +625,8 @@ exports['src/cypress/runner tests finish with correct state hook failures fail i "title": "", "root": true, "type": "suite", - "file": "relative/path/to/spec.js" + "file": "relative/path/to/spec.js", + "retries": -1 } ], [ @@ -511,7 +637,8 @@ exports['src/cypress/runner tests finish with correct state hook failures fail i "title": "suite 1", "root": false, "type": "suite", - "file": null + "file": null, + "retries": -1 } ], [ @@ -524,7 +651,25 @@ exports['src/cypress/runner tests finish with correct state hook failures fail i "body": "[body]", "type": "test", "file": null, - "invocationDetails": "{Object 8}" + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "test:before:run", + { + "id": "r3", + "order": 1, + "title": "test 1", + "body": "[body]", + "type": "test", + "wallClockStartedAt": "match.date", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 } ], [ @@ -547,7 +692,10 @@ exports['src/cypress/runner tests finish with correct state hook failures fail i } }, "file": null, - "invocationDetails": "{Object 8}" + "invocationDetails": "{Object 8}", + "final": true, + "currentRetry": 0, + "retries": 0 } ], [ @@ -570,7 +718,10 @@ exports['src/cypress/runner tests finish with correct state hook failures fail i } }, "file": null, - "invocationDetails": "{Object 8}" + "invocationDetails": "{Object 8}", + "final": true, + "currentRetry": 0, + "retries": 0 } ], [ @@ -594,7 +745,10 @@ exports['src/cypress/runner tests finish with correct state hook failures fail i } }, "file": null, - "invocationDetails": "{Object 8}" + "invocationDetails": "{Object 8}", + "final": true, + "currentRetry": 0, + "retries": 0 } ], [ @@ -607,67 +761,25 @@ exports['src/cypress/runner tests finish with correct state hook failures fail i "body": "[body]", "type": "test", "file": null, - "invocationDetails": "{Object 8}" - } - ], - [ - "mocha", - "pass", - { - "id": "r4", - "order": 2, - "title": "test 2", - "state": "passed", - "body": "[body]", - "type": "test", - "duration": "match.number", - "wallClockStartedAt": "match.date", - "timings": { - "lifecycle": "match.number", - "test": { - "fnDuration": "match.number", - "afterFnDuration": "match.number" - }, - "after all": [ - { - "hookId": "h1", - "fnDuration": "match.number", - "afterFnDuration": "match.number" - } - ] - }, - "file": null, - "invocationDetails": "{Object 8}" + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 } ], [ "mocha", - "test end", + "test:before:run", { "id": "r4", "order": 2, "title": "test 2", - "state": "passed", "body": "[body]", "type": "test", - "duration": "match.number", "wallClockStartedAt": "match.date", - "timings": { - "lifecycle": "match.number", - "test": { - "fnDuration": "match.number", - "afterFnDuration": "match.number" - }, - "after all": [ - { - "hookId": "h1", - "fnDuration": "match.number", - "afterFnDuration": "match.number" - } - ] - }, "file": null, - "invocationDetails": "{Object 8}" + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 } ], [ @@ -681,7 +793,9 @@ exports['src/cypress/runner tests finish with correct state hook failures fail i "body": "[body]", "type": "hook", "file": null, - "invocationDetails": "{Object 8}" + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 } ], [ @@ -699,7 +813,9 @@ exports['src/cypress/runner tests finish with correct state hook failures fail i "duration": "match.number", "file": null, "originalTitle": "\"after all\" hook", - "invocationDetails": "{Object 8}" + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 }, { "message": "[error message]", @@ -713,14 +829,51 @@ exports['src/cypress/runner tests finish with correct state hook failures fail i ], [ "mocha", - "suite end", + "test end", { - "id": "r2", - "title": "suite 1", - "root": false, - "type": "suite", - "file": null - } + "id": "r4", + "order": 2, + "title": "test 2", + "hookName": "after all", + "err": "{Object 9}", + "state": "failed", + "failedFromHookId": "h1", + "body": "[body]", + "type": "test", + "duration": "match.number", + "wallClockStartedAt": "match.date", + "timings": { + "lifecycle": "match.number", + "test": { + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + "after all": [ + { + "hookId": "h1", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ] + }, + "file": null, + "invocationDetails": "{Object 8}", + "final": true, + "currentRetry": 0, + "retries": 0 + } + ], + [ + "mocha", + "suite end", + { + "id": "r2", + "title": "suite 1", + "root": false, + "type": "suite", + "file": null, + "retries": -1 + } ], [ "mocha", @@ -753,7 +906,10 @@ exports['src/cypress/runner tests finish with correct state hook failures fail i ] }, "file": null, - "invocationDetails": "{Object 8}" + "invocationDetails": "{Object 8}", + "final": true, + "currentRetry": 0, + "retries": 0 } ], [ @@ -764,7 +920,8 @@ exports['src/cypress/runner tests finish with correct state hook failures fail i "title": "", "root": true, "type": "suite", - "file": "relative/path/to/spec.js" + "file": "relative/path/to/spec.js", + "retries": -1 } ], [ @@ -792,7 +949,8 @@ exports['src/cypress/runner tests finish with correct state mocha grep fail with "title": "", "root": true, "type": "suite", - "file": "relative/path/to/spec.js" + "file": "relative/path/to/spec.js", + "retries": -1 } ], [ @@ -803,7 +961,8 @@ exports['src/cypress/runner tests finish with correct state mocha grep fail with "title": "suite 1", "root": false, "type": "suite", - "file": null + "file": null, + "retries": -1 } ], [ @@ -817,7 +976,25 @@ exports['src/cypress/runner tests finish with correct state mocha grep fail with "body": "[body]", "type": "hook", "file": null, - "invocationDetails": "{Object 8}" + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "test:before:run", + { + "id": "r5", + "order": 2, + "title": "test 2", + "body": "[body]", + "type": "test", + "wallClockStartedAt": "match.date", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 } ], [ @@ -832,7 +1009,9 @@ exports['src/cypress/runner tests finish with correct state mocha grep fail with "type": "hook", "duration": "match.number", "file": null, - "invocationDetails": "{Object 8}" + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 } ], [ @@ -840,6 +1019,7 @@ exports['src/cypress/runner tests finish with correct state mocha grep fail with "test", { "id": "r5", + "order": 2, "title": "test 2", "body": "[body]", "type": "test", @@ -880,7 +1060,9 @@ exports['src/cypress/runner tests finish with correct state mocha grep fail with ] }, "file": null, - "invocationDetails": "{Object 8}" + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": 0 } ], [ @@ -894,7 +1076,9 @@ exports['src/cypress/runner tests finish with correct state mocha grep fail with "body": "[body]", "type": "hook", "file": null, - "invocationDetails": "{Object 8}" + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 } ], [ @@ -909,7 +1093,9 @@ exports['src/cypress/runner tests finish with correct state mocha grep fail with "type": "hook", "duration": "match.number", "file": null, - "invocationDetails": "{Object 8}" + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 } ], [ @@ -917,6 +1103,7 @@ exports['src/cypress/runner tests finish with correct state mocha grep fail with "fail", { "id": "r5", + "order": 2, "title": "test 2", "err": "{Object 9}", "state": "failed", @@ -960,7 +1147,9 @@ exports['src/cypress/runner tests finish with correct state mocha grep fail with ] }, "file": null, - "invocationDetails": "{Object 8}" + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": 0 }, { "message": "[error message]", @@ -972,57 +1161,6 @@ exports['src/cypress/runner tests finish with correct state mocha grep fail with "showDiff": false } ], - [ - "mocha", - "test end", - { - "id": "r5", - "title": "test 2", - "err": "{Object 9}", - "state": "failed", - "body": "[body]", - "type": "test", - "duration": "match.number", - "wallClockStartedAt": "match.date", - "timings": { - "lifecycle": "match.number", - "before all": [ - { - "hookId": "h1", - "fnDuration": "match.number", - "afterFnDuration": "match.number" - } - ], - "before each": [ - { - "hookId": "h2", - "fnDuration": "match.number", - "afterFnDuration": "match.number" - } - ], - "test": { - "fnDuration": "match.number", - "afterFnDuration": "match.number" - }, - "after each": [ - { - "hookId": "h4", - "fnDuration": "match.number", - "afterFnDuration": "match.number" - } - ], - "after all": [ - { - "hookId": "h3", - "fnDuration": "match.number", - "afterFnDuration": "match.number" - } - ] - }, - "file": null, - "invocationDetails": "{Object 8}" - } - ], [ "mocha", "hook", @@ -1034,7 +1172,9 @@ exports['src/cypress/runner tests finish with correct state mocha grep fail with "body": "[body]", "type": "hook", "file": null, - "invocationDetails": "{Object 8}" + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 } ], [ @@ -1049,7 +1189,9 @@ exports['src/cypress/runner tests finish with correct state mocha grep fail with "type": "hook", "duration": "match.number", "file": null, - "invocationDetails": "{Object 8}" + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 } ], [ @@ -1063,7 +1205,9 @@ exports['src/cypress/runner tests finish with correct state mocha grep fail with "body": "[body]", "type": "hook", "file": null, - "invocationDetails": "{Object 8}" + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 } ], [ @@ -1078,14 +1222,17 @@ exports['src/cypress/runner tests finish with correct state mocha grep fail with "type": "hook", "duration": "match.number", "file": null, - "invocationDetails": "{Object 8}" + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 } ], [ "mocha", - "test:after:run", + "test end", { "id": "r5", + "order": 2, "title": "test 2", "err": "{Object 9}", "state": "failed", @@ -1093,7 +1240,6 @@ exports['src/cypress/runner tests finish with correct state mocha grep fail with "type": "test", "duration": "match.number", "wallClockStartedAt": "match.date", - "wallClockDuration": "match.number", "timings": { "lifecycle": "match.number", "before all": [ @@ -1130,7 +1276,10 @@ exports['src/cypress/runner tests finish with correct state mocha grep fail with ] }, "file": null, - "invocationDetails": "{Object 8}" + "invocationDetails": "{Object 8}", + "final": true, + "currentRetry": 0, + "retries": 0 } ], [ @@ -1141,7 +1290,64 @@ exports['src/cypress/runner tests finish with correct state mocha grep fail with "title": "suite 1", "root": false, "type": "suite", - "file": null + "file": null, + "retries": -1 + } + ], + [ + "mocha", + "test:after:run", + { + "id": "r5", + "order": 2, + "title": "test 2", + "err": "{Object 9}", + "state": "failed", + "body": "[body]", + "type": "test", + "duration": "match.number", + "wallClockStartedAt": "match.date", + "wallClockDuration": "match.number", + "timings": { + "lifecycle": "match.number", + "before all": [ + { + "hookId": "h1", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "before each": [ + { + "hookId": "h2", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "test": { + "fnDuration": "match.number", + "afterFnDuration": "match.number" + }, + "after each": [ + { + "hookId": "h4", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ], + "after all": [ + { + "hookId": "h3", + "fnDuration": "match.number", + "afterFnDuration": "match.number" + } + ] + }, + "file": null, + "invocationDetails": "{Object 8}", + "final": true, + "currentRetry": 0, + "retries": 0 } ], [ @@ -1152,7 +1358,8 @@ exports['src/cypress/runner tests finish with correct state mocha grep fail with "title": "", "root": true, "type": "suite", - "file": "relative/path/to/spec.js" + "file": "relative/path/to/spec.js", + "retries": -1 } ], [ @@ -1180,7 +1387,8 @@ exports['src/cypress/runner tests finish with correct state mocha grep pass with "title": "", "root": true, "type": "suite", - "file": "relative/path/to/spec.js" + "file": "relative/path/to/spec.js", + "retries": -1 } ], [ @@ -1191,7 +1399,8 @@ exports['src/cypress/runner tests finish with correct state mocha grep pass with "title": "suite 1", "root": false, "type": "suite", - "file": null + "file": null, + "retries": -1 } ], [ @@ -1205,7 +1414,25 @@ exports['src/cypress/runner tests finish with correct state mocha grep pass with "body": "[body]", "type": "hook", "file": null, - "invocationDetails": "{Object 8}" + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "test:before:run", + { + "id": "r5", + "order": 2, + "title": "test 2", + "body": "[body]", + "type": "test", + "wallClockStartedAt": "match.date", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 } ], [ @@ -1220,7 +1447,9 @@ exports['src/cypress/runner tests finish with correct state mocha grep pass with "type": "hook", "duration": "match.number", "file": null, - "invocationDetails": "{Object 8}" + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 } ], [ @@ -1228,6 +1457,7 @@ exports['src/cypress/runner tests finish with correct state mocha grep pass with "test", { "id": "r5", + "order": 2, "title": "test 2", "body": "[body]", "type": "test", @@ -1268,7 +1498,9 @@ exports['src/cypress/runner tests finish with correct state mocha grep pass with ] }, "file": null, - "invocationDetails": "{Object 8}" + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": 0 } ], [ @@ -1282,7 +1514,9 @@ exports['src/cypress/runner tests finish with correct state mocha grep pass with "body": "[body]", "type": "hook", "file": null, - "invocationDetails": "{Object 8}" + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 } ], [ @@ -1297,7 +1531,75 @@ exports['src/cypress/runner tests finish with correct state mocha grep pass with "type": "hook", "duration": "match.number", "file": null, - "invocationDetails": "{Object 8}" + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook", + { + "id": "r5", + "title": "\"after each\" hook", + "hookName": "after each", + "hookId": "h4", + "body": "[body]", + "type": "hook", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook end", + { + "id": "r5", + "title": "\"after each\" hook", + "hookName": "after each", + "hookId": "h4", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook", + { + "id": "r5", + "title": "\"after all\" hook", + "hookName": "after all", + "hookId": "h3", + "body": "[body]", + "type": "hook", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook end", + { + "id": "r5", + "title": "\"after all\" hook", + "hookName": "after all", + "hookId": "h3", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 } ], [ @@ -1305,6 +1607,7 @@ exports['src/cypress/runner tests finish with correct state mocha grep pass with "pass", { "id": "r5", + "order": 2, "title": "test 2", "state": "passed", "body": "[body]", @@ -1347,7 +1650,10 @@ exports['src/cypress/runner tests finish with correct state mocha grep pass with ] }, "file": null, - "invocationDetails": "{Object 8}" + "invocationDetails": "{Object 8}", + "final": true, + "currentRetry": 0, + "retries": 0 } ], [ @@ -1355,6 +1661,7 @@ exports['src/cypress/runner tests finish with correct state mocha grep pass with "test end", { "id": "r5", + "order": 2, "title": "test 2", "state": "passed", "body": "[body]", @@ -1397,65 +1704,22 @@ exports['src/cypress/runner tests finish with correct state mocha grep pass with ] }, "file": null, - "invocationDetails": "{Object 8}" - } - ], - [ - "mocha", - "hook", - { - "id": "r5", - "title": "\"after each\" hook", - "hookName": "after each", - "hookId": "h4", - "body": "[body]", - "type": "hook", - "file": null, - "invocationDetails": "{Object 8}" - } - ], - [ - "mocha", - "hook end", - { - "id": "r5", - "title": "\"after each\" hook", - "hookName": "after each", - "hookId": "h4", - "body": "[body]", - "type": "hook", - "duration": "match.number", - "file": null, - "invocationDetails": "{Object 8}" - } - ], - [ - "mocha", - "hook", - { - "id": "r5", - "title": "\"after all\" hook", - "hookName": "after all", - "hookId": "h3", - "body": "[body]", - "type": "hook", - "file": null, - "invocationDetails": "{Object 8}" + "invocationDetails": "{Object 8}", + "final": true, + "currentRetry": 0, + "retries": 0 } ], [ "mocha", - "hook end", + "suite end", { - "id": "r5", - "title": "\"after all\" hook", - "hookName": "after all", - "hookId": "h3", - "body": "[body]", - "type": "hook", - "duration": "match.number", + "id": "r4", + "title": "suite 1", + "root": false, + "type": "suite", "file": null, - "invocationDetails": "{Object 8}" + "retries": -1 } ], [ @@ -1463,6 +1727,7 @@ exports['src/cypress/runner tests finish with correct state mocha grep pass with "test:after:run", { "id": "r5", + "order": 2, "title": "test 2", "state": "passed", "body": "[body]", @@ -1506,18 +1771,10 @@ exports['src/cypress/runner tests finish with correct state mocha grep pass with ] }, "file": null, - "invocationDetails": "{Object 8}" - } - ], - [ - "mocha", - "suite end", - { - "id": "r4", - "title": "suite 1", - "root": false, - "type": "suite", - "file": null + "invocationDetails": "{Object 8}", + "final": true, + "currentRetry": 0, + "retries": 0 } ], [ @@ -1528,7 +1785,8 @@ exports['src/cypress/runner tests finish with correct state mocha grep pass with "title": "", "root": true, "type": "suite", - "file": "relative/path/to/spec.js" + "file": "relative/path/to/spec.js", + "retries": -1 } ], [ @@ -1542,78 +1800,7 @@ exports['src/cypress/runner tests finish with correct state mocha grep pass with exports['serialize state - hooks'] = { "currentId": "r6", - "tests": { - "r3": { - "id": "r3", - "order": 1, - "title": "test 1", - "state": "passed", - "body": "stub", - "type": "test", - "duration": 1, - "wallClockStartedAt": "1970-01-01T00:00:00.000Z", - "wallClockDuration": 1, - "timings": { - "lifecycle": 1, - "before all": [ - { - "hookId": "h1", - "fnDuration": 1, - "afterFnDuration": 1 - } - ], - "before each": [ - { - "hookId": "h2", - "fnDuration": 1, - "afterFnDuration": 1 - } - ], - "test": { - "fnDuration": 1, - "afterFnDuration": 1 - }, - "after each": [ - { - "hookId": "h4", - "fnDuration": 1, - "afterFnDuration": 1 - } - ], - "after all": [ - { - "hookId": "h3", - "fnDuration": 1, - "afterFnDuration": 1 - } - ] - }, - "file": null, - "invocationDetails": "{Object 8}", - "hooks": [] - }, - "r5": { - "id": "r5", - "order": 2, - "title": "test 1", - "state": "passed", - "body": "stub", - "type": "test", - "duration": 1, - "wallClockStartedAt": "1970-01-01T00:00:00.000Z", - "wallClockDuration": 1, - "timings": { - "lifecycle": 1, - "test": { - "fnDuration": 1, - "afterFnDuration": 1 - } - }, - "file": null, - "invocationDetails": "{Object 8}", - "hooks": [] - } - }, + "tests": "{Object 2}", "startTime": "1970-01-01T00:00:00.000Z", "emissions": { "started": { @@ -1645,6 +1832,7 @@ exports['src/cypress/runner other specs screenshots screenshot after failed test "test 1" ], "testId": "r3", + "testAttemptIndex": 0, "simple": true, "testFailure": true, "capture": "runner", @@ -1681,7 +1869,8 @@ exports['src/cypress/runner mocha events simple single test #1'] = [ "title": "", "root": true, "type": "suite", - "file": "relative/path/to/spec.js" + "file": "relative/path/to/spec.js", + "retries": -1 } ], [ @@ -1692,7 +1881,8 @@ exports['src/cypress/runner mocha events simple single test #1'] = [ "title": "suite 1", "root": false, "type": "suite", - "file": null + "file": null, + "retries": -1 } ], [ @@ -1705,7 +1895,25 @@ exports['src/cypress/runner mocha events simple single test #1'] = [ "body": "[body]", "type": "test", "file": null, - "invocationDetails": "{Object 8}" + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "test:before:run", + { + "id": "r3", + "order": 1, + "title": "test 1", + "body": "[body]", + "type": "test", + "wallClockStartedAt": "match.date", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 } ], [ @@ -1728,7 +1936,10 @@ exports['src/cypress/runner mocha events simple single test #1'] = [ } }, "file": null, - "invocationDetails": "{Object 8}" + "invocationDetails": "{Object 8}", + "final": true, + "currentRetry": 0, + "retries": 0 } ], [ @@ -1751,7 +1962,10 @@ exports['src/cypress/runner mocha events simple single test #1'] = [ } }, "file": null, - "invocationDetails": "{Object 8}" + "invocationDetails": "{Object 8}", + "final": true, + "currentRetry": 0, + "retries": 0 } ], [ @@ -1762,7 +1976,8 @@ exports['src/cypress/runner mocha events simple single test #1'] = [ "title": "suite 1", "root": false, "type": "suite", - "file": null + "file": null, + "retries": -1 } ], [ @@ -1786,7 +2001,10 @@ exports['src/cypress/runner mocha events simple single test #1'] = [ } }, "file": null, - "invocationDetails": "{Object 8}" + "invocationDetails": "{Object 8}", + "final": true, + "currentRetry": 0, + "retries": 0 } ], [ @@ -1797,7 +2015,8 @@ exports['src/cypress/runner mocha events simple single test #1'] = [ "title": "", "root": true, "type": "suite", - "file": "relative/path/to/spec.js" + "file": "relative/path/to/spec.js", + "retries": -1 } ], [ @@ -1825,7 +2044,8 @@ exports['src/cypress/runner mocha events simple three tests #1'] = [ "title": "", "root": true, "type": "suite", - "file": "relative/path/to/spec.js" + "file": "relative/path/to/spec.js", + "retries": -1 } ], [ @@ -1836,7 +2056,8 @@ exports['src/cypress/runner mocha events simple three tests #1'] = [ "title": "suite 1", "root": false, "type": "suite", - "file": null + "file": null, + "retries": -1 } ], [ @@ -1850,7 +2071,25 @@ exports['src/cypress/runner mocha events simple three tests #1'] = [ "body": "[body]", "type": "hook", "file": null, - "invocationDetails": "{Object 8}" + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "test:before:run", + { + "id": "r3", + "order": 1, + "title": "test 1", + "body": "[body]", + "type": "test", + "wallClockStartedAt": "match.date", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 } ], [ @@ -1865,7 +2104,9 @@ exports['src/cypress/runner mocha events simple three tests #1'] = [ "type": "hook", "duration": "match.number", "file": null, - "invocationDetails": "{Object 8}" + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 } ], [ @@ -1907,7 +2148,9 @@ exports['src/cypress/runner mocha events simple three tests #1'] = [ ] }, "file": null, - "invocationDetails": "{Object 8}" + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": 0 } ], [ @@ -1921,7 +2164,9 @@ exports['src/cypress/runner mocha events simple three tests #1'] = [ "body": "[body]", "type": "hook", "file": null, - "invocationDetails": "{Object 8}" + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 } ], [ @@ -1936,7 +2181,42 @@ exports['src/cypress/runner mocha events simple three tests #1'] = [ "type": "hook", "duration": "match.number", "file": null, - "invocationDetails": "{Object 8}" + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook", + { + "id": "r3", + "title": "\"after each\" hook", + "hookName": "after each", + "hookId": "h4", + "body": "[body]", + "type": "hook", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook end", + { + "id": "r3", + "title": "\"after each\" hook", + "hookName": "after each", + "hookId": "h4", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 } ], [ @@ -1980,7 +2260,10 @@ exports['src/cypress/runner mocha events simple three tests #1'] = [ ] }, "file": null, - "invocationDetails": "{Object 8}" + "invocationDetails": "{Object 8}", + "final": true, + "currentRetry": 0, + "retries": 0 } ], [ @@ -2024,36 +2307,10 @@ exports['src/cypress/runner mocha events simple three tests #1'] = [ ] }, "file": null, - "invocationDetails": "{Object 8}" - } - ], - [ - "mocha", - "hook", - { - "id": "r3", - "title": "\"after each\" hook", - "hookName": "after each", - "hookId": "h4", - "body": "[body]", - "type": "hook", - "file": null, - "invocationDetails": "{Object 8}" - } - ], - [ - "mocha", - "hook end", - { - "id": "r3", - "title": "\"after each\" hook", - "hookName": "after each", - "hookId": "h4", - "body": "[body]", - "type": "hook", - "duration": "match.number", - "file": null, - "invocationDetails": "{Object 8}" + "invocationDetails": "{Object 8}", + "final": true, + "currentRetry": 0, + "retries": 0 } ], [ @@ -2098,7 +2355,10 @@ exports['src/cypress/runner mocha events simple three tests #1'] = [ ] }, "file": null, - "invocationDetails": "{Object 8}" + "invocationDetails": "{Object 8}", + "final": true, + "currentRetry": 0, + "retries": 0 } ], [ @@ -2111,7 +2371,9 @@ exports['src/cypress/runner mocha events simple three tests #1'] = [ "body": "[body]", "type": "test", "file": null, - "invocationDetails": "{Object 8}" + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 } ], [ @@ -2126,7 +2388,25 @@ exports['src/cypress/runner mocha events simple three tests #1'] = [ "type": "hook", "duration": "match.number", "file": null, - "invocationDetails": "{Object 8}" + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "test:before:run", + { + "id": "r4", + "order": 2, + "title": "test 2", + "body": "[body]", + "type": "test", + "wallClockStartedAt": "match.date", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 } ], [ @@ -2141,7 +2421,43 @@ exports['src/cypress/runner mocha events simple three tests #1'] = [ "type": "hook", "duration": "match.number", "file": null, - "invocationDetails": "{Object 8}" + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook", + { + "id": "r4", + "title": "\"after each\" hook", + "hookName": "after each", + "hookId": "h4", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook end", + { + "id": "r4", + "title": "\"after each\" hook", + "hookName": "after each", + "hookId": "h4", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 } ], [ @@ -2178,7 +2494,10 @@ exports['src/cypress/runner mocha events simple three tests #1'] = [ ] }, "file": null, - "invocationDetails": "{Object 8}" + "invocationDetails": "{Object 8}", + "final": true, + "currentRetry": 0, + "retries": 0 } ], [ @@ -2215,37 +2534,10 @@ exports['src/cypress/runner mocha events simple three tests #1'] = [ ] }, "file": null, - "invocationDetails": "{Object 8}" - } - ], - [ - "mocha", - "hook", - { - "id": "r4", - "title": "\"after each\" hook", - "hookName": "after each", - "hookId": "h4", - "body": "[body]", - "type": "hook", - "duration": "match.number", - "file": null, - "invocationDetails": "{Object 8}" - } - ], - [ - "mocha", - "hook end", - { - "id": "r4", - "title": "\"after each\" hook", - "hookName": "after each", - "hookId": "h4", - "body": "[body]", - "type": "hook", - "duration": "match.number", - "file": null, - "invocationDetails": "{Object 8}" + "invocationDetails": "{Object 8}", + "final": true, + "currentRetry": 0, + "retries": 0 } ], [ @@ -2283,7 +2575,10 @@ exports['src/cypress/runner mocha events simple three tests #1'] = [ ] }, "file": null, - "invocationDetails": "{Object 8}" + "invocationDetails": "{Object 8}", + "final": true, + "currentRetry": 0, + "retries": 0 } ], [ @@ -2296,7 +2591,9 @@ exports['src/cypress/runner mocha events simple three tests #1'] = [ "body": "[body]", "type": "test", "file": null, - "invocationDetails": "{Object 8}" + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 } ], [ @@ -2311,7 +2608,25 @@ exports['src/cypress/runner mocha events simple three tests #1'] = [ "type": "hook", "duration": "match.number", "file": null, - "invocationDetails": "{Object 8}" + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "test:before:run", + { + "id": "r5", + "order": 3, + "title": "test 3", + "body": "[body]", + "type": "test", + "wallClockStartedAt": "match.date", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 } ], [ @@ -2326,7 +2641,76 @@ exports['src/cypress/runner mocha events simple three tests #1'] = [ "type": "hook", "duration": "match.number", "file": null, - "invocationDetails": "{Object 8}" + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook", + { + "id": "r5", + "title": "\"after each\" hook", + "hookName": "after each", + "hookId": "h4", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook end", + { + "id": "r5", + "title": "\"after each\" hook", + "hookName": "after each", + "hookId": "h4", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook", + { + "id": "r5", + "title": "\"after all\" hook", + "hookName": "after all", + "hookId": "h3", + "body": "[body]", + "type": "hook", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 + } + ], + [ + "mocha", + "hook end", + { + "id": "r5", + "title": "\"after all\" hook", + "hookName": "after all", + "hookId": "h3", + "body": "[body]", + "type": "hook", + "duration": "match.number", + "file": null, + "invocationDetails": "{Object 8}", + "currentRetry": 0, + "retries": -1 } ], [ @@ -2370,7 +2754,10 @@ exports['src/cypress/runner mocha events simple three tests #1'] = [ ] }, "file": null, - "invocationDetails": "{Object 8}" + "invocationDetails": "{Object 8}", + "final": true, + "currentRetry": 0, + "retries": 0 } ], [ @@ -2414,66 +2801,10 @@ exports['src/cypress/runner mocha events simple three tests #1'] = [ ] }, "file": null, - "invocationDetails": "{Object 8}" - } - ], - [ - "mocha", - "hook", - { - "id": "r5", - "title": "\"after each\" hook", - "hookName": "after each", - "hookId": "h4", - "body": "[body]", - "type": "hook", - "duration": "match.number", - "file": null, - "invocationDetails": "{Object 8}" - } - ], - [ - "mocha", - "hook end", - { - "id": "r5", - "title": "\"after each\" hook", - "hookName": "after each", - "hookId": "h4", - "body": "[body]", - "type": "hook", - "duration": "match.number", - "file": null, - "invocationDetails": "{Object 8}" - } - ], - [ - "mocha", - "hook", - { - "id": "r5", - "title": "\"after all\" hook", - "hookName": "after all", - "hookId": "h3", - "body": "[body]", - "type": "hook", - "file": null, - "invocationDetails": "{Object 8}" - } - ], - [ - "mocha", - "hook end", - { - "id": "r5", - "title": "\"after all\" hook", - "hookName": "after all", - "hookId": "h3", - "body": "[body]", - "type": "hook", - "duration": "match.number", - "file": null, - "invocationDetails": "{Object 8}" + "invocationDetails": "{Object 8}", + "final": true, + "currentRetry": 0, + "retries": 0 } ], [ @@ -2484,7 +2815,8 @@ exports['src/cypress/runner mocha events simple three tests #1'] = [ "title": "suite 1", "root": false, "type": "suite", - "file": null + "file": null, + "retries": -1 } ], [ @@ -2529,7 +2861,10 @@ exports['src/cypress/runner mocha events simple three tests #1'] = [ ] }, "file": null, - "invocationDetails": "{Object 8}" + "invocationDetails": "{Object 8}", + "final": true, + "currentRetry": 0, + "retries": 0 } ], [ @@ -2540,7 +2875,8 @@ exports['src/cypress/runner mocha events simple three tests #1'] = [ "title": "", "root": true, "type": "suite", - "file": "relative/path/to/spec.js" + "file": "relative/path/to/spec.js", + "retries": -1 } ], [ diff --git a/packages/runner/cypress/integration/reporter.errors.spec.js b/packages/runner/cypress/integration/reporter.errors.spec.js index 29d621de9cb8..236760cdbaae 100644 --- a/packages/runner/cypress/integration/reporter.errors.spec.js +++ b/packages/runner/cypress/integration/reporter.errors.spec.js @@ -1,7 +1,7 @@ const helpers = require('../support/helpers') const _ = Cypress._ -const { runIsolatedCypress } = helpers.createCypress() +const { runIsolatedCypress } = helpers.createCypress({ config: { isTextTerminal: true, retries: 0 } }) export const verifyFailure = (options) => { const { diff --git a/packages/runner/cypress/integration/retries.mochaEvents.spec.js b/packages/runner/cypress/integration/retries.mochaEvents.spec.js new file mode 100644 index 000000000000..252185cc327b --- /dev/null +++ b/packages/runner/cypress/integration/retries.mochaEvents.spec.js @@ -0,0 +1,338 @@ +const helpers = require('../support/helpers') + +const { shouldHaveTestResults, getRunState, cleanseRunStateMap } = helpers +const { runIsolatedCypress, snapshotMochaEvents, getAutCypress } = helpers.createCypress({ config: { retries: 2, isTextTerminal: true } }) +const { sinon } = Cypress +const match = Cypress.sinon.match + +const threeTestsWithRetry = { + suites: { + 'suite 1': { + hooks: ['before', 'beforeEach', 'afterEach', 'after'], + tests: [ + 'test 1', + { name: 'test 2', fail: 2 }, + 'test 3', + ], + }, + }, +} + +describe('src/cypress/runner retries mochaEvents', () => { + // NOTE: for test-retries + it('can set retry config', () => { + runIsolatedCypress({}, { config: { retries: 1 } }) + .then(({ autCypress }) => { + expect(autCypress.config()).to.has.property('retries', 1) + }) + }) + + it('simple retry', () => { + runIsolatedCypress({ + suites: { + 'suite 1': { + tests: [ + { name: 'test 1', + fail: 1, + }, + ], + }, + }, + }, { config: { retries: 1 } }) + .then(snapshotMochaEvents) + }) + + it('test retry with hooks', () => { + runIsolatedCypress({ + suites: { + 'suite 1': { + hooks: ['before', 'beforeEach', 'afterEach', 'after'], + tests: [{ name: 'test 1', fail: 1 }], + }, + }, + }, { config: { retries: 1 } }) + .then(snapshotMochaEvents) + }) + + it('test retry with [only]', () => { + runIsolatedCypress({ + suites: { + 'suite 1': { + hooks: ['before', 'beforeEach', 'afterEach', 'after'], + tests: [ + { name: 'test 1' }, + { name: 'test 2', fail: 1, only: true }, + { name: 'test 3' }, + ], + }, + }, + }, { config: { retries: 1 } }) + .then(snapshotMochaEvents) + }) + + it('can retry from [beforeEach]', () => { + runIsolatedCypress({ + suites: { + 'suite 1': { + hooks: [ + 'before', + 'beforeEach', + { type: 'beforeEach', fail: 1 }, + 'beforeEach', + 'afterEach', + 'after', + ], + tests: [{ name: 'test 1' }], + }, + }, + }, { config: { retries: 1 } }) + .then(snapshotMochaEvents) + }) + + it('can retry from [afterEach]', () => { + runIsolatedCypress({ + hooks: [{ type: 'afterEach', fail: 1 }], + suites: { + 'suite 1': { + hooks: [ + 'before', + 'beforeEach', + 'beforeEach', + 'afterEach', + 'after', + ], + tests: [{ name: 'test 1' }, 'test 2', 'test 3'], + }, + 'suite 2': { + hooks: [{ type: 'afterEach', fail: 2 }], + tests: ['test 1'], + }, + 'suite 3': { + tests: ['test 1'], + }, + }, + }, { config: { retries: 2, isTextTerminal: true } }) + + .then(snapshotMochaEvents) + }) + + it('cant retry from [before]', () => { + runIsolatedCypress({ + suites: { + 'suite 1': { + hooks: [ + { type: 'before', fail: 1 }, + 'beforeEach', + 'beforeEach', + 'afterEach', + 'afterEach', + 'after', + ], + tests: [{ name: 'test 1' }], + }, + }, + }, { config: { retries: 1 } }) + .then(snapshotMochaEvents) + }) + + it('cant retry from [after]', () => { + runIsolatedCypress({ + suites: { + 'suite 1': { + hooks: [ + 'before', + 'beforeEach', + 'beforeEach', + 'afterEach', + 'afterEach', + { type: 'after', fail: 1 }, + ], + tests: [{ name: 'test 1' }], + }, + }, + }, { config: { retries: 1 } }) + .then(snapshotMochaEvents) + }) + + it('three tests with retry', () => { + runIsolatedCypress(threeTestsWithRetry, { + config: { + retries: 2, + }, + }) + .then(snapshotMochaEvents) + }) + + describe('screenshots', () => { + it('retry screenshot in test body', () => { + let onAfterScreenshot + + runIsolatedCypress({ + suites: { + 'suite 1': { + tests: [ + { + name: 'test 1', + fn: () => { + cy.screenshot() + cy.then(() => assert(false)) + }, + eval: true, + }, + ], + }, + }, + }, { config: { retries: 1 }, + onBeforeRun ({ autCypress }) { + autCypress.Screenshot.onAfterScreenshot = cy.stub() + onAfterScreenshot = cy.stub() + autCypress.on('after:screenshot', onAfterScreenshot) + }, + }) + .then(({ autCypress }) => { + expect(autCypress.automation.withArgs('take:screenshot')).callCount(4) + expect(autCypress.automation.withArgs('take:screenshot').args).matchDeep([ + { 1: { testAttemptIndex: 0 } }, + { 1: { testAttemptIndex: 0 } }, + { 1: { testAttemptIndex: 1 } }, + { 1: { testAttemptIndex: 1 } }, + ]) + + expect(autCypress.automation.withArgs('take:screenshot').args[0]).matchSnapshot({ startTime: match.string, testAttemptIndex: match(0) }) + expect(onAfterScreenshot.args[0][0]).to.matchSnapshot({ testAttemptIndex: match(0) }) + expect(onAfterScreenshot.args[2][0]).to.matchDeep({ testAttemptIndex: 1 }) + }) + }) + + it('retry screenshot in hook', () => { + let onAfterScreenshot + + runIsolatedCypress({ + suites: { + 'suite 1': { + hooks: [ + { + type: 'beforeEach', + fn: () => { + cy.screenshot() + cy.then(() => assert(false)) + }, + eval: true, + }, + ], + tests: [ + { + name: 'test 1', + }, + ], + }, + }, + }, { config: { retries: 1 }, + onBeforeRun ({ autCypress }) { + autCypress.Screenshot.onAfterScreenshot = cy.stub() + onAfterScreenshot = cy.stub() + autCypress.on('after:screenshot', onAfterScreenshot) + }, + }) + .then(({ autCypress }) => { + expect(autCypress.automation.withArgs('take:screenshot')).callCount(4) + expect(autCypress.automation.withArgs('take:screenshot').args).matchDeep([ + { 1: { testAttemptIndex: 0 } }, + { 1: { testAttemptIndex: 0 } }, + { 1: { testAttemptIndex: 1 } }, + { 1: { testAttemptIndex: 1 } }, + ]) + + expect(onAfterScreenshot.args[0][0]).matchDeep({ testAttemptIndex: 0 }) + expect(onAfterScreenshot.args[2][0]).matchDeep({ testAttemptIndex: 1 }) + }) + }) + }) + + describe('save/reload state', () => { + const serializeState = () => { + return getRunState(getAutCypress()) + } + + const loadStateFromSnapshot = (cypressConfig, name) => { + cy.task('getSnapshot', { + file: Cypress.spec.name, + exactSpecName: name, + }) + .then((state) => { + cypressConfig[1].state = state + }) + } + + // NOTE: for test-retries + describe('retries rehydrate spec state after navigation', () => { + let realState + + let runCount = 0 + const failThenSerialize = () => { + if (!runCount++) { + assert(false, 'stub 3 fail') + } + + assert(true, 'stub 3 pass') + + return realState = serializeState() + } + + let runCount2 = 0 + const failOnce = () => { + if (!runCount2++) { + assert(false, 'stub 2 fail') + } + + assert(true, 'stub 2 pass') + } + + const stub1 = sinon.stub() + const stub2 = sinon.stub().callsFake(failOnce) + const stub3 = sinon.stub().callsFake(failThenSerialize) + + let cypressConfig = [ + { + suites: { + 'suite 1': { + hooks: [ + 'before', + 'beforeEach', + 'afterEach', + 'after', + ], + tests: [{ name: 'test 1', fn: stub1 }], + }, + 'suite 2': { + tests: [ + { name: 'test 1', fn: stub2 }, + { name: 'test 2', fn: stub3 }, + 'test 3', + ], + }, + }, + }, { config: { retries: 1 } }, + ] + + it('1/2', () => { + runIsolatedCypress(...cypressConfig) + .then(shouldHaveTestResults(4, 0)) + .then(() => { + expect(realState).to.matchSnapshot(cleanseRunStateMap, 'serialize state - retries') + }) + }) + + it('2/2', () => { + loadStateFromSnapshot(cypressConfig, 'serialize state - retries') + runIsolatedCypress(...cypressConfig) + .then(shouldHaveTestResults(4, 0)) + .then(() => { + expect(stub1).to.calledOnce + expect(stub2).to.calledTwice + expect(stub3).calledThrice + }) + }) + }) + }) +}) diff --git a/packages/runner/cypress/integration/retries.ui.spec.js b/packages/runner/cypress/integration/retries.ui.spec.js new file mode 100644 index 000000000000..e373a5a972f2 --- /dev/null +++ b/packages/runner/cypress/integration/retries.ui.spec.js @@ -0,0 +1,491 @@ +const helpers = require('../support/helpers') + +const { shouldHaveTestResults, containText } = helpers +const { runIsolatedCypress } = helpers.createCypress({ config: { retries: 2 } }) + +const getAttemptTag = (sel) => { + return cy.get(`.test.runnable:contains(${sel}) .attempt-tag`) +} + +const shouldBeOpen = ($el) => cy.wrap($el).parentsUntil('.collapsible').last().parent().should('have.class', 'is-open') + +const attemptTag = (sel) => `.attempt-tag:contains(Attempt ${sel})` +const cyReject = (fn) => { + return () => { + try { + fn() + } catch (e) { + cy.state('reject')(e) + } + } +} + +describe('runner/cypress retries.ui.spec', { viewportWidth: 600, viewportHeight: 900 }, () => { + it('collapses tests that retry and pass', () => { + runIsolatedCypress({ + suites: { + 'suite 1': { + tests: [ + { name: 'test pass', fail: 0 }, + { name: 'test pass on 2nd attempt', fail: 1 }, + ], + }, + }, + }) + .then(shouldHaveTestResults(2, 0)) + + cy.percySnapshot() + }) + + it('collapses prev attempts and keeps final one open on failure', () => { + runIsolatedCypress({ + suites: { + 'suite 1': { + tests: [ + { name: 'test 1', + fail: true, + }, + { name: 'test 2', + + }, + ], + }, + }, + }, { config: { retries: 2 } }) + .then(shouldHaveTestResults(1, 1)) + + cy.percySnapshot() + }) + + it('can toggle failed prev attempt open and log its error', () => { + runIsolatedCypress({ + suites: { + 'suite 1': { + tests: [ + { name: 'test 1', fail: 1 }, + { name: 'test 2', fail: 2 }, + { name: 'test 3', fail: 1 }, + ], + }, + }, + }, { config: { retries: 1 } }) + .then(shouldHaveTestResults(2, 1)) + .then(() => { + cy.contains('Attempt 1') + .click() + .closest('.attempt-item') + .find('.runnable-err-print') + .click() + + cy.get('@console_error').should('be.calledWithMatch', 'AssertionError: test 2') + }) + + cy.percySnapshot() + }) + + it('opens attempt on each attempt failure for the screenshot, and closes after test passes', { retries: 2 }, () => { + let stub + + runIsolatedCypress( + { + suites: { + 's1': { + tests: [ + 't1', + { + name: 't2', + fail: 3, + }, + 't3', + ], + }, + }, + }, { config: { retries: 3, isTextTerminal: true }, + onBeforeRun ({ autCypress }) { + let attempt = 0 + + stub = cy.stub().callsFake(cyReject(() => { + attempt++ + + const $attemptCollapsible = cy.$$(attemptTag(attempt)) + .parentsUntil('.collapsible').last().parent() + + expect($attemptCollapsible).have.class('is-open') + })) + + autCypress.Screenshot.onAfterScreenshot = stub + }, + }, + ).then(() => { + expect(stub).callCount(3) + cy.get('.test.runnable:contains(t2)').then(($el) => { + expect($el).not.class('is-open') + }) + }) + }) + + it('includes routes, spies, hooks, and commands in attempt', () => { + runIsolatedCypress({ + suites: { + 's1': { + hooks: [{ type: 'beforeEach', fail: 1, agents: true }], + tests: [{ name: 't1', fail: 1, agents: true }], + }, + }, + }) + .then(shouldHaveTestResults(1, 0)) + .then(() => { + cy.get(attemptTag(1)).click().parentsUntil('.collapsible').last().parent().within(() => { + cy.get('.instruments-container').should('contain', 'Spies / Stubs (1)') + cy.get('.instruments-container').should('contain', 'Routes (1)') + cy.get('.runnable-err').should('contain', 'AssertionError') + }) + + cy.get(attemptTag(2)).click().parentsUntil('.collapsible').last().parent().within(() => { + cy.get('.instruments-container').should('contain', 'Spies / Stubs (2)') + cy.get('.instruments-container').should('contain', 'Routes (2)') + cy.get('.runnable-err').should('contain', 'AssertionError') + }) + + cy.get(attemptTag(3)).parentsUntil('.collapsible').last().parent().within(() => { + cy.get('.instruments-container').should('contain', 'Spies / Stubs (2)') + cy.get('.instruments-container').should('contain', 'Routes (2)') + cy.get('.runnable-err').should('not.contain', 'AssertionError') + }) + }) + + cy.percySnapshot() + }) + + describe('only', () => { + it('test retry with [only]', () => { + runIsolatedCypress({ + suites: { + 'suite 1': { + hooks: ['before', 'beforeEach', 'afterEach', 'after'], + tests: [ + { name: 'test 1' }, + { name: 'test 2', fail: 1, only: true }, + { name: 'test 3' }, + ], + }, + }, + }, { config: { retries: 1 } }) + .then(shouldHaveTestResults(1, 0)) + .then(() => { + cy.contains('test 2') + cy.contains('test 1').should('not.exist') + cy.contains('test 3').should('not.exist') + }) + + cy.percySnapshot() + }) + }) + + describe('beforeAll', () => { + // TODO: make beforeAll hooks retry + it('tests do not retry when beforeAll fails', () => { + runIsolatedCypress({ + suites: { + 'suite 1': { + hooks: [ + { type: 'before', fail: 1 }, + 'beforeEach', + 'beforeEach', + 'afterEach', + 'afterEach', + 'after', + ], + tests: ['test 1'], + }, + }, + }, { config: { retries: 1 } }) + .then(shouldHaveTestResults(0, 1)) + .then(() => { + cy.contains('Although you have test retries') + }) + + cy.percySnapshot() + }) + + // TODO: future versions should run all hooks associated with test on retry + it('before all hooks are not run on the second attempt when fails outside of beforeAll', () => { + runIsolatedCypress({ + suites: { + 'suite 1': { + hooks: ['before', 'beforeEach', 'afterEach', 'after'], + tests: [{ name: 'test 1', fail: 1 }], + }, + }, + }, { config: { retries: 1 } }) + .then(shouldHaveTestResults(1, 0)) + .then(() => { + cy.contains('test') + cy.contains('after all') + cy.contains('before all').should('not.exist') + }) + + cy.percySnapshot() + }) + }) + + describe('beforeEach', () => { + it('beforeEach hooks retry on failure, but only run same-level afterEach hooks', () => { + runIsolatedCypress({ + hooks: [{ type: 'beforeEach', fail: 1 }], + suites: { + 'suite 1': { + hooks: [ + 'before', + 'beforeEach', + { type: 'beforeEach', fail: 1 }, + 'beforeEach', + 'afterEach', + 'after', + ], + tests: [{ name: 'test 1' }], + }, + }, + }, { config: { retries: 2 } }) + .then(shouldHaveTestResults(1, 0)) + .then(() => { + cy.contains('Attempt 1').click() + cy.get('.attempt-1 .hook-item .collapsible:contains(before each)').find('.command-state-failed') + cy.get('.attempt-1 .hook-item .collapsible:contains(before each (2))').should('not.exist') + cy.get('.attempt-1 .hook-item .collapsible:contains(test body)').should('not.exist') + cy.get('.attempt-1 .hook-item .collapsible:contains(after each)').should('not.exist') + cy.get('.attempt-1 .hook-item .collapsible:contains(after all)').should('not.exist') + + cy.contains('Attempt 2').click() + cy.get('.attempt-2 .hook-item .collapsible:contains(before each)') + cy.get('.attempt-2 .hook-item .collapsible:contains(before each (2))') + cy.get('.attempt-2 .hook-item .collapsible:contains(before each (3))').find('.command-state-failed') + cy.get('.attempt-2 .hook-item .collapsible:contains(test body)').should('not.exist') + cy.get('.attempt-2 .hook-item .collapsible:contains(after each)') + cy.get('.attempt-2 .hook-item .collapsible:contains(after all)').should('not.exist') + + cy.get('.attempt-3 .hook-item .collapsible:contains(before each)') + cy.get('.attempt-3 .hook-item .collapsible:contains(before each (2))') + cy.get('.attempt-3 .hook-item .collapsible:contains(before each (3))') + cy.get('.attempt-3 .hook-item .collapsible:contains(before each (4))') + cy.get('.attempt-3 .hook-item .collapsible:contains(test body)') + cy.get('.attempt-3 .hook-item .collapsible:contains(after each)') + cy.get('.attempt-3 .hook-item .collapsible:contains(after all)') + }) + + cy.percySnapshot() + }) + + it('beforeEach retried tests skip remaining tests in suite', () => { + runIsolatedCypress({ suites: { + 'beforeEach hooks': { + hooks: [{ type: 'beforeEach', fail: true }], + tests: ['fails in beforeEach', 'skips this'], + }, + + } }, { config: { retries: 1 } }) + .then(shouldHaveTestResults(0, 1, 0)) + + cy.percySnapshot() + }) + }) + + describe('afterEach', () => { + it('afterEach hooks retry on failure, but only run higher-level afterEach hooks', () => { + runIsolatedCypress({ + hooks: [{ type: 'afterEach', fail: 2 }], + suites: { + 's1': { + hooks: [{ type: 'afterEach', fail: 1 }, 'afterEach', 'after'], + tests: ['t1'], + }, + + }, + }, { config: { retries: 2 } }) + .then(shouldHaveTestResults(1, 0)) + .then(() => { + cy.contains('Attempt 1') + .click() + .then(shouldBeOpen) + + cy.get('.attempt-1 .hook-item .collapsible:contains(after each (1))').find('.command-state-failed') + cy.get('.attempt-1 .hook-item .collapsible:contains(after each (2))') + cy.get('.attempt-1 .hook-item .collapsible:contains(after each (3))').should('not.exist') + cy.get('.attempt-1 .hook-item .collapsible:contains(after all)').should('not.exist') + + cy.contains('Attempt 2').click() + .then(shouldBeOpen) + + cy.get('.attempt-2 .hook-item .collapsible:contains(after each (1))') + cy.get('.attempt-2 .hook-item .collapsible:contains(after each (2))') + cy.get('.attempt-2 .hook-item .collapsible:contains(after each (3))').find('.command-state-failed') + cy.get('.attempt-2 .hook-item .collapsible:contains(after all)').should('not.exist') + + cy.get('.attempt-tag').should('have.length', 3) + cy.get('.attempt-2 .hook-item .collapsible:contains(after each (1))') + cy.get('.attempt-2 .hook-item .collapsible:contains(after each (2))') + cy.get('.attempt-2 .hook-item .collapsible:contains(after each (3))') + cy.get('.attempt-3 .hook-item .collapsible:contains(after all)') + }) + + cy.percySnapshot() + }) + + it('afterEach retried tests skip remaining tests in suite', () => { + runIsolatedCypress({ suites: { + 'afterEach hooks': { + hooks: [{ type: 'afterEach', fail: true }], + tests: ['fails in afterEach', 'skips this'], + }, + + } }, { config: { retries: 1 } }) + .then(shouldHaveTestResults(0, 1, 0)) + + cy.percySnapshot() + }) + }) + + describe('afterAll', () => { + it('only run afterAll hook on last attempt', () => { + runIsolatedCypress({ + suites: { + 'suite 1': { + hooks: [ + 'before', + 'beforeEach', + 'afterEach', + 'after', + ], + tests: [ + { name: 'test 1' }, + { name: 'test 2' }, + { name: 'test 3', fail: 1 }, + ], + }, + }, + }, { config: { retries: 1 } }) + .then(shouldHaveTestResults(3, 0)) + .then(() => { + cy.contains('test 3').click() + getAttemptTag('test 3').first().click() + cy.contains('.attempt-1', 'after all').should('not.exist') + cy.contains('.attempt-2', 'after all') + }) + }) + + it('tests do not retry when afterAll fails', () => { + runIsolatedCypress({ + suites: { + 'suite 1': { + hooks: [ + 'before', + 'beforeEach', + 'beforeEach', + 'afterEach', + 'afterEach', + { type: 'after', fail: 1 }, + ], + tests: [{ name: 'test 1' }], + }, + }, + }, { config: { retries: 1 } }) + .then(shouldHaveTestResults(0, 1)) + .then(() => { + cy.contains('Although you have test retries') + cy.get('.runnable-err-print').click() + cy.get('@console_error').its('lastCall').should('be.calledWithMatch', 'Error') + }) + + cy.percySnapshot() + }) + }) + + describe('can configure retries', () => { + const haveCorrectError = ($el) => cy.wrap($el).last().parentsUntil('.collapsible').last().parent().find('.runnable-err').should('contain', 'Unspecified AssertionError') + + it('via config value', () => { + runIsolatedCypress({ + suites: { + 'suite 1': () => { + it('[no retry]', { retries: 0 }, () => assert(false)) + it('[1 retry]', { retries: 1 }, () => assert(false)) + it('[2 retries]', { retries: 2 }, () => assert(false)) + it('[open mode, no retry]', { retries: { runMode: 2, openMode: 0 } }, () => assert(false)) + it('[run mode, retry]', { retries: { runMode: 1, openMode: 0 }, isInteractive: false }, () => assert(false)) + it('[open mode, 2 retries]', { isInteractive: true }, () => assert(false)) + describe('suite 2', { retries: 1 }, () => { + it('[set retries on suite]', () => assert(false)) + }) + }, + }, + }) + .then(shouldHaveTestResults(0, 7)) + .then(() => { + getAttemptTag('[no retry]').should('have.length', 1).then(haveCorrectError) + getAttemptTag('[1 retry]').should('have.length', 2).then(haveCorrectError) + getAttemptTag('[2 retries]').should('have.length', 3).then(haveCorrectError) + getAttemptTag('[open mode, no retry]').should('have.length', 1).then(haveCorrectError) + getAttemptTag('[run mode, retry]').should('have.length', 2).then(haveCorrectError) + getAttemptTag('[open mode, 2 retries]').should('have.length', 3).then(haveCorrectError) + getAttemptTag('[set retries on suite]').should('have.length', 2).then(haveCorrectError) + }) + }) + + it('throws when set via this.retries in test', () => { + runIsolatedCypress({ + suites: { + 'suite 1' () { + it('tries to set mocha retries', function () { + this.retries(null) + }) + }, + }, + }) + .then(shouldHaveTestResults(0, 1)) + .then(() => { + cy.get('.runnable-err').should(containText(`it('tries to set mocha retries', { retries: 2 }, () => `)) + }) + + cy.percySnapshot() + }) + + it('throws when set via this.retries in hook', () => { + runIsolatedCypress({ + suites: { + 'suite 1' () { + beforeEach(function () { + this.retries(0) + }) + + it('foo', () => {}) + }, + }, + }) + .then(shouldHaveTestResults(0, 1)) + .then(() => { + cy.get('.runnable-err').should(containText(`describe('suite 1', { retries: 0 }, () => `)) + }) + + cy.percySnapshot() + }) + + it('throws when set via this.retries in suite', () => { + runIsolatedCypress({ + suites: { + 'suite 1' () { + this.retries(3) + it('test 1', () => { + }) + }, + }, + }) + .then(shouldHaveTestResults(0, 1)) + .then(() => { + cy.get('.runnable-err') + .should(containText(`describe('suite 1', { retries: 3 }, () => `)) + }) + + cy.percySnapshot() + }) + }) +}) diff --git a/packages/runner/cypress/integration/runner.mochaEvents.spec.js b/packages/runner/cypress/integration/runner.mochaEvents.spec.js index a55892fba141..6987ecc7cbd4 100644 --- a/packages/runner/cypress/integration/runner.mochaEvents.spec.js +++ b/packages/runner/cypress/integration/runner.mochaEvents.spec.js @@ -3,7 +3,7 @@ const sinon = require('sinon') const helpers = require('../support/helpers') const { cleanseRunStateMap, shouldHaveTestResults, getRunState } = helpers -const { runIsolatedCypress, snapshotMochaEvents, onInitialized, getAutCypress } = helpers.createCypress() +const { runIsolatedCypress, snapshotMochaEvents, getAutCypress } = helpers.createCypress({ config: { isTextTerminal: true, retries: 0 } }) const simpleSingleTest = { suites: { 'suite 1': { tests: [{ name: 'test 1' }] } }, @@ -239,17 +239,24 @@ describe('src/cypress/runner', () => { }) }) - describe('screenshots', () => { - let onAfterScreenshotListener - - beforeEach(() => { - onInitialized((autCypress) => { - autCypress.Screenshot.onAfterScreenshot = cy.stub() - onAfterScreenshotListener = cy.stub() - autCypress.on('after:screenshot', onAfterScreenshotListener) - }) + it('buffer mocha pass event when fail in afterEach hooks', () => { + runIsolatedCypress({ + suites: { + 'suite 1': { + suites: { + 'suite 1-1': { + hooks: [{ type: 'afterEach', fail: true }], + tests: ['test 1'], + }, + }, + }, + }, + }).then(({ mochaStubs }) => { + expect(_.find(mochaStubs.args, { 1: 'pass' })).not.exist }) + }) + describe('screenshots', () => { it('screenshot after failed test', () => { runIsolatedCypress({ suites: { diff --git a/packages/runner/cypress/integration/runner.ui.spec.js b/packages/runner/cypress/integration/runner.ui.spec.js index ba63c81f9f1f..66bd90d01a95 100644 --- a/packages/runner/cypress/integration/runner.ui.spec.js +++ b/packages/runner/cypress/integration/runner.ui.spec.js @@ -147,6 +147,31 @@ describe('src/cypress/runner', () => { describe('hook failures', () => { describe('test failures w/ hooks', () => { + it('test [only]', () => { + runIsolatedCypress({ + suites: { + 'suite 1': { + hooks: ['before', 'beforeEach', 'afterEach', 'after'], + tests: [ + { name: 'test 1' }, + { name: 'test 2', only: true }, + { name: 'test 3' }, + ], + }, + }, + }).then(shouldHaveTestResults(1, 0)) + }) + + it('test [pending]', () => { + runIsolatedCypress(() => { + before(() => {}) + it('t1') + it('t2') + it('t3') + after(() => {}) + }).then(shouldHaveTestResults(0, 0, 3)) + }) + it('fail with [before]', () => { runIsolatedCypress({ suites: { @@ -263,5 +288,31 @@ describe('src/cypress/runner', () => { }) .then(shouldHaveTestResults(0, 1)) }) + + it('scrolls each command into view', () => { + // HACK to assert on the dom DURING the runIsolatedCypress run + // we expect the last command item to be scrolled into view before + // the test ends + cy.now('get', '.command-number:contains(25)') + .then(($el) => { + return new Promise((resolve) => { + requestAnimationFrame(() => { + expect($el).visible + resolve() + }) + }) + }) + .catch((e) => cy.state('reject')(e)) + + runIsolatedCypress(() => { + describe('s1', () => { + // eslint-disable-next-line + it('t1', (done) => { + cy.timeout(10) + Cypress._.times(25, () => expect(true).ok) + }) + }) + }) + }) }) }) diff --git a/packages/runner/cypress/plugins/index.js b/packages/runner/cypress/plugins/index.js index e5158967e1ca..4e3fd18039e6 100644 --- a/packages/runner/cypress/plugins/index.js +++ b/packages/runner/cypress/plugins/index.js @@ -1,11 +1,14 @@ // static file server that serves fixtures needed for testing require('@packages/driver/cypress/plugins/server') const { getSnapshot, saveSnapshot } = require('./snapshot/snapshotPlugin') +const percyHealthCheck = require('@percy/cypress/task') /** * @type {Cypress.PluginConfig} */ module.exports = (on) => { + on('task', percyHealthCheck) + on('task', { getSnapshot, saveSnapshot, diff --git a/packages/runner/cypress/plugins/snapshot/snapshotCommand.js b/packages/runner/cypress/plugins/snapshot/snapshotCommand.js index 4e021a871bb7..1a460ecb2cef 100644 --- a/packages/runner/cypress/plugins/snapshot/snapshotCommand.js +++ b/packages/runner/cypress/plugins/snapshot/snapshotCommand.js @@ -21,7 +21,7 @@ function throwErr (e, message, exp, ctx) { } } -function getMatchDeepMessage ({ act, exp }) { +function getMatchDeepMessage (act, exp) { return `Expected **${chai.util.objDisplay(act)}** to deep match: **${chai.util.objDisplay(exp)}**` } diff --git a/packages/runner/cypress/support/helpers.js b/packages/runner/cypress/support/helpers.js index 5ecabd962046..dba886e316fe 100644 --- a/packages/runner/cypress/support/helpers.js +++ b/packages/runner/cypress/support/helpers.js @@ -37,6 +37,18 @@ const mochaEventCleanseMap = { end: match.date, } +const cleanseRunStateMap = { + ...eventCleanseMap, + 'err.stack': '[err stack]', + wallClockStartedAt: new Date(0), + wallClockDuration: 1, + fnDuration: 1, + afterFnDuration: 1, + lifecycle: 1, + duration: 1, + startTime: new Date(0), +} + const spyOn = (obj, prop, fn) => { const _fn = obj[prop] @@ -49,7 +61,7 @@ const spyOn = (obj, prop, fn) => { } } -function createCypress () { +function createCypress (defaultOptions = {}) { /** * @type {sinon.SinonStub} */ @@ -84,19 +96,13 @@ function createCypress () { window.Cypress = backupCypress }) - let onInitializedListeners = [] - - const onInitialized = function (fn) { - onInitializedListeners.push(fn) - } - /** * Spawns an isolated Cypress runner as the AUT, with provided spec/fixture and optional state/config * @param {string | ()=>void | {[key:string]: any}} mochaTestsOrFile * @param {{state?: any, config?: any}} opts */ const runIsolatedCypress = (mochaTestsOrFile, opts = {}) => { - _.defaultsDeep(opts, { + _.defaultsDeep(opts, defaultOptions, { state: {}, config: { video: false }, onBeforeRun () {}, @@ -106,9 +112,9 @@ function createCypress () { .then({ timeout: 60000 }, (win) => { win.runnerWs.destroy() - allStubs = cy.stub().snapshot(enableStubSnapshots) - mochaStubs = cy.stub().snapshot(enableStubSnapshots) - setRunnablesStub = cy.stub().snapshot(enableStubSnapshots) + allStubs = cy.stub().snapshot(enableStubSnapshots).log(false) + mochaStubs = cy.stub().snapshot(enableStubSnapshots).log(false) + setRunnablesStub = cy.stub().snapshot(enableStubSnapshots).log(false) return new Promise((resolve) => { const runIsolatedCypress = () => { @@ -118,7 +124,7 @@ function createCypress () { const emitMap = autCypress.emitMap const emitThen = autCypress.emitThen - cy.stub(autCypress, 'automation').snapshot(enableStubSnapshots) + cy.stub(autCypress, 'automation').log(false).snapshot(enableStubSnapshots) .callThrough() .withArgs('clear:cookies') .resolves({ @@ -177,7 +183,9 @@ function createCypress () { spyOn(autCypress.mocha.getRunner(), 'fail', (...args) => { Cypress.log({ - name: 'Runner Fail', + name: 'Runner (fail event)', + ended: true, + event: true, message: `${args[1]}`, state: 'failed', consoleProps: () => { @@ -191,28 +199,26 @@ function createCypress () { // TODO: clean this up, sinon doesn't like wrapping things multiple times // and this catches that error try { - cy.spy(cy.state('window').console, 'log').as('console_log') - cy.spy(cy.state('window').console, 'error').as('console_error') + cy.spy(cy.state('window').console, 'log').as('console_log').log(false) + cy.spy(cy.state('window').console, 'error').as('console_error').log(false) } catch (_e) { // console was already wrapped, noop } - onInitializedListeners.forEach((fn) => fn(autCypress)) - onInitializedListeners = [] autCypress.run((failed) => { resolve({ failed, mochaStubs, autCypress, win }) }) } - cy.spy(win.eventManager.reporterBus, 'emit').snapshot(enableStubSnapshots).as('reporterBus') - cy.spy(win.eventManager.localBus, 'emit').snapshot(enableStubSnapshots).as('localBus') + cy.spy(win.eventManager.reporterBus, 'emit').snapshot(enableStubSnapshots).log(false).as('reporterBus') + cy.spy(win.eventManager.localBus, 'emit').snapshot(enableStubSnapshots).log(false).as('localBus') - cy.stub(win.runnerWs, 'emit').snapshot(enableStubSnapshots) + cy.stub(win.runnerWs, 'emit').snapshot(enableStubSnapshots).log(false) .withArgs('watch:test:file') .callsFake(() => { autCypress = win.Cypress - cy.stub(autCypress, 'onSpecWindow').snapshot(enableStubSnapshots).callsFake((specWindow) => { + cy.stub(autCypress, 'onSpecWindow').snapshot(enableStubSnapshots).log(false).callsFake((specWindow) => { autCypress.onSpecWindow.restore() opts.onBeforeRun({ specWindow, win, autCypress }) @@ -238,7 +244,7 @@ function createCypress () { specWindow.describe = () => {} }) - cy.stub(autCypress, 'run').snapshot(enableStubSnapshots).callsFake(runIsolatedCypress) + cy.stub(autCypress, 'run').snapshot(enableStubSnapshots).log(false).callsFake(runIsolatedCypress) }) .withArgs('is:automation:client:connected') .yieldsAsync(true) @@ -271,16 +277,17 @@ function createCypress () { .yieldsAsync({ response: {} }) const c = _.extend({}, Cypress.config(), { - isTextTerminal: true, + isTextTerminal: false, spec: { relative: 'relative/path/to/spec.js', absolute: '/absolute/path/to/spec.js', + name: 'empty_spec.js', }, }, opts.config) c.state = {} - cy.stub(win.runnerWs, 'on').snapshot(enableStubSnapshots) + cy.stub(win.runnerWs, 'on').snapshot(enableStubSnapshots).log(false) win.Runner.start(win.document.getElementById('app'), window.btoa(JSON.stringify(c))) }) @@ -290,7 +297,6 @@ function createCypress () { return { runIsolatedCypress, snapshotMochaEvents, - onInitialized, getAutCypress, } } @@ -301,7 +307,7 @@ const createHooks = (win, hooks = []) => { hook = { type: hook } } - let { type, fail, fn } = hook + let { type, fail, fn, agents } = hook if (fn) { if (hook.eval) { @@ -321,24 +327,34 @@ const createHooks = (win, hooks = []) => { if (fail) { const numFailures = fail - return win[type](() => { + return win[type](function () { + const message = `${type} - ${this._runnable.parent.title || 'root'}` + + if (agents) { + registerAgents(win) + } + if (_.isNumber(fail) && fail-- <= 0) { debug(`hook pass after (${numFailures}) failures: ${type}`) - win.assert(true, type) + win.assert(true, message) return } - debug(`hook fail: ${type}`) + if (agents) { + failCypressCommand(win, type) + } else { + debug(`hook fail: ${type}`) - win.assert(false, type) + win.assert(false, message) - throw new Error(`hook failed: ${type}`) + throw new Error(`hook failed: ${type}`) + } }) } - return win[type](() => { - win.assert(true, type) + return win[type](function () { + win.assert(true, `${type} - ${this._runnable.parent.title || 'root'}`) debug(`hook pass: ${type}`) }) }) @@ -350,7 +366,7 @@ const createTests = (win, tests = []) => { test = { name: test } } - let { name, pending, fail, fn, only } = test + let { name, pending, fail, fn, only, agents } = test let it = win.it @@ -379,6 +395,10 @@ const createTests = (win, tests = []) => { if (fail) { return it(name, () => { + if (agents) { + registerAgents(win) + } + if (_.isNumber(fail) && fail-- === 0) { debug(`test pass after retry: ${name}`) win.assert(true, name) @@ -386,10 +406,14 @@ const createTests = (win, tests = []) => { return } - debug(`test fail: ${name}`) - win.assert(false, name) + if (agents) { + failCypressCommand(win, name) + } else { + debug(`test fail: ${name}`) + win.assert(false, name) - throw new Error(`test fail: ${name}`) + throw new Error(`test fail: ${name}`) + } }) } @@ -400,6 +424,16 @@ const createTests = (win, tests = []) => { }) } +const failCypressCommand = (win, name) => win.cy.wrap(name).then(() => win.assert(false, name)) +const registerAgents = (win) => { + const obj = { foo: 'bar' } + + win.cy.stub(obj, 'foo') + win.cy.wrap(obj).should('exist') + win.cy.server() + win.cy.route('https://example.com') +} + const createSuites = (win, suites = {}) => { _.each(suites, (obj, suiteName) => { let fn = () => { @@ -434,27 +468,13 @@ const evalFn = (win, fn) => { } } -const cleanseRunStateMap = { - wallClockStartedAt: new Date(0), - wallClockDuration: 1, - fnDuration: 1, - afterFnDuration: 1, - lifecycle: 1, - duration: 1, - startTime: new Date(0), - 'err.stack': '[err stack]', - sourceMappedStack: match.string, - parsedStack: match.array, - invocationDetails: stringifyShort, -} - -const shouldHaveTestResults = (expPassed, expFailed) => { - return ({ failed }) => { - expect(failed, 'resolve with failure count').eq(failed) +const shouldHaveTestResults = (expPassed, expFailed, expPending) => { + return () => { expPassed = expPassed || '--' expFailed = expFailed || '--' cy.get('header .passed .num').should('have.text', `${expPassed}`) cy.get('header .failed .num').should('have.text', `${expFailed}`) + if (expPending) cy.get('header .pending .num').should('have.text', `${expPending}`) } } diff --git a/packages/runner/cypress/support/index.js b/packages/runner/cypress/support/index.js index e69de29bb2d1..565e08fd47c7 100644 --- a/packages/runner/cypress/support/index.js +++ b/packages/runner/cypress/support/index.js @@ -0,0 +1 @@ +require('@packages/ui-components/cypress/support/customPercyCommand') diff --git a/packages/server/__snapshots__/1_blacklist_hosts_spec.js b/packages/server/__snapshots__/1_block_hosts_spec.js similarity index 83% rename from packages/server/__snapshots__/1_blacklist_hosts_spec.js rename to packages/server/__snapshots__/1_block_hosts_spec.js index ddc788d39721..e96f050822b3 100644 --- a/packages/server/__snapshots__/1_blacklist_hosts_spec.js +++ b/packages/server/__snapshots__/1_block_hosts_spec.js @@ -1,4 +1,4 @@ -exports['e2e blacklist passes 1'] = ` +exports['e2e blockHosts passes 1'] = ` ==================================================================================================== @@ -7,18 +7,18 @@ exports['e2e blacklist passes 1'] = ` โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ Cypress: 1.2.3 โ”‚ โ”‚ Browser: FooBrowser 88 โ”‚ - โ”‚ Specs: 1 found (blacklist_hosts_spec.coffee) โ”‚ - โ”‚ Searched: cypress/integration/blacklist_hosts_spec.coffee โ”‚ + โ”‚ Specs: 1 found (block_hosts_spec.coffee) โ”‚ + โ”‚ Searched: cypress/integration/block_hosts_spec.coffee โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - Running: blacklist_hosts_spec.coffee (1 of 1) + Running: block_hosts_spec.coffee (1 of 1) - blacklist - โœ“ forces blacklisted hosts to return 503 + block hosts + โœ“ forces blocked hosts to return 503 1 passing @@ -33,18 +33,12 @@ exports['e2e blacklist passes 1'] = ` โ”‚ Pending: 0 โ”‚ โ”‚ Skipped: 0 โ”‚ โ”‚ Screenshots: 0 โ”‚ - โ”‚ Video: true โ”‚ + โ”‚ Video: false โ”‚ โ”‚ Duration: X seconds โ”‚ - โ”‚ Spec Ran: blacklist_hosts_spec.coffee โ”‚ + โ”‚ Spec Ran: block_hosts_spec.coffee โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ - (Video) - - - Started processing: Compressing to 32 CRF - - Finished processing: /XXX/XXX/XXX/cypress/videos/blacklist_hosts_spec.coffee.mp4 (X second) - - ==================================================================================================== (Run Finished) @@ -52,7 +46,7 @@ exports['e2e blacklist passes 1'] = ` Spec Tests Passing Failing Pending Skipped โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” - โ”‚ โœ” blacklist_hosts_spec.coffee XX:XX 1 1 - - - โ”‚ + โ”‚ โœ” block_hosts_spec.coffee XX:XX 1 1 - - - โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โœ” All specs passed! XX:XX 1 1 - - - diff --git a/packages/server/__snapshots__/1_busted_support_file_spec.js b/packages/server/__snapshots__/1_busted_support_file_spec.js index 5e07b4965537..13f96bdac038 100644 --- a/packages/server/__snapshots__/1_busted_support_file_spec.js +++ b/packages/server/__snapshots__/1_busted_support_file_spec.js @@ -21,7 +21,18 @@ Oops...we found an error preparing this test file: The error was: -Error: Cannot find module './does/not/exist' from '/foo/bar/.projects/busted-support-file/cypress/support' +Error: Webpack Compilation Error +./cypress/support/index.js +Module not found: Error: Can't resolve './does/not/exist' in '/foo/bar/.projects/busted-support-file/cypress/support' +Looked for and couldn't find the file at the following paths: +[/foo/bar/.projects/busted-support-file/cypress/support/does/not/exist] +[/foo/bar/.projects/busted-support-file/cypress/support/does/not/exist.js] +[/foo/bar/.projects/busted-support-file/cypress/support/does/not/exist.json] +[/foo/bar/.projects/busted-support-file/cypress/support/does/not/exist.jsx] +[/foo/bar/.projects/busted-support-file/cypress/support/does/not/exist.coffee] +[/foo/bar/.projects/busted-support-file/cypress/support/does/not/exist.ts] +[/foo/bar/.projects/busted-support-file/cypress/support/does/not/exist.tsx] + @ ./cypress/support/index.js 3:0-27 This occurred while Cypress was compiling and bundling your test code. This is usually caused by: diff --git a/packages/server/__snapshots__/1_caught_uncaught_hook_errors_spec.js b/packages/server/__snapshots__/1_caught_uncaught_hook_errors_spec.js index 5c66ddd225a4..797be373f43c 100644 --- a/packages/server/__snapshots__/1_caught_uncaught_hook_errors_spec.js +++ b/packages/server/__snapshots__/1_caught_uncaught_hook_errors_spec.js @@ -1,4 +1,4 @@ -exports['e2e caught and uncaught hooks errors failing1 1'] = ` +exports['e2e caught and uncaught hooks errors / failing1'] = ` ==================================================================================================== @@ -110,7 +110,7 @@ Because this error occurred during a \`before all\` hook we are skipping the rem ` -exports['e2e caught and uncaught hooks errors failing2 1'] = ` +exports['e2e caught and uncaught hooks errors / failing2'] = ` ==================================================================================================== @@ -203,7 +203,7 @@ Because this error occurred during a \`before each\` hook we are skipping the re ` -exports['e2e caught and uncaught hooks errors failing3 1'] = ` +exports['e2e caught and uncaught hooks errors / failing3'] = ` ==================================================================================================== @@ -287,7 +287,7 @@ Because this error occurred during a \`before each\` hook we are skipping all of ` -exports['e2e caught and uncaught hooks errors failing4 1'] = ` +exports['e2e caught and uncaught hooks errors / failing4'] = ` ==================================================================================================== diff --git a/packages/server/__snapshots__/1_browserify_babel_es201_spec.js b/packages/server/__snapshots__/1_es_modules_spec.js similarity index 84% rename from packages/server/__snapshots__/1_browserify_babel_es201_spec.js rename to packages/server/__snapshots__/1_es_modules_spec.js index aa760b12e4a9..07b9c4ae4b8a 100644 --- a/packages/server/__snapshots__/1_browserify_babel_es201_spec.js +++ b/packages/server/__snapshots__/1_es_modules_spec.js @@ -1,4 +1,4 @@ -exports['e2e browserify, babel, es2015 passes 1'] = ` +exports['e2e es modules passes 1'] = ` ==================================================================================================== @@ -7,14 +7,14 @@ exports['e2e browserify, babel, es2015 passes 1'] = ` โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ Cypress: 1.2.3 โ”‚ โ”‚ Browser: FooBrowser 88 โ”‚ - โ”‚ Specs: 1 found (browserify_babel_es2015_passing_spec.coffee) โ”‚ - โ”‚ Searched: cypress/integration/browserify_babel_es2015_passing_spec.coffee โ”‚ + โ”‚ Specs: 1 found (es_modules_in_coffee_spec.coffee) โ”‚ + โ”‚ Searched: cypress/integration/es_modules_in_coffee_spec.coffee โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - Running: browserify_babel_es2015_passing_spec.coffee (1 of 1) + Running: es_modules_in_coffee_spec.coffee (1 of 1) imports work @@ -37,15 +37,15 @@ exports['e2e browserify, babel, es2015 passes 1'] = ` โ”‚ Screenshots: 0 โ”‚ โ”‚ Video: true โ”‚ โ”‚ Duration: X seconds โ”‚ - โ”‚ Spec Ran: browserify_babel_es2015_passing_spec.coffee โ”‚ + โ”‚ Spec Ran: es_modules_in_coffee_spec.coffee โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ (Video) - Started processing: Compressing to 32 CRF - - Finished processing: /XXX/XXX/XXX/cypress/videos/browserify_babel_es2015_passing (X second) - _spec.coffee.mp4 + - Finished processing: /XXX/XXX/XXX/cypress/videos/es_modules_in_coffee_spec.coffe (X second) + e.mp4 ==================================================================================================== @@ -55,15 +55,14 @@ exports['e2e browserify, babel, es2015 passes 1'] = ` Spec Tests Passing Failing Pending Skipped โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” - โ”‚ โœ” browserify_babel_es2015_passing_spe XX:XX 3 3 - - - โ”‚ - โ”‚ c.coffee โ”‚ + โ”‚ โœ” es_modules_in_coffee_spec.coffee XX:XX 3 3 - - - โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โœ” All specs passed! XX:XX 3 3 - - - ` -exports['e2e browserify, babel, es2015 fails 1'] = ` +exports['e2e es modules fails 1'] = ` ==================================================================================================== @@ -72,26 +71,31 @@ exports['e2e browserify, babel, es2015 fails 1'] = ` โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ Cypress: 1.2.3 โ”‚ โ”‚ Browser: FooBrowser 88 โ”‚ - โ”‚ Specs: 1 found (browserify_babel_es2015_failing_spec.js) โ”‚ - โ”‚ Searched: cypress/integration/browserify_babel_es2015_failing_spec.js โ”‚ + โ”‚ Specs: 1 found (es_module_import_failing_spec.js) โ”‚ + โ”‚ Searched: cypress/integration/es_module_import_failing_spec.js โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - Running: browserify_babel_es2015_failing_spec.js (1 of 1) + Running: es_module_import_failing_spec.js (1 of 1) Oops...we found an error preparing this test file: - /foo/bar/.projects/e2e/cypress/integration/browserify_babel_es2015_failing_spec.js + /foo/bar/.projects/e2e/cypress/integration/es_module_import_failing_spec.js The error was: +Error: Webpack Compilation Error +./lib/fail.js +Module build failed (from [..]): SyntaxError: /foo/bar/.projects/e2e/lib/fail.js: Unexpected token (2:0) 1 | export default { > 2 | - | ^ while parsing file: /foo/bar/.projects/e2e/lib/fail.js + | ^ + + @ ./cypress/integration/es_module_import_failing_spec.js 3:0-25 This occurred while Cypress was compiling and bundling your test code. This is usually caused by: @@ -111,15 +115,15 @@ Fix the error in your code and re-run your tests. โ”‚ Screenshots: 0 โ”‚ โ”‚ Video: true โ”‚ โ”‚ Duration: X seconds โ”‚ - โ”‚ Spec Ran: browserify_babel_es2015_failing_spec.js โ”‚ + โ”‚ Spec Ran: es_module_import_failing_spec.js โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ (Video) - Started processing: Compressing to 32 CRF - - Finished processing: /XXX/XXX/XXX/cypress/videos/browserify_babel_es2015_failing (X second) - _spec.js.mp4 + - Finished processing: /XXX/XXX/XXX/cypress/videos/es_module_import_failing_spec.j (X second) + s.mp4 ==================================================================================================== @@ -129,8 +133,7 @@ Fix the error in your code and re-run your tests. Spec Tests Passing Failing Pending Skipped โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” - โ”‚ โœ– browserify_babel_es2015_failing_spe XX:XX - - 1 - - โ”‚ - โ”‚ c.js โ”‚ + โ”‚ โœ– es_module_import_failing_spec.js XX:XX - - 1 - - โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โœ– 1 of 1 failed (100%) XX:XX - - 1 - - diff --git a/packages/server/__snapshots__/1_typescript_support_spec.js b/packages/server/__snapshots__/1_typescript_spec_support_spec.ts.js similarity index 88% rename from packages/server/__snapshots__/1_typescript_support_spec.js rename to packages/server/__snapshots__/1_typescript_spec_support_spec.ts.js index fe53ebdc7c7f..330167f09d38 100644 --- a/packages/server/__snapshots__/1_typescript_support_spec.js +++ b/packages/server/__snapshots__/1_typescript_spec_support_spec.ts.js @@ -1,4 +1,4 @@ -exports['e2e typescript spec passes 1'] = ` +exports['e2e typescript in spec and support file spec passes 1'] = ` ==================================================================================================== @@ -7,45 +7,45 @@ exports['e2e typescript spec passes 1'] = ` โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ Cypress: 1.2.3 โ”‚ โ”‚ Browser: FooBrowser 88 โ”‚ - โ”‚ Specs: 1 found (browserify_typescript_passing_spec.ts) โ”‚ - โ”‚ Searched: cypress/integration/browserify_typescript_passing_spec.ts โ”‚ + โ”‚ Specs: 1 found (typescript_passing_spec.ts) โ”‚ + โ”‚ Searched: cypress/integration/typescript_passing_spec.ts โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - Running: browserify_typescript_passing_spec.ts (1 of 1) + Running: typescript_passing_spec.ts (1 of 1) imports work โœ“ foo coffee โœ“ bar babel โœ“ dom jsx + โœ“ issue 7098 - 3 passing + 4 passing (Results) โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” - โ”‚ Tests: 3 โ”‚ - โ”‚ Passing: 3 โ”‚ + โ”‚ Tests: 4 โ”‚ + โ”‚ Passing: 4 โ”‚ โ”‚ Failing: 0 โ”‚ โ”‚ Pending: 0 โ”‚ โ”‚ Skipped: 0 โ”‚ โ”‚ Screenshots: 0 โ”‚ โ”‚ Video: true โ”‚ โ”‚ Duration: X seconds โ”‚ - โ”‚ Spec Ran: browserify_typescript_passing_spec.ts โ”‚ + โ”‚ Spec Ran: typescript_passing_spec.ts โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ (Video) - Started processing: Compressing to 32 CRF - - Finished processing: /XXX/XXX/XXX/cypress/videos/browserify_typescript_passing_s (X second) - pec.ts.mp4 + - Finished processing: /XXX/XXX/XXX/cypress/videos/typescript_passing_spec.ts.mp4 (X second) ==================================================================================================== @@ -55,15 +55,14 @@ exports['e2e typescript spec passes 1'] = ` Spec Tests Passing Failing Pending Skipped โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” - โ”‚ โœ” browserify_typescript_passing_spec. XX:XX 3 3 - - - โ”‚ - โ”‚ ts โ”‚ + โ”‚ โœ” typescript_passing_spec.ts XX:XX 4 4 - - - โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ - โœ” All specs passed! XX:XX 3 3 - - - + โœ” All specs passed! XX:XX 4 4 - - - ` -exports['e2e typescript spec fails 1'] = ` +exports['e2e typescript in spec and support file spec fails with syntax error 1'] = ` ==================================================================================================== @@ -72,25 +71,31 @@ exports['e2e typescript spec fails 1'] = ` โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ Cypress: 1.2.3 โ”‚ โ”‚ Browser: FooBrowser 88 โ”‚ - โ”‚ Specs: 1 found (browserify_typescript_failing_spec.ts) โ”‚ - โ”‚ Searched: cypress/integration/browserify_typescript_failing_spec.ts โ”‚ + โ”‚ Specs: 1 found (typescript_syntax_error_spec.ts) โ”‚ + โ”‚ Searched: cypress/integration/typescript_syntax_error_spec.ts โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - Running: browserify_typescript_failing_spec.ts (1 of 1) + Running: typescript_syntax_error_spec.ts (1 of 1) Oops...we found an error preparing this test file: - /foo/bar/.projects/e2e/cypress/integration/browserify_typescript_failing_spec.ts + /foo/bar/.projects/e2e/cypress/integration/typescript_syntax_error_spec.ts The error was: -/foo/bar/.projects/e2e/cypress/integration/browserify_typescript_failing_spec.ts:3 -describe('fail', - > ); - ^ -ParseError: Unexpected token +Error: Webpack Compilation Error +./cypress/integration/typescript_syntax_error_spec.tsXX:XX +Module parse failed: Unexpected token (4:19) +File was processed with these loaders: + * ../../../../node_modules/@cypress/webpack-batteries-included-preprocessor/node_modules/ts-loader/index.js +You may need an additional loader to handle the result of these loaders. +| // The code below is ignored by eslint +| // because it tests failing spec. +> describe('fail', - > ); +| This occurred while Cypress was compiling and bundling your test code. This is usually caused by: @@ -110,15 +115,15 @@ Fix the error in your code and re-run your tests. โ”‚ Screenshots: 0 โ”‚ โ”‚ Video: true โ”‚ โ”‚ Duration: X seconds โ”‚ - โ”‚ Spec Ran: browserify_typescript_failing_spec.ts โ”‚ + โ”‚ Spec Ran: typescript_syntax_error_spec.ts โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ (Video) - Started processing: Compressing to 32 CRF - - Finished processing: /XXX/XXX/XXX/cypress/videos/browserify_typescript_failing_s (X second) - pec.ts.mp4 + - Finished processing: /XXX/XXX/XXX/cypress/videos/typescript_syntax_error_spec.ts (X second) + .mp4 ==================================================================================================== @@ -128,15 +133,14 @@ Fix the error in your code and re-run your tests. Spec Tests Passing Failing Pending Skipped โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” - โ”‚ โœ– browserify_typescript_failing_spec. XX:XX - - 1 - - โ”‚ - โ”‚ ts โ”‚ + โ”‚ โœ– typescript_syntax_error_spec.ts XX:XX - - 1 - - โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โœ– 1 of 1 failed (100%) XX:XX - - 1 - - ` -exports['e2e typescript project passes 1'] = ` +exports['e2e typescript in spec and support file project passes 1'] = ` ==================================================================================================== diff --git a/packages/server/__snapshots__/1_typescript_support_spec.ts.js b/packages/server/__snapshots__/1_typescript_support_spec.ts.js deleted file mode 100644 index 3363bf4d83ca..000000000000 --- a/packages/server/__snapshots__/1_typescript_support_spec.ts.js +++ /dev/null @@ -1,244 +0,0 @@ -exports['e2e typescript spec passes 1'] = ` - -==================================================================================================== - - (Run Starting) - - โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” - โ”‚ Cypress: 1.2.3 โ”‚ - โ”‚ Browser: FooBrowser 88 โ”‚ - โ”‚ Specs: 1 found (browserify_typescript_passing_spec.ts) โ”‚ - โ”‚ Searched: cypress/integration/browserify_typescript_passing_spec.ts โ”‚ - โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ - - -โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - - Running: browserify_typescript_passing_spec.ts (1 of 1) - - - imports work - โœ“ foo coffee - โœ“ bar babel - โœ“ dom jsx - โœ“ issue 7098 - - - 4 passing - - - (Results) - - โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” - โ”‚ Tests: 4 โ”‚ - โ”‚ Passing: 4 โ”‚ - โ”‚ Failing: 0 โ”‚ - โ”‚ Pending: 0 โ”‚ - โ”‚ Skipped: 0 โ”‚ - โ”‚ Screenshots: 0 โ”‚ - โ”‚ Video: true โ”‚ - โ”‚ Duration: X seconds โ”‚ - โ”‚ Spec Ran: browserify_typescript_passing_spec.ts โ”‚ - โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ - - - (Video) - - - Started processing: Compressing to 32 CRF - - Finished processing: /XXX/XXX/XXX/cypress/videos/browserify_typescript_passing_s (X second) - pec.ts.mp4 - - -==================================================================================================== - - (Run Finished) - - - Spec Tests Passing Failing Pending Skipped - โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” - โ”‚ โœ” browserify_typescript_passing_spec. XX:XX 4 4 - - - โ”‚ - โ”‚ ts โ”‚ - โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ - โœ” All specs passed! XX:XX 4 4 - - - - - -` - -exports['e2e typescript spec fails 1'] = ` - -==================================================================================================== - - (Run Starting) - - โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” - โ”‚ Cypress: 1.2.3 โ”‚ - โ”‚ Browser: FooBrowser 88 โ”‚ - โ”‚ Specs: 1 found (browserify_typescript_failing_spec.ts) โ”‚ - โ”‚ Searched: cypress/integration/browserify_typescript_failing_spec.ts โ”‚ - โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ - - -โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - - Running: browserify_typescript_failing_spec.ts (1 of 1) - -Oops...we found an error preparing this test file: - - /foo/bar/.projects/e2e/cypress/integration/browserify_typescript_failing_spec.ts - -The error was: - -/foo/bar/.projects/e2e/cypress/integration/browserify_typescript_failing_spec.ts:3 -describe('fail', - > ); - ^ -ParseError: Unexpected token - -This occurred while Cypress was compiling and bundling your test code. This is usually caused by: - -- A missing file or dependency -- A syntax error in the file or one of its dependencies - -Fix the error in your code and re-run your tests. - - (Results) - - โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” - โ”‚ Tests: 0 โ”‚ - โ”‚ Passing: 0 โ”‚ - โ”‚ Failing: 1 โ”‚ - โ”‚ Pending: 0 โ”‚ - โ”‚ Skipped: 0 โ”‚ - โ”‚ Screenshots: 0 โ”‚ - โ”‚ Video: true โ”‚ - โ”‚ Duration: X seconds โ”‚ - โ”‚ Spec Ran: browserify_typescript_failing_spec.ts โ”‚ - โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ - - - (Video) - - - Started processing: Compressing to 32 CRF - - Finished processing: /XXX/XXX/XXX/cypress/videos/browserify_typescript_failing_s (X second) - pec.ts.mp4 - - -==================================================================================================== - - (Run Finished) - - - Spec Tests Passing Failing Pending Skipped - โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” - โ”‚ โœ– browserify_typescript_failing_spec. XX:XX - - 1 - - โ”‚ - โ”‚ ts โ”‚ - โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ - โœ– 1 of 1 failed (100%) XX:XX - - 1 - - - - -` - -exports['e2e typescript project passes 1'] = ` - -==================================================================================================== - - (Run Starting) - - โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” - โ”‚ Cypress: 1.2.3 โ”‚ - โ”‚ Browser: FooBrowser 88 โ”‚ - โ”‚ Specs: 2 found (app_spec.ts, math.ts) โ”‚ - โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ - - -โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - - Running: app_spec.ts (1 of 2) - - - โœ“ is true - - 1 passing - - - (Results) - - โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” - โ”‚ Tests: 1 โ”‚ - โ”‚ Passing: 1 โ”‚ - โ”‚ Failing: 0 โ”‚ - โ”‚ Pending: 0 โ”‚ - โ”‚ Skipped: 0 โ”‚ - โ”‚ Screenshots: 0 โ”‚ - โ”‚ Video: true โ”‚ - โ”‚ Duration: X seconds โ”‚ - โ”‚ Spec Ran: app_spec.ts โ”‚ - โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ - - - (Video) - - - Started processing: Compressing to 32 CRF - - Finished processing: /XXX/XXX/XXX/cypress/videos/app_spec.ts.mp4 (X second) - - -โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - - Running: math.ts (2 of 2) - - - 0 passing - - - (Results) - - โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” - โ”‚ Tests: 0 โ”‚ - โ”‚ Passing: 0 โ”‚ - โ”‚ Failing: 0 โ”‚ - โ”‚ Pending: 0 โ”‚ - โ”‚ Skipped: 0 โ”‚ - โ”‚ Screenshots: 0 โ”‚ - โ”‚ Video: true โ”‚ - โ”‚ Duration: X seconds โ”‚ - โ”‚ Spec Ran: math.ts โ”‚ - โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ - - - (Video) - - - Started processing: Compressing to 32 CRF - - Finished processing: /XXX/XXX/XXX/cypress/videos/math.ts.mp4 (X second) - - -==================================================================================================== - - (Run Finished) - - - Spec Tests Passing Failing Pending Skipped - โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” - โ”‚ โœ” app_spec.ts XX:XX 1 1 - - - โ”‚ - โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค - โ”‚ โœ” math.ts XX:XX - - - - - โ”‚ - โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ - โœ” All specs passed! XX:XX 1 1 - - - - - -` - -exports['typescript with tsconfig run'] = ` - (Run Finished) - - - Spec Tests Passing Failing Pending Skipped - โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” - โ”‚ โœ” app_spec.ts XX:XX 1 1 - - - โ”‚ - โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค - โ”‚ โœ” js-spec.js XX:XX 2 2 - - - โ”‚ - โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค - โ”‚ โœ” math.ts XX:XX - - - - - โ”‚ - โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ - โœ” All specs passed! XX:XX 3 3 - - - - - -` diff --git a/packages/server/__snapshots__/2_cookies_spec.js b/packages/server/__snapshots__/2_cookies_spec.ts.js similarity index 95% rename from packages/server/__snapshots__/2_cookies_spec.js rename to packages/server/__snapshots__/2_cookies_spec.ts.js index 39c46f5cdafa..06024ba31b53 100644 --- a/packages/server/__snapshots__/2_cookies_spec.js +++ b/packages/server/__snapshots__/2_cookies_spec.ts.js @@ -5,11 +5,10 @@ exports['e2e cookies with baseurl'] = ` (Run Starting) โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” - โ”‚ Cypress: 1.2.3 โ”‚ - โ”‚ Browser: FooBrowser 88 โ”‚ - โ”‚ Specs: 1 found (cookies_spec_baseurl.coffee) โ”‚ - โ”‚ Searched: cypress/integration/cookies_spec_baseurl.coffee โ”‚ - โ”‚ Experiments: experimentalGetCookiesSameSite=true โ”‚ + โ”‚ Cypress: 1.2.3 โ”‚ + โ”‚ Browser: FooBrowser 88 โ”‚ + โ”‚ Specs: 1 found (cookies_spec_baseurl.coffee) โ”‚ + โ”‚ Searched: cypress/integration/cookies_spec_baseurl.coffee โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ @@ -19,12 +18,12 @@ exports['e2e cookies with baseurl'] = ` cookies - with whitelist + with preserve โœ“ can get all cookies โœ“ resets cookies between tests correctly โœ“ should be only two left now โœ“ handles undefined cookies - without whitelist + without preserve โœ“ sends set cookies to path โœ“ handles expired cookies secure โœ“ issue: #224 sets expired cookies between redirects @@ -123,12 +122,12 @@ exports['e2e cookies with no baseurl'] = ` cookies - with whitelist + with preserve โœ“ can get all cookies โœ“ resets cookies between tests correctly โœ“ should be only two left now โœ“ handles undefined cookies - without whitelist + without preserve โœ“ sends cookies to localhost:2121 โœ“ handles expired cookies secure โœ“ issue: #224 sets expired cookies between redirects diff --git a/packages/server/__snapshots__/3_issue_173_spec.js b/packages/server/__snapshots__/3_issue_173_spec.ts.js similarity index 100% rename from packages/server/__snapshots__/3_issue_173_spec.js rename to packages/server/__snapshots__/3_issue_173_spec.ts.js diff --git a/packages/server/__snapshots__/3_plugins_spec.js b/packages/server/__snapshots__/3_plugins_spec.js index 6f8fd40476fc..ebe43b1b2a64 100644 --- a/packages/server/__snapshots__/3_plugins_spec.js +++ b/packages/server/__snapshots__/3_plugins_spec.js @@ -311,7 +311,7 @@ exports['e2e plugins calls after:screenshot for cy.screenshot() and failure scre โ”‚ Failing: 1 โ”‚ โ”‚ Pending: 0 โ”‚ โ”‚ Skipped: 0 โ”‚ - โ”‚ Screenshots: 4 โ”‚ + โ”‚ Screenshots: 3 โ”‚ โ”‚ Video: true โ”‚ โ”‚ Duration: X seconds โ”‚ โ”‚ Spec Ran: after_screenshot_spec.coffee โ”‚ @@ -323,7 +323,6 @@ exports['e2e plugins calls after:screenshot for cy.screenshot() and failure scre - /XXX/XXX/XXX/screenshot-replacement.png (YxX) - /XXX/XXX/XXX/cypress/screenshots/after_screenshot_spec.coffee/ignored-values.png (YxX) - /XXX/XXX/XXX/cypress/screenshots/after_screenshot_spec.coffee/invalid-return.png (YxX) - - /XXX/XXX/XXX/screenshot-replacement.png (YxX) (Video) @@ -446,3 +445,139 @@ The following are valid events: [stack trace lines] ` + +exports['e2e plugins does not report more screenshots than exist if user overwrites screenshot in afterScreenshot hook 1'] = ` + +==================================================================================================== + + (Run Starting) + + โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” + โ”‚ Cypress: 1.2.3 โ”‚ + โ”‚ Browser: FooBrowser 88 โ”‚ + โ”‚ Specs: 1 found (after_screenshot_overwrite_spec.coffee) โ”‚ + โ”‚ Searched: cypress/integration/after_screenshot_overwrite_spec.coffee โ”‚ + โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ + + +โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + + Running: after_screenshot_overwrite_spec.coffee (1 of 1) + + + โœ“ cy.screenshot() - replacement + โœ“ cy.screenshot() - replacement + โœ“ cy.screenshot() - replacement + + 3 passing + + + (Results) + + โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” + โ”‚ Tests: 3 โ”‚ + โ”‚ Passing: 3 โ”‚ + โ”‚ Failing: 0 โ”‚ + โ”‚ Pending: 0 โ”‚ + โ”‚ Skipped: 0 โ”‚ + โ”‚ Screenshots: 1 โ”‚ + โ”‚ Video: true โ”‚ + โ”‚ Duration: X seconds โ”‚ + โ”‚ Spec Ran: after_screenshot_overwrite_spec.coffee โ”‚ + โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ + + + (Screenshots) + + - /XXX/XXX/XXX/screenshot-replacement.png (2x2) + + + (Video) + + - Started processing: Compressing to 32 CRF + - Finished processing: /XXX/XXX/XXX/cypress/videos/after_screenshot_overwrite_spec (X second) + .coffee.mp4 + + +==================================================================================================== + + (Run Finished) + + + Spec Tests Passing Failing Pending Skipped + โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” + โ”‚ โœ” after_screenshot_overwrite_spec.cof XX:XX 3 3 - - - โ”‚ + โ”‚ fee โ”‚ + โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ + โœ” All specs passed! XX:XX 3 3 - - - + + +` + +exports['e2e plugins does not report more screenshots than exist if user overwrites previous screenshot in afterScreenshot 1'] = ` + +==================================================================================================== + + (Run Starting) + + โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” + โ”‚ Cypress: 1.2.3 โ”‚ + โ”‚ Browser: FooBrowser 88 โ”‚ + โ”‚ Specs: 1 found (after_screenshot_overwrite_spec.coffee) โ”‚ + โ”‚ Searched: cypress/integration/after_screenshot_overwrite_spec.coffee โ”‚ + โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ + + +โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + + Running: after_screenshot_overwrite_spec.coffee (1 of 1) + + + โœ“ cy.screenshot() - replacement + โœ“ cy.screenshot() - replacement + โœ“ cy.screenshot() - replacement + + 3 passing + + + (Results) + + โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” + โ”‚ Tests: 3 โ”‚ + โ”‚ Passing: 3 โ”‚ + โ”‚ Failing: 0 โ”‚ + โ”‚ Pending: 0 โ”‚ + โ”‚ Skipped: 0 โ”‚ + โ”‚ Screenshots: 1 โ”‚ + โ”‚ Video: true โ”‚ + โ”‚ Duration: X seconds โ”‚ + โ”‚ Spec Ran: after_screenshot_overwrite_spec.coffee โ”‚ + โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ + + + (Screenshots) + + - /XXX/XXX/XXX/screenshot-replacement.png (2x2) + + + (Video) + + - Started processing: Compressing to 32 CRF + - Finished processing: /XXX/XXX/XXX/cypress/videos/after_screenshot_overwrite_spec (X second) + .coffee.mp4 + + +==================================================================================================== + + (Run Finished) + + + Spec Tests Passing Failing Pending Skipped + โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” + โ”‚ โœ” after_screenshot_overwrite_spec.cof XX:XX 3 3 - - - โ”‚ + โ”‚ fee โ”‚ + โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ + โœ” All specs passed! XX:XX 3 3 - - - + + +` diff --git a/packages/server/__snapshots__/3_retries_spec.ts.js b/packages/server/__snapshots__/3_retries_spec.ts.js new file mode 100644 index 000000000000..39bea32e843c --- /dev/null +++ b/packages/server/__snapshots__/3_retries_spec.ts.js @@ -0,0 +1,134 @@ +exports['retries / supports retries'] = ` + +==================================================================================================== + + (Run Starting) + + โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” + โ”‚ Cypress: 1.2.3 โ”‚ + โ”‚ Browser: FooBrowser 88 โ”‚ + โ”‚ Specs: 1 found (fail-twice.js) โ”‚ + โ”‚ Searched: cypress/integration/fail-twice.js โ”‚ + โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ + + +โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + + Running: fail-twice.js (1 of 1) + + + (Attempt 1 of 3) fail twice + (Attempt 2 of 3) fail twice + โœ“ fail twice + + 1 passing + + + (Results) + + โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” + โ”‚ Tests: 1 โ”‚ + โ”‚ Passing: 1 โ”‚ + โ”‚ Failing: 0 โ”‚ + โ”‚ Pending: 0 โ”‚ + โ”‚ Skipped: 0 โ”‚ + โ”‚ Screenshots: 2 โ”‚ + โ”‚ Video: true โ”‚ + โ”‚ Duration: X seconds โ”‚ + โ”‚ Spec Ran: fail-twice.js โ”‚ + โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ + + + (Screenshots) + + - /XXX/XXX/XXX/cypress/screenshots/fail-twice.js/fail twice (failed).png (1280x720) + - /XXX/XXX/XXX/cypress/screenshots/fail-twice.js/fail twice (failed) (attempt 2).p (1280x720) + ng + + + (Video) + + - Started processing: Compressing to 32 CRF + - Finished processing: /XXX/XXX/XXX/cypress/videos/fail-twice.js.mp4 (X second) + + +==================================================================================================== + + (Run Finished) + + + Spec Tests Passing Failing Pending Skipped + โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” + โ”‚ โœ” fail-twice.js XX:XX 1 1 - - - โ”‚ + โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ + โœ” All specs passed! XX:XX 1 1 - - - + + +` + +exports['retries / warns about retries plugin'] = ` +We've detected that the incompatible plugin \`cypress-plugin-retries\` is installed at \`node_modules/cypress-plugin-retries\`. + +Test retries is now supported in Cypress version \`5.0.0\`. + +Remove the plugin from your dependencies to silence this warning. + +https://on.cypress.io/test-retries + + +==================================================================================================== + + (Run Starting) + + โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” + โ”‚ Cypress: 1.2.3 โ”‚ + โ”‚ Browser: FooBrowser 88 โ”‚ + โ”‚ Specs: 1 found (main.spec.js) โ”‚ + โ”‚ Searched: cypress/integration/main.spec.js โ”‚ + โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ + + +โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + + Running: main.spec.js (1 of 1) + + + โœ“ foo + + 1 passing + + + (Results) + + โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” + โ”‚ Tests: 1 โ”‚ + โ”‚ Passing: 1 โ”‚ + โ”‚ Failing: 0 โ”‚ + โ”‚ Pending: 0 โ”‚ + โ”‚ Skipped: 0 โ”‚ + โ”‚ Screenshots: 0 โ”‚ + โ”‚ Video: true โ”‚ + โ”‚ Duration: X seconds โ”‚ + โ”‚ Spec Ran: main.spec.js โ”‚ + โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ + + + (Video) + + - Started processing: Compressing to 32 CRF + - Finished processing: /XXX/XXX/XXX/cypress/videos/main.spec.js.mp4 (X second) + + +==================================================================================================== + + (Run Finished) + + + Spec Tests Passing Failing Pending Skipped + โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” + โ”‚ โœ” main.spec.js XX:XX 1 1 - - - โ”‚ + โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ + โœ” All specs passed! XX:XX 1 1 - - - + + +` diff --git a/packages/server/__snapshots__/3_runnable_execution_spec.ts.js b/packages/server/__snapshots__/3_runnable_execution_spec.ts.js index 06dc92d31c09..3fe12b45bce5 100644 --- a/packages/server/__snapshots__/3_runnable_execution_spec.ts.js +++ b/packages/server/__snapshots__/3_runnable_execution_spec.ts.js @@ -24,9 +24,12 @@ exports['e2e runnable execution / cannot navigate in before hook and test'] = ` โœ“ test 1) causes domain navigation + navigation error in beforeEach + 2) "before each" hook for "never gets here" + 2 passing - 1 failing + 2 failing 1) suite causes domain navigation: @@ -51,15 +54,40 @@ You may need to restructure some of your test code to avoid this problem. https://on.cypress.io/cannot-visit-different-origin-domain [stack trace lines] + 2) navigation error in beforeEach + "before each" hook for "never gets here": + CypressError: \`cy.visit()\` failed because you are attempting to visit a URL that is of a different origin. + +The new URL is considered a different origin because the following parts of the URL are different: + + > port + +You may only \`cy.visit()\` same-origin URLs within a single test. + +The previous URL you visited was: + + > 'http://localhost:4545' + +You're attempting to visit this URL: + + > 'http://localhost:5656' + +You may need to restructure some of your test code to avoid this problem. + +https://on.cypress.io/cannot-visit-different-origin-domain + +Because this error occurred during a \`before each\` hook we are skipping the remaining tests in the current suite: \`navigation error in beforeEach\` + [stack trace lines] + (Results) โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” - โ”‚ Tests: 3 โ”‚ + โ”‚ Tests: 4 โ”‚ โ”‚ Passing: 2 โ”‚ - โ”‚ Failing: 1 โ”‚ + โ”‚ Failing: 2 โ”‚ โ”‚ Pending: 0 โ”‚ โ”‚ Skipped: 0 โ”‚ โ”‚ Screenshots: 0 โ”‚ @@ -83,9 +111,9 @@ https://on.cypress.io/cannot-visit-different-origin-domain Spec Tests Passing Failing Pending Skipped โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” - โ”‚ โœ– beforehook-and-test-navigation.js XX:XX 3 2 1 - - โ”‚ + โ”‚ โœ– beforehook-and-test-navigation.js XX:XX 4 2 2 - - โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ - โœ– 1 of 1 failed (100%) XX:XX 3 2 1 - - + โœ– 1 of 1 failed (100%) XX:XX 4 2 2 - - ` diff --git a/packages/server/__snapshots__/5_screenshots_spec.js b/packages/server/__snapshots__/5_screenshots_spec.js index e4fef3d1c010..b513571f7ce3 100644 --- a/packages/server/__snapshots__/5_screenshots_spec.js +++ b/packages/server/__snapshots__/5_screenshots_spec.js @@ -29,8 +29,11 @@ exports['e2e screenshots / passes'] = ` โœ“ accepts screenshot after multiple tries if somehow app has pixels that match helper pixels โœ“ can capture element screenshots โœ“ retries each screenshot for up to XX:XX + (Attempt 1 of 3) screenshots in a retried test + (Attempt 2 of 3) screenshots in a retried test + 2) screenshots in a retried test โœ“ ensures unique paths for non-named screenshots - 2) ensures unique paths when there's a non-named screenshot and a failure + 3) ensures unique paths when there's a non-named screenshot and a failure โœ“ properly resizes the AUT iframe - does not take a screenshot for a pending test โœ“ adds padding to element screenshot when specified @@ -41,10 +44,10 @@ exports['e2e screenshots / passes'] = ` โœ“ can clip fullPage screenshots โœ“ can clip element screenshots before hooks - 3) "before all" hook for "empty test 1" + 4) "before all" hook for "empty test 1" each hooks - 4) "before each" hook for "empty test 2" - 5) "after each" hook for "empty test 2" + 5) "before each" hook for "empty test 2" + 6) "after each" hook for "empty test 2" really long test title aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa โœ“ takes a screenshot โœ“ takes another screenshot @@ -52,7 +55,7 @@ exports['e2e screenshots / passes'] = ` 20 passing 1 pending - 5 failing + 6 failing 1) taking screenshots generates pngs on failure: @@ -60,11 +63,16 @@ exports['e2e screenshots / passes'] = ` [stack trace lines] 2) taking screenshots + screenshots in a retried test: + Error: fail + [stack trace lines] + + 3) taking screenshots ensures unique paths when there's a non-named screenshot and a failure: Error: failing on purpose [stack trace lines] - 3) taking screenshots + 4) taking screenshots before hooks "before all" hook for "empty test 1": Error: before hook failing @@ -72,7 +80,7 @@ exports['e2e screenshots / passes'] = ` Because this error occurred during a \`before all\` hook we are skipping the remaining tests in the current suite: \`before hooks\` [stack trace lines] - 4) taking screenshots + 5) taking screenshots each hooks "before each" hook for "empty test 2": Error: before each hook failed @@ -80,7 +88,7 @@ Because this error occurred during a \`before all\` hook we are skipping the rem Because this error occurred during a \`before each\` hook we are skipping the remaining tests in the current suite: \`each hooks\` [stack trace lines] - 5) taking screenshots + 6) taking screenshots each hooks "after each" hook for "empty test 2": Error: after each hook failed @@ -94,12 +102,12 @@ Because this error occurred during a \`after each\` hook we are skipping the rem (Results) โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” - โ”‚ Tests: 25 โ”‚ + โ”‚ Tests: 26 โ”‚ โ”‚ Passing: 20 โ”‚ - โ”‚ Failing: 4 โ”‚ + โ”‚ Failing: 5 โ”‚ โ”‚ Pending: 1 โ”‚ โ”‚ Skipped: 0 โ”‚ - โ”‚ Screenshots: 28 โ”‚ + โ”‚ Screenshots: 34 โ”‚ โ”‚ Video: true โ”‚ โ”‚ Duration: X seconds โ”‚ โ”‚ Spec Ran: screenshots_spec.js โ”‚ @@ -121,6 +129,17 @@ Because this error occurred during a \`after each\` hook we are skipping the rem - /XXX/XXX/XXX/cypress/screenshots/screenshots_spec.js/element.png (400x300) - /XXX/XXX/XXX/cypress/screenshots/screenshots_spec.js/taking screenshots -- retri (200x1300) es each screenshot for up to XX:XX.png + - /XXX/XXX/XXX/cypress/screenshots/screenshots_spec.js/retrying-test.png (1000x1316) + - /XXX/XXX/XXX/cypress/screenshots/screenshots_spec.js/taking screenshots -- scree (1280x720) + nshots in a retried test (failed).png + - /XXX/XXX/XXX/cypress/screenshots/screenshots_spec.js/retrying-test (attempt 2).p (1000x1316) + ng + - /XXX/XXX/XXX/cypress/screenshots/screenshots_spec.js/taking screenshots -- scree (1280x720) + nshots in a retried test (failed) (attempt 2).png + - /XXX/XXX/XXX/cypress/screenshots/screenshots_spec.js/retrying-test (attempt 3).p (1000x1316) + ng + - /XXX/XXX/XXX/cypress/screenshots/screenshots_spec.js/taking screenshots -- scree (1280x720) + nshots in a retried test (failed) (attempt 3).png - /XXX/XXX/XXX/cypress/screenshots/screenshots_spec.js/taking screenshots -- ensur (1280x720) es unique paths for non-named screenshots.png - /XXX/XXX/XXX/cypress/screenshots/screenshots_spec.js/taking screenshots -- ensur (1280x720) @@ -167,9 +186,9 @@ Because this error occurred during a \`after each\` hook we are skipping the rem Spec Tests Passing Failing Pending Skipped โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” - โ”‚ โœ– screenshots_spec.js XX:XX 25 20 4 1 - โ”‚ + โ”‚ โœ– screenshots_spec.js XX:XX 26 20 5 1 - โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ - โœ– 1 of 1 failed (100%) XX:XX 25 20 4 1 - + โœ– 1 of 1 failed (100%) XX:XX 26 20 5 1 - ` diff --git a/packages/server/__snapshots__/5_spec_isolation_spec.js b/packages/server/__snapshots__/5_spec_isolation_spec.js index a756c1dbb073..6f439cfdc402 100644 --- a/packages/server/__snapshots__/5_spec_isolation_spec.js +++ b/packages/server/__snapshots__/5_spec_isolation_spec.js @@ -17,15 +17,15 @@ exports['e2e spec isolation fails'] = { "pending": 1, "skipped": 1, "failures": 3, - "wallClockStartedAt": "2018-02-01T20:14:19.323Z", - "wallClockEndedAt": "2018-02-01T20:14:19.323Z", - "wallClockDuration": 1234 + "duration": 1234, + "startedAt": "2018-02-01T20:14:19.323Z", + "endedAt": "2018-02-01T20:14:19.323Z" }, "reporter": "spec", "reporterStats": { "suites": 5, - "tests": 4, - "passes": 3, + "tests": 5, + "passes": 1, "pending": 1, "failures": 3, "start": "2018-02-01T20:14:19.323Z", @@ -34,74 +34,61 @@ exports['e2e spec isolation fails'] = { }, "hooks": [ { - "hookId": "h1", - "hookName": "before all", - "title": [ - "\"before all\" hook" - ], - "body": "function () {\n if (Cypress.browser.family === 'chromium' && Cypress.browser.name !== 'electron') {\n return Cypress.automation('remote:debugger:protocol', {\n command: 'Emulation.setDeviceMetricsOverride',\n params: {\n width: 1280,\n height: 720,\n deviceScaleFactor: 1,\n mobile: false,\n screenWidth: 1280,\n screenHeight: 720,\n },\n })\n .then(function () {\n // can't tell expect() not to log, so manually throwing here\n if (window.devicePixelRatio !== 1) {\n throw new Error('Setting devicePixelRatio to 1 failed');\n }\n });\n }\n}" - }, - { - "hookId": "h2", "hookName": "before each", "title": [ "\"before each\" hook" ], - "body": "function () {\n throw new Error(\"fail1\");\n }" + "body": "function() {\n throw new Error(\"fail1\");\n }" }, { - "hookId": "h3", "hookName": "after each", "title": [ "\"after each\" hook" ], - "body": "function () {\n throw new Error(\"fail2\");\n }" + "body": "function() {\n throw new Error(\"fail2\");\n }" }, { - "hookId": "h4", "hookName": "after all", "title": [ "\"after all\" hook" ], - "body": "function () {\n throw new Error(\"fail3\");\n }" + "body": "function() {\n throw new Error(\"fail3\");\n }" } ], "tests": [ { - "testId": "r4", "title": [ "simple failing hook spec", "beforeEach hooks", "never gets here" ], "state": "failed", - "body": "function () { }", - "stack": "Error: fail1\n\nBecause this error occurred during a `before each` hook we are skipping the remaining tests in the current suite: `beforeEach hooks`\n [stack trace lines]", - "error": "fail1\n\nBecause this error occurred during a `before each` hook we are skipping the remaining tests in the current suite: `beforeEach hooks`", - "timings": { - "lifecycle": 100, - "before all": [ - { - "hookId": "h1", - "fnDuration": 400, - "afterFnDuration": 200 - } - ], - "before each": [ - { - "hookId": "h2", - "fnDuration": 400, - "afterFnDuration": 200 - } - ] - }, - "failedFromHookId": "h2", - "wallClockStartedAt": "2018-02-01T20:14:19.323Z", - "wallClockDuration": 1234, - "videoTimestamp": 9999 + "body": "function() {}", + "displayError": "Error: fail1\n\nBecause this error occurred during a `before each` hook we are skipping the remaining tests in the current suite: `beforeEach hooks`\n [stack trace lines]", + "attempts": [ + { + "state": "failed", + "error": { + "name": "Error", + "message": "fail1\n\nBecause this error occurred during a `before each` hook we are skipping the remaining tests in the current suite: `beforeEach hooks`", + "stack": "[stack trace lines]" + }, + "videoTimestamp": 9999, + "duration": 1234, + "startedAt": "2018-02-01T20:14:19.323Z", + "screenshots": [ + { + "name": null, + "takenAt": "2018-02-01T20:14:19.323Z", + "path": "/foo/bar/.projects/e2e/cypress/screenshots/simple_failing_hook_spec.coffee/simple failing hook spec -- beforeEach hooks -- never gets here -- before each hook (failed).png", + "height": 720, + "width": 1280 + } + ] + } + ] }, { - "testId": "r6", "title": [ "simple failing hook spec", "pending", @@ -109,146 +96,125 @@ exports['e2e spec isolation fails'] = { ], "state": "pending", "body": "", - "stack": null, - "error": null, - "timings": null, - "failedFromHookId": null, - "wallClockStartedAt": null, - "wallClockDuration": null, - "videoTimestamp": null + "displayError": null, + "attempts": [ + { + "state": "pending", + "error": null, + "videoTimestamp": null, + "duration": null, + "startedAt": null, + "screenshots": [] + } + ] }, { - "testId": "r8", "title": [ "simple failing hook spec", "afterEach hooks", "runs this" ], "state": "failed", - "body": "function () { }", - "stack": "Error: fail2\n\nBecause this error occurred during a `after each` hook we are skipping the remaining tests in the current suite: `afterEach hooks`\n [stack trace lines]", - "error": "fail2\n\nBecause this error occurred during a `after each` hook we are skipping the remaining tests in the current suite: `afterEach hooks`", - "timings": { - "lifecycle": 100, - "test": { - "fnDuration": 400, - "afterFnDuration": 200 - }, - "after each": [ - { - "hookId": "h3", - "fnDuration": 400, - "afterFnDuration": 200 - } - ] - }, - "failedFromHookId": "h3", - "wallClockStartedAt": "2018-02-01T20:14:19.323Z", - "wallClockDuration": 1234, - "videoTimestamp": 9999 + "body": "function() {}", + "displayError": "Error: fail2\n\nBecause this error occurred during a `after each` hook we are skipping the remaining tests in the current suite: `afterEach hooks`\n [stack trace lines]", + "attempts": [ + { + "state": "failed", + "error": { + "name": "Error", + "message": "fail2\n\nBecause this error occurred during a `after each` hook we are skipping the remaining tests in the current suite: `afterEach hooks`", + "stack": "[stack trace lines]" + }, + "videoTimestamp": 9999, + "duration": 1234, + "startedAt": "2018-02-01T20:14:19.323Z", + "screenshots": [ + { + "name": null, + "takenAt": "2018-02-01T20:14:19.323Z", + "path": "/foo/bar/.projects/e2e/cypress/screenshots/simple_failing_hook_spec.coffee/simple failing hook spec -- afterEach hooks -- runs this -- after each hook (failed).png", + "height": 720, + "width": 1280 + } + ] + } + ] }, { - "testId": "r9", "title": [ "simple failing hook spec", "afterEach hooks", "does not run this" ], "state": "skipped", - "body": "function () { }", - "stack": null, - "error": null, - "timings": null, - "failedFromHookId": null, - "wallClockStartedAt": null, - "wallClockDuration": null, - "videoTimestamp": null + "body": "function() {}", + "displayError": null, + "attempts": [ + { + "state": "skipped", + "error": null, + "videoTimestamp": null, + "duration": null, + "startedAt": null, + "screenshots": [] + } + ] }, { - "testId": "r11", "title": [ "simple failing hook spec", "after hooks", "runs this" ], "state": "passed", - "body": "function () { }", - "stack": null, - "error": null, - "timings": { - "lifecycle": 100, - "test": { - "fnDuration": 400, - "afterFnDuration": 200 + "body": "function() {}", + "displayError": null, + "attempts": [ + { + "state": "passed", + "error": null, + "videoTimestamp": 9999, + "duration": 1234, + "startedAt": "2018-02-01T20:14:19.323Z", + "screenshots": [] } - }, - "failedFromHookId": null, - "wallClockStartedAt": "2018-02-01T20:14:19.323Z", - "wallClockDuration": 1234, - "videoTimestamp": 9999 + ] }, { - "testId": "r12", "title": [ "simple failing hook spec", "after hooks", "fails on this" ], "state": "failed", - "body": "function () { }", - "stack": "Error: fail3\n\nBecause this error occurred during a `after all` hook we are skipping the remaining tests in the current suite: `after hooks`\n [stack trace lines]", - "error": "fail3\n\nBecause this error occurred during a `after all` hook we are skipping the remaining tests in the current suite: `after hooks`", - "timings": { - "lifecycle": 100, - "test": { - "fnDuration": 400, - "afterFnDuration": 200 - }, - "after all": [ - { - "hookId": "h4", - "fnDuration": 400, - "afterFnDuration": 200 - } - ] - }, - "failedFromHookId": "h4", - "wallClockStartedAt": "2018-02-01T20:14:19.323Z", - "wallClockDuration": 1234, - "videoTimestamp": 9999 + "body": "function() {}", + "displayError": "Error: fail3\n\nBecause this error occurred during a `after all` hook we are skipping the remaining tests in the current suite: `after hooks`\n [stack trace lines]", + "attempts": [ + { + "state": "failed", + "error": { + "name": "Error", + "message": "fail3\n\nBecause this error occurred during a `after all` hook we are skipping the remaining tests in the current suite: `after hooks`", + "stack": "[stack trace lines]" + }, + "videoTimestamp": 9999, + "duration": 1234, + "startedAt": "2018-02-01T20:14:19.323Z", + "screenshots": [ + { + "name": null, + "takenAt": "2018-02-01T20:14:19.323Z", + "path": "/foo/bar/.projects/e2e/cypress/screenshots/simple_failing_hook_spec.coffee/simple failing hook spec -- after hooks -- fails on this -- after all hook (failed).png", + "height": 720, + "width": 1280 + } + ] + } + ] } ], "error": null, "video": "/foo/bar/.projects/e2e/cypress/videos/simple_failing_hook_spec.coffee.mp4", - "screenshots": [ - { - "screenshotId": "some-random-id", - "name": null, - "testId": "r4", - "takenAt": "2018-02-01T20:14:19.323Z", - "path": "/foo/bar/.projects/e2e/cypress/screenshots/simple_failing_hook_spec.coffee/simple failing hook spec -- beforeEach hooks -- never gets here -- before each hook (failed).png", - "height": 720, - "width": 1280 - }, - { - "screenshotId": "some-random-id", - "name": null, - "testId": "r8", - "takenAt": "2018-02-01T20:14:19.323Z", - "path": "/foo/bar/.projects/e2e/cypress/screenshots/simple_failing_hook_spec.coffee/simple failing hook spec -- afterEach hooks -- runs this -- after each hook (failed).png", - "height": 720, - "width": 1280 - }, - { - "screenshotId": "some-random-id", - "name": null, - "testId": "r12", - "takenAt": "2018-02-01T20:14:19.323Z", - "path": "/foo/bar/.projects/e2e/cypress/screenshots/simple_failing_hook_spec.coffee/simple failing hook spec -- after hooks -- fails on this -- after all hook (failed).png", - "height": 720, - "width": 1280 - } - ], "spec": { "name": "simple_failing_hook_spec.coffee", "relative": "cypress/integration/simple_failing_hook_spec.coffee", @@ -265,9 +231,9 @@ exports['e2e spec isolation fails'] = { "pending": 0, "skipped": 0, "failures": 2, - "wallClockStartedAt": "2018-02-01T20:14:19.323Z", - "wallClockEndedAt": "2018-02-01T20:14:19.323Z", - "wallClockDuration": 1234 + "duration": 1234, + "startedAt": "2018-02-01T20:14:19.323Z", + "endedAt": "2018-02-01T20:14:19.323Z" }, "reporter": "spec", "reporterStats": { @@ -280,91 +246,73 @@ exports['e2e spec isolation fails'] = { "end": "2018-02-01T20:14:19.323Z", "duration": 1234 }, - "hooks": [ - { - "hookId": "h1", - "hookName": "before all", - "title": [ - "\"before all\" hook" - ], - "body": "function () {\n if (Cypress.browser.family === 'chromium' && Cypress.browser.name !== 'electron') {\n return Cypress.automation('remote:debugger:protocol', {\n command: 'Emulation.setDeviceMetricsOverride',\n params: {\n width: 1280,\n height: 720,\n deviceScaleFactor: 1,\n mobile: false,\n screenWidth: 1280,\n screenHeight: 720,\n },\n })\n .then(function () {\n // can't tell expect() not to log, so manually throwing here\n if (window.devicePixelRatio !== 1) {\n throw new Error('Setting devicePixelRatio to 1 failed');\n }\n });\n }\n}" - } - ], + "hooks": [], "tests": [ { - "testId": "r3", "title": [ "simple failing spec", "fails1" ], "state": "failed", - "body": "function () {\n return cy.wrap(true, {\n timeout: 100\n }).should(\"be.false\");\n }", - "stack": "AssertionError: Timed out retrying: expected true to be false\n [stack trace lines]", - "error": "Timed out retrying: expected true to be false", - "timings": { - "lifecycle": 100, - "before all": [ - { - "hookId": "h1", - "fnDuration": 400, - "afterFnDuration": 200 - } - ], - "test": { - "fnDuration": 400, - "afterFnDuration": 200 + "body": "function() {\n return cy.wrap(true, {\n timeout: 100\n }).should(\"be.false\");\n }", + "displayError": "AssertionError: Timed out retrying: expected true to be false\n [stack trace lines]", + "attempts": [ + { + "state": "failed", + "error": { + "name": "AssertionError", + "message": "Timed out retrying: expected true to be false", + "stack": "[stack trace lines]" + }, + "videoTimestamp": 9999, + "duration": 1234, + "startedAt": "2018-02-01T20:14:19.323Z", + "screenshots": [ + { + "name": null, + "takenAt": "2018-02-01T20:14:19.323Z", + "path": "/foo/bar/.projects/e2e/cypress/screenshots/simple_failing_spec.coffee/simple failing spec -- fails1 (failed).png", + "height": 720, + "width": 1280 + } + ] } - }, - "failedFromHookId": null, - "wallClockStartedAt": "2018-02-01T20:14:19.323Z", - "wallClockDuration": 1234, - "videoTimestamp": 9999 + ] }, { - "testId": "r4", "title": [ "simple failing spec", "fails2" ], "state": "failed", - "body": "function () {\n throw new Error(\"fails2\");\n }", - "stack": "Error: fails2\n [stack trace lines]", - "error": "fails2", - "timings": { - "lifecycle": 100, - "test": { - "fnDuration": 400, - "afterFnDuration": 200 + "body": "function() {\n throw new Error(\"fails2\");\n }", + "displayError": "Error: fails2\n [stack trace lines]", + "attempts": [ + { + "state": "failed", + "error": { + "name": "Error", + "message": "fails2", + "stack": "[stack trace lines]" + }, + "videoTimestamp": 9999, + "duration": 1234, + "startedAt": "2018-02-01T20:14:19.323Z", + "screenshots": [ + { + "name": null, + "takenAt": "2018-02-01T20:14:19.323Z", + "path": "/foo/bar/.projects/e2e/cypress/screenshots/simple_failing_spec.coffee/simple failing spec -- fails2 (failed).png", + "height": 720, + "width": 1280 + } + ] } - }, - "failedFromHookId": null, - "wallClockStartedAt": "2018-02-01T20:14:19.323Z", - "wallClockDuration": 1234, - "videoTimestamp": 9999 + ] } ], "error": null, "video": "/foo/bar/.projects/e2e/cypress/videos/simple_failing_spec.coffee.mp4", - "screenshots": [ - { - "screenshotId": "some-random-id", - "name": null, - "testId": "r3", - "takenAt": "2018-02-01T20:14:19.323Z", - "path": "/foo/bar/.projects/e2e/cypress/screenshots/simple_failing_spec.coffee/simple failing spec -- fails1 (failed).png", - "height": 720, - "width": 1280 - }, - { - "screenshotId": "some-random-id", - "name": null, - "testId": "r4", - "takenAt": "2018-02-01T20:14:19.323Z", - "path": "/foo/bar/.projects/e2e/cypress/screenshots/simple_failing_spec.coffee/simple failing spec -- fails2 (failed).png", - "height": 720, - "width": 1280 - } - ], "spec": { "name": "simple_failing_spec.coffee", "relative": "cypress/integration/simple_failing_spec.coffee", @@ -381,9 +329,9 @@ exports['e2e spec isolation fails'] = { "pending": 0, "skipped": 0, "failures": 0, - "wallClockStartedAt": "2018-02-01T20:14:19.323Z", - "wallClockEndedAt": "2018-02-01T20:14:19.323Z", - "wallClockDuration": 1234 + "duration": 1234, + "startedAt": "2018-02-01T20:14:19.323Z", + "endedAt": "2018-02-01T20:14:19.323Z" }, "reporter": "spec", "reporterStats": { @@ -398,178 +346,95 @@ exports['e2e spec isolation fails'] = { }, "hooks": [ { - "hookId": "h1", "hookName": "before all", "title": [ "\"before all\" hook" ], - "body": "function () {\n if (Cypress.browser.family === 'chromium' && Cypress.browser.name !== 'electron') {\n return Cypress.automation('remote:debugger:protocol', {\n command: 'Emulation.setDeviceMetricsOverride',\n params: {\n width: 1280,\n height: 720,\n deviceScaleFactor: 1,\n mobile: false,\n screenWidth: 1280,\n screenHeight: 720,\n },\n })\n .then(function () {\n // can't tell expect() not to log, so manually throwing here\n if (window.devicePixelRatio !== 1) {\n throw new Error('Setting devicePixelRatio to 1 failed');\n }\n });\n }\n}" + "body": "function() {\n return cy.wait(100);\n }" }, { - "hookId": "h2", - "hookName": "before all", - "title": [ - "\"before all\" hook" - ], - "body": "function () {\n return cy.wait(100);\n }" - }, - { - "hookId": "h3", "hookName": "before each", "title": [ "\"before each\" hook" ], - "body": "function () {\n return cy.wait(200);\n }" + "body": "function() {\n return cy.wait(200);\n }" }, { - "hookId": "h5", "hookName": "after each", "title": [ "\"after each\" hook" ], - "body": "function () {\n return cy.wait(200);\n }" + "body": "function() {\n return cy.wait(200);\n }" }, { - "hookId": "h4", "hookName": "after all", "title": [ "\"after all\" hook" ], - "body": "function () {\n return cy.wait(100);\n }" + "body": "function() {\n return cy.wait(100);\n }" } ], "tests": [ { - "testId": "r3", "title": [ "simple hooks spec", "t1" ], "state": "passed", - "body": "function () {\n return cy.wrap(\"t1\").should(\"eq\", \"t1\");\n }", - "stack": null, - "error": null, - "timings": { - "lifecycle": 100, - "before all": [ - { - "hookId": "h1", - "fnDuration": 400, - "afterFnDuration": 200 - }, - { - "hookId": "h2", - "fnDuration": 400, - "afterFnDuration": 200 - } - ], - "before each": [ - { - "hookId": "h3", - "fnDuration": 400, - "afterFnDuration": 200 - } - ], - "test": { - "fnDuration": 400, - "afterFnDuration": 200 - }, - "after each": [ - { - "hookId": "h5", - "fnDuration": 400, - "afterFnDuration": 200 - } - ] - }, - "failedFromHookId": null, - "wallClockStartedAt": "2018-02-01T20:14:19.323Z", - "wallClockDuration": 1234, - "videoTimestamp": 9999 + "body": "function() {\n return cy.wrap(\"t1\").should(\"eq\", \"t1\");\n }", + "displayError": null, + "attempts": [ + { + "state": "passed", + "error": null, + "videoTimestamp": 9999, + "duration": 1234, + "startedAt": "2018-02-01T20:14:19.323Z", + "screenshots": [] + } + ] }, { - "testId": "r4", "title": [ "simple hooks spec", "t2" ], "state": "passed", - "body": "function () {\n return cy.wrap(\"t2\").should(\"eq\", \"t2\");\n }", - "stack": null, - "error": null, - "timings": { - "lifecycle": 100, - "before each": [ - { - "hookId": "h3", - "fnDuration": 400, - "afterFnDuration": 200 - } - ], - "test": { - "fnDuration": 400, - "afterFnDuration": 200 - }, - "after each": [ - { - "hookId": "h5", - "fnDuration": 400, - "afterFnDuration": 200 - } - ] - }, - "failedFromHookId": null, - "wallClockStartedAt": "2018-02-01T20:14:19.323Z", - "wallClockDuration": 1234, - "videoTimestamp": 9999 + "body": "function() {\n return cy.wrap(\"t2\").should(\"eq\", \"t2\");\n }", + "displayError": null, + "attempts": [ + { + "state": "passed", + "error": null, + "videoTimestamp": 9999, + "duration": 1234, + "startedAt": "2018-02-01T20:14:19.323Z", + "screenshots": [] + } + ] }, { - "testId": "r5", "title": [ "simple hooks spec", "t3" ], "state": "passed", - "body": "function () {\n return cy.wrap(\"t3\").should(\"eq\", \"t3\");\n }", - "stack": null, - "error": null, - "timings": { - "lifecycle": 100, - "before each": [ - { - "hookId": "h3", - "fnDuration": 400, - "afterFnDuration": 200 - } - ], - "test": { - "fnDuration": 400, - "afterFnDuration": 200 - }, - "after each": [ - { - "hookId": "h5", - "fnDuration": 400, - "afterFnDuration": 200 - } - ], - "after all": [ - { - "hookId": "h4", - "fnDuration": 400, - "afterFnDuration": 200 - } - ] - }, - "failedFromHookId": null, - "wallClockStartedAt": "2018-02-01T20:14:19.323Z", - "wallClockDuration": 1234, - "videoTimestamp": 9999 + "body": "function() {\n return cy.wrap(\"t3\").should(\"eq\", \"t3\");\n }", + "displayError": null, + "attempts": [ + { + "state": "passed", + "error": null, + "videoTimestamp": 9999, + "duration": 1234, + "startedAt": "2018-02-01T20:14:19.323Z", + "screenshots": [] + } + ] } ], "error": null, "video": "/foo/bar/.projects/e2e/cypress/videos/simple_hooks_spec.coffee.mp4", - "screenshots": [], "spec": { "name": "simple_hooks_spec.coffee", "relative": "cypress/integration/simple_hooks_spec.coffee", @@ -586,9 +451,9 @@ exports['e2e spec isolation fails'] = { "pending": 0, "skipped": 0, "failures": 0, - "wallClockStartedAt": "2018-02-01T20:14:19.323Z", - "wallClockEndedAt": "2018-02-01T20:14:19.323Z", - "wallClockDuration": 1234 + "duration": 1234, + "startedAt": "2018-02-01T20:14:19.323Z", + "endedAt": "2018-02-01T20:14:19.323Z" }, "reporter": "spec", "reporterStats": { @@ -603,63 +468,36 @@ exports['e2e spec isolation fails'] = { }, "hooks": [ { - "hookId": "h1", - "hookName": "before all", - "title": [ - "\"before all\" hook" - ], - "body": "function () {\n if (Cypress.browser.family === 'chromium' && Cypress.browser.name !== 'electron') {\n return Cypress.automation('remote:debugger:protocol', {\n command: 'Emulation.setDeviceMetricsOverride',\n params: {\n width: 1280,\n height: 720,\n deviceScaleFactor: 1,\n mobile: false,\n screenWidth: 1280,\n screenHeight: 720,\n },\n })\n .then(function () {\n // can't tell expect() not to log, so manually throwing here\n if (window.devicePixelRatio !== 1) {\n throw new Error('Setting devicePixelRatio to 1 failed');\n }\n });\n }\n}" - }, - { - "hookId": "h2", "hookName": "before each", "title": [ "\"before each\" hook" ], - "body": "function () {\n return cy.wait(1000);\n }" + "body": "function() {\n return cy.wait(1000);\n }" } ], "tests": [ { - "testId": "r3", "title": [ "simple passing spec", "passes" ], "state": "passed", - "body": "function () {\n return cy.wrap(true).should(\"be.true\");\n }", - "stack": null, - "error": null, - "timings": { - "lifecycle": 100, - "before all": [ - { - "hookId": "h1", - "fnDuration": 400, - "afterFnDuration": 200 - } - ], - "before each": [ - { - "hookId": "h2", - "fnDuration": 400, - "afterFnDuration": 200 - } - ], - "test": { - "fnDuration": 400, - "afterFnDuration": 200 + "body": "function() {\n return cy.wrap(true).should(\"be.true\");\n }", + "displayError": null, + "attempts": [ + { + "state": "passed", + "error": null, + "videoTimestamp": 9999, + "duration": 1234, + "startedAt": "2018-02-01T20:14:19.323Z", + "screenshots": [] } - }, - "failedFromHookId": null, - "wallClockStartedAt": "2018-02-01T20:14:19.323Z", - "wallClockDuration": 1234, - "videoTimestamp": 9999 + ] } ], "error": null, "video": "/foo/bar/.projects/e2e/cypress/videos/simple_passing_spec.coffee.mp4", - "screenshots": [], "spec": { "name": "simple_passing_spec.coffee", "relative": "cypress/integration/simple_passing_spec.coffee", @@ -677,3 +515,396 @@ exports['e2e spec isolation fails'] = { "cypressVersion": "9.9.9", "config": {} } + +exports['e2e spec_isolation / failing with retries enabled'] = ` + +==================================================================================================== + + (Run Starting) + + โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” + โ”‚ Cypress: 1.2.3 โ”‚ + โ”‚ Browser: FooBrowser 88 โ”‚ + โ”‚ Specs: 1 found (simple_failing_hook_spec.coffee) โ”‚ + โ”‚ Searched: cypress/integration/simple_failing_hook_spec.coffee โ”‚ + โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ + + +โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + + Running: simple_failing_hook_spec.coffee (1 of 1) + + + simple failing hook spec + beforeEach hooks + (Attempt 1 of 2) never gets here + 1) "before each" hook for "never gets here" + pending + - is pending + afterEach hooks + (Attempt 1 of 2) runs this + 2) "after each" hook for "runs this" + after hooks + โœ“ runs this + 3) "after all" hook for "fails on this" + + + 1 passing + 1 pending + 3 failing + + 1) simple failing hook spec + beforeEach hooks + "before each" hook for "never gets here": + Error: fail1 + +Because this error occurred during a \`before each\` hook we are skipping the remaining tests in the current suite: \`beforeEach hooks\` + [stack trace lines] + + 2) simple failing hook spec + afterEach hooks + "after each" hook for "runs this": + Error: fail2 + +Because this error occurred during a \`after each\` hook we are skipping the remaining tests in the current suite: \`afterEach hooks\` + [stack trace lines] + + 3) simple failing hook spec + after hooks + "after all" hook for "fails on this": + Error: fail3 + +Because this error occurred during a \`after all\` hook we are skipping the remaining tests in the current suite: \`after hooks\` + +Although you have test retries enabled, we do not retry tests when \`before all\` or \`after all\` hooks fail + [stack trace lines] + + + + + (Results) + + โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” + โ”‚ Tests: 6 โ”‚ + โ”‚ Passing: 1 โ”‚ + โ”‚ Failing: 3 โ”‚ + โ”‚ Pending: 1 โ”‚ + โ”‚ Skipped: 1 โ”‚ + โ”‚ Screenshots: 5 โ”‚ + โ”‚ Video: true โ”‚ + โ”‚ Duration: X seconds โ”‚ + โ”‚ Spec Ran: simple_failing_hook_spec.coffee โ”‚ + โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ + + + (Screenshots) + + - /XXX/XXX/XXX/cypress/screenshots/simple_failing_hook_spec.coffee/simple failing (1280x720) + hook spec -- beforeEach hooks -- never gets here (failed).png + - /XXX/XXX/XXX/cypress/screenshots/simple_failing_hook_spec.coffee/simple failing (1280x720) + hook spec -- beforeEach hooks -- never gets here -- before each hook (failed) (a + ttempt 2).png + - /XXX/XXX/XXX/cypress/screenshots/simple_failing_hook_spec.coffee/simple failing (1280x720) + hook spec -- afterEach hooks -- runs this -- after each hook (failed).png + - /XXX/XXX/XXX/cypress/screenshots/simple_failing_hook_spec.coffee/simple failing (1280x720) + hook spec -- afterEach hooks -- runs this -- after each hook (failed) (attempt 2 + ).png + - /XXX/XXX/XXX/cypress/screenshots/simple_failing_hook_spec.coffee/simple failing (1280x720) + hook spec -- after hooks -- fails on this -- after all hook (failed).png + + + (Video) + + - Started processing: Compressing to 32 CRF + - Finished processing: /XXX/XXX/XXX/cypress/videos/simple_failing_hook_spec.coffee (X second) + .mp4 + + +==================================================================================================== + + (Run Finished) + + + Spec Tests Passing Failing Pending Skipped + โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” + โ”‚ โœ– simple_failing_hook_spec.coffee XX:XX 6 1 3 1 1 โ”‚ + โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ + โœ– 1 of 1 failed (100%) XX:XX 6 1 3 1 1 + + +` + +exports['failing with retries enabled'] = { + "startedTestsAt": "2018-02-01T20:14:19.323Z", + "endedTestsAt": "2018-02-01T20:14:19.323Z", + "totalDuration": 5555, + "totalSuites": 5, + "totalTests": 6, + "totalFailed": 3, + "totalPassed": 1, + "totalPending": 1, + "totalSkipped": 1, + "runs": [ + { + "stats": { + "suites": 5, + "tests": 6, + "passes": 1, + "pending": 1, + "skipped": 1, + "failures": 3, + "duration": 1234, + "startedAt": "2018-02-01T20:14:19.323Z", + "endedAt": "2018-02-01T20:14:19.323Z" + }, + "reporter": "spec", + "reporterStats": { + "suites": 5, + "tests": 5, + "passes": 1, + "pending": 1, + "failures": 3, + "start": "2018-02-01T20:14:19.323Z", + "end": "2018-02-01T20:14:19.323Z", + "duration": 1234 + }, + "hooks": [ + { + "hookName": "before each", + "title": [ + "\"before each\" hook" + ], + "body": "function() {\n throw new Error(\"fail1\");\n }" + }, + { + "hookName": "after each", + "title": [ + "\"after each\" hook" + ], + "body": "function() {\n throw new Error(\"fail2\");\n }" + }, + { + "hookName": "after all", + "title": [ + "\"after all\" hook" + ], + "body": "function() {\n throw new Error(\"fail3\");\n }" + } + ], + "tests": [ + { + "title": [ + "simple failing hook spec", + "beforeEach hooks", + "never gets here" + ], + "state": "failed", + "body": "function() {}", + "displayError": "Error: fail1\n\nBecause this error occurred during a `before each` hook we are skipping the remaining tests in the current suite: `beforeEach hooks`\n [stack trace lines]", + "attempts": [ + { + "state": "failed", + "error": { + "name": "Error", + "message": "fail1\n\nBecause this error occurred during a `before each` hook we are skipping the remaining tests in the current suite: `beforeEach hooks`", + "stack": "[stack trace lines]" + }, + "videoTimestamp": 9999, + "duration": 1234, + "startedAt": "2018-02-01T20:14:19.323Z", + "screenshots": [ + { + "name": null, + "takenAt": "2018-02-01T20:14:19.323Z", + "path": "/foo/bar/.projects/e2e/cypress/screenshots/simple_failing_hook_spec.coffee/simple failing hook spec -- beforeEach hooks -- never gets here (failed).png", + "height": 720, + "width": 1280 + } + ] + }, + { + "state": "failed", + "error": { + "name": "Error", + "message": "fail1", + "stack": "[stack trace lines]" + }, + "videoTimestamp": 9999, + "duration": 1234, + "startedAt": "2018-02-01T20:14:19.323Z", + "screenshots": [ + { + "name": null, + "takenAt": "2018-02-01T20:14:19.323Z", + "path": "/foo/bar/.projects/e2e/cypress/screenshots/simple_failing_hook_spec.coffee/simple failing hook spec -- beforeEach hooks -- never gets here -- before each hook (failed) (attempt 2).png", + "height": 720, + "width": 1280 + } + ] + } + ] + }, + { + "title": [ + "simple failing hook spec", + "pending", + "is pending" + ], + "state": "pending", + "body": "", + "displayError": null, + "attempts": [ + { + "state": "pending", + "error": null, + "videoTimestamp": null, + "duration": null, + "startedAt": null, + "screenshots": [] + } + ] + }, + { + "title": [ + "simple failing hook spec", + "afterEach hooks", + "runs this" + ], + "state": "failed", + "body": "function() {}", + "displayError": "Error: fail2\n\nBecause this error occurred during a `after each` hook we are skipping the remaining tests in the current suite: `afterEach hooks`\n [stack trace lines]", + "attempts": [ + { + "state": "failed", + "error": { + "name": "Error", + "message": "fail2\n\nBecause this error occurred during a `after each` hook we are skipping the remaining tests in the current suite: `afterEach hooks`", + "stack": "[stack trace lines]" + }, + "videoTimestamp": 9999, + "duration": 1234, + "startedAt": "2018-02-01T20:14:19.323Z", + "screenshots": [ + { + "name": null, + "takenAt": "2018-02-01T20:14:19.323Z", + "path": "/foo/bar/.projects/e2e/cypress/screenshots/simple_failing_hook_spec.coffee/simple failing hook spec -- afterEach hooks -- runs this -- after each hook (failed).png", + "height": 720, + "width": 1280 + } + ] + }, + { + "state": "failed", + "error": { + "name": "Error", + "message": "fail2", + "stack": "[stack trace lines]" + }, + "videoTimestamp": 9999, + "duration": 1234, + "startedAt": "2018-02-01T20:14:19.323Z", + "screenshots": [ + { + "name": null, + "takenAt": "2018-02-01T20:14:19.323Z", + "path": "/foo/bar/.projects/e2e/cypress/screenshots/simple_failing_hook_spec.coffee/simple failing hook spec -- afterEach hooks -- runs this -- after each hook (failed) (attempt 2).png", + "height": 720, + "width": 1280 + } + ] + } + ] + }, + { + "title": [ + "simple failing hook spec", + "afterEach hooks", + "does not run this" + ], + "state": "skipped", + "body": "function() {}", + "displayError": null, + "attempts": [ + { + "state": "skipped", + "error": null, + "videoTimestamp": null, + "duration": null, + "startedAt": null, + "screenshots": [] + } + ] + }, + { + "title": [ + "simple failing hook spec", + "after hooks", + "runs this" + ], + "state": "passed", + "body": "function() {}", + "displayError": null, + "attempts": [ + { + "state": "passed", + "error": null, + "videoTimestamp": 9999, + "duration": 1234, + "startedAt": "2018-02-01T20:14:19.323Z", + "screenshots": [] + } + ] + }, + { + "title": [ + "simple failing hook spec", + "after hooks", + "fails on this" + ], + "state": "failed", + "body": "function() {}", + "displayError": "Error: fail3\n\nBecause this error occurred during a `after all` hook we are skipping the remaining tests in the current suite: `after hooks`\n\nAlthough you have test retries enabled, we do not retry tests when `before all` or `after all` hooks fail\n [stack trace lines]", + "attempts": [ + { + "state": "failed", + "error": { + "name": "Error", + "message": "fail3\n\nBecause this error occurred during a `after all` hook we are skipping the remaining tests in the current suite: `after hooks`\n\nAlthough you have test retries enabled, we do not retry tests when `before all` or `after all` hooks fail", + "stack": "[stack trace lines]" + }, + "videoTimestamp": 9999, + "duration": 1234, + "startedAt": "2018-02-01T20:14:19.323Z", + "screenshots": [ + { + "name": null, + "takenAt": "2018-02-01T20:14:19.323Z", + "path": "/foo/bar/.projects/e2e/cypress/screenshots/simple_failing_hook_spec.coffee/simple failing hook spec -- after hooks -- fails on this -- after all hook (failed).png", + "height": 720, + "width": 1280 + } + ] + } + ] + } + ], + "error": null, + "video": "/foo/bar/.projects/e2e/cypress/videos/simple_failing_hook_spec.coffee.mp4", + "spec": { + "name": "simple_failing_hook_spec.coffee", + "relative": "cypress/integration/simple_failing_hook_spec.coffee", + "absolute": "/foo/bar/.projects/e2e/cypress/integration/simple_failing_hook_spec.coffee", + "specType": "integration" + }, + "shouldUploadVideo": true + } + ], + "browserPath": "path/to/browser", + "browserName": "FooBrowser", + "browserVersion": "88", + "osName": "FooOS", + "osVersion": "1234", + "cypressVersion": "9.9.9", + "config": {} +} diff --git a/packages/server/__snapshots__/5_stdout_spec.js b/packages/server/__snapshots__/5_stdout_spec.js index bc8aa9edb69e..8b8abed0ca38 100644 --- a/packages/server/__snapshots__/5_stdout_spec.js +++ b/packages/server/__snapshots__/5_stdout_spec.js @@ -141,10 +141,14 @@ Oops...we found an error preparing this test file: The error was: -/foo/bar/.projects/e2e/cypress/integration/stdout_exit_early_failing_spec.js:1 -+ > - ^ -ParseError: Unexpected token +Error: Webpack Compilation Error +./cypress/integration/stdout_exit_early_failing_spec.js +Module build failed (from [..]): +SyntaxError: /foo/bar/.projects/e2e/cypress/integration/stdout_exit_early_failing_spec.js: Unexpected token (1:1) + +> 1 | +> + | ^ + 2 | This occurred while Cypress was compiling and bundling your test code. This is usually caused by: diff --git a/packages/server/__snapshots__/5_subdomain_spec.js b/packages/server/__snapshots__/5_subdomain_spec.ts.js similarity index 100% rename from packages/server/__snapshots__/5_subdomain_spec.js rename to packages/server/__snapshots__/5_subdomain_spec.ts.js diff --git a/packages/server/__snapshots__/7_record_spec.js b/packages/server/__snapshots__/7_record_spec.js index 1421c521401b..a9d38b4101fd 100644 --- a/packages/server/__snapshots__/7_record_spec.js +++ b/packages/server/__snapshots__/7_record_spec.js @@ -11,7 +11,7 @@ exports['e2e record passing passes 1'] = ` โ”‚ e, record_uncaught_spec.coffee) โ”‚ โ”‚ Searched: cypress/integration/record* โ”‚ โ”‚ Params: Tag: false, Group: false, Parallel: false โ”‚ - โ”‚ Run URL: https://dashboard.cypress.io/#/projects/cjvoj7/runs/12 โ”‚ + โ”‚ Run URL: https://dashboard.cypress.io/projects/cjvoj7/runs/12 โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ @@ -26,7 +26,18 @@ Oops...we found an error preparing this test file: The error was: -Error: Cannot find module '../it/does/not/exist' from '/foo/bar/.projects/e2e/cypress/integration' +Error: Webpack Compilation Error +./cypress/integration/record_error_spec.coffee +Module not found: Error: Can't resolve '../it/does/not/exist' in '/foo/bar/.projects/e2e/cypress/integration' +Looked for and couldn't find the file at the following paths: +[/foo/bar/.projects/e2e/cypress/it/does/not/exist] +[/foo/bar/.projects/e2e/cypress/it/does/not/exist.js] +[/foo/bar/.projects/e2e/cypress/it/does/not/exist.json] +[/foo/bar/.projects/e2e/cypress/it/does/not/exist.jsx] +[/foo/bar/.projects/e2e/cypress/it/does/not/exist.coffee] +[/foo/bar/.projects/e2e/cypress/it/does/not/exist.ts] +[/foo/bar/.projects/e2e/cypress/it/does/not/exist.tsx] + @ ./cypress/integration/record_error_spec.coffee 1:0-31 This occurred while Cypress was compiling and bundling your test code. This is usually caused by: @@ -236,7 +247,7 @@ We dynamically generated a new test to display this failure. โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - Recorded Run: https://dashboard.cypress.io/#/projects/cjvoj7/runs/12 + Recorded Run: https://dashboard.cypress.io/projects/cjvoj7/runs/12 ` @@ -337,7 +348,7 @@ exports['e2e record api interaction errors create instance does not update insta โ”‚ Specs: 1 found (record_pass_spec.coffee) โ”‚ โ”‚ Searched: cypress/integration/record_pass* โ”‚ โ”‚ Params: Tag: false, Group: false, Parallel: false โ”‚ - โ”‚ Run URL: https://dashboard.cypress.io/#/projects/cjvoj7/runs/12 โ”‚ + โ”‚ Run URL: https://dashboard.cypress.io/projects/cjvoj7/runs/12 โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ Warning: We encountered an error talking to our servers. @@ -396,7 +407,7 @@ StatusCodeError: 500 - "Internal Server Error" โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - Recorded Run: https://dashboard.cypress.io/#/projects/cjvoj7/runs/12 + Recorded Run: https://dashboard.cypress.io/projects/cjvoj7/runs/12 ` @@ -413,7 +424,7 @@ exports['e2e record api interaction errors update instance does not update insta โ”‚ Specs: 1 found (record_pass_spec.coffee) โ”‚ โ”‚ Searched: cypress/integration/record_pass* โ”‚ โ”‚ Params: Tag: false, Group: false, Parallel: false โ”‚ - โ”‚ Run URL: https://dashboard.cypress.io/#/projects/cjvoj7/runs/12 โ”‚ + โ”‚ Run URL: https://dashboard.cypress.io/projects/cjvoj7/runs/12 โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ @@ -477,7 +488,7 @@ StatusCodeError: 500 - "Internal Server Error" โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - Recorded Run: https://dashboard.cypress.io/#/projects/cjvoj7/runs/12 + Recorded Run: https://dashboard.cypress.io/projects/cjvoj7/runs/12 ` @@ -494,7 +505,7 @@ exports['e2e record api interaction errors update instance stdout warns but proc โ”‚ Specs: 1 found (record_pass_spec.coffee) โ”‚ โ”‚ Searched: cypress/integration/record_pass* โ”‚ โ”‚ Params: Tag: false, Group: false, Parallel: false โ”‚ - โ”‚ Run URL: https://dashboard.cypress.io/#/projects/cjvoj7/runs/12 โ”‚ + โ”‚ Run URL: https://dashboard.cypress.io/projects/cjvoj7/runs/12 โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ @@ -559,7 +570,7 @@ StatusCodeError: 500 - "Internal Server Error" โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - Recorded Run: https://dashboard.cypress.io/#/projects/cjvoj7/runs/12 + Recorded Run: https://dashboard.cypress.io/projects/cjvoj7/runs/12 ` @@ -615,7 +626,7 @@ exports['e2e record video recording does not upload when not enabled 1'] = ` โ”‚ Specs: 1 found (record_pass_spec.coffee) โ”‚ โ”‚ Searched: cypress/integration/record_pass* โ”‚ โ”‚ Params: Tag: false, Group: false, Parallel: false โ”‚ - โ”‚ Run URL: https://dashboard.cypress.io/#/projects/cjvoj7/runs/12 โ”‚ + โ”‚ Run URL: https://dashboard.cypress.io/projects/cjvoj7/runs/12 โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ @@ -673,7 +684,7 @@ exports['e2e record video recording does not upload when not enabled 1'] = ` โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - Recorded Run: https://dashboard.cypress.io/#/projects/cjvoj7/runs/12 + Recorded Run: https://dashboard.cypress.io/projects/cjvoj7/runs/12 ` @@ -690,7 +701,7 @@ exports['e2e record api interaction errors uploading assets warns but proceeds 1 โ”‚ Specs: 1 found (record_pass_spec.coffee) โ”‚ โ”‚ Searched: cypress/integration/record_pass* โ”‚ โ”‚ Params: Tag: false, Group: false, Parallel: false โ”‚ - โ”‚ Run URL: https://dashboard.cypress.io/#/projects/cjvoj7/runs/12 โ”‚ + โ”‚ Run URL: https://dashboard.cypress.io/projects/cjvoj7/runs/12 โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ @@ -755,7 +766,7 @@ exports['e2e record api interaction errors uploading assets warns but proceeds 1 โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - Recorded Run: https://dashboard.cypress.io/#/projects/cjvoj7/runs/12 + Recorded Run: https://dashboard.cypress.io/projects/cjvoj7/runs/12 ` @@ -871,7 +882,7 @@ exports['e2e record parallelization passes in parallel with group 1'] = ` โ”‚ e, record_uncaught_spec.coffee) โ”‚ โ”‚ Searched: cypress/integration/record* โ”‚ โ”‚ Params: Tag: nightly, Group: prod-e2e, Parallel: true โ”‚ - โ”‚ Run URL: https://dashboard.cypress.io/#/projects/cjvoj7/runs/12 โ”‚ + โ”‚ Run URL: https://dashboard.cypress.io/projects/cjvoj7/runs/12 โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ @@ -929,7 +940,7 @@ exports['e2e record parallelization passes in parallel with group 1'] = ` โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - Recorded Run: https://dashboard.cypress.io/#/projects/cjvoj7/runs/12 + Recorded Run: https://dashboard.cypress.io/projects/cjvoj7/runs/12 ` @@ -947,7 +958,7 @@ exports['e2e record parallelization passes in parallel with group 2'] = ` โ”‚ e, record_uncaught_spec.coffee) โ”‚ โ”‚ Searched: cypress/integration/record* โ”‚ โ”‚ Params: Tag: nightly, Group: prod-e2e, Parallel: true โ”‚ - โ”‚ Run URL: https://dashboard.cypress.io/#/projects/cjvoj7/runs/12 โ”‚ + โ”‚ Run URL: https://dashboard.cypress.io/projects/cjvoj7/runs/12 โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ @@ -962,7 +973,18 @@ Oops...we found an error preparing this test file: The error was: -Error: Cannot find module '../it/does/not/exist' from '/foo/bar/.projects/e2e/cypress/integration' +Error: Webpack Compilation Error +./cypress/integration/record_error_spec.coffee +Module not found: Error: Can't resolve '../it/does/not/exist' in '/foo/bar/.projects/e2e/cypress/integration' +Looked for and couldn't find the file at the following paths: +[/foo/bar/.projects/e2e/cypress/it/does/not/exist] +[/foo/bar/.projects/e2e/cypress/it/does/not/exist.js] +[/foo/bar/.projects/e2e/cypress/it/does/not/exist.json] +[/foo/bar/.projects/e2e/cypress/it/does/not/exist.jsx] +[/foo/bar/.projects/e2e/cypress/it/does/not/exist.coffee] +[/foo/bar/.projects/e2e/cypress/it/does/not/exist.ts] +[/foo/bar/.projects/e2e/cypress/it/does/not/exist.tsx] + @ ./cypress/integration/record_error_spec.coffee 1:0-31 This occurred while Cypress was compiling and bundling your test code. This is usually caused by: @@ -1130,7 +1152,7 @@ We dynamically generated a new test to display this failure. โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - Recorded Run: https://dashboard.cypress.io/#/projects/cjvoj7/runs/12 + Recorded Run: https://dashboard.cypress.io/projects/cjvoj7/runs/12 ` @@ -1264,7 +1286,7 @@ exports['e2e record api interaction errors create instance 500 does not proceed โ”‚ Specs: 1 found (record_pass_spec.coffee) โ”‚ โ”‚ Searched: cypress/integration/record_pass* โ”‚ โ”‚ Params: Tag: nightly, Group: foo, Parallel: true โ”‚ - โ”‚ Run URL: https://dashboard.cypress.io/#/projects/cjvoj7/runs/12 โ”‚ + โ”‚ Run URL: https://dashboard.cypress.io/projects/cjvoj7/runs/12 โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ We encountered an unexpected error talking to our servers. @@ -1292,7 +1314,7 @@ exports['e2e record api interaction errors update instance 500 does not proceed โ”‚ Specs: 1 found (record_pass_spec.coffee) โ”‚ โ”‚ Searched: cypress/integration/record_pass* โ”‚ โ”‚ Params: Tag: nightly, Group: foo, Parallel: true โ”‚ - โ”‚ Run URL: https://dashboard.cypress.io/#/projects/cjvoj7/runs/12 โ”‚ + โ”‚ Run URL: https://dashboard.cypress.io/projects/cjvoj7/runs/12 โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ @@ -1380,7 +1402,7 @@ StatusCodeError: 500 - "Internal Server Error" โ”‚ Specs: 1 found (record_pass_spec.coffee) โ”‚ โ”‚ Searched: cypress/integration/record_pass* โ”‚ โ”‚ Params: Tag: nightly, Group: foo, Parallel: true โ”‚ - โ”‚ Run URL: https://dashboard.cypress.io/#/projects/cjvoj7/runs/12 โ”‚ + โ”‚ Run URL: https://dashboard.cypress.io/projects/cjvoj7/runs/12 โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ We encountered an unexpected error talking to our servers. @@ -1445,7 +1467,7 @@ StatusCodeError: 500 - "Internal Server Error" โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - Recorded Run: https://dashboard.cypress.io/#/projects/cjvoj7/runs/12 + Recorded Run: https://dashboard.cypress.io/projects/cjvoj7/runs/12 ` @@ -1589,7 +1611,7 @@ https://on.cypress.io/dashboard/organizations/org-id-1234/billing โ”‚ Specs: 1 found (record_pass_spec.coffee) โ”‚ โ”‚ Searched: cypress/integration/record_pass* โ”‚ โ”‚ Params: Tag: false, Group: false, Parallel: false โ”‚ - โ”‚ Run URL: https://dashboard.cypress.io/#/projects/cjvoj7/runs/12 โ”‚ + โ”‚ Run URL: https://dashboard.cypress.io/projects/cjvoj7/runs/12 โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ @@ -1647,7 +1669,7 @@ https://on.cypress.io/dashboard/organizations/org-id-1234/billing โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - Recorded Run: https://dashboard.cypress.io/#/projects/cjvoj7/runs/12 + Recorded Run: https://dashboard.cypress.io/projects/cjvoj7/runs/12 ` @@ -1669,7 +1691,7 @@ https://on.cypress.io/dashboard/organizations/org-id-1234/billing โ”‚ Specs: 1 found (record_pass_spec.coffee) โ”‚ โ”‚ Searched: cypress/integration/record_pass* โ”‚ โ”‚ Params: Tag: false, Group: false, Parallel: false โ”‚ - โ”‚ Run URL: https://dashboard.cypress.io/#/projects/cjvoj7/runs/12 โ”‚ + โ”‚ Run URL: https://dashboard.cypress.io/projects/cjvoj7/runs/12 โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ @@ -1727,7 +1749,7 @@ https://on.cypress.io/dashboard/organizations/org-id-1234/billing โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - Recorded Run: https://dashboard.cypress.io/#/projects/cjvoj7/runs/12 + Recorded Run: https://dashboard.cypress.io/projects/cjvoj7/runs/12 ` @@ -1749,7 +1771,7 @@ https://on.cypress.io/dashboard/organizations/org-id-1234/billing โ”‚ Specs: 1 found (record_pass_spec.coffee) โ”‚ โ”‚ Searched: cypress/integration/record_pass* โ”‚ โ”‚ Params: Tag: false, Group: false, Parallel: false โ”‚ - โ”‚ Run URL: https://dashboard.cypress.io/#/projects/cjvoj7/runs/12 โ”‚ + โ”‚ Run URL: https://dashboard.cypress.io/projects/cjvoj7/runs/12 โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ @@ -1807,7 +1829,7 @@ https://on.cypress.io/dashboard/organizations/org-id-1234/billing โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - Recorded Run: https://dashboard.cypress.io/#/projects/cjvoj7/runs/12 + Recorded Run: https://dashboard.cypress.io/projects/cjvoj7/runs/12 ` @@ -1829,7 +1851,7 @@ https://on.cypress.io/dashboard/organizations/org-id-1234/billing โ”‚ Specs: 1 found (record_pass_spec.coffee) โ”‚ โ”‚ Searched: cypress/integration/record_pass* โ”‚ โ”‚ Params: Tag: false, Group: false, Parallel: false โ”‚ - โ”‚ Run URL: https://dashboard.cypress.io/#/projects/cjvoj7/runs/12 โ”‚ + โ”‚ Run URL: https://dashboard.cypress.io/projects/cjvoj7/runs/12 โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ @@ -1887,7 +1909,7 @@ https://on.cypress.io/dashboard/organizations/org-id-1234/billing โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - Recorded Run: https://dashboard.cypress.io/#/projects/cjvoj7/runs/12 + Recorded Run: https://dashboard.cypress.io/projects/cjvoj7/runs/12 ` @@ -1909,7 +1931,7 @@ https://on.cypress.io/dashboard/organizations/org-id-1234/billing โ”‚ Specs: 1 found (record_pass_spec.coffee) โ”‚ โ”‚ Searched: cypress/integration/record_pass* โ”‚ โ”‚ Params: Tag: false, Group: false, Parallel: false โ”‚ - โ”‚ Run URL: https://dashboard.cypress.io/#/projects/cjvoj7/runs/12 โ”‚ + โ”‚ Run URL: https://dashboard.cypress.io/projects/cjvoj7/runs/12 โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ @@ -1967,7 +1989,7 @@ https://on.cypress.io/dashboard/organizations/org-id-1234/billing โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - Recorded Run: https://dashboard.cypress.io/#/projects/cjvoj7/runs/12 + Recorded Run: https://dashboard.cypress.io/projects/cjvoj7/runs/12 ` @@ -1989,7 +2011,7 @@ https://on.cypress.io/dashboard/organizations/org-id-1234/billing โ”‚ Specs: 1 found (record_pass_spec.coffee) โ”‚ โ”‚ Searched: cypress/integration/record_pass* โ”‚ โ”‚ Params: Tag: false, Group: false, Parallel: false โ”‚ - โ”‚ Run URL: https://dashboard.cypress.io/#/projects/cjvoj7/runs/12 โ”‚ + โ”‚ Run URL: https://dashboard.cypress.io/projects/cjvoj7/runs/12 โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ @@ -2047,7 +2069,7 @@ https://on.cypress.io/dashboard/organizations/org-id-1234/billing โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - Recorded Run: https://dashboard.cypress.io/#/projects/cjvoj7/runs/12 + Recorded Run: https://dashboard.cypress.io/projects/cjvoj7/runs/12 ` @@ -2073,7 +2095,7 @@ Details: โ”‚ Specs: 1 found (record_pass_spec.coffee) โ”‚ โ”‚ Searched: cypress/integration/record_pass* โ”‚ โ”‚ Params: Tag: false, Group: false, Parallel: false โ”‚ - โ”‚ Run URL: https://dashboard.cypress.io/#/projects/cjvoj7/runs/12 โ”‚ + โ”‚ Run URL: https://dashboard.cypress.io/projects/cjvoj7/runs/12 โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ @@ -2131,7 +2153,272 @@ Details: โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - Recorded Run: https://dashboard.cypress.io/#/projects/cjvoj7/runs/12 + Recorded Run: https://dashboard.cypress.io/projects/cjvoj7/runs/12 ` + +exports['e2e record passing passes 2'] = [ + { + "stats": { + "suites": 1, + "tests": 2, + "passes": 0, + "pending": 0, + "skipped": 1, + "failures": 1, + "wallClockStartedAt": "2018-02-01T20:14:19.323Z", + "wallClockEndedAt": "2018-02-01T20:14:19.323Z", + "wallClockDuration": 1234 + }, + "tests": [ + { + "testId": "r3", + "title": [ + "record fails", + "fails 1" + ], + "state": "failed", + "body": "function() {}", + "displayError": "Error: foo\n\nBecause this error occurred during a `before each` hook we are skipping the remaining tests in the current suite: `record fails`\n [stack trace lines]", + "attempts": [ + { + "state": "failed", + "error": { + "name": "Error", + "message": "foo\n\nBecause this error occurred during a `before each` hook we are skipping the remaining tests in the current suite: `record fails`", + "stack": "[stack trace lines]" + }, + "timings": { + "lifecycle": 100, + "before each": [ + { + "hookId": "h1", + "fnDuration": 400, + "afterFnDuration": 200 + } + ] + }, + "failedFromHookId": "h1", + "wallClockStartedAt": "2018-02-01T20:14:19.323Z", + "wallClockDuration": 1234, + "videoTimestamp": 9999 + } + ] + }, + { + "testId": "r4", + "title": [ + "record fails", + "is skipped" + ], + "state": "skipped", + "body": "function() {}", + "displayError": null, + "attempts": [ + { + "state": "skipped", + "error": null, + "timings": null, + "failedFromHookId": null, + "wallClockStartedAt": null, + "wallClockDuration": null, + "videoTimestamp": null + } + ] + } + ], + "error": null, + "video": true, + "hooks": [ + { + "hookId": "h1", + "hookName": "before each", + "title": [ + "\"before each\" hook" + ], + "body": "function() {\n throw new Error(\"foo\");\n }" + } + ], + "screenshots": [ + { + "screenshotId": "some-random-id", + "name": null, + "testId": "r3", + "testAttemptIndex": 0, + "takenAt": "2018-02-01T20:14:19.323Z", + "height": 720, + "width": 1280 + } + ], + "cypressConfig": {}, + "reporterStats": { + "suites": 1, + "tests": 1, + "passes": 0, + "pending": 0, + "failures": 1, + "start": "2018-02-01T20:14:19.323Z", + "end": "2018-02-01T20:14:19.323Z", + "duration": 1234 + } + }, + { + "stats": { + "suites": 1, + "tests": 2, + "passes": 1, + "pending": 1, + "skipped": 0, + "failures": 0, + "wallClockStartedAt": "2018-02-01T20:14:19.323Z", + "wallClockEndedAt": "2018-02-01T20:14:19.323Z", + "wallClockDuration": 1234 + }, + "tests": [ + { + "testId": "r3", + "title": [ + "record pass", + "passes" + ], + "state": "passed", + "body": "function() {\n cy.visit(\"/scrollable.html\");\n return cy.viewport(400, 400).get(\"#box\").screenshot('yay it passes');\n }", + "displayError": null, + "attempts": [ + { + "state": "passed", + "error": null, + "timings": { + "lifecycle": 100, + "test": { + "fnDuration": 400, + "afterFnDuration": 200 + } + }, + "failedFromHookId": null, + "wallClockStartedAt": "2018-02-01T20:14:19.323Z", + "wallClockDuration": 1234, + "videoTimestamp": 9999 + } + ] + }, + { + "testId": "r4", + "title": [ + "record pass", + "is pending" + ], + "state": "pending", + "body": "", + "displayError": null, + "attempts": [ + { + "state": "pending", + "error": null, + "timings": null, + "failedFromHookId": null, + "wallClockStartedAt": null, + "wallClockDuration": null, + "videoTimestamp": null + } + ] + } + ], + "error": null, + "video": true, + "hooks": [], + "screenshots": [ + { + "screenshotId": "some-random-id", + "name": "yay it passes", + "testId": "r3", + "testAttemptIndex": 0, + "takenAt": "2018-02-01T20:14:19.323Z", + "height": 1002, + "width": 202 + } + ], + "cypressConfig": {}, + "reporterStats": { + "suites": 1, + "tests": 2, + "passes": 1, + "pending": 1, + "failures": 0, + "start": "2018-02-01T20:14:19.323Z", + "end": "2018-02-01T20:14:19.323Z", + "duration": 1234 + } + }, + { + "stats": { + "suites": 0, + "tests": 1, + "passes": 0, + "pending": 0, + "skipped": 0, + "failures": 1, + "wallClockStartedAt": "2018-02-01T20:14:19.323Z", + "wallClockEndedAt": "2018-02-01T20:14:19.323Z", + "wallClockDuration": 1234 + }, + "tests": [ + { + "testId": "r2", + "title": [ + "An uncaught error was detected outside of a test" + ], + "state": "failed", + "body": "function throwErr() {\n throw err;\n }", + "displayError": "Error: The following error originated from your test code, not from Cypress.\n\n > instantly fails\n\nWhen Cypress detects uncaught errors originating from your test code it will automatically fail the current test.\n\nCypress could not associate this error to any specific test.\n\nWe dynamically generated a new test to display this failure.\n [stack trace lines]", + "attempts": [ + { + "state": "failed", + "error": { + "name": "Error", + "message": "The following error originated from your test code, not from Cypress.\n\n > instantly fails\n\nWhen Cypress detects uncaught errors originating from your test code it will automatically fail the current test.\n\nCypress could not associate this error to any specific test.\n\nWe dynamically generated a new test to display this failure.", + "stack": "[stack trace lines]" + }, + "timings": { + "lifecycle": 100, + "test": { + "fnDuration": 400, + "afterFnDuration": 200 + } + }, + "failedFromHookId": null, + "wallClockStartedAt": "2018-02-01T20:14:19.323Z", + "wallClockDuration": 1234, + "videoTimestamp": 9999 + } + ] + } + ], + "error": null, + "video": true, + "hooks": [], + "screenshots": [ + { + "screenshotId": "some-random-id", + "name": null, + "testId": "r2", + "testAttemptIndex": 0, + "takenAt": "2018-02-01T20:14:19.323Z", + "height": 720, + "width": 1280 + } + ], + "cypressConfig": {}, + "reporterStats": { + "suites": 0, + "tests": 1, + "passes": 0, + "pending": 0, + "failures": 1, + "start": "2018-02-01T20:14:19.323Z", + "end": "2018-02-01T20:14:19.323Z", + "duration": 1234 + } + } +] diff --git a/packages/server/__snapshots__/8_reporters_spec.js b/packages/server/__snapshots__/8_reporters_spec.js index 706d8c13fa0e..55b815c5dfd0 100644 --- a/packages/server/__snapshots__/8_reporters_spec.js +++ b/packages/server/__snapshots__/8_reporters_spec.js @@ -224,15 +224,13 @@ exports['e2e reporters mochawesome fails with mochawesome-1.5.2 npm custom repor pending - is pending afterEach hooks - โœ“ runs this 2) "after each" hook for "runs this" after hooks โœ“ runs this - โœ“ fails on this 3) "after all" hook for "fails on this" - 3 passing + 1 passing 1 pending 3 failing @@ -404,15 +402,13 @@ exports['e2e reporters mochawesome fails with mochawesome-2.3.1 npm custom repor pending - is pending afterEach hooks - โœ“ runs this 2) "after each" hook for "runs this" after hooks โœ“ runs this - โœ“ fails on this 3) "after all" hook for "fails on this" - 3 passing + 1 passing 1 pending 3 failing @@ -584,15 +580,13 @@ exports['e2e reporters mochawesome fails with mochawesome-3.0.1 npm custom repor pending - is pending afterEach hooks - โœ“ runs this 2) "after each" hook for "runs this" after hooks โœ“ runs this - โœ“ fails on this 3) "after all" hook for "fails on this" - 3 passing + 1 passing 1 pending 3 failing diff --git a/packages/server/__snapshots__/browsers_spec.js b/packages/server/__snapshots__/browsers_spec.js index c311767ebe9b..d7e3f9a23c14 100644 --- a/packages/server/__snapshots__/browsers_spec.js +++ b/packages/server/__snapshots__/browsers_spec.js @@ -37,7 +37,7 @@ Available browsers found on your system are: - chrome:canary - firefox -Note: In Cypress 4.0, Canary must be launched as \`chrome:canary\`, not \`canary\`. +Note: In Cypress version 4.0.0, Canary must be launched as \`chrome:canary\`, not \`canary\`. -See https://on.cypress.io/migration-guide for more information on breaking changes in 4.0. +See https://on.cypress.io/migration-guide for more information on breaking changes in 4.0.0. ` diff --git a/packages/server/__snapshots__/reporter_spec.js b/packages/server/__snapshots__/reporter_spec.js index 5d5fdae8205a..6678e29bf06a 100644 --- a/packages/server/__snapshots__/reporter_spec.js +++ b/packages/server/__snapshots__/reporter_spec.js @@ -27,17 +27,21 @@ exports['lib/reporter #stats has reporterName stats, reporterStats, etc 1'] = { ], "state": "failed", "body": "", - "stack": [ - 1, - 2, - 3 - ], - "error": "foo", - "timings": null, - "failedFromHookId": null, - "wallClockStartedAt": null, - "wallClockDuration": null, - "videoTimestamp": null + "displayError": "at foo:1:1\nat bar:1:1\nat baz:1:1", + "attempts": [ + { + "state": "failed", + "error": { + "message": "foo", + "stack": "at foo:1:1\nat bar:1:1\nat baz:1:1" + }, + "timings": null, + "failedFromHookId": null, + "wallClockStartedAt": null, + "wallClockDuration": null, + "videoTimestamp": null + } + ] }, { "testId": "r5", @@ -48,13 +52,18 @@ exports['lib/reporter #stats has reporterName stats, reporterStats, etc 1'] = { ], "state": "pending", "body": "", - "stack": null, - "error": null, - "timings": null, - "failedFromHookId": null, - "wallClockStartedAt": null, - "wallClockDuration": null, - "videoTimestamp": null + "displayError": null, + "attempts": [ + { + "state": "pending", + "error": null, + "timings": null, + "failedFromHookId": null, + "wallClockStartedAt": null, + "wallClockDuration": null, + "videoTimestamp": null + } + ] } ] } diff --git a/packages/server/lib/api.js b/packages/server/lib/api.js index 176274721b43..a9f547bfc3ee 100644 --- a/packages/server/lib/api.js +++ b/packages/server/lib/api.js @@ -268,7 +268,7 @@ module.exports = { json: true, timeout: options.timeout != null ? options.timeout : SIXTY_SECONDS, headers: { - 'x-route-version': '2', + 'x-route-version': '3', }, body: _.pick(options, [ 'stats', diff --git a/packages/server/lib/browsers/electron.js b/packages/server/lib/browsers/electron.js index 51eb4f1283fd..84d83e4c5061 100644 --- a/packages/server/lib/browsers/electron.js +++ b/packages/server/lib/browsers/electron.js @@ -66,12 +66,12 @@ const _getAutomation = function (win, options) { return automation } -const _installExtensions = function (extensionPaths = [], options) { - Windows.removeAllExtensions() +const _installExtensions = function (win, extensionPaths = [], options) { + Windows.removeAllExtensions(win) - return extensionPaths.forEach((path) => { + return Bluebird.map(extensionPaths, (path) => { try { - return Windows.installExtension(path) + return Windows.installExtension(win, path) } catch (error) { return options.onWarning(errors.get('EXTENSION_NOT_LOADED', 'Electron', path)) } @@ -349,10 +349,10 @@ module.exports = { debug('launching browser window to url: %s', url) - _installExtensions(launchOptions.extensions, options) - return this._render(url, projectRoot, automation, preferences) - .then((win) => { + .then(async (win) => { + await _installExtensions(win, launchOptions.extensions, options) + // cause the webview to receive focus so that // native browser focus + blur events fire correctly // https://github.com/cypress-io/cypress/issues/1939 @@ -363,7 +363,7 @@ module.exports = { win.once('closed', () => { debug('closed event fired') - Windows.removeAllExtensions() + Windows.removeAllExtensions(win) return events.emit('exit') }) diff --git a/packages/server/lib/browsers/firefox-util.ts b/packages/server/lib/browsers/firefox-util.ts index 41b329a90c69..82b08cb06e9f 100644 --- a/packages/server/lib/browsers/firefox-util.ts +++ b/packages/server/lib/browsers/firefox-util.ts @@ -70,6 +70,9 @@ const getPrimaryTab = Bluebird.method((browser) => { }) const attachToTabMemory = Bluebird.method((tab) => { + // TODO: figure out why tab.memory is sometimes undefined + if (!tab.memory) return + if (tab.memory.isAttached) { return } @@ -186,6 +189,9 @@ export default { const gc = (tab) => { return () => { + // TODO: figure out why tab.memory is sometimes undefined + if (!tab.memory) return + let start = Date.now() return tab.memory.forceGarbageCollection() @@ -198,6 +204,9 @@ export default { const cc = (tab) => { return () => { + // TODO: figure out why tab.memory is sometimes undefined + if (!tab.memory) return + let start = Date.now() return tab.memory.forceCycleCollection() diff --git a/packages/server/lib/browsers/firefox.ts b/packages/server/lib/browsers/firefox.ts index 97a3da67d053..a57bc2bf4264 100644 --- a/packages/server/lib/browsers/firefox.ts +++ b/packages/server/lib/browsers/firefox.ts @@ -193,7 +193,7 @@ const defaultPreferences = { // Do not wait for the notification button security delay 'security.notification_enable_delay': 0, - // Ensure blocklist updates do not hit the network + // Ensure blocked updates do not hit the network 'services.settings.server': '', // Do not automatically fill sign-in forms with known usernames and diff --git a/packages/server/lib/config.js b/packages/server/lib/config.js index 73dd6f57db0c..5de52ab03c43 100644 --- a/packages/server/lib/config.js +++ b/packages/server/lib/config.js @@ -57,7 +57,7 @@ folders.push('componentFolder') const configKeys = toWords(`\ animationDistanceThreshold fileServerFolder baseUrl fixturesFolder -blacklistHosts +blockHosts chromeWebSecurity modifyObstructiveCode integrationFolder env pluginsFile @@ -80,21 +80,24 @@ screenshotOnRunFailure watchForFileChanges waitForAnimations resolvedNodeVersion nodeVersion resolvedNodePath -firefoxGcInterval\ +firefoxGcInterval +retries `) // NOTE: If you add a config value, make sure to update the following -// - cli/types/index.d.ts (including whitelisted config options on TestOptions) +// - cli/types/index.d.ts (including allowed config options on TestOptions) // - cypress.schema.json // experimentalComponentTesting configKeys.push('componentFolder') -// Deprecated and retired public configuration properties +// Breaking public configuration properties, will error const breakingConfigKeys = toWords(`\ +blacklistHosts videoRecording screenshotOnHeadlessFailure -trashAssetsBeforeHeadlessRuns\ +trashAssetsBeforeHeadlessRuns +experimentalGetCookiesSameSite\ `) // Internal configuration properties the user should be able to overwrite @@ -106,7 +109,6 @@ browsers\ // each should start with "experimental" and be camel cased // example: experimentalComponentTesting const experimentalConfigKeys = toWords(`\ -experimentalGetCookiesSameSite experimentalSourceRewriting experimentalComponentTesting experimentalShadowDomSupport @@ -126,7 +128,7 @@ const CONFIG_DEFAULTS = { isTextTerminal: false, reporter: 'spec', reporterOptions: null, - blacklistHosts: null, + blockHosts: null, clientRoute: '/__/', xhrRoute: '/xhrs/', socketIoRoute: '/__socket.io', @@ -176,16 +178,16 @@ const CONFIG_DEFAULTS = { componentFolder: 'cypress/component', // TODO: example for component testing with subkeys // experimentalComponentTesting: { componentFolder: 'cypress/component' } - experimentalGetCookiesSameSite: false, experimentalSourceRewriting: false, experimentalShadowDomSupport: false, experimentalFetchPolyfill: false, + retries: { runMode: 0, openMode: 0 }, } const validationRules = { animationDistanceThreshold: v.isNumber, baseUrl: v.isFullyQualifiedUrl, - blacklistHosts: v.isStringOrArrayOfStrings, + blockHosts: v.isStringOrArrayOfStrings, browsers: v.isValidBrowserList, chromeWebSecurity: v.isBoolean, configFile: v.isStringOrFalse, @@ -225,10 +227,10 @@ const validationRules = { // validation for component testing experiment componentFolder: v.isStringOrFalse, // experimental flag validation below - experimentalGetCookiesSameSite: v.isBoolean, experimentalSourceRewriting: v.isBoolean, experimentalShadowDomSupport: v.isBoolean, experimentalFetchPolyfill: v.isBoolean, + retries: v.isValidRetriesConfig, } const convertRelativeToAbsolutePaths = (projectRoot, obj, defaults = {}) => { @@ -254,7 +256,12 @@ const validateNoBreakingConfig = (cfg) => { return errors.throw('RENAMED_CONFIG_OPTION', key, 'trashAssetsBeforeRuns') case 'videoRecording': return errors.throw('RENAMED_CONFIG_OPTION', key, 'video') + case 'blacklistHosts': + return errors.throw('RENAMED_CONFIG_OPTION', key, 'blockHosts') + case 'experimentalGetCookiesSameSite': + return errors.warning('EXPERIMENTAL_SAMESITE_REMOVED') default: + throw new Error(`unknown breaking config key ${key}`) } } }) @@ -374,7 +381,7 @@ module.exports = { return _.includes(names, value) }, - whitelist (obj = {}) { + allowed (obj = {}) { const propertyNames = configKeys .concat(breakingConfigKeys) .concat(systemConfigKeys) @@ -429,7 +436,7 @@ module.exports = { debug('merged config with options, got %o', config) _ - .chain(this.whitelist(options)) + .chain(this.allowed(options)) .omit('env') .omit('browsers') .each((val, key) => { diff --git a/packages/server/lib/controllers/spec.js b/packages/server/lib/controllers/spec.js index b227cc9aa9b4..1cd4a4ce5606 100644 --- a/packages/server/lib/controllers/spec.js +++ b/packages/server/lib/controllers/spec.js @@ -3,6 +3,26 @@ const Promise = require('bluebird') const errors = require('../errors') const preprocessor = require('../plugins/preprocessor') +const ignoreECONNABORTED = () => { + // https://github.com/cypress-io/cypress/issues/1877 + // now that we are properly catching errors from + // res.sendFile, sendFile will reject if the browser aborts + // its internal requests (as it shuts down) with + // ECONNABORTED. This happens because if a previous spec + // file is unable to be transpiled correctly, we immediately + // shut down the run, which closes the browser, triggering + // the browser to abort the request which would end up here + // and display two different errors. +} + +const ignoreEPIPE = () => { + // 'write EPIPE' errors can occur if a spec is served and then rerun + // quickly because it's trying to send the spec file to a socket that + // has already been closed. this can be ignored because it means + // another version of the file has already been sent and will + // be loaded by the browser instead +} + module.exports = { handle (spec, req, res, config, next, onError) { debug('request for %o', { spec }) @@ -22,17 +42,12 @@ module.exports = { const sendFile = Promise.promisify(res.sendFile.bind(res)) return sendFile(filePath) - }).catch({ code: 'ECONNABORTED' }, (err) => { - // https://github.com/cypress-io/cypress/issues/1877 - // now that we are properly catching errors from - // res.sendFile, sendFile will reject if the browser aborts - // its internal requests (as it shuts down) with - // ECONNABORTED. This happens because if a previous spec - // file is unable to be transpiled correctly, we immediately - // shut down the run, which closes the browser, triggering - // the browser to abort the request which would end up here - // and display two different errors. - }).catch((err) => { + }) + .catch({ code: 'ECONNABORTED' }, ignoreECONNABORTED) + .catch({ code: 'EPIPE' }, ignoreEPIPE) + .catch((err) => { + debug(`preprocessor error for spec '%s': %s`, spec, err.stack) + if (!config.isTextTerminal) { return res.send(preprocessor.clientSideError(err)) } diff --git a/packages/server/lib/errors.js b/packages/server/lib/errors.js index 1df5ba0f7022..fe9e18f81abd 100644 --- a/packages/server/lib/errors.js +++ b/packages/server/lib/errors.js @@ -137,9 +137,9 @@ const getMsgByType = function (type, arg1 = {}, arg2, arg3) { if (arg1 === 'canary') { str += '\n\n' str += stripIndent`\ - Note: In Cypress 4.0, Canary must be launched as \`chrome:canary\`, not \`canary\`. + Note: In Cypress version 4.0.0, Canary must be launched as \`chrome:canary\`, not \`canary\`. - See https://on.cypress.io/migration-guide for more information on breaking changes in 4.0.` + See https://on.cypress.io/migration-guide for more information on breaking changes in 4.0.0.` } return str @@ -648,7 +648,7 @@ const getMsgByType = function (type, arg1 = {}, arg2, arg3) { ${chalk.yellow(arg1)}` case 'SCREENSHOT_ON_HEADLESS_FAILURE_REMOVED': return stripIndent`\ - In Cypress v3.0.0 we removed the configuration option ${chalk.yellow('\`screenshotOnHeadlessFailure\`')} + In Cypress version 3.0.0 we removed the configuration option ${chalk.yellow('\`screenshotOnHeadlessFailure\`')} You now configure this behavior in your test code. @@ -664,7 +664,7 @@ const getMsgByType = function (type, arg1 = {}, arg2, arg3) { Learn more at https://on.cypress.io/screenshot-api` case 'RENAMED_CONFIG_OPTION': return stripIndent`\ - A configuration option you have supplied has been renamed. + The ${chalk.yellow(arg1)} configuration option you have supplied has been renamed. Please rename ${chalk.yellow(arg1)} to ${chalk.blue(arg2)}` case 'CANNOT_CONNECT_BASE_URL': @@ -923,6 +923,21 @@ const getMsgByType = function (type, arg1 = {}, arg2, arg3) { Enable write permissions to this directory to ensure screenshots and videos are stored. If you don't require screenshots or videos to be stored you can safely ignore this warning.` + case 'EXPERIMENTAL_SAMESITE_REMOVED': + return stripIndent`\ + The \`experimentalGetCookiesSameSite\` configuration option was removed in Cypress version \`5.0.0\`. Yielding the \`sameSite\` property is now the default behavior of the \`cy.cookie\` commands. + + You can safely remove this option from your config.` + case 'INCOMPATIBLE_PLUGIN_RETRIES': + return stripIndent`\ + We've detected that the incompatible plugin \`cypress-plugin-retries\` is installed at \`${arg1}\`. + + Test retries is now supported in Cypress version \`5.0.0\`. + + Remove the plugin from your dependencies to silence this warning. + + https://on.cypress.io/test-retries + ` default: } } diff --git a/packages/server/lib/experiments.ts b/packages/server/lib/experiments.ts index 610bf5d194e3..e365e019ac56 100644 --- a/packages/server/lib/experiments.ts +++ b/packages/server/lib/experiments.ts @@ -53,7 +53,6 @@ interface StringValues { const _summaries: StringValues = { experimentalComponentTesting: 'Framework-specific component testing, uses `componentFolder` to load component specs', experimentalSourceRewriting: 'Enables AST-based JS/HTML rewriting. This may fix issues caused by the existing regex-based JS/HTML replacement algorithm.', - experimentalGetCookiesSameSite: 'Adds `sameSite` values to the objects yielded from `cy.setCookie()`, `cy.getCookie()`, and `cy.getCookies()`. This will become the default behavior in Cypress 5.0.', experimentalFetchPolyfill: 'Polyfills `window.fetch` to enable Network spying and stubbing', experimentalShadowDomSupport: 'Enables support for shadow DOM traversal, introduces the `shadow()` command and the `includeShadowDom` option to traversal commands.', } @@ -71,7 +70,6 @@ const _summaries: StringValues = { const _names: StringValues = { experimentalComponentTesting: 'Component Testing', experimentalSourceRewriting: 'Improved source rewriting', - experimentalGetCookiesSameSite: 'Set `sameSite` property when retrieving cookies', experimentalShadowDomSupport: 'Shadow DOM Support', experimentalFetchPolyfill: 'Fetch polyfill', } diff --git a/packages/server/lib/gui/events.js b/packages/server/lib/gui/events.js index 6bf51c919b19..57038921675e 100644 --- a/packages/server/lib/gui/events.js +++ b/packages/server/lib/gui/events.js @@ -36,6 +36,11 @@ const nullifyUnserializableValues = (obj) => { const handleEvent = function (options, bus, event, id, type, arg) { debug('got request for event: %s, %o', type, arg) + _.defaults(options, { + windowOpenFn: Windows.open, + getWindowByWebContentsFn: Windows.getByWebContents, + }) + const sendResponse = function (originalData = {}) { try { const data = nullifyUnserializableValues(originalData) @@ -167,12 +172,12 @@ const handleEvent = function (options, bus, event, id, type, arg) { .catch(sendErr) case 'window:open': - return Windows.open(options.projectRoot, arg) + return options.windowOpenFn(options.projectRoot, arg) .then(send) .catch(sendErr) case 'window:close': - return Windows.getByWebContents(event.sender).destroy() + return options.getWindowByWebContentsFn(event.sender).destroy() case 'open:file': return fileOpener.openFile(arg) diff --git a/packages/server/lib/gui/windows.js b/packages/server/lib/gui/windows.js deleted file mode 100644 index db5aff55c18f..000000000000 --- a/packages/server/lib/gui/windows.js +++ /dev/null @@ -1,327 +0,0 @@ -const _ = require('lodash') -const Promise = require('bluebird') -const cyDesktop = require('@packages/desktop-gui') -const contextMenu = require('electron-context-menu') -const { BrowserWindow } = require('electron') -const debug = require('debug')('cypress:server:windows') -const cwd = require('../cwd') -const savedState = require('../saved_state') - -let windows = {} -let recentlyCreatedWindow = false - -const getUrl = function (type) { - switch (type) { - case 'INDEX': - return cyDesktop.getPathToIndex() - default: - throw new Error(`No acceptable window type found for: '${type}'`) - } -} - -const getByType = (type) => { - return windows[type] -} - -const setWindowProxy = function (win) { - if (!process.env.HTTP_PROXY) { - return - } - - return win.webContents.session.setProxy({ - proxyRules: process.env.HTTP_PROXY, - proxyBypassRules: process.env.NO_PROXY, - }) -} - -module.exports = { - installExtension (path) { - // extensions can only be installed for all BrowserWindows - const name = BrowserWindow.addExtension(path) - - debug('electron extension installed %o', { success: !!name, name, path }) - - if (!name) { - throw new Error('Extension could not be installed.') - } - }, - - removeAllExtensions () { - const extensions = _.keys(BrowserWindow.getExtensions()) - - debug('removing all electron extensions %o', extensions) - - return extensions.forEach(BrowserWindow.removeExtension) - }, - - reset () { - windows = {} - }, - - destroy (type) { - let win - - if (type && (win = getByType(type))) { - return win.destroy() - } - }, - - get (type) { - return getByType(type) || (() => { - throw new Error(`No window exists for: '${type}'`) - })() - }, - - showAll () { - return _.invoke(windows, 'showInactive') - }, - - hideAllUnlessAnotherWindowIsFocused () { - // bail if we have another focused window - // or we are in the middle of creating a new one - if (BrowserWindow.getFocusedWindow() || recentlyCreatedWindow) { - return - } - - // else hide all windows - return _.invoke(windows, 'hide') - }, - - focusMainWindow () { - return getByType('INDEX').show() - }, - - getByWebContents (webContents) { - return BrowserWindow.fromWebContents(webContents) - }, - - _newBrowserWindow (options) { - return new BrowserWindow(options) - }, - - defaults (options = {}) { - return _.defaultsDeep(options, { - x: null, - y: null, - show: true, - frame: true, - width: null, - height: null, - minWidth: null, - minHeight: null, - devTools: false, - trackState: false, - contextMenu: false, - recordFrameRate: null, - // extension: null ## TODO add these once we update electron - // devToolsExtension: null ## since these API's were added in 1.7.6 - onFocus () {}, - onBlur () {}, - onClose () {}, - onCrashed () {}, - onNewWindow () {}, - webPreferences: { - partition: null, - webSecurity: true, - nodeIntegration: false, - backgroundThrottling: false, - }, - }) - }, - - create (projectRoot, options = {}) { - let ts - - options = this.defaults(options) - - if (options.show === false) { - options.frame = false - options.webPreferences.offscreen = true - } - - options.webPreferences.webSecurity = !!options.chromeWebSecurity - - if (options.partition) { - options.webPreferences.partition = options.partition - } - - const win = this._newBrowserWindow(options) - - win.on('blur', function (...args) { - return options.onBlur.apply(win, args) - }) - - win.on('focus', function (...args) { - return options.onFocus.apply(win, args) - }) - - win.once('closed', function (...args) { - win.removeAllListeners() - - return options.onClose.apply(win, args) - }) - - // the webview loses focus on navigation, so we - // have to refocus it everytime top navigates in headless mode - // https://github.com/cypress-io/cypress/issues/2190 - if (options.show === false) { - win.webContents.on('did-start-loading', () => { - if (!win.isDestroyed()) { - return win.focusOnWebView() - } - }) - } - - win.webContents.on('crashed', function (...args) { - return options.onCrashed.apply(win, args) - }) - - win.webContents.on('new-window', function (...args) { - return options.onNewWindow.apply(win, args) - }) - - ts = options.trackState - - if (ts) { - this.trackState(projectRoot, options.isTextTerminal, win, ts) - } - - // open dev tools if they're true - if (options.devTools) { - // and possibly detach dev tools if true - win.webContents.openDevTools() - } - - if (options.contextMenu) { - // adds context menu with copy, paste, inspect element, etc - contextMenu({ - showInspectElement: true, - window: win, - }) - } - - return win - }, - - open (projectRoot, options = {}) { - // if we already have a window open based - // on that type then just show + focus it! - let win - - win = getByType(options.type) - - if (win) { - win.show() - - return Promise.resolve(win) - } - - recentlyCreatedWindow = true - - _.defaults(options, { - width: 600, - height: 500, - show: true, - webPreferences: { - preload: cwd('lib', 'ipc', 'ipc.js'), - }, - }) - - if (!options.url) { - options.url = getUrl(options.type) - } - - win = this.create(projectRoot, options) - - debug('creating electron window with options %o', options) - - windows[options.type] = win - - win.webContents.id = _.uniqueId('webContents') - - win.once('closed', () => { - delete windows[options.type] - }) - - // enable our url to be a promise - // and wait for this to be resolved - return Promise.join( - options.url, - setWindowProxy(win), - ) - .spread((url) => { - // navigate the window here! - win.loadURL(url) - - recentlyCreatedWindow = false - }).thenReturn(win) - }, - - trackState (projectRoot, isTextTerminal, win, keys) { - const isDestroyed = () => { - return win.isDestroyed() - } - - win.on('resize', _.debounce(() => { - if (isDestroyed()) { - return - } - - const [width, height] = win.getSize() - const [x, y] = win.getPosition() - const newState = {} - - newState[keys.width] = width - newState[keys.height] = height - newState[keys.x] = x - newState[keys.y] = y - - return savedState.create(projectRoot, isTextTerminal) - .then((state) => { - return state.set(newState) - }) - } - , 500)) - - win.on('moved', _.debounce(() => { - if (isDestroyed()) { - return - } - - const [x, y] = win.getPosition() - const newState = {} - - newState[keys.x] = x - newState[keys.y] = y - - return savedState.create(projectRoot, isTextTerminal) - .then((state) => { - return state.set(newState) - }) - } - , 500)) - - win.webContents.on('devtools-opened', () => { - const newState = {} - - newState[keys.devTools] = true - - return savedState.create(projectRoot, isTextTerminal) - .then((state) => { - return state.set(newState) - }) - }) - - return win.webContents.on('devtools-closed', () => { - const newState = {} - - newState[keys.devTools] = false - - return savedState.create(projectRoot, isTextTerminal) - .then((state) => { - return state.set(newState) - }) - }) - }, - -} diff --git a/packages/server/lib/gui/windows.ts b/packages/server/lib/gui/windows.ts new file mode 100644 index 000000000000..f44a7bb6ab24 --- /dev/null +++ b/packages/server/lib/gui/windows.ts @@ -0,0 +1,332 @@ +import _ from 'lodash' +import Bluebird from 'bluebird' +import contextMenu from 'electron-context-menu' +import { BrowserWindow } from 'electron' +import Debug from 'debug' +import cwd from '../cwd' +import savedState from '../saved_state' +const cyDesktop = require('@packages/desktop-gui') + +const debug = Debug('cypress:server:windows') + +export type WindowOptions = Electron.BrowserWindowConstructorOptions & { + type?: 'INDEX' + url?: string + devTools?: boolean +} + +let windows = {} +let recentlyCreatedWindow = false + +const getUrl = function (type) { + switch (type) { + case 'INDEX': + return cyDesktop.getPathToIndex() + default: + throw new Error(`No acceptable window type found for: '${type}'`) + } +} + +const getByType = (type) => { + return windows[type] +} + +const setWindowProxy = function (win) { + if (!process.env.HTTP_PROXY) { + return + } + + return win.webContents.session.setProxy({ + proxyRules: process.env.HTTP_PROXY, + proxyBypassRules: process.env.NO_PROXY, + }) +} + +export function installExtension (win: BrowserWindow, path) { + return win.webContents.session.loadExtension(path) + .then((data) => { + debug('electron extension installed %o', { data, path }) + }) + .catch((err) => { + debug('error installing electron extension %o', { err, path }) + throw err + }) +} + +export function removeAllExtensions (win: BrowserWindow) { + let extensions + + try { + extensions = win.webContents.session.getAllExtensions() + + extensions.forEach(({ id }) => { + win.webContents.session.removeExtension(id) + }) + } catch (err) { + debug('error removing all extensions %o', { err, extensions }) + } +} + +export function reset () { + windows = {} +} + +export function destroy (type) { + let win + + if (type && (win = getByType(type))) { + return win.destroy() + } +} + +export function get (type) { + return getByType(type) || (() => { + throw new Error(`No window exists for: '${type}'`) + })() +} + +export function showAll () { + return _.invoke(windows, 'showInactive') +} + +export function hideAllUnlessAnotherWindowIsFocused () { + // bail if we have another focused window + // or we are in the middle of creating a new one + if (BrowserWindow.getFocusedWindow() || recentlyCreatedWindow) { + return + } + + // else hide all windows + return _.invoke(windows, 'hide') +} + +export function focusMainWindow () { + return getByType('INDEX').show() +} + +export function getByWebContents (webContents) { + return BrowserWindow.fromWebContents(webContents) +} + +export function _newBrowserWindow (options) { + return new BrowserWindow(options) +} + +export function defaults (options = {}) { + return _.defaultsDeep(options, { + x: null, + y: null, + show: true, + frame: true, + width: null, + height: null, + minWidth: null, + minHeight: null, + devTools: false, + trackState: false, + contextMenu: false, + recordFrameRate: null, + onFocus () {}, + onBlur () {}, + onClose () {}, + onCrashed () {}, + onNewWindow () {}, + webPreferences: { + partition: null, + webSecurity: true, + nodeIntegration: false, + backgroundThrottling: false, + }, + }) +} + +export function create (projectRoot, _options: WindowOptions = {}, newBrowserWindow = _newBrowserWindow) { + const options = defaults(_options) + + if (options.show === false) { + options.frame = false + options.webPreferences.offscreen = true + } + + options.webPreferences.webSecurity = !!options.chromeWebSecurity + + if (options.partition) { + options.webPreferences.partition = options.partition + } + + const win = newBrowserWindow(options) + + win.on('blur', function (...args) { + return options.onBlur.apply(win, args) + }) + + win.on('focus', function (...args) { + return options.onFocus.apply(win, args) + }) + + win.once('closed', function (...args) { + win.removeAllListeners() + + return options.onClose.apply(win, args) + }) + + // the webview loses focus on navigation, so we + // have to refocus it everytime top navigates in headless mode + // https://github.com/cypress-io/cypress/issues/2190 + if (options.show === false) { + win.webContents.on('did-start-loading', () => { + if (!win.isDestroyed()) { + return win.focusOnWebView() + } + }) + } + + win.webContents.on('crashed', function (...args) { + return options.onCrashed.apply(win, args) + }) + + win.webContents.on('new-window', function (...args) { + return options.onNewWindow.apply(win, args) + }) + + if (options.trackState) { + trackState(projectRoot, options.isTextTerminal, win, options.trackState) + } + + // open dev tools if they're true + if (options.devTools) { + // and possibly detach dev tools if true + win.webContents.openDevTools() + } + + if (options.contextMenu) { + // adds context menu with copy, paste, inspect element, etc + contextMenu({ + showInspectElement: true, + window: win, + }) + } + + return win +} + +export function open (projectRoot, options: WindowOptions = {}, newBrowserWindow = _newBrowserWindow) { + // if we already have a window open based + // on that type then just show + focus it! + let win + + win = getByType(options.type) + + if (win) { + win.show() + + return Bluebird.resolve(win) + } + + recentlyCreatedWindow = true + + _.defaults(options, { + width: 600, + height: 500, + show: true, + webPreferences: { + preload: cwd('lib', 'ipc', 'ipc.js'), + }, + }) + + if (!options.url) { + options.url = getUrl(options.type) + } + + win = create(projectRoot, options, newBrowserWindow) + + debug('creating electron window with options %o', options) + + if (options.type) { + windows[options.type] = win + + win.once('closed', () => { + delete windows[options.type!] + }) + } + + // enable our url to be a promise + // and wait for this to be resolved + return Bluebird.join( + options.url, + setWindowProxy(win), + ) + .spread((url) => { + // navigate the window here! + win.loadURL(url) + + recentlyCreatedWindow = false + }).thenReturn(win) +} + +export function trackState (projectRoot, isTextTerminal, win, keys) { + const isDestroyed = () => { + return win.isDestroyed() + } + + win.on('resize', _.debounce(() => { + if (isDestroyed()) { + return + } + + const [width, height] = win.getSize() + const [x, y] = win.getPosition() + const newState = {} + + newState[keys.width] = width + newState[keys.height] = height + newState[keys.x] = x + newState[keys.y] = y + + return savedState.create(projectRoot, isTextTerminal) + .then((state) => { + return state.set(newState) + }) + } + , 500)) + + win.on('moved', _.debounce(() => { + if (isDestroyed()) { + return + } + + const [x, y] = win.getPosition() + const newState = {} + + newState[keys.x] = x + newState[keys.y] = y + + return savedState.create(projectRoot, isTextTerminal) + .then((state) => { + return state.set(newState) + }) + } + , 500)) + + win.webContents.on('devtools-opened', () => { + const newState = {} + + newState[keys.devTools] = true + + return savedState.create(projectRoot, isTextTerminal) + .then((state) => { + return state.set(newState) + }) + }) + + return win.webContents.on('devtools-closed', () => { + const newState = {} + + newState[keys.devTools] = false + + return savedState.create(projectRoot, isTextTerminal) + .then((state) => { + return state.set(newState) + }) + }) +} diff --git a/packages/server/lib/modes/record.js b/packages/server/lib/modes/record.js index ea0023bdf20a..a74d858f6841 100644 --- a/packages/server/lib/modes/record.js +++ b/packages/server/lib/modes/record.js @@ -227,7 +227,6 @@ const updateInstance = (options = {}) => { error, video, hooks, - stdout: null, // don't send stdout with the instance payload to prevent requests that are too large. stdout will later get uploaded separately anyway. instanceId, screenshots, reporterStats, diff --git a/packages/server/lib/modes/run.js b/packages/server/lib/modes/run.js index cc8bb57c46f6..dff9299ec8a2 100644 --- a/packages/server/lib/modes/run.js +++ b/packages/server/lib/modes/run.js @@ -1,4 +1,4 @@ -/* eslint-disable no-console */ +/* eslint-disable no-console, @cypress/dev/arrow-body-multiline-braces */ const _ = require('lodash') const la = require('lazy-ass') const pkg = require('@packages/root') @@ -30,6 +30,7 @@ const electronApp = require('../util/electron-app') const settings = require('../util/settings') const chromePolicyCheck = require('../util/chrome_policy_check') const experiments = require('../experiments') +const objUtils = require('../util/obj_utils') const DELAY_TO_LET_VIDEO_FINISH_MS = 1000 @@ -916,7 +917,16 @@ module.exports = { browserOpts.automationMiddleware = { onAfterResponse: (message, data, resp) => { if (message === 'take:screenshot' && resp) { - screenshots.push(this.screenshotMetadata(data, resp)) + const existingScreenshot = _.findIndex(screenshots, { path: resp.path }) + + if (existingScreenshot !== -1) { + // NOTE: saving screenshots to the same path will overwrite the previous one + // so we shouldn't report more screenshots than exist on disk. + // this happens when cy.screenshot is used in a retried test + screenshots.splice(existingScreenshot, 1, this.screenshotMetadata(data, resp)) + } else { + screenshots.push(this.screenshotMetadata(data, resp)) + } } return resp @@ -1112,12 +1122,14 @@ module.exports = { const { tests, stats } = obj + const attempts = _.flatMap(tests, (test) => test.attempts) + const hasFailingTests = _.get(stats, 'failures') > 0 // if we have a video recording if (startedVideoCapture && tests && tests.length) { // always set the video timestamp on tests - obj.tests = Reporter.setVideoTimestamp(startedVideoCapture, tests) + Reporter.setVideoTimestamp(startedVideoCapture, attempts) } // we should upload the video if we upload on passes (by default) @@ -1160,6 +1172,7 @@ module.exports = { screenshotId: random.id(), name: data.name || null, testId: data.testId, + testAttemptIndex: data.testAttemptIndex, takenAt: resp.takenAt, path: resp.path, height: resp.dimensions.height, @@ -1248,7 +1261,41 @@ module.exports = { debug('final results of all runs: %o', results) - return writeOutput(outputPath, results).return(results) + const { each, remapKeys, remove, renameKey, setValue } = objUtils + + // Remap module API result json to remove private props and rename props to make more user-friendly + const moduleAPIResults = remapKeys(results, { + runs: each((run) => ({ + tests: each((test) => ({ + attempts: each((attempt, i) => ({ + timings: remove, + failedFromHookId: remove, + wallClockDuration: renameKey('duration'), + wallClockStartedAt: renameKey('startedAt'), + wallClockEndedAt: renameKey('endedAt'), + screenshots: setValue( + _(run.screenshots) + .filter({ testId: test.testId, testAttemptIndex: i }) + .map((screenshot) => _.omit(screenshot, + ['screenshotId', 'testId', 'testAttemptIndex'])) + .value(), + ), + })), + testId: remove, + })), + hooks: each({ + hookId: remove, + }), + stats: { + wallClockDuration: renameKey('duration'), + wallClockStartedAt: renameKey('startedAt'), + wallClockEndedAt: renameKey('endedAt'), + }, + screenshots: remove, + })), + }) + + return writeOutput(outputPath, moduleAPIResults).return(moduleAPIResults) }) }, diff --git a/packages/server/lib/plugins/child/index.js b/packages/server/lib/plugins/child/index.js index c8bd4d47cd86..224259ce0972 100644 --- a/packages/server/lib/plugins/child/index.js +++ b/packages/server/lib/plugins/child/index.js @@ -1,5 +1,7 @@ require('graceful-fs').gracefulify(require('fs')) +require('../../util/suppress_unauthorized_warning').suppress() + const ipc = require('../util').wrapIpc(process) const { file: pluginsFile, projectRoot } = require('minimist')(process.argv.slice(2)) diff --git a/packages/server/lib/plugins/child/run_plugins.js b/packages/server/lib/plugins/child/run_plugins.js index 1f70bb3f2706..894ad24a2331 100644 --- a/packages/server/lib/plugins/child/run_plugins.js +++ b/packages/server/lib/plugins/child/run_plugins.js @@ -4,15 +4,13 @@ const _ = require('lodash') const debug = require('debug')('cypress:server:plugins:child') const Promise = require('bluebird') -const tsnode = require('ts-node') -const resolve = require('resolve') const errors = require('../../errors') const preprocessor = require('./preprocessor') const task = require('./task') const util = require('../util') const validateEvent = require('./validate_event') -const tsNodeOptions = require('../../util/ts-node-options') +const { registerTsNode } = require('../../util/ts-node') const ARRAY_METHODS = ['concat', 'push', 'unshift', 'slice', 'pop', 'shift', 'slice', 'splice', 'filter', 'map', 'forEach', 'reduce', 'reverse', 'splice', 'includes'] @@ -183,21 +181,7 @@ module.exports = (ipc, pluginsFile, projectRoot) => { }) if (!tsRegistered) { - try { - const tsPath = resolve.sync('typescript', { - basedir: projectRoot, - }) - - const tsOptions = tsNodeOptions.getTsNodeOptions(tsPath) - - debug('typescript path: %s', tsPath) - debug('registering plugins TS with options %o', tsOptions) - - tsnode.register(tsOptions) - } catch (e) { - debug(`typescript doesn't exist. ts-node setup failed.`) - debug('error message: %s', e.message) - } + registerTsNode(projectRoot) // ensure typescript is only registered once tsRegistered = true diff --git a/packages/server/lib/plugins/index.js b/packages/server/lib/plugins/index.js index f40cf579b0c0..d9a2f3b271cc 100644 --- a/packages/server/lib/plugins/index.js +++ b/packages/server/lib/plugins/index.js @@ -2,6 +2,7 @@ const _ = require('lodash') const cp = require('child_process') const path = require('path') const debug = require('debug')('cypress:server:plugins') +const resolve = require('resolve') const Promise = require('bluebird') const errors = require('../errors') const util = require('./util') @@ -38,6 +39,17 @@ const registerHandler = (handler) => { const init = (config, options) => { debug('plugins.init', config.pluginsFile) + // test and warn for incompatible plugin + try { + const retriesPluginPath = path.dirname(resolve.sync('cypress-plugin-retries', { + basedir: options.projectRoot, + })) + + options.onWarning(errors.get('INCOMPATIBLE_PLUGIN_RETRIES', path.relative(options.projectRoot, retriesPluginPath))) + } catch (e) { + // noop, incompatible plugin not installed + } + return new Promise((_resolve, _reject) => { // provide a safety net for fulfilling the promise because the // 'handleError' function below can potentially be triggered diff --git a/packages/server/lib/plugins/preprocessor.js b/packages/server/lib/plugins/preprocessor.js index 1007830688e5..5ea1ba77cca3 100644 --- a/packages/server/lib/plugins/preprocessor.js +++ b/packages/server/lib/plugins/preprocessor.js @@ -35,11 +35,12 @@ const baseEmitter = new EE() let fileObjects = {} let fileProcessors = {} -const createBrowserifyPreprocessor = function (options) { - debug('creating browserify preprocessor with options %o', options) - const browserify = require('@cypress/browserify-preprocessor') +const createPreprocessor = function (options) { + debug('creating webpack preprocessor with options %o', options) - return browserify(options) + const webpackPreprocessor = require('@cypress/webpack-batteries-included-preprocessor') + + return webpackPreprocessor(options) } const setDefaultPreprocessor = function (config) { @@ -51,7 +52,7 @@ const setDefaultPreprocessor = function (config) { typescript: tsPath, } - return plugins.register('file:preprocessor', API.createBrowserifyPreprocessor(options)) + return plugins.register('file:preprocessor', API.createPreprocessor(options)) } plugins.registerHandler((ipc) => { @@ -76,7 +77,7 @@ const API = { setDefaultPreprocessor, - createBrowserifyPreprocessor, + createPreprocessor, emitter: baseEmitter, diff --git a/packages/server/lib/project.js b/packages/server/lib/project.js index 0feeef31eed1..bde157744fbb 100644 --- a/packages/server/lib/project.js +++ b/packages/server/lib/project.js @@ -6,8 +6,6 @@ const Promise = require('bluebird') const commitInfo = require('@cypress/commit-info') const la = require('lazy-ass') const check = require('check-more-types') -const tsnode = require('ts-node') -const resolve = require('resolve') const scaffoldDebug = require('debug')('cypress:server:scaffold') const debug = require('debug')('cypress:server:project') const cwd = require('./cwd') @@ -31,7 +29,7 @@ const keys = require('./util/keys') const settings = require('./util/settings') const specsUtil = require('./util/specs') const { escapeFilenameInUrl } = require('./util/escape_filename') -const tsNodeOptions = require('./util/ts-node-options') +const { registerTsNode } = require('./util/ts-node') const localCwd = cwd() @@ -103,21 +101,7 @@ class Project extends EE { return scaffold.plugins(path.dirname(cfg.pluginsFile), cfg) } }).then((cfg) => { - try { - const tsPath = resolve.sync('typescript', { - basedir: this.projectRoot, - }) - - const tsOptions = tsNodeOptions.getTsNodeOptions(tsPath) - - debug('typescript path: %s', tsPath) - debug('registering project TS with options %o', tsOptions) - - tsnode.register(tsOptions) - } catch (e) { - debug(`typescript doesn't exist. ts-node setup failed.`) - debug('error message %s', e.message) - } + registerTsNode(this.projectRoot) return cfg }).then((cfg) => { @@ -173,10 +157,10 @@ class Project extends EE { _initPlugins (cfg, options) { // only init plugins with the - // whitelisted config values to + // allowed config values to // prevent tampering with the // internals and breaking cypress - cfg = config.whitelist(cfg) + cfg = config.allowed(cfg) return plugins.init(cfg, { projectRoot: this.projectRoot, diff --git a/packages/server/lib/reporter.js b/packages/server/lib/reporter.js index b702a390734a..84119a80fd73 100644 --- a/packages/server/lib/reporter.js +++ b/packages/server/lib/reporter.js @@ -1,11 +1,13 @@ const _ = require('lodash') const path = require('path') +const stackUtils = require('./util/stack_utils') // mocha-* is used to allow us to have later versions of mocha specified in devDependencies // and prevents accidently upgrading this one // TODO: look into upgrading this to version in driver const Mocha = require('mocha-7.0.1') const mochaReporters = require('mocha-7.0.1/lib/reporters') const mochaCreateStatsCollector = require('mocha-7.0.1/lib/stats-collector') +const mochaColor = mochaReporters.Base.color const debug = require('debug')('cypress:server:reporter') const Promise = require('bluebird') @@ -99,6 +101,10 @@ const createRunnable = function (obj, parent) { runnable.sync = obj.sync runnable.duration = obj.duration runnable.state = obj.state != null ? obj.state : 'skipped' // skipped by default + runnable._retries = obj._retries + // shouldn't need to set _currentRetry, but we'll do it anyways + runnable._currentRetry = obj._currentRetry + if (runnable.body == null) { runnable.body = body } @@ -110,10 +116,42 @@ const createRunnable = function (obj, parent) { return runnable } +const mochaProps = { + 'currentRetry': '_currentRetry', + 'retries': '_retries', +} + +const toMochaProps = (testProps) => { + return _.each(mochaProps, (val, key) => { + if (testProps.hasOwnProperty(key)) { + testProps[val] = testProps[key] + + return delete testProps[key] + } + }) +} + const mergeRunnable = (eventName) => { return (function (testProps, runnables) { + toMochaProps(testProps) + const runnable = runnables[testProps.id] + if (eventName === 'test:before:run') { + if (testProps._currentRetry > runnable._currentRetry) { + debug('test retried:', testProps.title) + const prevAttempts = runnable.prevAttempts || [] + + delete runnable.prevAttempts + const prevAttempt = _.cloneDeep(runnable) + + delete runnable.failedFromHookId + delete runnable.err + delete runnable.hookName + testProps.prevAttempts = prevAttempts.concat([prevAttempt]) + } + } + return _.extend(runnable, testProps) }) } @@ -172,6 +210,12 @@ const setDate = function (obj, runnables, stats) { return null } +const orNull = function (prop) { + if (prop == null) return null + + return prop +} + const events = { 'start': setDate, 'end': setDate, @@ -180,11 +224,13 @@ const events = { 'test': mergeRunnable('test'), 'test end': mergeRunnable('test end'), 'hook': safelyMergeRunnable, + 'retry': true, 'hook end': safelyMergeRunnable, 'pass': mergeRunnable('pass'), 'pending': mergeRunnable('pending'), 'fail': mergeErr, 'test:after:run': mergeRunnable('test:after:run'), // our own custom event + 'test:before:run': mergeRunnable('test:before:run'), // our own custom event } const reporters = { @@ -201,6 +247,7 @@ class Reporter { this.reporterName = reporterName this.projectRoot = projectRoot this.reporterOptions = reporterOptions + this.normalizeTest = this.normalizeTest.bind(this) } setRunnables (rootRunnable) { @@ -219,6 +266,18 @@ class Reporter { this.runner = new Mocha.Runner(rootRunnable) mochaCreateStatsCollector(this.runner) + if (this.reporterName === 'spec') { + this.runner.on('retry', (test) => { + const runnable = this.runnables[test.id] + const padding = ' '.repeat(runnable.titlePath().length) + const retryMessage = mochaColor('medium', `(Attempt ${test.currentRetry + 1} of ${test.retries + 1})`) + + // Log: `(Attempt 1 of 2) test title` when a test retries + // eslint-disable-next-line no-console + return console.log(`${padding}${retryMessage} ${test.title}`) + }) + } + this.reporter = new this.mocha._reporter(this.runner, { reporterOptions: this.reporterOptions, }) @@ -260,7 +319,7 @@ class Reporter { args = this.parseArgs(event, args) if (args) { - return (this.runner != null ? this.runner.emit.apply(this.runner, args) : undefined) + return this.runner && this.runner.emit.apply(this.runner, args) } } @@ -292,39 +351,32 @@ class Reporter { } normalizeTest (test = {}) { - let wcs - const get = (prop) => { - return _.get(test, prop, null) - } - - // use this or null - wcs = get('wallClockStartedAt') - - if (wcs) { - // convert to actual date object - wcs = new Date(wcs) - } - - // wallClockDuration: - // this is the 'real' duration of wall clock time that the - // user 'felt' when the test run. it includes everything - // from hooks, to the test itself, to lifecycle, and event - // async browser compute time. this number is likely higher - // than summing the durations of the timings. - // - return { - testId: get('id'), + const normalizedTest = { + testId: orNull(test.id), title: getParentTitle(test), - state: get('state'), - body: get('body'), - stack: get('err.stack'), - error: get('err.message'), - timings: get('timings'), - failedFromHookId: get('failedFromHookId'), - wallClockStartedAt: wcs, - wallClockDuration: get('wallClockDuration'), - videoTimestamp: null, // always start this as null + state: orNull(test.state), + body: orNull(test.body), + displayError: orNull(test.err && test.err.stack), + attempts: _.map([test].concat(test.prevAttempts || []), (attempt) => { + const err = attempt.err && { + name: attempt.err.name, + message: attempt.err.message, + stack: stackUtils.stackWithoutMessage(attempt.err.stack), + } + + return { + state: orNull(attempt.state), + error: orNull(err), + timings: orNull(attempt.timings), + failedFromHookId: orNull(attempt.failedFromHookId), + wallClockStartedAt: orNull(attempt.wallClockStartedAt && new Date(attempt.wallClockStartedAt)), + wallClockDuration: orNull(attempt.wallClockDuration), + videoTimestamp: null, + } + }), } + + return normalizedTest } end () { diff --git a/packages/server/lib/saved_state.js b/packages/server/lib/saved_state.js index dee0a7126890..4623b7d96d0c 100644 --- a/packages/server/lib/saved_state.js +++ b/packages/server/lib/saved_state.js @@ -9,7 +9,7 @@ const fs = require('./util/fs') const stateFiles = {} -const whitelist = ` +const allowed = ` appWidth appHeight appX @@ -64,7 +64,7 @@ const formStatePath = (projectRoot) => { }) } -const normalizeAndWhitelistSet = (set, key, value) => { +const normalizeAndAllowSet = (set, key, value) => { const valueObject = (() => { if (_.isString(key)) { const tmp = {} @@ -78,15 +78,15 @@ const normalizeAndWhitelistSet = (set, key, value) => { })() const invalidKeys = _.filter(_.keys(valueObject), (key) => { - return !_.includes(whitelist, key) + return !_.includes(allowed, key) }) if (invalidKeys.length) { // eslint-disable-next-line no-console - console.error(`WARNING: attempted to save state for non-whitelisted key(s): ${invalidKeys.join(', ')}. All keys must be whitelisted in server/lib/saved_state.js`) + console.error(`WARNING: attempted to save state for non-allowed key(s): ${invalidKeys.join(', ')}. All keys must be allowed in server/lib/saved_state.js`) } - return set(_.pick(valueObject, whitelist)) + return set(_.pick(valueObject, allowed)) } const create = (projectRoot, isTextTerminal) => { @@ -110,7 +110,7 @@ const create = (projectRoot, isTextTerminal) => { path: fullStatePath, }) - stateFile.set = _.wrap(stateFile.set.bind(stateFile), normalizeAndWhitelistSet) + stateFile.set = _.wrap(stateFile.set.bind(stateFile), normalizeAndAllowSet) stateFiles[fullStatePath] = stateFile diff --git a/packages/server/lib/screenshots.js b/packages/server/lib/screenshots.js index d5974c6991bf..52e84ffe7b49 100644 --- a/packages/server/lib/screenshots.js +++ b/packages/server/lib/screenshots.js @@ -340,6 +340,10 @@ const getPath = function (data, ext, screenshotsFolder) { names[index] = `${names[index]} (failed)` } + if (data.testAttemptIndex > 0) { + names[index] = `${names[index]} (attempt ${data.testAttemptIndex + 1})` + } + const withoutExt = path.join(screenshotsFolder, ...specNames, ...names) return ensureUniquePath(withoutExt, ext) @@ -484,7 +488,7 @@ module.exports = { const duration = new Date() - new Date(data.startTime) details = _.extend({}, data, details, { duration }) - details = _.pick(details, 'size', 'takenAt', 'dimensions', 'multipart', 'pixelRatio', 'name', 'specName', 'testFailure', 'path', 'scaled', 'blackout', 'duration') + details = _.pick(details, 'testAttemptIndex', 'size', 'takenAt', 'dimensions', 'multipart', 'pixelRatio', 'name', 'specName', 'testFailure', 'path', 'scaled', 'blackout', 'duration') if (!plugins.has('after:screenshot')) { return Promise.resolve(details) diff --git a/packages/server/lib/server.js b/packages/server/lib/server.js index 3a66707cd075..e1d0f2cbd03c 100644 --- a/packages/server/lib/server.js +++ b/packages/server/lib/server.js @@ -15,7 +15,7 @@ const compression = require('compression') const debug = require('debug')('cypress:server:server') const { agent, - blacklist, + blocked, concatStream, cors, uri, @@ -28,7 +28,7 @@ const appData = require('./util/app_data') const statusCode = require('./util/status_code') const headersUtil = require('./util/headers') const allowDestroy = require('./util/server_destroy') -const { SocketWhitelist } = require('./util/socket_whitelist') +const { SocketAllowed } = require('./util/socket_allowed') const errors = require('./errors') const logger = require('./logger') const Socket = require('./socket') @@ -59,7 +59,7 @@ const _forceProxyMiddleware = function (clientRoute) { const trimmedUrl = _.trimEnd(req.proxiedUrl, '/') if (_isNonProxiedRequest(req) && !ALLOWED_PROXY_BYPASS_URLS.includes(trimmedUrl) && (trimmedUrl !== trimmedClientRoute)) { - // this request is non-proxied and non-whitelisted, redirect to the runner error page + // this request is non-proxied and non-allowed, redirect to the runner error page return res.redirect(clientRoute) } @@ -115,7 +115,7 @@ class Server { return new Server() } - this._socketWhitelist = new SocketWhitelist() + this._socketAllowed = new SocketAllowed() this._request = null this._middleware = null this._server = null @@ -238,7 +238,7 @@ class Server { createServer (app, config, project, request, onWarning) { return new Promise((resolve, reject) => { - const { port, fileServerFolder, socketIoRoute, baseUrl, blacklistHosts } = config + const { port, fileServerFolder, socketIoRoute, baseUrl, blockHosts } = config this._server = http.createServer(app) @@ -276,7 +276,7 @@ class Server { this._server.on('connect', (req, socket, head) => { debug('Got CONNECT request from %s', req.url) - socket.once('upstream-connected', this._socketWhitelist.add) + socket.once('upstream-connected', this._socketAllowed.add) return this._httpsProxy.connect(req, socket, head, { onDirectConnection: (req) => { @@ -291,16 +291,17 @@ class Server { // if we are currently matching then we're // not making a direct connection anyway // so we only need to check this if we - // have blacklist hosts and are not matching. + // have blocked hosts and are not matching. // - // if we have blacklisted hosts lets + // if we have blocked hosts lets // see if this matches - if so then // we cannot allow it to make a direct // connection - if (blacklistHosts && !isMatching) { - isMatching = blacklist.matches(urlToCheck, blacklistHosts) - debug(`HTTPS request ${urlToCheck} matches blacklist?`, isMatching) + if (blockHosts && !isMatching) { + isMatching = blocked.matches(urlToCheck, blockHosts) + + debug(`HTTPS request ${urlToCheck} matches blockHosts?`, isMatching) } // make a direct connection only if @@ -759,7 +760,7 @@ class Server { let host; let remoteOrigin if (req.url.startsWith(socketIoRoute)) { - if (!this._socketWhitelist.isRequestWhitelisted(req)) { + if (!this._socketAllowed.isRequestAllowed(req)) { socket.write('HTTP/1.1 400 Bad Request\r\n\r\nRequest not made via a Cypress-launched browser.') socket.end() } diff --git a/packages/server/lib/util/args.js b/packages/server/lib/util/args.js index 088c8e4633ec..851c81a76579 100644 --- a/packages/server/lib/util/args.js +++ b/packages/server/lib/util/args.js @@ -13,7 +13,7 @@ const nestedObjectsInCurlyBracesRe = /\{(.+?)\}/g const nestedArraysInSquareBracketsRe = /\[(.+?)\]/g const everythingAfterFirstEqualRe = /=(.*)/ -const whitelist = 'appPath apiKey browser ci ciBuildId clearLogs config configFile cwd env execPath exit exitWithCode generateKey getKey group headed inspectBrk key logs mode outputPath parallel ping port project proxySource quiet record reporter reporterOptions returnPkg runMode runProject smokeTest spec tag updating version'.split(' ') +const allowList = 'appPath apiKey browser ci ciBuildId clearLogs config configFile cwd env execPath exit exitWithCode generateKey getKey group headed inspectBrk key logs mode outputPath parallel ping port project proxySource quiet record reporter reporterOptions returnPkg runMode runProject smokeTest spec tag updating version'.split(' ') // returns true if the given string has double quote character " // only at the last position. const hasStrayEndQuote = (s) => { @@ -190,14 +190,14 @@ module.exports = { alias, }) - const whitelisted = _.pick(argv, whitelist) + const allowed = _.pick(argv, allowList) // were we invoked from the CLI or directly? const invokedFromCli = Boolean(options.cwd) options = _ .chain(options) - .defaults(whitelisted) + .defaults(allowed) .omit(_.keys(alias)) // remove aliases .extend({ invokedFromCli }) .defaults({ @@ -321,11 +321,11 @@ module.exports = { toArray (obj = {}) { // goes in reverse, takes an object // and converts to an array by picking - // only the whitelisted properties and + // only the allowed properties and // mapping them to include the argument return _ .chain(obj) - .pick(...whitelist) + .pick(...allowList) .mapValues((val, key) => { return `--${key}=${stringify(val)}` }).values() diff --git a/packages/server/lib/util/obj_utils.ts b/packages/server/lib/util/obj_utils.ts new file mode 100644 index 000000000000..c768bd2daca0 --- /dev/null +++ b/packages/server/lib/util/obj_utils.ts @@ -0,0 +1,48 @@ +import _ from 'lodash' + +const traverse = (obj, mapObj, parent?, key?) => { + if (_.isFunction(mapObj)) { + mapObj(parent, key, obj) + + return + } + + if (_.isObject(mapObj)) { + _.each(mapObj, (mapVal, mapKey) => { + traverse(obj[mapKey], mapVal, obj, mapKey) + }) + } +} + +export const remapKeys = (fromObj, toObj) => { + fromObj = _.cloneDeep(fromObj) + + traverse(fromObj, toObj) + + return fromObj +} + +export const remove = (obj, key) => delete obj[key] + +export const renameKey = (newName) => { + return (obj, key, val) => { + delete obj[key] + obj[newName] = val + } +} + +export const setValue = (defaultVal) => { + return (obj, key) => { + obj[key] = defaultVal + } +} + +export const each = (fn) => { + return (__, ___, arr) => { + return _.each(arr, (val, i) => { + const mapObj = _.isFunction(fn) ? fn(val, i) : fn + + traverse(val, mapObj) + }) + } +} diff --git a/packages/server/lib/util/socket_allowed.ts b/packages/server/lib/util/socket_allowed.ts new file mode 100644 index 000000000000..46ed8a32a386 --- /dev/null +++ b/packages/server/lib/util/socket_allowed.ts @@ -0,0 +1,46 @@ +import _ from 'lodash' +import Debug from 'debug' +import net from 'net' +import { Request } from 'express' + +const debug = Debug('cypress:server:util:socket_allowed') + +/** + * Utility to validate incoming, local socket connections against a list of + * expected client TCP ports. + */ +export class SocketAllowed { + allowedLocalPorts: number[] = [] + + /** + * Add a socket to the allowed list. + */ + add = (socket: net.Socket) => { + const { localPort } = socket + + debug('allowing socket %o', { localPort }) + this.allowedLocalPorts.push(localPort) + + socket.once('close', () => { + debug('allowed socket closed, removing %o', { localPort }) + this._remove(socket) + }) + } + + _remove (socket: net.Socket) { + _.pull(this.allowedLocalPorts, socket.localPort) + } + + /** + * Is this socket that this request originated allowed? + */ + isRequestAllowed (req: Request) { + const { remotePort, remoteAddress } = req.socket + const isAllowed = this.allowedLocalPorts.includes(remotePort!) + && ['127.0.0.1', '::1'].includes(remoteAddress!) + + debug('is incoming request allowed? %o', { isAllowed, reqUrl: req.url, remotePort, remoteAddress }) + + return isAllowed + } +} diff --git a/packages/server/lib/util/socket_whitelist.ts b/packages/server/lib/util/socket_whitelist.ts deleted file mode 100644 index 421426d417b6..000000000000 --- a/packages/server/lib/util/socket_whitelist.ts +++ /dev/null @@ -1,46 +0,0 @@ -import _ from 'lodash' -import Debug from 'debug' -import net from 'net' -import { Request } from 'express' - -const debug = Debug('cypress:server:util:socket_whitelist') - -/** - * Utility to validate incoming, local socket connections against a list of - * expected client TCP ports. - */ -export class SocketWhitelist { - whitelistedLocalPorts: number[] = [] - - /** - * Add a socket to the whitelist. - */ - add = (socket: net.Socket) => { - const { localPort } = socket - - debug('whitelisting socket %o', { localPort }) - this.whitelistedLocalPorts.push(localPort) - - socket.once('close', () => { - debug('whitelisted socket closed, removing %o', { localPort }) - this._remove(socket) - }) - } - - _remove (socket: net.Socket) { - _.pull(this.whitelistedLocalPorts, socket.localPort) - } - - /** - * Is this socket that this request originated from whitelisted? - */ - isRequestWhitelisted (req: Request) { - const { remotePort, remoteAddress } = req.socket - const isWhitelisted = this.whitelistedLocalPorts.includes(remotePort!) - && ['127.0.0.1', '::1'].includes(remoteAddress!) - - debug('is incoming request whitelisted? %o', { isWhitelisted, reqUrl: req.url, remotePort, remoteAddress }) - - return isWhitelisted - } -} diff --git a/packages/server/lib/util/stack_utils.ts b/packages/server/lib/util/stack_utils.ts new file mode 100644 index 000000000000..1018a367a2a5 --- /dev/null +++ b/packages/server/lib/util/stack_utils.ts @@ -0,0 +1,44 @@ +import _ from 'lodash' + +const stackLineRegex = /^\s*(at )?.*@?\(?.*\:\d+\:\d+\)?$/ + +// returns tuple of [message, stack] +export const splitStack = (stack: string) => { + const lines = stack.split('\n') + + return _.reduce(lines, (memo, line) => { + if (memo.messageEnded || stackLineRegex.test(line)) { + memo.messageEnded = true + memo[1].push(line) + } else { + memo[0].push(line) + } + + return memo + }, [[], []] as any[] & {messageEnded: boolean}) +} + +export const unsplitStack = (messageLines, stackLines) => { + return _.castArray(messageLines).concat(stackLines).join('\n') +} + +export const getStackLines = (stack) => { + const [, stackLines] = splitStack(stack) + + return stackLines +} + +export const stackWithoutMessage = (stack) => { + return getStackLines(stack).join('\n') +} + +export const replacedStack = (err, newStack) => { + // if err already lacks a stack or we've removed the stack + // for some reason, keep it stackless + if (!err.stack) return err.stack + + const errString = err.toString() + const stackLines = getStackLines(newStack) + + return unsplitStack(errString, stackLines) +} diff --git a/packages/server/lib/util/suppress_unauthorized_warning.ts b/packages/server/lib/util/suppress_unauthorized_warning.js similarity index 52% rename from packages/server/lib/util/suppress_unauthorized_warning.ts rename to packages/server/lib/util/suppress_unauthorized_warning.js index 29e2bfb39eef..7cde5918984a 100644 --- a/packages/server/lib/util/suppress_unauthorized_warning.ts +++ b/packages/server/lib/util/suppress_unauthorized_warning.js @@ -1,4 +1,4 @@ -import _ from 'lodash' +const _ = require('lodash') const originalEmitWarning = process.emitWarning @@ -9,22 +9,32 @@ let suppressed = false * we work on proper SSL verification. * https://github.com/cypress-io/cypress/issues/5248 */ -export function suppress () { +const suppress = () => { if (suppressed) { return } suppressed = true - process.emitWarning = (warning, ...args) => { + process.emitWarning = (warning, type, code, ...args) => { if (_.isString(warning) && _.includes(warning, 'NODE_TLS_REJECT_UNAUTHORIZED')) { - // node will only emit the warning once // https://github.com/nodejs/node/blob/82f89ec8c1554964f5029fab1cf0f4fad1fa55a8/lib/_tls_wrap.js#L1378-L1384 - process.emitWarning = originalEmitWarning return } - return originalEmitWarning.call(process, warning, ...args) + // silence Buffer allocation warning since there are no + // security problems due to the way Cypress works + if (code === 'DEP0005') { + // https://github.com/nodejs/node/blob/master/lib/buffer.js#L176-L192 + + return + } + + return originalEmitWarning.call(process, warning, type, code, ...args) } } + +module.exports = { + suppress, +} diff --git a/packages/server/lib/util/ts-node-options.js b/packages/server/lib/util/ts-node-options.js deleted file mode 100644 index de72ee032712..000000000000 --- a/packages/server/lib/util/ts-node-options.js +++ /dev/null @@ -1,29 +0,0 @@ -// returns options for ts-node registration -// https://github.com/TypeStrong/ts-node -const _ = require('lodash') - -/** - * Default ts - node options.We want to output CommonJS modules. - * And we want to run fast - thus transpile only mode (no type checking) -*/ -const tsOptions = { - transpileOnly: true, - compilerOptions: { - module: 'CommonJS', - esModuleInterop: true, - }, -} - -/** - * Returns combined object with ts-node options. - * @param {string} tsPath Path to TypeScript - */ -function getTsNodeOptions (tsPath) { - const merged = _.cloneDeep(tsOptions) - - merged.compiler = tsPath - - return merged -} - -module.exports = { getTsNodeOptions } diff --git a/packages/server/lib/util/ts-node.js b/packages/server/lib/util/ts-node.js new file mode 100644 index 000000000000..fa81234c9b24 --- /dev/null +++ b/packages/server/lib/util/ts-node.js @@ -0,0 +1,34 @@ +const debug = require('debug')('cypress:server:ts-node') +const tsnode = require('ts-node') +const resolve = require('resolve') + +const getTsNodeOptions = (tsPath) => { + return { + compiler: tsPath, // use the user's installed typescript + compilerOptions: { + module: 'CommonJS', + }, + transpileOnly: true, // transpile only (no type-check) for speed + } +} + +const registerTsNode = (projectRoot) => { + try { + const tsPath = resolve.sync('typescript', { + basedir: projectRoot, + }) + const tsOptions = getTsNodeOptions(tsPath) + + debug('typescript path: %s', tsPath) + debug('registering project TS with options %o', tsOptions) + + tsnode.register(tsOptions) + } catch (err) { + debug(`typescript doesn't exist. ts-node setup failed.`) + debug('error message: %s', err.message) + } +} + +module.exports = { + registerTsNode, +} diff --git a/packages/server/lib/util/validation.js b/packages/server/lib/util/validation.js index 3dfcb9b13264..1e4e2736b0da 100644 --- a/packages/server/lib/util/validation.js +++ b/packages/server/lib/util/validation.js @@ -103,6 +103,22 @@ const isValidBrowserList = (key, browsers) => { return true } +const isValidRetriesConfig = (key, value) => { + const optionalKeys = ['runMode', 'openMode'] + const isValidRetryValue = (val) => _.isNull(val) || (Number.isInteger(val) && val >= 0) + const optionalKeysAreValid = (val, k) => optionalKeys.includes(k) && isValidRetryValue(val) + + if (isValidRetryValue(value)) { + return true + } + + if (_.isObject(value) && _.every(value, optionalKeysAreValid)) { + return true + } + + return errMsg(key, value, 'a positive number or null or an object with keys "openMode" and "runMode" with values of numbers or nulls') +} + const isValidFirefoxGcInterval = (key, value) => { const isIntervalValue = (val) => { if (isNumber(val)) { @@ -122,6 +138,24 @@ const isValidFirefoxGcInterval = (key, value) => { return errMsg(key, value, 'a positive number or null or an object with "openMode" and "runMode" as keys and positive numbers or nulls as values') } +const isOneOf = (...values) => { + return (key, value) => { + if (values.some((v) => { + if (typeof value === 'function') { + return value(v) + } + + return v === value + })) { + return true + } + + const strings = values.map(str).join(', ') + + return errMsg(key, value, `one of these values: ${strings}`) + } +} + module.exports = { isValidBrowser, @@ -129,6 +163,8 @@ module.exports = { isValidFirefoxGcInterval, + isValidRetriesConfig, + isNumber (key, value) { if (value == null || isNumber(value)) { return true @@ -214,17 +250,5 @@ module.exports = { validate("example", "else") // error message string ``` */ - isOneOf (...values) { - return (key, value) => { - if (values.some((v) => { - return v === value - })) { - return true - } - - const strings = values.map(str).join(', ') - - return errMsg(key, value, `one of these values: ${strings}`) - } - }, + isOneOf, } diff --git a/packages/server/package.json b/packages/server/package.json index a1af51d340c9..4c70f24d7e8c 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -21,18 +21,18 @@ }, "dependencies": { "@benmalka/foxdriver": "0.4.1", - "@cypress/browserify-preprocessor": "2.2.4", "@cypress/commit-info": "2.2.0", "@cypress/get-windows-proxy": "1.6.1", "@cypress/icons": "0.7.0", "@cypress/mocha-teamcity-reporter": "1.0.0", "@cypress/request": "2.88.5", "@cypress/request-promise": "4.2.6", + "@cypress/webpack-batteries-included-preprocessor": "2.0.0", + "@cypress/webpack-preprocessor": "5.4.4", "@ffmpeg-installer/ffmpeg": "1.0.20", "ansi_up": "4.0.4", "black-hole-stream": "0.0.1", "bluebird": "3.7.0", - "browserify": "16.3.0", "chai": "1.10.0", "chalk": "2.4.2", "check-more-types": "2.24.0", @@ -122,14 +122,9 @@ }, "devDependencies": { "@babel/core": "7.9.0", - "@babel/plugin-proposal-class-properties": "7.8.3", - "@babel/plugin-proposal-object-rest-spread": "7.9.0", - "@babel/plugin-transform-runtime": "7.9.0", "@babel/preset-env": "7.9.0", - "@babel/preset-react": "7.9.4", - "@babel/runtime": "7.9.2", "@cypress/debugging-proxy": "2.0.1", - "@cypress/json-schemas": "5.34.2", + "@cypress/json-schemas": "5.35.0", "@cypress/sinon-chai": "1.1.0", "@packages/desktop-gui": "*", "@packages/electron": "*", @@ -147,15 +142,12 @@ "@types/chrome": "0.0.101", "awesome-typescript-loader": "5.2.1", "babel-loader": "8.1.0", - "babel-plugin-add-module-exports": "1.0.2", - "babelify": "10.0.0", "body-parser": "1.19.0", "chai-as-promised": "7.1.1", "chai-subset": "1.6.0", "chai-uuid": "1.0.6", "chokidar-cli": "1.2.2", "chrome-har-capturer": "0.13.4", - "coffeeify": "3.0.1", "cors": "2.8.5", "cross-env": "6.0.3", "devtools-protocol": "0.0.734984", @@ -170,7 +162,7 @@ "mochawesome-1.5.2": "npm:mochawesome@1.5.2", "mochawesome-2.3.1": "npm:mochawesome@2.3.1", "mochawesome-3.0.1": "npm:mochawesome@3.0.1", - "mock-fs": "4.10.4", + "mock-fs": "4.12.0", "mocked-env": "1.2.4", "mockery": "2.1.0", "multiparty": "4.2.1", @@ -181,7 +173,6 @@ "sinon": "5.1.1", "snap-shot-it": "7.9.3", "ssestream": "1.0.1", - "stream-to-promise": "1.1.1", "supertest": "4.0.2", "supertest-session": "4.0.0", "through2": "2.0.5", diff --git a/packages/server/patches/@benmalka+foxdriver+0.4.0.patch b/packages/server/patches/@benmalka+foxdriver+0.4.1.patch similarity index 100% rename from packages/server/patches/@benmalka+foxdriver+0.4.0.patch rename to packages/server/patches/@benmalka+foxdriver+0.4.1.patch diff --git a/packages/server/test/e2e/1_blacklist_hosts_spec.js b/packages/server/test/e2e/1_block_hosts_spec.js similarity index 82% rename from packages/server/test/e2e/1_blacklist_hosts_spec.js rename to packages/server/test/e2e/1_block_hosts_spec.js index ae38f96f5f0d..946f656ff6b1 100644 --- a/packages/server/test/e2e/1_blacklist_hosts_spec.js +++ b/packages/server/test/e2e/1_block_hosts_spec.js @@ -14,7 +14,7 @@ const onServer = function (app) { }) } -describe('e2e blacklist', () => { +describe('e2e blockHosts', () => { e2e.setup({ servers: [{ port: 3131, @@ -25,13 +25,14 @@ describe('e2e blacklist', () => { }], settings: { baseUrl: 'http://localhost:3232', - blacklistHosts: 'localhost:3131', + blockHosts: 'localhost:3131', + video: false, }, }) it('passes', function () { return e2e.exec(this, { - spec: 'blacklist_hosts_spec.coffee', + spec: 'block_hosts_spec.coffee', snapshot: true, }) }) diff --git a/packages/server/test/e2e/1_busted_support_file_spec.js b/packages/server/test/e2e/1_busted_support_file_spec.js index 039a0a1fe24e..1a54dbbbe7c9 100644 --- a/packages/server/test/e2e/1_busted_support_file_spec.js +++ b/packages/server/test/e2e/1_busted_support_file_spec.js @@ -12,6 +12,7 @@ describe('e2e busted support file', () => { sanitizeScreenshotDimensions: true, snapshot: true, expectedExitCode: 1, + onStdout: e2e.normalizeWebpackErrors, }) }) }) diff --git a/packages/server/test/e2e/1_caught_uncaught_hook_errors_spec.js b/packages/server/test/e2e/1_caught_uncaught_hook_errors_spec.js index c629420088c6..f292ed4678fc 100644 --- a/packages/server/test/e2e/1_caught_uncaught_hook_errors_spec.js +++ b/packages/server/test/e2e/1_caught_uncaught_hook_errors_spec.js @@ -8,35 +8,27 @@ describe('e2e caught and uncaught hooks errors', () => { }, }) - it('failing1', function () { - return e2e.exec(this, { - spec: 'hook_caught_error_failing_spec.coffee', - snapshot: true, - expectedExitCode: 3, - }) + e2e.it('failing1', { + spec: 'hook_caught_error_failing_spec.coffee', + snapshot: true, + expectedExitCode: 3, }) - it('failing2', function () { - return e2e.exec(this, { - spec: 'hook_uncaught_error_failing_spec.coffee', - snapshot: true, - expectedExitCode: 1, - }) + e2e.it('failing2', { + spec: 'hook_uncaught_error_failing_spec.coffee', + snapshot: true, + expectedExitCode: 1, }) - it('failing3', function () { - return e2e.exec(this, { - spec: 'hook_uncaught_root_error_failing_spec.coffee', - snapshot: true, - expectedExitCode: 1, - }) + e2e.it('failing3', { + spec: 'hook_uncaught_root_error_failing_spec.coffee', + snapshot: true, + expectedExitCode: 1, }) - it('failing4', function () { - return e2e.exec(this, { - spec: 'hook_uncaught_error_events_failing_spec.coffee', - snapshot: true, - expectedExitCode: 1, - }) + e2e.it('failing4', { + spec: 'hook_uncaught_error_events_failing_spec.coffee', + snapshot: true, + expectedExitCode: 1, }) }) diff --git a/packages/server/test/e2e/1_browserify_babel_es201_spec.js b/packages/server/test/e2e/1_es_modules_spec.js similarity index 65% rename from packages/server/test/e2e/1_browserify_babel_es201_spec.js rename to packages/server/test/e2e/1_es_modules_spec.js index 02d963be937e..cf5df3230e60 100644 --- a/packages/server/test/e2e/1_browserify_babel_es201_spec.js +++ b/packages/server/test/e2e/1_es_modules_spec.js @@ -1,11 +1,11 @@ const e2e = require('../support/helpers/e2e').default -describe('e2e browserify, babel, es2015', () => { +describe('e2e es modules', () => { e2e.setup() it('passes', function () { return e2e.exec(this, { - spec: 'browserify_babel_es2015_passing_spec.coffee', + spec: 'es_modules_in_coffee_spec.coffee', snapshot: true, noTypeScript: true, }) @@ -13,10 +13,11 @@ describe('e2e browserify, babel, es2015', () => { it('fails', function () { return e2e.exec(this, { - spec: 'browserify_babel_es2015_failing_spec.js', + spec: 'es_module_import_failing_spec.js', snapshot: true, expectedExitCode: 1, noTypeScript: true, + onStdout: e2e.normalizeWebpackErrors, }) }) }) diff --git a/packages/server/test/e2e/1_typescript_plugins_spec.ts b/packages/server/test/e2e/1_typescript_plugins_spec.ts new file mode 100644 index 000000000000..5954530e9367 --- /dev/null +++ b/packages/server/test/e2e/1_typescript_plugins_spec.ts @@ -0,0 +1,26 @@ +import e2e from '../support/helpers/e2e' +import Fixtures from '../support/helpers/fixtures' + +describe('e2e typescript in plugins file', function () { + e2e.setup() + + it('handles tsconfig with module other than commonjs', function () { + return e2e.exec(this, { + project: Fixtures.projectPath('ts-proj-with-module-esnext'), + }) + }) + + // https://github.com/cypress-io/cypress/issues/7575 + it('defaults to esModuleInterop: false', function () { + return e2e.exec(this, { + project: Fixtures.projectPath('ts-proj'), + }) + }) + + // https://github.com/cypress-io/cypress/issues/7575 + it('allows esModuleInterop to be overridden with true via tsconfig.json', function () { + return e2e.exec(this, { + project: Fixtures.projectPath('ts-proj-esmoduleinterop-true'), + }) + }) +}) diff --git a/packages/server/test/e2e/1_typescript_spec_support_spec.ts b/packages/server/test/e2e/1_typescript_spec_support_spec.ts new file mode 100644 index 000000000000..82dfa6f8fdfa --- /dev/null +++ b/packages/server/test/e2e/1_typescript_spec_support_spec.ts @@ -0,0 +1,37 @@ +import e2e from '../support/helpers/e2e' +import Fixtures from '../support/helpers/fixtures' + +describe('e2e typescript in spec and support file', function () { + e2e.setup() + + it('spec passes', function () { + return e2e.exec(this, { + spec: 'typescript_passing_spec.ts', + snapshot: true, + }) + }) + + it('spec fails with syntax error', function () { + return e2e.exec(this, { + spec: 'typescript_syntax_error_spec.ts', + snapshot: true, + expectedExitCode: 1, + onStdout: e2e.normalizeWebpackErrors, + }) + }) + + it('project passes', function () { + const projPath = Fixtures.projectPath('ts-proj') + + return e2e.exec(this, { + project: projPath, + snapshot: true, + }) + }) + + it('respects tsconfig paths', function () { + return e2e.exec(this, { + project: Fixtures.projectPath('ts-proj-with-paths'), + }) + }) +}) diff --git a/packages/server/test/e2e/1_typescript_support_spec.ts b/packages/server/test/e2e/1_typescript_support_spec.ts deleted file mode 100644 index 3252ac68ba94..000000000000 --- a/packages/server/test/e2e/1_typescript_support_spec.ts +++ /dev/null @@ -1,47 +0,0 @@ -import snapshot from 'snap-shot-it' - -import e2e from '../support/helpers/e2e' -import Fixtures from '../support/helpers/fixtures' - -describe('e2e typescript', function () { - e2e.setup() - - it('spec passes', function () { - return e2e.exec(this, { - spec: 'browserify_typescript_passing_spec.ts', - snapshot: true, - }) - }) - - it('spec fails', function () { - return e2e.exec(this, { - spec: 'browserify_typescript_failing_spec.ts', - snapshot: true, - expectedExitCode: 1, - }) - }) - - it('project passes', function () { - const projPath = Fixtures.projectPath('ts-proj') - - return e2e.exec(this, { - project: projPath, - snapshot: true, - }) - }) - - it('handles tsconfig with module other than commonjs', function () { - const projPath = Fixtures.projectPath('ts-proj-with-own-tsconfig') - - return e2e.exec(this, { - project: projPath, - config: { - video: false, - }, - }).then((result) => { - const runSummary = e2e.leaveRunFinishedTable(e2e.normalizeStdout(result.stdout)) - - snapshot('typescript with tsconfig run', runSummary) - }) - }) -}) diff --git a/packages/server/test/e2e/2_cookies_spec.js b/packages/server/test/e2e/2_cookies_spec.ts similarity index 96% rename from packages/server/test/e2e/2_cookies_spec.js rename to packages/server/test/e2e/2_cookies_spec.ts index 2b9d06263068..83a10d35886e 100644 --- a/packages/server/test/e2e/2_cookies_spec.js +++ b/packages/server/test/e2e/2_cookies_spec.ts @@ -1,7 +1,7 @@ -const moment = require('moment') -const parser = require('cookie-parser') -const e2e = require('../support/helpers/e2e').default -const humanInterval = require('human-interval') +import moment from 'moment' +import parser from 'cookie-parser' +import e2e from '../support/helpers/e2e' +import humanInterval from 'human-interval' const onServer = function (app) { app.use(parser()) @@ -194,7 +194,6 @@ describe('e2e cookies', () => { // we can remove this extra test case e2e.it('with forced SameSite strictness', { config: { - experimentalGetCookiesSameSite: true, baseUrl, env: { baseUrl, @@ -248,7 +247,6 @@ describe('e2e cookies', () => { ) => { e2e.it(`passes with baseurl: ${baseUrl}`, { config: { - experimentalGetCookiesSameSite: true, baseUrl, env: { baseUrl, diff --git a/packages/server/test/e2e/3_issue_173_spec.js b/packages/server/test/e2e/3_issue_173_spec.ts similarity index 79% rename from packages/server/test/e2e/3_issue_173_spec.js rename to packages/server/test/e2e/3_issue_173_spec.ts index d73090d33af0..dc11a1c4cf25 100644 --- a/packages/server/test/e2e/3_issue_173_spec.js +++ b/packages/server/test/e2e/3_issue_173_spec.ts @@ -1,4 +1,4 @@ -const e2e = require('../support/helpers/e2e').default +import e2e from '../support/helpers/e2e' describe('e2e issue 173', () => { e2e.setup() diff --git a/packages/server/test/e2e/3_plugins_spec.js b/packages/server/test/e2e/3_plugins_spec.js index c218039ed88c..c7428f701533 100644 --- a/packages/server/test/e2e/3_plugins_spec.js +++ b/packages/server/test/e2e/3_plugins_spec.js @@ -150,6 +150,15 @@ describe('e2e plugins', function () { }) }) + // https://github.com/cypress-io/cypress/issues/8079 + it('does not report more screenshots than exist if user overwrites previous screenshot in afterScreenshot', function () { + return e2e.exec(this, { + spec: 'after_screenshot_overwrite_spec.coffee', + project: pluginAfterScreenshot, + snapshot: true, + }) + }) + it('fails when invalid event is registered', function () { return e2e.exec(this, { spec: 'app_spec.js', diff --git a/packages/server/test/e2e/3_retries_spec.ts b/packages/server/test/e2e/3_retries_spec.ts new file mode 100644 index 000000000000..1129093470a3 --- /dev/null +++ b/packages/server/test/e2e/3_retries_spec.ts @@ -0,0 +1,21 @@ +import e2e from '../support/helpers/e2e' +import Fixtures from '../support/helpers/fixtures' + +const it = e2e.it + +describe('retries', () => { + e2e.setup() + + it('supports retries', { + project: Fixtures.projectPath('retries-2'), + spec: 'fail-twice.js', + snapshot: true, + }) + + it('warns about retries plugin', { + project: Fixtures.projectPath('plugin-retries'), + spec: 'main.spec.js', + stubPackage: 'cypress-plugin-retries', + snapshot: true, + }) +}) diff --git a/packages/server/test/e2e/3_runnable_execution_spec.ts b/packages/server/test/e2e/3_runnable_execution_spec.ts index 361475a13526..769d05ba9d4b 100644 --- a/packages/server/test/e2e/3_runnable_execution_spec.ts +++ b/packages/server/test/e2e/3_runnable_execution_spec.ts @@ -24,7 +24,7 @@ describe('e2e runnable execution', () => { project: Fixtures.projectPath('hooks-after-rerun'), spec: 'beforehook-and-test-navigation.js', snapshot: true, - expectedExitCode: 1, + expectedExitCode: 2, }) e2e.it('runnables run correct number of times with navigation', { diff --git a/packages/server/test/e2e/4_controllers_spec.js b/packages/server/test/e2e/4_controllers_spec.js index d3d67403b412..06cef27690ee 100644 --- a/packages/server/test/e2e/4_controllers_spec.js +++ b/packages/server/test/e2e/4_controllers_spec.js @@ -20,14 +20,8 @@ describe('e2e plugins', () => { }) }) - it('handles specs with $, &, ?, + in file name', function () { - let relativeSpecPath = path.join('d?ir&1%', '%di?r2&', 's%p+ec&?.js') - - // windows doesn't support ? in file names - if (process.platform === 'win32') { - relativeSpecPath = specPath.replace(/\?/, '') - } - + it('handles specs with $, &, and + in file name', function () { + const relativeSpecPath = path.join('dir&1%', '%dir2&', 's%p+ec&.js') const specPath = path.join(e2eProject, 'cypress', 'integration', relativeSpecPath) return fs.outputFile(specPath, 'it(\'passes\', () => {})') diff --git a/packages/server/test/e2e/5_screenshots_spec.js b/packages/server/test/e2e/5_screenshots_spec.js index a5934ec1b605..7dafd8a1d2b1 100644 --- a/packages/server/test/e2e/5_screenshots_spec.js +++ b/packages/server/test/e2e/5_screenshots_spec.js @@ -63,9 +63,10 @@ describe('e2e screenshots', () => { // the test title as the file name e2e.it('passes', { spec: 'screenshots_spec.js', - expectedExitCode: 4, + expectedExitCode: 5, snapshot: true, timeout: 180000, + onStdout: e2e.normalizeWebpackErrors, onRun (exec, browser) { return exec() .then(() => { diff --git a/packages/server/test/e2e/5_spec_isolation_spec.js b/packages/server/test/e2e/5_spec_isolation_spec.js index 9756d610294a..17f47704770c 100644 --- a/packages/server/test/e2e/5_spec_isolation_spec.js +++ b/packages/server/test/e2e/5_spec_isolation_spec.js @@ -1,17 +1,16 @@ -const _ = require('lodash') +// TODO: rename this file to 5_module_api_spec + const path = require('path') -const moment = require('moment') const snapshot = require('snap-shot-it') const fs = require('../../lib/util/fs') const e2e = require('../support/helpers/e2e').default const Fixtures = require('../support/helpers/fixtures') +const { expectCorrectModuleApiResult } = require('../support/helpers/resultsUtils') const e2ePath = Fixtures.projectPath('e2e') const outputPath = path.join(e2ePath, 'output.json') -const STATIC_DATE = '2018-02-01T20:14:19.323Z' - const specs = [ 'simple_passing_spec.coffee', 'simple_hooks_spec.coffee', @@ -19,169 +18,6 @@ const specs = [ 'simple_failing_h*_spec.coffee', // simple failing hook spec ].join(',') -const expectStartToBeBeforeEnd = function (obj, start, end) { - const s = _.get(obj, start) - const e = _.get(obj, end) - - expect( - moment(s).isBefore(e), - `expected start: ${s} to be before end: ${e}`, - ).to.be.true - - // once valid, mutate and set static dates - _.set(obj, start, STATIC_DATE) - - return _.set(obj, end, STATIC_DATE) -} - -const expectDurationWithin = function (obj, duration, low, high, reset) { - const d = _.get(obj, duration) - - // bail if we don't have a duration - if (!_.isNumber(d)) { - return - } - - // ensure the duration is within range - expect(d, duration).to.be.within(low, high) - - // once valid, mutate and set static range - return _.set(obj, duration, reset) -} - -const normalizeTestTimings = function (obj, timings) { - const t = _.get(obj, timings) - - // bail if we don't have any timings - if (!t) { - return - } - - return _.set(obj, 'timings', _.mapValues(t, (val, key) => { - switch (key) { - case 'lifecycle': - // ensure that lifecycle is under 500ms - expect(val, 'lifecycle').to.be.within(0, 500) - - // reset to 100 - return 100 - case 'test': - // ensure test fn duration is within 1500ms - expectDurationWithin(val, 'fnDuration', 0, 1500, 400) - // ensure test after fn duration is within 500ms - expectDurationWithin(val, 'afterFnDuration', 0, 500, 200) - - return val - default: - return _.map(val, (hook) => { - // ensure test fn duration is within 1500ms - expectDurationWithin(hook, 'fnDuration', 0, 1500, 400) - // ensure test after fn duration is within 500ms - expectDurationWithin(hook, 'afterFnDuration', 0, 500, 200) - - return hook - }) - } - })) -} - -const expectRunsToHaveCorrectStats = (runs = []) => { - return runs.forEach((run) => { - expectStartToBeBeforeEnd(run, 'stats.wallClockStartedAt', 'stats.wallClockEndedAt') - expectStartToBeBeforeEnd(run, 'reporterStats.start', 'reporterStats.end') - - // grab all the wallclock durations for all tests - // because our duration should be at least this - const wallClocks = _.sumBy(run.tests, 'wallClockDuration') - - // ensure each run's duration is around the sum - // of all tests wallclock duration - expectDurationWithin( - run, - 'stats.wallClockDuration', - wallClocks, - wallClocks + 200, // add 200ms to account for padding - 1234, - ) - - expectDurationWithin( - run, - 'reporterStats.duration', - wallClocks, - wallClocks + 200, // add 200ms to account for padding - 1234, - ) - - const addFnAndAfterFn = (obj) => { - return obj.fnDuration + obj.afterFnDuration - } - - run.spec.absolute = e2e.normalizeStdout(run.spec.absolute) - - // now make sure that each tests wallclock duration - // is around the sum of all of its timings - run.tests.forEach((test) => { - // cannot sum an object, must use array of values - const timings = _.sumBy(_.values(test.timings), (val) => { - if (_.isArray(val)) { - // array for hooks - return _.sumBy(val, addFnAndAfterFn) - } - - if (_.isObject(val)) { - // obj for test itself - return addFnAndAfterFn(val) - } - - return val - }) - - expectDurationWithin( - test, - 'wallClockDuration', - timings, - timings + 80, // add 80ms to account for padding - 1234, - ) - - // now reset all the test timings - normalizeTestTimings(test, 'timings') - - // normalize stack - if (test.stack) { - test.stack = e2e.normalizeStdout(test.stack) - } - - if (test.wallClockStartedAt) { - const d = new Date(test.wallClockStartedAt) - - expect(d.toJSON()).to.eq(test.wallClockStartedAt) - test.wallClockStartedAt = STATIC_DATE - - expect(test.videoTimestamp).to.be.a('number') - test.videoTimestamp = 9999 - } - }) - - // normalize video path - run.video = e2e.normalizeStdout(run.video) - - run.screenshots = _.map(run.screenshots, (screenshot) => { - expect(screenshot.screenshotId).to.have.length('5') - - const d = new Date(screenshot.takenAt) - - expect(d.toJSON()).to.eq(screenshot.takenAt) - screenshot.takenAt = STATIC_DATE - - screenshot.screenshotId = 'some-random-id' - screenshot.path = e2e.normalizeStdout(screenshot.path) - - return screenshot - }) - }) -} - describe('e2e spec_isolation', () => { e2e.setup() @@ -190,66 +26,38 @@ describe('e2e spec_isolation', () => { outputPath, snapshot: false, expectedExitCode: 5, - onRun (exec) { - return exec() - .then(() => { - // now what we want to do is read in the outputPath - // and snapshot it so its what we expect after normalizing it - return fs.readJsonAsync(outputPath) - .then((json) => { - // ensure that config has been set - expect(json.config).to.be.an('object') - expect(json.config.projectName).to.eq('e2e') - expect(json.config.projectRoot).to.eq(e2ePath) - - // but zero out config because it's too volatile - json.config = {} - - expect(json.browserPath).to.be.a('string') - expect(json.browserName).to.be.a('string') - expect(json.browserVersion).to.be.a('string') - expect(json.osName).to.be.a('string') - expect(json.osVersion).to.be.a('string') - expect(json.cypressVersion).to.be.a('string') - - _.extend(json, { - browserPath: 'path/to/browser', - browserName: 'FooBrowser', - browserVersion: '88', - osName: 'FooOS', - osVersion: '1234', - cypressVersion: '9.9.9', - }) + async onRun (exec) { + await exec() - // ensure the totals are accurate - expect(json.totalTests).to.eq( - _.sum([ - json.totalFailed, - json.totalPassed, - json.totalPending, - json.totalSkipped, - ]), - ) + // now what we want to do is read in the outputPath + // and snapshot it so its what we expect after normalizing it + const json = await fs.readJsonAsync(outputPath) - expectStartToBeBeforeEnd(json, 'startedTestsAt', 'endedTestsAt') + // also mutates into normalized obj ready for snapshot + expectCorrectModuleApiResult(json, { + e2ePath, runs: 4, + }) - // ensure totalDuration matches all of the stats durations - expectDurationWithin( - json, - 'totalDuration', - _.sumBy(json.runs, 'stats.wallClockDuration'), - _.sumBy(json.runs, 'stats.wallClockDuration'), - 5555, - ) + snapshot('e2e spec isolation fails', json, { allowSharedSnapshot: true }) + }, + }) - // should be 4 total runs - expect(json.runs).to.have.length(4) + e2e.it('failing with retries enabled', { + spec: 'simple_failing_hook_spec.coffee', + outputPath, + snapshot: true, + expectedExitCode: 3, + config: { + retries: 1, + }, + async onRun (execFn) { + await execFn() + const json = await fs.readJsonAsync(outputPath) - expectRunsToHaveCorrectStats(json.runs) + // also mutates into normalized obj ready for snapshot + expectCorrectModuleApiResult(json, { e2ePath, runs: 1 }) - return snapshot('e2e spec isolation fails', json, { allowSharedSnapshot: true }) - }) - }) + snapshot('failing with retries enabled', json) }, }) }) diff --git a/packages/server/test/e2e/5_stdout_spec.js b/packages/server/test/e2e/5_stdout_spec.js index 969521025711..7e0f71e0f707 100644 --- a/packages/server/test/e2e/5_stdout_spec.js +++ b/packages/server/test/e2e/5_stdout_spec.js @@ -17,6 +17,7 @@ describe('e2e stdout', () => { spec: 'stdout_exit_early_failing_spec.js', snapshot: true, expectedExitCode: 1, + onStdout: e2e.normalizeWebpackErrors, }) }) diff --git a/packages/server/test/e2e/5_subdomain_spec.js b/packages/server/test/e2e/5_subdomain_spec.ts similarity index 93% rename from packages/server/test/e2e/5_subdomain_spec.js rename to packages/server/test/e2e/5_subdomain_spec.ts index ebcf82fb2109..568330b5a5b2 100644 --- a/packages/server/test/e2e/5_subdomain_spec.js +++ b/packages/server/test/e2e/5_subdomain_spec.ts @@ -1,7 +1,7 @@ -const cors = require('cors') -const parser = require('cookie-parser') -const session = require('express-session') -const e2e = require('../support/helpers/e2e').default +import cors from 'cors' +import parser from 'cookie-parser' +import session from 'express-session' +import e2e from '../support/helpers/e2e' const onServer = function (app) { app.use(parser()) @@ -48,7 +48,7 @@ const onServer = function (app) { cookie: { sameSite: true, }, - }) + }) as Function app.get('/htmlCookies', (req, res) => { const { diff --git a/packages/server/test/e2e/7_record_spec.js b/packages/server/test/e2e/7_record_spec.js index 51bd2bdebd2f..295fe8755fcd 100644 --- a/packages/server/test/e2e/7_record_spec.js +++ b/packages/server/test/e2e/7_record_spec.js @@ -3,10 +3,11 @@ const path = require('path') const Promise = require('bluebird') const bodyParser = require('body-parser') const jsonSchemas = require('@cypress/json-schemas').api +const snapshot = require('snap-shot-it') const e2e = require('../support/helpers/e2e').default const fs = require('../../lib/util/fs') const Fixtures = require('../support/helpers/fixtures') - +const { expectRunsToHaveCorrectTimings } = require('../support/helpers/resultsUtils') const postRunResponseWithWarnings = jsonSchemas.getExample('postRunResponse')('2.2.0') const postRunResponse = _.assign({}, postRunResponseWithWarnings, { warnings: [] }) const postRunInstanceResponse = jsonSchemas.getExample('postRunInstanceResponse')('2.1.0') @@ -192,7 +193,7 @@ const defaultRoutes = [ }, { method: 'put', url: '/instances/:id', - req: 'putInstanceRequest@2.0.0', + req: 'putInstanceRequest@3.0.0', resSchema: 'putInstanceResponse@2.0.0', res: sendUploadUrls, }, { @@ -228,8 +229,8 @@ describe('e2e record', () => { context('passing', () => { setup(defaultRoutes) - it('passes', function () { - return e2e.exec(this, { + it('passes', async function () { + const { stdout } = await e2e.exec(this, { key: 'f858a2bc-b469-4e48-be67-0876339ee7e1', spec: 'record*', record: true, @@ -237,174 +238,179 @@ describe('e2e record', () => { outputPath, expectedExitCode: 3, }) - .get('stdout') - .then((stdout) => { - expect(stdout).to.include('Run URL:') - expect(stdout).to.include(runUrl) - - const urls = getRequestUrls() - - // first create run request - expect(urls[0]).to.eq('POST /runs') - - // grab the first set of 4 - const firstInstanceSet = urls.slice(1, 5) - - expect(firstInstanceSet).to.deep.eq([ - `POST /runs/${runId}/instances`, - `PUT /instances/${instanceId}`, - 'PUT /videos/video.mp4', - `PUT /instances/${instanceId}/stdout`, - ]) - - // grab the second set of 5 - const secondInstanceSet = urls.slice(5, 10) - - expect(secondInstanceSet).to.have.members([ - `POST /runs/${runId}/instances`, - `PUT /instances/${instanceId}`, - 'PUT /videos/video.mp4', - 'PUT /screenshots/1.png', - `PUT /instances/${instanceId}/stdout`, - ]) - - // grab the third set of 5 - const thirdInstanceSet = urls.slice(10, 14) - - // no video because no tests failed - expect(thirdInstanceSet).to.deep.eq([ - `POST /runs/${runId}/instances`, - `PUT /instances/${instanceId}`, - 'PUT /screenshots/1.png', - `PUT /instances/${instanceId}/stdout`, - ]) - - // grab the forth set of 5 - const forthInstanceSet = urls.slice(14, 19) - - expect(forthInstanceSet).to.have.members([ - `POST /runs/${runId}/instances`, - `PUT /instances/${instanceId}`, - 'PUT /videos/video.mp4', - 'PUT /screenshots/1.png', - `PUT /instances/${instanceId}/stdout`, - ]) - - const postRun = requests[0] - - // ensure its relative to projectRoot - expect(postRun.body.specs).to.deep.eq([ - 'cypress/integration/record_error_spec.coffee', - 'cypress/integration/record_fail_spec.coffee', - 'cypress/integration/record_pass_spec.coffee', - 'cypress/integration/record_uncaught_spec.coffee', - ]) - - expect(postRun.body.projectId).to.eq('pid123') - expect(postRun.body.recordKey).to.eq('f858a2bc-b469-4e48-be67-0876339ee7e1') - expect(postRun.body.specPattern).to.eq('cypress/integration/record*') - - const firstInstance = requests[1] - - expect(firstInstance.body.groupId).to.eq(groupId) - expect(firstInstance.body.machineId).to.eq(machineId) - expect(firstInstance.body.spec).to.eq( - 'cypress/integration/record_error_spec.coffee', - ) - const firstInstancePut = requests[2] + console.log(stdout) + expect(stdout).to.include('Run URL:') + expect(stdout).to.include(runUrl) - expect(firstInstancePut.body.error).to.include('Oops...we found an error preparing this test file') - expect(firstInstancePut.body.tests).to.be.null - expect(firstInstancePut.body.hooks).to.be.null - expect(firstInstancePut.body.screenshots).to.have.length(0) - expect(firstInstancePut.body.stats.tests).to.eq(0) - expect(firstInstancePut.body.stats.failures).to.eq(1) - expect(firstInstancePut.body.stats.passes).to.eq(0) + const urls = getRequestUrls() - const firstInstanceStdout = requests[4] + // first create run request + expect(urls[0]).to.eq('POST /runs') - expect(firstInstanceStdout.body.stdout).to.include('record_error_spec.coffee') + // grab the first set of 4 + const firstInstanceSet = urls.slice(1, 5) - const secondInstance = requests[5] + expect(firstInstanceSet).to.deep.eq([ + `POST /runs/${runId}/instances`, + `PUT /instances/${instanceId}`, + 'PUT /videos/video.mp4', + `PUT /instances/${instanceId}/stdout`, + ]) - expect(secondInstance.body.groupId).to.eq(groupId) - expect(secondInstance.body.machineId).to.eq(machineId) - expect(secondInstance.body.spec).to.eq( - 'cypress/integration/record_fail_spec.coffee', - ) + // grab the second set of 5 + const secondInstanceSet = urls.slice(5, 10) - const secondInstancePut = requests[6] + console.log(secondInstanceSet) + expect(secondInstanceSet).to.have.members([ + `POST /runs/${runId}/instances`, + `PUT /instances/${instanceId}`, + 'PUT /videos/video.mp4', + 'PUT /screenshots/1.png', + `PUT /instances/${instanceId}/stdout`, + ]) - expect(secondInstancePut.body.error).to.be.null - expect(secondInstancePut.body.tests).to.have.length(2) - expect(secondInstancePut.body.hooks).to.have.length(2) - expect(secondInstancePut.body.screenshots).to.have.length(1) - expect(secondInstancePut.body.stats.tests).to.eq(2) - expect(secondInstancePut.body.stats.failures).to.eq(1) - expect(secondInstancePut.body.stats.passes).to.eq(0) - expect(secondInstancePut.body.stats.skipped).to.eq(1) + // grab the third set of 5 + const thirdInstanceSet = urls.slice(10, 14) - const secondInstanceStdout = requests[9] + // no video because no tests failed + expect(thirdInstanceSet).to.deep.eq([ + `POST /runs/${runId}/instances`, + `PUT /instances/${instanceId}`, + 'PUT /screenshots/1.png', + `PUT /instances/${instanceId}/stdout`, + ]) - expect(secondInstanceStdout.body.stdout).to.include('record_fail_spec.coffee') - expect(secondInstanceStdout.body.stdout).not.to.include('record_error_spec.coffee') + // grab the forth set of 5 + const forthInstanceSet = urls.slice(14, 19) - const thirdInstance = requests[10] + expect(forthInstanceSet).to.have.members([ + `POST /runs/${runId}/instances`, + `PUT /instances/${instanceId}`, + 'PUT /videos/video.mp4', + 'PUT /screenshots/1.png', + `PUT /instances/${instanceId}/stdout`, + ]) - expect(thirdInstance.body.groupId).to.eq(groupId) - expect(thirdInstance.body.machineId).to.eq(machineId) - expect(thirdInstance.body.spec).to.eq( - 'cypress/integration/record_pass_spec.coffee', - ) + const postRun = requests[0] - const thirdInstancePut = requests[11] + // ensure its relative to projectRoot + expect(postRun.body.specs).to.deep.eq([ + 'cypress/integration/record_error_spec.coffee', + 'cypress/integration/record_fail_spec.coffee', + 'cypress/integration/record_pass_spec.coffee', + 'cypress/integration/record_uncaught_spec.coffee', + ]) - expect(thirdInstancePut.body.error).to.be.null - expect(thirdInstancePut.body.tests).to.have.length(2) - expect(thirdInstancePut.body.hooks).to.have.length(1) - expect(thirdInstancePut.body.screenshots).to.have.length(1) - expect(thirdInstancePut.body.stats.tests).to.eq(2) - expect(thirdInstancePut.body.stats.passes).to.eq(1) - expect(thirdInstancePut.body.stats.failures).to.eq(0) - expect(thirdInstancePut.body.stats.pending).to.eq(1) + expect(postRun.body.projectId).to.eq('pid123') + expect(postRun.body.recordKey).to.eq('f858a2bc-b469-4e48-be67-0876339ee7e1') + expect(postRun.body.specPattern).to.eq('cypress/integration/record*') - const thirdInstanceStdout = requests[13] + const firstInstance = requests[1] - expect(thirdInstanceStdout.body.stdout).to.include('record_pass_spec.coffee') - expect(thirdInstanceStdout.body.stdout).not.to.include('record_error_spec.coffee') - expect(thirdInstanceStdout.body.stdout).not.to.include('record_fail_spec.coffee') + expect(firstInstance.body.groupId).to.eq(groupId) + expect(firstInstance.body.machineId).to.eq(machineId) + expect(firstInstance.body.spec).to.eq( + 'cypress/integration/record_error_spec.coffee', + ) - const fourthInstance = requests[14] + const firstInstancePut = requests[2] - expect(fourthInstance.body.groupId).to.eq(groupId) - expect(fourthInstance.body.machineId).to.eq(machineId) - expect(fourthInstance.body.spec).to.eq( - 'cypress/integration/record_uncaught_spec.coffee', - ) + expect(firstInstancePut.body.error).to.include('Oops...we found an error preparing this test file') + expect(firstInstancePut.body.tests).to.be.null + expect(firstInstancePut.body.hooks).to.be.null + expect(firstInstancePut.body.screenshots).to.have.length(0) + expect(firstInstancePut.body.stats.tests).to.eq(0) + expect(firstInstancePut.body.stats.failures).to.eq(1) + expect(firstInstancePut.body.stats.passes).to.eq(0) - const fourthInstancePut = requests[15] + const firstInstanceStdout = requests[4] - expect(fourthInstancePut.body.error).to.be.null - expect(fourthInstancePut.body.tests).to.have.length(1) - expect(fourthInstancePut.body.hooks).to.have.length(1) - expect(fourthInstancePut.body.screenshots).to.have.length(1) - expect(fourthInstancePut.body.stats.tests).to.eq(1) - expect(fourthInstancePut.body.stats.failures).to.eq(1) - expect(fourthInstancePut.body.stats.passes).to.eq(0) + expect(firstInstanceStdout.body.stdout).to.include('record_error_spec.coffee') - const forthInstanceStdout = requests[18] + const secondInstance = requests[5] - expect(forthInstanceStdout.body.stdout).to.include('record_uncaught_spec.coffee') - expect(forthInstanceStdout.body.stdout).not.to.include('record_error_spec.coffee') - expect(forthInstanceStdout.body.stdout).not.to.include('record_fail_spec.coffee') - expect(forthInstanceStdout.body.stdout).not.to.include('record_pass_spec.coffee') + expect(secondInstance.body.groupId).to.eq(groupId) + expect(secondInstance.body.machineId).to.eq(machineId) + expect(secondInstance.body.spec).to.eq( + 'cypress/integration/record_fail_spec.coffee', + ) - return fs.readJsonAsync(outputPath) - .then((results) => { - expect(results.runUrl).to.equal(runUrl) - }) - }) + const secondInstancePut = requests[6] + + expect(secondInstancePut.body.error).to.be.null + expect(secondInstancePut.body.tests).to.have.length(2) + expect(secondInstancePut.body.hooks).to.have.length(1) + expect(secondInstancePut.body.screenshots).to.have.length(1) + expect(secondInstancePut.body.stats.tests).to.eq(2) + expect(secondInstancePut.body.stats.failures).to.eq(1) + expect(secondInstancePut.body.stats.passes).to.eq(0) + expect(secondInstancePut.body.stats.skipped).to.eq(1) + + const secondInstanceStdout = requests[9] + + expect(secondInstanceStdout.body.stdout).to.include('record_fail_spec.coffee') + expect(secondInstanceStdout.body.stdout).not.to.include('record_error_spec.coffee') + + const thirdInstance = requests[10] + + expect(thirdInstance.body.groupId).to.eq(groupId) + expect(thirdInstance.body.machineId).to.eq(machineId) + expect(thirdInstance.body.spec).to.eq( + 'cypress/integration/record_pass_spec.coffee', + ) + + const thirdInstancePut = requests[11] + + expect(thirdInstancePut.body.error).to.be.null + expect(thirdInstancePut.body.tests).to.have.length(2) + expect(thirdInstancePut.body.hooks).to.have.length(0) + expect(thirdInstancePut.body.screenshots).to.have.length(1) + expect(thirdInstancePut.body.stats.tests).to.eq(2) + expect(thirdInstancePut.body.stats.passes).to.eq(1) + expect(thirdInstancePut.body.stats.failures).to.eq(0) + expect(thirdInstancePut.body.stats.pending).to.eq(1) + + const thirdInstanceStdout = requests[13] + + expect(thirdInstanceStdout.body.stdout).to.include('record_pass_spec.coffee') + expect(thirdInstanceStdout.body.stdout).not.to.include('record_error_spec.coffee') + expect(thirdInstanceStdout.body.stdout).not.to.include('record_fail_spec.coffee') + + const fourthInstance = requests[14] + + expect(fourthInstance.body.groupId).to.eq(groupId) + expect(fourthInstance.body.machineId).to.eq(machineId) + expect(fourthInstance.body.spec).to.eq( + 'cypress/integration/record_uncaught_spec.coffee', + ) + + const fourthInstancePut = requests[15] + + expect(fourthInstancePut.body.error).to.be.null + expect(fourthInstancePut.body.tests).to.have.length(1) + expect(fourthInstancePut.body.hooks).to.have.length(0) + expect(fourthInstancePut.body.screenshots).to.have.length(1) + expect(fourthInstancePut.body.stats.tests).to.eq(1) + expect(fourthInstancePut.body.stats.failures).to.eq(1) + expect(fourthInstancePut.body.stats.passes).to.eq(0) + + const forthInstanceStdout = requests[18] + + expect(forthInstanceStdout.body.stdout).to.include('record_uncaught_spec.coffee') + expect(forthInstanceStdout.body.stdout).not.to.include('record_error_spec.coffee') + expect(forthInstanceStdout.body.stdout).not.to.include('record_fail_spec.coffee') + expect(forthInstanceStdout.body.stdout).not.to.include('record_pass_spec.coffee') + + const runs = requests.filter((v) => v.body.tests).map((v) => v.body) + + expectRunsToHaveCorrectTimings(runs) + + snapshot(runs) + + const results = await fs.readJsonAsync(outputPath) + + expect(results.runUrl).to.equal(runUrl) }) }) @@ -869,7 +875,7 @@ describe('e2e record', () => { routes[2] = { method: 'put', url: '/instances/:id', - req: 'putInstanceRequest@2.0.0', + req: 'putInstanceRequest@3.0.0', res (req, res) { return res.sendStatus(500) }, @@ -1169,7 +1175,7 @@ describe('e2e record', () => { }, { method: 'put', url: '/instances/:id', - req: 'putInstanceRequest@2.0.0', + req: 'putInstanceRequest@3.0.0', res (req, res) { return res.sendStatus(500) }, @@ -1216,7 +1222,7 @@ describe('e2e record', () => { }, { method: 'put', url: '/instances/:id', - req: 'putInstanceRequest@2.0.0', + req: 'putInstanceRequest@3.0.0', resSchema: 'putInstanceResponse@2.0.0', res: sendUploadUrls, }, { @@ -1287,7 +1293,7 @@ describe('e2e record', () => { }, { method: 'put', url: '/instances/:id', - req: 'putInstanceRequest@2.0.0', + req: 'putInstanceRequest@3.0.0', resSchema: 'putInstanceResponse@2.0.0', res: sendUploadUrls, }, { diff --git a/packages/server/test/e2e/8_reporters_spec.js b/packages/server/test/e2e/8_reporters_spec.js index c22481e8009c..f2349eb97cc9 100644 --- a/packages/server/test/e2e/8_reporters_spec.js +++ b/packages/server/test/e2e/8_reporters_spec.js @@ -117,7 +117,7 @@ describe('e2e reporters', () => { .then((xml) => { expect(xml).to.include('

    simple failing hook spec

    ') - expect(xml).to.include('
    3 Failed Hooks
    ') + expect(xml).to.not.include('.status-item-hooks') }) } @@ -125,10 +125,12 @@ describe('e2e reporters', () => { .then((json) => { // mochawesome does not consider hooks to be // 'failures' but it does collect them in 'other' + // HOWEVER we now change how mocha events fire to make mocha stats reflect ours expect(json.stats).to.be.an('object') - expect(json.stats.failures).to.eq(0) - - expect(json.stats.other).to.eq(3) + expect(json.stats.passes).to.eq(1) + expect(json.stats.failures).to.eq(3) + expect(json.stats.skipped).to.eq(1) + expect(json.stats.other).to.eq(0) }) }) }) diff --git a/packages/server/test/integration/cypress_spec.js b/packages/server/test/integration/cypress_spec.js index 627fd351ab30..762541c514be 100644 --- a/packages/server/test/integration/cypress_spec.js +++ b/packages/server/test/integration/cypress_spec.js @@ -889,25 +889,31 @@ describe('lib/cypress', () => { }) }) - it('logs error and exits when using an old configuration option: trashAssetsBeforeHeadlessRuns', function () { - return cypress.start([ - `--run-project=${this.todosPath}`, - '--config=trashAssetsBeforeHeadlessRuns=false', - ]) - .then(() => { - this.expectExitWithErr('RENAMED_CONFIG_OPTION', 'trashAssetsBeforeHeadlessRuns') - this.expectExitWithErr('RENAMED_CONFIG_OPTION', 'trashAssetsBeforeRuns') - }) - }) - - it('logs error and exits when using an old configuration option: videoRecording', function () { - return cypress.start([ - `--run-project=${this.todosPath}`, - '--config=videoRecording=false', - ]) - .then(() => { - this.expectExitWithErr('RENAMED_CONFIG_OPTION', 'videoRecording') - this.expectExitWithErr('RENAMED_CONFIG_OPTION', 'video') + const renamedConfigs = [ + { + old: 'trashAssetsBeforeHeadlessRuns', + new: 'trashAssetsBeforeRuns', + }, + { + old: 'videoRecording', + new: 'video', + }, + { + old: 'blacklistHosts', + new: 'blockHosts', + }, + ] + + renamedConfigs.forEach(function (config) { + it(`logs error and exits when using an old configuration option: ${config.old}`, function () { + return cypress.start([ + `--run-project=${this.todosPath}`, + `--config=${config.old}=''`, + ]) + .then(() => { + this.expectExitWithErr('RENAMED_CONFIG_OPTION', config.old) + this.expectExitWithErr('RENAMED_CONFIG_OPTION', config.new) + }) }) }) diff --git a/packages/server/test/integration/http_requests_spec.js b/packages/server/test/integration/http_requests_spec.js index 5c2e6844bcf8..63c925783132 100644 --- a/packages/server/test/integration/http_requests_spec.js +++ b/packages/server/test/integration/http_requests_spec.js @@ -11,10 +11,6 @@ const path = require('path') const url = require('url') let zlib = require('zlib') const str = require('underscore.string') -const browserify = require('browserify') -const babelify = require('babelify') -const coffeeify = require('coffeeify') -const streamToPromise = require('stream-to-promise') const evilDns = require('evil-dns') const Promise = require('bluebird') const httpsServer = require(`${root}../https-proxy/test/helpers/https_server`) @@ -32,7 +28,6 @@ const fs = require(`${root}lib/util/fs`) const glob = require(`${root}lib/util/glob`) const CacheBuster = require(`${root}lib/util/cache_buster`) const Fixtures = require(`${root}test/support/helpers/fixtures`) -const simple_tsify = require(`${root}test/support/helpers/simple_tsify`) zlib = Promise.promisifyAll(zlib) @@ -46,10 +41,6 @@ const replaceAbsolutePaths = (content) => { return content.replace(absolutePathRegex, '"/') } -const removeSourceMap = (content) => { - return content.replace(sourceMapRegex, ';') -} - const removeWhitespace = function (c) { c = str.clean(c) c = str.lines(c).join(' ') @@ -61,36 +52,6 @@ const cleanResponseBody = (body) => { return replaceAbsolutePaths(removeWhitespace(body)) } -const browserifyFile = (filePath) => { - return streamToPromise( - browserify({ - entries: [filePath], - extensions: ['.js', '.jsx', '.coffee'], - cache: {}, - packageCache: {}, - transform: [ - [coffeeify, {}], - [babelify, { - plugins: ['add-module-exports', '@babel/plugin-proposal-class-properties', '@babel/plugin-proposal-object-rest-spread', '@babel/plugin-transform-runtime'], - presets: ['@babel/preset-env', '@babel/preset-react'], - }], - ], - }) - .bundle(), - ) -} - -const browserifyFileTs = (filePath) => { - return streamToPromise( - browserify(filePath) - .transform(coffeeify) - .transform(simple_tsify, { - typescript: require('typescript'), - }) - .bundle(), - ) -} - describe('Routes', () => { require('mocha-banner').register() @@ -605,22 +566,11 @@ describe('Routes', () => { }) }) - const checkTranspilation = function (body, file) { - const b = removeSourceMap(body).replace(/\n/g, '') - const f = file.toString().replace(/\n/g, '') - - expect(b).to.equal(f) - } - it('processes foo.coffee spec', function () { return this.rp('http://localhost:2020/__cypress/tests?p=cypress/integration/foo.coffee') .then((res) => { expect(res.statusCode).to.eq(200) - - return browserifyFileTs(Fixtures.path('projects/ids/cypress/integration/foo.coffee')) - .then((file) => { - return checkTranspilation(res.body, file) - }) + expect(res.body).to.include('expect("foo.coffee")') }) }) @@ -628,13 +578,7 @@ describe('Routes', () => { return this.rp('http://localhost:2020/__cypress/tests?p=cypress/integration/baz.js') .then((res) => { expect(res.statusCode).to.eq(200) - - return browserifyFileTs(Fixtures.path('projects/ids/cypress/integration/baz.js')) - .then((file) => { - checkTranspilation(res.body, file) - - expect(res.body).to.include('React.createElement(') - }) + expect(res.body).to.include('React.createElement(') }) }) @@ -643,8 +587,7 @@ describe('Routes', () => { .then((res) => { expect(res.statusCode).to.eq(200) expect(res.body).to.include('Cypress.action("spec:script:error", {') - - expect(res.body).to.include('Cannot find module') + expect(res.body).to.include('Module not found') }) }) }) @@ -653,8 +596,6 @@ describe('Routes', () => { beforeEach(function () { Fixtures.scaffold('ids') - // remove cached options - delete require.cache[require.resolve('@cypress/browserify-preprocessor')] sinon.stub(resolve, 'typescript').callsFake(() => { return null }) @@ -669,11 +610,7 @@ describe('Routes', () => { .then((res) => { expect(res.statusCode).to.eq(200) expect(res.body).to.match(sourceMapRegex) - - return browserifyFile(Fixtures.path('projects/ids/cypress/integration/foo.coffee')) - .then((file) => { - expect(removeSourceMap(res.body)).to.equal(file.toString()) - }) + expect(res.body).to.include('expect("foo.coffee")') }) }) @@ -682,13 +619,7 @@ describe('Routes', () => { .then((res) => { expect(res.statusCode).to.eq(200) expect(res.body).to.match(sourceMapRegex) - - return browserifyFile(Fixtures.path('projects/ids/cypress/integration/baz.js')) - .then((file) => { - expect(removeSourceMap(res.body)).to.equal(file.toString()) - - expect(res.body).to.include('React.createElement(') - }) + expect(res.body).to.include('React.createElement(') }) }) @@ -697,8 +628,7 @@ describe('Routes', () => { .then((res) => { expect(res.statusCode).to.eq(200) expect(res.body).to.include('Cypress.action("spec:script:error", {') - - expect(res.body).to.include('Cannot find module') + expect(res.body).to.include('Module not found') }) }) }) @@ -717,8 +647,7 @@ describe('Routes', () => { .then((res) => { expect(res.statusCode).to.eq(200) expect(res.body).to.include('Cypress.action("spec:script:error", {') - - expect(res.body).to.include('ParseError') + expect(res.body).to.include('Unexpected token') }) }) }) @@ -741,11 +670,7 @@ describe('Routes', () => { .then((res) => { expect(res.statusCode).to.eq(200) expect(res.body).to.match(sourceMapRegex) - - return browserifyFileTs(Fixtures.path('projects/no-server/my-tests/test1.js')) - .then((file) => { - expect(removeSourceMap(res.body)).to.equal(file.toString()) - }) + expect(res.body).to.include(`expect('no-server')`) }) }) @@ -754,11 +679,7 @@ describe('Routes', () => { .then((res) => { expect(res.statusCode).to.eq(200) expect(res.body).to.match(sourceMapRegex) - - return browserifyFileTs(Fixtures.path('projects/no-server/helpers/includes.js')) - .then((file) => { - expect(removeSourceMap(res.body)).to.equal(file.toString()) - }) + expect(res.body).to.include(`console.log('includes')`) }) }) }) @@ -3748,11 +3669,11 @@ describe('Routes', () => { }) }) - context('blacklisted hosts', () => { + context('blocked hosts', () => { beforeEach(function () { return this.setup({ config: { - blacklistHosts: [ + blockHosts: [ '*.google.com', 'shop.apple.com', 'cypress.io', @@ -3765,7 +3686,7 @@ describe('Routes', () => { it('returns 503 and custom headers for all hosts', function () { const expectedHeader = (res, val) => { - expect(res.headers['x-cypress-matched-blacklisted-host']).to.eq(val) + expect(res.headers['x-cypress-matched-blocked-host']).to.eq(val) } return Promise.all([ diff --git a/packages/server/test/scripts/run.js b/packages/server/test/scripts/run.js index 0a1ab38e1c52..43c28a91a67f 100644 --- a/packages/server/test/scripts/run.js +++ b/packages/server/test/scripts/run.js @@ -155,6 +155,10 @@ if (options.exit === false) { env.NO_EXIT = '1' } +if (options['cypress-inspect-brk']) { + env.CYPRESS_INSPECT_BRK = '1' +} + const cmd = `${commandAndArguments.command} ${ commandAndArguments.args.join(' ')}` diff --git a/packages/server/test/support/fixtures/projects/browser-extensions/cypress/integration/spec.js b/packages/server/test/support/fixtures/projects/browser-extensions/cypress/integration/spec.js index d9cafa56b83b..0804337984fb 100644 --- a/packages/server/test/support/fixtures/projects/browser-extensions/cypress/integration/spec.js +++ b/packages/server/test/support/fixtures/projects/browser-extensions/cypress/integration/spec.js @@ -1,11 +1,5 @@ context('before:browser:launch extension e2e', () => { it('has the expected extension', () => { - if (Cypress.browser.name === 'electron') { - cy.wrap(window.top).its('theExtensionLoaded').should('be.true') - - return - } - cy.visit('/index.html') .get('#extension') .should('contain', 'inserted from extension!') diff --git a/packages/server/test/support/fixtures/projects/browser-extensions/cypress/plugins/index.js b/packages/server/test/support/fixtures/projects/browser-extensions/cypress/plugins/index.js index e708af7d7f9d..1b9a005ab36c 100644 --- a/packages/server/test/support/fixtures/projects/browser-extensions/cypress/plugins/index.js +++ b/packages/server/test/support/fixtures/projects/browser-extensions/cypress/plugins/index.js @@ -2,16 +2,7 @@ const path = require('path') module.exports = (on) => { on('before:browser:launch', (browser, options) => { - const { extensions } = options - - if (browser.name === 'electron') { - // electron doesn't support background pages yet, so load a devtools extension - // instead which will work - extensions.push(path.join(__dirname, '../../devtools-ext')) - } else { - extensions.push(path.join(__dirname, '../../../plugin-extension/ext')) - } - + options.extensions.push(path.join(__dirname, '../../../plugin-extension/ext')) options.preferences.devTools = true return options diff --git a/packages/server/test/support/fixtures/projects/browser-extensions/devtools-ext/devtools.html b/packages/server/test/support/fixtures/projects/browser-extensions/devtools-ext/devtools.html deleted file mode 100644 index 46e7f0645178..000000000000 --- a/packages/server/test/support/fixtures/projects/browser-extensions/devtools-ext/devtools.html +++ /dev/null @@ -1,15 +0,0 @@ - diff --git a/packages/server/test/support/fixtures/projects/browser-extensions/devtools-ext/manifest.json b/packages/server/test/support/fixtures/projects/browser-extensions/devtools-ext/manifest.json deleted file mode 100644 index 0b9d8264c1c7..000000000000 --- a/packages/server/test/support/fixtures/projects/browser-extensions/devtools-ext/manifest.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "name": "e2e devtools ext", - "version": "0", - "description": "tests adding devtools extension into Cypress", - "permissions": [ - "tabs", - "webNavigation", - "" - ], - "content_scripts": [], - "devtools_page": "devtools.html", - "manifest_version": 2 -} diff --git a/packages/server/test/support/fixtures/projects/cookies/cypress/integration/app_spec.coffee b/packages/server/test/support/fixtures/projects/cookies/cypress/integration/app_spec.coffee index 32bdcc41fcd0..b80abfbddd1c 100644 --- a/packages/server/test/support/fixtures/projects/cookies/cypress/integration/app_spec.coffee +++ b/packages/server/test/support/fixtures/projects/cookies/cypress/integration/app_spec.coffee @@ -1,5 +1,5 @@ Cypress.Cookies.defaults({ - whitelist: "foo1" + preserve: "foo1" }) describe "Cookies", -> @@ -84,3 +84,4 @@ describe "Cookies", -> domain: "brian.dev.local" }) .its("body").should("deep.eq", {wow: "bob"}) + \ No newline at end of file diff --git a/packages/server/test/support/fixtures/projects/e2e/cypress.json b/packages/server/test/support/fixtures/projects/e2e/cypress.json index 9e26dfeeb6e6..0f77b44749ce 100644 --- a/packages/server/test/support/fixtures/projects/e2e/cypress.json +++ b/packages/server/test/support/fixtures/projects/e2e/cypress.json @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "retries": null +} diff --git a/packages/server/test/support/fixtures/projects/e2e/cypress/integration/blacklist_hosts_spec.coffee b/packages/server/test/support/fixtures/projects/e2e/cypress/integration/block_hosts_spec.coffee similarity index 91% rename from packages/server/test/support/fixtures/projects/e2e/cypress/integration/blacklist_hosts_spec.coffee rename to packages/server/test/support/fixtures/projects/e2e/cypress/integration/block_hosts_spec.coffee index 47fecb9a4e39..16ee8ecc9552 100644 --- a/packages/server/test/support/fixtures/projects/e2e/cypress/integration/blacklist_hosts_spec.coffee +++ b/packages/server/test/support/fixtures/projects/e2e/cypress/integration/block_hosts_spec.coffee @@ -1,5 +1,5 @@ -describe "blacklist", -> - it "forces blacklisted hosts to return 503", -> +describe "block hosts", -> + it "forces blocked hosts to return 503", -> cy .visit("http://localhost:3232") diff --git a/packages/server/test/support/fixtures/projects/e2e/cypress/integration/cookies_spec_baseurl.coffee b/packages/server/test/support/fixtures/projects/e2e/cypress/integration/cookies_spec_baseurl.coffee index a712c2597fe6..bea74bb33864 100644 --- a/packages/server/test/support/fixtures/projects/e2e/cypress/integration/cookies_spec_baseurl.coffee +++ b/packages/server/test/support/fixtures/projects/e2e/cypress/integration/cookies_spec_baseurl.coffee @@ -35,10 +35,10 @@ describe "cookies", -> beforeEach -> cy.wrap({foo: "bar"}) - context "with whitelist", -> + context "with preserve", -> before -> Cypress.Cookies.defaults({ - whitelist: "foo1" + preserve: "foo1" }) it "can get all cookies", -> @@ -104,10 +104,10 @@ describe "cookies", -> it "handles undefined cookies", -> cy.visit("/cookieWithNoName") - context "without whitelist", -> + context "without preserve", -> before -> Cypress.Cookies.defaults({ - whitelist: [] + preserve: [] }) it "sends set cookies to path", -> diff --git a/packages/server/test/support/fixtures/projects/e2e/cypress/integration/cookies_spec_no_baseurl.coffee b/packages/server/test/support/fixtures/projects/e2e/cypress/integration/cookies_spec_no_baseurl.coffee index ebe46a3cd9a9..7fdba2822b5f 100644 --- a/packages/server/test/support/fixtures/projects/e2e/cypress/integration/cookies_spec_no_baseurl.coffee +++ b/packages/server/test/support/fixtures/projects/e2e/cypress/integration/cookies_spec_no_baseurl.coffee @@ -5,13 +5,18 @@ describe "cookies", -> beforeEach -> cy.wrap({foo: "bar"}) - context "with whitelist", -> + context "with preserve", -> before -> Cypress.Cookies.defaults({ - whitelist: "foo1" + preserve: "foo1" }) it "can get all cookies", -> + expectedKeys = ["domain", "name", "value", "path", "secure", "httpOnly", "expiry"] + + if Cypress.isBrowser('firefox') + expectedKeys.push('sameSite') + cy .clearCookie("foo1") .setCookie("foo", "bar").then (c) -> @@ -23,9 +28,7 @@ describe "cookies", -> expect(c.secure).to.eq(false) expect(c.expiry).to.be.a("number") - expect(c).to.have.keys( - "domain", "name", "value", "path", "secure", "httpOnly", "expiry" - ) + expect(c).to.have.keys(expectedKeys) .getCookies() .should("have.length", 1) .then (cookies) -> @@ -39,9 +42,7 @@ describe "cookies", -> expect(c.secure).to.eq(false) expect(c.expiry).to.be.a("number") - expect(c).to.have.keys( - "domain", "name", "value", "path", "secure", "httpOnly", "expiry" - ) + expect(c).to.have.keys(expectedKeys) .clearCookies() .should("be.null") .setCookie("wtf", "bob", {httpOnly: true, path: "/foo", secure: true}) @@ -54,9 +55,7 @@ describe "cookies", -> expect(c.secure).to.eq(true) expect(c.expiry).to.be.a("number") - expect(c).to.have.keys( - "domain", "name", "value", "path", "secure", "httpOnly", "expiry" - ) + expect(c).to.have.keys(expectedKeys) .clearCookie("wtf") .should("be.null") .getCookie("doesNotExist") @@ -80,10 +79,10 @@ describe "cookies", -> it "handles undefined cookies", -> cy.visit("#{httpUrl}/cookieWithNoName") - context "without whitelist", -> + context "without preserve", -> before -> Cypress.Cookies.defaults({ - whitelist: [] + preserve: [] }) it "sends cookies to localhost:2121", -> diff --git a/packages/server/test/support/fixtures/projects/e2e/cypress/integration/browserify_babel_es2015_failing_spec.js b/packages/server/test/support/fixtures/projects/e2e/cypress/integration/es_module_import_failing_spec.js similarity index 100% rename from packages/server/test/support/fixtures/projects/e2e/cypress/integration/browserify_babel_es2015_failing_spec.js rename to packages/server/test/support/fixtures/projects/e2e/cypress/integration/es_module_import_failing_spec.js diff --git a/packages/server/test/support/fixtures/projects/e2e/cypress/integration/browserify_babel_es2015_passing_spec.coffee b/packages/server/test/support/fixtures/projects/e2e/cypress/integration/es_modules_in_coffee_spec.coffee similarity index 100% rename from packages/server/test/support/fixtures/projects/e2e/cypress/integration/browserify_babel_es2015_passing_spec.coffee rename to packages/server/test/support/fixtures/projects/e2e/cypress/integration/es_modules_in_coffee_spec.coffee diff --git a/packages/server/test/support/fixtures/projects/e2e/cypress/integration/form_submission_multipart_spec.coffee b/packages/server/test/support/fixtures/projects/e2e/cypress/integration/form_submission_multipart_spec.coffee index 20f7bb960a1c..171b9109393d 100644 --- a/packages/server/test/support/fixtures/projects/e2e/cypress/integration/form_submission_multipart_spec.coffee +++ b/packages/server/test/support/fixtures/projects/e2e/cypress/integration/form_submission_multipart_spec.coffee @@ -18,13 +18,17 @@ Cypress.Commands.add 'setFile', { prevSubject: "element" }, (element, filePath) return cy.fixture(filePath, "base64") return fixtureOrReadFile(filePath).then (image) -> - return Blob.base64StringToBlob(image).then (blob) -> + return new Promise((resolve) => + blob = Blob.base64StringToBlob(image) elementNode = element[0] file = new File([ blob ], filePath, type: mimeType) dataTransfer = new DataTransfer dataTransfer.items.add(file) elementNode.files = dataTransfer.files - elementNode.dispatchEvent new Event("change", { bubbles: true }) + result = elementNode.dispatchEvent new Event("change", { bubbles: true }) + + resolve(result) + ) describe "
    submissions", -> it "can submit a form correctly", -> diff --git a/packages/server/test/support/fixtures/projects/e2e/cypress/integration/request_spec.js b/packages/server/test/support/fixtures/projects/e2e/cypress/integration/request_spec.js index b0758fe9f164..c1577c5de469 100644 --- a/packages/server/test/support/fixtures/projects/e2e/cypress/integration/request_spec.js +++ b/packages/server/test/support/fixtures/projects/e2e/cypress/integration/request_spec.js @@ -20,14 +20,20 @@ describe('redirects + requests', () => { expect(cookies[0].secure).to.eq(false) expect(cookies[0].expiry).to.be.closeTo(oneMinuteFromNow, 5) - expect(cookies[1]).to.deep.eq({ + const expectedCookie = { domain: 'localhost', name: '2293-session', value: 'true', httpOnly: false, path: '/', secure: false, - }) + } + + if (Cypress.isBrowser('firefox')) { + expectedCookie.sameSite = 'no_restriction' + } + + expect(cookies[1]).to.deep.eq(expectedCookie) }) }) diff --git a/packages/server/test/support/fixtures/projects/e2e/cypress/integration/screenshots_spec.js b/packages/server/test/support/fixtures/projects/e2e/cypress/integration/screenshots_spec.js index 64645d0fe7ef..6718492889f2 100644 --- a/packages/server/test/support/fixtures/projects/e2e/cypress/integration/screenshots_spec.js +++ b/packages/server/test/support/fixtures/projects/e2e/cypress/integration/screenshots_spec.js @@ -163,6 +163,13 @@ describe('taking screenshots', () => { }) }) + it('screenshots in a retried test', { retries: 2 }, () => { + cy.screenshot('retrying-test') + .then(() => { + throw new Error('fail') + }) + }) + it('ensures unique paths for non-named screenshots', () => { cy.screenshot({ capture: 'runner' }) cy.screenshot({ capture: 'runner' }) diff --git a/packages/server/test/support/fixtures/projects/e2e/cypress/integration/subdomain_spec.coffee b/packages/server/test/support/fixtures/projects/e2e/cypress/integration/subdomain_spec.coffee index 08d712e80cd3..6af1d6a2b348 100644 --- a/packages/server/test/support/fixtures/projects/e2e/cypress/integration/subdomain_spec.coffee +++ b/packages/server/test/support/fixtures/projects/e2e/cypress/integration/subdomain_spec.coffee @@ -42,7 +42,7 @@ describe "subdomains", -> cy .visit("http://domain.foobar.com:2292") .getCookies().should("have.length", 1) - .getCookie("nomnom").should("deep.eq", { + .getCookie("nomnom").should("include", { domain: ".foobar.com" name: "nomnom" value: "good" diff --git a/packages/server/test/support/fixtures/projects/e2e/cypress/integration/browserify_typescript_passing_spec.ts b/packages/server/test/support/fixtures/projects/e2e/cypress/integration/typescript_passing_spec.ts similarity index 100% rename from packages/server/test/support/fixtures/projects/e2e/cypress/integration/browserify_typescript_passing_spec.ts rename to packages/server/test/support/fixtures/projects/e2e/cypress/integration/typescript_passing_spec.ts diff --git a/packages/server/test/support/fixtures/projects/e2e/cypress/integration/browserify_typescript_failing_spec.ts b/packages/server/test/support/fixtures/projects/e2e/cypress/integration/typescript_syntax_error_spec.ts similarity index 76% rename from packages/server/test/support/fixtures/projects/e2e/cypress/integration/browserify_typescript_failing_spec.ts rename to packages/server/test/support/fixtures/projects/e2e/cypress/integration/typescript_syntax_error_spec.ts index 09a8d2b75070..c476d7946782 100644 --- a/packages/server/test/support/fixtures/projects/e2e/cypress/integration/browserify_typescript_failing_spec.ts +++ b/packages/server/test/support/fixtures/projects/e2e/cypress/integration/typescript_syntax_error_spec.ts @@ -1,3 +1,3 @@ // The code below is ignored by eslint // because it tests failing spec. -describe('fail', -> ) \ No newline at end of file +describe('fail', -> ) diff --git a/packages/server/test/support/fixtures/projects/e2e/cypress/plugins/index.js b/packages/server/test/support/fixtures/projects/e2e/cypress/plugins/index.js index 35d8fca9fd01..b88d7624d7c3 100644 --- a/packages/server/test/support/fixtures/projects/e2e/cypress/plugins/index.js +++ b/packages/server/test/support/fixtures/projects/e2e/cypress/plugins/index.js @@ -6,6 +6,7 @@ const http = require('http') const Jimp = require('jimp') const path = require('path') const Promise = require('bluebird') +const { useFixedFirefoxResolution } = require('../../../utils') module.exports = (on, config) => { let performance = { @@ -45,13 +46,7 @@ module.exports = (on, config) => { }) on('before:browser:launch', (browser, options) => { - if (browser.family === 'firefox' && !config.env['NO_RESIZE']) { - // this is needed to ensure correct error screenshot / video recording - // resolution of exactly 1280x720 (height must account for firefox url bar) - options.args = options.args.concat( - ['-width', '1280', '-height', '794'], - ) - } + useFixedFirefoxResolution(browser, options, config) if (browser.family === 'firefox' && process.env.FIREFOX_FORCE_STRICT_SAMESITE) { // @see https://www.jardinesoftware.net/2019/10/28/samesite-by-default-in-2020/ diff --git a/packages/server/test/support/fixtures/projects/e2e/cypress/support/index.js b/packages/server/test/support/fixtures/projects/e2e/cypress/support/index.js index 27e017398261..7d300bff722d 100644 --- a/packages/server/test/support/fixtures/projects/e2e/cypress/support/index.js +++ b/packages/server/test/support/fixtures/projects/e2e/cypress/support/index.js @@ -1,5 +1,8 @@ -before(function () { - if (Cypress.browser.family === 'chromium' && Cypress.browser.name !== 'electron') { +import _ from 'lodash' + +// we don't use a `before` here since that would show up in run results and cause confusion during test debugging +const before = _.once(function () { + if (Cypress.isBrowser([{ name: '!electron', family: 'chromium' }])) { return Cypress.automation('remote:debugger:protocol', { command: 'Emulation.setDeviceMetricsOverride', params: { @@ -19,3 +22,5 @@ before(function () { }) } }) + +Cypress.on('test:before:run:async', before) diff --git a/packages/server/test/support/fixtures/projects/e2e/cypress/support/util.js b/packages/server/test/support/fixtures/projects/e2e/cypress/support/util.js index 2ae8eb8fe3a2..da5ebf6b0ccd 100644 --- a/packages/server/test/support/fixtures/projects/e2e/cypress/support/util.js +++ b/packages/server/test/support/fixtures/projects/e2e/cypress/support/util.js @@ -85,7 +85,7 @@ export const verify = (ctx, options) => { // code frames will show `fail(this,()=>` as the 1st line cy.get('.test-err-code-frame pre span').should('include.text', 'fail(this,()=>') - cy.contains('.test-err-code-frame .runnable-err-file-path', openInIdePath.relative) + cy.contains('.test-err-code-frame .runnable-err-file-path span', openInIdePath.relative) .click() .should(() => { expect(runnerWs.emit.withArgs('open:file')).to.be.calledTwice diff --git a/packages/server/test/support/fixtures/projects/hooks-after-rerun/cypress/integration/beforehook-and-test-navigation.js b/packages/server/test/support/fixtures/projects/hooks-after-rerun/cypress/integration/beforehook-and-test-navigation.js index e1b1b31523a6..9b2bebc88e26 100644 --- a/packages/server/test/support/fixtures/projects/hooks-after-rerun/cypress/integration/beforehook-and-test-navigation.js +++ b/packages/server/test/support/fixtures/projects/hooks-after-rerun/cypress/integration/beforehook-and-test-navigation.js @@ -23,3 +23,15 @@ describe('suite', () => { cy.visit(urls[2]) }) }) + +describe('navigation error in beforeEach', () => { + before(() => { + cy.visit(urls[1]) + }) + + beforeEach(() => { + cy.visit(urls[2]) + }) + + it('never gets here', () => {}) +}) diff --git a/packages/server/test/support/fixtures/projects/ids/cypress/integration/foo.coffee b/packages/server/test/support/fixtures/projects/ids/cypress/integration/foo.coffee index 74a9e8deb45e..f8e373a2222c 100644 --- a/packages/server/test/support/fixtures/projects/ids/cypress/integration/foo.coffee +++ b/packages/server/test/support/fixtures/projects/ids/cypress/integration/foo.coffee @@ -1,4 +1,5 @@ describe "foo [000]", -> it "bars [001]", -> + expect("foo.coffee").to.equal("foo.coffee") - it 'quux [002]' \ No newline at end of file + it 'quux [002]' diff --git a/packages/server/test/support/fixtures/projects/no-server/helpers/includes.js b/packages/server/test/support/fixtures/projects/no-server/helpers/includes.js index 81969706f702..610c29484b78 100644 --- a/packages/server/test/support/fixtures/projects/no-server/helpers/includes.js +++ b/packages/server/test/support/fixtures/projects/no-server/helpers/includes.js @@ -1,3 +1,3 @@ beforeEach(function () { - + console.log('includes') }) diff --git a/packages/server/test/support/fixtures/projects/no-server/my-tests/test1.js b/packages/server/test/support/fixtures/projects/no-server/my-tests/test1.js index e3a5395eee36..1ff93d7bd5e4 100644 --- a/packages/server/test/support/fixtures/projects/no-server/my-tests/test1.js +++ b/packages/server/test/support/fixtures/projects/no-server/my-tests/test1.js @@ -1,4 +1,4 @@ /* eslint-disable mocha/no-global-tests */ it('tests without a server', function () { - + expect('no-server').to.equal('no-server') }) diff --git a/packages/server/test/support/fixtures/projects/plugin-after-screenshot/cypress/integration/after_screenshot_overwrite_spec.coffee b/packages/server/test/support/fixtures/projects/plugin-after-screenshot/cypress/integration/after_screenshot_overwrite_spec.coffee new file mode 100644 index 000000000000..600d04a52b56 --- /dev/null +++ b/packages/server/test/support/fixtures/projects/plugin-after-screenshot/cypress/integration/after_screenshot_overwrite_spec.coffee @@ -0,0 +1,8 @@ +Cypress._.times 3, () => + it "cy.screenshot() - replacement", -> + cy.screenshot("replace-me", { capture: "runner" }, { + onAfterScreenshot: (details) -> + expect(details.path).to.include("screenshot-replacement.png") + expect(details.size).to.equal(1047) + expect(details.dimensions).to.eql({ width: 1, height: 1 }) + }) diff --git a/packages/server/test/support/fixtures/projects/ts-proj-with-own-tsconfig/cypress.json b/packages/server/test/support/fixtures/projects/plugin-retries/cypress.json similarity index 100% rename from packages/server/test/support/fixtures/projects/ts-proj-with-own-tsconfig/cypress.json rename to packages/server/test/support/fixtures/projects/plugin-retries/cypress.json diff --git a/packages/server/test/support/fixtures/projects/plugin-retries/cypress/integration/main.spec.js b/packages/server/test/support/fixtures/projects/plugin-retries/cypress/integration/main.spec.js new file mode 100644 index 000000000000..ba620e423491 --- /dev/null +++ b/packages/server/test/support/fixtures/projects/plugin-retries/cypress/integration/main.spec.js @@ -0,0 +1,2 @@ +it('foo', () => { +}) diff --git a/packages/server/test/support/fixtures/projects/read-only-project-root/cypress.json b/packages/server/test/support/fixtures/projects/read-only-project-root/cypress.json index 0967ef424bce..0f77b44749ce 100644 --- a/packages/server/test/support/fixtures/projects/read-only-project-root/cypress.json +++ b/packages/server/test/support/fixtures/projects/read-only-project-root/cypress.json @@ -1 +1,3 @@ -{} +{ + "retries": null +} diff --git a/packages/server/test/support/fixtures/projects/retries-2/cypress.json b/packages/server/test/support/fixtures/projects/retries-2/cypress.json new file mode 100644 index 000000000000..cd6342eef42e --- /dev/null +++ b/packages/server/test/support/fixtures/projects/retries-2/cypress.json @@ -0,0 +1,3 @@ +{ + "retries": 2 +} diff --git a/packages/server/test/support/fixtures/projects/retries-2/cypress/integration/fail-twice.js b/packages/server/test/support/fixtures/projects/retries-2/cypress/integration/fail-twice.js new file mode 100644 index 000000000000..214e7233b376 --- /dev/null +++ b/packages/server/test/support/fixtures/projects/retries-2/cypress/integration/fail-twice.js @@ -0,0 +1,8 @@ +let count = 0 + +it('fail twice', () => { + count++ + if (count < 3) { + throw new Error(`failed attempt #${count}`) + } +}) diff --git a/packages/server/test/support/fixtures/projects/retries-2/cypress/plugins/index.js b/packages/server/test/support/fixtures/projects/retries-2/cypress/plugins/index.js new file mode 100644 index 000000000000..27a4eac6e871 --- /dev/null +++ b/packages/server/test/support/fixtures/projects/retries-2/cypress/plugins/index.js @@ -0,0 +1,14 @@ +/// + +const { useFixedFirefoxResolution } = require('../../../utils') + +/** + * @type {Cypress.PluginConfig} + */ +module.exports = (on, config) => { + on('before:browser:launch', (browser, options) => { + useFixedFirefoxResolution(browser, options, config) + + return options + }) +} diff --git a/packages/server/test/support/fixtures/projects/task-not-registered/cypress.json b/packages/server/test/support/fixtures/projects/task-not-registered/cypress.json index 0967ef424bce..0f77b44749ce 100644 --- a/packages/server/test/support/fixtures/projects/task-not-registered/cypress.json +++ b/packages/server/test/support/fixtures/projects/task-not-registered/cypress.json @@ -1 +1,3 @@ -{} +{ + "retries": null +} diff --git a/packages/server/test/support/fixtures/projects/ts-proj-esmoduleinterop-true/cypress.json b/packages/server/test/support/fixtures/projects/ts-proj-esmoduleinterop-true/cypress.json new file mode 100644 index 000000000000..0c2bdde8665b --- /dev/null +++ b/packages/server/test/support/fixtures/projects/ts-proj-esmoduleinterop-true/cypress.json @@ -0,0 +1,3 @@ +{ + "supportFile": false +} diff --git a/packages/server/test/support/fixtures/projects/ts-proj-esmoduleinterop-true/cypress/integration/passing_spec.ts b/packages/server/test/support/fixtures/projects/ts-proj-esmoduleinterop-true/cypress/integration/passing_spec.ts new file mode 100644 index 000000000000..99a13400edf9 --- /dev/null +++ b/packages/server/test/support/fixtures/projects/ts-proj-esmoduleinterop-true/cypress/integration/passing_spec.ts @@ -0,0 +1,3 @@ +it('passes', () => { + expect(true).to.be.true +}) diff --git a/packages/server/test/support/fixtures/projects/ts-proj-esmoduleinterop-true/cypress/plugins/commonjs-export.js b/packages/server/test/support/fixtures/projects/ts-proj-esmoduleinterop-true/cypress/plugins/commonjs-export.js new file mode 100644 index 000000000000..bb41bc70595c --- /dev/null +++ b/packages/server/test/support/fixtures/projects/ts-proj-esmoduleinterop-true/cypress/plugins/commonjs-export.js @@ -0,0 +1,3 @@ +exports.export1 = 'export1' + +exports.export2 = 'export2' diff --git a/packages/server/test/support/fixtures/projects/ts-proj-esmoduleinterop-true/cypress/plugins/index.ts b/packages/server/test/support/fixtures/projects/ts-proj-esmoduleinterop-true/cypress/plugins/index.ts new file mode 100644 index 000000000000..e9e9e040af8b --- /dev/null +++ b/packages/server/test/support/fixtures/projects/ts-proj-esmoduleinterop-true/cypress/plugins/index.ts @@ -0,0 +1,12 @@ +/// + +import commonjsExports from './commonjs-export' + +if (commonjsExports.export1 !== 'export1' || commonjsExports.export2 !== 'export2') { + throw new Error('Imported values do not match exported values') +} + +// Default Cypress plugin function +export default (on: Cypress.PluginEvents, config: Cypress.PluginConfigOptions) => { + +} diff --git a/packages/server/test/support/fixtures/projects/ts-proj-esmoduleinterop-true/tsconfig.json b/packages/server/test/support/fixtures/projects/ts-proj-esmoduleinterop-true/tsconfig.json new file mode 100644 index 000000000000..2f98042715ab --- /dev/null +++ b/packages/server/test/support/fixtures/projects/ts-proj-esmoduleinterop-true/tsconfig.json @@ -0,0 +1,5 @@ +{ + "compilerOptions": { + "esModuleInterop": true + } +} diff --git a/packages/server/test/support/fixtures/projects/ts-proj-with-module-esnext/cypress.json b/packages/server/test/support/fixtures/projects/ts-proj-with-module-esnext/cypress.json new file mode 100644 index 000000000000..9c5417cd8268 --- /dev/null +++ b/packages/server/test/support/fixtures/projects/ts-proj-with-module-esnext/cypress.json @@ -0,0 +1,3 @@ +{ + "supportFolder": false +} diff --git a/packages/server/test/support/fixtures/projects/ts-proj-with-module-esnext/cypress/integration/uses_cy_task_in_ts_plugins_file_spec.js b/packages/server/test/support/fixtures/projects/ts-proj-with-module-esnext/cypress/integration/uses_cy_task_in_ts_plugins_file_spec.js new file mode 100644 index 000000000000..8dada9612545 --- /dev/null +++ b/packages/server/test/support/fixtures/projects/ts-proj-with-module-esnext/cypress/integration/uses_cy_task_in_ts_plugins_file_spec.js @@ -0,0 +1,5 @@ +describe('uses task that is in typescript plugins file', () => { + it('calls task', () => { + cy.task('hello', 'TS').should('equal', 'Hello, TS!') + }) +}) diff --git a/packages/server/test/support/fixtures/projects/ts-proj-with-module-esnext/cypress/plugins/greeting.ts b/packages/server/test/support/fixtures/projects/ts-proj-with-module-esnext/cypress/plugins/greeting.ts new file mode 100644 index 000000000000..4bb20cd18999 --- /dev/null +++ b/packages/server/test/support/fixtures/projects/ts-proj-with-module-esnext/cypress/plugins/greeting.ts @@ -0,0 +1,3 @@ +export const asyncGreeting = async (greeting: string) => { + return Promise.resolve(`Hello, ${greeting}!`) +} diff --git a/packages/server/test/support/fixtures/projects/ts-proj-with-own-tsconfig/cypress/plugins/index.ts b/packages/server/test/support/fixtures/projects/ts-proj-with-module-esnext/cypress/plugins/index.ts similarity index 100% rename from packages/server/test/support/fixtures/projects/ts-proj-with-own-tsconfig/cypress/plugins/index.ts rename to packages/server/test/support/fixtures/projects/ts-proj-with-module-esnext/cypress/plugins/index.ts diff --git a/packages/server/test/support/fixtures/projects/ts-proj-with-own-tsconfig/tsconfig.json b/packages/server/test/support/fixtures/projects/ts-proj-with-module-esnext/tsconfig.json similarity index 100% rename from packages/server/test/support/fixtures/projects/ts-proj-with-own-tsconfig/tsconfig.json rename to packages/server/test/support/fixtures/projects/ts-proj-with-module-esnext/tsconfig.json diff --git a/packages/server/test/support/fixtures/projects/ts-proj-with-own-tsconfig/cypress/integration/app_spec.ts b/packages/server/test/support/fixtures/projects/ts-proj-with-own-tsconfig/cypress/integration/app_spec.ts deleted file mode 100644 index d539f78bfb6f..000000000000 --- a/packages/server/test/support/fixtures/projects/ts-proj-with-own-tsconfig/cypress/integration/app_spec.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { add } from './math' - -it('is true', () => { - expect(add(1, 2)).to.eq(3) -}) diff --git a/packages/server/test/support/fixtures/projects/ts-proj-with-own-tsconfig/cypress/integration/js-spec.js b/packages/server/test/support/fixtures/projects/ts-proj-with-own-tsconfig/cypress/integration/js-spec.js deleted file mode 100644 index 1f7c6d518cc5..000000000000 --- a/packages/server/test/support/fixtures/projects/ts-proj-with-own-tsconfig/cypress/integration/js-spec.js +++ /dev/null @@ -1,11 +0,0 @@ -import { add } from './math' - -describe('JS spec', () => { - it('adds 2 and 2 together', () => { - expect(add(2, 2)).to.equal(4) - }) - - it('calls task', () => { - cy.task('hello', 'TS').should('equal', 'Hello, TS!') - }) -}) diff --git a/packages/server/test/support/fixtures/projects/ts-proj-with-own-tsconfig/cypress/integration/math.ts b/packages/server/test/support/fixtures/projects/ts-proj-with-own-tsconfig/cypress/integration/math.ts deleted file mode 100644 index e29e78dc31cf..000000000000 --- a/packages/server/test/support/fixtures/projects/ts-proj-with-own-tsconfig/cypress/integration/math.ts +++ /dev/null @@ -1,3 +0,0 @@ -export const add = (a: number, b: number) => { - return a + b -} diff --git a/packages/server/test/support/fixtures/projects/ts-proj-with-own-tsconfig/cypress/plugins/greeting.ts b/packages/server/test/support/fixtures/projects/ts-proj-with-own-tsconfig/cypress/plugins/greeting.ts deleted file mode 100644 index eaa232c40687..000000000000 --- a/packages/server/test/support/fixtures/projects/ts-proj-with-own-tsconfig/cypress/plugins/greeting.ts +++ /dev/null @@ -1,3 +0,0 @@ -export const asyncGreeting = async (greeting) => { - return Promise.resolve(`Hello, ${greeting}!`) -} diff --git a/packages/server/test/support/fixtures/projects/ts-proj-with-own-tsconfig/cypress/support/.eslintrc.json b/packages/server/test/support/fixtures/projects/ts-proj-with-own-tsconfig/cypress/support/.eslintrc.json deleted file mode 100644 index ff5b2657922f..000000000000 --- a/packages/server/test/support/fixtures/projects/ts-proj-with-own-tsconfig/cypress/support/.eslintrc.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "parserOptions": { - "parser": "@typescript-eslint/parser", - "project": "packages/server/test/support/fixtures/projects/ts-proj-with-own-tsconfig/tsconfig.json" - }, - "rules": { - "@typescript-eslint/no-misused-promises": "error" - } -} \ No newline at end of file diff --git a/packages/server/test/support/fixtures/projects/ts-proj-with-own-tsconfig/cypress/support/commands.ts b/packages/server/test/support/fixtures/projects/ts-proj-with-own-tsconfig/cypress/support/commands.ts deleted file mode 100644 index 9dc223e893e5..000000000000 --- a/packages/server/test/support/fixtures/projects/ts-proj-with-own-tsconfig/cypress/support/commands.ts +++ /dev/null @@ -1,13 +0,0 @@ -/// - -// Copied an example command from https://on.cypress.io/custom-commands -Cypress.Commands.add('clickLink', (label: string | number | RegExp) => { - cy.get('a').contains(label).click() -}) - -// https://github.com/cypress-io/cypress/issues/7510 -// The code below fails when @typescript-eslint/no-misused-promises is error -// and the return type of function in Cypress.Commands.add doesn't support Chainable. -Cypress.Commands.add('dataCy', (value) => { - return cy.get(`[data-cy=${value}]`) -}) diff --git a/packages/server/test/support/fixtures/projects/ts-proj-with-own-tsconfig/cypress/support/index.ts b/packages/server/test/support/fixtures/projects/ts-proj-with-own-tsconfig/cypress/support/index.ts deleted file mode 100644 index d68db96df269..000000000000 --- a/packages/server/test/support/fixtures/projects/ts-proj-with-own-tsconfig/cypress/support/index.ts +++ /dev/null @@ -1,20 +0,0 @@ -// *********************************************************** -// This example support/index.js is processed and -// loaded automatically before your test files. -// -// This is a great place to put global configuration and -// behavior that modifies Cypress. -// -// You can change the location of this file or turn off -// automatically serving support files with the -// 'supportFile' configuration option. -// -// You can read more here: -// https://on.cypress.io/configuration -// *********************************************************** - -// Import commands.js using ES2015 syntax: -import './commands' - -// Alternatively you can use CommonJS syntax: -// require('./commands') diff --git a/packages/server/test/support/fixtures/projects/ts-proj-with-paths/cypress.json b/packages/server/test/support/fixtures/projects/ts-proj-with-paths/cypress.json new file mode 100644 index 000000000000..be9e6bf4576b --- /dev/null +++ b/packages/server/test/support/fixtures/projects/ts-proj-with-paths/cypress.json @@ -0,0 +1,4 @@ +{ + "supportFile": false, + "pluginsFile": false +} diff --git a/packages/server/test/support/fixtures/projects/ts-proj-with-paths/cypress/integration/app_spec.ts b/packages/server/test/support/fixtures/projects/ts-proj-with-paths/cypress/integration/app_spec.ts new file mode 100644 index 000000000000..af091afe0536 --- /dev/null +++ b/packages/server/test/support/fixtures/projects/ts-proj-with-paths/cypress/integration/app_spec.ts @@ -0,0 +1,6 @@ +import { expect } from 'chai' +import { appName } from '@app/main' + +it('verifies path mapping', () => { + expect(appName).to.equal('Best App Ever') +}) diff --git a/packages/server/test/support/fixtures/projects/ts-proj-with-paths/src/main.ts b/packages/server/test/support/fixtures/projects/ts-proj-with-paths/src/main.ts new file mode 100644 index 000000000000..8e774ef932a0 --- /dev/null +++ b/packages/server/test/support/fixtures/projects/ts-proj-with-paths/src/main.ts @@ -0,0 +1 @@ +export const appName = 'Best App Ever' diff --git a/packages/server/test/support/fixtures/projects/ts-proj-with-paths/tsconfig.json b/packages/server/test/support/fixtures/projects/ts-proj-with-paths/tsconfig.json new file mode 100644 index 000000000000..9da0a51cf8c5 --- /dev/null +++ b/packages/server/test/support/fixtures/projects/ts-proj-with-paths/tsconfig.json @@ -0,0 +1,8 @@ +{ + "compilerOptions": { + "baseUrl": ".", + "paths": { + "@app/*": ["src/*"] + }, + } +} diff --git a/packages/server/test/support/fixtures/projects/ts-proj/cypress/integration/app_spec.ts b/packages/server/test/support/fixtures/projects/ts-proj/cypress/integration/app_spec.ts index d539f78bfb6f..ceacd67310bb 100644 --- a/packages/server/test/support/fixtures/projects/ts-proj/cypress/integration/app_spec.ts +++ b/packages/server/test/support/fixtures/projects/ts-proj/cypress/integration/app_spec.ts @@ -1,5 +1,6 @@ import { add } from './math' it('is true', () => { + // @ts-ignore expect(add(1, 2)).to.eq(3) }) diff --git a/packages/server/test/support/fixtures/projects/ts-proj/cypress/plugins/commonjs-export-function.js b/packages/server/test/support/fixtures/projects/ts-proj/cypress/plugins/commonjs-export-function.js new file mode 100644 index 000000000000..0c0c42d5b58c --- /dev/null +++ b/packages/server/test/support/fixtures/projects/ts-proj/cypress/plugins/commonjs-export-function.js @@ -0,0 +1 @@ +module.exports = () => {} diff --git a/packages/server/test/support/fixtures/projects/ts-proj/cypress/plugins/index.ts b/packages/server/test/support/fixtures/projects/ts-proj/cypress/plugins/index.ts index a728da18c1f9..7f27d46b4c1a 100644 --- a/packages/server/test/support/fixtures/projects/ts-proj/cypress/plugins/index.ts +++ b/packages/server/test/support/fixtures/projects/ts-proj/cypress/plugins/index.ts @@ -1,17 +1,13 @@ -// Copied an example from https://docs.cypress.io/api/plugins/browser-launch-api.html#Use-fake-video-for-webcam-testing - /// -export default (on: Cypress.PluginEvents, config: Cypress.PluginConfigOptions) => { - on('before:browser:launch', (browser, launchOptions) => { - if (browser.family === 'chromium' && browser.name !== 'electron') { - // Mac/Linux - //launchOptions.args.push('--use-file-for-fake-video-capture=cypress/fixtures/my-video.y4m') +import fn from './commonjs-export-function' - // Windows - // launchOptions.args.push('--use-file-for-fake-video-capture=c:\\path\\to\\video\\my-video.y4m') - } +// if esModuleInterop is forced to be true, this will error // with 'fn is +// not a function'. instead, we allow the tsconfig.json to determine the value +// of esModuleInterop +fn() + +// Default Cypress plugin function +export default (on: Cypress.PluginEvents, config: Cypress.PluginConfigOptions) => { - return launchOptions - }) } diff --git a/packages/server/test/support/fixtures/projects/utils.js b/packages/server/test/support/fixtures/projects/utils.js new file mode 100644 index 000000000000..71f37842f5f3 --- /dev/null +++ b/packages/server/test/support/fixtures/projects/utils.js @@ -0,0 +1,11 @@ +module.exports = { + useFixedFirefoxResolution (browser, options, config) { + if (browser.family === 'firefox' && !config.env['NO_RESIZE']) { + // this is needed to ensure correct error screenshot / video recording + // resolution of exactly 1280x720 (height must account for firefox url bar) + options.args = options.args.concat( + ['-width', '1280', '-height', '794'], + ) + } + }, +} diff --git a/packages/server/test/support/fixtures/projects/webpack-preprocessor-awesome-typescript-loader/cypress.json b/packages/server/test/support/fixtures/projects/webpack-preprocessor-awesome-typescript-loader/cypress.json index 0967ef424bce..0f77b44749ce 100644 --- a/packages/server/test/support/fixtures/projects/webpack-preprocessor-awesome-typescript-loader/cypress.json +++ b/packages/server/test/support/fixtures/projects/webpack-preprocessor-awesome-typescript-loader/cypress.json @@ -1 +1,3 @@ -{} +{ + "retries": null +} diff --git a/packages/server/test/support/fixtures/projects/webpack-preprocessor-ts-loader-compiler-options/cypress.json b/packages/server/test/support/fixtures/projects/webpack-preprocessor-ts-loader-compiler-options/cypress.json index 0967ef424bce..0f77b44749ce 100644 --- a/packages/server/test/support/fixtures/projects/webpack-preprocessor-ts-loader-compiler-options/cypress.json +++ b/packages/server/test/support/fixtures/projects/webpack-preprocessor-ts-loader-compiler-options/cypress.json @@ -1 +1,3 @@ -{} +{ + "retries": null +} diff --git a/packages/server/test/support/fixtures/projects/webpack-preprocessor-ts-loader/cypress.json b/packages/server/test/support/fixtures/projects/webpack-preprocessor-ts-loader/cypress.json index 0967ef424bce..0f77b44749ce 100644 --- a/packages/server/test/support/fixtures/projects/webpack-preprocessor-ts-loader/cypress.json +++ b/packages/server/test/support/fixtures/projects/webpack-preprocessor-ts-loader/cypress.json @@ -1 +1,3 @@ -{} +{ + "retries": null +} diff --git a/packages/server/test/support/fixtures/projects/webpack-preprocessor/cypress.json b/packages/server/test/support/fixtures/projects/webpack-preprocessor/cypress.json index 0967ef424bce..0f77b44749ce 100644 --- a/packages/server/test/support/fixtures/projects/webpack-preprocessor/cypress.json +++ b/packages/server/test/support/fixtures/projects/webpack-preprocessor/cypress.json @@ -1 +1,3 @@ -{} +{ + "retries": null +} diff --git a/packages/server/test/support/helpers/e2e.ts b/packages/server/test/support/helpers/e2e.ts index 2630569b8dc2..1cb89a46ffa5 100644 --- a/packages/server/test/support/helpers/e2e.ts +++ b/packages/server/test/support/helpers/e2e.ts @@ -442,6 +442,14 @@ const e2e = { }, options (ctx, options = {}) { + if (options.inspectBrk != null) { + throw new Error(` + passing { inspectBrk: true } to e2e options is no longer supported + Please pass the --cypress-inspect-brk flag to the test command instead + e.g. "yarn test test/e2e/1_async_timeouts_spec.js --cypress-inspect-brk" + `) + } + _.defaults(options, { browser: 'electron', headed: process.env.HEADED || false, @@ -452,6 +460,7 @@ const e2e = { sanitizeScreenshotDimensions: false, normalizeStdoutAvailableBrowsers: true, noExit: process.env.NO_EXIT, + inspectBrk: process.env.CYPRESS_INSPECT_BRK, }) if (options.exit != null) { @@ -619,6 +628,10 @@ const e2e = { ctx.skip() } + if (options.stubPackage) { + Fixtures.installStubPackage(options.project, options.stubPackage) + } + args = ['index.js'].concat(args) let stdout = '' @@ -727,8 +740,13 @@ const e2e = { // pipe these to our current process // so we can see them in the terminal // color it so we can tell which is test output - sp.stdout.pipe(ColorOutput()).pipe(process.stdout) - sp.stderr.pipe(ColorOutput()).pipe(process.stderr) + sp.stdout + .pipe(ColorOutput()) + .pipe(process.stdout) + + sp.stderr + .pipe(ColorOutput()) + .pipe(process.stderr) sp.stdout.on('data', (buf) => stdout += buf.toString()) sp.stderr.on('data', (buf) => stderr += buf.toString()) @@ -753,6 +771,12 @@ const e2e = { `) } }, + + normalizeWebpackErrors (stdout) { + return stdout + .replace(/using description file: .* \(relative/g, 'using description file: [..] (relative') + .replace(/Module build failed \(from .*\)/g, 'Module build failed (from [..])') + }, } export { diff --git a/packages/server/test/support/helpers/fixtures.js b/packages/server/test/support/helpers/fixtures.js index 56858cc2f10e..857f2b5a8d6c 100644 --- a/packages/server/test/support/helpers/fixtures.js +++ b/packages/server/test/support/helpers/fixtures.js @@ -49,6 +49,14 @@ module.exports = { return fs.removeSync(tmpDir) }, + async installStubPackage (projectPath, pkgName) { + const pathToPkg = path.join(projectPath, 'node_modules', pkgName) + + await fs.outputJSON(path.join(projectPath, 'package.json'), { name: 'some-project' }) + await fs.mkdirp(pathToPkg) + await fs.outputFile(path.join(pathToPkg, 'index.js'), '') + }, + // returns the path to project fixture // in the tmpDir project (...args) { diff --git a/packages/server/test/support/helpers/resultsUtils.ts b/packages/server/test/support/helpers/resultsUtils.ts new file mode 100644 index 000000000000..ff57eaeec8a4 --- /dev/null +++ b/packages/server/test/support/helpers/resultsUtils.ts @@ -0,0 +1,302 @@ +import e2e from './e2e' +import moment from 'moment' +import _ from 'lodash' + +const expect = global.expect as unknown as Chai.ExpectStatic + +const STATIC_DATE = '2018-02-01T20:14:19.323Z' + +const expectDurationWithin = function (obj, duration, low, high, reset) { + const d = _.get(obj, duration) + + // bail if we don't have a duration + if (!_.isNumber(d)) { + return + } + + // ensure the duration is within range + expect(d, duration).to.be.within(low, high) + + // once valid, mutate and set static range + return _.set(obj, duration, reset) +} + +const expectStartToBeBeforeEnd = function (obj, start, end) { + const s = _.get(obj, start) + const e = _.get(obj, end) + + expect( + moment(s).isBefore(e), + `expected start: ${s} to be before end: ${e}`, + ).to.be.true + + // once valid, mutate and set static dates + _.set(obj, start, STATIC_DATE) + + return _.set(obj, end, STATIC_DATE) +} + +const normalizeTestTimings = function (obj, timings) { + const t = _.get(obj, timings) + + // bail if we don't have any timings + if (!t) { + return + } + + return _.set(obj, 'timings', _.mapValues(t, (val, key) => { + switch (key) { + case 'lifecycle': + // ensure that lifecycle is under 500ms + expect(val, 'lifecycle').to.be.within(0, 500) + + // reset to 100 + return 100 + case 'test': + // ensure test fn duration is within 1500ms + expectDurationWithin(val, 'fnDuration', 0, 1500, 400) + // ensure test after fn duration is within 500ms + expectDurationWithin(val, 'afterFnDuration', 0, 500, 200) + + return val + default: + return _.map(val, (hook) => { + // ensure test fn duration is within 1500ms + expectDurationWithin(hook, 'fnDuration', 0, 1500, 400) + // ensure test after fn duration is within 500ms + expectDurationWithin(hook, 'afterFnDuration', 0, 500, 200) + + return hook + }) + } + })) +} + +export const expectRunsToHaveCorrectTimings = (runs = []) => { + runs.forEach((run) => { + expect(run.cypressConfig).to.be.a('object') + run.cypressConfig = {} + expectStartToBeBeforeEnd(run, 'stats.wallClockStartedAt', 'stats.wallClockEndedAt') + expectStartToBeBeforeEnd(run, 'reporterStats.start', 'reporterStats.end') + + // grab all the wallclock durations for all test (and retried attempts) + // because our duration should be at least this + + const attempts = _.flatMap(run.tests, (test) => test.attempts) + + const wallClocks = _.sumBy(attempts, 'wallClockDuration') + + // ensure each run's duration is around the sum + // of all tests wallclock duration + + // TODO: if this remains flaky, increase padding here + // and add an additional non-e2e performance test with baseline p95 + expectDurationWithin( + run, + 'stats.wallClockDuration', + wallClocks, + wallClocks + 400, // add 400ms to account for padding + 1234, + ) + + expectDurationWithin( + run, + 'reporterStats.duration', + wallClocks, + wallClocks + 400, // add 400ms to account for padding + 1234, + ) + + const addFnAndAfterFn = (obj) => { + return obj.fnDuration + obj.afterFnDuration + } + + _.each(run.tests, (test) => { + if (test.displayError) { + test.displayError = e2e.normalizeStdout(test.displayError) + } + }) + + // now make sure that each tests wallclock duration + // is around the sum of all of its timings + attempts.forEach((attempt) => { + if (attempt.error) { + attempt.error.stack = e2e.normalizeStdout(attempt.error.stack).trim() + } + + // cannot sum an object, must use array of values + const timings = _.sumBy(_.values(attempt.timings), (val) => { + if (_.isArray(val)) { + // array for hooks + return _.sumBy(val, addFnAndAfterFn) + } + + if (_.isObject(val)) { + // obj for test itself + return addFnAndAfterFn(val) + } + + return val + }) + + expectDurationWithin( + attempt, + 'wallClockDuration', + timings, + timings + 80, // add 80ms to account for padding + 1234, + ) + + // now reset all the test timings + normalizeTestTimings(attempt, 'timings') + + if (attempt.wallClockStartedAt) { + const d = new Date(attempt.wallClockStartedAt) + + expect(d.toJSON()).to.eq(attempt.wallClockStartedAt) + attempt.wallClockStartedAt = STATIC_DATE + + expect(attempt.videoTimestamp).to.be.a('number') + attempt.videoTimestamp = 9999 + } + }) + + run.screenshots = _.map(run.screenshots, (screenshot) => { + expect(screenshot.screenshotId).to.have.length(5) + screenshot.screenshotId = 'some-random-id' + + const d = new Date(screenshot.takenAt) + + expect(d.toJSON()).to.eq(screenshot.takenAt) + screenshot.takenAt = STATIC_DATE + + return screenshot + }) + }) +} + +export const expectCorrectModuleApiResult = (json, opts: { + e2ePath: string + runs: number +}) => { + // should be n runs + expect(json.runs).to.have.length(opts.runs) + + // ensure that config has been set + expect(json.config).to.be.an('object') + expect(json.config.projectName).to.eq('e2e') + expect(json.config.projectRoot).to.eq(opts.e2ePath) + + // but zero out config because it's too volatile + json.config = {} + + expect(json.browserPath).to.be.a('string') + expect(json.browserName).to.be.a('string') + expect(json.browserVersion).to.be.a('string') + expect(json.osName).to.be.a('string') + expect(json.osVersion).to.be.a('string') + expect(json.cypressVersion).to.be.a('string') + + _.extend(json, { + browserPath: 'path/to/browser', + browserName: 'FooBrowser', + browserVersion: '88', + osName: 'FooOS', + osVersion: '1234', + cypressVersion: '9.9.9', + }) + + // ensure the totals are accurate + expect(json.totalTests).to.eq( + _.sum([ + json.totalFailed, + json.totalPassed, + json.totalPending, + json.totalSkipped, + ]), + ) + + // ensure totalDuration matches all of the stats durations + expectDurationWithin( + json, + 'totalDuration', + _.sumBy(json.runs, 'stats.duration'), + _.sumBy(json.runs, 'stats.duration'), + 5555, + ) + + expectStartToBeBeforeEnd(json, 'startedTestsAt', 'endedTestsAt') + + json.runs.forEach((run) => { + expectStartToBeBeforeEnd(run, 'stats.startedAt', 'stats.endedAt') + expectStartToBeBeforeEnd(run, 'reporterStats.start', 'reporterStats.end') + + const attempts = _.flatMap(run.tests, (test) => test.attempts) + + const wallClocks = _.sumBy(attempts, 'duration') + + // ensure each run's duration is around the sum + // of all tests wallclock duration + expectDurationWithin( + run, + 'stats.duration', + wallClocks, + wallClocks + 400, // add 400ms to account for padding + 1234, + ) + + expectDurationWithin( + run, + 'reporterStats.duration', + wallClocks, + wallClocks + 400, // add 400ms to account for padding + 1234, + ) + + run.spec.absolute = e2e.normalizeStdout(run.spec.absolute) + + _.each(run.tests, (test) => { + if (test.displayError) { + test.displayError = e2e.normalizeStdout(test.displayError) + } + }) + + attempts.forEach((attempt) => { + // normalize stack + if (attempt.error) { + attempt.error.stack = e2e.normalizeStdout(attempt.error.stack).trim() + } + + // normalize startedAt + if (attempt.startedAt) { + const d = new Date(attempt.startedAt) + + expect(d.toJSON()).to.eq(attempt.startedAt) + attempt.startedAt = STATIC_DATE + + expect(attempt.videoTimestamp).to.be.a('number') + attempt.videoTimestamp = 9999 + } + + attempt.screenshots.forEach((screenshot) => { + // expect(screenshot.screenshotId).to.have.length(5) + + const d = new Date(screenshot.takenAt) + + expect(d.toJSON()).to.eq(screenshot.takenAt) + screenshot.takenAt = STATIC_DATE + + // screenshot.screenshotId = 'some-random-id' + screenshot.path = e2e.normalizeStdout(screenshot.path) + }) + + if (attempt.duration) { + expect(attempt.duration).to.be.a('number') + attempt.duration = 1234 + } + }) + + // normalize video path + run.video = e2e.normalizeStdout(run.video) + }) +} diff --git a/packages/server/test/support/helpers/simple_tsify.js b/packages/server/test/support/helpers/simple_tsify.js deleted file mode 100644 index 450c3dee010c..000000000000 --- a/packages/server/test/support/helpers/simple_tsify.js +++ /dev/null @@ -1,45 +0,0 @@ -// Copied from cypress-browserify-preprocessor for unit tests. - -let through = require('through2') - -const isJson = (code) => { - try { - JSON.parse(code) - } catch (e) { - return false - } - - return true -} - -// tsify doesn't have transpile-only option like ts-node or ts-loader. -// It means it should check types whenever spec file is changed -// and it slows down the test speed a lot. -// We skip this slow type-checking process by using transpileModule() api. -module.exports = function (b, opts) { - const chunks = [] - - return through( - (buf, enc, next) => { - chunks.push(buf.toString()) - next() - }, - function (next) { - const ts = opts.typescript - const text = chunks.join('') - - if (isJson(text)) { - this.push(text) - } else { - this.push(ts.transpileModule(text, { - compilerOptions: { - esModuleInterop: true, - jsx: 'react', - }, - }).outputText) - } - - next() - }, - ) -} diff --git a/packages/server/test/unit/api_spec.js b/packages/server/test/unit/api_spec.js index 6a72cf4548ab..67cc36c38cfc 100644 --- a/packages/server/test/unit/api_spec.js +++ b/packages/server/test/unit/api_spec.js @@ -568,7 +568,7 @@ describe('lib/api', () => { it('PUTs /instances/:id', function () { nock(API_BASEURL) - .matchHeader('x-route-version', '2') + .matchHeader('x-route-version', '3') .matchHeader('x-os-name', 'linux') .matchHeader('x-cypress-version', pkg.version) .put('/instances/instance-id-123', this.putProps) @@ -579,7 +579,7 @@ describe('lib/api', () => { it('PUT /instances/:id failure formatting', () => { nock(API_BASEURL) - .matchHeader('x-route-version', '2') + .matchHeader('x-route-version', '3') .matchHeader('x-os-name', 'linux') .matchHeader('x-cypress-version', pkg.version) .put('/instances/instance-id-123') @@ -609,7 +609,7 @@ describe('lib/api', () => { it('handles timeouts', () => { nock(API_BASEURL) - .matchHeader('x-route-version', '2') + .matchHeader('x-route-version', '3') .matchHeader('x-os-name', 'linux') .matchHeader('x-cypress-version', pkg.version) .put('/instances/instance-id-123') diff --git a/packages/server/test/unit/args_spec.js b/packages/server/test/unit/args_spec.js index 657ddfeeb062..722f13b96959 100644 --- a/packages/server/test/unit/args_spec.js +++ b/packages/server/test/unit/args_spec.js @@ -251,7 +251,7 @@ describe('lib/util/args', () => { const config = { pageLoadTimeout: 10000, waitForAnimations: false, - blacklistHosts: ['one.com', 'www.two.io'], + blockHosts: ['one.com', 'www.two.io'], hosts: { 'foobar.com': '127.0.0.1', }, @@ -264,7 +264,7 @@ describe('lib/util/args', () => { // as mixed usage const hosts = JSON.stringify(config.hosts) - const blacklistHosts = JSON.stringify(config.blacklistHosts) + const blockHosts = JSON.stringify(config.blockHosts) options = this.setup( '--config', @@ -272,7 +272,7 @@ describe('lib/util/args', () => { 'pageLoadTimeout=10000', 'waitForAnimations=false', `hosts=${hosts}`, - `blacklistHosts=${blacklistHosts}`, + `blockHosts=${blockHosts}`, ].join(','), ) @@ -280,7 +280,7 @@ describe('lib/util/args', () => { expect(options.config).to.deep.eq(config) }) - it('whitelists config properties', function () { + it('allows config properties', function () { const options = this.setup('--config', 'foo=bar,port=1111,supportFile=path/to/support_file') expect(options.config.port).to.eq(1111) @@ -329,7 +329,7 @@ describe('lib/util/args', () => { context('.toObject', () => { beforeEach(function () { this.hosts = { a: 'b', b: 'c' } - this.blacklistHosts = ['a.com', 'b.com'] + this.blockHosts = ['a.com', 'b.com'] this.specs = [ path.join(cwd, 'foo'), path.join(cwd, 'bar'), @@ -346,7 +346,7 @@ describe('lib/util/args', () => { env: this.env, hosts: this.hosts, requestTimeout: 1234, - blacklistHosts: this.blacklistHosts, + blockHosts: this.blockHosts, reporterOptions: { foo: 'bar', }, @@ -360,7 +360,7 @@ describe('lib/util/args', () => { '--get-key', '--env=foo=bar,baz=quux,bar=foo=quz', '--config', - `requestTimeout=1234,blacklistHosts=${s(this.blacklistHosts)},hosts=${s(this.hosts)}`, + `requestTimeout=1234,blockHosts=${s(this.blockHosts)},hosts=${s(this.hosts)}`, '--reporter-options=foo=bar', '--spec=foo,bar,baz', ) @@ -387,7 +387,7 @@ describe('lib/util/args', () => { it('can transpose back to an array', function () { const mergedConfig = JSON.stringify({ requestTimeout: this.config.requestTimeout, - blacklistHosts: this.blacklistHosts, + blockHosts: this.blockHosts, hosts: this.hosts, env: this.env, reporterOptions: { diff --git a/packages/server/test/unit/browsers/electron_spec.js b/packages/server/test/unit/browsers/electron_spec.js index 85701d28ac64..b6eea551eac5 100644 --- a/packages/server/test/unit/browsers/electron_spec.js +++ b/packages/server/test/unit/browsers/electron_spec.js @@ -135,15 +135,15 @@ describe('lib/browsers/electron', () => { plugins.has.returns(true) plugins.execute.resolves({ extensions: ['foo', 'bar'] }) - Windows.installExtension.withArgs('bar').throws() + Windows.installExtension.withArgs(sinon.match.any, 'bar').throws() return electron.open('electron', this.url, this.options, this.automation) .then(() => { expect(Windows.removeAllExtensions).to.be.calledOnce expect(Windows.installExtension).to.be.calledTwice - expect(Windows.installExtension).to.be.calledWith('foo') - expect(Windows.installExtension).to.be.calledWith('bar') + expect(Windows.installExtension).to.be.calledWith(sinon.match.any, 'foo') + expect(Windows.installExtension).to.be.calledWith(sinon.match.any, 'bar') expect(this.options.onWarning).to.be.calledOnce diff --git a/packages/server/test/unit/browsers/firefox_spec.ts b/packages/server/test/unit/browsers/firefox_spec.ts index f2d737cbf479..b3fcafb53717 100644 --- a/packages/server/test/unit/browsers/firefox_spec.ts +++ b/packages/server/test/unit/browsers/firefox_spec.ts @@ -1,14 +1,15 @@ require('../../spec_helper') -import { expect } from 'chai' -import sinon from 'sinon' import 'chai-as-promised' -import firefoxUtil from '../../../lib/browsers/firefox-util' -import * as firefox from '../../../lib/browsers/firefox' +import { expect } from 'chai' import { EventEmitter } from 'events' -import Marionette from 'marionette-client' import Foxdriver from '@benmalka/foxdriver' +import Marionette from 'marionette-client' import os from 'os' +import sinon from 'sinon' +import * as firefox from '../../../lib/browsers/firefox' +import firefoxUtil from '../../../lib/browsers/firefox-util' + const mockfs = require('mock-fs') const FirefoxProfile = require('firefox-profile') const utils = require('../../../lib/browsers/utils') diff --git a/packages/server/test/unit/config_spec.js b/packages/server/test/unit/config_spec.js index c4ac45aae0fd..58bf50345bbb 100644 --- a/packages/server/test/unit/config_spec.js +++ b/packages/server/test/unit/config_spec.js @@ -663,33 +663,61 @@ describe('lib/config', () => { }) }) - context('blacklistHosts', () => { + context('blockHosts', () => { it('passes if a string', function () { - this.setup({ blacklistHosts: 'google.com' }) + this.setup({ blockHosts: 'google.com' }) return this.expectValidationPasses() }) it('passes if an array of strings', function () { - this.setup({ blacklistHosts: ['google.com'] }) + this.setup({ blockHosts: ['google.com'] }) return this.expectValidationPasses() }) it('fails if not a string or array', function () { - this.setup({ blacklistHosts: 5 }) + this.setup({ blockHosts: 5 }) return this.expectValidationFails('be a string or an array of strings') }) it('fails if not an array of strings', function () { - this.setup({ blacklistHosts: [5] }) + this.setup({ blockHosts: [5] }) this.expectValidationFails('be a string or an array of strings') return this.expectValidationFails('the value was: `[5]`') }) }) + context('retries', () => { + const retriesError = 'a positive number or null or an object with keys "openMode" and "runMode" with values of numbers or nulls' + + // need to keep the const here or it'll get stripped by the build + // eslint-disable-next-line no-unused-vars + const cases = [ + [{ retries: null }, 'with null', true], + [{ retries: 3 }, 'when a number', true], + [{ retries: 3.2 }, 'when a float', false], + [{ retries: -1 }, 'with a negative number', false], + [{ retries: true }, 'when true', false], + [{ retries: false }, 'when false', false], + [{ retries: {} }, 'with an empty object', true], + [{ retries: { runMode: 3 } }, 'when runMode is a positive number', true], + [{ retries: { runMode: -1 } }, 'when runMode is a negative number', false], + [{ retries: { openMode: 3 } }, 'when openMode is a positive number', true], + [{ retries: { openMode: -1 } }, 'when openMode is a negative number', false], + [{ retries: { openMode: 3, TypoRunMode: 3 } }, 'when there is an additional unknown key', false], + [{ retries: { openMode: 3, runMode: 3 } }, 'when both runMode and openMode are positive numbers', true], + ].forEach(([config, expectation, shouldPass]) => { + it(`${shouldPass ? 'passes' : 'fails'} ${expectation}`, function () { + this.setup(config) + + return shouldPass ? this.expectValidationPasses() : this.expectValidationFails(retriesError) + }) + }) + }) + context('firefoxGcInterval', () => { it('passes if a number', function () { this.setup({ firefoxGcInterval: 1 }) @@ -731,8 +759,8 @@ describe('lib/config', () => { } }) - it('includes blacklistHosts', function () { - return this.includes('blacklistHosts') + it('includes blockHosts', function () { + return this.includes('blockHosts') }) }) @@ -971,19 +999,19 @@ describe('lib/config', () => { return this.defaults('supportFile', false, { supportFile: false }) }) - it('blacklistHosts=null', function () { - return this.defaults('blacklistHosts', null) + it('blockHosts=null', function () { + return this.defaults('blockHosts', null) }) - it('blacklistHosts=[a,b]', function () { - return this.defaults('blacklistHosts', ['a', 'b'], { - blacklistHosts: ['a', 'b'], + it('blockHosts=[a,b]', function () { + return this.defaults('blockHosts', ['a', 'b'], { + blockHosts: ['a', 'b'], }) }) - it('blacklistHosts=a|b', function () { - return this.defaults('blacklistHosts', ['a', 'b'], { - blacklistHosts: ['a', 'b'], + it('blockHosts=a|b', function () { + return this.defaults('blockHosts', ['a', 'b'], { + blockHosts: ['a', 'b'], }) }) @@ -1093,6 +1121,17 @@ describe('lib/config', () => { }) }) + // @see https://github.com/cypress-io/cypress/issues/6892 + it('warns if experimentalGetCookiesSameSite is passed', async function () { + const warning = sinon.spy(errors, 'warning') + + await this.defaults('experimentalGetCookiesSameSite', true, { + experimentalGetCookiesSameSite: true, + }) + + expect(warning).to.be.calledWith('EXPERIMENTAL_SAMESITE_REMOVED') + }) + describe('.resolved', () => { it('sets reporter and port to cli', () => { const obj = { @@ -1111,7 +1150,7 @@ describe('lib/config', () => { projectId: { value: null, from: 'default' }, port: { value: 1234, from: 'cli' }, hosts: { value: null, from: 'default' }, - blacklistHosts: { value: null, from: 'default' }, + blockHosts: { value: null, from: 'default' }, browsers: { value: [], from: 'default' }, userAgent: { value: null, from: 'default' }, reporter: { value: 'json', from: 'cli' }, @@ -1122,7 +1161,6 @@ describe('lib/config', () => { requestTimeout: { value: 5000, from: 'default' }, responseTimeout: { value: 30000, from: 'default' }, execTimeout: { value: 60000, from: 'default' }, - experimentalGetCookiesSameSite: { value: false, from: 'default' }, experimentalSourceRewriting: { value: false, from: 'default' }, taskTimeout: { value: 60000, from: 'default' }, numTestsKeptInMemory: { value: 50, from: 'default' }, @@ -1153,6 +1191,7 @@ describe('lib/config', () => { componentFolder: { value: 'cypress/component', from: 'default' }, experimentalShadowDomSupport: { value: false, from: 'default' }, experimentalFetchPolyfill: { value: false, from: 'default' }, + retries: { value: { runMode: 0, openMode: 0 }, from: 'default' }, }) }) }) @@ -1189,7 +1228,7 @@ describe('lib/config', () => { projectId: { value: 'projectId123', from: 'env' }, port: { value: 2020, from: 'config' }, hosts: { value: null, from: 'default' }, - blacklistHosts: { value: null, from: 'default' }, + blockHosts: { value: null, from: 'default' }, browsers: { value: [], from: 'default' }, userAgent: { value: null, from: 'default' }, reporter: { value: 'spec', from: 'default' }, @@ -1200,7 +1239,6 @@ describe('lib/config', () => { requestTimeout: { value: 5000, from: 'default' }, responseTimeout: { value: 30000, from: 'default' }, execTimeout: { value: 60000, from: 'default' }, - experimentalGetCookiesSameSite: { value: false, from: 'default' }, experimentalSourceRewriting: { value: false, from: 'default' }, taskTimeout: { value: 60000, from: 'default' }, numTestsKeptInMemory: { value: 50, from: 'default' }, @@ -1231,6 +1269,7 @@ describe('lib/config', () => { componentFolder: { value: 'cypress/component', from: 'default' }, experimentalShadowDomSupport: { value: false, from: 'default' }, experimentalFetchPolyfill: { value: false, from: 'default' }, + retries: { value: { runMode: 0, openMode: 0 }, from: 'default' }, env: { foo: { value: 'foo', @@ -1847,7 +1886,7 @@ describe('lib/config', () => { }) it('sets the pluginsFile to index.ts if it exists', () => { - const projectRoot = path.join(process.cwd(), 'test/support/fixtures/projects/ts-proj') + const projectRoot = path.join(process.cwd(), 'test/support/fixtures/projects/ts-proj-with-module-esnext') const obj = { projectRoot, @@ -1864,7 +1903,7 @@ describe('lib/config', () => { }) it('sets the pluginsFile to index.ts if it exists (without ts require hook)', () => { - const projectRoot = path.join(process.cwd(), 'test/support/fixtures/projects/ts-proj') + const projectRoot = path.join(process.cwd(), 'test/support/fixtures/projects/ts-proj-with-module-esnext') const pluginsFolder = `${projectRoot}/cypress/plugins` const pluginsFilename = `${pluginsFolder}/index.ts` diff --git a/packages/server/test/unit/gui/events_spec.js b/packages/server/test/unit/gui/events_spec.js index af69794ef349..16c7ff38e85d 100644 --- a/packages/server/test/unit/gui/events_spec.js +++ b/packages/server/test/unit/gui/events_spec.js @@ -17,9 +17,8 @@ const openProject = require(`${root}../lib/open_project`) const open = require(`${root}../lib/util/open`) const auth = require(`${root}../lib/gui/auth`) const logs = require(`${root}../lib/gui/logs`) -const events = require(`${root}../lib/gui/events`) +const events = require(`../../../lib/gui/events`) const dialog = require(`${root}../lib/gui/dialog`) -const Windows = require(`${root}../lib/gui/windows`) const ensureUrl = require(`${root}../lib/util/ensure-url`) const konfig = require(`${root}../lib/konfig`) @@ -206,11 +205,11 @@ describe('lib/gui/events', () => { loadURL () {}, webContents: {}, }) - - return sinon.stub(Windows, 'create').withArgs(this.options.projectRoot).returns(this.win) }) - it('calls Windows#open with args and resolves with return of Windows.open', function () { + it('calls windowOpenFn with args and resolves with return', function () { + this.options.windowOpenFn = sinon.stub().rejects().withArgs({ type: 'INDEX ' }).resolves(this.win) + return this.handleEvent('window:open', { type: 'INDEX' }) .then((assert) => { return assert.sendCalledWith(events.nullifyUnserializableValues(this.win)) @@ -220,7 +219,7 @@ describe('lib/gui/events', () => { it('catches errors', function () { const err = new Error('foo') - sinon.stub(Windows, 'open').withArgs(this.options.projectRoot, { foo: 'bar' }).rejects(err) + this.options.windowOpenFn = sinon.stub().withArgs(this.options.projectRoot, { foo: 'bar' }).rejects(err) return this.handleEvent('window:open', { foo: 'bar' }).then((assert) => { return assert.sendErrCalledWith(err) @@ -230,11 +229,14 @@ describe('lib/gui/events', () => { describe('window:close', () => { it('calls destroy on Windows#getByWebContents', function () { - this.destroy = sinon.stub() - sinon.stub(Windows, 'getByWebContents').withArgs(this.event.sender).returns({ destroy: this.destroy }) + const win = { + destroy: sinon.stub(), + } + + this.options.getWindowByWebContentsFn = sinon.stub().withArgs(this.event.sender).returns(win) this.handleEvent('window:close') - expect(this.destroy).to.be.calledOnce + expect(win.destroy).to.be.calledOnce }) }) }) diff --git a/packages/server/test/unit/gui/windows_spec.js b/packages/server/test/unit/gui/windows_spec.ts similarity index 80% rename from packages/server/test/unit/gui/windows_spec.js rename to packages/server/test/unit/gui/windows_spec.ts index abfac43b39cd..952f0e4f9895 100644 --- a/packages/server/test/unit/gui/windows_spec.js +++ b/packages/server/test/unit/gui/windows_spec.ts @@ -1,13 +1,17 @@ -require('../../spec_helper') +import '../../spec_helper' + +import { expect } from 'chai' +import 'sinon-chai' + +import _ from 'lodash' +import path from 'path' +import Promise from 'bluebird' +import { EventEmitter } from 'events' +import { BrowserWindow } from 'electron' +import * as Windows from '../../../lib/gui/windows' +import savedState from '../../../lib/saved_state' -const _ = require('lodash') -const path = require('path') -const Promise = require('bluebird') -const EE = require('events').EventEmitter -const { BrowserWindow } = require('electron') const cyDesktop = require('@packages/desktop-gui') -const Windows = require(`${root}../lib/gui/windows`) -const savedState = require(`${root}../lib/saved_state`) const DEFAULT_USER_AGENT = 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Cypress/0.0.0 Chrome/59.0.3071.115 Electron/1.8.2 Safari/537.36' @@ -15,17 +19,15 @@ describe('lib/gui/windows', () => { beforeEach(function () { Windows.reset() - this.win = new EE() + this.win = new EventEmitter() this.win.loadURL = sinon.stub() this.win.destroy = sinon.stub() this.win.getSize = sinon.stub().returns([1, 2]) this.win.getPosition = sinon.stub().returns([3, 4]) - this.win.webContents = new EE() + this.win.webContents = new EventEmitter() this.win.webContents.openDevTools = sinon.stub() this.win.webContents.userAgent = DEFAULT_USER_AGENT this.win.isDestroyed = sinon.stub().returns(false) - - return sinon.stub(Windows, '_newBrowserWindow').returns(this.win) }) afterEach(() => { @@ -33,38 +35,31 @@ describe('lib/gui/windows', () => { }) context('.getByWebContents', () => { - beforeEach(() => { - return sinon.stub(BrowserWindow, 'fromWebContents') - }) - it('calls BrowserWindow.fromWebContents', () => { - BrowserWindow.fromWebContents.withArgs('foo').returns('bar') + sinon.stub(BrowserWindow, 'fromWebContents').withArgs('foo' as any).returns('bar' as any) expect(Windows.getByWebContents('foo')).to.eq('bar') }) }) context('.open', () => { - beforeEach(function () { - return sinon.stub(Windows, 'create').returns(this.win) - }) - - it('sets default options', () => { - const options = { + it('sets default options', function () { + const options: Windows.WindowOptions = { type: 'INDEX', } - return Windows.open('/path/to/project', options) + return Windows.open('/path/to/project', options, () => this.win) .then((win) => { - expect(options).to.deep.eq({ + expect(options).to.include({ height: 500, width: 600, type: 'INDEX', show: true, url: cyDesktop.getPathToIndex(), - webPreferences: { - preload: path.resolve('lib', 'ipc', 'ipc.js'), - }, + }) + + expect(options.webPreferences).to.include({ + preload: path.resolve('lib', 'ipc', 'ipc.js'), }) expect(win.loadURL).to.be.calledWith(cyDesktop.getPathToIndex()) @@ -74,10 +69,10 @@ describe('lib/gui/windows', () => { context('.create', () => { it('opens dev tools if saved state is open', function () { - Windows.create('/foo/', { devTools: true }) + Windows.create('/foo/', { devTools: true }, () => this.win) expect(this.win.webContents.openDevTools).to.be.called - Windows.create('/foo/', {}) + Windows.create('/foo/', {}, () => this.win) expect(this.win.webContents.openDevTools).not.to.be.calledTwice }) diff --git a/packages/server/test/unit/modes/run_spec.js b/packages/server/test/unit/modes/run_spec.js index 20c3c6f67814..ec852e3075c1 100644 --- a/packages/server/test/unit/modes/run_spec.js +++ b/packages/server/test/unit/modes/run_spec.js @@ -360,7 +360,7 @@ describe('lib/modes/run', () => { const screenshots = [{}, {}, {}] const endVideoCapture = sinon.stub().resolves() const results = { - tests: [4, 5, 6], + tests: [{ attempts: [1] }, { attempts: [2] }, { attempts: [3] }], stats: { tests: 1, passes: 2, @@ -371,9 +371,6 @@ describe('lib/modes/run', () => { } sinon.stub(Reporter, 'setVideoTimestamp') - .withArgs(startedVideoCapture, results.tests) - .returns([1, 2, 3]) - sinon.stub(runMode, 'postProcessRecording').resolves() sinon.spy(runMode, 'displayResults') sinon.spy(runMode, 'displayScreenshots') @@ -399,6 +396,7 @@ describe('lib/modes/run', () => { }) .then((obj) => { // since video was recording, there was a delay to let video finish + expect(Reporter.setVideoTimestamp).calledWith(startedVideoCapture, [1, 2, 3]) expect(runMode.getVideoRecordingDelay).to.have.returned(1000) expect(Promise.prototype.delay).to.be.calledWith(1000) expect(runMode.postProcessRecording).to.be.calledWith('foo.mp4', 'foo-compressed.mp4', 32, true) @@ -413,7 +411,7 @@ describe('lib/modes/run', () => { hooks: null, reporterStats: null, shouldUploadVideo: true, - tests: [1, 2, 3], + tests: results.tests, spec: { path: 'cypress/integration/spec.js', }, diff --git a/packages/server/test/unit/plugins/preprocessor_spec.js b/packages/server/test/unit/plugins/preprocessor_spec.js index fd1b923c8d47..6f2da7c9b47d 100644 --- a/packages/server/test/unit/plugins/preprocessor_spec.js +++ b/packages/server/test/unit/plugins/preprocessor_spec.js @@ -89,28 +89,18 @@ describe('lib/plugins/preprocessor', () => { plugins._reset() sinon.stub(plugins, 'register') sinon.stub(plugins, 'execute').returns(() => {}) - const browserifyFn = function () {} - const browserify = sinon.stub().returns(browserifyFn) - - // mock default options - browserify.defaultOptions = { - browserifyOptions: { - extensions: [], - transform: [ - [], - ['babelify', { - presets: [], - extensions: [], - }], - ], - }, - } - mockery.registerMock('@cypress/browserify-preprocessor', browserify) + const userPreprocessorFn = function () {} + const userPreprocessor = sinon.stub().returns(userPreprocessorFn) + + userPreprocessor.defaultOptions = {} + + mockery.registerMock('@cypress/webpack-batteries-included-preprocessor', userPreprocessor) + preprocessor.getFile(this.filePath, this.config) - expect(plugins.register).to.be.calledWith('file:preprocessor', browserifyFn) - expect(browserify).to.be.called + expect(plugins.register).to.be.calledWith('file:preprocessor', userPreprocessorFn) + expect(userPreprocessor).to.be.called }) }) @@ -224,7 +214,7 @@ describe('lib/plugins/preprocessor', () => { const mockPlugin = {} sinon.stub(plugins, 'register') - sinon.stub(preprocessor, 'createBrowserifyPreprocessor').returns(mockPlugin) + sinon.stub(preprocessor, 'createPreprocessor').returns(mockPlugin) preprocessor.setDefaultPreprocessor(this.config) @@ -236,14 +226,14 @@ describe('lib/plugins/preprocessor', () => { basedir: monorepoRoot, }) - expect(preprocessor.createBrowserifyPreprocessor).to.be.calledWith({ typescript }) + expect(preprocessor.createPreprocessor).to.be.calledWith({ typescript }) }) it('does not have typescript if not found', function () { const mockPlugin = {} sinon.stub(plugins, 'register') - sinon.stub(preprocessor, 'createBrowserifyPreprocessor').returns(mockPlugin) + sinon.stub(preprocessor, 'createPreprocessor').returns(mockPlugin) sinon.stub(resolve, 'sync') .withArgs('typescript', { basedir: this.todosPath }) .throws(new Error('TypeScript not found')) @@ -252,7 +242,7 @@ describe('lib/plugins/preprocessor', () => { expect(plugins.register).to.be.calledWithExactly('file:preprocessor', mockPlugin) - expect(preprocessor.createBrowserifyPreprocessor).to.be.calledWith({ typescript: null }) + expect(preprocessor.createPreprocessor).to.be.calledWith({ typescript: null }) }) }) }) diff --git a/packages/server/test/unit/project_spec.js b/packages/server/test/unit/project_spec.js index be4865e24531..1cae5ac3428c 100644 --- a/packages/server/test/unit/project_spec.js +++ b/packages/server/test/unit/project_spec.js @@ -354,7 +354,6 @@ This option will not have an effect in Some-other-name. Tests that rely on web s compiler: projTsPath, compilerOptions: { module: 'CommonJS', - esModuleInterop: true, }, }) }) diff --git a/packages/server/test/unit/reporter_spec.js b/packages/server/test/unit/reporter_spec.js index 6888b89131df..a8a75a1080d2 100644 --- a/packages/server/test/unit/reporter_spec.js +++ b/packages/server/test/unit/reporter_spec.js @@ -32,7 +32,7 @@ describe('lib/reporter', () => { sync: true, err: { message: 'foo', - stack: [1, 2, 3], + stack: 'at foo:1:1\nat bar:1:1\nat baz:1:1', }, }, { diff --git a/packages/server/test/unit/saved_state_spec.js b/packages/server/test/unit/saved_state_spec.js index 993e74248975..aadce5110414 100644 --- a/packages/server/test/unit/saved_state_spec.js +++ b/packages/server/test/unit/saved_state_spec.js @@ -62,7 +62,7 @@ describe('lib/saved_state', () => { }) }) - it('only saves whitelisted keys', () => { + it('only saves allowed keys', () => { return savedState.create() .then((state) => { return state.set({ foo: 'bar', appWidth: 20 }) @@ -81,7 +81,7 @@ describe('lib/saved_state', () => { .then((state) => { return state.set({ foo: 'bar', baz: 'qux' }) }).then(() => { - expect(console.error).to.be.calledWith('WARNING: attempted to save state for non-whitelisted key(s): foo, baz. All keys must be whitelisted in server/lib/saved_state.js') + expect(console.error).to.be.calledWith('WARNING: attempted to save state for non-allowed key(s): foo, baz. All keys must be allowed in server/lib/saved_state.js') }) }) }) diff --git a/packages/server/test/unit/screenshots_spec.js b/packages/server/test/unit/screenshots_spec.js index e14c68da4c96..b4b5aadce252 100644 --- a/packages/server/test/unit/screenshots_spec.js +++ b/packages/server/test/unit/screenshots_spec.js @@ -679,7 +679,7 @@ describe('lib/screenshots', () => { return sinon.stub(plugins, 'execute') }) - it('resolves whitelisted details if no after:screenshot plugin registered', function () { + it('resolves allowed details if no after:screenshot plugin registered', function () { plugins.has.returns(false) return screenshots.afterScreenshot(this.data, this.details).then((result) => { diff --git a/packages/server/test/unit/server_spec.js b/packages/server/test/unit/server_spec.js index fdc42b121614..c0025d36bbe0 100644 --- a/packages/server/test/unit/server_spec.js +++ b/packages/server/test/unit/server_spec.js @@ -338,7 +338,7 @@ describe('lib/server', () => { remoteAddress: '127.0.0.1', } - this.server._socketWhitelist.add({ + this.server._socketAllowed.add({ localPort: socket.remotePort, once: _.noop, }) diff --git a/packages/server/test/unit/spec_spec.js b/packages/server/test/unit/spec_spec.js index 4a62a6d2a06a..cb26a4630437 100644 --- a/packages/server/test/unit/spec_spec.js +++ b/packages/server/test/unit/spec_spec.js @@ -49,7 +49,6 @@ describe('lib/controllers/spec', () => { return this.handle(specName).then(() => { expect(this.res.send).to.be.called expect(this.res.send.firstCall.args[0]).to.include('(function') - expect(this.res.send.firstCall.args[0]).to.include('Reason request failed') }) }) @@ -60,7 +59,6 @@ describe('lib/controllers/spec', () => { return this.handle(specName, { isTextTerminal: true }).then(() => { expect(this.onError).to.be.called expect(this.onError.lastCall.args[0].message).to.include('Oops...we found an error preparing this test file') - expect(this.onError.lastCall.args[0].message).to.include('Reason request failed') }) }) @@ -72,8 +70,27 @@ describe('lib/controllers/spec', () => { return this.handle(specName).then(() => { expect(this.res.send.firstCall.args[0]).to.include('(function') - expect(this.res.send.firstCall.args[0]).to.include('ENOENT') }) }) + + it('ignores ECONNABORTED errors', function () { + const sendFileErr = new Error('ECONNABORTED') + + sendFileErr.code = 'ECONNABORTED' + + this.res.sendFile.yields(sendFileErr) + + return this.handle(specName) // should resolve, not error + }) + + it('ignores EPIPE errors', function () { + const sendFileErr = new Error('EPIPE') + + sendFileErr.code = 'EPIPE' + + this.res.sendFile.yields(sendFileErr) + + return this.handle(specName) // should resolve, not error + }) }) diff --git a/packages/server/test/unit/suppress_unauthorized_warning_spec.ts b/packages/server/test/unit/suppress_unauthorized_warning_spec.ts index b92972c337e9..b76b26fe023a 100644 --- a/packages/server/test/unit/suppress_unauthorized_warning_spec.ts +++ b/packages/server/test/unit/suppress_unauthorized_warning_spec.ts @@ -1,10 +1,12 @@ -import execa from 'execa' +import '../spec_helper' import { expect } from 'chai' +import execa from 'execa' +import proxyquire from 'proxyquire' const ERROR_MESSAGE = 'Setting the NODE_TLS_REJECT_UNAUTHORIZED' const TLS_CONNECT = `require('tls').connect().on('error', ()=>{});` -const SUPPRESS_WARNING = `require('@packages/ts/register'); require('${__dirname}/../../lib/util/suppress_unauthorized_warning').suppress();` +const SUPPRESS_WARNING = `require('${__dirname}/../../lib/util/suppress_unauthorized_warning').suppress();` describe('lib/util/suppress_unauthorized_warning', function () { it('tls.connect emits warning if NODE_TLS_REJECT_UNAUTHORIZED=0 and not suppressed', function () { @@ -29,4 +31,20 @@ describe('lib/util/suppress_unauthorized_warning', function () { expect(stderr).to.not.contain(ERROR_MESSAGE) }) }) + + it('does not emit buffer deprecation warnings', () => { + const emitWarning = sinon.spy(process, 'emitWarning') + + // force typescript to always be non-requireable + const { suppress } = proxyquire('../../lib/util/suppress_unauthorized_warning', {}) + + suppress() + + // eslint-disable-next-line no-buffer-constructor + new Buffer(0) + // eslint-disable-next-line no-buffer-constructor + new Buffer('asdf') + + expect(emitWarning).not.to.be.called + }) }) diff --git a/packages/server/test/unit/util/obj_utils_spec.ts b/packages/server/test/unit/util/obj_utils_spec.ts new file mode 100644 index 000000000000..8de42a8cecf2 --- /dev/null +++ b/packages/server/test/unit/util/obj_utils_spec.ts @@ -0,0 +1,29 @@ +import * as objUtils from '../../../lib/util/obj_utils' +import { expect } from 'chai' + +const { each, remapKeys, renameKey, setValue, remove } = objUtils + +describe('obj_utils', () => { + context('#remapKeys', () => { + it('returns cloned object with renamed, removed, and modified key/values', () => { + const initial = { + foos: [{ id: 1, renameMe: 'foo' }, { id: 2, renameMe: 'bar' }, { id: 3, renameMe: 'baz' }], + foos2: [{ id: 1, renameMe: 'foo' }, { id: 2, renameMe: 'bar' }, { id: 3, renameMe: 'baz' }], + bar: 'foobar', + } + + const result = remapKeys(initial, { + foos: each((foo, i) => ({ renameMe: renameKey('newName'), id: setValue(i) })), + foos2: each({ renameMe: remove }), + bar: remove, + }) + + expect(result).deep.eq({ + foos: [{ id: 0, newName: 'foo' }, { id: 1, newName: 'bar' }, { id: 2, newName: 'baz' }], + foos2: [{ id: 1 }, { id: 2 }, { id: 3 }], + }) + + expect(result).not.eq(initial) + }) + }) +}) diff --git a/packages/server/test/unit/util/socket_allowed_spec.ts b/packages/server/test/unit/util/socket_allowed_spec.ts new file mode 100644 index 000000000000..836e38ca8093 --- /dev/null +++ b/packages/server/test/unit/util/socket_allowed_spec.ts @@ -0,0 +1,42 @@ +import '../../spec_helper' + +import { expect } from 'chai' +import { Request } from 'express' +import { SocketAllowed } from '../../../lib/util/socket_allowed' +import { EventEmitter } from 'events' +import { Socket } from 'net' + +describe('lib/util/socket_allowed', function () { + let sw: SocketAllowed + + beforeEach(() => { + sw = new SocketAllowed() + }) + + context('#add', () => { + it('adds localPort to allowed list and removes it when closed', () => { + const socket = new EventEmitter as Socket + + // @ts-ignore readonly + socket.localPort = 12345 + + const req = { + socket: { + remotePort: socket.localPort, + remoteAddress: '127.0.0.1', + }, + } as Request + + expect(sw.allowedLocalPorts).to.deep.eq([]) + expect(sw.isRequestAllowed(req)).to.be.false + + sw.add(socket) + expect(sw.allowedLocalPorts).to.deep.eq([socket.localPort]) + expect(sw.isRequestAllowed(req)).to.be.true + + socket.emit('close') + expect(sw.allowedLocalPorts).to.deep.eq([]) + expect(sw.isRequestAllowed(req)).to.be.false + }) + }) +}) diff --git a/packages/server/test/unit/util/socket_whitelist_spec.ts b/packages/server/test/unit/util/socket_whitelist_spec.ts deleted file mode 100644 index e8fa34642671..000000000000 --- a/packages/server/test/unit/util/socket_whitelist_spec.ts +++ /dev/null @@ -1,42 +0,0 @@ -import '../../spec_helper' - -import { expect } from 'chai' -import { Request } from 'express' -import { SocketWhitelist } from '../../../lib/util/socket_whitelist' -import { EventEmitter } from 'events' -import { Socket } from 'net' - -describe('lib/util/socket_whitelist', function () { - let sw: SocketWhitelist - - beforeEach(() => { - sw = new SocketWhitelist() - }) - - context('#add', () => { - it('adds localPort to whitelist and removes it when closed', () => { - const socket = new EventEmitter as Socket - - // @ts-ignore readonly - socket.localPort = 12345 - - const req = { - socket: { - remotePort: socket.localPort, - remoteAddress: '127.0.0.1', - }, - } as Request - - expect(sw.whitelistedLocalPorts).to.deep.eq([]) - expect(sw.isRequestWhitelisted(req)).to.be.false - - sw.add(socket) - expect(sw.whitelistedLocalPorts).to.deep.eq([socket.localPort]) - expect(sw.isRequestWhitelisted(req)).to.be.true - - socket.emit('close') - expect(sw.whitelistedLocalPorts).to.deep.eq([]) - expect(sw.isRequestWhitelisted(req)).to.be.false - }) - }) -}) diff --git a/packages/ts/package.json b/packages/ts/package.json index 790850b48a5a..dbe88bcd7025 100644 --- a/packages/ts/package.json +++ b/packages/ts/package.json @@ -5,6 +5,7 @@ "main": "index.js", "scripts": { "clean-deps": "rm -rf node_modules", + "postinstall": "patch-package", "test": "yarn test-unit", "test-unit": "node test", "test-watch": "echo 'no watching of tests'" diff --git a/packages/ts/patches/ts-node+5.0.1.patch b/packages/ts/patches/ts-node+5.0.1.patch new file mode 100644 index 000000000000..b53b150ae8a7 --- /dev/null +++ b/packages/ts/patches/ts-node+5.0.1.patch @@ -0,0 +1,13 @@ +diff --git a/node_modules/ts-node/dist/index.js b/node_modules/ts-node/dist/index.js +index 2dfd704..c00aa39 100644 +--- a/node_modules/ts-node/dist/index.js ++++ b/node_modules/ts-node/dist/index.js +@@ -298,7 +298,7 @@ function readThrough(cachedir, shouldCache, memoryCache, compile, getExtension) + }; + } + function updateOutput(outputText, fileName, sourceMap, getExtension) { +- var base64Map = new Buffer(updateSourceMap(sourceMap, fileName), 'utf8').toString('base64'); ++ var base64Map = Buffer.from(updateSourceMap(sourceMap, fileName), 'utf8').toString('base64'); + var sourceMapContent = "data:application/json;charset=utf-8;base64," + base64Map; + var sourceMapLength = (path_1.basename(fileName) + ".map").length + (getExtension(fileName).length - path_1.extname(fileName).length); + return outputText.slice(0, -sourceMapLength) + sourceMapContent; diff --git a/packages/ui-components/cypress/support/customPercyCommand.js b/packages/ui-components/cypress/support/customPercyCommand.js new file mode 100644 index 000000000000..be1041d59c3e --- /dev/null +++ b/packages/ui-components/cypress/support/customPercyCommand.js @@ -0,0 +1,51 @@ +require('@percy/cypress') +const _ = require('lodash') + +function customPercySnapshot ( + origFn, + name, + options = {}, +) { + if (_.isObject(name)) { + options = name + name = null + } + + const opts = _.defaults({}, options, { + elementOverrides: { '.stats .duration': ($el) => $el.text('XX.XX'), '.cy-tooltip': true }, + widths: [Cypress.config().viewportWidth], + }) + + /** + * @type {Mocha.Test} + */ + const test = cy.state('test') + + const titlePath = test.titlePath() + + const screenshotName = titlePath.concat(name).filter(Boolean).join(' > ') + + _.each(opts.elementOverrides, (v, k) => { + // eslint-disable-next-line cypress/no-assigning-return-values + const $el = cy.$$(k) + + if (_.isFunction(v)) { + v($el) + + return + } + + $el.css({ visibility: 'hidden' }) + }) + + // if we're in interactive mode via (cypress open) + // then bail immediately + if (Cypress.config().isInteractive) { + return cy.log('percy: skipping snapshot in interactive mode') + } + + return origFn(screenshotName, { + widths: opts.widths, + }) +} +Cypress.Commands.overwrite('percySnapshot', customPercySnapshot) diff --git a/scripts/check-node-version.js b/scripts/check-node-version.js index 9ccc2c3b42b3..aef89a5b5a71 100644 --- a/scripts/check-node-version.js +++ b/scripts/check-node-version.js @@ -3,23 +3,10 @@ const assert = require('assert') // TODO make this check a 3rd party little tool -// on CircleCI Mac machine, we need to use on of the laer executors -// that already has Node 10 / 11 -const isMac = () => { - return os.platform() === 'darwin' -} - const isWindows = () => { return os.platform() === 'win32' } -if (isMac() && process.env.CIRCLECI) { - // eslint-disable-next-line no-console - console.log('Skipping Node version check on CircleCI Mac') - - return -} - // if we're windows + in appveyor... if (isWindows() && process.env.APPVEYOR) { // check to ensure that the cpuArch + nodeArch are in sync diff --git a/scripts/load-nvm.sh b/scripts/load-nvm.sh new file mode 100755 index 000000000000..d2259dfb81ca --- /dev/null +++ b/scripts/load-nvm.sh @@ -0,0 +1,11 @@ +# loads previously installed NVM +# USE: +# - run: +# name: check Node version +# command: | +# . ./scripts/load-nvm.sh +# yarn check-node-version + +export NVM_DIR="$HOME/.nvm" +[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" +export NODE_VERSION=$(cat .node-version) diff --git a/scripts/run-docker-local.sh b/scripts/run-docker-local.sh index 495998aa2955..27fd5c49ccf6 100755 --- a/scripts/run-docker-local.sh +++ b/scripts/run-docker-local.sh @@ -3,7 +3,7 @@ set e+x echo "This script should be run from cypress's root" -name=cypress/browsers:node12.13.0-chrome80-ff74 +name=cypress/browsers:node12.14.1-chrome83-ff77 echo "Pulling CI container $name" docker pull $name diff --git a/scripts/wait-on-circle-jobs.js b/scripts/wait-on-circle-jobs.js new file mode 100644 index 000000000000..09eee4afb5b4 --- /dev/null +++ b/scripts/wait-on-circle-jobs.js @@ -0,0 +1,167 @@ +/* eslint-disable no-console */ + +const _ = require('lodash') +const minimist = require('minimist') +const Promise = require('bluebird') +const retry = require('bluebird-retry') +const got = require('got') +// always print the debug logs +const debug = require('debug')('*') + +// we expect CircleCI to set the current polling job name +const jobName = process.env.CIRCLE_JOB || 'wait-on-circle-jobs' + +const workflowId = process.env.CIRCLE_WORKFLOW_ID + +const getAuth = () => `${process.env.CIRCLE_TOKEN}:` + +if (!process.env.CIRCLE_TOKEN) { + console.error('Cannot find CIRCLE_TOKEN') + process.exit(1) +} + +if (!process.env.CIRCLE_WORKFLOW_ID) { + console.error('Cannot find CIRCLE_WORKFLOW_ID') + process.exit(1) +} + +const args = minimist(process.argv.slice(2), { boolean: false }) + +const jobNames = _ +.chain(args['job-names']) +.split(',') +.without('true') +.map(_.trim) +.compact() +.value() + +if (!jobNames.length) { + console.error('Missing argument: --job-names') + console.error('You must pass a comma separated list of Circle CI job names to wait for.') + process.exit(1) +} + +debug('received circle jobs: %o', jobNames) + +/* eslint-disable-next-line no-unused-vars */ +const getWorkflow = async (workflowId) => { + const auth = getAuth() + const url = `https://${auth}@circleci.com/api/v2/workflow/${workflowId}` + const response = await got(url).json() + + // returns something like + // { + // pipeline_id: '5b937e8b-6138-41ad-b8d0-1c1969c4dad1', + // id: '566ffe9a-62d4-45cd-9a27-9882139e0121', + // name: 'linux', + // project_slug: 'gh/cypress-io/cypress', + // status: 'failed', + // started_by: '45ae8c6a-4686-4e71-a078-fb7a3b9d9e59', + // pipeline_number: 12461, + // created_at: '2020-07-20T19:45:41Z', + // stopped_at: '2020-07-20T20:06:54Z' + // } + + return response +} + +/** + * Job status + * - blocked (has not run yet) + * - running (currently running) + * - failed | success +*/ +const getJobStatus = async (workfowId) => { + const auth = getAuth() + // typo at https://circleci.com/docs/2.0/api-intro/ + // to retrieve all jobs, the url is "/workflow/:id/job" + const url = `https://${auth}@circleci.com/api/v2/workflow/${workflowId}/job` + const response = await got(url).json() + + // returns something like + // { + // next_page_token: null, + // items: [ + // { + // dependencies: [], + // job_number: 400959, + // id: '7021bcc7-90c1-47d9-bf99-c0372a4f8f49', + // started_at: '2020-07-20T19:45:46Z', + // name: 'build', + // project_slug: 'gh/cypress-io/cypress', + // status: 'success', + // type: 'build', + // stopped_at: '2020-07-20T19:50:07Z' + // } + // ] + // } + return response +} + +const waitForAllJobs = async (workflowId) => { + let response + + try { + response = await getJobStatus(workflowId) + } catch (e) { + console.error(e) + process.exit(1) + } + + // if a job is pending, its status will be "blocked" + const blockedJobs = _.filter(response.items, { status: 'blocked' }) + const failedJobs = _.filter(response.items, { status: 'failed' }) + const runningJobs = _.filter(response.items, { status: 'running' }) + + const blockedJobNames = _.map(blockedJobs, 'name') + const runningJobNames = _.map(runningJobs, 'name') + + debug('failed jobs %o', _.map(failedJobs, 'name')) + debug('blocked jobs %o', blockedJobNames) + debug('running jobs %o', runningJobNames) + + if (!runningJobs.length || (runningJobs.length === 1 && runningJobs[0].name === jobName)) { + // there are no more jobs to run, or this is the last running job + console.log('all jobs are done, finishing this job') + + return Promise.resolve() + } + + const futureOrRunning = _.union(blockedJobs, runningJobNames) + const jobsToWaitFor = _.intersection(jobNames, futureOrRunning) + + debug('jobs to wait for %o', jobsToWaitFor) + + if (!jobsToWaitFor.length) { + console.log('No more jobs to wait for!') + + return Promise.resolve() + } + + return Promise.reject(new Error('Jobs have not finished')) +} + +// finished, has one failed job +// const workflowId = '566ffe9a-62d4-45cd-9a27-9882139e0121' +// pending workflow +// jobs that have not run have "status: 'blocked'" + +// getWorkflow(workflowId).then(console.log, console.error) +// getWorkflowJobs(workflowId).then(console.log, console.error) + +const seconds = (s) => s * 1000 +const minutes = (m) => m * 60 * 1000 + +// https://github.com/demmer/bluebird-retry +retry(waitForAllJobs.bind(null, workflowId), { + timeout: minutes(30), // max time for this job + interval: seconds(30), // poll intervals + max_interval: seconds(30), +}).then(() => { + console.log('all done') +}, (err) => { + console.error(err) + process.exit(1) +}) + +// getJobStatus(workflowId).then(console.log, console.error) diff --git a/yarn.lock b/yarn.lock index f6d3a2c0967d..17eed3ce185c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -51,6 +51,28 @@ invariant "^2.2.4" semver "^5.5.0" +"@babel/core@7.10.5": + version "7.10.5" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.10.5.tgz#1f15e2cca8ad9a1d78a38ddba612f5e7cdbbd330" + integrity sha512-O34LQooYVDXPl7QWCdW9p4NR+QlzOr7xShPPJz8GsuCU3/8ua/wqTr7gmnxXv+WBESiGU/G5s16i6tUvHkNb+w== + dependencies: + "@babel/code-frame" "^7.10.4" + "@babel/generator" "^7.10.5" + "@babel/helper-module-transforms" "^7.10.5" + "@babel/helpers" "^7.10.4" + "@babel/parser" "^7.10.5" + "@babel/template" "^7.10.4" + "@babel/traverse" "^7.10.5" + "@babel/types" "^7.10.5" + convert-source-map "^1.7.0" + debug "^4.1.0" + gensync "^1.0.0-beta.1" + json5 "^2.1.2" + lodash "^4.17.19" + resolve "^1.3.2" + semver "^5.4.1" + source-map "^0.5.0" + "@babel/core@7.4.5": version "7.4.5" resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.4.5.tgz#081f97e8ffca65a9b4b0fdc7e274e703f000c06a" @@ -125,6 +147,15 @@ lodash "^4.17.13" source-map "^0.5.0" +"@babel/generator@^7.10.5": + version "7.10.5" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.10.5.tgz#1b903554bc8c583ee8d25f1e8969732e6b829a69" + integrity sha512-3vXxr3FEW7E7lJZiWQ3bM4+v/Vyr9C+hpolQ8BGFr9Y8Ri2tFLWTixmwKBafDujO1WVah4fhZBeU1bieKdghig== + dependencies: + "@babel/types" "^7.10.5" + jsesc "^2.5.1" + source-map "^0.5.0" + "@babel/helper-annotate-as-pure@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.10.4.tgz#5bf0d495a3f757ac3bda48b5bf3b3ba309c72ba3" @@ -256,6 +287,19 @@ "@babel/types" "^7.10.4" lodash "^4.17.13" +"@babel/helper-module-transforms@^7.10.5": + version "7.10.5" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.10.5.tgz#120c271c0b3353673fcdfd8c053db3c544a260d6" + integrity sha512-4P+CWMJ6/j1W915ITJaUkadLObmCRRSC234uctJfn/vHrsLNxsR8dwlcXv9ZhJWzl77awf+mWXSZEKt5t0OnlA== + dependencies: + "@babel/helper-module-imports" "^7.10.4" + "@babel/helper-replace-supers" "^7.10.4" + "@babel/helper-simple-access" "^7.10.4" + "@babel/helper-split-export-declaration" "^7.10.4" + "@babel/template" "^7.10.4" + "@babel/types" "^7.10.5" + lodash "^4.17.19" + "@babel/helper-optimise-call-expression@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.10.4.tgz#50dc96413d594f995a77905905b05893cd779673" @@ -349,6 +393,11 @@ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.10.4.tgz#9eedf27e1998d87739fb5028a5120557c06a1a64" integrity sha512-8jHII4hf+YVDsskTF6WuMB3X4Eh+PsUkC2ljq22so5rHvH+T8BzyL94VOdyFLNR8tBSVXOTbNHOKpR4TfRxVtA== +"@babel/parser@^7.10.5": + version "7.10.5" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.10.5.tgz#e7c6bf5a7deff957cec9f04b551e2762909d826b" + integrity sha512-wfryxy4bE1UivvQKSQDU4/X6dr+i8bctjUjj8Zyt3DQy7NtPizJXT8M52nqpNKL+nq2PW8lxk4ZqLj0fD4B4hQ== + "@babel/plugin-proposal-async-generator-functions@^7.10.4", "@babel/plugin-proposal-async-generator-functions@^7.2.0", "@babel/plugin-proposal-async-generator-functions@^7.8.3": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.10.4.tgz#4b65abb3d9bacc6c657aaa413e56696f9f170fc6" @@ -358,6 +407,14 @@ "@babel/helper-remap-async-to-generator" "^7.10.4" "@babel/plugin-syntax-async-generators" "^7.8.0" +"@babel/plugin-proposal-class-properties@7.10.4", "@babel/plugin-proposal-class-properties@^7.1.0", "@babel/plugin-proposal-class-properties@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.10.4.tgz#a33bf632da390a59c7a8c570045d1115cd778807" + integrity sha512-vhwkEROxzcHGNu2mzUC0OFFNXdZ4M23ib8aRRcJSsW8BZK9pQMD7QB7csl97NBbgGZO7ZyHUyKDnxzOaP4IrCg== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.10.4" + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-proposal-class-properties@7.3.0": version "7.3.0" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.3.0.tgz#272636bc0fa19a0bc46e601ec78136a173ea36cd" @@ -374,14 +431,6 @@ "@babel/helper-create-class-features-plugin" "^7.8.3" "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-proposal-class-properties@^7.1.0", "@babel/plugin-proposal-class-properties@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.10.4.tgz#a33bf632da390a59c7a8c570045d1115cd778807" - integrity sha512-vhwkEROxzcHGNu2mzUC0OFFNXdZ4M23ib8aRRcJSsW8BZK9pQMD7QB7csl97NBbgGZO7ZyHUyKDnxzOaP4IrCg== - dependencies: - "@babel/helper-create-class-features-plugin" "^7.10.4" - "@babel/helper-plugin-utils" "^7.10.4" - "@babel/plugin-proposal-decorators@7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.8.3.tgz#2156860ab65c5abf068c3f67042184041066543e" @@ -423,6 +472,15 @@ "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-numeric-separator" "^7.10.4" +"@babel/plugin-proposal-object-rest-spread@7.10.4", "@babel/plugin-proposal-object-rest-spread@^7.0.0", "@babel/plugin-proposal-object-rest-spread@^7.10.4", "@babel/plugin-proposal-object-rest-spread@^7.4.4", "@babel/plugin-proposal-object-rest-spread@^7.9.0", "@babel/plugin-proposal-object-rest-spread@^7.9.5": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.10.4.tgz#50129ac216b9a6a55b3853fdd923e74bf553a4c0" + integrity sha512-6vh4SqRuLLarjgeOf4EaROJAHjvu9Gl+/346PbDH9yWbJyfnJ/ah3jmYKYtswEyCoWZiidvVHjHshd4WgjB9BA== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-syntax-object-rest-spread" "^7.8.0" + "@babel/plugin-transform-parameters" "^7.10.4" + "@babel/plugin-proposal-object-rest-spread@7.3.2": version "7.3.2" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.3.2.tgz#6d1859882d4d778578e41f82cc5d7bf3d5daf6c1" @@ -439,15 +497,6 @@ "@babel/helper-plugin-utils" "^7.8.3" "@babel/plugin-syntax-object-rest-spread" "^7.8.0" -"@babel/plugin-proposal-object-rest-spread@^7.0.0", "@babel/plugin-proposal-object-rest-spread@^7.10.4", "@babel/plugin-proposal-object-rest-spread@^7.4.4", "@babel/plugin-proposal-object-rest-spread@^7.9.0", "@babel/plugin-proposal-object-rest-spread@^7.9.5": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.10.4.tgz#50129ac216b9a6a55b3853fdd923e74bf553a4c0" - integrity sha512-6vh4SqRuLLarjgeOf4EaROJAHjvu9Gl+/346PbDH9yWbJyfnJ/ah3jmYKYtswEyCoWZiidvVHjHshd4WgjB9BA== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - "@babel/plugin-syntax-object-rest-spread" "^7.8.0" - "@babel/plugin-transform-parameters" "^7.10.4" - "@babel/plugin-proposal-optional-catch-binding@^7.10.4", "@babel/plugin-proposal-optional-catch-binding@^7.2.0", "@babel/plugin-proposal-optional-catch-binding@^7.8.3": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.10.4.tgz#31c938309d24a78a49d68fdabffaa863758554dd" @@ -781,14 +830,14 @@ dependencies: "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-transform-react-display-name@^7.0.0", "@babel/plugin-transform-react-display-name@^7.8.3": +"@babel/plugin-transform-react-display-name@^7.0.0", "@babel/plugin-transform-react-display-name@^7.10.4", "@babel/plugin-transform-react-display-name@^7.8.3": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.10.4.tgz#b5795f4e3e3140419c3611b7a2a3832b9aef328d" integrity sha512-Zd4X54Mu9SBfPGnEcaGcOrVAYOtjT2on8QZkLKEq1S/tHexG39d9XXGZv19VfRrDjPJzFmPfTAqOQS1pfFOujw== dependencies: "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-transform-react-jsx-development@^7.9.0": +"@babel/plugin-transform-react-jsx-development@^7.10.4", "@babel/plugin-transform-react-jsx-development@^7.9.0": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.10.4.tgz#6ec90f244394604623880e15ebc3c34c356258ba" integrity sha512-RM3ZAd1sU1iQ7rI2dhrZRZGv0aqzNQMbkIUCS1txYpi9wHQ2ZHNjo5TwX+UD6pvFW4AbWqLVYvKy5qJSAyRGjQ== @@ -797,7 +846,7 @@ "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-jsx" "^7.10.4" -"@babel/plugin-transform-react-jsx-self@^7.0.0", "@babel/plugin-transform-react-jsx-self@^7.9.0": +"@babel/plugin-transform-react-jsx-self@^7.0.0", "@babel/plugin-transform-react-jsx-self@^7.10.4", "@babel/plugin-transform-react-jsx-self@^7.9.0": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.10.4.tgz#cd301a5fed8988c182ed0b9d55e9bd6db0bd9369" integrity sha512-yOvxY2pDiVJi0axdTWHSMi5T0DILN+H+SaeJeACHKjQLezEzhLx9nEF9xgpBLPtkZsks9cnb5P9iBEi21En3gg== @@ -813,7 +862,15 @@ "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-jsx" "^7.10.4" -"@babel/plugin-transform-react-jsx@^7.0.0", "@babel/plugin-transform-react-jsx@^7.9.4": +"@babel/plugin-transform-react-jsx-source@^7.10.4": + version "7.10.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.10.5.tgz#34f1779117520a779c054f2cdd9680435b9222b4" + integrity sha512-wTeqHVkN1lfPLubRiZH3o73f4rfon42HpgxUSs86Nc+8QIcm/B9s8NNVXu/gwGcOyd7yDib9ikxoDLxJP0UiDA== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-syntax-jsx" "^7.10.4" + +"@babel/plugin-transform-react-jsx@^7.0.0", "@babel/plugin-transform-react-jsx@^7.10.4", "@babel/plugin-transform-react-jsx@^7.9.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.10.4.tgz#673c9f913948764a4421683b2bef2936968fddf2" integrity sha512-L+MfRhWjX0eI7Js093MM6MacKU4M6dnCRa/QPDwYMxjljzSCzzlzKzj9Pk4P3OtrPcxr2N3znR419nr3Xw+65A== @@ -823,6 +880,14 @@ "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-jsx" "^7.10.4" +"@babel/plugin-transform-react-pure-annotations@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.10.4.tgz#3eefbb73db94afbc075f097523e445354a1c6501" + integrity sha512-+njZkqcOuS8RaPakrnR9KvxjoG1ASJWpoIv/doyWngId88JoFlPlISenGXjrVacZUIALGUr6eodRs1vmPnF23A== + dependencies: + "@babel/helper-annotate-as-pure" "^7.10.4" + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-transform-regenerator@^7.10.4", "@babel/plugin-transform-regenerator@^7.4.5", "@babel/plugin-transform-regenerator@^7.8.7": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.10.4.tgz#2015e59d839074e76838de2159db421966fd8b63" @@ -837,6 +902,16 @@ dependencies: "@babel/helper-plugin-utils" "^7.10.4" +"@babel/plugin-transform-runtime@7.10.5": + version "7.10.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.10.5.tgz#3b39b7b24830e0c2d8ff7a4489fe5cf99fbace86" + integrity sha512-tV4V/FjElJ9lQtyjr5xD2IFFbgY46r7EeVu5a8CpEKT5laheHKSlFeHjpkPppW3PqzGLAuv5k2qZX5LgVZIX5w== + dependencies: + "@babel/helper-module-imports" "^7.10.4" + "@babel/helper-plugin-utils" "^7.10.4" + resolve "^1.8.1" + semver "^5.5.1" + "@babel/plugin-transform-runtime@7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.2.0.tgz#566bc43f7d0aedc880eaddbd29168d0f248966ea" @@ -847,23 +922,20 @@ resolve "^1.8.1" semver "^5.5.1" -"@babel/plugin-transform-runtime@7.9.0": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.9.0.tgz#45468c0ae74cc13204e1d3b1f4ce6ee83258af0b" - integrity sha512-pUu9VSf3kI1OqbWINQ7MaugnitRss1z533436waNXp+0N3ur3zfut37sXiQMxkuCF4VUjwZucen/quskCh7NHw== - dependencies: - "@babel/helper-module-imports" "^7.8.3" - "@babel/helper-plugin-utils" "^7.8.3" - resolve "^1.8.1" - semver "^5.5.1" - -"@babel/plugin-transform-shorthand-properties@^7.10.4", "@babel/plugin-transform-shorthand-properties@^7.2.0", "@babel/plugin-transform-shorthand-properties@^7.8.3": +"@babel/plugin-transform-shorthand-properties@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.10.4.tgz#9fd25ec5cdd555bb7f473e5e6ee1c971eede4dd6" integrity sha512-AC2K/t7o07KeTIxMoHneyX90v3zkm5cjHJEokrPEAGEy3UCp8sLKfnfOIGdZ194fyN4wfX/zZUWT9trJZ0qc+Q== dependencies: "@babel/helper-plugin-utils" "^7.10.4" +"@babel/plugin-transform-shorthand-properties@^7.2.0", "@babel/plugin-transform-shorthand-properties@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.8.3.tgz#28545216e023a832d4d3a1185ed492bcfeac08c8" + integrity sha512-I9DI6Odg0JJwxCHzbzW08ggMdCezoWcuQRz3ptdudgwaHxTjxw5HgdFJmZIkIMlRymL6YiZcped4TTCB0JcC8w== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-transform-spread@^7.10.4", "@babel/plugin-transform-spread@^7.2.0", "@babel/plugin-transform-spread@^7.8.3": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.10.4.tgz#4e2c85ea0d6abaee1b24dcfbbae426fe8d674cff" @@ -926,6 +998,76 @@ core-js "^2.6.5" regenerator-runtime "^0.13.4" +"@babel/preset-env@7.10.4", "@babel/preset-env@^7.1.6": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.10.4.tgz#fbf57f9a803afd97f4f32e4f798bb62e4b2bef5f" + integrity sha512-tcmuQ6vupfMZPrLrc38d0sF2OjLT3/bZ0dry5HchNCQbrokoQi4reXqclvkkAT5b+gWc23meVWpve5P/7+w/zw== + dependencies: + "@babel/compat-data" "^7.10.4" + "@babel/helper-compilation-targets" "^7.10.4" + "@babel/helper-module-imports" "^7.10.4" + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-proposal-async-generator-functions" "^7.10.4" + "@babel/plugin-proposal-class-properties" "^7.10.4" + "@babel/plugin-proposal-dynamic-import" "^7.10.4" + "@babel/plugin-proposal-json-strings" "^7.10.4" + "@babel/plugin-proposal-nullish-coalescing-operator" "^7.10.4" + "@babel/plugin-proposal-numeric-separator" "^7.10.4" + "@babel/plugin-proposal-object-rest-spread" "^7.10.4" + "@babel/plugin-proposal-optional-catch-binding" "^7.10.4" + "@babel/plugin-proposal-optional-chaining" "^7.10.4" + "@babel/plugin-proposal-private-methods" "^7.10.4" + "@babel/plugin-proposal-unicode-property-regex" "^7.10.4" + "@babel/plugin-syntax-async-generators" "^7.8.0" + "@babel/plugin-syntax-class-properties" "^7.10.4" + "@babel/plugin-syntax-dynamic-import" "^7.8.0" + "@babel/plugin-syntax-json-strings" "^7.8.0" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.0" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" + "@babel/plugin-syntax-object-rest-spread" "^7.8.0" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.0" + "@babel/plugin-syntax-optional-chaining" "^7.8.0" + "@babel/plugin-syntax-top-level-await" "^7.10.4" + "@babel/plugin-transform-arrow-functions" "^7.10.4" + "@babel/plugin-transform-async-to-generator" "^7.10.4" + "@babel/plugin-transform-block-scoped-functions" "^7.10.4" + "@babel/plugin-transform-block-scoping" "^7.10.4" + "@babel/plugin-transform-classes" "^7.10.4" + "@babel/plugin-transform-computed-properties" "^7.10.4" + "@babel/plugin-transform-destructuring" "^7.10.4" + "@babel/plugin-transform-dotall-regex" "^7.10.4" + "@babel/plugin-transform-duplicate-keys" "^7.10.4" + "@babel/plugin-transform-exponentiation-operator" "^7.10.4" + "@babel/plugin-transform-for-of" "^7.10.4" + "@babel/plugin-transform-function-name" "^7.10.4" + "@babel/plugin-transform-literals" "^7.10.4" + "@babel/plugin-transform-member-expression-literals" "^7.10.4" + "@babel/plugin-transform-modules-amd" "^7.10.4" + "@babel/plugin-transform-modules-commonjs" "^7.10.4" + "@babel/plugin-transform-modules-systemjs" "^7.10.4" + "@babel/plugin-transform-modules-umd" "^7.10.4" + "@babel/plugin-transform-named-capturing-groups-regex" "^7.10.4" + "@babel/plugin-transform-new-target" "^7.10.4" + "@babel/plugin-transform-object-super" "^7.10.4" + "@babel/plugin-transform-parameters" "^7.10.4" + "@babel/plugin-transform-property-literals" "^7.10.4" + "@babel/plugin-transform-regenerator" "^7.10.4" + "@babel/plugin-transform-reserved-words" "^7.10.4" + "@babel/plugin-transform-shorthand-properties" "^7.10.4" + "@babel/plugin-transform-spread" "^7.10.4" + "@babel/plugin-transform-sticky-regex" "^7.10.4" + "@babel/plugin-transform-template-literals" "^7.10.4" + "@babel/plugin-transform-typeof-symbol" "^7.10.4" + "@babel/plugin-transform-unicode-escapes" "^7.10.4" + "@babel/plugin-transform-unicode-regex" "^7.10.4" + "@babel/preset-modules" "^0.1.3" + "@babel/types" "^7.10.4" + browserslist "^4.12.0" + core-js-compat "^3.6.2" + invariant "^2.2.2" + levenary "^1.1.1" + semver "^5.5.0" + "@babel/preset-env@7.4.5": version "7.4.5" resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.4.5.tgz#2fad7f62983d5af563b5f3139242755884998a58" @@ -1112,76 +1254,6 @@ levenary "^1.1.1" semver "^5.5.0" -"@babel/preset-env@^7.1.6": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.10.4.tgz#fbf57f9a803afd97f4f32e4f798bb62e4b2bef5f" - integrity sha512-tcmuQ6vupfMZPrLrc38d0sF2OjLT3/bZ0dry5HchNCQbrokoQi4reXqclvkkAT5b+gWc23meVWpve5P/7+w/zw== - dependencies: - "@babel/compat-data" "^7.10.4" - "@babel/helper-compilation-targets" "^7.10.4" - "@babel/helper-module-imports" "^7.10.4" - "@babel/helper-plugin-utils" "^7.10.4" - "@babel/plugin-proposal-async-generator-functions" "^7.10.4" - "@babel/plugin-proposal-class-properties" "^7.10.4" - "@babel/plugin-proposal-dynamic-import" "^7.10.4" - "@babel/plugin-proposal-json-strings" "^7.10.4" - "@babel/plugin-proposal-nullish-coalescing-operator" "^7.10.4" - "@babel/plugin-proposal-numeric-separator" "^7.10.4" - "@babel/plugin-proposal-object-rest-spread" "^7.10.4" - "@babel/plugin-proposal-optional-catch-binding" "^7.10.4" - "@babel/plugin-proposal-optional-chaining" "^7.10.4" - "@babel/plugin-proposal-private-methods" "^7.10.4" - "@babel/plugin-proposal-unicode-property-regex" "^7.10.4" - "@babel/plugin-syntax-async-generators" "^7.8.0" - "@babel/plugin-syntax-class-properties" "^7.10.4" - "@babel/plugin-syntax-dynamic-import" "^7.8.0" - "@babel/plugin-syntax-json-strings" "^7.8.0" - "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.0" - "@babel/plugin-syntax-numeric-separator" "^7.10.4" - "@babel/plugin-syntax-object-rest-spread" "^7.8.0" - "@babel/plugin-syntax-optional-catch-binding" "^7.8.0" - "@babel/plugin-syntax-optional-chaining" "^7.8.0" - "@babel/plugin-syntax-top-level-await" "^7.10.4" - "@babel/plugin-transform-arrow-functions" "^7.10.4" - "@babel/plugin-transform-async-to-generator" "^7.10.4" - "@babel/plugin-transform-block-scoped-functions" "^7.10.4" - "@babel/plugin-transform-block-scoping" "^7.10.4" - "@babel/plugin-transform-classes" "^7.10.4" - "@babel/plugin-transform-computed-properties" "^7.10.4" - "@babel/plugin-transform-destructuring" "^7.10.4" - "@babel/plugin-transform-dotall-regex" "^7.10.4" - "@babel/plugin-transform-duplicate-keys" "^7.10.4" - "@babel/plugin-transform-exponentiation-operator" "^7.10.4" - "@babel/plugin-transform-for-of" "^7.10.4" - "@babel/plugin-transform-function-name" "^7.10.4" - "@babel/plugin-transform-literals" "^7.10.4" - "@babel/plugin-transform-member-expression-literals" "^7.10.4" - "@babel/plugin-transform-modules-amd" "^7.10.4" - "@babel/plugin-transform-modules-commonjs" "^7.10.4" - "@babel/plugin-transform-modules-systemjs" "^7.10.4" - "@babel/plugin-transform-modules-umd" "^7.10.4" - "@babel/plugin-transform-named-capturing-groups-regex" "^7.10.4" - "@babel/plugin-transform-new-target" "^7.10.4" - "@babel/plugin-transform-object-super" "^7.10.4" - "@babel/plugin-transform-parameters" "^7.10.4" - "@babel/plugin-transform-property-literals" "^7.10.4" - "@babel/plugin-transform-regenerator" "^7.10.4" - "@babel/plugin-transform-reserved-words" "^7.10.4" - "@babel/plugin-transform-shorthand-properties" "^7.10.4" - "@babel/plugin-transform-spread" "^7.10.4" - "@babel/plugin-transform-sticky-regex" "^7.10.4" - "@babel/plugin-transform-template-literals" "^7.10.4" - "@babel/plugin-transform-typeof-symbol" "^7.10.4" - "@babel/plugin-transform-unicode-escapes" "^7.10.4" - "@babel/plugin-transform-unicode-regex" "^7.10.4" - "@babel/preset-modules" "^0.1.3" - "@babel/types" "^7.10.4" - browserslist "^4.12.0" - core-js-compat "^3.6.2" - invariant "^2.2.2" - levenary "^1.1.1" - semver "^5.5.0" - "@babel/preset-flow@^7.0.0": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/preset-flow/-/preset-flow-7.10.4.tgz#e0d9c72f8cb02d1633f6a5b7b16763aa2edf659f" @@ -1212,6 +1284,19 @@ "@babel/plugin-transform-react-jsx-self" "^7.0.0" "@babel/plugin-transform-react-jsx-source" "^7.0.0" +"@babel/preset-react@7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/preset-react/-/preset-react-7.10.4.tgz#92e8a66d816f9911d11d4cc935be67adfc82dbcf" + integrity sha512-BrHp4TgOIy4M19JAfO1LhycVXOPWdDbTRep7eVyatf174Hff+6Uk53sDyajqZPu8W1qXRBiYOfIamek6jA7YVw== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-transform-react-display-name" "^7.10.4" + "@babel/plugin-transform-react-jsx" "^7.10.4" + "@babel/plugin-transform-react-jsx-development" "^7.10.4" + "@babel/plugin-transform-react-jsx-self" "^7.10.4" + "@babel/plugin-transform-react-jsx-source" "^7.10.4" + "@babel/plugin-transform-react-pure-annotations" "^7.10.4" + "@babel/preset-react@7.9.4": version "7.9.4" resolved "https://registry.yarnpkg.com/@babel/preset-react/-/preset-react-7.9.4.tgz#c6c97693ac65b6b9c0b4f25b948a8f665463014d" @@ -1262,6 +1347,13 @@ pirates "^4.0.0" source-map-support "^0.5.16" +"@babel/runtime@7.10.5", "@babel/runtime@^7.10.2": + version "7.10.5" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.10.5.tgz#303d8bd440ecd5a491eae6117fd3367698674c5c" + integrity sha512-otddXKhdNn7d0ptoFRHtMLa8LqDxLYwTjB4nYgM1yy5N6gU/MUf8zqyyLltCH3yAVitBzmwK4us+DD0l/MauAg== + dependencies: + regenerator-runtime "^0.13.4" + "@babel/runtime@7.3.1": version "7.3.1" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.3.1.tgz#574b03e8e8a9898eaf4a872a92ea20b7846f6f2a" @@ -1269,17 +1361,10 @@ dependencies: regenerator-runtime "^0.12.0" -"@babel/runtime@7.9.2": - version "7.9.2" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.9.2.tgz#d90df0583a3a252f09aaa619665367bae518db06" - integrity sha512-NE2DtOdufG7R5vnfQUTehdTfNycfUANEtCa9PssN9O/xmTzP4E08UI797ixaei6hBEVL9BI/PsdJS5x7mWoB9Q== - dependencies: - regenerator-runtime "^0.13.4" - -"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.4.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.10.4.tgz#a6724f1a6b8d2f6ea5236dbfe58c7d7ea9c5eb99" - integrity sha512-UpTN5yUJr9b4EX2CnGNWIvER7Ab83ibv0pcvvHc4UOdrBI5jb8bj+32cCwPX6xu0mt2daFNjYhoi+X7beH0RSw== +"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.4.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7": + version "7.9.6" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.9.6.tgz#a9102eb5cadedf3f31d08a9ecf294af7827ea29f" + integrity sha512-64AF1xY3OAkFHqOb9s4jpgk1Mm5vDZ4L3acHvAml+53nO1XbXLuDodsVpO4OIUsmemlUHMxNdYMNJmsvOwLrvQ== dependencies: regenerator-runtime "^0.13.4" @@ -1307,6 +1392,21 @@ globals "^11.1.0" lodash "^4.17.13" +"@babel/traverse@^7.10.5": + version "7.10.5" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.10.5.tgz#77ce464f5b258be265af618d8fddf0536f20b564" + integrity sha512-yc/fyv2gUjPqzTz0WHeRJH2pv7jA9kA7mBX2tXl/x5iOE81uaVPuGPtaYk7wmkx4b67mQ7NqI8rmT2pF47KYKQ== + dependencies: + "@babel/code-frame" "^7.10.4" + "@babel/generator" "^7.10.5" + "@babel/helper-function-name" "^7.10.4" + "@babel/helper-split-export-declaration" "^7.10.4" + "@babel/parser" "^7.10.5" + "@babel/types" "^7.10.5" + debug "^4.1.0" + globals "^11.1.0" + lodash "^4.17.19" + "@babel/types@^7.0.0", "@babel/types@^7.10.4", "@babel/types@^7.3.0", "@babel/types@^7.4.0", "@babel/types@^7.4.4", "@babel/types@^7.6.1", "@babel/types@^7.7.0", "@babel/types@^7.9.0", "@babel/types@^7.9.5": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.10.4.tgz#369517188352e18219981efd156bfdb199fff1ee" @@ -1316,6 +1416,15 @@ lodash "^4.17.13" to-fast-properties "^2.0.0" +"@babel/types@^7.10.5": + version "7.10.5" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.10.5.tgz#d88ae7e2fde86bfbfe851d4d81afa70a997b5d15" + integrity sha512-ixV66KWfCI6GKoA/2H9v6bQdbfXEwwpOdQ8cRvb4F+eyvhlaHxWFMQB4+3d9QFJXZsiiiqVrewNV0DFEQpyT4Q== + dependencies: + "@babel/helper-validator-identifier" "^7.10.4" + lodash "^4.17.19" + to-fast-properties "^2.0.0" + "@bahmutov/all-paths@1.0.2": version "1.0.2" resolved "https://registry.yarnpkg.com/@bahmutov/all-paths/-/all-paths-1.0.2.tgz#9ae0dcdf9022dd6e5e14d7fda3479e6a330d035b" @@ -1391,30 +1500,6 @@ resolved "https://registry.yarnpkg.com/@cypress/bower-kendo-ui/-/bower-kendo-ui-0.0.2.tgz#62ea93d7f0653c0b91a7a4e5e9ede9d26d5990ea" integrity sha1-YuqT1/BlPAuRp6Tl6e3p0m1ZkOo= -"@cypress/browserify-preprocessor@2.2.4": - version "2.2.4" - resolved "https://registry.yarnpkg.com/@cypress/browserify-preprocessor/-/browserify-preprocessor-2.2.4.tgz#a2ff5a6a06938f7f1e78eb6de0e492641cf8561c" - integrity sha512-kMjkIFe6qka8Tkm9N3BrMB+Nn7WEAHIzEd3gfVoDL17Tr40xyOnKGuMhEkff1scd3RV3bjQxwQ9BQ6kI2nToAQ== - dependencies: - "@babel/core" "7.4.5" - "@babel/plugin-proposal-class-properties" "7.3.0" - "@babel/plugin-proposal-object-rest-spread" "7.3.2" - "@babel/plugin-transform-runtime" "7.2.0" - "@babel/preset-env" "7.4.5" - "@babel/preset-react" "7.0.0" - "@babel/runtime" "7.3.1" - babel-plugin-add-module-exports "1.0.2" - babelify "10.0.0" - bluebird "3.5.3" - browserify "16.2.3" - coffeeify "3.0.1" - coffeescript "1.12.7" - debug "4.1.1" - fs-extra "7.0.1" - lodash.clonedeep "4.5.0" - through2 "^2.0.0" - watchify "3.11.1" - "@cypress/browserify-preprocessor@3.0.0": version "3.0.0" resolved "https://registry.yarnpkg.com/@cypress/browserify-preprocessor/-/browserify-preprocessor-3.0.0.tgz#2d1fa6a96ed7130a1b172c540448a5955cbc1264" @@ -1564,6 +1649,16 @@ lodash.merge "^4.6.2" lodash.omit "^4.5.0" +"@cypress/json-schemas@5.35.0": + version "5.35.0" + resolved "https://registry.yarnpkg.com/@cypress/json-schemas/-/json-schemas-5.35.0.tgz#9a699f680a7c58809f743b951f02107fd7b29b80" + integrity sha512-EyCPTw9k3fOkDu1n3zWwRdIGQp6ehZRbCNwYCFtFXxgXW1IK/jTO6ese1mDAIjcfQgLOpBKnj77+ahIC093p7w== + dependencies: + "@cypress/schema-tools" "4.7.4" + lodash.clonedeep "^4.5.0" + lodash.merge "^4.6.2" + lodash.omit "^4.5.0" + "@cypress/listr-verbose-renderer@^0.4.1": version "0.4.1" resolved "https://registry.yarnpkg.com/@cypress/listr-verbose-renderer/-/listr-verbose-renderer-0.4.1.tgz#a77492f4b11dcc7c446a34b3e28721afd33c642a" @@ -1689,6 +1784,27 @@ dependencies: css.escape "^1.5.1" +"@cypress/webpack-batteries-included-preprocessor@2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@cypress/webpack-batteries-included-preprocessor/-/webpack-batteries-included-preprocessor-2.0.0.tgz#b64883e0bd6fcb5433211a547179a76581e45cb3" + integrity sha512-0LNQ7bhKVDDTF/P5FIP7FQrEbiRSwcWv4Qur7fEQoSHs+06pu0HYtNhIT83nG1X2BCIRmIqGvZGiuJ4ABZrT0w== + dependencies: + "@babel/core" "7.10.5" + "@babel/plugin-proposal-class-properties" "7.10.4" + "@babel/plugin-proposal-object-rest-spread" "7.10.4" + "@babel/plugin-transform-runtime" "7.10.5" + "@babel/preset-env" "7.10.4" + "@babel/preset-react" "7.10.4" + "@babel/runtime" "7.10.5" + babel-loader "8.1.0" + babel-plugin-add-module-exports "1.0.2" + coffee-loader "0.9.0" + coffeescript "1.12.7" + ts-loader "8.0.1" + tsconfig "7.0.0" + tsconfig-paths-webpack-plugin "3.2.0" + webpack "4.43.0" + "@cypress/webpack-preprocessor@5.4.1": version "5.4.1" resolved "https://registry.yarnpkg.com/@cypress/webpack-preprocessor/-/webpack-preprocessor-5.4.1.tgz#eb58f6cd02932a95653c1a674cfd769da2409806" @@ -1707,6 +1823,15 @@ debug "4.1.1" lodash "4.17.19" +"@cypress/webpack-preprocessor@5.4.4": + version "5.4.4" + resolved "https://registry.yarnpkg.com/@cypress/webpack-preprocessor/-/webpack-preprocessor-5.4.4.tgz#20adaa338799485aeb67227a9784991c420acd31" + integrity sha512-aNOS4J7vilVO6CgzYUnMCraZTCF+SvQtGTlG0HKdqbpI4+dzCWGRFpwpqiSsCb83m+WAP2gfuGQVaFTCM43JcA== + dependencies: + bluebird "3.7.1" + debug "4.1.1" + lodash "4.17.19" + "@cypress/what-is-circular@1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@cypress/what-is-circular/-/what-is-circular-1.0.1.tgz#c88adb7106a4e1624e403512fc87c18e9700c877" @@ -3630,6 +3755,11 @@ resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.7.0.tgz#9a06f4f137ee84d7df0460c1fdb1135ffa6c50fd" integrity sha512-ONhaKPIufzzrlNbqtWFFd+jlnemX6lJAgq9ZeiZtS7I1PIf/la7CW4m83rTXRnVnsMbW2k56pGYu7AUFJD9Pow== +"@sindresorhus/is@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-3.0.0.tgz#78fabc5e295adb6e1ef57eaafe4cc5d7aa35b183" + integrity sha512-kqA5I6Yun7PBHk8WN9BBP1c7FfN2SrD05GuVSEYPqDb4nerv7HqYfgBfMIKmT/EuejURkJKLZuLyGKGs6WEG9w== + "@sinonjs/commons@^1", "@sinonjs/commons@^1.2.0", "@sinonjs/commons@^1.3.0", "@sinonjs/commons@^1.4.0", "@sinonjs/commons@^1.6.0", "@sinonjs/commons@^1.7.0", "@sinonjs/commons@^1.7.2": version "1.8.0" resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.0.tgz#c8d68821a854c555bba172f3b06959a0039b236d" @@ -3714,6 +3844,13 @@ dependencies: defer-to-connect "^1.0.1" +"@szmarczak/http-timer@^4.0.5": + version "4.0.5" + resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-4.0.5.tgz#bfbd50211e9dfa51ba07da58a14cdfd333205152" + integrity sha512-PyRA9sm1Yayuj5OIoJ1hGt2YISX45w9WcFbh6ddT0Z/0yaFxOtGLInr4jUfU1EAFVs0Yfyfev4RNwBlUaHdlDQ== + dependencies: + defer-to-connect "^2.0.0" + "@types/anymatch@*": version "1.3.1" resolved "https://registry.yarnpkg.com/@types/anymatch/-/anymatch-1.3.1.tgz#336badc1beecb9dacc38bea2cf32adf627a8421a" @@ -3752,11 +3889,6 @@ dependencies: "@babel/types" "^7.3.0" -"@types/blob-util@1.3.3": - version "1.3.3" - resolved "https://registry.yarnpkg.com/@types/blob-util/-/blob-util-1.3.3.tgz#adba644ae34f88e1dd9a5864c66ad651caaf628a" - integrity sha512-4ahcL/QDnpjWA2Qs16ZMQif7HjGP2cw3AGjHabybjw7Vm1EKu+cfQN1D78BaZbS1WJNa1opSMF5HNMztx7lR0w== - "@types/bluebird@*": version "3.5.32" resolved "https://registry.yarnpkg.com/@types/bluebird/-/bluebird-3.5.32.tgz#381e7b59e39f010d20bbf7e044e48f5caf1ab620" @@ -3775,6 +3907,16 @@ "@types/connect" "*" "@types/node" "*" +"@types/cacheable-request@^6.0.1": + version "6.0.1" + resolved "https://registry.yarnpkg.com/@types/cacheable-request/-/cacheable-request-6.0.1.tgz#5d22f3dded1fd3a84c0bbeb5039a7419c2c91976" + integrity sha512-ykFq2zmBGOCbpIXtoVbz4SKY5QriWPh3AjyU4G74RYbtt5yOc5OfaY75ftjg7mikMOla1CTGpX3lLbuJh8DTrQ== + dependencies: + "@types/http-cache-semantics" "*" + "@types/keyv" "*" + "@types/node" "*" + "@types/responselike" "*" + "@types/caseless@*": version "0.12.2" resolved "https://registry.yarnpkg.com/@types/caseless/-/caseless-0.12.2.tgz#f65d3d6389e01eeb458bd54dc8f52b95a9463bc8" @@ -3815,6 +3957,13 @@ resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.2.7.tgz#1c8c25cbf6e59ffa7d6b9652c78e547d9a41692d" integrity sha512-luq8meHGYwvky0O7u0eQZdA7B4Wd9owUCqvbw2m3XCrCU8mplYOujMBbvyS547AxJkC+pGnd0Cm15eNxEUNU8g== +"@types/chalk@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@types/chalk/-/chalk-2.2.0.tgz#b7f6e446f4511029ee8e3f43075fb5b73fbaa0ba" + integrity sha512-1zzPV9FDe1I/WHhRkf9SNgqtRJWZqrBWgu7JGveuHmmyR9CnAPCie2N/x+iHrgnpYBIcCJWHBoMRv2TRWktsvw== + dependencies: + chalk "*" + "@types/cheerio@*": version "0.22.21" resolved "https://registry.yarnpkg.com/@types/cheerio/-/cheerio-0.22.21.tgz#5e37887de309ba11b2e19a6e14cad7874b31a8a3" @@ -3846,6 +3995,11 @@ resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0" integrity sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ== +"@types/common-tags@^1.8.0": + version "1.8.0" + resolved "https://registry.yarnpkg.com/@types/common-tags/-/common-tags-1.8.0.tgz#79d55e748d730b997be5b7fce4b74488d8b26a6b" + integrity sha512-htRqZr5qn8EzMelhX/Xmx142z218lLyGaeZ3YR8jlze4TATRU9huKKvuBmAJEW4LCC4pnY1N6JAm6p85fMHjhg== + "@types/concat-stream@1.6.0": version "1.6.0" resolved "https://registry.yarnpkg.com/@types/concat-stream/-/concat-stream-1.6.0.tgz#394dbe0bb5fee46b38d896735e8b68ef2390d00d" @@ -3944,13 +4098,20 @@ resolved "https://registry.yarnpkg.com/@types/filewriter/-/filewriter-0.0.28.tgz#c054e8af4d9dd75db4e63abc76f885168714d4b3" integrity sha1-wFTor02d11205jq8dviFFocU1LM= -"@types/fs-extra@^8.0.1", "@types/fs-extra@^8.1.0": +"@types/fs-extra@^8.0.1": version "8.1.1" resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-8.1.1.tgz#1e49f22d09aa46e19b51c0b013cb63d0d923a068" integrity sha512-TcUlBem321DFQzBNuz8p0CLLKp0VvF/XH9E4KHNmgwyp4E3AfgI5cjiIVZWlbfThBop2qxFIh4+LeY6hVWWZ2w== dependencies: "@types/node" "*" +"@types/fs-extra@^9.0.1": + version "9.0.1" + resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-9.0.1.tgz#91c8fc4c51f6d5dbe44c2ca9ab09310bd00c7918" + integrity sha512-B42Sxuaz09MhC3DDeW5kubRcQ5by4iuVQ0cRRWM2lggLzAa/KVom0Aft/208NgMvNQQZ86s5rVcqDdn/SH0/mg== + dependencies: + "@types/node" "*" + "@types/glob@7.1.1": version "7.1.1" resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.1.tgz#aa59a1c6e3fbc421e07ccd31a944c30eba521575" @@ -3986,6 +4147,11 @@ "@types/tapable" "*" "@types/webpack" "*" +"@types/http-cache-semantics@*": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@types/http-cache-semantics/-/http-cache-semantics-4.0.0.tgz#9140779736aa2655635ee756e2467d787cfe8a2a" + integrity sha512-c3Xy026kOF7QOTn00hbIllV1dLR9hG9NkSrLQgCVs8NF6sBU+VGWjD3wLPhmh1TYAc7ugCFsvHYMN4VcBN1U1A== + "@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0": version "2.0.3" resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz#4ba8ddb720221f432e443bd5f9117fd22cfd4762" @@ -4034,12 +4200,24 @@ resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.5.tgz#dcce4430e64b443ba8945f0290fb564ad5bac6dd" integrity sha512-7+2BITlgjgDhH0vvwZU/HZJVyk+2XUlvxXe8dFMedNX/aMkaOq++rMAFXc0tM7ij15QaWlbdQASBR9dihi+bDQ== +"@types/json5@^0.0.29": + version "0.0.29" + resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" + integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4= + +"@types/keyv@*": + version "3.1.1" + resolved "https://registry.yarnpkg.com/@types/keyv/-/keyv-3.1.1.tgz#e45a45324fca9dab716ab1230ee249c9fb52cfa7" + integrity sha512-MPtoySlAZQ37VoLaPcTHCu1RWJ4llDkULYZIzOYxlhxBqYPB0RsRlmMU0R6tahtFe27mIdkHV+551ZWV4PLmVw== + dependencies: + "@types/node" "*" + "@types/linkify-it@*": version "2.1.0" resolved "https://registry.yarnpkg.com/@types/linkify-it/-/linkify-it-2.1.0.tgz#ea3dd64c4805597311790b61e872cbd1ed2cd806" integrity sha512-Q7DYAOi9O/+cLLhdaSvKdaumWyHbm7HAk/bFwwyTuU0arR5yyCeW5GOoqt4tJTpDRxhpx9Q8kQL6vMpuw9hDSw== -"@types/lodash@4.14.149": +"@types/lodash@4.14.149", "@types/lodash@^4.14.123": version "4.14.149" resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.149.tgz#1342d63d948c6062838fbf961012f74d4e638440" integrity sha512-ijGqzZt/b7BfzcK9vTrS6MFljQRPn5BFWOx8oE0GYxribu6uV+aA9zZuXI1zc/etK9E8nrgdoF2+LgUw7+9tJQ== @@ -4078,7 +4256,7 @@ resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.0.tgz#69a23a3ad29caf0097f06eda59b361ee2f0639f6" integrity sha1-aaI6OtKcrwCX8G7aWbNh7i8GOfY= -"@types/mocha@5.2.7": +"@types/mocha@5.2.7", "@types/mocha@^5.2.6": version "5.2.7" resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-5.2.7.tgz#315d570ccb56c53452ff8638738df60726d5b6ea" integrity sha512-NYrtPht0wGzhwe9+/idPaBB+TqkY9AhTvOLMkThm0IoEfLaiVQZwBwyJ5puCkO3AUCWrmcoePjp2mbFocKy4SQ== @@ -4203,6 +4381,13 @@ "@types/tough-cookie" "*" form-data "^2.5.0" +"@types/responselike@*", "@types/responselike@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@types/responselike/-/responselike-1.0.0.tgz#251f4fe7d154d2bad125abe1b429b23afd262e29" + integrity sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA== + dependencies: + "@types/node" "*" + "@types/serve-static@*": version "1.13.4" resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.13.4.tgz#6662a93583e5a6cabca1b23592eb91e12fa80e7c" @@ -4251,6 +4436,16 @@ resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-1.0.1.tgz#0a851d3bd96498fa25c33ab7278ed3bd65f06c3e" integrity sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw== +"@types/strip-bom@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@types/strip-bom/-/strip-bom-3.0.0.tgz#14a8ec3956c2e81edb7520790aecf21c290aebd2" + integrity sha1-FKjsOVbC6B7bdSB5CuzyHCkK69I= + +"@types/strip-json-comments@0.0.30": + version "0.0.30" + resolved "https://registry.yarnpkg.com/@types/strip-json-comments/-/strip-json-comments-0.0.30.tgz#9aa30c04db212a9a0649d6ae6fd50accc40748a1" + integrity sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ== + "@types/tapable@*": version "1.0.6" resolved "https://registry.yarnpkg.com/@types/tapable/-/tapable-1.0.6.tgz#a9ca4b70a18b270ccb2bc0aaafefd1d486b7ea74" @@ -5083,7 +5278,7 @@ any-observable@^0.3.0: resolved "https://registry.yarnpkg.com/any-observable/-/any-observable-0.3.0.tgz#af933475e5806a67d0d7df090dd5e8bef65d119b" integrity sha512-/FQM1EDkTsf63Ub2C6O7GuYFDsSXUwsaZDurV0np41ocwq0jthUAYCmhBX9f+KwlaCgIuWyr/4WlUQUBfKfZog== -any-promise@^1.0.0, any-promise@^1.1.0: +any-promise@^1.0.0: version "1.3.0" resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" integrity sha1-q8av7tzqUugJzcA3au0845Y10X8= @@ -5109,26 +5304,26 @@ app-builder-bin@3.5.9: resolved "https://registry.yarnpkg.com/app-builder-bin/-/app-builder-bin-3.5.9.tgz#a3ac0c25286bac68357321cb2eaf7128b0bc0a4f" integrity sha512-NSjtqZ3x2kYiDp3Qezsgukx/AUzKPr3Xgf9by4cYt05ILWGAptepeeu0Uv+7MO+41o6ujhLixTou8979JGg2Kg== -app-builder-lib@22.6.1: - version "22.6.1" - resolved "https://registry.yarnpkg.com/app-builder-lib/-/app-builder-lib-22.6.1.tgz#f17bfbde1bbb26ae438e450b66005bf6714feb30" - integrity sha512-ENL7r+H7IBfDb4faeLASgndsXrAT7AV7m7yJjcpbFDXYma6an7ZWGFIvR0HJrsfiC5TIB8kdLJ/aMSImrrSi/Q== +app-builder-lib@22.8.0: + version "22.8.0" + resolved "https://registry.yarnpkg.com/app-builder-lib/-/app-builder-lib-22.8.0.tgz#342a8976f50ae35cfd07412dbfd4f6c895b32eac" + integrity sha512-RGaIRjCUrqkmh6QOGsyekQPEOaVynHfmeh8JZuyUymFYUOFdzBbPamkA2nhBVBTkkgfjRHsxK7LhedFKPzvWEQ== dependencies: "7zip-bin" "~5.0.3" "@develar/schema-utils" "~2.6.5" async-exit-hook "^2.0.1" bluebird-lst "^1.0.9" - builder-util "22.6.1" - builder-util-runtime "8.7.0" + builder-util "22.8.0" + builder-util-runtime "8.7.2" chromium-pickle-js "^0.2.0" debug "^4.1.1" - ejs "^3.1.2" - electron-publish "22.6.1" - fs-extra "^9.0.0" - hosted-git-info "^3.0.4" + ejs "^3.1.3" + electron-publish "22.8.0" + fs-extra "^9.0.1" + hosted-git-info "^3.0.5" is-ci "^2.0.0" isbinaryfile "^4.0.6" - js-yaml "^3.13.1" + js-yaml "^3.14.0" lazy-val "^1.0.4" minimatch "^3.0.4" normalize-package-data "^2.5.0" @@ -6907,18 +7102,10 @@ black-hole-stream@0.0.1: resolved "https://registry.yarnpkg.com/black-hole-stream/-/black-hole-stream-0.0.1.tgz#33b7a06b9f1e7453d6041b82974481d2152aea42" integrity sha1-M7ega58edFPWBBuCl0SB0hUq6kI= -blob-util@1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/blob-util/-/blob-util-1.3.0.tgz#dbb4e8caffd50b5720d347e1169b6369ba34fe95" - integrity sha512-cjmYgWj8BQwoX+95rKkWvITL6PiEhSr19sX8qLRu+O6J2qmWmgUvxqhqJn425RFAwLovdDNnsCQ64RRHXjsXSg== - dependencies: - blob "0.0.4" - native-or-lie "1.0.2" - -blob@0.0.4: - version "0.0.4" - resolved "https://registry.yarnpkg.com/blob/-/blob-0.0.4.tgz#bcf13052ca54463f30f9fc7e95b9a47630a94921" - integrity sha1-vPEwUspURj8w+fx+lbmkdjCpSSE= +blob-util@2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/blob-util/-/blob-util-2.0.2.tgz#3b4e3c281111bb7f11128518006cdc60b403a1eb" + integrity sha512-T7JQa+zsXXEa6/8ZhHcQEW1UFfVM49Ts65uBkFL6fz2QmrElqmbajIDJvuA0tEhRe5eIjpV9ZF+0RfZR9voJFQ== blob@0.0.5: version "0.0.5" @@ -6979,11 +7166,6 @@ bluebird@^2.9.30, bluebird@^2.9.33: resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-2.11.0.tgz#534b9033c022c9579c56ba3b3e5a5caafbb650e1" integrity sha1-U0uQM8AiyVecVro7Plpcqvu2UOE= -bluebird@~3.0.6: - version "3.0.6" - resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.0.6.tgz#f2488f325782f66d174842f481992e2faba56f38" - integrity sha1-8kiPMleC9m0XSEL0gZkuL6ulbzg= - blueimp-md5@^2.3.0: version "2.16.0" resolved "https://registry.yarnpkg.com/blueimp-md5/-/blueimp-md5-2.16.0.tgz#9018bb805e4ee05512e0e8cbdb9305eeecbdc87c" @@ -7069,7 +7251,7 @@ bower-config@^1.4.0: untildify "^2.1.0" wordwrap "^0.0.3" -boxen@1.3.0, boxen@^1.2.1: +boxen@1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/boxen/-/boxen-1.3.0.tgz#55c6c39a8ba58d9c61ad22cd877532deb665a20b" integrity sha512-TNPjfTr432qx7yOjQyaXm3dSR0MH9vXp7eT1BFSl/C51g+EFnOR9hTg1IreahGBmDNCehscshe45f+C1TBZbLw== @@ -7511,30 +7693,30 @@ buffer@~5.2.1: base64-js "^1.0.2" ieee754 "^1.1.4" -builder-util-runtime@8.7.0: - version "8.7.0" - resolved "https://registry.yarnpkg.com/builder-util-runtime/-/builder-util-runtime-8.7.0.tgz#e48ad004835c8284662e8eaf47a53468c66e8e8d" - integrity sha512-G1AqqVM2vYTrSFR982c1NNzwXKrGLQjVjaZaWQdn4O6Z3YKjdMDofw88aD9jpyK9ZXkrCxR0tI3Qe9wNbyTlXg== +builder-util-runtime@8.7.2: + version "8.7.2" + resolved "https://registry.yarnpkg.com/builder-util-runtime/-/builder-util-runtime-8.7.2.tgz#d93afc71428a12789b437e13850e1fa7da956d72" + integrity sha512-xBqv+8bg6cfnzAQK1k3OGpfaHg+QkPgIgpEkXNhouZ0WiUkyZCftuRc2LYzQrLucFywpa14Xbc6+hTbpq83yRA== dependencies: debug "^4.1.1" sax "^1.2.4" -builder-util@22.6.1: - version "22.6.1" - resolved "https://registry.yarnpkg.com/builder-util/-/builder-util-22.6.1.tgz#78172c3634da460325277ef798994592e595eff3" - integrity sha512-A9cF+bSHqRTSKIUHEyE92Tl0Uh12N7yZRH9bccIL3gRUwtp6ulF28LsjNIWTSQ1clZo2M895cT5PCrKzjPQFVg== +builder-util@22.8.0: + version "22.8.0" + resolved "https://registry.yarnpkg.com/builder-util/-/builder-util-22.8.0.tgz#01684085d1f2370b1bd182f69cbd007426f63f64" + integrity sha512-H80P1JzVy3TGpi63x81epQDK24XalL034+jAZlrPb5IhLtYmnNNdxCCAVJvg3VjSISd73Y71O+uhqCxWpqbPHw== dependencies: "7zip-bin" "~5.0.3" "@types/debug" "^4.1.5" - "@types/fs-extra" "^8.1.0" + "@types/fs-extra" "^9.0.1" app-builder-bin "3.5.9" bluebird-lst "^1.0.9" - builder-util-runtime "8.7.0" - chalk "^4.0.0" + builder-util-runtime "8.7.2" + chalk "^4.1.0" debug "^4.1.1" - fs-extra "^9.0.0" + fs-extra "^9.0.1" is-ci "^2.0.0" - js-yaml "^3.13.1" + js-yaml "^3.14.0" source-map-support "^0.5.19" stat-mode "^1.0.0" temp-file "^3.3.7" @@ -7637,6 +7819,11 @@ cache-base@^1.0.1: union-value "^1.0.0" unset-value "^1.0.0" +cacheable-lookup@^5.0.3: + version "5.0.3" + resolved "https://registry.yarnpkg.com/cacheable-lookup/-/cacheable-lookup-5.0.3.tgz#049fdc59dffdd4fc285e8f4f82936591bd59fec3" + integrity sha512-W+JBqF9SWe18A72XFzN/V/CULFzPm7sBXzzR6ekkE+3tLG72wFZrBiBZhrZuDoYexop4PHJVdFAKb/Nj9+tm9w== + cacheable-request@^2.1.1: version "2.1.4" resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-2.1.4.tgz#0d808801b6342ad33c91df9d0b44dc09b91e5c3d" @@ -7663,6 +7850,19 @@ cacheable-request@^6.0.0: normalize-url "^4.1.0" responselike "^1.0.2" +cacheable-request@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-7.0.1.tgz#062031c2856232782ed694a257fa35da93942a58" + integrity sha512-lt0mJ6YAnsrBErpTMWeu5kl/tg9xMAWjavYTN6VQXM1A/teBITuNcccXsCxF0tDQQJf9DfAaX5O4e0zp0KlfZw== + dependencies: + clone-response "^1.0.2" + get-stream "^5.1.0" + http-cache-semantics "^4.0.0" + keyv "^4.0.0" + lowercase-keys "^2.0.0" + normalize-url "^4.1.0" + responselike "^2.0.0" + cached-path-relative@^1.0.0, cached-path-relative@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/cached-path-relative/-/cached-path-relative-1.0.2.tgz#a13df4196d26776220cc3356eb147a52dba2c6db" @@ -7810,11 +8010,6 @@ capture-exit@^2.0.0: dependencies: rsvp "^4.8.4" -capture-stack-trace@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/capture-stack-trace/-/capture-stack-trace-1.0.1.tgz#a6c0bbe1f38f3aa0b92238ecb6ff42c344d4135d" - integrity sha512-mYQLZnx5Qt1JgB1WEiMCf2647plpGeQ2NMR/5L0HNZzGQo4fuSPnK+wjfPnKZV0aiJDgzmWqqkV/g7JD+DW0qw== - cardinal@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/cardinal/-/cardinal-2.1.1.tgz#7cc1055d822d212954d07b085dea251cc7bc5505" @@ -7899,6 +8094,14 @@ chai@4.2.0: pathval "^1.1.0" type-detect "^4.0.5" +chalk@*, chalk@^4.0.0, chalk@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.0.tgz#4e14870a618d9e2edd97dd8345fd9d9dc315646a" + integrity sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + chalk@1.x.x, chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" @@ -7936,14 +8139,6 @@ chalk@^3.0.0: ansi-styles "^4.1.0" supports-color "^7.1.0" -chalk@^4.0.0, chalk@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.0.tgz#4e14870a618d9e2edd97dd8345fd9d9dc315646a" - integrity sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - chalk@~0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/chalk/-/chalk-0.4.0.tgz#5199a3ddcd0c1efe23bc08c1b027b06176e0c64f" @@ -8157,11 +8352,6 @@ chromium-pickle-js@^0.2.0: resolved "https://registry.yarnpkg.com/chromium-pickle-js/-/chromium-pickle-js-0.2.0.tgz#04a106672c18b085ab774d983dfa3ea138f22205" integrity sha1-BKEGZywYsIWrd02YPfo+oTjyIgU= -ci-info@^1.5.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.6.0.tgz#2ca20dbb9ceb32d4524a683303313f0304b1e497" - integrity sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A== - ci-info@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" @@ -8252,7 +8442,7 @@ cli-cursor@^3.1.0: dependencies: restore-cursor "^3.1.0" -cli-table3@0.5.1, cli-table3@~0.5.1: +cli-table3@0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/cli-table3/-/cli-table3-0.5.1.tgz#0252372d94dfc40dbd8df06005f48f31f656f202" integrity sha512-7Qg2Jrep1S/+Q3EceiZtQcDPWxhAvBw+ERf1162v4sikJrvojMHFqXt8QIVha8UlH9rgU0BeWPytZ9/TzYqlUw== @@ -8262,6 +8452,16 @@ cli-table3@0.5.1, cli-table3@~0.5.1: optionalDependencies: colors "^1.1.2" +cli-table3@~0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/cli-table3/-/cli-table3-0.6.0.tgz#b7b1bc65ca8e7b5cef9124e13dc2b21e2ce4faee" + integrity sha512-gnB85c3MGC7Nm9I/FkiasNBOKjOiO1RNuXXarQms37q4QMpWdlbBgD/VnOStA2faG1dpXMv31RFApjX1/QdgWQ== + dependencies: + object-assign "^4.1.0" + string-width "^4.2.0" + optionalDependencies: + colors "^1.1.2" + cli-truncate@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-0.2.1.tgz#9f15cfbb0705005369216c626ac7d05ab90dd574" @@ -8447,6 +8647,13 @@ coffee-lex@^9.1.5: resolved "https://registry.yarnpkg.com/coffee-lex/-/coffee-lex-9.1.5.tgz#6f46f33df539de3c00831d47bbe115991336aa4e" integrity sha512-94lUMjs1vhlV86vnbCCnnIYzR4oszuO4qJzKUuKOLidiksh/UyQFOzPusjmLJt6vy5CNB0d/KtaceqV84zr46g== +coffee-loader@0.9.0: + version "0.9.0" + resolved "https://registry.yarnpkg.com/coffee-loader/-/coffee-loader-0.9.0.tgz#6deabd336062ddc6d773da4dfd16367fc7107bd6" + integrity sha512-VSoQ5kWr6Yfjn4RDpVbba2XMs3XG1ZXtLakPRt8dNfUcNU9h+1pocpdUUEd7NK9rLDwrju4yonhxrL8aMr5tww== + dependencies: + loader-utils "^1.0.2" + coffee-script@1.12.5: version "1.12.5" resolved "https://registry.yarnpkg.com/coffee-script/-/coffee-script-1.12.5.tgz#809f4585419112bbfe46a073ad7543af18c27346" @@ -8792,18 +8999,6 @@ config-chain@^1.1.11: ini "^1.3.4" proto-list "~1.2.1" -configstore@^3.0.0: - version "3.1.2" - resolved "https://registry.yarnpkg.com/configstore/-/configstore-3.1.2.tgz#c6f25defaeef26df12dd33414b001fe81a543f8f" - integrity sha512-vtv5HtGjcYUgFrXc6Kx747B83MRRVS5R1VTEQoXvuP+kMI+if6uywV0nDGoiydJRy4yk7h9od5Og0kxx4zUXmw== - dependencies: - dot-prop "^4.1.0" - graceful-fs "^4.1.2" - make-dir "^1.0.0" - unique-string "^1.0.0" - write-file-atomic "^2.0.0" - xdg-basedir "^3.0.0" - configstore@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/configstore/-/configstore-5.0.1.tgz#d365021b5df4b98cdd187d6a3b0e3f6a7cc5ed96" @@ -9109,13 +9304,6 @@ create-ecdh@^4.0.0: bn.js "^4.1.0" elliptic "^6.0.0" -create-error-class@^3.0.0: - version "3.0.2" - resolved "https://registry.yarnpkg.com/create-error-class/-/create-error-class-3.0.2.tgz#06be7abef947a3f14a30fd610671d401bca8b7b6" - integrity sha1-Br56vvlHo/FKMP1hBnHUAbyot7Y= - dependencies: - capture-stack-trace "^1.0.0" - create-hash@^1.1.0, create-hash@^1.1.2, create-hash@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196" @@ -9252,11 +9440,6 @@ crypto-browserify@^3.0.0, crypto-browserify@^3.11.0: randombytes "^2.0.0" randomfill "^1.0.3" -crypto-random-string@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e" - integrity sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4= - crypto-random-string@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5" @@ -9608,6 +9791,13 @@ decompress-response@^4.2.0: dependencies: mimic-response "^2.0.0" +decompress-response@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-6.0.0.tgz#ca387612ddb7e104bd16d85aab00d5ecf09c66fc" + integrity sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ== + dependencies: + mimic-response "^3.1.0" + dedent@^0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c" @@ -9683,6 +9873,11 @@ defer-to-connect@^1.0.1: resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-1.1.3.tgz#331ae050c08dcf789f8c83a7b81f0ed94f4ac591" integrity sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ== +defer-to-connect@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-2.0.0.tgz#83d6b199db041593ac84d781b5222308ccf4c2c1" + integrity sha512-bYL2d05vOSf1JEZNx5vSAtPuBMkX8K9EUutg7zlKvTqKXHt7RhWJFbmd7qakVuf13i+IkGmp6FwSsONOf6VYIg== + define-properties@^1.1.2, define-properties@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" @@ -10106,16 +10301,16 @@ disparity@3.0.0: ansi-styles "^4.1.0" diff "^4.0.1" -dmg-builder@22.6.1: - version "22.6.1" - resolved "https://registry.yarnpkg.com/dmg-builder/-/dmg-builder-22.6.1.tgz#5777a9eb6904db5bf1f4c69addbf462f5f9bf4e4" - integrity sha512-jUTN0acP15puzevtQASj7QEPgUGpedWSuSnOwR/++JbeYRTwU2oro09h/KZnaeMcxgxjdmT3tYLJeY1XUfPbRg== +dmg-builder@22.8.0: + version "22.8.0" + resolved "https://registry.yarnpkg.com/dmg-builder/-/dmg-builder-22.8.0.tgz#2b17127837ed444db3086317eda5cf8912f6e6a9" + integrity sha512-orePWjcrl97SYLA8F/6UUtbXJSoZCYu5KOP1lVqD4LOomr8bjGDyEVYZmZYcg5WqKmXucdmO6OpqgzH/aRMMuA== dependencies: - app-builder-lib "22.6.1" - builder-util "22.6.1" - fs-extra "^9.0.0" - iconv-lite "^0.5.1" - js-yaml "^3.13.1" + app-builder-lib "22.8.0" + builder-util "22.8.0" + fs-extra "^9.0.1" + iconv-lite "^0.6.2" + js-yaml "^3.14.0" sanitize-filename "^1.6.3" doctrine@^2.1.0: @@ -10227,7 +10422,7 @@ dot-prop@^3.0.0: dependencies: is-obj "^1.0.0" -dot-prop@^4.1.0, dot-prop@^4.2.0: +dot-prop@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-4.2.0.tgz#1f19e0c2e1aa0e32797c49799f2837ac6af69c57" integrity sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ== @@ -10357,26 +10552,26 @@ ee-first@1.1.1: resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= -ejs@^3.1.2: +ejs@^3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/ejs/-/ejs-3.1.3.tgz#514d967a8894084d18d3d47bd169a1c0560f093d" integrity sha512-wmtrUGyfSC23GC/B1SMv2ogAUgbQEtDmTIhfqielrG5ExIM9TP4UoYdi90jLF1aTcsWCJNEO0UrgKzP0y3nTSg== dependencies: jake "^10.6.1" -electron-builder@22.6.1: - version "22.6.1" - resolved "https://registry.yarnpkg.com/electron-builder/-/electron-builder-22.6.1.tgz#9cc704356ecba1342ff1c94d610aad1f3c6a8b02" - integrity sha512-3/VNg9GfXKHM53TilFtfF1+bsAR8THK1XHgeqCpsiequa02J9jTPc/DhpCUKQPkrs6/EIGxP7uboop7XYoew0Q== +electron-builder@22.8.0: + version "22.8.0" + resolved "https://registry.yarnpkg.com/electron-builder/-/electron-builder-22.8.0.tgz#d2c9fc5438c834e41fd794a271fca200165a3bad" + integrity sha512-dUv4F3srJouqxhWivtKqSoQP4Df6vYgjooGdzms+iYMTFi9f0b4LlEbr7kgsPvte8zAglee7VOGOODkCRJDkUQ== dependencies: "@types/yargs" "^15.0.5" - app-builder-lib "22.6.1" + app-builder-lib "22.8.0" bluebird-lst "^1.0.9" - builder-util "22.6.1" - builder-util-runtime "8.7.0" - chalk "^4.0.0" - dmg-builder "22.6.1" - fs-extra "^9.0.0" + builder-util "22.8.0" + builder-util-runtime "8.7.2" + chalk "^4.1.0" + dmg-builder "22.8.0" + fs-extra "^9.0.1" is-ci "^2.0.0" lazy-val "^1.0.4" read-config-file "6.0.0" @@ -10407,7 +10602,15 @@ electron-is-dev@^1.0.1: resolved "https://registry.yarnpkg.com/electron-is-dev/-/electron-is-dev-1.2.0.tgz#2e5cea0a1b3ccf1c86f577cee77363ef55deb05e" integrity sha512-R1oD5gMBPS7PVU8gJwH6CtT0e6VSoD0+SzSnYpNm+dBkcijgA+K7VAMHDfnRq/lkKPZArpzplTW6jfiMYosdzw== -electron-notarize@0.2.1, electron-notarize@^0.2.0: +electron-notarize@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/electron-notarize/-/electron-notarize-1.0.0.tgz#bc925b1ccc3f79e58e029e8c4706572b01a9fd8f" + integrity sha512-dsib1IAquMn0onCrNMJ6gtEIZn/azG8hZMCYOuZIMVMUeRMgBYHK1s5TK9P8xAcrAjh/2aN5WYHzgVSWX314og== + dependencies: + debug "^4.1.1" + fs-extra "^9.0.1" + +electron-notarize@^0.2.0: version "0.2.1" resolved "https://registry.yarnpkg.com/electron-notarize/-/electron-notarize-0.2.1.tgz#759e8006decae19134f82996ed910db26d9192cc" integrity sha512-oZ6/NhKeXmEKNROiFmRNfytqu3cxqC95sjooG7kBXQVEUSQkZnbiAhxVh5jXngL881G197pbwpeVPJyM7Ikmxw== @@ -10450,29 +10653,29 @@ electron-packager@14.1.1: semver "^6.0.0" yargs-parser "^16.0.0" -electron-publish@22.6.1: - version "22.6.1" - resolved "https://registry.yarnpkg.com/electron-publish/-/electron-publish-22.6.1.tgz#d5381220d3e0f3bfa869c5a059fd253a561e0f8a" - integrity sha512-/MkS47ospdSfAFW5Jp52OzYou14HhGJpZ51uAc3GJ5rCfACeqpimC/n1ajRLE3hcXxTWfd3t9MCuClq5jrUO5w== +electron-publish@22.8.0: + version "22.8.0" + resolved "https://registry.yarnpkg.com/electron-publish/-/electron-publish-22.8.0.tgz#7f410fe043abc5d3d896c4ee9eea7a43ea352c7d" + integrity sha512-uM0Zdi9hUqqGOrPj478v7toTvV1Kgto1w11rIiI168batiXAJvNLD8VZRfehOrZT0ibUyZlw8FtxoGCrjyHUOw== dependencies: - "@types/fs-extra" "^8.1.0" + "@types/fs-extra" "^9.0.1" bluebird-lst "^1.0.9" - builder-util "22.6.1" - builder-util-runtime "8.7.0" - chalk "^4.0.0" - fs-extra "^9.0.0" + builder-util "22.8.0" + builder-util-runtime "8.7.2" + chalk "^4.1.0" + fs-extra "^9.0.1" lazy-val "^1.0.4" - mime "^2.4.5" + mime "^2.4.6" electron-to-chromium@^1.3.488: version "1.3.496" resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.496.tgz#3f43d32930481d82ad3663d79658e7c59a58af0b" integrity sha512-TXY4mwoyowwi4Lsrq9vcTUYBThyc1b2hXaTZI13p8/FRhY2CTaq5lK+DVjhYkKiTLsKt569Xes+0J5JsVXFurQ== -electron@8.3.1: - version "8.3.1" - resolved "https://registry.yarnpkg.com/electron/-/electron-8.3.1.tgz#79e98c4d5b8e7c09a8a811f1aa78903f0c692721" - integrity sha512-VZpgLVFyD2SwFDkO9rwUcNgrAMah+g38FEtALGxli8bRVTbcHl8bt21szfa0YUWpc6hWcaf6JdZjqDS5q73Bsg== +electron@9.2.0: + version "9.2.0" + resolved "https://registry.yarnpkg.com/electron/-/electron-9.2.0.tgz#d9fc8c8c9e5109669c366bd7b9ba83b06095d7a4" + integrity sha512-4ecZ3rcGg//Gk4fAK3Jo61T+uh36JhU6HHR/PTujQqQiBw1g4tNPd4R2hGGth2d+7FkRIs5GdRNef7h64fQEMw== dependencies: "@electron/get" "^1.0.1" "@types/node" "^12.0.12" @@ -11344,6 +11547,21 @@ execa@^2.0.3: signal-exit "^3.0.2" strip-final-newline "^2.0.0" +execa@^4.0.2: + version "4.0.3" + resolved "https://registry.yarnpkg.com/execa/-/execa-4.0.3.tgz#0a34dabbad6d66100bd6f2c576c8669403f317f2" + integrity sha512-WFDXGHckXPWZX19t1kCsXzOpqX9LWYNqn4C+HqZlk/V0imTkzJZqf87ZBhvpHaftERYknpk0fjSylnXVlVgI0A== + dependencies: + cross-spawn "^7.0.0" + get-stream "^5.0.0" + human-signals "^1.1.1" + is-stream "^2.0.0" + merge-stream "^2.0.0" + npm-run-path "^4.0.0" + onetime "^5.1.0" + signal-exit "^3.0.2" + strip-final-newline "^2.0.0" + executable@^4.1.0, executable@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/executable/-/executable-4.1.1.tgz#41532bff361d3e57af4d763b70582db18f5d133c" @@ -12268,15 +12486,6 @@ fs-constants@^1.0.0: resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow== -fs-extra@7.0.1, fs-extra@^7.0.0, fs-extra@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9" - integrity sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw== - dependencies: - graceful-fs "^4.1.2" - jsonfile "^4.0.0" - universalify "^0.1.0" - fs-extra@8.1.0, fs-extra@^8.1.0: version "8.1.0" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" @@ -12332,7 +12541,16 @@ fs-extra@^6.0.1: jsonfile "^4.0.0" universalify "^0.1.0" -fs-extra@^9.0.0, fs-extra@^9.0.1: +fs-extra@^7.0.0, fs-extra@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9" + integrity sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw== + dependencies: + graceful-fs "^4.1.2" + jsonfile "^4.0.0" + universalify "^0.1.0" + +fs-extra@^9.0.1: version "9.0.1" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.0.1.tgz#910da0062437ba4c39fedd863f1675ccfefcb9fc" integrity sha512-h2iAoN838FqAFJY2/qVpzFXy+EBxfVE220PalAqQLDVsFOHLJrZvut5puAbCdNv6WJk+B8ihI+k0c7JK5erwqQ== @@ -12874,13 +13092,6 @@ global-agent@^2.0.2: semver "^7.3.2" serialize-error "^7.0.1" -global-dirs@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-0.1.1.tgz#b319c0dd4607f353f3be9cca4c72fc148c49f445" - integrity sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU= - dependencies: - ini "^1.3.4" - global-dirs@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-2.0.1.tgz#acdf3bb6685bcd55cb35e8a052266569e9469201" @@ -13114,22 +13325,22 @@ good-listener@^1.2.2: dependencies: delegate "^3.1.2" -got@^6.7.1: - version "6.7.1" - resolved "https://registry.yarnpkg.com/got/-/got-6.7.1.tgz#240cd05785a9a18e561dc1b44b41c763ef1e8db0" - integrity sha1-JAzQV4WpoY5WHcG0S0HHY+8ejbA= - dependencies: - create-error-class "^3.0.0" - duplexer3 "^0.1.4" - get-stream "^3.0.0" - is-redirect "^1.0.0" - is-retry-allowed "^1.0.0" - is-stream "^1.0.0" - lowercase-keys "^1.0.0" - safe-buffer "^5.0.1" - timed-out "^4.0.0" - unzip-response "^2.0.1" - url-parse-lax "^1.0.0" +got@11.5.1: + version "11.5.1" + resolved "https://registry.yarnpkg.com/got/-/got-11.5.1.tgz#bf098a270fe80b3fb88ffd5a043a59ebb0a391db" + integrity sha512-reQEZcEBMTGnujmQ+Wm97mJs/OK6INtO6HmLI+xt3+9CvnRwWjXutUvb2mqr+Ao4Lu05Rx6+udx9sOQAmExMxA== + dependencies: + "@sindresorhus/is" "^3.0.0" + "@szmarczak/http-timer" "^4.0.5" + "@types/cacheable-request" "^6.0.1" + "@types/responselike" "^1.0.0" + cacheable-lookup "^5.0.3" + cacheable-request "^7.0.1" + decompress-response "^6.0.0" + http2-wrapper "^1.0.0-beta.5.0" + lowercase-keys "^2.0.0" + p-cancelable "^2.0.0" + responselike "^2.0.0" got@^8.3.2: version "8.3.2" @@ -13601,7 +13812,7 @@ hosted-git-info@^2.1.4, hosted-git-info@^2.7.1: resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.8.tgz#7539bd4bc1e0e0a895815a2e0262420b12858488" integrity sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg== -hosted-git-info@^3.0.4: +hosted-git-info@^3.0.5: version "3.0.5" resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-3.0.5.tgz#bea87905ef7317442e8df3087faa3c842397df03" integrity sha512-i4dpK6xj9BIpVOTboXIlKG9+8HMKggcrMX7WA24xZtKwX0TPelq/rbaS5rCKeNX8sJXZJGdSxpnEGtta+wismQ== @@ -13787,6 +13998,14 @@ http-status-codes@1.4.0: resolved "https://registry.yarnpkg.com/http-status-codes/-/http-status-codes-1.4.0.tgz#6e4c15d16ff3a9e2df03b89f3a55e1aae05fb477" integrity sha512-JrT3ua+WgH8zBD3HEJYbeEgnuQaAnUeRRko/YojPAJjGmIfGD3KPU/asLdsLwKjfxOmQe5nXMQ0pt/7MyapVbQ== +http2-wrapper@^1.0.0-beta.5.0: + version "1.0.0-beta.5.2" + resolved "https://registry.yarnpkg.com/http2-wrapper/-/http2-wrapper-1.0.0-beta.5.2.tgz#8b923deb90144aea65cf834b016a340fc98556f3" + integrity sha512-xYz9goEyBnC8XwXDTuC/MZ6t+MrKVQZOk4s7+PaDkwIsQd8IwqvM+0M6bA/2lvG8GHXcPdf+MejTUeO2LCPCeQ== + dependencies: + quick-lru "^5.1.1" + resolve-alpn "^1.0.0" + https-browserify@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" @@ -13877,13 +14096,6 @@ iconv-lite@0.5.0: dependencies: safer-buffer ">= 2.1.2 < 3" -iconv-lite@^0.5.1: - version "0.5.2" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.5.2.tgz#af6d628dccfb463b7364d97f715e4b74b8c8c2b8" - integrity sha512-kERHXvpSaB4aU3eANwidg79K8FlrN77m8G9V+0vOR3HYaRifrlwMEpT7ZBJqLSEIHnEgJTHcWK82wwLwwKwtag== - dependencies: - safer-buffer ">= 2.1.2 < 3" - iconv-lite@^0.6.2: version "0.6.2" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.2.tgz#ce13d1875b0c3a674bd6a04b7f76b01b1b6ded01" @@ -13952,11 +14164,6 @@ image-size@0.8.3, image-size@^0.8.2: dependencies: queue "6.0.1" -immediate@~3.0.5: - version "3.0.6" - resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b" - integrity sha1-nbHb0Pr43m++D13V5Wu2BigN5ps= - immutable@3.7.6: version "3.7.6" resolved "https://registry.yarnpkg.com/immutable/-/immutable-3.7.6.tgz#13b4d3cb12befa15482a26fe1b2ebae640071e4b" @@ -14350,13 +14557,6 @@ is-ci@2.0.0, is-ci@^2.0.0: dependencies: ci-info "^2.0.0" -is-ci@^1.0.10: - version "1.2.1" - resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-1.2.1.tgz#e3779c8ee17fccf428488f6e281187f2e632841c" - integrity sha512-s6tfsaQaQi3JNciBH6shVqEDvhGut0SUXr31ag8Pd8BBbVVlcGfWhpPmEOoM6RJ5TFhbypvf5yyRw/VXW1IiWg== - dependencies: - ci-info "^1.5.0" - is-data-descriptor@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" @@ -14516,14 +14716,6 @@ is-html@2.0.0: dependencies: html-tags "^3.0.0" -is-installed-globally@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/is-installed-globally/-/is-installed-globally-0.1.0.tgz#0dfd98f5a9111716dd535dda6492f67bf3d25a80" - integrity sha1-Df2Y9akRFxbdU13aZJL2e/PSWoA= - dependencies: - global-dirs "^0.1.0" - is-path-inside "^1.0.0" - is-installed-globally@^0.3.1, is-installed-globally@^0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/is-installed-globally/-/is-installed-globally-0.3.2.tgz#fd3efa79ee670d1187233182d5b0a1dd00313141" @@ -14565,11 +14757,6 @@ is-negated-glob@^1.0.0: resolved "https://registry.yarnpkg.com/is-negated-glob/-/is-negated-glob-1.0.0.tgz#6910bca5da8c95e784b5751b976cf5a10fee36d2" integrity sha1-aRC8pdqMleeEtXUbl2z1oQ/uNtI= -is-npm@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-1.0.0.tgz#f2fb63a65e4905b406c86072765a1a4dc793b9f4" - integrity sha1-8vtjpl5JBbQGyGBydloaTceTufQ= - is-npm@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-4.0.0.tgz#c90dd8380696df87a7a6d823c20d0b12bbe3c84d" @@ -14711,11 +14898,6 @@ is-property@^1.0.0, is-property@^1.0.2: resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" integrity sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ= -is-redirect@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-redirect/-/is-redirect-1.0.0.tgz#1d03dded53bd8db0f30c26e4f95d36fc7c87dc24" - integrity sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ= - is-regex@^1.0.5, is-regex@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.0.tgz#ece38e389e490df0dc21caea2bd596f987f767ff" @@ -14740,7 +14922,7 @@ is-relative@^1.0.0: dependencies: is-unc-path "^1.0.0" -is-retry-allowed@^1.0.0, is-retry-allowed@^1.1.0: +is-retry-allowed@^1.1.0: version "1.2.0" resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz#d778488bd0a4666a3be8a1482b9f2baafedea8b4" integrity sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg== @@ -14757,7 +14939,7 @@ is-ssh@^1.3.0: dependencies: protocols "^1.1.0" -is-stream@^1.0.0, is-stream@^1.0.1, is-stream@^1.1.0: +is-stream@^1.0.1, is-stream@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= @@ -15533,7 +15715,7 @@ js-yaml@3.13.1: argparse "^1.0.7" esprima "^4.0.0" -js-yaml@3.14.0, js-yaml@3.x, js-yaml@^3.13.1, js-yaml@^3.7.0: +js-yaml@3.14.0, js-yaml@3.x, js-yaml@^3.13.1, js-yaml@^3.14.0, js-yaml@^3.7.0: version "3.14.0" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.0.tgz#a7a34170f26a21bb162424d8adacb4113a69e482" integrity sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A== @@ -15737,6 +15919,11 @@ json-buffer@3.0.0: resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898" integrity sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg= +json-buffer@3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" + integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== + json-fixer@^1.3.1: version "1.5.2" resolved "https://registry.yarnpkg.com/json-fixer/-/json-fixer-1.5.2.tgz#1c99f7f2e93106a105f1311fec7c13c6925a0a93" @@ -15969,6 +16156,13 @@ keyv@^3.0.0: dependencies: json-buffer "3.0.0" +keyv@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.0.1.tgz#9fe703cb4a94d6d11729d320af033307efd02ee6" + integrity sha512-xz6Jv6oNkbhrFCvCP7HQa8AaII8y8LRpoSm661NOKLr4uHuBwhX4epXrPQgF3+xdJnN4Esm5X0xwY4bOlALOtw== + dependencies: + json-buffer "3.0.1" + kind-of@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-1.1.0.tgz#140a3d2d41a36d2efcfa9377b62c24f8495a5c44" @@ -16047,13 +16241,6 @@ last-run@^1.1.0: default-resolution "^2.0.0" es6-weak-map "^2.0.1" -latest-version@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/latest-version/-/latest-version-3.1.0.tgz#a205383fea322b33b5ae3b18abee0dc2f356ee15" - integrity sha1-ogU4P+oyKzO1rjsYq+4NwvNW7hU= - dependencies: - package-json "^4.0.0" - latest-version@^5.0.0: version "5.1.0" resolved "https://registry.yarnpkg.com/latest-version/-/latest-version-5.1.0.tgz#119dfe908fe38d15dfa43ecd13fa12ec8832face" @@ -16171,13 +16358,6 @@ levn@^0.3.0, levn@~0.3.0: prelude-ls "~1.1.2" type-check "~0.3.2" -lie@*: - version "3.3.0" - resolved "https://registry.yarnpkg.com/lie/-/lie-3.3.0.tgz#dcf82dee545f46074daf200c7c1c5a08e0f40f6a" - integrity sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ== - dependencies: - immediate "~3.0.5" - liftoff@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/liftoff/-/liftoff-3.1.0.tgz#c9ba6081f908670607ee79062d700df062c52ed3" @@ -16652,6 +16832,13 @@ log-symbols@^1.0.2: dependencies: chalk "^1.0.0" +log-symbols@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.0.0.tgz#69b3cc46d20f448eccdb75ea1fa733d9e821c920" + integrity sha512-FN8JBzLx6CzeMrB0tg6pqlGU1wCrXW+ZXGH481kfsBqer0hToTIiHdjH4Mq8xJUbvATujKCvaREGWpGUionraA== + dependencies: + chalk "^4.0.0" + log-update@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/log-update/-/log-update-2.3.0.tgz#88328fd7d1ce7938b29283746f0b1bc126b24708" @@ -17210,7 +17397,7 @@ mime@2.4.4: resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.4.tgz#bd7b91135fc6b01cde3e9bae33d659b63d8857e5" integrity sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA== -mime@^2.0.3, mime@^2.4.5: +mime@^2.0.3, mime@^2.4.6: version "2.4.6" resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.6.tgz#e5b407c90db442f2beb5b162373d07b69affa4d1" integrity sha512-RZKhC3EmpBchfTGBVb8fb+RL2cWyw/32lshnsETttkBAyAUXSGHxbEJWWRXc751DrIxG1q04b8QwMbAwkRPpUA== @@ -17235,6 +17422,11 @@ mimic-response@^2.0.0: resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-2.1.0.tgz#d13763d35f613d09ec37ebb30bac0469c0ee8f43" integrity sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA== +mimic-response@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-3.1.0.tgz#2d1d59af9c1b129815accc2c46a022a5ce1fa3c9" + integrity sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ== + min-document@^2.19.0: version "2.19.0" resolved "https://registry.yarnpkg.com/min-document/-/min-document-2.19.0.tgz#7bd282e3f5842ed295bb748cdd9f1ffa2c824685" @@ -17716,10 +17908,10 @@ mochawesome-report-generator@^3.0.1: validator "^9.1.2" yargs "^10.0.3" -mock-fs@4.10.4: - version "4.10.4" - resolved "https://registry.yarnpkg.com/mock-fs/-/mock-fs-4.10.4.tgz#4eaa3d6f7da2f44e1f3dd6b462cbbcb7b082e3d4" - integrity sha512-gDfZDLaPIvtOusbusLinfx6YSe2YpQsDT8qdP41P47dQ/NQggtkHukz7hwqgt8QvMBmAv+Z6DGmXPyb5BWX2nQ== +mock-fs@4.12.0: + version "4.12.0" + resolved "https://registry.yarnpkg.com/mock-fs/-/mock-fs-4.12.0.tgz#a5d50b12d2d75e5bec9dac3b67ffe3c41d31ade4" + integrity sha512-/P/HtrlvBxY4o/PzXY9cCNBrdylDNxg7gnrv2sMNxj+UJ2m8jSpl0/A6fuJeNAWr99ZvGWH8XCbE0vmnM5KupQ== mock-fs@4.9.0: version "4.9.0" @@ -17962,13 +18154,6 @@ napi-build-utils@^1.0.1: resolved "https://registry.yarnpkg.com/napi-build-utils/-/napi-build-utils-1.0.2.tgz#b1fddc0b2c46e380a0b7a76f984dd47c41a13806" integrity sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg== -native-or-lie@1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/native-or-lie/-/native-or-lie-1.0.2.tgz#c870ee0ba0bf0ff11350595d216cfea68a6d8086" - integrity sha1-yHDuC6C/D/ETUFldIWz+poptgIY= - dependencies: - lie "*" - native-promise-only@~0.8.1: version "0.8.1" resolved "https://registry.yarnpkg.com/native-promise-only/-/native-promise-only-0.8.1.tgz#20a318c30cb45f71fe7adfbf7b21c99c1472ef11" @@ -18925,6 +19110,11 @@ p-cancelable@^1.0.0: resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-1.1.0.tgz#d078d15a3af409220c886f1d9a0ca2e441ab26cc" integrity sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw== +p-cancelable@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-2.0.0.tgz#4a3740f5bdaf5ed5d7c3e34882c6fb5d6b266a6e" + integrity sha512-wvPXDmbMmu2ksjkB4Z3nZWTSkJEb9lqVdMaCKpZUGJG9TMiNp9XcbG3fn9fPKjem04fJMJnXoyFPk2FmgiaiNg== + p-defer@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-1.0.0.tgz#9f6eb182f6c9aa8cd743004a7d4f96b196b0fb0c" @@ -19082,16 +19272,6 @@ package-hash@^4.0.0: lodash.flattendeep "^4.4.0" release-zalgo "^1.0.0" -package-json@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/package-json/-/package-json-4.0.1.tgz#8869a0401253661c4c4ca3da6c2121ed555f5eed" - integrity sha1-iGmgQBJTZhxMTKPabCEh7VVfXu0= - dependencies: - got "^6.7.1" - registry-auth-token "^3.0.1" - registry-url "^3.0.3" - semver "^5.1.0" - package-json@^6.3.0: version "6.5.0" resolved "https://registry.yarnpkg.com/package-json/-/package-json-6.5.0.tgz#6feedaca35e75725876d0b0e64974697fed145b0" @@ -19348,10 +19528,10 @@ password-prompt@^1.0.7: ansi-escapes "^3.1.0" cross-spawn "^6.0.5" -patch-package@6.2.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/patch-package/-/patch-package-6.2.0.tgz#677de858e352b6ca4e6cb48a6efde2cec9fde566" - integrity sha512-HWlQflaBBMjLBfOWomfolF8aqsFDeNbSNro1JDUgYqnVvPM5OILJ9DQdwIRiKmGaOsmHvhkl1FYkvv1I9r2ZJw== +patch-package@6.2.2: + version "6.2.2" + resolved "https://registry.yarnpkg.com/patch-package/-/patch-package-6.2.2.tgz#71d170d650c65c26556f0d0fbbb48d92b6cc5f39" + integrity sha512-YqScVYkVcClUY0v8fF0kWOjDYopzIM8e3bj/RU1DPeEF14+dCGm6UeOYm4jvCyxqIEQ5/eJzmbWfDWnUleFNMg== dependencies: "@yarnpkg/lockfile" "^1.1.0" chalk "^2.4.2" @@ -19365,7 +19545,6 @@ patch-package@6.2.0: semver "^5.6.0" slash "^2.0.0" tmp "^0.0.33" - update-notifier "^2.5.0" path-browserify@0.0.1, path-browserify@~0.0.0: version "0.0.1" @@ -19882,11 +20061,6 @@ prelude-ls@~1.1.2: resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= -prepend-http@^1.0.1: - version "1.0.4" - resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" - integrity sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw= - prepend-http@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" @@ -20267,6 +20441,11 @@ quick-lru@^4.0.1: resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-4.0.1.tgz#5b8878f113a58217848c6482026c73e1ba57727f" integrity sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g== +quick-lru@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932" + integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA== + quote@0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/quote/-/quote-0.4.0.tgz#10839217f6c1362b89194044d29b233fd7f32f01" @@ -21142,14 +21321,6 @@ registry-auth-token@3.3.2: rc "^1.1.6" safe-buffer "^5.0.1" -registry-auth-token@^3.0.1: - version "3.4.0" - resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-3.4.0.tgz#d7446815433f5d5ed6431cd5dca21048f66b397e" - integrity sha512-4LM6Fw8eBQdwMYcES4yTnn2TqIasbXuwDx3um+QRs7S55aMKCBKBxvPXl2RiUjHwuJLTyYfxSpmfSAjQpcuP+A== - dependencies: - rc "^1.1.6" - safe-buffer "^5.0.1" - registry-auth-token@^4.0.0: version "4.1.1" resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-4.1.1.tgz#40a33be1e82539460f94328b0f7f0f84c16d9479" @@ -21165,7 +21336,7 @@ registry-js@1.8.0: nan "^2.10.0" prebuild-install "^5.2.4" -registry-url@3.1.0, registry-url@^3.0.3: +registry-url@3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/registry-url/-/registry-url-3.1.0.tgz#3d4ef870f73dde1d77f0cf9a381432444e174942" integrity sha1-PU74cPc93h138M+aOBQyRE4XSUI= @@ -21422,6 +21593,11 @@ requires-port@^1.0.0: resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8= +resolve-alpn@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/resolve-alpn/-/resolve-alpn-1.0.0.tgz#745ad60b3d6aff4b4a48e01b8c0bdc70959e0e8c" + integrity sha512-rTuiIEqFmGxne4IovivKSDzld2lWW9QCjqv80SYjPgf+gS35eaCAjaP54CCwGAwBtnCsvNLYtqxe1Nw+i6JEmA== + resolve-cwd@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-2.0.0.tgz#00a9f7387556e27038eae232caa372a6a59b665a" @@ -21521,6 +21697,13 @@ responselike@1.0.2, responselike@^1.0.2: dependencies: lowercase-keys "^1.0.0" +responselike@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/responselike/-/responselike-2.0.0.tgz#26391bcc3174f750f9a79eacc40a12a5c42d7723" + integrity sha512-xH48u3FTB9VsZw7R+vvgaKeLKzT6jOogbQhEe/jewwnZgzPcnyWui2Av6JpoYZF/91uueC+lqhWqeURw5/qhCw== + dependencies: + lowercase-keys "^2.0.0" + restore-cursor@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541" @@ -21891,13 +22074,6 @@ semver-compare@^1.0.0: resolved "https://registry.yarnpkg.com/semver-compare/-/semver-compare-1.0.0.tgz#0dee216a1c941ab37e9efb1788f6afc5ff5537fc" integrity sha1-De4hahyUGrN+nvsXiPavxf9VN/w= -semver-diff@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-2.1.0.tgz#4bbb8437c8d37e4b0cf1a68fd726ec6d645d6d36" - integrity sha1-S7uEN8jTfksM8aaP1ybsbWRdbTY= - dependencies: - semver "^5.0.3" - semver-diff@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-3.1.1.tgz#05f77ce59f325e00e2706afd67bb506ddb1ca32b" @@ -21912,7 +22088,7 @@ semver-greatest-satisfied-range@^1.1.0: dependencies: sver-compat "^1.5.0" -"semver@2 || 3 || 4 || 5", "semver@2.x || 3.x || 4 || 5", semver@^5.0.3, semver@^5.1.0, semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0, semver@^5.7.0, semver@^5.7.1: +"semver@2 || 3 || 4 || 5", "semver@2.x || 3.x || 4 || 5", semver@^5.0.3, semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0, semver@^5.7.0, semver@^5.7.1: version "5.7.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== @@ -23024,21 +23200,6 @@ stream-splicer@^2.0.0: inherits "^2.0.1" readable-stream "^2.0.2" -stream-to-array@~2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/stream-to-array/-/stream-to-array-2.3.0.tgz#bbf6b39f5f43ec30bc71babcb37557acecf34353" - integrity sha1-u/azn19D7DC8cbq8s3VXrOzzQ1M= - dependencies: - any-promise "^1.1.0" - -stream-to-promise@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/stream-to-promise/-/stream-to-promise-1.1.1.tgz#838f5df7c92b8c9ba8fb95d7aa3ac312eec7527f" - integrity sha1-g49d98krjJuo+5XXqjrDEu7HUn8= - dependencies: - bluebird "~3.0.6" - stream-to-array "~2.3.0" - strict-uri-encode@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713" @@ -23264,7 +23425,7 @@ strip-indent@^3.0.0: dependencies: min-indent "^1.0.0" -strip-json-comments@2.0.1, strip-json-comments@^2.0.1, strip-json-comments@~2.0.1: +strip-json-comments@2.0.1, strip-json-comments@^2.0.0, strip-json-comments@^2.0.1, strip-json-comments@~2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= @@ -23744,7 +23905,7 @@ time-stamp@^1.0.0: resolved "https://registry.yarnpkg.com/time-stamp/-/time-stamp-1.1.0.tgz#764a5a11af50561921b133f3b44e618687e0f5c3" integrity sha1-dkpaEa9QVhkhsTPztE5hhofg9cM= -timed-out@^4.0.0, timed-out@^4.0.1: +timed-out@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" integrity sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8= @@ -23805,13 +23966,20 @@ tmp@0.0.33, tmp@^0.0.33: dependencies: os-tmpdir "~1.0.2" -tmp@0.1.0, tmp@~0.1.0: +tmp@0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.1.0.tgz#ee434a4e22543082e294ba6201dcc6eafefa2877" integrity sha512-J7Z2K08jbGcdA1kkQpJSqLF6T0tdQqpR2pnSUXsIchbPdTI9v3e85cLW0d6WDhwuAleOV71j2xWs8qMPfK7nKw== dependencies: rimraf "^2.6.3" +tmp@~0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.1.tgz#8457fc3037dcf4719c251367a1af6500ee1ccf14" + integrity sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ== + dependencies: + rimraf "^3.0.0" + tmpl@1.0.x: version "1.0.4" resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1" @@ -24029,6 +24197,17 @@ ts-loader@7.0.4: micromatch "^4.0.0" semver "^6.0.0" +ts-loader@8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-8.0.1.tgz#9670dcbce2a8c8506d01a37fee042350d02c8c21" + integrity sha512-I9Nmly0ufJoZRMuAT9d5ijsC2B7oSPvUnOJt/GhgoATlPGYfa17VicDKPcqwUCrHpOkCxr/ybLYwbnS4cOxmvQ== + dependencies: + chalk "^2.3.0" + enhanced-resolve "^4.0.0" + loader-utils "^1.0.2" + micromatch "^4.0.0" + semver "^6.0.0" + ts-node@5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-5.0.1.tgz#78e5d1cb3f704de1b641e43b76be2d4094f06f81" @@ -24065,6 +24244,35 @@ ts-node@8.5.4: source-map-support "^0.5.6" yn "^3.0.0" +tsconfig-paths-webpack-plugin@3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/tsconfig-paths-webpack-plugin/-/tsconfig-paths-webpack-plugin-3.2.0.tgz#6e70bd42915ad0efb64d3385163f0c1270f3e04d" + integrity sha512-S/gOOPOkV8rIL4LurZ1vUdYCVgo15iX9ZMJ6wx6w2OgcpT/G4wMyHB6WM+xheSqGMrWKuxFul+aXpCju3wmj/g== + dependencies: + chalk "^2.3.0" + enhanced-resolve "^4.0.0" + tsconfig-paths "^3.4.0" + +tsconfig-paths@^3.4.0: + version "3.9.0" + resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz#098547a6c4448807e8fcb8eae081064ee9a3c90b" + integrity sha512-dRcuzokWhajtZWkQsDVKbWyY+jgcLC5sqJhg2PSgf4ZkH2aHPvaOY8YWGhmjb68b5qqTfasSsDO9k7RUiEmZAw== + dependencies: + "@types/json5" "^0.0.29" + json5 "^1.0.1" + minimist "^1.2.0" + strip-bom "^3.0.0" + +tsconfig@7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/tsconfig/-/tsconfig-7.0.0.tgz#84538875a4dc216e5c4a5432b3a4dec3d54e91b7" + integrity sha512-vZXmzPrL+EmC4T/4rVlT2jNVMWCi/O4DIiSj3UHg1OE5kCKbk4mfrXc6dZksLgRM/TZlKnousKH9bbTazUWRRw== + dependencies: + "@types/strip-bom" "^3.0.0" + "@types/strip-json-comments" "0.0.30" + strip-bom "^3.0.0" + strip-json-comments "^2.0.0" + tslib@^1, tslib@^1.0.0, tslib@^1.8.0, tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3: version "1.13.0" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.13.0.tgz#c881e13cc7015894ed914862d276436fa9a47043" @@ -24441,13 +24649,6 @@ unique-stream@^2.0.2: json-stable-stringify-without-jsonify "^1.0.1" through2-filter "^3.0.0" -unique-string@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-1.0.0.tgz#9e1057cca851abb93398f8b33ae187b99caec11a" - integrity sha1-nhBXzKhRq7kzmPizOuGHuZyuwRo= - dependencies: - crypto-random-string "^1.0.0" - unique-string@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-2.0.0.tgz#39c6451f81afb2749de2b233e3f7c5e8843bd89d" @@ -24519,11 +24720,6 @@ unused-filename@^2.1.0: modify-filename "^1.1.0" path-exists "^4.0.0" -unzip-response@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/unzip-response/-/unzip-response-2.0.1.tgz#d2f0f737d16b0615e72a6935ed04214572d56f97" - integrity sha1-0vD3N9FrBhXnKmk17QQhRXLVb5c= - upath@^1.1.0, upath@^1.1.1, upath@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/upath/-/upath-1.2.0.tgz#8f66dbcd55a883acdae4408af8b035a5044c1894" @@ -24537,22 +24733,6 @@ update-check@1.5.2: registry-auth-token "3.3.2" registry-url "3.1.0" -update-notifier@^2.5.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-2.5.0.tgz#d0744593e13f161e406acb1d9408b72cad08aff6" - integrity sha512-gwMdhgJHGuj/+wHJJs9e6PcCszpxR1b236igrOkUofGhqJuG+amlIKwApH1IW1WWl7ovZxsX49lMBWLxSdm5Dw== - dependencies: - boxen "^1.2.1" - chalk "^2.0.1" - configstore "^3.0.0" - import-lazy "^2.1.0" - is-ci "^1.0.10" - is-installed-globally "^0.1.0" - is-npm "^1.0.0" - latest-version "^3.0.0" - semver-diff "^2.0.0" - xdg-basedir "^3.0.0" - update-notifier@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-4.1.0.tgz#4866b98c3bc5b5473c020b1250583628f9a328f3" @@ -24601,13 +24781,6 @@ url-join@^2.0.5: resolved "https://registry.yarnpkg.com/url-join/-/url-join-2.0.5.tgz#5af22f18c052a000a48d7b82c5e9c2e2feeda728" integrity sha1-WvIvGMBSoACkjXuCxenC4v7tpyg= -url-parse-lax@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-1.0.0.tgz#7af8f303645e9bd79a272e7a14ac68bc0609da73" - integrity sha1-evjzA2Rem9eaJy56FKxovAYJ2nM= - dependencies: - prepend-http "^1.0.1" - url-parse-lax@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-3.0.0.tgz#16b5cafc07dbe3676c1b1999177823d6503acb0c" @@ -25572,11 +25745,6 @@ xdg-basedir@^2.0.0: dependencies: os-homedir "^1.0.0" -xdg-basedir@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-3.0.0.tgz#496b2cc109eca8dbacfe2dc72b603c17c5870ad4" - integrity sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ= - xdg-basedir@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-4.0.0.tgz#4bc8d9984403696225ef83a1573cbbcb4e79db13"