version: 2.1

# usually we don't build Mac app - it takes a long time
# but sometimes we want to really confirm we are doing the right thing
# so just add your branch to the list here to build and test on Mac
macBuildFilters: &macBuildFilters
  filters:
    branches:
      only:
        - develop
        - fix-next-version
        - include-electron-node-version

defaults: &defaults
  parallelism: 1
  working_directory: ~/cypress
  parameters:
    executor:
      type: executor
      default: cy-doc
  executor: <<parameters.executor>>
  environment:
    ## set specific timezone
    TZ: "/usr/share/zoneinfo/America/New_York"

    ## store artifacts here
    CIRCLE_ARTIFACTS: /tmp/artifacts

    ## set so that e2e tests are consistent
    COLUMNS: 100
    LINES: 24

# filters and requires for testing binary with Firefox
testBinaryFirefox: &testBinaryFirefox
  filters:
    branches:
      only:
        - develop
        - fix-next-version
  requires:
    - create-build-artifacts

executors:
  # the Docker image with Cypress dependencies and Chrome browser
  cy-doc:
    docker:
      - image: cypress/browsers:node12.18.3-chrome83-ff77
    environment:
      PLATFORM: linux

  cy-doc-plus:
    docker:
      - image: cypress/browsers:node12.18.3-chrome83-ff77
    resource_class: medium+
    environment:
      PLATFORM: linux

  # Docker image with non-root "node" user
  non-root-docker-user:
    docker:
      - image: cypress/browsers:node12.18.3-chrome83-ff77
        user: node
    environment:
      PLATFORM: linux

  # executor to run on Mac OS
  # https://circleci.com/docs/2.0/executor-types/#using-macos
  # https://circleci.com/docs/2.0/testing-ios/#supported-xcode-versions
  mac:
    macos:
      # Executor should have Node >= required version
      xcode: "11.3.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:
      browser:
        default: "electron"
        description: browser shortname to target
        type: string
    steps:
      - run:
          name: Install latest Google Chrome (stable)
          command: |
            if [ <<parameters.browser>> == "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>>' ****"
            fi

  run-driver-integration-tests:
    parameters:
      browser:
        description: browser shortname to target
        type: string
    steps:
      - attach_workspace:
          at: ~/
      - check-conditional-ci
      - run:
          environment:
            CYPRESS_KONFIG_ENV: production
          command: |
            echo Current working directory is $PWD
            echo Total containers $CIRCLE_NODE_TOTAL

            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>>
            else
              # external PR
              TESTFILES=$(circleci tests glob "cypress/integration/**/*_spec.*" | circleci tests split --total=$CIRCLE_NODE_TOTAL)
              echo "Test files for this machine are $TESTFILES"

              if [[ -z "$TESTFILES" ]]; then
                echo "Empty list of test files"
              fi
              yarn cypress:run --browser <<parameters.browser>> --spec $TESTFILES
            fi
          working_directory: packages/driver
      - verify-mocha-results
      - store_test_results:
          path: /tmp/cypress
      - store_artifacts:
          path: /tmp/artifacts
      - store-npm-logs

  run-runner-integration-tests:
    parameters:
      browser:
        description: browser shortname to target
        type: string
      percy:
        description: enable percy
        type: boolean
        default: false
    steps:
      - attach_workspace:
          at: ~/
      - check-conditional-ci
      - run:
          command: |
            cmd=$([[ <<parameters.percy>> == 'true' ]] && echo 'yarn percy exec --') || true

            CYPRESS_KONFIG_ENV=production \
            CYPRESS_RECORD_KEY=$PACKAGES_RECORD_KEY \
            PERCY_PARALLEL_NONCE=$CIRCLE_WORKFLOW_ID \
            PERCY_PARALLEL_TOTAL=-1 \
            $cmd yarn workspace @packages/runner cypress:run --record --parallel --group runner-integration-<<parameters.browser>> --browser <<parameters.browser>>
      - store_test_results:
          path: /tmp/cypress
      - store_artifacts:
          path: /tmp/artifacts
      - store-npm-logs

  run-runner-ct-integration-tests:
    parameters:
      browser:
        description: browser shortname to target
        type: string
      percy:
        description: enable percy
        type: boolean
        default: false
    steps:
      - attach_workspace:
          at: ~/
      - check-conditional-ci
      - run:
          command: |
            cmd=$([[ <<parameters.percy>> == 'true' ]] && echo 'yarn percy exec --') || true
            PERCY_PARALLEL_NONCE=$CIRCLE_WORKFLOW_ID \
            PERCY_PARALLEL_TOTAL=-1 \
            $cmd yarn workspace @packages/runner-ct run cypress:run --browser <<parameters.browser>>
      - run:
          command: |
            if [[ <<parameters.percy>> == 'true' ]]; then
              PERCY_PARALLEL_NONCE=$CIRCLE_WORKFLOW_ID \
              PERCY_PARALLEL_TOTAL=-1 \
              yarn percy upload packages/runner-ct/cypress/screenshots/screenshot.spec.tsx/percy
            else
              echo "skipping percy screenshots uploading"
            fi
      - store_test_results:
          path: /tmp/cypress
      - store_artifacts:
          path: ./packages/runner-ct/cypress/videos
      - store-npm-logs

  run-e2e-tests:
    parameters:
      browser:
        description: browser shortname to target
        type: string
    steps:
      - attach_workspace:
          at: ~/
      - check-conditional-ci
      - run:
          command: yarn workspace @packages/server test ./test/e2e/$(( $CIRCLE_NODE_INDEX ))_*spec* --browser <<parameters.browser>>
      - verify-mocha-results
      - store_test_results:
          path: /tmp/cypress
      - store_artifacts:
          path: /tmp/artifacts
      - store-npm-logs

  store-npm-logs:
    description: Saves any NPM debug logs as artifacts in case there is a problem
    steps:
      - store_artifacts:
          path: ~/.npm/_logs

  post-install-comment:
    description: Post GitHub comment with a blurb on how to install pre-release version
    steps:
      - run: ls -la
      - run: ls -la binary-url.json npm-package-url.json
      - run: cat binary-url.json
      - run: cat npm-package-url.json
      - run:
          name: Post pre-release install comment
          command: |
            node scripts/add-install-comment.js \
              --npm npm-package-url.json \
              --binary binary-url.json

  verify-mocha-results:
    description: Double-check that Mocha tests ran as expected.
    parameters:
      expectedResultCount:
        description: The number of result files to expect, ie, the number of Mocha test suites that ran.
        type: integer
        ## by default, assert that at least 1 test ran
        default: 0
    steps:
      - run: yarn verify:mocha:results <<parameters.expectedResultCount>>

  clone-repo-and-checkout-release-branch:
    description: |
      Clones an external repo and then checks out the branch that matches the next 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: ~/
      - check-conditional-ci
      - run:
          name: "Cloning test project: <<parameters.repo>>"
          command: |
            git clone --depth 1 --no-single-branch https://github.com/cypress-io/<<parameters.repo>>.git /tmp/<<parameters.repo>>
            cd /tmp/<<parameters.repo>> && (git checkout $(node ./scripts/get-next-version) || true)

  test-binary-against-rwa:
    description: |
      Takes the built binary and NPM package, clones the RWA repo
      and runs the new version of Cypress against it.
    parameters:
      repo:
        description: "Name of the github repo to clone like"
        type: string
        default: "cypress-realworld-app"
      browser:
        description: Name of the browser to use, like "electron", "chrome", "firefox"
        type: enum
        enum: ["", "electron", "chrome", "firefox"]
        default: ""
      command:
        description: Test command to run to start Cypress tests
        type: string
        default: "yarn cypress:run"
      # if the repo to clone and test is a monorepo, you can
      # run tests inside a specific subfolder
      folder:
        description: Subfolder to test in
        type: string
        default: ""
      # you can test new features in the test runner against recipes or other repos
      # by opening a pull request in those repos and running this test job
      # against a pull request number in the example repo
      pull_request_id:
        description: Pull request number to check out before installing and testing
        type: integer
        default: 0
      wait-on:
        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: "CI=true yarn start"
    steps:
      - attach_workspace:
          at: ~/
      - check-conditional-ci
      # make sure the binary and NPM package files are present
      - run: ls -l
      - run: ls -l cypress.zip cypress.tgz
      - clone-repo-and-checkout-release-branch:
          repo: <<parameters.repo>>
      - when:
          condition: <<parameters.pull_request_id>>
          steps:
            - run:
                name: Check out PR <<parameters.pull_request_id>>
                working_directory: /tmp/<<parameters.repo>>
                command: |
                  git fetch origin pull/<<parameters.pull_request_id>>/head:pr-<<parameters.pull_request_id>>
                  git checkout pr-<<parameters.pull_request_id>>
                  git log -n 2
      - run:
          command: yarn
          working_directory: /tmp/<<parameters.repo>>
      - run:
          name: Install Cypress
          working_directory: /tmp/<<parameters.repo>>
          # force installing the freshly built binary
          command: |
            CYPRESS_INSTALL_BINARY=~/cypress/cypress.zip npm i ~/cypress/cypress.tgz && [[ -f yarn.lock ]] && yarn
      - run:
          name: Print Cypress version
          working_directory: /tmp/<<parameters.repo>>
          command: npx cypress version
      - run:
          name: Types check 🧩 (maybe)
          working_directory: /tmp/<<parameters.repo>>
          command: yarn types
      - run:
          working_directory: /tmp/<<parameters.repo>>
          command: <<parameters.server-start-command>>
          background: true
      - run:
          condition: <<parameters.wait-on>>
          name: "Waiting on server to boot: <<parameters.wait-on>>"
          command: "npx wait-on <<parameters.wait-on>>"
      - when:
          condition: <<parameters.folder>>
          steps:
            - when:
                condition: <<parameters.browser>>
                steps:
                  - run:
                      name: Run tests using browser "<<parameters.browser>>"
                      working_directory: /tmp/<<parameters.repo>>/<<parameters.folder>>
                      command: |
                        <<parameters.command>> -- --browser <<parameters.browser>>
            - unless:
                condition: <<parameters.browser>>
                steps:
                  - run:
                      name: Run tests using command
                      working_directory: /tmp/<<parameters.repo>>/<<parameters.folder>>
                      command: <<parameters.command>>

            - store_artifacts:
                name: screenshots
                path: /tmp/<<parameters.repo>>/<<parameters.folder>>/cypress/screenshots
            - store_artifacts:
                name: videos
                path: /tmp/<<parameters.repo>>/<<parameters.folder>>/cypress/videos
      - unless:
          condition: <<parameters.folder>>
          steps:
            - when:
                condition: <<parameters.browser>>
                steps:
                  - run:
                      name: Run tests using browser "<<parameters.browser>>"
                      working_directory: /tmp/<<parameters.repo>>
                      command: <<parameters.command>> -- --browser <<parameters.browser>>
            - unless:
                condition: <<parameters.browser>>
                steps:
                  - run:
                      name: Run tests using command
                      working_directory: /tmp/<<parameters.repo>>
                      command: <<parameters.command>>
            - store_artifacts:
                name: screenshots
                path: /tmp/<<parameters.repo>>/cypress/screenshots
            - store_artifacts:
                name: videos
                path: /tmp/<<parameters.repo>>/cypress/videos
      - store-npm-logs

  test-binary-against-repo:
    description: |
      Takes the built binary and NPM package, clones given example repo
      and runs the new version of Cypress against it.
    parameters:
      repo:
        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"
        type: enum
        enum: ["", "electron", "chrome", "firefox"]
        default: ""
      command:
        description: Test command to run to start Cypress tests
        type: string
        default: "npm run e2e"
      build-project:
        description: Should the project build script be executed
        type: boolean
        default: true
      # if the repo to clone and test is a monorepo, you can
      # run tests inside a specific subfolder
      folder:
        description: Subfolder to test in
        type: string
        default: ""
      # you can test new features in the test runner against recipes or other repos
      # by opening a pull request in those repos and running this test job
      # against a pull request number in the example repo
      pull_request_id:
        description: Pull request number to check out before installing and testing
        type: integer
        default: 0
      wait-on:
        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: ~/
      - check-conditional-ci
      # make sure the binary and NPM package files are present
      - run: ls -l
      - run: ls -l cypress.zip cypress.tgz
      - clone-repo-and-checkout-release-branch:
          repo: <<parameters.repo>>
      - when:
          condition: <<parameters.pull_request_id>>
          steps:
            - run:
                name: Check out PR <<parameters.pull_request_id>>
                working_directory: /tmp/<<parameters.repo>>
                command: |
                  git fetch origin pull/<<parameters.pull_request_id>>/head:pr-<<parameters.pull_request_id>>
                  git checkout pr-<<parameters.pull_request_id>>
                  git log -n 2
      - run:
          # Install with yarn if yarn.lock present
          command: |
            [[ -f yarn.lock ]] && yarn || npm install
          working_directory: /tmp/<<parameters.repo>>
      - run:
          name: Install Cypress
          working_directory: /tmp/<<parameters.repo>>
          # force installing the freshly built binary
          command: |
            CYPRESS_INSTALL_BINARY=~/cypress/cypress.zip npm i ~/cypress/cypress.tgz
      - run:
          name: Print Cypress version
          working_directory: /tmp/<<parameters.repo>>
          command: npx cypress version
      - run:
          name: Types check 🧩 (maybe)
          working_directory: /tmp/<<parameters.repo>>
          command: |
            [[ -f yarn.lock ]] && yarn types || npm run types --if-present
      - when:
          condition: <<parameters.build-project>>
          steps:
          - run:
              name: Build 🏗 (maybe)
              working_directory: /tmp/<<parameters.repo>>
              command: |
                [[ -f yarn.lock ]] && yarn build || npm run build --if-present
      - run:
          working_directory: /tmp/<<parameters.repo>>
          command: <<parameters.server-start-command>>
          background: true
      - run:
          condition: <<parameters.wait-on>>
          name: "Waiting on server to boot: <<parameters.wait-on>>"
          command: "npx wait-on <<parameters.wait-on>> --timeout 120000"
      - when:
          condition: <<parameters.folder>>
          steps:
            - when:
                condition: <<parameters.browser>>
                steps:
                  - run:
                      name: Run tests using browser "<<parameters.browser>>"
                      working_directory: /tmp/<<parameters.repo>>/<<parameters.folder>>
                      command: |
                        <<parameters.command>> -- --browser <<parameters.browser>>
            - unless:
                condition: <<parameters.browser>>
                steps:
                  - run:
                      name: Run tests using command
                      working_directory: /tmp/<<parameters.repo>>/<<parameters.folder>>
                      command: <<parameters.command>>

            - store_artifacts:
                name: screenshots
                path: /tmp/<<parameters.repo>>/<<parameters.folder>>/cypress/screenshots
            - store_artifacts:
                name: videos
                path: /tmp/<<parameters.repo>>/<<parameters.folder>>/cypress/videos
      - unless:
          condition: <<parameters.folder>>
          steps:
            - when:
                condition: <<parameters.browser>>
                steps:
                  - run:
                      name: Run tests using browser "<<parameters.browser>>"
                      working_directory: /tmp/<<parameters.repo>>
                      command: <<parameters.command>> -- --browser <<parameters.browser>>
            - unless:
                condition: <<parameters.browser>>
                steps:
                  - run:
                      name: Run tests using command
                      working_directory: /tmp/<<parameters.repo>>
                      command: <<parameters.command>>
            - store_artifacts:
                name: screenshots
                path: /tmp/<<parameters.repo>>/cypress/screenshots
            - store_artifacts:
                name: videos
                path: /tmp/<<parameters.repo>>/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: <<parameters.job-names>>"
          command: node ./scripts/wait-on-circle-jobs.js --job-names="<<parameters.job-names>>"

  check-conditional-ci:
    description: Halt CI if the package that this job corresponds to is unchanged
    steps:
      - run:
          name: Check if job should run
          command: node scripts/check-conditional-ci.js

  build-binary:
    steps:
      - run:
          name: Check environment variables before code sign (if on Mac)
          # NOTE
          # our Mac code sign works via electron-builder
          # by default, electron-builder will NOT sign app built in a pull request
          # even our internal one (!)
          # Usually this is not a problem, since we only build and test binary
          # built on "develop" and "master" branches
          # but if you need to really build and sign a Mac binary in a PR
          # set variable CSC_FOR_PULL_REQUEST=true
          command: |
            set -e
            if [[ "$OSTYPE" == "darwin"* ]]; then
              if [ -z "$CSC_LINK" ]; then
                echo "Need to provide environment variable CSC_LINK"
                  echo "with base64 encoded certificate .p12 file"
                exit 1
              fi
              if [ -z "$CSC_KEY_PASSWORD" ]; then
                echo "Need to provide environment variable CSC_KEY_PASSWORD"
                  echo "with password for unlocking certificate .p12 file"
                exit 1
              fi
            else
              echo "Not Mac platform, skipping code sign setup"
            fi
      - install-required-node
      - run:
          environment:
            DEBUG: electron-builder,electron-osx-sign*
          # notarization on Mac can take a while
          no_output_timeout: "45m"
          command: |
            . ./scripts/load-nvm.sh
            node --version
            yarn binary-build --platform $PLATFORM --version $(node ./scripts/get-next-version.js)
      - run:
          name: Zip the binary
          command: |
            . ./scripts/load-nvm.sh
            yarn binary-zip --platform $PLATFORM
      - store-npm-logs
      - persist_to_workspace:
          root: ~/
          paths:
            - cypress/cypress.zip

  upload-binary:
    steps:
      - run:
          name: upload unique binary
          command: |
            node scripts/binary.js upload-unique-binary \
              --file cypress.zip \
              --version $(node -p "require('./package.json').version")
      - run: cat binary-url.json
      - store-npm-logs
      - persist_to_workspace:
          root: ~/
          paths:
            - cypress/binary-url.json

  build-npm-package:
    steps:
      - run:
          name: bump NPM version
          command: yarn get-next-version --npm
      - run:
          name: build NPM package
          command: |
            . ./scripts/load-nvm.sh
            yarn build --scope cypress
      - run:
          command: ls -la types
          working_directory: cli/build
      - run:
          name: list NPM package contents
          command: yarn workspace cypress size
      - run:
          name: pack NPM package
          working_directory: cli/build
          command: yarn pack
      - run:
          name: list created NPM package
          working_directory: cli/build
          command: ls -l
      # created file should have filename cypress-<version>.tgz
      - run: cp cli/build/cypress-v*.tgz cypress.tgz
      - store-npm-logs
      - run: pwd
      - run: ls -l
      - persist_to_workspace:
          root: ~/
          paths:
            - cypress/cypress.tgz

  upload-npm-package:
    steps:
      - run: ls -l
      - run:
          name: upload NPM package
          command: |
            node scripts/binary.js upload-npm-package \
              --file cypress.tgz \
              --version $(node -p "require('./package.json').version")
      - store-npm-logs
      - run: ls -l
      - run: cat npm-package-url.json
      - persist_to_workspace:
          root: ~/
          paths:
            - cypress/npm-package-url.json

jobs:
  ## code checkout and yarn installs
  build:
    <<: *defaults
    steps:
      - checkout
      - install-required-node
      - run:
          name: Print working folder
          command: echo $PWD
      - run:
          name: print global yarn cache path
          command: echo $(yarn global bin)
      - run:
          name: print Node version
          command: |
            . ./scripts/load-nvm.sh
            echo "nvm use default"
            nvm use default
            node -v
      - run:
          name: print yarn version
          command: yarn -v
      - 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:
          name: Check terminal
          command: |
            . ./scripts/load-nvm.sh
            yarn check-terminal

      - run:
          name: Stop .only
          command: |
            . ./scripts/load-nvm.sh
            yarn stop-only-all

      - restore_cache:
          name: Restore yarn cache
          key: v{{ .Environment.CACHE_VERSION }}-{{ arch }}-deps-root-{{ checksum "yarn.lock" }}

      # show what is already cached globally
      - run: ls $(yarn global bin)
      - run: ls $(yarn global bin)/../lib/node_modules

      # try several times, because flaky NPM installs ...
      - run:
          name: install and build
          command: |
            . ./scripts/load-nvm.sh
            yarn --frozen-lockfile || yarn --frozen-lockfile
            yarn build-prod
      - run:
          name: Top level packages
          command: yarn list --depth=0 || true

      - store-npm-logs

      - save_cache:
          name: Save yarn cache
          key: v{{ .Environment.CACHE_VERSION }}-{{ arch }}-deps-root-{{ checksum "yarn.lock" }}
          paths:
            - ~/.cache

      ## save entire folder as artifact for other jobs to run without reinstalling
      - persist_to_workspace:
          root: ~/
          paths:
            - cypress
            - .ssh

  lint:
    <<: *defaults
    steps:
      - attach_workspace:
          at: ~/
      - install-required-node
      ## this will catch ".only"s in js/coffee as well
      - run:
          name: Linting 🧹
          command: |
            . ./scripts/load-nvm.sh
            git clean -df
            yarn lint
      - run:
          name: cypress info (dev)
          command: node cli/bin/cypress info --dev
      - store-npm-logs

  list-changed-packages:
    <<: *defaults
    steps:
      - attach_workspace:
          at: ~/
      - run:
          name: List changed packages
          command: node scripts/changed-packages.js

  # 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 <<parameters.required_env_var>> is set
          command: |
            if [[ -v <<parameters.required_env_var>> ]]; 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,
            runner-ct-integration-tests-chrome
            reporter-integration-tests,
      - run: npx percy finalize --all

  cli-visual-tests:
    <<: *defaults
    parallelism: 8
    steps:
      - attach_workspace:
          at: ~/
      - check-conditional-ci
      - run: mkdir -p cli/visual-snapshots
      - run:
          command: node cli/bin/cypress info --dev | yarn --silent term-to-html | node scripts/sanitize --type cli-info > cli/visual-snapshots/cypress-info.html
          environment:
            FORCE_COLOR: 2
      - run:
          command: node cli/bin/cypress help | yarn --silent term-to-html > cli/visual-snapshots/cypress-help.html
          environment:
            FORCE_COLOR: 2
      - store_artifacts:
          path: cli/visual-snapshots
      - run:
          name: Upload CLI snapshots for diffing
          command: |
            PERCY_PARALLEL_NONCE=$CIRCLE_WORKFLOW_ID \
            PERCY_PARALLEL_TOTAL=-1 \
            yarn percy snapshot ./cli/visual-snapshots

  unit-tests:
    <<: *defaults
    parallelism: 1
    steps:
      - attach_workspace:
          at: ~/
      - check-conditional-ci
      # make sure mocha runs
      - run: yarn test-mocha
      # test binary build code
      - run: yarn test-scripts
      # make sure our snapshots are compared correctly
      - run: yarn test-mocha-snapshot
      # make sure packages with TypeScript can be transpiled to JS
      - run: yarn lerna run build-prod --stream
      # run unit tests from each individual package
      - run: yarn test
      - verify-mocha-results:
          expectedResultCount: 9
      - store_test_results:
          path: /tmp/cypress
      # CLI tests generate HTML files with sample CLI command output
      - store_artifacts:
          path: cli/test/html
      - store-npm-logs

  lint-types:
    <<: *defaults
    parallelism: 1
    steps:
      - attach_workspace:
          at: ~/
      - run:
          command: ls -la types
          working_directory: cli
      - run:
          command: ls -la chai
          working_directory: cli/types
      - run:
          name: "Lint types 🧹"
          command: yarn workspace cypress dtslint
      - run:
          name: "TypeScript check 🧩"
          command: yarn type-check --ignore-progress
      - store-npm-logs

  server-unit-tests:
    <<: *defaults
    parallelism: 1
    steps:
      - attach_workspace:
          at: ~/
      - check-conditional-ci
      - run: yarn test-unit --scope @packages/server
      - verify-mocha-results:
          expectedResultCount: 1
      - store_test_results:
          path: /tmp/cypress
      - store-npm-logs

  server-ct-unit-tests:
    <<: *defaults
    parallelism: 1
    steps:
      - attach_workspace:
          at: ~/
      - check-conditional-ci
      - run: yarn test-unit --scope @packages/server-ct
      - verify-mocha-results:
          expectedResultCount: 1
      - store_test_results:
          path: /tmp/cypress
      - store-npm-logs

  server-integration-tests:
    <<: *defaults
    parallelism: 1
    steps:
      - attach_workspace:
          at: ~/
      - check-conditional-ci
      - run: yarn test-integration --scope @packages/server
      - verify-mocha-results:
          expectedResultCount: 1
      - store_test_results:
          path: /tmp/cypress
      - store-npm-logs

  server-performance-tests:
    <<: *defaults
    steps:
      - attach_workspace:
          at: ~/
      - check-conditional-ci
      - run:
          command: yarn workspace @packages/server test-performance
      - verify-mocha-results:
          expectedResultCount: 1
      - store_test_results:
          path: /tmp/cypress
      - store_artifacts:
          path: /tmp/artifacts
      - store-npm-logs

  server-e2e-tests-chrome:
    <<: *defaults
    parallelism: 8
    steps:
      - run-e2e-tests:
          browser: chrome

  server-e2e-tests-electron:
    <<: *defaults
    parallelism: 8
    steps:
      - run-e2e-tests:
          browser: electron

  server-e2e-tests-firefox:
    <<: *defaults
    parallelism: 8
    steps:
      - run-e2e-tests:
          browser: firefox

  server-e2e-tests-non-root:
    <<: *defaults
    steps:
      - attach_workspace:
          at: ~/
      - run:
          command: yarn workspace @packages/server test ./test/e2e/non_root*spec* --browser electron
      - verify-mocha-results
      - store_test_results:
          path: /tmp/cypress
      - store_artifacts:
          path: /tmp/artifacts
      - store-npm-logs

  runner-integration-tests-chrome:
    <<: *defaults
    parallelism: 2
    steps:
      - run-runner-integration-tests:
          browser: chrome
          percy: true

  runner-integration-tests-firefox:
    <<: *defaults
    parallelism: 2
    steps:
      - run-runner-integration-tests:
          browser: firefox

  runner-ct-integration-tests-chrome:
    <<: *defaults
    parallelism: 1
    steps:
      - run-runner-ct-integration-tests:
          browser: chrome
          percy: true

  driver-integration-tests-chrome:
    <<: *defaults
    parallelism: 5
    steps:
      - run-driver-integration-tests:
          browser: chrome

  driver-integration-tests-firefox:
    <<: *defaults
    parallelism: 5
    steps:
      - run-driver-integration-tests:
          browser: firefox

  desktop-gui-integration-tests-2x:
    <<: *defaults
    parallelism: 2
    steps:
      - attach_workspace:
          at: ~/
      - check-conditional-ci
      - run:
          command: yarn build-prod
          working_directory: packages/desktop-gui
      - run:
          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
      - store_test_results:
          path: /tmp/cypress
      - store_artifacts:
          path: /tmp/artifacts
      - store-npm-logs

  desktop-gui-component-tests:
    <<: *defaults
    parallelism: 1
    steps:
      - attach_workspace:
          at: ~/
      - check-conditional-ci
      - run:
          # builds JS and CSS, and we need the app CSS
          # to correctly apply component styles
          command: |
            yarn build-prod
            ls -la dist
          working_directory: packages/desktop-gui
      # for now, because we have baseUrl in cypress.json
      # we must start it, even if we don't use it for component tests
      # https://github.com/cypress-io/cypress/issues/7800
      - run:
          name: Unnecessary Desktop GUI server
          command: yarn start
          working_directory: packages/desktop-gui
          background: true
      - run:
          # will use PERCY_TOKEN environment variable if available
          command: |
            CYPRESS_KONFIG_ENV=production \
            PERCY_PARALLEL_NONCE=$CIRCLE_WORKFLOW_ID \
            PERCY_PARALLEL_TOTAL=-1 \
            yarn percy exec -- \
            yarn cypress:run --spec 'src/**/*_spec.jsx'
          working_directory: packages/desktop-gui
      - verify-mocha-results
      # we don't really need any artifacts - we are only interested in visual screenshots
      - store-npm-logs

  reporter-integration-tests:
    <<: *defaults
    steps:
      - attach_workspace:
          at: ~/
      - check-conditional-ci
      - run:
          command: yarn build-for-tests
          working_directory: packages/reporter
      - run:
          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 reporter
          working_directory: packages/reporter
      - verify-mocha-results
      - store_test_results:
          path: /tmp/cypress
      - store_artifacts:
          path: /tmp/artifacts
      - store-npm-logs

  ui-components-integration-tests:
    <<: *defaults
    steps:
      - attach_workspace:
          at: ~/
      - check-conditional-ci
      - run:
          command: yarn build-for-tests
          working_directory: packages/ui-components
      - run:
          command: |
            CYPRESS_KONFIG_ENV=production \
            CYPRESS_RECORD_KEY=$PACKAGES_RECORD_KEY \
            yarn cypress:run --record --parallel --group ui-components
          working_directory: packages/ui-components
      - verify-mocha-results
      - store_test_results:
          path: /tmp/cypress
      - store_artifacts:
          path: /tmp/artifacts
      - store-npm-logs

  run-launcher:
    <<: *defaults
    steps:
      - attach_workspace:
          at: ~/
      - check-conditional-ci
      - run:
          command: node index.js
          working_directory: packages/launcher

  npm-webpack-preprocessor:
    <<: *defaults
    steps:
      - attach_workspace:
          at: ~/
      - check-conditional-ci
      - run:
          name: Build
          command: yarn workspace @cypress/webpack-preprocessor build
      - run:
          name: Run tests
          command: yarn workspace @cypress/webpack-preprocessor test
      - run:
          name: Test babelrc
          command: yarn test
          working_directory: npm/webpack-preprocessor/examples/use-babelrc
      - run:
          name: Build ts-loader
          command: yarn install
          working_directory: npm/webpack-preprocessor/examples/use-ts-loader
      - run:
          name: Types ts-loader
          command: yarn types
          working_directory: npm/webpack-preprocessor/examples/use-ts-loader
      - run:
          name: Test ts-loader
          command: yarn test
          working_directory: npm/webpack-preprocessor/examples/use-ts-loader
      - run:
          name: Start React app
          command: yarn start
          background: true
          working_directory: npm/webpack-preprocessor/examples/react-app
      - run:
          name: Test React app
          command: yarn test
          working_directory: npm/webpack-preprocessor/examples/react-app
      - store-npm-logs

  npm-webpack-dev-server:
    <<: *defaults
    steps:
      - attach_workspace:
          at: ~/
      - check-conditional-ci
      - run:
          name: Run tests
          command: yarn workspace @cypress/webpack-dev-server test
  npm-vite-dev-server:
    <<: *defaults
    steps:
      - attach_workspace:
          at: ~/
      - check-conditional-ci
      - run:
          name: Run tests
          command: yarn workspace @cypress/vite-dev-server test

  npm-rollup-dev-server:
    <<: *defaults
    steps:
      - attach_workspace:
          at: ~/
      - check-conditional-ci
      - run:
          name: Run tests
          command: yarn workspace @cypress/rollup-dev-server test

  npm-webpack-batteries-included-preprocessor:
    <<: *defaults
    steps:
      - attach_workspace:
          at: ~/
      - check-conditional-ci
      - run:
          name: Run tests
          command: yarn workspace @cypress/webpack-batteries-included-preprocessor test

  npm-vue:
    <<: *defaults
    steps:
      - attach_workspace:
          at: ~/
      - check-conditional-ci
      - run:
          name: Build
          command: yarn workspace @cypress/vue build
      - run:
          name: Run tests
          command: yarn test
          working_directory: npm/vue
      - store-npm-logs

  npm-design-system:
    <<: *defaults
    steps:
      - attach_workspace:
          at: ~/
      - check-conditional-ci
      - run:
          name: Build
          command: yarn workspace @cypress/design-system build
      - run:
          name: Run tests
          command: yarn test
          working_directory: npm/design-system
      - store-npm-logs


  npm-react:
    <<: *defaults
    parallelism: 8
    steps:
      - attach_workspace:
          at: ~/
      - check-conditional-ci
      - restore_cache:
          name: Restore yarn cache
          key: v{{ .Environment.CACHE_VERSION }}-{{ arch }}-npm-react-babel-cache
      - run:
          name: Build
          command: yarn workspace @cypress/react build
      - run:
          name: Run tests
          command: yarn test-ci
          working_directory: npm/react
      - store_test_results:
          path: npm/react/test_results
      - store_artifacts:
          path: npm/react/test_results
      - store-npm-logs


  npm-create-cypress-tests:
    <<: *defaults
    steps:
      - attach_workspace:
          at: ~/
      - run: yarn workspace create-cypress-tests build
      - run:
          name: Run unit test
          command: yarn workspace create-cypress-tests test

  npm-eslint-plugin-dev:
    <<: *defaults
    steps:
      - attach_workspace:
          at: ~/
      - check-conditional-ci
      - run:
          name: Run tests
          command: yarn workspace @cypress/eslint-plugin-dev test

  npm-release:
    <<: *defaults
    steps:
      - attach_workspace:
          at: ~/
      - run:
          name: Release packages
          command: yarn npm-release

  create-build-artifacts:
    <<: *defaults
    shell: /bin/bash --login
    steps:
      - attach_workspace:
          at: ~/
      - check-conditional-ci
      - build-binary
      - build-npm-package
      - run:
          name: Check current branch to persist artifacts
          command: |
            if [[ "$CIRCLE_BRANCH" != "develop" && "$CIRCLE_BRANCH" != "fix-next-version" ]]; then
              echo "Not uploading artifacts or posting install comment for this branch."
              circleci-agent step halt
            fi
      - upload-binary
      - upload-npm-package
      - post-install-comment

  test-kitchensink:
    <<: *defaults
    steps:
      - clone-repo-and-checkout-release-branch:
          repo: cypress-example-kitchensink
      - install-required-node
      - run:
          name: Install prod dependencies
          command: yarn --production
          working_directory: /tmp/cypress-example-kitchensink
      - run:
          name: Example server
          command: yarn start
          working_directory: /tmp/cypress-example-kitchensink
          background: true
      - run:
          name: Run Kitchensink example project
          command: |
            . ./scripts/load-nvm.sh
            yarn cypress:run --project /tmp/cypress-example-kitchensink
      - store_artifacts:
          path: /tmp/cypress-example-kitchensink/cypress/screenshots
      - store_artifacts:
          path: /tmp/cypress-example-kitchensink/cypress/videos
      - store-npm-logs

  "test-kitchensink-against-staging":
    <<: *defaults
    steps:
      - clone-repo-and-checkout-release-branch:
          repo: cypress-example-kitchensink
      - run:
          name: Install prod dependencies
          command: yarn --production
          working_directory: /tmp/cypress-example-kitchensink
      - run:
          name: Example server
          command: yarn start
          working_directory: /tmp/cypress-example-kitchensink
          background: true
      - run:
          name: Run Kitchensink example project
          command: |
            CYPRESS_PROJECT_ID=$TEST_KITCHENSINK_PROJECT_ID \
            CYPRESS_RECORD_KEY=$TEST_KITCHENSINK_RECORD_KEY \
            CYPRESS_INTERNAL_ENV=staging \
            CYPRESS_video=false \
            yarn cypress:run --project /tmp/cypress-example-kitchensink --record
      - store-npm-logs

  "test-against-staging":
    <<: *defaults
    steps:
      - 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/cypress-test-tiny --record
      - store-npm-logs

  "test-binary-and-npm-against-other-projects":
    <<: *defaults
    steps:
      # needs uploaded NPM and test binary
      - attach_workspace:
          at: ~/
      - check-conditional-ci
      - run: ls -la
      # make sure JSON files with uploaded urls are present
      - run: ls -la binary-url.json npm-package-url.json
      - run: cat binary-url.json
      - run: cat npm-package-url.json
      - run: mkdir /tmp/testing
      - run:
          name: create dummy package
          working_directory: /tmp/testing
          command: npm init -y
      - run:
          # install NPM from unique urls
          name: Install Cypress
          command: |
            node scripts/test-unique-npm-and-binary.js \
              --npm npm-package-url.json \
              --binary binary-url.json \
              --cwd /tmp/testing
      - run:
          name: Verify Cypress binary
          working_directory: /tmp/testing
          command: $(yarn bin)/cypress verify
      - run:
          name: Running other test projects with new NPM package and binary
          command: |
            node scripts/test-other-projects.js \
              --npm npm-package-url.json \
              --binary binary-url.json \
              --provider circle
      - store-npm-logs

  "test-npm-module-and-verify-binary":
    <<: *defaults
    steps:
      - attach_workspace:
          at: ~/
      - check-conditional-ci
      # make sure we have cypress.zip received
      - run: ls -l
      - run: ls -l cypress.zip cypress.tgz
      - run: mkdir test-binary
      - run:
          name: Create new NPM package
          working_directory: test-binary
          command: npm init -y
      - run:
          # install NPM from built NPM package folder
          name: Install Cypress
          working_directory: test-binary
          # force installing the freshly built binary
          command: CYPRESS_INSTALL_BINARY=/root/cypress/cypress.zip npm i /root/cypress/cypress.tgz
      - run:
          name: Cypress version
          working_directory: test-binary
          command: $(yarn bin)/cypress version
      - run:
          name: Verify Cypress binary
          working_directory: test-binary
          command: $(yarn bin)/cypress verify
      - run:
          name: Cypress help
          working_directory: test-binary
          command: $(yarn bin)/cypress help
      - run:
          name: Cypress info
          working_directory: test-binary
          command: $(yarn bin)/cypress info
      - store-npm-logs

  test-npm-module-on-minimum-node-version:
    <<: *defaults
    docker:
      - image: cypress/base:10.0.0
    steps:
      - attach_workspace:
          at: ~/
      - check-conditional-ci
      # make sure we have cypress.zip received
      - run: ls -l
      - run: ls -l cypress.zip cypress.tgz
      - run: mkdir test-binary
      - run: node --version
      - run: npm --version
      - run:
          name: Create new NPM package
          working_directory: test-binary
          command: npm init -y
      - run:
          name: Install Cypress
          working_directory: test-binary
          command: CYPRESS_INSTALL_BINARY=/root/cypress/cypress.zip npm install /root/cypress/cypress.tgz
      - run:
          name: Verify Cypress binary
          working_directory: test-binary
          command: $(npm bin)/cypress verify
      - run:
          name: Print Cypress version
          working_directory: test-binary
          command: $(npm bin)/cypress version
      - run:
          name: Cypress info
          working_directory: test-binary
          command: $(npm bin)/cypress info

  test-types-cypress-and-jest:
    parameters:
      executor:
        description: Executor name to use
        type: executor
        default: cy-doc
      wd:
        description: Working directory, should be OUTSIDE cypress monorepo folder
        type: string
        default: /root/test-cypress-and-jest
    <<: *defaults
    steps:
      - attach_workspace:
          at: ~/
      - check-conditional-ci
      # make sure we have cypress.zip received
      - run: ls -l
      - run: ls -l cypress.zip cypress.tgz
      - run: mkdir <<parameters.wd>>
      - run: node --version
      - run: npm --version
      - run:
          name: Create new NPM package ⚗️
          working_directory: <<parameters.wd>>
          command: npm init -y
      - run:
          name: Install dependencies 📦
          working_directory: <<parameters.wd>>
          environment:
            CYPRESS_INSTALL_BINARY: /root/cypress/cypress.zip
          # let's install Cypress, Jest and any other package that might conflict
          # https://github.com/cypress-io/cypress/issues/6690
          command: |
            npm install /root/cypress/cypress.tgz \
              typescript jest @types/jest enzyme @types/enzyme
      - run:
          name: Test types clash ⚔️
          working_directory: <<parameters.wd>>
          command: |
            echo "console.log('hello world')" > hello.ts
            npx tsc hello.ts --noEmit

  # testing scaffolding examples and running them
  # against example.cypress.io
  test-cypress-scaffold:
    parameters:
      executor:
        description: Executor name to use
        type: executor
        default: cy-doc
      wd:
        description: Working directory, should be OUTSIDE cypress monorepo folder
        type: string
        default: /root/test-scaffold
    <<: *defaults
    steps:
      - attach_workspace:
          at: ~/
      - check-conditional-ci
      # make sure we have cypress.zip received
      - run: ls -l
      - run: ls -l cypress.zip cypress.tgz
      - run: mkdir <<parameters.wd>>
      - run: node --version
      - run: npm --version
      - run:
          name: Create new NPM package ⚗️
          working_directory: <<parameters.wd>>
          command: npm init -y
      - run:
          name: Install dependencies 📦
          working_directory: <<parameters.wd>>
          environment:
            CYPRESS_INSTALL_BINARY: /root/cypress/cypress.zip
          # let's install Cypress, Jest and any other package that might conflict
          # https://github.com/cypress-io/cypress/issues/6690
          command: |
            npm install /root/cypress/cypress.tgz \
              typescript jest @types/jest enzyme @types/enzyme
      - run:
          name: Scaffold and test examples 🏗
          working_directory: <<parameters.wd>>
          environment:
            CYPRESS_INTERNAL_FORCE_SCAFFOLD: "1"
          command: |
            echo '{}' > cypress.json
            npx cypress run

  test-full-typescript-project:
    parameters:
      executor:
        description: Executor name to use
        type: executor
        default: cy-doc
      wd:
        description: Working directory, should be OUTSIDE cypress monorepo folder
        type: string
        default: /root/test-full-typescript
    <<: *defaults
    steps:
      - attach_workspace:
          at: ~/
      - check-conditional-ci
      # make sure we have cypress.zip received
      - run: ls -l
      - run: ls -l cypress.zip cypress.tgz
      - run: mkdir <<parameters.wd>>
      - run: node --version
      - run: npm --version
      - run:
          name: Create new NPM package ⚗️
          working_directory: <<parameters.wd>>
          command: npm init -y
      - run:
          name: Install dependencies 📦
          working_directory: <<parameters.wd>>
          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>>
          command: npx @bahmutov/cly@1 init --typescript
      - run:
          name: Run project tests 🗳
          working_directory: <<parameters.wd>>
          command: npx cypress run

  # install NPM + binary zip and run against staging API
  "test-binary-against-staging":
    <<: *defaults
    steps:
      - attach_workspace:
          at: ~/
      - check-conditional-ci
      - run: ls -l
      # make sure we have the binary and NPM package
      - run: ls -l cypress.zip cypress.tgz
      - clone-repo-and-checkout-release-branch:
          repo: cypress-test-tiny
      - run:
          name: Install Cypress
          working_directory: /tmp/cypress-test-tiny
          # force installing the freshly built binary
          command: CYPRESS_INSTALL_BINARY=~/cypress/cypress.zip npm i ~/cypress/cypress.tgz
      - run:
          name: Run test project
          working_directory: /tmp/cypress-test-tiny
          command: |
            CYPRESS_PROJECT_ID=$TEST_TINY_PROJECT_ID \
            CYPRESS_RECORD_KEY=$TEST_TINY_RECORD_KEY \
            CYPRESS_INTERNAL_ENV=staging \
            $(yarn bin)/cypress run --record
      - store-npm-logs

  "test-binary-against-recipes-firefox":
    <<: *defaults
    steps:
      - test-binary-against-repo:
          repo: cypress-example-recipes
          command: npm run test:ci:firefox

  # This is a special job. It allows you to test the current
  # built test runner against a pull request in the repo
  # cypress-example-recipes.
  # Imagine you are working on a feature and want to show / test a recipe
  # You would need to run the built test runner before release
  # against a PR that cannot be merged until the new version
  # of the test runner is released.
  # Use:
  #   specify pull request number
  #   and the recipe folder

  # 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-kitchensink":
    <<: *defaults
    steps:
      - test-binary-against-repo:
          repo: cypress-example-kitchensink
          browser: "electron"

  test-binary-against-awesome-typescript-loader:
    <<: *defaults
    steps:
      - test-binary-against-repo:
          repo: cypress-test-awesome-typescript-loader
          browser: "electron"

  "test-binary-against-kitchensink-firefox":
    <<: *defaults
    steps:
      - test-binary-against-repo:
          repo: cypress-example-kitchensink
          browser: firefox

  "test-binary-against-kitchensink-chrome":
    <<: *defaults
    steps:
      - test-binary-against-repo:
          repo: cypress-example-kitchensink
          browser: chrome

  "test-binary-against-todomvc-firefox":
    <<: *defaults
    steps:
      - test-binary-against-repo:
          repo: cypress-example-todomvc
          browser: firefox

  "test-binary-against-documentation-firefox":
    <<: *defaults
    steps:
      - test-binary-against-repo:
          repo: cypress-documentation
          browser: firefox
          command: "npm run cypress:run"
          wait-on: http://localhost:2222

  "test-binary-against-realworld-firefox":
    <<: *defaults
    steps:
      - test-binary-against-repo:
          repo: cypress-example-realworld
          browser: firefox
          command: "npm run cypress:run"

  "test-binary-against-api-testing-firefox":
    <<: *defaults
    steps:
      - test-binary-against-repo:
          repo: cypress-example-api-testing
          browser: firefox
          command: "npm run cy:run"

  "test-binary-against-piechopper-firefox":
    <<: *defaults
    steps:
      - test-binary-against-repo:
          repo: cypress-example-piechopper
          browser: firefox
          command: "npm run cypress:run"

  "test-binary-against-cypress-realworld-app":
    <<: *defaults
    executor: cy-doc-plus
    steps:
      - test-binary-against-rwa:
          repo: cypress-realworld-app
          browser: chrome
          wait-on: http://localhost:3000

  test-binary-as-specific-user:
    <<: *defaults
    steps:
      - attach_workspace:
          at: ~/
      - check-conditional-ci
      # the user should be "node"
      - run: whoami
      - run: pwd
      # prints the current user's effective user id
      # for root it is 0
      # for other users it is a positive integer
      - run: node -e 'console.log(process.geteuid())'
      # make sure the binary and NPM package files are present
      - run: ls -l
      - run: ls -l cypress.zip cypress.tgz
      - run: mkdir test-binary
      - run:
          name: Create new NPM package
          working_directory: test-binary
          command: npm init -y
      - run:
          # install NPM from built NPM package folder
          name: Install Cypress
          working_directory: test-binary
          # force installing the freshly built binary
          command: CYPRESS_INSTALL_BINARY=~/cypress/cypress.zip npm i ~/cypress/cypress.tgz
      - run:
          name: Cypress help
          working_directory: test-binary
          command: $(yarn bin)/cypress help
      - run:
          name: Cypress info
          working_directory: test-binary
          command: $(yarn bin)/cypress info
      - run:
          name: Add Cypress demo
          working_directory: test-binary
          command: npx @bahmutov/cly init
      - run:
          name: Verify Cypress binary
          working_directory: test-binary
          command: DEBUG=cypress:cli $(yarn bin)/cypress verify
      - run:
          name: Run Cypress binary
          working_directory: test-binary
          command: DEBUG=cypress:cli $(yarn bin)/cypress run
      - store-npm-logs

linux-workflow: &linux-workflow
  jobs:
    - build
    - lint:
        name: Linux lint
        requires:
          - build
    - list-changed-packages:
        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
    # unit, integration and e2e tests
    - cli-visual-tests:
        requires:
          - build
    - unit-tests:
        requires:
          - build
    - server-unit-tests:
        requires:
          - build
    - server-integration-tests:
        requires:
          - build
    - server-performance-tests:
        requires:
          - build
    - server-e2e-tests-chrome:
        requires:
          - build
    - server-e2e-tests-electron:
        requires:
          - build
    - server-e2e-tests-firefox:
        requires:
          - build
    - server-e2e-tests-non-root:
        executor: non-root-docker-user
        requires:
          - build
    - driver-integration-tests-chrome:
        requires:
          - build
    - driver-integration-tests-firefox:
        requires:
          - build
    - runner-integration-tests-chrome:
        requires:
          - build
    - runner-integration-tests-firefox:
        requires:
          - build
    - runner-ct-integration-tests-chrome:
        requires:
          - build

    ## TODO: add these back in when flaky tests are fixed
    # - driver-integration-tests-electron:
    #     requires:
    #       - build
    - desktop-gui-integration-tests-2x:
        requires:
          - build
    - desktop-gui-component-tests:
        requires:
          - build
    - reporter-integration-tests:
        requires:
          - build
    - ui-components-integration-tests:
        requires:
          - build
    - run-launcher:
        requires:
          - build

    - npm-webpack-dev-server:
        requires:
          - build
    - npm-vite-dev-server:
        requires:
          - build
    - npm-rollup-dev-server:
        requires:
          - build
    - npm-webpack-preprocessor:
        requires:
          - build
    - npm-webpack-batteries-included-preprocessor:
        requires:
          - build
    - npm-design-system:
        requires:
          - build
    - npm-vue:
        requires:
          - build
    - npm-react:
        requires:
          - build
    - npm-create-cypress-tests:
        requires:
          - build
    - npm-eslint-plugin-dev:
        requires:
          - build
    - npm-release:
        requires:
          - build

    # various testing scenarios, like building full binary
    # and testing it on a real project
    - test-against-staging:
        context: test-runner:record-tests
        filters:
          branches:
            only:
              - develop
              - fix-next-version
        requires:
          - build
    - test-kitchensink:
        requires:
          - build
    - test-kitchensink-against-staging:
        context: test-runner:record-tests
        filters:
          branches:
            only:
              - develop
              - fix-next-version
        requires:
          - build
    - create-build-artifacts:
        context:
          - test-runner:upload
          - test-runner:commit-status-checks
        requires:
          - build
    - test-npm-module-on-minimum-node-version:
        requires:
          - create-build-artifacts
    - test-types-cypress-and-jest:
        requires:
          - create-build-artifacts
    - test-cypress-scaffold:
        requires:
          - create-build-artifacts
    - test-full-typescript-project:
        requires:
          - create-build-artifacts
    - test-binary-against-kitchensink:
        requires:
          - create-build-artifacts
    # 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
    # against this branch. This workflow job includes
    # the job but only when it runs on specific branch
    # DO NOT DELETE THIS JOB BEFORE MERGING TO DEVELOP
    # on "develop" this branch will be ignored anyway
    # and someone else might use this job definition for another
    # feature branch and would just update the branch filter
    # - test-binary-against-recipe-pull-request:
    #     name: Test cypress run parsing
    #     filters:
    #       branches:
    #         only:
    #           - cli-to-module-api-7760
        # requires:
        #   - create-build-artifacts
    - test-binary-against-awesome-typescript-loader:
        requires:
          - create-build-artifacts
    - test-binary-and-npm-against-other-projects:
        context: test-runner:trigger-test-jobs
        filters:
          branches:
            only:
              - develop
              - fix-next-version
        requires:
          - create-build-artifacts
    - test-npm-module-and-verify-binary:
        filters:
          branches:
            only:
              - develop
              - fix-next-version
        requires:
          - create-build-artifacts
    - test-binary-against-staging:
        context: test-runner:record-tests
        filters:
          branches:
            only:
              - develop
              - fix-next-version
        requires:
          - create-build-artifacts

    - test-binary-against-recipes-firefox:
        <<: *testBinaryFirefox
    - test-binary-against-kitchensink-firefox:
        <<: *testBinaryFirefox
    - test-binary-against-kitchensink-chrome:
        <<: *testBinaryFirefox
    - test-binary-against-todomvc-firefox:
        <<: *testBinaryFirefox
    - test-binary-against-documentation-firefox:
        <<: *testBinaryFirefox
    - test-binary-against-api-testing-firefox:
        <<: *testBinaryFirefox
    - test-binary-against-realworld-firefox:
        <<: *testBinaryFirefox
    - test-binary-against-piechopper-firefox:
        <<: *testBinaryFirefox
    - test-binary-against-cypress-realworld-app:
        executor: cy-doc-plus
        filters:
          branches:
            only:
              - develop
              - fix-next-version
        requires:
          - create-build-artifacts

    - test-binary-as-specific-user:
        name: "test binary as a non-root user"
        executor: non-root-docker-user
        requires:
          - create-build-artifacts
    - test-binary-as-specific-user:
        name: "test binary as a root user"
        requires:
          - create-build-artifacts

mac-workflow: &mac-workflow
  jobs:
    - build:
        name: darwin-build
        executor: mac
        <<: *macBuildFilters

    - lint:
        name: darwin-lint
        executor: mac
        <<: *macBuildFilters
        requires:
          - darwin-build

    # maybe run all unit tests?

    - create-build-artifacts:
        name: darwin-create-build-artifacts
        context:
          - test-runner:sign-mac-binary
          - test-runner:upload
          - test-runner:commit-status-checks
        executor: mac
        <<: *macBuildFilters
        requires:
          - darwin-build

    - test-kitchensink:
        name: darwin-test-kitchensink
        executor: mac
        <<: *macBuildFilters
        requires:
          - darwin-build

    - test-binary-against-kitchensink:
        name: darwin-test-binary-against-kitchensink
        executor: mac
        <<: *macBuildFilters
        requires:
          - darwin-create-build-artifacts

    - test-binary-against-staging:
        context: test-runner:record-tests
        name: darwin-test-binary-against-staging
        executor: mac
        filters:
          branches:
            only:
              - develop
              - fix-next-version
        requires:
          - darwin-create-build-artifacts

    - test-binary-and-npm-against-other-projects:
        context: test-runner:trigger-test-jobs
        name: darwin-test-binary-and-npm-against-other-projects
        executor: mac
        filters:
          branches:
            only:
              - develop
              - fix-next-version
        requires:
          - darwin-create-build-artifacts

workflows:
  linux:
    <<: *linux-workflow
  mac:
    <<: *mac-workflow
