From d1c8fd04b58cfee2e743ec3e6e66c9705818d207 Mon Sep 17 00:00:00 2001 From: Cameron Rollheiser Date: Wed, 8 Jul 2020 16:22:39 -0400 Subject: [PATCH] Multistage Docker + Test in Docker This change updates force to use a multistage docker build and leverages the new docker build enginer, buildkit. Some of the benefits are better layer caching, meaning we should see decreases in the average image build time, we now run our tests in the same docker image that they are compiled in, and the production image is significantly smaller (down to 500MiB from 3GiB). --- .circleci/config.yml | 222 ++++++++++++++++----------- .dockerignore | 51 +++--- Dockerfile | 216 +++++++++++++++++++++++--- hokusai/build.yml | 5 +- hokusai/development.yml | 3 +- hokusai/test.yml | 3 +- jest.config.v1.js | 30 ++++ jest.config.js => jest.config.v2.js | 14 +- package.json | 17 +- scripts/acceptance.sh | 14 +- scripts/smoke_test.sh | 19 ++- scripts/xvfb-run.sh | 5 + src/test/acceptance/artist.js | 5 - src/test/acceptance/helpers/index.js | 29 ++-- yarn.lock | 173 ++++++++++++++++----- 15 files changed, 589 insertions(+), 217 deletions(-) create mode 100644 jest.config.v1.js rename jest.config.js => jest.config.v2.js (71%) create mode 100755 scripts/xvfb-run.sh diff --git a/.circleci/config.yml b/.circleci/config.yml index e63e1400b10..408314db0bd 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -6,6 +6,7 @@ orbs: horizon: artsy/release@0.0.1 node: artsy/node@1.0.0 yarn: artsy/yarn@5.1.3 + artsy-remote-docker: artsy/remote-docker@dev:d16c1de2b9f6072b68c6b2c8ef44cbe7 jobs: run_deepcrawl_automator: @@ -20,14 +21,6 @@ jobs: - run: name: Start automator crawl command: chmod +x automator.sh && ./automator.sh - acceptance_cypress: - docker: - - image: circleci/node:12-stretch-browsers - steps: - - yarn/setup - - run: - name: Cypress Tests - command: yarn test:smoke validate_production_schema: executor: node/build @@ -37,29 +30,6 @@ jobs: name: Validate Production Schema command: node scripts/validateSchemas.js production - build: - executor: node/build - steps: - - yarn/setup - - run: - name: Build force assets - command: yarn assets - - store_artifacts: - path: ~/project/.artifacts - - run: - name: Duplicates Report - command: curl "https://artsy-dupe-report.now.sh/packages/dupe-report/now.js?owner=artsy&repo=force&buildNum=$CIRCLE_BUILD_NUM" - - # FIXME: Reenable after https://github.com/artsy/force/pull/5673 is addressed - # danger: - # executor: node/build - # steps: - # - yarn/setup - # - run: - # name: Danger - # # Formatted this way to prevent GitHub's token detection. This is intended to be committed and public. - # command: DANGER_GITHUB_API_TOKEN="3f715685d9d032e17""48c3368dc8f22c672849136" yarn danger ci - create_or_update_review_app: executor: hokusai/deploy steps: @@ -76,15 +46,55 @@ jobs: name: "Create or update review app" command: | review_app_name=$(echo $CIRCLE_BRANCH | sed 's/review-app-//') - kubectl config use-context staging - if $(kubectl get namespace | grep -qi $review_app_name); then ./scripts/update_review_app.sh $review_app_name else ./scripts/build_review_app.sh $review_app_name fi + mocha: + executor: hokusai/deploy + steps: + - hokusai/setup-docker + - run: hokusai registry pull --tag "${CIRCLE_SHA1}-builder" + - run: docker run --rm -e NODE_ENV=test --entrypoint /bin/bash "hokusai_force" /usr/local/bin/yarn test:mocha + + jest-v1: + executor: hokusai/deploy + steps: + - hokusai/setup-docker + - run: hokusai registry pull --tag "${CIRCLE_SHA1}-builder" + - run: docker run --rm -e NODE_ENV=test --entrypoint /bin/bash "hokusai_force" /usr/local/bin/yarn test:jest:v1 + + jest-v2: + executor: hokusai/deploy + steps: + - hokusai/setup-docker + - run: hokusai registry pull --tag "${CIRCLE_SHA1}-builder" + - run: docker run --rm -e NODE_ENV=test --entrypoint /bin/bash "hokusai_force" /usr/local/bin/yarn test:jest:v2 + + type-check: + executor: hokusai/deploy + steps: + - hokusai/setup-docker + - run: hokusai registry pull --tag "${CIRCLE_SHA1}-builder" + - run: docker run --rm -e NODE_ENV=test --entrypoint /bin/bash "hokusai_force" /usr/local/bin/yarn type-check + + acceptance: + executor: hokusai/deploy + steps: + - hokusai/setup-docker + - run: hokusai registry pull --tag "${CIRCLE_SHA1}-electron-runner" + - run: docker run --rm --entrypoint /app/scripts/xvfb-run.sh "hokusai_force" /usr/local/bin/yarn test:acceptance + + acceptance-cypress: + executor: hokusai/deploy + steps: + - hokusai/setup-docker + - run: hokusai registry pull --tag "${CIRCLE_SHA1}-electron-runner" + - run: docker run --rm --entrypoint /app/scripts/xvfb-run.sh "hokusai_force" /usr/local/bin/yarn test:smoke + not_master_or_staging_or_release: ¬_master_or_staging_or_release filters: branches: @@ -115,80 +125,119 @@ only_release: &only_release workflows: default: jobs: - - horizon/block: - <<: *only_release - context: horizon - project_id: 11 + # Main build + - artsy-remote-docker/buildkit-build: + <<: *not_staging_or_release + context: hokusai + name: builder-build + pre-steps: + - run: + command: echo 'export BUILD_TARGET="builder";' >> $BASH_ENV - # Pre-staging - - yarn/jest: + - artsy-remote-docker/buildkit-push: <<: *not_staging_or_release - args: --runInBand + context: hokusai + name: builder-push + requires: + - builder-build + pre-steps: + - run: + command: echo 'export BUILD_TARGET="builder";' >> $BASH_ENV - - yarn/run: + # Electron Runner build + - artsy-remote-docker/buildkit-build: <<: *not_staging_or_release - name: test:mocha - script: "test:mocha" - - # TODO: Disabled due to memory issues. Can we use our workflows above and - # upload coverage that way (similar to reaction). We save a lot of time - # by running outside of an unnecessary docker context. - - # - hokusai/test: - # name: test - # <<: *not_staging_or_release - # post-steps: - # - run: mkdir -p ./coverage ./.nyc_output ./reports - # - run: - # name: Copy jest coverage artifacts - # command: docker cp hokusai_force_1:/app/coverage ./ - # when: always - # - codecov/upload: - # file: ./coverage/lcov.info - # - run: - # name: Copy mocha coverage artifacts - # command: docker cp hokusai_force_1:/app/.nyc_output ./ - # when: always - # - codecov/upload: - # file: ./.nyc_output/lcov.info - # - run: - # name: Copy coverage reports - # command: docker cp hokusai_force_1:/app/reports ./ - # when: always - # - store_test_results: - # path: ./reports - - - yarn/update-cache: + context: hokusai + name: electron-runner-build + requires: + - builder-build + pre-steps: + - run: + command: echo 'export BUILD_TARGET="electron-runner";' >> $BASH_ENV + + - artsy-remote-docker/buildkit-push: <<: *not_staging_or_release - - yarn/type-check: + context: hokusai + name: electron-runner-push + requires: + - electron-runner-build + pre-steps: + - run: + command: echo 'export BUILD_TARGET="electron-runner";' >> $BASH_ENV + + # Test steps + - mocha: <<: *not_staging_or_release - - acceptance_cypress: - <<: *not_master_or_staging_or_release - - build: + context: hokusai + requires: + - builder-push + + - jest-v1: + <<: *not_staging_or_release + context: hokusai + requires: + - builder-push + + - jest-v2: <<: *not_staging_or_release - # - danger: - # <<: *not_staging_or_release + context: hokusai + requires: + - builder-push + + - type-check: + <<: *not_staging_or_release + context: hokusai + requires: + - builder-push + + - acceptance: + <<: *not_staging_or_release + context: hokusai + requires: + - electron-runner-push + + - acceptance-cypress: + <<: *not_staging_or_release + context: hokusai + requires: + - electron-runner-push # Staging - - hokusai/push: - name: push-staging-image + - artsy-remote-docker/buildkit-build: <<: *only_master + context: hokusai + name: production-build requires: - - yarn/type-check - - yarn/jest - - test:mocha - - build + - mocha + - jest-v1 + - jest-v2 + - type-check + - acceptance + - acceptance-cypress + + - artsy-remote-docker/buildkit-push: + <<: *not_staging_or_release + context: hokusai + name: production-push + requires: + - production-build - hokusai/deploy-staging: <<: *only_master name: deploy-staging project-name: force requires: - - push-staging-image + - production-push # Release + - horizon/block: + <<: *only_release + context: horizon + project_id: 11 + - validate_production_schema: <<: *only_release + - hokusai/deploy-production: <<: *only_release name: deploy-production @@ -196,6 +245,7 @@ workflows: - horizon/block - validate_production_schema + # Other - run_deepcrawl_automator: context: deepcrawl-automator requires: diff --git a/.dockerignore b/.dockerignore index 51b9d788584..9fcbf53a60a 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,23 +1,36 @@ -.git -.gitignore -.dockerignore -Dockerfile -hokusai +# Prefer excluding all assets by default. It prevents large artifacts from +# accidentally becomming part of the Docker context. +* -README.md -LICENSE -VERSION -docs +# CI +!scripts/ -.DS_Store -.AppleDouble -.LSOverride +# Source +!data/ +!patches/ +!src/ +!webpack/ -.env -.env.* +# Testing +!__mocks__/ +!cypress/ !.env.oss -log -tmp -node_modules -.vscode -redis.conf +!.env.test +!cypress.json +!jest.config.v1.js +!jest.config.v2.js +!test.config.js +!test.mocha.js + +# Build Configuration +!.eslintrc.js +!.nvmrc +!.prettierignore +!apollo.config.js +!babel.config.js +!coffeelint.json +!dangerfile.ts +!package.json +!relay.config.js +!tsconfig.json +!yarn.lock diff --git a/Dockerfile b/Dockerfile index c474ad6a91d..fa1e68f1c2e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,39 +1,217 @@ -FROM node:12.14-alpine +# +------------------+ +# | | +# | builder-base | +# | | +# +------------------+ +# ^ +# | +# | +# +------------------+ +# | | +# | yarn-base | +# | | +# +------------------+ +# ^ +# | +# | +# +------------------+ +# | | +# | yarn-deps +<------------------------+ +# | | | +# +------------------+ | +# ^ | +# | | +# | | +# +------------------+ | +# | | | +# | builder-src | | +# | | | +# +------------------+ | +# ^ ^ | +# | | | +# | | | +# +------------------+ +------------------+ | +# | | | | | +# | builder-assets | | builder-server | | +# | | | | | +# +------------------+ +------------------+ | +# ^ ^ | +# | | | +# | | | +# +------------------+ | +# | | | +# | builder +<------------------+ | +# | | | | +# +------------------+ | | +# ^ | | +# | | | +# | | | +# +------------------+ +------------------+ +# | | | | +# | electron-runner | | production | +# | | | | +# +------------------+ +------------------+ + +# --------------------------------------------------------- +# Base build dependencies +# --------------------------------------------------------- +FROM node:12.14-alpine as builder-base + +WORKDIR /app # Install system dependencies -# Add deploy user RUN apk --no-cache --quiet add \ bash \ build-base \ curl \ - dumb-init \ git \ - python && \ - adduser -D -g '' deploy + python + +# --------------------------------------------------------- +# Yarn base +# --------------------------------------------------------- +FROM builder-base as yarn-base + +# Copy files required for installation of application dependencies +COPY package.json yarn.lock ./ +COPY patches ./patches + +# --------------------------------------------------------- +# Yarn dependencies +# --------------------------------------------------------- +FROM yarn-base as yarn-deps + +RUN yarn install --production --frozen-lockfile --quiet \ + && mv node_modules /opt/node_modules.prod \ + && yarn install --frozen-lockfile --quiet \ + && yarn cache clean --force + +# --------------------------------------------------------- +# Builder with source code +# --------------------------------------------------------- +FROM yarn-deps as builder-src + +# Copy application code +COPY __mocks__ ./__mocks__ +COPY cypress ./cypress +COPY data ./data +COPY patches ./patches +COPY src ./src +COPY webpack ./webpack +COPY .env.oss \ + .env.test \ + .eslintrc.js \ + .nvmrc \ + .prettierignore \ + apollo.config.js \ + babel.config.js \ + coffeelint.json \ + cypress.json \ + dangerfile.ts \ + jest.config.v1.js \ + jest.config.v2.js \ + package.json \ + relay.config.js \ + test.config.js \ + test.mocha.js \ + tsconfig.json \ + yarn.lock \ + ./ + +# --------------------------------------------------------- +# Compile assets +# --------------------------------------------------------- +FROM builder-src as builder-assets + +# Build application +RUN yarn assets + +# --------------------------------------------------------- +# Compile server +# --------------------------------------------------------- +FROM builder-src as builder-server + +# Build application +RUN yarn build:server + +# --------------------------------------------------------- +# All development assets +# --------------------------------------------------------- +FROM builder-src as builder + +# Scripts +COPY ./scripts ./scripts + +# Client assets +COPY --from=builder-assets /app/manifest.json . +COPY --from=builder-assets /app/public ./public +COPY --from=builder-assets /app/src ./src + +# Server assets +COPY --from=builder-server /app/server.dist.js . +COPY --from=builder-server /app/server.dist.js.map . + +# --------------------------------------------------------- +# Image with xvfb to run Electron with a virtual display +# --------------------------------------------------------- +FROM node:12.18.4-stretch as electron-runner WORKDIR /app -# Set the correct owner on the /app +# Install electron deps +RUN apt-get update && apt-get install -y \ + libgtk2.0-0 \ + libgtk-3-0 \ + libgbm-dev \ + libnotify-dev \ + libgconf-2-4 \ + libnss3 \ + libxss1 \ + libasound2 \ + libxtst6 \ + xauth \ + xvfb + +COPY --from=builder /app /app + +# --------------------------------------------------------- +# Release image +# --------------------------------------------------------- +# +# Release stage. This stage creates the final docker iamge that will be +# released. It contains only production dependencies and artifacts. +# +FROM node:12.14-alpine as production + +RUN apk --no-cache --quiet add \ + bash \ + dumb-init \ + && adduser -D -g '' deploy + +WORKDIR /app RUN chown deploy:deploy $(pwd) -# Switch to less-privileged user, do this early to ensure files are created -# with proper ownership. USER deploy -# Copy files required for installation of application dependencies -COPY --chown=deploy:deploy package.json yarn.lock ./ -COPY --chown=deploy:deploy patches ./patches +# Base code +COPY --chown=deploy:deploy --from=builder /app/data ./data +COPY --chown=deploy:deploy --from=builder /app/package.json . +COPY --chown=deploy:deploy --from=builder /app/scripts ./scripts +COPY --chown=deploy:deploy --from=builder /app/webpack ./webpack +COPY --chown=deploy:deploy --from=builder /app/yarn.lock . -# Install application dependencies -RUN yarn install --frozen-lockfile --quiet && \ - yarn cache clean --force +# Client assets +COPY --chown=deploy:deploy --from=builder /app/manifest.json . +COPY --chown=deploy:deploy --from=builder /app/public ./public +COPY --chown=deploy:deploy --from=builder /app/src ./src -# Copy application code -COPY --chown=deploy:deploy . ./ +# Server assets +COPY --chown=deploy:deploy --from=builder /app/server.dist.js . +COPY --chown=deploy:deploy --from=builder /app/server.dist.js.map . -# Build application -RUN yarn assets && \ - yarn build:server + +# Production node modules. +COPY --chown=deploy:deploy --from=yarn-deps /opt/node_modules.prod ./node_modules ENTRYPOINT ["/usr/bin/dumb-init", "--"] CMD ["yarn", "start"] diff --git a/hokusai/build.yml b/hokusai/build.yml index 534b57b09d8..f15e02846ed 100644 --- a/hokusai/build.yml +++ b/hokusai/build.yml @@ -1,5 +1,8 @@ -version: "2" +--- +version: "3.8" services: force: + image: "hokusai_force:${BUILD_TAG:-latest}" build: context: ../ + target: "${BUILD_TARGET}" diff --git a/hokusai/development.yml b/hokusai/development.yml index 542a29ad2e2..e446d12c9bb 100644 --- a/hokusai/development.yml +++ b/hokusai/development.yml @@ -1,4 +1,5 @@ -version: "2" +--- +version: "3.8" services: force: extends: diff --git a/hokusai/test.yml b/hokusai/test.yml index 4355ad46cd7..b03d2a4f658 100644 --- a/hokusai/test.yml +++ b/hokusai/test.yml @@ -1,4 +1,5 @@ -version: "2" +--- +version: "3.8" services: force: command: yarn test diff --git a/jest.config.v1.js b/jest.config.v1.js new file mode 100644 index 00000000000..e70d9669c41 --- /dev/null +++ b/jest.config.v1.js @@ -0,0 +1,30 @@ +const sharedConfig = { + transform: { + "\\.(gql|graphql)$": "jest-transform-graphql", + "^.+\\.coffee$": "/node_modules/jest-coffee-preprocessor/index.js", + ".(ts|tsx|js|jsx)": "babel-jest", + }, + cacheDirectory: ".cache/jest", + coverageDirectory: "./coverage/", + collectCoverage: false, + coverageReporters: ["lcov", "text-summary"], + reporters: ["default", "jest-junit"], + moduleFileExtensions: ["coffee", "js", "json", "jsx", "ts", "tsx"], +} + +module.exports = { + projects: [ + /** + * Config for wider force, excluding src/v2 directory + */ + { + ...sharedConfig, + displayName: "v1", + testPathIgnorePatterns: ["/src/v2"], + testRegex: ".*\\.jest\\.(ts|tsx|js|jsx)$", + setupFiles: ["/test.config.js"], + roots: ["/src"], + testURL: "https://artsy.net", + }, + ], +} diff --git a/jest.config.js b/jest.config.v2.js similarity index 71% rename from jest.config.js rename to jest.config.v2.js index 8067e3e1479..da5617e2d7d 100644 --- a/jest.config.js +++ b/jest.config.v2.js @@ -6,7 +6,7 @@ const sharedConfig = { }, cacheDirectory: ".cache/jest", coverageDirectory: "./coverage/", - collectCoverage: true, + collectCoverage: false, coverageReporters: ["lcov", "text-summary"], reporters: ["default", "jest-junit"], moduleFileExtensions: ["coffee", "js", "json", "jsx", "ts", "tsx"], @@ -14,18 +14,6 @@ const sharedConfig = { module.exports = { projects: [ - /** - * Config for wider force, excluding src/v2 directory - */ - { - ...sharedConfig, - displayName: "v1", - testPathIgnorePatterns: ["/src/v2"], - testRegex: ".*\\.jest\\.(ts|tsx|js|jsx)$", - setupFiles: ["/test.config.js"], - roots: ["/src"], - testURL: "https://artsy.net", - }, // Config for src/v2 (former Reaction code) { ...sharedConfig, diff --git a/package.json b/package.json index 76791a916e9..664a389ffba 100644 --- a/package.json +++ b/package.json @@ -21,8 +21,10 @@ "cypress:run": "./node_modules/.bin/cypress run", "cypress": "./node_modules/.bin/cypress open", "delete-review-app": "kubectl --context staging delete namespace", - "jest": "JEST_JUNIT_OUTPUT=reports/junit/js-test-results.xml node --expose-gc --max_old_space_size=4096 ./node_modules/.bin/jest --no-cache --runInBand --logHeapUsage", - "lint": "eslint --rulesdir ./eslint --cache --cache-location '.cache/eslint/' --ext ts,tsx --ignore-pattern 'src/v2/__generated__'", + "jest": "yarn jest:v1 && yarn jest:v2", + "jest:v1": "JEST_JUNIT_OUTPUT=reports/junit/js-test-results.xml node --expose-gc --max_old_space_size=4096 ./node_modules/.bin/jest --no-cache --runInBand --logHeapUsage --config jest.config.v1.js", + "jest:v2": "JEST_JUNIT_OUTPUT=reports/junit/js-test-results.xml node --expose-gc --max_old_space_size=4096 ./node_modules/.bin/jest --no-cache --runInBand --logHeapUsage --config jest.config.v2.js", + "lint": "eslint --cache --cache-location '.cache/eslint/' --ext ts,tsx --ignore-pattern 'src/v2/__generated__'", "mocha": "scripts/mocha.sh", "prepare": "patch-package", "prettier-project": "yarn run prettier-write 'src/**/*.{ts,tsx,js,jsx}'", @@ -36,9 +38,12 @@ "start:prod": "yarn assets && yarn build:server && NODE_ENV=production yarn start", "start": "scripts/start.sh", "storybook": "concurrently --raw --kill-others 'yarn relay --watch' 'start-storybook --quiet -s ./public -p 9001'", + "test:acceptance": "yarn acceptance src/test/acceptance/*.js", "test:smoke": "scripts/smoke_test.sh", "test": "scripts/test.sh", - "test:jest": "node node_modules/.bin/jest", + "test:jest": "node --expose-gc --max_old_space_size=4096 node_modules/.bin/jest --logHeapUsage", + "test:jest:v1": "node --expose-gc --max_old_space_size=4096 ./node_modules/.bin/jest --logHeapUsage --config jest.config.v1.js", + "test:jest:v2": "node --expose-gc --max_old_space_size=4096 ./node_modules/.bin/jest --logHeapUsage --runInBand --config jest.config.v2.js", "test:mocha": "yarn mocha $(find src -name '*.test.js')", "type-check": "tsc", "unlink-all": "yalc remove --all && yarn --check-files", @@ -96,6 +101,7 @@ "cookie-parser": "1.4.3", "cookie-session": "2.0.0-beta.3", "cookies-js": "1.2.3", + "core-js": "2.6.5", "cors": "2.8.3", "dd-trace": "0.7.3", "diacritics": "1.3.0", @@ -152,7 +158,6 @@ "nock": "9.0.13", "node-uuid": "1.4.8", "nouislider": "9.2.0", - "nyc": "13.3.0", "openseadragon": "2.4.0", "particle": "artsy/particle", "path-to-regexp": "6.1.0", @@ -193,6 +198,7 @@ "scroll-frame": "1.0.0", "serve-favicon": "2.4.3", "sharify": "0.1.6", + "source-map-support": "0.5.10", "standard": "9.0.2", "stickyfill": "1.1.1", "styled-components": "4.3.2", @@ -282,7 +288,6 @@ "cache-loader": "1.2.2", "coffee-loader": "0.8.0", "coffeescript": "1.11.1", - "core-js": "2.6.5", "cypress": "5.1.0", "danger": "7.0.16", "electron": "3.0.16", @@ -318,6 +323,7 @@ "mocha-junit-reporter": "1.22.0", "mocha-multi-reporters": "1.1.7", "nightmare": "2.10.0", + "nyc": "13.3.0", "patch-package": "6.2.0", "postinstall-prepare": "1.0.1", "prettier": "2.0.5", @@ -335,7 +341,6 @@ "should": "11.2.1", "simple-progress-webpack-plugin": "1.1.2", "sinon": "1.17.7", - "source-map-support": "0.5.10", "speed-measure-webpack-plugin": "1.3.3", "static-extend": "0.1.2", "strip-ansi": "5.0.0", diff --git a/scripts/acceptance.sh b/scripts/acceptance.sh index 9a539eb0c59..027c0379872 100755 --- a/scripts/acceptance.sh +++ b/scripts/acceptance.sh @@ -2,16 +2,18 @@ set -ex -# Build the client assets for testing -export BUILD_CLIENT=true +if [ ! -f server.dist.js ]; then + # Build the client assets for testing + export BUILD_CLIENT=true -# CSS is only compiled during a development build? -export NODE_ENV=production + # CSS is only compiled during a development build? + export NODE_ENV=production -yarn webpack + yarn webpack +fi mocha \ --retries 5 \ --require test.config.js \ - -t 60000 \ + -t 360000 \ $@ diff --git a/scripts/smoke_test.sh b/scripts/smoke_test.sh index 1bd8219ba6b..dd81191dd4d 100755 --- a/scripts/smoke_test.sh +++ b/scripts/smoke_test.sh @@ -1,6 +1,6 @@ #! /bin/bash -set -euxo pipefail +set -ex # provide a default environment if none exists if [ ! -f ".env" ]; then @@ -8,19 +8,24 @@ if [ ! -f ".env" ]; then cp .env.oss .env fi -# prepare a production build -yarn assets -yarn build:server +# # prepare a production build +if [ ! -f server.dist.js ]; then + yarn assets + yarn build:server +fi # start server in the background in production mode -NODE_ENV=production yarn start & +NODE_ENV=production nohup yarn start & # wait for it to accept connections ./node_modules/.bin/wait-on http://localhost:5000 +sleep 10 + +export ELECTRON_EXTRA_LAUNCH_ARGS=disable-dev-shm-usage # run ./cypress/integration/* tests in headless mode ./node_modules/.bin/cypress install ./node_modules/.bin/cypress run -# kill server -kill $! +# Kill the server +kill -9 $! || true diff --git a/scripts/xvfb-run.sh b/scripts/xvfb-run.sh new file mode 100755 index 00000000000..efb52ee30c3 --- /dev/null +++ b/scripts/xvfb-run.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +DISPLAY_MACBOOK_AIR=1440x900x24 + +xvfb-run --server-args="-screen 0 $DISPLAY_MACBOOK_AIR" $@ diff --git a/src/test/acceptance/artist.js b/src/test/acceptance/artist.js index d435826161c..9e34b86fef5 100644 --- a/src/test/acceptance/artist.js +++ b/src/test/acceptance/artist.js @@ -1,10 +1,5 @@ /* eslint-env mocha */ import { setup, teardown } from "./helpers" -import { JSDOM } from "jsdom" - -const jsdom = new JSDOM("") -global.Node = jsdom.window.Node -global.DOMParser = jsdom.window.DOMParser describe("Artist page", () => { let metaphysics, browser diff --git a/src/test/acceptance/helpers/index.js b/src/test/acceptance/helpers/index.js index 62e7be4d4b5..6bb5ca5bd32 100644 --- a/src/test/acceptance/helpers/index.js +++ b/src/test/acceptance/helpers/index.js @@ -35,15 +35,15 @@ export const setup = async () => { positron = await startApp(POSITRON_PORT) metaphysics = await startApp(METAPHYSICS_PORT) force = await startForce(FORCE_PORT) - browser = mixinBrowserHelpers( - Nightmare({ - waitTimeout: TIMEOUT, - gotoTimeout: TIMEOUT, - loadTimeout: TIMEOUT, - executionTimeout: TIMEOUT, - typeInterval: 10, - }) - ) + browser = Nightmare({ + waitTimeout: TIMEOUT, + gotoTimeout: TIMEOUT, + loadTimeout: TIMEOUT, + executionTimeout: TIMEOUT, + typeInterval: 10, + }) + + initializeBrowser(browser) // Make sure cancelling the process cleans up the servers/Electron process.on("exit", teardown) @@ -77,7 +77,7 @@ export const sleep = ms => setTimeout(resolve, ms) }) -const mixinBrowserHelpers = browser => { +function initializeBrowser(browser) { // Steps to log in through the auth modal browser.login = async () => { await browser.el(".mlh-login") @@ -104,10 +104,10 @@ const mixinBrowserHelpers = browser => { }, selector) return html } - return browser } -const warn = e => console.log(chalk.red(e)) +// eslint-disable-next-line +const warn = e => console.log("warning", chalk.yellow(e)) const startForce = port => new Promise((resolve, reject) => { @@ -142,10 +142,7 @@ const startGravity = port => app.get("/api/v1/xapp_token", (req, res) => { res.send({ xapp_token: "xapp-token", - expires_in: moment() - .add(100, "days") - .utc() - .format(), + expires_in: moment().add(100, "days").utc().format(), }) }) app.get("/api/v1/profile/pace-gallery", (req, res) => { diff --git a/yarn.lock b/yarn.lock index 5d1261669a5..fd5575623d2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3136,13 +3136,14 @@ "@types/yargs" "^15.0.0" chalk "^3.0.0" -"@jest/types@^26.0.1": - version "26.0.1" - resolved "https://registry.yarnpkg.com/@jest/types/-/types-26.0.1.tgz#b78333fbd113fa7aec8d39de24f88de8686dac67" - integrity sha512-IbtjvqI9+eS1qFnOIEL7ggWmT+iK/U+Vde9cGWtYb/b6XgKb3X44ZAe/z9YZzoAAZ/E92m0DqrilF934IGNnQA== +"@jest/types@^26.3.0": + version "26.3.0" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-26.3.0.tgz#97627bf4bdb72c55346eef98e3b3f7ddc4941f71" + integrity sha512-BDPG23U0qDeAvU4f99haztXwdAg3hz4El95LkAM+tHAqqhiVzRpEGHHU8EDxT/AnxOrA65YjLBwDahdJ9pTLJQ== dependencies: "@types/istanbul-lib-coverage" "^2.0.0" - "@types/istanbul-reports" "^1.1.1" + "@types/istanbul-reports" "^3.0.0" + "@types/node" "*" "@types/yargs" "^15.0.0" chalk "^4.0.0" @@ -4404,6 +4405,13 @@ "@types/istanbul-lib-coverage" "*" "@types/istanbul-lib-report" "*" +"@types/istanbul-reports@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.0.tgz#508b13aa344fa4976234e75dddcc34925737d821" + integrity sha512-nwKNbvnwJ2/mndE9ItP/zc2TCzw6uuodnF4EHYWD+gCQDVBuRQL5UzbZD0/ezy1iKsFU2ZQiDqg4M9dN4+wZgA== + dependencies: + "@types/istanbul-lib-report" "*" + "@types/jest-diff@*": version "24.3.0" resolved "https://registry.yarnpkg.com/@types/jest-diff/-/jest-diff-24.3.0.tgz#29e237a3d954babfe6e23cc59b57ecd8ca8d858d" @@ -5107,6 +5115,11 @@ acorn@^5.0.0, acorn@^5.0.1, acorn@^5.3.0: resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.3.tgz#67aa231bf8812974b85235a96771eb6bd07ea279" integrity sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw== +acorn@^5.5.3: + version "5.7.4" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.4.tgz#3e8d8a9947d0599a1796d10225d7432f4a4acf5e" + integrity sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg== + acorn@^6.0.1, acorn@^6.1.1, acorn@^6.4.1: version "6.4.1" resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.1.tgz#531e58ba3f51b9dacb9a6646ca4debf5b14ca474" @@ -8693,6 +8706,13 @@ cssom@~0.3.6: dependencies: cssom "0.3.x" +cssstyle@^1.0.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-1.4.0.tgz#9d31328229d3c565c61e586b02041a28fccdccf1" + integrity sha512-GBrLZYZ4X4x6/QEoBnIrqb8B/f5l4+8me2dkom/j1Gtbxy0kBv6OGzKuAsGM75bkGwGAFkt56Iwg28S3XTZgSA== + dependencies: + cssom "0.3.x" + cssstyle@^2.0.0: version "2.3.0" resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-2.3.0.tgz#ff665a0ddbdc31864b09647f34163443d90b0852" @@ -8877,7 +8897,7 @@ dashify@^0.2.0: resolved "https://registry.yarnpkg.com/dashify/-/dashify-0.2.2.tgz#6a07415a01c91faf4a32e38d9dfba71f61cb20fe" integrity sha1-agdBWgHJH69KMuONnfunH2HLIP4= -data-urls@^1.1.0: +data-urls@^1.0.0, data-urls@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-1.1.0.tgz#15ee0582baa5e22bb59c77140da8f9c76963bbfe" integrity sha512-YTWYI9se1P55u58gL5GkQHW4P6VJBJ5iBT+B5a7i2Tjadhv52paJG0qHX4A0OR6/t52odI64KP2YvFpkDOi3eQ== @@ -9303,10 +9323,10 @@ diff-sequences@^25.2.6: resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-25.2.6.tgz#5f467c00edd35352b7bca46d7927d60e687a76dd" integrity sha512-Hq8o7+6GaZeoFjtpgvRBUknSXNeJiCx7V9Fr94ZMljNiCr9n9L8H8aJqgWOQiDDGdyn29fRNcDdRVJ5fdyihfg== -diff-sequences@^26.0.0: - version "26.0.0" - resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-26.0.0.tgz#0760059a5c287637b842bd7085311db7060e88a6" - integrity sha512-JC/eHYEC3aSS0vZGjuoc4vHA0yAQTzhQQldXMeMF+JlxLGJlCO38Gma82NV9gk1jGFz8mDzUMeaKXvjRRdJ2dg== +diff-sequences@^26.3.0: + version "26.3.0" + resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-26.3.0.tgz#62a59b1b29ab7fd27cef2a33ae52abe73042d0a2" + integrity sha512-5j5vdRcw3CNctePNYN0Wy2e/JbWT6cAYnXv5OuqPhDpyCGc0uLu2TK0zOCJWNB9kOIfYMSpIulRaDgIi4HJ6Ig== diff@3.2.0: version "3.2.0" @@ -10068,7 +10088,7 @@ escape-string-regexp@1.0.5, escape-string-regexp@^1.0.0, escape-string-regexp@^1 resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= -escodegen@^1.11.1: +escodegen@^1.11.1, escodegen@^1.9.1: version "1.14.3" resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.14.3.tgz#4e7b81fba61581dc97582ed78cab7f0e8d63f503" integrity sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw== @@ -14093,14 +14113,14 @@ jest-config@^25.5.4: realpath-native "^2.0.0" jest-diff@*: - version "26.0.1" - resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-26.0.1.tgz#c44ab3cdd5977d466de69c46929e0e57f89aa1de" - integrity sha512-odTcHyl5X+U+QsczJmOjWw5tPvww+y9Yim5xzqxVl/R1j4z71+fHW4g8qu1ugMmKdFdxw+AtQgs5mupPnzcIBQ== + version "26.4.2" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-26.4.2.tgz#a1b7b303bcc534aabdb3bd4a7caf594ac059f5aa" + integrity sha512-6T1XQY8U28WH0Z5rGpQ+VqZSZz8EN8rZcBtfvXaOkbwxIEeRre6qnuZQlbY1AJ4MKDxQF8EkrCvK+hL/VkyYLQ== dependencies: chalk "^4.0.0" - diff-sequences "^26.0.0" - jest-get-type "^26.0.0" - pretty-format "^26.0.1" + diff-sequences "^26.3.0" + jest-get-type "^26.3.0" + pretty-format "^26.4.2" jest-diff@^24.9.0: version "24.9.0" @@ -14220,10 +14240,10 @@ jest-get-type@^25.2.6: resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-25.2.6.tgz#0b0a32fab8908b44d508be81681487dbabb8d877" integrity sha512-DxjtyzOHjObRM+sM1knti6or+eOgcGU4xVSb2HNP1TqO4ahsT+rqZg+nyqHWJSvWgKC5cG3QjGFBqxLghiF/Ig== -jest-get-type@^26.0.0: - version "26.0.0" - resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-26.0.0.tgz#381e986a718998dbfafcd5ec05934be538db4039" - integrity sha512-zRc1OAPnnws1EVfykXOj19zo2EMw5Hi6HLbFCSjpuJiXtOWAYIjNsHVSbpQ8bDX7L5BGYGI8m+HmKdjHYFF0kg== +jest-get-type@^26.3.0: + version "26.3.0" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-26.3.0.tgz#e97dc3c3f53c2b406ca7afaed4493b1d099199e0" + integrity sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig== jest-haste-map@^24.9.0: version "24.9.0" @@ -14906,7 +14926,7 @@ jsdom-global@3.0.2: resolved "https://registry.yarnpkg.com/jsdom-global/-/jsdom-global-3.0.2.tgz#6bd299c13b0c4626b2da2c0393cd4385d606acb9" integrity sha1-a9KZwTsMRiay2iwDk81DhdYGrLk= -jsdom@11.6.2, "jsdom@>= 10.0", jsdom@^11.5.1: +jsdom@11.6.2, "jsdom@>= 10.0": version "11.6.2" resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-11.6.2.tgz#25d1ef332d48adf77fc5221fe2619967923f16bb" integrity sha512-pAeZhpbSlUp5yQcS6cBQJwkbzmv4tWFaYxHbFVSxzXefqjvtRA851Z5N2P+TguVG9YeUDcgb8pdeVQRJh0XR3Q== @@ -14938,6 +14958,38 @@ jsdom@11.6.2, "jsdom@>= 10.0", jsdom@^11.5.1: ws "^4.0.0" xml-name-validator "^3.0.0" +jsdom@^11.5.1: + version "11.12.0" + resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-11.12.0.tgz#1a80d40ddd378a1de59656e9e6dc5a3ba8657bc8" + integrity sha512-y8Px43oyiBM13Zc1z780FrfNLJCXTL40EWlty/LXUtcjykRBNgLlCjWXpfSPBl2iv+N7koQN+dvqszHZgT/Fjw== + dependencies: + abab "^2.0.0" + acorn "^5.5.3" + acorn-globals "^4.1.0" + array-equal "^1.0.0" + cssom ">= 0.3.2 < 0.4.0" + cssstyle "^1.0.0" + data-urls "^1.0.0" + domexception "^1.0.1" + escodegen "^1.9.1" + html-encoding-sniffer "^1.0.2" + left-pad "^1.3.0" + nwsapi "^2.0.7" + parse5 "4.0.0" + pn "^1.1.0" + request "^2.87.0" + request-promise-native "^1.0.5" + sax "^1.2.4" + symbol-tree "^3.2.2" + tough-cookie "^2.3.4" + w3c-hr-time "^1.0.1" + webidl-conversions "^4.0.2" + whatwg-encoding "^1.0.3" + whatwg-mimetype "^2.1.0" + whatwg-url "^6.4.1" + ws "^5.2.0" + xml-name-validator "^3.0.0" + jsdom@^15.2.1: version "15.2.1" resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-15.2.1.tgz#d2feb1aef7183f86be521b8c6833ff5296d07ec5" @@ -15401,6 +15453,11 @@ left-pad@^1.2.0: resolved "https://registry.yarnpkg.com/left-pad/-/left-pad-1.2.0.tgz#d30a73c6b8201d8f7d8e7956ba9616087a68e0ee" integrity sha1-0wpzxrggHY99jnlWupYWCHpo4O4= +left-pad@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/left-pad/-/left-pad-1.3.0.tgz#5b8a3a7765dfe001261dde915589e782f8c94d1e" + integrity sha512-XI5MPzVNApjAyhQzphX8BkmKsKUxD4LdyK24iZeQGinBN9yTQT3bFlCBy/aVx2HrNcqQGsdot8ghrjyrvMCoEA== + leven@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/leven/-/leven-2.1.0.tgz#c2e7a9f772094dee9d34202ae8acce4687875580" @@ -17141,7 +17198,7 @@ nwmatcher@^1.4.3: resolved "https://registry.yarnpkg.com/nwmatcher/-/nwmatcher-1.4.4.tgz#2285631f34a95f0d0395cd900c96ed39b58f346e" integrity sha512-3iuY4N5dhgMpCUrOVnuAdGrgxVqV2cJpM+XNccjR2DKOB1RUP0aA+wGXEiNziG/UKboFyGBIoKOaNlJxx8bciQ== -nwsapi@^2.2.0: +nwsapi@^2.0.7, nwsapi@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.0.tgz#204879a9e3d068ff2a55139c2c772780681a38b7" integrity sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ== @@ -18466,12 +18523,12 @@ pretty-format@^25.5.0: ansi-styles "^4.0.0" react-is "^16.12.0" -pretty-format@^26.0.1: - version "26.0.1" - resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-26.0.1.tgz#a4fe54fe428ad2fd3413ca6bbd1ec8c2e277e197" - integrity sha512-SWxz6MbupT3ZSlL0Po4WF/KujhQaVehijR2blyRDCzk9e45EaYMVhMBn49fnRuHxtkSpXTes1GxNpVmH86Bxfw== +pretty-format@^26.4.2: + version "26.4.2" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-26.4.2.tgz#d081d032b398e801e2012af2df1214ef75a81237" + integrity sha512-zK6Gd8zDsEiVydOCGLkoBoZuqv8VTiHyAbKznXe/gaph/DAeZOmit9yMfgIz5adIgAMMs5XfoYSwAX3jcCO1tA== dependencies: - "@jest/types" "^26.0.1" + "@jest/types" "^26.3.0" ansi-regex "^5.0.0" ansi-styles "^4.0.0" react-is "^16.12.0" @@ -20427,6 +20484,32 @@ request@^2.45.0, request@^2.75.0, request@^2.83.0: tunnel-agent "^0.6.0" uuid "^3.1.0" +request@^2.87.0: + version "2.88.2" + resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3" + integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw== + dependencies: + aws-sign2 "~0.7.0" + aws4 "^1.8.0" + caseless "~0.12.0" + combined-stream "~1.0.6" + extend "~3.0.2" + forever-agent "~0.6.1" + form-data "~2.3.2" + har-validator "~5.1.3" + http-signature "~1.2.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.19" + oauth-sign "~0.9.0" + performance-now "^2.1.0" + qs "~6.5.2" + safe-buffer "^5.1.2" + tough-cookie "~2.5.0" + tunnel-agent "^0.6.0" + uuid "^3.3.2" + request@^2.88.0: version "2.88.0" resolved "https://registry.yarnpkg.com/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef" @@ -22827,6 +22910,14 @@ tough-cookie@>=2.3.3, tough-cookie@^2.3.3, tough-cookie@~2.4.3: psl "^1.1.24" punycode "^1.4.1" +tough-cookie@^2.3.4, tough-cookie@~2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2" + integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g== + dependencies: + psl "^1.1.28" + punycode "^2.1.1" + tough-cookie@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-3.0.1.tgz#9df4f57e739c26930a018184887f4adb7dca73b2" @@ -22843,14 +22934,6 @@ tough-cookie@~2.3.3: dependencies: punycode "^1.4.1" -tough-cookie@~2.5.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2" - integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g== - dependencies: - psl "^1.1.28" - punycode "^2.1.1" - tr46@^1.0.0, tr46@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/tr46/-/tr46-1.0.1.tgz#a8b13fd6bfd2489519674ccde55ba3693b706d09" @@ -24023,7 +24106,7 @@ whatwg-fetch@>=0.10.0: resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.2.0.tgz#8e134f701f0a4ab5fda82626f113e2b647fd16dc" integrity sha512-SdGPoQMMnzVYThUbSrEvqTlkvC1Ux27NehaJ/GUHBfNrh5Mjg+1/uRyFMwVnxO2MrikMWvWAqUGgQOfVU4hT7w== -whatwg-mimetype@^2.2.0, whatwg-mimetype@^2.3.0: +whatwg-mimetype@^2.1.0, whatwg-mimetype@^2.2.0, whatwg-mimetype@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf" integrity sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g== @@ -24037,6 +24120,15 @@ whatwg-url@^6.4.0: tr46 "^1.0.0" webidl-conversions "^4.0.1" +whatwg-url@^6.4.1: + version "6.5.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-6.5.0.tgz#f2df02bff176fd65070df74ad5ccbb5a199965a8" + integrity sha512-rhRZRqx/TLJQWUpQ6bmrt2UV4f0HCQ463yQuONJqC6fO2VoEb1pTYddbe59SkYq87aoM5A3bdhMZiUiVws+fzQ== + dependencies: + lodash.sortby "^4.7.0" + tr46 "^1.0.1" + webidl-conversions "^4.0.2" + whatwg-url@^7.0.0: version "7.1.0" resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-7.1.0.tgz#c2c492f1eca612988efd3d2266be1b9fc6170d06" @@ -24297,6 +24389,13 @@ ws@^4.0.0: async-limiter "~1.0.0" safe-buffer "~5.1.0" +ws@^5.2.0: + version "5.2.2" + resolved "https://registry.yarnpkg.com/ws/-/ws-5.2.2.tgz#dffef14866b8e8dc9133582514d1befaf96e980f" + integrity sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA== + dependencies: + async-limiter "~1.0.0" + ws@^6.0.0: version "6.2.1" resolved "https://registry.yarnpkg.com/ws/-/ws-6.2.1.tgz#442fdf0a47ed64f59b6a5d8ff130f4748ed524fb"