diff --git a/package-lock.json b/package-lock.json index cbb33b9fbb..942733a13a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2656,6 +2656,11 @@ "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", "dev": true }, + "buffer-writer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz", + "integrity": "sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==" + }, "builtins": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/builtins/-/builtins-1.0.3.tgz", @@ -7654,6 +7659,11 @@ "p-reduce": "^1.0.0" } }, + "packet-reader": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz", + "integrity": "sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==" + }, "parallel-transform": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.2.0.tgz", @@ -7779,6 +7789,67 @@ "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" }, + "pg": { + "version": "8.7.3", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.7.3.tgz", + "integrity": "sha512-HPmH4GH4H3AOprDJOazoIcpI49XFsHCe8xlrjHkWiapdbHK+HLtbm/GQzXYAZwmPju/kzKhjaSfMACG+8cgJcw==", + "requires": { + "buffer-writer": "2.0.0", + "packet-reader": "1.0.0", + "pg-connection-string": "^2.5.0", + "pg-pool": "^3.5.1", + "pg-protocol": "^1.5.0", + "pg-types": "^2.1.0", + "pgpass": "1.x" + } + }, + "pg-connection-string": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.5.0.tgz", + "integrity": "sha512-r5o/V/ORTA6TmUnyWZR9nCj1klXCO2CEKNRlVuJptZe85QuhFayC7WeMic7ndayT5IRIR0S0xFxFi2ousartlQ==" + }, + "pg-int8": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", + "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==" + }, + "pg-pool": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.5.1.tgz", + "integrity": "sha512-6iCR0wVrro6OOHFsyavV+i6KYL4lVNyYAB9RD18w66xSzN+d8b66HiwuP30Gp1SH5O9T82fckkzsRjlrhD0ioQ==" + }, + "pg-protocol": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.5.0.tgz", + "integrity": "sha512-muRttij7H8TqRNu/DxrAJQITO4Ac7RmX3Klyr/9mJEOBeIpgnF8f9jAfRz5d3XwQZl5qBjF9gLsUtMPJE0vezQ==" + }, + "pg-types": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", + "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", + "requires": { + "pg-int8": "1.0.1", + "postgres-array": "~2.0.0", + "postgres-bytea": "~1.0.0", + "postgres-date": "~1.0.4", + "postgres-interval": "^1.1.0" + } + }, + "pgpass": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", + "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", + "requires": { + "split2": "^4.1.0" + }, + "dependencies": { + "split2": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.1.0.tgz", + "integrity": "sha512-VBiJxFkxiXRlUIeyMQi8s4hgvKCSjtknJv/LVYbrgALPwf5zSKmEwV9Lst25AkvMDnvxODugjdl6KZgwKM1WYQ==" + } + } + }, "pify": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", @@ -7815,6 +7886,29 @@ "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", "dev": true }, + "postgres-array": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", + "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==" + }, + "postgres-bytea": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", + "integrity": "sha1-AntTPAqokOJtFy1Hz5zOzFIazTU=" + }, + "postgres-date": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", + "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==" + }, + "postgres-interval": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", + "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", + "requires": { + "xtend": "^4.0.0" + } + }, "pretty-bytes": { "version": "5.6.0", "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", @@ -10030,8 +10124,7 @@ "xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "dev": true + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" }, "y18n": { "version": "4.0.3", diff --git a/package.json b/package.json index 374cfe0f36..b1e7d09111 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ }, "dependencies": { "mysql2": "^2.3.3", + "pg": "^8.7.3", "sqlite3": "^5.0.2" } } diff --git a/scripts/cypress/cypress.json b/scripts/cypress/cypress.json index 1b8b792f9b..ed881fc298 100644 --- a/scripts/cypress/cypress.json +++ b/scripts/cypress/cypress.json @@ -16,7 +16,11 @@ "test/xcdb-gqlTableOps.js", "test/xcdb-gqlViews.js", "test/xcdb-gqlRoles.js", - "test/xcdb-gqlMisc.js" + "test/xcdb-gqlMisc.js", + "test/pg-restTableOps.js", + "test/pg-restViews.js", + "test/pg-restRoles.js", + "test/pg-restMisc.js" ], "defaultCommandTimeout": 13000, "pageLoadTimeout": 600000, @@ -31,7 +35,8 @@ { "apiType": "rest", "dbType": "xcdb" }, { "apiType": "graphql", "dbType": "xcdb" }, { "apiType": "rest", "dbType": "mysql" }, - { "apiType": "graphql", "dbType": "mysql" } + { "apiType": "graphql", "dbType": "mysql" }, + { "apiType": "rest", "dbType": "postgres" } ], "db": { "host": "127.0.0.1", diff --git a/scripts/cypress/docker-compose.yml b/scripts/cypress/docker-compose.yml new file mode 100644 index 0000000000..24c60a0413 --- /dev/null +++ b/scripts/cypress/docker-compose.yml @@ -0,0 +1,17 @@ +version: "2.1" + +services: + pg96: + image: postgres:9.6 + restart: always + environment: + POSTGRES_PASSWORD: password + ports: + - 5432:5432 + volumes: + - ../../packages/nocodb/tests/pg-sakila-db:/docker-entrypoint-initdb.d + healthcheck: + test: ["CMD-SHELL", "pg_isready -U postgres"] + interval: 10s + timeout: 5s + retries: 5 diff --git a/scripts/cypress/integration/common/1c_sql_view.js b/scripts/cypress/integration/common/1c_sql_view.js index 346a607091..c9e6de7f68 100644 --- a/scripts/cypress/integration/common/1c_sql_view.js +++ b/scripts/cypress/integration/common/1c_sql_view.js @@ -91,7 +91,7 @@ export const genTest = (apiType, dbType) => { .should("exist"); mainPage .getCell(`FilmInfo`, 1) - .contains("Animation: ANACONDA CONFESSIONS;") + .contains("Animation: ANACONDA CONFESSIONS") .should("exist"); // Record-2 validation @@ -106,9 +106,7 @@ export const genTest = (apiType, dbType) => { .should("exist"); mainPage .getCell(`FilmInfo`, 2) - .contains( - "Action: BULL SHAWSHANK; Animation: FIGHT JAWBREAKER;" - ) + .contains("Action: BULL SHAWSHANK") .should("exist"); // Column operations: Hide @@ -135,7 +133,7 @@ export const genTest = (apiType, dbType) => { } }); - it.skip(`SQL View List`, () => { + it(`SQL View List`, () => { // confirm if other views exist // cy.openViewsTab("CustomerList", 25); diff --git a/scripts/cypress/integration/common/4f_pg_grid_view_share.js b/scripts/cypress/integration/common/4f_pg_grid_view_share.js new file mode 100644 index 0000000000..d78d11280c --- /dev/null +++ b/scripts/cypress/integration/common/4f_pg_grid_view_share.js @@ -0,0 +1,471 @@ +import { isTestSuiteActive } from "../../support/page_objects/projectConstants"; +import { mainPage } from "../../support/page_objects/mainPage"; + +let storedURL = ""; + +// 0: all enabled +// 1: field hide +// 2: field sort +// 3: field filter +// 4: default (address table): for view operation validation +// 5: default (country table): for update row/column validation +let viewURL = {}; + +export const genTest = (apiType, dbType) => { + if (!isTestSuiteActive(apiType, dbType)) return; + + const generateViewLink = (viewName) => { + // click on share view + // cy.get(".v-navigation-drawer__content > .container") + // .find(".v-list > .v-list-item") + // .contains("Share View") + // .click(); + mainPage.shareView().click(); + + // wait, as URL initially will be /undefined + cy.getActiveModal() + .find(".share-link-box") + .contains("/nc/view/", { timeout: 10000 }) + .should("exist"); + + // copy link text, visit URL + cy.getActiveModal() + .find(".share-link-box") + .contains("/nc/view/", { timeout: 10000 }) + .then(($obj) => { + cy.get("body").type("{esc}"); + // viewURL.push($obj.text()) + viewURL[viewName] = $obj.text().trim(); + }); + }; + + describe(`${apiType.toUpperCase()} api - GRID view (Share)`, () => { + // Run once before test- create project (rest/graphql) + // + before(() => { + // open a table to work on views + // + cy.openTableTab("Address", 25); + + cy.saveLocalStorage(); + }); + + beforeEach(() => { + cy.restoreLocalStorage(); + }); + + afterEach(() => { + cy.saveLocalStorage(); + }); + + after(() => { + // close table + // mainPage.deleteCreatedViews() + cy.closeTableTab("Address"); + }); + + // Common routine to create/edit/delete GRID & GALLERY view + // Input: viewType - 'grid'/'gallery' + // + const viewTest = (viewType) => { + it(`Create ${viewType.toUpperCase()} view`, () => { + // create a normal public view + cy.get(`.nc-create-${viewType}-view`).click(); + cy.getActiveModal().find("button:contains(Submit)").click(); + cy.toastWait("View created successfully"); + + // store base URL- to re-visit and delete form view later + cy.url().then((url) => { + storedURL = url; + }); + }); + + it(`Share ${viewType.toUpperCase()} hide, sort, filter & verify`, () => { + cy.get(`.nc-view-item.nc-${viewType}-view-item`) + .contains("Address1") + .click(); + mainPage.hideField("Address2"); + mainPage.sortField("Address", "Z -> A"); + mainPage.filterField("Address", "is like", "Ab"); + generateViewLink("combined"); + cy.log(viewURL["combined"]); + }); + + it(`Share GRID view : ensure we have only one link even if shared multiple times`, () => { + // generate view link multiple times + generateViewLink("combined"); + generateViewLink("combined"); + + // verify if only one link exists in table + // cy.get(".v-navigation-drawer__content > .container") + // .find(".v-list > .v-list-item") + // .contains("Share View") + // .parent() + // .find("button.mdi-dots-vertical") + // .click(); + mainPage.shareViewList().click(); + + // cy.getActiveMenu().find(".v-list-item").contains("Views List").click(); + + cy.get('th:contains("View Link")').should("exist"); + + cy.get('th:contains("View Link")') + .parent() + .parent() + .next() + .find("tr") + .its("length") + .should("eq", 1) + .then(() => { + // cy.get(".v-overlay__content > .d-flex > .v-icon").click(); + // close modal (fix me! add a close button to share view list modal) + cy.get(".v-overlay--active > .v-overlay__scrim").click({ + force: true, + }); + }); + }); + + it(`Share ${viewType.toUpperCase()} view : Visit URL, Verify title`, () => { + // visit public view + cy.visit(viewURL["combined"], { + baseUrl: null, + }); + + // wait for page rendering to complete + cy.get(".nc-grid-row").should("have.length", 18); + + // verify title + cy.get("div.model-name").contains("Address1").should("exist"); + }); + + it(`Share ${viewType.toUpperCase()} view : verify fields hidden/open`, () => { + // verify column headers + cy.get('[data-col="Address"]').should("exist"); + cy.get('[data-col="Address2"]').should("not.exist"); + cy.get('[data-col="District"]').should("exist"); + }); + + it(`Share ${viewType.toUpperCase()} view : verify fields sort/ filter`, () => { + // country column content verification before sort + mainPage + .getCell("Address", 1) + .contains("669 Firozabad Loop") + .should("exist"); + mainPage + .getCell("Address", 2) + .contains("48 Maracabo Place") + .should("exist"); + mainPage + .getCell("Address", 3) + .contains("44 Najafabad Way") + .should("exist"); + }); + + it(`Share ${viewType.toUpperCase()} view : verify download CSV`, () => { + mainPage.hideField("LastUpdate"); + const verifyCsv = (retrievedRecords) => { + // expected output, statically configured + let storedRecords = [ + `Address,District,PostalCode,Phone`, + `669 Firozabad Loop,,92265,,[object Object],2,,Kanchrapara,`, + `48 Maracabo Place,,1570,,[object Object],2,,Tafuna,`, + `44 Najafabad Way,,61391,,[object Object],2,,Tambaram,`, + `381 Kabul Way,,87272,,[object Object],1,,Pudukkottai,`, + ]; + + for (let i = 0; i < storedRecords.length; i++) { + let strCol = storedRecords[i].split(","); + let retCol = retrievedRecords[i].split(","); + expect(strCol[0]).to.be.equal(retCol[0]); + expect(strCol[2]).to.be.equal(retCol[2]); + // expect(retrievedRecords[i]).to.be.equal(storedRecords[i]) + } + }; + + // download & verify + mainPage.downloadAndVerifyCsv( + `Address_exported_1.csv`, + verifyCsv + ); + mainPage.unhideField("LastUpdate"); + }); + + it(`Share ${viewType.toUpperCase()} view : Disable sort`, () => { + // remove sort and validate + mainPage.clearSort(); + mainPage + .getCell("Address", 1) + .contains("217 Botshabelo Place") + .should("exist"); + }); + + it(`Share ${viewType.toUpperCase()} view : Enable sort`, () => { + // Sort menu operations (Country Column, Z->A) + mainPage.sortField("Address", "Z -> A"); + mainPage + .getCell("Address", 1) + .contains("669 Firozabad Loop") + .should("exist"); + }); + + it(`Share ${viewType.toUpperCase()} view : Create Filter`, () => { + // add filter & validate + mainPage.filterField("Address", "is like", "drive"); + // wait for page rendering to complete + cy.get(".nc-grid-row").should("have.length", 3); + mainPage + .getCell("Address", 1) + .contains("1888 Kabul Drive") + .should("exist"); + }); + + it(`Share ${viewType.toUpperCase()} view : verify download CSV after local filter`, () => { + mainPage.hideField("LastUpdate"); + const verifyCsv = (retrievedRecords) => { + // expected output, statically configured + let storedRecords = [ + `Address,District,PostalCode,Phone,Location,Address => Customer,Address => Staff,City <= Address,Address <=> Staff`, + `1888 Kabul Drive,,20936,,1,,Ife,,`, + `1661 Abha Drive,,14400,,1,,Pudukkottai,,`, + ]; + + // for (let i = 0; i < storedRecords.length; i++) { + // expect(retrievedRecords[i]).to.be.equal(storedRecords[i]) + // } + + for (let i = 0; i < storedRecords.length; i++) { + let strCol = storedRecords[i].split(","); + let retCol = retrievedRecords[i].split(","); + expect(strCol[0]).to.be.equal(retCol[0]); + expect(strCol[2]).to.be.equal(retCol[2]); + } + }; + mainPage.downloadAndVerifyCsv( + `Address_exported_1.csv`, + verifyCsv + ); + mainPage.unhideField("LastUpdate"); + }); + + it(`Share ${viewType.toUpperCase()} view : Delete Filter`, () => { + // Remove sort and Validate + mainPage.filterReset(); + mainPage + .getCell("Address", 1) + .contains("669 Firozabad Loop") + .should("exist"); + }); + + it(`Share GRID view : Virtual column validation > has many`, () => { + // verify column headers + cy.get('[data-col="Address => Customer"]').should("exist"); + cy.get('[data-col="Address => Staff"]').should("exist"); + cy.get('[data-col="City <= Address"]').should("exist"); + cy.get('[data-col="Address <=> Staff"]').should("exist"); + + // has many field validation + mainPage + .getCell("Address => Customer", 3) + .click() + .find("button.mdi-close-thick") + .should("not.exist"); + mainPage + .getCell("Address => Customer", 3) + .click() + .find("button.mdi-plus") + .should("not.exist"); + mainPage + .getCell("Address => Customer", 3) + .click() + .find("button.mdi-arrow-expand") + .click(); + + cy.getActiveModal().find("button.mdi-reload").should("exist"); + cy.getActiveModal() + .find("button") + .contains("Link to") + .should("not.exist"); + cy.getActiveModal() + .find(".child-card") + .contains("2") + .should("exist"); + cy.getActiveModal() + .find(".child-card") + .find("button") + .should("not.exist"); + cy.get("body").type("{esc}"); + }); + + it(`Share GRID view : Virtual column validation > belongs to`, () => { + // belongs to field validation + mainPage + .getCell("City <= Address", 1) + .click() + .find("button.mdi-close-thick") + .should("not.exist"); + mainPage + .getCell("City <= Address", 1) + .click() + .find("button.mdi-arrow-expand") + .should("not.exist"); + mainPage + .getCell("City <= Address", 1) + .find(".v-chip") + .contains("al-Ayn") + .should("exist"); + }); + + it(`Share GRID view : Virtual column validation > many to many`, () => { + // many-to-many field validation + mainPage + .getCell("Address <=> Staff", 1) + .click() + .find("button.mdi-close-thick") + .should("not.exist"); + mainPage + .getCell("Address <=> Staff", 1) + .click() + .find("button.mdi-plus") + .should("not.exist"); + mainPage + .getCell("Address <=> Staff", 1) + .click() + .find("button.mdi-arrow-expand") + .click(); + + cy.getActiveModal().find("button.mdi-reload").should("exist"); + cy.getActiveModal() + .find("button") + .contains("Link to") + .should("not.exist"); + cy.get("body").type("{esc}"); + }); + + it(`Delete ${viewType.toUpperCase()} view`, () => { + // go back to base page + cy.visit(storedURL, { + baseUrl: null, + }); + + // number of view entries should be 2 before we delete + cy.get(".nc-view-item").its("length").should("eq", 2); + + cy.get(".nc-view-delete-icon").eq(0).click({ force: true }); + cy.toastWait("View deleted successfully"); + + // confirm if the number of veiw entries is reduced by 1 + cy.get(".nc-view-item").its("length").should("eq", 1); + }); + }; + + // below scenario's will be invoked twice, once for rest & then for graphql + viewTest("grid"); + }); + + describe(`${apiType.toUpperCase()} api - Grid view/ row-column update verification`, () => { + before(() => { + // Address table has belongs to, has many & many-to-many + cy.openTableTab("Country", 25); + + cy.saveLocalStorage(); + // store base URL- to re-visit and delete form view later + cy.url().then((url) => { + storedURL = url; + generateViewLink("rowColUpdate"); + }); + }); + + after(() => { + // close table + cy.restoreLocalStorage(); + cy.visit(storedURL, { + baseUrl: null, + }); + + // delete row + mainPage.getPagination(5).click(); + // wait for page rendering to complete + cy.get(".nc-grid-row").should("have.length", 10); + mainPage + .getRow(10) + .find(".mdi-checkbox-blank-outline") + .click({ force: true }); + mainPage.getCell("Country", 10).rightclick(); + cy.getActiveMenu().contains("Delete Selected Row").click(); + + // delete column + cy.get(`th:contains('dummy') .mdi-menu-down`) + .trigger("mouseover") + .click(); + cy.get(".nc-column-delete").click(); + cy.get("button:contains(Confirm)").click(); + + cy.toastWait("Update table successful"); + + mainPage.deleteCreatedViews(); + + // close table + cy.closeTableTab("Country"); + }); + + it(`Generate default Shared GRID view URL`, () => { + // add row + cy.get(".nc-add-new-row-btn").click({ force: true }); + cy.get("#data-table-form-Country > input") + .first() + .click() + .type("a"); + cy.contains("Save Row").filter("button").click({ force: true }); + cy.toastWait("updated successfully"); + + // add column + mainPage.addColumn("dummy", "Country"); + + // visit public view + cy.log(viewURL["rowColUpdate"]); + cy.restoreLocalStorage(); + cy.visit(viewURL["rowColUpdate"], { + baseUrl: null, + }); //5 + // wait for public view page to load! + // wait for page rendering to complete + cy.get(".nc-grid-row").should("have.length", 25); + }); + + it(`Share GRID view : new row visible`, () => { + // verify row + cy.get(`.v-pagination > li:contains('5') button`).click(); + // wait for page rendering to complete + cy.get(".nc-grid-row").should("have.length", 10); + mainPage.getCell("Country", 10).contains("a").should("exist"); + }); + + it.skip(`Share GRID view : new column visible`, () => { + // verify column headers + cy.get('[data-col="dummy"]').should("exist"); + }); + }); +}; + +/** + * @copyright Copyright (c) 2021, Xgene Cloud Ltd + * + * @author Pranav C Balan + * @author Raju Udava + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ diff --git a/scripts/cypress/integration/test/pg-restMisc.js b/scripts/cypress/integration/test/pg-restMisc.js new file mode 100644 index 0000000000..103c99da4d --- /dev/null +++ b/scripts/cypress/integration/test/pg-restMisc.js @@ -0,0 +1,61 @@ +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"); +let t7a = require("../common/7a_create_project_from_excel"); +const { + setCurrentMode, +} = require("../../support/page_objects/projectConstants"); + +// use 0 as mode to execute individual files (debug mode, skip pre-configs) +// use 1 mode if noco.db doesnt contain user credentials (full run over GIT) +const executionMode = 1; + +const nocoTestSuite = (apiType, dbType) => { + setCurrentMode(apiType, dbType); + if (0 == executionMode) { + t0.genTest(apiType, dbType); + } else { + t01.genTest(apiType, dbType); + } + + t6b.genTest(apiType, dbType); + t6d.genTest(apiType, dbType); + t6c.genTest(apiType, dbType); + t6f.genTest(apiType, dbType); + t6g.genTest(apiType, dbType); + // **deletes created project, hence place it @ end + t6e.genTest(apiType, dbType); + + // intended to keep this after earlier project deletion + // creates project using excel & deletes it + t7a.genTest(apiType, dbType); +}; + +nocoTestSuite("rest", "postgres"); + +/** + * @copyright Copyright (c) 2021, Xgene Cloud Ltd + * + * @author Raju Udava + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ diff --git a/scripts/cypress/integration/test/pg-restRoles.js b/scripts/cypress/integration/test/pg-restRoles.js new file mode 100644 index 0000000000..4a4d2fdeb9 --- /dev/null +++ b/scripts/cypress/integration/test/pg-restRoles.js @@ -0,0 +1,47 @@ +let t0 = require("./explicitLogin"); +let t01 = require("../common/00_pre_configurations"); +let t5a = require("../common/5a_user_role"); +let t5b = require("../common/5b_preview_role"); +const { + setCurrentMode, +} = require("../../support/page_objects/projectConstants"); + +// use 0 as mode to execute individual files (debug mode, skip pre-configs) +// use 1 mode if noco.db doesnt contain user credentials (full run over GIT) +const executionMode = 1; + +const nocoTestSuite = (apiType, dbType) => { + setCurrentMode(apiType, dbType); + if (0 == executionMode) { + t0.genTest(apiType, dbType); + } else { + t01.genTest(apiType, dbType); + } + + t5a.genTest(apiType, dbType); + t5b.genTest(apiType, dbType); +}; + +nocoTestSuite("rest", "postgres"); + +/** + * @copyright Copyright (c) 2021, Xgene Cloud Ltd + * + * @author Raju Udava + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ diff --git a/scripts/cypress/integration/test/pg-restTableOps.js b/scripts/cypress/integration/test/pg-restTableOps.js new file mode 100644 index 0000000000..34fe517ad3 --- /dev/null +++ b/scripts/cypress/integration/test/pg-restTableOps.js @@ -0,0 +1,65 @@ +let t0 = require("./explicitLogin"); +let t01 = require("../common/00_pre_configurations"); +let t1a = require("../common/1a_table_operations"); +let t1b = require("../common/1b_table_column_operations"); +let t1c = require("../common/1c_sql_view"); +let t1d = require("../common/1d_table_view_drag_drop_reorder"); +let t1e = require("../common/1e_meta_sync"); +let t2a = require("../common/2a_table_with_belongs_to_colulmn"); +let t2b = require("../common/2b_table_with_m2m_column"); +let t3a = require("../common/3a_filter_sort_fields_operations"); +let t3b = require("../common/3b_formula_column"); +let t3c = require("../common/3c_lookup_column"); +let t3d = require("../common/3d_rollup_column"); +const { + setCurrentMode, +} = require("../../support/page_objects/projectConstants"); + +// use 0 as mode to execute individual files (debug mode, skip pre-configs) +// use 1 mode if noco.db doesnt contain user credentials (full run over GIT) +const executionMode = 1; + +const nocoTestSuite = (apiType, dbType) => { + setCurrentMode(apiType, dbType); + if (0 == executionMode) { + t0.genTest(apiType, dbType); + } else { + t01.genTest(apiType, dbType); + } + + t1a.genTest(apiType, dbType); + t1b.genTest(apiType, dbType); + t1c.genTest(apiType, dbType); + t1d.genTest(apiType, dbType); + t1e.genTest(apiType, dbType); + t2a.genTest(apiType, dbType); + t2b.genTest(apiType, dbType); + t3a.genTest(apiType, dbType); + // t3b.genTest(apiType, dbType); + t3c.genTest(apiType, dbType); + t3d.genTest(apiType, dbType); +}; + +nocoTestSuite("rest", "postgres"); + +/** + * @copyright Copyright (c) 2021, Xgene Cloud Ltd + * + * @author Raju Udava + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ diff --git a/scripts/cypress/integration/test/pg-restViews.js b/scripts/cypress/integration/test/pg-restViews.js new file mode 100644 index 0000000000..cefd93d29c --- /dev/null +++ b/scripts/cypress/integration/test/pg-restViews.js @@ -0,0 +1,55 @@ +let t0 = require("./explicitLogin"); +let t01 = require("../common/00_pre_configurations"); +let t4a = require("../common/4a_table_view_grid_gallery_form"); +let t4b = require("../common/4b_table_view_share"); +let t4c = require("../common/4c_form_view_detailed"); +let t4d = require("../common/4d_table_view_grid_locked"); +let t4e = require("../common/4e_form_view_share"); +let t4f = require("../common/4f_pg_grid_view_share"); +const { + setCurrentMode, +} = require("../../support/page_objects/projectConstants"); + +// use 0 as mode to execute individual files (debug mode, skip pre-configs) +// use 1 mode if noco.db doesnt contain user credentials (full run over GIT) +const executionMode = 1; + +const nocoTestSuite = (apiType, dbType) => { + setCurrentMode(apiType, dbType); + if (0 == executionMode) { + t0.genTest(apiType, dbType); + } else { + t01.genTest(apiType, dbType); + } + + t4a.genTest(apiType, dbType); + t4b.genTest(apiType, dbType); + t4c.genTest(apiType, dbType); + t4d.genTest(apiType, dbType); + t4e.genTest(apiType, dbType); + t4f.genTest(apiType, dbType); +}; + +nocoTestSuite("rest", "postgres"); + +/** + * @copyright Copyright (c) 2021, Xgene Cloud Ltd + * + * @author Raju Udava + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ diff --git a/scripts/cypress/plugins/index.js b/scripts/cypress/plugins/index.js index 48d064d70b..9209c32364 100644 --- a/scripts/cypress/plugins/index.js +++ b/scripts/cypress/plugins/index.js @@ -21,40 +21,48 @@ const readXlsx = require("./read-xlsx"); */ // eslint-disable-next-line no-unused-vars module.exports = (on, config) => { - // `on` is used to hook into various events Cypress emits - // `config` is the resolved Cypress config + // `on` is used to hook into various events Cypress emits + // `config` is the resolved Cypress config - // register utility tasks to read and parse Excel files - on("task", { - deleteFolder(folderName) { - console.log("deleting folder %s", folderName); + // register utility tasks to read and parse Excel files + on("task", { + deleteFolder(folderName) { + console.log("deleting folder %s", folderName); - return new Promise((resolve, reject) => { - rmdir(folderName, { maxRetries: 10, recursive: true }, (err) => { - if (err) { - console.error(err); + return new Promise((resolve, reject) => { + rmdir( + folderName, + { maxRetries: 10, recursive: true }, + (err) => { + if (err) { + console.error(err); - return reject(err); - } + return reject(err); + } - resolve(null); - }); - }); - }, - readXlsx: readXlsx.read, - readSheetList: readXlsx.sheetList, - log(message) { - console.log(`##Cypress>> ${message}`); - return null; - }, - queryDb: (query) => { - return queryTestDb(query, config); - }, - sqliteExec: (query) => { - _sqliteExec(query); - return null; - }, - }); + resolve(null); + } + ); + }); + }, + readXlsx: readXlsx.read, + readSheetList: readXlsx.sheetList, + log(message) { + console.log(`##Cypress>> ${message}`); + return null; + }, + queryDb: (query) => { + return queryTestDb(query, config); + }, + sqliteExec: (query) => { + _sqliteExec(query); + return null; + }, + pgExec: (query) => { + _pgExec(query); + return null; + }, + }); }; // mysql connection @@ -62,49 +70,70 @@ module.exports = (on, config) => { const mysql = require("mysql2"); function queryTestDb(query, config) { - // creates a new mysql connection using credentials from cypress.json env's - const connection = mysql.createConnection(config.env.db); - // start connection to db - connection.connect(); - // exec query + disconnect to db as a Promise - return new Promise((resolve, reject) => { - connection.query(query, (error, results) => { - if (error) reject(error); - else { - connection.end(); - // console.log(results) - return resolve(results); - } + // creates a new mysql connection using credentials from cypress.json env's + const connection = mysql.createConnection(config.env.db); + // start connection to db + connection.connect(); + // exec query + disconnect to db as a Promise + return new Promise((resolve, reject) => { + connection.query(query, (error, results) => { + if (error) reject(error); + else { + connection.end(); + // console.log(results) + return resolve(results); + } + }); }); - }); } // sqlite connection const sqlite3 = require("sqlite3").verbose(); function _sqliteExec(query) { - // open the database - console.log("Current directory: " + process.cwd()); - let db = new sqlite3.Database( - "./scripts/cypress/fixtures/sqlite-sakila/sakila.db", - sqlite3.OPEN_READWRITE, - (err) => { - if (err) { - console.error(err.message); - } else { - console.log("Connected to the noco xcdb database."); - } - } - ); + // open the database + console.log("Current directory: " + process.cwd()); + let db = new sqlite3.Database( + "./scripts/cypress/fixtures/sqlite-sakila/sakila.db", + sqlite3.OPEN_READWRITE, + (err) => { + if (err) { + console.error(err.message); + } else { + console.log("Connected to the noco xcdb database."); + } + } + ); + + db.serialize(() => { + db.run(query); + }); - db.serialize(() => { - db.run(query); - }); + db.close((err) => { + if (err) { + console.error(err.message); + } else { + console.log("Close the database connection."); + } + }); +} - db.close((err) => { - if (err) { - console.error(err.message); - } else { - console.log("Close the database connection."); - } - }); +// pg connection +const { Pool, Client } = require("pg"); +const pg_credentials = { + user: "postgres", + host: "localhost", + database: "postgres", + password: "password", + port: 5432, +}; +function _pgExec(query) { + // open pg client connection + const client = new Client(pg_credentials); + client.connect(); + + // query & terminate + client.query(query, (err, res) => { + console.log(err, res); + client.end(); + }); } diff --git a/scripts/cypress/support/page_objects/mainPage.js b/scripts/cypress/support/page_objects/mainPage.js index 3503cfd2b9..6a81dc7848 100644 --- a/scripts/cypress/support/page_objects/mainPage.js +++ b/scripts/cypress/support/page_objects/mainPage.js @@ -278,9 +278,9 @@ export class _mainPage { cy.get(".nc-sort-menu-btn").click(); cy.contains("Add Sort Option").click(); cy.get(".nc-sort-field-select div").first().click(); - cy.get( - `.menuable__content__active .v-list-item:contains(${field})` - ).click(); + cy.get(`.menuable__content__active .v-list-item:contains(${field})`) + .first() + .click(); cy.get(".nc-sort-dir-select div").first().click(); cy.get( `.menuable__content__active .v-list-item:contains(${criteria})`