Browse Source

Merge pull request #1292 from nocodb/develop

0.84.11 Pre-Release
pull/1295/head
աɨռɢӄաօռɢ 3 years ago committed by GitHub
parent
commit
873e682146
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 9
      .all-contributorsrc
  2. 23
      .github/ISSUE_TEMPLATE/I18n_translations.md
  3. 2
      .github/ISSUE_TEMPLATE/feature_request.md
  4. 32
      .github/ISSUE_TEMPLATE/i18n-translation-request.md
  5. 184
      .github/workflows/ci-cd.yml
  6. 34
      .github/workflows/release-close-issue.yml
  7. 12
      .github/workflows/release-docker.yml
  8. 16
      .github/workflows/release-draft.yml
  9. 52
      .github/workflows/release-nocodb.yml
  10. 124
      .github/workflows/release-npm.yml
  11. 23
      .github/workflows/sync-to-develop.yml
  12. 1
      .gitignore
  13. 1
      README.md
  14. 97
      package-lock.json
  15. 1
      package.json
  16. 12
      packages/nc-cli/package-lock.json
  17. 6
      packages/nc-common/package-lock.json
  18. 6
      packages/nc-gui/components/auth/roles.vue
  19. 115
      packages/nc-gui/components/auth/userManagement.vue
  20. 72
      packages/nc-gui/components/base/shareBase.vue
  21. 2
      packages/nc-gui/components/project/spreadsheet/components/expandedForm.vue
  22. 2
      packages/nc-gui/components/project/spreadsheet/components/extras.vue
  23. 22
      packages/nc-gui/components/project/spreadsheet/components/importExport/columnMappingModal.vue
  24. 15
      packages/nc-gui/components/project/spreadsheet/components/moreActions.vue
  25. 2
      packages/nc-gui/components/project/spreadsheet/components/virtualCell/components/listItems.vue
  26. 5
      packages/nc-gui/components/project/spreadsheet/mixins/spreadsheet.js
  27. 2
      packages/nc-gui/components/project/spreadsheet/views/xcGridView.vue
  28. 205
      packages/nc-gui/components/utils/dlgTableCreate.vue
  29. 34
      packages/nc-gui/helpers/formulaList.js
  30. 4
      packages/nc-gui/helpers/sqlUi/MssqlUi.js
  31. 2
      packages/nc-gui/helpers/sqlUi/MysqlUi.js
  32. 2
      packages/nc-gui/helpers/sqlUi/SqliteUi.js
  33. 378
      packages/nc-gui/lang/de.json
  34. 2
      packages/nc-gui/layouts/default.vue
  35. 2
      packages/nc-gui/pages/projects/index.vue
  36. 28
      packages/nc-migrator-archived/package-lock.json
  37. 34
      packages/noco-docs/content/en/engineering/publish.md
  38. 65
      packages/noco-docs/content/en/engineering/translation.md
  39. 6
      packages/noco-i18n/package-lock.json
  40. 7
      packages/nocodb/src/__tests__/rest.test.ts
  41. 22
      packages/nocodb/src/lib/dataMapper/lib/sql/CustomKnex.ts
  42. 4
      packages/nocodb/src/lib/noco/NcProjectBuilder.ts
  43. 5
      packages/nocodb/src/lib/noco/meta/NcMetaIO.ts
  44. 9
      packages/nocodb/src/lib/noco/meta/NcMetaIOImpl.ts
  45. 42
      packages/nocodb/src/lib/noco/rest/RestAuthCtrl.ts
  46. 4
      packages/nocodb/src/lib/sqlUi/MssqlUi.ts
  47. 2
      packages/nocodb/src/lib/sqlUi/MysqlUi.ts
  48. 2
      packages/nocodb/src/lib/sqlUi/SqliteUi.ts
  49. 104
      scripts/cypress/cypress.json
  50. 17
      scripts/cypress/docker-compose-pg.yml
  51. 64
      scripts/cypress/integration/common/00_pre_configurations.js
  52. 188
      scripts/cypress/integration/common/1a_table_operations.js
  53. 325
      scripts/cypress/integration/common/1b_table_column_operations.js
  54. 297
      scripts/cypress/integration/common/1c_sql_view.js
  55. 171
      scripts/cypress/integration/common/1d_pg_table_view_drag_drop_reorder.js
  56. 268
      scripts/cypress/integration/common/1d_table_view_drag_drop_reorder.js
  57. 321
      scripts/cypress/integration/common/1e_meta_sync.js
  58. 202
      scripts/cypress/integration/common/1e_pg_meta_sync.js
  59. 106
      scripts/cypress/integration/common/2a_table_with_belongs_to_colulmn.js
  60. 153
      scripts/cypress/integration/common/2b_table_with_m2m_column.js
  61. 421
      scripts/cypress/integration/common/3a_filter_sort_fields_operations.js
  62. 440
      scripts/cypress/integration/common/3b_formula_column.js
  63. 192
      scripts/cypress/integration/common/3c_lookup_column.js
  64. 8
      scripts/cypress/integration/common/3d_rollup_column.js
  65. 143
      scripts/cypress/integration/common/4a_table_view_grid_gallery_form.js
  66. 11
      scripts/cypress/integration/common/4b_table_view_share.js
  67. 6
      scripts/cypress/integration/common/4c_form_view_detailed.js
  68. 7
      scripts/cypress/integration/common/4d_table_view_grid_locked.js
  69. 391
      scripts/cypress/integration/common/4e_form_view_share.js
  70. 813
      scripts/cypress/integration/common/4f_grid_view_share.js
  71. 471
      scripts/cypress/integration/common/4f_pg_grid_view_share.js
  72. 396
      scripts/cypress/integration/common/5a_user_role.js
  73. 234
      scripts/cypress/integration/common/5b_preview_role.js
  74. 62
      scripts/cypress/integration/common/6b_downloadCsv.js
  75. 452
      scripts/cypress/integration/common/6c_swagger_api.js
  76. 11
      scripts/cypress/integration/common/6d_language_validation.js
  77. 117
      scripts/cypress/integration/common/6e_project_operations.js
  78. 10
      scripts/cypress/integration/common/6f_attachments.js
  79. 207
      scripts/cypress/integration/common/6g_base_share.js
  80. 538
      scripts/cypress/integration/common/7a_create_project_from_excel.js
  81. 30
      scripts/cypress/integration/test/explicitLogin.js
  82. 22
      scripts/cypress/integration/test/gqlMisc.js
  83. 14
      scripts/cypress/integration/test/gqlRoles.js
  84. 32
      scripts/cypress/integration/test/gqlTableOps.js
  85. 22
      scripts/cypress/integration/test/gqlViews.js
  86. 52
      scripts/cypress/integration/test/masterSuiteGql.js
  87. 52
      scripts/cypress/integration/test/masterSuiteRest.js
  88. 61
      scripts/cypress/integration/test/pg-restMisc.js
  89. 47
      scripts/cypress/integration/test/pg-restRoles.js
  90. 65
      scripts/cypress/integration/test/pg-restTableOps.js
  91. 55
      scripts/cypress/integration/test/pg-restViews.js
  92. 24
      scripts/cypress/integration/test/restMisc.js
  93. 14
      scripts/cypress/integration/test/restRoles.js
  94. 32
      scripts/cypress/integration/test/restTableOps.js
  95. 22
      scripts/cypress/integration/test/restViews.js
  96. 22
      scripts/cypress/integration/test/xcdb-gqlMisc.js
  97. 14
      scripts/cypress/integration/test/xcdb-gqlRoles.js
  98. 32
      scripts/cypress/integration/test/xcdb-gqlTableOps.js
  99. 22
      scripts/cypress/integration/test/xcdb-gqlViews.js
  100. 24
      scripts/cypress/integration/test/xcdb-restMisc.js
  101. Some files were not shown because too many files have changed in this diff Show More

9
.all-contributorsrc

@ -612,6 +612,15 @@
"contributions": [
"code"
]
},
{
"login": "LancerComet",
"name": "LancerComet",
"avatar_url": "https://avatars.githubusercontent.com/u/10321350?v=4",
"profile": "https://github.com/LancerComet",
"contributions": [
"code"
]
}
],
"contributorsPerLine": 7,

23
.github/ISSUE_TEMPLATE/I18n_translations.md

@ -0,0 +1,23 @@
# i18n translation request
**Please enter the following details**
1. Select applicalbe
- [ ] **New language support request**
- [ ] **Existing language translation corrections request**
Verify if language support already exists in NocoDB i18n master spreadsheet [here](https://docs.google.com/spreadsheets/d/1kGp92yLwhs1l7lwwgeor3oN1dFl7JZWuQOa4WSeZ0TE/edit#gid=2076107172)
2. Associated language code (pick from [here](https://developers.google.com/admin-sdk/directory/v1/languages)):
3. Google spreadsheet
- Procedure to share google spread sheet can be found [here](https://support.google.com/docs/answer/2494822?hl=en&co=GENIE.Platform%3DDesktop#zippy=%2Cshare-a-file-publicly)
- When requested, select public sharable link.
- Alternatively, you can download & attach spreadsheet here along with the issue as well.
- [ ] **Attached**
- [ ] **Shared link**:
4. Summary of the changes made
- You can highlight modified items in Spreadsheet attached/shared, to help us quickly identify change set
5. Any specific message to be conveyed to moderators?
- Help us simplify process if you find something hard about it

2
.github/ISSUE_TEMPLATE/feature_request.md

@ -2,7 +2,7 @@
name: Feature request
about: Suggest an idea for this project
title: "[Feature] "
labels: Feature
labels: ''
assignees: ''
---

32
.github/ISSUE_TEMPLATE/i18n-translation-request.md

@ -0,0 +1,32 @@
---
name: i18n translation request
about: translation & localisation support
title: "[i18n] Language support extension- <language code>"
labels: i18n translation
assignees: dstala
---
# i18n translation request
**Please enter the following details**
1. Select applicalbe
- [ ] **New language support request**
- [ ] **Existing language translation corrections request**
Verify if language support already exists in the NocoDB i18n master spreadsheet [here](https://docs.google.com/spreadsheets/d/1kGp92yLwhs1l7lwwgeor3oN1dFl7JZWuQOa4WSeZ0TE/edit#gid=2076107172)
2. Associated language code (pick from [here](https://developers.google.com/admin-sdk/directory/v1/languages)):
3. Google spreadsheet
- Procedure to share google spreadsheet can be found [here](https://support.google.com/docs/answer/2494822?hl=en&co=GENIE.Platform%3DDesktop#zippy=%2Cshare-a-file-publicly)
- When requested, select public sharable link.
- Alternatively, you can download & attach a spreadsheet here along with the issue as well.
- [ ] **Attached**
- [ ] **Shared link**:
4. Summary of the changes made
- You can highlight modified items in the Spreadsheet attached/shared, to help us quickly identify changeset
5. Any specific message to be conveyed to moderators?
- Help us simplify the process if you find something hard about it

184
.github/workflows/ci-cd.yml

@ -4,13 +4,15 @@
name: "CI/CD"
on:
push:
branches-ignore:
- master
paths:
- "packages/nc-gui/**"
- "scripts/cypress/**"
- "packages/nocodb/**"
- ".github/workflows/ci-cd.yml"
pull_request:
branches: [master, develop]
branches: [develop]
paths:
- "packages/nc-gui/**"
- "scripts/cypress/**"
@ -18,6 +20,178 @@ on:
- ".github/workflows/ci-cd.yml"
jobs:
cypress-pg-restTableOps-run:
runs-on: ubuntu-20.04
steps:
- name: Setup Node
uses: actions/setup-node@v1
with:
node-version: 14
- name: Checkout
uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Cache node modules
uses: actions/cache@v2
env:
cache-name: cache-node-modules
with:
# npm cache files are stored in `~/.npm` on Linux/macOS
path: ~/.npm
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-build-${{ env.cache-name }}-
${{ runner.os }}-build-
${{ runner.os }}-
- name: Set env
run: echo "NODE_ENV=test" >> $GITHUB_ENV
- name: Cypress run
uses: cypress-io/github-action@v2
with:
start: |
npm run start:api
npm run start:web
docker-compose -f ./scripts/cypress/docker-compose-pg.yml up -d
spec: "./scripts/cypress/integration/test/pg-restTableOps.js"
wait-on: "http://localhost:8080, http://localhost:3000/_nuxt/runtime.js"
wait-on-timeout: 1200
config-file: scripts/cypress/cypress.json
- name: Upload screenshots
uses: actions/upload-artifact@v2
with:
name: restTableOps-snapshots
path: scripts/cypress/screenshots
retention-days: 2
cypress-pg-restViews-run:
runs-on: ubuntu-20.04
steps:
- name: Setup Node
uses: actions/setup-node@v1
with:
node-version: 14
- name: Checkout
uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Cache node modules
uses: actions/cache@v2
env:
cache-name: cache-node-modules
with:
# npm cache files are stored in `~/.npm` on Linux/macOS
path: ~/.npm
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-build-${{ env.cache-name }}-
${{ runner.os }}-build-
${{ runner.os }}-
- name: Set env
run: echo "NODE_ENV=test" >> $GITHUB_ENV
- name: Cypress run
uses: cypress-io/github-action@v2
with:
start: |
npm run start:api
npm run start:web
docker-compose -f ./scripts/cypress/docker-compose-pg.yml up -d
spec: "./scripts/cypress/integration/test/pg-restViews.js"
wait-on: "http://localhost:8080, http://localhost:3000/_nuxt/runtime.js"
wait-on-timeout: 1200
config-file: scripts/cypress/cypress.json
- name: Upload screenshots
uses: actions/upload-artifact@v2
with:
name: restTableOps-snapshots
path: scripts/cypress/screenshots
retention-days: 2
cypress-pg-restRoles-run:
runs-on: ubuntu-20.04
steps:
- name: Setup Node
uses: actions/setup-node@v1
with:
node-version: 14
- name: Checkout
uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Cache node modules
uses: actions/cache@v2
env:
cache-name: cache-node-modules
with:
# npm cache files are stored in `~/.npm` on Linux/macOS
path: ~/.npm
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-build-${{ env.cache-name }}-
${{ runner.os }}-build-
${{ runner.os }}-
- name: Set env
run: echo "NODE_ENV=test" >> $GITHUB_ENV
- name: Cypress run
uses: cypress-io/github-action@v2
with:
start: |
npm run start:api
npm run start:web
docker-compose -f ./scripts/cypress/docker-compose-pg.yml up -d
spec: "./scripts/cypress/integration/test/pg-restRoles.js"
wait-on: "http://localhost:8080, http://localhost:3000/_nuxt/runtime.js"
wait-on-timeout: 1200
config-file: scripts/cypress/cypress.json
- name: Upload screenshots
uses: actions/upload-artifact@v2
with:
name: restTableOps-snapshots
path: scripts/cypress/screenshots
retention-days: 2
cypress-pg-restMisc-run:
runs-on: ubuntu-20.04
steps:
- name: Setup Node
uses: actions/setup-node@v1
with:
node-version: 14
- name: Checkout
uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Cache node modules
uses: actions/cache@v2
env:
cache-name: cache-node-modules
with:
# npm cache files are stored in `~/.npm` on Linux/macOS
path: ~/.npm
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-build-${{ env.cache-name }}-
${{ runner.os }}-build-
${{ runner.os }}-
- name: Set env
run: echo "NODE_ENV=test" >> $GITHUB_ENV
- name: Cypress run
uses: cypress-io/github-action@v2
with:
start: |
npm run start:api
npm run start:web
docker-compose -f ./scripts/cypress/docker-compose-pg.yml up -d
spec: "./scripts/cypress/integration/test/pg-restMisc.js"
wait-on: "http://localhost:8080, http://localhost:3000/_nuxt/runtime.js"
wait-on-timeout: 1200
config-file: scripts/cypress/cypress.json
- name: Upload screenshots
uses: actions/upload-artifact@v2
with:
name: restTableOps-snapshots
path: scripts/cypress/screenshots
retention-days: 2
cypress-restTableOps-run:
runs-on: ubuntu-20.04
steps:
@ -225,7 +399,6 @@ jobs:
start: |
npm run start:xcdb-api
npm run start:web
docker-compose -f ./scripts/docker-compose-cypress.yml up -d
spec: "./scripts/cypress/integration/test/xcdb-restTableOps.js"
wait-on: "http://localhost:8080, http://localhost:3000/_nuxt/runtime.js"
wait-on-timeout: 1200
@ -269,7 +442,6 @@ jobs:
start: |
npm run start:xcdb-api
npm run start:web
docker-compose -f ./scripts/docker-compose-cypress.yml up -d
spec: "./scripts/cypress/integration/test/xcdb-restViews.js"
wait-on: "http://localhost:8080, http://localhost:3000/_nuxt/runtime.js"
wait-on-timeout: 1200
@ -313,7 +485,6 @@ jobs:
start: |
npm run start:xcdb-api
npm run start:web
docker-compose -f ./scripts/docker-compose-cypress.yml up -d
spec: "./scripts/cypress/integration/test/xcdb-restRoles.js"
wait-on: "http://localhost:8080, http://localhost:3000/_nuxt/runtime.js"
wait-on-timeout: 1200
@ -357,7 +528,6 @@ jobs:
start: |
npm run start:xcdb-api
npm run start:web
docker-compose -f ./scripts/docker-compose-cypress.yml up -d
spec: "./scripts/cypress/integration/test/xcdb-restMisc.js"
wait-on: "http://localhost:8080, http://localhost:3000/_nuxt/runtime.js"
wait-on-timeout: 1200
@ -577,7 +747,6 @@ jobs:
start: |
npm run start:xcdb-api
npm run start:web
docker-compose -f ./scripts/docker-compose-cypress.yml up -d
spec: "./scripts/cypress/integration/test/xcdb-gqlTableOps.js"
wait-on: "http://localhost:8080, http://localhost:3000/_nuxt/runtime.js"
wait-on-timeout: 1200
@ -621,7 +790,6 @@ jobs:
start: |
npm run start:xcdb-api
npm run start:web
docker-compose -f ./scripts/docker-compose-cypress.yml up -d
spec: "./scripts/cypress/integration/test/xcdb-gqlViews.js"
wait-on: "http://localhost:8080, http://localhost:3000/_nuxt/runtime.js"
wait-on-timeout: 1200
@ -665,7 +833,6 @@ jobs:
start: |
npm run start:xcdb-api
npm run start:web
docker-compose -f ./scripts/docker-compose-cypress.yml up -d
spec: "./scripts/cypress/integration/test/xcdb-gqlRoles.js"
wait-on: "http://localhost:8080, http://localhost:3000/_nuxt/runtime.js"
wait-on-timeout: 1200
@ -709,7 +876,6 @@ jobs:
start: |
npm run start:xcdb-api
npm run start:web
docker-compose -f ./scripts/docker-compose-cypress.yml up -d
spec: "./scripts/cypress/integration/test/xcdb-gqlMisc.js"
wait-on: "http://localhost:8080, http://localhost:3000/_nuxt/runtime.js"
wait-on-timeout: 1200

34
.github/workflows/release-close-issue.yml

@ -0,0 +1,34 @@
name: 'Close Issues with Labels'
on:
# Triggered manually
workflow_dispatch:
inputs:
issue_label:
description: "All issues with such label will be closed"
required: true
version:
description: "Which version is this issue fixed in"
required: true
# Triggered by release-nocodb.yml
workflow_call:
inputs:
issue_label:
description: "All issues with such label will be closed"
required: true
type: string
version:
description: "Which version is this issue fixed in"
required: true
type: string
jobs:
close-issues:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- name: close-resolved-issues
uses: wingkwong/close-issues-based-on-label@master
env:
LABEL: ${{ github.event.inputs.issue_label || inputs.issue_label }}
VERSION: ${{ github.event.inputs.version || inputs.version }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

12
.github/workflows/release-docker.yml

@ -1,11 +1,19 @@
name: "Release : Docker"
on:
# Triggered manually
workflow_dispatch:
inputs:
tag:
description: "Docker image tag"
required: true
# Triggered by release-nocodb.yml
workflow_call:
inputs:
tag:
description: "Docker image tag"
required: true
type: string
jobs:
buildx:
@ -59,13 +67,13 @@ jobs:
uses: docker/build-push-action@v2
with:
context: ${{ env.working-directory }}
build-args: NC_VERSION=${{ github.event.inputs.tag }}
build-args: NC_VERSION=${{ github.event.inputs.tag || inputs.tag }}
platforms: linux/amd64,linux/arm64,linux/arm/v7
cache-from: type=local,src=/tmp/.buildx-cache
cache-to: type=local,dest=/tmp/.buildx-cache-new
push: true
tags: |
nocodb/nocodb:${{ github.event.inputs.tag }}
nocodb/nocodb:${{ github.event.inputs.tag || inputs.tag }}
nocodb/nocodb:latest
# Temp fix

16
.github/workflows/release-draft.yml

@ -1,6 +1,7 @@
name: "Release : Draft Notes"
on:
# Triggered manually
workflow_dispatch:
inputs:
tag:
@ -9,6 +10,17 @@ on:
prev_tag:
description: "Previous Tag"
required: true
# Triggered by release-nocodb.yml
workflow_call:
inputs:
tag:
description: "Tag"
required: true
type: string
prev_tag:
description: "Previous Tag"
required: true
type: string
jobs:
build:
@ -22,7 +34,7 @@ jobs:
github.git.createRef({
owner: context.repo.owner,
repo: context.repo.repo,
ref: "refs/tags/${{ github.event.inputs.tag }}",
ref: "refs/tags/${{ github.event.inputs.tag || inputs.tag }} ",
sha: context.sha
})
@ -33,4 +45,4 @@ jobs:
- uses: actions/setup-node@v2
with:
node-version: 14
- run: "npx github-release-notes@0.17.2 release --token ${{ secrets.GH_TOKEN }} --draft --tags ${{ github.event.inputs.tag }}..${{ github.event.inputs.prev_tag }}"
- run: "npx github-release-notes@0.17.2 release --token ${{ secrets.GH_TOKEN }} --draft --tags ${{ github.event.inputs.tag || inputs.tag }}..${{ github.event.inputs.prev_tag || inputs.prev_tag }} "

52
.github/workflows/release-nocodb.yml

@ -0,0 +1,52 @@
name: 'NocoDB Release'
on:
# Triggered manually
workflow_dispatch:
inputs:
tag:
description: "Target Tag"
required: true
prev_tag:
description: "Previous Tag"
required: true
jobs:
# Close all issues with target tags 'Fixed' & 'Resolved'
close-fixed-issues:
needs: release-npm
uses: ./.github/workflows/release-close-issue.yml
with:
issue_label: 'Fixed'
version: ${{ github.event.inputs.tag }}
close-resolved-issues:
needs: close-fixed-issues
uses: ./.github/workflows/release-close-issue.yml
with:
issue_label: 'Resolved'
version: ${{ github.event.inputs.tag }}
# Build, install, publish frontend and backend to npm
release-npm:
uses: ./.github/workflows/release-npm.yml
with:
tag: ${{ github.event.inputs.tag }}
# Draft Release Note
release-draft-note:
needs: close-issues
uses: ./.github/workflows/release-draft.yml
with:
tag: ${{ github.event.inputs.tag }}
prev_tag: ${{ github.event.inputs.prev_tag }}
# Build docker image and push to docker hub
release-docker:
needs: release-draft-note
uses: ./.github/workflows/release-docker.yml
with:
tag: ${{ github.event.inputs.tag }}
# Sync changes to develop
sync-to-develop:
needs: release-docker
uses: ./.github/workflows/sync-to-develop.yml

124
.github/workflows/release-npm.yml

@ -1,15 +1,19 @@
name: "Release : NPM packages"
on:
# Triggered manually
workflow_dispatch:
inputs:
tag:
description: "Tag"
required: true
prev_tag:
description: "Previous Tag"
type: string
# Triggered by release-nocodb.yml
workflow_call:
inputs:
tag:
description: "Tag"
required: true
jobs:
release:
runs-on: ubuntu-latest
@ -31,7 +35,7 @@ jobs:
npm run build:copy:jsdeliver
cd ../..
npm install
VERSION=${{github.event.inputs.tag}} node scripts/upgradeNcGui.js node scripts/upgradeNcGui.js && cd packages/nocodb && npm run obfuscate:build:publish
VERSION=${{ github.event.inputs.tag || inputs.tag }} node scripts/upgradeNcGui.js node scripts/upgradeNcGui.js && cd packages/nocodb && npm run obfuscate:build:publish
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
- name: Create Pull Request
@ -44,113 +48,17 @@ jobs:
# committer: GitHub <noreply@github.com>
# author: ${{ github.actor }} <${{ github.actor }}@users.noreply.github.com>
signoff: true
branch: release-patches
branch: 'release/${{ github.event.inputs.tag || inputs.tag }}'
delete-branch: true
title: 'Release ${{github.event.inputs.tag}}'
title: 'Release ${{ github.event.inputs.tag || inputs.tag }}'
labels: |
automerge
Bot: Automated PR
- name: Check outputs
run: |
echo "Pull Request Number - ${{ steps.cpr.outputs.pull-request-number }}"
echo "Pull Request URL - ${{ steps.cpr.outputs.pull-request-url }}"
- name: automerge
uses: "pascalgn/automerge-action@v0.14.3"
env:
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
PULL_REQUEST: "${{ steps.cpr.outputs.pull-request-number }}"
buildx:
runs-on: ubuntu-latest
needs: [release]
env:
working-directory: ./packages/nocodb
strategy:
matrix:
node-version: [ 12 ]
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v2
with:
node-version: ${{ matrix.node-version }}
- uses: bahmutov/npm-install@v1
with:
working-directory: ${{ env.working-directory }}
- name: Build nocodb and docker files
run: |
npm run build
npm run docker:build
working-directory: ${{ env.working-directory }}
- name: Set up QEMU
uses: docker/setup-qemu-action@v1
- name: Set up Docker Buildx
id: buildx
uses: docker/setup-buildx-action@v1
- name: Cache Docker layers
uses: actions/cache@v2
with:
path: /tmp/.buildx-cache
key: ${{ runner.os }}-buildx-${{ github.sha }}
restore-keys: |
${{ runner.os }}-buildx-
- name: Login to DockerHub
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v2
with:
context: ${{ env.working-directory }}
build-args: NC_VERSION=${{ github.event.inputs.tag }}
platforms: linux/amd64,linux/arm64,linux/arm/v7
cache-from: type=local,src=/tmp/.buildx-cache
cache-to: type=local,dest=/tmp/.buildx-cache-new
push: true
tags: |
nocodb/nocodb:${{ github.event.inputs.tag }}
nocodb/nocodb:latest
# Temp fix
# https://github.com/docker/build-push-action/issues/252
# https://github.com/moby/buildkit/issues/1896
- name: Move cache
run: |
rm -rf /tmp/.buildx-cache
mv /tmp/.buildx-cache-new /tmp/.buildx-cache
draft:
runs-on: ubuntu-latest
needs: [release]
steps:
- name: Create tag
uses: actions/github-script@v3
with:
github-token: ${{ secrets.GH_TOKEN }}
script: |
github.git.createRef({
owner: context.repo.owner,
repo: context.repo.repo,
ref: "refs/tags/${{ github.event.inputs.tag }}",
sha: context.sha
})
- uses: actions/checkout@v2
with:
fetch-depth: 0
- uses: actions/setup-node@v2
with:
node-version: 14
- run: "npx github-release-notes@0.17.2 release --token ${{ secrets.GH_TOKEN }} --draft --tags ${{ github.event.inputs.tag }}..${{ github.event.inputs.prev_tag }}"
- name: automerge
uses: "pascalgn/automerge-action@v0.14.3"
env:
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
PULL_REQUEST: "${{ steps.cpr.outputs.pull-request-number }}"

23
.github/workflows/sync-to-develop.yml

@ -0,0 +1,23 @@
name: 'Sync changes back to develop branch from master'
on:
# Triggered manually
workflow_dispatch:
# Triggered by release-nocodb.yml
workflow_call:
jobs:
close-issues:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v1
- name: Merge from master to develop
uses: robotology/gh-action-nightly-merge@v1.3.1
with:
stable_branch: 'master'
development_branch: 'develop'
allow_ff: true
allow_forks: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

1
.gitignore vendored

@ -83,3 +83,4 @@ mongod
# Cypress
#=========
shared.json
/scripts/Cypress/screenshots

1
README.md

@ -389,6 +389,7 @@ Our mission is to provide the most powerful no-code interface for databases whic
<td align="center"><a href="https://github.com/willnewii"><img src="https://avatars.githubusercontent.com/u/652003?v=4?s=100" width="100px;" alt=""/><br /><sub><b>诗人的咸鱼</b></sub></a><br /><a href="https://github.com/nocodb/nocodb/commits?author=willnewii" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/bitbytejoy"><img src="https://avatars.githubusercontent.com/u/11807034?v=4?s=100" width="100px;" alt=""/><br /><sub><b>bitbytejoy</b></sub></a><br /><a href="https://github.com/nocodb/nocodb/commits?author=bitbytejoy" title="Code">💻</a></td>
<td align="center"><a href="http://blog.pan93.com"><img src="https://avatars.githubusercontent.com/u/28441561?v=4?s=100" width="100px;" alt=""/><br /><sub><b>pan93412</b></sub></a><br /><a href="https://github.com/nocodb/nocodb/commits?author=pan93412" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/LancerComet"><img src="https://avatars.githubusercontent.com/u/10321350?v=4?s=100" width="100px;" alt=""/><br /><sub><b>LancerComet</b></sub></a><br /><a href="https://github.com/nocodb/nocodb/commits?author=LancerComet" title="Code">💻</a></td>
</tr>
</table>

97
package-lock.json generated

@ -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",

1
package.json

@ -28,6 +28,7 @@
},
"dependencies": {
"mysql2": "^2.3.3",
"pg": "^8.7.3",
"sqlite3": "^5.0.2"
}
}

12
packages/nc-cli/package-lock.json generated

@ -6610,9 +6610,9 @@
}
},
"node_modules/follow-redirects": {
"version": "1.14.6",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.6.tgz",
"integrity": "sha512-fhUl5EwSJbbl8AR+uYL2KQDxLkdSjZGR36xy46AO7cOMTrCMON6Sa28FmAnC2tRTDbd/Uuzz3aJBv7EBN7JH8A==",
"version": "1.14.8",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.8.tgz",
"integrity": "sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA==",
"funding": [
{
"type": "individual",
@ -21377,9 +21377,9 @@
"integrity": "sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q=="
},
"follow-redirects": {
"version": "1.14.6",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.6.tgz",
"integrity": "sha512-fhUl5EwSJbbl8AR+uYL2KQDxLkdSjZGR36xy46AO7cOMTrCMON6Sa28FmAnC2tRTDbd/Uuzz3aJBv7EBN7JH8A=="
"version": "1.14.8",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.8.tgz",
"integrity": "sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA=="
},
"for-in": {
"version": "1.0.2",

6
packages/nc-common/package-lock.json generated

@ -5208,9 +5208,9 @@
"dev": true
},
"handlebars": {
"version": "4.7.6",
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.6.tgz",
"integrity": "sha512-1f2BACcBfiwAfStCKZNrUCgqNZkGsAT7UM3kkYtXuLo0KnaVfjKOyf7PRzB6++aK9STyT1Pd2ZCPe3EGOXleXA==",
"version": "4.7.7",
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz",
"integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==",
"dev": true,
"requires": {
"minimist": "^1.2.5",

6
packages/nc-gui/components/auth/roles.vue

@ -23,11 +23,11 @@
<!-- </v-toolbar-title>-->
<v-spacer />
<!-- tooltip="Reload roles" -->
<x-btn
v-ge="['roles','reload']"
outlined
tooltip="Reload roles"
:tooltip="$t('activity.reloadRoles')"
color="primary"
small
:disabled="loading"
@ -36,7 +36,7 @@
<v-icon small left>
refresh
</v-icon>
Reload
{{ $t('general.reload')}}
</x-btn>
<x-btn
v-ge="['roles','add new']"

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

@ -20,10 +20,11 @@
</v-text-field>
<v-spacer />
<!-- tooltip="Reload roles" -->
<x-btn
v-ge="['roles','reload']"
outlined
tooltip="Reload roles"
:tooltip="$t('activity.reloadRoles')"
color="primary"
small
:disabled="loading"
@ -33,13 +34,15 @@
<v-icon small left>
refresh
</v-icon>
Reload
<!-- Reload -->
{{ $t('general.reload')}}
</x-btn>
<!-- tooltip="Add new role" -->
<x-btn
v-if="_isUIAllowed('newUser')"
v-ge="['roles','add new']"
outlined
tooltip="Add new role"
:tooltip="$t('tooltip.addRole')"
color="primary"
small
:disabled="loading"
@ -48,7 +51,8 @@
<v-icon small left>
mdi-plus
</v-icon>
New User
<!-- New User -->
{{ $t('activity.newUser')}}
</x-btn>
</v-toolbar>
@ -91,17 +95,20 @@
<v-icon small>
mdi-email-outline
</v-icon>
Email
<!-- Email -->
{{ $t('labels.email')}}
</th>
<th class="font-weight-regular caption">
<v-icon small>
mdi-drama-masks
</v-icon>
Roles
<!-- Roles -->
{{ $t('objects.roles')}}
</th>
<th class="font-weight-regular caption">
<!-- <v-icon small class="mt-n1">mdi-cursor-default-outline</v-icon>-->
Actions
<!-- Actions -->
{{ $t('labels.actions')}}
</th>
</tr>
</thead>
@ -145,9 +152,10 @@
<!-- </v-edit-dialog>-->
</td>
<td>
<!-- tooltip="Edit User" -->
<x-icon
v-if="item.project_id"
tooltip="Edit User"
:tooltip="$t('activity.editUser')"
icon-class=""
color="primary"
small
@ -155,30 +163,41 @@
>
mdi-pencil-outline
</x-icon>
<x-icon
v-if="!item.project_id"
tooltip="Add user to project"
color="primary"
small
@click="inviteUser(item.email)"
>
mdi-plus
</x-icon>
<span v-if="!item.project_id">
<x-icon
tooltip="Add user to project"
color="primary"
small
@click="inviteUser(item.email)"
>
mdi-plus
</x-icon>
<!-- <x-icon
tooltip="Remove user from NocoDB"
class="ml-2"
color="error"
small
@click.prevent.stop="deleteId = item.id; deleteItem = item.id;showConfirmDlg = true;deleteUserType='DELETE_FROM_NOCODB'"
>
mdi-delete-forever-outline
</x-icon> -->
</span>
<!-- tooltip="Remove user from project" -->
<x-icon
v-else
tooltip="Remove user from project"
:tooltip="$t('activity.deleteUser')"
class="ml-2"
color="error"
small
@click.prevent.stop="deleteId = item.id; deleteItem = item.id;showConfirmDlg = true"
@click.prevent.stop="deleteId = item.id; deleteItem = item.id;showConfirmDlg = true;deleteUserType='DELETE_FROM_PROJECT'"
>
mdi-delete-outline
</x-icon>
<!-- tooltip="Resend invite email" -->
<x-icon
v-if="item.invite_token"
tooltip="Resend invite email"
:tooltip="$t('activity.resendInvite')"
icon-class="mt-n1"
color="primary"
small
@ -187,9 +206,10 @@
mdi-email-send-outline
</x-icon>
<!-- tooltip="Copy invite url" -->
<x-icon
v-if="item.invite_token"
tooltip="Copy invite url"
:tooltip="$t('activity.copyInviteURL')"
icon-class=""
color="primary"
small
@ -201,12 +221,13 @@
</tr>
</template>
</v-data-table>
<!-- tooltip="Add new user" -->
<div class="mt-10 text-center">
<x-btn
v-if="_isUIAllowed('newUser')"
v-ge="['roles','add new']"
outlined
tooltip="Add new user"
:tooltip="$t('msg.info.addUser')"
color="primary"
small
:disabled="loading"
@ -215,7 +236,8 @@
<v-icon small left>
mdi-plus
</v-icon>
New User
<!-- New User -->
{{ $t('activity.newUser') }}
</x-btn>
</div>
@ -296,7 +318,7 @@
<dlg-label-submit-cancel
type="primary"
:actions-mtd="confirmDelete"
heading="Do you want to remove the user from project?"
:heading="dialogMessage"
:dialog-show="showConfirmDlg"
/>
@ -304,7 +326,7 @@
<v-dialog v-model="userEditDialog" :width="invite_token ? 700 :700" @close="invite_token = null">
<v-card v-if="selectedUser" style="min-height: 100%">
<v-card-title>
Share : {{ $store.getters['project/GtrProjectName'] }}
{{ $t('activity.share') }} : {{ $store.getters['project/GtrProjectName'] }}
<!--
<h4 class="text-center text-capitalize mt-2 d-100 display-1">
<template v-if="invite_token">
@ -333,7 +355,8 @@
Edit User
</template>
<template v-else>
Invite Team
<!-- Invite Team -->
{{ $t('activity.inviteTeam') }}
</template>
</div>
<div class="pa-4 nc-invite-container">
@ -357,9 +380,10 @@
</v-alert>
<p class="caption grey--text mt-3">
Looks like you have not configured mailer yet! <br>Please copy above
invite
link and send it to
{{ $t('msg.info.userInviteNoSMTP') }}
<!-- Looks like you have not configured mailer yet! <br>Please copy above -->
<!-- invite -->
<!-- link and send it to -->
{{ invite_token && (invite_token.email || invite_token.emails && invite_token.emails.join(', ')) }}.
</p>
@ -398,7 +422,10 @@
@input="edited=true"
>
<template #label>
<span class="caption">Email</span>
<span class="caption">
<!-- Email -->
{{ $t('labels.email') }}
</span>
</template>
</v-text-field>
</v-col>
@ -433,6 +460,8 @@
</v-form>
<!-- </v-card-text>
<v-card-actions class="justify-center">-->
<!-- tooltip="Save Changes" -->
<div class="text-center mt-0">
<x-btn
v-ge="['rows','save']"
@ -445,7 +474,7 @@
<v-icon small left>
{{ selectedUser.id ? 'save' : 'mdi-send' }}
</v-icon>
{{ selectedUser.id ? 'Save' : 'Invite' }}
{{ selectedUser.id ? $t('general.save') : $t('activity.invite') }}
</x-btn>
</div>
</template>
@ -497,7 +526,8 @@ export default {
}
],
userList: [],
roleDescriptions: {}
roleDescriptions: {},
deleteUserType: '' // [DELETE_FROM_PROJECT, DELETE_FROM_NOCODB]
}),
computed: {
roleNames() {
@ -530,6 +560,12 @@ export default {
set(i) {
this.selectedUser = this.users[i]
}
},
dialogMessage() {
let msg = 'Do you want to remove the user'
if (this.deleteUserType === 'DELETE_FROM_PROJECT') { msg += ' from Project' } else if (this.deleteUserType === 'DELETE_FROM_NOCODB') { msg += ' from NocoDB' }
msg += '?'
return msg
}
},
watch: {
@ -669,30 +705,30 @@ export default {
console.log(e)
}
},
async deleteUser(id) {
async deleteUser(id, type) {
try {
await this.$axios.delete('/admin/' + id, {
params: {
project_id: this.$route.params.project_id,
email: this.deleteItem.email
email: this.deleteItem.email,
type
},
headers: {
'xc-auth': this.$store.state.users.token
}
})
this.$toast.success('Successfully removed the user from project').goAway(3000)
this.$toast.success(`Successfully removed the user from ${type === 'DELETE_FROM_PROJECT' ? 'project' : 'NocoDB'}`).goAway(3000)
await this.loadUsers()
} catch (e) {
this.$toast.error(e.response.data.msg).goAway(3000)
}
},
async confirmDelete(hideDialog) {
if (hideDialog) {
this.showConfirmDlg = false
return
}
await this.deleteUser(this.deleteId)
await this.deleteUser(this.deleteId, this.deleteUserType)
this.showConfirmDlg = false
},
addUser() {
@ -832,6 +868,7 @@ export default {
*
* @author Naveen MR <oof1lab@gmail.com>
* @author Pranav C Balan <pranavxc@gmail.com>
* @author Wing-Kam Wong <wingkwong.code@gmail.com>
*
* @license GNU AGPL version 3 or any later version
*

72
packages/nc-gui/components/base/shareBase.vue

@ -3,23 +3,46 @@
<v-icon color="grey" small>
mdi-open-in-new
</v-icon>
<span class="grey--text caption">Shared base link</span>
<span class="grey--text caption">
<!-- Shared base link -->
{{ $t('activity.shareBase.link') }}
</span>
<div class="nc-container">
<v-chip v-if="base.enabled" :color="colors[4]" style="" class="rounded pl-1 pr-0 d-100 nc-url-chip pr-3">
<div class="nc-url-wrapper d-flex mx-1 align-center d-100">
<span class="nc-url flex-grow-1 caption ">{{ url }}</span>
<v-spacer />
<v-divider vertical />
<x-icon tooltip="reload" @click="recreate">
<!-- tooltip="reload" -->
<x-icon
:tooltip="$t('general.reload')"
@click="recreate"
>
mdi-reload
</x-icon>
<x-icon tooltip="copy URL" @click="copyUrl">
<!-- tooltip="copy URL" -->
<x-icon
:tooltip="$t('activity.copyUrl')"
@click="copyUrl"
>
mdi-content-copy
</x-icon>
<x-icon tooltip="open new tab" @click="navigateToSharedBase">
<!-- tooltip="open new tab" -->
<x-icon
:tooltip="$t('activity.openTab')"
@click="navigateToSharedBase"
>
mdi-open-in-new
</x-icon>
<x-icon tooltip="copy embeddable HTML code" @click="generateEmbeddableIframe">
<!-- tooltip="copy embeddable HTML code" -->
<x-icon
:tooltip="$t('activity.iFrame')"
@click="generateEmbeddableIframe"
>
mdi-xml
</x-icon>
</div>
@ -31,8 +54,14 @@
<template #activator="{on}">
<div class="my-2" v-on="on">
<div class="font-weight-bold nc-disable-shared-base">
<span v-if="base.enabled">Anyone with the link</span>
<span v-else>Disabled shared base</span>
<span v-if="base.enabled">
<!-- Anyone with the link -->
{{ $t('activity.shareBase.enable') }}
</span>
<span v-else>
<!-- Disable shared base -->
{{ $t('activity.shareBase.disable') }}
</span>
<v-icon small>
mdi-menu-down-outline
</v-icon>
@ -45,7 +74,10 @@
<v-icon small class="mr-1">
mdi-link-variant
</v-icon>
<span class="caption">Anyone with the link</span>
<span class="caption">
<!-- Anyone with the link -->
{{ $t('activity.shareBase.enable') }}
</span>
</v-list-item-title>
</v-list-item>
<v-list-item dense @click="disableSharedBase">
@ -53,18 +85,28 @@
<v-icon small class="mr-1">
mdi-link-variant-off
</v-icon>
<span class="caption">Disable shared base</span>
<span class="caption">
<!-- Disable shared base -->
{{ $t('activity.shareBase.link') }}
</span>
</v-list-item-title>
</v-list-item>
</v-list>
</v-menu>
<div class=" caption">
<template v-if="base.enabled">
<span v-if="base.roles === 'editor'">Anyone on the internet with this link can edit</span>
<span v-else-if="base.roles === 'viewer'">Anyone on the internet with this link can view</span>
<span v-if="base.roles === 'editor'">
Anyone on the internet with this link can edit
<!-- {{ $t('msg.info.shareBasePrivate') }} -->
</span>
<span v-else-if="base.roles === 'viewer'">
<!-- Anyone on the internet with this link can view -->
{{ $t('msg.info.shareBasePublic') }}
</span>
</template>
<template v-else>
Generate publicly shareable readonly base
<!-- Generate publicly shareable readonly base -->
{{ $t('msg.info.shareBasePrivate') }}
</template>
</div>
</div>
@ -84,12 +126,14 @@
<v-list dense>
<v-list-item @click="createSharedBase('editor')">
<v-list-item-title>
Editor
<!-- Editor -->
{{ $t('objects.roleType.editor') }}
</v-list-item-title>
</v-list-item>
<v-list-item @click="createSharedBase('viewer')">
<v-list-item-title>
Viewer
<!-- Viewer -->
{{ $t('objects.roleType.viewer') }}
</v-list-item-title>
</v-list-item>
</v-list>

2
packages/nc-gui/components/project/spreadsheet/components/expandedForm.vue

@ -437,7 +437,7 @@ export default {
this.$emit('input', this.localState)
this.$emit('update:isNew', false)
this.$toast.success(`${this.primaryValue()} updated successfully.`, {
this.$toast.success(`${this.primaryValue() || "Row"} updated successfully.`, {
position: 'bottom-right'
}).goAway(3000)
} catch (e) {

2
packages/nc-gui/components/project/spreadsheet/components/extras.vue

@ -76,7 +76,7 @@
<v-list-item
dense
target="_blank"
href="https://calendly.com/nocodb"
href="https://calendly.com/nocodb-meeting"
>
<!-- Book a Free DEMO -->
<v-list-item-title>

22
packages/nc-gui/components/project/spreadsheet/components/importExport/columnMappingModal.vue

@ -158,8 +158,28 @@ export default {
return 'Source data contains some invalid numbers'
}
break
case UITypes.Checkbox:
if (
this.parsedCsv && this.parsedCsv.data && this.parsedCsv.data.slice(0, 500)
.some((r) => {
if (r => r[row.sourceCn] !== null && r[row.sourceCn] !== undefined) {
var input = r[row.sourceCn]
if (typeof input === 'string') {
input = input.replace(/["']/g, "").toLowerCase().trim()
return (
input == "false" || input == "no" || input == "n" || input == "0" ||
input == "true" || input == "yes" || input == "y" || input == "1"
) ? false : true
}
return input != 1 && input != 0 && input != true && input != false
}
return false
})
) {
return 'Source data contains some invalid boolean values'
}
break
}
return true
},
mapDefaultColumns() {

15
packages/nc-gui/components/project/spreadsheet/components/moreActions.vue

@ -106,6 +106,7 @@ import FileSaver from 'file-saver'
import DropOrSelectFileModal from '~/components/import/dropOrSelectFileModal'
import ColumnMappingModal from '~/components/project/spreadsheet/components/importExport/columnMappingModal'
import CSVTemplateAdapter from '~/components/import/templateParsers/CSVTemplateAdapter'
import { UITypes } from '~/components/project/spreadsheet/helpers/uiTypes'
export default {
name: 'ExportImport',
@ -276,9 +277,19 @@ export default {
for (let i = 0, progress = 0; i < data.length; i += 500) {
const batchData = data.slice(i, i + 500).map(row => columnMappings.reduce((res, col) => {
// todo: parse data
if (col.enabled && col.destCn) {
res[col.destCn] = row[col.sourceCn]
const v = this.meta && this.meta.columns.find(c => c._cn === col.destCn)
var input = row[col.sourceCn]
// parse potential boolean values
if (v.uidt == UITypes.Checkbox) {
input = input.replace(/["']/g, "").toLowerCase().trim()
if (input == "false" || input == "no" || input == "n") {
input = "0"
} else if (input == "true" || input == "yes" || input == "y") {
input = "1"
}
}
res[col.destCn] = input
}
return res
}, {}))

2
packages/nc-gui/components/project/spreadsheet/components/virtualCell/components/listItems.vue

@ -162,7 +162,7 @@ export default {
offset: this.size * (this.page - 1),
...this.queryParams,
where
}, this.mm.vtn, this.parentId)
}, this.mm.vtn, this.parentId || -1)
} else {
this.data = await this.api.paginatedList({
limit: this.size,

5
packages/nc-gui/components/project/spreadsheet/mixins/spreadsheet.js

@ -163,7 +163,10 @@ export default {
concatenatedXWhere() {
let where = ''
if (this.searchField && this.searchQuery.trim()) {
if (['text', 'string'].includes(this.sqlUi.getAbstractType(this.availableColumns.find(({ _cn }) => _cn === this.searchField) || this.availableColumns[0]))) {
const col = this.availableColumns.find(({ _cn }) => _cn === this.searchField) || this.availableColumns[0]
// bigint values are displayed in string format in UI
// when searching bigint values, the operator should be 'eq' instead of 'like'
if (['text', 'string'].includes(this.sqlUi.getAbstractType(col)) && col.dt !== 'bigint') {
where = `(${this.searchField},like,%${this.searchQuery.trim()}%)`
} else {
where = `(${this.searchField},eq,${this.searchQuery.trim()})`

2
packages/nc-gui/components/project/spreadsheet/views/xcGridView.vue

@ -237,7 +237,7 @@
/>
</td>
</tr>
<tr v-if="isPkAvail && !isLocked && !isPublicView && isEditable && relationType !== 'bt'">
<tr v-if="!isLocked && !isPublicView && isEditable && relationType !== 'bt'">
<td :colspan="visibleColLength + 1" class="text-left pointer nc-grid-add-new-cell" @click="insertNewRow(true)">
<v-tooltip top>
<template #activator="{on}">

205
packages/nc-gui/components/utils/dlgTableCreate.vue

@ -7,112 +7,114 @@
@keydown.enter="$emit('create', table)"
>
<v-card class="elevation-1 backgroundColor nc-create-table-card">
<v-card-title class="primary subheading white--text py-2">
Create A New Table
</v-card-title>
<v-form ref="form" v-model="valid">
<v-card-title class="primary subheading white--text py-2">
Create A New Table
</v-card-title>
<v-card-text class=" py-6 px-10 ">
<v-text-field
ref="input"
v-model="table.alias"
solo
flat
persistent-hint
dense
hide-details1
:rules="[validateTableName]"
hint="Enter table name"
class="mt-4 caption nc-table-name"
/>
<v-card-text class=" py-6 px-10 ">
<v-text-field
ref="input"
v-model="table.alias"
solo
flat
persistent-hint
dense
hide-details1
:rules="[validateTableName]"
hint="Enter table name"
class="mt-4 caption nc-table-name"
/>
<v-text-field
v-if="!projectPrefix"
v-model="table.name"
solo
flat
dense
persistent-hint
hint="Table name as saved in database"
class="mt-4 caption nc-table-name-alias"
/>
<v-text-field
v-if="!projectPrefix"
v-model="table.name"
solo
flat
dense
persistent-hint
hint="Table name as saved in database"
class="mt-4 caption nc-table-name-alias"
/>
<div class=" mt-5">
<label class="add-default-title grey--text">Add Default Columns</label>
<div class=" mt-5">
<label class="add-default-title grey--text">Add Default Columns</label>
<div class=" d-flex caption justify-space-between">
<v-checkbox
v-model="table.columns"
dense
class="mt-0 "
color="info"
hide-details
value="id"
@click.capture.prevent.stop="()=>{
$toast.info('ID column is required, you can rename this later if required.').goAway(3000);
if(!table.columns.includes('id')){
table.columns.push('id');
}
}"
>
<template #label>
<span class="caption">id</span>
</template>
</v-checkbox>
<v-checkbox
v-model="table.columns"
dense
class="mt-0 "
color="info"
hide-details
value="title"
>
<template #label>
<span class="caption">title</span>
</template>
</v-checkbox>
<v-checkbox
v-model="table.columns"
dense
class="mt-0 "
color="info"
hide-details
value="created_at"
>
<template #label>
<span class="caption">created_at</span>
</template>
</v-checkbox>
<v-checkbox
v-model="table.columns"
dense
class="mt-0 "
color="info"
hide-details
value="updated_at"
>
<template #label>
<span class="caption">updated_at</span>
</template>
</v-checkbox>
<div class=" d-flex caption justify-space-between">
<v-checkbox
v-model="table.columns"
dense
class="mt-0 "
color="info"
hide-details
value="id"
@click.capture.prevent.stop="()=>{
$toast.info('ID column is required, you can rename this later if required.').goAway(3000);
if(!table.columns.includes('id')){
table.columns.push('id');
}
}"
>
<template #label>
<span class="caption">id</span>
</template>
</v-checkbox>
<v-checkbox
v-model="table.columns"
dense
class="mt-0 "
color="info"
hide-details
value="title"
>
<template #label>
<span class="caption">title</span>
</template>
</v-checkbox>
<v-checkbox
v-model="table.columns"
dense
class="mt-0 "
color="info"
hide-details
value="created_at"
>
<template #label>
<span class="caption">created_at</span>
</template>
</v-checkbox>
<v-checkbox
v-model="table.columns"
dense
class="mt-0 "
color="info"
hide-details
value="updated_at"
>
<template #label>
<span class="caption">updated_at</span>
</template>
</v-checkbox>
</div>
</div>
</div>
</v-card-text>
<v-divider />
</v-card-text>
<v-divider />
<v-card-actions class="py-4 px-10">
<v-spacer />
<v-btn class="" @click="dialogShow = false">
Cancel
</v-btn>
<v-btn
:disabled="!(table.name && table.name.length) || !(table.alias && table.alias.length)"
color="primary"
class="nc-create-table-submit"
@click="$emit('create',table)"
>
Submit
</v-btn>
</v-card-actions>
<v-card-actions class="py-4 px-10">
<v-spacer />
<v-btn class="" @click="dialogShow = false">
Cancel
</v-btn>
<v-btn
:disabled="!(table.name && table.name.length) || !(table.alias && table.alias.length) || !valid"
color="primary"
class="nc-create-table-submit"
@click="$emit('create',table)"
>
Submit
</v-btn>
</v-card-actions>
</v-form>
</v-card>
</v-dialog>
</template>
@ -134,7 +136,8 @@ export default {
'created_at',
'updated_at']
},
validateTableName
validateTableName,
valid: false
}
},
computed: {

34
packages/nc-gui/helpers/formulaList.js

@ -1,32 +1,32 @@
const validations = {
AVG: {
validation: {
args: { min: 1 }
}
args: { min: 1 },
},
},
ADD: {
validation: {
args: { min: 1 }
}
args: { min: 1 },
},
},
AND: {
validation: {
args: { min: 1 }
}
args: { min: 1 },
},
},
OR: {
validation: {
args: { min: 1 }
}
args: { min: 1 },
},
},
CONCAT: {
validation: { args: { min: 1 } }
validation: { args: { min: 1 } },
},
TRIM: {
validation: { args: { min: 1 } }
validation: { args: { min: 1 } },
},
UPPER: {
validation: { args: { rqd: 1 } }
validation: { args: { rqd: 1 } },
},
LOWER: { validation: { args: { rqd: 1 } } },
LEN: { validation: { args: { rqd: 1 } } },
@ -43,18 +43,18 @@ const validations = {
SQRT: { validation: { args: { rqd: 1 } } },
ABS: { validation: { args: { rqd: 1 } } },
NOW: { validation: { args: { rqd: 0 } } },
REPLACE: { validation: { args: { rqd: 2 } } },
REPLACE: { validation: { args: { rqd: 3 } } },
SEARCH: { validation: { args: { rqd: 2 } } },
INT: { validation: { args: { rqd: 1 } } },
RIGHT: { validation: { args: { rqd: 2 } } },
LEFT: {
validation: { args: { rqd: 1 } }
validation: { args: { rqd: 1 } },
},
SUBSTR: { validation: { args: { min: 2, max: 3 } } },
MID: { validation: { args: { rqd: 1 } } },
IF: { validation: { args: { min: 2, max: 3 } } },
SWITCH: { validation: { args: { min: 3 } } }
}
SWITCH: { validation: { args: { min: 3 } } },
};
export default Object.keys(validations)
export { validations }
export default Object.keys(validations);
export { validations };

4
packages/nc-gui/helpers/sqlUi/MssqlUi.js

@ -921,16 +921,14 @@ export class MssqlUi {
static getAbstractType(col) {
switch ((col.dt || col.dt).toLowerCase()) {
case 'bigint':
case 'smallint':
case 'bit':
case 'tinyint':
case 'int':
return 'integer'
case 'bigint':
case 'binary':
return 'string'
case 'char':
return 'string'

2
packages/nc-gui/helpers/sqlUi/MysqlUi.js

@ -842,7 +842,6 @@ export class MysqlUi {
case 'int':
case 'smallint':
case 'mediumint':
case 'bigint':
case 'bit':
return 'integer'
@ -897,6 +896,7 @@ export class MysqlUi {
case 'set':
return 'set'
case 'bigint':
case 'geometry':
case 'point':
case 'linestring':

2
packages/nc-gui/helpers/sqlUi/SqliteUi.js

@ -683,7 +683,6 @@ export class SqliteUi {
case 'tinyint':
case 'smallint':
case 'mediumint':
case 'bigint':
case 'int2':
case 'int8':
return 'integer'
@ -702,6 +701,7 @@ export class SqliteUi {
case 'blob':
return 'blob'
case 'bigint':
case 'character':
case 'varchar':
return 'string'

378
packages/nc-gui/lang/de.json

@ -1,10 +1,10 @@
{
"general": {
"home": "Heim",
"load": "Belastung",
"open": "Offen",
"close": "Nah dran",
"yes": "ja",
"home": "Start",
"load": "Laden",
"open": "Öffnen",
"close": "Schließen",
"yes": "Ja",
"no": "Nein",
"ok": "OK",
"and": "Und",
@ -14,7 +14,7 @@
"remove": "Entfernen",
"save": "Speichern",
"cancel": "Abbrechen",
"submit": "einreichen",
"submit": "Übermitteln",
"create": "Erstellen",
"delete": "Löschen",
"update": "Aktualisieren",
@ -22,20 +22,20 @@
"reload": "Neu laden",
"reset": "Zurücksetzen",
"install": "Installieren",
"show": "Show",
"show": "Zeigen",
"hide": "Verstecken",
"showAll": "Zeige alles",
"hideAll": "Versteck alles",
"showMore": "Zeig mehr",
"showOptions": "Optionen anzeigen.",
"hideOptions": "Optionen ausblenden.",
"showMenu": "Zeige das Menü",
"hideMenu": "Menü ausblenden.",
"addAll": "Füge alle Hinzu",
"showAll": "Alles zeigen",
"hideAll": "Alles verstecken",
"showMore": "Mehr anzeigen",
"showOptions": "Optionen anzeigen",
"hideOptions": "Optionen ausblenden",
"showMenu": "Menü anzeigen",
"hideMenu": "Menü ausblenden",
"addAll": "Alles hinzufügen",
"removeAll": "Alles entfernen",
"signUp": "Anmeldung",
"signIn": "EINLOGGEN",
"signOut": "Austragen",
"signUp": "Anmelden",
"signIn": "Einloggen",
"signOut": "Ausloggen",
"required": "Erforderlich",
"preferred": "Bevorzugt",
"mandatory": "Verpflichtend",
@ -45,24 +45,24 @@
"project": "Projekt",
"projects": "Projekte",
"table": "Tabelle",
"tables": "Tische",
"field": "Bereich",
"tables": "Tabellen",
"field": "Feld",
"fields": "Felder",
"column": "Spalte",
"columns": "Säulen",
"page": "Buchseite",
"columns": "Spalten",
"page": "Seite",
"pages": "Seiten",
"record": "Aufzeichnen",
"records": "Aufzeichnungen",
"webhook": "WEBHOOK.",
"webhooks": "WebHooks",
"view": "Aussicht",
"webhook": "Webhook",
"webhooks": "Webhooks",
"view": "Ansicht",
"views": "Ansichten",
"viewType": {
"grid": "Grid",
"grid": "Gitter",
"gallery": "Galerie",
"form": "Formular",
"kanban": "Kanban.",
"kanban": "Kanban",
"calendar": "Kalender"
},
"user": "Nutzer",
@ -71,21 +71,21 @@
"roles": "Rollen",
"roleType": {
"owner": "Eigentümer",
"creator": "Schöpfer",
"editor": "Editor",
"creator": "Ersteller",
"editor": "Bearbeiter",
"commenter": "Kommentator",
"viewer": "Zuschauer"
}
},
"datatype": {
"ID": "ICH WÜRDE",
"ID": "ID",
"ForeignKey": "Unbekannter Schlüssel",
"SingleLineText": "Einzelsteintext",
"SingleLineText": "Einzeiliger Text",
"LongText": "Langer Text",
"Attachment": "Anhang",
"Checkbox": "Kontrollkästchen",
"MultiSelect": "Mehrfachauswahl",
"SingleSelect": "Single Select.",
"SingleSelect": "Einfache Auswahl",
"Collaborator": "Mitarbeiter",
"Date": "Datum",
"Year": "Jahr",
@ -98,15 +98,15 @@
"Currency": "Währung",
"Percent": "Prozent",
"Duration": "Dauer",
"Rating": "Nennen",
"Rating": "Klassifizierung",
"Formula": "Formel",
"Rollup": "Aufrollen",
"Rollup": "Rollup",
"Count": "Zählen",
"Lookup": "Nachschlagen",
"DateTime": "Terminzeit",
"CreateTime": "Zeit schaffen",
"LastModifiedTime": "Letzte geänderte Zeit",
"AutoNumber": "Auto Nummer",
"DateTime": "Datum/Zeit",
"CreateTime": "Zeit erstellen",
"LastModifiedTime": "Zuletzt bearbeitet",
"AutoNumber": "Auto-Numerierung",
"Barcode": "Barcode",
"Button": "Taste",
"Password": "Passwort"
@ -115,78 +115,78 @@
"isEqual": "ist gleich",
"isNotEqual": "ist nicht gleich",
"isLike": "ist wie",
"isNot like": "Ist nicht wie",
"isNot like": "ist nicht wie",
"isEmpty": "ist leer",
"isNotEmpty": "ist nicht leer",
"isNull": "ist Null",
"isNotNull": "ist nicht null"
"isNotNull": "ist nicht Null"
},
"title": {
"newProj": "Neues Projekt",
"myProject": "Meine Projekte",
"formTitle": "Titel bilden",
"collabView": "Kollaborative Sicht",
"formTitle": "Formular Titel",
"collabView": "Mitarbeitersicht",
"lockedView": "Gesperrter Blick",
"personalView": "Persönliche Ansicht",
"appStore": "Appstore",
"team&auth": "Team & Auth.",
"rolesUserMgmt": "Rollen & Benutzermanagement",
"userMgmt": "Benutzermanagement.",
"apiTokenMgmt": "API-Tokens-Management.",
"rolesMgmt": "Rollenmanagement.",
"userMgmt": "Benutzermanagement",
"apiTokenMgmt": "API-Tokens-Management",
"rolesMgmt": "Rollenmanagement",
"projMeta": "Projektmetadaten",
"metaMgmt": "Meta-Management.",
"metaMgmt": "Meta-Management",
"metadata": "Metadaten",
"exportImportMeta": "Metadaten exportieren / importieren",
"metaOperations": "Metadatenoperationen.",
"audit": "Prüfung",
"metaOperations": "Metadatenoperationen",
"audit": "Audit",
"auditLogs": "Audit-Log",
"sqlMigrations": "SQL-Migrationen",
"dbCredentials": "Datenbank-Anmeldeinformationen",
"advancedParameters": "SSL & Erweiterte Parameter",
"headCreateProject": "Projekt erstellen | NocOdb",
"headLogin": "Anmelden | NocOdb",
"resetPassword": "Setzen Sie Ihr Passwort zurück"
"headCreateProject": "Projekt erstellen | NocoDB",
"headLogin": "Anmelden | NocoDB",
"resetPassword": "Passwort zurücksetzen"
},
"labels": {
"projName": "Projektname",
"viewName": "Name anzeigen.",
"viewLink": "Link anzeigen.",
"viewName": "Name anzeigen",
"viewLink": "Link anzeigen",
"columnName": "Spaltenname",
"columnType": "Säulentyp",
"columnType": "Spaltentyp",
"roleName": "Rollenname",
"roleDescription": "Rollenbeschreibung",
"databaseType": "Geben Sie in der Datenbank ein",
"databaseType": "Typ in der Datenbank",
"lengthValue": "Länge / Wert",
"dbType": "Datenbanktyp.",
"sqliteFile": "SQLite-Datei.",
"dbType": "Datenbanktyp",
"sqliteFile": "SQLite-Datei",
"hostAddress": "Host-Adresse",
"port": "Port-Nummer",
"username": "Nutzername",
"username": "Benutzername",
"password": "Passwort",
"action": "Aktion",
"actions": "Aktionen",
"operation": "Betrieb",
"operationType": "Betriebstyp.",
"operationSubType": "Betriebsuntertyp",
"operation": "Vorgang",
"operationType": "Vorgangstyp",
"operationSubType": "Vorgangsuntertyp",
"description": "Beschreibung",
"authentication": "Authentifizierung",
"token": "Zeichen",
"token": "Token",
"where": "Wo",
"cache": "Zwischenspeicher",
"chat": "Plaudern",
"chat": "Chat",
"email": "Email",
"storage": "Lager",
"storage": "Speicher",
"uiAcl": "UI-ACL.",
"models": "Modelle",
"syncState": "Sync-Zustand",
"syncState": "Sync-Stand",
"created": "Erstellt",
"sqlOutput": "SQL-Ausgang",
"sqlOutput": "SQL-Ausgabe",
"dbCreateIfNotExists": "Datenbank: Erstellen, falls nicht vorhanden",
"clientKey": "Client-Schlüssel",
"clientCert": "Client Cert.",
"clientCert": "Client Cert",
"serverCA": "Server CA",
"requriedCa": "CA Erforderlich",
"requriedCa": "Erforderliches CA",
"requriedIdentity": "Erforderliche Identität",
"inflection": {
"tableName": "Flexion - Tabellenname",
@ -194,7 +194,7 @@
},
"community": {
"starUs1": "Stern",
"starUs2": "uns auf Github.",
"starUs2": "uns auf Github",
"bookDemo": "Buchen Sie eine kostenlose Demo",
"getAnswered": "Erhalten Sie Antworten auf Ihre Fragen",
"joinDiscord": "Discord beitreten",
@ -204,9 +204,9 @@
},
"activity": {
"createProject": "Projekt erstellen",
"importProject": "Projektimport",
"importProject": "Projekt importieren",
"searchProject": "Projekt suchen",
"editProject": "Projekt bearbeiten.",
"editProject": "Projekt bearbeiten",
"stopProject": "Projekt stoppen",
"startProject": "Projekt starten",
"restartProject": "Projekt neu starten",
@ -214,21 +214,21 @@
"refreshProject": "Projekte aktualisieren",
"saveProject": "Projekt speichern",
"createProjectExtended": {
"extDB": "Erstellen mit einer<br>externen Datenbank",
"excel": "Projekt von Excel erstellen",
"template": "Projekt aus der Vorlage erstellen"
"extDB": "Erstellen durch Verbinden <br>mit einer externen Datenbank",
"excel": "Projekt aus Excel erstellen",
"template": "Projekt aus Vorlage erstellen"
},
"OkSaveProject": "OK & Save Project",
"OkSaveProject": "OK & Project speichern",
"upgrade": {
"available": "Upgrade verfügbar",
"releaseNote": "Versionshinweise",
"howTo": "Wie aktualisiere ich?"
"howTo": "Wie wird aktualisiert?"
},
"translate": "Hilfe umsetzen",
"translate": "Übersetzen helfen",
"account": {
"authToken": "Copy Auth-Token",
"swagger": "Swagger Apis Doc.",
"projInfo": "Projektinfo kopieren.",
"authToken": "Auth-Token kopieren",
"swagger": "Swagger Apis Doc",
"projInfo": "Projektinfo kopieren",
"themes": "Themen"
},
"sort": "Sortieren",
@ -237,70 +237,70 @@
"addFilter": "Filter hinzufügen",
"share": "Teilen",
"shareBase": {
"disable": "Freigegebene Basis deaktivieren.",
"disable": "Freigegebene Datenbank deaktivieren",
"enable": "Jeder mit dem Link",
"link": "Gemeinsamer Basis-Link"
"link": "Freigegebene Datenbank-Link"
},
"invite": "Einladen",
"inviteMore": "Mehr einladen",
"inviteTeam": "Team einladen",
"inviteToken": "Einladen",
"inviteToken": "Token einladen",
"newUser": "Neuer Benutzer",
"editUser": "Benutzer bearbeiten",
"deleteUser": "Benutzer vom Projekt entfernen",
"resendInvite": "Senden Sie die E-Mail-Adresse ein",
"copyInviteURL": "Kopieren Laden Sie die URL ein",
"resendInvite": "Einladungs-Email erneut versenden",
"copyInviteURL": "Einladungs-URL kopieren",
"newRole": "Neue Rolle",
"reloadRoles": "Rollen neu laden",
"nextPage": "Nächste Seite",
"prevPage": "Vorherige Seite",
"nextRecord": "Nächster Rekord",
"previousRecord": "Bisherigen Rekord",
"nextRecord": "Nächster Eintrag",
"previousRecord": "Vorheriger Eintrag",
"copyApiURL": "API-URL kopieren",
"createTable": "Tabelle erstellen",
"refreshTable": "Tabellen erfrischt.",
"renameTable": "Tisch umbenennen",
"addField": "Fügen Sie diesem Tisch neues Feld hinzu",
"setPrimary": "Als Primärwert einstellen",
"addRow": "Neue Row hinzufügen",
"saveRow": "REIBEN REIBEN",
"refreshTable": "Tabellen aktualisieren",
"renameTable": "Tabelle umbenennen",
"addField": "Neues Feld zu dieser Tabelle hinzufügen",
"setPrimary": "Als Primärwert festlegen",
"addRow": "Neue Spalte hinzufügen",
"saveRow": "Spalte speichern",
"insertRow": "Neue Reihe einfügen",
"deleteRow": "Zeile löschen",
"deleteSelectedRow": "Ausgewählte Zeilen löschen",
"importExcel": "Excel importieren",
"downloadCSV": "Download als CSV.",
"uploadCSV": "Laden Sie CSV hoch",
"importExcel": "Import Excel",
"downloadCSV": "Download als CSV",
"uploadCSV": "Hochladen CSV",
"import": "Importieren",
"importMetadata": "Metadaten importieren",
"exportMetadata": "Metadaten exportieren",
"clearMetadata": "Metadaten löschen",
"exportToFile": "Export in die Datei.",
"exportToFile": "Export in Datei",
"changePwd": "Kennwort ändern",
"createView": "Eine Ansicht erstellen.",
"shareView": "Ansicht teilen.",
"listSharedView": "Gemeinsame Ansichtsliste",
"ListView": "Ansichten Liste.",
"createView": "Ansicht erstellen",
"shareView": "Ansicht teilen",
"listSharedView": "Geteilte Ansichtsliste",
"ListView": "Ansichtenliste",
"copyView": "Ansicht kopieren",
"renameView": "Ansicht umbenennen",
"deleteView": "Ansicht löschen",
"createGrid": "Grid-Sicht erstellen.",
"createGallery": "Ansicht der Galerie erstellen.",
"createCalendar": "Kalender-Sicht erstellen.",
"createKanban": "Kanban-Sicht erstellen.",
"createForm": "Formula erstellen.",
"showSystemFields": "Systemfelder anzeigen.",
"createGrid": "Raster-Ansicht erstellen",
"createGallery": "Galerie-Ansicht erstellen",
"createCalendar": "Kalender-Ansicht erstellen",
"createKanban": "Kanban-Ansicht erstellen",
"createForm": "Formular-Ansicht erstellen",
"showSystemFields": "Systemfelder anzeigen",
"copyUrl": "URL kopieren",
"openTab": "Neue Registerkarte öffnen.",
"iFrame": "Kopieren Sie eingebettete HTML-Code",
"addWebhook": "Fügen Sie einen neuen WebHook hinzu",
"newToken": "Neues Token hinzufügen",
"openTab": "Neue Registerkarte öffnen",
"iFrame": "Eingebettete HTML-Code kopieren",
"addWebhook": "Neuen WebHook hinzufügen",
"newToken": "Neuen Token hinzufügen",
"exportZip": "Zip-Datei exportieren",
"importZip": "Zip-Datei importieren",
"metaSync": "Jetzt synchronisieren",
"settings": "Einstellungen",
"previewAs": "Vorschau anzeigen als",
"resetReview": "Vorschau zurücksetzen.",
"testDbConn": "Datenbankverbindung testen.",
"resetReview": "Vorschau zurücksetzen",
"testDbConn": "Datenbankverbindung testen",
"removeDbFromEnv": "Datenbank aus der Umgebung entfernen",
"editConnJson": "Verbindung JSON bearbeiten",
"sponsorUs": "Sponsor uns.",
@ -313,112 +313,112 @@
"apiGQL": "Zugänglich über Graphql-APIs",
"theme": {
"dark": "Es kommt in Schwarz (^ ⇧b)",
"light": "Kommt es schwarz? (^ ⇧b)"
"light": "Kommt es in schwarz? (^ ⇧b)"
},
"addTable": "Neue Tabelle hinzufügen",
"inviteMore": "Laden Sie mehr Benutzer ein",
"toggleNavDraw": "Navigationsschublade umschalten",
"inviteMore": "Mehr Benutzer einladen",
"toggleNavDraw": "Navigationsbereich umschalten",
"reloadApiToken": "API-Token neu laden",
"generateNewApiToken": "Neues API-Token generieren",
"generateNewApiToken": "Neuen API-Token generieren",
"addRole": "Neue Rolle hinzufügen",
"metaReloadList": "Listenliste neu laden",
"metaSync": "Metadaten synchronisieren.",
"metaReloadList": "Liste neu laden",
"metaSync": "Metadaten synchronisieren",
"sqlMigration": "Migrationen neu laden",
"updateRestart": "Update & Neustart.",
"cancelReturn": "Abbrechen und Rückkehr.",
"exportMetadata": "Exportieren Sie alle Metadaten von den Metastabellen in Meta-Verzeichnis.",
"importMetadata": "Importieren Sie alle Metadaten aus dem Meta-Verzeichnis in Meta-Tabellen.",
"updateRestart": "Update & Neustart",
"cancelReturn": "Abbrechen und Zurück",
"exportMetadata": "Alle Metadaten von den Metatabellen in Meta-Verzeichnis exportieren.",
"importMetadata": "Alle Metadaten vom Meta-Verzeichnis in Metatabellen importieren.",
"clearMetadata": "Alle Metadaten aus Meta-Tabellen löschen.",
"clientKey": "Wählen Sie .key-Datei aus",
"clientCert": "Wählen Sie .Cert-Datei",
"clientCA": "Wählen Sie CA-Datei"
"clientKey": "Auswahl .key-Datei",
"clientCert": "Auswahl .cert-Datei",
"clientCA": "Auswahl CA-Datei"
},
"placeholder": {
"projName": "Geben Sie den Projektnamen ein",
"projName": "Projektnamen eingeben",
"password": {
"enter": "Geben Sie das Passwort ein",
"current": "Jetziges Passwort",
"enter": "Passwort eingeben",
"current": "Aktuelles Passwort",
"new": "Neues Passwort",
"save": "Passwort speichern",
"confirm": "Bestätige neues Passwort"
"confirm": "Neues Passwort bestätigen"
},
"searchProjectTree": "Tische suchen.",
"searchFields": "Suchfelder",
"searchColumn": "Suchen Sie {Suchen} Säule",
"searchProjectTree": "Tabellen suchen",
"searchFields": "Felder suchen",
"searchColumn": "Suche {search} Spalte",
"searchApps": "Apps suchen",
"searchModels": "Suchmodelle",
"searchModels": "Suche Modelle",
"noItemsFound": "Keine Elemente gefunden",
"defaultValue": "Standardwert",
"filterByEmail": "Filtern per E-Mail"
"filterByEmail": "Filtern nach E-Mail"
},
"msg": {
"info": {
"footerInfo": "Reihen pro Seite.",
"upload": "Wählen Sie Datei zum Hochladen",
"upload_sub": "oder Drag & Drop-Datei",
"footerInfo": "Reihen pro Seite",
"upload": "Datei zum Hochladen auswählen",
"upload_sub": "oder Drag & Drop Datei",
"excelSupport": "Unterstützt: .xls ,.xlsx ,.xlsm, .ods, .ots",
"excelURL": "Geben Sie Excel-Datei-URL ein",
"excelURL": "Excel-Datei-URL eingeben",
"footMsg": "Anzahl der Zeilen, um den Datentyp analysieren zu können",
"excelImport": "Blatt (s) stehen für den Import zur Verfügung",
"exportMetadata": "Möchten Sie Metadaten von Meta-Tabellen exportieren?",
"importMetadata": "Möchten Sie Metadaten von Metastischen importieren?",
"clearMetadata": "Möchten Sie Metadaten von Meta-Tischen löschen?",
"projectEmptyMessage": "Beginnen Sie mit dem Erstellen eines neuen Projekts",
"stopProject": "Möchten Sie das Projekt aufhalten?",
"importMetadata": "Möchten Sie Metadaten von Metatabellen importieren?",
"clearMetadata": "Möchten Sie Metadaten von Meta-Tabellen löschen?",
"projectEmptyMessage": "Beginnen mit dem Erstellen eines neuen Projekts",
"stopProject": "Möchten Sie das Projekt beenden?",
"startProject": "Möchten Sie das Projekt starten?",
"restartProject": "Möchten Sie das Projekt neu starten?",
"deleteProject": "Möchten Sie das Projekt löschen?",
"shareBasePrivate": "Öffentlich genutzbare readontly Base generieren",
"shareBasePrivate": "Öffentlich freigegebene Nur-Lese-Datenbank generieren",
"shareBasePublic": "Jeder im Internet mit diesem Link kann sehen",
"userInviteNoSMTP": "Sieht aus, als hätten Sie den Mailer noch nicht konfiguriert! \\ n Bitte kopieren Sie den obigen Link einladen und senden Sie es an",
"dragDropHide": "Ziehen Sie die Felder hierher, um sich zu verstecken",
"formInput": "Geben Sie das Formular-Eingabetikett ein",
"formHelpText": "Fügen Sie etwas Hilfe Text hinzu",
"userInviteNoSMTP": "Sieht aus, als hätten Sie den Mailer noch nicht konfiguriert! \\ n Bitte kopieren Sie den obigen Einladungs-Link und senden Sie ihn an",
"dragDropHide": "Ziehen Sie die Felder hierher, um sie zu verstecken",
"formInput": "Formularbezeichnung eingeben",
"formHelpText": "Fügen Sie einen Hilfs-Text hinzu",
"onlyCreator": "Nur für den Ersteller sichtbar",
"formDesc": "Formularbeschreibung hinzufügen.",
"formDesc": "Formularbeschreibung hinzufügen",
"beforeEnablePwd": "Den Zugriff mit einem Passwort einschränken",
"afterEnablePwd": "Zugriff ist Passwort eingeschränkt",
"privateLink": "Diese Ansicht wird über einen privaten Link geteilt",
"privateLinkAdditionalInfo": "Personen mit privatem Link können nur Zellen sehen, die in dieser Ansicht angezeigt werden",
"afterFormSubmitted": "Nachdem das Formular eingereicht wird",
"apiOptions": "Zugriff auf Projekt via.",
"submitAnotherForm": "'Senden Sie ein anderes Formular einreichen'",
"showBlankForm": "Zeigen Sie nach 5 Sekunden ein leeres Formular an",
"emailForm": "E-Mail an mich an",
"showSysFields": "Systemfelder anzeigen.",
"filterAutoApply": "Automatisch anwenden.",
"showMessage": "Diese Nachricht anzeigen.",
"afterEnablePwd": "Zugriff ist Passwort-geschützt",
"privateLink": "Diese Ansicht wird durch einen privaten Link geteilt",
"privateLinkAdditionalInfo": "Personen mit einem privatem Link können nur Zellen sehen, die in dieser Ansicht angezeigt werden",
"afterFormSubmitted": "Nachdem das Formular übermittelt wurde",
"apiOptions": "Zugriff auf das Projekt via",
"submitAnotherForm": "Weiteres Formular übermitteln'-Button anzeigen",
"showBlankForm": "Ein leeres Formular nach 5 Sekunden anzeigen",
"emailForm": "E-Mail mich unter",
"showSysFields": "Systemfelder anzeigen",
"filterAutoApply": "Automatisch anwenden",
"showMessage": "Diese Nachricht anzeigen",
"viewNotShared": "Aktuelle Ansicht wird nicht geteilt!",
"showAllViews": "Alle gemeinsamen Ansichten dieser Tabelle anzeigen",
"collabView": "Mitarbeitern mit Bearbeitungsberechtigungen oder höher können die Ansichtskonfiguration ändern.",
"lockedView": "Niemand kann die Ansichtskonfiguration bearbeiten, bis er freigeschaltet ist.",
"personalView": "Nur Sie können die Ansichtskonfiguration bearbeiten. Weitere persönliche Ansichten der Ankäufer sind standardmäßig ausgeblendet.",
"ownerDesc": "Können Ersteller hinzufügen / entfernen. Und Full-Edit-Datenbankstrukturen und -felder.",
"showAllViews": "Alle geteilten Ansichten dieser Tabelle anzeigen",
"collabView": "Mitarbeitern mit Bearbeitungsberechtigung oder höher können die Ansichtskonfiguration ändern",
"lockedView": "Niemand kann die Ansichtskonfiguration bearbeiten, bis sie freigeschaltet ist.",
"personalView": "Nur Sie können die Ansichtskonfiguration bearbeiten. Weitere Mitarbeiter-Ansichten sind standardmäßig ausgeblendet.",
"ownerDesc": "Kann Ersteller hinzufügen / entfernen und Datenbankstrukturen und -felder voll bearbeiten.",
"creatorDesc": "Kann Datenbankstrukturen und Werte vollständig bearbeiten.",
"editorDesc": "Können Datensätze bearbeiten, aber die Struktur von Datenbanken / Feldern nicht ändern.",
"editorDesc": "Kann Datensätze bearbeiten, aber die Struktur von Datenbanken / Feldern nicht ändern.",
"commenterDesc": "Kann die Datensätze anzeigen und kommentieren, aber nichts bearbeiten",
"viewerDesc": "Kann die Datensätze anzeigen, aber nichts bearbeiten",
"viewerDesc": "Kann die Einträge anzeigen, aber nichts bearbeiten",
"addUser": "Neuen Benutzer hinzufügen",
"staticRoleInfo": "Systemdefinierte Rollen können nicht bearbeitet werden",
"exportZip": "Exportieren Sie das Projekt Meta in ZIP-Datei und downloaden.",
"importZip": "Importieren Sie das Projekt Meta-ZIP-Datei und starten Sie erneut.",
"importText": "Importieren von NOCODB-Projekt, indem Sie Metadaten-ZIP-Datei hochladen",
"exportZip": "Projekt-Meta in ZIP-Datei exportieren und downloaden",
"importZip": "Projekt Meta-ZIP-Datei importieren und neu starten.",
"importText": "Importieren von NOCODB-Projekt durch Hochladen von Metadaten-ZIP-Datei",
"metaNoChange": "Keine Änderung identifiziert",
"sqlMigration": "Schema-Migrationen werden automatisch erstellt. Erstellen Sie eine Tabelle und aktualisieren Sie diese Seite.",
"dbConnectionStatus": "Umwelt validiert.",
"sqlMigration": "Schema-Migrationen werden automatisch erstellt. Tabelle erstellen und diese Seite aktualisieren.",
"dbConnectionStatus": "Umgebung validiert",
"dbConnected": "Verbindung war erfolgreich",
"notifications": {
"no_new": "Keine neuen Benachrichtigungen",
"clear": "Löschen"
"clear": "Leeren"
},
"sponsor": {
"header": "Sie können uns helfen!",
"message": "Wir sind ein winziges Team, das Vollzeit, um die NOCODB-Open-Source zu erstellen. Wir glauben, dass ein Werkzeug wie NOCODB für jeden Problemlöser im Internet frei verfügbar sein sollte."
"message": "Wir sind ein winziges Team, das Vollzeit arbeitet, um die NOCODB-Open-Source zu machen. Wir glauben, daß ein Werkzeug wie NOCODB für jeden Problemlöser im Internet frei verfügbar sein sollte."
},
"loginMsg": "Melden Sie sich bei NOCODB an",
"loginMsg": "In NocoDB einloggen",
"passwordRecovery": {
"message_1": "Bitte geben Sie die E-Mail-Adresse an, die Sie bei der Anmeldung verwendet haben.",
"message_2": "Wir senden Ihnen eine E-Mail mit einem Link, um Ihr Passwort zurückzusetzen.",
"message_2": "Wir senden Ihnen eine E-Mail mit einem Link, um das Passwort zurückzusetzen.",
"success": "Bitte überprüfen Sie Ihre E-Mail, um das Passwort zurückzusetzen"
},
"signUp": {
@ -427,14 +427,14 @@
"workEmail": "Geben Sie Ihre Arbeits-E-Mail ein",
"enterPassword": "Geben Sie Ihr Passwort ein",
"forgotPassword": "Passwort vergessen ?",
"dontHaveAccount": "Ich habe kein Konto?"
"dontHaveAccount": "Sie haben kein Konto?"
},
"addView": {
"grid": "Grid-Ansicht hinzufügen.",
"gallery": "Galerieansicht hinzufügen",
"form": "Fügen Sie den Formularansicht hinzu",
"kanban": "Kanban-Sicht hinzufügen",
"calendar": "Kalenderansicht hinzufügen"
"grid": "Gitter-Ansicht hinzufügen",
"gallery": "Galerie-Ansicht hinzufügen",
"form": "Formular-Ansicht hinzufügen",
"kanban": "Kanban-Ansicht hinzufügen",
"calendar": "Kalender-Ansicht hinzufügen"
}
},
"error": {
@ -447,9 +447,9 @@
"dbConnectionFailed": "Verbindungsfehler:",
"signUpRules": {
"emailReqd": "E-Mail ist erforderlich",
"emailInvalid": "Email muss gültig sein",
"emailInvalid": "Email muß gültig sein",
"passwdRequired": "Passwort ist erforderlich",
"passwdLength": "Ihr Passwort muss mindestens 8 Zeichen sein"
"passwdLength": "Ihr Passwort muß mindestens 8 Zeichen haben"
}
},
"toast": {
@ -459,12 +459,12 @@
"stopProject": "Projekt wurde erfolgreich angehalten",
"startProject": "Projekt begann erfolgreich",
"restartProject": "Projekt neu gestartet",
"deleteProject": "Projekt erfolgreich gelöscht.",
"deleteProject": "Projekt erfolgreich gelöscht",
"authToken": "Auth-Token in die Zwischenablage kopiert",
"projInfo": "Kopie Projektinformationen in die Zwischenablage",
"inviteUrlCopy": "Kopierte Laden Sie die URL in die Zwischenablage ein",
"createView": "Erfolgreich erstellt",
"formEmailSMTP": "Bitte aktivieren Sie das SMTP-Plugin in App Store, um die E-Mail-Benachrichtigung zu aktivieren",
"projInfo": "Projektinformationen in die Zwischenablage kopiert",
"inviteUrlCopy": "Einladungs-URL in die Zwischenablage kopiert",
"createView": "Ansicht erfolgreich erstellt",
"formEmailSMTP": "Bitte aktivieren Sie das SMTP-Plugin im App Store, um die E-Mail-Benachrichtigung zu aktivieren",
"collabView": "Erfolgreich auf die kollaborative Ansicht gewechselt",
"lockedView": "Erfolgreich auf gesperrte Ansicht gewechselt",
"futureRelease": "Kommt bald!"

2
packages/nc-gui/layouts/default.vue

@ -47,7 +47,7 @@
</v-toolbar-items>
<!-- <template v-if="!isThisMobile ">
<a class="align-self-center" style="" target="_blank" href="https://calendly.com/nocodb">
<a class="align-self-center" style="" target="_blank" href="https://calendly.com/nocodb-meeting">
<x-icon size="20" tooltip="Book a free demo" color="white" icon.class="mr-3">mdi-calendar-month</x-icon>

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

@ -624,7 +624,7 @@
v-if="!_isZh"
dense
target="_blank"
href="https://calendly.com/nocodb"
href="https://calendly.com/nocodb-meeting"
>
<v-list-item-icon>
<v-icon

28
packages/nc-migrator-archived/package-lock.json generated

@ -123,15 +123,23 @@
"dev": true
},
"ajv": {
"version": "6.10.2",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz",
"integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==",
"version": "6.12.6",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
"dev": true,
"requires": {
"fast-deep-equal": "^2.0.1",
"fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0",
"json-schema-traverse": "^0.4.1",
"uri-js": "^4.2.2"
},
"dependencies": {
"fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
"dev": true
}
}
},
"ansi-align": {
@ -1383,12 +1391,6 @@
}
}
},
"fast-deep-equal": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz",
"integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=",
"dev": true
},
"fast-diff": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz",
@ -4233,9 +4235,9 @@
}
},
"pathval": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz",
"integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=",
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz",
"integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==",
"dev": true
},
"pg-connection-string": {

34
packages/noco-docs/content/en/engineering/publish.md

@ -6,10 +6,16 @@ category: "Engineering"
menuTitle: "Making a release"
---
> This is exclusive to NocoDB team members only
<alert>
This is exclusive to NocoDB team members only.
</alert>
<alert types='danger'>
The version 0.84.8 will be used as an example. Please change it during the release.
</alert>
## 1. Merge ```develop``` to ```master```
- When several features are included in develop branch and they are ready to be released, make a PR from `develop` branch to `master` branch. At least one NocoDB team member approval is required.
- When several features are included in ``develop`` branch and they are ready to be released, make a PR with the title ``0.84.8 Pre-Release`` from `develop` branch to `master` branch. At least one NocoDB team member approval is required.
## 2. Publish frontend
- Navigate to `packages/nc-gui` and execute following command.
@ -20,7 +26,7 @@ menuTitle: "Making a release"
- Install the latest published version of `nc-lib-gui` in `packages/nocodb`, package version can be extracted from result of step 1 or copy it from `packages/nc-lib-gui/package.json`. While installing, add `-E` to install exact version of the package.
- Example: for latest published version `0.84.8`
```bash
```bash
npm i -E nc-lib-gui@0.84.8
```
@ -31,11 +37,25 @@ menuTitle: "Making a release"
npm run obfuscate:build:publish
```
## 5. Prepare release notes
## 5. Close all issues
- Go to Issue page and close all issues with tags ``Fixed`` or ``Resolved``.
## 6. Commit release changes
- Commit those changes made by previous steps with the commit message ``chore(publish): v0.84.8``.
## 7. Prepare release notes
- Populate release note by running following github action (on `master` branch) - `Release : Draft Notes`. While running the action you have to provide 2 inputs:
- **Tag** : Provide current package version
- **Previous Tag** : Provide previously released tag version
## 6. Publish docker & release
- Publish docker image by running `Release : Docker` action in github (on `master` branch), where you have to provide the package version/tag.
- Update the populated release (remove issues which is not related to release) draft and publish. In release note you can use `Auto-generate release notes` button to populate release content from commits & PR.
## 8. Publish docker & release
- Publish docker image by running `Release : Docker` action in github (on `master` branch), where you have to provide the package version/tag. It may take half an hour. Test it locally after it is done.
- Update the populated release (remove issues which is not related to release) draft and publish. In release note you can use `Auto-generate release notes` button to populate release content from commits & PR.
## 9. Sync the changes back to develop branch
- Pull the latest chagnes for both branches to your local
- Switch to ``develop`` branch
- Run ``git merge master``
- Push the diff to remote repository

65
packages/noco-docs/content/en/engineering/translation.md

@ -0,0 +1,65 @@
---
title: "i18n"
description: "Contribute to NocoDB's i18n translation"
position: 2000
category: "Engineering"
menuTitle: "i18n"
---
NocoDB supports many foreign languages & we welcome community contributions via an easy to use [google-spreadsheet](https://docs.google.com/spreadsheets/d/1kGp92yLwhs1l7lwwgeor3oN1dFl7JZWuQOa4WSeZ0TE/edit#gid=2076107172).
Your help in fixing i18n goes a long way supporting NocoDB. Please follow below simple procedure to request corrections to existing translation errors.
## How to contribute ? (for community members)
### 1. How to change a string value ?
- Make a copy of [Google spreadsheet](https://docs.google.com/spreadsheets/d/1kGp92yLwhs1l7lwwgeor3oN1dFl7JZWuQOa4WSeZ0TE/edit#gid=2076107172)
<img width="995" alt="Screenshot 2022-02-10 at 1 47 06 PM" src="https://user-images.githubusercontent.com/86527202/153368423-d1d898ef-bdcb-48c4-a772-b75e2c66566d.png">
- Find your language code [here](https://developers.google.com/admin-sdk/directory/v1/languages)
- Go to the column containing your language code. Make necessary changes. Origin text in ENGLISH can be found in `Column B` of master spreadsheet.
- Create a new [issue in Github](https://github.com/nocodb/nocodb/issues/new?assignees=dstala&labels=i18n+translation&template=i18n-translation-request.md&title=%5Bi18n%5D+Language+support+extension-+%3Clanguage+code%3E) request with a link to your spreadsheet from Step-1 (for us to verify & update master spreadsheet).
- NocoDB Maintainers will take changes and merge it.
- It's that simple!
### 2. How to add a new language ?
Your native language not in list, we will be glad to support with your help! Please follow below steps
- Make a copy of [Google spreadsheet](https://docs.google.com/spreadsheets/d/1kGp92yLwhs1l7lwwgeor3oN1dFl7JZWuQOa4WSeZ0TE/edit#gid=2076107172)
<img width="995" alt="Screenshot 2022-02-10 at 1 47 06 PM" src="https://user-images.githubusercontent.com/86527202/153368423-d1d898ef-bdcb-48c4-a772-b75e2c66566d.png">
- Find your language code [here](https://developers.google.com/admin-sdk/directory/v1/languages)
- Replace cell $AB$1 (rightmost, containing text `en`) with language code obtained above.
- Google will generate first version translation in column AB. Review. Make changes as you find appropriate for various items listed. Origin text in ENGLISH can be found in `Column B` of master spreadsheet.
- Create new [issue](https://github.com/nocodb/nocodb/issues/new?assignees=dstala&labels=i18n+translation&template=i18n-translation-request.md&title=%5Bi18n%5D+Language+support+extension-+%3Clanguage+code%3E) request with a link to your spreadsheet from Step-1 (for us to verify & update master spreadsheet).
---
## How to accept i18n contributions ? (for NocoDB maintainers)
> _This is exclusive to NocoDB maintainers only_
### 1. Adding / Updating a string
- Open master [Spreadsheet](https://docs.google.com/spreadsheets/d/1kGp92yLwhs1l7lwwgeor3oN1dFl7JZWuQOa4WSeZ0TE/edit#gid=2076107172)
- For the string/ text under consideration, look-up in existing sheet if it exists already
- [New string already exists] Consider re-using it; align string key if required
- [New string need to be inserted] Insert a new record into appropriate categories as defined below
- Download spreadsheet as .csv (File > Download > Comma-seperated values (.csv, current sheet)
- Use noco-i18n-from-cli to generate new language JSON file
- Copy respective i18n/\*.json files to `nocodb/packages/nc-gui/lang`
### 2. String Categories
- **General**: simple & common tokens (save, cancel, submit, open, close, home, and such)
- **Objects**: objects from NocoDB POV (project, table, field, column, view, page, and such)
- **Title**: screen headers (compact) (menu headers, modal headers)
- **Lables**: text box/ radio/ field headers (few words) (Labels over textbox, radio buttons, and such)
- **Activity**/ actions: work items (few words) (Create Project, Delete Table, Add Row, and such)
- **Tooltip**: additional information associated with work items (usually lengthy) (Additional information provided for activity)
- **Placeholder**: placeholders associated with various textboxes (Text placeholders)
- **Msg**
- Info: general/success category for everything
- Error: warnings & errors
- Toast: pop-up toast messages
> Note: string name should be in camelCase. Use above list as priority order in case of ambiguity.

6
packages/noco-i18n/package-lock.json generated

@ -5537,9 +5537,9 @@
}
},
"follow-redirects": {
"version": "1.14.7",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.7.tgz",
"integrity": "sha512-+hbxoLbFMbRKDwohX8GkTataGqO6Jb7jGwpAlwgy2bIz25XtRm7KEzJM76R1WiNT5SwZkX4Y75SwBolkpmE7iQ==",
"version": "1.14.8",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.8.tgz",
"integrity": "sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA==",
"dev": true
},
"for-in": {

7
packages/nocodb/src/__tests__/rest.test.ts

@ -189,6 +189,13 @@ describe('{Auth, CRUD, HasMany, Belongs} Tests', () => {
.send({ email: EMAIL_ID, password: 'wrongPassword' })
.expect(400, done);
});
it('Signup with no credentials', done => {
request(app)
.post('/auth/signin')
.send({})
.expect(400, done)
})
it('Forgot password with a non-existing email id', function(done) {
request(app)

22
packages/nocodb/src/lib/dataMapper/lib/sql/CustomKnex.ts

@ -92,9 +92,10 @@ const appendWhereCondition = function(
knexRef,
isHaving = false
) {
const clientType = knexRef?.client?.config?.client;
const opMapping = {
...opMappingGen,
...(knexRef?.client?.config?.client === 'pg' ? { like: 'ilike' } : {})
...(clientType === 'pg' ? { like: 'ilike' } : {})
};
const camKey = isHaving ? 'Having' : 'Where';
const key = isHaving ? 'having' : 'where';
@ -430,11 +431,19 @@ const appendWhereCondition = function(
);
break;
case '':
knexRef[`${key}`](
columnAliases[matches[2]] || matches[2],
opMapping[matches[3]],
matches[4]
);
const column = columnAliases[matches[2]] || matches[2];
const operator = opMapping[matches[3]];
const target = matches[4];
if (matches[3] == 'like' && clientType === 'pg') {
// handle uuid case
knexRef[`${key}`](
knexRef?.client.raw(`??::TEXT ${operator} '${target}'`, [
column
])
);
} else {
knexRef[`${key}`](column, operator, target);
}
break;
default:
throw new Error(`${matches[1] || ''} Invalid operation.`);
@ -991,6 +1000,7 @@ export { Knex };
*
* @author Naveen MR <oof1lab@gmail.com>
* @author Pranav C Balan <pranavxc@gmail.com>
* @author Wing-Kam Wong <wingkwong.code@gmail.com>
*
* @license GNU AGPL version 3 or any later version
*

4
packages/nocodb/src/lib/noco/NcProjectBuilder.ts

@ -696,7 +696,7 @@ export default class NcProjectBuilder {
for (const connectionConfig of dbs) {
try {
const sqlClient = NcConnectionMgr.getSqlClient({
dbAlias: connectionConfig?.mets?.dbAlias,
dbAlias: connectionConfig?.meta?.dbAlias,
env: this.config.env,
config: this.config,
projectId: this.id
@ -892,7 +892,7 @@ export default class NcProjectBuilder {
for (const connectionConfig of dbs) {
NcConnectionMgr.delete({
dbAlias: connectionConfig?.mets?.dbAlias,
dbAlias: connectionConfig?.meta?.dbAlias,
env: this.config.env,
projectId: this.id
});

5
packages/nocodb/src/lib/noco/meta/NcMetaIO.ts

@ -168,11 +168,15 @@ export default abstract class NcMetaIO {
roles: string
): Promise<any>;
// Remove user in project level
public abstract projectRemoveUser(
projectId: string,
userId: any
): Promise<any>;
// Remove user globally
public abstract removeXcUser(userId: any): Promise<any>;
public abstract projectStatusUpdate(
projectId: string,
status: string
@ -235,6 +239,7 @@ export { META_TABLES };
*
* @author Naveen MR <oof1lab@gmail.com>
* @author Pranav C Balan <pranavxc@gmail.com>
* @author Wing-Kam Wong <wingkwong.code@gmail.com>
*
* @license GNU AGPL version 3 or any later version
*

9
packages/nocodb/src/lib/noco/meta/NcMetaIOImpl.ts

@ -573,6 +573,14 @@ export default class NcMetaIOImpl extends NcMetaIO {
.delete();
}
public removeXcUser(userId: any): Promise<any> {
return this.knexConnection('xc_users')
.where({
id: userId
})
.delete();
}
get isRest(): boolean {
return this.config?.envs?.[this.config.workingEnv]?.db?.some(
db => db?.meta?.api?.type === 'rest'
@ -616,6 +624,7 @@ export default class NcMetaIOImpl extends NcMetaIO {
*
* @author Naveen MR <oof1lab@gmail.com>
* @author Pranav C Balan <pranavxc@gmail.com>
* @author Wing-Kam Wong <wingkwong.code@gmail.com>
*
* @license GNU AGPL version 3 or any later version
*

42
packages/nocodb/src/lib/noco/rest/RestAuthCtrl.ts

@ -635,7 +635,13 @@ export default class RestAuthCtrl {
try {
if (!user || !user.email) {
if (err) {
return res.status(400).send(err);
// This exception was thrown directly before.
// In order to avoid breaking change, both "msg" and "message" are returned.
const message = err.message ?? ''
return res.status(400).send({
msg: message,
message
});
}
if (info) {
return res.status(400).send(info);
@ -694,7 +700,13 @@ export default class RestAuthCtrl {
try {
if (!user || !user.email) {
if (err) {
return res.status(400).send(err);
// This exception was thrown directly before.
// In order to avoid breaking change, both "msg" and "message" are returned.
const message = err.message ?? ''
return res.status(400).send({
msg: message,
message
});
}
if (info) {
return res.status(400).send(info);
@ -753,7 +765,13 @@ export default class RestAuthCtrl {
try {
if (!user || !user.email) {
if (err) {
return res.status(400).send(err);
// This exception was thrown directly before.
// In order to avoid breaking change, both "msg" and "message" are returned.
const message = err.message ?? ''
return res.status(400).send({
msg: message,
message
});
}
if (info) {
return res.status(400).send(info);
@ -1355,7 +1373,7 @@ export default class RestAuthCtrl {
protected async deleteAdmin(req, res, next): Promise<any> {
try {
const { project_id } = req.query;
const { project_id, type } = req.query;
if (req.session?.passport?.user?.id === +req.params.id) {
return next(new Error("Admin can't delete themselves!"));
@ -1372,11 +1390,16 @@ export default class RestAuthCtrl {
);
}
}
XcCache.del(`${req?.query?.email}___${req?.req?.project_id}`);
// await this.users.where('id', req.params.id).del();
await this.xcMeta.projectRemoveUser(project_id, req.params.id);
if (type === 'DELETE_FROM_PROJECT') {
// remove user from Project
XcCache.del(`${req?.query?.email}___${req?.req?.project_id}`);
await this.xcMeta.projectRemoveUser(project_id, req.params.id);
} else if (type === 'DELETE_FROM_NOCODB') {
// remove user from NocoDB
await this.xcMeta.removeXcUser(req.params.id);
} else {
new Error('Invalid type is provided.');
}
} catch (e) {
return next(e);
}
@ -1748,6 +1771,7 @@ export default class RestAuthCtrl {
*
* @author Naveen MR <oof1lab@gmail.com>
* @author Pranav C Balan <pranavxc@gmail.com>
* @author Wing-Kam Wong <wingkwong.code@gmail.com>
*
* @license GNU AGPL version 3 or any later version
*

4
packages/nocodb/src/lib/sqlUi/MssqlUi.ts

@ -937,16 +937,14 @@ export class MssqlUi {
static getAbstractType(col): any {
switch ((col.dt || col.dt).toLowerCase()) {
case 'bigint':
case 'smallint':
case 'bit':
case 'tinyint':
case 'int':
return 'integer';
case 'bigint':
case 'binary':
return 'string';
case 'char':
return 'string';

2
packages/nocodb/src/lib/sqlUi/MysqlUi.ts

@ -868,7 +868,6 @@ export class MysqlUi {
case 'int':
case 'smallint':
case 'mediumint':
case 'bigint':
case 'bit':
return 'integer';
@ -922,6 +921,7 @@ export class MysqlUi {
case 'set':
return 'set';
case 'bigint':
case 'geometry':
case 'point':
case 'linestring':

2
packages/nocodb/src/lib/sqlUi/SqliteUi.ts

@ -694,7 +694,6 @@ export class SqliteUi {
case 'tinyint':
case 'smallint':
case 'mediumint':
case 'bigint':
case 'int2':
case 'int8':
return 'integer';
@ -713,6 +712,7 @@ export class SqliteUi {
case 'blob':
return 'blob';
case 'bigint':
case 'character':
case 'varchar':
return 'string';

104
scripts/cypress/cypress.json

@ -1,52 +1,56 @@
{
"baseUrl": "http://localhost:3000/",
"testFiles": [
"test/restTableOps.js",
"test/restViews.js",
"test/restRoles.js",
"test/restMisc.js",
"test/xcdb-restTableOps.js",
"test/xcdb-restViews.js",
"test/xcdb-restRoles.js",
"test/xcdb-restMisc.js",
"test/gqlTableOps.js",
"test/gqlViews.js",
"test/gqlRoles.js",
"test/gqlMisc.js",
"test/xcdb-gqlTableOps.js",
"test/xcdb-gqlViews.js",
"test/xcdb-gqlRoles.js",
"test/xcdb-gqlMisc.js"
],
"defaultCommandTimeout": 13000,
"pageLoadTimeout": 600000,
"viewportWidth": 1980,
"viewportHeight": 1000,
"video": false,
"retries": 0,
"screenshotOnRunFailure": false,
"numTestsKeptInMemory": 0,
"env": {
"testMode": "extREST.extGQL.xcdbREST.xcdbGQL",
"db": {
"host": "127.0.0.1",
"user": "root",
"password": "password"
}
},
"supportedOptionsForTestModes": [
"extGQL",
"extREST",
"xcdbREST",
"xcdbREST",
"can configure multiple too, seperated by a . as in extREST.extGQL"
],
"fixturesFolder": "scripts/cypress/fixtures",
"integrationFolder": "scripts/cypress/integration",
"pluginsFile": "scripts/cypress/plugins/index.js",
"screenshotsFolder": "scripts/cypress/screenshots",
"videosFolder": "scripts/cypress/videos",
"downloadsFolder": "scripts/cypress/downloads",
"supportFile": "scripts/cypress/support/index.js",
"chromeWebSecurity": false
"baseUrl": "http://localhost:3000/",
"testFiles": [
"test/restTableOps.js",
"test/restViews.js",
"test/restRoles.js",
"test/restMisc.js",
"test/xcdb-restTableOps.js",
"test/xcdb-restViews.js",
"test/xcdb-restRoles.js",
"test/xcdb-restMisc.js",
"test/gqlTableOps.js",
"test/gqlViews.js",
"test/gqlRoles.js",
"test/gqlMisc.js",
"test/xcdb-gqlTableOps.js",
"test/xcdb-gqlViews.js",
"test/xcdb-gqlRoles.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,
"viewportWidth": 1980,
"viewportHeight": 1000,
"video": false,
"retries": 0,
"screenshotOnRunFailure": false,
"numTestsKeptInMemory": 0,
"env": {
"testMode": [
{ "apiType": "rest", "dbType": "xcdb" },
{ "apiType": "graphql", "dbType": "xcdb" },
{ "apiType": "rest", "dbType": "mysql" },
{ "apiType": "graphql", "dbType": "mysql" },
{ "apiType": "rest", "dbType": "postgres" }
],
"db": {
"host": "127.0.0.1",
"user": "root",
"password": "password"
},
"screenshot": false
},
"fixturesFolder": "scripts/cypress/fixtures",
"integrationFolder": "scripts/cypress/integration",
"pluginsFile": "scripts/cypress/plugins/index.js",
"screenshotsFolder": "scripts/cypress/screenshots",
"videosFolder": "scripts/cypress/videos",
"downloadsFolder": "scripts/cypress/downloads",
"supportFile": "scripts/cypress/support/index.js",
"chromeWebSecurity": false
}

17
scripts/cypress/docker-compose-pg.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

64
scripts/cypress/integration/common/00_pre_configurations.js

@ -7,8 +7,6 @@ import {
staticProjects,
roles,
isTestSuiteActive,
getPrimarySuite,
isSecondarySuite,
getCurrentMode,
isXcdb,
setProjectString,
@ -157,8 +155,8 @@ function prepareSqliteQuery(projId) {
return sqliteQuery;
}
export const genTest = (type, xcdb) => {
if (!isTestSuiteActive(type, xcdb)) return;
export const genTest = (apiType, dbType) => {
if (!isTestSuiteActive(apiType, dbType)) return;
describe(`Project pre-configurations`, () => {
it("Admin SignUp", () => {
cy.task("log", "This will be output to the terminal");
@ -168,6 +166,7 @@ export const genTest = (type, xcdb) => {
const createProject = (proj) => {
it(`Create ${proj.basic.name} project`, () => {
cy.snip("ProjectPage");
// click home button
cy.get(".nc-noco-brand-icon").click();
@ -182,7 +181,7 @@ export const genTest = (type, xcdb) => {
projectsPage.createProject(proj.basic, proj.config);
}
if (xcdb) {
if (dbType === "xcdb") {
// store base URL- to re-visit and delete form view later
let projId;
cy.url()
@ -223,59 +222,24 @@ export const genTest = (type, xcdb) => {
// if (isTestSuiteActive('rest', false)) createProject(staticProjects.externalREST)
// if (isTestSuiteActive('graphql', false)) createProject(staticProjects.externalGQL)
if ("rest" == type) {
if (true == xcdb) {
if ("rest" === apiType) {
if ("xcdb" === dbType) {
createProject(staticProjects.sampleREST);
} else {
} else if (dbType === "mysql") {
createProject(staticProjects.externalREST);
} else if (dbType === "postgres") {
createProject(staticProjects.pgExternalREST);
}
} else if ("graphql" == type) {
if (true == xcdb) {
} else if ("graphql" === apiType) {
if ("xcdb" === dbType) {
createProject(staticProjects.sampleGQL);
} else {
} else if (dbType === "mysql") {
createProject(staticProjects.externalGQL);
} else if (dbType === "postgres") {
createProject(staticProjects.pgExternalGQL);
}
}
});
// describe('Static user creations (different roles)', () => {
// beforeEach(() => {
// loginPage.signIn(roles.owner.credentials)
// projectsPage.openProject(getPrimarySuite().basic.name)
// })
// const addUser = (user) => {
// it(`RoleType: ${user.name}`, () => {
// mainPage.addNewUserToProject(user.credentials, user.name)
// })
// }
// addUser(roles.creator)
// addUser(roles.editor)
// addUser(roles.commenter)
// addUser(roles.viewer)
// })
// describe('Static users- add to other static projects', () => {
// const addUserToProject = (proj) => {
// it(`Add users to ${proj.basic.name}`, () => {
// loginPage.signIn(roles.owner.credentials)
// projectsPage.openProject(proj.basic.name)
// mainPage.addExistingUserToProject(roles.creator.credentials.username, roles.creator.name)
// mainPage.addExistingUserToProject(roles.editor.credentials.username, roles.editor.name)
// mainPage.addExistingUserToProject(roles.commenter.credentials.username, roles.commenter.name)
// mainPage.addExistingUserToProject(roles.viewer.credentials.username, roles.viewer.name)
// })
// }
// if (isSecondarySuite('rest', true)) addUserToProject(staticProjects.sampleREST)
// if (isSecondarySuite('graphql', true)) addUserToProject(staticProjects.sampleGQL)
// if (isSecondarySuite('rest', false)) addUserToProject(staticProjects.externalREST)
// if (isSecondarySuite('graphql', false)) addUserToProject(staticProjects.externalGQL)
// })
};
/**

188
scripts/cypress/integration/common/1a_table_operations.js

@ -1,99 +1,103 @@
import { isTestSuiteActive } from "../../support/page_objects/projectConstants";
import { mainPage } from "../../support/page_objects/mainPage";
export const genTest = (type, xcdb) => {
if (!isTestSuiteActive(type, xcdb)) return;
describe(`${xcdb ? "Meta - " : ""}${type.toUpperCase()} api - Table`, () => {
before(() => {
cy.get(".mdi-close").click({ multiple: true });
});
after(() => {
cy.get(".mdi-close").click({ multiple: true });
});
const name = "tablex";
// create a new random table
it("Create Table", () => {
cy.createTable(name);
});
// delete newly created table
it("Delete Table", () => {
cy.deleteTable(name);
});
const getAuditCell = (row, col) => {
return cy.get("table > tbody > tr").eq(row).find("td").eq(col);
};
it("Open Audit tab", () => {
mainPage.navigationDraw(mainPage.AUDIT).click();
// wait for column headers to appear
//
cy.get("thead > tr > th.caption").should("have.length", 5);
// Audit table entries
// [Header] Operation Type, Operation Sub Type, Description, User, Created
// [0] TABLE, DELETED, delete table table-x, user@nocodb.com, ...
// [1] TABLE, Created, created table table-x, user@nocodb.com, ...
getAuditCell(0, 0).contains("TABLE").should("exist");
getAuditCell(0, 1).contains("DELETED").should("exist");
getAuditCell(0, 3).contains("user@nocodb.com").should("exist");
getAuditCell(1, 0).contains("TABLE").should("exist");
getAuditCell(1, 1).contains("CREATED").should("exist");
getAuditCell(1, 3).contains("user@nocodb.com").should("exist");
});
it("Table Rename operation", () => {
cy.renameTable("City", "CityX");
// verify
// 1. Table name in project tree has changed
cy.get(".nc-project-tree").contains("CityX").should("exist");
// 2. Table tab name has changed
cy.get(`.project-tab:contains('CityX'):visible`).should("exist");
// 3. contents of the table are valid
mainPage
.getCell(`City`, 1)
.contains("A Corua (La Corua)")
.should("exist");
cy.closeTableTab("CityX");
// 4. verify linked contents in other table
// 4a. Address table, has many field
cy.openTableTab("Address", 25);
mainPage.getCell("City <= Address", 1).scrollIntoView();
mainPage
.getCell("City <= Address", 1)
.find(".name")
.contains("Lethbridge")
.should("exist");
cy.closeTableTab("Address");
// 4b. Country table, belongs to field
cy.openTableTab("Country", 25);
mainPage
.getCell("Country => City", 1)
.find(".name")
.contains("Kabul")
.should("exist");
cy.closeTableTab("Country");
// revert re-name operation to not impact rest of test suite
cy.renameTable("CityX", "City");
export const genTest = (apiType, dbType) => {
if (!isTestSuiteActive(apiType, dbType)) return;
describe(`${
dbType === "xcdb" ? "Meta - " : ""
}${apiType.toUpperCase()} api - Table`, () => {
before(() => {
cy.get(".mdi-close").click({ multiple: true });
});
after(() => {
cy.get(".mdi-close").click({ multiple: true });
});
const name = "tablex";
// create a new random table
it("Create Table", () => {
cy.createTable(name);
});
// delete newly created table
it("Delete Table", () => {
cy.deleteTable(name, dbType);
});
const getAuditCell = (row, col) => {
return cy.get("table > tbody > tr").eq(row).find("td").eq(col);
};
it("Open Audit tab", () => {
mainPage.navigationDraw(mainPage.AUDIT).click();
cy.snip("AuditPage");
// wait for column headers to appear
//
cy.get("thead > tr > th.caption").should("have.length", 5);
// Audit table entries
// [Header] Operation Type, Operation Sub Type, Description, User, Created
// [0] TABLE, DELETED, delete table table-x, user@nocodb.com, ...
// [1] TABLE, Created, created table table-x, user@nocodb.com, ...
getAuditCell(0, 0).contains("TABLE").should("exist");
getAuditCell(0, 1).contains("DELETED").should("exist");
getAuditCell(0, 3).contains("user@nocodb.com").should("exist");
getAuditCell(1, 0).contains("TABLE").should("exist");
getAuditCell(1, 1).contains("CREATED").should("exist");
getAuditCell(1, 3).contains("user@nocodb.com").should("exist");
});
it("Table Rename operation", () => {
cy.renameTable("City", "CityX");
// verify
// 1. Table name in project tree has changed
cy.get(".nc-project-tree").contains("CityX").should("exist");
// 2. Table tab name has changed
cy.get(`.project-tab:contains('CityX'):visible`).should("exist");
// 3. contents of the table are valid
mainPage
.getCell(`City`, 1)
.contains("A Corua (La Corua)")
.should("exist");
cy.closeTableTab("CityX");
// 4. verify linked contents in other table
// 4a. Address table, has many field
cy.openTableTab("Address", 25);
mainPage.getCell("City <= Address", 1).scrollIntoView();
mainPage
.getCell("City <= Address", 1)
.find(".name")
.contains("Lethbridge")
.should("exist");
cy.closeTableTab("Address");
// 4b. Country table, belongs to field
cy.openTableTab("Country", 25);
mainPage
.getCell("Country => City", 1)
.find(".name")
.contains("Kabul")
.should("exist");
cy.closeTableTab("Country");
// revert re-name operation to not impact rest of test suite
cy.renameTable("CityX", "City");
});
});
});
};
/**

325
scripts/cypress/integration/common/1b_table_column_operations.js

@ -1,165 +1,176 @@
import { mainPage } from "../../support/page_objects/mainPage";
import {
isTestSuiteActive,
isXcdb,
isTestSuiteActive,
isXcdb,
} from "../../support/page_objects/projectConstants";
export const genTest = (type, xcdb) => {
if (!isTestSuiteActive(type, xcdb)) return;
function addNewRow(index, cellValue) {
cy.get(".nc-add-new-row-btn:visible").should("exist");
cy.get(".nc-add-new-row-btn").click({ force: true });
cy.get("#data-table-form-Title > input").first().type(cellValue);
cy.getActiveModal()
.find("button")
.contains("Save Row")
.click({ force: true });
cy.toastWait("updated successfully");
mainPage.getCell("Title", index).contains(cellValue).should("exist");
}
describe(`${type.toUpperCase()} api - Table Column`, () => {
const name = "tablex";
const colName = "column_name_a";
const updatedColName = "updated_column_name";
const randVal = "Test@1234.com";
const updatedRandVal = "Updated@1234.com";
before(() => {
cy.createTable(name);
export const genTest = (apiType, dbType) => {
if (!isTestSuiteActive(apiType, dbType)) return;
function addNewRow(index, cellValue) {
cy.get(".nc-add-new-row-btn:visible").should("exist");
cy.get(".nc-add-new-row-btn").click({ force: true });
cy.get("#data-table-form-Title > input").first().type(cellValue);
cy.snipActiveModal("Modal_AddNewRow");
cy.getActiveModal()
.find("button")
.contains("Save Row")
.click({ force: true });
cy.toastWait("updated successfully");
mainPage.getCell("Title", index).contains(cellValue).should("exist");
}
describe(`${apiType.toUpperCase()} api - Table Column`, () => {
const name = "tablex";
const colName = "column_name_a";
const updatedColName = "updated_column_name";
const randVal = "Test@1234.com";
const updatedRandVal = "Updated@1234.com";
before(() => {
cy.createTable(name);
});
// delete table
after(() => {
cy.deleteTable(name, dbType);
});
it("Create Table Column", () => {
cy.get(`.project-tab:contains(${name}):visible`).should("exist");
mainPage.addColumn(colName, name);
cy.get(`th:contains(${colName})`).should("exist");
});
// edit the newly created column
it("Edit table column - change datatype", () => {
if (!isXcdb()) {
cy.get(`th:contains(${colName}) .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.toastWait("Update table successful");
cy.get(`th[data-col="${colName}"] .mdi-text-subject`).should(
"exist"
);
cy.get(`th:contains(${colName}) .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(${colName}) .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(updatedColName);
cy.get(".nc-col-create-or-edit-card").contains("Save").click();
cy.toastWait("Update table successful");
cy.get(`th:contains(${colName})`).should("not.exist");
cy.get(`th:contains(${updatedColName})`).should("exist");
});
// delete the newly created column
it("Delete table column", () => {
cy.get(`th:contains(${updatedColName})`).should("exist");
cy.get(`th:contains(${updatedColName}) .mdi-menu-down`)
.trigger("mouseover")
.click();
cy.get(".nc-column-delete").click();
cy.get("button:contains(Confirm)").click();
cy.toastWait("Update table successful");
cy.get(`th:contains(${updatedColName})`).should("not.exist");
});
it("Add new row", () => {
addNewRow(1, randVal);
});
it("Update row", () => {
mainPage
.getRow(1)
.find(".nc-row-expand-icon")
.click({ force: true });
cy.get("#data-table-form-Title > input")
.first()
.clear()
.type(updatedRandVal);
cy.getActiveModal()
.find("button")
.contains("Save Row")
.click({ force: true });
cy.toastWait("updated successfully");
mainPage.getCell("Title", 1).contains(randVal).should("not.exist");
mainPage
.getCell("Title", 1)
.contains(updatedRandVal)
.should("exist");
});
it("Delete row", () => {
mainPage
.getCell("Title", 1)
.contains(updatedRandVal)
.rightclick({ force: true });
// delete row
cy.getActiveMenu()
.find('.v-list-item:contains("Delete Row")')
.first()
.click({ force: true });
// cy.toastWait('Deleted row successfully')
cy.get("td").contains(randVal).should("not.exist");
});
it("Select all row check-box validation", () => {
// add multiple rows
addNewRow(1, "a1");
addNewRow(2, "a2");
addNewRow(3, "a3");
addNewRow(4, "a4");
addNewRow(5, "a5");
// check-box, select-all. 0 indicates table header
mainPage
.getRow(0)
.find(".mdi-checkbox-blank-outline")
.click({ force: true });
// delete selected rows
mainPage.getCell("Title", 1).rightclick({ force: true });
cy.getActiveMenu()
.contains("Delete Selected Row")
.click({ force: true });
// verify if everything is wiped off
mainPage.getCell("Title", 1).contains("a1").should("not.exist");
});
});
// delete table
after(() => {
cy.deleteTable(name);
});
it("Create Table Column", () => {
cy.get(`.project-tab:contains(${name}):visible`).should("exist");
mainPage.addColumn(colName, name);
cy.get(`th:contains(${colName})`).should("exist");
});
// edit the newly created column
it("Edit table column - change datatype", () => {
if (!isXcdb()) {
cy.get(`th:contains(${colName}) .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.toastWait("Update table successful");
cy.get(`th[data-col="${colName}"] .mdi-text-subject`).should("exist");
cy.get(`th:contains(${colName}) .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(${colName}) .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(updatedColName);
cy.get(".nc-col-create-or-edit-card").contains("Save").click();
cy.toastWait("Update table successful");
cy.get(`th:contains(${colName})`).should("not.exist");
cy.get(`th:contains(${updatedColName})`).should("exist");
});
// delete the newly created column
it("Delete table column", () => {
cy.get(`th:contains(${updatedColName})`).should("exist");
cy.get(`th:contains(${updatedColName}) .mdi-menu-down`)
.trigger("mouseover")
.click();
cy.get(".nc-column-delete").click();
cy.get("button:contains(Confirm)").click();
cy.toastWait("Update table successful");
cy.get(`th:contains(${updatedColName})`).should("not.exist");
});
it("Add new row", () => {
addNewRow(1, randVal);
});
it("Update row", () => {
mainPage.getRow(1).find(".nc-row-expand-icon").click({ force: true });
cy.get("#data-table-form-Title > input")
.first()
.clear()
.type(updatedRandVal);
cy.getActiveModal()
.find("button")
.contains("Save Row")
.click({ force: true });
cy.toastWait("updated successfully");
mainPage.getCell("Title", 1).contains(randVal).should("not.exist");
mainPage.getCell("Title", 1).contains(updatedRandVal).should("exist");
});
it("Delete row", () => {
mainPage
.getCell("Title", 1)
.contains(updatedRandVal)
.rightclick({ force: true });
// delete row
cy.getActiveMenu()
.find('.v-list-item:contains("Delete Row")')
.first()
.click({ force: true });
// cy.toastWait('Deleted row successfully')
cy.get("td").contains(randVal).should("not.exist");
});
it("Select all row check-box validation", () => {
// add multiple rows
addNewRow(1, "a1");
addNewRow(2, "a2");
addNewRow(3, "a3");
addNewRow(4, "a4");
addNewRow(5, "a5");
// check-box, select-all. 0 indicates table header
mainPage
.getRow(0)
.find(".mdi-checkbox-blank-outline")
.click({ force: true });
// delete selected rows
mainPage.getCell("Title", 1).rightclick({ force: true });
cy.getActiveMenu().contains("Delete Selected Row").click({ force: true });
// verify if everything is wiped off
mainPage.getCell("Title", 1).contains("a1").should("not.exist");
});
});
};
/**

297
scripts/cypress/integration/common/1c_sql_view.js

@ -1,140 +1,173 @@
import {
isTestSuiteActive,
isXcdb,
isTestSuiteActive,
isXcdb,
} from "../../support/page_objects/projectConstants";
import { mainPage } from "../../support/page_objects/mainPage";
export const genTest = (type, xcdb) => {
if (!isTestSuiteActive(type, xcdb)) return;
describe(`${type.toUpperCase()} SQL Views`, () => {
// Run once before test- create project (rest/graphql)
//
before(() => {
// void
});
it(`XCDB: SQL View Column operations`, () => {
// Open one of the views & verify validity of first two entries
if (isXcdb()) {
cy.openViewsTab("CustomerList", 25);
// Record-1 validation
mainPage.getCell(`ID`, 1).contains("1").should("exist");
mainPage.getCell(`Name`, 1).contains("MARY SMITH").should("exist");
mainPage
.getCell(`Address`, 1)
.contains("1913 Hanoi Way")
.should("exist");
mainPage.getCell(`ZipCode`, 1).contains("35200").should("exist");
// Record-2 validation
mainPage.getCell(`ID`, 2).contains("2").should("exist");
mainPage
.getCell(`Name`, 2)
.contains("PATRICIA JOHNSON")
.should("exist");
mainPage
.getCell(`Address`, 2)
.contains("1121 Loja Avenue")
.should("exist");
mainPage.getCell(`ZipCode`, 2).contains("17886").should("exist");
// Column operations: Hide
mainPage.hideField(`ZipCode`);
mainPage.unhideField(`ZipCode`);
// Column operations: Sort
mainPage.sortField("Name", "Z -> A");
mainPage.getCell(`Name`, 1).contains("ZACHARY HITE").should("exist");
mainPage.clearSort();
// Column operations: Filter
mainPage.filterField("Name", "is like", "MARY");
mainPage.getCell(`Name`, 1).contains("MARY SMITH").should("exist");
mainPage.filterReset();
cy.closeViewsTab("CustomerList");
}
});
it(`SQL View Column operations`, () => {
if (!isXcdb()) {
// Open one of the views & verify validity of first two entries
cy.openViewsTab("ActorInfo", 25);
// Record-1 validation
mainPage.getCell(`ActorId`, 1).contains("1").should("exist");
mainPage.getCell(`FirstName`, 1).contains("PENELOPE").should("exist");
mainPage.getCell(`LastName`, 1).contains("GUINESS").should("exist");
mainPage
.getCell(`FilmInfo`, 1)
.contains("Animation: ANACONDA CONFESSIONS;")
.should("exist");
// Record-2 validation
mainPage.getCell(`ActorId`, 2).contains("2").should("exist");
mainPage.getCell(`FirstName`, 2).contains("NICK").should("exist");
mainPage.getCell(`LastName`, 2).contains("WAHLBERG").should("exist");
mainPage
.getCell(`FilmInfo`, 2)
.contains("Action: BULL SHAWSHANK; Animation: FIGHT JAWBREAKER;")
.should("exist");
// Column operations: Hide
mainPage.hideField("FilmInfo");
mainPage.unhideField("FilmInfo");
// Column operations: Sort
mainPage.sortField("FirstName", "Z -> A");
mainPage.getCell(`FirstName`, 1).contains("ZERO").should("exist");
mainPage.clearSort();
// Column operations: Filter
mainPage.filterField("FirstName", "is like", "PENELOPE");
mainPage.getCell(`FirstName`, 1).contains("PENELOPE").should("exist");
mainPage.filterReset();
cy.closeViewsTab("ActorInfo");
}
});
it(`SQL View List`, () => {
// confirm if other views exist
//
cy.openViewsTab("CustomerList", 25);
cy.closeViewsTab("CustomerList");
cy.openViewsTab("FilmList", 25);
cy.closeViewsTab("FilmList");
cy.openViewsTab("SalesByFilmCategory", 16);
cy.closeViewsTab("SalesByFilmCategory");
if (!isXcdb()) {
cy.openViewsTab("NicerButSlowerFilmList", 25);
cy.closeViewsTab("NicerButSlowerFilmList");
// SalesByStore && StaffList contain no entries. Hence marking row count to 0
cy.openViewsTab("SalesByStore", 0);
cy.closeViewsTab("SalesByStore");
cy.openViewsTab("StaffList", 0);
cy.closeViewsTab("StaffList");
} else {
cy.openViewsTab("SalesByStore", 2);
cy.closeViewsTab("SalesByStore");
cy.openViewsTab("StaffList", 2);
cy.closeViewsTab("StaffList");
}
});
after(() => {
// void
export const genTest = (apiType, dbType) => {
if (!isTestSuiteActive(apiType, dbType)) return;
describe(`${apiType.toUpperCase()} SQL Views`, () => {
// Run once before test- create project (rest/graphql)
//
before(() => {
// void
});
it(`XCDB: SQL View Column operations`, () => {
// Open one of the views & verify validity of first two entries
if (isXcdb()) {
cy.openViewsTab("CustomerList", 25);
// Record-1 validation
mainPage.getCell(`ID`, 1).contains("1").should("exist");
mainPage
.getCell(`Name`, 1)
.contains("MARY SMITH")
.should("exist");
mainPage
.getCell(`Address`, 1)
.contains("1913 Hanoi Way")
.should("exist");
mainPage
.getCell(`ZipCode`, 1)
.contains("35200")
.should("exist");
// Record-2 validation
mainPage.getCell(`ID`, 2).contains("2").should("exist");
mainPage
.getCell(`Name`, 2)
.contains("PATRICIA JOHNSON")
.should("exist");
mainPage
.getCell(`Address`, 2)
.contains("1121 Loja Avenue")
.should("exist");
mainPage
.getCell(`ZipCode`, 2)
.contains("17886")
.should("exist");
// Column operations: Hide
mainPage.hideField(`ZipCode`);
mainPage.unhideField(`ZipCode`);
// Column operations: Sort
mainPage.sortField("Name", "Z -> A");
mainPage
.getCell(`Name`, 1)
.contains("ZACHARY HITE")
.should("exist");
mainPage.clearSort();
// Column operations: Filter
mainPage.filterField("Name", "is like", "MARY");
mainPage
.getCell(`Name`, 1)
.contains("MARY SMITH")
.should("exist");
mainPage.filterReset();
cy.closeViewsTab("CustomerList");
}
});
it(`SQL View Column operations`, () => {
if (!isXcdb()) {
// Open one of the views & verify validity of first two entries
cy.openViewsTab("ActorInfo", 25);
// Record-1 validation
mainPage.getCell(`ActorId`, 1).contains("1").should("exist");
mainPage
.getCell(`FirstName`, 1)
.contains("PENELOPE")
.should("exist");
mainPage
.getCell(`LastName`, 1)
.contains("GUINESS")
.should("exist");
mainPage
.getCell(`FilmInfo`, 1)
.contains("Animation: ANACONDA CONFESSIONS")
.should("exist");
// Record-2 validation
mainPage.getCell(`ActorId`, 2).contains("2").should("exist");
mainPage
.getCell(`FirstName`, 2)
.contains("NICK")
.should("exist");
mainPage
.getCell(`LastName`, 2)
.contains("WAHLBERG")
.should("exist");
mainPage
.getCell(`FilmInfo`, 2)
.contains("Action: BULL SHAWSHANK")
.should("exist");
// Column operations: Hide
mainPage.hideField("FilmInfo");
mainPage.unhideField("FilmInfo");
// Column operations: Sort
mainPage.sortField("FirstName", "Z -> A");
mainPage
.getCell(`FirstName`, 1)
.contains("ZERO")
.should("exist");
mainPage.clearSort();
// Column operations: Filter
mainPage.filterField("FirstName", "is like", "PENELOPE");
mainPage
.getCell(`FirstName`, 1)
.contains("PENELOPE")
.should("exist");
mainPage.filterReset();
cy.closeViewsTab("ActorInfo");
}
});
it(`SQL View List`, () => {
// confirm if other views exist
//
cy.openViewsTab("CustomerList", 25);
cy.closeViewsTab("CustomerList");
cy.openViewsTab("FilmList", 25);
cy.closeViewsTab("FilmList");
cy.openViewsTab("SalesByFilmCategory", 16);
cy.closeViewsTab("SalesByFilmCategory");
if (!isXcdb()) {
cy.openViewsTab("NicerButSlowerFilmList", 25);
cy.closeViewsTab("NicerButSlowerFilmList");
// SalesByStore && StaffList contain no entries. Hence marking row count to 0
cy.openViewsTab("SalesByStore", 0);
cy.closeViewsTab("SalesByStore");
cy.openViewsTab("StaffList", 0);
cy.closeViewsTab("StaffList");
} else {
cy.openViewsTab("SalesByStore", 2);
cy.closeViewsTab("SalesByStore");
cy.openViewsTab("StaffList", 2);
cy.closeViewsTab("StaffList");
}
});
after(() => {
// void
});
});
});
};
/**

171
scripts/cypress/integration/common/1d_pg_table_view_drag_drop_reorder.js

@ -0,0 +1,171 @@
import {
isTestSuiteActive,
isXcdb,
getProjectString,
isPostgres,
} from "../../support/page_objects/projectConstants";
export const genTest = (apiType, dbType) => {
if (!isTestSuiteActive(apiType, dbType)) return;
describe(`${apiType.toUpperCase()} Table/view drag-drop reorder`, () => {
function validateTreeField(index, tblName) {
cy.get(`:nth-child(${index}) > .v-list-item__title > .caption`)
.contains(tblName)
.should("exist");
}
/*
Original order of list items
Actor, Address, Category, City, Country, Customer, FIlm, FilmText, Language, Payment, Rental Staff
ActorInfo, CustomerList, FilmList, NiceButSlowerFilmList, SalesByFilmCategory, SalesByStore, StaffList
*/
it(`Table & SQL View list, Drag/drop`, () => {
// expand tree-view menu
// cy.get(".nc-project-tree")
// .find(".v-list-item__title:contains(Tables)", { timeout: 10000 })
// .should("exist")
// .first()
// .click({ force: true });
validateTreeField(1, "Actor");
// move Actor field down, above Staff (drag, drop)
cy.get(".nc-child-draggable-icon-Actor").drag(
".nc-child-draggable-icon-Film"
);
validateTreeField(7, "Actor");
// move ActorInfo (View) field up to first place (drag, drop)
cy.get(".nc-child-draggable-icon-ActorInfo").drag(
".nc-child-draggable-icon-Address"
);
validateTreeField(1, "ActorInfo");
validateTreeField(2, "Address");
validateTreeField(8, "Actor");
// restore ActorInfo field (drag, drop)
cy.get(".nc-child-draggable-icon-ActorInfo").drag(
".nc-child-draggable-icon-Staff"
);
// restore Actor field (drag, drop)
cy.get(".nc-child-draggable-icon-Actor").drag(
".nc-child-draggable-icon-Address"
);
validateTreeField(1, "Actor");
validateTreeField(2, "Address");
if (isPostgres()) {
validateTreeField(17, "Staff");
validateTreeField(18, "ActorInfo");
validateTreeField(19, "CustomerList");
} else {
validateTreeField(12, "Staff");
validateTreeField(13, "ActorInfo");
validateTreeField(14, "CustomerList");
}
// undo project-tree expand operation
cy.get(".nc-project-tree")
.find(".v-list-item__title:contains(Tables)", {
timeout: 10000,
})
.should("exist")
.first()
.click({ force: true });
});
// create new view as specified by 'viewType'
// can be - grid/ gallery/ form
// wait for toast to appear
//
function createView(viewType) {
// click on 'Grid/Gallery' button on Views bar
cy.get(`.nc-create-${viewType}-view`).click();
cy.snipActiveModal(`Modal_createView_${viewType}`);
// Pop up window, click Submit (accepting default name for view)
cy.getActiveModal().find("button:contains(Submit)").click();
cy.toastWait("View created successfully");
}
// verify view 'viewName' to be present at position 'index'
// index starts from 0
function validateViewField(index, viewName) {
cy.get(".nc-view-item.nc-draggable-child")
.eq(index)
.contains(viewName)
.should("exist");
}
it(`View (Gallery/ Grid/ Form) re-order`, () => {
cy.openTableTab("Actor", 25);
// create 3 views, use default names
// Actor1, Actor2, Actor3
createView("grid");
createView("gallery");
createView("form");
// validate position order
validateViewField(0, "Actor");
validateViewField(1, "Actor1");
validateViewField(2, "Actor2");
validateViewField(3, "Actor3");
// move Actor3 field on top (drag, drop)
cy.get(".nc-child-draggable-icon-Actor3").drag(
`.nc-child-draggable-icon-${
isXcdb() ? `nc_${getProjectString()}__` : ``
}actor`
);
// validate new position order, Actor3 on top
validateViewField(0, "Actor3");
validateViewField(1, "Actor");
validateViewField(2, "Actor1");
validateViewField(3, "Actor2");
// delete all created views
// click on delete icon (becomes visible on hovering mouse)
cy.get(".nc-view-delete-icon").eq(0).click({ force: true });
cy.toastWait("View deleted successfully");
cy.get(".nc-view-delete-icon").eq(0).click({ force: true });
cy.toastWait("View deleted successfully");
cy.get(".nc-view-delete-icon").eq(0).click({ force: true });
cy.toastWait("View deleted successfully");
// wind up
cy.closeTableTab("Actor");
});
});
};
/**
* @copyright Copyright (c) 2021, Xgene Cloud Ltd
*
* @author Pranav C Balan <pranavxc@gmail.com>
* @author Raju Udava <sivadstala@gmail.com>
*
* @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 <http://www.gnu.org/licenses/>.
*
*/

268
scripts/cypress/integration/common/1d_table_view_drag_drop_reorder.js

@ -1,139 +1,143 @@
import {
isTestSuiteActive,
isXcdb,
getProjectString,
isTestSuiteActive,
isXcdb,
getProjectString,
} from "../../support/page_objects/projectConstants";
export const genTest = (type, xcdb) => {
if (!isTestSuiteActive(type, xcdb)) return;
describe(`${type.toUpperCase()} Table/view drag-drop reorder`, () => {
function validateTreeField(index, tblName) {
cy.get(`:nth-child(${index}) > .v-list-item__title > .caption`)
.contains(tblName)
.should("exist");
}
/*
Original order of list items
Actor, Address, Category, City, Country, Customer, FIlm, FilmText, Language, Payment, Rental Staff
ActorInfo, CustomerList, FilmList, NiceButSlowerFilmList, SalesByFilmCategory, SalesByStore, StaffList
*/
it(`Table & SQL View list, Drag/drop`, () => {
// expand tree-view menu
// cy.get(".nc-project-tree")
// .find(".v-list-item__title:contains(Tables)", { timeout: 10000 })
// .should("exist")
// .first()
// .click({ force: true });
validateTreeField(1, "Actor");
// move Actor field down, above Staff (drag, drop)
cy.get(".nc-child-draggable-icon-Actor").drag(
".nc-child-draggable-icon-Staff"
);
validateTreeField(12, "Actor");
// move ActorInfo (View) field up to first place (drag, drop)
cy.get(".nc-child-draggable-icon-ActorInfo").drag(
".nc-child-draggable-icon-Address"
);
validateTreeField(1, "ActorInfo");
validateTreeField(2, "Address");
validateTreeField(13, "Actor");
// restore ActorInfo field (drag, drop)
cy.get(".nc-child-draggable-icon-ActorInfo").drag(
".nc-child-draggable-icon-Actor"
);
// restore Actor field (drag, drop)
cy.get(".nc-child-draggable-icon-Actor").drag(
".nc-child-draggable-icon-Address"
);
validateTreeField(1, "Actor");
validateTreeField(2, "Address");
validateTreeField(12, "Staff");
validateTreeField(13, "ActorInfo");
validateTreeField(14, "CustomerList");
// undo project-tree expand operation
cy.get(".nc-project-tree")
.find(".v-list-item__title:contains(Tables)", { timeout: 10000 })
.should("exist")
.first()
.click({ force: true });
export const genTest = (apiType, dbType) => {
if (!isTestSuiteActive(apiType, dbType)) return;
describe(`${apiType.toUpperCase()} Table/view drag-drop reorder`, () => {
function validateTreeField(index, tblName) {
cy.get(`:nth-child(${index}) > .v-list-item__title > .caption`)
.contains(tblName)
.should("exist");
}
/*
Original order of list items
Actor, Address, Category, City, Country, Customer, FIlm, FilmText, Language, Payment, Rental Staff
ActorInfo, CustomerList, FilmList, NiceButSlowerFilmList, SalesByFilmCategory, SalesByStore, StaffList
*/
it(`Table & SQL View list, Drag/drop`, () => {
// expand tree-view menu
// cy.get(".nc-project-tree")
// .find(".v-list-item__title:contains(Tables)", { timeout: 10000 })
// .should("exist")
// .first()
// .click({ force: true });
validateTreeField(1, "Actor");
// move Actor field down, above Staff (drag, drop)
cy.get(".nc-child-draggable-icon-Actor").drag(
".nc-child-draggable-icon-Staff"
);
validateTreeField(12, "Actor");
// move ActorInfo (View) field up to first place (drag, drop)
cy.get(".nc-child-draggable-icon-ActorInfo").drag(
".nc-child-draggable-icon-Address"
);
validateTreeField(1, "ActorInfo");
validateTreeField(2, "Address");
validateTreeField(13, "Actor");
// restore ActorInfo field (drag, drop)
cy.get(".nc-child-draggable-icon-ActorInfo").drag(
".nc-child-draggable-icon-Actor"
);
// restore Actor field (drag, drop)
cy.get(".nc-child-draggable-icon-Actor").drag(
".nc-child-draggable-icon-Address"
);
validateTreeField(1, "Actor");
validateTreeField(2, "Address");
validateTreeField(12, "Staff");
validateTreeField(13, "ActorInfo");
validateTreeField(14, "CustomerList");
// undo project-tree expand operation
cy.get(".nc-project-tree")
.find(".v-list-item__title:contains(Tables)", {
timeout: 10000,
})
.should("exist")
.first()
.click({ force: true });
});
// create new view as specified by 'viewType'
// can be - grid/ gallery/ form
// wait for toast to appear
//
function createView(viewType) {
// click on 'Grid/Gallery' button on Views bar
cy.get(`.nc-create-${viewType}-view`).click();
cy.snipActiveModal(`Modal_createView_${viewType}`);
// Pop up window, click Submit (accepting default name for view)
cy.getActiveModal().find("button:contains(Submit)").click();
cy.toastWait("View created successfully");
}
// verify view 'viewName' to be present at position 'index'
// index starts from 0
function validateViewField(index, viewName) {
cy.get(".nc-view-item.nc-draggable-child")
.eq(index)
.contains(viewName)
.should("exist");
}
it(`View (Gallery/ Grid/ Form) re-order`, () => {
cy.openTableTab("Actor", 25);
// create 3 views, use default names
// Actor1, Actor2, Actor3
createView("grid");
createView("gallery");
createView("form");
// validate position order
validateViewField(0, "Actor");
validateViewField(1, "Actor1");
validateViewField(2, "Actor2");
validateViewField(3, "Actor3");
// move Actor3 field on top (drag, drop)
cy.get(".nc-child-draggable-icon-Actor3").drag(
`.nc-child-draggable-icon-${
isXcdb() ? `nc_${getProjectString()}__` : ``
}actor`
);
// validate new position order, Actor3 on top
validateViewField(0, "Actor3");
validateViewField(1, "Actor");
validateViewField(2, "Actor1");
validateViewField(3, "Actor2");
// delete all created views
// click on delete icon (becomes visible on hovering mouse)
cy.get(".nc-view-delete-icon").eq(0).click({ force: true });
cy.toastWait("View deleted successfully");
cy.get(".nc-view-delete-icon").eq(0).click({ force: true });
cy.toastWait("View deleted successfully");
cy.get(".nc-view-delete-icon").eq(0).click({ force: true });
cy.toastWait("View deleted successfully");
// wind up
cy.closeTableTab("Actor");
});
});
// create new view as specified by 'viewType'
// can be - grid/ gallery/ form
// wait for toast to appear
//
function createView(viewType) {
// click on 'Grid/Gallery' button on Views bar
cy.get(`.nc-create-${viewType}-view`).click();
// Pop up window, click Submit (accepting default name for view)
cy.getActiveModal().find("button:contains(Submit)").click();
cy.toastWait("View created successfully");
}
// verify view 'viewName' to be present at position 'index'
// index starts from 0
function validateViewField(index, viewName) {
cy.get(".nc-view-item.nc-draggable-child")
.eq(index)
.contains(viewName)
.should("exist");
}
it(`View (Gallery/ Grid/ Form) re-order`, () => {
cy.openTableTab("Actor", 25);
// create 3 views, use default names
// Actor1, Actor2, Actor3
createView("grid");
createView("gallery");
createView("form");
// validate position order
validateViewField(0, "Actor");
validateViewField(1, "Actor1");
validateViewField(2, "Actor2");
validateViewField(3, "Actor3");
// move Actor3 field on top (drag, drop)
cy.get(".nc-child-draggable-icon-Actor3").drag(
`.nc-child-draggable-icon-${
isXcdb() ? `nc_${getProjectString()}__` : ``
}actor`
);
// validate new position order, Actor3 on top
validateViewField(0, "Actor3");
validateViewField(1, "Actor");
validateViewField(2, "Actor1");
validateViewField(3, "Actor2");
// delete all created views
// click on delete icon (becomes visible on hovering mouse)
cy.get(".nc-view-delete-icon").eq(0).click({ force: true });
cy.toastWait("View deleted successfully");
cy.get(".nc-view-delete-icon").eq(0).click({ force: true });
cy.toastWait("View deleted successfully");
cy.get(".nc-view-delete-icon").eq(0).click({ force: true });
cy.toastWait("View deleted successfully");
// wind up
cy.closeTableTab("Actor");
});
});
};
/**

321
scripts/cypress/integration/common/1e_meta_sync.js

@ -1,165 +1,174 @@
import { mainPage } from "../../support/page_objects/mainPage";
import { loginPage } from "../../support/page_objects/navigation";
import {
getCurrentMode,
getProjectString,
isTestSuiteActive,
isXcdb,
getCurrentMode,
getProjectString,
isTestSuiteActive,
isXcdb,
} from "../../support/page_objects/projectConstants";
export const genTest = (type, xcdb) => {
if (!isTestSuiteActive(type, xcdb)) return;
let projPrefix = `sakila.`;
let dbCmd = `queryDb`;
let tblDisplayPrefix = ``;
describe(`${type.toUpperCase()} api - Meta Sync`, () => {
// Run once before test- create project (rest/graphql)
//
before(() => {
if (isXcdb()) {
cy.log(getProjectString());
projPrefix = `nc_${getProjectString()}__`;
dbCmd = `sqliteExec`;
tblDisplayPrefix = `nc_${getProjectString()}__`;
}
mainPage.openMetaTab();
export const genTest = (apiType, dbType) => {
if (!isTestSuiteActive(apiType, dbType)) return;
let projPrefix = `sakila.`;
let dbCmd = `queryDb`;
let tblDisplayPrefix = ``;
describe(`${apiType.toUpperCase()} api - Meta Sync`, () => {
// Run once before test- create project (rest/graphql)
//
before(() => {
if (isXcdb()) {
cy.log(getProjectString());
projPrefix = `nc_${getProjectString()}__`;
dbCmd = `sqliteExec`;
tblDisplayPrefix = `nc_${getProjectString()}__`;
}
mainPage.openMetaTab();
});
after(() => {
mainPage.closeMetaTab();
});
it(`Create table`, () => {
// Create Table
cy.task(
dbCmd,
`CREATE TABLE ${projPrefix}table1 (id INT NOT NULL, col1 INT NULL, PRIMARY KEY (id))`
);
cy.task(
dbCmd,
`CREATE TABLE ${projPrefix}table2 (id INT NOT NULL, col1 INT NULL, PRIMARY KEY (id))`
);
mainPage.metaSyncValidate(`${tblDisplayPrefix}table1`, "New table");
});
it(`Add relation`, () => {
// working with relations in sqlite requires table to be deleted & recreated
//
if (!isXcdb()) {
// Add relation (FK)
cy.task(
dbCmd,
`ALTER TABLE ${projPrefix}table1 ADD INDEX fk1_idx (col1 ASC) VISIBLE`
);
cy.task(
dbCmd,
`ALTER TABLE ${projPrefix}table1 ADD CONSTRAINT fk1 FOREIGN KEY (col1) REFERENCES ${projPrefix}table2 (id) ON DELETE NO ACTION ON UPDATE NO ACTION`
);
mainPage.metaSyncValidate(
`${tblDisplayPrefix}table1`,
"New relation added"
);
}
});
it(`Remove relation`, () => {
// working with relations in sqlite requires table to be deleted & recreated
//
if (!isXcdb()) {
// Remove relation (FK)
cy.task(
dbCmd,
`ALTER TABLE ${projPrefix}table1 DROP FOREIGN KEY fk1`
);
cy.task(
dbCmd,
`ALTER TABLE ${projPrefix}table1 DROP INDEX fk1_idx`
);
mainPage.metaSyncValidate(
`${tblDisplayPrefix}table1`,
"Relation removed"
);
}
});
it(`Add column`, () => {
// Add Column
let queryString = `ALTER TABLE ${projPrefix}table1 ADD COLUMN newCol VARCHAR(45) NULL AFTER id`;
if (isXcdb())
queryString = `ALTER TABLE ${projPrefix}table1 ADD COLUMN newCol TEXT NULL`;
cy.task(dbCmd, queryString);
mainPage.metaSyncValidate(
`${tblDisplayPrefix}table1`,
"New column(newCol)"
);
});
it(`Rename column`, () => {
// Rename Column
let queryString = `ALTER TABLE ${projPrefix}table1 CHANGE COLUMN newCol newColName VARCHAR(45) NULL DEFAULT NULL`;
if (isXcdb())
queryString = `ALTER TABLE ${projPrefix}table1 RENAME COLUMN newCol TO newColName`;
cy.task(dbCmd, queryString);
mainPage.metaSyncValidate(
`${tblDisplayPrefix}table1`,
"New column(newColName), Column removed(newCol)"
);
});
it(`Delete column`, () => {
// Remove Column
// to be fixed for SQLITE
if (!isXcdb()) {
cy.task(
dbCmd,
`ALTER TABLE ${projPrefix}table1 DROP COLUMN newColName`
);
mainPage.metaSyncValidate(
`${tblDisplayPrefix}table1`,
"Column removed(newColName)"
);
}
});
it(`Delete table`, () => {
// DROP TABLE
cy.task(dbCmd, `DROP TABLE ${projPrefix}table1`);
cy.task(dbCmd, `DROP TABLE ${projPrefix}table2`);
mainPage.metaSyncValidate(
`${tblDisplayPrefix}table1`,
"Table removed"
);
});
it(`Hide, Filter, Sort`, () => {
cy.task(
dbCmd,
`CREATE TABLE ${projPrefix}table1 (id INT NOT NULL, col1 INT NULL, col2 INT NULL, col3 INT NULL, col4 INT NULL, PRIMARY KEY (id))`
);
cy.task(
dbCmd,
`INSERT INTO ${projPrefix}table1 (id, col1, col2, col3, col4) VALUES (1,1,1,1,1), (2,2,2,2,2), (3,3,3,3,3), (4,4,4,4,4), (5,5,5,5,5), (6,6,6,6,6), (7,7,7,7,7), (8,8,8,8,8), (9,9,9,9,9);`
);
mainPage.metaSyncValidate(`${tblDisplayPrefix}table1`, "New table");
mainPage.closeMetaTab();
cy.openTableTab("Table1", 9);
mainPage.hideField("Col1");
mainPage.sortField("Col1", "Z -> A");
mainPage.filterField(`Col1`, ">=", "5");
cy.get(".nc-grid-row").should("have.length", 5);
cy.closeTableTab("Table1");
});
it(`Verify`, () => {
mainPage.openMetaTab();
// Rename Column
let queryString = `ALTER TABLE ${projPrefix}table1 CHANGE COLUMN col1 newCol INT NULL DEFAULT NULL`;
if (isXcdb())
queryString = `ALTER TABLE ${projPrefix}table1 RENAME COLUMN col1 TO newCol`;
cy.task(dbCmd, queryString);
mainPage.metaSyncValidate(
`${tblDisplayPrefix}table1`,
"New column(newCol), Column removed(col1)"
);
cy.openTableTab("Table1", 9);
cy.deleteTable("Table1", dbType);
});
});
after(() => {
mainPage.closeMetaTab();
});
it(`Create table`, () => {
// Create Table
cy.task(
dbCmd,
`CREATE TABLE ${projPrefix}table1 (id INT NOT NULL, col1 INT NULL, PRIMARY KEY (id))`
);
cy.task(
dbCmd,
`CREATE TABLE ${projPrefix}table2 (id INT NOT NULL, col1 INT NULL, PRIMARY KEY (id))`
);
mainPage.metaSyncValidate(`${tblDisplayPrefix}table1`, "New table");
});
it(`Add relation`, () => {
// working with relations in sqlite requires table to be deleted & recreated
//
if (!isXcdb()) {
// Add relation (FK)
cy.task(
dbCmd,
`ALTER TABLE ${projPrefix}table1 ADD INDEX fk1_idx (col1 ASC) VISIBLE`
);
cy.task(
dbCmd,
`ALTER TABLE ${projPrefix}table1 ADD CONSTRAINT fk1 FOREIGN KEY (col1) REFERENCES ${projPrefix}table2 (id) ON DELETE NO ACTION ON UPDATE NO ACTION`
);
mainPage.metaSyncValidate(
`${tblDisplayPrefix}table1`,
"New relation added"
);
}
});
it(`Remove relation`, () => {
// working with relations in sqlite requires table to be deleted & recreated
//
if (!isXcdb()) {
// Remove relation (FK)
cy.task(dbCmd, `ALTER TABLE ${projPrefix}table1 DROP FOREIGN KEY fk1`);
cy.task(dbCmd, `ALTER TABLE ${projPrefix}table1 DROP INDEX fk1_idx`);
mainPage.metaSyncValidate(
`${tblDisplayPrefix}table1`,
"Relation removed"
);
}
});
it(`Add column`, () => {
// Add Column
let queryString = `ALTER TABLE ${projPrefix}table1 ADD COLUMN newCol VARCHAR(45) NULL AFTER id`;
if (isXcdb())
queryString = `ALTER TABLE ${projPrefix}table1 ADD COLUMN newCol TEXT NULL`;
cy.task(dbCmd, queryString);
mainPage.metaSyncValidate(
`${tblDisplayPrefix}table1`,
"New column(newCol)"
);
});
it(`Rename column`, () => {
// Rename Column
let queryString = `ALTER TABLE ${projPrefix}table1 CHANGE COLUMN newCol newColName VARCHAR(45) NULL DEFAULT NULL`;
if (isXcdb())
queryString = `ALTER TABLE ${projPrefix}table1 RENAME COLUMN newCol TO newColName`;
cy.task(dbCmd, queryString);
mainPage.metaSyncValidate(
`${tblDisplayPrefix}table1`,
"New column(newColName), Column removed(newCol)"
);
});
it(`Delete column`, () => {
// Remove Column
// to be fixed for SQLITE
if (!isXcdb()) {
cy.task(
dbCmd,
`ALTER TABLE ${projPrefix}table1 DROP COLUMN newColName`
);
mainPage.metaSyncValidate(
`${tblDisplayPrefix}table1`,
"Column removed(newColName)"
);
}
});
it(`Delete table`, () => {
// DROP TABLE
cy.task(dbCmd, `DROP TABLE ${projPrefix}table1`);
cy.task(dbCmd, `DROP TABLE ${projPrefix}table2`);
mainPage.metaSyncValidate(`${tblDisplayPrefix}table1`, "Table removed");
});
it(`Hide, Filter, Sort`, () => {
cy.task(
dbCmd,
`CREATE TABLE ${projPrefix}table1 (id INT NOT NULL, col1 INT NULL, col2 INT NULL, col3 INT NULL, col4 INT NULL, PRIMARY KEY (id))`
);
cy.task(
dbCmd,
`INSERT INTO ${projPrefix}table1 (id, col1, col2, col3, col4) VALUES (1,1,1,1,1), (2,2,2,2,2), (3,3,3,3,3), (4,4,4,4,4), (5,5,5,5,5), (6,6,6,6,6), (7,7,7,7,7), (8,8,8,8,8), (9,9,9,9,9);`
);
mainPage.metaSyncValidate(`${tblDisplayPrefix}table1`, "New table");
mainPage.closeMetaTab();
cy.openTableTab("Table1", 9);
mainPage.hideField("Col1");
mainPage.sortField("Col1", "Z -> A");
mainPage.filterField(`Col1`, ">=", "5");
cy.get(".nc-grid-row").should("have.length", 5);
cy.closeTableTab("Table1");
});
it(`Verify`, () => {
mainPage.openMetaTab();
// Rename Column
let queryString = `ALTER TABLE ${projPrefix}table1 CHANGE COLUMN col1 newCol INT NULL DEFAULT NULL`;
if (isXcdb())
queryString = `ALTER TABLE ${projPrefix}table1 RENAME COLUMN col1 TO newCol`;
cy.task(dbCmd, queryString);
mainPage.metaSyncValidate(
`${tblDisplayPrefix}table1`,
"New column(newCol), Column removed(col1)"
);
cy.openTableTab("Table1", 9);
cy.deleteTable("Table1");
});
});
};
/**

202
scripts/cypress/integration/common/1e_pg_meta_sync.js

@ -0,0 +1,202 @@
import { mainPage } from "../../support/page_objects/mainPage";
import { loginPage } from "../../support/page_objects/navigation";
import {
getCurrentMode,
getProjectString,
isTestSuiteActive,
isXcdb,
} from "../../support/page_objects/projectConstants";
export const genTest = (apiType, dbType) => {
if (!isTestSuiteActive(apiType, dbType)) return;
let projPrefix = `sakila.`;
let dbCmd = `pgExec`;
let tblDisplayPrefix = ``;
describe(`${apiType.toUpperCase()} api - Meta Sync`, () => {
// Run once before test- create project (rest/graphql)
//
before(() => {
mainPage.openMetaTab();
});
after(() => {
mainPage.closeMetaTab();
});
it(`Create table`, () => {
cy.log("this works");
// Create Table
cy.task(
dbCmd,
`CREATE TABLE table1( id INT NOT NULL, col1 INT NOT NULL, PRIMARY KEY(id))`
);
cy.task(
dbCmd,
`CREATE TABLE table2( id INT NOT NULL, col1 INT NOT NULL, PRIMARY KEY(id))`
);
mainPage.metaSyncValidate(`${tblDisplayPrefix}table1`, "New table");
});
it(`Add relation`, () => {
// working with relations in sqlite requires table to be deleted & recreated
//
// Add relation (FK)
cy.task(
dbCmd,
`ALTER TABLE table1 ADD CONSTRAINT fk_idx FOREIGN KEY (id) REFERENCES table2 (id);`
);
// cy.task(
// dbCmd,
// `ALTER TABLE ${projPrefix}table1 ADD CONSTRAINT fk1 FOREIGN KEY (col1) REFERENCES ${projPrefix}table2 (id) ON DELETE NO ACTION ON UPDATE NO ACTION`
// );
mainPage.metaSyncValidate(
`${tblDisplayPrefix}table1`,
"New relation added"
);
});
it(`Remove relation`, () => {
// working with relations in sqlite requires table to be deleted & recreated
//
// Remove relation (FK)
cy.task(dbCmd, `ALTER TABLE table1 DROP CONSTRAINT fk_idx`);
mainPage.metaSyncValidate(
`${tblDisplayPrefix}table1`,
"Relation removed"
);
});
it(`Add column`, () => {
// Add Column
let queryString = `ALTER TABLE table1 ADD COLUMN newCol INT`;
cy.task(dbCmd, queryString);
mainPage.metaSyncValidate(
`${tblDisplayPrefix}table1`,
"New column(newcol)"
);
});
it(`Rename column`, () => {
// Rename Column
let queryString = `ALTER TABLE table1 RENAME COLUMN newCol TO newColName`;
cy.task(dbCmd, queryString);
mainPage.metaSyncValidate(
`${tblDisplayPrefix}table1`,
"New column(newcolname), Column removed(newcol)"
);
});
it(`Delete column`, () => {
// Remove Column
cy.task(dbCmd, `ALTER TABLE table1 DROP COLUMN newColName`);
mainPage.metaSyncValidate(
`${tblDisplayPrefix}table1`,
"Column removed(newcolname)"
);
});
it(`Delete table`, () => {
// DROP TABLE
cy.task(dbCmd, `DROP TABLE IF EXISTS table1`);
cy.task(dbCmd, `DROP TABLE IF EXISTS table2`);
mainPage.metaSyncValidate(
`${tblDisplayPrefix}table1`,
"Table removed"
);
});
it(`Hide, Filter, Sort`, () => {
// kludge: bulk insert fail.
cy.task(
dbCmd,
`CREATE TABLE table1( id INT NOT NULL, col1 INT NOT NULL, col2 INT NOT NULL, col3 INT NOT NULL, col4 INT NOT NULL, PRIMARY KEY(id))`
);
cy.wait(3000);
cy.task(
dbCmd,
`INSERT INTO table1 (id, col1, col2, col3, col4) VALUES (1,1,1,1,1)`
);
cy.task(
dbCmd,
`INSERT INTO table1 (id, col1, col2, col3, col4) VALUES (2,2,2,2,2)`
);
cy.task(
dbCmd,
`INSERT INTO table1 (id, col1, col2, col3, col4) VALUES (3,3,3,3,3)`
);
cy.task(
dbCmd,
`INSERT INTO table1 (id, col1, col2, col3, col4) VALUES (4,4,4,4,4)`
);
cy.task(
dbCmd,
`INSERT INTO table1 (id, col1, col2, col3, col4) VALUES (5,5,5,5,5)`
);
cy.task(
dbCmd,
`INSERT INTO table1 (id, col1, col2, col3, col4) VALUES (6,6,6,6,6)`
);
cy.task(
dbCmd,
`INSERT INTO table1 (id, col1, col2, col3, col4) VALUES (7,7,7,7,7)`
);
cy.task(
dbCmd,
`INSERT INTO table1 (id, col1, col2, col3, col4) VALUES (8,8,8,8,8)`
);
cy.task(
dbCmd,
`INSERT INTO table1 (id, col1, col2, col3, col4) VALUES (9,9,9,9,9)`
);
mainPage.metaSyncValidate(`${tblDisplayPrefix}table1`, "New table");
mainPage.closeMetaTab();
cy.openTableTab("Table1", 9);
mainPage.hideField("Col1");
mainPage.sortField("Col1", "Z -> A");
mainPage.filterField(`Col1`, ">=", "5");
cy.get(".nc-grid-row").should("have.length", 5);
cy.closeTableTab("Table1");
});
it(`Verify`, () => {
mainPage.openMetaTab();
// Rename Column
let queryString = `ALTER TABLE table1 RENAME COLUMN col1 TO newcol`;
cy.task(dbCmd, queryString);
mainPage.metaSyncValidate(
`${tblDisplayPrefix}table1`,
"New column(newcol), Column removed(col1)"
);
cy.openTableTab("Table1", 9);
// kludge- delete table triggered post sql backend operations doesnt carry any trigger toast
cy.deleteTable("Table1", "mysql");
});
});
};
/**
* @copyright Copyright (c) 2021, Xgene Cloud Ltd
*
* @author Pranav C Balan <pranavxc@gmail.com>
* @author Raju Udava <sivadstala@gmail.com>
*
* @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 <http://www.gnu.org/licenses/>.
*
*/

106
scripts/cypress/integration/common/2a_table_with_belongs_to_colulmn.js

@ -1,60 +1,72 @@
import { isTestSuiteActive } from "../../support/page_objects/projectConstants";
export const genTest = (type, xcdb) => {
if (!isTestSuiteActive(type, xcdb)) return;
export const genTest = (apiType, dbType) => {
if (!isTestSuiteActive(apiType, dbType)) return;
describe(`${type.toUpperCase()} api - Table: belongs to, link record`, () => {
before(() => {
cy.openTableTab("Country", 25);
});
describe(`${apiType.toUpperCase()} api - Table: belongs to, link record`, () => {
before(() => {
cy.openTableTab("Country", 25);
});
after(() => {
cy.closeTableTab("Country");
});
after(() => {
cy.closeTableTab("Country");
});
it("Table column header, URL validation", () => {
// column name validation
cy.get(`.project-tab:contains(Country):visible`).should("exist");
// URL validation
cy.url().should("contain", `name=Country`);
});
it("Table column header, URL validation", () => {
// column name validation
cy.get(`.project-tab:contains(Country):visible`).should("exist");
// URL validation
cy.url().should("contain", `name=Country`);
});
it("Expand belongs-to column", () => {
// expand first row
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();
});
it("Expand belongs-to column", () => {
// expand first row
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.snipActiveModal("Modal_BelongsTo");
});
it("Expand Link record, validate", () => {
cy.getActiveModal()
.find("button:contains(Link to 'City')")
.click()
.then(() => {
cy.snipActiveModal("Modal_BT_LinkRecord");
it("Expand Link record, validate", () => {
cy.getActiveModal()
.find("button:contains(Link to 'City')")
.click()
.then(() => {
// Link record form validation
cy.getActiveModal().contains("Link Record").should("exist");
cy.getActiveModal().find("button.mdi-reload").should("exist");
cy.getActiveModal()
.find('button:contains("New Record")')
.should("exist");
cy.getActiveModal()
.find(".child-card")
.eq(0)
.contains("A Corua (La Corua)")
.should("exist");
// Link record form validation
cy.getActiveModal().contains("Link Record").should("exist");
cy.getActiveModal()
.find("button.mdi-reload")
.should("exist");
cy.getActiveModal()
.find('button:contains("New Record")')
.should("exist");
cy.getActiveModal()
.find(".child-card")
.eq(0)
.contains("A Corua (La Corua)")
.should("exist");
cy.getActiveModal()
.find("button.mdi-close")
.click()
.then(() => {
cy.getActiveModal().find("button.mdi-close").click();
});
cy.getActiveModal()
.find("button.mdi-close")
.click()
.then(() => {
cy.getActiveModal()
.find("button.mdi-close")
.click();
});
});
});
});
});
};
/**

153
scripts/cypress/integration/common/2b_table_with_m2m_column.js

@ -1,88 +1,97 @@
import { isTestSuiteActive } from "../../support/page_objects/projectConstants";
export const genTest = (type, xcdb) => {
if (!isTestSuiteActive(type, xcdb)) return;
export const genTest = (apiType, dbType) => {
if (!isTestSuiteActive(apiType, dbType)) return;
describe(`${type.toUpperCase()} api - M2M Column validation`, () => {
before(() => {
cy.openTableTab("Actor", 25);
});
describe(`${apiType.toUpperCase()} api - M2M Column validation`, () => {
before(() => {
cy.openTableTab("Actor", 25);
});
after(() => {
cy.closeTableTab("Actor");
});
after(() => {
cy.closeTableTab("Actor");
});
it("Table column header, URL validation", () => {
// column name validation
cy.get(`.project-tab:contains(Actor):visible`).should("exist");
// URL validation
cy.url().should("contain", `name=Actor`);
});
it("Table column header, URL validation", () => {
// column name validation
cy.get(`.project-tab:contains(Actor):visible`).should("exist");
// URL validation
cy.url().should("contain", `name=Actor`);
});
it("Expand m2m column", () => {
// expand first row
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 });
it("Expand m2m column", () => {
// expand first row
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 });
// validations
cy.getActiveModal().contains("Film").should("exist");
cy.getActiveModal().find("button.mdi-reload").should("exist");
cy.getActiveModal()
.find("button:contains(Link to 'Film')")
.should("exist");
cy.getActiveModal()
.find(".child-card")
.eq(0)
.contains("ACADEMY DINOSAUR")
.should("exist");
});
cy.snipActiveModal("Modal_ManyToMany");
it('Expand "Link to" record, validate', () => {
cy.getActiveModal()
.find("button:contains(Link to 'Film')")
.click()
.then(() => {
// Link record form validation
cy.getActiveModal().contains("Link Record").should("exist");
cy.getActiveModal().find("button.mdi-reload").should("exist");
cy.getActiveModal()
.find('button:contains("New Record")')
.should("exist");
cy.getActiveModal()
.find(".child-card")
.eq(0)
.contains("ACE GOLDFINGER")
.should("exist");
cy.get("body").type("{esc}");
// validations
cy.getActiveModal().contains("Film").should("exist");
cy.getActiveModal().find("button.mdi-reload").should("exist");
cy.getActiveModal()
.find("button:contains(Link to 'Film')")
.should("exist");
cy.getActiveModal()
.find(".child-card")
.eq(0)
.contains("ACADEMY DINOSAUR")
.should("exist");
});
it('Expand "Link to" record, validate', () => {
cy.getActiveModal()
.find("button:contains(Link to 'Film')")
.click()
.then(() => {
cy.snipActiveModal("Modal_M2M_LinkToRecord");
// Link record form validation
cy.getActiveModal().contains("Link Record").should("exist");
cy.getActiveModal()
.find("button.mdi-reload")
.should("exist");
cy.getActiveModal()
.find('button:contains("New Record")')
.should("exist");
cy.getActiveModal()
.find(".child-card")
.eq(0)
.contains("ACE GOLDFINGER")
.should("exist");
cy.get("body").type("{esc}");
});
});
});
it("Expand first linked card, validate", () => {
cy.getActiveModal()
.find(".child-card")
.eq(0)
.contains("ACADEMY DINOSAUR", { timeout: 2000 })
.click()
.then(() => {
// Link card validation
cy.getActiveModal()
.find("h5")
.contains("ACADEMY DINOSAUR")
.should("exist");
cy.getActiveModal()
.find('button:contains("Save Row")')
.should("exist");
cy.getActiveModal().find('button:contains("Cancel")').should("exist");
it("Expand first linked card, validate", () => {
cy.getActiveModal()
.find(".child-card")
.eq(0)
.contains("ACADEMY DINOSAUR", { timeout: 2000 })
.click()
.then(() => {
// Link card validation
cy.getActiveModal()
.find("h5")
.contains("ACADEMY DINOSAUR")
.should("exist");
cy.getActiveModal()
.find('button:contains("Save Row")')
.should("exist");
cy.getActiveModal()
.find('button:contains("Cancel")')
.should("exist");
cy.getActiveModal().find('button:contains("Cancel")').click();
cy.getActiveModal().find("button.mdi-close").click();
cy.getActiveModal()
.find('button:contains("Cancel")')
.click();
cy.getActiveModal().find("button.mdi-close").click();
});
});
});
});
};
/**

421
scripts/cypress/integration/common/3a_filter_sort_fields_operations.js

@ -1,213 +1,222 @@
import { mainPage } from "../../support/page_objects/mainPage";
import { isTestSuiteActive } from "../../support/page_objects/projectConstants";
export const genTest = (type, xcdb) => {
if (!isTestSuiteActive(type, xcdb)) return;
describe(`${type.toUpperCase()} api - Filter, Fields, Sort`, () => {
before(() => {
// open country table
cy.openTableTab("Country", 25);
});
after(() => {
cy.closeTableTab("Country");
});
describe(`Pagination`, () => {
// check pagination
it("Check country table - Pagination", () => {
cy.get(".nc-pagination").should("exist");
// verify > pagination option
mainPage.getPagination(">").click();
mainPage
.getPagination(2)
.should("have.class", "v-pagination__item--active");
// verify < pagination option
mainPage.getPagination("<").click();
mainPage
.getPagination(1)
.should("have.class", "v-pagination__item--active");
});
});
describe(`Row operations`, () => {
// create new row using + button in header
//
it("Add row using tool header button", () => {
// add a row to end of Country table
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();
cy.toastWait("updated successfully");
// verify
mainPage.getPagination(5).click();
mainPage
.getCell("Country", 10)
.contains("Test Country")
.should("exist");
});
// delete slingle row
//
it("Delete row", () => {
// delete row added in previous step
mainPage.getCell("Country", 10).rightclick();
cy.getActiveMenu().contains("Delete Row").click();
// cy.toastWait('Deleted row successfully')
// verify
mainPage.getCell("Country", 10).should("not.exist");
});
// create new row using right click menu option
//
it("Add row using rightclick menu option", () => {
mainPage.getCell("Country", 9).rightclick({ force: true });
cy.getActiveMenu().contains("Insert New Row").click({ force: true });
mainPage
.getCell("Country", 10)
.dblclick()
.find("input")
.type("Test Country-1{enter}");
// cy.toastWait('saved successfully')
mainPage.getCell("Country", 10).rightclick({ force: true });
cy.getActiveMenu().contains("Insert New Row").click({ force: true });
mainPage
.getCell("Country", 11)
.dblclick()
.find("input")
.type("Test Country-2{enter}");
// cy.toastWait('saved successfully')
// verify
mainPage
.getCell("Country", 10)
.contains("Test Country-1")
.should("exist");
mainPage
.getCell("Country", 11)
.contains("Test Country-2")
.should("exist");
});
// delete selected rows (multiple)
//
it("Delete Selected", () => {
mainPage
.getRow(10)
.find(".mdi-checkbox-blank-outline")
.click({ force: true });
mainPage
.getRow(11)
.find(".mdi-checkbox-blank-outline")
.click({ force: true });
mainPage.getCell("Country", 10).rightclick({ force: true });
cy.getActiveMenu()
.contains("Delete Selected Row")
.click({ force: true });
// cy.toastWait('Deleted 2 selected rows successfully')
// verify
mainPage.getCell("Country", 10).should("not.exist");
mainPage.getCell("Country", 11).should("not.exist");
mainPage.getPagination(1).click();
});
});
describe(`Sort operations`, () => {
it("Enable sort", () => {
mainPage.sortField('Country', "Z -> A")
// Sort menu operations (Country Column, Z->A)
// 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");
});
it("Disable sort", () => {
// remove sort and validate
// cy.get(".nc-sort-item-remove-btn").click();
mainPage.clearSort();
cy.contains("Zambia").should("not.exist");
});
});
describe("Field Operation", () => {
it("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(".nc-fields-menu-btn").click();
mainPage.hideField('LastUpdate')
cy.get("th:contains(LastUpdate)").should("not.be.visible");
});
it("Show field", () => {
// cy.get(".nc-fields-menu-btn").click();
// cy.get(
// ".menuable__content__active .v-list-item label:contains(LastUpdate)"
// ).click();
// cy.get(".nc-fields-menu-btn").click();
mainPage.unhideField('LastUpdate')
cy.get("th:contains(LastUpdate)").should("be.visible");
});
});
describe("Filter operations", () => {
it("Create Filter", () => {
mainPage.filterField('Country', 'is equal', 'India');
cy.get("td:contains(India)").should("exist");
// cy.get(".nc-filter-menu-btn").click();
// cy.contains("Add Filter").click();
// cy.get(".nc-filter-field-select").last().click();
// cy.getActiveMenu().find(".v-list-item:contains(Country)").click();
// cy.get(".nc-filter-operation-select").last().click();
// cy.getActiveMenu().find('.v-list-item:contains("is equal")').click();
// cy.get(".nc-filter-value-select input:text").last().type("India");
// cy.get(".nc-filter-menu-btn")
// .click()
// .then(() => {
// cy.get("td:contains(India)").should("exist");
// });
});
it("Delete Filter", () => {
// remove sort and check
mainPage.filterReset();
// cy.get(".nc-filter-menu-btn").click();
// cy.get(".nc-filter-item-remove-btn").click();
// cy.get(".nc-filter-menu-btn").click();
cy.contains("td:contains(India)").should("not.exist");
});
export const genTest = (apiType, dbType) => {
if (!isTestSuiteActive(apiType, dbType)) return;
describe(`${apiType.toUpperCase()} api - Filter, Fields, Sort`, () => {
before(() => {
// open country table
cy.openTableTab("Country", 25);
});
after(() => {
cy.closeTableTab("Country");
});
describe(`Pagination`, () => {
// check pagination
it("Check country table - Pagination", () => {
cy.get(".nc-pagination").should("exist");
// verify > pagination option
mainPage.getPagination(">").click();
mainPage
.getPagination(2)
.should("have.class", "v-pagination__item--active");
// verify < pagination option
mainPage.getPagination("<").click();
mainPage
.getPagination(1)
.should("have.class", "v-pagination__item--active");
});
});
describe(`Row operations`, () => {
// create new row using + button in header
//
it("Add row using tool header button", () => {
// add a row to end of Country table
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();
cy.toastWait("updated successfully");
// verify
mainPage.getPagination(5).click();
mainPage
.getCell("Country", 10)
.contains("Test Country")
.should("exist");
});
// delete slingle row
//
it("Delete row", () => {
// delete row added in previous step
mainPage.getCell("Country", 10).rightclick();
cy.getActiveMenu().contains("Delete Row").click();
// cy.toastWait('Deleted row successfully')
// verify
mainPage.getCell("Country", 10).should("not.exist");
});
// create new row using right click menu option
//
it("Add row using rightclick menu option", () => {
mainPage.getCell("Country", 9).rightclick({ force: true });
cy.snipActiveMenu("Menu_GridRightClick");
cy.getActiveMenu()
.contains("Insert New Row")
.click({ force: true });
mainPage
.getCell("Country", 10)
.dblclick()
.find("input")
.type("Test Country-1{enter}");
// cy.toastWait('saved successfully')
mainPage.getCell("Country", 10).rightclick({ force: true });
cy.getActiveMenu()
.contains("Insert New Row")
.click({ force: true });
mainPage
.getCell("Country", 11)
.dblclick()
.find("input")
.type("Test Country-2{enter}");
// cy.toastWait('saved successfully')
// verify
mainPage
.getCell("Country", 10)
.contains("Test Country-1")
.should("exist");
mainPage
.getCell("Country", 11)
.contains("Test Country-2")
.should("exist");
});
// delete selected rows (multiple)
//
it("Delete Selected", () => {
mainPage
.getRow(10)
.find(".mdi-checkbox-blank-outline")
.click({ force: true });
mainPage
.getRow(11)
.find(".mdi-checkbox-blank-outline")
.click({ force: true });
mainPage.getCell("Country", 10).rightclick({ force: true });
cy.getActiveMenu()
.contains("Delete Selected Row")
.click({ force: true });
// cy.toastWait('Deleted 2 selected rows successfully')
// verify
mainPage.getCell("Country", 10).should("not.exist");
mainPage.getCell("Country", 11).should("not.exist");
mainPage.getPagination(1).click();
});
});
describe(`Sort operations`, () => {
it("Enable sort", () => {
mainPage.sortField("Country", "Z -> A");
// Sort menu operations (Country Column, Z->A)
// 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");
});
it("Disable sort", () => {
// remove sort and validate
// cy.get(".nc-sort-item-remove-btn").click();
mainPage.clearSort();
cy.contains("Zambia").should("not.exist");
});
});
describe("Field Operation", () => {
it("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(".nc-fields-menu-btn").click();
mainPage.hideField("LastUpdate");
cy.get("th:contains(LastUpdate)").should("not.be.visible");
});
it("Show field", () => {
// cy.get(".nc-fields-menu-btn").click();
// cy.get(
// ".menuable__content__active .v-list-item label:contains(LastUpdate)"
// ).click();
// cy.get(".nc-fields-menu-btn").click();
mainPage.unhideField("LastUpdate");
cy.get("th:contains(LastUpdate)").should("be.visible");
});
});
describe("Filter operations", () => {
it("Create Filter", () => {
mainPage.filterField("Country", "is equal", "India");
cy.get("td:contains(India)").should("exist");
// cy.get(".nc-filter-menu-btn").click();
// cy.contains("Add Filter").click();
// cy.get(".nc-filter-field-select").last().click();
// cy.getActiveMenu().find(".v-list-item:contains(Country)").click();
// cy.get(".nc-filter-operation-select").last().click();
// cy.getActiveMenu().find('.v-list-item:contains("is equal")').click();
// cy.get(".nc-filter-value-select input:text").last().type("India");
// cy.get(".nc-filter-menu-btn")
// .click()
// .then(() => {
// cy.get("td:contains(India)").should("exist");
// });
});
it("Delete Filter", () => {
// remove sort and check
mainPage.filterReset();
// cy.get(".nc-filter-menu-btn").click();
// cy.get(".nc-filter-item-remove-btn").click();
// cy.get(".nc-filter-menu-btn").click();
cy.contains("td:contains(India)").should("not.exist");
});
});
});
});
};
/**

440
scripts/cypress/integration/common/3b_formula_column.js

@ -1,221 +1,233 @@
import {
isTestSuiteActive,
isXcdb,
isTestSuiteActive,
isXcdb,
} from "../../support/page_objects/projectConstants";
export const genTest = (type, xcdb) => {
if (!isTestSuiteActive(type, xcdb)) return;
describe(`${type.toUpperCase()} api - FORMULA`, () => {
// Run once before test- create project (rest/graphql)
//
before(() => {
// open a table to work on views
//
cy.openTableTab("City", 25);
});
after(() => {
cy.closeTableTab("City");
});
// Given rowname & expected result for first 10 entries, validate
// NOTE: Scroll issue with Cypress automation, to fix
// validating partial data, row number 5 to 9
//
const rowValidation = (rowName, result) => {
// scroll back
cy.get(`tbody > :nth-child(1) > [data-col="City"]`).scrollIntoView();
// for (let i = 0; i < 10; i++)
for (let i = 3; i < 6; i++)
cy.get(`tbody > :nth-child(${i + 1}) > [data-col="${rowName}"]`)
.contains(result[i].toString())
.should("exist");
};
// Routine to create a new look up column
//
const addFormulaBasedColumn = (columnName, formula) => {
// (+) icon at end of column header (to add a new column)
// opens up a pop up window
//
cy.get(".new-column-header").click();
// Column name
cy.get(".nc-column-name-input input")
.clear()
.type(`${columnName}`);
// Column data type: to be set to formula in this context
cy.get(".nc-ui-dt-dropdown").click().type("Formula");
cy.getActiveMenu().contains("Formula").click({ force: true });
// Configure formula
cy.get("label").contains("Formula").parent().click().type(formula).click();
// click on Save
cy.get(".nc-col-create-or-edit-card").contains("Save").click({ force: true });
cy.toastWait("Formula column saved successfully");
// Verify if column exists.
//
cy.get(`th:contains(${columnName})`).should("exist");
};
// routine to delete column
//
const deleteColumnByName = (columnName) => {
// verify if column exists before delete
cy.get(`th:contains(${columnName})`).should("exist");
// delete opiton visible on mouse-over
cy.get(`th:contains(${columnName}) .mdi-menu-down`)
.trigger("mouseover")
.click();
// delete/ confirm on pop-up
cy.get(".nc-column-delete").click();
cy.getActiveModal().find("button:contains(Confirm)").click();
// validate if deleted (column shouldnt exist)
cy.get(`th:contains(${columnName})`).should("not.exist");
};
// routine to edit column
//
const editColumnByName = (oldName, newName, newFormula) => {
// verify if column exists before delete
cy.get(`th:contains(${oldName})`).should("exist");
// delete opiton visible on mouse-over
cy.get(`th:contains(${oldName}) .mdi-menu-down`)
.trigger("mouseover")
.click();
// edit/ save on pop-up
cy.get(".nc-column-edit").click();
cy.get(".nc-column-name-input input").clear().type(newName);
cy.get("label")
.contains("Formula")
.parent()
.find("input")
.clear()
.type(newFormula)
.click();
cy.get(".nc-col-create-or-edit-card").contains("Save").click({force: true});
cy.toastWait("Formula column updated successfully");
// validate if deleted (column shouldnt exist)
cy.get(`th:contains(${oldName})`).should("not.exist");
cy.get(`th:contains(${newName})`).should("exist");
};
///////////////////////////////////////////////////
// Test case
// On City table (from Sakila DB), first 10 entries recorded here for verification
let cityId = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let countryId = [87, 82, 101, 60, 97, 31, 107, 44, 44, 50];
let city = [
"A corua (La Corua)",
"Abha",
"Abu Dhabi",
"Acua",
"Adana",
"Addis Abeba",
"Aden",
"Adoni",
"Ahmadnagar",
"Akishima",
];
// Temporary locally computed expected results
let RESULT_STRING = [];
let RESULT_MATH_0 = [];
let RESULT_MATH_1 = [];
let RESULT_MATH_2 = [];
for (let i = 0; i < 10; i++) {
// CONCAT, LOWER, UPPER, TRIM
RESULT_STRING[i] = `${city[i].toUpperCase()}${city[
i
].toLowerCase()}trimmed`;
// ADD, AVG, LEN
RESULT_MATH_0[i] =
cityId[i] +
countryId[i] +
(cityId[i] + countryId[i]) / 2 +
city[i].length;
// CEILING, FLOOR, ROUND, MOD, MIN, MAX
RESULT_MATH_1[i] =
Math.ceil(1.4) +
Math.floor(1.6) +
Math.round(2.5) +
(cityId[i] % 3) +
Math.min(cityId[i], countryId[i]) +
Math.max(cityId[i], countryId[i]);
// LOG, EXP, POWER, SQRT
// only integer verification being computed, hence trunc
RESULT_MATH_2[i] = Math.trunc(
Math.log(cityId[i]) +
Math.exp(cityId[i]) +
Math.pow(cityId[i], 3) +
Math.sqrt(countryId[i])
);
}
it("Formula: CONCAT, LOWER, UPPER, TRIM", () => {
addFormulaBasedColumn(
"NC_MATH_0",
"ADD(CityId, CountryId) + AVG(CityId, CountryId) + LEN(City)"
);
rowValidation("NC_MATH_0", RESULT_MATH_0);
});
it("Formula: ADD, AVG, LEN", () => {
editColumnByName(
"NC_MATH_0",
"NC_STR_1",
`CONCAT(UPPER(City), LOWER(City), TRIM(' trimmed '))`
);
rowValidation("NC_STR_1", RESULT_STRING);
});
it("Formula: CEILING, FLOOR, ROUND, MOD, MIN, MAX", () => {
editColumnByName(
"NC_STR_1",
"NC_MATH_1",
`CEILING(1.4) + FLOOR(1.6) + ROUND(2.5) + MOD(CityId, 3) + MIN(CityId, CountryId) + MAX(CityId, CountryId)`
);
rowValidation("NC_MATH_1", RESULT_MATH_1);
});
it("Formula: LOG, EXP, POWER, SQRT", () => {
if (!isXcdb()) {
// SQLITE doesnt support LOG, EXP, POWER SQRT construct
editColumnByName(
"NC_MATH_1",
"NC_MATH_2",
`LOG(CityId) + EXP(CityId) + POWER(CityId, 3) + SQRT(CountryId)`
);
rowValidation("NC_MATH_2", RESULT_MATH_2);
}
});
it("Formula: NOW, EDIT & Delete column", () => {
if (!isXcdb()) editColumnByName("NC_MATH_2", "NC_NOW", `NOW()`);
else editColumnByName("NC_MATH_1", "NC_NOW", `NOW()`);
deleteColumnByName("NC_NOW");
export const genTest = (apiType, dbType) => {
if (!isTestSuiteActive(apiType, dbType)) return;
describe(`${apiType.toUpperCase()} api - FORMULA`, () => {
// Run once before test- create project (rest/graphql)
//
before(() => {
// open a table to work on views
//
cy.openTableTab("City", 25);
});
after(() => {
cy.closeTableTab("City");
});
// Given rowname & expected result for first 10 entries, validate
// NOTE: Scroll issue with Cypress automation, to fix
// validating partial data, row number 5 to 9
//
const rowValidation = (rowName, result) => {
// scroll back
cy.get(
`tbody > :nth-child(1) > [data-col="City"]`
).scrollIntoView();
// for (let i = 0; i < 10; i++)
for (let i = 3; i < 6; i++)
cy.get(`tbody > :nth-child(${i + 1}) > [data-col="${rowName}"]`)
.contains(result[i].toString())
.should("exist");
};
// Routine to create a new look up column
//
const addFormulaBasedColumn = (columnName, formula) => {
// (+) icon at end of column header (to add a new column)
// opens up a pop up window
//
cy.get(".new-column-header").click();
// Column name
cy.get(".nc-column-name-input input").clear().type(`${columnName}`);
// Column data type: to be set to formula in this context
cy.get(".nc-ui-dt-dropdown").click().type("Formula");
cy.snipActiveMenu("Formula");
cy.getActiveMenu().contains("Formula").click({ force: true });
// Configure formula
cy.get("label")
.contains("Formula")
.parent()
.click()
.type(formula)
.click();
// click on Save
cy.get(".nc-col-create-or-edit-card")
.contains("Save")
.click({ force: true });
cy.toastWait("Formula column saved successfully");
// Verify if column exists.
//
cy.get(`th:contains(${columnName})`).should("exist");
};
// routine to delete column
//
const deleteColumnByName = (columnName) => {
// verify if column exists before delete
cy.get(`th:contains(${columnName})`).should("exist");
// delete opiton visible on mouse-over
cy.get(`th:contains(${columnName}) .mdi-menu-down`)
.trigger("mouseover")
.click();
// delete/ confirm on pop-up
cy.get(".nc-column-delete").click();
cy.getActiveModal().find("button:contains(Confirm)").click();
// validate if deleted (column shouldnt exist)
cy.get(`th:contains(${columnName})`).should("not.exist");
};
// routine to edit column
//
const editColumnByName = (oldName, newName, newFormula) => {
// verify if column exists before delete
cy.get(`th:contains(${oldName})`).should("exist");
// delete opiton visible on mouse-over
cy.get(`th:contains(${oldName}) .mdi-menu-down`)
.trigger("mouseover")
.click();
// edit/ save on pop-up
cy.get(".nc-column-edit").click();
cy.get(".nc-column-name-input input").clear().type(newName);
cy.get("label")
.contains("Formula")
.parent()
.find("input")
.clear()
.type(newFormula)
.click();
cy.get(".nc-col-create-or-edit-card")
.contains("Save")
.click({ force: true });
cy.toastWait("Formula column updated successfully");
// validate if deleted (column shouldnt exist)
cy.get(`th:contains(${oldName})`).should("not.exist");
cy.get(`th:contains(${newName})`).should("exist");
};
///////////////////////////////////////////////////
// Test case
// On City table (from Sakila DB), first 10 entries recorded here for verification
let cityId = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let countryId = [87, 82, 101, 60, 97, 31, 107, 44, 44, 50];
let city = [
"A corua (La Corua)",
"Abha",
"Abu Dhabi",
"Acua",
"Adana",
"Addis Abeba",
"Aden",
"Adoni",
"Ahmadnagar",
"Akishima",
];
// Temporary locally computed expected results
let RESULT_STRING = [];
let RESULT_MATH_0 = [];
let RESULT_MATH_1 = [];
let RESULT_MATH_2 = [];
for (let i = 0; i < 10; i++) {
// CONCAT, LOWER, UPPER, TRIM
RESULT_STRING[i] = `${city[i].toUpperCase()}${city[
i
].toLowerCase()}trimmed`;
// ADD, AVG, LEN
RESULT_MATH_0[i] =
cityId[i] +
countryId[i] +
(cityId[i] + countryId[i]) / 2 +
city[i].length;
// CEILING, FLOOR, ROUND, MOD, MIN, MAX
RESULT_MATH_1[i] =
Math.ceil(1.4) +
Math.floor(1.6) +
Math.round(2.5) +
(cityId[i] % 3) +
Math.min(cityId[i], countryId[i]) +
Math.max(cityId[i], countryId[i]);
// LOG, EXP, POWER, SQRT
// only integer verification being computed, hence trunc
RESULT_MATH_2[i] = Math.trunc(
Math.log(cityId[i]) +
Math.exp(cityId[i]) +
Math.pow(cityId[i], 3) +
Math.sqrt(countryId[i])
);
}
it("Formula: ADD, AVG, LEN", () => {
addFormulaBasedColumn(
"NC_MATH_0",
"ADD(CityId, CountryId) + AVG(CityId, CountryId) + LEN(City)"
);
rowValidation("NC_MATH_0", RESULT_MATH_0);
});
it("Formula: CONCAT, LOWER, UPPER, TRIM", () => {
editColumnByName(
"NC_MATH_0",
"NC_STR_1",
`CONCAT(UPPER(City), LOWER(City), TRIM(' trimmed '))`
);
rowValidation("NC_STR_1", RESULT_STRING);
});
it("Formula: CEILING, FLOOR, ROUND, MOD, MIN, MAX", () => {
editColumnByName(
"NC_STR_1",
"NC_MATH_1",
`CEILING(1.4) + FLOOR(1.6) + ROUND(2.5) + MOD(CityId, 3) + MIN(CityId, CountryId) + MAX(CityId, CountryId)`
);
rowValidation("NC_MATH_1", RESULT_MATH_1);
});
it("Formula: LOG, EXP, POWER, SQRT", () => {
if (!isXcdb()) {
// SQLITE doesnt support LOG, EXP, POWER SQRT construct
editColumnByName(
"NC_MATH_1",
"NC_MATH_2",
`LOG(CityId) + EXP(CityId) + POWER(CityId, 3) + SQRT(CountryId)`
);
rowValidation("NC_MATH_2", RESULT_MATH_2);
}
});
it("Formula: NOW, EDIT & Delete column", () => {
if (!isXcdb()) editColumnByName("NC_MATH_2", "NC_NOW", `NOW()`);
else editColumnByName("NC_MATH_1", "NC_NOW", `NOW()`);
deleteColumnByName("NC_NOW");
});
});
});
};
/**

192
scripts/cypress/integration/common/3c_lookup_column.js

@ -1,101 +1,103 @@
import { isTestSuiteActive } from "../../support/page_objects/projectConstants";
export const genTest = (type, xcdb) => {
if (!isTestSuiteActive(type, xcdb)) return;
describe(`${type.toUpperCase()} api - LookUp column`, () => {
// to retrieve few v-input nodes from their label
//
const fetchParentFromLabel = (label) => {
cy.get("label").contains(label).parents(".v-input").click();
};
// Run once before test- create project (rest/graphql)
//
before(() => {
// open a table to work on views
//
cy.openTableTab("City", 25);
export const genTest = (apiType, dbType) => {
if (!isTestSuiteActive(apiType, dbType)) return;
describe(`${apiType.toUpperCase()} api - LookUp column`, () => {
// to retrieve few v-input nodes from their label
//
const fetchParentFromLabel = (label) => {
cy.get("label").contains(label).parents(".v-input").click();
};
// Run once before test- create project (rest/graphql)
//
before(() => {
// open a table to work on views
//
cy.openTableTab("City", 25);
});
after(() => {
cy.closeTableTab("City");
});
// Routine to create a new look up column
//
const addLookUpColumn = (childTable, childCol) => {
// (+) icon at end of column header (to add a new column)
// opens up a pop up window
//
cy.get(".new-column-header").click();
// Redundant to feed column name. as alias is displayed & referred for
cy.get(".nc-column-name-input input").clear().type(childCol);
// Column data type: to be set to lookup in this context
cy.get(".nc-ui-dt-dropdown").click();
cy.getActiveMenu().contains("Lookup").click();
// Configure Child table & column names
fetchParentFromLabel("Child Table");
cy.getActiveMenu().contains(childTable).click();
fetchParentFromLabel("Child column");
cy.getActiveMenu().contains(childCol).click();
cy.snipActiveMenu("LookUp");
// click on Save
cy.get(".nc-col-create-or-edit-card").contains("Save").click();
// Verify if column exists.
//
cy.get(`th:contains(${childCol})`).should("exist");
};
// routine to delete column
//
const deleteColumnByName = (childCol) => {
// verify if column exists before delete
cy.get(`th:contains(${childCol})`).should("exist");
// delete opiton visible on mouse-over
cy.get(`th:contains(${childCol}) .mdi-menu-down`)
.trigger("mouseover")
.click();
// delete/ confirm on pop-up
cy.get(".nc-column-delete").click();
cy.getActiveModal().find("button:contains(Confirm)").click();
// validate if deleted (column shouldnt exist)
cy.get(`th:contains(${childCol})`).should("not.exist");
};
///////////////////////////////////////////////////
// Test case
it("Add Lookup column (Address, PostalCode) & Delete", () => {
addLookUpColumn("Address", "PostalCode");
// Verify first entry, will be displayed as alias here 'childColumn (from childTable)'
cy.get(`tbody > :nth-child(1) > [data-col="PostalCode"]`)
.contains("4166")
.should("exist");
deleteColumnByName("PostalCode");
});
it.skip("Add Lookup column (Country, CountryId) & Delete", () => {
addLookUpColumn("Country", "CountryId");
// Verify first entry, will be displayed as alias here 'childColumn (from childTable)'
cy.get(`tbody > :nth-child(1) > [data-col="CountryId"]`)
.contains("87")
.should("exist");
deleteColumnByName("CountryId");
});
});
after(() => {
cy.closeTableTab("City");
});
// Routine to create a new look up column
//
const addLookUpColumn = (childTable, childCol) => {
// (+) icon at end of column header (to add a new column)
// opens up a pop up window
//
cy.get(".new-column-header").click();
// Redundant to feed column name. as alias is displayed & referred for
cy.get(".nc-column-name-input input").clear().type(childCol);
// Column data type: to be set to lookup in this context
cy.get(".nc-ui-dt-dropdown").click();
cy.getActiveMenu().contains("Lookup").click();
// Configure Child table & column names
fetchParentFromLabel("Child Table");
cy.getActiveMenu().contains(childTable).click();
fetchParentFromLabel("Child column");
cy.getActiveMenu().contains(childCol).click();
// click on Save
cy.get(".nc-col-create-or-edit-card").contains("Save").click();
// Verify if column exists.
//
cy.get(`th:contains(${childCol})`).should("exist");
};
// routine to delete column
//
const deleteColumnByName = (childCol) => {
// verify if column exists before delete
cy.get(`th:contains(${childCol})`).should("exist");
// delete opiton visible on mouse-over
cy.get(`th:contains(${childCol}) .mdi-menu-down`)
.trigger("mouseover")
.click();
// delete/ confirm on pop-up
cy.get(".nc-column-delete").click();
cy.getActiveModal().find("button:contains(Confirm)").click();
// validate if deleted (column shouldnt exist)
cy.get(`th:contains(${childCol})`).should("not.exist");
};
///////////////////////////////////////////////////
// Test case
it("Add Lookup column (Address, District) & Delete", () => {
addLookUpColumn("Address", "District");
// Verify first entry, will be displayed as alias here 'childColumn (from childTable)'
cy.get(`tbody > :nth-child(1) > [data-col="District"]`)
.contains("Galicia")
.should("exist");
deleteColumnByName("District");
});
it.skip("Add Lookup column (Country, CountryId) & Delete", () => {
addLookUpColumn("Country", "CountryId");
// Verify first entry, will be displayed as alias here 'childColumn (from childTable)'
cy.get(`tbody > :nth-child(1) > [data-col="CountryId"]`)
.contains("87")
.should("exist");
deleteColumnByName("CountryId");
});
});
};
// genTest('rest', false)

8
scripts/cypress/integration/common/3d_rollup_column.js

@ -1,9 +1,9 @@
import { isTestSuiteActive } from "../../support/page_objects/projectConstants";
export const genTest = (type, xcdb) => {
if (!isTestSuiteActive(type, xcdb)) return;
export const genTest = (apiType, dbType) => {
if (!isTestSuiteActive(apiType, dbType)) return;
describe(`${type.toUpperCase()} api - RollUp column`, () => {
describe(`${apiType.toUpperCase()} api - RollUp column`, () => {
// to retrieve few v-input nodes from their label
//
const fetchParentFromLabel = (label) => {
@ -55,6 +55,8 @@ export const genTest = (type, xcdb) => {
fetchParentFromLabel("Aggregate function");
cy.getActiveMenu().contains(aggregateFunc).click();
cy.snipActiveMenu("RollUp");
// click on Save
cy.get(".nc-col-create-or-edit-card").contains("Save").click();

143
scripts/cypress/integration/common/4a_table_view_grid_gallery_form.js

@ -1,76 +1,81 @@
import { isTestSuiteActive } from "../../support/page_objects/projectConstants";
export const genTest = (type, xcdb) => {
if (!isTestSuiteActive(type, xcdb)) return;
describe(`${type.toUpperCase()} api - Table views: Create/Edit/Delete`, () => {
const name = "Test" + Date.now();
// Run once before test- create project (rest/graphql)
//
before(() => {
// open a table to work on views
//
cy.openTableTab("Country", 25);
});
export const genTest = (apiType, dbType) => {
if (!isTestSuiteActive(apiType, dbType)) return;
after(() => {
cy.closeTableTab("Country");
});
describe(`${apiType.toUpperCase()} api - Table views: Create/Edit/Delete`, () => {
const name = "Test" + Date.now();
// Run once before test- create project (rest/graphql)
//
before(() => {
// open a table to work on views
//
cy.openTableTab("Country", 25);
});
after(() => {
cy.closeTableTab("Country");
});
// Common routine to create/edit/delete GRID & GALLERY view
// Input: viewType - 'grid'/'gallery'
//
const viewTest = (viewType) => {
it(`Create ${viewType} view`, () => {
// click on 'Grid/Gallery' button on Views bar
cy.get(`.nc-create-${viewType}-view`).click();
// Pop up window, click Submit (accepting default name for view)
cy.getActiveModal().find("button:contains(Submit)").click();
cy.toastWait("View created successfully");
// validate if view was creted && contains default name 'Country1'
cy.get(`.nc-view-item.nc-${viewType}-view-item`)
.contains("Country1")
.should("exist");
cy.snip(`View_${viewType}`);
});
// Common routine to create/edit/delete GRID & GALLERY view
// Input: viewType - 'grid'/'gallery'
//
const viewTest = (viewType) => {
it(`Create ${viewType} view`, () => {
// click on 'Grid/Gallery' button on Views bar
cy.get(`.nc-create-${viewType}-view`).click();
// Pop up window, click Submit (accepting default name for view)
cy.getActiveModal().find("button:contains(Submit)").click();
cy.toastWait("View created successfully");
// validate if view was creted && contains default name 'Country1'
cy.get(`.nc-view-item.nc-${viewType}-view-item`)
.contains("Country1")
.should("exist");
});
it(`Edit ${viewType} view name`, () => {
// click on edit-icon (becomes visible on hovering mouse)
cy.get(".nc-view-edit-icon").click({ force: true, timeout: 1000 });
// feed new name
cy.get(`.nc-${viewType}-view-item input`).type(
`${viewType}View-1{enter}`
);
cy.toastWait("View renamed successfully");
// validate
cy.get(`.nc-view-item.nc-${viewType}-view-item`)
.contains(`${viewType}View-1`)
.should("exist");
});
it(`Delete ${viewType} view`, () => {
// number of view entries should be 2 before we delete
cy.get(".nc-view-item").its("length").should("eq", 2);
// click on delete icon (becomes visible on hovering mouse)
cy.get(".nc-view-delete-icon").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 four scenario's will be invoked twice, once for rest & then for graphql
viewTest("grid");
viewTest("gallery");
viewTest("form");
// viewTest("kanban");
});
it(`Edit ${viewType} view name`, () => {
// click on edit-icon (becomes visible on hovering mouse)
cy.get(".nc-view-edit-icon").click({
force: true,
timeout: 1000,
});
// feed new name
cy.get(`.nc-${viewType}-view-item input`).type(
`${viewType}View-1{enter}`
);
cy.toastWait("View renamed successfully");
// validate
cy.get(`.nc-view-item.nc-${viewType}-view-item`)
.contains(`${viewType}View-1`)
.should("exist");
});
it(`Delete ${viewType} view`, () => {
// number of view entries should be 2 before we delete
cy.get(".nc-view-item").its("length").should("eq", 2);
// click on delete icon (becomes visible on hovering mouse)
cy.get(".nc-view-delete-icon").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 four scenario's will be invoked twice, once for rest & then for graphql
viewTest("grid");
viewTest("gallery");
viewTest("form");
// viewTest("kanban");
});
};
/**

11
scripts/cypress/integration/common/4b_table_view_share.js

@ -10,12 +10,17 @@ const generateLinkWithPwd = () => {
// .contains("Share View")
// .click();
mainPage.shareView().click();
cy.snipActiveModal("Modal_ShareView")
// enable checkbox & feed pwd, save
cy.getActiveModal()
.find('[role="switch"][type="checkbox"]')
.click({ force: true });
cy.getActiveModal().find('input[type="password"]').type("1");
cy.snipActiveModal("Modal_ShareView_Password");
cy.getActiveModal().find('button:contains("Save password")').click();
cy.toastWait("Successfully updated");
@ -29,10 +34,10 @@ const generateLinkWithPwd = () => {
});
};
export const genTest = (type, xcdb) => {
if (!isTestSuiteActive(type, xcdb)) return;
export const genTest = (apiType, dbType) => {
if (!isTestSuiteActive(apiType, dbType)) return;
describe(`${type.toUpperCase()} api - Shared VIEWs (GRID)`, () => {
describe(`${apiType.toUpperCase()} api - Shared VIEWs (GRID)`, () => {
// Run once before test- create project (rest/graphql)
//
before(() => {

6
scripts/cypress/integration/common/4c_form_view_detailed.js

@ -3,10 +3,10 @@ import { mainPage } from "../../support/page_objects/mainPage";
let formViewURL;
export const genTest = (type, xcdb) => {
if (!isTestSuiteActive(type, xcdb)) return;
export const genTest = (apiType, dbType) => {
if (!isTestSuiteActive(apiType, dbType)) return;
describe(`${type.toUpperCase()} api - FORM view`, () => {
describe(`${apiType.toUpperCase()} api - FORM view`, () => {
const name = "Test" + Date.now();
// Run once before test- create project (rest/graphql)

7
scripts/cypress/integration/common/4d_table_view_grid_locked.js

@ -1,10 +1,10 @@
import { isTestSuiteActive } from "../../support/page_objects/projectConstants";
import { mainPage } from "../../support/page_objects/mainPage";
export const genTest = (type, xcdb) => {
if (!isTestSuiteActive(type, xcdb)) return;
export const genTest = (apiType, dbType) => {
if (!isTestSuiteActive(apiType, dbType)) return;
describe(`${type.toUpperCase()} api - Lock view`, () => {
describe(`${apiType.toUpperCase()} api - Lock view`, () => {
// Run once before test- create project (rest/graphql)
//
before(() => {
@ -25,6 +25,7 @@ export const genTest = (type, xcdb) => {
// on menu, collaboration view appears first (at index 0)
// followed by Locked view (at index 1)
cy.get(".xc-toolbar").find(".nc-view-lock-menu:enabled").click();
cy.snipActiveMenu("Menu_Collaboration")
cy.getActiveMenu().find('[role="menuitem"]').eq(menuOption).click();
// expected toolbar for Lock view: Only lock-view menu, reload, toggle-nav-drawer to be enabled

391
scripts/cypress/integration/common/4e_form_view_share.js

@ -3,194 +3,223 @@ import { mainPage } from "../../support/page_objects/mainPage";
let storedURL = "";
export const genTest = (type, xcdb) => {
if (!isTestSuiteActive(type, xcdb)) return;
describe(`${type.toUpperCase()} api - FORM view (Share)`, () => {
const name = "Test" + Date.now();
// Run once before test- create project (rest/graphql)
//
before(() => {
// open a table to work on views
//
cy.openTableTab("City", 25);
});
beforeEach(() => {
cy.restoreLocalStorage();
});
export const genTest = (apiType, dbType) => {
if (!isTestSuiteActive(apiType, dbType)) return;
describe(`${apiType.toUpperCase()} api - FORM view (Share)`, () => {
const name = "Test" + Date.now();
// Run once before test- create project (rest/graphql)
//
before(() => {
// open a table to work on views
//
cy.openTableTab("City", 25);
});
afterEach(() => {
cy.saveLocalStorage();
});
beforeEach(() => {
cy.restoreLocalStorage();
});
after(() => {
cy.closeTableTab("City");
});
afterEach(() => {
cy.saveLocalStorage();
});
// Common routine to create/edit/delete GRID & GALLERY view
// Input: viewType - 'grid'/'gallery'
//
const viewTest = (viewType) => {
it(`Create ${viewType} view`, () => {
// click on 'Grid/Gallery' button on Views bar
cy.get(`.nc-create-${viewType}-view`).click();
// Pop up window, click Submit (accepting default name for view)
cy.getActiveModal().find("button:contains(Submit)").click();
cy.toastWait("View created successfully");
// Prepare form
// add header, description
// add post submission message
// swap position for City, LastUpdate fields
// remove City=>Address field
cy.get(".nc-form > .mx-auto").find('[type="checkbox"]').eq(1).click();
cy.get(".nc-form > .mx-auto")
.find('[type="checkbox"]')
.eq(1)
.should("be.checked");
cy.get(".nc-form").find('[placeholder="Form Title"]').type("A B C D");
cy.get(".nc-form")
.find('[placeholder="Add form description"]')
.type("Some description about form comes here");
cy.get(".nc-form > .mx-auto").find("textarea").type("Congratulations!");
cy.get("#data-table-form-City").drag("#data-table-form-LastUpdate");
cy.get('[title="City => Address"]').drag(".nc-drag-n-drop-to-hide");
cy.get(".nc-form > .mx-auto")
.find('[type="checkbox"]')
.eq(1)
.should("be.checked");
// store base URL- to re-visit and delete form view later
cy.url().then((url) => {
storedURL = url;
after(() => {
cy.closeTableTab("City");
});
});
it(`Share form view`, () => {
cy.get(".nc-form > .mx-auto")
.find('[type="checkbox"]')
.eq(1)
.should("be.checked");
cy.get(`.nc-view-item.nc-${viewType}-view-item`)
.contains("City1")
.click();
// cy.get(".v-navigation-drawer__content > .container")
// .find(".v-list > .v-list-item")
// .contains("Share View")
// .click();
mainPage.shareView().click();
// copy link text, visit URL
cy.getActiveModal()
.find(".share-link-box")
.contains("/nc/form/", { timeout: 10000 })
.then(($obj) => {
let linkText = $obj.text().trim();
cy.log(linkText);
cy.visit(linkText, {
baseUrl: null,
// Common routine to create/edit/delete GRID & GALLERY view
// Input: viewType - 'grid'/'gallery'
//
const viewTest = (viewType) => {
it(`Create ${viewType} view`, () => {
// click on 'Grid/Gallery' button on Views bar
cy.get(`.nc-create-${viewType}-view`).click();
// Pop up window, click Submit (accepting default name for view)
cy.getActiveModal().find("button:contains(Submit)").click();
cy.toastWait("View created successfully");
// Prepare form
// add header, description
// add post submission message
// swap position for City, LastUpdate fields
// remove City=>Address field
cy.get(".nc-form > .mx-auto")
.find('[type="checkbox"]')
.eq(1)
.click();
cy.get(".nc-form > .mx-auto")
.find('[type="checkbox"]')
.eq(1)
.should("be.checked");
cy.get(".nc-form")
.find('[placeholder="Form Title"]')
.type("A B C D");
cy.get(".nc-form")
.find('[placeholder="Add form description"]')
.type("Some description about form comes here");
cy.get(".nc-form > .mx-auto")
.find("textarea")
.type("Congratulations!");
cy.get("#data-table-form-City").drag(
"#data-table-form-LastUpdate"
);
cy.get('[title="City => Address"]').drag(
".nc-drag-n-drop-to-hide"
);
cy.get(".nc-form > .mx-auto")
.find('[type="checkbox"]')
.eq(1)
.should("be.checked");
// store base URL- to re-visit and delete form view later
cy.url().then((url) => {
storedURL = url;
});
});
// wait for share view page to load!
cy.get(".nc-form").should("exist");
// New form appeared? Header & description should exist
cy.get(".nc-form", { timeout: 10000 })
.find("h2")
.contains("A B C D")
.should("exist");
cy.get(".nc-form", { timeout: 10000 })
.find(".body-1")
.contains("Some description about form comes here")
.should("exist");
// all fields, barring removed field should exist
cy.get('[title="City"]').should("exist");
cy.get('[title="LastUpdate"]').should("exist");
cy.get('[title="Country <= City"]').should("exist");
cy.get('[title="City => Address"]').should("not.exist");
// order of LastUpdate & City field is retained
cy.get(".nc-field-wrapper")
.eq(0)
.contains("LastUpdate")
.should("exist");
cy.get(".nc-field-wrapper").eq(1).contains("City").should("exist");
// submit form, to read message
cy.get("#data-table-form-City").type("_abc");
cy.get("#data-table-form-LastUpdate").click();
cy.getActiveModal().find("button").contains("19").click();
cy.getActiveModal().find("button").contains("OK").click();
cy.get("button").contains("Link to 'Country'").click();
cy.getActiveModal()
.find(".child-card")
.contains("Afghanistan")
.click();
// submit button & validate
cy.get(".nc-form").find("button").contains("Submit").click();
cy.toastWait("Congratulations");
cy.get(".v-alert")
.contains("Congratulations")
.should("exist")
.then(() => {
cy.get(".nc-form").should("exist");
// validate if form has appeared again
cy.get(".nc-form", { timeout: 10000 })
.find("h2")
.contains("A B C D")
.should("exist");
cy.get(".nc-form", { timeout: 10000 })
.find(".body-1")
.contains("Some description about form comes here")
.should("exist");
});
});
});
it(`Delete ${viewType} view`, () => {
// go back to base page
cy.visit(storedURL, {
baseUrl: null,
});
it(`Share form view`, () => {
cy.get(".nc-form > .mx-auto")
.find('[type="checkbox"]')
.eq(1)
.should("be.checked");
cy.get(`.nc-view-item.nc-${viewType}-view-item`)
.contains("City1")
.click();
// cy.get(".v-navigation-drawer__content > .container")
// .find(".v-list > .v-list-item")
// .contains("Share View")
// .click();
mainPage.shareView().click();
cy.snipActiveModal("Modal_ShareView");
// copy link text, visit URL
cy.getActiveModal()
.find(".share-link-box")
.contains("/nc/form/", { timeout: 10000 })
.then(($obj) => {
let linkText = $obj.text().trim();
cy.log(linkText);
cy.visit(linkText, {
baseUrl: null,
});
// wait for share view page to load!
cy.get(".nc-form").should("exist");
cy.snip("ShareView_Form");
// New form appeared? Header & description should exist
cy.get(".nc-form", { timeout: 10000 })
.find("h2")
.contains("A B C D")
.should("exist");
cy.get(".nc-form", { timeout: 10000 })
.find(".body-1")
.contains("Some description about form comes here")
.should("exist");
// all fields, barring removed field should exist
cy.get('[title="City"]').should("exist");
cy.get('[title="LastUpdate"]').should("exist");
cy.get('[title="Country <= City"]').should("exist");
cy.get('[title="City => Address"]').should("not.exist");
// order of LastUpdate & City field is retained
cy.get(".nc-field-wrapper")
.eq(0)
.contains("LastUpdate")
.should("exist");
cy.get(".nc-field-wrapper")
.eq(1)
.contains("City")
.should("exist");
// submit form, to read message
cy.get("#data-table-form-City").type("_abc");
cy.get("#data-table-form-LastUpdate").click();
cy.getActiveModal()
.find("button")
.contains("19")
.click();
cy.getActiveModal()
.find("button")
.contains("OK")
.click();
cy.get("button").contains("Link to 'Country'").click();
cy.getActiveModal()
.find(".child-card")
.contains("Afghanistan")
.click();
// submit button & validate
cy.get(".nc-form")
.find("button")
.contains("Submit")
.click();
cy.toastWait("Congratulations");
cy.get(".v-alert")
.contains("Congratulations")
.should("exist")
.then(() => {
cy.get(".nc-form").should("exist");
// validate if form has appeared again
cy.get(".nc-form", { timeout: 10000 })
.find("h2")
.contains("A B C D")
.should("exist");
cy.get(".nc-form", { timeout: 10000 })
.find(".body-1")
.contains(
"Some description about form comes here"
)
.should("exist");
});
});
});
// number of view entries should be 2 before we delete
cy.get(".nc-view-item").its("length").should("eq", 2);
// click on delete icon (becomes visible on hovering mouse)
cy.get(".nc-view-delete-icon").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);
// clean up newly added rows into Country table operations
// this auto verifies successfull addition of rows to table as well
mainPage.getPagination(25).click();
cy.get(".nc-grid-row").should("have.length", 1);
mainPage
.getRow(1)
.find(".mdi-checkbox-blank-outline")
.click({ force: true });
mainPage.getCell("City", 1).rightclick();
cy.getActiveMenu().contains("Delete Selected Row").click();
// cy.toastWait('Deleted selected rows successfully')
});
};
// below scenario's will be invoked twice, once for rest & then for graphql
viewTest("form");
});
it(`Delete ${viewType} 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);
// click on delete icon (becomes visible on hovering mouse)
cy.get(".nc-view-delete-icon").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);
// clean up newly added rows into Country table operations
// this auto verifies successfull addition of rows to table as well
mainPage.getPagination(25).click();
cy.get(".nc-grid-row").should("have.length", 1);
mainPage
.getRow(1)
.find(".mdi-checkbox-blank-outline")
.click({ force: true });
mainPage.getCell("City", 1).rightclick();
cy.getActiveMenu().contains("Delete Selected Row").click();
// cy.toastWait('Deleted selected rows successfully')
});
};
// below scenario's will be invoked twice, once for rest & then for graphql
viewTest("form");
});
};
/**

813
scripts/cypress/integration/common/4f_grid_view_share.js

@ -11,419 +11,444 @@ let storedURL = "";
// 5: default (country table): for update row/column validation
let viewURL = {};
export const genTest = (type, xcdb) => {
if (!isTestSuiteActive(type, xcdb)) 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(`${type.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");
});
export const genTest = (apiType, dbType) => {
if (!isTestSuiteActive(apiType, dbType)) return;
// 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("District", "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
const generateViewLink = (viewName) => {
// click on share view
// 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("District", 1)
.contains("West Bengali")
.should("exist");
mainPage.getCell("District", 2).contains("Tutuila").should("exist");
mainPage.getCell("District", 3).contains("Tamil Nadu").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,Location,Address => Customer,Address => Staff,City <= Address,Address <=> Staff`,
`1013 Tabuk Boulevard,West Bengali,96203,158399646978,[object Object],2,,Kanchrapara,`,
`1892 Nabereznyje Telny Lane,Tutuila,28396,478229987054,[object Object],2,,Tafuna,`,
`1993 Tabuk Lane,Tamil Nadu,64221,648482415405,[object Object],2,,Tambaram,`,
`1661 Abha Drive,Tamil Nadu,14400,270456873752,[object Object],1,,Pudukkottai,`,
];
for (let i = 0; i < storedRecords.length; i++) {
let strCol = storedRecords[i].split(",");
let retCol = retrievedRecords[i].split(",");
for (let j = 0; j < 4; j++) {
expect(strCol[j]).to.be.equal(retCol[j]);
}
// expect(retrievedRecords[i]).to.be.equal(storedRecords[i])
}
};
mainPage.shareView().click();
// 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("District", 1)
.contains("Southern Mindanao")
.should("exist");
});
it(`Share ${viewType.toUpperCase()} view : Enable sort`, () => {
// Sort menu operations (Country Column, Z->A)
mainPage.sortField("District", "Z -> A");
mainPage
.getCell("District", 1)
.contains("West Bengali")
.should("exist");
});
it(`Share ${viewType.toUpperCase()} view : Create Filter`, () => {
// add filter & validate
mainPage.filterField("District", "is like", "Tamil");
// wait for page rendering to complete
cy.get(".nc-grid-row").should("have.length", 2);
mainPage.getCell("District", 1).contains("Tamil").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`,
`1993 Tabuk Lane,Tamil Nadu,64221,648482415405,[object Object],2,,Tambaram,`,
`1661 Abha Drive,Tamil Nadu,14400,270456873752,[object Object],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(",");
for (let j = 0; j < 4; j++) {
expect(strCol[j]).to.be.equal(retCol[j]);
}
}
};
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("District", 1)
.contains("West Bengali")
.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");
// wait, as URL initially will be /undefined
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("Kanchrapara")
.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");
.find(".share-link-box")
.contains("/nc/view/", { timeout: 10000 })
.should("exist");
// copy link text, visit URL
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,
.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();
});
// number of view entries should be 2 before we delete
cy.get(".nc-view-item").its("length").should("eq", 2);
beforeEach(() => {
cy.restoreLocalStorage();
});
cy.get(".nc-view-delete-icon").eq(0).click({ force: true });
cy.toastWait("View deleted successfully");
afterEach(() => {
cy.saveLocalStorage();
});
// confirm if the number of veiw entries is reduced by 1
cy.get(".nc-view-item").its("length").should("eq", 1);
});
};
after(() => {
// close table
// mainPage.deleteCreatedViews()
cy.closeTableTab("Address");
});
// below scenario's will be invoked twice, once for rest & then for graphql
viewTest("grid");
});
describe(`${type.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");
});
});
// 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("District", "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);
cy.snip("ShareView_Grid");
// 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("District", 1)
.contains("West Bengali")
.should("exist");
mainPage
.getCell("District", 2)
.contains("Tutuila")
.should("exist");
mainPage
.getCell("District", 3)
.contains("Tamil Nadu")
.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,Location,Address => Customer,Address => Staff,City <= Address,Address <=> Staff`,
`1013 Tabuk Boulevard,West Bengali,96203,158399646978,[object Object],2,,Kanchrapara,`,
`1892 Nabereznyje Telny Lane,Tutuila,28396,478229987054,[object Object],2,,Tafuna,`,
`1993 Tabuk Lane,Tamil Nadu,64221,648482415405,[object Object],2,,Tambaram,`,
`1661 Abha Drive,Tamil Nadu,14400,270456873752,[object Object],1,,Pudukkottai,`,
];
for (let i = 0; i < storedRecords.length; i++) {
let strCol = storedRecords[i].split(",");
let retCol = retrievedRecords[i].split(",");
for (let j = 0; j < 4; j++) {
expect(strCol[j]).to.be.equal(retCol[j]);
}
// 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("District", 1)
.contains("Southern Mindanao")
.should("exist");
});
it(`Share ${viewType.toUpperCase()} view : Enable sort`, () => {
// Sort menu operations (Country Column, Z->A)
mainPage.sortField("District", "Z -> A");
mainPage
.getCell("District", 1)
.contains("West Bengali")
.should("exist");
});
it(`Share ${viewType.toUpperCase()} view : Create Filter`, () => {
// add filter & validate
mainPage.filterField("District", "is like", "Tamil");
// wait for page rendering to complete
cy.get(".nc-grid-row").should("have.length", 2);
mainPage
.getCell("District", 1)
.contains("Tamil")
.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`,
`1993 Tabuk Lane,Tamil Nadu,64221,648482415405,[object Object],2,,Tambaram,`,
`1661 Abha Drive,Tamil Nadu,14400,270456873752,[object Object],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(",");
for (let j = 0; j < 4; j++) {
expect(strCol[j]).to.be.equal(retCol[j]);
}
}
};
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("District", 1)
.contains("West Bengali")
.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("Kanchrapara")
.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);
});
};
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");
// below scenario's will be invoked twice, once for rest & then for graphql
viewTest("grid");
});
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);
});
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");
});
});
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");
});
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");
it.skip(`Share GRID view : new column visible`, () => {
// verify column headers
cy.get('[data-col="dummy"]').should("exist");
});
});
});
};
/**

471
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 <pranavxc@gmail.com>
* @author Raju Udava <sivadstala@gmail.com>
*
* @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 <http://www.gnu.org/licenses/>.
*
*/

396
scripts/cypress/integration/common/5a_user_role.js

@ -1,205 +1,229 @@
import { loginPage, projectsPage } from "../../support/page_objects/navigation";
import { mainPage } from "../../support/page_objects/mainPage";
import {
roles,
staticProjects,
isPostgres,
roles,
staticProjects,
} from "../../support/page_objects/projectConstants";
import { isTestSuiteActive } from "../../support/page_objects/projectConstants";
import {
_advSettings,
_editSchema,
_editData,
_editComment,
_viewMenu,
_topRightMenu,
disableTableAccess,
_accessControl,
_advSettings,
_editSchema,
_editData,
_editComment,
_viewMenu,
_topRightMenu,
disableTableAccess,
_accessControl,
} from "../spec/roleValidation.spec";
export const genTest = (type, xcdb) => {
if (!isTestSuiteActive(type, xcdb)) return;
export const genTest = (apiType, dbType) => {
if (!isTestSuiteActive(apiType, dbType)) return;
describe("Static user creations (different roles)", () => {
// beforeEach(() => {
// loginPage.signIn(roles.owner.credentials)
// projectsPage.openProject(getPrimarySuite().basic.name)
// })
before(() => {
mainPage.navigationDraw(mainPage.TEAM_N_AUTH).click();
});
const addUser = (user) => {
it(`RoleType: ${user.name}`, () => {
// for first project, users need to be added explicitly using "New User" button
// for subsequent projects, they will be required to just add to this project
// using ROW count to identify if its former or latter scenario
// 5 users (owner, creator, editor, viewer, commenter) + row header = 6
cy.get(`tr`).then((obj) => {
cy.log(obj.length);
if (obj.length == 6) {
mainPage.addExistingUserToProject(
user.credentials.username,
user.name
);
} else {
mainPage.addNewUserToProject(user.credentials, user.name);
}
});
});
};
addUser(roles.creator);
addUser(roles.editor);
addUser(roles.commenter);
addUser(roles.viewer);
// Access contrl list- configuration
//
it(`Access control list- configuration`, () => {
// open Project metadata tab
//
mainPage.navigationDraw(mainPage.PROJ_METADATA).click();
cy.get(".nc-exp-imp-metadata").dblclick({ force: true });
cy.get(".nc-ui-acl-tab").click({ force: true });
// validate if it has 19 entries representing tables & views
cy.get(".nc-acl-table-row").should("have.length", 19);
// disable table & view access
//
disableTableAccess("language", "editor");
disableTableAccess("language", "commenter");
disableTableAccess("language", "viewer");
disableTableAccess("customerlist", "editor");
disableTableAccess("customerlist", "commenter");
disableTableAccess("customerlist", "viewer");
});
});
const roleValidation = (roleType) => {
describe(`User role validation`, () => {
if (roleType != "owner") {
it(`[${roles[roleType].name}] SignIn, Open project`, () => {
cy.log(mainPage.roleURL[roleType]);
cy.visit(mainPage.roleURL[roleType], {
baseUrl: null,
});
// Redirected to new URL, feed details
//
cy.get('input[type="text"]')
.should("exist")
.type(roles[roleType].credentials.username);
cy.get('input[type="password"]').type(
roles[roleType].credentials.password
);
cy.get('button:contains("SIGN")').click();
cy.url({ timeout: 6000 }).should("contain", "#/project");
if (xcdb) {
if ("rest" == type)
projectsPage.openProject(staticProjects.sampleREST.basic.name);
else projectsPage.openProject(staticProjects.sampleGQL.basic.name);
} else {
if ("rest" == type)
projectsPage.openProject(staticProjects.externalREST.basic.name);
else
projectsPage.openProject(staticProjects.externalGQL.basic.name);
}
if (roleType != "creator") {
cy.closeTableTab("Actor");
}
describe("Static user creations (different roles)", () => {
before(() => {
mainPage.navigationDraw(mainPage.TEAM_N_AUTH).click();
});
}
///////////////////////////////////////////////////////
// Test suite
it(`[${roles[roleType].name}] Left navigation menu, New User add`, () => {
// project configuration settings
//
_advSettings(roleType, false);
});
it(`[${roles[roleType].name}] Access control`, () => {
// Access control validation
//
_accessControl(roleType, false);
});
const addUser = (user) => {
it(`RoleType: ${user.name}`, () => {
// for first project, users need to be added explicitly using "New User" button
// for subsequent projects, they will be required to just add to this project
// using ROW count to identify if its former or latter scenario
// 5 users (owner, creator, editor, viewer, commenter) + row header = 6
cy.get(`tr`).then((obj) => {
cy.log(obj.length);
if (obj.length == 6) {
mainPage.addExistingUserToProject(
user.credentials.username,
user.name
);
} else {
mainPage.addNewUserToProject(
user.credentials,
user.name
);
}
});
});
};
it(`[${roles[roleType].name}] Schema: create table, add/modify/delete column`, () => {
// Schema related validations
// - Add/delete table
// - Add/Update/delete column
//
_editSchema(roleType, false);
});
addUser(roles.creator);
addUser(roles.editor);
addUser(roles.commenter);
addUser(roles.viewer);
it(`[${roles[roleType].name}] Data: add/modify/delete row, update cell contents`, () => {
// Table data related validations
// - Add/delete/modify row
// Access contrl list- configuration
//
_editData(roleType, false);
});
it(`Access control list- configuration`, () => {
// open Project metadata tab
//
mainPage.navigationDraw(mainPage.PROJ_METADATA).click();
cy.get(".nc-exp-imp-metadata").dblclick({ force: true });
cy.get(".nc-ui-acl-tab").click({ force: true });
cy.snip("Meta_Tab3");
// validate if it has 19 entries representing tables & views
if (isPostgres())
cy.get(".nc-acl-table-row").should("have.length", 24);
else cy.get(".nc-acl-table-row").should("have.length", 19);
// disable table & view access
//
disableTableAccess("language", "editor");
disableTableAccess("language", "commenter");
disableTableAccess("language", "viewer");
disableTableAccess("customerlist", "editor");
disableTableAccess("customerlist", "commenter");
disableTableAccess("customerlist", "viewer");
});
});
it(`[${roles[roleType].name}] Comments: view/add`, () => {
// read &/ update comment
// Viewer: only allowed to read
// Everyone else: read &/ update
//
if (roleType != "viewer") _editComment(roleType, false);
});
it(`[${roles[roleType].name}] Right navigation menu, share view`, () => {
// right navigation menu bar
// Editor/Viewer/Commenter : can only view 'existing' views
// Rest: can create/edit
_viewMenu(roleType, false);
});
it(`[${roles[roleType].name}] Top Right Menu bar`, () => {
// Share button is conditional
// Rest are static/ mandatory
//
_topRightMenu(roleType, false);
});
it(`[${roles[roleType].name}] Download files`, () => {
// #ID, City, LastUpdate, City => Address, Country <= City, +
mainPage.hideField("LastUpdate");
const verifyCsv = (retrievedRecords) => {
// expected output, statically configured
let storedRecords = [
`City,City => Address,Country <= City`,
`A Corua (La Corua),939 Probolinggo Loop,Spain`,
`Abha,733 Mandaluyong Place,Saudi Arabia`,
`Abu Dhabi,535 Ahmadnagar Manor,United Arab Emirates`,
`Acua,1789 Saint-Denis Parkway,Mexico`,
];
for (let i = 0; i < storedRecords.length; i++) {
// cy.log(retrievedRecords[i])
expect(retrievedRecords[i]).to.be.equal(storedRecords[i]);
}
};
const roleValidation = (roleType) => {
describe(`User role validation`, () => {
if (roleType != "owner") {
it(`[${roles[roleType].name}] SignIn, Open project`, () => {
cy.log(mainPage.roleURL[roleType]);
cy.visit(mainPage.roleURL[roleType], {
baseUrl: null,
});
// Redirected to new URL, feed details
//
cy.get('input[type="text"]')
.should("exist")
.type(roles[roleType].credentials.username);
cy.get('input[type="password"]').type(
roles[roleType].credentials.password
);
cy.get('button:contains("SIGN")').click();
cy.url({ timeout: 6000 }).should("contain", "#/project");
if (dbType === "xcdb") {
if ("rest" == apiType)
projectsPage.openProject(
staticProjects.sampleREST.basic.name
);
else
projectsPage.openProject(
staticProjects.sampleGQL.basic.name
);
} else if (dbType === "mysql") {
if ("rest" == apiType)
projectsPage.openProject(
staticProjects.externalREST.basic.name
);
else
projectsPage.openProject(
staticProjects.externalGQL.basic.name
);
} else if (dbType === "postgres") {
if ("rest" == apiType)
projectsPage.openProject(
staticProjects.pgExternalREST.basic.name
);
else
projectsPage.openProject(
staticProjects.pgExternalGQL.basic.name
);
}
if (roleType != "creator") {
cy.closeTableTab("Actor");
}
});
}
///////////////////////////////////////////////////////
// Test suite
it(`[${roles[roleType].name}] Left navigation menu, New User add`, () => {
// project configuration settings
//
_advSettings(roleType, false);
});
it(`[${roles[roleType].name}] Access control`, () => {
// Access control validation
//
_accessControl(roleType, false);
});
it(`[${roles[roleType].name}] Schema: create table, add/modify/delete column`, () => {
// Schema related validations
// - Add/delete table
// - Add/Update/delete column
//
_editSchema(roleType, false);
});
it(`[${roles[roleType].name}] Data: add/modify/delete row, update cell contents`, () => {
// Table data related validations
// - Add/delete/modify row
//
_editData(roleType, false);
});
it(`[${roles[roleType].name}] Comments: view/add`, () => {
// read &/ update comment
// Viewer: only allowed to read
// Everyone else: read &/ update
//
if (roleType != "viewer") _editComment(roleType, false);
});
it(`[${roles[roleType].name}] Right navigation menu, share view`, () => {
// right navigation menu bar
// Editor/Viewer/Commenter : can only view 'existing' views
// Rest: can create/edit
_viewMenu(roleType, false);
});
it(`[${roles[roleType].name}] Top Right Menu bar`, () => {
// Share button is conditional
// Rest are static/ mandatory
//
_topRightMenu(roleType, false);
});
it(`[${roles[roleType].name}] Download files`, () => {
// #ID, City, LastUpdate, City => Address, Country <= City, +
mainPage.hideField("LastUpdate");
const verifyCsv = (retrievedRecords) => {
// expected output, statically configured
let storedRecords = [
`City,City => Address,Country <= City`,
`A Corua (La Corua),939 Probolinggo Loop,Spain`,
`Abha,733 Mandaluyong Place,Saudi Arabia`,
`Abu Dhabi,535 Ahmadnagar Manor,United Arab Emirates`,
`Acua,1789 Saint-Denis Parkway,Mexico`,
];
for (let i = 0; i < storedRecords.length; i++) {
// cy.log(retrievedRecords[i])
expect(retrievedRecords[i]).to.be.equal(
storedRecords[i]
);
}
};
// download & verify
mainPage.downloadAndVerifyCsv(`City_exported_1.csv`, verifyCsv);
mainPage.unhideField("LastUpdate");
});
});
};
// download & verify
mainPage.downloadAndVerifyCsv(`City_exported_1.csv`, verifyCsv);
mainPage.unhideField("LastUpdate");
});
});
};
// skip owner validation as rest of the cases pretty much cover the same
// roleValidation('owner')
roleValidation("creator");
roleValidation("editor");
roleValidation("commenter");
roleValidation("viewer");
// skip owner validation as rest of the cases pretty much cover the same
// roleValidation('owner')
roleValidation("creator");
roleValidation("editor");
roleValidation("commenter");
roleValidation("viewer");
};
/**

234
scripts/cypress/integration/common/5b_preview_role.js

@ -4,123 +4,131 @@
import { loginPage, projectsPage } from "../../support/page_objects/navigation";
import { mainPage } from "../../support/page_objects/mainPage";
import { isTestSuiteActive } from "../../support/page_objects/projectConstants";
import {
_advSettings,
_editSchema,
_editData,
_editComment,
_viewMenu,
_topRightMenu,
enableTableAccess,
_accessControl,
isPostgres,
isTestSuiteActive,
} from "../../support/page_objects/projectConstants";
import {
_advSettings,
_editSchema,
_editData,
_editComment,
_viewMenu,
_topRightMenu,
enableTableAccess,
_accessControl,
} from "../spec/roleValidation.spec";
export const genTest = (type, xcdb, roleType) => {
if (!isTestSuiteActive(type, xcdb)) return;
///////////////////////////////////////////////////////////
//// Test Suite
describe("Role preview validations", () => {
// Sign in/ open project
before(() => {
loginPage.loginAndOpenProject(type, xcdb);
cy.openTableTab("City", 25);
export const genTest = (apiType, dbType, roleType) => {
if (!isTestSuiteActive(apiType, dbType)) return;
///////////////////////////////////////////////////////////
//// Test Suite
describe("Role preview validations", () => {
// Sign in/ open project
before(() => {
loginPage.loginAndOpenProject(apiType, dbType);
cy.openTableTab("City", 25);
});
after(() => {
cy.get(".nc-preview-reset").click({ force: true });
// cy.wait(20000)
// wait for page rendering to complete
cy.get(".nc-grid-row", { timeout: 25000 }).should(
"have.length",
25
);
// cy.get('.nc-preview-reset:visible').should('not-exist')
// mainPage.navigationDraw(mainPage.ROLE_VIEW).contains('Reset Preview').should('not.exist')
// cy.get('.nc-preview-reset').should('not-exist')
cy.closeTableTab("City");
// open Project metadata tab
//
mainPage.navigationDraw(mainPage.PROJ_METADATA).click();
cy.get(".nc-exp-imp-metadata").dblclick({ force: true });
cy.get(".nc-ui-acl-tab").click({ force: true });
// validate if it has 19 entries representing tables & views
if (isPostgres())
cy.get(".nc-acl-table-row").should("have.length", 24);
else cy.get(".nc-acl-table-row").should("have.length", 19);
// restore access
//
enableTableAccess("language", "editor");
enableTableAccess("language", "commenter");
enableTableAccess("language", "viewer");
enableTableAccess("customerlist", "editor");
enableTableAccess("customerlist", "commenter");
enableTableAccess("customerlist", "viewer");
});
const genTestSub = (roleType) => {
it(`Role preview: ${roleType}: Enable preview`, () => {
cy.get(`.nc-preview-${roleType}`).click();
});
it(`Role preview: ${roleType}: Advance settings`, () => {
// project configuration settings
//
_advSettings(roleType, true);
});
it(`Role preview: ${roleType}: Access control`, () => {
// Access control validation
//
_accessControl(roleType, false);
});
it(`Role preview: ${roleType}: Edit data`, () => {
// Table data related validations
// - Add/delete/modify row
//
_editData(roleType, true);
});
it(`Role preview: ${roleType}: Edit comment`, () => {
// read &/ update comment
// Viewer: not allowed to read
// Everyone else: read &/ update
//
_editComment(roleType, true);
});
it(`Role preview: ${roleType}: Preview menu`, () => {
// right navigation menu bar
// Editor/Viewer/Commenter : can only view 'existing' views
// Rest: can create/edit
_viewMenu(roleType, true);
});
it(`Role preview: ${roleType}: Top Right Menu bar`, () => {
// Share button is conditional
// Rest are static/ mandatory
//
_topRightMenu(roleType, false);
});
it(`Role preview: ${roleType}: Edit Schema`, () => {
// Schema related validations
// - Add/delete table
// - Add/Update/delete column
//
_editSchema(roleType, true);
});
};
genTestSub("editor");
genTestSub("commenter");
genTestSub("viewer");
});
after(() => {
cy.get(".nc-preview-reset").click({ force: true });
// cy.wait(20000)
// wait for page rendering to complete
cy.get(".nc-grid-row", { timeout: 25000 }).should("have.length", 25);
// cy.get('.nc-preview-reset:visible').should('not-exist')
// mainPage.navigationDraw(mainPage.ROLE_VIEW).contains('Reset Preview').should('not.exist')
// cy.get('.nc-preview-reset').should('not-exist')
cy.closeTableTab("City");
// open Project metadata tab
//
mainPage.navigationDraw(mainPage.PROJ_METADATA).click();
cy.get(".nc-exp-imp-metadata").dblclick({ force: true });
cy.get(".nc-ui-acl-tab").click({ force: true });
// validate if it has 19 entries representing tables & views
cy.get(".nc-acl-table-row").should("have.length", 19);
// restore access
//
enableTableAccess("language", "editor");
enableTableAccess("language", "commenter");
enableTableAccess("language", "viewer");
enableTableAccess("customerlist", "editor");
enableTableAccess("customerlist", "commenter");
enableTableAccess("customerlist", "viewer");
});
const genTestSub = (roleType) => {
it(`Role preview: ${roleType}: Enable preview`, () => {
cy.get(`.nc-preview-${roleType}`).click();
});
it(`Role preview: ${roleType}: Advance settings`, () => {
// project configuration settings
//
_advSettings(roleType, true);
});
it(`Role preview: ${roleType}: Access control`, () => {
// Access control validation
//
_accessControl(roleType, false);
});
it(`Role preview: ${roleType}: Edit data`, () => {
// Table data related validations
// - Add/delete/modify row
//
_editData(roleType, true);
});
it(`Role preview: ${roleType}: Edit comment`, () => {
// read &/ update comment
// Viewer: not allowed to read
// Everyone else: read &/ update
//
_editComment(roleType, true);
});
it(`Role preview: ${roleType}: Preview menu`, () => {
// right navigation menu bar
// Editor/Viewer/Commenter : can only view 'existing' views
// Rest: can create/edit
_viewMenu(roleType, true);
});
it(`Role preview: ${roleType}: Top Right Menu bar`, () => {
// Share button is conditional
// Rest are static/ mandatory
//
_topRightMenu(roleType, false);
});
it(`Role preview: ${roleType}: Edit Schema`, () => {
// Schema related validations
// - Add/delete table
// - Add/Update/delete column
//
_editSchema(roleType, true);
});
};
genTestSub("editor");
genTestSub("commenter");
genTestSub("viewer");
});
};
/**

62
scripts/cypress/integration/common/6b_downloadCsv.js

@ -2,44 +2,42 @@ import { mainPage } from "../../support/page_objects/mainPage";
import { loginPage } from "../../support/page_objects/navigation";
import { isTestSuiteActive } from "../../support/page_objects/projectConstants";
export const genTest = (type, xcdb) => {
if (!isTestSuiteActive(type, xcdb)) return;
export const genTest = (apiType, dbType) => {
if (!isTestSuiteActive(apiType, dbType)) return;
describe(`${type.toUpperCase()} Upload/ Download CSV`, () => {
before(() => {
// loginPage.loginAndOpenProject(type)
cy.openTableTab("Country", 25);
cy.screenshot("6b-before");
});
describe(`${apiType.toUpperCase()} Upload/ Download CSV`, () => {
before(() => {
// loginPage.loginAndOpenProject(type)
cy.openTableTab("Country", 25);
});
after(() => {
cy.closeTableTab("Country");
cy.screenshot('6b-after')
});
after(() => {
cy.closeTableTab("Country");
});
it("Download verification- base view, default columns", () => {
mainPage.hideField("LastUpdate");
const verifyCsv = (retrievedRecords) => {
// expected output, statically configured
let storedRecords = [
`Country,Country => City`,
`Afghanistan,Kabul`,
`Algeria,"Batna,Bchar,Skikda"`,
`American Samoa,Tafuna`,
`Angola,"Benguela,Namibe"`,
];
it("Download verification- base view, default columns", () => {
mainPage.hideField("LastUpdate");
const verifyCsv = (retrievedRecords) => {
// expected output, statically configured
let storedRecords = [
`Country,Country => City`,
`Afghanistan,Kabul`,
`Algeria,"Batna,Bchar,Skikda"`,
`American Samoa,Tafuna`,
`Angola,"Benguela,Namibe"`,
];
for (let i = 0; i < storedRecords.length; i++) {
cy.log(retrievedRecords[i]);
expect(retrievedRecords[i]).to.be.equal(storedRecords[i]);
}
};
for (let i = 0; i < storedRecords.length - 1; i++) {
cy.log(retrievedRecords[i]);
expect(retrievedRecords[i]).to.be.equal(storedRecords[i]);
}
};
// download & verify
mainPage.downloadAndVerifyCsv(`Country_exported_1.csv`, verifyCsv);
mainPage.unhideField("LastUpdate");
// download & verify
mainPage.downloadAndVerifyCsv(`Country_exported_1.csv`, verifyCsv);
mainPage.unhideField("LastUpdate");
});
});
});
};
/**

452
scripts/cypress/integration/common/6c_swagger_api.js

@ -3,225 +3,249 @@ import { mainPage } from "../../support/page_objects/mainPage";
import { roles } from "../../support/page_objects/projectConstants";
import { isTestSuiteActive } from "../../support/page_objects/projectConstants";
export const genTest = (type, xcdb) => {
if (!isTestSuiteActive(type, xcdb)) return;
export const genTest = (apiType, dbType) => {
if (!isTestSuiteActive(apiType, dbType)) return;
describe(`${type.toUpperCase()} : API List - Test preparation`, () => {
before(() => {
loginPage.loginAndOpenProject(type, xcdb);
});
describe(`${apiType.toUpperCase()} : API List - Test preparation`, () => {
before(() => {
loginPage.loginAndOpenProject(apiType, dbType);
});
it("Open project & record swagger URL, AuthToken", () => {
let authToken = mainPage.getAuthToken();
cy.url().then((url) => {
// retrieve project name from URL & use it to construct Swagger URL
// URL on homepage: http://localhost:3000/#/nc/externalrest_weUO?type=roles&dbalias=&name=Team%20%26%20Auth%20
// [REST] Swagger URL: http://localhost:8080/nc/externalrest_weUO/db/swagger
// [GQL] http://localhost:8080/nc/externalgql_dgwx/v1/graphql
const projectName = url.split("/")[5].split("?")[0];
let swaggerURL = ``;
if ("rest" == type) {
swaggerURL = `http://localhost:8080/nc/${projectName}/db/swagger`;
} else {
swaggerURL = `http://localhost:8080/nc/${projectName}/v1/graphql`;
}
// exchange information between two tests using a file
// https://stackoverflow.com/questions/52050657/what-is-the-best-practice-of-pass-states-between-tests-in-cypress
//
cy.writeFile("shared.json", {
SWAGGER_URL: swaggerURL,
AUTH_TOKEN: authToken,
it("Open project & record swagger URL, AuthToken", () => {
let authToken = mainPage.getAuthToken();
cy.url().then((url) => {
// retrieve project name from URL & use it to construct Swagger URL
// URL on homepage: http://localhost:3000/#/nc/externalrest_weUO?type=roles&dbalias=&name=Team%20%26%20Auth%20
// [REST] Swagger URL: http://localhost:8080/nc/externalrest_weUO/db/swagger
// [GQL] http://localhost:8080/nc/externalgql_dgwx/v1/graphql
const projectName = url.split("/")[5].split("?")[0];
let swaggerURL = ``;
if ("rest" == apiType) {
swaggerURL = `http://localhost:8080/nc/${projectName}/db/swagger`;
} else {
swaggerURL = `http://localhost:8080/nc/${projectName}/v1/graphql`;
}
// exchange information between two tests using a file
// https://stackoverflow.com/questions/52050657/what-is-the-best-practice-of-pass-states-between-tests-in-cypress
//
cy.writeFile("shared.json", {
SWAGGER_URL: swaggerURL,
AUTH_TOKEN: authToken,
});
});
});
});
});
});
if ("rest" == type) {
describe(`Swagger page, base verification`, () => {
// returns swagger button intended for
//
const getSwaggerButton = (tag, idx, desc) => {
return cy
.get(`#operations-tag-${tag}`)
.next()
.find(".opblock")
.eq(idx)
.find(`button:contains(${desc})`);
};
let Token;
// basic authentication tag verification
//
it("Swagger URL access & basic validation", () => {
// retrieve information stored in previous IT block
//
cy.readFile("shared.json").then((jsonPayload) => {
let URL = jsonPayload.SWAGGER_URL;
Token = jsonPayload.AUTH_TOKEN;
cy.visit(URL, {
baseUrl: null,
}).then(() => {
// wait to allow time for SWAGGER Library loading to finish
cy.log(Token);
// validate; API order assumed
cy.get("#operations-tag-Authentication", { timeout: 20000 })
.should("exist")
.next()
.find(".opblock")
.should("has.length", 9);
getSwaggerButton("Authentication", 0, "User login").should("exist");
getSwaggerButton("Authentication", 1, "User signup").should(
"exist"
);
getSwaggerButton("Authentication", 2, "Password Forgot").should(
"exist"
);
getSwaggerButton("Authentication", 3, "Email validate link").should(
"exist"
);
getSwaggerButton(
"Authentication",
4,
"Validate password reset token"
).should("exist");
getSwaggerButton("Authentication", 5, "Password reset").should(
"exist"
);
getSwaggerButton("Authentication", 6, "User details").should(
"exist"
);
getSwaggerButton("Authentication", 7, "Update user details").should(
"exist"
);
getSwaggerButton("Authentication", 8, "Update user details").should(
"exist"
);
});
if ("rest" == apiType) {
describe(`Swagger page, base verification`, () => {
// returns swagger button intended for
//
const getSwaggerButton = (tag, idx, desc) => {
return cy
.get(`#operations-tag-${tag}`)
.next()
.find(".opblock")
.eq(idx)
.find(`button:contains(${desc})`);
};
let Token;
// basic authentication tag verification
//
it("Swagger URL access & basic validation", () => {
// retrieve information stored in previous IT block
//
cy.readFile("shared.json").then((jsonPayload) => {
let URL = jsonPayload.SWAGGER_URL;
Token = jsonPayload.AUTH_TOKEN;
cy.visit(URL, {
baseUrl: null,
}).then(() => {
// wait to allow time for SWAGGER Library loading to finish
cy.log(Token);
// cy.snip("Swagger");
// validate; API order assumed
cy.get("#operations-tag-Authentication", {
timeout: 20000,
})
.should("exist")
.next()
.find(".opblock")
.should("has.length", 9);
getSwaggerButton(
"Authentication",
0,
"User login"
).should("exist");
getSwaggerButton(
"Authentication",
1,
"User signup"
).should("exist");
getSwaggerButton(
"Authentication",
2,
"Password Forgot"
).should("exist");
getSwaggerButton(
"Authentication",
3,
"Email validate link"
).should("exist");
getSwaggerButton(
"Authentication",
4,
"Validate password reset token"
).should("exist");
getSwaggerButton(
"Authentication",
5,
"Password reset"
).should("exist");
getSwaggerButton(
"Authentication",
6,
"User details"
).should("exist");
getSwaggerButton(
"Authentication",
7,
"Update user details"
).should("exist");
getSwaggerButton(
"Authentication",
8,
"Update user details"
).should("exist");
});
});
});
it("Authorize success: Valid token", () => {
// authorize button, feed token, click authorize
cy.get('[class="btn authorize unlocked"]').click();
cy.get("input").type(Token);
cy.get(".auth-btn-wrapper > .authorize").click();
// Response: "Authorized" should exist on DOM
cy.get(".auth-container")
.contains("Authorized")
.should("exist");
cy.get(".btn-done").click();
// Authorize button is LOCKED now
cy.get('[class="btn authorize locked"]').should("exist");
});
it("Execute Authentication (valid token case) > GET: User details API", () => {
// Auth> User details API
getSwaggerButton("Authentication", 6, "User details").click();
// "Try it out" button, followed by "Execute"
cy.get(".try-out > .btn").click();
cy.get(".execute-wrapper > .btn").click();
// check response: validate email credentials
cy.get(".highlight-code > .microlight")
.contains("email")
.should("exist");
cy.get(".highlight-code > .microlight")
.contains(roles.owner.credentials.username)
.should("exist");
// reset operations (clear, cancel, windback User details tab)
cy.get(".btn-clear").click();
cy.get(".try-out > .btn").click();
getSwaggerButton("Authentication", 6, "User details").click();
});
it("Logout post authorization", () => {
// authorize button, logout
cy.get('[class="btn authorize locked"]').click();
cy.get('.auth-btn-wrapper > button:contains("Logout")').click();
cy.get(".btn-done").click();
// Authorize button is UNLOCKED now
cy.get('[class="btn authorize unlocked"]').should("exist");
});
it("Execute Authentication (logout case) > GET: User details API", () => {
// Auth> User details API
getSwaggerButton("Authentication", 6, "User details").click();
// "Try it out" button, followed by "Execute"
cy.get(".try-out > .btn").click();
cy.get(".execute-wrapper > .btn").click();
// check response: email credentials shouldnt exist. should display 'guest:true'
cy.get(".highlight-code > .microlight")
.contains("guest")
.should("exist");
cy.get(".highlight-code > .microlight")
.contains("email")
.should("not.exist");
cy.get(".highlight-code > .microlight")
.contains(roles.owner.credentials.username)
.should("not.exist");
// reset operations (clear, cancel, windback User details tab)
cy.get(".btn-clear").click();
cy.get(".try-out > .btn").click();
getSwaggerButton("Authentication", 6, "User details").click();
});
it("Authorize failure: invalid token", () => {
// authorize button, feed *invalid* token, click authorize
cy.get('[class="btn authorize unlocked"]').click();
cy.get("input").type("xyz");
cy.get(".auth-btn-wrapper > .authorize").click();
// Response: "Authorized" should *not* exist on DOM
// TBD: cy.get('.auth-container').contains('Authorized').should('not.exist')
cy.get(".btn-done").click();
// Authorize button should be UNLOCKED now
// TBD: cy.get('[class="btn authorize unlocked"]').should('exist')
});
it("Execute Authentication (invalid token case) > GET: User details API", () => {
// Auth> User details API
getSwaggerButton("Authentication", 6, "User details").click();
// "Try it out" button, followed by "Execute"
cy.get(".try-out > .btn").click();
cy.get(".execute-wrapper > .btn").click();
// check response: email credentials shouldnt exist. should display 'guest:true'
cy.get(".highlight-code > .microlight")
.contains("guest")
.should("exist");
cy.get(".highlight-code > .microlight")
.contains("email")
.should("not.exist");
cy.get(".highlight-code > .microlight")
.contains(roles.owner.credentials.username)
.should("not.exist");
// reset operations (clear, cancel, windback User details tab)
cy.get(".btn-clear").click();
cy.get(".try-out > .btn").click();
getSwaggerButton("Authentication", 6, "User details").click();
});
// clean-up created file (shared.json)
// after(() => {
// cy.exec("del shared.json").then(()=> {
// cy.log("file cleaned up!")
// })
// })
});
});
it("Authorize success: Valid token", () => {
// authorize button, feed token, click authorize
cy.get('[class="btn authorize unlocked"]').click();
cy.get("input").type(Token);
cy.get(".auth-btn-wrapper > .authorize").click();
// Response: "Authorized" should exist on DOM
cy.get(".auth-container").contains("Authorized").should("exist");
cy.get(".btn-done").click();
// Authorize button is LOCKED now
cy.get('[class="btn authorize locked"]').should("exist");
});
it("Execute Authentication (valid token case) > GET: User details API", () => {
// Auth> User details API
getSwaggerButton("Authentication", 6, "User details").click();
// "Try it out" button, followed by "Execute"
cy.get(".try-out > .btn").click();
cy.get(".execute-wrapper > .btn").click();
// check response: validate email credentials
cy.get(".highlight-code > .microlight")
.contains("email")
.should("exist");
cy.get(".highlight-code > .microlight")
.contains(roles.owner.credentials.username)
.should("exist");
// reset operations (clear, cancel, windback User details tab)
cy.get(".btn-clear").click();
cy.get(".try-out > .btn").click();
getSwaggerButton("Authentication", 6, "User details").click();
});
it("Logout post authorization", () => {
// authorize button, logout
cy.get('[class="btn authorize locked"]').click();
cy.get('.auth-btn-wrapper > button:contains("Logout")').click();
cy.get(".btn-done").click();
// Authorize button is UNLOCKED now
cy.get('[class="btn authorize unlocked"]').should("exist");
});
it("Execute Authentication (logout case) > GET: User details API", () => {
// Auth> User details API
getSwaggerButton("Authentication", 6, "User details").click();
// "Try it out" button, followed by "Execute"
cy.get(".try-out > .btn").click();
cy.get(".execute-wrapper > .btn").click();
// check response: email credentials shouldnt exist. should display 'guest:true'
cy.get(".highlight-code > .microlight")
.contains("guest")
.should("exist");
cy.get(".highlight-code > .microlight")
.contains("email")
.should("not.exist");
cy.get(".highlight-code > .microlight")
.contains(roles.owner.credentials.username)
.should("not.exist");
// reset operations (clear, cancel, windback User details tab)
cy.get(".btn-clear").click();
cy.get(".try-out > .btn").click();
getSwaggerButton("Authentication", 6, "User details").click();
});
it("Authorize failure: invalid token", () => {
// authorize button, feed *invalid* token, click authorize
cy.get('[class="btn authorize unlocked"]').click();
cy.get("input").type("xyz");
cy.get(".auth-btn-wrapper > .authorize").click();
// Response: "Authorized" should *not* exist on DOM
// TBD: cy.get('.auth-container').contains('Authorized').should('not.exist')
cy.get(".btn-done").click();
// Authorize button should be UNLOCKED now
// TBD: cy.get('[class="btn authorize unlocked"]').should('exist')
});
it("Execute Authentication (invalid token case) > GET: User details API", () => {
// Auth> User details API
getSwaggerButton("Authentication", 6, "User details").click();
// "Try it out" button, followed by "Execute"
cy.get(".try-out > .btn").click();
cy.get(".execute-wrapper > .btn").click();
// check response: email credentials shouldnt exist. should display 'guest:true'
cy.get(".highlight-code > .microlight")
.contains("guest")
.should("exist");
cy.get(".highlight-code > .microlight")
.contains("email")
.should("not.exist");
cy.get(".highlight-code > .microlight")
.contains(roles.owner.credentials.username)
.should("not.exist");
// reset operations (clear, cancel, windback User details tab)
cy.get(".btn-clear").click();
cy.get(".try-out > .btn").click();
getSwaggerButton("Authentication", 6, "User details").click();
});
// clean-up created file (shared.json)
// after(() => {
// cy.exec("del shared.json").then(()=> {
// cy.log("file cleaned up!")
// })
// })
});
}
}
};
/**

11
scripts/cypress/integration/common/6d_language_validation.js

@ -3,13 +3,13 @@ const { loginPage } = require("../../support/page_objects/navigation");
const { roles } = require("../../support/page_objects/projectConstants");
import { isTestSuiteActive } from "../../support/page_objects/projectConstants";
export const genTest = (type, xcdb) => {
if (!isTestSuiteActive(type, xcdb)) return;
export const genTest = (apiType, dbType) => {
if (!isTestSuiteActive(apiType, dbType)) return;
describe(`Language support`, () => {
before(() => {
//loginPage.signIn(roles.owner.credentials)
mainPage.toolBarTopLeft(mainPage.HOME).click();
cy.screenshot("6d-1");
cy.screenshot("Debug 6d-1", { overwrite: true });
});
const langVerification = (idx, lang) => {
@ -19,9 +19,12 @@ export const genTest = (type, xcdb) => {
// toggle menu as per index
cy.get(".nc-menu-translate").click();
cy.snipActiveMenu("Menu_Translation");
cy.getActiveMenu().find(".v-list-item").eq(idx).click();
cy.screenshot("6d-2");
cy.screenshot("Debug 6d-2", { overwrite: true });
// basic validations
// 1. Page title: "My Projects"

117
scripts/cypress/integration/common/6e_project_operations.js

@ -2,70 +2,79 @@ import { loginPage } from "../../support/page_objects/navigation";
import { isXcdb, roles } from "../../support/page_objects/projectConstants";
import { isTestSuiteActive } from "../../support/page_objects/projectConstants";
export const genTest = (type, xcdb) => {
describe(`${type.toUpperCase()} Project operations`, () => {
if (!isTestSuiteActive(type, xcdb)) return;
export const genTest = (apiType, dbType) => {
describe(`${apiType.toUpperCase()} Project operations`, () => {
if (!isTestSuiteActive(apiType, dbType)) return;
before(() => {
loginPage.signIn(roles.owner.credentials);
});
before(() => {
loginPage.signIn(roles.owner.credentials);
});
it("Stop Project", () => {
//cy.visit('./#/projects')
cy.get(`.nc-${type}-project-row .mdi-stop-circle-outline`, {
timeout: 10000,
})
.should("exist")
.last()
.invoke("show")
.click();
cy.contains("Submit").closest("button").click();
it("Stop Project", () => {
//cy.visit('./#/projects')
cy.get(`.nc-${apiType}-project-row .mdi-stop-circle-outline`, {
timeout: 10000,
})
.should("exist")
.last()
.invoke("show")
.click();
cy.snipActiveModal("Modal_StopProject");
cy.contains("Submit").closest("button").click();
cy.toastWait("stopped successfully");
});
cy.toastWait("stopped successfully");
});
it("Start Project", () => {
//cy.visit('./#/projects')
cy.get(`.nc-${type}-project-row .mdi-play-circle-outline`, {
timeout: 10000,
})
.should("exist")
.last()
.invoke("show")
.click();
cy.contains("Submit").closest("button").click();
it("Start Project", () => {
//cy.visit('./#/projects')
cy.get(`.nc-${apiType}-project-row .mdi-play-circle-outline`, {
timeout: 10000,
})
.should("exist")
.last()
.invoke("show")
.click();
cy.snipActiveModal("Modal_StartProject");
cy.toastWait("started successfully");
});
cy.contains("Submit").closest("button").click();
it("Restart Project", () => {
if (!isXcdb()) {
//cy.visit('./#/projects')
cy.get(`.nc-${type}-project-row .mdi-restart`, { timeout: 10000 })
.should("exist")
.last()
.invoke("show")
.click();
cy.contains("Submit").closest("button").click();
cy.toastWait("started successfully");
});
cy.toastWait("restarted successfully");
}
});
it("Restart Project", () => {
if (!isXcdb()) {
//cy.visit('./#/projects')
cy.get(`.nc-${apiType}-project-row .mdi-restart`, {
timeout: 10000,
})
.should("exist")
.last()
.invoke("show")
.click();
cy.snipActiveModal("Modal_RestartProject");
cy.contains("Submit").closest("button").click();
cy.toastWait("restarted successfully");
}
});
it("Delete Project", () => {
//cy.visit('./#/projects')
cy.get(`.nc-${apiType}-project-row .mdi-delete-circle-outline`, {
timeout: 10000,
})
.should("exist")
.last()
.invoke("show")
.click();
cy.snipActiveModal("Modal_DeleteProject");
it("Delete Project", () => {
//cy.visit('./#/projects')
cy.get(`.nc-${type}-project-row .mdi-delete-circle-outline`, {
timeout: 10000,
})
.should("exist")
.last()
.invoke("show")
.click();
cy.contains("Submit").closest("button").click();
cy.contains("Submit").closest("button").click();
cy.toastWait("deleted successfully");
cy.toastWait("deleted successfully");
});
});
});
};
/**

10
scripts/cypress/integration/common/6f_attachments.js

@ -2,12 +2,12 @@ import { mainPage } from "../../support/page_objects/mainPage";
import { loginPage } from "../../support/page_objects/navigation";
import { isTestSuiteActive } from "../../support/page_objects/projectConstants";
export const genTest = (type, xcdb) => {
if (!isTestSuiteActive(type, xcdb)) return;
export const genTest = (apiType, dbType) => {
if (!isTestSuiteActive(apiType, dbType)) return;
describe(`${type.toUpperCase()} Columns of type attachment`, () => {
describe(`${apiType.toUpperCase()} Columns of type attachment`, () => {
before(() => {
loginPage.loginAndOpenProject(type, xcdb);
loginPage.loginAndOpenProject(apiType, dbType);
cy.openTableTab("Country", 25);
});
@ -91,7 +91,7 @@ export const genTest = (type, xcdb) => {
it(`Filter column which contain only attachments, download CSV`, () => {
// come back to main window
loginPage.loginAndOpenProject(type, xcdb);
loginPage.loginAndOpenProject(apiType, dbType);
cy.openTableTab("Country", 25);
mainPage.filterField("testAttach", "is not null", null);

207
scripts/cypress/integration/common/6g_base_share.js

@ -3,75 +3,78 @@ import { projectsPage } from "../../support/page_objects/navigation";
import { loginPage } from "../../support/page_objects/navigation";
import { isTestSuiteActive } from "../../support/page_objects/projectConstants";
import {
_advSettings,
_editSchema,
_editData,
_editComment,
_viewMenu,
_topRightMenu,
_advSettings,
_editSchema,
_editData,
_editComment,
_viewMenu,
_topRightMenu,
} from "../spec/roleValidation.spec";
let linkText = "";
export const genTest = (type, xcdb) => {
if (!isTestSuiteActive(type, xcdb)) return;
export const genTest = (apiType, dbType) => {
if (!isTestSuiteActive(apiType, dbType)) return;
const permissionValidation = (roleType) => {
it(`${roleType}: Visit base shared URL`, () => {
cy.log(linkText);
const permissionValidation = (roleType) => {
it(`${roleType}: Visit base shared URL`, () => {
cy.log(linkText);
// visit URL & wait for page load to complete
cy.visit(linkText, {
baseUrl: null,
});
projectsPage.waitHomePageLoad();
// visit URL & wait for page load to complete
cy.visit(linkText, {
baseUrl: null,
});
projectsPage.waitHomePageLoad();
cy.closeTableTab("Actor");
});
cy.closeTableTab("Actor");
});
it(`${roleType}: Validate access permissions: advance menu`, () => {
_advSettings(roleType, false);
});
it(`${roleType}: Validate access permissions: advance menu`, () => {
_advSettings(roleType, false);
});
it(`${roleType}: Validate access permissions: edit schema`, () => {
_editSchema(roleType, false);
});
it(`${roleType}: Validate access permissions: edit schema`, () => {
_editSchema(roleType, false);
});
it(`${roleType}: Validate access permissions: edit data`, () => {
_editData(roleType, false);
});
it(`${roleType}: Validate access permissions: edit data`, () => {
_editData(roleType, false);
});
it(`${roleType}: Validate access permissions: edit comments`, () => {
_editComment(roleType, false);
});
it(`${roleType}: Validate access permissions: edit comments`, () => {
_editComment(roleType, false);
});
it(`${roleType}: Validate access permissions: view's menu`, () => {
_viewMenu(roleType, false);
});
};
describe(`${type.toUpperCase()} Base VIEW share`, () => {
it(`Generate base share URL`, () => {
// click SHARE
cy.get(".nc-topright-menu").find(".nc-menu-share").click();
// Click on readonly base text
cy.getActiveModal().find(".nc-disable-shared-base").click();
// Select 'Readonly link'
cy.getActiveMenu()
.find(".caption")
.contains("Anyone with the link")
.click();
// Copy URL
cy.getActiveModal()
.find(".nc-url")
.then(($obj) => {
cy.log($obj[0]);
linkText = $obj[0].innerText.trim();
const htmlFile = `
it(`${roleType}: Validate access permissions: view's menu`, () => {
_viewMenu(roleType, false);
});
};
describe(`${apiType.toUpperCase()} Base VIEW share`, () => {
it(`Generate base share URL`, () => {
// click SHARE
cy.get(".nc-topright-menu").find(".nc-menu-share").click();
cy.snipActiveModal("Modal_BaseShare");
// Click on readonly base text
cy.getActiveModal().find(".nc-disable-shared-base").click();
// Select 'Readonly link'
cy.snipActiveMenu("Menu_ShareLink");
cy.getActiveMenu()
.find(".caption")
.contains("Anyone with the link")
.click();
// Copy URL
cy.getActiveModal()
.find(".nc-url")
.then(($obj) => {
cy.log($obj[0]);
linkText = $obj[0].innerText.trim();
const htmlFile = `
<!DOCTYPE html>
<html>
<body>
@ -87,55 +90,63 @@ style="background: transparent; "></iframe>
</body>
</html>
`;
cy.writeFile(
"scripts/cypress/fixtures/sampleFiles/iFrame.html",
htmlFile
);
cy.writeFile(
"scripts/cypress/fixtures/sampleFiles/iFrame.html",
htmlFile
);
});
});
});
permissionValidation("viewer");
permissionValidation("viewer");
it("Update to EDITOR base share link", () => {
loginPage.loginAndOpenProject(type, xcdb);
it("Update to EDITOR base share link", () => {
loginPage.loginAndOpenProject(apiType, dbType);
// click SHARE
cy.get(".nc-topright-menu").find(".nc-menu-share").click();
// click SHARE
cy.get(".nc-topright-menu").find(".nc-menu-share").click();
cy.getActiveModal().find(".nc-shared-base-role").click();
cy.getActiveModal().find(".nc-shared-base-role").click();
cy.getActiveMenu().find('[role="menuitem"]').contains("Editor").click();
});
cy.getActiveMenu()
.find('[role="menuitem"]')
.contains("Editor")
.click();
});
permissionValidation("editor");
it("Generate & verify embed HTML IFrame", { baseUrl: null }, () => {
// open iFrame html
cy.visit("scripts/cypress/fixtures/sampleFiles/iFrame.html");
// wait for iFrame to load
cy.frameLoaded(".nc-embed");
// for GQL- additionally close GQL Client window
if (type === "graphql") {
cy.iframe().find(`[title="Graphql Client"] > button.mdi-close`).click();
}
// validation for base menu opitons
cy.iframe().find(".nc-project-tree").should("exist");
cy.iframe().find(".nc-fields-menu-btn").should("exist");
cy.iframe().find(".nc-sort-menu-btn").should("exist");
cy.iframe().find(".nc-filter-menu-btn").should("exist");
cy.iframe().find(".nc-actions-menu-btn").should("exist");
// validate data (row-1)
mainPage
.getIFrameCell("FirstName", 1)
.contains("PENELOPE")
.should("exist");
mainPage.getIFrameCell("LastName", 1).contains("GUINESS").should("exist");
permissionValidation("editor");
it("Generate & verify embed HTML IFrame", { baseUrl: null }, () => {
// open iFrame html
cy.visit("scripts/cypress/fixtures/sampleFiles/iFrame.html");
// wait for iFrame to load
cy.frameLoaded(".nc-embed");
// for GQL- additionally close GQL Client window
if (apiType === "graphql") {
cy.iframe()
.find(`[title="Graphql Client"] > button.mdi-close`)
.click();
}
// validation for base menu opitons
cy.iframe().find(".nc-project-tree").should("exist");
cy.iframe().find(".nc-fields-menu-btn").should("exist");
cy.iframe().find(".nc-sort-menu-btn").should("exist");
cy.iframe().find(".nc-filter-menu-btn").should("exist");
cy.iframe().find(".nc-actions-menu-btn").should("exist");
// validate data (row-1)
mainPage
.getIFrameCell("FirstName", 1)
.contains("PENELOPE")
.should("exist");
mainPage
.getIFrameCell("LastName", 1)
.contains("GUINESS")
.should("exist");
});
});
});
};
/**

538
scripts/cypress/integration/common/7a_create_project_from_excel.js

@ -4,8 +4,8 @@
import { projectsPage } from "../../support/page_objects/navigation";
import { mainPage } from "../../support/page_objects/mainPage";
import {
roles,
isTestSuiteActive,
roles,
isTestSuiteActive,
} from "../../support/page_objects/projectConstants";
// stores sheet names (table name)
@ -21,29 +21,29 @@ let filepath = `sampleFiles/simple.xlsx`;
// let UrlFilePath = `sampleFiles/Financial Sample.xlsx`
let expectedData = {
0: ["number", "Number"],
1: ["float", "Decimal"],
2: ["text", "SingleLineText"],
0: ["number", "Number"],
1: ["float", "Decimal"],
2: ["text", "SingleLineText"],
};
// column names with spaces will be converted to include _
let UrlFileExpectedData = {
0: ["Segment", "SingleSelect", ["Government"]],
1: ["Country", "SingleSelect", ["Canada"]],
2: ["Product", "SingleSelect", ["Carretera"]],
3: ["Discount_Band", "SingleSelect", ["None"]],
4: ["Units_Sold", "Decimal", [1618.5]],
5: ["Manufacturing_Price", "Number", [3]],
6: ["Sale_Price", "Number", [20]],
7: ["Gross_Sales", "Decimal", [32370]],
8: ["Discounts", "Decimal", [0]],
9: ["Sales", "Decimal", [32370]],
10: ["COGS", "Decimal", [16185]],
11: ["Profit", "Decimal", [16185]],
12: ["Date", "Date", ["2014-01-01"]],
13: ["Month_Number", "Number", [1]],
14: ["Month_Name", "SingleSelect", ["January"]],
15: ["Year", "SingleSelect", [2014]],
0: ["Segment", "SingleSelect", ["Government"]],
1: ["Country", "SingleSelect", ["Canada"]],
2: ["Product", "SingleSelect", ["Carretera"]],
3: ["Discount_Band", "SingleSelect", ["None"]],
4: ["Units_Sold", "Decimal", [1618.5]],
5: ["Manufacturing_Price", "Number", [3]],
6: ["Sale_Price", "Number", [20]],
7: ["Gross_Sales", "Decimal", [32370]],
8: ["Discounts", "Decimal", [0]],
9: ["Sales", "Decimal", [32370]],
10: ["COGS", "Decimal", [16185]],
11: ["Profit", "Decimal", [16185]],
12: ["Date", "Date", ["2014-01-01"]],
13: ["Month_Number", "Number", [1]],
14: ["Month_Name", "SingleSelect", ["January"]],
15: ["Year", "SingleSelect", [2014]],
};
// let filepath = `sampleFiles/sample.xlsx`
@ -63,260 +63,282 @@ let UrlFileExpectedData = {
// 12: ['dateTime', 'DateTime']
// }
export const genTest = (type, xcdb) => {
if (!isTestSuiteActive(type, xcdb)) return;
describe(`Import from excel`, () => {
before(() => {
cy.task("readSheetList", {
file: `./scripts/cypress/fixtures/${filepath}`,
}).then((rows) => {
cy.log(rows);
sheetList = rows;
});
cy.task("readXlsx", {
file: `./scripts/cypress/fixtures/${filepath}`,
sheet: "Sheet2",
}).then((rows) => {
cy.log(rows);
sheetData = rows;
});
// cy.task('readXlsx', { file: `./scripts/cypress/fixtures/${UrlFilePath}`, sheet: "Sheet1" })
// .then((rows) => {
// cy.log(rows)
// UrlSheetData = rows
// })
});
export const genTest = (apiType, dbType) => {
if (!isTestSuiteActive(apiType, dbType)) return;
it("File Upload: Upload excel as template", () => {
mainPage.toolBarTopLeft(mainPage.HOME).click();
describe(`Import from excel`, () => {
before(() => {
cy.task("readSheetList", {
file: `./scripts/cypress/fixtures/${filepath}`,
}).then((rows) => {
cy.log(rows);
sheetList = rows;
});
// click on "New Project"
cy.get(":nth-child(5) > .v-btn", { timeout: 20000 }).click();
cy.task("readXlsx", {
file: `./scripts/cypress/fixtures/${filepath}`,
sheet: "Sheet2",
}).then((rows) => {
cy.log(rows);
sheetData = rows;
});
// Subsequent form, select (+ Create) option
cy.get(".nc-create-project-from-excel", { timeout: 20000 }).click({
force: true,
});
// cy.task('readXlsx', { file: `./scripts/cypress/fixtures/${UrlFilePath}`, sheet: "Sheet1" })
// .then((rows) => {
// cy.log(rows)
// UrlSheetData = rows
// })
});
cy.get(".nc-excel-import-input").attachFile(filepath);
cy.get(".nc-btn-use-template", { timeout: 120000 }).should("exist");
});
it("File Upload: Upload excel as template", () => {
mainPage.toolBarTopLeft(mainPage.HOME).click();
it("File Upload: Verify pre-load template page", () => {
cy.getActiveContentModal()
.find(".v-expansion-panel")
.then((sheets) => {
for (let i = 0; i < sheets.length; i++) {
// verify if all sheet names are correct
// cy.wrap(sheets[i]).find('.title').then((blk) => {
// cy.log(blk.text().trim())
// expect(blk.text().trim()).to.equal(sheetList[i])
// })
// click on "New Project"
cy.get(":nth-child(5) > .v-btn", { timeout: 20000 }).click();
cy.wrap(sheets[i]).contains(sheetList[i]).should("exist");
// for each sheet, expand to verify table names & their data types
cy.wrap(sheets[i]).find(".mdi-chevron-down").click();
// wait for 4 DOM rows to become visible, corresponding to 4 column names in excel
// change to avoid static wait
cy.get(".v-data-table").find("tr:visible").should("have.length", 4);
cy.get(".v-data-table")
.find("tr:visible")
.then((row) => {
for (let j = 1; j < row.length; j++) {
// column name to match input in excel
cy.wrap(row[j])
.find('[placeholder="Column name"]')
.then((obj) => {
cy.log(obj[0].value);
expect(obj[0].value).to.equal(expectedData[j - 1][0]);
});
// datatype to match expected output
cy.wrap(row[j])
.find("span.caption")
.then((obj) => {
cy.log(obj[0].innerText);
expect(obj[0].innerText).to.equal(expectedData[j - 1][1]);
});
}
});
// unwind
cy.wrap(sheets[i]).find(".mdi-chevron-down").click();
}
// Subsequent form, select (+ Create) option
cy.get(".nc-create-project-from-excel", { timeout: 20000 }).click({
force: true,
});
cy.snipActiveModal("Modal_CreateFromExcel");
cy.get(".nc-excel-import-input").attachFile(filepath);
cy.get(".nc-btn-use-template", { timeout: 120000 }).should("exist");
});
});
it("File Upload: Verify loaded data", () => {
// create rest/ gql project
cy.get(".nc-btn-use-template", { timeout: 120000 }).click();
// if (type == 'rest') {
// cy.getActiveMenu().find('[role="menuitem"]').contains('REST').click()
// } else {
// cy.getActiveMenu().find('[role="menuitem"]').contains('GQL').click()
// }
// wait for loading to be completed
projectsPage.waitHomePageLoad();
// open sheet & validate contents
// sheetData contains data read from excel in format
// 0: { float: 1.1, number: 1, text: "abc" }
// 1: { float: 1.2, number: 0, text: "def" }
cy.openTableTab("Sheet2", 2);
for (const [key, value] of Object.entries(expectedData)) {
mainPage
.getCell(value[0], 1)
.contains(sheetData[0][value[0]])
.should("exist");
mainPage
.getCell(value[0], 2)
.contains(sheetData[1][value[0]])
.should("exist");
}
cy.closeTableTab("Sheet2");
cy.openTableTab("Sheet3", 2);
for (const [key, value] of Object.entries(expectedData)) {
mainPage
.getCell(value[0], 1)
.contains(sheetData[0][value[0]])
.should("exist");
mainPage
.getCell(value[0], 2)
.contains(sheetData[1][value[0]])
.should("exist");
}
cy.closeTableTab("Sheet3");
// delete project once all operations are completed
mainPage.toolBarTopLeft(mainPage.HOME).click();
cy.get(`.nc-${type}-project-row .mdi-delete-circle-outline`, {
timeout: 10000,
})
.should("exist")
.last()
.invoke("show")
.click();
cy.contains("Submit").closest("button").click();
});
it("File Upload: Verify pre-load template page", () => {
cy.snip("ExcelImport");
cy.getActiveContentModal()
.find(".v-expansion-panel")
.then((sheets) => {
for (let i = 0; i < sheets.length; i++) {
// verify if all sheet names are correct
// cy.wrap(sheets[i]).find('.title').then((blk) => {
// cy.log(blk.text().trim())
// expect(blk.text().trim()).to.equal(sheetList[i])
// })
cy.wrap(sheets[i])
.contains(sheetList[i])
.should("exist");
// for each sheet, expand to verify table names & their data types
cy.wrap(sheets[i]).find(".mdi-chevron-down").click();
// wait for 4 DOM rows to become visible, corresponding to 4 column names in excel
// change to avoid static wait
cy.get(".v-data-table")
.find("tr:visible")
.should("have.length", 4);
cy.get(".v-data-table")
.find("tr:visible")
.then((row) => {
for (let j = 1; j < row.length; j++) {
// column name to match input in excel
cy.wrap(row[j])
.find('[placeholder="Column name"]')
.then((obj) => {
cy.log(obj[0].value);
expect(obj[0].value).to.equal(
expectedData[j - 1][0]
);
});
// datatype to match expected output
cy.wrap(row[j])
.find("span.caption")
.then((obj) => {
cy.log(obj[0].innerText);
expect(obj[0].innerText).to.equal(
expectedData[j - 1][1]
);
});
}
});
// unwind
cy.wrap(sheets[i]).find(".mdi-chevron-down").click();
}
});
});
it("URL: Upload excel as template", () => {
// click on "New Project"
cy.get(":nth-child(5) > .v-btn", { timeout: 20000 }).click();
// Subsequent form, select (+ Create) option
cy.get(".nc-create-project-from-excel", { timeout: 20000 }).click({
force: true,
});
cy.getActiveModal().find(".caption").contains("URL").click();
cy.get(".nc-excel-import-tab-item")
.find('input[type="url"]')
.click()
.type(URL);
cy.get(".nc-excel-import-tab-item")
.find("button")
.contains("Load")
.click();
cy.get(".nc-btn-use-template", { timeout: 120000 }).should("exist");
});
it("File Upload: Verify loaded data", () => {
// create rest/ gql project
cy.get(".nc-btn-use-template", { timeout: 120000 }).click();
// if (type == 'rest') {
// cy.getActiveMenu().find('[role="menuitem"]').contains('REST').click()
// } else {
// cy.getActiveMenu().find('[role="menuitem"]').contains('GQL').click()
// }
// wait for loading to be completed
projectsPage.waitHomePageLoad();
// open sheet & validate contents
// sheetData contains data read from excel in format
// 0: { float: 1.1, number: 1, text: "abc" }
// 1: { float: 1.2, number: 0, text: "def" }
cy.openTableTab("Sheet2", 2);
for (const [key, value] of Object.entries(expectedData)) {
mainPage
.getCell(value[0], 1)
.contains(sheetData[0][value[0]])
.should("exist");
mainPage
.getCell(value[0], 2)
.contains(sheetData[1][value[0]])
.should("exist");
}
cy.closeTableTab("Sheet2");
cy.openTableTab("Sheet3", 2);
for (const [key, value] of Object.entries(expectedData)) {
mainPage
.getCell(value[0], 1)
.contains(sheetData[0][value[0]])
.should("exist");
mainPage
.getCell(value[0], 2)
.contains(sheetData[1][value[0]])
.should("exist");
}
cy.closeTableTab("Sheet3");
// delete project once all operations are completed
mainPage.toolBarTopLeft(mainPage.HOME).click();
cy.get(`.nc-${apiType}-project-row .mdi-delete-circle-outline`, {
timeout: 10000,
})
.should("exist")
.last()
.invoke("show")
.click();
cy.contains("Submit").closest("button").click();
});
it("URL: Verify pre-load template page", () => {
cy.getActiveContentModal()
.find(".v-expansion-panel")
.then((sheets) => {
for (let i = 0; i < sheets.length; i++) {
// verify if all sheet names are correct
// cy.wrap(sheets[i]).find('.title').then((blk) => {
// cy.log(blk.text().trim())
// expect(blk.text().trim()).to.equal('Sheet1')
// })
it("URL: Upload excel as template", () => {
// click on "New Project"
cy.get(":nth-child(5) > .v-btn", { timeout: 20000 }).click();
cy.wrap(sheets[i]).contains("Sheet1").should("exist");
// for each sheet, expand to verify table names & their data types
cy.wrap(sheets[i]).find(".mdi-chevron-down").click();
cy.wait(3000).then(() => {
cy.get(".v-data-table")
.find("tr:visible")
.then((row) => {
// verification restricting to 10, as others need to be scrolled back into view
for (let j = 1; j <= 10 /*row.length*/; j++) {
// column name to match input in excel
cy.wrap(row[j])
.find('[placeholder="Column name"]')
.then((obj) => {
cy.log(obj[0].value);
expect(obj[0].value).to.equal(
UrlFileExpectedData[j - 1][0]
);
});
// datatype to match expected output
cy.wrap(row[j])
.find("span.caption")
.then((obj) => {
cy.log(obj[0].innerText);
expect(obj[0].innerText).to.equal(
UrlFileExpectedData[j - 1][1]
);
});
}
});
// Subsequent form, select (+ Create) option
cy.get(".nc-create-project-from-excel", { timeout: 20000 }).click({
force: true,
});
// unwind
cy.wrap(sheets[i]).find(".mdi-chevron-down").click();
}
cy.snipActiveModal("Modal_ImportExcelURL");
cy.getActiveModal().find(".caption").contains("URL").click();
cy.get(".nc-excel-import-tab-item")
.find('input[type="url"]')
.click()
.type(URL);
cy.get(".nc-excel-import-tab-item")
.find("button")
.contains("Load")
.click();
cy.get(".nc-btn-use-template", { timeout: 120000 }).should("exist");
});
});
it("URL: Verify loaded data", () => {
// create rest/ gql project
cy.get(".nc-btn-use-template", { timeout: 120000 }).click();
// wait for loading to be completed
projectsPage.waitHomePageLoad();
// open sheet & validate contents
// sheetData contains data read from excel in format
// 0: { float: 1.1, number: 1, text: "abc" }
// 1: { float: 1.2, number: 0, text: "def" }
cy.openTableTab("Sheet1", 25);
let idx = 0;
for (const [key, value] of Object.entries(UrlFileExpectedData)) {
if (UrlFileExpectedData[idx][1] != "Date")
mainPage
.getCell(value[0], 1)
.contains(UrlFileExpectedData[idx++][2][0])
.should("exist");
}
cy.closeTableTab("Sheet1");
});
it("URL: Verify pre-load template page", () => {
cy.getActiveContentModal()
.find(".v-expansion-panel")
.then((sheets) => {
for (let i = 0; i < sheets.length; i++) {
// verify if all sheet names are correct
// cy.wrap(sheets[i]).find('.title').then((blk) => {
// cy.log(blk.text().trim())
// expect(blk.text().trim()).to.equal('Sheet1')
// })
cy.wrap(sheets[i]).contains("Sheet1").should("exist");
// for each sheet, expand to verify table names & their data types
cy.wrap(sheets[i]).find(".mdi-chevron-down").click();
cy.wait(3000).then(() => {
cy.get(".v-data-table")
.find("tr:visible")
.then((row) => {
// verification restricting to 10, as others need to be scrolled back into view
for (
let j = 1;
j <= 10 /*row.length*/;
j++
) {
// column name to match input in excel
cy.wrap(row[j])
.find('[placeholder="Column name"]')
.then((obj) => {
cy.log(obj[0].value);
expect(obj[0].value).to.equal(
UrlFileExpectedData[
j - 1
][0]
);
});
// datatype to match expected output
cy.wrap(row[j])
.find("span.caption")
.then((obj) => {
cy.log(obj[0].innerText);
expect(
obj[0].innerText
).to.equal(
UrlFileExpectedData[
j - 1
][1]
);
});
}
});
});
// unwind
cy.wrap(sheets[i]).find(".mdi-chevron-down").click();
}
});
});
after(() => {
// delete project once all operations are completed
mainPage.toolBarTopLeft(mainPage.HOME).click();
cy.get(`.nc-${type}-project-row .mdi-delete-circle-outline`, {
timeout: 10000,
})
.should("exist")
.last()
.invoke("show")
.click();
cy.contains("Submit").closest("button").click();
it("URL: Verify loaded data", () => {
// create rest/ gql project
cy.get(".nc-btn-use-template", { timeout: 120000 }).click();
// wait for loading to be completed
projectsPage.waitHomePageLoad();
// open sheet & validate contents
// sheetData contains data read from excel in format
// 0: { float: 1.1, number: 1, text: "abc" }
// 1: { float: 1.2, number: 0, text: "def" }
cy.openTableTab("Sheet1", 25);
let idx = 0;
for (const [key, value] of Object.entries(UrlFileExpectedData)) {
if (UrlFileExpectedData[idx][1] != "Date")
mainPage
.getCell(value[0], 1)
.contains(UrlFileExpectedData[idx++][2][0])
.should("exist");
}
cy.closeTableTab("Sheet1");
});
after(() => {
// delete project once all operations are completed
mainPage.toolBarTopLeft(mainPage.HOME).click();
cy.get(`.nc-${apiType}-project-row .mdi-delete-circle-outline`, {
timeout: 10000,
})
.should("exist")
.last()
.invoke("show")
.click();
cy.contains("Submit").closest("button").click();
});
});
});
};
// if (typeof require !== 'undefined') XLSX = require('xlsx');

30
scripts/cypress/integration/test/explicitLogin.js

@ -1,27 +1,27 @@
import { loginPage } from "../../support/page_objects/navigation";
import { isTestSuiteActive } from "../../support/page_objects/projectConstants";
export const genTest = (type, xcdb) => {
if (!isTestSuiteActive(type, xcdb)) return;
export const genTest = (apiType, dbType) => {
// if (!isTestSuiteActive(apiType, dbType)) return;
describe(`${type.toUpperCase()} api - Login & Open project`, () => {
// Run once before test- create project (rest/graphql)
//
before(() => {
loginPage.loginAndOpenProject(type, xcdb);
describe(`${apiType.toUpperCase()} api - Login & Open project`, () => {
// Run once before test- create project (rest/graphql)
//
before(() => {
loginPage.loginAndOpenProject(apiType, dbType);
// open a table to work on views
//
// cy.openTableTab('City');
});
// open a table to work on views
//
// cy.openTableTab('City');
});
it(``, () => {
cy.log("Test-1");
it(``, () => {
cy.log("Test-1");
});
});
});
};
// genTest('rest', false)
// genTest("rest", "mysql");
/**
* @copyright Copyright (c) 2021, Xgene Cloud Ltd

22
scripts/cypress/integration/test/gqlMisc.js

@ -14,24 +14,24 @@ const {
// use 1 mode if noco.db doesnt contain user credentials (full run over GIT)
const executionMode = 1;
const nocoTestSuite = (type, xcdb) => {
setCurrentMode(type, xcdb);
const nocoTestSuite = (apiType, dbType) => {
setCurrentMode(apiType, dbType);
if (0 == executionMode) {
t0.genTest(type, xcdb);
t0.genTest(apiType, dbType);
} else {
t01.genTest(type, xcdb);
t01.genTest(apiType, dbType);
}
t6b.genTest(type, xcdb);
t6c.genTest(type, xcdb);
t6d.genTest(type, xcdb);
t6f.genTest(type, xcdb);
t6g.genTest(type, xcdb);
t6b.genTest(apiType, dbType);
t6c.genTest(apiType, dbType);
t6d.genTest(apiType, dbType);
t6f.genTest(apiType, dbType);
t6g.genTest(apiType, dbType);
// **deletes created project, hence place it @ end
t6e.genTest(type, xcdb);
t6e.genTest(apiType, dbType);
};
nocoTestSuite("graphql", false);
nocoTestSuite("graphql", "mysql");
/**
* @copyright Copyright (c) 2021, Xgene Cloud Ltd

14
scripts/cypress/integration/test/gqlRoles.js

@ -10,19 +10,19 @@ const {
// use 1 mode if noco.db doesnt contain user credentials (full run over GIT)
const executionMode = 1;
const nocoTestSuite = (type, xcdb) => {
setCurrentMode(type, xcdb);
const nocoTestSuite = (apiType, dbType) => {
setCurrentMode(apiType, dbType);
if (0 == executionMode) {
t0.genTest(type, xcdb);
t0.genTest(apiType, dbType);
} else {
t01.genTest(type, xcdb);
t01.genTest(apiType, dbType);
}
t5a.genTest(type, xcdb);
t5b.genTest(type, xcdb);
t5a.genTest(apiType, dbType);
t5b.genTest(apiType, dbType);
};
nocoTestSuite("graphql", false);
nocoTestSuite("graphql", "mysql");
/**
* @copyright Copyright (c) 2021, Xgene Cloud Ltd

32
scripts/cypress/integration/test/gqlTableOps.js

@ -19,28 +19,28 @@ const {
// use 1 mode if noco.db doesnt contain user credentials (full run over GIT)
const executionMode = 1;
const nocoTestSuite = (type, xcdb) => {
const nocoTestSuite = (apiType, dbType) => {
if (0 == executionMode) {
setCurrentMode(type, xcdb);
t0.genTest(type, xcdb);
setCurrentMode(apiType, dbType);
t0.genTest(apiType, dbType);
} else {
t01.genTest(type, xcdb);
t01.genTest(apiType, dbType);
}
t1a.genTest(type, xcdb);
t1b.genTest(type, xcdb);
t1c.genTest(type, xcdb);
t1d.genTest(type, xcdb);
t1e.genTest(type, xcdb);
t2a.genTest(type, xcdb);
t2b.genTest(type, xcdb);
t3a.genTest(type, xcdb);
t3b.genTest(type, xcdb);
t3c.genTest(type, xcdb);
t3d.genTest(type, xcdb);
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("graphql", false);
nocoTestSuite("graphql", "mysql");
/**
* @copyright Copyright (c) 2021, Xgene Cloud Ltd

22
scripts/cypress/integration/test/gqlViews.js

@ -14,23 +14,23 @@ const {
// use 1 mode if noco.db doesnt contain user credentials (full run over GIT)
const executionMode = 1;
const nocoTestSuite = (type, xcdb) => {
setCurrentMode(type, xcdb);
const nocoTestSuite = (apiType, dbType) => {
setCurrentMode(apiType, dbType);
if (0 == executionMode) {
t0.genTest(type, xcdb);
t0.genTest(apiType, dbType);
} else {
t01.genTest(type, xcdb);
t01.genTest(apiType, dbType);
}
t4a.genTest(type, xcdb);
t4b.genTest(type, xcdb);
t4c.genTest(type, xcdb);
t4d.genTest(type, xcdb);
t4e.genTest(type, xcdb);
t4f.genTest(type, xcdb);
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("graphql", false);
nocoTestSuite("graphql", "mysql");
/**
* @copyright Copyright (c) 2021, Xgene Cloud Ltd

52
scripts/cypress/integration/test/masterSuiteGql.js

@ -26,39 +26,39 @@ let t6e = require("../common/6e_project_operations");
// use 1 mode if noco.db doesnt contain user credentials (full run over GIT)
const executionMode = 1;
const nocoTestSuite = (type, xcdb) => {
const nocoTestSuite = (apiType, dbType) => {
if (0 == executionMode) {
t0.genTest(type, xcdb);
t0.genTest(apiType, dbType);
} else {
t00.genTest(type, xcdb);
t00.genTest(apiType, dbType);
}
t1a.genTest(type, xcdb);
t1b.genTest(type, xcdb);
// merged with t1b: t1c.genTest(type, xcdb)
t2a.genTest(type, xcdb);
t2b.genTest(type, xcdb);
t3a.genTest(type, xcdb);
t3b.genTest(type, xcdb);
t3c.genTest(type, xcdb);
t3d.genTest(type, xcdb);
t4a.genTest(type, xcdb);
t4b.genTest(type, xcdb);
t4c.genTest(type, xcdb);
t4d.genTest(type, xcdb);
t4e.genTest(type, xcdb);
t4f.genTest(type, xcdb);
t5a.genTest(type, xcdb);
t5b.genTest(type, xcdb);
// merged with t1a: t6a.genTest(type, xcdb)
t6c.genTest(type, xcdb);
t6d.genTest(type, xcdb);
t1a.genTest(apiType, dbType);
t1b.genTest(apiType, dbType);
// merged with t1b: t1c.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);
t4a.genTest(apiType, dbType);
t4b.genTest(apiType, dbType);
t4c.genTest(apiType, dbType);
t4d.genTest(apiType, dbType);
t4e.genTest(apiType, dbType);
t4f.genTest(apiType, dbType);
t5a.genTest(apiType, dbType);
t5b.genTest(apiType, dbType);
// merged with t1a: t6a.genTest(apiType, dbType)
t6c.genTest(apiType, dbType);
t6d.genTest(apiType, dbType);
// **deletes created project, hence place it @ end
t6e.genTest(type, xcdb);
t6e.genTest(apiType, dbType);
};
// nocoTestSuite('rest', false)
nocoTestSuite("graphql", false);
// nocoTestSuite('rest', "mysql")
nocoTestSuite("graphql", "mysql");
/**
* @copyright Copyright (c) 2021, Xgene Cloud Ltd

52
scripts/cypress/integration/test/masterSuiteRest.js

@ -26,39 +26,39 @@ let t6e = require("../common/6e_project_operations");
// use 1 mode if noco.db doesnt contain user credentials (full run over GIT)
const executionMode = 1;
const nocoTestSuite = (type, xcdb) => {
const nocoTestSuite = (apiType, dbType) => {
if (0 == executionMode) {
t0.genTest(type, xcdb);
t0.genTest(apiType, dbType);
} else {
t00.genTest(type, xcdb);
t00.genTest(apiType, dbType);
}
t1a.genTest(type, xcdb);
t1b.genTest(type, xcdb);
// merged with t1b: t1c.genTest(type, xcdb)
t2a.genTest(type, xcdb);
t2b.genTest(type, xcdb);
t3a.genTest(type, xcdb);
t3b.genTest(type, xcdb);
t3c.genTest(type, xcdb);
t3d.genTest(type, xcdb);
t4a.genTest(type, xcdb);
t4b.genTest(type, xcdb);
t4c.genTest(type, xcdb);
t4d.genTest(type, xcdb);
t4e.genTest(type, xcdb);
t4f.genTest(type, xcdb);
t5a.genTest(type, xcdb);
t5b.genTest(type, xcdb);
// merged with t1a: t6a.genTest(type, xcdb)
t6c.genTest(type, xcdb);
t6d.genTest(type, xcdb);
t1a.genTest(apiType, dbType);
t1b.genTest(apiType, dbType);
// merged with t1b: t1c.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);
t4a.genTest(apiType, dbType);
t4b.genTest(apiType, dbType);
t4c.genTest(apiType, dbType);
t4d.genTest(apiType, dbType);
t4e.genTest(apiType, dbType);
t4f.genTest(apiType, dbType);
t5a.genTest(apiType, dbType);
t5b.genTest(apiType, dbType);
// merged with t1a: t6a.genTest(apiType, dbType)
t6c.genTest(apiType, dbType);
t6d.genTest(apiType, dbType);
// **deletes created project, hence place it @ end
t6e.genTest(type, xcdb);
t6e.genTest(apiType, dbType);
};
nocoTestSuite("rest", false);
// nocoTestSuite('graphql', false)
nocoTestSuite("rest", "mysql");
// nocoTestSuite('graphql', "mysql")
/**
* @copyright Copyright (c) 2021, Xgene Cloud Ltd

61
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 <sivadstala@gmail.com>
*
* @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 <http://www.gnu.org/licenses/>.
*
*/

47
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 <sivadstala@gmail.com>
*
* @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 <http://www.gnu.org/licenses/>.
*
*/

65
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_pg_table_view_drag_drop_reorder");
let t1e = require("../common/1e_pg_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 <sivadstala@gmail.com>
*
* @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 <http://www.gnu.org/licenses/>.
*
*/

55
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 <sivadstala@gmail.com>
*
* @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 <http://www.gnu.org/licenses/>.
*
*/

24
scripts/cypress/integration/test/restMisc.js

@ -15,28 +15,28 @@ const {
// use 1 mode if noco.db doesnt contain user credentials (full run over GIT)
const executionMode = 1;
const nocoTestSuite = (type, xcdb) => {
setCurrentMode(type, xcdb);
const nocoTestSuite = (apiType, dbType) => {
setCurrentMode(apiType, dbType);
if (0 == executionMode) {
t0.genTest(type, xcdb);
t0.genTest(apiType, dbType);
} else {
t01.genTest(type, xcdb);
t01.genTest(apiType, dbType);
}
t6b.genTest(type, xcdb);
t6d.genTest(type, xcdb);
t6c.genTest(type, xcdb);
t6f.genTest(type, xcdb);
t6g.genTest(type, xcdb);
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(type, xcdb);
t6e.genTest(apiType, dbType);
// intended to keep this after earlier project deletion
// creates project using excel & deletes it
t7a.genTest(type, xcdb);
t7a.genTest(apiType, dbType);
};
nocoTestSuite("rest", false);
nocoTestSuite("rest", "mysql");
/**
* @copyright Copyright (c) 2021, Xgene Cloud Ltd

14
scripts/cypress/integration/test/restRoles.js

@ -10,19 +10,19 @@ const {
// use 1 mode if noco.db doesnt contain user credentials (full run over GIT)
const executionMode = 1;
const nocoTestSuite = (type, xcdb) => {
setCurrentMode(type, xcdb);
const nocoTestSuite = (apiType, dbType) => {
setCurrentMode(apiType, dbType);
if (0 == executionMode) {
t0.genTest(type, xcdb);
t0.genTest(apiType, dbType);
} else {
t01.genTest(type, xcdb);
t01.genTest(apiType, dbType);
}
t5a.genTest(type, xcdb);
t5b.genTest(type, xcdb);
t5a.genTest(apiType, dbType);
t5b.genTest(apiType, dbType);
};
nocoTestSuite("rest", false);
nocoTestSuite("rest", "mysql");
/**
* @copyright Copyright (c) 2021, Xgene Cloud Ltd

32
scripts/cypress/integration/test/restTableOps.js

@ -19,28 +19,28 @@ const {
// use 1 mode if noco.db doesnt contain user credentials (full run over GIT)
const executionMode = 1;
const nocoTestSuite = (type, xcdb) => {
setCurrentMode(type, xcdb);
const nocoTestSuite = (apiType, dbType) => {
setCurrentMode(apiType, dbType);
if (0 == executionMode) {
t0.genTest(type, xcdb);
t0.genTest(apiType, dbType);
} else {
t01.genTest(type, xcdb);
t01.genTest(apiType, dbType);
}
t1a.genTest(type, xcdb);
t1b.genTest(type, xcdb);
t1c.genTest(type, xcdb);
t1d.genTest(type, xcdb);
t1e.genTest(type, xcdb);
t2a.genTest(type, xcdb);
t2b.genTest(type, xcdb);
t3a.genTest(type, xcdb);
t3b.genTest(type, xcdb);
t3c.genTest(type, xcdb);
t3d.genTest(type, xcdb);
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", false);
nocoTestSuite("rest", "mysql");
/**
* @copyright Copyright (c) 2021, Xgene Cloud Ltd

22
scripts/cypress/integration/test/restViews.js

@ -14,23 +14,23 @@ const {
// use 1 mode if noco.db doesnt contain user credentials (full run over GIT)
const executionMode = 1;
const nocoTestSuite = (type, xcdb) => {
setCurrentMode(type, xcdb);
const nocoTestSuite = (apiType, dbType) => {
setCurrentMode(apiType, dbType);
if (0 == executionMode) {
t0.genTest(type, xcdb);
t0.genTest(apiType, dbType);
} else {
t01.genTest(type, xcdb);
t01.genTest(apiType, dbType);
}
t4a.genTest(type, xcdb);
t4b.genTest(type, xcdb);
t4c.genTest(type, xcdb);
t4d.genTest(type, xcdb);
t4e.genTest(type, xcdb);
t4f.genTest(type, xcdb);
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", false);
nocoTestSuite("rest", "mysql");
/**
* @copyright Copyright (c) 2021, Xgene Cloud Ltd

22
scripts/cypress/integration/test/xcdb-gqlMisc.js

@ -14,24 +14,24 @@ const {
// use 1 mode if noco.db doesnt contain user credentials (full run over GIT)
const executionMode = 1;
const nocoTestSuite = (type, xcdb) => {
setCurrentMode(type, xcdb);
const nocoTestSuite = (apiType, dbType) => {
setCurrentMode(apiType, dbType);
if (0 == executionMode) {
t0.genTest(type, xcdb);
t0.genTest(apiType, dbType);
} else {
t01.genTest(type, xcdb);
t01.genTest(apiType, dbType);
}
t6b.genTest(type, xcdb);
t6c.genTest(type, xcdb);
t6d.genTest(type, xcdb);
t6f.genTest(type, xcdb);
t6g.genTest(type, xcdb);
t6b.genTest(apiType, dbType);
t6c.genTest(apiType, dbType);
t6d.genTest(apiType, dbType);
t6f.genTest(apiType, dbType);
t6g.genTest(apiType, dbType);
// **deletes created project, hence place it @ end
t6e.genTest(type, xcdb);
t6e.genTest(apiType, dbType);
};
nocoTestSuite("graphql", true);
nocoTestSuite("graphql", "xcdb");
/**
* @copyright Copyright (c) 2021, Xgene Cloud Ltd

14
scripts/cypress/integration/test/xcdb-gqlRoles.js

@ -10,19 +10,19 @@ const {
// use 1 mode if noco.db doesnt contain user credentials (full run over GIT)
const executionMode = 1;
const nocoTestSuite = (type, xcdb) => {
setCurrentMode(type, xcdb);
const nocoTestSuite = (apiType, dbType) => {
setCurrentMode(apiType, dbType);
if (0 == executionMode) {
t0.genTest(type, xcdb);
t0.genTest(apiType, dbType);
} else {
t01.genTest(type, xcdb);
t01.genTest(apiType, dbType);
}
t5a.genTest(type, xcdb);
t5b.genTest(type, xcdb);
t5a.genTest(apiType, dbType);
t5b.genTest(apiType, dbType);
};
nocoTestSuite("graphql", true);
nocoTestSuite("graphql", "xcdb");
/**
* @copyright Copyright (c) 2021, Xgene Cloud Ltd

32
scripts/cypress/integration/test/xcdb-gqlTableOps.js

@ -19,28 +19,28 @@ const {
// use 1 mode if noco.db doesnt contain user credentials (full run over GIT)
const executionMode = 1;
const nocoTestSuite = (type, xcdb) => {
setCurrentMode(type, xcdb);
const nocoTestSuite = (apiType, dbType) => {
setCurrentMode(apiType, dbType);
if (0 == executionMode) {
t0.genTest(type, xcdb);
t0.genTest(apiType, dbType);
} else {
t01.genTest(type, xcdb);
t01.genTest(apiType, dbType);
}
t1a.genTest(type, xcdb);
t1b.genTest(type, xcdb);
t1c.genTest(type, xcdb);
t1d.genTest(type, xcdb);
t1e.genTest(type, xcdb);
t2a.genTest(type, xcdb);
t2b.genTest(type, xcdb);
t3a.genTest(type, xcdb);
t3b.genTest(type, xcdb);
t3c.genTest(type, xcdb);
t3d.genTest(type, xcdb);
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("graphql", true);
nocoTestSuite("graphql", "xcdb");
/**
* @copyright Copyright (c) 2021, Xgene Cloud Ltd

22
scripts/cypress/integration/test/xcdb-gqlViews.js

@ -14,23 +14,23 @@ const {
// use 1 mode if noco.db doesnt contain user credentials (full run over GIT)
const executionMode = 1;
const nocoTestSuite = (type, xcdb) => {
setCurrentMode(type, xcdb);
const nocoTestSuite = (apiType, dbType) => {
setCurrentMode(apiType, dbType);
if (0 == executionMode) {
t0.genTest(type, xcdb);
t0.genTest(apiType, dbType);
} else {
t01.genTest(type, xcdb);
t01.genTest(apiType, dbType);
}
t4a.genTest(type, xcdb);
t4b.genTest(type, xcdb);
t4c.genTest(type, xcdb);
t4d.genTest(type, xcdb);
t4e.genTest(type, xcdb);
t4f.genTest(type, xcdb);
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("graphql", true);
nocoTestSuite("graphql", "xcdb");
/**
* @copyright Copyright (c) 2021, Xgene Cloud Ltd

24
scripts/cypress/integration/test/xcdb-restMisc.js

@ -15,28 +15,28 @@ const {
// use 1 mode if noco.db doesnt contain user credentials (full run over GIT)
const executionMode = 1;
const nocoTestSuite = (type, xcdb) => {
setCurrentMode(type, xcdb);
const nocoTestSuite = (apiType, dbType) => {
setCurrentMode(apiType, dbType);
if (0 == executionMode) {
t0.genTest(type, xcdb);
t0.genTest(apiType, dbType);
} else {
t01.genTest(type, xcdb);
t01.genTest(apiType, dbType);
}
t6b.genTest(type, xcdb);
t6d.genTest(type, xcdb);
t6c.genTest(type, xcdb);
t6f.genTest(type, xcdb);
t6g.genTest(type, xcdb);
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(type, xcdb);
t6e.genTest(apiType, dbType);
// intended to keep this after earlier project deletion
// creates project using excel & deletes it
t7a.genTest(type, xcdb);
t7a.genTest(apiType, dbType);
};
nocoTestSuite("rest", true);
nocoTestSuite("rest", "xcdb");
/**
* @copyright Copyright (c) 2021, Xgene Cloud Ltd

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save