Browse Source

test(cypress): xcdb project test, user invite, docs update

Signed-off-by: Pranav C <pranavxc@gmail.com>
pull/510/head
Pranav C 3 years ago
parent
commit
fef5599e5c
  1. 17
      README.md
  2. 2
      cypress.json
  3. 49
      cypress/integration/common/filter_sort_fields_operations_spec.js
  4. 42
      cypress/integration/common/open_existing_table_spec.js
  5. 46
      cypress/integration/common/open_existing_table_with_m2m_spec.js
  6. 60
      cypress/integration/common/project_operations_spec.js
  7. 124
      cypress/integration/common/table_column_operations_spec.js
  8. 134
      cypress/integration/common/table_operations_spec.js
  9. 71
      cypress/integration/common/table_row_operations_spec.js
  10. 52
      cypress/integration/common/table_view_spec.js
  11. 48
      cypress/integration/common/users_spec.js
  12. 26
      cypress/integration/graphql/open_existing_table_spec.js
  13. 33
      cypress/integration/graphql/open_existing_table_with_m2m_spec.js
  14. 51
      cypress/integration/graphql/project_operations_spec.js
  15. 72
      cypress/integration/graphql/table_operations_spec.js
  16. 26
      cypress/integration/rest/open_existing_table_spec.js
  17. 33
      cypress/integration/rest/open_existing_table_with_m2m_spec.js
  18. 49
      cypress/integration/rest/project_operations_spec.js
  19. 36
      cypress/integration/rest/table_view_spec.js
  20. 25
      cypress/integration/rest/users_spec.js
  21. 79
      cypress/support/commands.js
  22. 18
      docker-compose-cypress.yml
  23. 3
      package.json
  24. 4
      packages/nc-gui/components/auth/userManagement.vue
  25. 2
      packages/nc-gui/pages/project/xcdb.vue
  26. 10
      packages/nc-gui/pages/projects/index.vue
  27. 2
      packages/nc-lib-gui/package.json
  28. 4
      packages/nocodb/src/lib/noco/meta/NcMetaMgr.ts

17
README.md

@ -200,6 +200,23 @@ npm run dev
Changes made to code automatically restart.
## Running Cypress tests locally
```shell
# run requered services by using docker compose
docker-compose -f ./docker-compose-cypress.yml up
# wait until both 3000 and 8080 porta are avalable
# and run cypress test using following command
npm run cypress:run
# or run following command to run it with GUI
npm run cypress:open
```
# Contributing
- Please take a look at ./contribute/HowToApplyLicense.md
- Ignore adding headers for .json or .md or .yml

2
cypress.json

@ -2,7 +2,7 @@
"baseUrl": "http://localhost:3000",
"defaultCommandTimeout": 10000,
"pageLoadTimeout": 600000,
"viewportWidth": 1800,
"viewportWidth": 1600,
"viewportHeight": 1000,
"video": false,
"retries": 2

49
cypress/integration/common/filter_sort_fields_operations_spec.js

@ -29,7 +29,7 @@ const genTest = (type) => {
})
// check pagination
it('Check country table - ', () => {
it('Check country table - Pagination', () => {
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')
@ -40,9 +40,7 @@ const genTest = (type) => {
// 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
@ -64,21 +62,33 @@ const genTest = (type) => {
})
// Test fields
it.only('Add fields options', () => {
describe('Field Operation', () => {
before(() => {
cy.get('.nc-fields-menu-btn').click()
})
if ('Hide field', () => {
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()
it('Show field', () => {
cy.get('.menuable__content__active .v-list-item label:contains(LastUpdate)').click()
cy.get('th:contains(LastUpdate)').should('be.visible')
})
})
// Test fields
// it('Add fields options', () => {
// 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')
// 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)')
@ -116,11 +126,12 @@ const genTest = (type) => {
// draggable.dispatchEvent(new MouseEvent('mouseup'));
})*/
})
// })
// Test filter
it('Add filter options', () => {
describe('Filter operations', () => {
it('Create Filter', () => {
cy.get('.nc-filter-menu-btn').click()
cy.contains('Add Filter').click();
@ -131,7 +142,9 @@ const genTest = (type) => {
cy.get('.nc-filter-value-select input:text').last().type('India');
cy.get('td:contains(India)').should('exist')
})
it('Delete Filter', () => {
// remove sort and check
cy.get('.nc-filter-item-remove-btn').click()
@ -140,6 +153,16 @@ const genTest = (type) => {
})
})
//
// // Test filter
// it('Add filter options', () => {
//
//
// })
})
}

42
cypress/integration/common/open_existing_table_spec.js

@ -0,0 +1,42 @@
const genTest = (type) => {
describe(`${type.toUpperCase()} api - Existing table`, () => {
before(() => {
cy.waitForSpinners();
if (type === 'rest') {
cy.openOrCreateRestProject({
new: true
});
} else {
cy.openOrCreateGqlProject({
new: true
});
}
});
it('Open Country table', () => {
cy.get('.nc-project-tree :contains(Tables)', {timeout: 10000})
.first().click()
.contains('Country', {timeout: 6000}).first().click({force: true});
cy.get(`.project-tab:contains(Country):visible`).should('exist')
cy.url().should('contain', `?name=Country&`)
cy.get('td[data-col="Country => City"] div:visible', {timeout: 12000}).first().click()
cy.get('td[data-col="Country => City"] div .mdi-arrow-expand:visible').first().click()
cy.get(":contains(Link to 'City'):visible").should('exist')
cy.get(":contains(Link to 'City'):visible").first().click()
});
})
}
genTest('rest')
genTest('graphql')

46
cypress/integration/common/open_existing_table_with_m2m_spec.js

@ -0,0 +1,46 @@
const genTest = (type) => {
describe(`${type.toUpperCase()} api - Existing table with M2M'`, () => {
before(() => {
cy.waitForSpinners();
if (type === 'rest') {
cy.openOrCreateRestProject({
new: true
});
} else {
cy.openOrCreateGqlProject({
new: true
});
}
})
it('Open Actor table', () => {
cy.openTableTab('Actor');
cy.get(`.project-tab:contains(Actor)`).should('exist')
cy.url().should('contain', `?name=Actor&`)
cy.get('td[data-col="Actor <=> Film"] div', {timeout: 12000}).first().click({force: true})
cy.get('td[data-col="Actor <=> Film"] div .mdi-arrow-expand').first().click({force: true})
//
// cy.get(":contains(Link to 'City')").should('exist')
//
// cy.get(":contains(Link to 'City'):visible").click()
cy.get('.child-card:visible').should('exist').first().click()
cy.contains('Save Row').should('exist');
});
})
}
genTest('rest')
genTest('graphql')

60
cypress/integration/common/project_operations_spec.js

@ -0,0 +1,60 @@
const genTest = (type) => {
describe(`${type.toUpperCase()} Project operations`, () => {
before(() => {
cy.waitForSpinners();
cy.signinOrSignup();
})
beforeEach(() => {
cy.restoreLocalStorage();
});
afterEach(() => {
cy.saveLocalStorage();
});
it('Create Project', () => {
cy.contains('New Project').trigger('onmouseover').trigger('mouseenter');
cy.get('.create-external-db-project').click()
cy.url({timeout: 6000}).should('contain', '#/project/')
if (type === 'graphql') {
cy.contains('GRAPHQL APIs').closest('label').click()
}
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-${type}-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-${type}-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-${type}-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-${type}-project-row .mdi-delete-circle-outline`, {timeout: 10000}).last().invoke('show').click();
cy.contains('Submit').closest('button').click();
});
})
}
genTest('rest')
genTest('graphql')

124
cypress/integration/common/table_column_operations_spec.js

@ -0,0 +1,124 @@
const genTest = (type) => {
describe(`${type.toUpperCase()} api - Table Column`, () => {
const randVal = 'Test' + Date.now();
const updatedRandVal = 'Updated' + Date.now();
const name = 'Test' + Date.now();
before(() => {
cy.waitForSpinners();
if (type === 'rest') {
cy.openOrCreateRestProject({
new: true
});
} else {
cy.openOrCreateGqlProject({
new: true
});
}
cy.createTable(name)
});
// delete table
after(() => {
cy.deleteTable(name)
});
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()
})
// edit the newly created column
it('Edit table column - rename', () => {
cy.get('th:contains(new_column) .mdi-menu-down')
.trigger('mouseover', {force: true})
.click({force: true})
// 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');
})
});
}
genTest('rest')
genTest('graphql')

134
cypress/integration/common/table_operations_spec.js

@ -1,33 +1,32 @@
const genTest = (type) => {
const genTest = (type, meta) => {
describe(`${type.toUpperCase()} api - Table`, () => {
describe(`${meta ? 'Meta - ' : ''}${type.toUpperCase()} api - Table`, () => {
before(() => {
cy.waitForSpinners();
if (type === 'rest') {
cy.openOrCreateRestProject({
new: true
new: true,
meta
});
} else {
cy.openOrCreateGqlProject({
new: true
new: true,
meta
});
}
});
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)
if (!meta) {
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')
@ -35,118 +34,6 @@ const genTest = (type) => {
});
// 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', () => {
@ -165,10 +52,11 @@ const genTest = (type) => {
})
});
}
genTest('rest')
genTest('graphql')
genTest('rest', true)
genTest('graphql', true)

71
cypress/integration/common/table_row_operations_spec.js

@ -0,0 +1,71 @@
const genTest = (type) => {
describe(`${type.toUpperCase()} api - Table Row`, () => {
const randVal = 'Test' + Date.now();
const updatedRandVal = 'Updated' + Date.now();
const name = 'Test' + Date.now();
before(() => {
cy.waitForSpinners();
if (type === 'rest') {
cy.openOrCreateRestProject({
new: true
});
} else {
cy.openOrCreateGqlProject({
new: true
});
}
cy.createTable(name)
});
// delete table
after(() => {
cy.deleteTable(name)
});
it('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');
})
it('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');
})
it('Delete row', () => {
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');
})
});
}
genTest('rest')
genTest('graphql')

52
cypress/integration/common/table_view_spec.js

@ -0,0 +1,52 @@
const genTest = (type) => {
describe(`${type.toUpperCase()} api - Table views`, () => {
const name = 'Test' + Date.now();
before(() => {
cy.waitForSpinners();
if (type === 'rest') {
cy.openOrCreateRestProject({
new: true
});
} else {
cy.openOrCreateGqlProject({
new: true
});
}
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)
})
})*/
})
}
genTest('rest')
genTest('graphql')

48
cypress/integration/common/users_spec.js

@ -0,0 +1,48 @@
const genTest = (type) => {
describe(`${type.toUpperCase()} api - User Management`, () => {
before(() => {
cy.waitForSpinners();
if (type === 'rest') {
cy.openOrCreateRestProject({
new: true
});
} else {
cy.openOrCreateGqlProject({
new: true
});
}
});
const email = `noco${Date.now()}@gmail.com`;
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).trigger('input')
cy.get('.nc-invite-or-save-btn').then($el => {
cy.wrap($el[0]).click()
// cy.contains('.v-alert', /http:\/\/locahost/).should('exist')
cy.contains('.v-alert', '#/user/authentication/signup/').should('exist')
})
})
})
}
genTest('rest')
genTest('graphql')

26
cypress/integration/graphql/open_existing_table_spec.js

@ -1,26 +0,0 @@
describe('GraphQL api - Existing table', () => {
before(() => {
cy.waitForSpinners();
cy.openOrCreateGqlProject();
})
it('Open Country table', () => {
cy.get('.nc-project-tree :contains(Tables)', {timeout: 10000})
.first().click()
.contains('Country', {timeout: 6000}).first().click({force: true});
cy.get(`.project-tab:contains(Country):visible`).should('exist')
cy.url().should('contain', `?name=Country&`)
cy.get('td[data-col="Country => City"] div:visible', {timeout: 12000}).first().click()
cy.get('td[data-col="Country => City"] div .mdi-arrow-expand:visible').first().click()
cy.get(":contains(Link to 'City'):visible").should('exist')
cy.get(":contains(Link to 'City'):visible").first().click()
});
})

33
cypress/integration/graphql/open_existing_table_with_m2m_spec.js

@ -1,33 +0,0 @@
describe('GraphQL api - Existing table with M2M', () => {
before(() => {
cy.waitForSpinners();
cy.openOrCreateGqlProject();
})
it('Open Actor table', () => {
cy.get('.nc-project-tree :contains(Tables)', {timeout: 10000})
.first().click()
.contains('Actor', {timeout: 6000}).first().click({force: true});
cy.get(`.project-tab:contains(Actor)`).should('exist')
cy.url().should('contain', `?name=Actor&`)
cy.get('td[data-col="Actor <=> Film"] div', {timeout:12000}).first().click({force: true})
cy.get('td[data-col="Actor <=> Film"] div .mdi-arrow-expand').first().click({force: true})
//
// cy.get(":contains(Link to 'City')").should('exist')
//
// cy.get(":contains(Link to 'City'):visible").click()
cy.get('.child-card:visible').should('exist').first().click()
cy.contains('Save Row').should('exist');
cy.contains('Save Row').should('exist');
});
})

51
cypress/integration/graphql/project_operations_spec.js

@ -1,51 +0,0 @@
describe('GraphQL Project operations', () => {
beforeEach(() => {
cy.restoreLocalStorage();
});
afterEach(() => {
cy.saveLocalStorage();
});
before(() => {
cy.waitForSpinners();
cy.signinOrSignup();
})
it('Create Project', () => {
cy.contains('New Project').trigger('onmouseover').trigger('mouseenter');
cy.get('.create-external-db-project').click()
cy.url({timeout: 6000}).should('contain', '#/project/')
cy.contains('GRAPHQL APIs').closest('label').click()
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-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();
});
})

72
cypress/integration/graphql/table_operations_spec.js

@ -1,72 +0,0 @@
describe('GraphQL 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()
});
// delete the newly created column
it('Delete table column', () => {
cy
.get('th:contains(new_column)')
.should('exist');
cy.get('th:contains(new_column) .mdi-menu-down')
.trigger('mouseover')
.click()
cy.get('.nc-column-delete').click()
cy.get('button:contains(Confirm)').click()
cy
.get('th:contains(new_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')
});
})

26
cypress/integration/rest/open_existing_table_spec.js

@ -1,26 +0,0 @@
describe('Rest api - Existing table', () => {
before(() => {
cy.waitForSpinners();
cy.openOrCreateRestProject();
})
it('Open Country table', () => {
cy.get('.nc-project-tree :contains(Tables)', {timeout: 10000})
.first().click()
.contains('Country', {timeout: 6000}).first().click({force: true});
cy.get(`.project-tab:contains(Country):visible`).should('exist')
cy.url().should('contain', `?name=Country&`)
cy.get('td[data-col="Country => City"] div:visible', {timeout: 12000}).first().click()
cy.get('td[data-col="Country => City"] div .mdi-arrow-expand:visible').first().click()
cy.get(":contains(Link to 'City'):visible").should('exist')
cy.get(":contains(Link to 'City'):visible").first().click()
});
})

33
cypress/integration/rest/open_existing_table_with_m2m_spec.js

@ -1,33 +0,0 @@
describe('Rest api - Existing table with M2M', () => {
before(() => {
cy.waitForSpinners();
cy.openOrCreateRestProject();
})
it('Open Actor table', () => {
cy.get('.nc-project-tree :contains(Tables)', {timeout: 10000})
.first().click()
.contains('Actor', {timeout: 6000}).first().click({force: true});
cy.get(`.project-tab:contains(Actor)`).should('exist')
cy.url().should('contain', `?name=Actor&`)
cy.get('td[data-col="Actor <=> Film"] div', {timeout:12000}).first().click({force: true})
cy.get('td[data-col="Actor <=> Film"] div .mdi-arrow-expand').first().click({force: true})
//
// cy.get(":contains(Link to 'City')").should('exist')
//
// cy.get(":contains(Link to 'City'):visible").click()
cy.get('.child-card:visible').should('exist').first().click()
cy.contains('Save Row').should('exist');
cy.contains('Save Row').should('exist');
});
})

49
cypress/integration/rest/project_operations_spec.js

@ -1,49 +0,0 @@
describe('Rest Project operations', () => {
beforeEach(() => {
cy.restoreLocalStorage();
});
afterEach(() => {
cy.saveLocalStorage();
});
before(() => {
cy.waitForSpinners();
cy.signinOrSignup();
})
it('Create Project', () => {
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('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();
});
})

36
cypress/integration/rest/table_view_spec.js

@ -1,36 +0,0 @@
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)
})
})*/
})

25
cypress/integration/rest/users_spec.js

@ -1,25 +0,0 @@
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()
})
})

79
cypress/support/commands.js

@ -24,7 +24,7 @@
// -- This will overwrite an existing command --
// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... })
require('@4tw/cypress-drag-drop')
// require('@4tw/cypress-drag-drop')
// for waiting until page load
Cypress.Commands.add('waitForSpinners', () => {
@ -72,18 +72,26 @@ Cypress.Commands.add('openOrCreateRestProject', (_args) => {
cy.signinOrSignup()
cy.wait(2000);
cy.get('body').then($body => {
const filter = args.meta ? '.nc-meta-project-row' : ':not(.nc-meta-project-row)';
// 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
if ($body.find('.nc-rest-project-row').filter(filter).length && !args.new) {
cy.get('.nc-rest-project-row').filter(filter).first().click()
} else {
cy.contains('New Project').trigger('onmouseover').trigger('mouseenter');
cy.get('.create-external-db-project').click()
if (args.meta) {
cy.get('.nc-create-xc-db-project').click()
cy.url({timeout: 6000}).should('contain', '#/project/xcdb')
cy.get('.nc-metadb-project-name').type('test_proj' + Date.now())
cy.contains('button','Create', {timeout: 3000}).click()
} else {
cy.get('.nc-create-external-db-project').click()
cy.url({timeout: 6000}).should('contain', '#/project')
cy.contains('GRAPHQL APIs').closest('label').click()
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/')
@ -101,26 +109,33 @@ Cypress.Commands.add('openTableTab', (tn) => {
});
Cypress.Commands.add('openOrCreateGqlProject', (_args) => {
const args = Object.assign({new: false}, _args)
const args = Object.assign({new: false, meta: false}, _args)
cy.signinOrSignup()
cy.wait(2000);
cy.get('body').then($body => {
const filter = args.meta ? '.nc-meta-project-row' : ':not(.nc-meta-project-row)';
// if project exist open
if ($body.find('.nc-graphql-project-row').length && !args.new) {
cy.get('.nc-graphql-project-row').first().click()
// create new project
if ($body.find('.nc-graphql-project-row').filter(filter).length && !args.new) {
cy.get('.nc-graphql-project-row').filter(filter).first().click()
} else {
cy.contains('New Project').trigger('onmouseover').trigger('mouseenter');
cy.get('.create-external-db-project').click()
if (args.meta) {
cy.get('.nc-create-xc-db-project').click()
cy.url({timeout: 6000}).should('contain', '#/project/xcdb')
cy.contains('GRAPHQL APIs').closest('label').click();
cy.get('.nc-metadb-project-name').type('test_proj' + Date.now())
cy.contains('button','Create', {timeout: 3000}).click()
} else {
cy.get('.nc-create-external-db-project').click()
cy.url({timeout: 6000}).should('contain', '#/project')
cy.contains('GRAPHQL APIs').closest('label').click()
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/')
@ -149,9 +164,50 @@ Cypress.Commands.add("getActiveMenu", () => {
});
Cypress.Commands.add('createTable', (name) => {
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}&`)
})
Cypress.Commands.add('deleteTable', (name) => {
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')
})
Cypress.Commands.add('createColumn', (table, columnName) => {
cy.get('.nc-project-tree').find('.v-list-item__title:contains(Tables)', {timeout: 10000})
.first().click()
cy.get('.nc-project-tree').contains(table, {timeout: 6000}).first().click({force: true});
cy.get(`.project-tab:contains(${table}):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(columnName)
cy.get('.nc-col-create-or-edit-card').contains('Save').click()
cy
.get('th:contains(new_column)')
.should('exist');
})
// Drag n Drop
// refer: https://stackoverflow.com/a/55409853
/*
const getCoords = ($el) => {
const domRect = $el[0].getBoundingClientRect()
@ -258,5 +314,6 @@ Cypress.Commands.addAll(
dragTo,
}
)
*/

18
docker-compose-cypress.yml

@ -24,7 +24,8 @@ services:
# 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
# cd /home/app/ && npm i && EE=true npm run run
cd /home/app/ && npm i && EE=true npm run watch:run
xc-cypress-nc-gui:
network_mode: host
image: node:14-alpine
@ -45,3 +46,18 @@ services:
rm /home/app/package-lock.json
# cd /home/app/ && npm i && npm run dev
cd /home/app/ && npm i && NODE_ENV=development npm run build && npm start

3
package.json

@ -2,12 +2,13 @@
"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"
},
"scripts": {
"cypress:run": "cypress run",
"cypress:open": "cypress open",
"test:travis": "git log --pretty=format:'%h' -n 1 --skip 1 | xargs lerna run test:travis --since",
"lerna:install": "git log --pretty=format:'%h' -n 1 --skip 1 | xargs lerna bootstrap --ignore nc-cli --since",
"updated:xc-migrator": "lerna run publish --scope xc-migrator && lerna run xc && lerna publish && npm install -f xc-cli",

4
packages/nc-gui/components/auth/userManagement.vue

@ -447,7 +447,7 @@
<!-- todo: show error message if failed-->
</div>
<template v-else>
<v-form v-model="valid" @submit.prevent="saveUser">
<v-form ref="form" v-model="valid" @submit.prevent="saveUser">
<v-row class="mt-4">
<v-col cols="12">
<v-text-field
@ -753,7 +753,7 @@ export default {
}
},
async saveUser() {
if (this.loading || !this.valid || !this.selectedUser) {
if (this.loading || !this.$refs.form.validate() || !this.selectedUser) {
return
}

2
packages/nc-gui/pages/project/xcdb.vue

@ -34,7 +34,7 @@
v-model="name"
autofocus
:full-width="false"
class=""
class="nc-metadb-project-name"
label="Enter Project Name"
:rules="[v => !!v || 'Project name required']"
/>

10
packages/nc-gui/pages/projects/index.vue

@ -120,7 +120,7 @@
</template>
<v-list dense>
<v-list-item
class="create-xc-db-project"
class="create-xc-db-project nc-create-xc-db-project"
@click="onCreateProject('xcdb')"
>
<v-list-item-icon class="mr-2">
@ -130,7 +130,7 @@
</v-list-item-icon>
<v-list-item-title>
<!-- Create -->
<span class="caption font-weight-regular">{{
<span class="caption font-weight-regular ">{{
$t('projects.create_new_project_button.subtext_1')
}}</span>
</v-list-item-title>
@ -155,7 +155,7 @@
<v-divider />
<v-list-item
title
class="pt-2 create-external-db-project"
class="pt-2 create-external-db-project nc-create-external-db-project"
@click="onCreateProject()"
>
<v-list-item-icon class="mr-2">
@ -225,7 +225,9 @@
<template #item="props">
<tr
class="project-row"
:class="`nc-${props.item.projectType}-project-row`"
:class="[`nc-${props.item.projectType}-project-row`,{
'nc-meta-project-row': props.item.prefix
}]"
@click="projectRouteHandler(props.item)"
>
<td data-v-step="2">

2
packages/nc-lib-gui/package.json

@ -1,6 +1,6 @@
{
"name": "nc-lib-gui",
"version": "0.2.41",
"version": "0.2.43",
"description": "> TODO: description",
"author": "“pranavxc” <pranavxc@gmail.com>",
"homepage": "https://gitlab.com/xgenecloud-ts/xgenecloud-ts#readme",

4
packages/nocodb/src/lib/noco/meta/NcMetaMgr.ts

@ -1352,7 +1352,9 @@ export default class NcMetaMgr {
case 'projectList':
result = await this.xcMeta.userProjectList(req?.session?.passport?.user?.id);
result.forEach(p => {
p.projectType = JSON.parse(p.config)?.projectType;
const config =JSON.parse(p.config);
p.projectType = config?.projectType;
p.prefix = config?.prefix
delete p.config
})
break;

Loading…
Cancel
Save