Add development watch mode to puppeteer jest tests

This commit is contained in:
Rene
2021-01-08 21:50:14 +01:00
parent 67c412bc55
commit 6810865045
17 changed files with 613 additions and 52 deletions
+3
View File
@@ -0,0 +1,3 @@
// remove jsdom warning for not implemented second argument for window.getComputedStyle
const cmptdStyle = window.getComputedStyle;
window.getComputedStyle = (a) => cmptdStyle(a);
+4 -3
View File
@@ -6,18 +6,19 @@ class PuppeteerRollupEnvironment extends PuppeteerEnvironment {
constructor(envConfig, envContext) {
super(envConfig, envContext);
this.watch = envConfig.displayName.name === 'puppeteer-dev';
this.ctx = envContext;
this.cfg = envConfig;
}
async setup() {
// setup
await setupRollupTest(this.cfg.rootDir, this.ctx.testPath, this.cfg.cache && this.cfg.cacheDirectory);
await setupRollupTest(this.cfg.rootDir, this.ctx.testPath, this.cfg.cache && this.cfg.cacheDirectory, this.watch);
await super.setup();
// coverage
const { page } = this.global;
await Promise.all([page.coverage.startCSSCoverage(), page.coverage.startJSCoverage()]);
// const { page } = this.global;
// await Promise.all([page.coverage.startCSSCoverage(), page.coverage.startJSCoverage()]);
}
async teardown() {
+96 -8
View File
@@ -2,9 +2,12 @@ const fs = require('fs');
const crypto = require('crypto');
const path = require('path');
const del = require('del');
const readline = require('readline');
const rollup = require('rollup');
const rollupPluginHtml = require('@rollup/plugin-html');
const rollupPluginStyles = require('rollup-plugin-styles');
const rollupPluginServe = require('rollup-plugin-serve');
const rollupPluginLivereload = require('rollup-plugin-livereload');
const deploymentConfig = require('./jest-puppeteer.rollup.config.js');
const rollupConfigName = 'rollup.config.js';
@@ -132,10 +135,12 @@ const filesChanged = (testPath, cacheDir) => {
return result;
};
const setupRollupTest = async (rootDir, testPath, cacheDir) => {
const setupRollupTest = async (rootDir, testPath, cacheDir, watch) => {
const rollupWatchers = [];
const rollupServers = [];
const testDir = path.dirname(testPath);
const testName = path.basename(testDir);
const changed = cacheDir ? filesChanged(testPath, cacheDir) : true;
const changed = cacheDir && !watch ? filesChanged(testPath, cacheDir) : true;
const buildFolderExists = fs.existsSync(path.resolve(testDir, deploymentConfig.build));
if (changed || !buildFolderExists) {
@@ -148,13 +153,14 @@ const setupRollupTest = async (rootDir, testPath, cacheDir) => {
try {
const htmlFilePath = path.resolve(testDir, deploymentConfig.html.input);
const htmlFileContent = fs.existsSync(htmlFilePath) ? fs.readFileSync(htmlFilePath, 'utf8') : null;
const dist = path.resolve(testDir, deploymentConfig.build);
let rollupConfigObj = rollupConfig(undefined, {
project: rootDir,
overwrite: ({ defaultConfig }) => {
return {
dist,
input: path.resolve(testDir, deploymentConfig.js.input),
dist: path.resolve(testDir, deploymentConfig.build),
file: deploymentConfig.js.output,
types: null,
minVersions: false,
@@ -170,6 +176,23 @@ const setupRollupTest = async (rootDir, testPath, cacheDir) => {
template: genHtmlTemplateFunc(htmlFileContent),
meta: [{ charset: 'utf-8' }, { 'http-equiv': 'X-UA-Compatible', content: 'IE=edge' }],
}),
...(watch
? [
rollupPluginServe({
contentBase: dist,
historyApiFallback: `/${deploymentConfig.html.output}`,
port: 18080,
onListening(server) {
rollupServers.push(server);
},
}),
rollupPluginLivereload({
watch: dist,
verbose: true,
port: 28080,
}),
]
: []),
],
};
},
@@ -184,17 +207,82 @@ const setupRollupTest = async (rootDir, testPath, cacheDir) => {
for (let i = 0; i < rollupConfigObj.length; i++) {
const inputConfig = rollupConfigObj[i];
let { output } = inputConfig;
// eslint-disable-next-line no-await-in-loop
const bundle = await rollup.rollup(inputConfig);
if (!Array.isArray(output)) {
output = [output];
}
for (let v = 0; v < output.length; v++) {
const outputConfig = output[i];
if (watch) {
let firstWatch = true;
const rollupWatcher = rollup.watch({
...inputConfig,
output,
});
// eslint-disable-next-line no-await-in-loop
await bundle.write(outputConfig);
await new Promise((resolve) => {
rollupWatcher.on('event', ({ code, duration, error, result }) => {
if (code === 'ERROR') {
console.log('Error:', error); // eslint-disable-line
}
if (code === 'START') {
console.log(firstWatch ? 'Building...' : 'Rebuilding...'); // eslint-disable-line
}
if (code === 'BUNDLE_END') {
console.log(`Bundle finished after ${Math.round(duration / 1000)} seconds.`); // eslint-disable-line
if (result && result.close) {
result.close();
}
}
if (code === 'END') {
console.log('Watching for changes, press ENTER to continue.'); // eslint-disable-line
console.log(''); // eslint-disable-line
if (firstWatch) {
firstWatch = false;
resolve();
}
}
});
});
rollupWatchers.push(rollupWatcher);
} else {
// eslint-disable-next-line no-await-in-loop
const bundle = await rollup.rollup(inputConfig);
for (let v = 0; v < output.length; v++) {
const outputConfig = output[i];
// eslint-disable-next-line no-await-in-loop
await bundle.write(outputConfig);
}
}
}
if (watch) {
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
await new Promise((resolve) => {
rl.on('line', () => {
resolve();
});
rl.on('close', () => {
resolve();
});
});
rl.close();
rollupWatchers.forEach((watcher) => {
watcher.close();
});
rollupServers.forEach((server) => {
server.close();
});
if (rollupPluginLivereload && global.PLUGIN_LIVERELOAD && global.PLUGIN_LIVERELOAD.server) {
global.PLUGIN_LIVERELOAD.server.close();
global.PLUGIN_LIVERELOAD.server = null;
}
}
} catch (e) {
+4
View File
@@ -0,0 +1,4 @@
const setDefaultOptions = require('expect-puppeteer').setDefaultOptions;
jest.setTimeout(60000);
setDefaultOptions({ timeout: 60000 });
+22 -10
View File
@@ -4,6 +4,8 @@ const puppeteerRollupConfig = require('./config/jest-puppeteer.rollup.config.js'
const testEnvironmentPath = path.resolve(__dirname, './config/jest-puppeteer.env.js');
const testServerLoaderPath = path.resolve(__dirname, './config/jest-test-server.loader.js');
const jsdomSetupFile = path.resolve(__dirname, './config/jest-jsdom.setup.js');
const puppeteerSetupFile = path.resolve(__dirname, './config/jest-puppeteer.setup.js');
// For a detailed explanation regarding each configuration property, visit:
// https://jestjs.io/docs/en/configuration.html
@@ -20,26 +22,36 @@ const base = {
},
};
const pptrBase = {
...base,
preset: 'jest-puppeteer',
setupFilesAfterEnv: ['expect-puppeteer', puppeteerSetupFile],
testMatch: ['**/tests/puppeteer/**/*.test.[jt]s?(x)'],
testEnvironment: testEnvironmentPath,
coveragePathIgnorePatterns: ['/node_modules/', `/${puppeteerRollupConfig.build}/`],
transform: {
'^.+\\.[jt]sx?$': 'babel-jest',
[`^.+${puppeteerRollupConfig.build}.+${puppeteerRollupConfig.html.output}?$`]: testServerLoaderPath,
},
};
module.exports = {
...base,
projects: [
{
...base,
displayName: 'jsdom',
setupFilesAfterEnv: [jsdomSetupFile],
testMatch: ['**/tests/jsdom/**/*.test.[jt]s?(x)'],
},
{
...base,
preset: 'jest-puppeteer',
...pptrBase,
displayName: 'puppeteer',
setupFilesAfterEnv: ['expect-puppeteer'],
testMatch: ['**/tests/puppeteer/**/*.test.[jt]s?(x)'],
testEnvironment: testEnvironmentPath,
coveragePathIgnorePatterns: ['/node_modules/', `/${puppeteerRollupConfig.build}/`],
transform: {
'^.+\\.[jt]sx?$': 'babel-jest',
[`^.+${puppeteerRollupConfig.build}.+${puppeteerRollupConfig.html.output}?$`]: testServerLoaderPath,
},
},
{
...pptrBase,
displayName: 'puppeteer-dev',
collectCoverage: false,
},
],
};
+4 -1
View File
@@ -48,8 +48,10 @@
"prettier-eslint": "^11.0.0",
"puppeteer": "^5.2.1",
"puppeteer-to-istanbul": "^1.4.0",
"rollup": "^2.22.1",
"rollup": "^2.36.1",
"rollup-plugin-livereload": "^2.0.0",
"rollup-plugin-prettier": "^2.1.0",
"rollup-plugin-serve": "^1.1.0",
"rollup-plugin-styles": "^3.10.0",
"rollup-plugin-terser": "^6.1.0",
"rollup-plugin-typescript2": "^0.27.1",
@@ -62,6 +64,7 @@
"test": "yarn workspaces run test",
"test:jsdom": "yarn workspaces run test:jsdom",
"test:pptr": "yarn workspaces run test:pptr",
"test:pptr-dev": "yarn workspaces run test:pptr-dev",
"build": "yarn workspaces run build",
"lint": "npx eslint --fix ."
}
+1
View File
@@ -7,6 +7,7 @@
"test": "jest --coverage --runInBand --detectOpenHandles",
"test:jsdom": "jest --coverage --runInBand --detectOpenHandles --selectProjects jsdom --testPathPattern",
"test:pptr": "jest --coverage --runInBand --detectOpenHandles --selectProjects puppeteer --testPathPattern",
"test:pptr-dev": "jest --coverage --runInBand --detectOpenHandles --selectProjects puppeteer-dev --testPathPattern",
"build": "rollup -c"
}
}
@@ -6,7 +6,7 @@ describe('Environment', () => {
await page.goto(url);
});
it('should be titled "Environment"', async () => {
test('page should be titled "Environment"', async () => {
// @ts-ignore
const a: Environment = await page.evaluate(() => window.environment.envInstance);
console.log(a);
@@ -6,7 +6,7 @@ describe('StructureLifecycle', () => {
await page.goto(url);
});
it('should be titled "Environment"', async () => {
test('page should be titled "Environment"', async () => {
// @ts-ignore
const a: Environment = await page.evaluate(() => window.structureLifecycle.envInstance);
console.log(a);
@@ -0,0 +1,185 @@
import 'overlayscrollbars.scss';
import './index.scss';
import should from 'should';
import { waitFor } from '@testing-library/dom';
import { generateSelectCallback, iterateSelect } from '@/testing-browser/Select';
import { setTestResult } from '@/testing-browser/TestResult';
import { hasDimensions, offsetSize, WH, style } from 'support';
import { createSizeObserver } from 'observers/sizeObserver';
let sizeIterations = 0;
let directionIterations = 0;
const contentBox = (elm: HTMLElement | null): WH<number> => {
if (elm) {
const computedStyle = window.getComputedStyle(elm);
return {
w: elm.clientWidth - (parseFloat(computedStyle.paddingLeft) + parseFloat(computedStyle.paddingRight)),
h: elm.clientHeight - (parseFloat(computedStyle.paddingTop) + parseFloat(computedStyle.paddingBottom)),
};
}
return { w: 0, h: 0 };
};
const targetElm = document.querySelector('#target');
const heightSelect: HTMLSelectElement | null = document.querySelector('#height');
const widthSelect: HTMLSelectElement | null = document.querySelector('#width');
const paddingSelect: HTMLSelectElement | null = document.querySelector('#padding');
const borderSelect: HTMLSelectElement | null = document.querySelector('#border');
const boxSizingSelect: HTMLSelectElement | null = document.querySelector('#boxSizing');
const displaySelect: HTMLSelectElement | null = document.querySelector('#display');
const directionSelect: HTMLSelectElement | null = document.querySelector('#direction');
const startBtn: HTMLButtonElement | null = document.querySelector('#start');
const resizesSlot: HTMLButtonElement | null = document.querySelector('#resizes');
const selectCallback = generateSelectCallback(targetElm as HTMLElement);
const iterate = async (select: HTMLSelectElement | null, afterEach?: () => any) => {
interface IterateSelect {
currSizeIterations: number;
currDirectionIterations: number;
currOffsetSize: WH<number>;
currContentSize: WH<number>;
currDir: string;
}
await iterateSelect<IterateSelect>(select, {
beforeEach() {
const currSizeIterations = sizeIterations;
const currDirectionIterations = directionIterations;
const currOffsetSize = offsetSize(targetElm as HTMLElement);
const currContentSize = contentBox(targetElm as HTMLElement);
const currDir = style(targetElm as HTMLElement, 'direction');
return {
currSizeIterations,
currDirectionIterations,
currOffsetSize,
currContentSize,
currDir,
};
},
async check({ currSizeIterations, currDirectionIterations, currOffsetSize, currContentSize, currDir }) {
const newOffsetSize = offsetSize(targetElm as HTMLElement);
const newContentSize = contentBox(targetElm as HTMLElement);
const newDir = style(targetElm as HTMLElement, 'direction');
const offsetSizeChanged = currOffsetSize.w !== newOffsetSize.w || currOffsetSize.h !== newOffsetSize.h;
const contentSizeChanged = currContentSize.w !== newContentSize.w || currContentSize.h !== newContentSize.h;
const dirChanged = currDir !== newDir;
const dimensions = hasDimensions(targetElm as HTMLElement);
const observerElm = targetElm?.firstElementChild as HTMLElement;
// no overflow if not needed
if (targetElm && newContentSize.w > 0) {
should.ok(observerElm.getBoundingClientRect().right <= targetElm.getBoundingClientRect().right);
}
if (targetElm && newContentSize.h > 0) {
should.ok(observerElm.getBoundingClientRect().bottom <= targetElm.getBoundingClientRect().bottom);
}
if (dimensions && (offsetSizeChanged || contentSizeChanged || dirChanged)) {
await waitFor(
() => {
if (offsetSizeChanged || contentSizeChanged) {
should.equal(sizeIterations, currSizeIterations + 1);
}
if (dirChanged) {
should.equal(directionIterations, currDirectionIterations + 1);
}
},
{
onTimeout(error): Error {
setTestResult(false);
return error;
},
}
);
}
},
afterEach,
});
};
heightSelect?.addEventListener('change', selectCallback);
widthSelect?.addEventListener('change', selectCallback);
paddingSelect?.addEventListener('change', selectCallback);
borderSelect?.addEventListener('change', selectCallback);
boxSizingSelect?.addEventListener('change', selectCallback);
displaySelect?.addEventListener('change', selectCallback);
directionSelect?.addEventListener('change', selectCallback);
selectCallback(heightSelect);
selectCallback(widthSelect);
selectCallback(paddingSelect);
selectCallback(borderSelect);
selectCallback(boxSizingSelect);
selectCallback(displaySelect);
selectCallback(directionSelect);
const iteratePadding = async (afterEach?: () => any) => {
await iterate(paddingSelect, afterEach);
};
const iterateBorder = async (afterEach?: () => any) => {
await iterate(borderSelect, afterEach);
};
const iterateHeight = async (afterEach?: () => any) => {
await iterate(heightSelect, afterEach);
};
const iterateWidth = async (afterEach?: () => any) => {
await iterate(widthSelect, afterEach);
};
const iterateBoxSizing = async (afterEach?: () => any) => {
await iterate(boxSizingSelect, afterEach);
};
const iterateDisplay = async (afterEach?: () => any) => {
await iterate(displaySelect, afterEach);
};
const iterateDirection = async (afterEach?: () => any) => {
await iterate(directionSelect, afterEach);
};
const start = async () => {
setTestResult(null);
console.log('init direction changes:', directionIterations);
console.log('init size changes:', sizeIterations);
should.ok(directionIterations > 0);
should.ok(sizeIterations > 0);
targetElm?.removeAttribute('style');
await iterateDisplay();
await iterateDirection();
await iterateBoxSizing(async () => {
await iterateHeight(async () => {
await iterateWidth(async () => {
await iterateBorder(async () => {
await iterateDirection();
await iteratePadding();
});
});
});
});
setTestResult(true);
};
startBtn?.addEventListener('click', start);
createSizeObserver(
targetElm as HTMLElement,
(directionCache?: any) => {
if (directionCache) {
directionIterations += 1;
} else {
sizeIterations += 1;
}
requestAnimationFrame(() => {
if (resizesSlot) {
resizesSlot.textContent = (directionIterations + sizeIterations).toString();
}
});
},
{ _direction: true, _appear: true }
);
console.log('h1');
export { start };
@@ -0,0 +1,49 @@
<div id="controls">
<label for="height">height</label>
<select name="height" id="height">
<option value="heightAuto">auto</option>
<option value="heightHundred">100%</option>
<option value="height200">200px</option>
</select>
<label for="width">width</label>
<select name="width" id="width">
<option value="widthAuto">auto</option>
<option value="widthHundred">100%</option>
<option value="width200">200px</option>
</select>
<label for="padding">padding</label>
<select name="padding" id="padding">
<option value="padding0">0</option>
<option value="padding10">10px</option>
<option value="padding50">50px</option>
</select>
<label for="border">border</label>
<select name="border" id="border">
<option value="border2">2px</option>
<option value="border10">10px</option>
<option value="border0">0</option>
</select>
<label for="boxSizing">boxSizing</label>
<select name="boxSizing" id="boxSizing">
<option value="boxSizingBorderBox">border-box</option>
<option value="boxSizingContentBox">content-box</option>
</select>
<label for="display">display</label>
<select name="display" id="display">
<option value="displayBlock">block</option>
<option value="displayNone">none</option>
</select>
<label for="direction">direction</label>
<select name="direction" id="direction">
<option value="directionLTR">ltr</option>
<option value="directionRTL">rtl</option>
</select>
<button id="start">start</button>
<span>Detected resizes: <span id="resizes">0</span></span>
</div>
<div id="stage">
<div>
<div id="target"></div>
</div>
</div>
@@ -0,0 +1,99 @@
body {
display: flex;
flex-direction: column;
}
#controls {
flex: none;
}
#stage {
flex: auto;
position: relative;
& > div {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
background: lightgoldenrodyellow;
}
}
#canvas > div {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
#target {
overflow: hidden;
resize: both;
position: relative;
// prevent container from reaching 0x0 dimensions for testing purposes
min-width: 50px;
min-height: 50px;
}
.padding0 {
padding: 0;
}
.padding10 {
padding: 10px;
}
.padding50 {
padding: 50px;
}
.border2 {
border: 2px solid red;
}
.border10 {
border: 10px solid red;
}
.border0 {
border: none;
}
.heightAuto {
height: auto;
}
.height200 {
height: 200px;
}
.heightHundred {
height: 100%;
}
.widthAuto {
width: auto;
float: left;
}
.width200 {
width: 200px;
}
.widthHundred {
width: 100%;
}
.boxSizingBorderBox {
box-sizing: border-box;
}
.boxSizingContentBox {
box-sizing: content-box;
}
.displayNone {
display: none;
}
.displayBlock {
display: block;
}
.directionltr {
direction: ltr;
}
.directionRTL {
direction: rtl;
}
@@ -0,0 +1,13 @@
import expectPuppeteer from 'expect-puppeteer';
import url from './.build/build.html';
describe('DOMObserver', () => {
beforeAll(async () => {
await page.goto(url);
});
test('test', async () => {
await expectPuppeteer(page).toClick('#start');
await expectPuppeteer(page).toMatchElement('#testResult.passed');
});
});
@@ -1,15 +1,13 @@
import expectPuppeteer from 'expect-puppeteer';
import url from './.build/build.html';
describe('Environment', () => {
describe('SizeObserver', () => {
beforeAll(async () => {
await page.goto(url);
});
it('test', async () => {
test('test', async () => {
await expectPuppeteer(page).toClick('#start');
await expectPuppeteer(page).toMatchElement('#testResult.passed', {
timeout: 60000,
});
}, 60000);
await expectPuppeteer(page).toMatchElement('#testResult.passed');
});
});
@@ -1,15 +1,13 @@
import expectPuppeteer from 'expect-puppeteer';
import url from './.build/build.html';
describe('Environment', () => {
describe('TrinsicObserver', () => {
beforeAll(async () => {
await page.goto(url);
});
it('test', async () => {
test('test', async () => {
await expectPuppeteer(page).toClick('#start');
await expectPuppeteer(page).toMatchElement('#testResult.passed', {
timeout: 60000,
});
}, 60000);
await expectPuppeteer(page).toMatchElement('#testResult.passed');
});
});
+18 -7
View File
@@ -243,26 +243,37 @@ const rollupConfig = (config = {}, { project = process.cwd(), overwrite = {}, si
const isLast = index === buildsArr.length - 1;
if (isFirst) {
const deleteGeneratedDirs = () => {
const deletedDirs = del.sync([distPath, typesPath].filter((curr) => curr !== null));
if (deletedDirs.length > 0 && !silent) {
console.log('Deleted directories:\n', deletedDirs.join('\n'));
}
};
build.plugins.unshift({
name: 'deleteGeneratedDirs',
options() {
const deletedDirs = del.sync([distPath, typesPath].filter((curr) => curr !== null));
if (deletedDirs.length > 0 && !silent) {
console.log('Deleted directories:\n', deletedDirs.join('\n'));
if (!this.meta.watchMode) {
deleteGeneratedDirs();
}
},
});
}
if (isLast) {
const deleteCacheDirs = () => {
const cacheDirs = cache.map((dir) => path.resolve(projectPath, dir));
const deletedDirs = del.sync(cacheDirs);
if (deletedDirs.length > 0 && !silent) {
console.log('Deleted cache:\n', deletedDirs.join('\n'));
}
};
build.plugins.push({
name: 'deleteCacheDirs',
writeBundle() {
const cacheDirs = cache.map((dir) => path.resolve(projectPath, dir));
const deletedDirs = del.sync(cacheDirs);
if (deletedDirs.length > 0 && !silent) {
console.log('Deleted cache:\n', deletedDirs.join('\n'));
if (!this.meta.watchMode) {
deleteCacheDirs();
}
},
closeWatcher: deleteCacheDirs,
});
}
+105 -9
View File
@@ -1784,7 +1784,7 @@ anymatch@^2.0.0:
micromatch "^3.1.4"
normalize-path "^2.1.1"
anymatch@^3.0.3:
anymatch@^3.0.3, anymatch@~3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.1.tgz#c55ecf02185e2469259399310c173ce31233b142"
integrity sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==
@@ -1913,6 +1913,11 @@ async-foreach@^0.1.3:
resolved "https://registry.yarnpkg.com/async-foreach/-/async-foreach-0.1.3.tgz#36121f845c0578172de419a97dbeb1d16ec34542"
integrity sha1-NhIfhFwFeBct5Bmpfb6x0W7DRUI=
async-limiter@~1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd"
integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==
asynckit@^0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
@@ -2055,6 +2060,11 @@ bcrypt-pbkdf@^1.0.0:
dependencies:
tweetnacl "^0.14.3"
binary-extensions@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.1.0.tgz#30fa40c9e7fe07dbc895678cd287024dea241dd9"
integrity sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==
bindings@^1.5.0:
version "1.5.0"
resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df"
@@ -2123,7 +2133,7 @@ braces@^2.3.1:
split-string "^3.0.2"
to-regex "^3.0.1"
braces@^3.0.1:
braces@^3.0.1, braces@~3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==
@@ -2331,6 +2341,21 @@ chardet@^0.7.0:
resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e"
integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==
chokidar@^3.3.0:
version "3.5.0"
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.0.tgz#458a4816a415e9d3b3caa4faec2b96a6935a9e65"
integrity sha512-JgQM9JS92ZbFR4P90EvmzNpSGhpPBGBSj10PILeDyYFwp4h2/D9OM03wsJ4zW1fEp4ka2DGrnUeD7FuvQ2aZ2Q==
dependencies:
anymatch "~3.1.1"
braces "~3.0.2"
glob-parent "~5.1.0"
is-binary-path "~2.1.0"
is-glob "~4.0.1"
normalize-path "~3.0.0"
readdirp "~3.5.0"
optionalDependencies:
fsevents "~2.3.1"
chownr@^1.1.1:
version "1.1.4"
resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b"
@@ -3963,6 +3988,11 @@ fsevents@^2.1.2, fsevents@~2.1.2:
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.1.3.tgz#fb738703ae8d2f9fe900c33836ddebee8b97f23e"
integrity sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==
fsevents@~2.3.1:
version "2.3.1"
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.1.tgz#b209ab14c61012636c8863507edf7fb68cc54e9f"
integrity sha512-YR47Eg4hChJGAB1O3yEAOkGO+rlzutoICGqGo9EZ4lKWokzZRSyIW1QmTzqjtw8MJdj9srP869CuWw/hyzSiBw==
fstream@^1.0.0, fstream@^1.0.12:
version "1.0.12"
resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.12.tgz#4e8ba8ee2d48be4f7d0de505455548eae5932045"
@@ -4055,7 +4085,7 @@ getpass@^0.1.1:
dependencies:
assert-plus "^1.0.0"
glob-parent@^5.0.0, glob-parent@^5.1.0:
glob-parent@^5.0.0, glob-parent@^5.1.0, glob-parent@~5.1.0:
version "5.1.1"
resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.1.tgz#b6c1ef417c4e5663ea498f1c45afac6916bbc229"
integrity sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==
@@ -4487,6 +4517,13 @@ is-arrayish@^0.3.1:
resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03"
integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==
is-binary-path@~2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09"
integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==
dependencies:
binary-extensions "^2.0.0"
is-buffer@^1.0.2, is-buffer@^1.1.5:
version "1.1.6"
resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
@@ -4607,7 +4644,7 @@ is-generator-fn@^2.0.0:
resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118"
integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==
is-glob@^4.0.0, is-glob@^4.0.1:
is-glob@^4.0.0, is-glob@^4.0.1, is-glob@~4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc"
integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==
@@ -5555,6 +5592,21 @@ lines-and-columns@^1.1.6:
resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00"
integrity sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=
livereload-js@^3.1.0:
version "3.3.1"
resolved "https://registry.yarnpkg.com/livereload-js/-/livereload-js-3.3.1.tgz#61f887468086762e61fb2987412cf9d1dda99202"
integrity sha512-CBu1gTEfzVhlOK1WASKAAJ9Qx1fHECTq0SUB67sfxwQssopTyvzqTlgl+c0h9pZ6V+Fzd2rc510ppuNusg9teQ==
livereload@^0.9.1:
version "0.9.1"
resolved "https://registry.yarnpkg.com/livereload/-/livereload-0.9.1.tgz#65125dabdf2db4fd3f1169e953fe56e3bcc6f477"
integrity sha512-9g7sua11kkyZNo2hLRCG3LuZZwqexoyEyecSlV8cAsfAVVCZqLzVir6XDqmH0r+Vzgnd5LrdHDMyjtFnJQLAYw==
dependencies:
chokidar "^3.3.0"
livereload-js "^3.1.0"
opts ">= 1.2.0"
ws "^6.2.1"
load-json-file@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0"
@@ -5837,6 +5889,11 @@ mime@1.6.0:
resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==
mime@>=2.4.6:
version "2.4.7"
resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.7.tgz#962aed9be0ed19c91fd7dc2ece5d7f4e89a90d74"
integrity sha512-dhNd1uA2u397uQk3Nv5LM4lm93WYDUXFn3Fu291FJerns4jyTudqhIWe4W04YLy7Uk1tm1Ore04NpjRvQp/NPA==
mime@^2.0.3:
version "2.4.6"
resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.6.tgz#e5b407c90db442f2beb5b162373d07b69affa4d1"
@@ -6099,7 +6156,7 @@ normalize-path@^2.1.1:
dependencies:
remove-trailing-separator "^1.0.1"
normalize-path@^3.0.0:
normalize-path@^3.0.0, normalize-path@~3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
@@ -6282,6 +6339,11 @@ onetime@^5.1.0:
dependencies:
mimic-fn "^2.1.0"
opener@1:
version "1.5.2"
resolved "https://registry.yarnpkg.com/opener/-/opener-1.5.2.tgz#5d37e1f35077b9dcac4301372271afdeb2a13598"
integrity sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==
optionator@^0.8.1, optionator@^0.8.3:
version "0.8.3"
resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495"
@@ -6306,6 +6368,11 @@ optionator@^0.9.1:
type-check "^0.4.0"
word-wrap "^1.2.3"
"opts@>= 1.2.0":
version "2.0.2"
resolved "https://registry.yarnpkg.com/opts/-/opts-2.0.2.tgz#a17e189fbbfee171da559edd8a42423bc5993ce1"
integrity sha512-k41FwbcLnlgnFh69f4qdUfvDQ+5vaSDnVPFI/y5XuhKRq97EnVVneO9F1ESVCdiVu4fCS2L8usX3mU331hB7pg==
os-homedir@^1.0.0, os-homedir@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3"
@@ -7206,6 +7273,13 @@ readable-stream@^3.1.1, readable-stream@^3.4.0:
string_decoder "^1.1.1"
util-deprecate "^1.0.1"
readdirp@~3.5.0:
version "3.5.0"
resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.5.0.tgz#9ba74c019b15d365278d2e91bb8c48d7b4d42c9e"
integrity sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==
dependencies:
picomatch "^2.2.1"
realpath-native@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/realpath-native/-/realpath-native-1.1.0.tgz#2003294fea23fb0672f2476ebe22fcf498a2d65c"
@@ -7465,6 +7539,13 @@ rimraf@^3.0.0, rimraf@^3.0.2:
dependencies:
glob "^7.1.3"
rollup-plugin-livereload@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/rollup-plugin-livereload/-/rollup-plugin-livereload-2.0.0.tgz#d3928d74e8cf2ae4286c5dd46b770fd3f3b82313"
integrity sha512-oC/8NqumGYuphkqrfszOHUUIwzKsaHBICw6QRwT5uD07gvePTS+HW+GFwu6f9K8W02CUuTvtIM9AWJrbj4wE1A==
dependencies:
livereload "^0.9.1"
rollup-plugin-prettier@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/rollup-plugin-prettier/-/rollup-plugin-prettier-2.1.0.tgz#06b42169e28cb23163d4648bef412e57ff70acb4"
@@ -7477,6 +7558,14 @@ rollup-plugin-prettier@^2.1.0:
lodash.omitby "4.6.0"
magic-string "0.25.7"
rollup-plugin-serve@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/rollup-plugin-serve/-/rollup-plugin-serve-1.1.0.tgz#0654a57021a21b903340c69940f7463706e8288d"
integrity sha512-pYkSsuA0/psKqhhictkJw1c2klya5b+LlCvipWqI9OE1aG2M97mRumZCbBlry5CMEOzYBBgSDgd1694sNbmyIw==
dependencies:
mime ">=2.4.6"
opener "1"
rollup-plugin-styles@^3.10.0:
version "3.10.0"
resolved "https://registry.yarnpkg.com/rollup-plugin-styles/-/rollup-plugin-styles-3.10.0.tgz#8e0e6c96ae235d15bfe5f03d9d0ee5282f3f40a2"
@@ -7521,10 +7610,10 @@ rollup-plugin-typescript2@^0.27.1:
resolve "1.17.0"
tslib "2.0.1"
rollup@^2.22.1:
version "2.26.11"
resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.26.11.tgz#4fc31de9c7b83d50916fc8395f8c3d24730cdaae"
integrity sha512-xyfxxhsE6hW57xhfL1I+ixH8l2bdoIMaAecdQiWF3N7IgJEMu99JG+daBiSZQjnBpzFxa0/xZm+3pbCdAQehHw==
rollup@^2.36.1:
version "2.36.1"
resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.36.1.tgz#2174f0c25c7b400d57b05628d0e732c7ae8d2178"
integrity sha512-eAfqho8dyzuVvrGqpR0ITgEdq0zG2QJeWYh+HeuTbpcaXk8vNFc48B7bJa1xYosTCKx0CuW+447oQOW8HgBIZQ==
optionalDependencies:
fsevents "~2.1.2"
@@ -8925,6 +9014,13 @@ write@1.0.3:
dependencies:
mkdirp "^0.5.1"
ws@^6.2.1:
version "6.2.1"
resolved "https://registry.yarnpkg.com/ws/-/ws-6.2.1.tgz#442fdf0a47ed64f59b6a5d8ff130f4748ed524fb"
integrity sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==
dependencies:
async-limiter "~1.0.0"
ws@^7.2.3:
version "7.3.1"
resolved "https://registry.yarnpkg.com/ws/-/ws-7.3.1.tgz#d0547bf67f7ce4f12a72dfe31262c68d7dc551c8"