Added functional tests for scatterplot facets

* Added test for scatterplots
* Enriched test docs with a section on visual testing

Co-authored-by: Kush Trivedi <44091822+kushthedude@users.noreply.github.com>
This commit is contained in:
Florian Giroud 2021-04-11 21:05:27 +02:00 committed by GitHub
parent 8369a10cfd
commit 2f5c765b4d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 542 additions and 55 deletions

View File

@ -13,8 +13,8 @@ With Cypress, tests are performing assertions using a real browser, the same way
Cypress tests can be ran
- using the Cypress test runner (development mode)
- using a command line (CI/CD mode)
- using the Cypress test runner (development mode)
- using a command line (CI/CD mode)
If you are writing tests, the Cypress test runner is good enough, and the command-line is mainly used by the CI/CD platform (Github actions)
@ -31,25 +31,25 @@ Good starting points with Cypress are the [Getting started guide](https://docs.c
The general workflow of a Cypress test is to
- Start a browser (yarn run cypress open)
- Visit a URL
- Trigger user actions
- Assert that the DOM contains expected texts and elements using selectors
- Start a browser (yarn run cypress open)
- Visit a URL
- Trigger user actions
- Assert that the DOM contains expected texts and elements using selectors
## Getting started
If this is the first time you use Cypress, it is recommended for you to get familiar with the tool.
- [Cypress overview](https://docs.cypress.io/guides/overview/why-cypress.html)
- [Cypress examples of tests and syntax](https://example.cypress.io/)
- [Cypress overview](https://docs.cypress.io/guides/overview/why-cypress.html)
- [Cypress examples of tests and syntax](https://example.cypress.io/)
### 1. Install Cypress
You will need:
- [Node.js 10 or 12 and above](https://nodejs.org)
- [Yarn or NPM](https://yarnpkg.com/)
- A Unix/Linux shell environment or the Windows command line
- [Node.js 10 or 12 and above](https://nodejs.org)
- [Yarn or NPM](https://yarnpkg.com/)
- A Unix/Linux shell environment or the Windows command line
To install Cypress and dependencies, run :
@ -81,10 +81,10 @@ Click on one of them and the test will start.
### 4. Add your first test
- Add a `test.spec.js` into the `main/tests/cypress/cypress/integration` folder.
- The test is instantly available in the list
- Click on the test
- Start to add some code
- Add a `test.spec.js` into the `main/tests/cypress/cypress/integration` folder.
- The test is instantly available in the list
- Click on the test
- Start to add some code
## Tests technical documentation
@ -94,10 +94,10 @@ A typical OpenRefine test starts with the following code
```javascript
it('Ensure cells are blanked down', function () {
cy.loadAndVisitProject('food.mini')
cy.get('.viewpanel-sorting a').contains('Sort').click()
cy.get('.viewpanel').should('to.contain', 'Something')
})
cy.loadAndVisitProject('food.mini');
cy.get('.viewpanel-sorting a').contains('Sort').click();
cy.get('.viewpanel').should('to.contain', 'Something');
});
```
The first noticeable thing about a test is the description (`Ensure cells are blanked down`), which describes what the test is doing.
@ -105,24 +105,24 @@ Lines usually starts with `cy.something...`, which is the main way to interact w
A few examples:
- `cy.get('a.my-class')` will retrieve the `<a class="my-class" />` element
- `cy.click()` will click on the element
- eventually, `cy.should()` will perform an assertion, for example that the element contains an expected text with `cy.should('to.contains', 'my text')`
- `cy.get('a.my-class')` will retrieve the `<a class="my-class" />` element
- `cy.click()` will click on the element
- eventually, `cy.should()` will perform an assertion, for example that the element contains an expected text with `cy.should('to.contains', 'my text')`
On top of that, OpenRefine contributors have added some functions for common OpenRefine interactions.
For example
- `cy.loadAndVisitProject` will create a fresh project in OpenRefine
- `cy.assertCellEquals` will ensure that a cell contains a given value
- `cy.loadAndVisitProject` will create a fresh project in OpenRefine
- `cy.assertCellEquals` will ensure that a cell contains a given value
See below on the dedicated section 'Testing utilities'
### Testing guidelines
- `cy.wait` should be used in the last resort scenario. It's considered a bad practice, though sometimes there is no other choice
- Tests should remain isolated from each other. It's best to try one feature at the time
- A test should always start with a fresh project
- The name of the files should mirror the OpenRefine UI organization
- `cy.wait` should be used in the last resort scenario. It's considered a bad practice, though sometimes there is no other choice
- Tests should remain isolated from each other. It's best to try one feature at the time
- A test should always start with a fresh project
- The name of the files should mirror the OpenRefine UI organization
### Testing utilities
@ -135,26 +135,26 @@ The most important utility method is `loadAndVisitProject`.
This method will create a fresh OpenRefine project based on a dataset given as a parameter.
The fixture parameter can be
- An arbitrary array, the first row is for the column names, other rows are for the values
Use an arbitrary array **only** if the test requires some specific grid values
**Example:**
- An arbitrary array, the first row is for the column names, other rows are for the values
Use an arbitrary array **only** if the test requires some specific grid values
**Example:**
```javascript
const fixture = [
['Column A', 'Column B', 'Column C'],
['0A', '0B', '0C'],
['1A', '1B', '1C'],
['2A', '2B', '2C'],
]
cy.loadAndVisitProject(fixture)
```
```javascript
const fixture = [
['Column A', 'Column B', 'Column C'],
['0A', '0B', '0C'],
['1A', '1B', '1C'],
['2A', '2B', '2C'],
];
cy.loadAndVisitProject(fixture);
```
- A referenced dataset: `food.small` or `food.mini`
Most of the time, tests does not require any specific grid values
Use food.mini as much as possible, it loads 2 rows and very few columns in the grid
Use food.small if the test requires a few hundred rows in the grid
- A referenced dataset: `food.small` or `food.mini`
Most of the time, tests does not require any specific grid values
Use food.mini as much as possible, it loads 2 rows and very few columns in the grid
Use food.small if the test requires a few hundred rows in the grid
Those datasets live in `cypress/fixtures`
Those datasets live in `cypress/fixtures`
### Browsers
@ -166,11 +166,11 @@ See the [Cypress documentation](https://docs.cypress.io/guides/guides/launching-
Tests are located in `main/tests/cypress/cypress` folder.
The test should not use any file outside the cypress folder.
- `/fixtures` contains CSVs and OpenRefine project files used by the tests
- `/integration` contains the tests
- `/plugins` contains custom plugins for the OR project
- `/screenshots` and `/videos` contains the recording of the tests, Git ignored
- `/support` is a custom library of assertion and common user actions, to avoid code duplication in the tests themselves
- `/fixtures` contains CSVs and OpenRefine project files used by the tests
- `/integration` contains the tests
- `/plugins` contains custom plugins for the OR project
- `/screenshots` and `/videos` contains the recording of the tests, Git ignored
- `/support` is a custom library of assertion and common user actions, to avoid code duplication in the tests themselves
### Configuration
@ -178,7 +178,7 @@ Cypress execution can be configured with environment variables, they can be decl
Available variables are
- OPENREFINE_URL, determine on which scheme://url:port to access OpenRefine, default to http://localhost:333
- OPENREFINE_URL, determine on which scheme://url:port to access OpenRefine, default to http://localhost:333
Cypress contains [exaustive documentation](https://docs.cypress.io/guides/guides/environment-variables.html#Setting) about configuration, but here are two simple ways to configure the execution of the tests:
@ -194,6 +194,35 @@ You can pass variables at the command-line level
yarn --cwd ./main/tests/cypress run cypress open --env OPENREFINE_URL="http://localhost:1234"
```
### Visual testing
Tests generally ensure application behavior by making assertions against the DOM, to ensure specific texts or css attributes are present in the document body.
Visual testing, on the contrary, is a way to test applications by comparing images.
A reference screenshot is taken the first time the test runs, and subsequent runs will compare a new screenshot against the reference, at the pixel level.
Here is an [introduction to visual testing by Cypress](https://docs.cypress.io/plugins/directory#visual-testing).
In some cases, we are using visual testing.
We are using [Cypress Image Snapshot](https://github.com/jaredpalmer/cypress-image-snapshot)
Identified cases are so far:
- testing images created by OpenRefine backend (scatterplots for example)
Reference screenshots (Called snapshots), are stored in /cypress/snapshots.
And a snapshot can be taken for the whole page, or just a single part of the page.
#### When a visual test fails
First, Cypress will display the following error message:
![Diff image when a visual test fails](/img/visual-test-cypress-failure.png)
Then, a diff image will be created in /cypress/snapshots, this directory is ignored by Git.
The diff images shows the reference image on the left, the image that was taken during the test run on the right, and the diff in the middle.
![Diff image when a visual test fails](/img/failed-visual-test.png)
## CI/CD
In CI/CD, tests are run headless, with the following command-line

BIN
docs/static/img/failed-visual-test.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

View File

@ -4,6 +4,7 @@ node_modules
cypress/videos
cypress/screenshots
cypress/downloads
cypress/snapshots_diffs
npm-debug.log
cypress.env.json
out

View File

@ -0,0 +1,167 @@
// Common configuration for scatterplot snapshots
// 5% is required, there are some differences between a local run and the images on ubuntu (github actions)
const matchImageSnapshotOptions = {
failureThreshold: 0.05,
failureThresholdType: 'percent',
};
/**
* Those tests are generic test to ensure the general behavior of the various facets components
* It's using "text facet" as it is the most simple facet
*/
describe(__filename, function () {
it('Test and verify the matrix against a snapshot (3 integer columns)', function () {
cy.loadAndVisitProject('food.small', 'food-small');
cy.castColumnTo('Water', 'number');
cy.castColumnTo('Energ_Kcal', 'number');
cy.castColumnTo('Protein', 'number');
cy.columnActionClick('Protein', ['Facet', 'Scatterplot facet']);
cy.get('.scatterplot-matrix-table').matchImageSnapshot(
'scatterplot-default',
matchImageSnapshotOptions
);
});
it('Verify the scatterplot matrix order of elements', function () {
cy.loadAndVisitProject('food.small', 'food-small');
cy.castColumnTo('Water', 'number');
cy.castColumnTo('Energ_Kcal', 'number');
cy.castColumnTo('Protein', 'number');
cy.columnActionClick('Protein', ['Facet', 'Scatterplot facet']);
cy.get('.scatterplot-matrix-table').within(() => {
// Check row headers
cy.get('tr:first-child .column_header').should('to.contain', 'Water');
cy.get('tr:nth-child(2) .column_header').should(
'to.contain',
'Energ_Kcal'
);
cy.get('tr:nth-child(3) .column_header').should('to.contain', 'Protein');
// check first row
cy.get('tr:first-child td:nth-child(2) a')
.invoke('attr', 'title')
.should('eq', 'Water (x) vs. Energ_Kcal (y)');
cy.get('tr:first-child td:nth-child(3) a')
.invoke('attr', 'title')
.should('eq', 'Water (x) vs. Protein (y)');
// check second row
cy.get('tr:nth-child(2) td:nth-child(2) a')
.invoke('attr', 'title')
.should('eq', 'Energ_Kcal (x) vs. Protein (y)');
});
});
it('Test the rendering options (lin, log, dot sizes) (visual testing)', function () {
cy.loadAndVisitProject('food.small', 'food-small');
cy.castColumnTo('Water', 'number');
cy.castColumnTo('Energ_Kcal', 'number');
cy.castColumnTo('Protein', 'number');
cy.columnActionClick('Protein', ['Facet', 'Scatterplot facet']);
// test linear rendering
cy.get('.scatterplot-selectors label').contains('lin').click();
cy.get('.scatterplot-matrix-table').matchImageSnapshot(
'scatterplot-matrix-lin',
matchImageSnapshotOptions
);
// test log rendering
cy.get('.scatterplot-selectors label').contains('log').click();
cy.get('.scatterplot-matrix-table').matchImageSnapshot(
'scatterplot-matrix-log',
matchImageSnapshotOptions
);
// test the small dots rendering
cy.get('label[title="Small Dot Size"]').click();
cy.get('.scatterplot-matrix-table').matchImageSnapshot(
'scatterplot-matrix-small-dot',
matchImageSnapshotOptions
);
// test the regular dots rendering
cy.get('label[title="Regular Dot Size"]').click();
cy.get('.scatterplot-matrix-table').matchImageSnapshot(
'scatterplot-matrix-regulat-dot',
matchImageSnapshotOptions
);
// test the big dots rendering
cy.get('label[title="Big Dot Size"]').click();
cy.get('.scatterplot-matrix-table').matchImageSnapshot(
'scatterplot-matrix-big-dot',
matchImageSnapshotOptions
);
});
it('Test facet created from the scatterplot matrix', function () {
cy.loadAndVisitProject('food.small', 'food-small');
cy.castColumnTo('Water', 'number');
cy.castColumnTo('Energ_Kcal', 'number');
cy.castColumnTo('Protein', 'number');
cy.columnActionClick('Protein', ['Facet', 'Scatterplot facet']);
// test against the linear screenshot
cy.get(
'.scatterplot-matrix-table a[title="Water (x) vs. Protein (y)"]'
).click();
// test the facet
cy.getFacetContainer('Water (x) vs. Protein (y)').should('to.exist');
// verify that all the buttons to change the scatterplot look&feel are there + export button
cy.getFacetContainer('Water (x) vs. Protein (y)').within(() => {
cy.get('label').contains('lin').should('to.exist');
cy.get('label').contains('log').should('to.exist');
cy.get('label[title="Rotated 45° Counter-Clockwise"]').should('to.exist');
cy.get('label[title="No rotation"]').should('to.exist');
cy.get('label[title="Rotated 45° Clockwise"]').should('to.exist');
cy.get('label[title="Small Dot Size"]').should('to.exist');
cy.get('label[title="Regular Dot Size"]').should('to.exist');
cy.get('label[title="Big Dot Size"]').should('to.exist');
cy.get('a').contains('export plot').should('to.exist');
});
});
// it('Test image rendering inside the facet (visual testing)', function () {
// cy.loadAndVisitProject('food.small', 'food-small');
// cy.castColumnTo('Water', 'number');
// cy.castColumnTo('Energ_Kcal', 'number');
// cy.castColumnTo('Protein', 'number');
// cy.columnActionClick('Protein', ['Facet', 'Scatterplot facet']);
// cy.get(
// '.scatterplot-matrix-table a[title="Water (x) vs. Protein (y)"]'
// ).click();
// // // verify that all the buttons to change the scatterplot look&feel are there + export button
// // // cy.getFacetContainer('Water (x) vs. Protein (y)').within(() => {
// // // test linear rendering
// // cy.get('#left-panel .scatterplot-selectors label').contains('lin').click();
// // cy.get('#left-panel .facet-scatterplot-plot-container').matchImageSnapshot(
// // 'scatterplot-facet-lin',
// // matchImageSnapshotOptions
// // );
// // test log rendering
// cy.get('#left-panel .scatterplot-selectors label').contains('log').click();
// cy.get('#left-panel .facet-scatterplot-plot-container').matchImageSnapshot(
// 'scatterplot-facet-log',
// matchImageSnapshotOptions
// );
// // test the small dots rendering
// cy.get('#left-panel label[title="Small Dot Size"]').click();
// cy.get('#left-panel .facet-scatterplot-plot-container').matchImageSnapshot(
// 'scatterplot-facet-small-dot',
// matchImageSnapshotOptions
// );
// // test the regular dots rendering
// cy.get('#left-panel label[title="Regular Dot Size"]').click();
// cy.get('#left-panel .facet-scatterplot-plot-container').matchImageSnapshot(
// 'scatterplot-facet-regulat-dot',
// matchImageSnapshotOptions
// );
// // test the big dots rendering
// cy.get('#left-panel label[title="Big Dot Size"]').click();
// cy.get('#left-panel .facet-scatterplot-plot-container').matchImageSnapshot(
// 'scatterplot-facet-big-dot',
// matchImageSnapshotOptions
// );
// });
});

View File

@ -14,9 +14,14 @@
/**
* @type {Cypress.PluginConfig}
*/
const {
addMatchImageSnapshotPlugin,
} = require('cypress-image-snapshot/plugin');
module.exports = (on, config) => {
// `on` is used to hook into various events Cypress emits
// `config` is the resolved Cypress config
addMatchImageSnapshotPlugin(on, config);
return config;
};

View File

@ -11,6 +11,10 @@
import 'cypress-file-upload';
import 'cypress-wait-until';
import { addMatchImageSnapshotCommand } from 'cypress-image-snapshot/command';
addMatchImageSnapshotCommand({ customDiffDir: 'cypress/snapshots_diffs' });
/**
* Return the .facets-container for a given facet name
*/
@ -104,6 +108,7 @@ Cypress.Commands.add('doCreateProjectThroughUserInterface', () => {
* Cast a whole column to the given type, using Edit Cell / Common transform / To {type}
*/
Cypress.Commands.add('castColumnTo', (selector, target) => {
cy.get('body[ajax_in_progress="false"]');
cy.get(
'.data-table th:contains("' + selector + '") .column-header-menu'
).click();

View File

@ -12,6 +12,7 @@
},
"dependencies": {
"cypress": "6.8.0",
"cypress-image-snapshot": "^4.0.1",
"cypress-file-upload": "^5.0.3",
"cypress-wait-until": "^1.7.1",
"dotenv": "^8.2.0",

View File

@ -154,6 +154,13 @@ ansi-escapes@^3.0.0:
resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz"
integrity sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==
ansi-escapes@^4.1.0:
version "4.3.1"
resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.1.tgz#a5c47cc43181f1f38ffd7076837700d395522a61"
integrity sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA==
dependencies:
type-fest "^0.11.0"
ansi-regex@^2.0.0:
version "2.1.1"
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz"
@ -201,6 +208,13 @@ any-observable@^0.3.0:
resolved "https://registry.yarnpkg.com/any-observable/-/any-observable-0.3.0.tgz"
integrity sha512-/FQM1EDkTsf63Ub2C6O7GuYFDsSXUwsaZDurV0np41ocwq0jthUAYCmhBX9f+KwlaCgIuWyr/4WlUQUBfKfZog==
app-path@^3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/app-path/-/app-path-3.2.0.tgz#06d426e0c988885264e0aa0a766dfa2723491633"
integrity sha512-PQPaKXi64FZuofJkrtaO3I5RZESm9Yjv7tkeJaDz4EZMeBBfGtr5MyQ3m5AC7F0HVrISBLatPxAAAgvbe418fQ==
dependencies:
execa "^1.0.0"
arch@^2.1.2:
version "2.1.2"
resolved "https://registry.yarnpkg.com/arch/-/arch-2.1.2.tgz"
@ -260,6 +274,11 @@ balanced-match@^1.0.0:
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz"
integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
base64-js@^1.2.3:
version "1.5.1"
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
bcrypt-pbkdf@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz"
@ -458,6 +477,17 @@ core-util-is@1.0.2, core-util-is@~1.0.0:
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz"
integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=
cross-spawn@^6.0.0:
version "6.0.5"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4"
integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==
dependencies:
nice-try "^1.0.4"
path-key "^2.0.1"
semver "^5.5.0"
shebang-command "^1.2.0"
which "^1.2.9"
cross-spawn@^7.0.0, cross-spawn@^7.0.2:
version "7.0.3"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz"
@ -474,6 +504,18 @@ cypress-file-upload@^5.0.3:
dependencies:
mime "^2.5.0"
cypress-image-snapshot@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/cypress-image-snapshot/-/cypress-image-snapshot-4.0.1.tgz#59084e713a8d03500c8e053ad7a76f3f18609648"
integrity sha512-PBpnhX/XItlx3/DAk5ozsXQHUi72exybBNH5Mpqj1DVmjq+S5Jd9WE5CRa4q5q0zuMZb2V2VpXHth6MjFpgj9Q==
dependencies:
chalk "^2.4.1"
fs-extra "^7.0.1"
glob "^7.1.3"
jest-image-snapshot "4.2.0"
pkg-dir "^3.0.0"
term-img "^4.0.0"
cypress-wait-until@^1.7.1:
version "1.7.1"
resolved "https://registry.yarnpkg.com/cypress-wait-until/-/cypress-wait-until-1.7.1.tgz"
@ -765,6 +807,19 @@ eventemitter2@^6.4.2:
resolved "https://registry.yarnpkg.com/eventemitter2/-/eventemitter2-6.4.3.tgz"
integrity sha512-t0A2msp6BzOf+QAcI6z9XMktLj52OjGQg+8SJH6v5+3uxNpWYRR3wQmfA+6xtMU9kOC59qk9licus5dYcrYkMQ==
execa@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8"
integrity sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==
dependencies:
cross-spawn "^6.0.0"
get-stream "^4.0.0"
is-stream "^1.1.0"
npm-run-path "^2.0.0"
p-finally "^1.0.0"
signal-exit "^3.0.0"
strip-eof "^1.0.0"
execa@^4.0.2:
version "4.0.3"
resolved "https://registry.yarnpkg.com/execa/-/execa-4.0.3.tgz"
@ -861,6 +916,13 @@ file-entry-cache@^6.0.1:
dependencies:
flat-cache "^3.0.4"
find-up@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73"
integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==
dependencies:
locate-path "^3.0.0"
flat-cache@^3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz"
@ -888,6 +950,15 @@ form-data@~2.3.2:
combined-stream "^1.0.6"
mime-types "^2.1.12"
fs-extra@^7.0.1:
version "7.0.1"
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9"
integrity sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==
dependencies:
graceful-fs "^4.1.2"
jsonfile "^4.0.0"
universalify "^0.1.0"
fs-extra@^9.0.1, fs-extra@^9.1.0:
version "9.1.0"
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.1.0.tgz"
@ -908,6 +979,18 @@ functional-red-black-tree@^1.0.1:
resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz"
integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=
get-stdin@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-5.0.1.tgz#122e161591e21ff4c52530305693f20e6393a398"
integrity sha1-Ei4WFZHiH/TFJTAwVpPyDmOTo5g=
get-stream@^4.0.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5"
integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==
dependencies:
pump "^3.0.0"
get-stream@^5.0.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz"
@ -974,6 +1057,16 @@ globals@^13.6.0:
dependencies:
type-fest "^0.20.2"
glur@^1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/glur/-/glur-1.1.2.tgz#f20ea36db103bfc292343921f1f91e83c3467689"
integrity sha1-8g6jbbEDv8KSNDkh8fkeg8NGdok=
graceful-fs@^4.1.2:
version "4.2.6"
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.6.tgz#ff040b2b0853b23c3d31027523706f1885d76bee"
integrity sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==
graceful-fs@^4.1.6, graceful-fs@^4.1.9, graceful-fs@^4.2.0:
version "4.2.4"
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.4.tgz"
@ -1155,6 +1248,29 @@ isstream@~0.1.2:
resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz"
integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=
iterm2-version@^4.1.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/iterm2-version/-/iterm2-version-4.2.0.tgz#b78069f747f34a772bc7dc17bda5bd9ed5e09633"
integrity sha512-IoiNVk4SMPu6uTcK+1nA5QaHNok2BMDLjSl5UomrOixe5g4GkylhPwuiGdw00ysSCrXAKNMfFTu+u/Lk5f6OLQ==
dependencies:
app-path "^3.2.0"
plist "^3.0.1"
jest-image-snapshot@4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/jest-image-snapshot/-/jest-image-snapshot-4.2.0.tgz#559d7ade69e9918517269cef184261c80029a69e"
integrity sha512-6aAqv2wtfOgxiJeBayBCqHo1zX+A12SUNNzo7rIxiXh6W6xYVu8QyHWkada8HeRi+QUTHddp0O0Xa6kmQr+xbQ==
dependencies:
chalk "^1.1.3"
get-stdin "^5.0.1"
glur "^1.1.2"
lodash "^4.17.4"
mkdirp "^0.5.1"
pixelmatch "^5.1.0"
pngjs "^3.4.0"
rimraf "^2.6.2"
ssim.js "^3.1.1"
js-tokens@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz"
@ -1225,6 +1341,13 @@ json-stringify-safe@~5.0.1:
resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz"
integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=
jsonfile@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb"
integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=
optionalDependencies:
graceful-fs "^4.1.6"
jsonfile@^6.0.1:
version "6.0.1"
resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.0.1.tgz"
@ -1315,12 +1438,20 @@ listr@^0.14.3:
p-map "^2.0.0"
rxjs "^6.3.3"
locate-path@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e"
integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==
dependencies:
p-locate "^3.0.0"
path-exists "^3.0.0"
lodash.once@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz"
integrity sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=
lodash@^4.17.14, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21:
lodash@^4.17.14, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.17.4:
version "4.17.21"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
@ -1425,7 +1556,7 @@ minimist@^1.2.5:
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz"
integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==
mkdirp@^0.5.4:
mkdirp@^0.5.1, mkdirp@^0.5.4:
version "0.5.5"
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz"
integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==
@ -1457,6 +1588,18 @@ natural-compare@^1.4.0:
resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz"
integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=
nice-try@^1.0.4:
version "1.0.5"
resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366"
integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==
npm-run-path@^2.0.0:
version "2.0.2"
resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f"
integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=
dependencies:
path-key "^2.0.0"
npm-run-path@^4.0.0:
version "4.0.1"
resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz"
@ -1522,11 +1665,35 @@ ospath@^1.2.2:
resolved "https://registry.yarnpkg.com/ospath/-/ospath-1.2.2.tgz"
integrity sha1-EnZjl3Sj+O8lcvf+QoDg6kVQwHs=
p-finally@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae"
integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=
p-limit@^2.0.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1"
integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==
dependencies:
p-try "^2.0.0"
p-locate@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4"
integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==
dependencies:
p-limit "^2.0.0"
p-map@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/p-map/-/p-map-2.1.0.tgz"
integrity sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==
p-try@^2.0.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6"
integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==
parent-module@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz"
@ -1534,11 +1701,21 @@ parent-module@^1.0.0:
dependencies:
callsites "^3.0.0"
path-exists@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515"
integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=
path-is-absolute@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz"
integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18=
path-key@^2.0.0, path-key@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40"
integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=
path-key@^3.0.0, path-key@^3.1.0:
version "3.1.1"
resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz"
@ -1559,6 +1736,39 @@ pify@^2.2.0:
resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz"
integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw=
pixelmatch@^5.1.0:
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@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-3.0.0.tgz#2749020f239ed990881b1f71210d51eb6523bea3"
integrity sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==
dependencies:
find-up "^3.0.0"
plist@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/plist/-/plist-3.0.1.tgz#a9b931d17c304e8912ef0ba3bdd6182baf2e1f8c"
integrity sha512-GpgvHHocGRyQm74b6FWEZZVRroHKE1I0/BTjAmySaohK+cUn+hZpbqXkc3KWgW3gQYkqcQej35FohcT0FRlkRQ==
dependencies:
base64-js "^1.2.3"
xmlbuilder "^9.0.7"
xmldom "0.1.x"
pngjs@^3.4.0:
version "3.4.0"
resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-3.4.0.tgz#99ca7d725965fb655814eaf65f38f12bbdbf555f"
integrity sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w==
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==
prelude-ls@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz"
@ -1680,6 +1890,13 @@ restore-cursor@^2.0.0:
onetime "^2.0.0"
signal-exit "^3.0.2"
rimraf@^2.6.2:
version "2.7.1"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec"
integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==
dependencies:
glob "^7.1.3"
rimraf@^3.0.0, rimraf@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz"
@ -1709,6 +1926,11 @@ safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0:
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz"
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
semver@^5.5.0:
version "5.7.1"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
semver@^7.2.1:
version "7.3.4"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.4.tgz"
@ -1716,6 +1938,13 @@ semver@^7.2.1:
dependencies:
lru-cache "^6.0.0"
shebang-command@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea"
integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=
dependencies:
shebang-regex "^1.0.0"
shebang-command@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz"
@ -1723,12 +1952,17 @@ shebang-command@^2.0.0:
dependencies:
shebang-regex "^3.0.0"
shebang-regex@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3"
integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=
shebang-regex@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz"
integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==
signal-exit@^3.0.2:
signal-exit@^3.0.0, signal-exit@^3.0.2:
version "3.0.3"
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz"
integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==
@ -1767,6 +2001,11 @@ sshpk@^1.7.0:
safer-buffer "^2.0.2"
tweetnacl "~0.14.0"
ssim.js@^3.1.1:
version "3.5.0"
resolved "https://registry.yarnpkg.com/ssim.js/-/ssim.js-3.5.0.tgz#d7276b9ee99b57a5ff0db34035f02f35197e62df"
integrity sha512-Aj6Jl2z6oDmgYFFbQqK7fght19bXdOxY7Tj03nF+03M9gCBAjeIiO8/PlEGMfKDwYpw4q6iBqVq2YuREorGg/g==
string-width@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz"
@ -1821,6 +2060,11 @@ strip-ansi@^6.0.0:
dependencies:
ansi-regex "^5.0.0"
strip-eof@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf"
integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=
strip-final-newline@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz"
@ -1870,6 +2114,14 @@ taffydb@2.6.2:
resolved "https://registry.yarnpkg.com/taffydb/-/taffydb-2.6.2.tgz#7cbcb64b5a141b6a2efc2c5d2c67b4e150b2a268"
integrity sha1-fLy2S1oUG2ou/CxdLGe04VCyomg=
term-img@^4.0.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/term-img/-/term-img-4.1.0.tgz#5b170961f7aa20b2f3b22deb8ad504beb963a8a5"
integrity sha512-DFpBhaF5j+2f7kheKFc1ajsAUUDGOaNPpKPtiIMxlbfud6mvfFZuWGnTRpaujUa5J7yl6cIw/h6nyr4mSsENPg==
dependencies:
ansi-escapes "^4.1.0"
iterm2-version "^4.1.0"
text-table@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz"
@ -1919,6 +2171,11 @@ type-check@^0.4.0, type-check@~0.4.0:
dependencies:
prelude-ls "^1.2.1"
type-fest@^0.11.0:
version "0.11.0"
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.11.0.tgz#97abf0872310fed88a5c466b25681576145e33f1"
integrity sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ==
type-fest@^0.20.2:
version "0.20.2"
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4"
@ -1949,6 +2206,11 @@ uniqid@^5.3.0:
resolved "https://registry.yarnpkg.com/uniqid/-/uniqid-5.3.0.tgz#4545f8e9c9a5830ef804e512cca6a9331e9761bf"
integrity sha512-Jq8EzvAT8/CcLu8tzoSiylnzPkNhJJKpnMT964Dj1jI4pG4sKYP9aFVByNTp8KzMvYlW1Um63PCDqtOoujNzrA==
universalify@^0.1.0:
version "0.1.2"
resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66"
integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==
universalify@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/universalify/-/universalify-1.0.0.tgz"
@ -2003,6 +2265,13 @@ verror@1.10.0:
core-util-is "1.0.2"
extsprintf "^1.2.0"
which@^1.2.9:
version "1.3.1"
resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==
dependencies:
isexe "^2.0.0"
which@^2.0.1:
version "2.0.2"
resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz"
@ -2028,11 +2297,21 @@ wrappy@1:
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz"
integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
xmlbuilder@^9.0.7:
version "9.0.7"
resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-9.0.7.tgz#132ee63d2ec5565c557e20f4c22df9aca686b10d"
integrity sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=
xmlcreate@^2.0.3:
version "2.0.3"
resolved "https://registry.yarnpkg.com/xmlcreate/-/xmlcreate-2.0.3.tgz#df9ecd518fd3890ab3548e1b811d040614993497"
integrity sha512-HgS+X6zAztGa9zIK3Y3LXuJes33Lz9x+YyTxgrkIdabu2vqcGOWwdfCpf1hWLRrd553wd4QCDf6BBO6FfdsRiQ==
xmldom@0.1.x:
version "0.1.31"
resolved "https://registry.yarnpkg.com/xmldom/-/xmldom-0.1.31.tgz#b76c9a1bd9f0a9737e5a72dc37231cf38375e2ff"
integrity sha512-yS2uJflVQs6n+CyjHoaBmVSqIDevTAWrzMmjG1Gc7h1qQ7uVozNhEPJAwZXWyGQ/Gafo3fCwrcaokezLPupVyQ==
yallist@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz"