From f595112b38c40e1cea6ab242e6466e67d3a1b1b6 Mon Sep 17 00:00:00 2001 From: Mitch-Budibase Date: Fri, 1 Apr 2022 11:31:18 +0100 Subject: [PATCH 1/5] Updating tests to work with test Env I've made some changes to the tests and commands file to allow for the tests to run within the Test env after the latest round of UI changes. Some of these changes also allow for testing instances in which apps already exist - This is specific for the test env, the CI runs always have a clean instance --- .../changeAppIconAndColour.spec.js | 4 - .../cypress/integration/createApp.spec.js | 78 ++++++++++++------- .../cypress/integration/createTable.spec.js | 4 - .../integration/createUserAndRoles.spec.js | 9 ++- .../cypress/integration/createView.spec.js | 1 - .../integration/datasources/rest.spec.js | 1 - .../queryLevelTransformers.spec.js | 3 +- .../integration/renameAnApplication.spec.js | 6 +- packages/builder/cypress/support/commands.js | 45 +++++++---- 9 files changed, 86 insertions(+), 65 deletions(-) diff --git a/packages/builder/cypress/integration/changeAppIconAndColour.spec.js b/packages/builder/cypress/integration/changeAppIconAndColour.spec.js index bd532aa3fb..0db2d49e3f 100644 --- a/packages/builder/cypress/integration/changeAppIconAndColour.spec.js +++ b/packages/builder/cypress/integration/changeAppIconAndColour.spec.js @@ -6,10 +6,6 @@ filterTests(['all'], () => { cy.login() }) - after(() => { - cy.deleteAllApps() - }) - it("should change the icon and colour for an application", () => { // Search for test application cy.applicationInAppTable("Cypress Tests") diff --git a/packages/builder/cypress/integration/createApp.spec.js b/packages/builder/cypress/integration/createApp.spec.js index 9507f88be9..4867534241 100644 --- a/packages/builder/cypress/integration/createApp.spec.js +++ b/packages/builder/cypress/integration/createApp.spec.js @@ -3,25 +3,32 @@ import filterTests from '../support/filterTests' filterTests(['smoke', 'all'], () => { context("Create an Application", () => { - beforeEach(() => { + before(() => { cy.login() + cy.deleteApp("Cypress Tests") }) - it("should show the new user UI/UX", () => { - cy.visit(`${Cypress.config().baseUrl}/builder`) - cy.get(`[data-cy="create-app-btn"]`).contains('Start from scratch').should("exist") - cy.get(`[data-cy="import-app-btn"]`).should("exist") - - cy.get(".template-category-filters").should("exist") - cy.get(".template-categories").should("exist") - - cy.get(".appTable").should("not.exist") - }) + if (!(Cypress.env("TEST_ENV"))) { + it("should show the new user UI/UX", () => { + cy.visit(`${Cypress.config().baseUrl}/builder`) + cy.get(`[data-cy="create-app-btn"]`).contains('Start from scratch').should("exist") + cy.get(`[data-cy="import-app-btn"]`).should("exist") + + cy.get(".template-category-filters").should("exist") + cy.get(".template-categories").should("exist") + + cy.get(".appTable").should("not.exist") + }) + } it("should provide filterable templates", () => { cy.visit(`${Cypress.config().baseUrl}/builder`) cy.wait(500) + if (Cypress.env("TEST_ENV")) { + cy.get(".spectrum-Button").contains("Templates").click({force: true}) + } + cy.get(".template-category-filters").should("exist") cy.get(".template-categories").should("exist") @@ -39,14 +46,22 @@ filterTests(['smoke', 'all'], () => { cy.visit(`${Cypress.config().baseUrl}/builder`) cy.wait(500) - const appName = "A New App" - - cy.get(`[data-cy="create-app-btn"]`).contains('Start from scratch').click({force: true}) + // Start create app process. If apps already exist, click second button + cy.get(`[data-cy="create-app-btn"]`).click({ force: true }) + cy.request(`${Cypress.config().baseUrl}/api/applications?status=all`) + .its("body") + .then(val => { + if (val.length > 0) { + cy.get(`[data-cy="create-app-btn"]`).click({ force: true }) + } + }) + + const appName = "Cypress Tests" cy.get(".spectrum-Modal").within(() => { //Auto fill cy.get("input").eq(0).type(appName).should("have.value", appName).blur() - cy.get("input").eq(1).should("have.value", "/a-new-app") + cy.get("input").eq(1).should("have.value", "/cypress-tests") cy.get(".spectrum-ButtonGroup").contains("Create app").should('not.be.disabled') //Empty the app url - disabled create @@ -69,8 +84,7 @@ filterTests(['smoke', 'all'], () => { it("should create the first application from scratch", () => { const appName = "Cypress Tests" - cy.deleteApp(appName) - cy.createApp(appName, "This app is used for Cypress testing.") + cy.createApp(appName) cy.visit(`${Cypress.config().baseUrl}/builder`) cy.wait(1000) @@ -83,10 +97,19 @@ filterTests(['smoke', 'all'], () => { cy.visit(`${Cypress.config().baseUrl}/builder`) cy.wait(500) + // Navigate to Create new app section if apps already exist + cy.request(`${Cypress.config().baseUrl}/api/applications?status=all`) + .its("body") + .then(val => { + if (val.length > 0) { + cy.get(`[data-cy="create-app-btn"]`).click({ force: true }) + } + }) + cy.get(".template-category-filters").should("exist") cy.get(".template-categories").should("exist") - //### Select nth template and choose to create? + // Select template cy.get('.template-category').eq(0).within(() => { const card = cy.get('.template-card').eq(0).should("exist"); const cardOverlay = card.get('.template-thumbnail-action-overlay').should("exist") @@ -94,7 +117,7 @@ filterTests(['smoke', 'all'], () => { cardOverlay.get("button").contains("Use template").should("exist").click({force: true}) }) - //### CMD Create app from theme card + // CMD Create app from theme card cy.get(".spectrum-Modal").should('be.visible') const templateName = cy.get(".spectrum-Modal .template-thumbnail-text") @@ -111,27 +134,22 @@ filterTests(['smoke', 'all'], () => { cy.wait(1000) cy.applicationInAppTable(templateNameText) - cy.deleteAllApps() + cy.deleteApp(templateNameText) }); }) it("should display a second application and app filtering", () => { + // Create first app const appName = "Cypress Tests" - cy.deleteApp(appName) - cy.createApp(appName, "This app is used for Cypress testing.") + cy.createApp(appName) cy.visit(`${Cypress.config().baseUrl}/builder`) cy.wait(500) + // Create second app const secondAppName = "Second App Demo" - cy.deleteApp(secondAppName) - - cy.get(`[data-cy="create-app-btn"]`).contains('Create new app').click({force: true}) - cy.wait(500) - cy.url().should('include', '/builder/portal/apps/create') - - cy.createAppFromScratch(secondAppName) + cy.createApp(secondAppName) cy.visit(`${Cypress.config().baseUrl}/builder`) cy.wait(500) @@ -140,7 +158,7 @@ filterTests(['smoke', 'all'], () => { cy.searchForApplication(appName) cy.searchForApplication(secondAppName) - cy.deleteAllApps() + cy.deleteApp(secondAppName) }) }) diff --git a/packages/builder/cypress/integration/createTable.spec.js b/packages/builder/cypress/integration/createTable.spec.js index df6ca5c7ca..81b7c2f045 100644 --- a/packages/builder/cypress/integration/createTable.spec.js +++ b/packages/builder/cypress/integration/createTable.spec.js @@ -7,10 +7,6 @@ filterTests(["smoke", "all"], () => { cy.createTestApp() }) - after(() => { - cy.deleteAllApps() - }) - it("should create a new Table", () => { cy.createTable("dog") cy.wait(1000) diff --git a/packages/builder/cypress/integration/createUserAndRoles.spec.js b/packages/builder/cypress/integration/createUserAndRoles.spec.js index 9c12971bd8..17864dd975 100644 --- a/packages/builder/cypress/integration/createUserAndRoles.spec.js +++ b/packages/builder/cypress/integration/createUserAndRoles.spec.js @@ -4,11 +4,14 @@ filterTests(["smoke", "all"], () => { context("Create a User and Assign Roles", () => { before(() => { cy.login() - cy.visit(`${Cypress.config().baseUrl}/builder`) - cy.wait(500) - cy.createAppFromScratch("Initial App") }) + if (!(Cypress.env("TEST_ENV"))) { + after(() => { + cy.deleteAllApps() + }) + } + it("should create a user", () => { cy.visit(`${Cypress.config().baseUrl}/builder`) cy.wait(1000) diff --git a/packages/builder/cypress/integration/createView.spec.js b/packages/builder/cypress/integration/createView.spec.js index ad21d6afa7..a8c3b03cee 100644 --- a/packages/builder/cypress/integration/createView.spec.js +++ b/packages/builder/cypress/integration/createView.spec.js @@ -4,7 +4,6 @@ filterTests(['smoke', 'all'], () => { context("Create a View", () => { before(() => { cy.login() - cy.deleteAllApps() cy.createTestApp() cy.createTable("data") diff --git a/packages/builder/cypress/integration/datasources/rest.spec.js b/packages/builder/cypress/integration/datasources/rest.spec.js index 7216a13847..a15487c01b 100644 --- a/packages/builder/cypress/integration/datasources/rest.spec.js +++ b/packages/builder/cypress/integration/datasources/rest.spec.js @@ -4,7 +4,6 @@ filterTests(["smoke", "all"], () => { context("REST Datasource Testing", () => { before(() => { cy.login() - cy.deleteAllApps() cy.createTestApp() }) diff --git a/packages/builder/cypress/integration/queryLevelTransformers.spec.js b/packages/builder/cypress/integration/queryLevelTransformers.spec.js index 86aea8eafb..bec0825e70 100644 --- a/packages/builder/cypress/integration/queryLevelTransformers.spec.js +++ b/packages/builder/cypress/integration/queryLevelTransformers.spec.js @@ -4,8 +4,7 @@ filterTests(["smoke", "all"], () => { context("Query Level Transformers", () => { before(() => { cy.login() - cy.deleteAllApps() - cy.createApp("Cypress Tests") + cy.createTestApp() }) it("should write a transformer function", () => { diff --git a/packages/builder/cypress/integration/renameAnApplication.spec.js b/packages/builder/cypress/integration/renameAnApplication.spec.js index 258479b628..ebfc2c3ae6 100644 --- a/packages/builder/cypress/integration/renameAnApplication.spec.js +++ b/packages/builder/cypress/integration/renameAnApplication.spec.js @@ -15,6 +15,7 @@ filterTests(['all'], () => { renameApp(appName, appRename) cy.reload() cy.wait(1000) + cy.searchForApplication(appRename) cy.get(".appTable").find(".title").should("have.length", 1) cy.applicationInAppTable(appRename) // Set app name back to Cypress Tests @@ -52,8 +53,6 @@ filterTests(['all'], () => { cy.reload() cy.wait(1000) cy.applicationInAppTable(appName) - cy.get(".appTable").find(".title").should("have.length", 1) - }) xit("Should create two applications with the same name", () => { @@ -82,7 +81,6 @@ filterTests(['all'], () => { cy.reload() cy.wait(1000) cy.applicationInAppTable(numberName) - cy.get(".appTable").find(".title").should("have.length", 1) cy.reload() cy.wait(1000) renameApp(numberName, specialCharName) @@ -94,7 +92,7 @@ filterTests(['all'], () => { }) const renameApp = (originalName, changedName, published, noName) => { - cy.applicationInAppTable(originalName) + cy.searchForApplication(originalName) cy.request(`${Cypress.config().baseUrl}/api/applications?status=all`) .its("body") .then(val => { diff --git a/packages/builder/cypress/support/commands.js b/packages/builder/cypress/support/commands.js index c45978e026..dee14a92ae 100644 --- a/packages/builder/cypress/support/commands.js +++ b/packages/builder/cypress/support/commands.js @@ -35,9 +35,17 @@ Cypress.Commands.add("login", () => { Cypress.Commands.add("createApp", name => { cy.visit(`${Cypress.config().baseUrl}/builder`) cy.wait(500) - cy.get(`[data-cy="create-app-btn"]`).click({ force: true }) + // If apps already exist + cy.request(`${Cypress.config().baseUrl}/api/applications?status=all`) + .its("body") + .then(val => { + if (val.length > 0) { + cy.get(`[data-cy="create-app-btn"]`).click({ force: true }) + } + }) + cy.get(".spectrum-Modal").within(() => { cy.get("input").eq(0).type(name).should("have.value", name).blur() cy.get(".spectrum-ButtonGroup").contains("Create app").click() @@ -53,23 +61,30 @@ Cypress.Commands.add("deleteApp", name => { .its("body") .then(val => { if (val.length > 0) { - const appId = val.reduce((acc, app) => { - if (name === app.name) { - acc = app.appId + if (Cypress.env("TEST_ENV")) { + cy.searchForApplication(name) + cy.get(".appTable").within(() => { + cy.get(".spectrum-Icon").eq(1).click() + }) + } else { + const appId = val.reduce((acc, app) => { + if (name === app.name) { + acc = app.appId + } + return acc + }, "") + + if (appId == "") { + return } - return acc - }, "") - if (appId == "") { - return + const appIdParsed = appId.split("_").pop() + const actionEleId = `[data-cy=row_actions_${appIdParsed}]` + cy.get(actionEleId).within(() => { + cy.get(".spectrum-Icon").eq(0).click() + }) } - const appIdParsed = appId.split("_").pop() - const actionEleId = `[data-cy=row_actions_${appIdParsed}]` - cy.get(actionEleId).within(() => { - cy.get(".spectrum-Icon").eq(0).click() - }) - cy.get(".spectrum-Menu").then($menu => { if ($menu.text().includes("Unpublish")) { cy.get(".spectrum-Menu").contains("Unpublish").click() @@ -335,8 +350,6 @@ Cypress.Commands.add("searchForApplication", appName => { cy.get("input").eq(0).type(appName) }) }) - // Confirms app exists after search - cy.applicationInAppTable(appName) }) //Assumes there are no others From f3b9a063181a6fb6b908a8363c6df0f863a4a7bc Mon Sep 17 00:00:00 2001 From: Mitch-Budibase Date: Fri, 1 Apr 2022 12:05:31 +0100 Subject: [PATCH 2/5] Adding and increasing wait times surrounding renameAnApplication.spec.js Passes locally but looks like a timing issue when run against the CI. Adding and increasing wait times to hopefully combat this. I will extend further if unsuccessful --- .../builder/cypress/integration/renameAnApplication.spec.js | 1 + packages/builder/cypress/support/commands.js | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/builder/cypress/integration/renameAnApplication.spec.js b/packages/builder/cypress/integration/renameAnApplication.spec.js index ebfc2c3ae6..267492ed8d 100644 --- a/packages/builder/cypress/integration/renameAnApplication.spec.js +++ b/packages/builder/cypress/integration/renameAnApplication.spec.js @@ -92,6 +92,7 @@ filterTests(['all'], () => { }) const renameApp = (originalName, changedName, published, noName) => { + cy.wait(2000) cy.searchForApplication(originalName) cy.request(`${Cypress.config().baseUrl}/api/applications?status=all`) .its("body") diff --git a/packages/builder/cypress/support/commands.js b/packages/builder/cypress/support/commands.js index dee14a92ae..ad801be145 100644 --- a/packages/builder/cypress/support/commands.js +++ b/packages/builder/cypress/support/commands.js @@ -342,7 +342,7 @@ Cypress.Commands.add("addCustomSourceOptions", totalOptions => { //Filters visible with 1 or more Cypress.Commands.add("searchForApplication", appName => { - cy.wait(1000) + cy.wait(2000) // Searches for the app cy.get(".filter").then(() => { cy.get(".spectrum-Textfield").within(() => { From 4ad60322abb569e7e938951156886cef09b7dbfd Mon Sep 17 00:00:00 2001 From: Mitch-Budibase Date: Fri, 1 Apr 2022 13:15:06 +0100 Subject: [PATCH 3/5] Changes to renameAnApplication & createUserAndRoles renameAnApplication - changing the navigation to a direct URL rather than clicking the home logo button createUserAndRoles - Removing the After action (now supports correct flow of tests) --- .../cypress/integration/createUserAndRoles.spec.js | 6 ------ .../cypress/integration/renameAnApplication.spec.js | 9 ++++++--- packages/builder/cypress/support/commands.js | 1 + 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/packages/builder/cypress/integration/createUserAndRoles.spec.js b/packages/builder/cypress/integration/createUserAndRoles.spec.js index 17864dd975..5cd3697e38 100644 --- a/packages/builder/cypress/integration/createUserAndRoles.spec.js +++ b/packages/builder/cypress/integration/createUserAndRoles.spec.js @@ -6,12 +6,6 @@ filterTests(["smoke", "all"], () => { cy.login() }) - if (!(Cypress.env("TEST_ENV"))) { - after(() => { - cy.deleteAllApps() - }) - } - it("should create a user", () => { cy.visit(`${Cypress.config().baseUrl}/builder`) cy.wait(1000) diff --git a/packages/builder/cypress/integration/renameAnApplication.spec.js b/packages/builder/cypress/integration/renameAnApplication.spec.js index 267492ed8d..204d18972e 100644 --- a/packages/builder/cypress/integration/renameAnApplication.spec.js +++ b/packages/builder/cypress/integration/renameAnApplication.spec.js @@ -11,7 +11,8 @@ filterTests(['all'], () => { const appName = "Cypress Tests" const appRename = "Cypress Renamed" // Rename app, Search for app, Confirm name was changed - cy.get(".home-logo").click() + cy.visit(`${Cypress.config().baseUrl}/builder`) + cy.wait(500) renameApp(appName, appRename) cy.reload() cy.wait(1000) @@ -37,7 +38,8 @@ filterTests(['all'], () => { cy.get(".spectrum-Button").contains("Publish").click({ force: true }) }) // Rename app, Search for app, Confirm name was changed - cy.get(".home-logo").click() + cy.visit(`${Cypress.config().baseUrl}/builder`) + cy.wait(500) renameApp(appName, appRename, true) cy.get(".appTable").find(".wrapper").should("have.length", 1) cy.applicationInAppTable(appRename) @@ -45,7 +47,8 @@ filterTests(['all'], () => { it("Should try to rename an application to have no name", () => { const appName = "Cypress Tests" - cy.get(".home-logo").click() + cy.visit(`${Cypress.config().baseUrl}/builder`) + cy.wait(500) renameApp(appName, " ", false, true) cy.wait(500) // Close modal and confirm name has not been changed diff --git a/packages/builder/cypress/support/commands.js b/packages/builder/cypress/support/commands.js index ad801be145..afedeaba49 100644 --- a/packages/builder/cypress/support/commands.js +++ b/packages/builder/cypress/support/commands.js @@ -342,6 +342,7 @@ Cypress.Commands.add("addCustomSourceOptions", totalOptions => { //Filters visible with 1 or more Cypress.Commands.add("searchForApplication", appName => { + cy.visit(`${Cypress.config().baseUrl}/builder`) cy.wait(2000) // Searches for the app cy.get(".filter").then(() => { From b64b5edaa7516b676b32362759d4b5bbf0a9238c Mon Sep 17 00:00:00 2001 From: Mitch-Budibase Date: Fri, 1 Apr 2022 14:37:11 +0100 Subject: [PATCH 4/5] Changing test structure when searching for applications Search functionality is not available when only 1 app exists - Updating to reflect this --- .../integration/renameAnApplication.spec.js | 65 +++++++++---------- packages/builder/cypress/support/commands.js | 23 +++++-- 2 files changed, 46 insertions(+), 42 deletions(-) diff --git a/packages/builder/cypress/integration/renameAnApplication.spec.js b/packages/builder/cypress/integration/renameAnApplication.spec.js index 204d18972e..f4899f98a0 100644 --- a/packages/builder/cypress/integration/renameAnApplication.spec.js +++ b/packages/builder/cypress/integration/renameAnApplication.spec.js @@ -79,7 +79,8 @@ filterTests(['all'], () => { const appName = "Cypress Tests" const numberName = 12345 const specialCharName = "£$%^" - cy.get(".home-logo").click() + cy.visit(`${Cypress.config().baseUrl}/builder`) + cy.wait(500) renameApp(appName, numberName) cy.reload() cy.wait(1000) @@ -95,41 +96,33 @@ filterTests(['all'], () => { }) const renameApp = (originalName, changedName, published, noName) => { - cy.wait(2000) cy.searchForApplication(originalName) - cy.request(`${Cypress.config().baseUrl}/api/applications?status=all`) - .its("body") - .then(val => { - if (val.length > 0) { - cy.get(".appTable") - .within(() => { - cy.get(".spectrum-Icon").eq(1).click() - }) - // Check for when an app is published - if (published == true) { - // Should not have Edit as option, will unpublish app - cy.should("not.have.value", "Edit") - cy.get(".spectrum-Menu").contains("Unpublish").click() - cy.get(".spectrum-Dialog-grid").contains("Unpublish app").click() - cy.get(".appTable > :nth-child(5) > :nth-child(2) > .spectrum-Icon").click() + cy.get(".appTable") + .within(() => { + cy.get(".spectrum-Icon").eq(1).click() + }) + // Check for when an app is published + if (published == true) { + // Should not have Edit as option, will unpublish app + cy.should("not.have.value", "Edit") + cy.get(".spectrum-Menu").contains("Unpublish").click() + cy.get(".spectrum-Dialog-grid").contains("Unpublish app").click() + cy.get(".appTable > :nth-child(5) > :nth-child(2) > .spectrum-Icon").click() + } + cy.contains("Edit").click() + cy.get(".spectrum-Modal") + .within(() => { + if (noName == true) { + cy.get("input").clear() + cy.get(".spectrum-Dialog-grid").click() + .contains("App name must be letters, numbers and spaces only") + return cy } - cy.contains("Edit").click() - cy.get(".spectrum-Modal") - .within(() => { - if (noName == true) { - cy.get("input").clear() - cy.get(".spectrum-Dialog-grid").click() - .contains("App name must be letters, numbers and spaces only") - return cy - } - cy.get("input").clear() - cy.get("input").eq(0).type(changedName).should("have.value", changedName).blur() - cy.get(".spectrum-ButtonGroup").contains("Save").click({ force: true }) - cy.wait(500) - }) - } - }) - - } - }) + cy.get("input").clear() + cy.get("input").eq(0).type(changedName).should("have.value", changedName).blur() + cy.get(".spectrum-ButtonGroup").contains("Save").click({ force: true }) + cy.wait(500) + }) + } + }) }) diff --git a/packages/builder/cypress/support/commands.js b/packages/builder/cypress/support/commands.js index afedeaba49..751449fb07 100644 --- a/packages/builder/cypress/support/commands.js +++ b/packages/builder/cypress/support/commands.js @@ -344,14 +344,25 @@ Cypress.Commands.add("addCustomSourceOptions", totalOptions => { Cypress.Commands.add("searchForApplication", appName => { cy.visit(`${Cypress.config().baseUrl}/builder`) cy.wait(2000) - // Searches for the app - cy.get(".filter").then(() => { - cy.get(".spectrum-Textfield").within(() => { - cy.get("input").eq(0).clear() - cy.get("input").eq(0).type(appName) + + // No app filter functionality if only 1 app exists + cy.request(`${Cypress.config().baseUrl}/api/applications?status=all`) + .its("body") + .then(val => { + if (val.length < 2) { + return + } + else { + // Searches for the app + cy.get(".filter").then(() => { + cy.get(".spectrum-Textfield").within(() => { + cy.get("input").eq(0).clear() + cy.get("input").eq(0).type(appName) + }) + }) + } }) }) -}) //Assumes there are no others Cypress.Commands.add("applicationInAppTable", appName => { From c3447d418ffa2f457ee614e9fb5cf447de99d8f1 Mon Sep 17 00:00:00 2001 From: Mitch-Budibase Date: Fri, 1 Apr 2022 14:41:45 +0100 Subject: [PATCH 5/5] lint --- packages/builder/cypress/support/commands.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/builder/cypress/support/commands.js b/packages/builder/cypress/support/commands.js index 751449fb07..f4ccdcca24 100644 --- a/packages/builder/cypress/support/commands.js +++ b/packages/builder/cypress/support/commands.js @@ -351,8 +351,7 @@ Cypress.Commands.add("searchForApplication", appName => { .then(val => { if (val.length < 2) { return - } - else { + } else { // Searches for the app cy.get(".filter").then(() => { cy.get(".spectrum-Textfield").within(() => { @@ -362,7 +361,7 @@ Cypress.Commands.add("searchForApplication", appName => { }) } }) - }) +}) //Assumes there are no others Cypress.Commands.add("applicationInAppTable", appName => {