diff --git a/.github/workflows/cypress-appbuilder.yml b/.github/workflows/cypress-appbuilder.yml index 67eb0ae432..8f0a20615e 100644 --- a/.github/workflows/cypress-appbuilder.yml +++ b/.github/workflows/cypress-appbuilder.yml @@ -13,16 +13,18 @@ jobs: Cypress-App-Builder: runs-on: ubuntu-22.04 if: | - contains(github.event.pull_request.labels.*.name, 'run-ce-app-builder') || - contains(github.event.pull_request.labels.*.name, 'run-ee-app-builder') || - contains(github.event.pull_request.labels.*.name, 'run-cypress') + contains(github.event.pull_request.labels.*.name, 'run-cypress-app-builder-ce') || + contains(github.event.pull_request.labels.*.name, 'run-cypress-app-builder-ee') || + contains(github.event.pull_request.labels.*.name, 'run-cypress') || + contains(github.event.pull_request.labels.*.name, 'run-cypress-ce') strategy: matrix: edition: >- ${{ - contains(github.event.pull_request.labels.*.name, 'run-ce-app-builder') && fromJson('["ce"]') || - contains(github.event.pull_request.labels.*.name, 'run-ee-app-builder') && fromJson('["ee"]') || + contains(github.event.pull_request.labels.*.name, 'run-cypress-app-builder-ce') && fromJson('["ce"]') || + contains(github.event.pull_request.labels.*.name, 'run-cypress-ce') && fromJson('["ce"]') || + contains(github.event.pull_request.labels.*.name, 'run-cypress-app-builder-ee') && fromJson('["ee"]') || contains(github.event.pull_request.labels.*.name, 'run-cypress') && fromJson('["ce", "ee"]') || fromJson('[]') }} @@ -158,35 +160,35 @@ jobs: name: screenshots-appbuilder-${{ matrix.edition }} path: cypress-tests/cypress/screenshots - Cypress-App-builder-Subpath: - runs-on: ubuntu-22.04 - if: contains(github.event.pull_request.labels.*.name, 'run-cypress') || - contains(github.event.pull_request.labels.*.name, 'run-cypress-app-builder-subpath') + # Cypress-App-builder-Subpath: + # runs-on: ubuntu-22.04 + # if: contains(github.event.pull_request.labels.*.name, 'run-cypress') || + # contains(github.event.pull_request.labels.*.name, 'run-cypress-app-builder-subpath') - steps: - - name: Checkout - uses: actions/checkout@v3 - with: - ref: ${{ github.event.pull_request.head.ref }} + # steps: + # - name: Checkout + # uses: actions/checkout@v3 + # with: + # ref: ${{ github.event.pull_request.head.ref }} - - name: Create Cypress environment file - id: create-json - uses: jsdaniell/create-json@1.1.2 - with: - name: "cypress.env.json" - json: ${{ secrets.CYPRESS_SECRETS }} - dir: "./cypress-tests" + # - name: Create Cypress environment file + # id: create-json + # uses: jsdaniell/create-json@1.1.2 + # with: + # name: "cypress.env.json" + # json: ${{ secrets.CYPRESS_SECRETS }} + # dir: "./cypress-tests" - - name: App Builder subpath - uses: cypress-io/github-action@v5 - with: - working-directory: ./cypress-tests - config: "baseUrl=http://localhost:80/apps/tooljet/" - config-file: cypress-app-builder.config.js + # - name: App Builder subpath + # uses: cypress-io/github-action@v5 + # with: + # working-directory: ./cypress-tests + # config: "baseUrl=http://localhost:80/apps/tooljet/" + # config-file: cypress-app-builder.config.js - - name: Capture Screenshots - uses: actions/upload-artifact@v4 - if: always() - with: - name: screenshots - path: cypress-tests/cypress/screenshots + # - name: Capture Screenshots + # uses: actions/upload-artifact@v4 + # if: always() + # with: + # name: screenshots + # path: cypress-tests/cypress/screenshots diff --git a/.github/workflows/cypress-marketplace.yml b/.github/workflows/cypress-marketplace.yml index 7193798ec4..9ddf476e12 100644 --- a/.github/workflows/cypress-marketplace.yml +++ b/.github/workflows/cypress-marketplace.yml @@ -15,16 +15,18 @@ jobs: runs-on: ubuntu-22.04 if: contains(github.event.pull_request.labels.*.name, 'run-cypress') || - contains(github.event.pull_request.labels.*.name, 'run-ce-cypress-marketplace') || - contains(github.event.pull_request.labels.*.name, 'run-ee-cypress-marketplace') + contains(github.event.pull_request.labels.*.name, 'run-cypress-marketplace-ce') || + contains(github.event.pull_request.labels.*.name, 'run-cypress-marketplace-ee') || + contains(github.event.pull_request.labels.*.name, 'run-cypress-ce') strategy: matrix: edition: >- ${{ contains(github.event.pull_request.labels.*.name, 'run-cypress') && fromJson('["ce", "ee"]') || - contains(github.event.pull_request.labels.*.name, 'run-ce-cypress-marketplace') && fromJson('["ce"]') || - contains(github.event.pull_request.labels.*.name, 'run-ee-cypress-marketplace') && fromJson('["ee"]') || + contains(github.event.pull_request.labels.*.name, 'run-cypress-ce') && fromJson('["ce"]') || + contains(github.event.pull_request.labels.*.name, 'run-cypress-marketplace-ce') && fromJson('["ce"]') || + contains(github.event.pull_request.labels.*.name, 'run-cypress-marketplace-ee') && fromJson('["ee"]') || fromJson('[]') }} diff --git a/.github/workflows/cypress-platform.yml b/.github/workflows/cypress-platform.yml index 0480db39f9..c6a0db4be6 100644 --- a/.github/workflows/cypress-platform.yml +++ b/.github/workflows/cypress-platform.yml @@ -13,15 +13,18 @@ jobs: Cypress-Platform: runs-on: ubuntu-22.04 if: contains(github.event.pull_request.labels.*.name, 'run-cypress') || - contains(github.event.pull_request.labels.*.name, 'run-ce-cypress-platform') || - contains(github.event.pull_request.labels.*.name, 'run-ee-cypress-platform') + contains(github.event.pull_request.labels.*.name, 'run-cypress-platform-ce') || + contains(github.event.pull_request.labels.*.name, 'run-cypress-platform-ee') || + contains(github.event.pull_request.labels.*.name, 'run-cypress-ce') + strategy: matrix: edition: >- ${{ contains(github.event.pull_request.labels.*.name, 'run-cypress') && fromJson('["ce", "ee"]') || - contains(github.event.pull_request.labels.*.name, 'run-ce-cypress-platform') && fromJson('["ce"]') || - contains(github.event.pull_request.labels.*.name, 'run-ee-cypress-platform') && fromJson('["ee"]') || + contains(github.event.pull_request.labels.*.name, 'run-cypress-ce') && fromJson('["ce"]') || + contains(github.event.pull_request.labels.*.name, 'run-cypress-platform-ce') && fromJson('["ce"]') || + contains(github.event.pull_request.labels.*.name, 'run-cypress-platform-ee') && fromJson('["ee"]') || fromJson('[]') }} diff --git a/.github/workflows/render-preview-deploy.yml b/.github/workflows/render-preview-deploy.yml index a8afdd8137..a9dc5aed2c 100644 --- a/.github/workflows/render-preview-deploy.yml +++ b/.github/workflows/render-preview-deploy.yml @@ -170,7 +170,7 @@ jobs: "serviceDetails": { "disk": { "name": "tooljet-ce-pr-${{ env.PR_NUMBER }}-postgresql", - "mountPath": "/data", + "mountPath": "/var/lib/postgresql/13/main", "sizeGB": 10 }, "env": "docker", @@ -283,35 +283,35 @@ jobs: console.log(e) } - - name: Install PostgreSQL client - run: | - sudo apt update - sudo apt install postgresql-client -y + # - name: Install PostgreSQL client + # run: | + # sudo apt update + # sudo apt install postgresql-client -y - - name: Wait after installing PostgreSQL - run: sleep 25 + # - name: Wait after installing PostgreSQL + # run: sleep 25 - - name: Drop PostgreSQL PR databases - env: - PGHOST: ${{ secrets.RENDER_DS_PG_HOST }} - PGPORT: 5432 - PGUSER: ${{ secrets.RENDER_DS_PG_USER }} - PGDATABASE: ${{ env.PR_NUMBER }}-ce - PGTJBDATABASE: ${{ env.PR_NUMBER }}-ce-tjdb - run: | - if PGPASSWORD=${{ secrets.RENDER_DS_PG_PASS }} psql -h $PGHOST -p $PGPORT -U $PGUSER -lqt | cut -d \| -f 1 | grep -qw $PGDATABASE; then - echo "Database $PGDATABASE exists, deleting..." - PGPASSWORD=${{ secrets.RENDER_DS_PG_PASS }} psql -h $PGHOST -p $PGPORT -U $PGUSER -d postgres -c "drop database \"$PGDATABASE\" ;" - else - echo "Database $PGDATABASE does not exist." - fi + # - name: Drop PostgreSQL PR databases + # env: + # PGHOST: ${{ secrets.RENDER_DS_PG_HOST }} + # PGPORT: 5432 + # PGUSER: ${{ secrets.RENDER_DS_PG_USER }} + # PGDATABASE: ${{ env.PR_NUMBER }}-ce + # PGTJBDATABASE: ${{ env.PR_NUMBER }}-ce-tjdb + # run: | + # if PGPASSWORD=${{ secrets.RENDER_DS_PG_PASS }} psql -h $PGHOST -p $PGPORT -U $PGUSER -lqt | cut -d \| -f 1 | grep -qw $PGDATABASE; then + # echo "Database $PGDATABASE exists, deleting..." + # PGPASSWORD=${{ secrets.RENDER_DS_PG_PASS }} psql -h $PGHOST -p $PGPORT -U $PGUSER -d postgres -c "drop database \"$PGDATABASE\" ;" + # else + # echo "Database $PGDATABASE does not exist." + # fi - if PGPASSWORD=${{ secrets.RENDER_DS_PG_PASS }} psql -h $PGHOST -p $PGPORT -U $PGUSER -lqt | cut -d \| -f 1 | grep -qw $PGTJBDATABASE; then - echo "Database $PGTJBDATABASE exists, deleting..." - PGPASSWORD=${{ secrets.RENDER_DS_PG_PASS }} psql -h $PGHOST -p $PGPORT -U $PGUSER -d postgres -c "drop database \"$PGTJBDATABASE\" ;" - else - echo "Database $PGTJBDATABASE does not exist." - fi + # if PGPASSWORD=${{ secrets.RENDER_DS_PG_PASS }} psql -h $PGHOST -p $PGPORT -U $PGUSER -lqt | cut -d \| -f 1 | grep -qw $PGTJBDATABASE; then + # echo "Database $PGTJBDATABASE exists, deleting..." + # PGPASSWORD=${{ secrets.RENDER_DS_PG_PASS }} psql -h $PGHOST -p $PGPORT -U $PGUSER -d postgres -c "drop database \"$PGTJBDATABASE\" ;" + # else + # echo "Database $PGTJBDATABASE does not exist." + # fi suspend-ce-review-app: if: ${{ github.event.action == 'labeled' && github.event.label.name == 'suspend-ce-review-app' }} @@ -321,7 +321,7 @@ jobs: - name: Suspend service run: | export SERVICE_ID=$(curl --request GET \ - --url 'https://api.render.com/v1/services?name=ToolJet%20PR%20%23${{ env.PR_NUMBER }}&limit=1' \ + --url 'https://api.render.com/v1/services?name=ToolJet%20CE%20PR%20%23${{ env.PR_NUMBER }}&limit=1' \ --header 'accept: application/json' \ --header 'authorization: Bearer ${{ secrets.RENDER_API_KEY }}' | \ jq -r '.[0].service.id') @@ -353,7 +353,7 @@ jobs: - name: Resume service run: | export SERVICE_ID=$(curl --request GET \ - --url 'https://api.render.com/v1/services?name=ToolJet%20PR%20%23${{ env.PR_NUMBER }}&limit=1' \ + --url 'https://api.render.com/v1/services?name=ToolJet%20CE%20PR%20%23${{ env.PR_NUMBER }}&limit=1' \ --header 'accept: application/json' \ --header 'authorization: Bearer ${{ secrets.RENDER_API_KEY }}' | \ jq -r '.[0].service.id') @@ -542,7 +542,7 @@ jobs: "serviceDetails": { "disk": { "name": "tooljet-ee-pr-${{ env.PR_NUMBER }}-postgresql", - "mountPath": "/data", + "mountPath": "/var/lib/postgresql/13/main", "sizeGB": 10 }, "env": "docker", @@ -655,35 +655,35 @@ jobs: console.log(e) } - - name: Install PostgreSQL client - run: | - sudo apt update - sudo apt install postgresql-client -y + # - name: Install PostgreSQL client + # run: | + # sudo apt update + # sudo apt install postgresql-client -y - - name: Wait after installing PostgreSQL - run: sleep 25 + # - name: Wait after installing PostgreSQL + # run: sleep 25 - - name: Drop PostgreSQL PR databases - env: - PGHOST: ${{ secrets.RENDER_DS_PG_HOST }} - PGPORT: 5432 - PGUSER: ${{ secrets.RENDER_DS_PG_USER }} - PGDATABASE: ${{ env.PR_NUMBER }}-ee - PGTJBDATABASE: ${{ env.PR_NUMBER }}-ee-tjdb - run: | - if PGPASSWORD=${{ secrets.RENDER_DS_PG_PASS }} psql -h $PGHOST -p $PGPORT -U $PGUSER -lqt | cut -d \| -f 1 | grep -qw $PGDATABASE; then - echo "Database $PGDATABASE exists, deleting..." - PGPASSWORD=${{ secrets.RENDER_DS_PG_PASS }} psql -h $PGHOST -p $PGPORT -U $PGUSER -d postgres -c "drop database \"$PGDATABASE\" ;" - else - echo "Database $PGDATABASE does not exist." - fi + # - name: Drop PostgreSQL PR databases + # env: + # PGHOST: ${{ secrets.RENDER_DS_PG_HOST }} + # PGPORT: 5432 + # PGUSER: ${{ secrets.RENDER_DS_PG_USER }} + # PGDATABASE: ${{ env.PR_NUMBER }}-ee + # PGTJBDATABASE: ${{ env.PR_NUMBER }}-ee-tjdb + # run: | + # if PGPASSWORD=${{ secrets.RENDER_DS_PG_PASS }} psql -h $PGHOST -p $PGPORT -U $PGUSER -lqt | cut -d \| -f 1 | grep -qw $PGDATABASE; then + # echo "Database $PGDATABASE exists, deleting..." + # PGPASSWORD=${{ secrets.RENDER_DS_PG_PASS }} psql -h $PGHOST -p $PGPORT -U $PGUSER -d postgres -c "drop database \"$PGDATABASE\" ;" + # else + # echo "Database $PGDATABASE does not exist." + # fi - if PGPASSWORD=${{ secrets.RENDER_DS_PG_PASS }} psql -h $PGHOST -p $PGPORT -U $PGUSER -lqt | cut -d \| -f 1 | grep -qw $PGTJBDATABASE; then - echo "Database $PGTJBDATABASE exists, deleting..." - PGPASSWORD=${{ secrets.RENDER_DS_PG_PASS }} psql -h $PGHOST -p $PGPORT -U $PGUSER -d postgres -c "drop database \"$PGTJBDATABASE\" ;" - else - echo "Database $PGTJBDATABASE does not exist." - fi + # if PGPASSWORD=${{ secrets.RENDER_DS_PG_PASS }} psql -h $PGHOST -p $PGPORT -U $PGUSER -lqt | cut -d \| -f 1 | grep -qw $PGTJBDATABASE; then + # echo "Database $PGTJBDATABASE exists, deleting..." + # PGPASSWORD=${{ secrets.RENDER_DS_PG_PASS }} psql -h $PGHOST -p $PGPORT -U $PGUSER -d postgres -c "drop database \"$PGTJBDATABASE\" ;" + # else + # echo "Database $PGTJBDATABASE does not exist." + # fi suspend-ee-review-app: if: ${{ github.event.action == 'labeled' && github.event.label.name == 'suspend-ee-review-app' }} @@ -693,7 +693,7 @@ jobs: - name: Suspend service run: | export SERVICE_ID=$(curl --request GET \ - --url 'https://api.render.com/v1/services?name=ToolJet%20PR%20%23${{ env.PR_NUMBER }}&limit=1' \ + --url 'https://api.render.com/v1/services?name=ToolJet%20EE%20PR%20%23${{ env.PR_NUMBER }}&limit=1' \ --header 'accept: application/json' \ --header 'authorization: Bearer ${{ secrets.RENDER_API_KEY }}' | \ jq -r '.[0].service.id') @@ -725,7 +725,7 @@ jobs: - name: Resume service run: | export SERVICE_ID=$(curl --request GET \ - --url 'https://api.render.com/v1/services?name=ToolJet%20PR%20%23${{ env.PR_NUMBER }}&limit=1' \ + --url 'https://api.render.com/v1/services?name=ToolJet%20EE%20PR%20%23${{ env.PR_NUMBER }}&limit=1' \ --header 'accept: application/json' \ --header 'authorization: Bearer ${{ secrets.RENDER_API_KEY }}' | \ jq -r '.[0].service.id') diff --git a/cypress-tests/cypress-platform.config.js b/cypress-tests/cypress-platform.config.js index a53733a70d..b565a0c1d1 100644 --- a/cypress-tests/cypress-platform.config.js +++ b/cypress-tests/cypress-platform.config.js @@ -39,11 +39,11 @@ module.exports = defineConfig({ chromeWebSecurity: false, trashAssetsBeforeRuns: true, e2e: { - setupNodeEvents(on, config) { + setupNodeEvents (on, config) { config.baseUrl = environment.baseUrl; on("task", { - readPdf(pathToPdf) { + readPdf (pathToPdf) { return new Promise((resolve) => { const pdfPath = path.resolve(pathToPdf); let dataBuffer = fs.readFileSync(pdfPath); @@ -55,7 +55,7 @@ module.exports = defineConfig({ }); on("task", { - readXlsx(filePath) { + readXlsx (filePath) { return new Promise((resolve, reject) => { try { let dataBuffer = fs.readFileSync(filePath); @@ -69,7 +69,7 @@ module.exports = defineConfig({ }); on("task", { - deleteFolder(folderName) { + deleteFolder (folderName) { return new Promise((resolve, reject) => { rmdir(folderName, { maxRetries: 10, recursive: true }, (err) => { if (err) { @@ -83,7 +83,7 @@ module.exports = defineConfig({ }); on("task", { - dbConnection({ dbconfig, sql }) { + dbConnection ({ dbconfig, sql }) { const client = new pg.Pool(dbconfig); return client.query(sql); }, @@ -97,9 +97,9 @@ module.exports = defineConfig({ baseUrl: environment.baseUrl, configFile: environment.configFile, specPattern: [ - "cypress/e2e/happyPath/platform/ceTestcases/userFlow/firstUserOnboarding.cy.js", - "cypress/e2e/happyPath/platform/commonTestcases/workspace/dashboard.cy.js", - "cypress/e2e/happyPath/platform/ceTestcases/!(userFlow)/**/*.cy.js", + "cypress/e2e/happyPath/platform/firstUser/firstUserOnboarding.cy.js", + "cypress/e2e/happyPath/platform/ceTestcases/apps/appSlug.cy.js", + "cypress/e2e/happyPath/platform/ceTestcases/**/!(*appSlug).cy.js", "cypress/e2e/happyPath/platform/commonTestcases/**/*.cy.js", ], numTestsKeptInMemory: 1, diff --git a/cypress-tests/cypress/commands/commands.js b/cypress-tests/cypress/commands/commands.js index 0acb76c866..d242eb1895 100644 --- a/cypress-tests/cypress/commands/commands.js +++ b/cypress-tests/cypress/commands/commands.js @@ -6,6 +6,7 @@ import { passwordInputText } from "Texts/passwordInput"; import { importSelectors } from "Selectors/exportImport"; import { importText } from "Texts/exportImport"; import { onboardingSelectors } from "Selectors/onboarding"; +import { selectAppCardOption } from "Support/utils/common"; const API_ENDPOINT = Cypress.env("environment") === "Community" @@ -160,12 +161,10 @@ Cypress.Commands.add( Cypress.Commands.add("deleteApp", (appName) => { cy.intercept("DELETE", "/api/apps/*").as("appDeleted"); - cy.get(commonSelectors.appCard(appName)) - .realHover() - .find(commonSelectors.appCardOptionsButton) - .realHover() - .click(); - cy.get(commonSelectors.deleteAppOption).click(); + selectAppCardOption( + appName, + commonSelectors.appCardOptions(commonText.deleteAppOption) + ); cy.get(commonSelectors.buttonSelector(commonText.modalYesButton)).click(); cy.verifyToastMessage( commonSelectors.toastMessage, @@ -227,9 +226,9 @@ Cypress.Commands.add( .invoke("text") .then((text) => { cy.wrap(subject).realType(createBackspaceText(text)), - { - delay: 0, - }; + { + delay: 0, + }; }); } ); @@ -398,39 +397,38 @@ Cypress.Commands.add("getPosition", (componentName) => { }); Cypress.Commands.add("defaultWorkspaceLogin", () => { - cy.apiLogin(); + cy.task("dbConnection", { + dbconfig: Cypress.env("app_db"), + sql: ` + SELECT id FROM organizations WHERE name = 'My workspace';`, + }).then((resp) => { + const workspaceId = resp.rows[0].id; - // cy.intercept("GET", API_ENDPOINT).as("library_apps"); - cy.visit("/my-workspace"); - cy.wait(2000); - cy.get(commonSelectors.homePageLogo, { timeout: 10000 }); - // cy.wait("@library_apps"); + cy.apiLogin( + "dev@tooljet.io", + "password", + workspaceId, + "/my-workspace" + ).then(() => { + cy.visit("/"); + cy.wait(2000); + cy.get(commonSelectors.homePageLogo, { timeout: 10000 }); + }); + }); }); -Cypress.Commands.add( - "visitSlug", - ({ - actualUrl, - errorUrls = [ - `${Cypress.config("baseUrl")}/error/unknown`, - `${Cypress.config("baseUrl")}/error/restricted`, - ], - }) => { - if (!actualUrl) { - throw new Error("actualUrl is required for visitSlug command."); +Cypress.Commands.add("visitSlug", ({ actualUrl }) => { + cy.visit(actualUrl); + cy.wait(1000); + + cy.url().then((currentUrl) => { + if (currentUrl !== actualUrl) { + cy.visit(actualUrl); + cy.wait(1000); } + }); +}); - cy.visit(actualUrl); - - cy.url().then((url) => { - if (errorUrls.includes(url)) { - cy.log(`Navigation resulted in error URL: ${url}. Retrying...`); - cy.visit(actualUrl); - cy.wait(1000); - } - }); - } -); Cypress.Commands.add("releaseApp", () => { if (Cypress.env("environment") !== "Community") { @@ -551,7 +549,7 @@ Cypress.Commands.add("installMarketplacePlugin", (pluginName) => { } }); - function installPlugin(pluginName) { + function installPlugin (pluginName) { cy.get('[data-cy="-list-item"]').eq(1).click(); cy.wait(1000); diff --git a/cypress-tests/cypress/constants/selectors/common.js b/cypress-tests/cypress/constants/selectors/common.js index 42e3378825..ec104d67bc 100644 --- a/cypress-tests/cypress/constants/selectors/common.js +++ b/cypress-tests/cypress/constants/selectors/common.js @@ -6,7 +6,8 @@ export const commonSelectors = { toastMessage: ".go3958317564", oldToastMessage: ".go318386747", appSlugAccept: '[data-cy="app-slug-accepted-label"]', - newToastMessage: '.drawer-container > [style="position: fixed; z-index: 9999; inset: 16px; pointer-events: none;"] > .go4109123758 > .go2072408551 > .go3958317564', + newToastMessage: + '.drawer-container > [style="position: fixed; z-index: 9999; inset: 16px; pointer-events: none;"] > .go4109123758 > .go2072408551 > .go3958317564', toastCloseButton: '[data-cy="toast-close-button"]', editButton: "[data-cy=edit-button]", workspaceConstantNameInput: '[data-cy="name-input-field"]', @@ -18,7 +19,7 @@ export const commonSelectors = { appCardOptionsButton: "[data-cy=app-card-menu-icon]", autoSave: "[data-cy=autosave-indicator]", nameInputFieldd: "[data-cy=name-input-field]", - valueInputFieldd: '[data-cy=value-input-field]', + valueInputFieldd: "[data-cy=value-input-field]", skipButton: ".driver-close-btn", skipInstallationModal: "[data-cy=skip-button]", homePageLogo: "[data-cy=home-page-logo]", @@ -395,7 +396,7 @@ export const commonWidgetSelector = { modalCloseButton: '[data-cy="modal-close-button"]', iframeLinkLabel: '[data-cy="iframe-link-label"]', ifameLinkCopyButton: '[data-cy="iframe-link-copy-button"]', - appSlugLabel: '[data-cy="input-field-label"]', + appSlugLabel: '[data-cy="unique-app-slug-field-label"]', appSlugInput: '[data-cy="app-slug-input-field"]', appSlugInfoLabel: '[data-cy="helper-text"]', appLinkLabel: '[data-cy="app-link-label"]', diff --git a/cypress-tests/cypress/constants/selectors/restAPI.js b/cypress-tests/cypress/constants/selectors/restAPI.js index a24c115712..5ec2d73954 100644 --- a/cypress-tests/cypress/constants/selectors/restAPI.js +++ b/cypress-tests/cypress/constants/selectors/restAPI.js @@ -24,7 +24,7 @@ export const restAPISelector = { return `[data-cy="${cyParamName(header)}-delete-button-${cyParamName(index)}"]`; }, addMoreButton: (header) => { - return `[data-cy="${cyParamName(header)}-add-more-button"]`; + return `[data-cy="${cyParamName(header)}-add-button"]`; }, dropdownLabel: (label) => { return `[data-cy="${cyParamName(label)}-dropdown-label"]`; diff --git a/cypress-tests/cypress/constants/texts/version.js b/cypress-tests/cypress/constants/texts/version.js index 4f640db63a..ed92ea4c29 100644 --- a/cypress-tests/cypress/constants/texts/version.js +++ b/cypress-tests/cypress/constants/texts/version.js @@ -8,11 +8,7 @@ export const editVersionText = { export const deleteVersionText = { deleteModalText: (text) => { - // return `Are you sure you want to delete this version - ${cyParamName( - // text - // )}?`; - - return `Deleting a version will permanently remove it from all environments.Are you sure you want to delete this version - ${cyParamName( + return `Are you sure you want to delete this version - ${cyParamName( text )}?`; }, diff --git a/cypress-tests/cypress/e2e/happyPath/platform/ceTestcases/apps/appExport.cy.js b/cypress-tests/cypress/e2e/happyPath/platform/ceTestcases/apps/appExport.cy.js index e97269cf39..b1f3733c73 100644 --- a/cypress-tests/cypress/e2e/happyPath/platform/ceTestcases/apps/appExport.cy.js +++ b/cypress-tests/cypress/e2e/happyPath/platform/ceTestcases/apps/appExport.cy.js @@ -46,9 +46,7 @@ describe("App Export", () => { }); it("Verify the elements of export dialog box", () => { - cy.window({ log: false }).then((win) => { - win.localStorage.setItem("walkthroughCompleted", "true"); - }); + cy.skipWalkthrough() cy.apiLogin(); cy.visit(`${data.workspaceSlug}`); diff --git a/cypress-tests/cypress/e2e/happyPath/platform/ceTestcases/apps/appImport.cy.js b/cypress-tests/cypress/e2e/happyPath/platform/ceTestcases/apps/appImport.cy.js index a6b068d137..2bd1ccf51e 100644 --- a/cypress-tests/cypress/e2e/happyPath/platform/ceTestcases/apps/appImport.cy.js +++ b/cypress-tests/cypress/e2e/happyPath/platform/ceTestcases/apps/appImport.cy.js @@ -34,6 +34,7 @@ describe("App Import Functionality", () => { cy.apiLogin(); cy.apiCreateWorkspace(data.workspaceName, data.workspaceSlug); cy.apiLogout(); + cy.skipWalkthrough() }); it("should verify app import functionality", () => { @@ -100,12 +101,13 @@ describe("App Import Functionality", () => { .and("have.text", importText.appImportedToastMessage); // Verify imported app - cy.get(".driver-close-btn").click(); + cy.get(commonSelectors.toastCloseButton).click(); cy.wait(500); cy.get(commonSelectors.appNameInput).verifyVisibleElement( "contain.value", "three-versions" ); + cy.get(appVersionSelectors.currentVersionField("v3")).should("be.visible"); // Configure app cy.skipEditorPopover(); diff --git a/cypress-tests/cypress/e2e/happyPath/platform/ceTestcases/apps/appSlug.cy.js b/cypress-tests/cypress/e2e/happyPath/platform/ceTestcases/apps/appSlug.cy.js index b3e3f975dc..b65d54eac6 100644 --- a/cypress-tests/cypress/e2e/happyPath/platform/ceTestcases/apps/appSlug.cy.js +++ b/cypress-tests/cypress/e2e/happyPath/platform/ceTestcases/apps/appSlug.cy.js @@ -27,17 +27,21 @@ describe("App Slug", () => { }); it("Verify app slug cases in global settings", () => { - cy.apiLogin(); const workspaceId = Cypress.env("workspaceId"); const appId = Cypress.env("appId"); + const appUrl = `${host}/${Cypress.env("workspaceId")}/apps/${Cypress.env("appId")}/`; - cy.visit("/my-workspace"); - cy.wait(1000); + cy.apiLogin(); + cy.skipWalkthrough(); - cy.window({ log: false }).then((win) => { - win.localStorage.setItem("walkthroughCompleted", "true"); + cy.visit(appUrl); + cy.url().then((url) => { + if (url !== appUrl) { + cy.visit(appUrl); + } }); - cy.visit(`/${Cypress.env("workspaceId")}/apps/${Cypress.env("appId")}/`); + cy.url().should("eq", appUrl); + cy.wait(1000); cy.get(commonSelectors.leftSideBarSettingsButton).click(); diff --git a/cypress-tests/cypress/e2e/happyPath/platform/ceTestcases/apps/privateAndpublicApps.skip.js b/cypress-tests/cypress/e2e/happyPath/platform/ceTestcases/apps/privateAndpublicApps.cy.js similarity index 96% rename from cypress-tests/cypress/e2e/happyPath/platform/ceTestcases/apps/privateAndpublicApps.skip.js rename to cypress-tests/cypress/e2e/happyPath/platform/ceTestcases/apps/privateAndpublicApps.cy.js index fdd6acfe80..d6483fa400 100644 --- a/cypress-tests/cypress/e2e/happyPath/platform/ceTestcases/apps/privateAndpublicApps.skip.js +++ b/cypress-tests/cypress/e2e/happyPath/platform/ceTestcases/apps/privateAndpublicApps.cy.js @@ -78,11 +78,11 @@ describe("Private and Public apps", { // Test private access logout(); - cy.get(onboardingSelectors.signInButton, { timeout: 20000 }).should("be.visible"); cy.visitSlug({ actualUrl: `${Cypress.config("baseUrl")}/applications/${data.slug}`, }); + cy.get(onboardingSelectors.signInButton, { timeout: 20000 }).should("be.visible"); cy.wait(2000); cy.appUILogin(); @@ -116,6 +116,9 @@ describe("Private and Public apps", { inviteUserToWorkspace(data.firstName, data.email); logout(); + cy.visit("/"); + cy.wait(2000); + cy.get(onboardingSelectors.signInButton, { timeout: 20000 }).should("be.visible"); // Test private access cy.visitSlug({ @@ -141,6 +144,8 @@ describe("Private and Public apps", { cy.wait(1000); cy.apiMakeAppPublic(); logout(); + cy.wait(1000); + cy.get(onboardingSelectors.signInButton, { timeout: 20000 }).should("be.visible"); cy.visitSlug({ actualUrl: `${Cypress.config("baseUrl")}/applications/${data.slug}`, @@ -177,6 +182,9 @@ describe("Private and Public apps", { cy.apiMakeAppPublic(); logout(); + cy.wait(1000); + cy.get(onboardingSelectors.signInButton, { timeout: 20000 }).should("be.visible"); + cy.visitSlug({ actualUrl: `${Cypress.config("baseUrl")}/applications/${data.slug}`, }); @@ -229,6 +237,8 @@ describe("Private and Public apps", { cy.get('[data-cy="viewer-page-logo"]').click(); logout(); + cy.wait(1000); + cy.get(onboardingSelectors.signInButton, { timeout: 20000 }).should("be.visible"); // Setup new workspace and app cy.defaultWorkspaceLogin(); diff --git a/cypress-tests/cypress/e2e/happyPath/platform/ceTestcases/apps/version.skip.js b/cypress-tests/cypress/e2e/happyPath/platform/ceTestcases/apps/version.cy.js similarity index 98% rename from cypress-tests/cypress/e2e/happyPath/platform/ceTestcases/apps/version.skip.js rename to cypress-tests/cypress/e2e/happyPath/platform/ceTestcases/apps/version.cy.js index f97962d910..c0f6064564 100644 --- a/cypress-tests/cypress/e2e/happyPath/platform/ceTestcases/apps/version.skip.js +++ b/cypress-tests/cypress/e2e/happyPath/platform/ceTestcases/apps/version.cy.js @@ -123,7 +123,7 @@ describe("App Version", () => { releasedVersionAndVerify("v2"); }); - it.only("should verify version management with components and queries", () => { + it("should verify version management with components and queries", () => { // Initial setup with component and datasource cy.apiAddComponentToApp( data.appName, diff --git a/cypress-tests/cypress/e2e/happyPath/platform/commonTestcases/workspace/appCreate.skip.js b/cypress-tests/cypress/e2e/happyPath/platform/commonTestcases/workspace/appCreate.cy.js similarity index 100% rename from cypress-tests/cypress/e2e/happyPath/platform/commonTestcases/workspace/appCreate.skip.js rename to cypress-tests/cypress/e2e/happyPath/platform/commonTestcases/workspace/appCreate.cy.js diff --git a/cypress-tests/cypress/e2e/happyPath/platform/commonTestcases/workspace/dashboard.skip.js b/cypress-tests/cypress/e2e/happyPath/platform/commonTestcases/workspace/dashboard.cy.js similarity index 63% rename from cypress-tests/cypress/e2e/happyPath/platform/commonTestcases/workspace/dashboard.skip.js rename to cypress-tests/cypress/e2e/happyPath/platform/commonTestcases/workspace/dashboard.cy.js index 64a05d00c7..fb8e932973 100644 --- a/cypress-tests/cypress/e2e/happyPath/platform/commonTestcases/workspace/dashboard.skip.js +++ b/cypress-tests/cypress/e2e/happyPath/platform/commonTestcases/workspace/dashboard.cy.js @@ -44,6 +44,164 @@ describe("dashboard", () => { cy.visit(`${data.workspaceSlug}`); }); + // it("Should verify app card elements and app card operations", () => { + // const customLayout = { + // desktop: { top: 100, left: 20 }, + // mobile: { width: 8, height: 50 }, + // }; + + // cy.apiCreateApp(data.appName); + // cy.visit(`${data.workspaceSlug}`); + + // cy.wait(2000); + // cy.get(commonSelectors.appCreationDetails).should("be.visible"); + // cy.get(commonSelectors.appCard(data.appName)).should("be.visible"); + // cy.get(commonSelectors.appTitle(data.appName)).verifyVisibleElement( + // "have.text", + // data.appName + // ); + + // viewAppCardOptions(data.appName); + // cy.get( + // commonSelectors.appCardOptions(commonText.changeIconOption) + // ).verifyVisibleElement("have.text", commonText.changeIconOption); + // cy.get( + // commonSelectors.appCardOptions(commonText.addToFolderOption) + // ).verifyVisibleElement("have.text", commonText.addToFolderOption); + // cy.get( + // commonSelectors.appCardOptions(commonText.cloneAppOption) + // ).verifyVisibleElement("have.text", commonText.cloneAppOption); + // cy.get( + // commonSelectors.appCardOptions(commonText.exportAppOption) + // ).verifyVisibleElement("have.text", commonText.exportAppOption); + // cy.get( + // commonSelectors.appCardOptions(commonText.deleteAppOption) + // ).verifyVisibleElement("have.text", commonText.deleteAppOption); + + // modifyAndVerifyAppCardIcon(data.appName); + // createFolder(data.folderName); + + // viewAppCardOptions(data.appName); + // cy.get( + // commonSelectors.appCardOptions(commonText.addToFolderOption) + // ).click(); + // verifyModal( + // dashboardText.addToFolderTitle, + // dashboardText.addToFolderButton, + // dashboardSelector.selectFolder + // ); + // cy.get(dashboardSelector.moveAppText).verifyVisibleElement( + // "have.text", + // dashboardText.moveAppText(data.appName) + // ); + + // cy.get(dashboardSelector.selectFolder).click(); + // cy.get(commonSelectors.folderList).contains(data.folderName).click(); + // cy.get(dashboardSelector.addToFolderButton).click(); + // cy.verifyToastMessage( + // commonSelectors.toastMessage, + // commonText.AddedToFolderToast, + // false + // ); + + // cy.get(dashboardSelector.folderName(data.folderName)).verifyVisibleElement( + // "have.text", + // dashboardText.folderName(`${data.folderName} (1)`) + // ); + + // cy.get(dashboardSelector.folderName(data.folderName)).click(); + // cy.get(commonSelectors.appCard(data.appName)) + // .contains(data.appName) + // .should("be.visible"); + + // viewAppCardOptions(data.appName); + + // cy.get(commonSelectors.appCardOptions(commonText.removeFromFolderOption)) + // .verifyVisibleElement("have.text", commonText.removeFromFolderOption) + // .click(); + // verifyConfirmationModal(commonText.appRemovedFromFolderMessage); + + // cancelModal(commonText.cancelButton); + + // viewAppCardOptions(data.appName); + // cy.get( + // commonSelectors.appCardOptions(commonText.removeFromFolderOption) + // ).click(); + // cy.get(commonSelectors.buttonSelector(commonText.modalYesButton)).click(); + // cy.verifyToastMessage( + // commonSelectors.toastMessage, + // commonText.appRemovedFromFolderTaost, + // false + // ); + // cy.get(commonSelectors.modalComponent).should("not.exist"); + // cy.get(commonSelectors.empytyFolderImage).should("be.visible"); + // cy.get(commonSelectors.emptyFolderText).verifyVisibleElement( + // "have.text", + // commonText.emptyFolderText + // ); + // cy.get(commonSelectors.allApplicationsLink).click(); + // deleteFolder(data.folderName); + + // cy.get(commonSelectors.allApplicationsLink).click(); + + // cy.wait(1000); + // viewAppCardOptions(data.appName); + // cy.wait(2000); + // cy.get(commonSelectors.appCardOptions(commonText.exportAppOption)).click(); + // cy.get(commonSelectors.exportAllButton).click(); + + // cy.exec("ls ./cypress/downloads/").then((result) => { + // const downloadedAppExportFileName = result.stdout.split("\n")[0]; + // expect(downloadedAppExportFileName).to.contain.string("app"); + // }); + + // viewAppCardOptions(data.appName); + // cy.get(commonSelectors.appCardOptions(commonText.cloneAppOption)).click(); + // cy.get('[data-cy="clone-app"]').click(); + // cy.get(".go3958317564") + // .should("be.visible") + // .and("have.text", dashboardText.appClonedToast); + // cy.wait(3000); + + // cy.renameApp(data.cloneAppName); + // cy.apiAddComponentToApp(data.cloneAppName, "button", 25, 25); + // cy.backToApps(); + // cy.wait("@appLibrary"); + // cy.wait(1000); + + // cy.get(commonSelectors.appCard(data.cloneAppName)).should("be.visible"); + + // cy.wait(1000); + + // viewAppCardOptions(data.cloneAppName); + // cy.get(commonSelectors.deleteAppOption).click(); + // cy.get(commonSelectors.modalMessage).verifyVisibleElement( + // "have.text", + // commonText.deleteAppModalMessage(data.cloneAppName) + // ); + // cy.get( + // commonSelectors.buttonSelector(commonText.cancelButton) + // ).verifyVisibleElement("have.text", commonText.cancelButton); + // cy.get( + // commonSelectors.buttonSelector(commonText.modalYesButton) + // ).verifyVisibleElement("have.text", commonText.modalYesButton); + // cancelModal(commonText.cancelButton); + + // viewAppCardOptions(data.cloneAppName); + // cy.get(commonSelectors.deleteAppOption).click(); + // cy.get(commonSelectors.buttonSelector(commonText.modalYesButton)).click(); + // cy.verifyToastMessage( + // commonSelectors.toastMessage, + // commonText.appDeletedToast, + // false + // ); + // verifyAppDelete(data.cloneAppName); + // cy.wait("@appLibrary"); + + // cy.deleteApp(data.appName); + // verifyAppDelete(data.appName); + // }); + it("should verify the elements on empty dashboard", () => { cy.intercept("GET", "/api/metadata", { body: { @@ -171,181 +329,6 @@ describe("dashboard", () => { verifyTooltip(dashboardSelector.modeToggle, "Mode"); }); - it.skip("Should verify app card elements and app card operations", () => { - const customLayout = { - desktop: { top: 100, left: 20 }, - mobile: { width: 8, height: 50 }, - }; - - cy.apiCreateApp(data.appName); - cy.openApp(); - cy.apiAddComponentToApp(data.appName, "text1", customLayout); - - cy.backToApps(); - - cy.wait(500); - cy.get(commonSelectors.appCard(data.appName)) - .parent() - .within(() => { - cy.get(commonSelectors.appCard(data.appName)).should("be.visible"); - cy.get(commonSelectors.appTitle(data.appName)).verifyVisibleElement( - "have.text", - data.appName - ); - cy.get(commonSelectors.appCreationDetails).should("be.visible"); - - //Add the edited details - }); - - viewAppCardOptions(data.appName); - cy.get( - commonSelectors.appCardOptions(commonText.changeIconOption) - ).verifyVisibleElement("have.text", commonText.changeIconOption); - cy.get( - commonSelectors.appCardOptions(commonText.addToFolderOption) - ).verifyVisibleElement("have.text", commonText.addToFolderOption); - cy.get( - commonSelectors.appCardOptions(commonText.cloneAppOption) - ).verifyVisibleElement("have.text", commonText.cloneAppOption); - cy.get( - commonSelectors.appCardOptions(commonText.exportAppOption) - ).verifyVisibleElement("have.text", commonText.exportAppOption); - cy.get( - commonSelectors.appCardOptions(commonText.deleteAppOption) - ).verifyVisibleElement("have.text", commonText.deleteAppOption); - - modifyAndVerifyAppCardIcon(data.appName); - createFolder(data.folderName); - - viewAppCardOptions(data.appName); - cy.get( - commonSelectors.appCardOptions(commonText.addToFolderOption) - ).click(); - verifyModal( - dashboardText.addToFolderTitle, - dashboardText.addToFolderButton, - dashboardSelector.selectFolder - ); - cy.get(dashboardSelector.moveAppText).verifyVisibleElement( - "have.text", - dashboardText.moveAppText(data.appName) - ); - - cy.get(dashboardSelector.selectFolder).click(); - cy.get(commonSelectors.folderList).contains(data.folderName).click(); - cy.get(dashboardSelector.addToFolderButton).click(); - cy.verifyToastMessage( - commonSelectors.toastMessage, - commonText.AddedToFolderToast - ); - - cy.get(dashboardSelector.folderName(data.folderName)).verifyVisibleElement( - "have.text", - dashboardText.folderName(`${data.folderName} (1)`) - ); - - cy.get(dashboardSelector.folderName(data.folderName)).click(); - cy.get(commonSelectors.appCard(data.appName)) - .contains(data.appName) - .should("be.visible"); - - cy.wait(2000); - viewAppCardOptions(data.appName); - - cy.get(commonSelectors.appCardOptions(commonText.removeFromFolderOption)) - .verifyVisibleElement("have.text", commonText.removeFromFolderOption) - .click(); - verifyConfirmationModal(commonText.appRemovedFromFolderMessage); - - cancelModal(commonText.cancelButton); - - cy.wait(3000); - viewAppCardOptions(data.appName); - cy.get( - commonSelectors.appCardOptions(commonText.removeFromFolderOption) - ).click(); - cy.get(commonSelectors.buttonSelector(commonText.modalYesButton)).click(); - cy.verifyToastMessage( - commonSelectors.toastMessage, - commonText.appRemovedFromFolderTaost - ); - cy.get(commonSelectors.modalComponent).should("not.exist"); - cy.get(commonSelectors.empytyFolderImage).should("be.visible"); - cy.get(commonSelectors.emptyFolderText).verifyVisibleElement( - "have.text", - commonText.emptyFolderText - ); - cy.get(commonSelectors.allApplicationsLink).click(); - deleteFolder(data.folderName); - - cy.get(commonSelectors.allApplicationsLink).click(); - - cy.wait(3000); - viewAppCardOptions(data.appName); - cy.get(commonSelectors.appCardOptions(commonText.cloneAppOption)).click(); - cy.get('[data-cy="clone-app"]').click(); - cy.get(".go3958317564") - .should("be.visible") - .and("have.text", dashboardText.appClonedToast); - cy.wait(3000); - cy.renameApp(data.cloneAppName); - cy.apiAddComponentToApp(data.cloneAppName, "button", 25, 25); - cy.backToApps(); - cy.wait("@appLibrary"); - cy.wait(1000); - cy.reloadAppForTheElement(data.cloneAppName); - - cy.get(commonSelectors.appCard(data.cloneAppName)).should("be.visible"); - - cy.get(commonSelectors.globalDataSourceIcon).click(); - cy.get(commonSelectors.dashboardIcon).click(); - cy.wait(3000); - cy.reloadAppForTheElement(data.cloneAppName); - viewAppCardOptions(data.cloneAppName); - cy.get(commonSelectors.appCardOptions(commonText.exportAppOption)).click(); - cy.get(commonSelectors.exportAllButton).click(); - - cy.exec("ls ./cypress/downloads/").then((result) => { - const downloadedAppExportFileName = result.stdout.split("\n")[0]; - expect(downloadedAppExportFileName).to.contain.string("app"); - }); - - cy.wait(3000); - cy.reloadAppForTheElement(data.cloneAppName); - viewAppCardOptions(data.cloneAppName); - cy.get(commonSelectors.deleteAppOption).click(); - cy.get(commonSelectors.modalMessage).verifyVisibleElement( - "have.text", - commonText.deleteAppModalMessage(data.cloneAppName) - ); - cy.get( - commonSelectors.buttonSelector(commonText.cancelButton) - ).verifyVisibleElement("have.text", commonText.cancelButton); - cy.get( - commonSelectors.buttonSelector(commonText.modalYesButton) - ).verifyVisibleElement("have.text", commonText.modalYesButton); - cancelModal(commonText.cancelButton); - - cy.wait(3000); - cy.reloadAppForTheElement(data.cloneAppName); - viewAppCardOptions(data.cloneAppName); - cy.get(commonSelectors.deleteAppOption).click(); - cy.get(commonSelectors.buttonSelector(commonText.modalYesButton)).click(); - cy.verifyToastMessage( - commonSelectors.toastMessage, - commonText.appDeletedToast - ); - verifyAppDelete(data.cloneAppName); - cy.wait("@appLibrary"); - - cy.deleteApp(data.appName); - cy.verifyToastMessage( - commonSelectors.toastMessage, - commonText.appDeletedToast - ); - verifyAppDelete(data.appName); - }); - it("Should verify the app CRUD operation", () => { const customLayout = { desktop: { top: 100, left: 20 }, @@ -369,10 +352,7 @@ describe("dashboard", () => { cy.wait("@appLibrary"); cy.deleteApp(data.appName); - cy.verifyToastMessage( - commonSelectors.toastMessage, - commonText.appDeletedToast - ); + verifyAppDelete(data.appName); }); @@ -493,10 +473,7 @@ describe("dashboard", () => { cy.get(commonSelectors.allApplicationsLink).click(); cy.deleteApp(data.appName); - cy.verifyToastMessage( - commonSelectors.toastMessage, - commonText.appDeletedToast - ); + verifyAppDelete(data.appName); logout(); }); diff --git a/cypress-tests/cypress/e2e/happyPath/platform/commonTestcases/workspace/groups/basicPermissions.skip.js b/cypress-tests/cypress/e2e/happyPath/platform/commonTestcases/workspace/groups/basicPermissions.cy.js similarity index 100% rename from cypress-tests/cypress/e2e/happyPath/platform/commonTestcases/workspace/groups/basicPermissions.skip.js rename to cypress-tests/cypress/e2e/happyPath/platform/commonTestcases/workspace/groups/basicPermissions.cy.js diff --git a/cypress-tests/cypress/e2e/happyPath/platform/commonTestcases/workspace/groups/permissions.skip.js b/cypress-tests/cypress/e2e/happyPath/platform/commonTestcases/workspace/groups/permissions.cy.js similarity index 99% rename from cypress-tests/cypress/e2e/happyPath/platform/commonTestcases/workspace/groups/permissions.skip.js rename to cypress-tests/cypress/e2e/happyPath/platform/commonTestcases/workspace/groups/permissions.cy.js index 22b6c6b6a5..bfa5806939 100644 --- a/cypress-tests/cypress/e2e/happyPath/platform/commonTestcases/workspace/groups/permissions.skip.js +++ b/cypress-tests/cypress/e2e/happyPath/platform/commonTestcases/workspace/groups/permissions.cy.js @@ -204,10 +204,7 @@ describe("Manage Groups", () => { cy.wait(2500); cy.deleteApp(data.appName); - cy.verifyToastMessage( - commonSelectors.toastMessage, - commonText.appDeletedToast - ); + // Folder operations createFolder(data.folderName); diff --git a/cypress-tests/cypress/e2e/happyPath/platform/externalApi/apiUsers.cy.js b/cypress-tests/cypress/e2e/happyPath/platform/eeTestcases/externalApi/apiUsers.cy.js similarity index 100% rename from cypress-tests/cypress/e2e/happyPath/platform/externalApi/apiUsers.cy.js rename to cypress-tests/cypress/e2e/happyPath/platform/eeTestcases/externalApi/apiUsers.cy.js diff --git a/cypress-tests/cypress/e2e/happyPath/platform/externalApi/appImportAndExportAPI.cy.js b/cypress-tests/cypress/e2e/happyPath/platform/eeTestcases/externalApi/appImportAndExportAPI.cy.js similarity index 100% rename from cypress-tests/cypress/e2e/happyPath/platform/externalApi/appImportAndExportAPI.cy.js rename to cypress-tests/cypress/e2e/happyPath/platform/eeTestcases/externalApi/appImportAndExportAPI.cy.js diff --git a/cypress-tests/cypress/e2e/happyPath/platform/ceTestcases/userFlow/firstUserOnboarding.cy.js b/cypress-tests/cypress/e2e/happyPath/platform/firstUser/firstUserOnboarding.cy.js similarity index 100% rename from cypress-tests/cypress/e2e/happyPath/platform/ceTestcases/userFlow/firstUserOnboarding.cy.js rename to cypress-tests/cypress/e2e/happyPath/platform/firstUser/firstUserOnboarding.cy.js diff --git a/cypress-tests/cypress/support/utils/common.js b/cypress-tests/cypress/support/utils/common.js index 0f54553472..7a8c55ffcf 100644 --- a/cypress-tests/cypress/support/utils/common.js +++ b/cypress-tests/cypress/support/utils/common.js @@ -101,11 +101,14 @@ export const navigateToAppEditor = (appName) => { export const viewAppCardOptions = (appName) => { cy.wait(1000); - cy.reloadAppForTheElement(appName); + cy.get(commonSelectors.appCard(appName)) + .realHover() + .find(commonSelectors.appCardOptionsButton) + .realHover() cy.contains("div", appName) .parent() .within(() => { - cy.get(commonSelectors.appCardOptionsButton).invoke("click"); + cy.get(commonSelectors.appCardOptionsButton).click(); }); }; @@ -185,8 +188,9 @@ export const searchUser = (email) => { }; export const selectAppCardOption = (appName, appCardOption) => { + cy.wait(1000); viewAppCardOptions(appName); - cy.get(appCardOption).should("be.visible").click({ force: true }); + cy.get(appCardOption).should("be.visible").click(); }; export const navigateToDatabase = () => { diff --git a/cypress-tests/cypress/support/utils/dataSource.js b/cypress-tests/cypress/support/utils/dataSource.js index 6f17004409..4c1446636e 100644 --- a/cypress-tests/cypress/support/utils/dataSource.js +++ b/cypress-tests/cypress/support/utils/dataSource.js @@ -239,7 +239,8 @@ export const createRestAPIQuery = ( key = "", value = "", url = "", - run = true + run = true, + kind = "restapi" ) => { cy.getCookie("tj_auth_token").then((cookie) => { const headers = { @@ -247,7 +248,6 @@ export const createRestAPIQuery = ( Cookie: `tj_auth_token=${cookie.value}`, }; - cy.log(Cypress.env("appId")); cy.request({ method: "GET", url: `${Cypress.env("server_host")}/api/apps/${Cypress.env("appId")}`, @@ -255,13 +255,13 @@ export const createRestAPIQuery = ( }).then((response) => { const editingVersionId = response.body.editing_version.id; - const data_source_id = Cypress.env(`${dsName}-id`); + const data_source_id = Cypress.env(kind); const requestBody = { app_id: Cypress.env("appId"), app_version_id: editingVersionId, name: queryName, - kind: "restapi", + kind: kind, options: { method: "get", url: url, diff --git a/cypress-tests/cypress/support/utils/version.js b/cypress-tests/cypress/support/utils/version.js index 77b7d8b0e8..b15d84f45b 100644 --- a/cypress-tests/cypress/support/utils/version.js +++ b/cypress-tests/cypress/support/utils/version.js @@ -115,8 +115,8 @@ export const verifyDuplicateVersion = (newVersion = [], version) => { cy.get(appVersionSelectors.createNewVersionButton).click(); cy.verifyToastMessage( commonSelectors.toastMessage, - // appVersionText.versionNameAlreadyExists - "Already exists!" + appVersionText.versionNameAlreadyExists + // "Already exists!" ); }; diff --git a/docker/ce-preview.Dockerfile b/docker/ce-preview.Dockerfile index 66588ac653..0c481e13a3 100644 --- a/docker/ce-preview.Dockerfile +++ b/docker/ce-preview.Dockerfile @@ -80,13 +80,21 @@ RUN wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-k RUN echo "deb http://apt.postgresql.org/pub/repos/apt/ bullseye-pgdg main" | tee /etc/apt/sources.list.d/pgdg.list RUN apt update && apt -y install postgresql-13 postgresql-client-13 supervisor -RUN mkdir -p /var/log/supervisor /var/run/postgresql && \ - chown -R postgres:postgres /var/run/postgresql /var/log/supervisor - # Explicitly create PG main directory with correct ownership RUN mkdir -p /var/lib/postgresql/13/main && \ chown -R postgres:postgres /var/lib/postgresql +RUN mkdir -p /var/log/supervisor /var/run/postgresql && \ + chown -R postgres:postgres /var/run/postgresql /var/log/supervisor + +# Remove existing data and create directory with proper ownership +RUN rm -rf /var/lib/postgresql/13/main && \ + mkdir -p /var/lib/postgresql/13/main && \ + chown -R postgres:postgres /var/lib/postgresql + +# Initialize PostgreSQL +RUN su - postgres -c "/usr/lib/postgresql/13/bin/initdb -D /var/lib/postgresql/13/main" + # Configure Supervisor to manage PostgREST, ToolJet, and Redis RUN echo "[supervisord] \n" \ "nodaemon=true \n" \ diff --git a/docker/ee/ee-preview.Dockerfile b/docker/ee/ee-preview.Dockerfile index 66fb4835ad..77ecbff29d 100644 --- a/docker/ee/ee-preview.Dockerfile +++ b/docker/ee/ee-preview.Dockerfile @@ -9,7 +9,7 @@ WORKDIR /app ARG CUSTOM_GITHUB_TOKEN ARG BRANCH_NAME -# Clone and checkout the frontend repository +# Clone and checkout the frontend repositorys RUN git config --global url."https://x-access-token:${CUSTOM_GITHUB_TOKEN}@github.com/".insteadOf "https://github.com/" RUN git config --global http.version HTTP/1.1 @@ -109,6 +109,14 @@ RUN wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-k RUN echo "deb http://apt.postgresql.org/pub/repos/apt/ bullseye-pgdg main" | tee /etc/apt/sources.list.d/pgdg.list RUN apt update && apt -y install postgresql-13 postgresql-client-13 supervisor --fix-missing + +# Explicitly create PG main directory with correct ownership +RUN mkdir -p /var/lib/postgresql/13/main && \ + chown -R postgres:postgres /var/lib/postgresql + +RUN mkdir -p /var/log/supervisor /var/run/postgresql && \ + chown -R postgres:postgres /var/run/postgresql /var/log/supervisor + # Remove existing data and create directory with proper ownership RUN rm -rf /var/lib/postgresql/13/main && \ mkdir -p /var/lib/postgresql/13/main && \ diff --git a/frontend/src/AppBuilder/_hooks/useAppData.js b/frontend/src/AppBuilder/_hooks/useAppData.js index f131b4eb59..433a677dc7 100644 --- a/frontend/src/AppBuilder/_hooks/useAppData.js +++ b/frontend/src/AppBuilder/_hooks/useAppData.js @@ -216,248 +216,237 @@ const useAppData = (appId, moduleId, darkMode, mode = 'edit', { environmentId, v } // const appDataPromise = appService.fetchApp(appId); - appDataPromise - .then(async (result) => { - let appData = { ...result }; - let editorEnvironment = result.editorEnvironment; - if (isPreviewForVersion) { - const rawDataQueries = appData?.data_queries; - const rawEditingVersionDataQueries = appData?.editing_version?.data_queries; - appData = convertAllKeysToSnakeCase(appData); + appDataPromise.then(async (result) => { + let appData = { ...result }; + let editorEnvironment = result.editorEnvironment; + if (isPreviewForVersion) { + const rawDataQueries = appData?.data_queries; + const rawEditingVersionDataQueries = appData?.editing_version?.data_queries; + appData = convertAllKeysToSnakeCase(appData); - appData.data_queries = rawDataQueries; - if (appData.editing_version && rawEditingVersionDataQueries) { - appData.editing_version.data_queries = rawEditingVersionDataQueries; - } + appData.data_queries = rawDataQueries; + if (appData.editing_version && rawEditingVersionDataQueries) { + appData.editing_version.data_queries = rawEditingVersionDataQueries; + } + editorEnvironment = { + id: environmentId, + name: queryParams.env, + }; + } + + let constantsResp; + if (mode !== 'edit') { + try { + const queryParams = { slug: slug }; + const viewerEnvironment = await appEnvironmentService.getEnvironment(environmentId, queryParams); editorEnvironment = { - id: environmentId, - name: queryParams.env, + id: viewerEnvironment?.environment?.id, + name: viewerEnvironment?.environment?.name, }; + constantsResp = + isPublicAccess && appData.is_public + ? await orgEnvironmentConstantService.getConstantsFromPublicApp(slug, viewerEnvironment?.environment?.id) + : await orgEnvironmentConstantService.getConstantsFromApp(slug, viewerEnvironment?.environment?.id); + } catch (error) { + console.error('Error fetching viewer environment:', error); } + } - let constantsResp; - if (mode !== 'edit') { - try { - const queryParams = { slug: slug }; - const viewerEnvironment = await appEnvironmentService.getEnvironment(environmentId, queryParams); - editorEnvironment = { - id: viewerEnvironment?.environment?.id, - name: viewerEnvironment?.environment?.name, - }; - constantsResp = - isPublicAccess && appData.is_public - ? await orgEnvironmentConstantService.getConstantsFromPublicApp( - slug, - viewerEnvironment?.environment?.id - ) - : await orgEnvironmentConstantService.getConstantsFromApp(slug, viewerEnvironment?.environment?.id); - } catch (error) { - console.error('Error fetching viewer environment:', error); - } - } + if (mode === 'edit') { + constantsResp = await orgEnvironmentConstantService.getConstantsFromEnvironment(editorEnvironment?.id); + } + // get the constants for specific environment + constantsResp.constants = extractEnvironmentConstantsFromConstantsList( + constantsResp?.constants, + editorEnvironment?.name + ); - if (mode === 'edit') { - constantsResp = await orgEnvironmentConstantService.getConstantsFromEnvironment(editorEnvironment?.id); - } - // get the constants for specific environment - constantsResp.constants = extractEnvironmentConstantsFromConstantsList( - constantsResp?.constants, - editorEnvironment?.name - ); + setIsPublicAccess(isPublicAccess && mode !== 'edit' && appData.is_public); - setIsPublicAccess(isPublicAccess && mode !== 'edit' && appData.is_public); + fetchAndInjectCustomStyles(isPublicAccess && mode !== 'edit' && appData.is_public); - fetchAndInjectCustomStyles(isPublicAccess && mode !== 'edit' && appData.is_public); - - const pages = appData.pages.map((page) => { - return page; - }); - const conversation = appData.ai_conversation; - const docsConversation = appData.ai_conversation_learn; - if (setConversation && setDocsConversation) { - setConversation(conversation); - setDocsConversation(docsConversation); - // important to control ai inputs - getCreditBalance(); - } - - let showWalkthrough = true; - // if app was created from propmt, and no earlier messages are present in the conversation, send the prompt message - - // handles the getappdataby slug api call. Gets the homePageId from the appData. - const homePageId = - appData.editing_version?.homePageId || appData.editing_version?.home_page_id || appData.home_page_id; - - setApp({ - appName: appData.name, - appId: appData.id, - slug: appData.slug, - currentAppEnvironmentId: editorEnvironment.id, - isMaintenanceOn: - 'is_maintenance_on' in result - ? result.is_maintenance_on - : 'isMaintenanceOn' in result - ? result.isMaintenanceOn - : false, - organizationId: appData.organizationId || appData.organization_id, - homePageId: homePageId, - isPublic: appData.is_public, - creationMode: appData.creation_mode, - }); - setIsEditorFreezed(appData.should_freeze_editor); - const global_settings = mapKeys( - appData.editing_version?.global_settings || appData.global_settings, - (value, key) => camelCase(key) - ); - if (!global_settings?.theme) { - global_settings.theme = baseTheme; - } - setGlobalSettings(global_settings); - setPages(pages, moduleId); - setPageSettings( - computePageSettings(deepCamelCase(appData?.editing_version?.page_settings ?? appData?.page_settings)) - ); - - // set starting page as homepage initially - let startingPage = appData.pages.find((page) => page.id === homePageId); - - //no access to homepage, set to the next available page - if (startingPage?.restricted) { - startingPage = appData.pages.find((page) => !page?.restricted); - } - - if (initialLoadRef.current) { - // if initial load, check if the path has a page handle and set that as the starting page - const initialLoadPath = location.pathname.split('/').pop(); - - const page = appData.pages.find((page) => page.handle === initialLoadPath && !page.isPageGroup); - if (page) { - // if page is disabled, and not editing redirect to home page - const shouldRedirect = page?.restricted || (mode !== 'edit' && page?.disabled); - - if (shouldRedirect) { - const newUrl = window.location.href.replace(initialLoadPath, startingPage.handle); - window.history.replaceState(null, null, newUrl); - - if (page?.restricted) { - toast.error('Access to this page is restricted. Contact admin to know more.', { - className: 'text-nowrap w-auto mw-100', - }); - } - } else { - startingPage = page; - } - } - - // navigate(`/${getWorkspaceId()}/apps/${slug ?? appId}/${startingPage.handle}`); - } - - // Add page id and handle to the state on initial load - const currentState = window.history.state || {}; - const pageInfo = { - id: startingPage.id, - handle: startingPage.handle, - }; - const newState = { ...currentState, ...pageInfo }; - window.history.replaceState(newState, '', window.location.href); - - setCurrentPageHandle(startingPage.handle); - updateFeatureAccess(); - setCurrentPageId(startingPage.id, moduleId); - setResolvedPageConstants({ - id: startingPage?.id, - handle: startingPage?.handle, - name: startingPage?.name, - }); - setComponentNameIdMapping(moduleId); - updateEventsField('events', appData.events); - setCurrentVersionId(appData.editing_version?.id || appData.current_version_id); - setAppHomePageId(homePageId); - - const queryData = - isPublicAccess || (mode !== 'edit' && appData.is_public) - ? appData - : await dataqueryService.getAll(appData.editing_version?.id || appData.current_version_id); - const dataQueries = queryData.data_queries || queryData?.editing_version?.data_queries; - dataQueries.forEach((query) => normalizeQueryTransformationOptions(query)); - setQueries(dataQueries); - if (dataQueries?.length > 0) { - setSelectedQuery(dataQueries[0]?.id); - initialiseResolvedQuery(dataQueries.map((query) => query.id)); - } - const constants = constantsResp?.constants; - - if (constants) { - const orgConstants = {}; - const orgSecrets = {}; - constants.map((constant) => { - if (constant.type !== 'Secret') { - orgConstants[constant.name] = constant.value; - } else { - orgSecrets[constant.name] = constant.value; - } - }); - setResolvedConstants(orgConstants); - setSecrets(orgSecrets); - } - setQueryMapping(moduleId); - - setResolvedGlobals('environment', editorEnvironment); - setResolvedGlobals('mode', { value: mode }); - setResolvedGlobals('currentUser', { - ...user, - groups: currentSession?.groups, - role: currentSession?.role?.name, - ssoUserInfo: currentSession?.ssoUserInfo, - ...(currentSession?.currentUser?.metadata && !isEmpty(currentSession?.currentUser?.metadata) - ? { metadata: currentSession?.currentUser?.metadata } - : {}), - }); - setResolvedGlobals('urlparams', JSON.parse(JSON.stringify(queryString.parse(location?.search)))); - initDependencyGraph(moduleId); - setCurrentMode(mode); // TODO: set mode based on the slug/appDef - if ( - state.ai && - state?.prompt && - initialLoadRef.current && - (conversation?.aiConversationMessages || []).length === 0 - ) { - setSelectedSidebarItem('tooljetai'); - toggleLeftSidebar('true'); - sendMessage(state.prompt); - setConversationZeroState(true); - showWalkthrough = false; - } - // fetchDataSources(appData.editing_version.id, editorEnvironment.id); - if (!isPublicAccess) { - const envFromQueryParams = mode === 'view' && new URLSearchParams(location?.search)?.get('env'); - useStore.getState().init(appData.editing_version?.id || appData.current_version_id, envFromQueryParams); - fetchGlobalDataSources( - appData.organization_id, - appData.editing_version?.id || appData.current_version_id, - editorEnvironment.id - ); - } - useStore.getState().updateEditingVersion(appData.editing_version?.id || appData.current_version_id); //check if this is needed - updateReleasedVersionId(appData.current_version_id); - - setEditorLoading(false); - initialLoadRef.current = false; - // only show if app is not created from prompt - if (showWalkthrough) initEditorWalkThrough(); - checkAndSetTrueBuildSuggestionsFlag(); - return () => { - document.title = retrieveWhiteLabelText(); - }; - }) - .catch((error) => { - if (isPublicAccess) { - if (mode !== 'edit') { - handleError('view', error); - } - } + const pages = appData.pages.map((page) => { + return page; }); + const conversation = appData.ai_conversation; + const docsConversation = appData.ai_conversation_learn; + if (setConversation && setDocsConversation) { + setConversation(conversation); + setDocsConversation(docsConversation); + // important to control ai inputs + getCreditBalance(); + } + + let showWalkthrough = true; + // if app was created from propmt, and no earlier messages are present in the conversation, send the prompt message + + // handles the getappdataby slug api call. Gets the homePageId from the appData. + const homePageId = + appData.editing_version?.homePageId || appData.editing_version?.home_page_id || appData.home_page_id; + + setApp({ + appName: appData.name, + appId: appData.id, + slug: appData.slug, + currentAppEnvironmentId: editorEnvironment.id, + isMaintenanceOn: + 'is_maintenance_on' in result + ? result.is_maintenance_on + : 'isMaintenanceOn' in result + ? result.isMaintenanceOn + : false, + organizationId: appData.organizationId || appData.organization_id, + homePageId: homePageId, + isPublic: appData.is_public, + creationMode: appData.creation_mode, + }); + setIsEditorFreezed(appData.should_freeze_editor); + const global_settings = mapKeys( + appData.editing_version?.global_settings || appData.global_settings, + (value, key) => camelCase(key) + ); + if (!global_settings?.theme) { + global_settings.theme = baseTheme; + } + setGlobalSettings(global_settings); + setPages(pages, moduleId); + setPageSettings( + computePageSettings(deepCamelCase(appData?.editing_version?.page_settings ?? appData?.page_settings)) + ); + + // set starting page as homepage initially + let startingPage = appData.pages.find((page) => page.id === homePageId); + + //no access to homepage, set to the next available page + if (startingPage?.restricted) { + startingPage = appData.pages.find((page) => !page?.restricted); + } + + if (initialLoadRef.current) { + // if initial load, check if the path has a page handle and set that as the starting page + const initialLoadPath = location.pathname.split('/').pop(); + + const page = appData.pages.find((page) => page.handle === initialLoadPath && !page.isPageGroup); + if (page) { + // if page is disabled, and not editing redirect to home page + const shouldRedirect = page?.restricted || (mode !== 'edit' && page?.disabled); + + if (shouldRedirect) { + const newUrl = window.location.href.replace(initialLoadPath, startingPage.handle); + window.history.replaceState(null, null, newUrl); + + if (page?.restricted) { + toast.error('Access to this page is restricted. Contact admin to know more.', { + className: 'text-nowrap w-auto mw-100', + }); + } + } else { + startingPage = page; + } + } + + // navigate(`/${getWorkspaceId()}/apps/${slug ?? appId}/${startingPage.handle}`); + } + + // Add page id and handle to the state on initial load + const currentState = window.history.state || {}; + const pageInfo = { + id: startingPage.id, + handle: startingPage.handle, + }; + const newState = { ...currentState, ...pageInfo }; + window.history.replaceState(newState, '', window.location.href); + + setCurrentPageHandle(startingPage.handle); + updateFeatureAccess(); + setCurrentPageId(startingPage.id, moduleId); + setResolvedPageConstants({ + id: startingPage?.id, + handle: startingPage?.handle, + name: startingPage?.name, + }); + setComponentNameIdMapping(moduleId); + updateEventsField('events', appData.events); + setCurrentVersionId(appData.editing_version?.id || appData.current_version_id); + setAppHomePageId(homePageId); + + const queryData = + isPublicAccess || (mode !== 'edit' && appData.is_public) + ? appData + : await dataqueryService.getAll(appData.editing_version?.id || appData.current_version_id); + const dataQueries = queryData.data_queries || queryData?.editing_version?.data_queries; + dataQueries.forEach((query) => normalizeQueryTransformationOptions(query)); + setQueries(dataQueries); + if (dataQueries?.length > 0) { + setSelectedQuery(dataQueries[0]?.id); + initialiseResolvedQuery(dataQueries.map((query) => query.id)); + } + const constants = constantsResp?.constants; + + if (constants) { + const orgConstants = {}; + const orgSecrets = {}; + constants.map((constant) => { + if (constant.type !== 'Secret') { + orgConstants[constant.name] = constant.value; + } else { + orgSecrets[constant.name] = constant.value; + } + }); + setResolvedConstants(orgConstants); + setSecrets(orgSecrets); + } + setQueryMapping(moduleId); + + setResolvedGlobals('environment', editorEnvironment); + setResolvedGlobals('mode', { value: mode }); + setResolvedGlobals('currentUser', { + ...user, + groups: currentSession?.groups, + role: currentSession?.role?.name, + ssoUserInfo: currentSession?.ssoUserInfo, + ...(currentSession?.currentUser?.metadata && !isEmpty(currentSession?.currentUser?.metadata) + ? { metadata: currentSession?.currentUser?.metadata } + : {}), + }); + setResolvedGlobals('urlparams', JSON.parse(JSON.stringify(queryString.parse(location?.search)))); + initDependencyGraph(moduleId); + setCurrentMode(mode); // TODO: set mode based on the slug/appDef + if ( + state.ai && + state?.prompt && + initialLoadRef.current && + (conversation?.aiConversationMessages || []).length === 0 + ) { + setSelectedSidebarItem('tooljetai'); + toggleLeftSidebar('true'); + sendMessage(state.prompt); + setConversationZeroState(true); + showWalkthrough = false; + } + // fetchDataSources(appData.editing_version.id, editorEnvironment.id); + if (!isPublicAccess) { + const envFromQueryParams = mode === 'view' && new URLSearchParams(location?.search)?.get('env'); + useStore.getState().init(appData.editing_version?.id || appData.current_version_id, envFromQueryParams); + fetchGlobalDataSources( + appData.organization_id, + appData.editing_version?.id || appData.current_version_id, + editorEnvironment.id + ); + } + useStore.getState().updateEditingVersion(appData.editing_version?.id || appData.current_version_id); //check if this is needed + updateReleasedVersionId(appData.current_version_id); + + setEditorLoading(false); + initialLoadRef.current = false; + // only show if app is not created from prompt + if (showWalkthrough) initEditorWalkThrough(); + checkAndSetTrueBuildSuggestionsFlag(); + return () => { + document.title = retrieveWhiteLabelText(); + }; + }); }, [setApp, setEditorLoading, currentSession]); useEffect(() => { diff --git a/frontend/src/_components/DynamicForm.jsx b/frontend/src/_components/DynamicForm.jsx index 0f5db30e9b..a71974afc4 100644 --- a/frontend/src/_components/DynamicForm.jsx +++ b/frontend/src/_components/DynamicForm.jsx @@ -26,6 +26,7 @@ import { Constants } from '@/_helpers/utils'; import { OverlayTrigger, Tooltip } from 'react-bootstrap'; import Sharepoint from '@/_components/Sharepoint'; import AccordionForm from './AccordionForm'; +import { generateCypressDataCy } from '../modules/common/helpers/cypressHelpers'; const DynamicForm = ({ schema, @@ -534,7 +535,7 @@ const DynamicForm = ({ const labelElement = ( )} -
+
{flipComponentDropdown.helpText && ( diff --git a/frontend/src/_ui/HttpHeaders/SourceEditor.jsx b/frontend/src/_ui/HttpHeaders/SourceEditor.jsx index 04df343740..dda0775468 100644 --- a/frontend/src/_ui/HttpHeaders/SourceEditor.jsx +++ b/frontend/src/_ui/HttpHeaders/SourceEditor.jsx @@ -21,8 +21,7 @@ export default ({ return (
{options.length === 0 && ( -
+
There are no key value pairs added
@@ -86,7 +85,7 @@ export default ({
addNewKeyValuePair(options)} diff --git a/frontend/src/components/ui/Input/CommonInput/Index.jsx b/frontend/src/components/ui/Input/CommonInput/Index.jsx index baee3ad5d8..2b968a0940 100644 --- a/frontend/src/components/ui/Input/CommonInput/Index.jsx +++ b/frontend/src/components/ui/Input/CommonInput/Index.jsx @@ -3,6 +3,7 @@ import NumberInput from './NumberInput'; import TextInput from './TextInput'; import { HelperMessage, InputLabel, ValidationMessage } from '../InputUtils/InputUtils'; import { ButtonSolid } from '../../../../_components/AppButton'; +import { generateCypressDataCy } from '../../../../modules/common/helpers/cypressHelpers.js'; const CommonInput = ({ label, helperText, disabled, required, onChange: change, ...restProps }) => { const { type, encrypted, validation, isValidatedMessages, isDisabled } = restProps; @@ -65,13 +66,14 @@ const CommonInput = ({ label, helperText, disabled, required, onChange: change, rel="noreferrer" disabled={isDisabled} onClick={toggleEditing} + data-cy={`button-${generateCypressDataCy(isEditing ? 'Cancel' : 'Edit')}`} > {isEditing ? 'Cancel' : 'Edit'}
- + Encrypted diff --git a/frontend/src/components/ui/Input/InputUtils/InputUtils.jsx b/frontend/src/components/ui/Input/InputUtils/InputUtils.jsx index 57128adf73..57e92a819b 100644 --- a/frontend/src/components/ui/Input/InputUtils/InputUtils.jsx +++ b/frontend/src/components/ui/Input/InputUtils/InputUtils.jsx @@ -3,6 +3,7 @@ import { Label } from '../../Label/Label'; import ValidationIcon from './ValidationIcon'; import { cn } from '@/lib/utils'; import HelperIcon from './HelperIcon'; +import { generateCypressDataCy } from '../../../../modules/common/helpers/cypressHelpers.js'; export const ValidationMessage = ({ response, validationMessage, className }) => (
@@ -14,7 +15,7 @@ export const ValidationMessage = ({ response, validationMessage, className }) => type="helper" size="default" className={`tw-font-normal ${response === true ? 'tw-text-text-success' : '!tw-text-text-warning'}`} - data-cy="validation-label" + data-cy={`${generateCypressDataCy(validationMessage)}-validation-label`} > {validationMessage} @@ -53,7 +54,7 @@ export const InputLabel = ({ disabled, label, required }) => ( type="label" size="default" className={`tw-font-medium tw-mb-[2px] ${disabled ? 'tw-text-text-disabled' : ''}`} - data-cy="input-field-label" + data-cy={`${generateCypressDataCy(label)}-field-label`} > {label} {required && } diff --git a/frontend/src/modules/common/helpers/cypressHelpers.js b/frontend/src/modules/common/helpers/cypressHelpers.js new file mode 100644 index 0000000000..36bb5d713f --- /dev/null +++ b/frontend/src/modules/common/helpers/cypressHelpers.js @@ -0,0 +1,6 @@ +export function generateCypressDataCy(text) { + return String(text) + .toLowerCase() + .replace(/[^a-z0-9]+/g, "-") + .replace(/^-+|-+$/g, ""); +} diff --git a/frontend/src/modules/dataSources/components/DataSourceManager/DataSourceManager.jsx b/frontend/src/modules/dataSources/components/DataSourceManager/DataSourceManager.jsx index 65ee96758b..ea556429dd 100644 --- a/frontend/src/modules/dataSources/components/DataSourceManager/DataSourceManager.jsx +++ b/frontend/src/modules/dataSources/components/DataSourceManager/DataSourceManager.jsx @@ -36,6 +36,7 @@ import './dataSourceManager.theme.scss'; import { canUpdateDataSource } from '@/_helpers'; import DataSourceSchemaManager from '@/_helpers/dataSourceSchemaManager'; import MultiEnvTabs from './MultiEnvTabs'; +import { generateCypressDataCy } from '../../../common/helpers/cypressHelpers'; class DataSourceManagerComponent extends React.Component { constructor(props) { @@ -1127,7 +1128,11 @@ class DataSourceManagerComponent extends React.Component {
{validationError.map((error, index) => ( -
+
{error}
))}