From 163aba26b38a56b8cbf50978d6e60b48f0883ebb Mon Sep 17 00:00:00 2001 From: Pranav C Date: Sat, 28 Aug 2021 01:43:48 +0530 Subject: [PATCH] test(cypress): Common test for GQL & Rest, Filter , Test for filter, row creation, etc... Signed-off-by: Pranav C --- cypress.json | 3 +- .../filter_sort_fields_operations_spec.js | 155 +++++++++++++++ .../common/table_operations_spec.js | 174 +++++++++++++++++ .../graphql/project_operations_spec.js | 14 +- .../integration/rest/api_operations_spec.js | 74 ------- .../rest/project_operations_spec.js | 18 +- .../integration/rest/table_operations_spec.js | 120 ------------ cypress/integration/rest/table_view_spec.js | 36 ++++ cypress/integration/rest/users_spec.js | 25 +++ cypress/support/commands.js | 184 +++++++++++++++--- docker-compose-cypress.yml | 1 + package-lock.json | 6 + package.json | 1 + .../nc-gui/components/auth/userManagement.vue | 2 +- .../spreadsheet/components/columnFilter.vue | 2 +- .../spreadsheet/components/sortListMenu.vue | 2 +- .../components/spreadsheetNavDrawer.vue | 9 +- .../project/spreadsheet/views/xcGridView.vue | 2 +- packages/nc-lib-gui/package.json | 4 +- 19 files changed, 598 insertions(+), 234 deletions(-) create mode 100644 cypress/integration/common/filter_sort_fields_operations_spec.js create mode 100644 cypress/integration/common/table_operations_spec.js delete mode 100644 cypress/integration/rest/api_operations_spec.js delete mode 100644 cypress/integration/rest/table_operations_spec.js create mode 100644 cypress/integration/rest/table_view_spec.js create mode 100644 cypress/integration/rest/users_spec.js diff --git a/cypress.json b/cypress.json index 89c97246ea..b1d7d699f5 100644 --- a/cypress.json +++ b/cypress.json @@ -4,5 +4,6 @@ "pageLoadTimeout": 600000, "viewportWidth": 1800, "viewportHeight": 1000, - "video": false + "video": false, + "retries": 2 } diff --git a/cypress/integration/common/filter_sort_fields_operations_spec.js b/cypress/integration/common/filter_sort_fields_operations_spec.js new file mode 100644 index 0000000000..b523557b44 --- /dev/null +++ b/cypress/integration/common/filter_sort_fields_operations_spec.js @@ -0,0 +1,155 @@ +const genTest = (type) => { + + describe(`${type.toUpperCase()} api - Filter, Fields, Sort`, () => { + + before(() => { + cy.waitForSpinners(); + if (type === 'rest') { + cy.openOrCreateRestProject({ + new: true + }); + } else { + cy.openOrCreateGqlProject({ + new: true + }); + } + + // open country table + cy.openTableTab('Country'); + // cy.intercept({ + // method: "GET", + // url: "/nc/**/api/v1/Country**", + // hostname: 'localhost', + // port: 8080 + // }).as("dataGetFirst"); + // cy.wait("@dataGetFirst"); + // todo: wait until api call completes + cy.wait(2000) + + }) + + // check pagination + it('Check country table - ', () => { + cy.get('.nc-pagination').should('exist'); + cy.get('.nc-pagination .v-pagination > li:last-child').click() + cy.get('.nc-pagination .v-pagination > li:contains(2) button').should('have.class', 'v-pagination__item--active') + + cy.get('.nc-pagination .v-pagination > li:first-child').click() + }); + + // create new row + it('Create new row', () => { + cy.get('.nc-add-new-row-btn').click(); + + cy.get('#data-table-form-Country > input').first().type('Test Country'); + + cy.contains('Save Row').filter('button').click() + + // todo: verify + }) + + // Test sort + it('Add sort option', () => { + 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(Country)').click() + cy.get('.nc-sort-dir-select div').first().click() + cy.get('.menuable__content__active .v-list-item:contains("Z -> A")').click() + cy.contains('Zambia').should('exist') + + // remove sort and check + cy.get('.nc-sort-item-remove-btn').click() + cy.contains('Zambia').should('not.exist') + }) + + + // Test fields + it.only('Add fields options', () => { + + cy.get('th:contains(LastUpdate)').should('be.visible') + + // toggle and confirm it's hidden + cy.get('.nc-fields-menu-btn').click() + cy.get('.menuable__content__active .v-list-item label:contains(LastUpdate)').click() + cy.get('th:contains(LastUpdate)').should('not.be.visible') + + + // toggle and confirm it's visible + // cy.get('.nc-fields-menu-btn').click() + cy.get('.menuable__content__active .v-list-item label:contains(LastUpdate)').click() + cy.get('th:contains(LastUpdate)').should('be.visible') + + + // drag fields + cy.get('.v-window-item--active .nc-grid tr > th:last button').click({force: true}); + cy.get('.nc-column-name-input input').clear().type('new_column1') + cy.get('.nc-col-create-or-edit-card').contains('Save').click() + cy.get('.v-window-item--active .nc-grid tr > th:last button').click({force: true}); + cy.get('.nc-column-name-input input').clear().type('new_column2') + cy.get('.nc-col-create-or-edit-card').contains('Save').click() + + // cy.get('.menuable__content__active .v-list-item label:contains(Country)').closest('.v-list-item').dragTo('.v-list-item:has(.menuable__content__active .v-list-item label:contains(LastUpdate)') + /* cy.get('.nc-fields-menu-btn').click() + + + cy.get('.menuable__content__active .v-list-item').eq(1).invoke('attr','draggable', 'true') + + cy.get('.menuable__content__active .v-list-item').eq(1).drag('.menuable__content__active .v-list > d') + cy.get('.menuable__content__active .v-list-item').eq(1).move({x: 100, y: 100}) + + + cy.get('.menuable__content__active .v-list-item').then($el => { + const draggable = $el[1]; // Cypress.$('.menuable__content__active .v-list-item label:contains(Country)').closest('.v-list-item')[0] // Pick up this + const droppable = $el[$el.length - 3]; + draggable.setAttribute('draggable', 'true') + // console.log(draggable, droppable) + // const coords = droppable.getBoundingClientRect() + // cy.wrap(draggable).click().dragTo(droppable) + + + // cy.wrap(draggable).trigger("dragstart"); + // cy.wrap(droppable).trigger("drop"); + + // cy.wrap(draggable).drop(droppable); + + + // draggable.parentElement.dispatchEvent(new MouseEvent('dragenter')) + // draggable.parentElement.dispatchEvent(new MouseEvent('dragover')) + // draggable.dispatchEvent(new MouseEvent('pointerdown')) + // draggable.dispatchEvent(new MouseEvent('mousemove')); + // draggable.dispatchEvent(new MouseEvent('mousedown')); + // draggable.dispatchEvent(new MouseEvent('mousemove', {clientX: 10, clientY: 0})); + // draggable.dispatchEvent(new MouseEvent('mousemove', {clientX: coords.x + 10, clientY: coords.y + 10})); + // draggable.dispatchEvent(new MouseEvent('mouseup')); + })*/ + + }) + + + // Test filter + it('Add filter options', () => { + cy.get('.nc-filter-menu-btn').click() + cy.contains('Add Filter').click(); + + cy.get('.nc-filter-field-select').last().click(); + cy.get('.menuable__content__active .v-list-item:contains(Country)').click() + cy.get('.nc-filter-operation-select').last().click(); + cy.get('.menuable__content__active .v-list-item:contains("is equal")').click() + cy.get('.nc-filter-value-select input:text').last().type('India'); + + cy.get('td:contains(India)').should('exist') + + + // remove sort and check + cy.get('.nc-filter-item-remove-btn').click() + cy.contains('td:contains(India)').should('not.exist') + + }) + + }) +} + + +genTest('rest') +genTest('graphql') diff --git a/cypress/integration/common/table_operations_spec.js b/cypress/integration/common/table_operations_spec.js new file mode 100644 index 0000000000..dae2d6e6df --- /dev/null +++ b/cypress/integration/common/table_operations_spec.js @@ -0,0 +1,174 @@ +const genTest = (type) => { + + describe(`${type.toUpperCase()} api - Table`, () => { + + before(() => { + cy.waitForSpinners(); + if (type === 'rest') { + cy.openOrCreateRestProject({ + new: true + }); + } else { + cy.openOrCreateGqlProject({ + new: true + }); + } + + const randVal = 'Test' + Date.now(); + const updatedRandVal = 'Updated' + Date.now(); + const name = 'Test' + Date.now(); + + before(() => { + cy.waitForSpinners(); + cy.openOrCreateRestProject(); + }) + + // create a new random table + it('Create Table', () => { + cy.get('.add-btn').click(); + cy.get('.nc-create-table-card .nc-table-name input[type="text"]').first().click().clear().type(name) + cy.get('.nc-create-table-card .nc-table-name-alias input[type="text"]').first().should('have.value', name.toLowerCase()) + cy.wait(5000) + cy.get('.nc-create-table-card .nc-create-table-submit').first().click() + cy.get(`.project-tab:contains(${name})`).should('exist') + cy.url().should('contain', `?name=${name}&`) + }); + + + // create new row + it('Create/Edit/Delete row', () => { + // add new row + cy.get('.nc-add-new-row-btn').click(); + + cy.get('#data-table-form-Title > input').first().type(randVal); + + cy.contains('Save Row').filter('button').click() + + cy.get('td').contains(randVal).should('exist'); + + // update row + cy.get('td').contains(randVal) + .closest('tr') + .find('.nc-row-expand-icon') + .click(); + + + cy.get('#data-table-form-Title > input').first().clear().type(updatedRandVal); + cy.contains('Save Row').filter('button').click() + + cy.get('td').contains(updatedRandVal).should('exist'); + cy.get('td').contains(randVal).should('not.exist'); + + cy.get('td').contains(updatedRandVal).rightclick() + + // delete row + cy.getActiveMenu().find('.v-list-item:contains("Delete Row")').first().click() + cy.wait(1000) + cy.get('td').contains(randVal).should('not.exist'); + }) + + + // add new column to newly created table + it('Create Table Column', () => { + cy.get('.nc-project-tree').find('.v-list-item__title:contains(Tables)', {timeout: 10000}) + .first().click() + + cy.get('.nc-project-tree').contains(name, {timeout: 6000}).first().click({force: true}); + + cy.get(`.project-tab:contains(${name}):visible`).should('exist') + + cy.get('.v-window-item--active .nc-grid tr > th:last button').click({force: true}); + cy.get('.nc-column-name-input input').clear().type('new_column') + cy.get('.nc-col-create-or-edit-card').contains('Save').click() + cy + .get('th:contains(new_column)') + .should('exist'); + }); + + // edit the newly created column + it('Edit table column - rename & uidt update', () => { + + + cy.get('th:contains(new_column) .mdi-menu-down') + .trigger('mouseover', {force: true}) + .click({force: true}) + + cy.get('.nc-column-edit').click() + + + // change column type and verify + cy.get('.nc-ui-dt-dropdown').click() + cy.contains('LongText').click() + cy.get('.nc-col-create-or-edit-card').contains('Save').click() + + cy.get('th[data-col="new_column"] .mdi-text-subject').should('exist') + + + cy.get('th:contains(new_column) .mdi-menu-down') + .trigger('mouseover', {force: true}) + .click({force: true}) + + cy.get('.nc-column-edit').click() + + // rename column and verify + cy.get('.nc-column-name-input input').clear().type('updated_column') + cy.get('.nc-col-create-or-edit-card').contains('Save').click() + + + cy + .get('th:contains(updated_column)') + .should('exist'); + cy + .get('th:contains(new_column)') + .should('not.exist'); + + + }) + + + // delete the newly created column + it('Delete table column', () => { + cy + .get('th:contains(updated_column)') + .should('exist'); + + cy.get('th:contains(updated_column) .mdi-menu-down') + .trigger('mouseover') + .click() + + cy.get('.nc-column-delete').click() + cy.get('button:contains(Confirm)').click() + + + cy + .get('th:contains(updated_column)') + .should('not.exist'); + + }) + + + // delete newly created table + it('Delete Table', () => { + + cy.get('.nc-project-tree').find('.v-list-item__title:contains(Tables)', {timeout: 10000}) + .first().click() + + cy.get('.nc-project-tree').contains(name, {timeout: 6000}).first().click({force: true}); + + cy.get(`.project-tab:contains(${name}):visible`).should('exist') + + cy.get('.nc-table-delete-btn:visible').click() + + cy.get('button:contains(Submit)').click() + cy.get(`.project-tab:contains(${name}):visible`).first().should('not.exist') + }); + + + }) + }); +} + + +genTest('rest') +genTest('graphql') + diff --git a/cypress/integration/graphql/project_operations_spec.js b/cypress/integration/graphql/project_operations_spec.js index 49ae751654..3d4ecc21a5 100644 --- a/cypress/integration/graphql/project_operations_spec.js +++ b/cypress/integration/graphql/project_operations_spec.js @@ -1,12 +1,19 @@ describe('GraphQL Project operations', () => { beforeEach(() => { + cy.restoreLocalStorage(); + }); + + afterEach(() => { + cy.saveLocalStorage(); + }); + + before(() => { cy.waitForSpinners(); cy.signinOrSignup(); }) it('Create Project', () => { - // cy.visit('') cy.contains('New Project').trigger('onmouseover').trigger('mouseenter'); cy.get('.create-external-db-project').click() cy.url({timeout: 6000}).should('contain', '#/project/') @@ -18,21 +25,24 @@ describe('GraphQL Project operations', () => { }); it('Stop Project', () => { - cy.wait(100000) + cy.visit('./#/projects') // cy.get('.nc-graphql-project-row .mdi-stop-circle-outline', {timeout: 10000}).last().trigger('onmouseover').trigger('mouseenter') cy.get('.nc-graphql-project-row .mdi-stop-circle-outline', {timeout: 10000}).last().invoke('show').click(); cy.contains('Submit').closest('button').click(); }); it('Start Project', () => { + cy.visit('./#/projects') cy.get('.nc-graphql-project-row .mdi-play-circle-outline', {timeout: 10000}).last().invoke('show').click(); cy.contains('Submit').closest('button').click(); }); it('Restart Project', () => { + cy.visit('./#/projects') cy.get('.nc-graphql-project-row .mdi-restart', {timeout: 10000}).last().invoke('show').click(); cy.contains('Submit').closest('button').click(); }); it('Delete Project', () => { + cy.visit('./#/projects') cy.get('.nc-graphql-project-row .mdi-delete-circle-outline', {timeout: 10000}).last().invoke('show').click(); cy.contains('Submit').closest('button').click(); }); diff --git a/cypress/integration/rest/api_operations_spec.js b/cypress/integration/rest/api_operations_spec.js deleted file mode 100644 index af84ee632c..0000000000 --- a/cypress/integration/rest/api_operations_spec.js +++ /dev/null @@ -1,74 +0,0 @@ -describe('Rest api - CRUD/Filter', () => { - - before(() => { - cy.waitForSpinners(); - cy.openOrCreateRestProject(); - - // open country table - cy.openTableTab('Country'); - // cy.intercept({ - // method: "GET", - // url: "/nc/**/api/v1/Country**", - // hostname: 'localhost', - // port: 8080 - // }).as("dataGetFirst"); - // cy.wait("@dataGetFirst"); - // todo: wait until api call completes - cy.wait(2000) - - }) - - // check pagination - it('Check country table - ', () => { - cy.get('.nc-pagination').should('exist'); - cy.get('.nc-pagination .v-pagination > li:last-child').click() - cy.get('.nc-pagination .v-pagination > li:contains(2)').should('have.class', 'v-pagination__item--active') - }); - - // create new row - it('Create new row', () => { - cy.get('.nc-add-new-row-btn').click(); - - cy.get('#data-table-form-Country > input').first().type('Test Country'); - - cy.contains('Save Row').filter('button').click() - - // todo: verify - }) - - // Test sort - it('Add sort option', () => { - 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(Country)').click() - cy.get('.nc-sort-dir-select div').first().click() - cy.get('.menuable__content__active .v-list-item:contains("Z -> A")').click() - cy.contains('Zambia').should('exist') - }) - - - // Test fields - it('Add fields options', () => { - cy.get('.nc-fields-menu-btn').click() - cy.get('.menuable__content__active .v-list-item label:contains(LastUpdate)').click() - cy.get('th:contains(LastUpdate)').should('not.exist') - }) - - - // Test filter - it('Add filter options', () => { - cy.get('.nc-filter-menu-btn').click() - cy.contains('Add Filter').click(); - - cy.get('.nc-filter-field-select').last().click(); - cy.get('.menuable__content__active .v-list-item:contains(Country)').click() - cy.get('.nc-filter-operation-select').last().click(); - cy.get('.menuable__content__active .v-list-item:contains("is equal")').click() - cy.get('.nc-filter-value-select input:text').last().type('India'); - - cy.get('td:contains(India)').should('exist') - - }) - -}) diff --git a/cypress/integration/rest/project_operations_spec.js b/cypress/integration/rest/project_operations_spec.js index 237c88e323..541802f173 100644 --- a/cypress/integration/rest/project_operations_spec.js +++ b/cypress/integration/rest/project_operations_spec.js @@ -1,34 +1,46 @@ describe('Rest Project operations', () => { - beforeEach(() => { + cy.restoreLocalStorage(); + }); + + afterEach(() => { + cy.saveLocalStorage(); + }); + + before(() => { cy.waitForSpinners(); cy.signinOrSignup(); }) it('Create Project', () => { - // cy.visit('') cy.contains('New Project').trigger('onmouseover').trigger('mouseenter'); cy.get('.create-external-db-project').click() - cy.url({timeout: 6000}).should('contain', '#/project') + cy.url({timeout: 6000}).should('contain', '#/project/') cy.get('.database-field input').click().clear().type('dummy_db') cy.contains('Test Database Connection').click() cy.contains('Ok & Save Project', {timeout: 3000}).click() cy.url({timeout: 12000}).should('contain', '#/nc/') }); + it('Stop Project', () => { + cy.visit('./#/projects') // cy.get('.nc-rest-project-row .mdi-stop-circle-outline', {timeout: 10000}).last().trigger('onmouseover').trigger('mouseenter') cy.get('.nc-rest-project-row .mdi-stop-circle-outline', {timeout: 10000}).last().invoke('show').click(); cy.contains('Submit').closest('button').click(); }); + it('Start Project', () => { + cy.visit('./#/projects') cy.get('.nc-rest-project-row .mdi-play-circle-outline', {timeout: 10000}).last().invoke('show').click(); cy.contains('Submit').closest('button').click(); }); it('Restart Project', () => { + cy.visit('./#/projects') cy.get('.nc-rest-project-row .mdi-restart', {timeout: 10000}).last().invoke('show').click(); cy.contains('Submit').closest('button').click(); }); it('Delete Project', () => { + cy.visit('./#/projects') cy.get('.nc-rest-project-row .mdi-delete-circle-outline', {timeout: 10000}).last().invoke('show').click(); cy.contains('Submit').closest('button').click(); }); diff --git a/cypress/integration/rest/table_operations_spec.js b/cypress/integration/rest/table_operations_spec.js deleted file mode 100644 index a81492d474..0000000000 --- a/cypress/integration/rest/table_operations_spec.js +++ /dev/null @@ -1,120 +0,0 @@ -describe('Rest api - Table', () => { - - const name = 'Test' + Date.now(); - - before(() => { - cy.waitForSpinners(); - cy.openOrCreateRestProject(); - }) - - // create a new random table - it('Create Table', () => { - cy.get('.add-btn').click(); - cy.get('.nc-create-table-card .nc-table-name input[type="text"]').first().click().clear().type(name) - cy.get('.nc-create-table-card .nc-table-name-alias input[type="text"]').first().should('have.value', name.toLowerCase()) - cy.wait(5000) - cy.get('.nc-create-table-card .nc-create-table-submit').first().click() - cy.get(`.project-tab:contains(${name})`).should('exist') - cy.url().should('contain', `?name=${name}&`) - }); - - - // add new column to newly created table - it('Create Table Column', () => { - cy.get('.nc-project-tree').find('.v-list-item__title:contains(Tables)', {timeout: 10000}) - .first().click() - - cy.get('.nc-project-tree').contains(name, {timeout: 6000}).first().click({force: true}); - - cy.get(`.project-tab:contains(${name}):visible`).should('exist') - - cy.get('.v-window-item--active .nc-grid tr > th:last button').click({force: true}); - cy.get('.nc-column-name-input input').clear().type('new_column') - cy.get('.nc-col-create-or-edit-card').contains('Save').click() - cy - .get('th:contains(new_column)') - .should('exist'); - }); - - // edit the newly created column - it('Edit table column - rename & uidt update', () => { - - - cy.get('th:contains(new_column) .mdi-menu-down') - .trigger('mouseover') - .click() - - cy.get('.nc-column-edit').click() - - - // change column type and verify - cy.get('.nc-ui-dt-dropdown').click() - cy.contains('LongText').click() - cy.get('.nc-col-create-or-edit-card').contains('Save').click() - - cy.get('th[data-col="new_column"] .mdi-text-subject').should('exist') - - - cy.get('th:contains(new_column) .mdi-menu-down') - .trigger('mouseover') - .click() - - cy.get('.nc-column-edit').click() - - // rename column and verify - cy.get('.nc-column-name-input input').clear().type('updated_column') - cy.get('.nc-col-create-or-edit-card').contains('Save').click() - - - cy - .get('th:contains(updated_column)') - .should('exist'); - cy - .get('th:contains(new_column)') - .should('not.exist'); - - - }) - - - // delete the newly created column - it('Delete table column', () => { - cy - .get('th:contains(updated_column)') - .should('exist'); - - cy.get('th:contains(updated_column) .mdi-menu-down') - .trigger('mouseover') - .click() - - cy.get('.nc-column-delete').click() - cy.get('button:contains(Confirm)').click() - - - cy - .get('th:contains(updated_column)') - .should('not.exist'); - - }) - - - // delete newly created table - it('Delete Table', () => { - - cy.get('.nc-project-tree').find('.v-list-item__title:contains(Tables)', {timeout: 10000}) - .first().click() - - cy.get('.nc-project-tree').contains(name, {timeout: 6000}).first().click({force: true}); - - cy.get(`.project-tab:contains(${name}):visible`).should('exist') - - cy.get('.nc-table-delete-btn:visible').click() - - cy.get('button:contains(Submit)').click() - cy.get(`.project-tab:contains(${name}):visible`).first().should('not.exist') - }); - - - - -}) diff --git a/cypress/integration/rest/table_view_spec.js b/cypress/integration/rest/table_view_spec.js new file mode 100644 index 0000000000..379254dea9 --- /dev/null +++ b/cypress/integration/rest/table_view_spec.js @@ -0,0 +1,36 @@ +describe('Rest api - Table', () => { + + const name = 'Test' + Date.now(); + + before(() => { + cy.waitForSpinners(); + cy.openOrCreateRestProject(); + cy.openTableTab('Country'); + }) + + it('Create grid view', () => { + cy.get('.nc-create-grid-view').click(); + cy.getActiveModal().find('button:contains(Submit)').click() + cy.get('.nc-view-item.nc-grid-view-item').should('exist') + }) + it('Create gallery view', () => { + cy.get('.nc-create-gallery-view').click(); + cy.getActiveModal().find('button:contains(Submit)').click() + cy.get('.nc-view-item.nc-gallery-view-item').should('exist') + }) +/* it('Delete grid view', () => { + cy.get('.nc-view-item.nc-grid-view-item').then($items => { + cy.get('.nc-view-item.nc-grid-view-item .nc-view-delete-icon').last().invoke('show').click() + expect(Cypress.$('.nc-view-item.nc-grid-view-item').length).to.be.lt($items.length) + }) + }) + it('Delete gallery view', () => { + cy.get('.nc-view-item.nc-gallery-view-item').then($items => { + cy.get('.nc-view-item.nc-gallery-view-item .nc-view-delete-icon').last().invoke('show').click() + expect(Cypress.$('.nc-view-item.nc-gallery-view-item').length).to.be.lt($items.length) + }) + + })*/ + + +}) diff --git a/cypress/integration/rest/users_spec.js b/cypress/integration/rest/users_spec.js new file mode 100644 index 0000000000..af8898d49b --- /dev/null +++ b/cypress/integration/rest/users_spec.js @@ -0,0 +1,25 @@ +describe('User mana', () => { + const email = `noco${Date.now()}@gmail.com`; + + before(() => { + cy.waitForSpinners(); + cy.openOrCreateRestProject(); + }) + + + it('Add new user', () => { + cy.get('.v-list-item:contains("Team & Auth")').click(); + + cy.get(`.project-tab:contains("Team & Auth"):visible`).should('exist') + cy.get(`td:contains("pranavc@gmail.com")`).should('exist') + + cy.get('button:contains("New User")').first().click() + + cy.get('label:contains(Email)').next('input').type(email) + + cy.get('.nc-invite-or-save-btn').click() + + }) + + +}) diff --git a/cypress/support/commands.js b/cypress/support/commands.js index b2662249fe..8b574edfa7 100644 --- a/cypress/support/commands.js +++ b/cypress/support/commands.js @@ -24,6 +24,8 @@ // -- This will overwrite an existing command -- // Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... }) +require('@4tw/cypress-drag-drop') + // for waiting until page load Cypress.Commands.add('waitForSpinners', () => { cy.visit('http://localhost:3000', { @@ -33,7 +35,7 @@ Cypress.Commands.add('waitForSpinners', () => { "Accept-Encoding": "gzip, deflate" } }) - cy.get('#nuxt-loading', {timeout: 10_000}).should('have.length', 0) + cy.get('#nuxt-loading', {timeout: 10_0000}).should('have.length', 0) }) Cypress.Commands.add('signinOrSignup', () => { @@ -63,28 +65,30 @@ Cypress.Commands.add('signinOrSignup', () => { }) }); // for opening/creating a rest project -Cypress.Commands.add('openOrCreateRestProject', () => { +Cypress.Commands.add('openOrCreateRestProject', (_args) => { + const args = Object.assign({new: false}, _args) - // signin/signup - cy.signinOrSignup() - cy.wait(2000); - cy.get('body').then($body => { - // if project exist open - if ($body.find('.nc-rest-project-row').length) { - cy.get('.nc-rest-project-row').first().click() - // create new project - } else { - cy.contains('New Project').trigger('onmouseover').trigger('mouseenter'); - cy.get('.create-external-db-project').click() - cy.url({timeout: 6000}).should('contain', '#/project') - cy.get('.database-field input').click().clear().type('sakila') - cy.contains('Test Database Connection').click() - cy.contains('Ok & Save Project', {timeout: 3000}).click() - } - }) - cy.url({timeout: 20000}).should('contain', '#/nc/') + // signin/signup + cy.signinOrSignup() + cy.wait(2000); + cy.get('body').then($body => { + // if project exist open + if ($body.find('.nc-rest-project-row').length && !args.new) { + cy.get('.nc-rest-project-row').first().click() + // create new project + } else { + cy.contains('New Project').trigger('onmouseover').trigger('mouseenter'); + cy.get('.create-external-db-project').click() + cy.url({timeout: 6000}).should('contain', '#/project') + cy.get('.database-field input').click().clear().type('sakila') + cy.contains('Test Database Connection').click() + cy.contains('Ok & Save Project', {timeout: 3000}).click() + } + }) + cy.url({timeout: 20000}).should('contain', '#/nc/') -}) + } +) Cypress.Commands.add('openTableTab', (tn) => { @@ -96,8 +100,8 @@ Cypress.Commands.add('openTableTab', (tn) => { cy.get(`.project-tab:contains(${tn}):visible`).should('exist') }); -Cypress.Commands.add('openOrCreateGqlProject', () => { - +Cypress.Commands.add('openOrCreateGqlProject', (_args) => { + const args = Object.assign({new: false}, _args) cy.signinOrSignup() @@ -105,7 +109,7 @@ Cypress.Commands.add('openOrCreateGqlProject', () => { cy.wait(2000); cy.get('body').then($body => { // if project exist open - if ($body.find('.nc-graphql-project-row').length) { + if ($body.find('.nc-graphql-project-row').length && !args.new) { cy.get('.nc-graphql-project-row').first().click() // create new project } else { @@ -122,5 +126,137 @@ Cypress.Commands.add('openOrCreateGqlProject', () => { }) +let LOCAL_STORAGE_MEMORY = {}; + +Cypress.Commands.add("saveLocalStorage", () => { + Object.keys(localStorage).forEach(key => { + LOCAL_STORAGE_MEMORY[key] = localStorage[key]; + }); +}); + +Cypress.Commands.add("restoreLocalStorage", () => { + Object.keys(LOCAL_STORAGE_MEMORY).forEach(key => { + localStorage.setItem(key, LOCAL_STORAGE_MEMORY[key]); + }); +}); + +Cypress.Commands.add("getActiveModal", () => { + return cy.get('.v-dialog.v-dialog--active') +}); + +Cypress.Commands.add("getActiveMenu", () => { + return cy.get('.menuable__content__active') +}); + + + +// Drag n Drop +// refer: https://stackoverflow.com/a/55409853 + +const getCoords = ($el) => { + const domRect = $el[0].getBoundingClientRect() + const coords = { x: domRect.left + (domRect.width / 2 || 0), y: domRect.top + (domRect.height / 2 || 0) } + + return coords +} + +const dragTo = (subject, to, opts) => { + + opts = Cypress._.defaults(opts, { + // delay inbetween steps + delay: 0, + // interpolation between coords + steps: 0, + // >=10 steps + smooth: false, + }) + + if (opts.smooth) { + opts.steps = Math.max(opts.steps, 10) + } + + const win = subject[0].ownerDocument.defaultView + + const elFromCoords = (coords) => win.document.elementFromPoint(coords.x, coords.y) + const winMouseEvent = win.MouseEvent + + const send = (type, coords, el) => { + + el = el || elFromCoords(coords) + + el.dispatchEvent( + new winMouseEvent(type, Object.assign({}, { clientX: coords.x, clientY: coords.y }, { bubbles: true, cancelable: true })) + ) + } + + const toSel = to + + function drag (from, to, steps = 1) { + + const fromEl = elFromCoords(from) + + const _log = Cypress.log({ + $el: fromEl, + name: 'drag to', + message: toSel, + }) + + _log.snapshot('before', { next: 'after', at: 0 }) + + _log.set({ coords: to }) + + send('mouseover', from, fromEl) + send('mousedown', from, fromEl) + + cy.then(() => { + return Cypress.Promise.try(() => { + + if (steps > 0) { + + const dx = (to.x - from.x) / steps + const dy = (to.y - from.y) / steps + + return Cypress.Promise.map(Array(steps).fill(), (v, i) => { + i = steps - 1 - i + + let _to = { + x: from.x + dx * (i), + y: from.y + dy * (i), + } + + send('mousemove', _to, fromEl) + + return Cypress.Promise.delay(opts.delay) + + }, { concurrency: 1 }) + } + }) + .then(() => { + + send('mousemove', to, fromEl) + send('mouseover', to) + send('mousemove', to) + send('mouseup', to) + _log.snapshot('after', { at: 1 }).end() + + }) + + }) + + } + + const $el = subject + const fromCoords = getCoords($el) + const toCoords = getCoords(cy.$$(to)) + + drag(fromCoords, toCoords, opts.steps) +} + +Cypress.Commands.addAll( + { prevSubject: 'element' }, + { + dragTo, + } +) diff --git a/docker-compose-cypress.yml b/docker-compose-cypress.yml index 93f9e6511c..8fd3a2c591 100644 --- a/docker-compose-cypress.yml +++ b/docker-compose-cypress.yml @@ -23,6 +23,7 @@ services: echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" # cp -r /home/app1/ /home/app/ rm /home/app/package-lock.json + rm /home/app/noco.db cd /home/app/ && npm i && EE=true npm run run xc-cypress-nc-gui: network_mode: host diff --git a/package-lock.json b/package-lock.json index b4bd52bf09..1cdac5aba8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3,6 +3,12 @@ "requires": true, "lockfileVersion": 1, "dependencies": { + "@4tw/cypress-drag-drop": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@4tw/cypress-drag-drop/-/cypress-drag-drop-1.8.0.tgz", + "integrity": "sha512-hPg9JvG3f+rzunVj6cZjgHaNtZ8JMbHBwD00PZjyl6/ysqyZzeR74b8yWUF0zohWcCG9bHVu666EhotOiIKhZw==", + "dev": true + }, "@babel/code-frame": { "version": "7.12.13", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", diff --git a/package.json b/package.json index c2235c9c05..64d8b8cb88 100644 --- a/package.json +++ b/package.json @@ -2,6 +2,7 @@ "name": "root", "private": true, "devDependencies": { + "@4tw/cypress-drag-drop": "^1.8.0", "cypress": "^7.3.0", "jsdoc-to-markdown": "^5.0.3", "lerna": "^3.20.1" diff --git a/packages/nc-gui/components/auth/userManagement.vue b/packages/nc-gui/components/auth/userManagement.vue index 84100bbe93..1bae7e2ab3 100644 --- a/packages/nc-gui/components/auth/userManagement.vue +++ b/packages/nc-gui/components/auth/userManagement.vue @@ -491,7 +491,7 @@ v-ge="['rows','save']" tooltip="Save Changes" color="primary" - btn.class="mt-5 mb-3 pr-5" + btn.class="mt-5 mb-3 pr-5 nc-invite-or-save-btn" @click="saveUser" > diff --git a/packages/nc-gui/components/project/spreadsheet/components/columnFilter.vue b/packages/nc-gui/components/project/spreadsheet/components/columnFilter.vue index 0d4b28c97a..ca2d17f538 100644 --- a/packages/nc-gui/components/project/spreadsheet/components/columnFilter.vue +++ b/packages/nc-gui/components/project/spreadsheet/components/columnFilter.vue @@ -9,7 +9,7 @@ v-if="!filter.readOnly" :key="i + '_3'" small - class="" + class="nc-filter-item-remove-btn" @click.stop="filters.splice(i,1)" > mdi-close-box diff --git a/packages/nc-gui/components/project/spreadsheet/components/sortListMenu.vue b/packages/nc-gui/components/project/spreadsheet/components/sortListMenu.vue index 79f8b9d73d..b8c6c7ca83 100644 --- a/packages/nc-gui/components/project/spreadsheet/components/sortListMenu.vue +++ b/packages/nc-gui/components/project/spreadsheet/components/sortListMenu.vue @@ -29,7 +29,7 @@