diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index 914a0406b5..8e3fcaea11 100644 --- a/.github/workflows/ci-cd.yml +++ b/.github/workflows/ci-cd.yml @@ -637,7 +637,7 @@ jobs: with: start: | docker-compose -f ./scripts/cypress/docker-compose-pg-cy-quick.yml up -d - npm run start:api:cache:pg:cyquick + npm run start:api:cache:pg:cyquick npm run start:web spec: "./scripts/cypress/integration/test/quickTest.js" wait-on: "http://localhost:8080, http://localhost:3000/_nuxt/assets/img/icons/512x512-trans.png" @@ -689,4 +689,49 @@ jobs: run: docker-compose -f ./scripts/docker-compose-cypress.yml up -d - name: run unit tests working-directory: ./packages/nocodb - run: npm run test:unit \ No newline at end of file + run: npm run test:unit + cypress-db-independent: + runs-on: ubuntu-20.04 + if: ${{ github.event_name == 'push' || !github.event.pull_request.draft }} + steps: + - name: Setup Node + uses: actions/setup-node@v1 + with: + node-version: 16.15.0 + - name: Checkout + uses: actions/checkout@v2 + with: + fetch-depth: 0 + - name: Cache node modules + uses: actions/cache@v2 + env: + cache-name: cache-node-modules + + with: + # npm cache files are stored in `~/.npm` on Linux/macOS + path: ~/.npm + key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }} + restore-keys: | + ${{ runner.os }}-build-${{ env.cache-name }}- + ${{ runner.os }}-build- + ${{ runner.os }}- + - name: Set env + run: echo "NODE_ENV=test" >> $GITHUB_ENV + - name: Cypress run + uses: cypress-io/github-action@v2 + with: + start: | + npm run start:api:cache + npm run start:web + docker-compose -f ./scripts/docker-compose-cypress.yml up -d + spec: "./scripts/cypress/integration/test/db-independent.js" + wait-on: "http://localhost:8080, http://localhost:3000/_nuxt/assets/img/icons/512x512-trans.png" + wait-on-timeout: 1200 + config-file: scripts/cypress/cypress.json + - name: Upload screenshots + if: always() + uses: actions/upload-artifact@v2 + with: + name: cypress-restMisc-run-cache-snapshots + path: scripts/cypress/screenshots + retention-days: 2 \ No newline at end of file diff --git a/scripts/cypress/cypress.json b/scripts/cypress/cypress.json index 2d162a3676..c916289496 100644 --- a/scripts/cypress/cypress.json +++ b/scripts/cypress/cypress.json @@ -13,7 +13,8 @@ "test/pg-restViews.js", "test/pg-restRoles.js", "test/pg-restMisc.js", - "test/quickTest.js" + "test/quickTest.js", + "test/db-independent.js" ], "defaultCommandTimeout": 13000, "pageLoadTimeout": 600000, diff --git a/scripts/cypress/integration/common/00_pre_configurations.js b/scripts/cypress/integration/common/00_pre_configurations.js index 31ce588fd1..fe518936b3 100644 --- a/scripts/cypress/integration/common/00_pre_configurations.js +++ b/scripts/cypress/integration/common/00_pre_configurations.js @@ -187,7 +187,7 @@ export const genTest = (apiType, dbType) => { } } else { projectsPage.createProject(proj.basic, proj.config); - cy.wait(5000); + // cy.wait(5000); if (dbType === "xcdb") { // store base URL- to re-visit and delete form view later let projId; diff --git a/scripts/cypress/integration/common/4e_form_view_share.js b/scripts/cypress/integration/common/4e_form_view_share.js index 07dd7a463b..ba8bbf6219 100644 --- a/scripts/cypress/integration/common/4e_form_view_share.js +++ b/scripts/cypress/integration/common/4e_form_view_share.js @@ -92,7 +92,6 @@ export const genTest = (apiType, dbType) => { cy.wait(2000); mainPage.shareView().click(); - // copy link text, visit URL cy.getActiveModal(".nc-modal-share-view") .should("exist") @@ -100,6 +99,11 @@ export const genTest = (apiType, dbType) => { .contains("/nc/form/", { timeout: 10000 }) .should("exist") .then(($obj) => { + // http://localhost:8080/api/v1/db/public/shared-view/761f0200-e72c-487a-85bf-615d0d277054/rows?offset=0&filterArrJson=[]&sortArrJson=[] + cy.intercept("/api/v1/db/public/shared-view/**").as( + "waitForPageLoad" + ); + let linkText = $obj.text().trim(); cy.log(linkText); @@ -108,7 +112,8 @@ export const genTest = (apiType, dbType) => { cy.visit(linkText, { baseUrl: null, }); - cy.wait(5000); + // cy.wait(5000); + cy.wait(["@waitForPageLoad"], { times: 2 }); // wait for share view page to load! diff --git a/scripts/cypress/integration/common/4f_grid_view_share.js b/scripts/cypress/integration/common/4f_grid_view_share.js index b34e276931..b815200d68 100644 --- a/scripts/cypress/integration/common/4f_grid_view_share.js +++ b/scripts/cypress/integration/common/4f_grid_view_share.js @@ -82,7 +82,9 @@ export const genTest = (apiType, dbType) => { }); it(`Share ${viewType.toUpperCase()} hide, sort, filter & verify`, () => { - cy.intercept("/api/v1/db/meta/audits/comments/*").as("waitForPageLoad"); + cy.intercept("/api/v1/db/meta/audits/comments/**").as( + "waitForPageLoad" + ); cy.get(`.nc-view-item.nc-${viewType}-view-item`) .contains("Grid-1") diff --git a/scripts/cypress/integration/common/6d_language_validation.js b/scripts/cypress/integration/common/6d_language_validation.js index d3704f13fd..3268b8d08f 100644 --- a/scripts/cypress/integration/common/6d_language_validation.js +++ b/scripts/cypress/integration/common/6d_language_validation.js @@ -1,6 +1,3 @@ -const { mainPage } = require("../../support/page_objects/mainPage"); -const { loginPage } = require("../../support/page_objects/navigation"); -const { roles } = require("../../support/page_objects/projectConstants"); import { isTestSuiteActive } from "../../support/page_objects/projectConstants"; export const genTest = (apiType, dbType) => { @@ -21,18 +18,8 @@ export const genTest = (apiType, dbType) => { cy.saveLocalStorage(); }); - after(() => { - cy.restoreLocalStorage(); - cy.get(".nc-menu-accounts").should("exist").click(); - cy.getActiveMenu(".nc-dropdown-user-accounts-menu") - .find(".ant-dropdown-menu-item") - .eq(1) - .click(); - - cy.wait(5000); - cy.get('button:contains("SIGN")').should("exist"); - cy.saveLocalStorage(); - }); + // after(() => { + // }); const langVerification = (idx, lang) => { // pick json from the file specified diff --git a/scripts/cypress/integration/common/6e_project_operations.js b/scripts/cypress/integration/common/6e_project_operations.js index 53d1cd6fc6..62c4aacb2f 100644 --- a/scripts/cypress/integration/common/6e_project_operations.js +++ b/scripts/cypress/integration/common/6e_project_operations.js @@ -7,9 +7,8 @@ export const genTest = (apiType, dbType) => { if (!isTestSuiteActive(apiType, dbType)) return; before(() => { - cy.restoreLocalStorage(); - cy.visit("/"); - cy.wait(4000); + loginPage.signIn(roles.owner.credentials); + cy.saveLocalStorage(); }); beforeEach(() => { diff --git a/scripts/cypress/integration/common/6f_attachments.js b/scripts/cypress/integration/common/6f_attachments.js index 92111e446c..2a76aaf303 100644 --- a/scripts/cypress/integration/common/6f_attachments.js +++ b/scripts/cypress/integration/common/6f_attachments.js @@ -6,11 +6,9 @@ export const genTest = (apiType, dbType) => { if (!isTestSuiteActive(apiType, dbType)) return; describe(`${apiType.toUpperCase()} Columns of type attachment`, () => { - before(() => { - loginPage.loginAndOpenProject(apiType, dbType); - cy.openTableTab("Country", 25); - cy.saveLocalStorage(); - }); + // before(() => { + // // loginPage.loginAndOpenProject(apiType, dbType); + // }); beforeEach(() => { cy.restoreLocalStorage(); @@ -49,6 +47,8 @@ export const genTest = (apiType, dbType) => { }); it(`Add column of type attachments`, () => { + cy.openTableTab("Country", 25); + mainPage.addColumnWithType("testAttach", "Attachment", "Country"); for (let i = 4; i <= 6; i++) { @@ -77,7 +77,7 @@ export const genTest = (apiType, dbType) => { mainPage.shareView().click(); - cy.wait(5000); + // cy.wait(5000); // copy link text, visit URL cy.getActiveModal(".nc-modal-share-view") @@ -85,6 +85,10 @@ export const genTest = (apiType, dbType) => { .contains("/nc/form/", { timeout: 10000 }) .should("exist") .then(($obj) => { + cy.intercept("/api/v1/db/public/shared-view/**").as( + "waitForSharedViewLoad" + ); + let linkText = $obj.text().trim(); cy.log(linkText); @@ -93,10 +97,12 @@ export const genTest = (apiType, dbType) => { cy.visit(linkText, { baseUrl: null, }); - cy.wait(5000); + // cy.wait(5000); + cy.wait(["@waitForSharedViewLoad"]); // wait for share view page to load! cy.get(".nc-form").should("exist"); + cy.get("button:contains(Submit)").should("exist"); // fill form // 0: Country @@ -128,7 +134,7 @@ export const genTest = (apiType, dbType) => { // projectsPage.openConfiguredProject(apiType, dbType); cy.openTableTab("Country", 25); - cy.wait(1000); + // cy.wait(1000); mainPage.filterField("testAttach", "is not null", null); mainPage.hideField("LastUpdate"); diff --git a/scripts/cypress/integration/common/6g_base_share.js b/scripts/cypress/integration/common/6g_base_share.js index 12d9f1835c..070fd0f1a9 100644 --- a/scripts/cypress/integration/common/6g_base_share.js +++ b/scripts/cypress/integration/common/6g_base_share.js @@ -56,12 +56,12 @@ export const genTest = (apiType, dbType) => { }; describe(`${apiType.toUpperCase()} Base VIEW share`, () => { - before(() => { - // loginPage.loginAndOpenProject(apiType, dbType); - cy.restoreLocalStorage(); - cy.openTableTab("Country", 25); - cy.saveLocalStorage(); - }); + // before(() => { + // // loginPage.loginAndOpenProject(apiType, dbType); + // cy.restoreLocalStorage(); + // cy.openTableTab("Country", 25); + // cy.saveLocalStorage(); + // }); beforeEach(() => { cy.restoreLocalStorage(); @@ -72,6 +72,8 @@ export const genTest = (apiType, dbType) => { }); it(`Generate base share URL`, () => { + cy.openTableTab("Country", 25); + // click SHARE cy.get(".nc-share-base:visible").should("exist").click(); diff --git a/scripts/cypress/integration/common/8a_webhook.js b/scripts/cypress/integration/common/8a_webhook.js index 6716b42c4b..fe967ed7ef 100644 --- a/scripts/cypress/integration/common/8a_webhook.js +++ b/scripts/cypress/integration/common/8a_webhook.js @@ -26,24 +26,13 @@ function createWebhook(hook, test) { cy.get(".nc-input-hook-header-key") .should("exist") .click() - .type("{downarrow}") - .type("{downarrow}") - .type("{downarrow}") - .type("{downarrow}") - .type("{downarrow}") - .type("{downarrow}") - .type("{downarrow}") - .type("{downarrow}") - .type("{downarrow}") - .type("{downarrow}") - .type("{downarrow}") - .type("{downarrow}"); - - cy.getActiveSelection(".nc-dropdown-webhook-header") - .find(".ant-select-item-option-content") - .contains("Content-Type") - .should("exist") - .click(); + .type("Content-Type{enter}"); + + // cy.getActiveSelection(".nc-dropdown-webhook-header") + // .find(".ant-select-item-option-content") + // .contains("Content-Type") + // .should("exist") + // .click(); cy.get("input.nc-input-hook-header-value") .should("exist") @@ -246,7 +235,8 @@ export const genTest = (apiType, dbType) => { if (!isTestSuiteActive(apiType, dbType)) return; describe(`Webhook`, () => { before(() => { - loginPage.loginAndOpenProject(apiType, dbType); + // loginPage.loginAndOpenProject(apiType, dbType); + cy.restoreLocalStorage(); cy.createTable("Temp"); cy.saveLocalStorage(); }); diff --git a/scripts/cypress/integration/test/db-independent.js b/scripts/cypress/integration/test/db-independent.js new file mode 100644 index 0000000000..529d456894 --- /dev/null +++ b/scripts/cypress/integration/test/db-independent.js @@ -0,0 +1,18 @@ +let t6d = require("../common/6d_language_validation"); + +const { + setCurrentMode, +} = require("../../support/page_objects/projectConstants"); +const t01 = require("../common/00_pre_configurations"); + +const nocoTestSuite = (apiType, dbType) => { + setCurrentMode(apiType, dbType); + + // Sakila Ext DB project creation + t01.genTest(apiType, dbType); + + // i18n + t6d.genTest(apiType, dbType); +}; + +nocoTestSuite("rest", "mysql"); diff --git a/scripts/cypress/integration/test/pg-restMisc.js b/scripts/cypress/integration/test/pg-restMisc.js index f4b92d498e..74cfd319c0 100644 --- a/scripts/cypress/integration/test/pg-restMisc.js +++ b/scripts/cypress/integration/test/pg-restMisc.js @@ -14,22 +14,35 @@ const t8a = require("../common/8a_webhook"); const nocoTestSuite = (apiType, dbType) => { setCurrentMode(apiType, dbType); + + // Sakila Ext DB project creation t01.genTest(apiType, dbType); + // Download CSV t6b.genTest(apiType, dbType); - t6d.genTest(apiType, dbType); + + // i18n: language validation suffice to be done in REST MySQL suite + // t6d.genTest(apiType, dbType); + + // Swagger API // exclude@ncv2 t6c.genTest(apiType, dbType); + + // Attachment cell t6f.genTest(apiType, dbType); - t6g.genTest(apiType, dbType); - // webhook tests + // ERD: + // t9b.genTest(apiType, dbType); + + // Webhook tests t8a.genTest(apiType, dbType); - // **deletes created project, hence place it @ end + // Base share (viewer, editor), iFrame tests + t6g.genTest(apiType, dbType); + + // Project operations: Delete t6e.genTest(apiType, dbType); - // intended to keep this after earlier project deletion - // creates project using excel & deletes it + // Create project from Excel t7a.genTest(apiType, dbType); }; diff --git a/scripts/cypress/integration/test/restMisc.js b/scripts/cypress/integration/test/restMisc.js index 704b494943..82e02246d5 100644 --- a/scripts/cypress/integration/test/restMisc.js +++ b/scripts/cypress/integration/test/restMisc.js @@ -2,7 +2,6 @@ let t0 = require("./explicitLogin"); let t01 = require("../common/00_pre_configurations"); let t6b = require("../common/6b_downloadCsv"); let t6c = require("../common/6c_swagger_api"); -let t6d = require("../common/6d_language_validation"); let t6e = require("../common/6e_project_operations"); let t6f = require("../common/6f_attachments"); let t6g = require("../common/6g_base_share"); @@ -15,25 +14,35 @@ const { const nocoTestSuite = (apiType, dbType) => { setCurrentMode(apiType, dbType); + + // Sakila Ext DB project creation t01.genTest(apiType, dbType); + // Download CSV t6b.genTest(apiType, dbType); - t6d.genTest(apiType, dbType); + + // // i18n + // t6d.genTest(apiType, dbType); + + // Swagger API // exclude@ncv2 t6c.genTest(apiType, dbType); + + // Attachment cell t6f.genTest(apiType, dbType); + // ERD t9b.genTest(apiType, dbType); - t6g.genTest(apiType, dbType); - - // webhook tests + // Webhook tests t8a.genTest(apiType, dbType); - // **deletes created project, hence place it @ end + // Base share (viewer, editor), iFrame tests + t6g.genTest(apiType, dbType); + + // Project operations: Delete t6e.genTest(apiType, dbType); - // intended to keep this after earlier project deletion - // creates project using excel & deletes it + // Create project from Excel t7a.genTest(apiType, dbType); }; diff --git a/scripts/cypress/integration/test/xcdb-restMisc.js b/scripts/cypress/integration/test/xcdb-restMisc.js index 31b8091486..84096b84ee 100644 --- a/scripts/cypress/integration/test/xcdb-restMisc.js +++ b/scripts/cypress/integration/test/xcdb-restMisc.js @@ -12,25 +12,39 @@ let t8a = require("../common/8a_webhook"); const { setCurrentMode, } = require("../../support/page_objects/projectConstants"); +const t9b = require("../common/9b_ERD"); const nocoTestSuite = (apiType, dbType) => { setCurrentMode(apiType, dbType); + + // Sakila Ext DB project creation t01.genTest(apiType, dbType); + // Download CSV t6b.genTest(apiType, dbType); - t6d.genTest(apiType, dbType); + + // i18n: language validation suffice to be done in REST MySQL suite + // t6d.genTest(apiType, dbType); + + // Swagger API // exclude@ncv2 t6c.genTest(apiType, dbType); + + // Attachment cell t6f.genTest(apiType, dbType); - t6g.genTest(apiType, dbType); - // webhook tests + // ERD: + // t9b.genTest(apiType, dbType); + + // Webhook tests t8a.genTest(apiType, dbType); - // **deletes created project, hence place it @ end + // Base share (viewer, editor), iFrame tests + t6g.genTest(apiType, dbType); + + // Project operations: Delete t6e.genTest(apiType, dbType); - // intended to keep this after earlier project deletion - // creates project using excel & deletes it + // Create project from Excel t7a.genTest(apiType, dbType); }; diff --git a/scripts/cypress/support/commands.js b/scripts/cypress/support/commands.js index a7feb162e2..64251d9554 100644 --- a/scripts/cypress/support/commands.js +++ b/scripts/cypress/support/commands.js @@ -149,7 +149,9 @@ Cypress.Commands.add("openTableTab", (tn, rc) => { // .contains(tn) // .should('exist') // .click(); - cy.wait(3000); + + // for some tables, linked records are not available immediately + cy.wait(1000); cy.get(".xc-row-table.nc-grid").should("exist"); @@ -480,8 +482,8 @@ Cypress.Commands.add("signOut", () => { .eq(1) .click(); - cy.wait(5000); - cy.get('button:contains("SIGN")').should("exist"); + // cy.wait(5000); + cy.get('button:contains("SIGN IN")').should("exist"); }); // Drag n Drop diff --git a/scripts/cypress/support/page_objects/navigation.js b/scripts/cypress/support/page_objects/navigation.js index 2712f19348..dbc33d53f1 100644 --- a/scripts/cypress/support/page_objects/navigation.js +++ b/scripts/cypress/support/page_objects/navigation.js @@ -97,6 +97,9 @@ export class _projectsPage { // for external database, {databaseType, hostAddress, portNumber, username, password, databaseName} openConfiguredProject(apiType, dbType) { + // http://localhost:8080/api/v1/db/meta/projects/p_kfxgmcd5jpyrje/users?limit=10&offset=0&query= + cy.intercept("/**/users?limit=*&offset=*&query=*").as("waitForPageLoad"); + if (dbType === "mysql") { projectsPage.openProject(staticProjects.externalREST.basic.name); } else if (dbType === "xcdb") { @@ -106,7 +109,9 @@ export class _projectsPage { } // kludge: wait for page load to finish - cy.wait(4000); + // cy.wait(4000); + cy.wait("@waitForPageLoad"); + // close team & auth tab cy.get("button.ant-tabs-tab-remove").should("exist").click(); cy.wait(1000);