diff --git a/.gitignore b/.gitignore index 7a0bab977c..cf1d1e01d5 100644 --- a/.gitignore +++ b/.gitignore @@ -17,4 +17,5 @@ app/client/cypress/locators/Widgets.json deploy/ansible/appsmith_playbook/inventory # performance tests -app/client/perf/traces/* \ No newline at end of file +app/client/perf/traces/* +.history \ No newline at end of file diff --git a/app/client/perf/package.json b/app/client/perf/package.json index 8302752bcc..7fea2dd891 100644 --- a/app/client/perf/package.json +++ b/app/client/perf/package.json @@ -9,7 +9,9 @@ "author": "", "license": "ISC", "dependencies": { + "node-stdev": "^1.0.1", "puppeteer": "^12.0.1", + "sanitize-filename": "^1.6.3", "tracelib": "^1.0.1" } } diff --git a/app/client/perf/src/index.js b/app/client/perf/src/index.js new file mode 100644 index 0000000000..2f748a5511 --- /dev/null +++ b/app/client/perf/src/index.js @@ -0,0 +1,21 @@ +const glob = require("glob"); +const path = require("path"); +const { summaries } = require("./summary"); +var cp = require("child_process"); +var fs = require("fs"); + +// Create the directory +global.APP_ROOT = path.join(__dirname, ".."); //Going back one level from src folder to /perf +const dir = `${APP_ROOT}/traces/reports`; +if (!fs.existsSync(dir)) { + fs.mkdirSync(dir, { recursive: true }); +} + +glob("./tests/*.perf.js", {}, async function(er, files) { + // Initial setup + await cp.execSync(`node ./tests/initial-setup.js`, { stdio: "inherit" }); + files.forEach(async (file) => { + await cp.execSync(`node ${file}`, { stdio: "inherit" }); // Logging to terminal, log it to a file in future? + }); + summaries(`${APP_ROOT}/traces/reports`); +}); diff --git a/app/client/perf/perf.js b/app/client/perf/src/perf.js similarity index 62% rename from app/client/perf/perf.js rename to app/client/perf/src/perf.js index e30fe86963..fe701a9742 100644 --- a/app/client/perf/perf.js +++ b/app/client/perf/src/perf.js @@ -1,21 +1,59 @@ const Tracelib = require("tracelib"); const puppeteer = require("puppeteer"); +var sanitize = require("sanitize-filename"); const fs = require("fs"); +const path = require("path"); + const { delay, login, getFormattedTime, sortObjectKeys, } = require("./utils/utils"); - +const selectors = { + appMoreIcon: "span.t--options-icon", + orgImportAppOption: '[data-cy*="t--org-import-app"]', + fileInput: "#fileInput", + importButton: '[data-cy*="t--org-import-app-button"]', + createNewApp: ".createnew", +}; module.exports = class Perf { constructor(launchOptions = {}) { this.launchOptions = { + defaultViewport: null, + args: ["--window-size=1920,1080"], + ignoreHTTPSErrors: true, // @todo Remove it after initial testing ...launchOptions, }; + + if (process.env.PERF_TEST_ENV === "dev") { + this.launchOptions.executablePath = + "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"; + this.launchOptions.devtools = true; + this.launchOptions.headless = false; + } + this.traces = []; - this.traceInProgress = false; + this.currentTrace = null; this.browser = null; + + // Initial setup + this.currentTestFile = process.argv[1] + .split("/") + .pop() + .replace(".perf.js", ""); + global.APP_ROOT = path.join(__dirname, ".."); //Going back one level from src folder to /perf + process.on("unhandledRejection", async (reason, p) => { + console.error("Unhandled Rejection at: Promise", p, "reason:", reason); + const fileName = sanitize( + `${this.currentTestFile}__${this.currentTrace}`, + ); + const screenshotPath = `${APP_ROOT}/traces/reports/${fileName}-${getFormattedTime()}.png`; + await this.page.screenshot({ + path: screenshotPath, + }); + this.browser.close(); + }); } /** * Launches the browser and, gives you the page @@ -33,12 +71,12 @@ module.exports = class Perf { }; startTrace = async (action = "foo") => { - if (this.traceInProgress) { + if (this.currentTrace) { console.warn("Trace progress. You can run only one trace at a time"); return; } - this.traceInProgress = true; + this.currentTrace = action; await delay(3000, `before starting trace ${action}`); const path = `${APP_ROOT}/traces/${action}-${getFormattedTime()}-chrome-profile.json`; await this.page.tracing.start({ @@ -49,8 +87,8 @@ module.exports = class Perf { }; stopTrace = async () => { - this.traceInProgress = false; - await delay(5000, "before stoping the trace"); + this.currentTrace = null; + await delay(3000, "before stopping the trace"); await this.page.tracing.stop(); }; @@ -60,7 +98,7 @@ module.exports = class Perf { }; loadDSL = async (dsl) => { - const selector = ".createnew"; + const selector = selectors.createNewApp; await this.page.waitForSelector(selector); await this.page.click(selector); // We goto the newly created app. @@ -106,6 +144,20 @@ module.exports = class Perf { }); }; + importApplication = async (jsonPath) => { + await this.page.waitForSelector(selectors.appMoreIcon); + await this.page.click(selectors.appMoreIcon); + await this.page.waitForSelector(selectors.orgImportAppOption); + await this.page.click(selectors.orgImportAppOption); + + const elementHandle = await this.page.$(selectors.fileInput); + await elementHandle.uploadFile(jsonPath); + await this.page.click(selectors.importButton); + + await this.page.waitForNavigation(); + await this.page.reload(); + }; + generateReport = async () => { const report = {}; this.traces.forEach(({ path, action }) => { diff --git a/app/client/perf/summary.js b/app/client/perf/src/summary.js similarity index 54% rename from app/client/perf/summary.js rename to app/client/perf/src/summary.js index 093155986e..1a3447fc54 100644 --- a/app/client/perf/summary.js +++ b/app/client/perf/src/summary.js @@ -1,5 +1,8 @@ const fs = require("fs"); const path = require("path"); +const sd = require("node-stdev"); + +global.APP_ROOT = path.resolve(__dirname); exports.summaries = async (directory) => { const files = await fs.promises.readdir(directory); @@ -14,62 +17,79 @@ exports.summaries = async (directory) => { if (!results[key]?.scripting) { results[key].scripting = []; } - results[key].scripting.push(content[key].summary.scripting); + results[key].scripting.push( + parseFloat(content[key].summary.scripting.toFixed(2)), + ); if (!results[key]?.painting) { results[key].painting = []; } - results[key].painting.push(content[key].summary.painting); + results[key].painting.push( + parseFloat(content[key].summary.painting.toFixed(2)), + ); if (!results[key]?.rendering) { results[key].rendering = []; } - results[key].rendering.push(content[key].summary.rendering); + results[key].rendering.push( + parseFloat(content[key].summary.rendering.toFixed(2)), + ); }); } }); - generateReport(results); + generateMarkdown(results); }; -const generateReport = (results) => { - var size = 5; +const getMaxSize = (results) => { + let size = 0; 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); - }); + size = Math.max(action["scripting"].length, size); }); - generateMarkdown(results, size); + return size; }; -const generateMarkdown = (results, size = 5) => { +const generateMarkdown = (results) => { + const size = getMaxSize(results); let markdown = `
Click to view performance test results\n\n| `; for (let i = 0; i < size; i++) { - markdown = markdown + `| Run #${i + 1} `; + markdown = markdown + `| Run ${i + 1} `; } - markdown = markdown + `| Avg `; + markdown = markdown + `| Mean | SD.Sample | SD.Population`; markdown += "|\n"; - for (let i = 0; i <= size + 1; i++) { + for (let i = 0; i <= size + 3; i++) { markdown = markdown + `| ------------- `; } markdown += "|\n"; Object.keys(results).forEach((key) => { const action = results[key]; - markdown = markdown + key; + markdown += `**${key}**`; for (let i = 0; i <= size; i++) { - markdown = markdown + `| `; + markdown += `| `; } markdown += "|\n"; + Object.keys(action).forEach((key) => { + const length = action[key].length; markdown += `| ${key} | `; markdown += action[key].reduce((sum, val) => `${sum} | ${val} `); + if (length < size) { + for (let i = 0; i < size - action[key].length; i++) { + markdown += " | "; + } + } + // Add average + const avg = parseFloat( + (action[key].reduce((sum, val) => sum + val, 0) / length).toFixed(2), + ); + markdown += `| ${avg} | ${((sd.sample(action[key]) / avg) * 100).toFixed( + 2, + )} | ${((sd.population(action[key]) / avg) * 100).toFixed(2)}`; + markdown += "| \n"; }); }); diff --git a/app/client/perf/utils/utils.js b/app/client/perf/src/utils/utils.js similarity index 85% rename from app/client/perf/utils/utils.js rename to app/client/perf/src/utils/utils.js index fb23b499f7..995ffd6a83 100644 --- a/app/client/perf/utils/utils.js +++ b/app/client/perf/src/utils/utils.js @@ -40,7 +40,7 @@ exports.startReactProfile = async (reactProfiler) => { "#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"); + console.log("Starting recording"); await reactProfiler.evaluate((el) => el.click(), container); console.log("Recording started"); }; @@ -61,7 +61,7 @@ exports.downloadReactProfile = async (reactProfiler) => { await reactProfiler.waitForSelector(saveProfileButton); const container = await reactProfiler.$(saveProfileButton); await reactProfiler.evaluate((el) => el.click(), container); - console.log("Downlaoded the profile"); + console.log("Downloaded the profile"); }; exports.saveProfile = async (reactProfiler, name) => { @@ -92,7 +92,7 @@ exports.login = async (page) => { const url = "https://dev.appsmith.com/user/login"; await page.goto(url); - await page.setViewport({ width: 1440, height: 714 }); + await page.setViewport({ width: 1920, height: 1080 }); await delay(1000, "before login"); @@ -100,23 +100,12 @@ exports.login = async (page) => { 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.waitForSelector(emailSelector); + await page.waitForSelector(passwordSelector); + await page.waitForSelector(buttonSelector); - await page.type(emailSelector, process.env.CYPRESS_TESTUSERNAME1); - await page.type(passwordSelector, process.env.CYPRESS_TESTPASSWORD1); + await page.type(emailSelector, "hello@myemail.com"); + await page.type(passwordSelector, "qwerty1234"); delay(1000, "before clicking login button"); await page.click(buttonSelector); }; diff --git a/app/client/perf/start-test.sh b/app/client/perf/start-test.sh index 82ce50eb92..28f0fd4bbc 100644 --- a/app/client/perf/start-test.sh +++ b/app/client/perf/start-test.sh @@ -1 +1 @@ -node index.js +node ./src/index.js diff --git a/app/client/perf/tests/dsl/ImportTest.json b/app/client/perf/tests/dsl/ImportTest.json new file mode 100644 index 0000000000..f39bc90aec --- /dev/null +++ b/app/client/perf/tests/dsl/ImportTest.json @@ -0,0 +1 @@ +{"exportedApplication":{"name":"ImportTest","isPublic":false,"appIsExample":false,"unreadCommentThreads":0,"color":"#F4FFDE","icon":"email","slug":"importtest","evaluationVersion":2,"new":true},"datasourceList":[],"pageList":[{"userPermissions":["read:pages","manage:pages"],"gitSyncId":"61c2bbdf7f07823aaeee800f_61c2bbdf7f07823aaeee8011","unpublishedPage":{"name":"Page1","slug":"page1","layouts":[{"id":"Page1","userPermissions":[],"dsl":{"widgetName":"MainContainer","backgroundColor":"none","rightColumn":1432,"snapColumns":64,"detachFromLayout":true,"widgetId":"0","topRow":0,"bottomRow":1290,"containerStyle":"none","snapRows":125,"parentRowSpace":1,"type":"CANVAS_WIDGET","canExtend":true,"version":47,"minHeight":1292,"parentColumnSpace":1,"dynamicBindingPathList":[],"leftColumn":0,"children":[{"widgetName":"Table1","defaultPageSize":0,"columnOrder":["id","userId","title","body"],"isVisibleDownload":true,"dynamicPropertyPathList":[],"displayName":"Table","iconSVG":"/static/media/icon.db8a9cbd.svg","topRow":0,"bottomRow":51,"isSortable":true,"parentRowSpace":10,"type":"TABLE_WIDGET","defaultSelectedRow":"0","hideCard":false,"animateLoading":true,"parentColumnSpace":22.1875,"dynamicTriggerPathList":[{"key":"onRowSelected"}],"dynamicBindingPathList":[{"key":"tableData"},{"key":"primaryColumns.userId.computedValue"},{"key":"primaryColumns.id.computedValue"},{"key":"primaryColumns.title.computedValue"},{"key":"primaryColumns.body.computedValue"}],"leftColumn":0,"primaryColumns":{"userId":{"index":0,"width":150,"id":"userId","horizontalAlignment":"LEFT","verticalAlignment":"CENTER","columnType":"text","textSize":"PARAGRAPH","enableFilter":true,"enableSort":true,"isVisible":true,"isDisabled":false,"isCellVisible":true,"isDerived":false,"label":"userId","computedValue":"{{Table1.sanitizedTableData.map((currentRow) => ( currentRow.userId))}}"},"id":{"index":1,"width":150,"id":"id","horizontalAlignment":"LEFT","verticalAlignment":"CENTER","columnType":"text","textSize":"PARAGRAPH","enableFilter":true,"enableSort":true,"isVisible":true,"isDisabled":false,"isCellVisible":true,"isDerived":false,"label":"id","computedValue":"{{Table1.sanitizedTableData.map((currentRow) => ( currentRow.id))}}"},"title":{"index":2,"width":150,"id":"title","horizontalAlignment":"LEFT","verticalAlignment":"CENTER","columnType":"text","textSize":"PARAGRAPH","enableFilter":true,"enableSort":true,"isVisible":true,"isDisabled":false,"isCellVisible":true,"isDerived":false,"label":"title","computedValue":"{{Table1.sanitizedTableData.map((currentRow) => ( currentRow.title))}}"},"body":{"index":3,"width":150,"id":"body","horizontalAlignment":"LEFT","verticalAlignment":"CENTER","columnType":"text","textSize":"PARAGRAPH","enableFilter":true,"enableSort":true,"isVisible":true,"isDisabled":false,"isCellVisible":true,"isDerived":false,"label":"body","computedValue":"{{Table1.sanitizedTableData.map((currentRow) => ( currentRow.body))}}"}},"delimiter":",","onRowSelected":"{{Comments.run()}}","key":"n0pj8z97ep","derivedColumns":{},"rightColumn":38,"textSize":"PARAGRAPH","widgetId":"zjf167vmt5","isVisibleFilters":true,"tableData":"{{Posts.data}}","isVisible":true,"label":"Data","searchKey":"","enableClientSideSearch":true,"version":3,"totalRecordsCount":0,"parentId":"0","renderMode":"CANVAS","isLoading":false,"horizontalAlignment":"LEFT","isVisibleSearch":true,"isVisiblePagination":true,"verticalAlignment":"CENTER","columnSizeMap":{"task":245,"step":62,"status":75,"id":60,"userId":63}},{"widgetName":"Table2","defaultPageSize":0,"columnOrder":["postId","id","name","email","body"],"isVisibleDownload":true,"dynamicPropertyPathList":[],"displayName":"Table","iconSVG":"/static/media/icon.db8a9cbd.svg","topRow":4,"bottomRow":49,"isSortable":true,"parentRowSpace":10,"type":"TABLE_WIDGET","defaultSelectedRow":"0","hideCard":false,"animateLoading":true,"parentColumnSpace":22.1875,"dynamicTriggerPathList":[],"dynamicBindingPathList":[{"key":"tableData"},{"key":"primaryColumns.postId.computedValue"},{"key":"primaryColumns.id.computedValue"},{"key":"primaryColumns.name.computedValue"},{"key":"primaryColumns.email.computedValue"},{"key":"primaryColumns.body.computedValue"}],"leftColumn":38,"primaryColumns":{"postId":{"index":0,"width":150,"id":"postId","horizontalAlignment":"LEFT","verticalAlignment":"CENTER","columnType":"text","textSize":"PARAGRAPH","enableFilter":true,"enableSort":true,"isVisible":true,"isDisabled":false,"isCellVisible":true,"isDerived":false,"label":"postId","computedValue":"{{Table2.sanitizedTableData.map((currentRow) => ( currentRow.postId))}}"},"id":{"index":1,"width":150,"id":"id","horizontalAlignment":"LEFT","verticalAlignment":"CENTER","columnType":"text","textSize":"PARAGRAPH","enableFilter":true,"enableSort":true,"isVisible":true,"isDisabled":false,"isCellVisible":true,"isDerived":false,"label":"id","computedValue":"{{Table2.sanitizedTableData.map((currentRow) => ( currentRow.id))}}"},"name":{"index":2,"width":150,"id":"name","horizontalAlignment":"LEFT","verticalAlignment":"CENTER","columnType":"text","textSize":"PARAGRAPH","enableFilter":true,"enableSort":true,"isVisible":true,"isDisabled":false,"isCellVisible":true,"isDerived":false,"label":"name","computedValue":"{{Table2.sanitizedTableData.map((currentRow) => ( currentRow.name))}}"},"email":{"index":3,"width":150,"id":"email","horizontalAlignment":"LEFT","verticalAlignment":"CENTER","columnType":"text","textSize":"PARAGRAPH","enableFilter":true,"enableSort":true,"isVisible":true,"isDisabled":false,"isCellVisible":true,"isDerived":false,"label":"email","computedValue":"{{Table2.sanitizedTableData.map((currentRow) => ( currentRow.email))}}"},"body":{"index":4,"width":150,"id":"body","horizontalAlignment":"LEFT","verticalAlignment":"CENTER","columnType":"text","textSize":"PARAGRAPH","enableFilter":true,"enableSort":true,"isVisible":true,"isDisabled":false,"isCellVisible":true,"isDerived":false,"label":"body","computedValue":"{{Table2.sanitizedTableData.map((currentRow) => ( currentRow.body))}}"}},"delimiter":",","key":"n0pj8z97ep","derivedColumns":{},"rightColumn":64,"textSize":"PARAGRAPH","widgetId":"yg7bh7rx32","isVisibleFilters":true,"tableData":"{{Comments.data}}","isVisible":true,"label":"Data","searchKey":"","enableClientSideSearch":true,"version":3,"totalRecordsCount":0,"parentId":"0","renderMode":"CANVAS","isLoading":false,"horizontalAlignment":"LEFT","isVisibleSearch":true,"isVisiblePagination":true,"verticalAlignment":"CENTER","columnSizeMap":{"task":245,"step":62,"status":75,"postId":67,"id":60}},{"widgetName":"Text1","displayName":"Text","iconSVG":"/static/media/icon.97c59b52.svg","topRow":0,"bottomRow":4,"parentRowSpace":10,"type":"TEXT_WIDGET","hideCard":false,"animateLoading":true,"parentColumnSpace":22.1875,"dynamicTriggerPathList":[],"leftColumn":38,"dynamicBindingPathList":[{"key":"text"}],"text":"Comments on {{Table1.selectedRow.title}}","key":"cg0sw4ivpy","rightColumn":54,"textAlign":"LEFT","widgetId":"qmerdmwfb9","isVisible":true,"fontStyle":"BOLD","textColor":"#231F20","version":1,"parentId":"0","renderMode":"CANVAS","isLoading":false,"fontSize":"PARAGRAPH"}]},"layoutOnLoadActions":[[{"id":"61c2bc207f07823aaeee8014","name":"Posts","pluginType":"API","jsonPathKeys":[],"timeoutInMillisecond":10000}],[{"id":"61c2bc637f07823aaeee8016","name":"Comments","pluginType":"API","jsonPathKeys":["Table1.selectedRow.id"],"timeoutInMillisecond":10000}]],"new":false}],"userPermissions":[]},"publishedPage":{"name":"Page1","slug":"page1","layouts":[{"id":"Page1","userPermissions":[],"dsl":{"widgetName":"MainContainer","backgroundColor":"none","rightColumn":1224,"snapColumns":16,"detachFromLayout":true,"widgetId":"0","topRow":0,"bottomRow":1254,"containerStyle":"none","snapRows":33,"parentRowSpace":1,"type":"CANVAS_WIDGET","canExtend":true,"version":4,"minHeight":1292,"parentColumnSpace":1,"dynamicBindingPathList":[],"leftColumn":0,"children":[]},"new":false}],"userPermissions":[]},"new":true}],"publishedDefaultPageName":"Page1","unpublishedDefaultPageName":"Page1","actionList":[{"id":"61c2bc207f07823aaeee8014","userPermissions":["read:actions","execute:actions","manage:actions"],"gitSyncId":"61c2bbdf7f07823aaeee800f_61c2bc207f07823aaeee8013","pluginType":"API","pluginId":"restapi-plugin","unpublishedAction":{"name":"Posts","datasource":{"userPermissions":[],"name":"DEFAULT_REST_DATASOURCE","pluginId":"restapi-plugin","datasourceConfiguration":{"url":"http://jsonplaceholder.typicode.com"},"invalids":[],"messages":[],"isValid":true,"new":true},"pageId":"Page1","actionConfiguration":{"timeoutInMillisecond":10000,"paginationType":"NONE","path":"/posts","headers":[],"encodeParamsToggle":true,"queryParameters":[],"body":"","httpMethod":"GET","pluginSpecifiedTemplates":[{"value":true}]},"executeOnLoad":true,"dynamicBindingPathList":[],"isValid":true,"invalids":[],"messages":[],"jsonPathKeys":[],"confirmBeforeExecute":false,"userPermissions":[],"validName":"Posts"},"publishedAction":{"datasource":{"userPermissions":[],"messages":[],"isValid":true,"new":true},"messages":[],"confirmBeforeExecute":false,"userPermissions":[]},"new":false},{"id":"61c2bc637f07823aaeee8016","userPermissions":["read:actions","execute:actions","manage:actions"],"gitSyncId":"61c2bbdf7f07823aaeee800f_61c2bc637f07823aaeee8015","pluginType":"API","pluginId":"restapi-plugin","unpublishedAction":{"name":"Comments","datasource":{"userPermissions":[],"name":"DEFAULT_REST_DATASOURCE","pluginId":"restapi-plugin","datasourceConfiguration":{"url":"http://jsonplaceholder.typicode.com"},"invalids":[],"messages":[],"isValid":true,"new":true},"pageId":"Page1","actionConfiguration":{"timeoutInMillisecond":10000,"paginationType":"NONE","path":"/comments","headers":[],"encodeParamsToggle":true,"queryParameters":[{"key":"postId","value":"{{Table1.selectedRow.id}}"}],"body":"","httpMethod":"GET","pluginSpecifiedTemplates":[{"value":true}]},"executeOnLoad":true,"dynamicBindingPathList":[{"key":"path"},{"key":"queryParameters[0].value"}],"isValid":true,"invalids":[],"messages":[],"jsonPathKeys":["Table1.selectedRow.id"],"confirmBeforeExecute":false,"userPermissions":[],"validName":"Comments"},"publishedAction":{"datasource":{"userPermissions":[],"messages":[],"isValid":true,"new":true},"messages":[],"confirmBeforeExecute":false,"userPermissions":[]},"new":false}],"actionCollectionList":[],"decryptedFields":{},"publishedLayoutmongoEscapedWidgets":{},"unpublishedLayoutmongoEscapedWidgets":{}} \ No newline at end of file diff --git a/app/client/perf/dsl/simple-typing.js b/app/client/perf/tests/dsl/simple-typing.js similarity index 100% rename from app/client/perf/dsl/simple-typing.js rename to app/client/perf/tests/dsl/simple-typing.js diff --git a/app/client/perf/tests/import-application.perf.js b/app/client/perf/tests/import-application.perf.js new file mode 100644 index 0000000000..4c633be545 --- /dev/null +++ b/app/client/perf/tests/import-application.perf.js @@ -0,0 +1,30 @@ +const path = require("path"); +const Perf = require("../src/perf.js"); +var fs = require("fs"); +const { delay } = require("../src/utils/utils"); + +process.env["NODE_TLS_REJECT_UNAUTHORIZED"] = 0; + +async function importApplication() { + const perf = new Perf(); + + await perf.launch(); + const page = perf.getPage(); + await perf.importApplication(`${APP_ROOT}/tests/dsl/ImportTest.json`); + await page.waitForSelector("#tablezjf167vmt5 div.tr:nth-child(4)"); + await perf.startTrace("Click on table row"); + await page.click("#tablezjf167vmt5 div.tr:nth-child(4)"); + await delay(3000); + await perf.stopTrace(); + await perf.generateReport(); + + perf.close(); +} +async function runTests() { + await importApplication(); + await importApplication(); + await importApplication(); + await importApplication(); + await importApplication(); +} +runTests(); diff --git a/app/client/perf/tests/initial-setup.js b/app/client/perf/tests/initial-setup.js new file mode 100644 index 0000000000..0ed80ac370 --- /dev/null +++ b/app/client/perf/tests/initial-setup.js @@ -0,0 +1,43 @@ +const puppeteer = require("puppeteer"); + +process.env["NODE_TLS_REJECT_UNAUTHORIZED"] = 0; + +(async () => { + const browser = await puppeteer.launch({ + args: ["--window-size=1920,1080"], + ignoreHTTPSErrors: true, + }); + let page = await browser.newPage(); + await page.goto("https://dev.appsmith.com/setup/welcome"); + // await page.goto("http://localhost/setup/welcome"); + // Since we are not testing the initial setup, just send the post request directly. + // Could be moved to bash script as well. + await page.evaluate(async () => { + const url = "https://dev.appsmith.com/api/v1/users/super"; + // const url = "http://localhost/api/v1/users/super"; + await fetch(url, { + headers: { + accept: + "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", + "accept-language": "en-US,en;q=0.9,fr-CA;q=0.8,fr;q=0.7", + "cache-control": "no-cache", + "content-type": "application/x-www-form-urlencoded", + }, + + referrerPolicy: "strict-origin-when-cross-origin", + body: + "name=Im+Puppeteer&email=hello%40myemail.com&password=qwerty1234&allowCollectingAnonymousData=true&signupForNewsletter=true&role=engineer&useCase=just+exploring", + method: "POST", + 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); + }); + }); + console.log("Initial setup is successful"); + await browser.close(); +})(); diff --git a/app/client/perf/index.js b/app/client/perf/tests/typing.perf.js similarity index 66% rename from app/client/perf/index.js rename to app/client/perf/tests/typing.perf.js index 58fe3755e3..c95ce49bed 100644 --- a/app/client/perf/index.js +++ b/app/client/perf/tests/typing.perf.js @@ -1,24 +1,11 @@ const path = require("path"); -const Perf = require("./perf.js"); +const Perf = require("../src/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 - }); + const perf = new Perf(); await perf.launch(); const page = perf.getPage(); await perf.loadDSL(dsl); @@ -50,6 +37,5 @@ async function runTests() { await testTyping(); await testTyping(); await testTyping(); - summaries(`${APP_ROOT}/traces/reports`); } runTests(); diff --git a/app/client/perf/yarn.lock b/app/client/perf/yarn.lock index 97aa4b264c..c63ab40a83 100644 --- a/app/client/perf/yarn.lock +++ b/app/client/perf/yarn.lock @@ -185,6 +185,11 @@ locate-path@^5.0.0: dependencies: p-locate "^4.1.0" +lodash@^4.17.2: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + minimatch@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" @@ -209,6 +214,13 @@ node-fetch@2.6.5: dependencies: whatwg-url "^5.0.0" +node-stdev@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/node-stdev/-/node-stdev-1.0.1.tgz#7a4ba4ae44123683b9f4f06a25e0ec88b1ff1c54" + integrity sha1-ekukrkQSNoO59PBqJeDsiLH/HFQ= + dependencies: + lodash "^4.17.2" + 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" @@ -314,6 +326,13 @@ safe-buffer@~5.2.0: resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== +sanitize-filename@^1.6.3: + version "1.6.3" + resolved "https://registry.yarnpkg.com/sanitize-filename/-/sanitize-filename-1.6.3.tgz#755ebd752045931977e30b2025d340d7c9090378" + integrity sha512-y/52Mcy7aw3gRm7IrcGDFx/bCk4AhRh2eI9luHOQM86nZsqwiRkkq2GekHXBBD+SmPidc8i2PqtYZl+pWJ8Oeg== + dependencies: + truncate-utf8-bytes "^1.0.0" + string_decoder@^1.1.1: version "1.3.0" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" @@ -357,6 +376,13 @@ tracelib@^1.0.1: resolved "https://registry.yarnpkg.com/tracelib/-/tracelib-1.0.1.tgz#bb44ea96c19b8d7a6c85a6ee1cac9945c5b75c64" integrity sha512-T2Vkpa/7Vdm3sV8nXRn8vZ0tnq6wlnO4Zx7Pux+JA1W6DMlg5EtbNcPZu/L7XRTPc9S0eAKhEFR4p/u0GcsDpQ== +truncate-utf8-bytes@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz#405923909592d56f78a5818434b0b78489ca5f2b" + integrity sha1-QFkjkJWS1W94pYGENLC3hInKXys= + dependencies: + utf8-byte-length "^1.0.1" + unbzip2-stream@1.4.3: version "1.4.3" resolved "https://registry.yarnpkg.com/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz#b0da04c4371311df771cdc215e87f2130991ace7" @@ -365,6 +391,11 @@ unbzip2-stream@1.4.3: buffer "^5.2.1" through "^2.3.8" +utf8-byte-length@^1.0.1: + version "1.0.4" + resolved "https://registry.yarnpkg.com/utf8-byte-length/-/utf8-byte-length-1.0.4.tgz#f45f150c4c66eee968186505ab93fcbb8ad6bf61" + integrity sha1-9F8VDExm7uloGGUFq5P8u4rWv2E= + util-deprecate@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"