diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index de6f757d8ace..bab46d79d261 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -17,14 +17,6 @@ updates:
# We don't use storybook at the moment.
- dependency-name: "@storybook/*"
- # In https://github.com/mdn/yari/issues/3694 we discovered that
- # installing puppeteer 9.1.0 seems to have made the tests flaky
- # when jest starts up. See the issue for more detail.
- # After this, we can keep an eye on puppeteer to see if the tests
- # get better later with new versions.
- - dependency-name: "puppeteer"
- versions: ["9.1.x"]
-
- package-ecosystem: "github-actions"
directory: "/"
schedule:
diff --git a/.github/workflows/dev-build.yml b/.github/workflows/dev-build.yml
index 89795470a184..f12c2cd77af7 100644
--- a/.github/workflows/dev-build.yml
+++ b/.github/workflows/dev-build.yml
@@ -71,8 +71,6 @@ jobs:
- name: Install all yarn packages
if: steps.cached-node_modules.outputs.cache-hit != 'true'
- env:
- PUPPETEER_SKIP_CHROMIUM_DOWNLOAD: 1
run: yarn --frozen-lockfile
- name: Install Python
diff --git a/.github/workflows/developing.yml b/.github/workflows/developing.yml
index 7af6a27a04d8..49191cb95d2d 100644
--- a/.github/workflows/developing.yml
+++ b/.github/workflows/developing.yml
@@ -19,6 +19,7 @@ jobs:
uses: actions/setup-node@v2.3.2
with:
node-version: "12"
+ cache: "yarn"
- name: Cache node_modules
uses: actions/cache@v2.1.6
@@ -26,14 +27,11 @@ jobs:
with:
path: |
node_modules
- key: ${{ runner.os }}-${{ hashFiles('yarn.lock') }}
+ key: ${{ runner.os }}-${{ hashFiles('yarn.lock') }}-${{ hashFiles('.github/workflows/developing.yml') }}
- name: Install all yarn packages
if: steps.cached-node_modules.outputs.cache-hit != 'true'
- env:
- PUPPETEER_SKIP_CHROMIUM_DOWNLOAD: 1
- run: |
- yarn --frozen-lockfile
+ run: yarn --frozen-lockfile
- name: Setup kernel for react native, increase watchers
run: |
@@ -72,11 +70,9 @@ jobs:
# This will make sure the tests in `testing/tests/*.test.js` only run
# if the development server is up and ready to be tested.
TESTING_DEVELOPING: true
- # Use local chrome installs since we skip downloading it as part
- # of the yarn installs above
- PUPPETEER_EXECUTABLE_PATH: /usr/bin/google-chrome
+ CONTENT_ROOT: mdn/content/files
run: |
- yarn test:testing developing
+ yarn test:developing
- name: Debug server's stdout and stderr if tests failed
if: failure()
diff --git a/.github/workflows/npm-publish.yml b/.github/workflows/npm-publish.yml
index 8fc5f3d639df..03b1d1b582a5 100644
--- a/.github/workflows/npm-publish.yml
+++ b/.github/workflows/npm-publish.yml
@@ -35,8 +35,6 @@ jobs:
- name: Install all yarn packages
if: steps.cached-node_modules.outputs.cache-hit != 'true'
- env:
- PUPPETEER_SKIP_CHROMIUM_DOWNLOAD: 1
run: yarn --frozen-lockfile
- name: Build the build
diff --git a/.github/workflows/npm-published-simulation.yml b/.github/workflows/npm-published-simulation.yml
index af1a5ff6cb2a..760a5057184c 100644
--- a/.github/workflows/npm-published-simulation.yml
+++ b/.github/workflows/npm-published-simulation.yml
@@ -24,6 +24,7 @@ jobs:
uses: actions/setup-node@v2.3.2
with:
node-version: "12"
+ cache: "yarn"
- name: Cache node_modules
uses: actions/cache@v2.1.6
@@ -31,12 +32,10 @@ jobs:
with:
path: |
node_modules
- key: ${{ runner.os }}-${{ hashFiles('yarn.lock') }}
+ key: ${{ runner.os }}-${{ hashFiles('yarn.lock') }}-${{ hashFiles('.github/workflows/npm-published-simulation.yml') }}
- name: Install all yarn packages
if: steps.cached-node_modules.outputs.cache-hit != 'true'
- env:
- PUPPETEER_SKIP_CHROMIUM_DOWNLOAD: 1
run: yarn --frozen-lockfile
- name: Setup kernel for react native, increase watchers
@@ -87,16 +86,19 @@ jobs:
# This will make sure the tests in `testing/tests/*.test.js` only run
# if the development server is up and ready to be tested.
TESTING_DEVELOPING: true
- # Use local chrome installs since we skip downloading it as part
- # of the yarn installs above
- PUPPETEER_EXECUTABLE_PATH: /usr/bin/google-chrome
# When running Yari from within mdn/content it only starts 1 server;
# the one on localhost:5000. No React dev server; the one
# on localhost:3000.
# Testing that dev server is not relevant or important in this context.
DEVELOPING_SKIP_DEV_URL: true
+ CONTENT_ROOT: mdn/content/files
+ run: |
+ yarn test:developing
+
+ - name: SSR build a page
+ working-directory: mdn/content
run: |
- yarn test:testing developing
+ yarn build files/en-us/mdn/kitchensink/index.html
- name: Debug server's stdout and stderr if tests failed
if: failure()
@@ -106,8 +108,3 @@ jobs:
echo ""
echo "STDERR..................................................."
cat /tmp/stderr.log
-
- - name: SSR build a page
- working-directory: mdn/content
- run: |
- yarn build files/en-us/mdn/kitchensink/index.html
diff --git a/.github/workflows/performance.yml b/.github/workflows/performance.yml
index ff4dec09614b..6d7d272533c6 100644
--- a/.github/workflows/performance.yml
+++ b/.github/workflows/performance.yml
@@ -39,8 +39,6 @@ jobs:
- name: Install all yarn packages
if: steps.cached-node_modules.outputs.cache-hit != 'true'
- env:
- PUPPETEER_SKIP_CHROMIUM_DOWNLOAD: 1
run: |
yarn --frozen-lockfile
diff --git a/.github/workflows/pr-kumascript.yml b/.github/workflows/pr-kumascript.yml
index f9bac236ad2d..7ee15b8bacc4 100644
--- a/.github/workflows/pr-kumascript.yml
+++ b/.github/workflows/pr-kumascript.yml
@@ -34,12 +34,10 @@ jobs:
with:
path: |
node_modules
- key: ${{ runner.os }}-${{ hashFiles('yarn.lock') }}
+ key: ${{ runner.os }}-${{ hashFiles('yarn.lock') }}-${{ hashFiles('.github/workflows/pr-kumascript.yml') }}
- name: Install all yarn packages
if: steps.cached-node_modules.outputs.cache-hit != 'true'
- env:
- PUPPETEER_SKIP_CHROMIUM_DOWNLOAD: 1
run: |
yarn --frozen-lockfile
diff --git a/.github/workflows/prod-build.yml b/.github/workflows/prod-build.yml
index b1c6a462cf51..a8ccb49113f4 100644
--- a/.github/workflows/prod-build.yml
+++ b/.github/workflows/prod-build.yml
@@ -94,8 +94,6 @@ jobs:
- name: Install all yarn packages
if: steps.cached-node_modules.outputs.cache-hit != 'true'
- env:
- PUPPETEER_SKIP_CHROMIUM_DOWNLOAD: 1
run: yarn --frozen-lockfile
- name: Install Python
diff --git a/.github/workflows/stage-build.yml b/.github/workflows/stage-build.yml
index b75abf1933f9..277bbc0271ca 100644
--- a/.github/workflows/stage-build.yml
+++ b/.github/workflows/stage-build.yml
@@ -94,8 +94,6 @@ jobs:
- name: Install all yarn packages
if: steps.cached-node_modules.outputs.cache-hit != 'true'
- env:
- PUPPETEER_SKIP_CHROMIUM_DOWNLOAD: 1
run: yarn --frozen-lockfile
- name: Install Python
diff --git a/.github/workflows/testing.yml b/.github/workflows/testing.yml
index e0fa5b6cb7e1..325c048d5bce 100644
--- a/.github/workflows/testing.yml
+++ b/.github/workflows/testing.yml
@@ -20,6 +20,7 @@ jobs:
uses: actions/setup-node@v2.3.2
with:
node-version: "12"
+ cache: "yarn"
- name: Cache node_modules
uses: actions/cache@v2.1.6
@@ -27,12 +28,10 @@ jobs:
with:
path: |
node_modules
- key: ${{ runner.os }}-${{ hashFiles('yarn.lock') }}
+ key: ${{ runner.os }}-${{ hashFiles('yarn.lock') }}-${{ hashFiles('.github/workflows/testing.yml') }}
- name: Install all yarn packages
if: steps.cached-node_modules.outputs.cache-hit != 'true'
- env:
- PUPPETEER_SKIP_CHROMIUM_DOWNLOAD: 1
run: |
yarn --frozen-lockfile
@@ -45,26 +44,27 @@ jobs:
- name: Unit testing client
run: yarn test:client
- - name: Functional testing
+ - name: Build and start server
env:
- # Make this env var explicit for GitHub Actions because in local
- # dev/debug you're encouraged to start it yourself in a separate
- # terminal.
- TESTING_START_SERVER: true
- # Use local chrome installs since we skip downloading it as part
- # of the yarn installs above
- PUPPETEER_EXECUTABLE_PATH: /usr/bin/google-chrome
+ ENV_FILE: testing/.env
run: |
- # Needed for the puppeteer tests that start a static Express server,
- # but it starts it from within the testing/ path.
- echo "CONTENT_ROOT=content/files" >> .env
+ yarn prepare-build
+ yarn build
+
+ yarn start:static-server > /tmp/stdout.log 2> /tmp/stderr.log &
+ sleep 1
+ curl --retry-connrefused --retry 5 http://localhost:5000 > /dev/null
- # In terms of the --maxWorkers option, it's not yet clear which
- # is best.
- # See https://jestjs.io/docs/en/troubleshooting#tests-are-extremely-slow-on-docker-andor-continuous-integration-ci-server
- # and https://www.peterbe.com/plog/ideal-number-of-workers-in-jest-maxWorkers
- # CI tends to have fewer CPUs than laptops so let's stay conservative
- # for now.
- # Also note that `--runInBand` is the same as `--maxWorkers=1`
+ - name: Functional testing
+ run: |
+ yarn test:testing
+ yarn test:headless
- ./testing/scripts/functional-test.sh --runInBand
+ - name: Debug server's stdout and stderr if tests failed
+ if: failure()
+ run: |
+ echo "STDOUT..................................................."
+ cat /tmp/stdout.log
+ echo ""
+ echo "STDERR..................................................."
+ cat /tmp/stderr.log
diff --git a/client/src/constants.ts b/client/src/constants.ts
index ec3e9d259b94..6d41db7891bd 100644
--- a/client/src/constants.ts
+++ b/client/src/constants.ts
@@ -15,10 +15,6 @@ export const CRUD_MODE_HOSTNAMES = (
.map((x) => x.trim())
.filter(Boolean);
-export const AUTOCOMPLETE_SEARCH_WIDGET = JSON.parse(
- process.env.REACT_APP_AUTOCOMPLETE_SEARCH_WIDGET || JSON.stringify(CRUD_MODE)
-);
-
// Remember to keep this in sync with the list inside the Node code.
// E.g. libs/constants.js
// Hardcoding the list in both places is most convenient and most performant.
diff --git a/client/src/ui/organisms/header/index.scss b/client/src/ui/organisms/header/index.scss
index 7a15ff5bcfc6..8bbd97bd163b 100644
--- a/client/src/ui/organisms/header/index.scss
+++ b/client/src/ui/organisms/header/index.scss
@@ -73,11 +73,12 @@
}
@media #{$mq-large-desktop-and-up} {
- grid-template-columns: 2fr 1fr;
+ grid-template-columns: 2fr 1fr 70px;
}
.main-nav,
- .header-search {
+ .header-search,
+ .auth-container {
grid-column: 1/2;
}
@@ -89,6 +90,10 @@
grid-row: 1/2;
}
+ .auth-container {
+ grid-row: 3/4;
+ }
+
@media #{$mq-tablet-and-up} {
.main-nav {
grid-column: 1/3;
@@ -99,11 +104,18 @@
grid-column: 1/2;
grid-row: 2/3;
}
+
+ .auth-container {
+ grid-column: 2/3;
+ grid-row: 2/3;
+ justify-self: flex-end;
+ }
}
@media #{$mq-large-desktop-and-up} {
.main-nav,
- .header-search {
+ .header-search,
+ .auth-container {
grid-row: 1/2;
}
@@ -114,6 +126,10 @@
.header-search {
grid-column: 2/3;
}
+
+ .auth-container {
+ grid-column: 3/4;
+ }
}
}
diff --git a/client/src/ui/organisms/header/index.tsx b/client/src/ui/organisms/header/index.tsx
index c43ff26adbef..d739c2981e81 100644
--- a/client/src/ui/organisms/header/index.tsx
+++ b/client/src/ui/organisms/header/index.tsx
@@ -1,5 +1,6 @@
import { useRef, useState } from "react";
+import Login from "../../molecules/login";
import { Logo } from "../../atoms/logo";
import MainMenu from "../../molecules/main-menu";
import { Search } from "../../molecules/search";
@@ -95,6 +96,9 @@ export function Header() {
toggleMainMenu();
}}
/>
+
+
+
);
diff --git a/docs/envvars.md b/docs/envvars.md
index 5c58ebd0dbe9..c57f478f4d93 100644
--- a/docs/envvars.md
+++ b/docs/envvars.md
@@ -205,31 +205,6 @@ This is the port for the WebSocket server, which is started when you run `yarn s
If you want to serve static files some a completely different directory.
-## Testing
-
-### `TESTING_OPEN_BROWSER`
-
-**Default: `false`**
-
-When running the `jest-puppeteer` test suites, if you set this to `true`,
-it will open a browser on every page navigation.
-
-It might just flash by too quickly, so consider putting in
-`await jestPuppeteer.debug()` inside the test function to slow it down.
-
-### `TESTING_START_SERVER`
-
-**Default: `false`**
-
-When `jest-puppeteer` starts the `jest` tests, if this variable is set
-to `true` it will execute `node ../server/index.js` to start the `server`
-on `localhost:5000`.
-
-In most cases, on your laptop it's better to start the server yourself
-in a separate terminal and then run the headless tests in another.
-
-For more information, see the `testing/README.md`.
-
## Client
NOTE! Due to a quirk of how we build the client, anything `REACT_APP_*` environment
diff --git a/package.json b/package.json
index bc3cd2514a82..90449c9c45d9 100644
--- a/package.json
+++ b/package.json
@@ -25,12 +25,20 @@
"test": "yarn prettier-check && yarn test:client && yarn test:kumascript && yarn test:content && yarn test:testing",
"test:client": "cd client && tsc --noEmit && react-scripts test --env=jest-environment-jsdom-sixteen",
"test:content": "jest content",
+ "test:headless": "playwright test headless",
+ "test:developing": "playwright test developing",
"test:kumascript": "jest kumascript",
- "test:testing": "cd testing && jest",
+ "test:testing": "jest --rootDir testing",
"tool": "node tool/cli.js",
"watch:ssr": "cd ssr && webpack --mode=production --watch",
"prepare": "husky install"
},
+ "jest": {
+ "testPathIgnorePatterns": [
+ "headless*",
+ "developing.spec.js"
+ ]
+ },
"resolutions": {
"@typescript-eslint/typescript-estree": ">=4.15.2",
"babel-loader": "8.1.0",
@@ -108,6 +116,7 @@
"@babel/core": "^7.15.0",
"@mdn/dinocons": "^0.3.4",
"@mdn/minimalist": "^2.0.2",
+ "@playwright/test": "1.13.0",
"@storybook/addon-a11y": "^6.3.4",
"@storybook/addon-essentials": "^6.3.4",
"@storybook/preset-create-react-app": "^3.2.0",
@@ -140,14 +149,12 @@
"ignore-loader": "^0.1.2",
"jest-environment-jsdom-sixteen": "^2.0.0",
"jest-junit-reporter": "^1.1.0",
- "jest-puppeteer": "5.0.4",
"jsdom": "^16.7.0",
"node-dev": "7.0.0",
"pegjs": "^0.10.0",
"prettier": "2.3.2",
"prettier-plugin-packagejson": "^2.2.11",
"pretty-quick": "3.1.1",
- "puppeteer": "9.0.0",
"react": "17.0.2",
"react-dom": "17.0.2",
"react-is": "^17.0.2",
diff --git a/playwright.config.js b/playwright.config.js
new file mode 100644
index 000000000000..a12f7d420513
--- /dev/null
+++ b/playwright.config.js
@@ -0,0 +1,10 @@
+const config = {
+ use: {
+ channel: "chrome",
+ // See more interesting options at https://playwright.dev/docs/test-configuration/
+ // viewport: { width: 1280, height: 720 },
+ // video: "retain-on-failure",
+ },
+};
+
+module.exports = config;
diff --git a/server/static.js b/server/static.js
index 3960bba12c25..0f31352a6623 100644
--- a/server/static.js
+++ b/server/static.js
@@ -23,6 +23,10 @@ app.use((req, res, next) => {
return next();
});
+app.get("/", async (req, res) => {
+ res.redirect(302, "/en-US/");
+});
+
app.use(staticMiddlewares);
app.use(cookieParser());
diff --git a/testing/README.md b/testing/README.md
index 690cb8908b1d..d5038af0389e 100644
--- a/testing/README.md
+++ b/testing/README.md
@@ -1,192 +1,186 @@
-# Functional tests
+# Testing
-This is a module dedicated to simulating all of Yari but with a
-fixed set of content files.
+There are many kinds of testing in Yari. Each one serving a different purpose.
+We try to test things as far away from the implementation details as possible.
+In particular, we always try to favor an end-to-end test instead of a unit test.
-Unlike testing the real content, this content "never changes". I.e. we
-control it and know exactly what to expect to find.
+In this directory (`/testing/`) we have the `jest` tests,
+[`playwright`](https://playwright.dev/)
+tests, and all the sample "fixture" content we use for testing.
+There are actually
+some tests that test with real content but mostly we try to control all
+the content that we test against.
-The general idea is that you run the same build commands as regular
-Yari but you point it to a different "content root" and then we run
-tests (using `jest`) on what got built.
+## Functional tests
-This way we can trigger specific `kumascript` macros and other effects
-and know exactly what it should have become.
+This is primarily to test the outcome of the Yari builder. You run `yarn build`
+in a way so it builds based on the content here in `/testing/` and then,
+using `jest`, we analyze the generated `index.json`, `index.html`, and
+file attachments generated from that build.
-## Local development
+To run these tests, first run:
-When hacking on the functional tests it's important that you can do
-this _without_ continuous integration (CI). That way you don't need to
-wait for CI to run your every commit in a pull request (PR).
-
-Also, you can start the full development environment with:
-
-```bash
+```sh
+export ENV_FILE=testing/.env
+yarn prepare-build
+yarn build
yarn start:static-server
```
-That will start the `server` (Express
-serve on ), and the client (`create-react-app` on
-).
-To test it go to:
-
-for example.
+This will start a server on which serves the built content.
+Now, in a separate terminal, you can run:
-Now you should be able to make edits and notice automatic reloading.
-But remember to unstage edits, otherwise it might break the automated
-test suite.
+```sh
+yarn test:testing
+```
-The first thing to do is to run the _whole_ test suite now:
+The last command is just an alias for `jest` so you can run, for example:
-```bash
-./testing/scripts/functional-test.sh
+```sh
+# See jest help
+yarn test:testing --help
+# Interactive re-run every time a file is saved and exit on the first error
+yarn test:testing --watch --bail
+# Alias for searching by test file name. I.e. only run `index.test.js`
+yarn test:testing index
```
-That includes all the important pre-build, build, and starting the `jest`
-tests. But once you've run that once, you can "break it apart" and just
-run the `jest` test suite and this you can run repeatedly:
+## Headless tests
-```bash
-yarn test:testing
+Headless tests are all about using a headless browser to browse the built
+HTML files with `playwright`. It's based on the same steps as above, so first:
+
+```sh
+export ENV_FILE=testing/.env
+yarn prepare-build
+yarn build
+yarn start:static-server
```
-This assumes you've set the appropriate environment variables and built the
-content. Alternatively, you can run `./testing/scripts/functional-test.sh`
-which takes care of all of these things.
+Now, to run the actual headless tests you run:
-## Conditional testing in CI
+```sh
+yarn test:headless
+```
-In GitHub Actions, instead of trying to optimize certain tests, just skip
-them if none of the files that affect the tests have changed.
+In CI automation it automatically picks up the browser binary according to the
+setting `channel` in the file `/playwright.config.js`. For local development on
+your laptop you might need to run:
-One such example is the tests for the `kumascript` source code plus macros.
-Use this technique heartily to speed up the continuous integration.
+```sh
+npx playwright install chrome
+```
-## Caveats
+(assuming `chrome` is what `channel` is set to in `playwright.config.js`)
-- At the moment it might not work on Windows. It should. At least the "Local
- development"
-- We should put all known `kumascript` macros in some form. At least the ones
- intend to support.
-- There is no guidelines for how to add tests but feel free to pile on
- sample pages. You should not be afraid to add more.
+### Debugging `playwright` tests
-## Writing headless tests
+`playwright` has powerful debugging capabilities. Your best guide is
+the [Debugging tools](https://playwright.dev/docs/debug) documentation. But
+here are some quick tips to get you started.
-Headless tests are when we use [`puppeteer`](https://pptr.dev/) to view pages
-rendered from the functional tests. If it helps, the non-headless tests
-use `fs.readFileSync()` and `cheerio` etc. to inspect the created files in
-`client/build/**`.
+```sh
+# Just run the test by a test description string
+yarn test:headless -g 'show your settings page'
+# Make it NOT headless by making a browser pop up for each test
+yarn test:headless --headed
+# Exclusively run the tests in headless.sitesearch.spec.js only
+playwright test headless.sitesearch
+```
-We use [`jest-puppeteer`](https://github.com/smooth-code/jest-puppeteer) and
-its README is very relevant to help you write tests. Here's the link to
-the [document for `expect-puppeteer`](https://github.com/smooth-code/jest-puppeteer/blob/master/packages/expect-puppeteer/README.md#api)
-which is your best friend when writing headless tests.
+When you use `--headed` the browser will almost flash before your eyes
+and close down before you get a chance to see what the browser is seeing.
+What you can do is inject one line of `await page.pause();` anywhere inside
+the test code. Now, next time you run, with `--headed`, a GUI should appear
+that pauses and allows you to skip and resume tests.
-To get started, open `testing/tests/headless.test.js` and make changes there.
-If you need a new page to open, you need to add that to
-`testing/content/files/...` first. Then it becomes possible to open it
-based on the slug you typed.
+## Headless tests of the development environment
-Before running the tests, start the function dev server instance:
+There are two kinds of headless tests that _don't_ use the `/testing/content/`
+and `/testing/translated-content/` fixtures. The first one is testing what
+Yari developers would see. To run these you first need to run, in one terminal:
```sh
-yarn start:functional
+yarn dev
```
-Before you proceed, appreciate that you can now open `http://localhost:5000`
-and from there open any page (for example using the search) and what you
-see in your browser is what you can expect to see in `jest-puppeteer` in
-the tests.
-
-In a separate terminal, run all the tests:
+And in another terminal, run:
```sh
-./testing/scripts/functional-test.sh
+export TESTING_DEVELOPING=true
+yarn test:developing
```
-As you notice, that shell script actually does a lot. It prebuilds the
-assets, builds the actual documents, and it runs _all_ `jest` tests.
+**Note!** To avoid "cross-contamination" with the other fixture-based headless
+tests, when doing this start a fresh new terminal so that previously set
+environment variables don't interfere.
-To just run all `jest` tests, just run the last command:
+The other kind of headless tests is those that test how Yari would work from the
+perspective of using the packaged `@mdn/yari` from within the `mdn/content`
+repository. To run these you need to go into your `mdn/content` repo and there
+first run in one terminal:
```sh
-yarn test:testing
+cd /where/is/mdn/content
+yarn start
```
-Which is just an alias to start `jest` which means you can apply your own
-parameters. For example, this starts the `jest` watcher:
+Now, to run the tests in another terminal:
```sh
-yarn test:testing --watch
+cd /back/to/mdn/yari
+export TESTING_DEVELOPING=true
+export DEVELOPING_SKIP_DEV_URL=true
+yarn test:developing
```
-Once the `jest` watcher has started press "p" and type `headless`
-and now it only (re-runs) tests the headless tests.
+**Note!** It's admittedly many permutations of testing and it's hard to
+remember which is doing what. But as a tip, open the various files in
+`.github/workflows/*.yml` and look through how they do it.
-**Note!** that only in local development do you need to start the functional
-server first. In GitHub Actions (CI), `jest-puppeteer` is instructed to start
-the server as a setup (and teardown) step.
+## Unit tests
-## Debugging headless tests
+There are currently 2 types of unit tests. The tests are located outside the
+`/testing/` directory.
-It's very likely that you'll want to see and test
-what the headless browser sees. To help with that there are a couple of
-useful tricks.
-
-The first trick is to set the `TESTING_OPEN_BROWSER=true` environment
-variable.
+First to unit test some React components. This tests the `client/src/**/*.test.tsx`
+files:
```sh
-TESTING_OPEN_BROWSER=true yarn test:testing --watch
-```
-
-Now, you'll see a browser window open and shut as the tests run.
-It's unlikely that you're fast enough to see what it's in that browser
-but what you can do is to "pause" the tests a little by injecting
-this line (temporarily) into your test code:
-
-```javascript
-await jestPuppeteer.debug();
-```
-
-Note that when you use `await jestPuppeteer.debug()` the real browser window will
-close as soon as the test failed with only a tiny timeout. To resolve that, add
-a third option to the test with the number of seconds you want it to wait. E.g.
-
-```javascript
-it("should show your settings page", async () => {
- const url = testURL("/en-US/settings");
- await page.goto(url);
- await jestPuppeteer.debug();
- await expect(page).toMatchElement("h1", { text: "Account settings" });
-}, 9999);
+yarn test:client
```
-Another useful trick is to dump the DOM HTML on the console. You can
-put this in anywhere:
+Secondly, to unit test the `kumascript` tests. These tests are located in
+`kumascript/tests/*.test.js`:
-```javascript
-console.log(await page.content());
+```sh
+yarn test:kumascript
```
-## Headless tests should only test static server
+In both of these cases, it's `jest` so you can do things like adding
+`--watch --bail` for example to interactively test over and over.
-To run the functional tests you need a server (on `localhost:5000`) and
-it should just be a static file server. You _can_ use `yarn start:functional`
-but that server has many tricks such as building on-the-fly.
+### Unit test deployer Python tests
-A better server to use is:
+See the file `deployer/README.md` for instructions.
-```sh
-yarn start:static-server
-```
+## Local development for debugging tests
-Now you can run just the functional `jest` tests over and over:
+Going back to testing the content in `/testing/content/files/` and
+`/testing/translated-content/files/` you might find it fiddly to see what
+you're testing. The `--headed` flag to `yarn test:headless` is good but it's
+a bit hard to see what you're getting to get around that you can do the
+following:
```sh
-export TESTING_START_SERVER=false # should be false by default anyway
-./testing/scripts/functional-test.sh
+echo 'CONTENT_ROOT=testing/content/files' >> .env
+echo 'CONTENT_TRANSLATED_ROOT=testing/translated-content/files' >> .env
+yarn dev
```
-If in doubt, look at the file `.github/workflows/testing.yml` and what it does.
+Now you can browse both and
+to see what the content fixtures are.
+For example, you can go to .
+Again, remember to start with a fresh new terminal so that no other testing
+related environment variables. And remember to undo these changes from
+your personal `.env` when you're done.
diff --git a/testing/jest-puppeteer.config.js b/testing/jest-puppeteer.config.js
deleted file mode 100644
index dab63f05c6f5..000000000000
--- a/testing/jest-puppeteer.config.js
+++ /dev/null
@@ -1,20 +0,0 @@
-const serverExports = {};
-if (JSON.parse(process.env.TESTING_START_SERVER || "false")) {
- serverExports.server = {
- // This is the .env file here inside the 'testing/' directory.
- // This is needed so that the server that gets started get the right
- // environment variables specifically for the functional test suite.
- command: "ENV_FILE=.env node ../server/static.js",
- port: 5000,
- host: "localhost",
- debug: true, // XXX Not sure that the harm is of having this on
- };
-}
-
-module.exports = {
- ...serverExports,
- launch: {
- headless: !JSON.parse(process.env.TESTING_OPEN_BROWSER || "false"),
- },
- setupFilesAfterEnv: ["expect-puppeteer"],
-};
diff --git a/testing/jest.config.js b/testing/jest.config.js
deleted file mode 100644
index d2c79a91a0d5..000000000000
--- a/testing/jest.config.js
+++ /dev/null
@@ -1,7 +0,0 @@
-const expectPuppeteer = require("expect-puppeteer");
-
-expectPuppeteer.setDefaultOptions({ timeout: 3000 });
-
-module.exports = {
- preset: "jest-puppeteer",
-};
diff --git a/testing/scripts/functional-test.sh b/testing/scripts/functional-test.sh
index a2fe15f632cf..9e83eae8ebc0 100755
--- a/testing/scripts/functional-test.sh
+++ b/testing/scripts/functional-test.sh
@@ -3,9 +3,6 @@ set -e
export ENV_FILE=testing/.env
-# Temporary whilst only the functional tests use the autocomplete search widget.
-export REACT_APP_AUTOCOMPLETE_SEARCH_WIDGET=true
-
yarn prepare-build
yarn build
diff --git a/testing/tests/destructive.test.js b/testing/tests/destructive.test.js
index 8e2bdcb2f654..d53f3328868f 100644
--- a/testing/tests/destructive.test.js
+++ b/testing/tests/destructive.test.js
@@ -15,8 +15,8 @@ const { execSync } = require("child_process");
const tempy = require("tempy");
-const CONTENT_DIR = path.resolve(path.join("content"));
-const BUILD_DIR = path.resolve(path.join("..", "client", "build"));
+const CONTENT_DIR = path.resolve(path.join("testing", "content"));
+const BUILD_DIR = path.resolve(path.join("client", "build"));
function* walker(root) {
const files = fs.readdirSync(root);
@@ -34,7 +34,7 @@ function* walker(root) {
describe("fixing flaws", () => {
const pattern = path.join("web", "fixable_flaws");
- const baseDir = path.resolve("..");
+ const baseDir = path.resolve(".");
let tempdir;
let tempBuildDir;
diff --git a/testing/tests/developing.test.js b/testing/tests/developing.spec.js
similarity index 58%
rename from testing/tests/developing.test.js
rename to testing/tests/developing.spec.js
index cc8a8058c92a..183e86a5a543 100644
--- a/testing/tests/developing.test.js
+++ b/testing/tests/developing.spec.js
@@ -1,10 +1,5 @@
+const { test, expect } = require("@playwright/test");
const got = require("got");
-const { setDefaultOptions } = require("expect-puppeteer");
-
-// The default it 500ms. Building and running these pages can be pretty slow
-// since the rendering both involves create-react-app bundling the test page,
-// and then the server building of the page can be pretty heavy.
-setDefaultOptions({ timeout: 5000 });
const DEV_BASE_URL =
process.env.DEVELOPING_DEV_BASE_URL || "http://localhost:3000";
@@ -15,54 +10,61 @@ function devURL(pathname = "/") {
const SERVER_BASE_URL =
process.env.DEVELOPING_SERVER_BASE_URL || "http://localhost:5000";
+
function serverURL(pathname = "/") {
return `${SERVER_BASE_URL}${pathname}`;
}
-const SKIP_DEV_URL = JSON.parse(process.env.DEVELOPING_SKIP_DEV_URL || "false");
-
-// This "trick" is to force every test to be skipped if the environment
-// variable hasn't been set. This way, when you run `jest ...`, and it finds
-// all `**/*.test.js` it doesn't actually run these tests unless explicitly
-// prepared to do so.
-// The source of this idea comes from https://github.com/facebook/jest/issues/7245
-const isTesting = JSON.parse(process.env.TESTING_DEVELOPING || "false");
-const withDeveloping = isTesting ? it : it.skip;
-// If the test suite runs in a way that there's no separate dev server,
-// don't bother using the `DEV_BASE_URL`.
-// For example, when it tests the `npm pack` tarball, it's starting only
-// the one server (on `localhost:5000`) that suite will set the `DEV_BASE_URL`
-// to be the same as `SAME_BASE_URL`.
-// In conclusion, if there's only 1 base URL to test again; don't test both.
-const withCrud = isTesting && !SKIP_DEV_URL ? it : it.skip;
-
-describe("Testing the kitchensink page", () => {
- withCrud("open the page", async () => {
+function withCrud() {
+ return (
+ withDevelop() || JSON.parse(process.env.DEVELOPING_SKIP_DEV_URL || "false")
+ );
+}
+
+function withDevelop() {
+ return !JSON.parse(process.env.TESTING_DEVELOPING || "false");
+}
+
+test.describe("Testing the kitchensink page", () => {
+ test("open the page", async ({ page }) => {
+ test.skip(withCrud());
+
await page.goto(devURL("/en-US/docs/MDN/Kitchensink"));
- await expect(page).toMatch("The MDN Content Kitchensink");
- await expect(page).toMatch("No known flaws at the moment");
+ await page.waitForLoadState("networkidle");
+ expect(await page.title()).toContain("The MDN Content Kitchensink");
+ expect(
+ await page.isVisible("text=The MDN Content Kitchensink")
+ ).toBeTruthy();
+ expect(
+ await page.isVisible("text=No known flaws at the moment")
+ ).toBeTruthy();
});
- withCrud("open a file attachement directly in the dev URL", async () => {
+ test("open a file attachement directly in the dev URL", async ({ page }) => {
+ test.skip(withCrud());
+
await page.goto(devURL("/en-US/docs/MDN/Kitchensink/iceberg.jpg"));
// This is how Chromium makes a document title when viewing an image.
expect(await page.title()).toBe("iceberg.jpg (1400×1050)");
- // Unfortunately, there's no API in puppeteer to test that the image URL
- // you opened of correct type or file size or even HTTP status code.
+ // TODO: It would be nice to know what you opened is of correct type
+ // or file size.
expect(page.url()).toBe(devURL("/en-US/docs/MDN/Kitchensink/iceberg.jpg"));
});
- withDeveloping("server-side render HTML", async () => {
+ test("server-side render HTML", async ({ page }) => {
+ test.skip(withDevelop());
+
// You can go to the page directly via the server
- await page.goto(serverURL("/en-US/docs/MDN/Kitchensink"), {
- // This is necessary because the page contains lazy loading iframes
- // to external domains.
- waitUntil: "networkidle0",
- });
- await expect(page).toMatch("The MDN Content Kitchensink");
+ await page.goto(serverURL("/en-US/docs/MDN/Kitchensink"));
+ await page.waitForLoadState("networkidle");
+ expect(
+ await page.isVisible("text=The MDN Content Kitchensink")
+ ).toBeTruthy();
});
- withDeveloping("server-side render HTML", async () => {
+ test("server-side render JSON", async () => {
+ test.skip(withDevelop());
+
// Loading the index.json doesn't require a headless browser
const { doc } = await got(
serverURL("/en-US/docs/MDN/Kitchensink/index.json")
@@ -77,8 +79,10 @@ describe("Testing the kitchensink page", () => {
// Note, some of these tests cover some of the core code that we use in
// the Lambda@Edge origin-request handler.
-describe("Testing the Express server", () => {
- withDeveloping("redirect without any useful headers", async () => {
+test.describe("Testing the Express server", () => {
+ test("redirect without any useful headers", async () => {
+ test.skip(withDevelop());
+
let response = await got(serverURL("/"), { followRedirect: false });
expect(response.statusCode).toBe(302);
expect(response.headers.location).toBe("/en-US/");
@@ -97,7 +101,9 @@ describe("Testing the Express server", () => {
expect(response.headers.location).toBe("/en-US/docs/Web");
});
- withDeveloping("redirect based on _redirects.txt", async () => {
+ test("redirect based on _redirects.txt", async () => {
+ test.skip(withDevelop());
+
// Yes, this is a bit delicate since it depends on non-fixtures, but
// it's realistic and it's a good end-to-end test.
// See mdn/content/files/en-us/_redirects.txt
@@ -127,7 +133,9 @@ describe("Testing the Express server", () => {
);
});
- withDeveloping("redirect by preferred locale cookie", async () => {
+ test("redirect by preferred locale cookie", async () => {
+ test.skip(withDevelop());
+
let response = await got(serverURL("/"), {
followRedirect: false,
headers: {
@@ -149,7 +157,9 @@ describe("Testing the Express server", () => {
expect(response.headers.location).toBe("/en-US/");
});
- withDeveloping("redirect by 'Accept-Language' header", async () => {
+ test("redirect by 'Accept-Language' header", async () => {
+ test.skip(withDevelop());
+
let response = await got(serverURL("/"), {
followRedirect: false,
headers: {
@@ -171,7 +181,9 @@ describe("Testing the Express server", () => {
expect(response.headers.location).toBe("/en-US/");
});
- withDeveloping("redirect by cookie trumps", async () => {
+ test("redirect by cookie trumps", async () => {
+ test.skip(withDevelop());
+
const response = await got(serverURL("/"), {
followRedirect: false,
headers: {
@@ -184,26 +196,37 @@ describe("Testing the Express server", () => {
});
});
-describe("Testing the CRUD apps", () => {
- withCrud("open the writer's home page", async () => {
+test.describe("Testing the CRUD apps", () => {
+ test("open the writer's home page", async ({ page }) => {
+ test.skip(withCrud());
+
await page.goto(devURL("/"));
- await expect(page).toMatch("Writer's home page");
- await expect(page).toMatchElement("a", { text: "Flaws Dashboard" });
+ expect(await page.title()).toContain("MDN Web Docs");
+ expect(await page.isVisible("text=Writer's home page")).toBeTruthy();
+ expect(await page.isVisible('a:has-text("Flaws Dashboard")')).toBeTruthy();
});
- withCrud("open the Flaws Dashboard", async () => {
+ test("open the Flaws Dashboard", async ({ page }) => {
+ test.skip(withCrud());
+
await page.goto(devURL("/"));
- await expect(page).toClick("a", { text: "Flaws Dashboard" });
- await expect(page).toMatch("Documents with flaws found (0)");
+ await page.click('a:has-text("Flaws Dashboard")');
+ await page.waitForLoadState("networkidle");
+ expect(
+ await page.isVisible("text=Documents with flaws found (0)")
+ ).toBeTruthy();
});
- withCrud("open the sitemap app", async () => {
+ test("open the sitemap app", async ({ page }) => {
+ test.skip(withCrud());
+
await page.goto(devURL("/"));
- await expect(page).toMatch("Writer's home page");
- await expect(page).toClick("a", { text: "Sitemap" });
- await expect(page).toMatchElement("a", { text: "Web" });
- await expect(page).toMatchElement("a", { text: "Learn" });
- await expect(page).toClick("a", { text: "Glossary" });
- await expect(page).toMatchElement("a", { text: "Glossary/PNG" });
+ expect(await page.isVisible("text=Writer's home page")).toBeTruthy();
+ await page.click('a:has-text("Sitemap")');
+ await page.waitForLoadState("networkidle");
+ expect(await page.isVisible('a:has-text("/Web")')).toBeTruthy();
+ expect(await page.isVisible('a:has-text("/Learn")')).toBeTruthy();
+ await page.click('a:has-text("/Glossary")');
+ expect(await page.isVisible('a:has-text("Glossary/PNG")')).toBeTruthy();
});
});
diff --git a/testing/tests/headless.auth.spec.js b/testing/tests/headless.auth.spec.js
new file mode 100644
index 000000000000..afbd29ad0ac2
--- /dev/null
+++ b/testing/tests/headless.auth.spec.js
@@ -0,0 +1,144 @@
+const { test, expect } = require("@playwright/test");
+
+function testURL(pathname = "/") {
+ return `http://localhost:5000${pathname}`;
+}
+
+test.describe("Visiting pages related and requiring authentication", () => {
+ test.beforeEach(async ({ context }) => {
+ // Necessary hack to make sure any existing 'sessionid' cookies don't
+ // interfere on the re-used `page` across tests.
+ await context.clearCookies();
+ });
+
+ test("clicking 'Sign in' should offer links to all identity providers", async ({
+ page,
+ }) => {
+ await page.goto(testURL("/en-US/docs/Web/Foo"));
+ await page.click("text=Sign in");
+ expect(await page.innerText("h1")).toContain("Sign in");
+ expect(page.url()).toContain(
+ testURL(
+ `/en-US/signin?${new URLSearchParams({
+ next: "/en-US/docs/Web/Foo",
+ }).toString()}`
+ )
+ );
+ expect(await page.isVisible('a:has-text("GitHub")')).toBeTruthy();
+ expect(await page.isVisible('a:has-text("Google")')).toBeTruthy();
+ });
+
+ test("going to 'Sign up' page without query string", async ({ page }) => {
+ await page.goto(testURL("/en-US/signup"));
+
+ expect(await page.innerText("h1")).toContain("Sign in to MDN Web Docs");
+ expect(await page.isVisible("text=Invalid URL")).toBeTruthy();
+ expect(
+ await page.isVisible("text=Please retry the sign-in process")
+ ).toBeTruthy();
+ });
+
+ test("going to 'Sign up' page with realistic (fake) query string", async ({
+ page,
+ }) => {
+ const sp = new URLSearchParams();
+ sp.set("csrfmiddlewaretoken", "abc");
+ sp.set("provider", "github");
+ sp.set(
+ "user_details",
+ JSON.stringify({
+ name: "Peter B",
+ })
+ );
+ await page.goto(testURL(`/en-US/signup?${sp.toString()}`));
+ expect(await page.innerText("h1")).toContain("Sign in to MDN Web Docs");
+ expect(await page.isVisible("text=Invalid URL")).toBeFalsy();
+ expect(
+ await page.isVisible(
+ "text=You are signing in to MDN Web Docs with GitHub as Peter B."
+ )
+ ).toBeTruthy();
+ expect(
+ await page.isVisible(
+ "text=I agree to Mozilla's Terms and Privacy Notice."
+ )
+ ).toBeTruthy();
+ expect(
+ await page.isVisible('button:has-text("Complete sign-in")')
+ ).toBeTruthy();
+ expect(
+ await page.isVisible('button[disabled]:has-text("Complete sign-in")')
+ ).toBeTruthy();
+ await page.check('input[name="terms"]');
+ expect(
+ await page.isVisible('button[disabled]:has-text("Complete sign-in")')
+ ).toBeFalsy();
+ expect(
+ await page.isVisible('button:has-text("Complete sign-in")')
+ ).toBeTruthy();
+ await page.click('button:has-text("Complete sign-in")');
+ });
+
+ test("show your settings page", async ({ page }) => {
+ await page.goto(testURL("/en-US/settings"));
+ expect(await page.innerText("h1")).toBe("Account settings");
+ expect(await page.isVisible("text=You have not signed in")).toBeTruthy();
+ expect(await page.isVisible("text=Sign in")).toBeTruthy();
+
+ // First sign in with GitHub (happy path)
+ await page.goto(testURL("/en-US/signin"));
+ expect(await page.isVisible('a:has-text("GitHub")')).toBeTruthy();
+ await page.click('a:has-text("GitHub")');
+ expect(page.url()).toMatch(testURL("/en-US/"));
+ // This is important otherwise it won't wait for the XHR where the
+ // cookie gets set!
+ await page.waitForLoadState("networkidle");
+ await page.goto(testURL("/en-US/settings"));
+ expect(await page.innerText("h1")).toBe("Account settings");
+ expect(
+ await page.isVisible('button:has-text("Close account")')
+ ).toBeTruthy();
+ // Change locale to French
+ await page.selectOption('select[name="locale"]', {
+ label: "French",
+ });
+ await page.click('button:has-text("Update language")');
+ await page.waitForLoadState("networkidle");
+ expect(
+ await page.isVisible("text=Updated settings successfully")
+ ).toBeTruthy();
+ });
+ // This test has turned out to be fragile. It's failing sporadically and
+ // we're not sure why or how. We've seen several times where the PR (on
+ // something entirely unrelated) passes but when tested on the main branch
+ // it then fails.
+ // Example:
+ // https://github.com/mdn/yari/actions/runs/1005504856
+ // Clearly, there's something fragile about it.
+ // But as of July 6 2021, there's an offline discussion that we might
+ // revamp how auth works, so instead of trying to unbreak this fragile
+ // test, let's comment it out. At least it'll unbreak our sporadically
+ // failing CI but we can keep it around in case we really do need it
+ // and find the time to work on fixing what's fragile about it.
+ // test("should ask you to checkbox to sign up with Google", async ({page}) => {
+ // const url = testURL("/en-US/");
+ // await page.goto(url);
+ // // Wait for it to figure out that you're not signed in.
+ // await expect(page).toClick("a", { text: /Sign in/ });
+ // await page.waitForNavigation({ waitUntil: "networkidle2" });
+ // await expect(page.url()).toMatch(testURL("/en-US/signin"));
+ // await expect(page).toMatch("Sign in with Google");
+ // await expect(page).toClick("a", {
+ // text: /Sign in with Google/,
+ // });
+ // await expect(page.url()).toMatch(testURL("/en-US/signin"));
+ // await page.waitForNavigation({ waitUntil: "networkidle2" });
+ // const checkbox = await page.$('input[type="checkbox"]');
+ // await checkbox.click();
+ // await expect(page).toClick("button", {
+ // text: /Complete sign-in/,
+ // });
+ // await expect(page.url()).toMatch(testURL("/en-US/"));
+ // await expect(page).toMatch("Googler-username");
+ // });
+});
diff --git a/testing/tests/headless.auth.test.js b/testing/tests/headless.auth.test.js
deleted file mode 100644
index cfb02f5dc89d..000000000000
--- a/testing/tests/headless.auth.test.js
+++ /dev/null
@@ -1,90 +0,0 @@
-const { setDefaultOptions } = require("expect-puppeteer");
-
-// The default it 500ms. It has happened and it can happen again, that sometimes
-// it just takes a little longer than 500ms. Give it a healthy margin of a
-// timeout so as to reduce the risk of it failing when there's nothing wrong.
-setDefaultOptions({ timeout: 1500 });
-
-function testURL(pathname = "/") {
- return `http://localhost:5000${pathname}`;
-}
-
-describe("Visiting pages related and requiring authentication", () => {
- beforeEach(async () => {
- // Necessary hack to make sure any existing 'sessionid' cookies don't
- // interfere on the re-used `page` across tests.
- await page.deleteCookie({ name: "sessionid", url: testURL() });
- });
-
- it("going to 'Sign up' page without query string", async () => {
- await page.goto(testURL("/en-US/signup"));
- await expect(page).toMatchElement("h1", {
- text: "Sign in to MDN Web Docs",
- });
- await expect(page).toMatch("Invalid URL");
- await expect(page).toMatchElement("a", {
- text: "Please retry the sign-in process",
- });
- });
-
- it("going to 'Sign up' page with realistic (fake) query string", async () => {
- const sp = new URLSearchParams();
- sp.set("csrfmiddlewaretoken", "abc");
- sp.set("provider", "github");
- sp.set(
- "user_details",
- JSON.stringify({
- name: "Peter B",
- })
- );
-
- await page.goto(testURL(`/en-US/signup?${sp.toString()}`));
- await expect(page).toMatchElement("h1", {
- text: "Sign in to MDN Web Docs",
- });
- await expect(page).not.toMatch("Invalid URL");
- await expect(page).toMatch(
- "You are signing in to MDN Web Docs with GitHub as Peter B."
- );
- await expect(page).toMatch(
- "I agree to Mozilla's Terms and Privacy Notice."
- );
- await expect(page).toMatchElement("button", { text: "Complete sign-in" });
- });
-
- // This test has turned out to be fragile. It's failing sporadically and
- // we're not sure why or how. We've seen several times where the PR (on
- // something entirely unrelated) passes but when tested on the main branch
- // it then fails.
- // Example:
- // https://github.com/mdn/yari/actions/runs/1005504856
- // Clearly, there's something fragile about it.
- // But as of July 6 2021, there's an offline discussion that we might
- // revamp how auth works, so instead of trying to unbreak this fragile
- // test, let's comment it out. At least it'll unbreak our sporadically
- // failing CI but we can keep it around in case we really do need it
- // and find the time to work on fixing what's fragile about it.
- // it("should ask you to checkbox to sign up with Google", async () => {
- // const url = testURL("/en-US/");
- // await page.goto(url);
- // // Wait for it to figure out that you're not signed in.
- // await expect(page).toClick("a", { text: /Sign in/ });
- // await page.waitForNavigation({ waitUntil: "networkidle2" });
- // await expect(page.url()).toMatch(testURL("/en-US/signin"));
-
- // await expect(page).toMatch("Sign in with Google");
- // await expect(page).toClick("a", {
- // text: /Sign in with Google/,
- // });
- // await expect(page.url()).toMatch(testURL("/en-US/signin"));
- // await page.waitForNavigation({ waitUntil: "networkidle2" });
- // const checkbox = await page.$('input[type="checkbox"]');
- // await checkbox.click();
-
- // await expect(page).toClick("button", {
- // text: /Complete sign-in/,
- // });
- // await expect(page.url()).toMatch(testURL("/en-US/"));
- // await expect(page).toMatch("Googler-username");
- // });
-});
diff --git a/testing/tests/headless.index.spec.js b/testing/tests/headless.index.spec.js
new file mode 100644
index 000000000000..4ca7791a2639
--- /dev/null
+++ b/testing/tests/headless.index.spec.js
@@ -0,0 +1,293 @@
+const { test, expect } = require("@playwright/test");
+
+function testURL(pathname = "/") {
+ return `http://localhost:5000${pathname}`;
+}
+
+test.describe("Basic viewing of functional pages", () => {
+ test("open the temporary home page", async ({ page }) => {
+ await page.goto(testURL("/"));
+ expect(await page.title()).toContain("MDN Web Docs");
+ expect(await page.innerText("h1")).toBe(
+ "Resources for developers, by developers."
+ );
+ });
+
+ test("open the /en-US/docs/Web/Foo page", async ({ page }) => {
+ await page.goto(testURL("/en-US/docs/Web/Foo"));
+ expect(await page.title()).toContain(": A test tag");
+ expect(await page.innerText("h1")).toBe(": A test tag");
+ expect(await page.isVisible(".metadata time")).toBeTruthy();
+ });
+
+ test("open the French /fr/docs/Web/Foo page and navigate to English", async ({
+ page,
+ }) => {
+ await page.goto(testURL("/fr/docs/Web/Foo"));
+ expect(await page.innerText("h1")).toBe(": Une page de test");
+ await page.click("text=View in English");
+ expect(await page.innerText("h1")).toBe(": A test tag");
+ // Should have been redirected too...
+ expect(page.url()).toBe(testURL("/en-US/docs/Web/Foo/"));
+ });
+
+ test("open the /en-US/docs/Web/InteractiveExample page", async ({ page }) => {
+ await page.goto(testURL("/en-US/docs/Web/InteractiveExample"));
+ expect(
+ await page.isVisible("text=I Have an Interactive Example")
+ ).toBeTruthy();
+ });
+
+ test("open the /en-US/docs/Learn/CSS/CSS_layout/Introduction page", async ({
+ page,
+ }) => {
+ const uri = "/en-US/docs/Learn/CSS/CSS_layout/Introduction";
+ const flexSample1Uri = `${uri}/Flex/_sample_.Flex_1.html`;
+ const flexSample2Uri = `${uri}/Flex/_sample_.Flex_2.html`;
+ const gridSample1Uri = `${uri}/Grid/_sample_.Grid_1.html`;
+ const gridSample2Uri = `${uri}/_sample_.Grid_2.html`;
+ await page.goto(testURL(uri));
+ expect(await page.title()).toContain("A Test Introduction to CSS layout");
+ expect(await page.innerText("h1")).toBe(
+ "A Test Introduction to CSS layout"
+ );
+ expect(await page.innerText("#flexbox")).toBe("Flexbox");
+ expect(
+ await page.isVisible(`iframe.sample-code-frame[src$="${flexSample1Uri}"]`)
+ ).toBeTruthy();
+ expect(
+ await page.isVisible(`iframe.sample-code-frame[src$="${flexSample2Uri}"]`)
+ ).toBeTruthy();
+ expect(await page.innerText("#grid_layout")).toBe("Grid Layout");
+ expect(
+ await page.isVisible(`iframe.sample-code-frame[src$="${gridSample1Uri}"]`)
+ ).toBeTruthy();
+ expect(await page.innerText("#Grid_2 pre.css.notranslate")).toMatch(
+ /\.wrapper\s*\{\s*display:\s*grid;/
+ );
+ expect(
+ await page.isVisible(`iframe.sample-code-frame[src$="${gridSample2Uri}"]`)
+ ).toBeTruthy();
+
+ // Ensure that the live-sample pages were built.
+ for (const sampleUri of [
+ flexSample1Uri,
+ flexSample2Uri,
+ gridSample1Uri,
+ gridSample2Uri,
+ ]) {
+ await page.goto(testURL(sampleUri));
+ expect(await page.innerText("body > div.wrapper > div.box1")).toBe("One");
+ expect(await page.innerText("body > div.wrapper > div.box2")).toBe("Two");
+ expect(await page.innerText("body > div.wrapper > div.box3")).toBe(
+ "Three"
+ );
+ }
+ });
+
+ test("open the /en-US/docs/Learn/CSS/CSS_layout/Introduction/Flex page", async ({
+ page,
+ }) => {
+ const uri = "/en-US/docs/Learn/CSS/CSS_layout/Introduction/Flex";
+ const flexSample1Uri = `${uri}/_sample_.Flex_1.html`;
+ const flexSample2Uri = `${uri}/_sample_.Flex_2.html`;
+ await page.goto(testURL(uri));
+ expect(await page.title()).toContain(
+ "A Test Introduction to CSS Flexbox Layout"
+ );
+ expect(await page.innerText("h1")).toBe(
+ "A Test Introduction to CSS Flexbox Layout"
+ );
+ expect(await page.innerText("#flexbox")).toBe("Flexbox");
+
+ expect(await page.innerText("#Flex_1 pre.css.notranslate")).toMatch(
+ /\.wrapper\s*\{\s*display:\s*flex;\s*\}/
+ );
+ expect(
+ await page.isVisible(`iframe.sample-code-frame[src$="${flexSample1Uri}"]`)
+ ).toBeTruthy();
+
+ expect(await page.innerText("#Flex_2 pre.css.notranslate")).toMatch(
+ /\.wrapper {\s*display: flex;\s*\}\s*\.wrapper > div \{\s*flex: 1;\s*\}/
+ );
+ expect(
+ await page.isVisible(`iframe.sample-code-frame[src$="${flexSample2Uri}"]`)
+ ).toBeTruthy();
+ });
+
+ test("open the /en-US/docs/Learn/CSS/CSS_layout/Introduction/Grid page", async ({
+ page,
+ }) => {
+ const uri = "/en-US/docs/Learn/CSS/CSS_layout/Introduction/Grid";
+ const gridSample1Uri = `${uri}/_sample_.Grid_1.html`;
+ const gridSample2Uri = `${uri}/_sample_.Grid_2.html`;
+ await page.goto(testURL(uri));
+ expect(await page.title()).toContain(
+ "A Test Introduction to CSS Grid Layout"
+ );
+ expect(await page.innerText("h1")).toBe(
+ "A Test Introduction to CSS Grid Layout"
+ );
+ expect(await page.innerText("#grid_layout")).toBe("Grid Layout");
+ expect(await page.innerText("#Grid_1 pre.css.notranslate")).toMatch(
+ /\.wrapper\s*\{\s*display:\s*grid;/
+ );
+ expect(
+ await page.isVisible(`iframe.sample-code-frame[src$="${gridSample1Uri}"]`)
+ ).toBeTruthy();
+
+ expect(await page.innerText("#Grid_2 pre.css.notranslate")).toMatch(
+ /grid-template-columns: 1fr 1fr 1fr;/
+ );
+ expect(
+ await page.isVisible(`iframe.sample-code-frame[src$="${gridSample2Uri}"]`)
+ ).toBeTruthy();
+
+ // Ensure that the live-sample page "gridSample2Uri" was built.
+ await page.goto(testURL(gridSample2Uri));
+ expect(await page.innerText("body > div.wrapper > div.box1")).toBe("One");
+ expect(await page.innerText("body > div.wrapper > div.box2")).toBe("Two");
+ expect(await page.innerText("body > div.wrapper > div.box3")).toBe("Three");
+ });
+
+ test("return to previous page on back-button press", async ({ page }) => {
+ await page.goto(testURL("/en-US/docs/Web/Foo"));
+ expect(await page.title()).toContain(": A test tag");
+ expect(await page.innerText("h1")).toBe(": A test tag");
+ // Click the parent page in the breadcrumbs
+ await page.click(".breadcrumbs-container a");
+ expect(await page.innerText("h1")).toBe("Web technology for developers");
+ expect(page.url()).toBe(testURL("/en-US/docs/Web"));
+ await page.goBack();
+ expect(await page.innerText("h1")).toBe(": A test tag");
+ });
+
+ test("have a semantically valid breadcrumb trail", async ({ page }) => {
+ await page.goto(testURL("/en-US/docs/Web/Foo"));
+ // Let's not get too technical about the name of the selectors and
+ // stuff but do note that the page you're on is always a valid link
+ expect(
+ await page.innerText(
+ "nav a.breadcrumb-penultimate[property=item][typeof=WebPage]"
+ )
+ ).toBe(
+ // You gotta know your fixture documents
+ "Web technology for developers"
+ );
+ expect(
+ await page.innerText(
+ "nav a.breadcrumb-current-page[property=item][typeof=WebPage]"
+ )
+ ).toBe(
+ // Always includes a link to "self"
+ ": A test tag"
+ );
+ });
+
+ test("say which page was not found", async ({ page }) => {
+ await page.goto(testURL("/en-US/docs/Doesnot/exist"));
+ expect(await page.isVisible("text=Page not found")).toBeTruthy();
+ expect(await page.isVisible("text=could not be found")).toBeTruthy();
+ });
+
+ test("suggest the en-US equivalent on non-en-US pages not found", async ({
+ page,
+ }) => {
+ await page.goto(testURL("/ja/docs/Web/foo"));
+ expect(await page.isVisible("text=Page not found")).toBeTruthy();
+ expect(await page.isVisible("text=could not be found")).toBeTruthy();
+ // Wait for XHR loading of the whole document
+ await page.waitForLoadState("networkidle");
+ // Simply by swapping the "ja" for "en-US" it's able to find the index.json
+ // for that slug and present a link to it.
+ expect(await page.isVisible("text=Good news!")).toBeTruthy();
+ expect(await page.getAttribute(".fallback-link a", "href")).toBe(
+ "/en-US/docs/Web/Foo"
+ );
+ });
+
+ test("give the home page and see Hacks blog posts", async ({ page }) => {
+ await page.goto(testURL("/en-US/"));
+ expect(
+ await page.isVisible("text=Resources for developers, by developers.")
+ ).toBeTruthy();
+ expect(await page.isVisible("text=Hacks Blog")).toBeTruthy();
+ });
+});
+
+test.describe("changing language", () => {
+ test("from French to English, set a cookie, and back again", async ({
+ page,
+ }) => {
+ await page.goto(testURL("/fr/docs/Web/Foo"));
+ expect(await page.isVisible("text=: Une page de test")).toBeTruthy();
+ await page.selectOption('select[name="language"]', {
+ label: "English (US)",
+ });
+
+ await page.click('button:has-text("Change language")');
+ // Wait for XHR loading of the whole document
+ await page.waitForLoadState("networkidle");
+ expect(await page.isVisible("text=: A test tag")).toBeTruthy();
+ expect(page.url()).toBe(testURL("/en-US/docs/Web/Foo/"));
+
+ // And change back to French
+ await page.selectOption('select[name="language"]', {
+ label: "Français",
+ });
+ await page.click('button:has-text("Change language")');
+ // Wait for XHR loading of the whole document
+ await page.waitForLoadState("networkidle");
+ expect(await page.isVisible("text=: Une page de test")).toBeTruthy();
+ expect(page.url()).toBe(testURL("/fr/docs/Web/Foo/"));
+ });
+});
+
+test.describe("viewing retired locales", () => {
+ test("redirect retired locale to English (document)", async ({ page }) => {
+ await page.goto(testURL("/ar/docs/Web/Foo"));
+ expect(page.url()).toMatch(
+ testURL("/en-US/docs/Web/Foo/?retiredLocale=ar")
+ );
+ expect(await page.innerText("h1")).toBe(": A test tag");
+ });
+
+ test("redirect retired locale to English (index.json)", async ({ page }) => {
+ await page.goto(testURL("/ar/docs/Web/Foo/index.json"));
+ expect(page.url()).toMatch(
+ testURL("/en-US/docs/Web/Foo/index.json?retiredLocale=ar")
+ );
+ expect(await page.isVisible("text=: A test tag")).toBeTruthy();
+ });
+
+ test("redirect retired locale to English (search with query string)", async ({
+ page,
+ }) => {
+ await page.goto(testURL("/ar/search?q=video"));
+ expect(page.url()).toMatch(
+ testURL("/en-US/search/?q=video&retiredLocale=ar")
+ );
+ expect(await page.isVisible("text=Search results for: video")).toBeTruthy();
+ });
+
+ test("say the locale was retired", async ({ page }) => {
+ await page.goto(testURL("/en-US/docs/Web/Foo/?retiredLocale=ar"));
+ expect(
+ await page.isVisible("text=The page you requested has been retired")
+ ).toBeTruthy();
+ // sanity check that it goes away
+ await page.goto(testURL("/en-US/docs/Web/Foo/"));
+ expect(
+ await page.isVisible("text=The page you requested has been retired")
+ ).toBeFalsy();
+ });
+
+ test("not say the locale was retired if viewing a translated page", async ({
+ page,
+ }) => {
+ await page.goto(testURL("/fr/docs/Web/Foo/?retiredLocale=sv-SE"));
+ expect(
+ await page.isVisible("text=The page you requested has been retired")
+ ).toBeFalsy();
+ });
+});
diff --git a/testing/tests/headless.search.spec.js b/testing/tests/headless.search.spec.js
new file mode 100644
index 000000000000..5aead32f8bc9
--- /dev/null
+++ b/testing/tests/headless.search.spec.js
@@ -0,0 +1,99 @@
+const { test, expect } = require("@playwright/test");
+
+function testURL(pathname = "/") {
+ return "http://localhost:5000" + pathname;
+}
+
+test.describe("Autocomplete search", () => {
+ const SEARCH_SELECTOR = 'form input[type="search"]';
+
+ test("find Foo page by title search", async ({ page }) => {
+ // Yes, this is a cheeky implementation testing detail but it's a nice
+ // sanity check that the server can respond with *something* that's
+ // sensible. This "test" also helps make sense of other potentially
+ // very confusing errors within the important tests themselves.
+ await page.goto(testURL("/en-US/search-index.json"));
+ // It's JSON but this asserts that page will be findable
+ expect(await page.isVisible("text=: A test tag")).toBeTruthy();
+
+ await page.goto(testURL("/"));
+
+ // This will activate the fancy autocomplete search and it should start
+ // a download of the `/en-US/search-index.json` too.
+ await page.focus(SEARCH_SELECTOR);
+ await page.waitForSelector("#nav-main-search"); // autocomplete search form
+ await page.waitForLoadState("networkidle");
+
+ await page.fill(SEARCH_SELECTOR, "foo");
+ expect(await page.isVisible("text=: A test tag")).toBeTruthy();
+ // There's only 1 and this clicks on the first one anyway.
+ await page.click("div.result-item");
+ await page.waitForLoadState("networkidle");
+ expect(await page.innerText("h1")).toBe(": A test tag");
+ // Should have been redirected too...
+ expect(page.url()).toBe(testURL("/en-US/docs/Web/Foo"));
+ });
+
+ test("find nothing by title search", async ({ page }) => {
+ await page.goto(testURL("/"));
+
+ // This will activate the fancy autocomplete search and it should start
+ // a download of the `/en-US/search-index.json` too.
+ await page.focus(SEARCH_SELECTOR);
+ await page.waitForSelector("#nav-main-search"); // autocomplete search form
+ await page.waitForLoadState("networkidle");
+
+ await page.fill(SEARCH_SELECTOR, "gooblyg00k");
+ expect(await page.innerText(".nothing-found")).toContain(
+ "No document titles found"
+ );
+ });
+
+ test("find Foo page by fuzzy-search", async ({ page }) => {
+ await page.goto(testURL("/"));
+
+ // This will activate the fancy autocomplete search and it should start
+ // a download of the `/en-US/search-index.json` too.
+ await page.focus(SEARCH_SELECTOR);
+ await page.waitForSelector("#nav-main-search"); // autocomplete search form
+ await page.waitForLoadState("networkidle");
+
+ await page.fill(SEARCH_SELECTOR, "/");
+ await page.waitForSelector("#nav-main-search"); // autocomplete search form
+ expect(await page.isVisible("text=Fuzzy searching by URI")).toBeTruthy();
+ expect(await page.isVisible("text=No document titles found")).toBeFalsy();
+ await page.fill(SEARCH_SELECTOR, "/wboo");
+ expect(await page.isVisible("text=: A test tag")).toBeTruthy();
+
+ await page.click("div.result-item");
+ await page.waitForLoadState("networkidle");
+ expect(await page.innerText("h1")).toBe(": A test tag");
+ // Should have been redirected too...
+ expect(page.url()).toBe(testURL("/en-US/docs/Web/Foo"));
+ });
+
+ test("find nothing by fuzzy-search", async ({ page }) => {
+ await page.goto(testURL("/"));
+
+ // This will activate the fancy autocomplete search and it should start
+ // a download of the `/en-US/search-index.json` too.
+ await page.focus(SEARCH_SELECTOR);
+ await page.waitForSelector("#nav-main-search"); // autocomplete search form
+ await page.waitForLoadState("networkidle");
+
+ await page.fill(SEARCH_SELECTOR, "/gooblygook");
+ await page.waitForSelector("#nav-main-search"); // autocomplete search form
+ expect(await page.isVisible("text=No document titles found")).toBeTruthy();
+ });
+
+ test("input placeholder changes when focused", async ({ page }) => {
+ await page.goto(testURL("/"));
+ expect(await page.getAttribute(SEARCH_SELECTOR, "placeholder")).toMatch(
+ /Site search/
+ );
+ await page.focus(SEARCH_SELECTOR);
+ expect(await page.getAttribute(SEARCH_SELECTOR, "placeholder")).toMatch(
+ /Go ahead/
+ );
+ });
+});
diff --git a/testing/tests/headless.search.test.js b/testing/tests/headless.search.test.js
deleted file mode 100644
index 8bcf30c6b5fd..000000000000
--- a/testing/tests/headless.search.test.js
+++ /dev/null
@@ -1,72 +0,0 @@
-function testURL(pathname = "/") {
- return `http://localhost:5000${pathname}`;
-}
-
-describe("Autocomplete search", () => {
- const SEARCH_SELECTOR = 'form input[type="search"]';
-
- beforeAll(async () => {
- // Yes, this is a cheeky implementation testing detail but it's a nice
- // sanity check that the server can respond with *something* that's
- // sensible. This "test" also helps make sense of other potentially
- // very confusing errors within the important tests themselves.
- await page.goto(testURL("/en-US/search-index.json"));
- // It's JSON but this asserts that page will be findable
- await expect(page).toMatch(": A test tag");
- });
-
- test("find Foo page by title search", async () => {
- await page.goto(testURL("/"));
- await expect(page).toFill(SEARCH_SELECTOR, "foo");
- await expect(page).toMatch(": A test tag");
- // There's only 1 and this clicks on the first one anyway.
- await expect(page).toClick("div.result-item");
- await page.waitForNavigation();
- await expect(page).toMatchElement("h1", { text: ": A test tag" });
- // Should have been redirected too...
- // Note! It's important that this happens *after* the `.toMatchElement`
- // on the line above because expect-puppeteer doesn't have a wait to
- // properly wait for the (pushState) URL to have changed.
- expect(page.url()).toBe(testURL("/en-US/docs/Web/Foo"));
- });
-
- test("find nothing by title search", async () => {
- await page.goto(testURL("/"));
- await expect(page).toFill(SEARCH_SELECTOR, "gooblyg00k");
- await expect(page).toMatchElement(".nothing-found", {
- text: "No document titles found",
- });
- });
-
- test("find Foo page by fuzzy-search", async () => {
- await page.goto(testURL("/"));
- await expect(page).toFill(SEARCH_SELECTOR, "/");
- await expect(page).toMatch("Fuzzy searching by URI");
- await expect(page).not.toMatchElement(".nothing-found", {
- text: "No document titles found",
- });
- await expect(page).toFill(SEARCH_SELECTOR, "/wboo");
- await expect(page).toMatch(": A test tag");
- await expect(page).toClick("div.result-item");
- await page.waitForNavigation();
- await expect(page).toMatchElement("h1", { text: ": A test tag" });
- });
-
- test("find nothing by fuzzy-search", async () => {
- await page.goto(testURL("/"));
- await expect(page).toFill(SEARCH_SELECTOR, "/gooblygook");
- await expect(page).toMatchElement(".nothing-found", {
- text: "No document titles found",
- });
- });
-
- test("input placeholder changes when focused", async () => {
- await expect(page).toMatchElement(SEARCH_SELECTOR, {
- placeholder: /Site search/,
- });
- await expect(page).toClick(SEARCH_SELECTOR);
- await expect(page).toMatchElement(SEARCH_SELECTOR, {
- placeholder: /Go ahead/,
- });
- });
-});
diff --git a/testing/tests/headless.sitesearch.spec.js b/testing/tests/headless.sitesearch.spec.js
new file mode 100644
index 000000000000..6177556ed620
--- /dev/null
+++ b/testing/tests/headless.sitesearch.spec.js
@@ -0,0 +1,81 @@
+const { test, expect } = require("@playwright/test");
+
+function testURL(pathname = "/") {
+ return "http://localhost:5000" + pathname;
+}
+
+test.describe("Site search", () => {
+ const SEARCH_SELECTOR = 'form input[type="search"]';
+
+ test("submit the autocomplete search form will redirect to site search", async ({
+ page,
+ }) => {
+ await page.goto(testURL("/en-US/search/"));
+ await page.fill(SEARCH_SELECTOR, "foo");
+ await page.waitForSelector("#nav-main-search"); // autocomplete search form
+ await page.$eval('form[role="search"]', (form) => form.submit());
+ // Force a wait for the lazy-loading
+ await page.waitForLoadState("networkidle");
+ // Force a wait for the search results
+ await page.waitForSelector("div.search-results");
+ expect(await page.isVisible("text=Search results for:")).toBeTruthy();
+ expect(page.url()).toBe(testURL("/en-US/search/?q=foo"));
+ });
+
+ test("go to site-search page without query", async ({ page }) => {
+ await page.goto(testURL("/en-US/search/"));
+ expect(await page.isVisible("text=No query, no results")).toBeTruthy();
+ // See server/static.js for how fixtures are hardcoded
+ await page.fill(SEARCH_SELECTOR, "FOO");
+ await page.waitForSelector("#nav-main-search"); // autocomplete search form
+ await page.$eval('form[role="search"]', (form) => form.submit());
+ // Force a wait for the lazy-loading
+ await page.waitForLoadState("networkidle");
+ expect(page.url()).toBe(testURL("/en-US/search/?q=FOO"));
+ expect(await page.isVisible("text=Search results for: FOO")).toBeTruthy();
+ expect(await page.isVisible("text=Found 1 match")).toBeTruthy();
+ });
+
+ test("search and find nothing", async ({ page }) => {
+ await page.goto(testURL("/en-US/search/"));
+ expect(await page.isVisible("text=No query, no results")).toBeTruthy();
+ // See server/static.js for how fixtures are hardcoded
+ await page.fill(SEARCH_SELECTOR, "NOTHING");
+ await page.waitForSelector("#nav-main-search"); // autocomplete search form
+ await page.$eval('form[role="search"]', (form) => form.submit());
+ await page.waitForLoadState("networkidle");
+ expect(page.url()).toBe(testURL("/en-US/search/?q=NOTHING"));
+ expect(
+ await page.isVisible("text=Search results for: NOTHING")
+ ).toBeTruthy();
+ expect(await page.isVisible("text=Found 0 matches")).toBeTruthy();
+ });
+
+ test("search and go to page 2", async ({ page }) => {
+ await page.goto(testURL("/en-US/search/"));
+ // See server/static.js for how fixtures are hardcoded
+ await page.fill(SEARCH_SELECTOR, "SERIAL(20)");
+ await page.waitForSelector("#nav-main-search"); // autocomplete search form
+ await page.$eval('form[role="search"]', (form) => form.submit());
+ await page.waitForLoadState("networkidle");
+ expect(
+ await page.isVisible("text=Search results for: SERIAL(20)")
+ ).toBeTruthy();
+ expect(page.url()).toBe(testURL("/en-US/search/?q=SERIAL%2820%29"));
+ expect(
+ await page.isVisible("text=Found 20 matches in 0.1 milliseconds")
+ ).toBeTruthy();
+ expect(await page.isVisible("text=Serial 0")).toBeTruthy();
+ expect(await page.isVisible("text=Serial 9")).toBeTruthy();
+ expect(await page.isVisible('a:has-text("Next")')).toBeTruthy();
+ expect(await page.isVisible("text=Serial 9")).toBeTruthy();
+ expect(await page.isVisible('a:has-text("Previous")')).toBeFalsy();
+ await page.click('a:has-text("Next")');
+ expect(await page.isVisible("text=(page 2)")).toBeTruthy();
+ expect(await page.isVisible("text=Serial 10")).toBeTruthy();
+ expect(await page.isVisible("text=Serial 19")).toBeTruthy();
+ expect(await page.isVisible('a:has-text("Previous")')).toBeTruthy();
+ expect(await page.isVisible('a:has-text("Next")')).toBeFalsy();
+ expect(page.url()).toBe(testURL("/en-US/search?q=SERIAL%2820%29&page=2"));
+ });
+});
diff --git a/testing/tests/headless.test.js b/testing/tests/headless.test.js
deleted file mode 100644
index bd9e156e9de0..000000000000
--- a/testing/tests/headless.test.js
+++ /dev/null
@@ -1,294 +0,0 @@
-const { setDefaultOptions } = require("expect-puppeteer");
-
-// The default it 500ms. It has happened and it can happen again, that sometimes
-// it just takes a little longer than 500ms. Give it a healthy margin of a
-// timeout so as to reduce the risk of it failing when there's nothing wrong.
-setDefaultOptions({ timeout: 1500 });
-
-function testURL(pathname = "/") {
- return `http://localhost:5000${pathname}`;
-}
-
-describe("Basic viewing of functional pages", () => {
- it("open the temporary home page", async () => {
- await page.goto(testURL("/"));
- await expect(page).toMatch("MDN Web Docs");
- await expect(page).toMatchElement("title", { text: /MDN Web Docs/ });
- });
-
- it("open the /en-US/docs/Web/Foo page", async () => {
- await page.goto(testURL("/en-US/docs/Web/Foo"));
- await expect(page).toMatch(": A test tag");
- await expect(page).toMatchElement(".metadata time", {
- visible: true,
- });
- });
-
- it("open the French /fr/docs/Web/Foo page and navigate to English", async () => {
- await page.goto(testURL("/fr/docs/Web/Foo"));
- await expect(page).toMatchElement("h1", {
- text: ": Une page de test",
- });
- await expect(page).toClick("a.view-in-english", {
- text: "View in English",
- });
- await expect(page).toMatchElement("h1", { text: ": A test tag" });
- // Should have been redirected too...
- // Note! It's important that this happens *after* the `.toMatchElement`
- // on the line above because expect-puppeteer doesn't have a wait to
- // properly wait for the (pushState) URL to have changed.
- expect(page.url()).toBe(testURL("/en-US/docs/Web/Foo/"));
- });
-
- it("open the /en-US/docs/Web/InteractiveExample page", async () => {
- await page.goto(testURL("/en-US/docs/Web/InteractiveExample"), {
- // Be a bit less patient with this particular page because it contains
- // an iframe, on an external URL, which we're not particularly
- // interested in waiting for.
- waitUntil: "domcontentloaded",
- });
- await expect(page).toMatch("I Have an Interactive Example");
- });
-
- it("open the /en-US/docs/Learn/CSS/CSS_layout/Introduction page", async () => {
- const uri = "/en-US/docs/Learn/CSS/CSS_layout/Introduction";
- const flexSample1Uri = `${uri}/Flex/_sample_.Flex_1.html`;
- const flexSample2Uri = `${uri}/Flex/_sample_.Flex_2.html`;
- const gridSample1Uri = `${uri}/Grid/_sample_.Grid_1.html`;
- const gridSample2Uri = `${uri}/_sample_.Grid_2.html`;
- await page.goto(testURL(uri));
- await expect(page).toMatch("A Test Introduction to CSS layout");
- await expect(page).toMatchElement("h1", {
- text: "A Test Introduction to CSS layout",
- });
- await expect(page).toMatchElement("#flexbox", {
- text: "Flexbox",
- });
- await expect(page).toMatchElement(
- `iframe.sample-code-frame[src$="${flexSample1Uri}"]`
- );
- await expect(page).toMatchElement(
- `iframe.sample-code-frame[src$="${flexSample2Uri}"]`
- );
- await expect(page).toMatchElement("#grid_layout", {
- text: "Grid Layout",
- });
- await expect(page).toMatchElement(
- `iframe.sample-code-frame[src$="${gridSample1Uri}"]`
- );
- await expect(page).toMatchElement("#Grid_2 pre.css.notranslate", {
- text: /\.wrapper\s*\{\s*display:\s*grid;/,
- });
- await expect(page).toMatchElement(
- `iframe.sample-code-frame[src$="${gridSample2Uri}"]`
- );
- // Ensure that the live-sample pages were built.
- for (const sampleUri of [
- flexSample1Uri,
- flexSample2Uri,
- gridSample1Uri,
- gridSample2Uri,
- ]) {
- await page.goto(testURL(sampleUri));
- await expect(page).toMatchElement("body > div.wrapper > div.box1", {
- text: "One",
- });
- await expect(page).toMatchElement("body > div.wrapper > div.box2", {
- text: "Two",
- });
- await expect(page).toMatchElement("body > div.wrapper > div.box3", {
- text: "Three",
- });
- }
- });
-
- it("open the /en-US/docs/Learn/CSS/CSS_layout/Introduction/Flex page", async () => {
- const uri = "/en-US/docs/Learn/CSS/CSS_layout/Introduction/Flex";
- const flexSample1Uri = `${uri}/_sample_.Flex_1.html`;
- const flexSample2Uri = `${uri}/_sample_.Flex_2.html`;
- await page.goto(testURL(uri));
- await expect(page).toMatch("A Test Introduction to CSS Flexbox Layout");
- await expect(page).toMatchElement("h1", {
- text: "A Test Introduction to CSS Flexbox Layout",
- });
- await expect(page).toMatchElement("#flexbox", {
- text: "Flexbox",
- });
- await expect(page).toMatchElement("#Flex_1 pre.css.notranslate", {
- text: /\.wrapper\s*\{\s*display:\s*flex;\s*\}/,
- });
- await expect(page).toMatchElement(
- `iframe.sample-code-frame[src$="${flexSample1Uri}"]`
- );
- await expect(page).toMatchElement("#Flex_2 pre.css.notranslate", {
- text: /\.wrapper\s*\{\s*display:\s*flex;\s*\}.+flex:\s*1;/,
- });
- await expect(page).toMatchElement(
- `iframe.sample-code-frame[src$="${flexSample2Uri}"]`
- );
- });
-
- it("open the /en-US/docs/Learn/CSS/CSS_layout/Introduction/Grid page", async () => {
- const uri = "/en-US/docs/Learn/CSS/CSS_layout/Introduction/Grid";
- const gridSample1Uri = `${uri}/_sample_.Grid_1.html`;
- const gridSample2Uri = `${uri}/_sample_.Grid_2.html`;
- await page.goto(testURL(uri));
- await expect(page).toMatch("A Test Introduction to CSS Grid Layout");
- await expect(page).toMatchElement("h1", {
- text: "A Test Introduction to CSS Grid Layout",
- });
- await expect(page).toMatchElement("#grid_layout", {
- text: "Grid Layout",
- });
- await expect(page).toMatchElement("#Grid_1 pre.css.notranslate", {
- text: /\.wrapper\s*\{\s*display:\s*grid;/,
- });
- await expect(page).toMatchElement(
- `iframe.sample-code-frame[src$="${gridSample1Uri}"]`
- );
- await expect(page).toMatchElement("#Grid_2 pre.css.notranslate", {
- text: /\.wrapper\s*\{\s*display:\s*grid;.+\.box1\s*\{/,
- });
- await expect(page).toMatchElement(
- `iframe.sample-code-frame[src$="${gridSample2Uri}"]`
- );
- // Ensure that the live-sample page "gridSample2Uri" was built.
- await page.goto(testURL(gridSample2Uri));
- await expect(page).toMatchElement("body > div.wrapper > div.box1", {
- text: "One",
- });
- await expect(page).toMatchElement("body > div.wrapper > div.box2", {
- text: "Two",
- });
- await expect(page).toMatchElement("body > div.wrapper > div.box3", {
- text: "Three",
- });
- });
-
- it("should return to previous page on back-button press", async () => {
- await page.goto(testURL("/en-US/docs/Web/Foo"));
- await expect(page).toMatch(": A test tag");
- await expect(page).toMatchElement("h1", {
- text: ": A test tag",
- });
- // Click the parent page in the breadcrumbs
- // BUT due to some bug somewhere, you can't do
- //
- // await expect(page).toClick("nav.breadcrumbs a")
- //
- // ...because you keep getting:
- //
- // "Node is either not visible or not an HTMLElement"
- //
- // So, because of that, let's just do it "the pure puppeteer way."
- //
- // For more information, see
- // https://github.com/puppeteer/puppeteer/issues/2977#issuecomment-412807613
- await page.evaluate(() => {
- document.querySelector(".breadcrumbs-container a").click();
- });
- await expect(page).toMatchElement("h1", {
- text: "Web technology for developers",
- });
- expect(page.url()).toBe(testURL("/en-US/docs/Web"));
- await page.goBack();
- await expect(page).toMatchElement("h1", {
- text: ": A test tag",
- });
- });
-
- it("should have a semantically valid breadcrumb trail", async () => {
- await page.goto(testURL("/en-US/docs/Web/Foo"));
- // Let's not get too technical about the name of the selectors and
- // stuff but do note that the page you're on is always a valid link
- await expect(page).toMatchElement("nav a[property=item][typeof=WebPage]", {
- // Always includes a link to "self"
- text: ": A test tag",
- });
- await expect(page).toMatchElement("nav a[property=item][typeof=WebPage]", {
- // You gotta know your fixture documents
- text: "Web technology for developers",
- });
- });
-
- it("should say which page was not found", async () => {
- await page.goto(testURL("/en-US/docs/Doesnot/exist"));
- await expect(page).toMatch("Page not found");
- await expect(page).toMatch("/en-US/docs/Doesnot/exist could not be found");
- });
-
- it("should suggest the en-US equivalent on non-en-US pages not found", async () => {
- await page.goto(testURL("/ja/docs/Web/foo"));
- await expect(page).toMatch("Page not found");
- await expect(page).toMatch("/ja/docs/Web/foo could not be found");
- // Simply by swapping the "ja" for "en-US" it's able to find the index.json
- // for that slug and present a link to it.
- await expect(page).toMatch("Good news!");
- await expect(page).toMatchElement("a", {
- text: ": A test tag",
- href: "/en-US/docs/Web/Foo",
- });
- });
-
- it("should give the home page and see Hacks blog posts", async () => {
- await page.goto(testURL("/en-US/"));
- await expect(page).toMatch("Resources for developers, by developers.");
- await expect(page).toMatch("Hacks Blog");
-
- // One home page for every built locale
- await page.goto(testURL("/fr/"));
- await expect(page).toMatch("Resources for developers, by developers.");
- });
-
- it("should be able to switch from French to English, set a cookie, and back again", async () => {
- await page.goto(testURL("/fr/docs/Web/Foo"));
- await expect(page).toMatch(": Une page de test");
- await expect(page).toSelect('select[name="language"]', "English (US)");
- await expect(page).toClick("button", { text: "Change language" });
- await expect(page).toMatch(": A test tag");
- expect(page.url()).toBe(testURL("/en-US/docs/Web/Foo/"));
-
- // And change back to French
- await expect(page).toSelect('select[name="language"]', "Français");
- await expect(page).toClick("button", { text: "Change language" });
- await expect(page).toMatch(": Une page de test");
- expect(page.url()).toBe(testURL("/fr/docs/Web/Foo/"));
- });
-
- it("should redirect retired locale to English (document)", async () => {
- await page.goto(testURL("/ar/docs/Web/Foo"));
- await expect(page.url()).toMatch(
- testURL("/en-US/docs/Web/Foo/?retiredLocale=ar")
- );
- await expect(page).toMatch(": A test tag");
- });
-
- it("should redirect retired locale to English (index.json)", async () => {
- await page.goto(testURL("/ar/docs/Web/Foo/index.json"));
- await expect(page.url()).toMatch(
- testURL("/en-US/docs/Web/Foo/index.json?retiredLocale=ar")
- );
- await expect(page).toMatch(": A test tag");
- });
-
- it("should redirect retired locale to English (search with query string)", async () => {
- await page.goto(testURL("/ar/search?q=video"));
- await expect(page.url()).toMatch(
- testURL("/en-US/search/?q=video&retiredLocale=ar")
- );
- await expect(page).toMatch("Search results for: video");
- });
-
- it("should say the locale was retired", async () => {
- await page.goto(testURL("/en-US/docs/Web/Foo/?retiredLocale=ar"));
- await expect(page).toMatch("The page you requested has been retired");
- // sanity check that it goes away
- await page.goto(testURL("/en-US/docs/Web/Foo/"));
- await expect(page).not.toMatch("The page you requested has been retired");
- });
-
- it("should not say the locale was retired if viewing a translated page", async () => {
- await page.goto(testURL("/fr/docs/Web/Foo/?retiredLocale=sv-SE"));
- await expect(page).not.toMatch("The page you requested has been retired");
- });
-});
diff --git a/testing/tests/index.test.js b/testing/tests/index.test.js
index 1ebfa8e0df9f..7a86441e010a 100644
--- a/testing/tests/index.test.js
+++ b/testing/tests/index.test.js
@@ -5,7 +5,7 @@ const cheerio = require("cheerio");
const glob = require("glob");
const sizeOf = require("image-size");
-const buildRoot = path.join("..", "client", "build");
+const buildRoot = path.join("client", "build");
test("all favicons on the home page", () => {
// The home page SPA is built, in terms of the index.html template,
diff --git a/testing/tests/sitesearch.test.js b/testing/tests/sitesearch.test.js
deleted file mode 100644
index eef148e61007..000000000000
--- a/testing/tests/sitesearch.test.js
+++ /dev/null
@@ -1,61 +0,0 @@
-function testURL(pathname = "/") {
- return "http://localhost:5000" + pathname;
-}
-
-describe("Site search", () => {
- const SEARCH_SELECTOR = 'form input[type="search"]';
-
- test("Submit the autocomplete search form will redirect to site search", async () => {
- await page.goto(testURL("/"));
- await expect(page).toFill(SEARCH_SELECTOR, "foo");
- await page.$eval('form[role="search"]', (form) => form.submit());
- // Force a wait for the lazy-loading
- await page.waitForNavigation({ waitUntil: "networkidle2" });
- expect(page.url()).toBe(testURL("/en-US/search/?q=foo"));
- });
-
- test("Go to site-search page without query", async () => {
- await page.goto(testURL("/en-us/search/"));
- await expect(page).toMatch("No query, no results");
- // See server/static.js for how fixtures are hardcoded
- await expect(page).toFill(SEARCH_SELECTOR, "FOO");
- await page.$eval('form[role="search"]', (form) => form.submit());
- // Force a wait for the lazy-loading
- await page.waitForNavigation({ waitUntil: "networkidle2" });
- await expect(page).toMatch("Search results for: FOO");
- await expect(page).toMatch("Found 1 match");
- });
-
- test("Search and find nothing", async () => {
- await page.goto(testURL("/en-us/search/"));
- await expect(page).toMatch("No query, no results");
- // See server/static.js for how fixtures are hardcoded
- await expect(page).toFill(SEARCH_SELECTOR, "NOTHING");
- await page.$eval('form[role="search"]', (form) => form.submit());
- await page.waitForNavigation({ waitUntil: "networkidle2" });
- await expect(page).toMatch("Search results for: NOTHING");
- await expect(page).toMatch("Found 0 matches");
- });
-
- test("Search and go to page 2", async () => {
- await page.goto(testURL("/en-US/search/"));
- // See server/static.js for how fixtures are hardcoded
- await expect(page).toFill(SEARCH_SELECTOR, "SERIAL(20)");
- await page.$eval('form[role="search"]', (form) => form.submit());
- await page.waitForNavigation({ waitUntil: "networkidle2" });
- await expect(page).toMatch("Search results for: SERIAL(20)");
- expect(page.url()).toBe(testURL("/en-US/search/?q=SERIAL%2820%29"));
- await expect(page).toMatch("Found 20 matches in 0.1 milliseconds");
- await expect(page).toMatch("Serial 0");
- await expect(page).toMatch("Serial 9");
- await expect(page).toMatchElement("a", { text: "Next" });
- await expect(page).not.toMatchElement("a", { text: "Previous" });
- await expect(page).toClick(".pagination a");
- await expect(page).toMatch("(page 2)");
- await expect(page).toMatch("Serial 10");
- await expect(page).toMatch("Serial 19");
- await expect(page).toMatchElement("a", { text: "Previous" });
- await expect(page).not.toMatchElement("a", { text: "Next" });
- expect(page.url()).toBe(testURL("/en-US/search?q=SERIAL%2820%29&page=2"));
- });
-});
diff --git a/yarn.lock b/yarn.lock
index e75a366079aa..b3d26e74fcd3 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -96,7 +96,28 @@
semver "^6.3.0"
source-map "^0.5.0"
-"@babel/generator@^7.12.1", "@babel/generator@^7.12.11", "@babel/generator@^7.12.5", "@babel/generator@^7.15.0":
+"@babel/core@^7.14.0":
+ version "7.14.8"
+ resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.14.8.tgz#20cdf7c84b5d86d83fac8710a8bc605a7ba3f010"
+ integrity sha512-/AtaeEhT6ErpDhInbXmjHcUQXH0L0TEgscfcxk1qbOvLuKCa5aZT0SOOtDKFY96/CLROwbLSKyFor6idgNaU4Q==
+ dependencies:
+ "@babel/code-frame" "^7.14.5"
+ "@babel/generator" "^7.14.8"
+ "@babel/helper-compilation-targets" "^7.14.5"
+ "@babel/helper-module-transforms" "^7.14.8"
+ "@babel/helpers" "^7.14.8"
+ "@babel/parser" "^7.14.8"
+ "@babel/template" "^7.14.5"
+ "@babel/traverse" "^7.14.8"
+ "@babel/types" "^7.14.8"
+ convert-source-map "^1.7.0"
+ debug "^4.1.0"
+ gensync "^1.0.0-beta.2"
+ json5 "^2.1.2"
+ semver "^6.3.0"
+ source-map "^0.5.0"
+
+"@babel/generator@^7.12.1", "@babel/generator@^7.12.11", "@babel/generator@^7.12.5", "@babel/generator@^7.14.8", "@babel/generator@^7.15.0":
version "7.15.0"
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.15.0.tgz#a7d0c172e0d814974bad5aa77ace543b97917f15"
integrity sha512-eKl4XdMrbpYvuB505KTta4AV9g+wWzmVBW69tX0H2NwKVKd2YJbKgyK6M8j/rgLbmHOYJn6rUklV677nOyJrEQ==
@@ -119,6 +140,13 @@
dependencies:
"@babel/types" "^7.12.13"
+"@babel/helper-annotate-as-pure@^7.14.5":
+ version "7.14.5"
+ resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.14.5.tgz#7bf478ec3b71726d56a8ca5775b046fc29879e61"
+ integrity sha512-EivH9EgBIb+G8ij1B2jAwSH36WnGvkQSEC6CkX/6v6ZFlw5fVOHvsgGF4uiEHO2GzMvunZb6tDLQEQSdrdocrA==
+ dependencies:
+ "@babel/types" "^7.14.5"
+
"@babel/helper-builder-binary-assignment-operator-visitor@^7.10.4":
version "7.10.4"
resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.10.4.tgz#bb0b75f31bf98cbf9ff143c1ae578b87274ae1a3"
@@ -152,7 +180,7 @@
"@babel/helper-annotate-as-pure" "^7.10.4"
"@babel/types" "^7.10.4"
-"@babel/helper-compilation-targets@^7.12.1", "@babel/helper-compilation-targets@^7.12.5", "@babel/helper-compilation-targets@^7.13.0", "@babel/helper-compilation-targets@^7.13.13", "@babel/helper-compilation-targets@^7.13.8", "@babel/helper-compilation-targets@^7.15.0":
+"@babel/helper-compilation-targets@^7.12.1", "@babel/helper-compilation-targets@^7.12.5", "@babel/helper-compilation-targets@^7.13.0", "@babel/helper-compilation-targets@^7.13.13", "@babel/helper-compilation-targets@^7.13.8", "@babel/helper-compilation-targets@^7.14.5", "@babel/helper-compilation-targets@^7.15.0":
version "7.15.0"
resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.15.0.tgz#973df8cbd025515f3ff25db0c05efc704fa79818"
integrity sha512-h+/9t0ncd4jfZ8wsdAsoIxSa61qhBYlycXiHWqJaQBCXAhDCMbPRSMTGnZIkkmt1u4ag+UQmuqcILwqKzZ4N2A==
@@ -184,6 +212,18 @@
"@babel/helper-replace-supers" "^7.13.0"
"@babel/helper-split-export-declaration" "^7.12.13"
+"@babel/helper-create-class-features-plugin@^7.14.5", "@babel/helper-create-class-features-plugin@^7.14.6":
+ version "7.14.8"
+ resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.14.8.tgz#a6f8c3de208b1e5629424a9a63567f56501955fc"
+ integrity sha512-bpYvH8zJBWzeqi1o+co8qOrw+EXzQ/0c74gVmY205AWXy9nifHrOg77y+1zwxX5lXE7Icq4sPlSQ4O2kWBrteQ==
+ dependencies:
+ "@babel/helper-annotate-as-pure" "^7.14.5"
+ "@babel/helper-function-name" "^7.14.5"
+ "@babel/helper-member-expression-to-functions" "^7.14.7"
+ "@babel/helper-optimise-call-expression" "^7.14.5"
+ "@babel/helper-replace-supers" "^7.14.5"
+ "@babel/helper-split-export-declaration" "^7.14.5"
+
"@babel/helper-create-regexp-features-plugin@^7.10.4":
version "7.10.4"
resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.10.4.tgz#fdd60d88524659a0b6959c0579925e425714f3b8"
@@ -345,6 +385,13 @@
dependencies:
"@babel/types" "^7.13.12"
+"@babel/helper-member-expression-to-functions@^7.14.7":
+ version "7.14.7"
+ resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.14.7.tgz#97e56244beb94211fe277bd818e3a329c66f7970"
+ integrity sha512-TMUt4xKxJn6ccjcOW7c4hlwyJArizskAhoSTOCkA0uZ+KghIaci0Qg9R043kUMWI9mtQfgny+NQ5QATnZ+paaA==
+ dependencies:
+ "@babel/types" "^7.14.5"
+
"@babel/helper-member-expression-to-functions@^7.15.0":
version "7.15.0"
resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.15.0.tgz#0ddaf5299c8179f27f37327936553e9bba60990b"
@@ -394,7 +441,7 @@
dependencies:
"@babel/types" "^7.14.5"
-"@babel/helper-module-transforms@^7.12.1", "@babel/helper-module-transforms@^7.13.0", "@babel/helper-module-transforms@^7.15.0":
+"@babel/helper-module-transforms@^7.12.1", "@babel/helper-module-transforms@^7.13.0", "@babel/helper-module-transforms@^7.14.8", "@babel/helper-module-transforms@^7.15.0":
version "7.15.0"
resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.15.0.tgz#679275581ea056373eddbe360e1419ef23783b08"
integrity sha512-RkGiW5Rer7fpXv9m1B3iHIFDZdItnO2/BLfWVW/9q7+KqQSDY5kUfQEbzdXM1MVhJGcugKV7kRrNVzNxmk7NBg==
@@ -408,6 +455,20 @@
"@babel/traverse" "^7.15.0"
"@babel/types" "^7.15.0"
+"@babel/helper-module-transforms@^7.14.5":
+ version "7.14.8"
+ resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.14.8.tgz#d4279f7e3fd5f4d5d342d833af36d4dd87d7dc49"
+ integrity sha512-RyE+NFOjXn5A9YU1dkpeBaduagTlZ0+fccnIcAGbv1KGUlReBj7utF7oEth8IdIBQPcux0DDgW5MFBH2xu9KcA==
+ dependencies:
+ "@babel/helper-module-imports" "^7.14.5"
+ "@babel/helper-replace-supers" "^7.14.5"
+ "@babel/helper-simple-access" "^7.14.8"
+ "@babel/helper-split-export-declaration" "^7.14.5"
+ "@babel/helper-validator-identifier" "^7.14.8"
+ "@babel/template" "^7.14.5"
+ "@babel/traverse" "^7.14.8"
+ "@babel/types" "^7.14.8"
+
"@babel/helper-optimise-call-expression@^7.10.4":
version "7.10.4"
resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.10.4.tgz#50dc96413d594f995a77905905b05893cd779673"
@@ -444,6 +505,11 @@
resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz#806526ce125aed03373bc416a828321e3a6a33af"
integrity sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==
+"@babel/helper-plugin-utils@^7.14.5":
+ version "7.14.5"
+ resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz#5ac822ce97eec46741ab70a517971e443a70c5a9"
+ integrity sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ==
+
"@babel/helper-regex@^7.10.4":
version "7.10.5"
resolved "https://registry.yarnpkg.com/@babel/helper-regex/-/helper-regex-7.10.5.tgz#32dfbb79899073c415557053a19bd055aae50ae0"
@@ -489,7 +555,7 @@
"@babel/traverse" "^7.13.0"
"@babel/types" "^7.13.12"
-"@babel/helper-replace-supers@^7.15.0":
+"@babel/helper-replace-supers@^7.14.5", "@babel/helper-replace-supers@^7.15.0":
version "7.15.0"
resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.15.0.tgz#ace07708f5bf746bf2e6ba99572cce79b5d4e7f4"
integrity sha512-6O+eWrhx+HEra/uJnifCwhwMd6Bp5+ZfZeJwbqUTuqkhIT6YcRhiZCOOFChRypOIe0cV46kFrRBlm+t5vHCEaA==
@@ -513,7 +579,7 @@
dependencies:
"@babel/types" "^7.13.12"
-"@babel/helper-simple-access@^7.14.8":
+"@babel/helper-simple-access@^7.14.5", "@babel/helper-simple-access@^7.14.8":
version "7.14.8"
resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.14.8.tgz#82e1fec0644a7e775c74d305f212c39f8fe73924"
integrity sha512-TrFN4RHh9gnWEU+s7JloIho2T76GPwRHhdzOWLqTrMnlas8T9O7ec+oEDNsRXndOmru9ymH9DFrEOxpzPoSbdg==
@@ -563,7 +629,7 @@
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.5.tgz#d0f0e277c512e0c938277faa85a3968c9a44c0e8"
integrity sha512-5lsetuxCLilmVGyiLEfoHBRX8UCFD+1m2x3Rj97WrW3V7H3u4RWRXA4evMjImCsin2J2YT0QaVDGf+z8ondbAg==
-"@babel/helper-validator-identifier@^7.14.9":
+"@babel/helper-validator-identifier@^7.14.8", "@babel/helper-validator-identifier@^7.14.9":
version "7.14.9"
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.9.tgz#6654d171b2024f6d8ee151bf2509699919131d48"
integrity sha512-pQYxPY0UP6IHISRitNe8bsijHex4TWZXi2HwKVsjPiltzlhse2znVcm9Ace510VT1kxIHjGJCZZQBX2gJDbo0g==
@@ -630,7 +696,7 @@
chalk "^2.0.0"
js-tokens "^4.0.0"
-"@babel/parser@^7.1.0", "@babel/parser@^7.12.11", "@babel/parser@^7.12.3", "@babel/parser@^7.12.7", "@babel/parser@^7.14.5", "@babel/parser@^7.15.0", "@babel/parser@^7.7.0":
+"@babel/parser@^7.1.0", "@babel/parser@^7.12.11", "@babel/parser@^7.12.3", "@babel/parser@^7.12.7", "@babel/parser@^7.14.5", "@babel/parser@^7.14.8", "@babel/parser@^7.15.0", "@babel/parser@^7.7.0":
version "7.15.0"
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.15.0.tgz#b6d6e29058ca369127b0eeca2a1c4b5794f1b6b9"
integrity sha512-0v7oNOjr6YT9Z2RAOTv4T9aP+ubfx4Q/OhVtAet7PFDt0t9Oy6Jn+/rfC6b8HJ5zEqrQCiMxJfgtHpmIminmJQ==
@@ -887,6 +953,16 @@
"@babel/helper-create-class-features-plugin" "^7.13.0"
"@babel/helper-plugin-utils" "^7.13.0"
+"@babel/plugin-proposal-private-property-in-object@^7.14.0":
+ version "7.14.5"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.14.5.tgz#9f65a4d0493a940b4c01f8aa9d3f1894a587f636"
+ integrity sha512-62EyfyA3WA0mZiF2e2IV9mc9Ghwxcg8YTu8BS4Wss4Y3PY725OmS9M0qLORbJwLqFtGh+jiE4wAmocK2CTUK2Q==
+ dependencies:
+ "@babel/helper-annotate-as-pure" "^7.14.5"
+ "@babel/helper-create-class-features-plugin" "^7.14.5"
+ "@babel/helper-plugin-utils" "^7.14.5"
+ "@babel/plugin-syntax-private-property-in-object" "^7.14.5"
+
"@babel/plugin-proposal-unicode-property-regex@^7.12.1":
version "7.12.1"
resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.12.1.tgz#2a183958d417765b9eae334f47758e5d6a82e072"
@@ -1051,6 +1127,13 @@
dependencies:
"@babel/helper-plugin-utils" "^7.8.0"
+"@babel/plugin-syntax-private-property-in-object@^7.14.5":
+ version "7.14.5"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz#0dc6671ec0ea22b6e94a1114f857970cd39de1ad"
+ integrity sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.14.5"
+
"@babel/plugin-syntax-top-level-await@^7.12.1":
version "7.12.1"
resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.12.1.tgz#dd6c0b357ac1bb142d98537450a319625d13d2a0"
@@ -1086,6 +1169,13 @@
dependencies:
"@babel/helper-plugin-utils" "^7.12.13"
+"@babel/plugin-syntax-typescript@^7.14.5":
+ version "7.14.5"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.14.5.tgz#b82c6ce471b165b5ce420cf92914d6fb46225716"
+ integrity sha512-u6OXzDaIXjEstBRRoBCQ/uKQKlbuaeE5in0RvWdA4pN6AhqxTIwUsnHPU1CFZA/amYObMsuWhYfRl3Ch90HD0Q==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.14.5"
+
"@babel/plugin-transform-arrow-functions@^7.12.1":
version "7.12.1"
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.12.1.tgz#8083ffc86ac8e777fbe24b5967c4b2521f3cb2b3"
@@ -1359,6 +1449,16 @@
"@babel/helper-simple-access" "^7.12.13"
babel-plugin-dynamic-import-node "^2.3.3"
+"@babel/plugin-transform-modules-commonjs@^7.14.0":
+ version "7.14.5"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.14.5.tgz#7aaee0ea98283de94da98b28f8c35701429dad97"
+ integrity sha512-en8GfBtgnydoao2PS+87mKyw62k02k7kJ9ltbKe0fXTHrQmG6QZZflYuGI1VVG7sVpx4E1n7KBpNlPb8m78J+A==
+ dependencies:
+ "@babel/helper-module-transforms" "^7.14.5"
+ "@babel/helper-plugin-utils" "^7.14.5"
+ "@babel/helper-simple-access" "^7.14.5"
+ babel-plugin-dynamic-import-node "^2.3.3"
+
"@babel/plugin-transform-modules-systemjs@^7.12.1":
version "7.12.1"
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.12.1.tgz#663fea620d593c93f214a464cd399bf6dc683086"
@@ -1695,6 +1795,15 @@
"@babel/helper-plugin-utils" "^7.13.0"
"@babel/plugin-syntax-typescript" "^7.12.13"
+"@babel/plugin-transform-typescript@^7.14.5":
+ version "7.14.6"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.14.6.tgz#6e9c2d98da2507ebe0a883b100cde3c7279df36c"
+ integrity sha512-XlTdBq7Awr4FYIzqhmYY80WN0V0azF74DMPyFqVHBvf81ZUgc4X7ZOpx6O8eLDK6iM5cCQzeyJw0ynTaefixRA==
+ dependencies:
+ "@babel/helper-create-class-features-plugin" "^7.14.6"
+ "@babel/helper-plugin-utils" "^7.14.5"
+ "@babel/plugin-syntax-typescript" "^7.14.5"
+
"@babel/plugin-transform-unicode-escapes@^7.12.1":
version "7.12.1"
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.12.1.tgz#5232b9f81ccb07070b7c3c36c67a1b78f1845709"
@@ -2027,6 +2136,15 @@
"@babel/helper-validator-option" "^7.12.17"
"@babel/plugin-transform-typescript" "^7.13.0"
+"@babel/preset-typescript@^7.13.0":
+ version "7.14.5"
+ resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.14.5.tgz#aa98de119cf9852b79511f19e7f44a2d379bcce0"
+ integrity sha512-u4zO6CdbRKbS9TypMqrlGH7sd2TAJppZwn3c/ZRLeO/wGsbddxgbPDUZVNrie3JWYLQ9vpineKlsrWFvO6Pwkw==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.14.5"
+ "@babel/helper-validator-option" "^7.14.5"
+ "@babel/plugin-transform-typescript" "^7.14.5"
+
"@babel/register@^7.12.1":
version "7.12.1"
resolved "https://registry.yarnpkg.com/@babel/register/-/register-7.12.1.tgz#cdb087bdfc4f7241c03231f22e15d211acf21438"
@@ -2290,11 +2408,6 @@
resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-8.5.1.tgz#fde96064ca446dec8c55a8c2f130957b070c6e06"
integrity sha512-yN7kbciD87WzLGc5539Tn0sApjyiGHAJgKvG9W8C7O+6c7qmoQMfVs0W4bX17eqz6C78QJqqFrtgdK5EWf6Qow==
-"@hapi/hoek@^9.0.0":
- version "9.2.0"
- resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-9.2.0.tgz#f3933a44e365864f4dad5db94158106d511e8131"
- integrity sha512-sqKVVVOe5ivCaXDWivIJYVSaEgdQK9ul7a4Kity5Iw7u9+wBAPbX1RMSnLLmp7O4Vzj0WOWwMAJsTL00xwaNug==
-
"@hapi/joi@^15.1.0":
version "15.1.1"
resolved "https://registry.yarnpkg.com/@hapi/joi/-/joi-15.1.1.tgz#c675b8a71296f02833f8d6d243b34c57b8ce19d7"
@@ -2312,13 +2425,6 @@
dependencies:
"@hapi/hoek" "^8.3.0"
-"@hapi/topo@^5.0.0":
- version "5.0.0"
- resolved "https://registry.yarnpkg.com/@hapi/topo/-/topo-5.0.0.tgz#c19af8577fa393a06e9c77b60995af959be721e7"
- integrity sha512-tFJlT47db0kMqVm3H4nQYgn6Pwg10GTZHb1pwmSiv1K4ks6drQOtfEF5ZnPjkvC+y4/bUPHK+bc87QvLcL+WMw==
- dependencies:
- "@hapi/hoek" "^9.0.0"
-
"@html-validate/stylish@^1.0.0":
version "1.0.0"
resolved "https://registry.yarnpkg.com/@html-validate/stylish/-/stylish-1.0.0.tgz#f8700775d8863e7de50564f8d3e6908a5f40ab9d"
@@ -2400,16 +2506,6 @@
"@types/node" "*"
jest-mock "^26.6.2"
-"@jest/environment@^27.0.1":
- version "27.0.1"
- resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-27.0.1.tgz#27ed89bf8179c0a030690f063d922d6da7a519ac"
- integrity sha512-nG+r3uSs2pOTsdhgt6lUm4ZGJLRcTc6HZIkrFsVpPcdSqEpJehEny9r9y2Bmhkn8fKXWdGCYJKF3i4nKO0HSmA==
- dependencies:
- "@jest/fake-timers" "^27.0.1"
- "@jest/types" "^27.0.1"
- "@types/node" "*"
- jest-mock "^27.0.1"
-
"@jest/fake-timers@^25.1.0":
version "25.5.0"
resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-25.5.0.tgz#46352e00533c024c90c2bc2ad9f2959f7f114185"
@@ -2433,18 +2529,6 @@
jest-mock "^26.6.2"
jest-util "^26.6.2"
-"@jest/fake-timers@^27.0.1":
- version "27.0.1"
- resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-27.0.1.tgz#6987a596b0bcf8c07653086076c17058b4c77b5c"
- integrity sha512-3CyLJQnHzKI4TCJSCo+I9TzIHjSK4RrNEk93jFM6Q9+9WlSJ3mpMq/p2YuKMe0SiHKbmZOd5G/Ll5ofF9Xkw9g==
- dependencies:
- "@jest/types" "^27.0.1"
- "@sinonjs/fake-timers" "^7.0.2"
- "@types/node" "*"
- jest-message-util "^27.0.1"
- jest-mock "^27.0.1"
- jest-util "^27.0.1"
-
"@jest/globals@^26.6.2":
version "26.6.2"
resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-26.6.2.tgz#5b613b78a1aa2655ae908eba638cc96a20df720a"
@@ -2569,17 +2653,6 @@
"@types/yargs" "^15.0.0"
chalk "^4.0.0"
-"@jest/types@^27.0.1":
- version "27.0.1"
- resolved "https://registry.yarnpkg.com/@jest/types/-/types-27.0.1.tgz#631738c942e70045ebbf42a3f9b433036d3845e4"
- integrity sha512-8A25RRV4twZutsx2D+7WphnDsp7If9Yu6ko0Gxwrwv8BiWESFzka34+Aa2kC8w9xewt7SDuCUSZ6IiAFVj3PRg==
- dependencies:
- "@types/istanbul-lib-coverage" "^2.0.0"
- "@types/istanbul-reports" "^3.0.0"
- "@types/node" "*"
- "@types/yargs" "^16.0.0"
- chalk "^4.0.0"
-
"@jest/types@^27.0.2":
version "27.0.2"
resolved "https://registry.yarnpkg.com/@jest/types/-/types-27.0.2.tgz#e153d6c46bda0f2589f0702b071f9898c7bbd37e"
@@ -2691,6 +2764,50 @@
dependencies:
mkdirp "^1.0.4"
+"@playwright/test@1.13.0":
+ version "1.13.0"
+ resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.13.0.tgz#d22fa9f02c17758f7cb6178be3e22462c4357582"
+ integrity sha512-pT9GTQ1eaxdxycnGg4ZANxGZsu4bzN6M8eRzcDxTprJUWZDBqZknGImOFKMRkHB+YhS8UJRuJ6YpPfZaNL2RLw==
+ dependencies:
+ "@babel/code-frame" "^7.12.13"
+ "@babel/core" "^7.14.0"
+ "@babel/plugin-proposal-class-properties" "^7.13.0"
+ "@babel/plugin-proposal-dynamic-import" "^7.13.8"
+ "@babel/plugin-proposal-export-namespace-from" "^7.12.13"
+ "@babel/plugin-proposal-logical-assignment-operators" "^7.13.8"
+ "@babel/plugin-proposal-nullish-coalescing-operator" "^7.13.8"
+ "@babel/plugin-proposal-numeric-separator" "^7.12.13"
+ "@babel/plugin-proposal-optional-chaining" "^7.13.12"
+ "@babel/plugin-proposal-private-methods" "^7.13.0"
+ "@babel/plugin-proposal-private-property-in-object" "^7.14.0"
+ "@babel/plugin-syntax-async-generators" "^7.8.4"
+ "@babel/plugin-syntax-json-strings" "^7.8.3"
+ "@babel/plugin-syntax-object-rest-spread" "^7.8.3"
+ "@babel/plugin-syntax-optional-catch-binding" "^7.8.3"
+ "@babel/plugin-transform-modules-commonjs" "^7.14.0"
+ "@babel/preset-typescript" "^7.13.0"
+ colors "^1.4.0"
+ commander "^6.1.0"
+ debug "^4.1.1"
+ expect "^26.4.2"
+ extract-zip "^2.0.1"
+ https-proxy-agent "^5.0.0"
+ jpeg-js "^0.4.2"
+ mime "^2.4.6"
+ minimatch "^3.0.3"
+ ms "^2.1.2"
+ pirates "^4.0.1"
+ pixelmatch "^5.2.1"
+ pngjs "^5.0.0"
+ progress "^2.0.3"
+ proper-lockfile "^4.1.1"
+ proxy-from-env "^1.1.0"
+ rimraf "^3.0.2"
+ source-map-support "^0.4.18"
+ stack-utils "^2.0.3"
+ ws "^7.4.6"
+ yazl "^2.5.1"
+
"@pmmmwh/react-refresh-webpack-plugin@0.4.3", "@pmmmwh/react-refresh-webpack-plugin@^0.4.3":
version "0.4.3"
resolved "https://registry.yarnpkg.com/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.4.3.tgz#1eec460596d200c0236bf195b078a5d1df89b766"
@@ -2751,23 +2868,6 @@
estree-walker "^1.0.1"
picomatch "^2.2.2"
-"@sideway/address@^4.1.0":
- version "4.1.1"
- resolved "https://registry.yarnpkg.com/@sideway/address/-/address-4.1.1.tgz#9e321e74310963fdf8eebfbee09c7bd69972de4d"
- integrity sha512-+I5aaQr3m0OAmMr7RQ3fR9zx55sejEYR2BFJaxL+zT3VM2611X0SHvPWIbAUBZVTn/YzYKbV8gJ2oT/QELknfQ==
- dependencies:
- "@hapi/hoek" "^9.0.0"
-
-"@sideway/formula@^3.0.0":
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/@sideway/formula/-/formula-3.0.0.tgz#fe158aee32e6bd5de85044be615bc08478a0a13c"
- integrity sha512-vHe7wZ4NOXVfkoRb8T5otiENVlT7a3IAiw7H5M2+GO+9CDgcVUUsX1zalAztCmwyOr2RUTGJdgB+ZvSVqmdHmg==
-
-"@sideway/pinpoint@^2.0.0":
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/@sideway/pinpoint/-/pinpoint-2.0.0.tgz#cff8ffadc372ad29fd3f78277aeb29e632cc70df"
- integrity sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==
-
"@sidvind/better-ajv-errors@^0.9.0":
version "0.9.0"
resolved "https://registry.yarnpkg.com/@sidvind/better-ajv-errors/-/better-ajv-errors-0.9.0.tgz#fcc84df0d2a68b100a4d6b9b2cc7066525c42dee"
@@ -2803,13 +2903,6 @@
dependencies:
"@sinonjs/commons" "^1.7.0"
-"@sinonjs/fake-timers@^7.0.2":
- version "7.1.0"
- resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-7.1.0.tgz#8f13af27d842cbf51ad4502e05562fe9391d084e"
- integrity sha512-hAEzXi6Wbvlb67NnGMGSNOeAflLVnMa4yliPU/ty1qjgW/vAletH15/v/esJwASSIA0YlIyjnloenFbEZc9q9A==
- dependencies:
- "@sinonjs/commons" "^1.7.0"
-
"@storybook/addon-a11y@^6.3.4":
version "6.3.4"
resolved "https://registry.yarnpkg.com/@storybook/addon-a11y/-/addon-a11y-6.3.4.tgz#056c3c0e3b2d66d8aa2f02dc84374c948d07df91"
@@ -5079,13 +5172,6 @@ axe-core@^4.2.0:
resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.3.1.tgz#0c6a076e4a1c3e0544ba6a9479158f9be7a7928e"
integrity sha512-3WVgVPs/7OnKU3s+lqMtkv3wQlg3WxK1YifmpJSDO0E1aPBrZWlrrTO6cxRqCXLuX2aYgCljqXIQd0VnRidV0g==
-axios@^0.21.1:
- version "0.21.1"
- resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.1.tgz#22563481962f4d6bde9a76d516ef0e5d3c09b2b8"
- integrity sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==
- dependencies:
- follow-redirects "^1.10.0"
-
axobject-query@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-2.2.0.tgz#943d47e10c0b704aa42275e20edf3722648989be"
@@ -5497,7 +5583,7 @@ bl@^1.0.0:
readable-stream "^2.3.5"
safe-buffer "^5.1.1"
-bl@^4.0.3, bl@^4.1.0:
+bl@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a"
integrity sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==
@@ -6195,11 +6281,6 @@ ci-info@^2.0.0:
resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46"
integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==
-ci-info@^3.1.1:
- version "3.1.1"
- resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.1.1.tgz#9a32fcefdf7bcdb6f0a7e1c0f8098ec57897b80a"
- integrity sha512-kdRWLBIJwdsYJWYJFtAFFYxybguqeF91qpZaggjG5Nf8QKdizFG2hjqvaTXbxFIcYbSaD74KpAXv6BSm17DHEQ==
-
cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3:
version "1.0.4"
resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de"
@@ -6319,17 +6400,6 @@ cliui@^6.0.0:
strip-ansi "^6.0.0"
wrap-ansi "^6.2.0"
-clone-deep@^0.2.4:
- version "0.2.4"
- resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-0.2.4.tgz#4e73dd09e9fb971cc38670c5dced9c1896481cc6"
- integrity sha1-TnPdCen7lxzDhnDF3O2cGJZIHMY=
- dependencies:
- for-own "^0.1.3"
- is-plain-object "^2.0.1"
- kind-of "^3.0.2"
- lazy-cache "^1.0.3"
- shallow-clone "^0.1.2"
-
clone-deep@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-4.0.1.tgz#c19fd9bdbbf85942b4fd979c84dcf7d5f07c2387"
@@ -6458,7 +6528,7 @@ colornames@^1.1.1:
resolved "https://registry.yarnpkg.com/colornames/-/colornames-1.1.1.tgz#f8889030685c7c4ff9e2a559f5077eb76a816f96"
integrity sha1-+IiQMGhcfE/54qVZ9Qd+t2qBb5Y=
-colors@^1.1.2, colors@^1.2.1:
+colors@^1.1.2, colors@^1.2.1, colors@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78"
integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==
@@ -6488,22 +6558,12 @@ commander@^2.15.1, commander@^2.19.0, commander@^2.20.0, commander@^2.8.1:
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
-commander@^3.0.2:
- version "3.0.2"
- resolved "https://registry.yarnpkg.com/commander/-/commander-3.0.2.tgz#6837c3fb677ad9933d1cfba42dd14d5117d6b39e"
- integrity sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow==
-
commander@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068"
integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==
-commander@^5.1.0:
- version "5.1.0"
- resolved "https://registry.yarnpkg.com/commander/-/commander-5.1.0.tgz#46abbd1652f8e059bddaef99bbdcb2ad9cf179ae"
- integrity sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==
-
-commander@^6.2.1:
+commander@^6.1.0, commander@^6.2.1:
version "6.2.1"
resolved "https://registry.yarnpkg.com/commander/-/commander-6.2.1.tgz#0792eb682dfbc325999bb2b84fddddba110ac73c"
integrity sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==
@@ -7206,14 +7266,6 @@ currently-unhandled@^0.4.1:
dependencies:
array-find-index "^1.0.1"
-cwd@^0.10.0:
- version "0.10.0"
- resolved "https://registry.yarnpkg.com/cwd/-/cwd-0.10.0.tgz#172400694057c22a13b0cf16162c7e4b7a7fe567"
- integrity sha1-FyQAaUBXwioTsM8WFix+S3p/5Wc=
- dependencies:
- find-pkg "^0.1.2"
- fs-exists-sync "^0.1.0"
-
cyclist@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-1.0.1.tgz#596e9698fd0c80e12038c2b82d6eb1b35b6224d9"
@@ -7577,11 +7629,6 @@ detect-port@^1.3.0:
address "^1.0.1"
debug "^2.6.0"
-devtools-protocol@0.0.869402:
- version "0.0.869402"
- resolved "https://registry.yarnpkg.com/devtools-protocol/-/devtools-protocol-0.0.869402.tgz#03ade701761742e43ae4de5dc188bcd80f156d8d"
- integrity sha512-VvlVYY+VDJe639yHs5PHISzdWTLL3Aw8rO4cvUtwvoxFd6FHbE4OpHHcde52M6096uYYazAmd4l0o5VuFRO2WA==
-
diagnostics@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/diagnostics/-/diagnostics-1.1.1.tgz#cab6ac33df70c9d9a727490ae43ac995a769b22a"
@@ -8019,7 +8066,7 @@ encodeurl@~1.0.2:
resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59"
integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=
-end-of-stream@^1.0.0, end-of-stream@^1.1.0, end-of-stream@^1.4.1:
+end-of-stream@^1.0.0, end-of-stream@^1.1.0:
version "1.4.4"
resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0"
integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==
@@ -8680,19 +8727,7 @@ expand-brackets@^2.1.4:
snapdragon "^0.8.1"
to-regex "^3.0.1"
-expand-tilde@^1.2.2:
- version "1.2.2"
- resolved "https://registry.yarnpkg.com/expand-tilde/-/expand-tilde-1.2.2.tgz#0b81eba897e5a3d31d1c3d102f8f01441e559449"
- integrity sha1-C4HrqJflo9MdHD0QL48BRB5VlEk=
- dependencies:
- os-homedir "^1.0.1"
-
-expect-puppeteer@^5.0.4:
- version "5.0.4"
- resolved "https://registry.yarnpkg.com/expect-puppeteer/-/expect-puppeteer-5.0.4.tgz#54bfdecabb2acb3e3f0d0292cd3dab2dd8ff5a81"
- integrity sha512-NV7jSiKhK+byocxg9A+0av+Q2RSCP9bcLVRz7zhHaESeCOkuomMvl9oD+uo1K+NdqRCXhNkQlUGWlmtbrpR1qw==
-
-expect@^26.6.0, expect@^26.6.2:
+expect@^26.4.2, expect@^26.6.0, expect@^26.6.2:
version "26.6.2"
resolved "https://registry.yarnpkg.com/expect/-/expect-26.6.2.tgz#c6b996bf26bf3fe18b67b2d0f51fc981ba934417"
integrity sha512-9/hlOBkQl2l/PLHJx6JjoDF6xPKcJEsUlWKb23rKE7KzeDqUZKXKNMW27KIue5JMdBV9HgmoJPcc8HtO85t9IA==
@@ -8805,7 +8840,7 @@ extglob@^2.0.4:
snapdragon "^0.8.1"
to-regex "^3.0.1"
-extract-zip@^2.0.0:
+extract-zip@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-2.0.1.tgz#663dca56fe46df890d5f131ef4a06d22bb8ba13a"
integrity sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==
@@ -9114,30 +9149,6 @@ find-cache-dir@^3.3.1:
make-dir "^3.0.2"
pkg-dir "^4.1.0"
-find-file-up@^0.1.2:
- version "0.1.3"
- resolved "https://registry.yarnpkg.com/find-file-up/-/find-file-up-0.1.3.tgz#cf68091bcf9f300a40da411b37da5cce5a2fbea0"
- integrity sha1-z2gJG8+fMApA2kEbN9pczlovvqA=
- dependencies:
- fs-exists-sync "^0.1.0"
- resolve-dir "^0.1.0"
-
-find-pkg@^0.1.2:
- version "0.1.2"
- resolved "https://registry.yarnpkg.com/find-pkg/-/find-pkg-0.1.2.tgz#1bdc22c06e36365532e2a248046854b9788da557"
- integrity sha1-G9wiwG42NlUy4qJIBGhUuXiNpVc=
- dependencies:
- find-file-up "^0.1.2"
-
-find-process@^1.4.4:
- version "1.4.4"
- resolved "https://registry.yarnpkg.com/find-process/-/find-process-1.4.4.tgz#52820561162fda0d1feef9aed5d56b3787f0fd6e"
- integrity sha512-rRSuT1LE4b+BFK588D2V8/VG9liW0Ark1XJgroxZXI0LtwmQJOb490DvDYvbm+Hek9ETFzTutGfJ90gumITPhQ==
- dependencies:
- chalk "^4.0.0"
- commander "^5.1.0"
- debug "^4.1.1"
-
find-root@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4"
@@ -9224,28 +9235,6 @@ follow-redirects@^1.0.0:
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.13.0.tgz#b42e8d93a2a7eea5ed88633676d6597bc8e384db"
integrity sha512-aq6gF1BEKje4a9i9+5jimNFIpq4Q1WiwBToeRK5NvZBd/TRsmW8BsJfOEGkr76TbOyPVD3OVDN910EcUNtRYEA==
-follow-redirects@^1.10.0:
- version "1.13.3"
- resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.13.3.tgz#e5598ad50174c1bc4e872301e82ac2cd97f90267"
- integrity sha512-DUgl6+HDzB0iEptNQEXLx/KhTmDb8tZUHSeLqpnjpknR70H0nC2t9N73BK6fN4hOvJ84pKlIQVQ4k5FFlBedKA==
-
-for-in@^0.1.3:
- version "0.1.8"
- resolved "https://registry.yarnpkg.com/for-in/-/for-in-0.1.8.tgz#d8773908e31256109952b1fdb9b3fa867d2775e1"
- integrity sha1-2Hc5COMSVhCZUrH9ubP6hn0ndeE=
-
-for-in@^1.0.1:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
- integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=
-
-for-own@^0.1.3:
- version "0.1.5"
- resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce"
- integrity sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=
- dependencies:
- for-in "^1.0.1"
-
foreach@^2.0.5:
version "2.0.5"
resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99"
@@ -9343,11 +9332,6 @@ fs-constants@^1.0.0:
resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad"
integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==
-fs-exists-sync@^0.1.0:
- version "0.1.0"
- resolved "https://registry.yarnpkg.com/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz#982d6893af918e72d08dec9e8673ff2b5a8d6add"
- integrity sha1-mC1ok6+RjnLQjeyehnP/K1qNat0=
-
fs-extra@10.0.0:
version "10.0.0"
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.0.0.tgz#9ff61b655dde53fb34a82df84bb214ce802e17c1"
@@ -9674,24 +9658,6 @@ global-modules@2.0.0, global-modules@^2.0.0:
dependencies:
global-prefix "^3.0.0"
-global-modules@^0.2.3:
- version "0.2.3"
- resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-0.2.3.tgz#ea5a3bed42c6d6ce995a4f8a1269b5dae223828d"
- integrity sha1-6lo77ULG1s6ZWk+KEmm12uIjgo0=
- dependencies:
- global-prefix "^0.1.4"
- is-windows "^0.2.0"
-
-global-prefix@^0.1.4:
- version "0.1.5"
- resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-0.1.5.tgz#8d3bc6b8da3ca8112a160d8d496ff0462bfef78f"
- integrity sha1-jTvGuNo8qBEqFg2NSW/wRiv+948=
- dependencies:
- homedir-polyfill "^1.0.0"
- ini "^1.3.4"
- is-windows "^0.2.0"
- which "^1.2.12"
-
global-prefix@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-3.0.0.tgz#fc85f73064df69f50421f47f883fe5b913ba9b97"
@@ -10271,13 +10237,6 @@ hoist-non-react-statics@^3.3.0:
dependencies:
react-is "^16.7.0"
-homedir-polyfill@^1.0.0:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz#743298cef4e5af3e194161fbadcc2151d3a058e8"
- integrity sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==
- dependencies:
- parse-passwd "^1.0.0"
-
hoopy@^0.1.4:
version "0.1.4"
resolved "https://registry.yarnpkg.com/hoopy/-/hoopy-0.1.4.tgz#609207d661100033a9a9402ad3dea677381c1b1d"
@@ -10968,7 +10927,7 @@ is-boolean-object@^1.1.0:
dependencies:
call-bind "^1.0.0"
-is-buffer@^1.0.2, is-buffer@^1.1.5:
+is-buffer@^1.1.5:
version "1.1.6"
resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==
@@ -11000,13 +10959,6 @@ is-ci@^2.0.0:
dependencies:
ci-info "^2.0.0"
-is-ci@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-3.0.0.tgz#c7e7be3c9d8eef7d0fa144390bd1e4b88dc4c994"
- integrity sha512-kDXyttuLeslKAHYL/K28F2YkM3x5jvFPEw3yXbRptXydjD9rpLEz+C5K5iutY9ZiUu6AP41JdvRQwF4Iqs4ZCQ==
- dependencies:
- ci-info "^3.1.1"
-
is-color-stop@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/is-color-stop/-/is-color-stop-1.1.0.tgz#cfff471aee4dd5c9e158598fbe12967b5cdad345"
@@ -11286,7 +11238,7 @@ is-plain-object@3.0.1:
resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-3.0.1.tgz#662d92d24c0aa4302407b0d45d21f2251c85f85b"
integrity sha512-Xnpx182SBMrr/aBik8y+GuR4U1L9FqMSojwDQwPMmxyC6bvEqly9UBCxhauBF5vNh2gwWJNX6oDV7O+OM4z34g==
-is-plain-object@^2.0.1, is-plain-object@^2.0.4:
+is-plain-object@^2.0.4:
version "2.0.4"
resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677"
integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==
@@ -11444,11 +11396,6 @@ is-window@^1.0.2:
resolved "https://registry.yarnpkg.com/is-window/-/is-window-1.0.2.tgz#2c896ca53db97de45d3c33133a65d8c9f563480d"
integrity sha1-LIlspT25feRdPDMTOmXYyfVjSA0=
-is-windows@^0.2.0:
- version "0.2.0"
- resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-0.2.0.tgz#de1aa6d63ea29dd248737b69f1ff8b8002d2108c"
- integrity sha1-3hqm1j6indJIc3tp8f+LgALSEIw=
-
is-windows@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d"
@@ -11654,19 +11601,6 @@ jest-config@^26.6.3:
micromatch "^4.0.2"
pretty-format "^26.6.2"
-jest-dev-server@^5.0.3:
- version "5.0.3"
- resolved "https://registry.yarnpkg.com/jest-dev-server/-/jest-dev-server-5.0.3.tgz#324bf6426477450ec3dae349ee9223d43f8be368"
- integrity sha512-aJR3a5KdY18Lsz+VbREKwx2HM3iukiui+J9rlv9o6iYTwZCSsJazSTStcD9K1q0AIF3oA+FqLOKDyo/sc7+fJw==
- dependencies:
- chalk "^4.1.1"
- cwd "^0.10.0"
- find-process "^1.4.4"
- prompts "^2.4.1"
- spawnd "^5.0.0"
- tree-kill "^1.2.2"
- wait-on "^5.3.0"
-
jest-diff@^26.0.0, jest-diff@^26.6.2:
version "26.6.2"
resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-26.6.2.tgz#1aa7468b52c3a68d7d5c5fdcdfcd5e49bd164394"
@@ -11730,29 +11664,6 @@ jest-environment-node@^26.6.2:
jest-mock "^26.6.2"
jest-util "^26.6.2"
-jest-environment-node@^27.0.1:
- version "27.0.1"
- resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-27.0.1.tgz#7d7df7ae191477a823ffb4fcc0772b4c23ec5c87"
- integrity sha512-/p94lo0hx+hbKUw1opnRFUPPsjncRBEUU+2Dh7BuxX8Nr4rRiTivLYgXzo79FhaeMYV0uiV5WAbHBq6xC11JJg==
- dependencies:
- "@jest/environment" "^27.0.1"
- "@jest/fake-timers" "^27.0.1"
- "@jest/types" "^27.0.1"
- "@types/node" "*"
- jest-mock "^27.0.1"
- jest-util "^27.0.1"
-
-jest-environment-puppeteer@^5.0.4:
- version "5.0.4"
- resolved "https://registry.yarnpkg.com/jest-environment-puppeteer/-/jest-environment-puppeteer-5.0.4.tgz#ed64689bf200923828ca98761b4da36eb8ce31bc"
- integrity sha512-wd4EDOD4QRi11QZ1IV8WsL1wlnnMUtcqtU0BNm+REzRtg78K2XHn3jS6YxGeXIOnsgrJeHxsD7DlRZ/GkFteLg==
- dependencies:
- chalk "^4.1.1"
- cwd "^0.10.0"
- jest-dev-server "^5.0.3"
- jest-environment-node "^27.0.1"
- merge-deep "^3.0.3"
-
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"
@@ -11857,21 +11768,6 @@ jest-message-util@^26.6.0, jest-message-util@^26.6.2:
slash "^3.0.0"
stack-utils "^2.0.2"
-jest-message-util@^27.0.1:
- version "27.0.1"
- resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-27.0.1.tgz#382b7c55d8e0b1aba9eeb41d3cfdd34e451210ed"
- integrity sha512-w8BfON2GwWORkos8BsxcwwQrLkV2s1ENxSRXK43+6yuquDE2hVxES/jrFqOArpP1ETVqqMmktU6iGkG8ncVzeA==
- dependencies:
- "@babel/code-frame" "^7.12.13"
- "@jest/types" "^27.0.1"
- "@types/stack-utils" "^2.0.0"
- chalk "^4.0.0"
- graceful-fs "^4.2.4"
- micromatch "^4.0.4"
- pretty-format "^27.0.1"
- slash "^3.0.0"
- stack-utils "^2.0.3"
-
jest-mock@^25.1.0, jest-mock@^25.5.0:
version "25.5.0"
resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-25.5.0.tgz#a91a54dabd14e37ecd61665d6b6e06360a55387a"
@@ -11887,27 +11783,11 @@ jest-mock@^26.6.2:
"@jest/types" "^26.6.2"
"@types/node" "*"
-jest-mock@^27.0.1:
- version "27.0.1"
- resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-27.0.1.tgz#8394e297bc3dfed980961622cb51fd042b4acf5a"
- integrity sha512-fXCSZQDT5hUcAUy8OBnB018x7JFOMQnz4XfpSKEbfpWzL6o5qaLRhgf2Qg2NPuVKmC/fgOf33Edj8wjF4I24CQ==
- dependencies:
- "@jest/types" "^27.0.1"
- "@types/node" "*"
-
jest-pnp-resolver@^1.2.2:
version "1.2.2"
resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz#b704ac0ae028a89108a4d040b3f919dfddc8e33c"
integrity sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==
-jest-puppeteer@5.0.4:
- version "5.0.4"
- resolved "https://registry.yarnpkg.com/jest-puppeteer/-/jest-puppeteer-5.0.4.tgz#c52e3379c11425ce974d025c1a8bf9f599da4b3f"
- integrity sha512-IUOVKgHEaKsLqahZy/J/DvXB59SQx4AVpZKTRDvJzCdkvdGc3NVsNwUhovr6SK+HOK1TOiqAiXPTAPiIq3mkrg==
- dependencies:
- expect-puppeteer "^5.0.4"
- jest-environment-puppeteer "^5.0.4"
-
jest-regex-util@^26.0.0:
version "26.0.0"
resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-26.0.0.tgz#d25e7184b36e39fd466c3bc41be0971e821fee28"
@@ -12062,18 +11942,6 @@ jest-util@^26.6.0, jest-util@^26.6.2:
is-ci "^2.0.0"
micromatch "^4.0.2"
-jest-util@^27.0.1:
- version "27.0.1"
- resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-27.0.1.tgz#324ed9879d129c1e64f9169a739d6d50d7928769"
- integrity sha512-lEw3waSmEOO4ZkwkUlFSvg4es1+8+LIkSGxp/kF60K0+vMR3Dv3O2HMZhcln9NHqSQzpVbsDT6OeMzUPW7DfRg==
- dependencies:
- "@jest/types" "^27.0.1"
- "@types/node" "*"
- chalk "^4.0.0"
- graceful-fs "^4.2.4"
- is-ci "^3.0.0"
- picomatch "^2.2.3"
-
jest-validate@^26.6.2:
version "26.6.2"
resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-26.6.2.tgz#23d380971587150467342911c3d7b4ac57ab20ec"
@@ -12138,16 +12006,10 @@ jest@26.6.0:
import-local "^3.0.2"
jest-cli "^26.6.0"
-joi@^17.3.0:
- version "17.4.0"
- resolved "https://registry.yarnpkg.com/joi/-/joi-17.4.0.tgz#b5c2277c8519e016316e49ababd41a1908d9ef20"
- integrity sha512-F4WiW2xaV6wc1jxete70Rw4V/VuMd6IN+a5ilZsxG4uYtUXWu2kq9W5P2dz30e7Gmw8RCbY/u/uk+dMPma9tAg==
- dependencies:
- "@hapi/hoek" "^9.0.0"
- "@hapi/topo" "^5.0.0"
- "@sideway/address" "^4.1.0"
- "@sideway/formula" "^3.0.0"
- "@sideway/pinpoint" "^2.0.0"
+jpeg-js@^0.4.2:
+ version "0.4.3"
+ resolved "https://registry.yarnpkg.com/jpeg-js/-/jpeg-js-0.4.3.tgz#6158e09f1983ad773813704be80680550eff977b"
+ integrity sha512-ru1HWKek8octvUHFHvE5ZzQ1yAsJmIvRdGWvSoKV52XKyuyYA437QWDttXT8eZXDSbuMpHlLzPDZUPd6idIz+Q==
js-string-escape@^1.0.1:
version "1.0.1"
@@ -12341,13 +12203,6 @@ killable@^1.0.1:
resolved "https://registry.yarnpkg.com/killable/-/killable-1.0.1.tgz#4c8ce441187a061c7474fb87ca08e2a638194892"
integrity sha512-LzqtLKlUwirEUyl/nicirVmNiPvYs7l5n8wOPP7fyJVpUPkvCnW/vuiXGpylGUlnPDnB7311rARzAt3Mhswpjg==
-kind-of@^2.0.1:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-2.0.1.tgz#018ec7a4ce7e3a86cb9141be519d24c8faa981b5"
- integrity sha1-AY7HpM5+OobLkUG+UZ0kyPqpgbU=
- dependencies:
- is-buffer "^1.0.2"
-
kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0:
version "3.2.2"
resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64"
@@ -12426,16 +12281,6 @@ last-call-webpack-plugin@^3.0.0:
lodash "^4.17.5"
webpack-sources "^1.1.0"
-lazy-cache@^0.2.3:
- version "0.2.7"
- resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-0.2.7.tgz#7feddf2dcb6edb77d11ef1d117ab5ffdf0ab1b65"
- integrity sha1-f+3fLctu23fRHvHRF6tf/fCrG2U=
-
-lazy-cache@^1.0.3:
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e"
- integrity sha1-odePw6UEdMuAhF07O24dpJpEbo4=
-
lazy-universal-dotenv@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/lazy-universal-dotenv/-/lazy-universal-dotenv-3.0.1.tgz#a6c8938414bca426ab8c9463940da451a911db38"
@@ -13140,15 +12985,6 @@ meow@^9.0.0:
type-fest "^0.18.0"
yargs-parser "^20.2.3"
-merge-deep@^3.0.3:
- version "3.0.3"
- resolved "https://registry.yarnpkg.com/merge-deep/-/merge-deep-3.0.3.tgz#1a2b2ae926da8b2ae93a0ac15d90cd1922766003"
- integrity sha512-qtmzAS6t6grwEkNrunqTBdn0qKwFgNWvlxUbAV8es9M7Ot1EbyApytCnvE0jALPa46ZpKDUo527kKiaWplmlFA==
- dependencies:
- arr-union "^3.1.0"
- clone-deep "^0.2.4"
- kind-of "^3.0.2"
-
merge-descriptors@1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61"
@@ -13292,6 +13128,11 @@ mime@^2.4.4:
resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.6.tgz#e5b407c90db442f2beb5b162373d07b69affa4d1"
integrity sha512-RZKhC3EmpBchfTGBVb8fb+RL2cWyw/32lshnsETttkBAyAUXSGHxbEJWWRXc751DrIxG1q04b8QwMbAwkRPpUA==
+mime@^2.4.6:
+ version "2.5.2"
+ resolved "https://registry.yarnpkg.com/mime/-/mime-2.5.2.tgz#6e3dc6cc2b9510643830e5f19d5cb753da5eeabe"
+ integrity sha512-tqkh47FzKeCPD2PUiPB6pkbMzsCasjxAfC62/Wap5qrUWcb+sFasXUC5I3gYM5iBM8v/Qpn4UK0x+j0iHyFPDg==
+
mimic-fn@^1.0.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022"
@@ -13344,7 +13185,7 @@ minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1:
resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a"
integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=
-minimatch@3.0.4, minimatch@^3.0.2, minimatch@^3.0.4:
+minimatch@3.0.4, minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
@@ -13422,19 +13263,6 @@ mixin-deep@>=1.3.2, mixin-deep@^1.2.0:
resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-2.0.1.tgz#9a6946bef4a368401b784970ae3caaaa6bab02fa"
integrity sha512-imbHQNRglyaplMmjBLL3V5R6Bfq5oM+ivds3SKgc6oRtzErEnBUUc5No11Z2pilkUvl42gJvi285xTNswcKCMA==
-mixin-object@^2.0.1:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/mixin-object/-/mixin-object-2.0.1.tgz#4fb949441dab182540f1fe035ba60e1947a5e57e"
- integrity sha1-T7lJRB2rGCVA8f4DW6YOGUel5X4=
- dependencies:
- for-in "^0.1.3"
- is-extendable "^0.1.1"
-
-mkdirp-classic@^0.5.2:
- version "0.5.3"
- resolved "https://registry.yarnpkg.com/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz#fa10c9115cc6d8865be221ba47ee9bed78601113"
- integrity sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==
-
mkdirp@^0.5.1, mkdirp@^0.5.3, mkdirp@^0.5.5, mkdirp@~0.5.1:
version "0.5.5"
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def"
@@ -13488,6 +13316,11 @@ ms@2.1.2, ms@^2.1.1:
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
+ms@^2.1.2:
+ version "2.1.3"
+ resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
+ integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
+
multicast-dns-service-types@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz#899f11d9686e5e05cb91b35d5f0e63b773cfc901"
@@ -14110,11 +13943,6 @@ os-filter-obj@^2.0.0:
dependencies:
arch "^2.1.0"
-os-homedir@^1.0.1:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3"
- integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M=
-
os-tmpdir@~1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
@@ -14412,11 +14240,6 @@ parse-json@^5.0.0:
json-parse-better-errors "^1.0.1"
lines-and-columns "^1.1.6"
-parse-passwd@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6"
- integrity sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=
-
parse5-htmlparser2-tree-adapter@^6.0.1:
version "6.0.1"
resolved "https://registry.yarnpkg.com/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz#2cdf9ad823321140370d4dbf5d3e92c7c8ddc6e6"
@@ -14607,6 +14430,13 @@ pirates@^4.0.0, pirates@^4.0.1:
dependencies:
node-modules-regexp "^1.0.0"
+pixelmatch@^5.2.1:
+ version "5.2.1"
+ resolved "https://registry.yarnpkg.com/pixelmatch/-/pixelmatch-5.2.1.tgz#9e4e4f4aa59648208a31310306a5bed5522b0d65"
+ integrity sha512-WjcAdYSnKrrdDdqTcVEY7aB7UhhwjYQKYhHiBXdJef0MOaQeYpUdQ+iVyBLa5YBKS8MPVPPMX7rpOByISLpeEQ==
+ dependencies:
+ pngjs "^4.0.1"
+
pkg-dir@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-2.0.0.tgz#f6d5d1109e19d63edf428e0bd57e12777615334b"
@@ -14647,6 +14477,16 @@ platform@^1.3.3:
resolved "https://registry.yarnpkg.com/platform/-/platform-1.3.6.tgz#48b4ce983164b209c2d45a107adb31f473a6e7a7"
integrity sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg==
+pngjs@^4.0.1:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-4.0.1.tgz#f803869bb2fc1bfe1bf99aa4ec21c108117cfdbe"
+ integrity sha512-rf5+2/ioHeQxR6IxuYNYGFytUyG3lma/WW1nsmjeHlWwtb2aByla6dkVc8pmJ9nplzkTA0q2xx7mMWrOTqT4Gg==
+
+pngjs@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-5.0.0.tgz#e79dd2b215767fd9c04561c01236df960bce7fbb"
+ integrity sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==
+
pngquant-bin@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/pngquant-bin/-/pngquant-bin-6.0.0.tgz#aff0d7e61095feb96ced379ad8c7294ad3dd1712"
@@ -15501,7 +15341,7 @@ pretty-format@^26.0.0, pretty-format@^26.6.0, pretty-format@^26.6.2:
ansi-styles "^4.0.0"
react-is "^17.0.1"
-pretty-format@^27.0.1, pretty-format@^27.0.2:
+pretty-format@^27.0.2:
version "27.0.2"
resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-27.0.2.tgz#9283ff8c4f581b186b2d4da461617143dca478a4"
integrity sha512-mXKbbBPnYTG7Yra9qFBtqj+IXcsvxsvOBco3QHxtxTl+hHKq6QdzMZ+q0CtL4ORHZgwGImRr2XZUX2EWzORxig==
@@ -15550,7 +15390,7 @@ process@^0.11.10:
resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182"
integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI=
-progress@^2.0.0, progress@^2.0.1:
+progress@^2.0.0, progress@^2.0.3:
version "2.0.3"
resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8"
integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==
@@ -15595,7 +15435,7 @@ prompts@2.4.0:
kleur "^3.0.3"
sisteransi "^1.0.5"
-prompts@^2.0.0, prompts@^2.0.1, prompts@^2.4.0, prompts@^2.4.1:
+prompts@^2.0.0, prompts@^2.0.1, prompts@^2.4.0:
version "2.4.1"
resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.1.tgz#befd3b1195ba052f9fd2fde8a486c4e82ee77f61"
integrity sha512-EQyfIuO2hPDsX1L/blblV+H7I0knhgAd82cVneCwcdND9B8AuCDuRcBH6yIcG4dFzlOUqbazQqwGjx5xmsNLuQ==
@@ -15612,6 +15452,15 @@ prop-types@^15.0.0, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2,
object-assign "^4.1.1"
react-is "^16.8.1"
+proper-lockfile@^4.1.1:
+ version "4.1.2"
+ resolved "https://registry.yarnpkg.com/proper-lockfile/-/proper-lockfile-4.1.2.tgz#c8b9de2af6b2f1601067f98e01ac66baa223141f"
+ integrity sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==
+ dependencies:
+ graceful-fs "^4.2.4"
+ retry "^0.12.0"
+ signal-exit "^3.0.2"
+
property-information@^5.0.0, property-information@^5.3.0:
version "5.5.0"
resolved "https://registry.yarnpkg.com/property-information/-/property-information-5.5.0.tgz#4dc075d493061a82e2b7d096f406e076ed859943"
@@ -15704,24 +15553,6 @@ punycode@^2.1.0, punycode@^2.1.1:
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
-puppeteer@9.0.0:
- version "9.0.0"
- resolved "https://registry.yarnpkg.com/puppeteer/-/puppeteer-9.0.0.tgz#b476e17ceb3e33a6667bf682d66dde9898f9c031"
- integrity sha512-Avu8SKWQRC1JKNMgfpH7d4KzzHOL/A65jRYrjNU46hxnOYGwqe4zZp/JW8qulaH0Pnbm5qyO3EbSKvqBUlfvkg==
- dependencies:
- debug "^4.1.0"
- devtools-protocol "0.0.869402"
- extract-zip "^2.0.0"
- https-proxy-agent "^5.0.0"
- node-fetch "^2.6.1"
- pkg-dir "^4.2.0"
- progress "^2.0.1"
- proxy-from-env "^1.1.0"
- rimraf "^3.0.2"
- tar-fs "^2.0.0"
- unbzip2-stream "^1.3.3"
- ws "^7.2.3"
-
q@^1.1.2:
version "1.5.1"
resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7"
@@ -16660,14 +16491,6 @@ resolve-cwd@^3.0.0:
dependencies:
resolve-from "^5.0.0"
-resolve-dir@^0.1.0:
- version "0.1.1"
- resolved "https://registry.yarnpkg.com/resolve-dir/-/resolve-dir-0.1.1.tgz#b219259a5602fac5c5c496ad894a6e8cc430261e"
- integrity sha1-shklmlYC+sXFxJatiUpujMQwJh4=
- dependencies:
- expand-tilde "^1.2.2"
- global-modules "^0.2.3"
-
resolve-from@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748"
@@ -16872,7 +16695,7 @@ run-queue@^1.0.0, run-queue@^1.0.3:
dependencies:
aproba "^1.1.1"
-rxjs@^6.4.0, rxjs@^6.6.3:
+rxjs@^6.4.0:
version "6.6.7"
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9"
integrity sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==
@@ -17186,16 +17009,6 @@ sha.js@^2.4.0, sha.js@^2.4.8:
inherits "^2.0.1"
safe-buffer "^5.0.1"
-shallow-clone@^0.1.2:
- version "0.1.2"
- resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-0.1.2.tgz#5909e874ba77106d73ac414cfec1ffca87d97060"
- integrity sha1-WQnodLp3EG1zrEFM/sH/yofZcGA=
- dependencies:
- is-extendable "^0.1.1"
- kind-of "^2.0.1"
- lazy-cache "^0.2.3"
- mixin-object "^2.0.1"
-
shallow-clone@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-3.0.1.tgz#8f2981ad92531f55035b01fb230769a40e02efa3"
@@ -17425,6 +17238,13 @@ source-map-support@0.5.19, source-map-support@^0.5.16, source-map-support@^0.5.1
buffer-from "^1.0.0"
source-map "^0.6.0"
+source-map-support@^0.4.18:
+ version "0.4.18"
+ resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.18.tgz#0286a6de8be42641338594e97ccea75f0a2c585f"
+ integrity sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==
+ dependencies:
+ source-map "^0.5.6"
+
source-map-url@^0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3"
@@ -17455,16 +17275,6 @@ space-separated-tokens@^1.0.0:
resolved "https://registry.yarnpkg.com/space-separated-tokens/-/space-separated-tokens-1.1.5.tgz#85f32c3d10d9682007e917414ddc5c26d1aa6899"
integrity sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA==
-spawnd@^5.0.0:
- version "5.0.0"
- resolved "https://registry.yarnpkg.com/spawnd/-/spawnd-5.0.0.tgz#ea72200bdc468998e84e1c3e7b914ce85fc1c32c"
- integrity sha512-28+AJr82moMVWolQvlAIv3JcYDkjkFTEmfDc503wxrF5l2rQ3dFz6DpbXp3kD4zmgGGldfM4xM4v1sFj/ZaIOA==
- dependencies:
- exit "^0.1.2"
- signal-exit "^3.0.3"
- tree-kill "^1.2.2"
- wait-port "^0.2.9"
-
spdx-correct@^3.0.0:
version "3.1.1"
resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.1.tgz#dece81ac9c1e6713e5f7d1b6f17d468fa53d89a9"
@@ -18157,16 +17967,6 @@ tapable@^1.0.0, tapable@^1.1.3:
resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2"
integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==
-tar-fs@^2.0.0:
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-2.1.1.tgz#489a15ab85f1f0befabb370b7de4f9eb5cbe8784"
- integrity sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==
- dependencies:
- chownr "^1.1.1"
- mkdirp-classic "^0.5.2"
- pump "^3.0.0"
- tar-stream "^2.1.4"
-
tar-stream@^1.5.2:
version "1.6.2"
resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-1.6.2.tgz#8ea55dab37972253d9a9af90fdcd559ae435c555"
@@ -18180,17 +17980,6 @@ tar-stream@^1.5.2:
to-buffer "^1.1.1"
xtend "^4.0.0"
-tar-stream@^2.1.4:
- version "2.2.0"
- resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.2.0.tgz#acad84c284136b060dc3faa64474aa9aebd77287"
- integrity sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==
- dependencies:
- bl "^4.0.3"
- end-of-stream "^1.4.1"
- fs-constants "^1.0.0"
- inherits "^2.0.3"
- readable-stream "^3.1.1"
-
tar@^6.0.2:
version "6.0.2"
resolved "https://registry.yarnpkg.com/tar/-/tar-6.0.2.tgz#5df17813468a6264ff14f766886c622b84ae2f39"
@@ -18478,11 +18267,6 @@ tr46@^2.0.2:
dependencies:
punycode "^2.1.1"
-tree-kill@^1.2.2:
- version "1.2.2"
- resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc"
- integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==
-
trim-newlines@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613"
@@ -18722,7 +18506,7 @@ typescript@^4.3.5:
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.3.5.tgz#4d1c37cc16e893973c45a06886b7113234f119f4"
integrity sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA==
-unbzip2-stream@^1.0.9, unbzip2-stream@^1.3.3:
+unbzip2-stream@^1.0.9:
version "1.4.3"
resolved "https://registry.yarnpkg.com/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz#b0da04c4371311df771cdc215e87f2130991ace7"
integrity sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==
@@ -19193,26 +18977,6 @@ w3c-xmlserializer@^2.0.0:
dependencies:
xml-name-validator "^3.0.0"
-wait-on@^5.3.0:
- version "5.3.0"
- resolved "https://registry.yarnpkg.com/wait-on/-/wait-on-5.3.0.tgz#584e17d4b3fe7b46ac2b9f8e5e102c005c2776c7"
- integrity sha512-DwrHrnTK+/0QFaB9a8Ol5Lna3k7WvUR4jzSKmz0YaPBpuN2sACyiPVKVfj6ejnjcajAcvn3wlbTyMIn9AZouOg==
- dependencies:
- axios "^0.21.1"
- joi "^17.3.0"
- lodash "^4.17.21"
- minimist "^1.2.5"
- rxjs "^6.6.3"
-
-wait-port@^0.2.9:
- version "0.2.9"
- resolved "https://registry.yarnpkg.com/wait-port/-/wait-port-0.2.9.tgz#3905cf271b5dbe37a85c03b85b418b81cb24ee55"
- integrity sha512-hQ/cVKsNqGZ/UbZB/oakOGFqic00YAMM5/PEj3Bt4vKarv2jWIWzDbqlwT94qMs/exAQAsvMOq99sZblV92zxQ==
- dependencies:
- chalk "^2.4.2"
- commander "^3.0.2"
- debug "^4.1.1"
-
walker@^1.0.7, walker@~1.0.5:
version "1.0.7"
resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb"
@@ -19560,7 +19324,7 @@ which-typed-array@^1.1.2:
has-symbols "^1.0.1"
is-typed-array "^1.1.3"
-which@^1.2.12, which@^1.2.9, which@^1.3.1:
+which@^1.2.9, which@^1.3.1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==
@@ -19837,7 +19601,7 @@ ws@^6.2.1:
dependencies:
async-limiter "~1.0.0"
-ws@^7.2.3, ws@^7.4.6:
+ws@^7.4.6:
version "7.5.3"
resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.3.tgz#160835b63c7d97bfab418fc1b8a9fced2ac01a74"
integrity sha512-kQ/dHIzuLrS6Je9+uv81ueZomEwH0qVYstcAQ4/Z93K8zeko9gtAbttJWzoC5ukqXY1PpoouV3+VSOqEAFt5wg==
@@ -19956,6 +19720,13 @@ yauzl@^2.10.0, yauzl@^2.4.2:
buffer-crc32 "~0.2.3"
fd-slicer "~1.1.0"
+yazl@^2.5.1:
+ version "2.5.1"
+ resolved "https://registry.yarnpkg.com/yazl/-/yazl-2.5.1.tgz#a3d65d3dd659a5b0937850e8609f22fffa2b5c35"
+ integrity sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw==
+ dependencies:
+ buffer-crc32 "~0.2.3"
+
yn@3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50"