feat: UI Performance Infra setup v1 (#9835)
Co-authored-by: Satish Gandham <satish@appsmith.com>
This commit is contained in:
parent
269e3a786d
commit
c5abd3dd6f
173
.github/workflows/integration-tests-command.yml
vendored
173
.github/workflows/integration-tests-command.yml
vendored
|
|
@ -570,3 +570,176 @@ jobs:
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
perf-test:
|
||||||
|
needs: [build, server-build]
|
||||||
|
# Only run if the build step is successful
|
||||||
|
if: success()
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
working-directory: app/client
|
||||||
|
shell: bash
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix: job:[0]
|
||||||
|
|
||||||
|
# Service containers to run with this job. Required for running tests
|
||||||
|
services:
|
||||||
|
# Label used to access the service container
|
||||||
|
redis:
|
||||||
|
# Docker Hub image for Redis
|
||||||
|
image: redis
|
||||||
|
ports:
|
||||||
|
# Opens tcp port 6379 on the host and service container
|
||||||
|
- 6379:6379
|
||||||
|
mongo:
|
||||||
|
image: mongo
|
||||||
|
ports:
|
||||||
|
- 27017:27017
|
||||||
|
|
||||||
|
steps:
|
||||||
|
# Check out merge commitGIT BRANCH
|
||||||
|
- name: Fork based /ok-to-test-perf checkout
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
ref: "refs/pull/${{ github.event.client_payload.pull_request.number }}/merge"
|
||||||
|
|
||||||
|
- name: Use Node.js 14.15.4
|
||||||
|
uses: actions/setup-node@v1
|
||||||
|
with:
|
||||||
|
node-version: "14.15.4"
|
||||||
|
|
||||||
|
- name: Get yarn cache directory path
|
||||||
|
id: yarn-dep-cache-dir-path
|
||||||
|
run: echo "::set-output name=dir::$(yarn cache dir)"
|
||||||
|
|
||||||
|
# Retrieve npm dependencies from cache. After a successful run, these dependencies are cached again
|
||||||
|
- name: Cache npm dependencies
|
||||||
|
id: yarn-dep-cache
|
||||||
|
uses: actions/cache@v2
|
||||||
|
env:
|
||||||
|
cache-name: cache-yarn-dependencies
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
${{ steps.yarn-dep-cache-dir-path.outputs.dir }}
|
||||||
|
key: ${{ runner.os }}-yarn-dep-${{ hashFiles('**/yarn.lock') }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-yarn-dep-
|
||||||
|
|
||||||
|
# Install all the dependencies
|
||||||
|
- name: Install dependencies
|
||||||
|
run: yarn install
|
||||||
|
|
||||||
|
- name: Download the react build artifact
|
||||||
|
uses: actions/download-artifact@v2
|
||||||
|
with:
|
||||||
|
name: build
|
||||||
|
path: app/client/build
|
||||||
|
|
||||||
|
- name: Download the server build artifact
|
||||||
|
uses: actions/download-artifact@v2
|
||||||
|
with:
|
||||||
|
name: build
|
||||||
|
path: app/server/dist
|
||||||
|
|
||||||
|
# Start server
|
||||||
|
- name: start server
|
||||||
|
working-directory: app/server
|
||||||
|
env:
|
||||||
|
APPSMITH_MONGODB_URI: "mongodb://localhost:27017/mobtools"
|
||||||
|
APPSMITH_REDIS_URL: "redis://127.0.0.1:6379"
|
||||||
|
APPSMITH_ENCRYPTION_PASSWORD: "password"
|
||||||
|
APPSMITH_ENCRYPTION_SALT: "salt"
|
||||||
|
APPSMITH_IS_SELF_HOSTED: false
|
||||||
|
APPSMITH_CLOUD_SERVICES_BASE_URL: https://release-cs.appsmith.com
|
||||||
|
APPSMITH_CLOUD_SERVICES_USERNAME: ""
|
||||||
|
APPSMITH_CLOUD_SERVICES_PASSWORD: ""
|
||||||
|
run: |
|
||||||
|
ls -l
|
||||||
|
ls -l scripts/
|
||||||
|
ls -l dist/
|
||||||
|
# Run the server in the background and redirect logs to a log file
|
||||||
|
./scripts/start-dev-server.sh &> server-logs.log &
|
||||||
|
|
||||||
|
- name: Wait for 30 seconds for server to start
|
||||||
|
run: |
|
||||||
|
sleep 30s
|
||||||
|
|
||||||
|
- name: Exit if Server hasnt started
|
||||||
|
run: |
|
||||||
|
if [[ `ps -ef | grep "server-1.0-SNAPSHOT" | grep java |wc -l` == 0 ]]; then
|
||||||
|
echo "Server Not Started";
|
||||||
|
exit 1;
|
||||||
|
else
|
||||||
|
echo "Server Found";
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Installing Yarn serve
|
||||||
|
run: |
|
||||||
|
yarn global add serve
|
||||||
|
echo "$(yarn global bin)" >> $GITHUB_PATH
|
||||||
|
|
||||||
|
- name: Setting up the perf tests
|
||||||
|
shell: bash
|
||||||
|
env:
|
||||||
|
APPSMITH_SSL_CERTIFICATE: ${{ secrets.APPSMITH_SSL_CERTIFICATE }}
|
||||||
|
APPSMITH_SSL_KEY: ${{ secrets.APPSMITH_SSL_KEY }}
|
||||||
|
CYPRESS_URL: ${{ secrets.CYPRESS_URL }}
|
||||||
|
CYPRESS_USERNAME: ${{ secrets.CYPRESS_USERNAME }}
|
||||||
|
CYPRESS_PASSWORD: ${{ secrets.CYPRESS_PASSWORD }}
|
||||||
|
CYPRESS_TESTUSERNAME1: ${{ secrets.CYPRESS_TESTUSERNAME1 }}
|
||||||
|
CYPRESS_TESTPASSWORD1: ${{ secrets.CYPRESS_TESTPASSWORD1 }}
|
||||||
|
CYPRESS_TESTUSERNAME2: ${{ secrets.CYPRESS_TESTUSERNAME2 }}
|
||||||
|
CYPRESS_TESTPASSWORD2: ${{ secrets.CYPRESS_TESTPASSWORD1 }}
|
||||||
|
CYPRESS_S3_ACCESS_KEY: ${{ secrets.CYPRESS_S3_ACCESS_KEY }}
|
||||||
|
CYPRESS_S3_SECRET_KEY: ${{ secrets.CYPRESS_S3_SECRET_KEY }}
|
||||||
|
APPSMITH_DISABLE_TELEMETRY: true
|
||||||
|
APPSMITH_GOOGLE_MAPS_API_KEY: ${{ secrets.APPSMITH_GOOGLE_MAPS_API_KEY }}
|
||||||
|
POSTGRES_PASSWORD: postgres
|
||||||
|
run: |
|
||||||
|
./cypress/setup-test.sh
|
||||||
|
|
||||||
|
- name: Installing performance tests dependencies
|
||||||
|
working-directory: app/client/perf
|
||||||
|
shell: bash
|
||||||
|
run: yarn install
|
||||||
|
|
||||||
|
- name: Change test script permissions
|
||||||
|
working-directory: app/client/perf
|
||||||
|
run: chmod +x ./start-test.sh
|
||||||
|
|
||||||
|
- name: Run performance tests
|
||||||
|
working-directory: app/client/perf
|
||||||
|
shell: bash
|
||||||
|
env:
|
||||||
|
APPSMITH_SSL_CERTIFICATE: ${{ secrets.APPSMITH_SSL_CERTIFICATE }}
|
||||||
|
APPSMITH_SSL_KEY: ${{ secrets.APPSMITH_SSL_KEY }}
|
||||||
|
CYPRESS_TESTUSERNAME1: ${{ secrets.CYPRESS_TESTUSERNAME9 }}
|
||||||
|
CYPRESS_TESTPASSWORD1: ${{ secrets.CYPRESS_TESTPASSWORD9 }}
|
||||||
|
APPSMITH_DISABLE_TELEMETRY: true
|
||||||
|
POSTGRES_PASSWORD: postgres
|
||||||
|
NODE_TLS_REJECT_UNAUTHORIZED: "0"
|
||||||
|
run: ./start-test.sh
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v2
|
||||||
|
with:
|
||||||
|
name: performance-summaries
|
||||||
|
path: app/client/perf/traces
|
||||||
|
|
||||||
|
|
||||||
|
- name: Read summary file
|
||||||
|
id: read_summary
|
||||||
|
uses: andstor/file-reader-action@v1
|
||||||
|
with:
|
||||||
|
path: app/client/perf/traces/reports/summary.md
|
||||||
|
|
||||||
|
- name: Add a comment with the results on the PR with link to workflow run
|
||||||
|
uses: peter-evans/create-or-update-comment@v1
|
||||||
|
with:
|
||||||
|
issue-number: ${{ github.event.client_payload.pull_request.number }}
|
||||||
|
body: |
|
||||||
|
UI Performance test run logs and artifacts: <https://github.com/appsmithorg/appsmith/actions/runs/${{ github.run_id }}>.
|
||||||
|
Commit: `${{ github.event.client_payload.slash_command.sha }}`.
|
||||||
|
Results: ${{ steps.read_summary.outputs.contents }}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -15,3 +15,6 @@ package-lock.json
|
||||||
coverage-summary.json
|
coverage-summary.json
|
||||||
app/client/cypress/locators/Widgets.json
|
app/client/cypress/locators/Widgets.json
|
||||||
deploy/ansible/appsmith_playbook/inventory
|
deploy/ansible/appsmith_playbook/inventory
|
||||||
|
|
||||||
|
# performance tests
|
||||||
|
app/client/perf/traces/*
|
||||||
85
app/client/perf/dsl/simple-typing.js
Normal file
85
app/client/perf/dsl/simple-typing.js
Normal file
|
|
@ -0,0 +1,85 @@
|
||||||
|
exports.dsl = {
|
||||||
|
dsl: {
|
||||||
|
widgetName: "MainContainer",
|
||||||
|
backgroundColor: "none",
|
||||||
|
rightColumn: 1936,
|
||||||
|
snapColumns: 64,
|
||||||
|
detachFromLayout: true,
|
||||||
|
widgetId: "0",
|
||||||
|
topRow: 0,
|
||||||
|
bottomRow: 1290,
|
||||||
|
containerStyle: "none",
|
||||||
|
snapRows: 125,
|
||||||
|
parentRowSpace: 1,
|
||||||
|
type: "CANVAS_WIDGET",
|
||||||
|
canExtend: true,
|
||||||
|
version: 46,
|
||||||
|
minHeight: 1292,
|
||||||
|
parentColumnSpace: 1,
|
||||||
|
dynamicBindingPathList: [],
|
||||||
|
leftColumn: 0,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
isVisible: true,
|
||||||
|
text: "<h1>{{Input1.text}}</h1>",
|
||||||
|
fontSize: "HEADING1",
|
||||||
|
fontStyle: "BOLD",
|
||||||
|
textAlign: "LEFT",
|
||||||
|
textColor: "#231F20",
|
||||||
|
widgetName: "Text1",
|
||||||
|
version: 1,
|
||||||
|
type: "TEXT_WIDGET",
|
||||||
|
hideCard: false,
|
||||||
|
displayName: "Text",
|
||||||
|
key: "4ln743vbxf",
|
||||||
|
iconSVG: "/static/media/icon.97c59b52.svg",
|
||||||
|
widgetId: "oylox3e28e",
|
||||||
|
renderMode: "CANVAS",
|
||||||
|
isLoading: false,
|
||||||
|
parentColumnSpace: 30.0625,
|
||||||
|
parentRowSpace: 10,
|
||||||
|
leftColumn: 1,
|
||||||
|
rightColumn: 39,
|
||||||
|
topRow: 16,
|
||||||
|
bottomRow: 40,
|
||||||
|
parentId: "0",
|
||||||
|
dynamicBindingPathList: [
|
||||||
|
{
|
||||||
|
key: "text",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
dynamicTriggerPathList: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
isVisible: true,
|
||||||
|
inputType: "TEXT",
|
||||||
|
label: "",
|
||||||
|
widgetName: "Input1",
|
||||||
|
version: 1,
|
||||||
|
defaultText: "",
|
||||||
|
iconAlign: "left",
|
||||||
|
autoFocus: false,
|
||||||
|
labelStyle: "",
|
||||||
|
resetOnSubmit: true,
|
||||||
|
isRequired: false,
|
||||||
|
isDisabled: false,
|
||||||
|
allowCurrencyChange: false,
|
||||||
|
type: "INPUT_WIDGET",
|
||||||
|
hideCard: false,
|
||||||
|
displayName: "Input",
|
||||||
|
key: "4xvbov2itw",
|
||||||
|
iconSVG: "/static/media/icon.9f505595.svg",
|
||||||
|
widgetId: "d454uqlxd0",
|
||||||
|
renderMode: "CANVAS",
|
||||||
|
isLoading: false,
|
||||||
|
parentColumnSpace: 30.0625,
|
||||||
|
parentRowSpace: 10,
|
||||||
|
leftColumn: 1,
|
||||||
|
rightColumn: 12,
|
||||||
|
topRow: 9,
|
||||||
|
bottomRow: 13,
|
||||||
|
parentId: "0",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
55
app/client/perf/index.js
Normal file
55
app/client/perf/index.js
Normal file
|
|
@ -0,0 +1,55 @@
|
||||||
|
const path = require("path");
|
||||||
|
const Perf = require("./perf.js");
|
||||||
|
const dsl = require("./dsl/simple-typing").dsl;
|
||||||
|
var fs = require("fs");
|
||||||
|
const { summaries } = require("./summary");
|
||||||
|
|
||||||
|
// Set the perf directory as APP_ROOT on the global level
|
||||||
|
global.APP_ROOT = path.resolve(__dirname);
|
||||||
|
|
||||||
|
// Create the directory
|
||||||
|
const dir = `${APP_ROOT}/traces/reports`;
|
||||||
|
if (!fs.existsSync(dir)) {
|
||||||
|
fs.mkdirSync(dir, { recursive: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
process.env["NODE_TLS_REJECT_UNAUTHORIZED"] = 0;
|
||||||
|
|
||||||
|
async function testTyping() {
|
||||||
|
const perf = new Perf({
|
||||||
|
ignoreHTTPSErrors: true, // @todo Remove it after initial testing
|
||||||
|
});
|
||||||
|
await perf.launch();
|
||||||
|
const page = perf.getPage();
|
||||||
|
await perf.loadDSL(dsl);
|
||||||
|
|
||||||
|
const selector = "input.bp3-input"; // Input selector
|
||||||
|
await page.waitForSelector(selector);
|
||||||
|
const input = await page.$(selector);
|
||||||
|
|
||||||
|
await perf.startTrace("Edit input");
|
||||||
|
await page.type(selector, "Hello Appsmith");
|
||||||
|
await perf.stopTrace();
|
||||||
|
|
||||||
|
await perf.startTrace("Clear input");
|
||||||
|
await input.click({ clickCount: 3 });
|
||||||
|
await input.press("Backspace");
|
||||||
|
await perf.stopTrace();
|
||||||
|
|
||||||
|
await perf.startTrace("Edit input again");
|
||||||
|
await page.type(selector, "Howdy satish");
|
||||||
|
await perf.stopTrace();
|
||||||
|
|
||||||
|
await perf.generateReport();
|
||||||
|
await perf.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function runTests() {
|
||||||
|
await testTyping();
|
||||||
|
await testTyping();
|
||||||
|
await testTyping();
|
||||||
|
await testTyping();
|
||||||
|
await testTyping();
|
||||||
|
summaries(`${APP_ROOT}/traces/reports`);
|
||||||
|
}
|
||||||
|
runTests();
|
||||||
15
app/client/perf/package.json
Normal file
15
app/client/perf/package.json
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
{
|
||||||
|
"name": "ui-performance-infra",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "Tools to automate chrome performance profiling",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"puppeteer": "^12.0.1",
|
||||||
|
"tracelib": "^1.0.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
136
app/client/perf/perf.js
Normal file
136
app/client/perf/perf.js
Normal file
|
|
@ -0,0 +1,136 @@
|
||||||
|
const Tracelib = require("tracelib");
|
||||||
|
const puppeteer = require("puppeteer");
|
||||||
|
const fs = require("fs");
|
||||||
|
const {
|
||||||
|
delay,
|
||||||
|
login,
|
||||||
|
getFormattedTime,
|
||||||
|
sortObjectKeys,
|
||||||
|
} = require("./utils/utils");
|
||||||
|
|
||||||
|
module.exports = class Perf {
|
||||||
|
constructor(launchOptions = {}) {
|
||||||
|
this.launchOptions = {
|
||||||
|
...launchOptions,
|
||||||
|
};
|
||||||
|
this.traces = [];
|
||||||
|
this.traceInProgress = false;
|
||||||
|
this.browser = null;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Launches the browser and, gives you the page
|
||||||
|
*/
|
||||||
|
launch = async () => {
|
||||||
|
this.browser = await puppeteer.launch(this.launchOptions);
|
||||||
|
const pages_ = await this.browser.pages();
|
||||||
|
this.page = pages_[0];
|
||||||
|
await this._login();
|
||||||
|
};
|
||||||
|
|
||||||
|
_login = async () => {
|
||||||
|
await login(this.page);
|
||||||
|
await delay(2000, "after login");
|
||||||
|
};
|
||||||
|
|
||||||
|
startTrace = async (action = "foo") => {
|
||||||
|
if (this.traceInProgress) {
|
||||||
|
console.warn("Trace progress. You can run only one trace at a time");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.traceInProgress = true;
|
||||||
|
await delay(3000, `before starting trace ${action}`);
|
||||||
|
const path = `${APP_ROOT}/traces/${action}-${getFormattedTime()}-chrome-profile.json`;
|
||||||
|
await this.page.tracing.start({
|
||||||
|
path: path,
|
||||||
|
screenshots: true,
|
||||||
|
});
|
||||||
|
this.traces.push({ action, path });
|
||||||
|
};
|
||||||
|
|
||||||
|
stopTrace = async () => {
|
||||||
|
this.traceInProgress = false;
|
||||||
|
await delay(5000, "before stoping the trace");
|
||||||
|
await this.page.tracing.stop();
|
||||||
|
};
|
||||||
|
|
||||||
|
getPage = () => {
|
||||||
|
if (this.page) return this.page;
|
||||||
|
throw Error("Can't find the page, please call launch method.");
|
||||||
|
};
|
||||||
|
|
||||||
|
loadDSL = async (dsl) => {
|
||||||
|
const selector = ".createnew";
|
||||||
|
await this.page.waitForSelector(selector);
|
||||||
|
await this.page.click(selector);
|
||||||
|
// We goto the newly created app.
|
||||||
|
// Lets update the page
|
||||||
|
await this.page.waitForNavigation();
|
||||||
|
|
||||||
|
const currentUrl = this.page.url();
|
||||||
|
const pageIdRegex = /pages(.*)/;
|
||||||
|
const match = pageIdRegex.exec(currentUrl);
|
||||||
|
const pageId = match[1].split("/")[1];
|
||||||
|
|
||||||
|
await this.page.evaluate(
|
||||||
|
async ({ pageId, dsl }) => {
|
||||||
|
const layoutId = await fetch(`/api/v1/pages/${pageId}`)
|
||||||
|
.then((response) => response.json())
|
||||||
|
.then((data) => data.data.layouts[0].id);
|
||||||
|
|
||||||
|
const pageSaveUrl = "/api/v1/layouts/" + layoutId + "/pages/" + pageId;
|
||||||
|
await fetch(pageSaveUrl, {
|
||||||
|
headers: {
|
||||||
|
accept: "application/json, text/plain, */*",
|
||||||
|
"content-type": "application/json",
|
||||||
|
},
|
||||||
|
|
||||||
|
referrerPolicy: "strict-origin-when-cross-origin",
|
||||||
|
body: JSON.stringify(dsl),
|
||||||
|
method: "PUT",
|
||||||
|
mode: "cors",
|
||||||
|
credentials: "include",
|
||||||
|
})
|
||||||
|
.then((res) =>
|
||||||
|
console.log("Save page with new DSL response:", res.json()),
|
||||||
|
)
|
||||||
|
.catch((err) => {
|
||||||
|
console.log("Save page with new DSL error:", err);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
{ pageId, dsl },
|
||||||
|
);
|
||||||
|
await this.page.goto(currentUrl.replace("generate-page", ""), {
|
||||||
|
waitUntil: "networkidle2",
|
||||||
|
timeout: 60000,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
generateReport = async () => {
|
||||||
|
const report = {};
|
||||||
|
this.traces.forEach(({ path, action }) => {
|
||||||
|
report[action] = {};
|
||||||
|
const trace = require(path);
|
||||||
|
const tasks = new Tracelib.default(trace.traceEvents);
|
||||||
|
report[action].path = path;
|
||||||
|
report[action].summary = sortObjectKeys(tasks.getSummary());
|
||||||
|
report[action].warnings = sortObjectKeys(tasks.getWarningCounts());
|
||||||
|
});
|
||||||
|
|
||||||
|
fs.writeFile(
|
||||||
|
`${APP_ROOT}/traces/reports/${getFormattedTime()}.json`,
|
||||||
|
JSON.stringify(report, "", 4),
|
||||||
|
(err) => {
|
||||||
|
if (err) {
|
||||||
|
console.log("Error writing file", err);
|
||||||
|
} else {
|
||||||
|
console.log("Successfully wrote report");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
close = async () => {
|
||||||
|
this.browser.close();
|
||||||
|
};
|
||||||
|
};
|
||||||
1
app/client/perf/start-test.sh
Normal file
1
app/client/perf/start-test.sh
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
node index.js
|
||||||
86
app/client/perf/summary.js
Normal file
86
app/client/perf/summary.js
Normal file
|
|
@ -0,0 +1,86 @@
|
||||||
|
const fs = require("fs");
|
||||||
|
const path = require("path");
|
||||||
|
|
||||||
|
exports.summaries = async (directory) => {
|
||||||
|
const files = await fs.promises.readdir(directory);
|
||||||
|
const results = {};
|
||||||
|
files.forEach((file) => {
|
||||||
|
if (file.endsWith(".json")) {
|
||||||
|
const content = require(`${APP_ROOT}/traces/reports/${file}`);
|
||||||
|
Object.keys(content).forEach((key) => {
|
||||||
|
if (!results[key]) {
|
||||||
|
results[key] = {};
|
||||||
|
}
|
||||||
|
if (!results[key]?.scripting) {
|
||||||
|
results[key].scripting = [];
|
||||||
|
}
|
||||||
|
results[key].scripting.push(content[key].summary.scripting);
|
||||||
|
|
||||||
|
if (!results[key]?.painting) {
|
||||||
|
results[key].painting = [];
|
||||||
|
}
|
||||||
|
results[key].painting.push(content[key].summary.painting);
|
||||||
|
|
||||||
|
if (!results[key]?.rendering) {
|
||||||
|
results[key].rendering = [];
|
||||||
|
}
|
||||||
|
results[key].rendering.push(content[key].summary.rendering);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
generateReport(results);
|
||||||
|
};
|
||||||
|
|
||||||
|
const generateReport = (results) => {
|
||||||
|
var size = 5;
|
||||||
|
Object.keys(results).forEach((key) => {
|
||||||
|
const action = results[key];
|
||||||
|
Object.keys(action).forEach((key) => {
|
||||||
|
size = action[key].length;
|
||||||
|
const sum = action[key].reduce((sum, val) => sum + val, 0);
|
||||||
|
const avg = (sum / action[key].length).toFixed(2);
|
||||||
|
action[key].push(avg);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
generateMarkdown(results, size);
|
||||||
|
};
|
||||||
|
|
||||||
|
const generateMarkdown = (results, size = 5) => {
|
||||||
|
let markdown = `<details><summary>Click to view performance test results</summary>\n\n| `;
|
||||||
|
for (let i = 0; i < size; i++) {
|
||||||
|
markdown = markdown + `| Run #${i + 1} `;
|
||||||
|
}
|
||||||
|
markdown = markdown + `| Avg `;
|
||||||
|
|
||||||
|
markdown += "|\n";
|
||||||
|
|
||||||
|
for (let i = 0; i <= size + 1; i++) {
|
||||||
|
markdown = markdown + `| ------------- `;
|
||||||
|
}
|
||||||
|
markdown += "|\n";
|
||||||
|
|
||||||
|
Object.keys(results).forEach((key) => {
|
||||||
|
const action = results[key];
|
||||||
|
markdown = markdown + key;
|
||||||
|
for (let i = 0; i <= size; i++) {
|
||||||
|
markdown = markdown + `| `;
|
||||||
|
}
|
||||||
|
markdown += "|\n";
|
||||||
|
Object.keys(action).forEach((key) => {
|
||||||
|
markdown += `| ${key} | `;
|
||||||
|
markdown += action[key].reduce((sum, val) => `${sum} | ${val} `);
|
||||||
|
markdown += "| \n";
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
markdown += "</details>";
|
||||||
|
|
||||||
|
fs.writeFile(`${APP_ROOT}/traces/reports/summary.md`, markdown, (err) => {
|
||||||
|
if (err) {
|
||||||
|
console.log("Error writing file", err);
|
||||||
|
} else {
|
||||||
|
console.log("Successfully wrote summary");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
143
app/client/perf/utils/utils.js
Normal file
143
app/client/perf/utils/utils.js
Normal file
|
|
@ -0,0 +1,143 @@
|
||||||
|
const fs = require("fs");
|
||||||
|
const path = require("path");
|
||||||
|
|
||||||
|
const delay = (time, msg = "") => {
|
||||||
|
console.log(`waiting ${msg}:`, time / 1000, "s");
|
||||||
|
return new Promise(function(resolve) {
|
||||||
|
setTimeout(resolve, time);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.delay = delay;
|
||||||
|
|
||||||
|
exports.getDevToolsPage = async (browser) => {
|
||||||
|
const targets = await browser.targets();
|
||||||
|
const devtoolsTarget = targets.filter((t) => {
|
||||||
|
return t.type() === "other" && t.url().startsWith("devtools://");
|
||||||
|
})[0];
|
||||||
|
|
||||||
|
// Hack to get a page pointing to the devtools
|
||||||
|
devtoolsTarget._targetInfo.type = "page";
|
||||||
|
const devtoolsPage = await devtoolsTarget.page();
|
||||||
|
return devtoolsPage;
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.gotoProfiler = async (devtoolsPage) => {
|
||||||
|
await devtoolsPage.bringToFront();
|
||||||
|
await devtoolsPage.keyboard.down("MetaLeft");
|
||||||
|
await devtoolsPage.keyboard.press("[");
|
||||||
|
await devtoolsPage.keyboard.up("MetaLeft");
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.getProfilerFrame = async (devtoolsPage) => {
|
||||||
|
const frames = await devtoolsPage.frames();
|
||||||
|
const reactProfiler = frames[2]; // This is not foolproof
|
||||||
|
return reactProfiler;
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.startReactProfile = async (reactProfiler) => {
|
||||||
|
const recordButton =
|
||||||
|
"#container > div > div > div > div > div.Toolbar___30kHu > button.Button___1-PiG.InactiveRecordToggle___2CUtF";
|
||||||
|
await reactProfiler.waitForSelector(recordButton);
|
||||||
|
const container = await reactProfiler.$(recordButton);
|
||||||
|
console.log("Satring recording");
|
||||||
|
await reactProfiler.evaluate((el) => el.click(), container);
|
||||||
|
console.log("Recording started");
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.stopReactProfile = async (reactProfiler) => {
|
||||||
|
const stopRecordingButton =
|
||||||
|
"#container > div > div > div > div > div.Toolbar___30kHu > button.Button___1-PiG.ActiveRecordToggle___1Cpcb";
|
||||||
|
await reactProfiler.waitForSelector(stopRecordingButton);
|
||||||
|
const container = await reactProfiler.$(stopRecordingButton);
|
||||||
|
console.log("Stopping recording");
|
||||||
|
await reactProfiler.evaluate((el) => el.click(), container);
|
||||||
|
console.log("Recording stopped");
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.downloadReactProfile = async (reactProfiler) => {
|
||||||
|
const saveProfileButton =
|
||||||
|
"#container > div > div > div > div.LeftColumn___3I7-I > div.Toolbar___30kHu > button:nth-child(8)";
|
||||||
|
await reactProfiler.waitForSelector(saveProfileButton);
|
||||||
|
const container = await reactProfiler.$(saveProfileButton);
|
||||||
|
await reactProfiler.evaluate((el) => el.click(), container);
|
||||||
|
console.log("Downlaoded the profile");
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.saveProfile = async (reactProfiler, name) => {
|
||||||
|
const anchorSelector =
|
||||||
|
"#container > div > div > div > div.LeftColumn___3I7-I > div.Toolbar___30kHu > a";
|
||||||
|
await reactProfiler.waitForSelector(anchorSelector);
|
||||||
|
const anchor = await reactProfiler.$(anchorSelector);
|
||||||
|
await reactProfiler.evaluate(
|
||||||
|
(el) => console.log(el.getAttribute("href")),
|
||||||
|
anchor,
|
||||||
|
);
|
||||||
|
const attr = await reactProfiler.$$eval(anchorSelector, (el) =>
|
||||||
|
el.map((x) => x.getAttribute("href")),
|
||||||
|
);
|
||||||
|
|
||||||
|
const url = attr[0];
|
||||||
|
|
||||||
|
const profile = await reactProfiler.evaluate(async (href) => {
|
||||||
|
const blob = await fetch(href).then(async (r) => r.blob());
|
||||||
|
const text = await blob.text();
|
||||||
|
return text;
|
||||||
|
}, url);
|
||||||
|
const location = path.join(__dirname, `/profiles/${name}.json`);
|
||||||
|
fs.writeFileSync(location, profile);
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.login = async (page) => {
|
||||||
|
const url = "https://dev.appsmith.com/user/login";
|
||||||
|
|
||||||
|
await page.goto(url);
|
||||||
|
await page.setViewport({ width: 1440, height: 714 });
|
||||||
|
|
||||||
|
await delay(1000, "before login");
|
||||||
|
|
||||||
|
const emailSelector = "input[name='username']";
|
||||||
|
const passwordSelector = "input[name='password']";
|
||||||
|
const buttonSelector = "button[type='submit']";
|
||||||
|
|
||||||
|
try {
|
||||||
|
await page.waitForSelector(emailSelector);
|
||||||
|
await page.waitForSelector(passwordSelector);
|
||||||
|
await page.waitForSelector(buttonSelector);
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
console.log(
|
||||||
|
"Screenshot:",
|
||||||
|
`${APP_ROOT}/traces/reports/login-selector-error.png`,
|
||||||
|
);
|
||||||
|
await page.screenshot({
|
||||||
|
path: `${APP_ROOT}/traces/reports/login-selector-error.png`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
await page.type(emailSelector, process.env.CYPRESS_TESTUSERNAME1);
|
||||||
|
await page.type(passwordSelector, process.env.CYPRESS_TESTPASSWORD1);
|
||||||
|
delay(1000, "before clicking login button");
|
||||||
|
await page.click(buttonSelector);
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.getFormattedTime = () => {
|
||||||
|
var today = new Date();
|
||||||
|
var y = today.getFullYear();
|
||||||
|
var m = today.getMonth() + 1;
|
||||||
|
var d = today.getDate();
|
||||||
|
var h = today.getHours();
|
||||||
|
var mi = today.getMinutes();
|
||||||
|
var s = today.getSeconds();
|
||||||
|
return y + "-" + m + "-" + d + "-" + h + "-" + mi + "-" + s;
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.sortObjectKeys = (obj) => {
|
||||||
|
const sortedObj = {};
|
||||||
|
Object.keys(obj)
|
||||||
|
.sort()
|
||||||
|
.forEach((key) => {
|
||||||
|
sortedObj[key] = obj[key];
|
||||||
|
});
|
||||||
|
return sortedObj;
|
||||||
|
};
|
||||||
402
app/client/perf/yarn.lock
Normal file
402
app/client/perf/yarn.lock
Normal file
|
|
@ -0,0 +1,402 @@
|
||||||
|
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
||||||
|
# yarn lockfile v1
|
||||||
|
|
||||||
|
|
||||||
|
"@types/node@*":
|
||||||
|
version "17.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.0.tgz#62797cee3b8b497f6547503b2312254d4fe3c2bb"
|
||||||
|
integrity sha512-eMhwJXc931Ihh4tkU+Y7GiLzT/y/DBNpNtr4yU9O2w3SYBsr9NaOPhQlLKRmoWtI54uNwuo0IOUFQjVOTZYRvw==
|
||||||
|
|
||||||
|
"@types/yauzl@^2.9.1":
|
||||||
|
version "2.9.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/yauzl/-/yauzl-2.9.2.tgz#c48e5d56aff1444409e39fa164b0b4d4552a7b7a"
|
||||||
|
integrity sha512-8uALY5LTvSuHgloDVUvWP3pIauILm+8/0pDMokuDYIoNsOkSwd5AiHBTSEJjKTDcZr5z8UpgOWZkxBF4iJftoA==
|
||||||
|
dependencies:
|
||||||
|
"@types/node" "*"
|
||||||
|
|
||||||
|
agent-base@6:
|
||||||
|
version "6.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77"
|
||||||
|
integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==
|
||||||
|
dependencies:
|
||||||
|
debug "4"
|
||||||
|
|
||||||
|
balanced-match@^1.0.0:
|
||||||
|
version "1.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
|
||||||
|
integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
|
||||||
|
|
||||||
|
base64-js@^1.3.1:
|
||||||
|
version "1.5.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
|
||||||
|
integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
|
||||||
|
|
||||||
|
bl@^4.0.3:
|
||||||
|
version "4.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a"
|
||||||
|
integrity sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==
|
||||||
|
dependencies:
|
||||||
|
buffer "^5.5.0"
|
||||||
|
inherits "^2.0.4"
|
||||||
|
readable-stream "^3.4.0"
|
||||||
|
|
||||||
|
brace-expansion@^1.1.7:
|
||||||
|
version "1.1.11"
|
||||||
|
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
|
||||||
|
integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
|
||||||
|
dependencies:
|
||||||
|
balanced-match "^1.0.0"
|
||||||
|
concat-map "0.0.1"
|
||||||
|
|
||||||
|
buffer-crc32@~0.2.3:
|
||||||
|
version "0.2.13"
|
||||||
|
resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242"
|
||||||
|
integrity sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=
|
||||||
|
|
||||||
|
buffer@^5.2.1, buffer@^5.5.0:
|
||||||
|
version "5.7.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0"
|
||||||
|
integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==
|
||||||
|
dependencies:
|
||||||
|
base64-js "^1.3.1"
|
||||||
|
ieee754 "^1.1.13"
|
||||||
|
|
||||||
|
chownr@^1.1.1:
|
||||||
|
version "1.1.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b"
|
||||||
|
integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==
|
||||||
|
|
||||||
|
concat-map@0.0.1:
|
||||||
|
version "0.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
|
||||||
|
integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
|
||||||
|
|
||||||
|
debug@4, debug@^4.1.1:
|
||||||
|
version "4.3.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664"
|
||||||
|
integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==
|
||||||
|
dependencies:
|
||||||
|
ms "2.1.2"
|
||||||
|
|
||||||
|
debug@4.3.2:
|
||||||
|
version "4.3.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.2.tgz#f0a49c18ac8779e31d4a0c6029dfb76873c7428b"
|
||||||
|
integrity sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==
|
||||||
|
dependencies:
|
||||||
|
ms "2.1.2"
|
||||||
|
|
||||||
|
devtools-protocol@0.0.937139:
|
||||||
|
version "0.0.937139"
|
||||||
|
resolved "https://registry.yarnpkg.com/devtools-protocol/-/devtools-protocol-0.0.937139.tgz#bdee3751fdfdb81cb701fd3afa94b1065dafafcf"
|
||||||
|
integrity sha512-daj+rzR3QSxsPRy5vjjthn58axO8c11j58uY0lG5vvlJk/EiOdCWOptGdkXDjtuRHr78emKq0udHCXM4trhoDQ==
|
||||||
|
|
||||||
|
end-of-stream@^1.1.0, end-of-stream@^1.4.1:
|
||||||
|
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==
|
||||||
|
dependencies:
|
||||||
|
once "^1.4.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==
|
||||||
|
dependencies:
|
||||||
|
debug "^4.1.1"
|
||||||
|
get-stream "^5.1.0"
|
||||||
|
yauzl "^2.10.0"
|
||||||
|
optionalDependencies:
|
||||||
|
"@types/yauzl" "^2.9.1"
|
||||||
|
|
||||||
|
fd-slicer@~1.1.0:
|
||||||
|
version "1.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.1.0.tgz#25c7c89cb1f9077f8891bbe61d8f390eae256f1e"
|
||||||
|
integrity sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=
|
||||||
|
dependencies:
|
||||||
|
pend "~1.2.0"
|
||||||
|
|
||||||
|
find-up@^4.0.0:
|
||||||
|
version "4.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19"
|
||||||
|
integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==
|
||||||
|
dependencies:
|
||||||
|
locate-path "^5.0.0"
|
||||||
|
path-exists "^4.0.0"
|
||||||
|
|
||||||
|
fs-constants@^1.0.0:
|
||||||
|
version "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.realpath@^1.0.0:
|
||||||
|
version "1.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
|
||||||
|
integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8=
|
||||||
|
|
||||||
|
get-stream@^5.1.0:
|
||||||
|
version "5.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3"
|
||||||
|
integrity sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==
|
||||||
|
dependencies:
|
||||||
|
pump "^3.0.0"
|
||||||
|
|
||||||
|
glob@^7.1.3:
|
||||||
|
version "7.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023"
|
||||||
|
integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==
|
||||||
|
dependencies:
|
||||||
|
fs.realpath "^1.0.0"
|
||||||
|
inflight "^1.0.4"
|
||||||
|
inherits "2"
|
||||||
|
minimatch "^3.0.4"
|
||||||
|
once "^1.3.0"
|
||||||
|
path-is-absolute "^1.0.0"
|
||||||
|
|
||||||
|
https-proxy-agent@5.0.0:
|
||||||
|
version "5.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz#e2a90542abb68a762e0a0850f6c9edadfd8506b2"
|
||||||
|
integrity sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==
|
||||||
|
dependencies:
|
||||||
|
agent-base "6"
|
||||||
|
debug "4"
|
||||||
|
|
||||||
|
ieee754@^1.1.13:
|
||||||
|
version "1.2.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352"
|
||||||
|
integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==
|
||||||
|
|
||||||
|
inflight@^1.0.4:
|
||||||
|
version "1.0.6"
|
||||||
|
resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
|
||||||
|
integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=
|
||||||
|
dependencies:
|
||||||
|
once "^1.3.0"
|
||||||
|
wrappy "1"
|
||||||
|
|
||||||
|
inherits@2, inherits@^2.0.3, inherits@^2.0.4:
|
||||||
|
version "2.0.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
|
||||||
|
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
|
||||||
|
|
||||||
|
locate-path@^5.0.0:
|
||||||
|
version "5.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0"
|
||||||
|
integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==
|
||||||
|
dependencies:
|
||||||
|
p-locate "^4.1.0"
|
||||||
|
|
||||||
|
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==
|
||||||
|
dependencies:
|
||||||
|
brace-expansion "^1.1.7"
|
||||||
|
|
||||||
|
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==
|
||||||
|
|
||||||
|
ms@2.1.2:
|
||||||
|
version "2.1.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
|
||||||
|
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
|
||||||
|
|
||||||
|
node-fetch@2.6.5:
|
||||||
|
version "2.6.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.5.tgz#42735537d7f080a7e5f78b6c549b7146be1742fd"
|
||||||
|
integrity sha512-mmlIVHJEu5rnIxgEgez6b9GgWXbkZj5YZ7fx+2r94a2E+Uirsp6HsPTPlomfdHtpt/B0cdKviwkoaM6pyvUOpQ==
|
||||||
|
dependencies:
|
||||||
|
whatwg-url "^5.0.0"
|
||||||
|
|
||||||
|
once@^1.3.0, once@^1.3.1, once@^1.4.0:
|
||||||
|
version "1.4.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
|
||||||
|
integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E=
|
||||||
|
dependencies:
|
||||||
|
wrappy "1"
|
||||||
|
|
||||||
|
p-limit@^2.2.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@^4.1.0:
|
||||||
|
version "4.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07"
|
||||||
|
integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==
|
||||||
|
dependencies:
|
||||||
|
p-limit "^2.2.0"
|
||||||
|
|
||||||
|
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==
|
||||||
|
|
||||||
|
path-exists@^4.0.0:
|
||||||
|
version "4.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3"
|
||||||
|
integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==
|
||||||
|
|
||||||
|
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#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
|
||||||
|
integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18=
|
||||||
|
|
||||||
|
pend@~1.2.0:
|
||||||
|
version "1.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50"
|
||||||
|
integrity sha1-elfrVQpng/kRUzH89GY9XI4AelA=
|
||||||
|
|
||||||
|
pkg-dir@4.2.0:
|
||||||
|
version "4.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3"
|
||||||
|
integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==
|
||||||
|
dependencies:
|
||||||
|
find-up "^4.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==
|
||||||
|
|
||||||
|
proxy-from-env@1.1.0:
|
||||||
|
version "1.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2"
|
||||||
|
integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==
|
||||||
|
|
||||||
|
pump@^3.0.0:
|
||||||
|
version "3.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64"
|
||||||
|
integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==
|
||||||
|
dependencies:
|
||||||
|
end-of-stream "^1.1.0"
|
||||||
|
once "^1.3.1"
|
||||||
|
|
||||||
|
puppeteer@^12.0.1:
|
||||||
|
version "12.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/puppeteer/-/puppeteer-12.0.1.tgz#ae79d0e174a07563e0bf2e05c94ccafce3e70033"
|
||||||
|
integrity sha512-YQ3GRiyZW0ddxTW+iiQcv2/8TT5c3+FcRUCg7F8q2gHqxd5akZN400VRXr9cHQKLWGukmJLDiE72MrcLK9tFHQ==
|
||||||
|
dependencies:
|
||||||
|
debug "4.3.2"
|
||||||
|
devtools-protocol "0.0.937139"
|
||||||
|
extract-zip "2.0.1"
|
||||||
|
https-proxy-agent "5.0.0"
|
||||||
|
node-fetch "2.6.5"
|
||||||
|
pkg-dir "4.2.0"
|
||||||
|
progress "2.0.3"
|
||||||
|
proxy-from-env "1.1.0"
|
||||||
|
rimraf "3.0.2"
|
||||||
|
tar-fs "2.1.1"
|
||||||
|
unbzip2-stream "1.4.3"
|
||||||
|
ws "8.2.3"
|
||||||
|
|
||||||
|
readable-stream@^3.1.1, readable-stream@^3.4.0:
|
||||||
|
version "3.6.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198"
|
||||||
|
integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==
|
||||||
|
dependencies:
|
||||||
|
inherits "^2.0.3"
|
||||||
|
string_decoder "^1.1.1"
|
||||||
|
util-deprecate "^1.0.1"
|
||||||
|
|
||||||
|
rimraf@3.0.2:
|
||||||
|
version "3.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a"
|
||||||
|
integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==
|
||||||
|
dependencies:
|
||||||
|
glob "^7.1.3"
|
||||||
|
|
||||||
|
safe-buffer@~5.2.0:
|
||||||
|
version "5.2.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
|
||||||
|
integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
|
||||||
|
|
||||||
|
string_decoder@^1.1.1:
|
||||||
|
version "1.3.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e"
|
||||||
|
integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==
|
||||||
|
dependencies:
|
||||||
|
safe-buffer "~5.2.0"
|
||||||
|
|
||||||
|
tar-fs@2.1.1:
|
||||||
|
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@^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"
|
||||||
|
|
||||||
|
through@^2.3.8:
|
||||||
|
version "2.3.8"
|
||||||
|
resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
|
||||||
|
integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=
|
||||||
|
|
||||||
|
tr46@~0.0.3:
|
||||||
|
version "0.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a"
|
||||||
|
integrity sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=
|
||||||
|
|
||||||
|
tracelib@^1.0.1:
|
||||||
|
version "1.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/tracelib/-/tracelib-1.0.1.tgz#bb44ea96c19b8d7a6c85a6ee1cac9945c5b75c64"
|
||||||
|
integrity sha512-T2Vkpa/7Vdm3sV8nXRn8vZ0tnq6wlnO4Zx7Pux+JA1W6DMlg5EtbNcPZu/L7XRTPc9S0eAKhEFR4p/u0GcsDpQ==
|
||||||
|
|
||||||
|
unbzip2-stream@1.4.3:
|
||||||
|
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==
|
||||||
|
dependencies:
|
||||||
|
buffer "^5.2.1"
|
||||||
|
through "^2.3.8"
|
||||||
|
|
||||||
|
util-deprecate@^1.0.1:
|
||||||
|
version "1.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
|
||||||
|
integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
|
||||||
|
|
||||||
|
webidl-conversions@^3.0.0:
|
||||||
|
version "3.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871"
|
||||||
|
integrity sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=
|
||||||
|
|
||||||
|
whatwg-url@^5.0.0:
|
||||||
|
version "5.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d"
|
||||||
|
integrity sha1-lmRU6HZUYuN2RNNib2dCzotwll0=
|
||||||
|
dependencies:
|
||||||
|
tr46 "~0.0.3"
|
||||||
|
webidl-conversions "^3.0.0"
|
||||||
|
|
||||||
|
wrappy@1:
|
||||||
|
version "1.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
|
||||||
|
integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
|
||||||
|
|
||||||
|
ws@8.2.3:
|
||||||
|
version "8.2.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/ws/-/ws-8.2.3.tgz#63a56456db1b04367d0b721a0b80cae6d8becbba"
|
||||||
|
integrity sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==
|
||||||
|
|
||||||
|
yauzl@^2.10.0:
|
||||||
|
version "2.10.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9"
|
||||||
|
integrity sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=
|
||||||
|
dependencies:
|
||||||
|
buffer-crc32 "~0.2.3"
|
||||||
|
fd-slicer "~1.1.0"
|
||||||
Loading…
Reference in New Issue
Block a user