Merge remote-tracking branch 'origin/appbuilder/sprint-12' into feat/inspector-revamp

This commit is contained in:
Shaurya Sharma 2025-05-02 14:04:06 +05:30
commit e6ee4e5bd8
421 changed files with 11229 additions and 19794 deletions

View file

@ -2,8 +2,7 @@ name: Cypress App-Builder
on:
pull_request_target:
types: [labeled, unlabeled, closed]
types: [labeled]
workflow_dispatch:
env:
@ -13,22 +12,18 @@ env:
jobs:
Cypress-App-Builder:
runs-on: ubuntu-22.04
if: |
github.event.action == 'labeled' &&
(
github.event.label.name == 'run-cypress' ||
github.event.label.name == 'run-ce-app-builder' ||
github.event.label.name == 'run-ee-app-builder'
)
contains(github.event.pull_request.labels.*.name, 'run-ce-app-builder') ||
contains(github.event.pull_request.labels.*.name, 'run-ee-app-builder') ||
contains(github.event.pull_request.labels.*.name, 'run-cypress')
strategy:
matrix:
edition: >-
${{
contains(github.event.pull_request.labels.*.name, 'run-cypress') && fromJson('["ce", "ee"]') ||
contains(github.event.pull_request.labels.*.name, 'run-ce-app-builder') && fromJson('["ce"]') ||
contains(github.event.pull_request.labels.*.name, 'run-ee-app-builder') && fromJson('["ee"]') ||
contains(github.event.pull_request.labels.*.name, 'run-cypress') && fromJson('["ce", "ee"]') ||
fromJson('[]')
}}
@ -54,20 +49,9 @@ jobs:
git submodule foreach --recursive '
git checkout ${{ env.BRANCH_NAME }} 2>/dev/null || git checkout main'
- name: Set up Docker
uses: docker-practice/actions-setup-docker@master
- name: Run PosgtreSQL Database Docker Container
run: |
sudo docker network create tooljet
sudo docker run -d --name postgres --network tooljet -p 5432:5432 -e POSTGRES_PASSWORD=postgres -e POSTGRES_USER=postgres -e POSTGRES_PORT=5432 -d postgres:13
- name: Checkout
uses: actions/checkout@v3
with:
ref: ${{ github.event.pull_request.head.ref }}
- name: Install and build dependencies
run: |
npm cache clean --force
@ -76,50 +60,59 @@ jobs:
npm install --prefix frontend
npm run build:plugins
- name: Local development setup
run: |
sudo docker network create tooljet
sudo docker run -d --name postgres -p 5432:5432 -e POSTGRES_PASSWORD=postgres -e POSTGRES_USER=postgres -e POSTGRES_PORT=5432 -d postgres:13
- name: Run PostgREST Docker Container
run: |
sudo docker run -d --name postgrest --network tooljet -p 3001:3000 \
-e PGRST_DB_URI="postgres://postgres:postgres@localhost:5432/tooljet" \
-e PGRST_DB_ANON_ROLE="postgres" \
-e PGRST_JWT_SECRET="r9iMKoe5CRMgvJBBtp4HrqN7QiPpUToj" \
-e PGRST_DB_PRE_CONFIG=postgrest.pre_config \
postgrest/postgrest:v12.2.0
- name: Set up environment variables
run: |
echo "TOOLJET_EDITION=${{ matrix.edition == 'ee' && 'EE' || 'CE' }}" >> .env
echo "TOOLJET_EDITION=${{ matrix.edition == 'ee' && 'ee' || 'ce' }}" >> .env
echo "TOOLJET_HOST=http://localhost:8082" >> .env
echo "LOCKBOX_MASTER_KEY=cd97331a419c09387bef49787f7da8d2a81d30733f0de6bed23ad8356d2068b2" >> .env
echo "SECRET_KEY_BASE=7073b9a35a15dd20914ae17e36a693093f25b74b96517a5fec461fc901c51e011cd142c731bee48c5081ec8bac321c1f259ef097ef2a16f25df17a3798c03426" >> .env
echo "SECRET_KEY_BASE=7073b9a35a15dd20914ae17e36a693093f25b74b96517a5fec461fc901c51e011cd142c731bee48c5081ec8bac321c1f259ef097ef2a16f25df17a3798c03426" >> .env
echo "PG_DB=tooljet_development" >> .env
echo "PG_USER=postgres" >> .env
echo "PG_HOST=localhost" >> .env
echo "PG_PASS=postgres" >> .env
echo "PG_PORT=5432" >> .env
echo "ENABLE_TOOLJET_DB=true" >> .env
echo "TOOLJET_DB=tooljet" >> .env
echo "TOOLJET_DB=tooljet_db" >> .env
echo "TOOLJET_DB_USER=postgres" >> .env
echo "TOOLJET_DB_HOST=localhost" >> .env
echo "TOOLJET_DB_PASS=postgres" >> .env
echo "PGRST_JWT_SECRET=r9iMKoe5CRMgvJBBtp4HrqN7QiPpUToj" >> .env
echo "PGRST_HOST=localhost:3001" >> .env
echo "TOOLJET_DB_STATEMENT_TIMEOUT=60000" >> .env
echo "TOOLJET_DB_RECONFIG=true" >> .env
echo "PGRST_JWT_SECRET=r9iMKoe5CRMgvJBBtp4HrqN7QiPpUToj" >> .env
echo "PGRST_HOST=localhost:3001" >> .env
echo "PGRST_DB_PRE_CONFIG=postgrest.pre_config" >> .env
echo "PGRST_DB_URI=postgres://postgres:postgres@localhost:5432/tooljet" >> .env
echo "ENABLE_MARKETPLACE_FEATURE=true" >> .env
echo "ENABLE_MARKETPLACE_DEV_MODE=true" >> .env
echo "ENABLE_PRIVATE_APP_EMBED=true" >> .env
- name: Set up database
run: |
npm run --prefix server db:create
npm run --prefix server db:reset
npm run --prefix server db:seed
- name: sleep 5
run: sleep 5
- name: Run PostgREST Docker Container
- name: Start services
run: |
sudo docker run -d --name postgrest --network tooljet -p 3001:3000 \
-e PGRST_DB_URI="postgres://postgres:postgres@postgres:5432/tooljet" -e PGRST_DB_ANON_ROLE="postgres" -e PGRST_JWT_SECRET="r9iMKoe5CRMgvJBBtp4HrqN7QiPpUToj" -e PGRST_DB_PRE_CONFIG=postgrest.pre_config \
postgrest/postgrest:v12.2.0
- name: Run plugins compilation in watch mode
run: cd plugins && npm start &
- name: Run the server
run: cd server && npm run start:dev &
- name: Run the client
run: cd frontend && npm start &
cd plugins && npm start &
cd server && npm run start:dev &
cd frontend && npm start &
- name: Wait for the server to be ready
run: |
@ -128,6 +121,18 @@ jobs:
sleep 5
done'
- name: Seeding (Setup Super Admin)
run: |
curl 'http://localhost:3000/api/onboarding/setup-super-admin' \
-H 'Content-Type: application/json' \
--data-raw '{
"companyName": "ToolJet",
"name": "The Developer",
"workspaceName": "Tooljet'\''s workspace",
"email": "dev@tooljet.io",
"password": "password"
}'
- name: docker logs
run: sudo docker logs postgrest
@ -140,7 +145,7 @@ jobs:
dir: "./cypress-tests"
- name: App builder
uses: cypress-io/github-action@v5
uses: cypress-io/github-action@v6
with:
working-directory: ./cypress-tests
config: "baseUrl=http://localhost:8082"
@ -150,13 +155,13 @@ jobs:
uses: actions/upload-artifact@v4
if: always()
with:
name: screenshots
name: screenshots-appbuilder-${{ matrix.edition }}
path: cypress-tests/cypress/screenshots
Cypress-App-builder-Subpath:
Cypress-App-builder-Subpath:
runs-on: ubuntu-22.04
if: ${{ github.event.action == 'labeled' && github.event.label.name == 'run-cypress-app-builder-subpath' }}
if: contains(github.event.pull_request.labels.*.name, 'run-cypress') ||
contains(github.event.pull_request.labels.*.name, 'run-cypress-app-builder-subpath')
steps:
- name: Checkout
@ -164,73 +169,6 @@ jobs:
with:
ref: ${{ github.event.pull_request.head.ref }}
# Create Docker Buildx builder with platform configuration
- name: Set up Docker Buildx
run: |
mkdir -p ~/.docker/cli-plugins
curl -SL https://github.com/docker/buildx/releases/download/v0.11.0/buildx-v0.11.0.linux-amd64 -o ~/.docker/cli-plugins/docker-buildx
chmod a+x ~/.docker/cli-plugins/docker-buildx
docker buildx create --name mybuilder --platform linux/arm64,linux/amd64,linux/amd64/v2,linux/riscv64,linux/ppc64le,linux/s390x,linux/386,linux/mips64le,linux/mips64,linux/arm/v7,linux/arm/v6
docker buildx use mybuilder
- name: Set DOCKER_CLI_EXPERIMENTAL
run: echo "DOCKER_CLI_EXPERIMENTAL=enabled" >> $GITHUB_ENV
- name: use mybuilder buildx
run: docker buildx use mybuilder
- name: Build docker image
run: docker buildx build --platform=linux/amd64 -f docker/production.Dockerfile . -t tooljet/tj-osv:cypressplaform
- name: Set up environment variables
run: |
echo "TOOLJET_HOST=http://localhost:3000" >> .env
echo "LOCKBOX_MASTER_KEY=cd97331a419c09387bef49787f7da8d2a81d30733f0de6bed23ad8356d2068b2" >> .env
echo "SECRET_KEY_BASE=7073b9a35a15dd20914ae17e36a693093f25b74b96517a5fec461fc901c51e011cd142c731bee48c5081ec8bac321c1f259ef097ef2a16f25df17a3798c03426" >> .env
echo "PG_DB=tooljet_development" >> .env
echo "PG_USER=postgres" >> .env
echo "PG_HOST=postgres" >> .env
echo "PG_PASS=postgres" >> .env
echo "PG_PORT=5432" >> .env
echo "ENABLE_TOOLJET_DB=true" >> .env
echo "TOOLJET_DB=tooljet_db" >> .env
echo "TOOLJET_DB_USER=postgres" >> .env
echo "TOOLJET_DB_HOST=postgres" >> .env
echo "TOOLJET_DB_PASS=postgres" >> .env
echo "PGRST_JWT_SECRET=r9iMKoe5CRMgvJBBtp4HrqN7QiPpUToj" >> .env
echo "PGRST_HOST=postgrest" >> .env
echo "PGRST_DB_URI=postgres://postgres:postgres@postgres/tooljet_db" >> .env
echo "SSO_GIT_OAUTH2_CLIENT_ID=dummy" >> .env
echo "SSO_GIT_OAUTH2_CLIENT_SECRET=dummy" >> .env
echo "SSO_GIT_OAUTH2_HOST=dummy" >> .env
echo "SSO_GOOGLE_OAUTH2_CLIENT_ID=dummy" >> .env
echo "SUB_PATH=/apps/tooljet/" >> .env
echo "NODE_ENV=production" >> .env
echo "SERVE_CLIENT=true" >> .env
echo "ENABLE_PRIVATE_APP_EMBED=true" >> .env
- name: Pulling the docker-compose file
run: curl -LO https://tooljet-test.s3.us-west-1.amazonaws.com/docker-compose.yaml && mkdir postgres_data
- name: Run docker-compose file
run: docker-compose up -d
- name: Checking containers
run: docker ps -a
- name: docker logs
run: sudo docker logs Tooljet-app
- name: Wait for the server to be ready
run: |
timeout 1500 bash -c '
until curl --silent --fail http://localhost:80/apps/tooljet/; do
sleep 5
done'
- name: Seeding
run: docker exec Tooljet-app npm run db:seed:prod
- name: Create Cypress environment file
id: create-json
uses: jsdaniell/create-json@1.1.2

View file

@ -2,7 +2,7 @@ name: Cypress Marketplace
on:
pull_request_target:
types: [labeled, unlabeled, closed]
types: [labeled]
workflow_dispatch:
@ -14,13 +14,9 @@ jobs:
Cypress-Marketplace:
runs-on: ubuntu-22.04
if: |
github.event.action == 'labeled' &&
(
github.event.label.name == 'run-cypress' ||
github.event.label.name == 'run-ce-cypress-marketplace' ||
github.event.label.name == 'run-ee-cypress-marketplace'
)
if: contains(github.event.pull_request.labels.*.name, 'run-cypress') ||
contains(github.event.pull_request.labels.*.name, 'run-ce-cypress-marketplace') ||
contains(github.event.pull_request.labels.*.name, 'run-ee-cypress-marketplace')
strategy:
matrix:
@ -44,7 +40,7 @@ jobs:
mkdir -p ~/.docker/cli-plugins
curl -SL https://github.com/docker/buildx/releases/download/v0.11.0/buildx-v0.11.0.linux-amd64 -o ~/.docker/cli-plugins/docker-buildx
chmod a+x ~/.docker/cli-plugins/docker-buildx
docker buildx create --name mybuilder --platform linux/arm64,linux/amd64,linux/amd64/v2,linux/riscv64,linux/ppc64le,linux/s390x,linux/386,linux/mips64le,linux/mips64,linux/arm/v7,linux/arm/v6
docker buildx create --name mybuilder --platform linux/arm64,linux/amd64
docker buildx use mybuilder
- name: Set DOCKER_CLI_EXPERIMENTAL
@ -67,8 +63,8 @@ jobs:
with:
context: .
file: docker/ce-production.Dockerfile
push: false
tags: tooljet/tj-osv:${{ env.SAFE_BRANCH_NAME }}
push: true
tags: tooljet/tj-osv:${{ env.SAFE_BRANCH_NAME }}-ce
platforms: linux/amd64
env:
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
@ -80,8 +76,8 @@ jobs:
with:
context: .
file: docker/ee/ee-production.Dockerfile
push: false
tags: tooljet/tj-osv:${{ env.SAFE_BRANCH_NAME }}
push: true
tags: tooljet/tj-osv:${{ env.SAFE_BRANCH_NAME }}-ee
platforms: linux/amd64
env:
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
@ -116,10 +112,16 @@ jobs:
- name: Pulling the docker-compose file
run: curl -LO https://tooljet-test.s3.us-west-1.amazonaws.com/docker-compose.yaml && mkdir postgres_data
- name: Update docker-compose file
- name: Update docker-compose file for CE
run: |
# Update docker-compose.yaml with the new image
sed -i '/^[[:space:]]*tooljet:/,/^$/ s|^\([[:space:]]*image:[[:space:]]*\).*|\1tooljet/tj-osv:${{ env.SAFE_BRANCH_NAME }}|' docker-compose.yaml
sed -i '/^[[:space:]]*tooljet:/,/^$/ s|^\([[:space:]]*image:[[:space:]]*\).*|\1tooljet/tj-osv:${{ env.SAFE_BRANCH_NAME }}-ce|' docker-compose.yaml
- name: Update docker-compose file for CE
if: matrix.edition == 'ee'
run: |
# Update docker-compose.yaml with the new image
sed -i '/^[[:space:]]*tooljet:/,/^$/ s|^\([[:space:]]*image:[[:space:]]*\).*|\1tooljet/tj-osv:${{ env.SAFE_BRANCH_NAME }}-ee|' docker-compose.yaml
- name: Install Docker Compose
run: |
@ -132,6 +134,9 @@ jobs:
- name: Checking containers
run: docker ps -a
- name: Checking containers
run: docker ps -a
- name: docker logs
run: sudo docker logs Tooljet-app
@ -142,8 +147,18 @@ jobs:
sleep 5
done'
- name: Seeding
run: docker exec Tooljet-app npm run db:seed:prod
- name: Seeding (Setup Super Admin)
run: |
curl 'http://localhost:3000/api/onboarding/setup-super-admin' \
-H 'Content-Type: application/json' \
--data-raw '{
"companyName": "ToolJet",
"name": "The Developer",
"workspaceName": "Tooljet'\''s workspace",
"email": "dev@tooljet.io",
"password": "password"
}'
- name: Create Cypress environment file
id: create-json
@ -170,7 +185,8 @@ jobs:
Cypress-Marketplace-Subpath:
runs-on: ubuntu-22.04
if: ${{ github.event.action == 'labeled' && github.event.label.name == 'run-cypress-marketplace-subpath' }}
if: contains(github.event.pull_request.labels.*.name, 'run-cypress') ||
contains(github.event.pull_request.labels.*.name, 'run-cypress-marketplace-subpath')
steps:
- name: Checkout

View file

@ -2,7 +2,7 @@ name: Cypress Platform
on:
pull_request_target:
types: [labeled, unlabeled, closed]
types: [labeled]
workflow_dispatch:
env:
@ -12,14 +12,9 @@ env:
jobs:
Cypress-Platform:
runs-on: ubuntu-22.04
if: |
github.event.action == 'labeled' &&
(
github.event.label.name == 'run-cypress' ||
github.event.label.name == 'run-ce-cypress-platform' ||
github.event.label.name == 'run-ee-cypress-platform'
)
if: contains(github.event.pull_request.labels.*.name, 'run-cypress') ||
contains(github.event.pull_request.labels.*.name, 'run-ce-cypress-platform') ||
contains(github.event.pull_request.labels.*.name, 'run-ee-cypress-platform')
strategy:
matrix:
edition: >-
@ -102,6 +97,10 @@ jobs:
echo "ENABLE_MARKETPLACE_FEATURE=true" >> .env
echo "ENABLE_MARKETPLACE_DEV_MODE=true" >> .env
echo "ENABLE_PRIVATE_APP_EMBED=true" >> .env
echo "SSO_GOOGLE_OAUTH2_CLIENT_ID=123456789.apps.googleusercontent.com" >> .env
echo "SSO_GOOGLE_OAUTH2_CLIENT_SECRET=ABCGFDNF-FHSDVFY-bskfh6234" >> .env
echo "SSO_GIT_OAUTH2_CLIENT_ID=1234567890" >> .env
echo "SSO_GIT_OAUTH2_CLIENT_SECRET=3346shfvkdjjsfkvxce32854e026a4531ed" >> .env
- name: Set up database
run: |
@ -147,13 +146,27 @@ jobs:
name: screenshots-${{ matrix.edition }}
path: cypress-tests/cypress/screenshots
Cypress-Platform-Subpath:
runs-on: ubuntu-22.04
if: |
github.event.action == 'labeled' &&
(github.event.label.name == 'run-cypress-platform-subpath' ||
github.event.label.name == 'run-proxy-platform')
github.event.action == 'labeled' &&
(
github.event.label.name == 'run-cypress-platform-subpath' ||
github.event.label.name == 'run-proxy-platform' ||
github.event.label.name == 'run-ce-cypress-platform-subpath' ||
github.event.label.name == 'run-ee-cypress-platform-subpath'
)
strategy:
matrix:
edition: >-
${{
contains(github.event.pull_request.labels.*.name, 'run-cypress-platform-subpath') && fromJson('["ce", "ee"]') ||
contains(github.event.pull_request.labels.*.name, 'run-proxy-platform') && fromJson('["ce", "ee"]') ||
contains(github.event.pull_request.labels.*.name, 'run-ce-cypress-platform-subpath') && fromJson('["ce"]') ||
contains(github.event.pull_request.labels.*.name, 'run-ee-cypress-platform-subpath') && fromJson('["ee"]') ||
fromJson('[]')
}}
steps:
- name: Setup Node.js
@ -161,11 +174,22 @@ jobs:
with:
node-version: 18.18.2
- name: Checkout
- name: Set up Git authentication for private submodules
run: |
git config --global url."https://x-access-token:${{ secrets.CUSTOM_GITHUB_TOKEN }}@github.com/".insteadOf "https://github.com/"
- name: Checkout with Submodules
uses: actions/checkout@v3
with:
ref: ${{ github.event.pull_request.head.ref }}
- name: Checking out the correct branch for submodules EE
if: matrix.edition == 'ee'
run: |
git submodule update --init --recursive
git submodule foreach --recursive '
git checkout ${{ env.BRANCH_NAME }} 2>/dev/null || git checkout main'
- name: Set up Docker configuration
run: |
mkdir -p ~/.docker/cli-plugins
@ -186,13 +210,14 @@ jobs:
uses: docker/build-push-action@v4
with:
context: .
file: docker/production.Dockerfile
file: ${{ matrix.edition == 'ee' && 'docker/ee/ee-production.Dockerfile' || 'docker/ce-production.Dockerfile' }}
push: true
tags: tooljet/tj-osv:${{ env.SAFE_BRANCH_NAME }}
platforms: linux/amd64
- name: Set up environment variables
run: |
echo "TOOLJET_EDITION=${{ matrix.edition == 'ee' && 'ee' || 'ce' }}" >> .env
echo "TOOLJET_HOST=http://localhost:3000" >> .env
echo "LOCKBOX_MASTER_KEY=cd97331a419c09387bef49787f7da8d2a81d30733f0de6bed23ad8356d2068b2" >> .env
echo "SECRET_KEY_BASE=7073b9a35a15dd20914ae17e36a693093f25b74b96517a5fec461fc901c51e011cd142c731bee48c5081ec8bac321c1f259ef097ef2a16f25df17a3798c03426" >> .env
@ -254,15 +279,30 @@ jobs:
uses: actions/upload-artifact@v4
if: always()
with:
name: screenshots
name: screenshots-${{ matrix.edition }}
path: cypress-tests/cypress/screenshots
Cypress-Platform-Proxy:
runs-on: ubuntu-22.04
if: |
github.event.action == 'labeled' &&
(github.event.label.name == 'run-cypress-platform-proxy' ||
github.event.label.name == 'run-proxy-platform')
github.event.action == 'labeled' &&
(
github.event.label.name == 'run-cypress-platform-proxy' ||
github.event.label.name == 'run-proxy-platform' ||
github.event.label.name == 'run-ce-cypress-platform-proxy' ||
github.event.label.name == 'run-ee-cypress-platform-proxy'
)
strategy:
matrix:
edition: >-
${{
contains(github.event.pull_request.labels.*.name, 'run-cypress-platform-proxy') && fromJson('["ce", "ee"]') ||
contains(github.event.pull_request.labels.*.name, 'run-proxy-platform') && fromJson('["ce", "ee"]') ||
contains(github.event.pull_request.labels.*.name, 'run-ce-cypress-platform-proxy') && fromJson('["ce"]') ||
contains(github.event.pull_request.labels.*.name, 'run-ee-cypress-platform-proxy') && fromJson('["ee"]') ||
fromJson('[]')
}}
steps:
- name: Setup Node.js
@ -270,11 +310,22 @@ jobs:
with:
node-version: 18.18.2
- name: Checkout
- name: Set up Git authentication for private submodules
run: |
git config --global url."https://x-access-token:${{ secrets.CUSTOM_GITHUB_TOKEN }}@github.com/".insteadOf "https://github.com/"
- name: Checkout with Submodules
uses: actions/checkout@v3
with:
ref: ${{ github.event.pull_request.head.ref }}
- name: Checking out the correct branch for submodules EE
if: matrix.edition == 'ee'
run: |
git submodule update --init --recursive
git submodule foreach --recursive '
git checkout ${{ env.BRANCH_NAME }} 2>/dev/null || git checkout main'
- name: Set up Docker configuration
run: |
mkdir -p ~/.docker/cli-plugins
@ -295,13 +346,14 @@ jobs:
uses: docker/build-push-action@v4
with:
context: .
file: docker/production.Dockerfile
file: ${{ matrix.edition == 'ee' && 'docker/ee/ee-production.Dockerfile' || 'docker/ce-production.Dockerfile' }}
push: true
tags: tooljet/tj-osv:${{ env.SAFE_BRANCH_NAME }}
platforms: linux/amd64
- name: Set up environment variables
run: |
echo "TOOLJET_EDITION=${{ matrix.edition == 'ee' && 'ee' || 'ce' }}" >> .env
echo "TOOLJET_HOST=http://localhost:3000" >> .env
echo "LOCKBOX_MASTER_KEY=cd97331a419c09387bef49787f7da8d2a81d30733f0de6bed23ad8356d2068b2" >> .env
echo "SECRET_KEY_BASE=7073b9a35a15dd20914ae17e36a693093f25b74b96517a5fec461fc901c51e011cd142c731bee48c5081ec8bac321c1f259ef097ef2a16f25df17a3798c03426" >> .env
@ -375,15 +427,30 @@ jobs:
uses: actions/upload-artifact@v4
if: always()
with:
name: screenshots
name: screenshots-${{ matrix.edition }}
path: cypress-tests/cypress/screenshots
Cypress-Platform-Proxy-Subpath:
runs-on: ubuntu-22.04
if: |
github.event.action == 'labeled' &&
(github.event.label.name == 'run-cypress-platform-proxy-subpath' ||
github.event.label.name == 'run-proxy-platform')
github.event.action == 'labeled' &&
(
github.event.label.name == 'run-cypress-platform-proxy-subpath' ||
github.event.label.name == 'run-proxy-platform' ||
github.event.label.name == 'run-ce-cypress-platform-proxy-subpath' ||
github.event.label.name == 'run-ee-cypress-platform-proxy-subpath'
)
strategy:
matrix:
edition: >-
${{
contains(github.event.pull_request.labels.*.name, 'run-cypress-platform-proxy-subpath') && fromJson('["ce", "ee"]') ||
contains(github.event.pull_request.labels.*.name, 'run-proxy-platform') && fromJson('["ce", "ee"]') ||
contains(github.event.pull_request.labels.*.name, 'run-ce-cypress-platform-proxy-subpath') && fromJson('["ce"]') ||
contains(github.event.pull_request.labels.*.name, 'run-ee-cypress-platform-proxy-subpath') && fromJson('["ee"]') ||
fromJson('[]')
}}
steps:
- name: Setup Node.js
@ -391,11 +458,22 @@ jobs:
with:
node-version: 18.18.2
- name: Checkout
- name: Set up Git authentication for private submodules
run: |
git config --global url."https://x-access-token:${{ secrets.CUSTOM_GITHUB_TOKEN }}@github.com/".insteadOf "https://github.com/"
- name: Checkout with Submodules
uses: actions/checkout@v3
with:
ref: ${{ github.event.pull_request.head.ref }}
- name: Checking out the correct branch for submodules EE
if: matrix.edition == 'ee'
run: |
git submodule update --init --recursive
git submodule foreach --recursive '
git checkout ${{ env.BRANCH_NAME }} 2>/dev/null || git checkout main'
- name: Set up Docker configuration
run: |
mkdir -p ~/.docker/cli-plugins
@ -416,13 +494,14 @@ jobs:
uses: docker/build-push-action@v4
with:
context: .
file: docker/production.Dockerfile
file: ${{ matrix.edition == 'ee' && 'docker/ee/ee-production.Dockerfile' || 'docker/ce-production.Dockerfile' }}
push: true
tags: tooljet/tj-osv:${{ env.SAFE_BRANCH_NAME }}
platforms: linux/amd64
- name: Set up environment variables
run: |
echo "TOOLJET_EDITION=${{ matrix.edition == 'ee' && 'ee' || 'ce' }}" >> .env
echo "TOOLJET_HOST=http://localhost:3000" >> .env
echo "LOCKBOX_MASTER_KEY=cd97331a419c09387bef49787f7da8d2a81d30733f0de6bed23ad8356d2068b2" >> .env
echo "SECRET_KEY_BASE=7073b9a35a15dd20914ae17e36a693093f25b74b96517a5fec461fc901c51e011cd142c731bee48c5081ec8bac321c1f259ef097ef2a16f25df17a3798c03426" >> .env
@ -497,5 +576,5 @@ jobs:
uses: actions/upload-artifact@v4
if: always()
with:
name: screenshots
name: screenshots-${{ matrix.edition }}
path: cypress-tests/cypress/screenshots

View file

@ -137,7 +137,8 @@ jobs:
uses: docker/build-push-action@v4
with:
context: .
args: ${{ secrets.CUSTOM_GITHUB_TOKEN }}
build-args: |
CUSTOM_GITHUB_TOKEN=${{ secrets.CUSTOM_GITHUB_TOKEN }}
file: docker/ee/ee-production.Dockerfile
push: true
tags: tooljet/tooljet-ee:${{ github.event.release.tag_name }},tooljet/tooljet-ee:ee-lts-latest,tooljet/tooljet:ee-lts-latest,tooljet/tooljet:${{ github.event.release.tag_name }}
@ -152,8 +153,9 @@ jobs:
uses: docker/build-push-action@v4
with:
context: .
args: ${{ secrets.CUSTOM_GITHUB_TOKEN }}
file: docker/ee-production.Dockerfile
build-args: |
CUSTOM_GITHUB_TOKEN=${{ secrets.CUSTOM_GITHUB_TOKEN }}
file: docker/ee/ee-production.Dockerfile
push: true
tags: tooljet/tooljet-ee:${{ github.event.release.tag_name }},tooljet/tooljet-ee:ee-lts-latest,tooljet/tooljet:ee-lts-latest,tooljet/tooljet:${{ github.event.release.tag_name }}
platforms: linux/amd64
@ -230,3 +232,95 @@ jobs:
# fi
# curl -X POST -H 'Content-type: application/json' --data "{\"text\":\"$message\"}" ${{ secrets.SLACK_WEBHOOK_URL }}
try-tooljet-image-build:
runs-on: ubuntu-latest
needs: build-tooljet-image-for-ee-edtion
if: ${{ needs.build-tooljet-image-for-ee-edtion.result == 'success' }}
steps:
- name: Checkout code to develop
if: "!contains(github.event.release.tag_name, 'ee-lts')"
uses: actions/checkout@v2
with:
ref: refs/heads/main
- name: Checkout code to lts-3.0
if: contains(github.event.release.tag_name, '-ee-lts')
uses: actions/checkout@v2
with:
ref: refs/heads/lts-3.0
# Create Docker Buildx builder with platform configuration
- name: Set up Docker Buildx
run: |
mkdir -p ~/.docker/cli-plugins
curl -SL https://github.com/docker/buildx/releases/download/v0.11.0/buildx-v0.11.0.linux-amd64 -o ~/.docker/cli-plugins/docker-buildx
chmod a+x ~/.docker/cli-plugins/docker-buildx
docker buildx create --name mybuilder --platform linux/arm64,linux/amd64,linux/amd64/v2,linux/riscv64,linux/ppc64le,linux/s390x,linux/386,linux/mips64le,linux/mips64,linux/arm/v7,linux/arm/v6
docker buildx use mybuilder
- name: Set DOCKER_CLI_EXPERIMENTAL
run: echo "DOCKER_CLI_EXPERIMENTAL=enabled" >> $GITHUB_ENV
- name: use mybuilder buildx
run: docker buildx use mybuilder
- name: Docker Login
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Check if Docker image is present
id: check-image-presence
run: |
response=$(curl -s "https://hub.docker.com/v2/repositories/tooljet/tooljet/tags/${{ github.event.release.tag_name }}")
if [[ $? -ne 0 ]]; then
echo "Failed to fetch JSON response. Stopping workflow execution."
exit 1
fi
if [[ $response == *"tag '${{ github.event.release.tag_name }}' not found"* ]]; then
echo "Docker image tag '${{ github.event.release.tag_name }}' not present."
exit 1
else
echo "Docker image tag '${{ github.event.release.tag_name }}' is present."
fi
- name: Build and Push Docker image for non-EE-LTS
if: "!contains(github.event.release.tag_name, '-ee-lts')"
uses: docker/build-push-action@v4
with:
context: .
file: docker/ee/ee-try-tooljet.Dockerfile
push: true
tags: tooljet/try:${{ github.event.release.tag_name }},tooljet/try:ee-latest
platforms: linux/amd64
env:
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
- name: Build and Push Docker image for EE-LTS-3.0
if: contains(github.event.release.tag_name, '-ee-lts')
uses: docker/build-push-action@v4
with:
context: .
file: docker/ee/ee-try-tooljet-lts.Dockerfile
push: true
tags: tooljet/try:${{ github.event.release.tag_name }},tooljet/try:ee-lts-latest
platforms: linux/amd64
env:
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
- name: Send Slack Notification
run: |
if [[ "${{ job.status }}" == "success" ]]; then
message="Try-ToolJet image published:\\n\`tooljet/try:${{ github.event.release.tag_name }}\`"
else
message="Job '${{ env.JOB_NAME }}' failed! tooljet/try:${{ github.event.release.tag_name }}"
fi
curl -X POST -H 'Content-type: application/json' --data "{\"text\":\"$message\"}" ${{ secrets.SLACK_WEBHOOK_URL }}

View file

@ -12,7 +12,7 @@ permissions:
jobs:
# Community Edition
# Community Edition CE
create-ce-review-app:
if: ${{ github.event.action == 'labeled' && (github.event.label.name == 'create-ce-review-app' || github.event.label.name == 'review-app') }}
runs-on: ubuntu-latest
@ -72,7 +72,7 @@ jobs:
"envVars": [
{
"key": "PG_HOST",
"value": "${{ secrets.RENDER_PG_HOST }}"
"value": "localhost"
},
{
"key": "PG_PORT",
@ -80,11 +80,11 @@ jobs:
},
{
"key": "PG_USER",
"value": "${{ secrets.RENDER_PG_USER }}"
"value": "tooljet"
},
{
"key": "PG_PASS",
"value": "${{ secrets.RENDER_PG_PASS }}"
"value": "postgres"
},
{
"key": "PG_DB",
@ -96,15 +96,15 @@ jobs:
},
{
"key": "TOOLJET_DB_HOST",
"value": "${{ secrets.RENDER_PG_HOST }}"
"value": "localhost"
},
{
"key": "TOOLJET_DB_USER",
"value": "${{ secrets.RENDER_PG_USER }}"
"value": "tooljet"
},
{
"key": "TOOLJET_DB_PASS",
"value": "${{ secrets.RENDER_PG_PASS }}"
"value": "postgres"
},
{
"key": "TOOLJET_DB_PORT",
@ -116,7 +116,7 @@ jobs:
},
{
"key": "PGRST_DB_URI",
"value": "postgres://${{ secrets.RENDER_PG_USER }}:${{ secrets.RENDER_PG_PASS }}@${{ secrets.RENDER_PG_HOST }}/${{ env.PR_NUMBER }}-ce-tjdb"
"value": "postgres://tooljet:postgres@localhost/${{ env.PR_NUMBER }}-ce-tjdb"
},
{
"key": "PGRST_HOST",
@ -162,18 +162,6 @@ jobs:
"key": "SMTP_PASSWORD",
"value": "${{ secrets.RENDER_SMTP_PASSWORD }}"
},
{
"key": "TEMPORAL_SERVER_ADDRESS",
"value": "https://auto-setup-1-25-1.onrender.com"
},
{
"key": "TEMPORAL_TASK_QUEUE_NAME_FOR_WORKFLOWS",
"value": "tooljet-ce-pr-${{ env.PR_NUMBER }}"
},
{
"key": "TOOLJET_WORKFLOWS_TEMPORAL_NAMESPACE",
"value": "default"
},
{
"key": "TOOLJET_MARKETPLACE_URL",
"value": "${{ secrets.MARKETPLACE_BUCKET }}"
@ -424,7 +412,7 @@ jobs:
"envVars": [
{
"key": "PG_HOST",
"value": "${{ secrets.RENDER_PG_HOST }}"
"value": "localhost"
},
{
"key": "PG_PORT",
@ -432,11 +420,11 @@ jobs:
},
{
"key": "PG_USER",
"value": "${{ secrets.RENDER_PG_USER }}"
"value": "tooljet"
},
{
"key": "PG_PASS",
"value": "${{ secrets.RENDER_PG_PASS }}"
"value": "postgres"
},
{
"key": "PG_DB",
@ -448,15 +436,15 @@ jobs:
},
{
"key": "TOOLJET_DB_HOST",
"value": "${{ secrets.RENDER_PG_HOST }}"
"value": "localhost"
},
{
"key": "TOOLJET_DB_USER",
"value": "${{ secrets.RENDER_PG_USER }}"
"value": "tooljet"
},
{
"key": "TOOLJET_DB_PASS",
"value": "${{ secrets.RENDER_PG_PASS }}"
"value": "postgres"
},
{
"key": "TOOLJET_DB_PORT",
@ -468,7 +456,7 @@ jobs:
},
{
"key": "PGRST_DB_URI",
"value": "postgres://${{ secrets.RENDER_PG_USER }}:${{ secrets.RENDER_PG_PASS }}@${{ secrets.RENDER_PG_HOST }}/${{ env.PR_NUMBER }}-ee-tjdb"
"value": "postgres://tooljet:postgres@localhost/${{ env.PR_NUMBER }}-ee-tjdb"
},
{
"key": "PGRST_HOST",
@ -1124,4 +1112,3 @@ jobs:
# } catch (e) {
# console.log(e)
# }

View file

@ -8,16 +8,16 @@ permissions:
issues: write
jobs:
label-stale-deploys:
label-stale-ce-deploys:
runs-on: ubuntu-latest
permissions:
pull-requests: write
pull-requests: write
steps:
- uses: akshaysasidrn/stale-label-fetch@v1.1
id: stale-label
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
stale-label: 'active-review-app'
stale-label: 'active-ce-review-app'
stale-time: '86400'
type: 'pull_request'
- name: Get stale numbers
@ -40,6 +40,42 @@ jobs:
issue_number: prNumber,
owner: context.repo.owner,
repo: context.repo.repo,
labels: ['suspend-review-app']
labels: ['suspend-ce-review-app']
})
}
label-stale-ee-deploys:
runs-on: ubuntu-latest
permissions:
pull-requests: write
steps:
- uses: akshaysasidrn/stale-label-fetch@v1.1
id: stale-label
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
stale-label: 'active-ee-review-app'
stale-time: '86400'
type: 'pull_request'
- name: Get stale numbers
run: echo "Matched PR numbers - ${{ steps.stale-label.outputs.stale-numbers }}"
- name: Add suspend label
uses: actions/github-script@v6
env:
STALE_NUMBERS: ${{ steps.stale-label.outputs.stale-numbers }}
with:
github-token: ${{ secrets.TJ_BOT_PAT }}
script: |
if (!process.env.STALE_NUMBERS) return
const prNumbers = process.env.STALE_NUMBERS.split(",")
console.log(`Adding suspend labels for: ${prNumbers}`)
for (const prNumber of prNumbers) {
github.rest.issues.addLabels({
issue_number: prNumber,
owner: context.repo.owner,
repo: context.repo.repo,
labels: ['suspend-ee-review-app']
})
}

View file

@ -11,7 +11,7 @@ on:
# Schedule the workflow to run every two weeks once
schedule:
- cron: '30 5 */14 * *'
- cron: '30 5 * * 1'
jobs:
PeriodicVulnerability-CheckOn-frontend-code:

View file

@ -19,9 +19,9 @@ module.exports = defineConfig({
trashAssetsBeforeRuns: true,
e2e: {
setupNodeEvents (on, config) {
setupNodeEvents(on, config) {
on("task", {
readPdf (pathToPdf) {
readPdf(pathToPdf) {
return new Promise((resolve) => {
const pdfPath = path.resolve(pathToPdf);
let dataBuffer = fs.readFileSync(pdfPath);
@ -33,7 +33,7 @@ module.exports = defineConfig({
});
on("task", {
readXlsx (filePath) {
readXlsx(filePath) {
return new Promise((resolve, reject) => {
try {
let dataBuffer = fs.readFileSync(filePath);
@ -48,7 +48,7 @@ module.exports = defineConfig({
});
on("task", {
deleteFolder (folderName) {
deleteFolder(folderName) {
return new Promise((resolve, reject) => {
rmdir(folderName, { maxRetries: 10, recursive: true }, (err) => {
if (err) {
@ -62,7 +62,7 @@ module.exports = defineConfig({
});
on("task", {
dbConnection ({ dbconfig, sql }) {
dbConnection({ dbconfig, sql }) {
const client = new pg.Pool(dbconfig);
return client.query(sql);
},
@ -76,8 +76,8 @@ module.exports = defineConfig({
experimentalRunAllSpecs: true,
baseUrl: "http://localhost:8082",
specPattern: [
"cypress/e2e/happyPath/appbuilder/commonTestcases/**/*.cy.js",
"cypress/e2e/happyPath/appbuilder/ceTestcases/**/*.cy.js"
"cypress/e2e/happyPath/appbuilder/commonTestcases/newSuits/**/*.cy.js",
// "cypress/e2e/happyPath/appbuilder/ceTestcases/**/*.cy.js"
],
numTestsKeptInMemory: 1,
redirectionLimit: 7,

View file

@ -39,11 +39,11 @@ module.exports = defineConfig({
chromeWebSecurity: false,
trashAssetsBeforeRuns: true,
e2e: {
setupNodeEvents (on, config) {
setupNodeEvents(on, config) {
config.baseUrl = environment.baseUrl;
on("task", {
readPdf (pathToPdf) {
readPdf(pathToPdf) {
return new Promise((resolve) => {
const pdfPath = path.resolve(pathToPdf);
let dataBuffer = fs.readFileSync(pdfPath);
@ -55,7 +55,7 @@ module.exports = defineConfig({
});
on("task", {
readXlsx (filePath) {
readXlsx(filePath) {
return new Promise((resolve, reject) => {
try {
let dataBuffer = fs.readFileSync(filePath);
@ -69,7 +69,7 @@ module.exports = defineConfig({
});
on("task", {
deleteFolder (folderName) {
deleteFolder(folderName) {
return new Promise((resolve, reject) => {
rmdir(folderName, { maxRetries: 10, recursive: true }, (err) => {
if (err) {
@ -83,7 +83,7 @@ module.exports = defineConfig({
});
on("task", {
dbConnection ({ dbconfig, sql }) {
dbConnection({ dbconfig, sql }) {
const client = new pg.Pool(dbconfig);
return client.query(sql);
},
@ -98,6 +98,7 @@ module.exports = defineConfig({
configFile: environment.configFile,
specPattern: [
"cypress/e2e/happyPath/platform/ceTestcases/userFlow/firstUserOnboarding.cy.js",
"cypress/e2e/happyPath/platform/commonTestcases/workspace/dashboard.cy.js",
"cypress/e2e/happyPath/platform/ceTestcases/!(userFlow)/**/*.cy.js",
"cypress/e2e/happyPath/platform/commonTestcases/**/*.cy.js",
],

View file

@ -92,11 +92,7 @@ module.exports = defineConfig({
experimentalModfyObstructiveThirdPartyCode: true,
experimentalRunAllSpecs: true,
baseUrl: "http://localhost:8082",
specPattern: [
"cypress/e2e/happyPath/platform/ceTestcases/userFlow/firstUserOnboarding.cy.js",
"cypress/e2e/happyPath/platform/ceTestcases/!(userFlow)/**/*.cy.js",
"cypress/e2e/happyPath/platform/commonTestcases/**/*.cy.js",
],
specPattern: "cypress/e2e/happyPath/**/*.cy.js",
downloadsFolder: "cypress/downloads",
numTestsKeptInMemory: 0,
redirectionLimit: 10,

View file

@ -52,7 +52,7 @@ Cypress.Commands.add("apiCreateGDS", (url, name, kind, options) => {
log: false;
}
expect(response.status).to.equal(201);
Cypress.env(`${name}-id`, response.body.id);
Cypress.env(`${kind}`, response.body.id);
Cypress.log({
name: "Create Data Source",
@ -63,6 +63,30 @@ Cypress.Commands.add("apiCreateGDS", (url, name, kind, options) => {
});
});
Cypress.Commands.add("apiFetchDataSourcesId", () => {
cy.getAuthHeaders().then((headers) => {
cy.request({
method: "GET",
url: `${Cypress.env("server_host")}/api/data-sources/${Cypress.env("workspaceId")}/environments/${Cypress.env("environmentId")}/versions/${Cypress.env("editingVersionId")}`,
headers,
}).then((response) => {
expect(response.status).to.equal(200);
const dataSources = response.body?.data_sources || [];
dataSources.forEach((item) => {
Cypress.env(`${item.kind}`, `${item.id}`);
});
Cypress.log({
name: "DS Fetch",
displayName: "Data Sources Fetched",
message: dataSources.map(ds => `\nKind: '${ds.kind}', Name: '${ds.id}'`).join(','),
});
});
});
});
Cypress.Commands.add("apiCreateApp", (appName = "testApp") => {
cy.window({ log: false }).then((win) => {
win.localStorage.setItem("walkthroughCompleted", "true");
@ -140,14 +164,11 @@ Cypress.Commands.add(
cy.visit(`/${workspaceId}/apps/${appId}/${slug}`);
cy.wait("@getAppData").then((interception) => {
// Assuming the response body is a JSON object
const responseData = interception.response.body;
// Set the response data as an environment variable
Cypress.env("apiResponseData", responseData);
Cypress.env("editingVersionId", responseData.editing_version.id);
Cypress.env("environmentId", responseData.editorEnvironment.id);
// You can log it to check if the env var is set correctly
cy.log(Cypress.env("apiResponseData"));
});
cy.get(componentSelector, { timeout: 10000 });
}
@ -171,6 +192,7 @@ Cypress.Commands.add("apiCreateWorkspace", (workspaceName, workspaceSlug) => {
{ log: false }
).then((response) => {
expect(response.status).to.equal(201);
return response;
});
});
});
@ -267,6 +289,7 @@ Cypress.Commands.add("apiAddQuery", (queryName, query, dataQueryId) => {
Cypress.Commands.add(
"apiAddQueryToApp",
(queryName, options, dsName, dsKind) => {
cy.log(`${Cypress.env("server_host")}/api/data-queries/data-sources/${Cypress.env(dsKind)}/versions/${Cypress.env("editingVersionId")}`)
cy.getCookie("tj_auth_token", { log: false }).then((cookie) => {
const authToken = `tj_auth_token=${cookie.value}`;
const workspaceId = Cypress.env("workspaceId");
@ -286,7 +309,7 @@ Cypress.Commands.add(
cy.request({
method: "POST",
url: `${Cypress.env("server_host")}/api/data-queries`,
url: `${Cypress.env("server_host")}/api/data-queries/data-sources/${Cypress.env(dsKind)}/versions/${Cypress.env("editingVersionId")}`,
headers: {
"Content-Type": "application/json",
Cookie: authToken,
@ -627,10 +650,11 @@ Cypress.Commands.add("apiAddDataToTable", (tableName, data) => {
});
Cypress.Commands.add("apiGetDataSourceIdByName", (dataSourceName) => {
const workspaceId = Cypress.env("workspaceId");
cy.getAuthHeaders().then((headers) => {
cy.request({
method: "GET",
url: `${Cypress.env("server_host")}/api/data-sources`,
url: `${Cypress.env("server_host")}/api/data-sources/${workspaceId}`,
headers: headers,
}).then((response) => {
expect(response.status).to.equal(200);
@ -665,7 +689,7 @@ Cypress.Commands.add(
name: dataSourceName,
options: [
{ key: "connection_type", value: "manual", encrypted: false },
{ key: "host", value: "35.202.183.199" },
{ key: "host", value: "35.238.9.114" },
{ key: "port", value: 5432 },
{ key: "database", value: "student" },
{ key: "username", value: "postgres" },

View file

@ -15,15 +15,11 @@ const API_ENDPOINT =
Cypress.Commands.add(
"appUILogin",
(email = "dev@tooljet.io", password = "password") => {
cy.visit("/");
cy.wait(1000);
cy.clearAndType(onboardingSelectors.loginEmailInput, email);
cy.clearAndType(onboardingSelectors.loginPasswordInput, password);
cy.get(onboardingSelectors.signInButton).click();
cy.intercept("GET", API_ENDPOINT).as("library_apps");
cy.get(commonSelectors.homePageLogo, { timeout: 10000 });
cy.wait("@library_apps");
cy.wait(2000);
cy.get('[data-cy="main-wrapper"]', { timeout: 10000 }).should("be.visible");
}
);
@ -400,36 +396,39 @@ Cypress.Commands.add("getPosition", (componentName) => {
Cypress.Commands.add("defaultWorkspaceLogin", () => {
cy.apiLogin();
// cy.intercept("GET", API_ENDPOINT).as("library_apps");
cy.visit("/my-workspace");
cy.intercept("GET", API_ENDPOINT).as("library_apps");
cy.wait(2000)
cy.get(commonSelectors.homePageLogo, { timeout: 10000 });
cy.wait("@library_apps");
// });
// cy.wait("@library_apps");
});
Cypress.Commands.add(
"visitSlug",
({
actualUrl,
currentUrl = `${Cypress.config("baseUrl")}/error/unknown`,
errorUrls = [
`${Cypress.config("baseUrl")}/error/unknown`,
`${Cypress.config("baseUrl")}/error/restricted`,
],
}) => {
// Ensure actualUrl is provided
if (!actualUrl) {
throw new Error("actualUrl is required for visitSlug command.");
}
cy.visit(actualUrl);
// Dynamically wait for the correct URL or handle navigation errors
cy.url().then((url) => {
if (url === currentUrl) {
cy.log(`Navigation resulted in unexpected URL: ${url}. Retrying...`);
if (errorUrls.includes(url)) {
cy.log(`Navigation resulted in error URL: ${url}. Retrying...`);
cy.visit(actualUrl);
cy.wait(1000);
}
});
}
);
Cypress.Commands.add("releaseApp", () => {
if (Cypress.env("environment") !== "Community") {
cy.get(commonEeSelectors.promoteButton).click();
@ -520,16 +519,6 @@ Cypress.Commands.add("verifyElement", (selector, text, eqValue) => {
element.should("be.visible").and("have.text", text);
});
Cypress.Commands.add("loginWithCredentials", (email, password) => {
cy.get(onboardingSelectors.loginEmailInput, { timeout: 20000 }).should(
"be.visible"
);
cy.clearAndType(onboardingSelectors.loginEmailInput, email);
cy.clearAndType(onboardingSelectors.loginPasswordInput, password);
cy.get(onboardingSelectors.signInButton).click();
cy.wait(3000);
cy.get(commonSelectors.pageLogo).should("be.visible");
});
Cypress.Commands.add("getAppId", (appName) => {
cy.task("dbConnection", {

View file

@ -259,7 +259,7 @@ export const commonSelectors = {
cloneAppTitle: '[data-cy="clone-app-title"]',
cloneAppButton: '[data-cy="clone-app"]',
appNameErrorLabel: '[data-cy="app-name-error-label"]',
importAppTitle: '[data-cy="import-app-title"]',
importAppTitle: '[data-cy="import-an-app"]',
importAppButton: '[data-cy="import-app"]',
chooseFromTemplateButton: '[data-cy="choose-from-template-button"]',
CreateAppFromTemplateButton: '[data-cy="create-new-app-from-template-title"]',

View file

@ -1,7 +1,7 @@
export const multipageSelector = {
sidebarPageButton: '[data-cy="left-sidebar-page-button"]',
pagesLabel: '[data-cy="label-pages"]',
addPageIcon: '[title="Add Page"]',
addPageIcon: '[data-cy="add-page-button"]',
searchPageIcon: '[title="Search"]',
pagesPinIcon: '[title="Pin"]',

View file

@ -13,7 +13,7 @@ export const dataSourceText = {
? "Databases (20)"
: "Databases (18)";
},
allApis: "APIs (20)",
allApis: "APIs (21)",
allCloudStorage: "Cloud Storages (4)",
pluginsLabelAndCount: "Plugins (0)",

View file

@ -5,7 +5,7 @@ export const postgreSqlText = {
allDataSources: () => {
return Cypress.env("marketplace_action")
? "All data sources (44)"
: "All data sources (42)";
: "All data sources (45)";
},
commonlyUsed: "Commonly used (5)",
allDatabase: () => {
@ -13,7 +13,7 @@ export const postgreSqlText = {
? "Databases (20)"
: "Databases (18)";
},
allApis: "APIs (20)",
allApis: "APIs (21)",
allCloudStorage: "Cloud Storages (4)",
postgreSQL: "PostgreSQL",

View file

@ -4,7 +4,7 @@ export const workspaceConstantsText = {
secretsConstantInfo: "To resolve a secret workspace constant use {{secrets.access_token}}Read documentation",
emptyStateHeader: "No Workspace constants yet",
emptyStateText:
"Use workspace constants seamlessly in both the app builder and data source connections across ToolJet.",
"Use workspace constants seamlessly within both the app builder and data source connections across the platform.",
addNewConstantButton: "+ Create new constant",
addConstatntText: "Add new constant in production ",
constantCreatedToast: (type) => { return `${type} constant created successfully!` },

View file

@ -351,7 +351,7 @@ describe("Text Input", () => {
).should("have.css", "border-radius", "20px");
});
it.skip("should verify the app preview", () => {});
it.skip("should verify the app preview", () => { });
it("should verify CSA", () => {
const data = {};

View file

@ -43,8 +43,10 @@ describe("Editor title", () => {
cy.apiDeleteApp();
});
it("should verify titles", () => {
cy.url().should("include", "/my-workspace");
cy.title().should("eq", "Dashboard | ToolJet");
cy.url().should("include", "/tooljets-workspace");
// cy.title().should("eq", "Dashboard | ToolJet");
cy.title().should("eq", "ToolJet");
cy.log(data.appName);
cy.openApp();
@ -54,12 +56,20 @@ describe("Editor title", () => {
cy.openInCurrentTab(commonWidgetSelector.previewButton);
cy.url().should("include", `/applications/${Cypress.env("appId")}`);
cy.title().should("eq", `Preview - ${data.appName} | ToolJet`);
// cy.title().should("eq", `${data.appName} | ToolJet`);
// cy.title().should("eq", `Preview - ${data.appName} | ToolJet`);
cy.go("back");
cy.releaseApp();
cy.url().then((url) => cy.visit(`/applications/${url.split("/").pop()}`));
cy.url().then((url) => {
const appId = url.split("/").filter(Boolean).pop();
cy.log(appId);
cy.visit(`/applications/${appId}`);
});
cy.url().should("include", `/applications/${Cypress.env("appId")}`);
cy.title().should("eq", `${data.appName}`);
cy.title().should("eq", `${data.appName} | ToolJet`);
// cy.title().should("eq", `${data.appName}`);
});
});

View file

@ -76,7 +76,7 @@ describe('Button Component Tests', () => {
cy.apiCreateApp(`${fake.companyName}-Button-App`);
cy.openApp();
cy.dragAndDropWidget("Button", 50, 50);
cy.get('[data-cy="query-manager-collapse-button"]').click();
cy.get('[data-cy="query-manager-toggle-button"]').click();
});
it('should verify all the exposed values on inspector', () => {
@ -90,7 +90,7 @@ describe('Button Component Tests', () => {
});
it('should verify all the events from the button', () => {
it.skip('should verify all the events from the button', () => {
const events = [
{ event: "On hover", message: "On hover Event" },
{ event: "On Click", message: "On Click Event" },
@ -110,7 +110,7 @@ describe('Button Component Tests', () => {
verifyTextInputEvents(textInputSelector);
});
it('should verify all the CSA from button', () => {
it.skip('should verify all the CSA from button', () => {
addMultiEventsWithAlert([
{ event: "On hover", message: "On hover Event" },
{ event: "On Click", message: "On Click Event" },

View file

@ -84,7 +84,7 @@ describe('Checkbox Component Tests', () => {
cy.apiCreateApp(`${fake.companyName}-Checkbox-App`);
cy.openApp();
cy.dragAndDropWidget("Checkbox", 50, 50);
cy.get('[data-cy="query-manager-collapse-button"]').click();
cy.get('[data-cy="query-manager-toggle-button"]').click();
});
it('should verify all the exposed values on inspector', () => {
@ -98,7 +98,7 @@ describe('Checkbox Component Tests', () => {
});
it('should verify all the events from the Checkbox', () => {
it.skip('should verify all the events from the Checkbox', () => {
const events = [
{ event: "On Change", message: "On Change Event" },
];
@ -118,7 +118,7 @@ describe('Checkbox Component Tests', () => {
verifyTextInputEvents(textInputSelector);
});
it('should verify all the CSA from Checkbox', () => {
it.skip('should verify all the CSA from Checkbox', () => {
const events = [
{ event: "On Change", message: "On Change Event" },
];

View file

@ -93,7 +93,7 @@ describe('Dropdown Component Tests', () => {
cy.apiCreateApp(`${fake.companyName}-Dropdown-App`);
cy.openApp();
cy.dragAndDropWidget("Dropdown", 50, 50);
cy.get('[data-cy="query-manager-collapse-button"]').click();
cy.get('[data-cy="query-manager-toggle-button"]').click();
});
it('should verify all the exposed values on inspector', () => {

View file

@ -91,7 +91,7 @@ describe("Global Actions", () => {
cy.waitForAutoSave();
addInputOnQueryField("runjs", "actions.showModal('modal1');");
query("run");
cy.get('[data-cy="modal-title"]').should("be.visible");
cy.get('.text-widget-section > div').should("be.visible");
addInputOnQueryField("runjs", "actions.closeModal('modal1');");
query("run");
@ -114,7 +114,7 @@ describe("Global Actions", () => {
"actions.setLocalStorage('localStorage','data from runjs');"
);
query("run");
cy.wait(500)
cy.getAllLocalStorage().then((result) => {
expect(result[Cypress.config().baseUrl].localStorage).to.deep.equal(
"data from runjs"

View file

@ -96,7 +96,7 @@ describe('Multiselect Component Tests', () => {
cy.apiCreateApp(`${fake.companyName}-Multiselect-App`);
cy.openApp();
cy.dragAndDropWidget("Multiselect", 50, 50);
cy.get('[data-cy="query-manager-collapse-button"]').click();
cy.get('[data-cy="query-manager-toggle-button"]').click();
});
it('should verify all the exposed values on inspector', () => {

View file

@ -87,7 +87,7 @@ describe('Number Input Component Tests', () => {
cy.apiCreateApp(`${fake.companyName}-Numberinput-App`);
cy.openApp();
cy.dragAndDropWidget("Number Input", 50, 50);
cy.get('[data-cy="query-manager-collapse-button"]').click();
cy.get('[data-cy="query-manager-toggle-button"]').click();
});
it('should verify all the exposed values on inspector', () => {
@ -101,7 +101,7 @@ describe('Number Input Component Tests', () => {
});
it('should verify all the events from the number input', () => {
it.skip('should verify all the events from the number input', () => {
const events = [
{ event: "On Focus", message: "On Focus Event" },
{ event: "On Blur", message: "On Blur Event" },
@ -129,7 +129,7 @@ describe('Number Input Component Tests', () => {
inputEvents(inputSelector);
});
it('should verify all the CSA from number input', () => {
it.skip('should verify all the CSA from number input', () => {
const actions = [
{ event: "On click", action: "Set visibility", valueToggle: "{{false}}" }, //b1
{ event: "On click", action: "Set visibility", valueToggle: "{{true}}" },//b2

View file

@ -87,7 +87,7 @@ describe('Password Input Component Tests', () => {
cy.apiCreateApp(`${fake.companyName}-Passwordinput-App`);
cy.openApp();
cy.dragAndDropWidget("Password Input", 50, 50);
cy.get('[data-cy="query-manager-collapse-button"]').click();
cy.get('[data-cy="query-manager-toggle-button"]').click();
});
it('should verify all the exposed values on inspector', () => {
@ -101,7 +101,7 @@ describe('Password Input Component Tests', () => {
});
it('should verify all the events from the password input', () => {
it.skip('should verify all the events from the password input', () => {
const events = [
{ event: "On Focus", message: "On Focus Event" },
{ event: "On Blur", message: "On Blur Event" },

View file

@ -95,10 +95,10 @@ describe('Text Input Component Tests', () => {
cy.apiCreateApp(`${fake.companyName}-Textinput-App`);
cy.openApp();
cy.dragAndDropWidget("Text Input", 50, 50);
cy.get('[data-cy="query-manager-collapse-button"]').click();
cy.get('[data-cy="query-manager-toggle-button"]').click();
});
it('should verify all the exposed values on inspector', () => {
it.skip('should verify all the exposed values on inspector', () => {
cy.get(commonWidgetSelector.sidebarinspector).click();
cy.get(".tooltip-inner").invoke("hide");
@ -109,7 +109,7 @@ describe('Text Input Component Tests', () => {
});
it('should verify all the events from the text input', () => {
it.skip('should verify all the events from the text input', () => {
const events = [
{ event: "On Focus", message: "On Focus Event" },
{ event: "On Blur", message: "On Blur Event" },
@ -137,7 +137,7 @@ describe('Text Input Component Tests', () => {
verifyTextInputEvents(textInputSelector);
});
it('should verify all the CSA from text input', () => {
it.skip('should verify all the CSA from text input', () => {
const actions = [
{ event: "On click", action: "Set visibility", valueToggle: "{{false}}" }, //b1
{ event: "On click", action: "Visibility", valueToggle: "{{true}}" },//b2

View file

@ -80,7 +80,7 @@ describe('ToggleSwitch Component Tests', () => {
cy.apiCreateApp(`${fake.companyName}-Toggle-App`);
cy.openApp();
cy.dragAndDropWidget("Toggle Switch", 50, 50);
cy.get('[data-cy="query-manager-collapse-button"]').click();
cy.get('[data-cy="query-manager-toggle-button"]').click();
});
it('should verify all the exposed values on inspector', () => {
@ -137,6 +137,8 @@ describe('ToggleSwitch Component Tests', () => {
cy.get(commonWidgetSelector.draggableWidget(component)).should("not.be.visible");
cy.get(commonWidgetSelector.draggableWidget("button2")).click();
cy.wait(500);
cy.forceClickOnCanvas();
cy.get(commonWidgetSelector.draggableWidget(component)).should("be.visible");
cy.get(commonWidgetSelector.draggableWidget("button3")).click();

View file

@ -35,13 +35,13 @@ describe("Editor- Global Settings", () => {
"have.text",
"Global settings"
);
cy.get(
'[data-cy="label-hide-header-for-launched-apps"]'
).verifyVisibleElement("have.text", "Hide header for launched apps");
cy.get('[data-cy="label-maintenance-mode"]').verifyVisibleElement(
"have.text",
"Maintenance mode"
);
// cy.get(
// '[data-cy="label-hide-header-for-launched-apps"]'
// ).verifyVisibleElement("have.text", "Hide header for launched apps");
// cy.get('[data-cy="label-maintenance-mode"]').verifyVisibleElement(
// "have.text",
// "Maintenance mode"
// );
cy.hideTooltip();
cy.get('[data-cy="label-max-canvas-width"]').verifyVisibleElement(
"have.text",
@ -60,7 +60,7 @@ describe("Editor- Global Settings", () => {
);
verifyWidgetColorCss(
".canvas-area",
'[data-cy="real-canvas"]',
"background-color",
data.backgroundColor,
true
@ -87,24 +87,25 @@ describe("Editor- Global Settings", () => {
cy.get("[data-cy='left-sidebar-settings-button']").click();
cy.get('[data-cy="toggle-maintenance-mode"]').realClick();
cy.get('[data-cy="modal-confirm-button"]').click();
cy.verifyToastMessage(
commonSelectors.toastMessage,
"Application is on maintenance.",
false
);
// cy.verifyToastMessage(
// commonSelectors.toastMessage,
// "Application is on maintenance.",
// false
// );
cy.forceClickOnCanvas();
cy.wait(500);
cy.waitForAutoSave();
//Fix this after the release. 2.9.0
// cy.get('[data-cy="button-release"]').click();
// cy.get('[data-cy="yes-button"]').click();
// cy.get('[data-cy="editor-page-logo"]').click();
// cy.get(`[data-cy="${data.appName.toLowerCase()}-card"]`)
// .realHover()
// .find('[data-cy="launch-button"]')
// .invoke("attr", "class")
// .should("contains", "disabled-btn");
// Fix this after the release. 2.9.0
cy.get('[data-cy="button-release"]').click();
cy.get('[data-cy="yes-button"]').click();
cy.get('[data-cy="editor-page-logo"]').click();
cy.get('[data-cy="back-to-app-option"]').click();
cy.get(`[data-cy="${data.appName.toLowerCase()}-card"]`)
.realHover().within(() => {
cy.get('[data-cy="launch-button"]').should('have.text', 'Maintenance')
.invoke("attr", "class")
.should("contains", "disabled-btn");
})
cy.apiDeleteApp();
});
});

View file

@ -17,6 +17,7 @@ describe("Editor- Inspector", () => {
cy.apiLogin();
cy.apiCreateApp(`${fake.companyName}-inspector-App`);
cy.openApp("?key=value");
cy.viewport(1800, 1800);
});
it("should verify the values of inspector", () => {
@ -45,14 +46,14 @@ describe("Editor- Inspector", () => {
cy.apiDeleteApp();
});
it("should verify dynamic items", () => {
it.skip("should verify dynamic items", () => {
cy.get(commonWidgetSelector.sidebarinspector).click();
cy.get(".tooltip-inner").invoke("hide");
cy.get(multipageSelector.sidebarPageButton).click();
addNewPage("test_page");
cy.dragAndDropWidget("Button", 500, 500);
cy.dragAndDropWidget("Button", 100, 100);
selectEvent("On click", "Switch page");
cy.get('[data-cy="switch-page-label-and-input"] > .select-search').click().type("home{enter}");
@ -72,7 +73,9 @@ describe("Editor- Inspector", () => {
cy.dragAndDropWidget("Button", 500, 300);
selectEvent("On click", "Set variable");
addSupportCSAData("event-key", "globalVar");
cy.wait(500)
addSupportCSAData("variable", "globalVar");
cy.wait(500)
cy.forceClickOnCanvas();
cy.waitForAutoSave();
@ -141,17 +144,17 @@ describe("Editor- Inspector", () => {
cy.dragAndDropWidget("Button", 500, 300);
cy.get(commonWidgetSelector.sidebarinspector).click();
openNode("components");
cy.get(`[data-cy="inspector-node-button1"] > .mx-1`).realHover();
cy.get('[style="height: 13px; width: 13px;"] > img').click();
cy.get(`[data-cy="inspector-node-button1"] > .mx-1`).eq(0).realHover();
cy.get('[style="height: 13px; width: 13px;"] > img').last().click();
cy.notVisible(commonWidgetSelector.draggableWidget("button1"));
cy.apiDeleteApp();
});
it("should verify deletion of component from inspector", () => {
it.skip("should verify deletion of component from inspector", () => {
cy.dragAndDropWidget("button", 500, 500);
cy.get(commonWidgetSelector.sidebarinspector).click();
deleteComponentFromInspector("button1");
cy.verifyToastMessage(`[class=go3958317564]`, "Component deleted! ( + Z to undo)");
cy.verifyToastMessage(`[class=go3958317564]`, "Component deleted! (ctrl + Z to undo)");
navigateToCreateNewVersionModal((currentVersion = "v1"));
createNewVersion((newVersion = ["v2"]), (versionFrom = "v1"));

View file

@ -14,6 +14,7 @@ describe("Chaining of queries", () => {
cy.apiLogin();
cy.apiCreateApp(`${fake.companyName}-chaining-App`);
cy.openApp();
cy.apiFetchDataSourcesId()
cy.viewport(1800, 1800);
cy.dragAndDropWidget("Button");
resizeQueryPanel("80");
@ -57,7 +58,7 @@ describe("Chaining of queries", () => {
);
cy.apiCreateGDS(
"http://localhost:3000/api/v2/data_sources",
`http://localhost:3000/api/data-sources`,
`cypress-${dsName}-qc-postgresql`,
"postgresql",
[
@ -68,8 +69,10 @@ describe("Chaining of queries", () => {
{ key: "password", value: Cypress.env("pg_password"), encrypted: true },
{ key: "ssl_enabled", value: false, encrypted: false },
{ key: "ssl_certificate", value: "none", encrypted: false },
{ key: "connection_type", value: "manual", encrypted: false }
]
);
cy.log("Data source created");
cy.apiAddQueryToApp(
"psql",
{
@ -92,8 +95,17 @@ describe("Chaining of queries", () => {
chainQuery("restapi", "tjdb");
addSuccessNotification("restapi");
cy.get(`[data-cy="list-query-tjdb"]`).click();
cy.get('[data-cy="query-tab-settings"]').click();
selectEvent("Query Failure", "Show Alert");
cy.get('[data-cy="debounce-input-field"]')
.click()
.type(`{selectAll}{backspace}2000{enter}`);
cy.wait(1000)
cy.get('[data-cy="query-tab-setup"]').click();
openEditorSidebar(buttonText.defaultWidgetName);
selectEvent("On Click", "Run Query", 1, `[data-cy="add-event-handler"]`, 1);
selectEvent("On Click", "Run Query", 0, `[data-cy="add-event-handler"]`, 0);
cy.wait(500);
cy.get('[data-cy="query-selection-field"]')
.click()
@ -105,11 +117,13 @@ describe("Chaining of queries", () => {
cy.verifyToastMessage(commonSelectors.toastMessage, "psql");
cy.verifyToastMessage(commonSelectors.toastMessage, "runjs");
cy.verifyToastMessage(commonSelectors.toastMessage, "runpy");
cy.wait(500);
cy.verifyToastMessage(commonSelectors.toastMessage, "restapi");
cy.verifyToastMessage(commonSelectors.toastMessage, "Invalid operation");
// cy.verifyToastMessage(commonSelectors.toastMessage, "Hello World");
});
it("should verify query duplication", () => {
it.skip("should verify query duplication", () => {
const data = {};
let dsName = fake.companyName;
data.customText = randomString(12);
@ -133,7 +147,7 @@ describe("Chaining of queries", () => {
addSuccessNotification("runjs");
openEditorSidebar(buttonText.defaultWidgetName);
selectEvent("On Click", "Run Query", 1, `[data-cy="add-event-handler"]`, 1);
selectEvent("On Click", "Run Query", 0, `[data-cy="add-event-handler"]`, 0);
cy.wait(500);
cy.get('[data-cy="query-selection-field"]')
.click()

View file

@ -54,7 +54,7 @@ describe("RunJS", () => {
cy.apiDeleteApp();
});
it("should verify global and page data", () => {
it.skip("should verify global and page data", () => {
const data = {};
data.customText = randomString(12);
@ -147,9 +147,9 @@ describe("RunJS", () => {
"runjs",
"actions.showAlert('success', 'alert from runjs');"
);
cy.get('[data-cy="query-tab-Settings"]').click();
cy.get('[data-cy="query-tab-settings"]').click();
changeQueryToggles("run-on-app-load");
cy.wait(`@editQuery`);
// cy.wait(`@editQuery`);
cy.waitForAutoSave();
cy.waitForAutoSave();
cy.reload();
@ -159,9 +159,9 @@ describe("RunJS", () => {
"alert from runjs",
false
);
cy.get('[data-cy="query-tab-Settings"]').click();
cy.get('[data-cy="query-tab-settings"]').click();
changeQueryToggles("confirmation-before-run");
cy.wait(`@editQuery`);
// cy.wait(`@editQuery`);
cy.waitForAutoSave();
cy.reload();
cy.get('[data-cy="modal-message"]').verifyVisibleElement(
@ -172,12 +172,12 @@ describe("RunJS", () => {
cy.verifyToastMessage(commonSelectors.toastMessage, "alert from runjs");
resizeQueryPanel("80");
cy.get('[data-cy="query-tab-Settings"]').click();
cy.get('[data-cy="query-tab-settings"]').click();
changeQueryToggles("notification-on-success");
cy.get('[data-cy="success-message-input-field"]').clearAndTypeOnCodeMirror(
"Success alert"
);
cy.get('[data-cy="query-tab-Setup"]').click();
cy.get('[data-cy="query-tab-setup"]').click();
cy.get('[data-cy="runjs-input-field"]').realClick();
cy.wait(1000);
cy.waitForAutoSave();

View file

@ -59,7 +59,7 @@ describe("runpy", () => {
cy.apiDeleteApp();
});
it.only("should verify actions", () => {
it.skip("should verify actions", () => {
const data = {};
data.customText = randomString(12);
@ -120,18 +120,18 @@ actions.unsetPageVariable('pageVar')`
cy.waitForAutoSave();
addInputOnQueryField("runpy", "actions.showModal('modal1')");
query("run");
cy.get('[data-cy="modal-title"]').should("be.visible");
cy.get('.text-widget-section > div').should("be.visible");
cy.get('[data-cy="runpy-input-field"]').click({ force: true });
addInputOnQueryField("runpy", "actions.closeModal('modal1')");
cy.wait(`@editQuery`);
// cy.wait(`@editQuery`);
cy.waitForAutoSave();
query("run");
waitForQueryAction("run");
cy.notVisible('[data-cy="modal-title"]');
addInputOnQueryField("runpy", "actions.copyToClipboard('data from runpy')");
cy.wait(`@editQuery`);
// cy.wait(`@editQuery`);
cy.waitForAutoSave();
query("run");
waitForQueryAction("run");
@ -144,7 +144,7 @@ actions.unsetPageVariable('pageVar')`
"runpy",
"actions.setLocalStorage('localStorage','data from runpy')"
);
cy.wait(`@editQuery`);
// cy.wait(`@editQuery`);
cy.waitForAutoSave();
query("run");
waitForQueryAction("run");
@ -155,17 +155,17 @@ actions.unsetPageVariable('pageVar')`
);
});
addInputOnQueryField(
"runpy",
"actions.generateFile('runpycsv', 'csv', [{ 'name': 'John', 'email': 'john@tooljet.com' }])"
);
query("run");
// addInputOnQueryField( //Need fix asap
// "runpy",
// "actions.generateFile('runpycsv', 'csv', [{ 'name': 'John', 'email': 'john@tooljet.com' }])"
// );
// query("run");
cy.wait(3000);
// cy.wait(3000);
cy.readFile("cypress/downloads/runpycsv.csv", "utf-8")
.should("contain", "name,email")
.and("contain", "John,john@tooljet.com");
// cy.readFile("cypress/downloads/runpycsv.csv", "utf-8")
// .should("contain", "name,email")
// .and("contain", "John,john@tooljet.com");
// addInputOnQueryField(
// "runpy",
@ -174,7 +174,7 @@ actions.unsetPageVariable('pageVar')`
// query("run");
addInputOnQueryField("runpy", "actions.logout()");
cy.wait(`@editQuery`);
// cy.wait(`@editQuery`);
cy.wait(200);
cy.waitForAutoSave();
query("run");
@ -184,7 +184,7 @@ actions.unsetPageVariable('pageVar')`
);
});
it("should verify global and page data", () => {
it.skip("should verify global and page data", () => {
const data = {};
data.customText = randomString(12);
@ -273,20 +273,20 @@ actions.unsetPageVariable('pageVar')`
"runpy",
"actions.showAlert('success', 'alert from runpy');"
);
cy.get('[data-cy="query-tab-Settings"]').click();
cy.wait("@editQuery");
cy.get('[data-cy="query-tab-settings"]').click();
// cy.wait("@editQuery");
cy.wait(200);
cy.waitForAutoSave();
changeQueryToggles("run-on-app-load");
cy.wait("@editQuery");
// cy.wait("@editQuery");
cy.waitForAutoSave();
cy.reload();
cy.verifyToastMessage(commonSelectors.toastMessage, "alert from runpy");
cy.get('[data-cy="query-tab-Settings"]').click();
cy.get('[data-cy="query-tab-settings"]').click();
changeQueryToggles("confirmation-before-run");
cy.wait("@editQuery");
// cy.wait("@editQuery");
cy.wait(200);
cy.waitForAutoSave();
cy.reload();
@ -297,13 +297,13 @@ actions.unsetPageVariable('pageVar')`
cy.get('[data-cy="modal-confirm-button"]').realClick();
cy.verifyToastMessage(commonSelectors.toastMessage, "alert from runpy");
cy.get('[data-cy="query-tab-Settings"]').click();
cy.get('[data-cy="query-tab-settings"]').click();
changeQueryToggles("notification-on-success");
cy.get('[data-cy="success-message-input-field"]').clearAndTypeOnCodeMirror(
"Success alert"
);
cy.forceClickOnCanvas();
cy.wait("@editQuery");
// cy.wait("@editQuery");
cy.wait(200);
cy.waitForAutoSave();
cy.reload();

View file

@ -26,7 +26,6 @@ describe("Data source amazon athena", () => {
beforeEach(() => {
cy.apiLogin();
cy.defaultWorkspaceLogin();
cy.intercept("POST", "/api/data_queries").as("createQuery");
});
it("Should verify elements on amazon athena connection form", () => {

View file

@ -26,7 +26,6 @@ describe("Data source amazon ses", () => {
beforeEach(() => {
cy.apiLogin();
cy.defaultWorkspaceLogin();
cy.intercept("POST", "/api/data_queries").as("createQuery");
});
it("Should verify elements on amazonses connection form", () => {

View file

@ -26,7 +26,6 @@ describe("Data source AppWrite", () => {
beforeEach(() => {
cy.apiLogin();
cy.defaultWorkspaceLogin();
cy.intercept("POST", "/api/data_queries").as("createQuery");
});
it("Should verify elements on appwrite connection form", () => {

View file

@ -26,7 +26,6 @@ describe("Data source AWS Lambda", () => {
beforeEach(() => {
cy.apiLogin();
cy.defaultWorkspaceLogin();
cy.intercept("POST", "/api/data_queries").as("createQuery");
});
it("Should verify elements on AWS Lambda connection form", () => {

View file

@ -27,7 +27,6 @@ describe("Data source AWS Textract", () => {
beforeEach(() => {
cy.apiLogin();
cy.defaultWorkspaceLogin();
cy.intercept("POST", "/api/data_queries").as("createQuery");
});
it("Should verify elements on AWS Textract connection form", () => {

View file

@ -18,7 +18,7 @@ data.customText = fake.randomSentence;
describe("Data source Azure Blob Storage", () => {
beforeEach(() => {
cy.appUILogin();
cy.intercept("GET", "/api/v2/data_sources");
cy.defaultWorkspaceLogin();
data.dataSourceName = fake.lastName
.toLowerCase()
.replaceAll("[^A-Za-z]", "");

View file

@ -26,7 +26,6 @@ describe("Data source baserow", () => {
beforeEach(() => {
cy.apiLogin();
cy.defaultWorkspaceLogin();
cy.intercept("POST", "/api/data_queries").as("createQuery");
});
it("Should verify elements on baserow connection form", () => {

View file

@ -4,6 +4,7 @@ import { postgreSqlText } from "Texts/postgreSql";
import { bigqueryText } from "Texts/bigquery";
import { firestoreText } from "Texts/firestore";
import { commonSelectors } from "Selectors/common";
import { dataSourceSelector } from "Selectors/dataSource";
import {
fillDataSourceTextField,
selectAndAddDataSource,
@ -16,7 +17,7 @@ const data = {};
describe("Data source BigQuery", () => {
beforeEach(() => {
cy.appUILogin();
cy.intercept("GET", "/api/v2/data_sources");
cy.defaultWorkspaceLogin();
data.dataSourceName = fake.lastName
.toLowerCase()
.replaceAll("[^A-Za-z]", "");
@ -50,10 +51,19 @@ describe("Data source BigQuery", () => {
postgreSqlText.allCloudStorage
);
selectAndAddDataSource(
"databases",
bigqueryText.bigQuery,
data.dataSourceName
cy.apiCreateGDS(
`${Cypress.env("server_host")}/api/data-sources`,
`cypress-${data.dataSourceName}-bigquery`,
"bigquery",
[{ key: "private_key", value: "", encrypted: true }]
);
cy.reload();
cy.get(`[data-cy="cypress-${data.dataSourceName}-bigquery-button"]`)
.should("be.visible")
.click();
cy.get(dataSourceSelector.dsNameInputField).should(
"have.value",
`cypress-${data.dataSourceName}-bigquery`
);
cy.get('[data-cy="label-private-key"]').verifyVisibleElement(

View file

@ -1,9 +1,8 @@
import { fake } from "Fixtures/fake";
import { postgreSqlSelector } from "Selectors/postgreSql";
import { postgreSqlText } from "Texts/postgreSql";
import { commonWidgetText } from "Texts/common";
import { commonSelectors, commonWidgetSelector } from "Selectors/common";
import { commonText } from "Texts/common";
import { dataSourceSelector } from "Selectors/dataSource";
import { closeDSModal, deleteDatasource } from "Support/utils/dataSource";
import {
addQuery,
@ -21,6 +20,7 @@ const data = {};
describe("Data sources", () => {
beforeEach(() => {
cy.appUILogin();
cy.defaultWorkspaceLogin();
data.dataSourceName = fake.lastName
.toLowerCase()
.replaceAll("[^A-Za-z]", "");
@ -51,13 +51,20 @@ describe("Data sources", () => {
postgreSqlText.allCloudStorage
);
selectAndAddDataSource("databases", "ClickHouse", data.dataSourceName);
// cy.get(postgreSqlSelector.dataSourceNameInputField).should(
// //username,password,host,port,protocol,dbname,usepost, trimquery,gzip,debug,raw
// "have.value",
// "ClickHouse"
// );
cy.apiCreateGDS(
`${Cypress.env("server_host")}/api/data-sources`,
`cypress-${data.dataSourceName}-clickhouse`,
"clickhouse",
[]
);
cy.reload();
cy.get(`[data-cy="cypress-${data.dataSourceName}-clickhouse-button"]`)
.should("be.visible")
.click();
cy.get(dataSourceSelector.dsNameInputField).should(
"have.value",
`cypress-${data.dataSourceName}-clickhouse`
);
cy.get(postgreSqlSelector.labelUserName).verifyVisibleElement(
"have.text",
postgreSqlText.labelUserName
@ -78,7 +85,7 @@ describe("Data sources", () => {
cy.get(postgreSqlSelector.labelDbName).verifyVisibleElement(
"have.text",
postgreSqlText.labelDbName
"Database Name"
);
cy.get('[data-cy="label-protocol"]').verifyVisibleElement(
"have.text",
@ -140,11 +147,7 @@ describe("Data sources", () => {
Cypress.env("pg_host")
);
fillDataSourceTextField(postgreSqlText.labelPort, "8123", "8123");
fillDataSourceTextField(
postgreSqlText.labelDbName,
"database name",
"{del}"
);
fillDataSourceTextField("Database Name", "database name", "{del}");
fillDataSourceTextField(
postgreSqlText.labelUserName,
postgreSqlText.placeholderEnterUserName,

View file

@ -1,9 +1,8 @@
import { fake } from "Fixtures/fake";
import { postgreSqlSelector } from "Selectors/postgreSql";
import { postgreSqlText } from "Texts/postgreSql";
import { commonWidgetText } from "Texts/common";
import { commonSelectors, commonWidgetSelector } from "Selectors/common";
import { commonText } from "Texts/common";
import { dataSourceSelector } from "Selectors/dataSource";
import { closeDSModal, deleteDatasource } from "Support/utils/dataSource";
import {
addQuery,
@ -21,6 +20,7 @@ const data = {};
describe("Data sources", () => {
beforeEach(() => {
cy.appUILogin();
cy.defaultWorkspaceLogin();
data.dataSourceName = fake.lastName
.toLowerCase()
.replaceAll("[^A-Za-z]", "");
@ -50,7 +50,23 @@ describe("Data sources", () => {
"have.text",
postgreSqlText.allCloudStorage
);
selectAndAddDataSource("databases", "CosmosDB", data.dataSourceName);
cy.apiCreateGDS(
`${Cypress.env("server_host")}/api/data-sources`,
`cypress-${data.dataSourceName}-cosmosdb`,
"cosmosdb",
[
{ key: "endpoint", value: "" },
{ key: "key", value: "", encrypted: true },
]
);
cy.reload();
cy.get(`[data-cy="cypress-${data.dataSourceName}-cosmosdb-button"]`)
.should("be.visible")
.click();
cy.get(dataSourceSelector.dsNameInputField).should(
"have.value",
`cypress-${data.dataSourceName}-cosmosdb`
);
cy.get('[data-cy="label-end-point"]').verifyVisibleElement(
"have.text",
@ -92,7 +108,7 @@ describe("Data sources", () => {
deleteDatasource(`cypress-${data.dataSourceName}-cosmosdb`);
});
it.only("Should verify the functionality of CosmosDB connection form.", () => {
it("Should verify the functionality of CosmosDB connection form.", () => {
selectAndAddDataSource("databases", "CosmosDB", data.dataSourceName);
fillDataSourceTextField(

View file

@ -3,7 +3,7 @@ import { postgreSqlSelector } from "Selectors/postgreSql";
import { postgreSqlText } from "Texts/postgreSql";
import { commonWidgetText } from "Texts/common";
import { commonSelectors, commonWidgetSelector } from "Selectors/common";
import { commonText } from "Texts/common";
import { dataSourceSelector } from "Selectors/dataSource";
import { closeDSModal, deleteDatasource } from "Support/utils/dataSource";
import {
@ -22,6 +22,7 @@ const data = {};
describe("Data sources", () => {
beforeEach(() => {
cy.appUILogin();
cy.defaultWorkspaceLogin();
data.dataSourceName = fake.lastName
.toLowerCase()
.replaceAll("[^A-Za-z]", "");
@ -52,7 +53,27 @@ describe("Data sources", () => {
postgreSqlText.allCloudStorage
);
selectAndAddDataSource("databases", "CouchDB", data.dataSourceName);
cy.apiCreateGDS(
`${Cypress.env("server_host")}/api/data-sources`,
`cypress-${data.dataSourceName}-couchdb`,
"couchdb",
[
{ key: "username", value: "", encrypted: false },
{ key: "password", value: "", encrypted: true },
{ key: "database", value: "" },
{ key: "port", value: "5984" },
{ key: "host", value: "" },
{ key: "protocol" },
]
);
cy.reload();
cy.get(`[data-cy="cypress-${data.dataSourceName}-couchdb-button"]`)
.should("be.visible")
.click();
cy.get(dataSourceSelector.dsNameInputField).should(
"have.value",
`cypress-${data.dataSourceName}-couchdb`
);
cy.get(postgreSqlSelector.labelHost).verifyVisibleElement(
"have.text",
@ -72,7 +93,7 @@ describe("Data sources", () => {
);
cy.get(postgreSqlSelector.labelDbName).verifyVisibleElement(
"have.text",
postgreSqlText.labelDbName
"Database Name"
);
cy.get('[data-cy="label-protocol"]').verifyVisibleElement(
@ -122,11 +143,7 @@ describe("Data sources", () => {
Cypress.env("couchdb_host")
);
fillDataSourceTextField(postgreSqlText.labelPort, "5984 ", "5984");
fillDataSourceTextField(
postgreSqlText.labelDbName,
"database name",
"{del}"
);
fillDataSourceTextField("Database Name", "database name", "{del}");
fillDataSourceTextField(
postgreSqlText.labelUserName,
"username for couchDB",

View file

@ -3,7 +3,7 @@ import { postgreSqlSelector } from "Selectors/postgreSql";
import { postgreSqlText } from "Texts/postgreSql";
import { dynamoDbText } from "Texts/dynamodb";
import { commonSelectors } from "Selectors/common";
import { commonText } from "Texts/common";
import { dataSourceSelector } from "Selectors/dataSource";
import {
fillDataSourceTextField,
@ -20,6 +20,7 @@ const data = {};
describe("Data source DynamoDB", () => {
beforeEach(() => {
cy.appUILogin();
cy.defaultWorkspaceLogin();
data.dataSourceName = fake.lastName
.toLowerCase()
.replaceAll("[^A-Za-z]", "");
@ -50,10 +51,28 @@ describe("Data source DynamoDB", () => {
postgreSqlText.allCloudStorage
);
selectAndAddDataSource(
"databases",
dynamoDbText.dynamoDb,
data.dataSourceName
cy.apiCreateGDS(
`${Cypress.env("server_host")}/api/data-sources`,
`cypress-${data.dataSourceName}-dynamodb`,
"dynamodb",
[
{ key: "region", value: "" },
{ key: "access_key", value: "" },
{ key: "secret_key", value: "", encrypted: true },
{
key: "instance_metadata_credentials",
value: "iam_access_keys",
encrypted: false,
},
]
);
cy.reload();
cy.get(`[data-cy="cypress-${data.dataSourceName}-dynamodb-button"]`)
.should("be.visible")
.click();
cy.get(dataSourceSelector.dsNameInputField).should(
"have.value",
`cypress-${data.dataSourceName}-dynamodb`
);
cy.get('[data-cy="label-region"]').verifyVisibleElement(

View file

@ -3,7 +3,7 @@ import { postgreSqlSelector } from "Selectors/postgreSql";
import { postgreSqlText } from "Texts/postgreSql";
import { elasticsearchText } from "Texts/elasticsearch";
import { commonSelectors } from "Selectors/common";
import { commonText } from "Texts/common";
import { dataSourceSelector } from "Selectors/dataSource";
import {
fillDataSourceTextField,
selectAndAddDataSource,
@ -18,6 +18,7 @@ const data = {};
describe("Data source Elasticsearch", () => {
beforeEach(() => {
cy.appUILogin();
cy.defaultWorkspaceLogin();
data.lastName = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
});
@ -46,12 +47,27 @@ describe("Data source Elasticsearch", () => {
postgreSqlText.allCloudStorage
);
selectAndAddDataSource(
"databases",
elasticsearchText.elasticSearch,
data.lastName
cy.apiCreateGDS(
`${Cypress.env("server_host")}/api/data-sources`,
`cypress-${data.dataSourceName}-elasticsearch`,
"elasticsearch",
[
{ key: "host", value: "localhost" },
{ key: "port", value: 9200 },
{ key: "username", value: "" },
{ key: "password", value: "", encrypted: true },
{ key: "ssl_enabled", value: true, encrypted: false },
{ key: "ssl_certificate", value: "none", encrypted: false },
]
);
cy.reload();
cy.get(`[data-cy="cypress-${data.dataSourceName}-elasticsearch-button"]`)
.should("be.visible")
.click();
cy.get(dataSourceSelector.dsNameInputField).should(
"have.value",
`cypress-${data.dataSourceName}-elasticsearch`
);
cy.get(postgreSqlSelector.labelHost).verifyVisibleElement(
"have.text",
postgreSqlText.labelHost
@ -74,7 +90,7 @@ describe("Data source Elasticsearch", () => {
);
cy.get(postgreSqlSelector.labelSSLCertificate).verifyVisibleElement(
"have.text",
postgreSqlText.sslCertificate
"SSL Certificate"
);
cy.get(postgreSqlSelector.labelIpWhitelist).verifyVisibleElement(
"have.text",

View file

@ -3,7 +3,7 @@ import { postgreSqlSelector } from "Selectors/postgreSql";
import { postgreSqlText } from "Texts/postgreSql";
import { firestoreText } from "Texts/firestore";
import { commonSelectors } from "Selectors/common";
import { commonText } from "Texts/common";
import { dataSourceSelector } from "Selectors/dataSource";
import {
verifyCouldnotConnectWithAlert,
deleteDatasource,
@ -18,6 +18,7 @@ const data = {};
describe("Data source Firestore", () => {
beforeEach(() => {
cy.appUILogin();
cy.defaultWorkspaceLogin();
data.dataSourceName = fake.lastName
.toLowerCase()
.replaceAll("[^A-Za-z]", "");
@ -47,12 +48,20 @@ describe("Data source Firestore", () => {
postgreSqlText.allCloudStorage
);
selectAndAddDataSource(
"databases",
firestoreText.firestore,
data.dataSourceName
cy.apiCreateGDS(
`${Cypress.env("server_host")}/api/data-sources`,
`cypress-${data.dataSourceName}-firestore`,
"firestore",
[{ key: "gcp_key", value: "", encrypted: true }]
);
cy.reload();
cy.get(`[data-cy="cypress-${data.dataSourceName}-firestore-button"]`)
.should("be.visible")
.click();
cy.get(dataSourceSelector.dsNameInputField).should(
"have.value",
`cypress-${data.dataSourceName}-firestore`
);
cy.get('[data-cy="label-private-key"]').verifyVisibleElement(
"have.text",
firestoreText.labelPrivateKey

View file

@ -1,8 +1,8 @@
import { fake } from "Fixtures/fake";
import { postgreSqlSelector } from "Selectors/postgreSql";
import { postgreSqlText } from "Texts/postgreSql";
import { commonWidgetText, commonText } from "Texts/common";
import { commonSelectors, commonWidgetSelector } from "Selectors/common";
import { dataSourceSelector } from "Selectors/dataSource";
import {
addQuery,
fillDataSourceTextField,
@ -24,6 +24,7 @@ const data = {};
describe("Data sources", () => {
beforeEach(() => {
cy.appUILogin();
cy.defaultWorkspaceLogin();
data.dataSourceName = fake.lastName
.toLowerCase()
.replaceAll("[^A-Za-z]", "");
@ -54,7 +55,25 @@ describe("Data sources", () => {
postgreSqlText.allCloudStorage
);
selectAndAddDataSource("databases", "InfluxDB", data.dataSourceName);
cy.apiCreateGDS(
`${Cypress.env("server_host")}/api/data-sources`,
`cypress-${data.dataSourceName}-influxdb`,
"influxdb",
[
{ key: "api_token", value: "", encrypted: true },
{ key: "port", value: "8086", encrypted: false },
{ key: "host", value: "", encrypted: false },
{ key: "protocol", value: "http", encrypted: false },
]
);
cy.reload();
cy.get(`[data-cy="cypress-${data.dataSourceName}-influxdb-button"]`)
.should("be.visible")
.click();
cy.get(dataSourceSelector.dsNameInputField).should(
"have.value",
`cypress-${data.dataSourceName}-influxdb`
);
cy.get('[data-cy="label-api-token"]').verifyVisibleElement(
"have.text",

View file

@ -1,6 +1,6 @@
import { postgreSqlSelector } from "Selectors/postgreSql";
import { postgreSqlText } from "Texts/postgreSql";
import { commonWidgetText, commonText } from "Texts/common";
import { dataSourceSelector } from "Selectors/dataSource";
import { commonSelectors, commonWidgetSelector } from "Selectors/common";
import {
addQuery,
@ -20,6 +20,7 @@ const data = {};
describe("Data sources", () => {
beforeEach(() => {
cy.appUILogin();
cy.defaultWorkspaceLogin();
data.dataSourceName = fake.lastName
.toLowerCase()
.replaceAll("[^A-Za-z]", "");
@ -50,7 +51,20 @@ describe("Data sources", () => {
postgreSqlText.allCloudStorage
);
selectAndAddDataSource("databases", "MariaDB", data.dataSourceName);
cy.apiCreateGDS(
`${Cypress.env("server_host")}/api/data-sources`,
`cypress-${data.dataSourceName}-mariadb`,
"mariadb",
[{ key: "connectionLimit", value: 5 }]
);
cy.reload();
cy.get(`[data-cy="cypress-${data.dataSourceName}-mariadb-button"]`)
.should("be.visible")
.click();
cy.get(dataSourceSelector.dsNameInputField).should(
"have.value",
`cypress-${data.dataSourceName}-mariadb`
);
cy.get(postgreSqlSelector.labelHost).verifyVisibleElement(
"have.text",
@ -83,7 +97,7 @@ describe("Data sources", () => {
cy.get(postgreSqlSelector.labelSSLCertificate).verifyVisibleElement(
"have.text",
postgreSqlText.sslCertificate
"SSL Certificate"
);
cy.get(postgreSqlSelector.labelIpWhitelist).verifyVisibleElement(
"have.text",

View file

@ -3,7 +3,7 @@ import { postgreSqlSelector } from "Selectors/postgreSql";
import { postgreSqlText } from "Texts/postgreSql";
import { mongoDbText } from "Texts/mongoDb";
import { commonSelectors } from "Selectors/common";
import { commonText } from "Texts/common";
import { dataSourceSelector } from "Selectors/dataSource";
import { closeDSModal, deleteDatasource } from "Support/utils/dataSource";
import {
fillDataSourceTextField,
@ -28,6 +28,7 @@ const data = {};
describe("Data source MongoDB", () => {
beforeEach(() => {
cy.appUILogin();
cy.defaultWorkspaceLogin();
data.dataSourceName = fake.lastName
.toLowerCase()
.replaceAll("[^A-Za-z]", "");
@ -56,10 +57,28 @@ describe("Data source MongoDB", () => {
"have.text",
postgreSqlText.allCloudStorage
);
selectAndAddDataSource(
"databases",
mongoDbText.mongoDb,
data.dataSourceName
cy.apiCreateGDS(
`${Cypress.env("server_host")}/api/data-sources`,
`cypress-${data.dataSourceName}-mongodb`,
"mongodb",
[
{ key: "database", value: "", encrypted: false },
{ key: "host", value: "localhost" },
{ key: "port", value: 27017 },
{ key: "username", value: "" },
{ key: "password", value: "", encrypted: true },
{ key: "connection_type", value: "manual" },
{ key: "connection_string", value: "", encrypted: true },
{ key: "tls_certificate", value: "none", encrypted: false },
]
);
cy.reload();
cy.get(`[data-cy="cypress-${data.dataSourceName}-mongodb-button"]`)
.should("be.visible")
.click();
cy.get(dataSourceSelector.dsNameInputField).should(
"have.value",
`cypress-${data.dataSourceName}-mongodb`
);
cy.get(postgreSqlSelector.labelHost).verifyVisibleElement(
@ -72,7 +91,7 @@ describe("Data source MongoDB", () => {
);
cy.get(postgreSqlSelector.labelDbName).verifyVisibleElement(
"have.text",
postgreSqlText.labelDbName
"Database Name"
);
cy.get(postgreSqlSelector.labelUserName).verifyVisibleElement(
"have.text",
@ -168,7 +187,7 @@ describe("Data source MongoDB", () => {
data.dataSourceName
);
cy.get('[data-cy="query-select-dropdown"]').type(
cy.get('[data-cy="connection-type-select-dropdown"]').type(
mongoDbText.optionConnectUsingConnectionString
);

View file

@ -19,6 +19,7 @@ import {
deleteDatasource,
verifyCouldnotConnectWithAlert,
} from "Support/utils/dataSource";
import { dataSourceSelector } from "Selectors/dataSource";
import { realHover } from "cypress-real-events/commands/realHover";
const data = {};
@ -26,6 +27,7 @@ const data = {};
describe("Data sources MySql", () => {
beforeEach(() => {
cy.appUILogin();
cy.defaultWorkspaceLogin();
data.dataSourceName = fake.lastName
.toLowerCase()
.replaceAll("[^A-Za-z]", "");
@ -56,7 +58,30 @@ describe("Data sources MySql", () => {
postgreSqlText.allCloudStorage
);
selectAndAddDataSource("databases", "MySQL", data.dataSourceName);
cy.apiCreateGDS(
`${Cypress.env("server_host")}/api/data-sources`,
`cypress-${data.dataSourceName}-mysql`,
"mysql",
[
{ key: "connection_type", value: "hostname" },
{ key: "host", value: "localhost" },
{ key: "port", value: 3306 },
{ key: "database", value: "" },
{ key: "socket", value: "", encrypted: false },
{ key: "username", value: "" },
{ key: "password", value: "", encrypted: true },
{ key: "ssl_enabled", value: false, encrypted: false },
{ key: "ssl_certificate", value: "none", encrypted: false },
]
);
cy.reload();
cy.get(`[data-cy="cypress-${data.dataSourceName}-mysql-button"]`)
.should("be.visible")
.click();
cy.get(dataSourceSelector.dsNameInputField).should(
"have.value",
`cypress-${data.dataSourceName}-mysql`
);
cy.get(postgreSqlSelector.labelHost).verifyVisibleElement(
"have.text",
@ -110,7 +135,7 @@ describe("Data sources MySql", () => {
deleteDatasource(`cypress-${data.dataSourceName}-mysql`);
});
it.only("Should verify the functionality of MySQL connection form.", () => {
it("Should verify the functionality of MySQL connection form.", () => {
selectAndAddDataSource("databases", "MySQL", data.dataSourceName);
fillDataSourceTextField(
@ -170,9 +195,9 @@ describe("Data sources MySql", () => {
verifyCouldnotConnectWithAlert(
"ER_ACCESS_DENIED_ERROR: Access denied for user 'root'@'103.171.99.42' (using password: YES)"
);
cy.get('[data-cy="-toggle-input"]').then(($el) => {
cy.get('[data-cy="ssl-enabled-toggle-input"]').then(($el) => {
if ($el.is(":checked")) {
cy.get('[data-cy="-toggle-input"]').uncheck();
cy.get('[data-cy="ssl-enabled-toggle-input"]').uncheck();
}
});

View file

@ -3,6 +3,7 @@ import { postgreSqlSelector } from "Selectors/postgreSql";
import { postgreSqlText } from "Texts/postgreSql";
import { commonWidgetText, commonText } from "Texts/common";
import { commonSelectors, commonWidgetSelector } from "Selectors/common";
import { dataSourceSelector } from "Selectors/dataSource";
import {
addQuery,
fillDataSourceTextField,
@ -20,6 +21,7 @@ const data = {};
describe("Data sources", () => {
beforeEach(() => {
cy.appUILogin();
cy.defaultWorkspaceLogin();
data.dataSourceName = fake.lastName
.toLowerCase()
.replaceAll("[^A-Za-z]", "");
@ -52,10 +54,31 @@ describe("Data sources", () => {
postgreSqlText.allCloudStorage
);
selectAndAddDataSource(
"databases",
postgreSqlText.postgreSQL,
data.dataSourceName
cy.apiCreateGDS(
`${Cypress.env("server_host")}/api/data-sources`,
`cypress-${data.dataSourceName}-postgresql`,
"postgresql",
[
{ key: "connection_type", value: "manual", encrypted: false },
{ key: "host", value: "localhost", encrypted: false },
{ key: "port", value: 5432, encrypted: false },
{ key: "ssl_enabled", value: true, encrypted: false },
{ key: "ssl_certificate", value: "none", encrypted: false },
{ key: "password", value: null, encrypted: true },
{ key: "ca_cert", value: null, encrypted: true },
{ key: "client_key", value: null, encrypted: true },
{ key: "client_cert", value: null, encrypted: true },
{ key: "root_cert", value: null, encrypted: true },
{ key: "connection_string", value: null, encrypted: true },
]
);
cy.reload();
cy.get(`[data-cy="cypress-${data.dataSourceName}-postgresql-button"]`)
.should("be.visible")
.click();
cy.get(dataSourceSelector.dsNameInputField).should(
"have.value",
`cypress-${data.dataSourceName}-postgresql`
);
cy.get(postgreSqlSelector.labelHost).verifyVisibleElement(

View file

@ -5,7 +5,7 @@ import { postgreSqlSelector } from "Selectors/postgreSql";
import { postgreSqlText } from "Texts/postgreSql";
import { restAPISelector } from "Selectors/restAPI";
import { restAPIText } from "Texts/restAPI";
import { fillDataSourceTextField } from "Support/utils/postgreSql";
import { createAndRunRestAPIQuery } from "Support/utils/restAPI";
const data = {};
const authenticationDropdownSelector =
@ -19,8 +19,8 @@ const clientAuthenticationDropdown =
describe("Data source Rest API", () => {
beforeEach(() => {
cy.apiLogin();
cy.defaultWorkspaceLogin();
cy.intercept("GET", "/api/v2/data_sources");
data.dataSourceName = fake.lastName
.toLowerCase()
.replaceAll("[^A-Za-z]", "");
@ -331,7 +331,8 @@ describe("Data source Rest API", () => {
cy.verifyToastMessage(commonSelectors.toastMessage, "Data Source Saved");
deleteDatasource(`cypress-${data.dataSourceName}-restapi`);
});
it("Should verify connection for Rest API", () => {
it("Should verify basic connection for Rest API", () => {
const storedId = Cypress.env("storedId");
cy.apiCreateGDS(
`${Cypress.env("server_host")}/api/data-sources`,
`cypress-${data.dataSourceName}-restapi`,
@ -366,18 +367,89 @@ describe("Data source Rest API", () => {
]
);
cy.reload();
// cy.apiCreateApp(`${fake.companyName}-restAPI-App`);
// cy.apiAddQueryToApp(
// "restapi1",
// {
// method: "get",
// url: "",
// url_params: [["", ""]],
// headers: [["", ""]],
// cookies: [["", ""]],
// },
// `cypress-${data.dataSourceName}-restapi`,
// "restapi"
// );
cy.apiCreateApp(`${fake.companyName}-restAPI-App`);
cy.openApp();
createAndRunRestAPIQuery(
"get_restapi",
`cypress-${data.dataSourceName}-restapi`,
"GET",
"/api/users"
);
createAndRunRestAPIQuery(
"post_restapi",
`cypress-${data.dataSourceName}-restapi`,
"POST",
"",
[["Content-Type", "application/json"]],
[],
{
price: 200,
name: "Violin",
},
true,
"/api/users"
);
cy.readFile("cypress/fixtures/restAPI/storedId.json").then(
(postResponseID) => {
const id1 = postResponseID.id;
createAndRunRestAPIQuery(
"put_restapi_id",
`cypress-${data.dataSourceName}-restapi`,
"PUT",
"",
[["Content-Type", "application/json"]],
[],
{
price: 500,
name: "Guitar",
},
true,
`/api/users/${id1}`
);
}
);
cy.readFile("cypress/fixtures/restAPI/storedId.json").then(
(putResponseID) => {
const id2 = putResponseID.id;
createAndRunRestAPIQuery(
"patch_restapi_id",
`cypress-${data.dataSourceName}-restapi`,
"PATCH",
"",
[["Content-Type", "application/json"]],
[],
{ price: 999 },
true,
`/api/users/${id2}`
);
}
);
cy.readFile("cypress/fixtures/restAPI/storedId.json").then(
(patchResponseID) => {
const id3 = patchResponseID.id;
createAndRunRestAPIQuery(
"get_restapi_id",
`cypress-${data.dataSourceName}-restapi`,
"GET",
"",
[],
[],
true,
`/api/users/${id3}`
);
createAndRunRestAPIQuery(
"delete_restapi_id",
`cypress-${data.dataSourceName}-restapi`,
"DELETE",
"",
[],
[],
true,
`/api/users/${id3}`
);
}
);
});
});

View file

@ -3,6 +3,7 @@ import { postgreSqlSelector } from "Selectors/postgreSql";
import { postgreSqlText } from "Texts/postgreSql";
import { commonWidgetText, commonText } from "Texts/common";
import { commonSelectors, commonWidgetSelector } from "Selectors/common";
import { dataSourceSelector } from "Selectors/dataSource";
import {
addQuery,
fillDataSourceTextField,
@ -19,6 +20,7 @@ const data = {};
describe("Data sources", () => {
beforeEach(() => {
cy.appUILogin();
cy.defaultWorkspaceLogin();
data.dataSourceName = fake.lastName
.toLowerCase()
.replaceAll("[^A-Za-z]", "");
@ -49,7 +51,26 @@ describe("Data sources", () => {
postgreSqlText.allCloudStorage
);
selectAndAddDataSource("databases", "RethinkDB", data.dataSourceName);
cy.apiCreateGDS(
`${Cypress.env("server_host")}/api/data-sources`,
`cypress-${data.dataSourceName}-rethinkdb`,
"rethinkdb",
[
{ key: "port", value: "28015", encrypted: false },
{ key: "host", value: "", encrypted: false },
{ key: "database", value: "", encrypted: false },
{ key: "username", value: "", encrypted: false },
{ key: "password", value: "", encrypted: true },
]
);
cy.reload();
cy.get(`[data-cy="cypress-${data.dataSourceName}-rethinkdb-button"]`)
.should("be.visible")
.click();
cy.get(dataSourceSelector.dsNameInputField).should(
"have.value",
`cypress-${data.dataSourceName}-rethinkdb`
);
cy.get('[data-cy="label-database"]').verifyVisibleElement(
"have.text",

View file

@ -4,7 +4,7 @@ import { s3Selector } from "Selectors/awss3";
import { postgreSqlText } from "Texts/postgreSql";
import { s3Text } from "Texts/awss3";
import { commonSelectors } from "Selectors/common";
import { commonText } from "Texts/common";
import { dataSourceSelector } from "Selectors/dataSource";
import {
fillDataSourceTextField,
selectAndAddDataSource,
@ -51,7 +51,31 @@ describe("Data sources AWS S3", () => {
postgreSqlText.allCloudStorage
);
selectAndAddDataSource("cloudstorage", s3Text.awsS3, data.dataSourceName);
cy.apiCreateGDS(
`${Cypress.env("server_host")}/api/data-sources`,
`cypress-${data.dataSourceName}-aws-s3`,
"s3",
[
{ key: "access_key", value: "" },
{ key: "secret_key", value: "", encrypted: true },
{ key: "region", value: "" },
{ key: "endpoint", value: "" },
{ key: "endpoint_enabled", value: false, encrypted: false },
{
key: "instance_metadata_credentials",
value: "iam_access_keys",
encrypted: false,
},
]
);
cy.reload();
cy.get(`[data-cy="cypress-${data.dataSourceName}-aws-s3-button"]`)
.should("be.visible")
.click();
cy.get(dataSourceSelector.dsNameInputField).should(
"have.value",
`cypress-${data.dataSourceName}-aws-s3`
);
cy.get(s3Selector.accessKeyLabel).verifyVisibleElement(
"have.text",
s3Text.accessKey

View file

@ -2,7 +2,7 @@ import { fake } from "Fixtures/fake";
import { postgreSqlSelector } from "Selectors/postgreSql";
import { postgreSqlText } from "Texts/postgreSql";
import { commonSelectors } from "Selectors/common";
import { commonText } from "Texts/common";
import { dataSourceSelector } from "Selectors/dataSource";
import {
fillDataSourceTextField,
selectAndAddDataSource,
@ -14,6 +14,7 @@ const data = {};
describe("Data source SMTP", () => {
beforeEach(() => {
cy.appUILogin();
cy.defaultWorkspaceLogin();
data.dataSourceName = fake.lastName
.toLowerCase()
.replaceAll("[^A-Za-z]", "");
@ -43,7 +44,25 @@ describe("Data source SMTP", () => {
postgreSqlText.allCloudStorage
);
selectAndAddDataSource("apis", "SMTP", data.dataSourceName);
cy.apiCreateGDS(
`${Cypress.env("server_host")}/api/data-sources`,
`cypress-${data.dataSourceName}-smtp`,
"smtp",
[
{ key: "host", value: "localhost", encrypted: false },
{ key: "port", value: 465, encrypted: false },
{ key: "user", value: "", encrypted: false },
{ key: "password", value: "", encrypted: true },
]
);
cy.reload();
cy.get(`[data-cy="cypress-${data.dataSourceName}-smtp-button"]`)
.should("be.visible")
.click();
cy.get(dataSourceSelector.dsNameInputField).should(
"have.value",
`cypress-${data.dataSourceName}-smtp`
);
cy.get(postgreSqlSelector.labelHost).verifyVisibleElement(
"have.text",

View file

@ -4,6 +4,7 @@ import { postgreSqlText } from "Texts/postgreSql";
import { commonWidgetText, commonText } from "Texts/common";
import { commonSelectors, commonWidgetSelector } from "Selectors/common";
import { closeDSModal, deleteDatasource } from "Support/utils/dataSource";
import { dataSourceSelector } from "Selectors/dataSource";
import {
addQuery,
@ -20,6 +21,7 @@ const data = {};
describe("Data sources", () => {
beforeEach(() => {
cy.appUILogin();
cy.defaultWorkspaceLogin();
data.dataSourceName = fake.lastName
.toLowerCase()
.replaceAll("[^A-Za-z]", "");
@ -49,8 +51,28 @@ describe("Data sources", () => {
"have.text",
postgreSqlText.allCloudStorage
);
selectAndAddDataSource("databases", "Snowflake", data.dataSourceName);
cy.apiCreateGDS(
`${Cypress.env("server_host")}/api/data-sources`,
`cypress-${data.dataSourceName}-snowflake`,
"snowflake",
[
{ key: "username", value: "" },
{ key: "account", value: "" },
{ key: "password", value: "", encrypted: true },
{ key: "database", value: "" },
{ key: "schema", value: "" },
{ key: "warehouse", value: "" },
{ key: "role", value: "" },
]
);
cy.reload();
cy.get(`[data-cy="cypress-${data.dataSourceName}-snowflake-button"]`)
.should("be.visible")
.click();
cy.get(dataSourceSelector.dsNameInputField).should(
"have.value",
`cypress-${data.dataSourceName}-snowflake`
);
cy.get(postgreSqlSelector.labelUserName).verifyVisibleElement(
"have.text",
postgreSqlText.labelUserName
@ -113,7 +135,7 @@ describe("Data sources", () => {
deleteDatasource(`cypress-${data.dataSourceName}-snowflake`);
});
it.skip("Should verify the functionality of PostgreSQL connection form.", () => {
it.skip("Should verify the functionality of snowflake connection form.", () => {
selectAndAddDataSource("databases", "Snowflake", data.dataSourceName);
fillDataSourceTextField(

View file

@ -4,6 +4,7 @@ import { postgreSqlText } from "Texts/postgreSql";
import { commonWidgetText, commonText } from "Texts/common";
import { commonSelectors, commonWidgetSelector } from "Selectors/common";
import { deleteDatasource, closeDSModal } from "Support/utils/dataSource";
import { dataSourceSelector } from "Selectors/dataSource";
import {
addQuery,
@ -21,6 +22,7 @@ const data = {};
describe("Data sources", () => {
beforeEach(() => {
cy.appUILogin();
cy.defaultWorkspaceLogin();
data.dataSourceName = fake.lastName
.toLowerCase()
.replaceAll("[^A-Za-z]", "");
@ -51,7 +53,28 @@ describe("Data sources", () => {
postgreSqlText.allCloudStorage
);
selectAndAddDataSource("databases", "SQL Server", data.dataSourceName);
cy.apiCreateGDS(
`${Cypress.env("server_host")}/api/data-sources`,
`cypress-${data.dataSourceName}-sql-server`,
"mssql",
[
{ key: "host", value: "localhost" },
{ key: "instanceName", value: "" },
{ key: "port", value: 1433 },
{ key: "database", value: "" },
{ key: "username", value: "" },
{ key: "password", value: "", encrypted: true },
{ key: "azure", value: false, encrypted: false },
]
);
cy.reload();
cy.get(`[data-cy="cypress-${data.dataSourceName}-sql-server-button"]`)
.should("be.visible")
.click();
cy.get(dataSourceSelector.dsNameInputField).should(
"have.value",
`cypress-${data.dataSourceName}-sql-server`
);
cy.get(postgreSqlSelector.labelHost).verifyVisibleElement(
"have.text",
@ -67,7 +90,7 @@ describe("Data sources", () => {
);
cy.get(postgreSqlSelector.labelDbName).verifyVisibleElement(
"have.text",
postgreSqlText.labelDbName
"Database Name"
);
cy.get(postgreSqlSelector.labelUserName).verifyVisibleElement(
"have.text",
@ -78,8 +101,8 @@ describe("Data sources", () => {
"Password"
);
cy.get('[data-cy="label-azure"]').verifyVisibleElement(
"have.text",
cy.get('[data-cy^="label-azure-"]').verifyVisibleElement(
"contain",
"Azure"
);
cy.get(postgreSqlSelector.labelIpWhitelist).verifyVisibleElement(
@ -135,7 +158,7 @@ describe("Data sources", () => {
"1433"
);
fillDataSourceTextField(
postgreSqlText.labelDbName,
"Database Name",
postgreSqlText.placeholderNameOfDB,
Cypress.env("sqlserver_db")
);

View file

@ -0,0 +1,219 @@
import { fake } from "Fixtures/fake";
import { commonSelectors } from "Selectors/common";
import { importSelectors } from "Selectors/exportImport";
import { commonText } from "Texts/common";
import { exportAppModalText } from "Texts/exportImport";
import {
clickOnExportButtonAndVerify,
exportAllVersionsAndVerify,
verifyElementsOfExportModal,
} from "Support/utils/exportImport";
import { selectAppCardOption, closeModal } from "Support/utils/common";
describe("App Export", () => {
const TEST_DATA = {
appFiles: {
multiVersion: "cypress/fixtures/templates/three-versions.json",
singleVersion: "cypress/fixtures/templates/one_version.json",
},
};
let data;
data = {
workspaceName: fake.firstName,
workspaceSlug: fake.firstName.toLowerCase().replace(/\s+/g, "-"),
appName: `${fake.companyName}-IE-App`,
appReName: `${fake.companyName}-${fake.companyName}-IE-App`,
dsName: fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", ""),
};
beforeEach(() => {
data = {
workspaceName: fake.firstName,
workspaceSlug: fake.firstName.toLowerCase().replace(/\s+/g, "-"),
appName: `${fake.companyName}-IE-App`,
appReName: `${fake.companyName}-${fake.companyName}-IE-App`,
dsName: fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", ""),
};
cy.exec("mkdir -p ./cypress/downloads/");
cy.wait(3000);
cy.apiLogin();
cy.apiCreateWorkspace(data.workspaceName, data.workspaceSlug);
cy.apiLogout();
});
it("Verify the elements of export dialog box", () => {
cy.window({ log: false }).then((win) => {
win.localStorage.setItem("walkthroughCompleted", "true");
});
cy.apiLogin();
cy.visit(`${data.workspaceSlug}`);
cy.get(importSelectors.importOptionInput)
.eq(0)
.selectFile(TEST_DATA.appFiles.multiVersion, {
force: true,
});
cy.wait(1500);
cy.clearAndType(commonSelectors.appNameInput, data.appName);
cy.get(importSelectors.importAppButton).click();
cy.wait(3000);
cy.backToApps();
// Select the app card option to export the app
selectAppCardOption(
data.appName,
commonSelectors.appCardOptions(commonText.exportAppOption)
);
// Verify the elements of the export modal
verifyElementsOfExportModal("v3", ["v2", "v1"], [true, false, false]);
// Close the modal
closeModal(exportAppModalText.modalCloseButton);
// Ensure the modal title is no longer visible
cy.get(
commonSelectors.modalTitle(exportAppModalText.selectVersionTitle)
).should("not.exist");
// Re-open the export modal and click the export button
selectAppCardOption(
data.appName,
commonSelectors.appCardOptions(commonText.exportAppOption)
);
clickOnExportButtonAndVerify(exportAppModalText.exportAll, data.appName);
cy.exec("ls ./cypress/downloads/").then((result) => {
const downloadedAppExportFileName = result.stdout.split("\n")[0];
const filePath = `./cypress/downloads/${downloadedAppExportFileName}`;
// Ensure the file name contains the expected app export name
expect(downloadedAppExportFileName).to.contain(
data.appName.toLowerCase()
);
// Read and validate the exported JSON file
cy.readFile(filePath).then((appData) => {
// Validate the app name
const appNameFromFile = appData.app[0].definition.appV2.name;
expect(appNameFromFile).to.equal(data.appName);
// Validate the schema for the student table in tooljetdb
const tooljetDatabase = appData.tooljet_database.find(
(db) => db.table_name === "student"
);
expect(tooljetDatabase).to.exist;
expect(tooljetDatabase.schema).to.exist;
// Validate components and queries
const components = appData.app[0].definition.appV2.components;
const text2Component = components.find(
(component) => component.name === "text2"
);
expect(text2Component).to.exist;
expect(text2Component.properties.text.value).to.equal(
"{{constants.pageHeader}}"
);
const textinput1 = components.find(
(component) => component.name === "textinput1"
);
expect(textinput1).to.exist;
expect(textinput1.properties.value.value).to.include("queries");
const textinput2 = components.find(
(component) => component.name === "textinput2"
);
expect(textinput2).to.exist;
expect(textinput2.properties.value.value).to.include("queries");
const textinput3 = components.find(
(component) => component.name === "textinput3"
);
expect(textinput3).to.exist;
expect(textinput3.properties.value.value).to.include("queries");
// Validate the data queries
const dataQueries = appData.app[0].definition.appV2.dataQueries;
const postgresqlQuery = dataQueries.find(
(query) => query.name === "postgresql1"
);
expect(postgresqlQuery).to.exist;
expect(postgresqlQuery.options.query).to.include(
"Select * from {{secrets.db_name}}"
);
const restapiQuery = dataQueries.find(
(query) => query.name === "restapi1"
);
expect(restapiQuery).to.exist;
expect(restapiQuery.options.url).to.equal(
"https://jsonplaceholder.typicode.com/users/1"
);
const tooljetdbQuery = dataQueries.find(
(query) => query.name === "tooljetdb1"
);
expect(tooljetdbQuery).to.exist;
expect(tooljetdbQuery.options.operation).to.equal("list_rows");
// Ensure appVersions exists
const appVersions = appData.app[0].definition.appV2.appVersions;
expect(appVersions).to.exist;
// Map and verify app version names
const versionNames = appVersions.map((version) => version.name);
expect(versionNames).to.include.members(["v1", "v2", "v3"]);
});
});
cy.exec("cd ./cypress/downloads/ && rm -rf *");
selectAppCardOption(
data.appName,
commonSelectors.appCardOptions(commonText.exportAppOption)
);
cy.get(`[data-cy="v1-radio-button"]`).check();
cy.get(
commonSelectors.buttonSelector(exportAppModalText.exportSelectedVersion)
).click();
cy.exec("ls ./cypress/downloads/").then((result) => {
const downloadedAppExportFileName = result.stdout.split("\n")[0];
const filePath = `./cypress/downloads/${downloadedAppExportFileName}`;
// Ensure the file name contains the expected app export name
expect(downloadedAppExportFileName).to.contain(
data.appName.toLowerCase()
);
// Read and validate the exported JSON file
cy.readFile(filePath).then((appData) => {
// Validate the app name
const appNameFromFile = appData.app[0].definition.appV2.name;
expect(appNameFromFile).to.equal(data.appName);
});
});
});
it.skip("Verify 'Export app' functionality of an application inside app editor", () => {
data.appName2 = `${fake.companyName}-App`;
cy.apiCreateApp(data.appName2);
cy.openApp(data.appName2);
cy.dragAndDropWidget("Text Input", 50, 50);
cy.get('[data-cy="left-sidebar-settings-button"]').click();
cy.get('[data-cy="button-user-status-change"]').click();
verifyElementsOfExportModal("v1");
exportAllVersionsAndVerify(data.appName1, "v1");
});
});

View file

@ -0,0 +1,230 @@
import { fake } from "Fixtures/fake";
import { commonSelectors, commonWidgetSelector } from "Selectors/common";
import { appVersionSelectors, importSelectors } from "Selectors/exportImport";
import { dashboardSelector } from "Selectors/dashboard";
import { buttonText } from "Texts/button";
import { importText } from "Texts/exportImport";
import { importAndVerifyApp } from "Support/utils/exportImport";
import { switchVersionAndVerify } from "Support/utils/version";
describe("App Import Functionality", () => {
const TEST_DATA = {
toolJetImage: "cypress/fixtures/Image/tooljet.png",
invalidApp: "cypress/fixtures/templates/invalid_app.json",
invalidFile: "cypress/fixtures/templates/invalid_file.json",
appFiles: {
multiVersion: "cypress/fixtures/templates/three-versions.json",
singleVersion: "cypress/fixtures/templates/one_version.json",
},
};
let data;
beforeEach(() => {
cy.viewport(1200, 1300);
data = {
workspaceName: fake.firstName,
workspaceSlug: fake.firstName.toLowerCase().replace(/\s+/g, "-"),
appName: `${fake.companyName}-IE-App`,
appReName: `${fake.companyName}-${fake.companyName}-IE-App`,
dsName: fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", ""),
};
cy.apiLogin();
cy.apiCreateWorkspace(data.workspaceName, data.workspaceSlug);
cy.apiLogout();
});
it("should verify app import functionality", () => {
cy.apiLogin();
cy.visit(`${data.workspaceSlug}`);
// Test invalid file import
cy.get(dashboardSelector.importAppButton).click();
importAndVerifyApp(
TEST_DATA.toolJetImage,
importText.couldNotImportAppToastMessage
);
cy.wait(500);
cy.get(dashboardSelector.importAppButton).click();
importAndVerifyApp(
TEST_DATA.invalidApp,
"Could not import: SyntaxError: Expected ',' or '}' after property value in JSON at position 246 (line 11 column 13)"
);
cy.wait(500);
// Test valid app import
cy.get(importSelectors.dropDownMenu).should("be.visible").click();
cy.get(importSelectors.importOptionLabel).verifyVisibleElement(
"have.text",
importText.importOption
);
cy.intercept("POST", "/api/v2/resources/import").as("importApp");
cy.get(importSelectors.importOptionInput)
.eq(0)
.selectFile(TEST_DATA.appFiles.multiVersion, {
force: true,
});
cy.wait(1500);
cy.get(importSelectors.importAppTitle).verifyVisibleElement(
"have.text",
"Import app"
);
cy.get(commonSelectors.appNameLabel).verifyVisibleElement(
"have.text",
"App name"
);
cy.get(commonSelectors.appNameInput)
.should("be.visible")
.and("have.value", "three-versions");
cy.get(commonSelectors.appNameInfoLabel).verifyVisibleElement(
"have.text",
"App name must be unique and max 50 characters"
);
cy.get(commonSelectors.cancelButton)
.should("be.visible")
.and("have.text", "Cancel");
cy.get(commonSelectors.importAppButton).verifyVisibleElement(
"have.text",
"Import app"
);
cy.get(importSelectors.importAppButton).click();
cy.get(".go3958317564")
.should("be.visible")
.and("have.text", importText.appImportedToastMessage);
// Verify imported app
cy.get(".driver-close-btn").click();
cy.wait(500);
cy.get(commonSelectors.appNameInput).verifyVisibleElement(
"contain.value",
"three-versions"
);
// Configure app
cy.skipEditorPopover();
cy.dragAndDropWidget(buttonText.defaultWidgetText);
cy.get(appVersionSelectors.appVersionLabel).should("be.visible");
cy.get(commonWidgetSelector.draggableWidget("button1")).should(
"be.visible"
);
cy.renameApp(data.appName);
cy.get(commonSelectors.appNameInput).verifyVisibleElement(
"contain.value",
data.appName
);
cy.waitForAutoSave();
// Verify initial widget states
verifyCommonData({
text2: "",
textInput1: "",
textInput2: "Leanne Graham",
});
// cy.get(
// commonWidgetSelector.draggableWidget("textInput3")
// ).verifyVisibleElement("have.value", "");
// Setup database and data sources
cy.visit(`${data.workspaceSlug}/database`);
cy.get('[data-cy="student-table"]').verifyVisibleElement(
"have.text",
"student"
);
// cy.apiAddDataToTable("student", {
// name: "Paramu",
// country: "India",
// state: "Kerala",
// });
cy.visit(`${data.workspaceSlug}/data-sources`);
cy.get('[data-cy="postgresql-button"]').should("be.visible");
cy.apiUpdateDataSource("postgresql", "production", {
options: [
{
key: "password",
value: `${Cypress.env("pg_password")}`,
encrypted: true,
},
],
});
cy.apiCreateWsConstant(
"pageHeader",
"Import and Export",
["Global"],
["production"]
);
cy.apiCreateWsConstant("db_name", "persons", ["Secret"], ["production"]);
// Verify app after setup
cy.wait("@importApp").then((interception) => {
const appId = interception.response.body.imports.app[0].id;
cy.openApp(
"",
Cypress.env("workspaceId"),
appId,
commonWidgetSelector.draggableWidget("text2")
);
});
verifyCommonData({
text2: "Import and Export",
textInput1: "John",
textInput2: "Leanne Graham",
});
// cy.get(
// commonWidgetSelector.draggableWidget("textInput3")
// ).verifyVisibleElement("have.value", "India");
switchVersionAndVerify("v3", "v1");
verifyCommonData({
text2: "Import and Export",
textInput1: "John",
textInput2: "Leanne Graham",
});
cy.wait(1000);
cy.backToApps();
// Test single version import
cy.get(importSelectors.dropDownMenu).click();
importAndVerifyApp(TEST_DATA.appFiles.singleVersion);
// Verify final state
cy.get(commonSelectors.appNameInput).verifyVisibleElement(
"contain.value",
"one_version"
);
verifyCommonData({
text2: "Import and Export",
textInput1: "John",
textInput2: "Leanne Graham",
});
});
});
const verifyCommonData = (values) => {
cy.get(commonWidgetSelector.draggableWidget("text2")).verifyVisibleElement(
"have.text",
values.text2
);
cy.get(
commonWidgetSelector.draggableWidget("textInput1")
).verifyVisibleElement("have.value", values.textInput1);
cy.get(
commonWidgetSelector.draggableWidget("textInput2")
).verifyVisibleElement("have.value", values.textInput2);
};

View file

@ -1,419 +0,0 @@
import { fake } from "Fixtures/fake";
import { commonSelectors, commonWidgetSelector } from "Selectors/common";
import { appVersionSelectors, importSelectors } from "Selectors/exportImport";
import { commonText } from "Texts/common";
import { dashboardSelector } from "Selectors/dashboard";
import { buttonText } from "Texts/button";
import { exportAppModalText, importText } from "Texts/exportImport";
import {
clickOnExportButtonAndVerify,
exportAllVersionsAndVerify,
verifyElementsOfExportModal,
importAndVerifyApp,
} from "Support/utils/exportImport";
import { selectAppCardOption, closeModal } from "Support/utils/common";
import { switchVersionAndVerify } from "Support/utils/version";
describe("App Import Functionality", () => {
const TEST_DATA = {
toolJetImage: "cypress/fixtures/Image/tooljet.png",
invalidApp: "cypress/fixtures/templates/invalid_app.json",
invalidFile: "cypress/fixtures/templates/invalid_file.json",
appFiles: {
multiVersion: "cypress/fixtures/templates/three-versions.json",
singleVersion: "cypress/fixtures/templates/one_version.json",
},
};
let data;
const initializeData = () => {
const firstName = fake.firstName;
return {
workspaceName: firstName,
workspaceSlug: firstName.toLowerCase().replace(/\s+/g, "-"),
appName: `${fake.companyName}-IE-App`,
appReName: `${fake.companyName}-${fake.companyName}-IE-App`,
dsName: fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", ""),
};
};
data = initializeData();
before(() => {
cy.exec("mkdir -p ./cypress/downloads/");
cy.wait(3000);
});
beforeEach(() => {
cy.viewport(1200, 1300);
cy.apiLogin();
});
it("should verify app import functionality", () => {
cy.apiCreateWorkspace(data.workspaceName, data.workspaceSlug);
cy.apiLogout();
cy.apiLogin();
cy.visit(`${data.workspaceSlug}`);
// Test invalid file import
cy.get(dashboardSelector.importAppButton).click();
importAndVerifyApp(
TEST_DATA.toolJetImage,
importText.couldNotImportAppToastMessage
);
cy.wait(500);
cy.get(dashboardSelector.importAppButton).click();
importAndVerifyApp(
TEST_DATA.invalidApp,
"Could not import: SyntaxError: Expected ',' or '}' after property value in JSON at position 246 (line 11 column 13)"
);
cy.wait(500);
cy.get(dashboardSelector.importAppButton).click();
cy.get(importSelectors.importOptionInput)
.eq(0)
.selectFile(TEST_DATA.invalidFile, {
force: true,
});
cy.get(importSelectors.importAppTitle).should("be.visible");
cy.get(importSelectors.importAppButton).click();
cy.verifyToastMessage(
commonSelectors.toastMessage,
"tooljet_version must be a string"
);
cy.wait(500);
// Test valid app import
cy.get(importSelectors.dropDownMenu).should("be.visible").click();
cy.get(importSelectors.importOptionLabel).verifyVisibleElement(
"have.text",
importText.importOption
);
cy.intercept("POST", "/api/v2/resources/import").as("importApp");
cy.get(importSelectors.importOptionInput)
.eq(0)
.selectFile(TEST_DATA.appFiles.multiVersion, {
force: true,
});
cy.wait(1500);
cy.get(importSelectors.importAppTitle).verifyVisibleElement(
"have.text",
"Import app"
);
cy.get(commonSelectors.appNameLabel).verifyVisibleElement(
"have.text",
"App name"
);
cy.get(commonSelectors.appNameInput)
.should("be.visible")
.and("have.value", "three-versions");
cy.get(commonSelectors.appNameInfoLabel).verifyVisibleElement(
"have.text",
"App name must be unique and max 50 characters"
);
cy.get(commonSelectors.cancelButton)
.should("be.visible")
.and("have.text", "Cancel");
cy.get(commonSelectors.importAppButton).verifyVisibleElement(
"have.text",
"Import app"
);
cy.get(importSelectors.importAppButton).click();
cy.get(".go3958317564")
.should("be.visible")
.and("have.text", importText.appImportedToastMessage);
// Verify imported app
cy.get(".driver-close-btn").click();
cy.wait(500);
cy.get(commonSelectors.appNameInput).verifyVisibleElement(
"contain.value",
"three-versions"
);
// Configure app
cy.skipEditorPopover();
cy.dragAndDropWidget(buttonText.defaultWidgetText);
cy.get(appVersionSelectors.appVersionLabel).should("be.visible");
cy.get(commonWidgetSelector.draggableWidget("button1")).should(
"be.visible"
);
cy.renameApp(data.appName);
cy.get(commonSelectors.appNameInput).verifyVisibleElement(
"contain.value",
data.appName
);
cy.waitForAutoSave();
// Verify initial widget states
verifyCommonData({
text2: "",
textInput1: "",
textInput2: "Leanne Graham",
});
cy.get(
commonWidgetSelector.draggableWidget("textInput3")
).verifyVisibleElement("have.value", "");
// Setup database and data sources
cy.visit(`${data.workspaceSlug}/database`);
cy.get('[data-cy="student-table"]').verifyVisibleElement(
"have.text",
"student"
);
cy.apiAddDataToTable("student", {
name: "Paramu",
country: "India",
state: "Kerala",
});
cy.visit(`${data.workspaceSlug}/data-sources`);
cy.get('[data-cy="postgresql-button"]').should("be.visible");
cy.apiUpdateDataSource("postgresql", "production", {
options: [
{
key: "password",
value: `${Cypress.env("pg_password")}`,
encrypted: true,
},
],
});
cy.apiCreateWsConstant(
"pageHeader",
"Import and Export",
["Global"],
["production"]
);
cy.apiCreateWsConstant("db_name", "persons", ["Secret"], ["production"]);
// Verify app after setup
cy.wait("@importApp").then((interception) => {
const appId = interception.response.body.imports.app[0].id;
cy.openApp(
"",
Cypress.env("workspaceId"),
appId,
commonWidgetSelector.draggableWidget("text2")
);
});
verifyCommonData({
text2: "Import and Export",
textInput1: "John",
textInput2: "Leanne Graham",
});
cy.get(
commonWidgetSelector.draggableWidget("textInput3")
).verifyVisibleElement("have.value", "India");
switchVersionAndVerify("v3", "v1");
verifyCommonData({
text2: "Import and Export",
textInput1: "John",
textInput2: "Leanne Graham",
});
cy.wait(1000);
cy.backToApps();
// Test single version import
cy.get(importSelectors.dropDownMenu).click();
importAndVerifyApp(TEST_DATA.appFiles.singleVersion);
// Verify final state
cy.get(commonSelectors.appNameInput).verifyVisibleElement(
"contain.value",
"one_version"
);
verifyCommonData({
text2: "Import and Export",
textInput1: "John",
textInput2: "Leanne Graham",
});
});
it("Verify the elements of export dialog box", () => {
cy.exec("cd ./cypress/downloads/ && rm -rf *");
cy.visit(`${data.workspaceSlug}`);
// Select the app card option to export the app
selectAppCardOption(
data.appName,
commonSelectors.appCardOptions(commonText.exportAppOption)
);
// Verify the elements of the export modal
verifyElementsOfExportModal("v3", ["v2", "v1"], [true, false, false]);
// Close the modal
closeModal(exportAppModalText.modalCloseButton);
// Ensure the modal title is no longer visible
cy.get(
commonSelectors.modalTitle(exportAppModalText.selectVersionTitle)
).should("not.exist");
// Re-open the export modal and click the export button
selectAppCardOption(
data.appName,
commonSelectors.appCardOptions(commonText.exportAppOption)
);
clickOnExportButtonAndVerify(exportAppModalText.exportAll, data.appName);
cy.exec("ls ./cypress/downloads/").then((result) => {
const downloadedAppExportFileName = result.stdout.split("\n")[0];
const filePath = `./cypress/downloads/${downloadedAppExportFileName}`;
// Ensure the file name contains the expected app export name
expect(downloadedAppExportFileName).to.contain(
data.appName.toLowerCase()
);
// Read and validate the exported JSON file
cy.readFile(filePath).then((appData) => {
// Validate the app name
const appNameFromFile = appData.app[0].definition.appV2.name;
expect(appNameFromFile).to.equal(data.appName);
// Validate the schema for the student table in tooljetdb
const tooljetDatabase = appData.tooljet_database.find(
(db) => db.table_name === "student"
);
expect(tooljetDatabase).to.exist;
expect(tooljetDatabase.schema).to.exist;
// Validate components and queries
const components = appData.app[0].definition.appV2.components;
const text2Component = components.find(
(component) => component.name === "text2"
);
expect(text2Component).to.exist;
expect(text2Component.properties.text.value).to.equal(
"{{constants.pageHeader}}"
);
const textinput1 = components.find(
(component) => component.name === "textinput1"
);
expect(textinput1).to.exist;
expect(textinput1.properties.value.value).to.include("queries");
const textinput2 = components.find(
(component) => component.name === "textinput2"
);
expect(textinput2).to.exist;
expect(textinput2.properties.value.value).to.include("queries");
const textinput3 = components.find(
(component) => component.name === "textinput3"
);
expect(textinput3).to.exist;
expect(textinput3.properties.value.value).to.include("queries");
// Validate the data queries
const dataQueries = appData.app[0].definition.appV2.dataQueries;
const postgresqlQuery = dataQueries.find(
(query) => query.name === "postgresql1"
);
expect(postgresqlQuery).to.exist;
expect(postgresqlQuery.options.query).to.include(
"Select * from {{secrets.db_name}}"
);
const restapiQuery = dataQueries.find(
(query) => query.name === "restapi1"
);
expect(restapiQuery).to.exist;
expect(restapiQuery.options.url).to.equal(
"https://jsonplaceholder.typicode.com/users/1"
);
const tooljetdbQuery = dataQueries.find(
(query) => query.name === "tooljetdb1"
);
expect(tooljetdbQuery).to.exist;
expect(tooljetdbQuery.options.operation).to.equal("list_rows");
// Ensure appVersions exists
const appVersions = appData.app[0].definition.appV2.appVersions;
expect(appVersions).to.exist;
// Map and verify app version names
const versionNames = appVersions.map((version) => version.name);
expect(versionNames).to.include.members(["v1", "v2", "v3"]);
});
});
cy.exec("cd ./cypress/downloads/ && rm -rf *");
selectAppCardOption(
data.appName,
commonSelectors.appCardOptions(commonText.exportAppOption)
);
cy.get(`[data-cy="v1-radio-button"]`).check();
cy.get(
commonSelectors.buttonSelector(exportAppModalText.exportSelectedVersion)
).click();
cy.exec("ls ./cypress/downloads/").then((result) => {
const downloadedAppExportFileName = result.stdout.split("\n")[0];
const filePath = `./cypress/downloads/${downloadedAppExportFileName}`;
// Ensure the file name contains the expected app export name
expect(downloadedAppExportFileName).to.contain(
data.appName.toLowerCase()
);
// Read and validate the exported JSON file
cy.readFile(filePath).then((appData) => {
// Validate the app name
const appNameFromFile = appData.app[0].definition.appV2.name;
expect(appNameFromFile).to.equal(data.appName);
});
});
});
it.skip("Verify 'Export app' functionality of an application inside app editor", () => {
data.appName2 = `${fake.companyName}-App`;
cy.apiCreateApp(data.appName2);
cy.openApp(data.appName2);
cy.dragAndDropWidget("Text Input", 50, 50);
cy.get('[data-cy="left-sidebar-settings-button"]').click();
cy.get('[data-cy="button-user-status-change"]').click();
verifyElementsOfExportModal("v1");
exportAllVersionsAndVerify(data.appName1, "v1");
});
});
const verifyCommonData = (values) => {
cy.get(commonWidgetSelector.draggableWidget("text2")).verifyVisibleElement(
"have.text",
values.text2
);
cy.get(
commonWidgetSelector.draggableWidget("textInput1")
).verifyVisibleElement("have.value", values.textInput1);
cy.get(
commonWidgetSelector.draggableWidget("textInput2")
).verifyVisibleElement("have.value", values.textInput2);
};

View file

@ -15,7 +15,6 @@ describe("App Slug", () => {
beforeEach(() => {
data.slug = `${fake.companyName.toLowerCase()}-app`;
data.appName = `${fake.companyName} App`;
cy.log(Cypress.env("workspaceId"));
cy.defaultWorkspaceLogin();
});
@ -25,133 +24,137 @@ describe("App Slug", () => {
cy.apiCreateApp(data.appName);
cy.wait(1000);
cy.apiLogout();
cy.log(Cypress.env("workspaceId"));
});
it("Verify app slug cases in global settings", () => {
cy.apiLogin("dev@tooljet.io", "password").then(() => {
const workspaceId = Cypress.env("workspaceId");
const appId = Cypress.env("appId");
cy.apiLogin();
const workspaceId = Cypress.env("workspaceId");
const appId = Cypress.env("appId");
cy.openApp("my-workspace");
cy.get(commonSelectors.leftSideBarSettingsButton).click();
cy.visit("/my-workspace");
cy.wait(1000);
// Verify initial state
cy.get(commonWidgetSelector.appSlugLabel).verifyVisibleElement(
"have.text",
"Unique app slug"
);
cy.get(commonWidgetSelector.appSlugInput).verifyVisibleElement(
"have.value",
Cypress.env("appId")
);
cy.get(commonWidgetSelector.appSlugInfoLabel).verifyVisibleElement(
"have.text",
"URL-friendly 'slug' consists of lowercase letters, numbers, and hyphens"
);
cy.get(commonWidgetSelector.appLinkLabel).verifyVisibleElement(
"have.text",
"App link"
);
cy.get(commonWidgetSelector.appLinkField).verifyVisibleElement(
"have.text",
`${host}/${workspaceId}/apps/${appId}`
);
// Validate all error cases
verifySlugValidations(commonWidgetSelector.appSlugInput);
// Verify successful slug update
cy.clearAndType(commonWidgetSelector.appSlugInput, data.slug);
verifySuccessfulSlugUpdate(workspaceId, data.slug);
// Verify persistence
cy.get('[data-cy="left-sidebar-debugger-button"]').click();
cy.get(commonSelectors.leftSideBarSettingsButton).click();
cy.get(commonWidgetSelector.appSlugInput).should("have.value", data.slug);
// Release and verify URLs
releaseApp();
verifyURLs(workspaceId, data.slug, false);
// Verify duplicate slug validation
cy.visit("/my-workspace");
cy.apiCreateApp(data.slug);
cy.openApp("my-workspace");
cy.get(commonSelectors.leftSideBarSettingsButton).click();
cy.get(commonWidgetSelector.appSlugInput).clear();
cy.clearAndType(commonWidgetSelector.appSlugInput, data.slug);
cy.get(commonWidgetSelector.appSlugErrorLabel).verifyVisibleElement(
"have.text",
"This app slug is already taken."
);
cy.window({ log: false }).then((win) => {
win.localStorage.setItem("walkthroughCompleted", "true");
});
cy.visit(`/${Cypress.env("workspaceId")}/apps/${Cypress.env("appId")}/`);
cy.wait(1000);
cy.get(commonSelectors.leftSideBarSettingsButton).click();
// Verify initial state
cy.get(commonWidgetSelector.appSlugLabel).verifyVisibleElement(
"have.text",
"Unique app slug"
);
cy.get(commonWidgetSelector.appSlugInput).verifyVisibleElement(
"have.value",
Cypress.env("appId")
);
cy.get(commonWidgetSelector.appSlugInfoLabel).verifyVisibleElement(
"have.text",
"URL-friendly 'slug' consists of lowercase letters, numbers, and hyphens"
);
cy.get(commonWidgetSelector.appLinkLabel).verifyVisibleElement(
"have.text",
"App link"
);
cy.get(commonWidgetSelector.appLinkField).verifyVisibleElement(
"have.text",
`${host}/${workspaceId}/apps/${appId}`
);
// Validate all error cases
verifySlugValidations(commonWidgetSelector.appSlugInput);
// Verify successful slug update
cy.clearAndType(commonWidgetSelector.appSlugInput, data.slug);
verifySuccessfulSlugUpdate(workspaceId, data.slug);
// Verify persistence
cy.get('[data-cy="left-sidebar-debugger-button"]').click();
cy.get(commonSelectors.leftSideBarSettingsButton).click();
cy.get(commonWidgetSelector.appSlugInput).should("have.value", data.slug);
// Release and verify URLs
releaseApp();
verifyURLs(workspaceId, data.slug, false);
// Verify duplicate slug validation
cy.visit("/my-workspace");
cy.apiCreateApp(data.slug);
cy.openApp("my-workspace");
cy.get(commonSelectors.leftSideBarSettingsButton).click();
cy.get(commonWidgetSelector.appSlugInput).clear();
cy.clearAndType(commonWidgetSelector.appSlugInput, data.slug);
cy.get(commonWidgetSelector.appSlugErrorLabel).verifyVisibleElement(
"have.text",
"This app slug is already taken."
);
});
it("Verify app slug cases in share modal", () => {
cy.apiLogin("dev@tooljet.io", "password").then(() => {
const workspaceId = Cypress.env("workspaceId");
cy.apiLogin();
const workspaceId = Cypress.env("workspaceId");
cy.apiCreateApp(data.appName);
cy.openApp("my-workspace");
cy.apiCreateApp(data.appName);
cy.openApp("my-workspace");
// Set up initial slug
cy.get(commonSelectors.leftSideBarSettingsButton).click();
cy.get(commonWidgetSelector.appSlugInput).clear();
cy.clearAndType(commonWidgetSelector.appSlugInput, data.slug);
// Set up initial slug
cy.get(commonSelectors.leftSideBarSettingsButton).click();
cy.get(commonWidgetSelector.appSlugInput).clear();
cy.clearAndType(commonWidgetSelector.appSlugInput, data.slug);
releaseApp();
releaseApp();
// Verify share modal
cy.get(commonWidgetSelector.shareAppButton).click();
cy.get(commonWidgetSelector.appLink).verifyVisibleElement(
"have.text",
`${host}/applications/`
);
cy.get(commonWidgetSelector.appNameSlugInput).should(
"have.value",
data.slug
);
// Verify share modal
cy.get(commonWidgetSelector.shareAppButton).click();
cy.get(commonWidgetSelector.appLink).verifyVisibleElement(
"have.text",
`${host}/applications/`
);
cy.get(commonWidgetSelector.appNameSlugInput).should(
"have.value",
data.slug
);
// Validate all error cases in share modal
verifySlugValidations(commonWidgetSelector.appNameSlugInput);
// Validate all error cases in share modal
verifySlugValidations(commonWidgetSelector.appNameSlugInput);
cy.wait(500);
cy.clearAndType(commonWidgetSelector.appNameSlugInput, data.slug);
cy.get('[data-cy="app-slug-info-label"]')
.invoke("text")
.then((text) => {
expect(text.trim()).to.eq(
"URL-friendly 'slug' consists of lowercase letters, numbers, and hyphens"
);
});
cy.wait(500);
cy.clearAndType(commonWidgetSelector.appNameSlugInput, data.slug);
cy.get('[data-cy="app-slug-info-label"]')
.invoke("text")
.then((text) => {
expect(text.trim()).to.eq(
"URL-friendly 'slug' consists of lowercase letters, numbers, and hyphens"
);
});
// Verify successful slug update in share modal
data.slug = `${fake.companyName.toLowerCase()}-app`;
cy.clearAndType(commonWidgetSelector.appNameSlugInput, data.slug);
cy.get('[data-cy="app-slug-accepted-label"]').verifyVisibleElement(
"have.text",
"Slug accepted!"
);
// Verify successful slug update in share modal
data.slug = `${fake.companyName.toLowerCase()}-app`;
cy.clearAndType(commonWidgetSelector.appNameSlugInput, data.slug);
cy.get('[data-cy="app-slug-accepted-label"]').verifyVisibleElement(
"have.text",
"Slug accepted!"
);
// Close modal and verify URLs
cy.get(commonWidgetSelector.modalCloseButton).click();
verifyURLs(workspaceId, data.slug, true);
// Close modal and verify URLs
cy.get(commonWidgetSelector.modalCloseButton).click();
verifyURLs(workspaceId, data.slug, true);
// Verify duplicate slug validation in share modal
cy.visit("/my-workspace");
cy.apiCreateApp(data.slug);
cy.openApp("my-workspace");
releaseApp();
cy.get(commonWidgetSelector.shareAppButton).click();
cy.clearAndType(commonWidgetSelector.appNameSlugInput, data.slug);
cy.get(commonWidgetSelector.appSlugErrorLabel).verifyVisibleElement(
"have.text",
"This app slug is already taken."
);
});
// Verify duplicate slug validation in share modal
cy.visit("/my-workspace");
cy.apiCreateApp(data.slug);
cy.openApp("my-workspace");
releaseApp();
cy.get(commonWidgetSelector.shareAppButton).click();
cy.clearAndType(commonWidgetSelector.appNameSlugInput, data.slug);
cy.get(commonWidgetSelector.appSlugErrorLabel).verifyVisibleElement(
"have.text",
"This app slug is already taken."
);
});
});

View file

@ -20,20 +20,20 @@ import {
describe("Private and Public apps", {
retries: { runMode: 2 },
}, () => {
const data = {};
let data;
beforeEach(() => {
data.appName = `${fake.companyName} P P App`;
data.slug = data.appName.toLowerCase().replace(/\s+/g, "-");
data.firstName = fake.firstName;
data.email = fake.email.toLowerCase();
data.workspaceName = fake.firstName;
data.workspaceSlug = fake.firstName.toLowerCase().replace(/\s+/g, "-");
data = {
appName: `${fake.companyName} P P App`,
slug: `${fake.companyName} P P App`.toLowerCase().replace(/\s+/g, "-"),
firstName: fake.firstName,
email: fake.email.toLowerCase(),
workspaceName: fake.firstName,
workspaceSlug: fake.firstName.toLowerCase().replace(/\s+/g, "-"),
}
cy.defaultWorkspaceLogin();
cy.skipWalkthrough();
cy.log(data.appName, "text1")
});
it("Verify private and public app share functionality", () => {
@ -85,9 +85,9 @@ describe("Private and Public apps", {
});
cy.get(onboardingSelectors.signInButton, { timeout: 20000 }).should("be.visible");
cy.wait(2000);
cy.loginWithCredentials("dev@tooljet.io", "password");
// cy.get(commonWidgetSelector.draggableWidget("text1")).should("be.visible");
cy.get('.text-widget-section > div').should("be.visible");
cy.appUILogin();
cy.get(commonWidgetSelector.draggableWidget("text1")).should("be.visible");
// Test public access
cy.get(commonSelectors.viewerPageLogo).click();
@ -106,8 +106,8 @@ describe("Private and Public apps", {
cy.visitSlug({
actualUrl: `${Cypress.config("baseUrl")}/applications/${data.slug}`,
});
// cy.get(commonWidgetSelector.draggableWidget("text1")).should("be.visible");
cy.get('.text-widget-section > div').should("be.visible");
cy.get(commonWidgetSelector.draggableWidget("text1")).should("be.visible");
});
@ -123,30 +123,30 @@ describe("Private and Public apps", {
});
cy.wait(2000);
cy.loginWithCredentials(data.email, "password");
cy.appUILogin(data.email, "password");
// cy.get(commonWidgetSelector.draggableWidget("text1")).should("be.visible");
cy.get('.text-widget-section > div').should("be.visible", { timeout: 20000 });
cy.get(commonWidgetSelector.draggableWidget("text1")).should("be.visible");
// Test with private app valid session
cy.visitSlug({
actualUrl: `${Cypress.config("baseUrl")}/applications/${data.slug}`,
});
// cy.get(commonWidgetSelector.draggableWidget("text1")).should("be.visible");
cy.get('.text-widget-section > div').should("be.visible");
cy.get(commonWidgetSelector.draggableWidget("text1")).should("be.visible");
cy.get(commonSelectors.viewerPageLogo).click();
// Test public access
cy.defaultWorkspaceLogin();
cy.wait(1000);
cy.apiMakeAppPublic();
logout();
cy.visitSlug({
actualUrl: `${Cypress.config("baseUrl")}/applications/${data.slug}`,
});
// cy.get(commonWidgetSelector.draggableWidget("text1")).should("be.visible");
cy.get('.text-widget-section > div').should("be.visible");
cy.get(commonWidgetSelector.draggableWidget("text1")).should("be.visible");
// Test with public app with valid session
@ -154,8 +154,8 @@ describe("Private and Public apps", {
cy.visitSlug({
actualUrl: `${Cypress.config("baseUrl")}/applications/${data.slug}`,
});
// cy.get(commonWidgetSelector.draggableWidget("text1")).should("be.visible");
cy.get('.text-widget-section > div').should("be.visible");
cy.get(commonWidgetSelector.draggableWidget("text1")).should("be.visible");
});
@ -180,8 +180,8 @@ describe("Private and Public apps", {
cy.visitSlug({
actualUrl: `${Cypress.config("baseUrl")}/applications/${data.slug}`,
});
// cy.get(commonWidgetSelector.draggableWidget("text1")).should("be.visible");
cy.get('.text-widget-section > div').should("be.visible");
cy.get(commonWidgetSelector.draggableWidget("text1")).should("be.visible");
// Verify public app with valid session
@ -189,8 +189,8 @@ describe("Private and Public apps", {
cy.visitSlug({
actualUrl: `${Cypress.config("baseUrl")}/applications/${data.slug}`,
});
// cy.get(commonWidgetSelector.draggableWidget("text1")).should("be.visible");
cy.get('.text-widget-section > div').should("be.visible");
cy.get(commonWidgetSelector.draggableWidget("text1")).should("be.visible");
});
@ -224,8 +224,8 @@ describe("Private and Public apps", {
// Process invitation
onboardUserFromAppLink(data.email, data.slug);
// cy.get(commonWidgetSelector.draggableWidget("text1")).should("be.visible");
cy.get('.text-widget-section > div').should("be.visible");
cy.get(commonWidgetSelector.draggableWidget("text1")).should("be.visible");
cy.get('[data-cy="viewer-page-logo"]').click();
logout();
@ -269,8 +269,8 @@ describe("Private and Public apps", {
});
onboardUserFromAppLink(data.email, data.slug, data.workspaceName, false);
// cy.get(commonWidgetSelector.draggableWidget("text1")).should("be.visible");
cy.get('.text-widget-section > div').should("be.visible");
cy.get(commonWidgetSelector.draggableWidget("text1")).should("be.visible");
});

View file

@ -114,7 +114,7 @@ describe("App Version", () => {
cy.wait(3000);
// cy.reload();
// cy.get(commonWidgetSelector.draggableWidget("text1")).should("be.visible", { timeout: 10000 });
cy.get(commonWidgetSelector.draggableWidget("text1")).should("be.visible", { timeout: 10000 });
// Preview and release verification
cy.openInCurrentTab(commonWidgetSelector.previewButton);

View file

@ -46,7 +46,7 @@ describe("Datasource Manager", () => {
data.dsName1 = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
data.dsName2 = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
const allDataSources = host.includes("8082") ? "All data sources (42)" : "All data sources (44)";
const allDataSources = host.includes("8082") ? "All data sources (43)" : "All data sources (45)";
const allDatabase = host.includes("8082") ? "Databases (18)" : "Databases (20)";
cy.get(commonSelectors.globalDataSourceIcon).click();
@ -214,7 +214,7 @@ describe("Datasource Manager", () => {
cy.get(commonWidgetSelector.sidebarinspector).click();
cy.get(dataSourceSelector.queryCreateAndRunButton).click();
verifyValueOnInspector("table_preview", "7 items ");
verifyValueOnInspector("table_preview", "10 items ");
cy.get('[data-cy="show-ds-popover-button"]').click();
cy.get(".p-2 > .tj-base-btn")
@ -275,7 +275,7 @@ describe("Datasource Manager", () => {
pinInspector();
cy.get(dataSourceSelector.queryCreateAndRunButton).click();
verifyValueOnInspector("table_preview", "7 items ");
verifyValueOnInspector("table_preview", "10 items ");
//scope changing is pending
});

View file

@ -18,10 +18,17 @@ import { roleBasedOnboarding } from "Support/utils/onboarding";
const data = {};
data.groupName = fake.firstName.replaceAll("[^A-Za-z]", "");
data.appName = `${fake.companyName}-App`;
const workspaceName = fake.firstName;
const workspaceSlug = fake.firstName.toLowerCase().replace(/[^A-Za-z]/g, "");
describe("Groups duplication", () => {
beforeEach(() => {
cy.defaultWorkspaceLogin();
cy.apiCreateWorkspace(workspaceName, workspaceSlug);
cy.visit(`${workspaceSlug}`);
cy.apiLogout();
cy.apiLogin();
cy.visit(`${workspaceSlug}`);
groupPermission(
[
"appsCreateCheck",
@ -32,15 +39,18 @@ describe("Groups duplication", () => {
"Admin"
);
cy.apiCreateApp(data.appName);
});
it("Should verify the group duplication feature", () => {
data.firstName = fake.firstName;
data.email = fake.email.toLowerCase().replaceAll("[^A-Za-z]", "");
cy.visit(`${workspaceSlug}`);
roleBasedOnboarding(data.firstName, data.email, "builder");
cy.apiLogout();
cy.defaultWorkspaceLogin();
cy.apiLogin();
cy.visit(`${workspaceSlug}`);
navigateToManageGroups();
verifyGroupCardOptions("Admin");
cy.wait(3000);
@ -105,15 +115,19 @@ describe("Groups duplication", () => {
cy.apiLogout();
cy.apiLogin(data.email, "password");
cy.visit("/my-workspace");
cy.visit(`${workspaceSlug}`);
cy.wait(2000);
cy.get(commonSelectors.appCreateButton).should("be.visible");
cy.get(commonSelectors.createNewFolderButton).should("be.visible");
cy.wait(2000);
cy.reload();
viewAppCardOptions(data.appName);
cy.contains("Delete app").should("exist");
cy.get(commonSelectors.workspaceConstantsIcon).should("be.visible");
cy.apiLogout();
cy.defaultWorkspaceLogin();
cy.apiLogin();
cy.visit(`${workspaceSlug}`);
navigateToManageGroups();
OpenGroupCardOption(`${data.groupName}_copy`);
cy.get(groupsSelector.deleteGroupOption).click();
@ -121,7 +135,7 @@ describe("Groups duplication", () => {
cy.apiLogout();
cy.apiLogin(data.email, "password");
cy.visit("/my-workspace");
cy.visit(`${workspaceSlug}`);
cy.get(commonSelectors.appCreateButton).should("not.exist");
cy.get(commonSelectors.createNewFolderButton).should("not.exist");
cy.get(commonSelectors.workspaceConstantsIcon).should("not.exist");

View file

@ -124,7 +124,8 @@ describe("Workspace constants", () => {
//verify global constant is resolved in static query url
cy.get('[data-cy="list-query-restapistaticg"]').click();
cy.get('.rest-api-methods-select-element-container .codehinter-container').click();
cy.get('.rest-api-methods-select-element-container .codehinter-container').eq(0).click();
cy.wait(500)
cy.get('.text-secondary').should('have.text', Cypress.env("constants_host"));
//Verify global constant is resolved in static query preview

View file

@ -200,7 +200,7 @@ describe("user invite flow cases", () => {
});
});
it.skip("Should verify the user onboarding with groups", () => {
it("Should verify the user onboarding with groups", () => {
data.firstName = fake.firstName;
data.email = fake.email.toLowerCase().replaceAll("[^A-Za-z]", "");
data.groupName1 = fake.firstName.replaceAll("[^A-Za-z]", "");

View file

@ -58,7 +58,8 @@ describe("inviteflow edge cases", () => {
cy.verifyToastMessage(commonSelectors.toastMessage, usersText.inviteToast);
logout();
cy.defaultWorkspaceLogin();
cy.apiLogin();
cy.visit(workspaceName);
navigateToManageUsers();
searchUser(data.email);
cy.contains("td", data.email)

View file

@ -8,7 +8,7 @@ import { importText } from "Texts/exportImport";
describe("App creation", () => {
const data = {};
const appFile = "cypress/fixtures/templates/test-app.json";
const appFile = "cypress/fixtures/templates/one_version.json";
beforeEach(() => {
cy.defaultWorkspaceLogin();
@ -200,7 +200,7 @@ describe("App creation", () => {
force: true,
});
cy.get(commonSelectors.importAppTitle).verifyVisibleElement(
cy.get(importSelectors.importAppTitle).verifyVisibleElement(
"have.text",
"Import app"
);
@ -210,7 +210,7 @@ describe("App creation", () => {
);
cy.get(commonSelectors.appNameInput).verifyVisibleElement(
"have.value",
"test-app"
"one_version"
);
cy.get(commonSelectors.appNameInfoLabel).verifyVisibleElement(
"have.text",
@ -236,7 +236,7 @@ describe("App creation", () => {
});
cy.get(commonSelectors.appNameInput).verifyVisibleElement(
"have.value",
"test-app"
"one_version"
);
cy.clearAndType(commonSelectors.appNameInput, data.appName);
cy.get(commonSelectors.cancelButton).click();
@ -247,7 +247,7 @@ describe("App creation", () => {
});
cy.get(commonSelectors.appNameInput).verifyVisibleElement(
"have.value",
"test-app"
"one_version"
);
cy.clearAndType(commonSelectors.appNameInput, data.appName);
cy.get(commonSelectors.importAppButton).should("be.enabled").click();

View file

@ -2,7 +2,6 @@ import { fake } from "Fixtures/fake";
import {
createFolder,
deleteFolder,
deleteDownloadsFolder,
navigateToAppEditor,
viewAppCardOptions,
verifyModal,
@ -14,49 +13,38 @@ import {
} from "Support/utils/common";
import {
modifyAndVerifyAppCardIcon,
login,
verifyAppDelete,
} from "Support/utils/dashboard";
import { profileSelector } from "Selectors/profile";
import { profileText } from "Texts/profile";
import { commonSelectors } from "Selectors/common";
import { dashboardSelector } from "Selectors/dashboard";
import { commonText } from "Texts/common";
import { dashboardText } from "Texts/dashboard";
import {
navigateToManageUsers,
logout,
searchUser,
navigateToManageGroups,
} from "Support/utils/common";
import { roleBasedOnboarding } from "Support/utils/onboarding";
import { logout } from "Support/utils/common";
describe("dashboard", () => {
const data = {};
data.appName = `${fake.companyName}-App`;
data.folderName = `${fake.companyName.toLowerCase()}-folder`;
data.cloneAppName = `cloned-${data.appName}`;
data.updatedFolderName = `new-${data.folderName}`;
data.firstName = fake.firstName;
data.email = fake.email.toLowerCase().replaceAll("[^A-Za-z]", "");
data.workspaceName = fake.firstName;
data.workspaceSlug = fake.firstName.toLowerCase().replaceAll("[^A-Za-z]", "");
let data = {};
beforeEach(() => {
data = {
appName: `${fake.companyName}-App`,
folderName: `${fake.companyName.toLowerCase()}-folder`,
cloneAppName: `cloned-${fake.companyName}-App`,
updatedFolderName: `new-${fake.companyName.toLowerCase()}-folder`,
workspaceName: fake.firstName,
workspaceSlug: fake.firstName.toLowerCase().replaceAll("[^A-Za-z]", ""),
};
cy.intercept("GET", "/api/library_apps").as("appLibrary");
cy.intercept("DELETE", "/api/folders/*").as("folderDeleted");
cy.skipWalkthrough();
cy.apiLogin();
cy.apiCreateWorkspace(data.workspaceName, data.workspaceSlug);
cy.apiLogout();
cy.apiLogin();
cy.visit(`${data.workspaceSlug}`);
});
it("should verify the elements on empty dashboard", () => {
cy.intercept("GET", "/api/apps?page=1&folder=&searchKey=&type=front-end", {
fixture: "intercept/emptyDashboard.json",
}).as("emptyDashboard");
cy.intercept("GET", "/api/folder-apps?searchKey=&type=front-end", {
body: { folders: [] },
}).as("folders");
cy.intercept("GET", "/api/metadata", {
body: {
installed_version: "2.9.2",
@ -64,15 +52,10 @@ describe("dashboard", () => {
},
}).as("version");
cy.defaultWorkspaceLogin();
cy.wait("@emptyDashboard");
cy.wait("@folders");
cy.wait("@version");
cy.get(commonSelectors.homePageLogo).should("be.visible");
cy.get(commonSelectors.workspaceName).verifyVisibleElement(
"have.text",
"My workspace"
data.workspaceName
);
cy.get(commonSelectors.workspaceName).click();
// cy.get(commonSelectors.editRectangleIcon).should("be.visible");
@ -188,12 +171,12 @@ describe("dashboard", () => {
verifyTooltip(dashboardSelector.modeToggle, "Mode");
});
it("Should verify app card elements and app card operations", () => {
it.skip("Should verify app card elements and app card operations", () => {
const customLayout = {
desktop: { top: 100, left: 20 },
mobile: { width: 8, height: 50 },
};
cy.apiLogin();
cy.apiCreateApp(data.appName);
cy.openApp();
cy.apiAddComponentToApp(data.appName, "text1", customLayout);
@ -276,6 +259,7 @@ describe("dashboard", () => {
cancelModal(commonText.cancelButton);
cy.wait(3000);
viewAppCardOptions(data.appName);
cy.get(
commonSelectors.appCardOptions(commonText.removeFromFolderOption)
@ -296,6 +280,7 @@ describe("dashboard", () => {
cy.get(commonSelectors.allApplicationsLink).click();
cy.wait(3000);
viewAppCardOptions(data.appName);
cy.get(commonSelectors.appCardOptions(commonText.cloneAppOption)).click();
cy.get('[data-cy="clone-app"]').click();
@ -312,7 +297,10 @@ describe("dashboard", () => {
cy.get(commonSelectors.appCard(data.cloneAppName)).should("be.visible");
cy.wait(3000)
cy.get(commonSelectors.globalDataSourceIcon).click();
cy.get(commonSelectors.dashboardIcon).click();
cy.wait(3000);
cy.reloadAppForTheElement(data.cloneAppName);
viewAppCardOptions(data.cloneAppName);
cy.get(commonSelectors.appCardOptions(commonText.exportAppOption)).click();
cy.get(commonSelectors.exportAllButton).click();
@ -322,6 +310,7 @@ describe("dashboard", () => {
expect(downloadedAppExportFileName).to.contain.string("app");
});
cy.wait(3000);
cy.reloadAppForTheElement(data.cloneAppName);
viewAppCardOptions(data.cloneAppName);
cy.get(commonSelectors.deleteAppOption).click();
@ -337,6 +326,7 @@ describe("dashboard", () => {
).verifyVisibleElement("have.text", commonText.modalYesButton);
cancelModal(commonText.cancelButton);
cy.wait(3000);
cy.reloadAppForTheElement(data.cloneAppName);
viewAppCardOptions(data.cloneAppName);
cy.get(commonSelectors.deleteAppOption).click();
@ -362,9 +352,6 @@ describe("dashboard", () => {
mobile: { width: 8, height: 50 },
};
cy.skipWalkthrough();
data.appName = `${fake.companyName}-App`;
cy.defaultWorkspaceLogin();
cy.createApp(data.appName);
cy.apiAddComponentToApp(data.appName, "text1", customLayout);
@ -395,12 +382,8 @@ describe("dashboard", () => {
mobile: { width: 8, height: 50 },
};
data.appName = `${fake.companyName}-App`;
cy.defaultWorkspaceLogin();
cy.createApp(data.appName);
cy.apiAddComponentToApp(data.appName, "text1", customLayout);
cy.backToApps();
cy.get(commonSelectors.createNewFolderButton).click();
@ -517,13 +500,4 @@ describe("dashboard", () => {
verifyAppDelete(data.appName);
logout();
});
it("should verify the elements on empty dashboard for end user", () => {
cy.defaultWorkspaceLogin();
cy.intercept("GET", "/api/apps?page=1&folder=&searchKey=&type=front-end", {
fixture: "intercept/emptyDashboard.json",
}).as("emptyDashboard")
roleBasedOnboarding(data.firstName, data.email, "end-user");
cy.get(commonSelectors.dashboardAppCreateButton).should("be.disabled");
});
});

View file

@ -522,10 +522,8 @@ describe("Manage Groups", () => {
commonSelectors.buttonSelector(exportAppModalText.exportSelectedVersion)
).click();
cy.exec("ls ./cypress/downloads/").then((result) => {
cy.log(result);
const downloadedAppExportFileName = result.stdout.split("\n")[0];
exportedFilePath = `cypress/downloads/${downloadedAppExportFileName}`;
cy.log(exportedFilePath);
cy.get(importSelectors.dropDownMenu).should("be.visible").click();
cy.get(importSelectors.importOptionInput).selectFile(exportedFilePath, {
force: true,

View file

@ -0,0 +1,382 @@
import { fake } from "Fixtures/fake";
import {
createUser, getAllUsers, getUser, updateUser, createGroup, validateUserInGroup, updateUserRole,
getAllWorkspaces, replaceUserWorkspace, replaceUserWorkspacesRelations
} from 'Support/utils/api';
import { groupsSelector } from "Selectors/manageGroups";
import { commonSelectors } from 'Selectors/common';
import { searchUser, navigateToManageUsers, logout, navigateToManageGroups } from 'Support/utils/common';
describe("API Test", () => {
const sanitize = (str) => str.toLowerCase().replace(/[^A-Za-z]/g, "");
let userId;
let workspaceId;
const data = {
firstName: fake.firstName,
lastName: fake.lastName,
firstName1: fake.firstName,
lastName1: fake.lastName,
firstName2: fake.firstName,
lastName2: fake.lastName,
email: fake.email.toLowerCase().replaceAll("[^A-Za-z]", ""),
email1: fake.email.toLowerCase().replaceAll("[^A-Za-z]", ""),
email2: fake.email.toLowerCase().replaceAll("[^A-Za-z]", ""),
workspaceName: sanitize(fake.lastName),
workspaceSlug: sanitize(fake.lastName),
workspaceName1: sanitize(fake.firstName),
workspaceSlug1: sanitize(fake.firstName),
group1: sanitize(fake.firstName),
group2: sanitize(fake.firstName),
group3: sanitize(fake.firstName),
group4: sanitize(fake.firstName),
group5: sanitize(fake.firstName),
appName: fake.companyName
};
//user with all valid details
const userData = {
name: `${data.firstName} ${data.lastName}`,
email: data.email,
password: "password",
status: "active",
workspaces: [
{
name: "My workspace",
status: "active",
groups: [
{ name: data.group1 },
{ name: data.group2 }
]
},
{
name: data.workspaceName,
status: "active",
role: "builder",
groups: [{ name: data.group3 }]
},
{
name: data.workspaceName1,
status: "archived",
role: "admin",
groups: [{ name: data.group4 }]
}
]
};
beforeEach(() => {
cy.defaultWorkspaceLogin();
});
it("Create user with valid details", () => {
// create multiple groups in different workspaces
navigateToManageGroups();
[data.group1, data.group2, data.group5].forEach(createGroup);
//builder group
cy.get(groupsSelector.groupLink(data.group5)).click();
cy.get(groupsSelector.permissionsLink).click();
cy.get(groupsSelector.appsCreateCheck).check();
[
{ name: data.workspaceName, slug: data.workspaceSlug, group: data.group3 },
{ name: data.workspaceName1, slug: data.workspaceSlug1, group: data.group4 }
].forEach(({ name, slug, group }) => {
cy.apiCreateWorkspace(name, slug);
cy.visit(slug);
navigateToManageGroups();
createGroup(group);
});
// Added valid user and logged-in in the workpsace
cy.visit("/my-workspace");
cy.wait(500);
createUser(userData).then((response) => {
expect(response.status).to.eq(201);
userId = response.body.id;
workspaceId = response.body.workspaces[0].id;
navigateToManageUsers();
searchUser(data.email);
cy.contains("td", data.email)
.parent()
.within(() => {
cy.get("td small").should("have.text", "active");
});
validateUserInGroup(data.email, "my-workspace", "end-user");
validateUserInGroup(data.email, data.workspaceSlug, "builder");
validateUserInGroup(data.email, data.workspaceSlug1, "admin", false);
cy.apiLogout();
cy.apiLogin(data.email, "password");
cy.visit("/my-workspace");
cy.get(commonSelectors.workspaceName).should("have.text", "My workspace");
logout();
//Retrieve all users, a specific user by ID, and all workspaces
cy.defaultWorkspaceLogin();
navigateToManageUsers();
let number = 0;
cy.get('[data-cy="title-users-page"]').invoke('text').then((text) => {
number = parseInt(text.match(/\d+/)[0], 10);
});
getAllUsers().then((response) => {
expect(response.status).to.eq(200);
//expect(response.body.length).to.eq(number); //error due to removal of user from instance
});
getUser(userId).then((response) => {
expect(response.status).to.eq(200);
expect(response.body.name).to.eq(`${data.firstName} ${data.lastName}`);
});
getAllWorkspaces().then((response) => {
expect(response.status).to.eq(200);
});
});
});
it('Handles user creation errors', () => {
const invalidUserData = [
{ // Duplicate user
data: { ...userData },
expectedStatus: 422,
expectedMessage: 'Already exists!'
},
{ // Invalid email and long password
data: {
...userData,
name: `${data.firstName1} ${data.lastName1}`,
email: 'invalid-email',
password: 'a'.repeat(101)
},
expectedStatus: 400,
expectedMessages: ['email must be an email', 'password must be shorter than or equal to 100 characters']
},
{ // Non-existing group
data: {
...userData,
name: `${data.firstName1} ${data.lastName1}`,
email: `${data.email1}`,
workspaces: [{ name: 'My workspace', status: 'active', groups: [{ name: 'NonExistingGroup' }] }]
},
expectedStatus: 400,
expectedMessage: 'Group permission id or name not found:'
},
{ // Non-existing workspace
data: {
...userData,
name: `${data.firstName1} ${data.lastName1}`,
email: `${data.email1}`,
workspaces: [{ name: 'NonExistingWorkspace', status: 'active' }]
},
expectedStatus: 400,
expectedMessage: 'The workspaces id or name do not exist:'
}
];
invalidUserData.forEach(({ data, expectedStatus, expectedMessages, expectedMessage }) => {
createUser(data).then((response) => {
expect(response.status).to.eq(expectedStatus);
if (expectedMessages) {
expectedMessages.forEach(msg => expect(response.body.message).to.include(msg));
} else {
expect(response.body.message).to.include(expectedMessage);
}
});
});
//Conflict permission
const enduserData = {
...userData,
name: `${data.firstName1} ${data.lastName1}`,
email: `${data.email1}`,
workspaces: [{ name: 'My workspace', status: 'active', groups: [{ name: data.group5 }] }]
}
createUser(enduserData).then((response) => {
expect(response.status).to.eq(400);
expect(response.body.message.title).to.include("Conflicting permissions");
})
});
it("Update user details and workspaces relations", () => {
const updatedUserData = {
name: `${data.firstName1} ${data.lastName1}`,
email: data.email1,
password: "updatedpassword"
}
updateUser(userId, updatedUserData).then((response) => {
expect(response.status).to.eq(200);
})
cy.apiLogout();
cy.apiLogin(updatedUserData.email, updatedUserData.password);
cy.apiLogout();
// Replace user workspaces relations
cy.apiLogin();
validateUserInGroup(updatedUserData.email, "my-workspace", data.group2);
validateUserInGroup(updatedUserData.email, data.workspaceSlug, data.group3);
cy.visit(data.workspaceSlug1);
navigateToManageUsers();
searchUser(updatedUserData.email);
cy.contains("td", updatedUserData.email);
replaceUserWorkspacesRelations(userId, [
{ name: "My workspace", status: "active", role: "end-user", groups: [{ name: data.group1 }] },
{ name: data.workspaceName, status: "active", role: "builder", groups: [] }
]).then((response) => {
expect(response.status).to.eq(200);
});
navigateToManageUsers();
validateUserInGroup(updatedUserData.email, "my-workspace", data.group2, false);
validateUserInGroup(updatedUserData.email, data.workspaceSlug, data.group3, false);
cy.visit(data.workspaceSlug1);
navigateToManageUsers();
searchUser(updatedUserData.email);
cy.get('[data-cy="text-no-result-found"]').contains("No result found");
replaceUserWorkspacesRelations(userId, []).then((response) => {
expect(response.status).to.eq(200);
});
cy.visit("my-workspace");
navigateToManageUsers();
searchUser(updatedUserData.email);
cy.get('[data-cy="text-no-result-found"]').contains("No result found");
});
it("update user role", () => {
const userData2 = {
name: `${data.firstName} ${data.lastName}`,
email: data.email,
password: "password",
status: "active",
workspaces: [
{
name: "My workspace",
status: "active"
}
]
}
let userId1;
let workspaceId1;
createUser(userData2).then((response) => {
expect(response.status).to.eq(201);
userId1 = response.body.id;
workspaceId1 = response.body.workspaces[0].id;
//update role to builder and validate user in builder's group
updateUserRole(workspaceId1, { newRole: "builder", userId: userId1 })
.then((response) => {
expect(response.status).to.eq(200);
});
validateUserInGroup(userData2.email, "my-workspace", "builder");
//update role to end-user and validate user is removed from builder's group
updateUserRole(workspaceId1, { newRole: "end-user", userId: userId1 })
.then((response) => {
expect(response.status).to.eq(200);
});
validateUserInGroup(userData2.email, "my-workspace", data.group5, false);
// update role to builders and validate app's owner role can't be updated
updateUserRole(workspaceId1, { newRole: "builder", userId: userId1 })
.then((response) => {
expect(response.status).to.eq(200);
});
cy.apiLogout();
cy.apiLogin(userData2.email, userData2.password);
cy.apiCreateApp(data.appName);
cy.apiLogout();
cy.defaultWorkspaceLogin();
updateUserRole(workspaceId1, { newRole: "end-user", userId: userId1 })
.then((response) => {
expect(response.status).to.eq(400);
expect(response.body.message.title).to.include("Can not change user role");
});
});
});
const userData3 = {
name: `${data.firstName2} ${data.lastName2}`,
email: data.email2,
password: "password",
status: "active",
workspaces: [
{
name: "My workspace",
status: "active",
groups: [
{ name: data.group1 },
{ name: data.group2 }
]
},
{
name: data.workspaceName,
status: "active",
role: "builder",
groups: [{ name: data.group3 }]
},
{
name: data.workspaceName1,
status: "archived",
role: "admin",
groups: [{ name: data.group4 }]
}
]
};
it("Replace user workspace", () => {
let userId1, workspaceId1;
createUser(userData3).then((response) => {
expect(response.status).to.eq(201);
userId1 = response.body.id;
workspaceId1 = response.body.workspaces[0].id;
// Helper function to replace user workspace and validate response
const replaceAndValidate = (payload, expectedStatus = 200) => {
return replaceUserWorkspace(userId1, workspaceId1, payload).then((response) => {
expect(response.status).to.eq(expectedStatus);
});
};
// No change if empty request body
replaceAndValidate({}).then(() => {
validateUserInGroup(userData3.email, "my-workspace", data.group1);
validateUserInGroup(userData3.email, "my-workspace", data.group2);
});
// Archive the user and verify status
replaceAndValidate({ status: "archived" }).then(() => {
navigateToManageUsers();
searchUser(userData3.email);
cy.contains("td", userData3.email)
.parent()
.within(() => {
cy.get("td small").should("have.text", "archived");
});
});
// Reactivate user and validate groups
replaceAndValidate({ status: "active" }).then(() => {
validateUserInGroup(userData3.email, "my-workspace", data.group1);
validateUserInGroup(userData3.email, "my-workspace", data.group2);
});
// Update groups and validate removal
replaceAndValidate({ groups: [{ name: data.group1 }] }).then(() => {
validateUserInGroup(userData3.email, "my-workspace", data.group2, false);
});
//Empty group array, user removed from groups
replaceAndValidate({ groups: [] }).then(() => {
validateUserInGroup(userData3.email, "my-workspace", data.group1, false);
});
//Conflict permission
replaceAndValidate({ groups: [{ name: data.group5 }] }, 400);
//Add user in groups and validate
replaceAndValidate({ groups: [{ name: data.group1 }, { name: data.group2 }] });
validateUserInGroup(userData3.email, "my-workspace", data.group1);
validateUserInGroup(userData3.email, "my-workspace", data.group2);
});
});
});

View file

@ -0,0 +1,160 @@
import { importApp, exportApp, allAppsDetails } from 'Support/utils/api';
import { fake } from "Fixtures/fake";
describe("Export and Import API ", () => {
const sanitize = (str) => str.toLowerCase().replace(/[^A-Za-z]/g, "");
const data = {
workspaceName: sanitize(fake.lastName),
workspaceSlug: sanitize(fake.lastName),
}
const fixtureFiles = {
requestData: "templates/import_unnamed_file.json",
requestData2: "templates/import_named_file.json",
requestData3: "templates/three-versions.json",
};
let requestData, requestData2, requestData3;
beforeEach(() => {
cy.defaultWorkspaceLogin();
const fixturePromises = Object.entries(fixtureFiles).map(([key, file]) =>
cy.fixture(file).then((data) => ({ key, data }))
);
// Assign loaded data to respective variables
return Promise.all(fixturePromises).then((results) => {
results.forEach(({ key, data }) => {
({ requestData, requestData2, requestData3 }[key] = data);
});
});
});
it("Import App API", () => {
const workspaceId = Cypress.env("workspaceId");
importApp(workspaceId, requestData).then((response) => {
expect(response.status).to.eq(201);
expect(response.body.message).to.include("App imported successfully into workspace");
});
//Invalid access token and workspace
importApp(workspaceId, requestData, {
Authorization: "Basic xyz",
"Content-Type": "application/json"
}).then((response) => {
expect(response.status).to.eq(403);
});
importApp(workspaceId, requestData, {
Authorization: "",
"Content-Type": "application/json"
}).then((response) => {
expect(response.status).to.eq(403);
});
importApp(`${workspaceId}ee`, requestData).then((response) => {
expect(response.status).to.eq(400);
});
//Import named file
importApp(workspaceId, requestData2).then((response) => {
expect(response.status).to.eq(201);
expect(response.body.message).to.include("App imported successfully into workspace");
});
cy.reload();
cy.get('[data-cy="app_json-title"]').should("exist");
//duplicate app
importApp(workspaceId, requestData2).then((response) => {
expect(response.status).to.eq(409);
expect(response.body.message).to.include("App with app_json already exists in the workspace");
});
cy.deleteApp("app_json");
cy.get('[data-cy="app_json-title"]').should("not.exist");
//Import app in another workpsace
let newWorkspaceId;
cy.apiCreateWorkspace(data.workspaceName, data.workspaceSlug).then((res) => {
newWorkspaceId = res.body.organization_id;
cy.visit(data.workspaceSlug);
importApp(newWorkspaceId, requestData).then((response) => {
expect(response.status).to.eq(201);
expect(response.body.message).to.include("App imported successfully into workspace");
});
});
});
it("Export App API", () => {
const workspaceId = Cypress.env("workspaceId");
let appId;
importApp(workspaceId, requestData3).then((response) => {
expect(response.status).to.eq(201);
expect(response.body.message).to.include("App imported successfully into workspace");
}).then(() => {
cy.get('[data-cy^="import-export-app"]')
.first()
.find('[data-cy="edit-button"]')
.click({ force: true });
cy.skipWalkthrough();
});
cy.get('[data-cy="left-sidebar-settings-button"]').click();
cy.get('[data-cy="app-slug-input-field"]').invoke('val').then((value) => {
appId = value;
//export last created version
exportApp(workspaceId, appId, "").then((response) => {
expect(response.status).to.eq(201);
expect(response.body.app[0].definition.appV2.appVersions.length).to.eq(1);
expect(response.body.app[0].definition.appV2.appVersions[0].name).to.eq("v3");
});
//export specific versions
exportApp(workspaceId, appId, "?appVersion=v2").then((response) => {
expect(response.status).to.eq(201);
expect(response.body.app[0].definition.appV2.appVersions.length).to.eq(1);
expect(response.body.app[0].definition.appV2.appVersions[0].name).to.eq("v2");
});
//export all versions
exportApp(workspaceId, appId, "?exportAllVersions=true").then((response) => {
expect(response.status).to.eq(201);
expect(response.body.app[0].definition.appV2.appVersions.length).to.eq(3);
});
//Invalid access token and workspace
/* exportApp(workspaceId, appId, "", {
Authorization: "",
"Content-Type": "application/json"
}).then((response) => {
expect(response.status).to.eq(403);
});
exportApp(workspaceId, appId, "", {
Authorization: "",
"Content-Type": "application/json"
}).then((response) => {
expect(response.status).to.eq(403);
});
exportApp(`${workspaceId}ee`, appId, "").then((response) => {
expect(response.status).to.eq(400);
});
*/
//with and without TJDB -x.tooljet_database
exportApp(workspaceId, appId, "?exportTJDB=false").then((response) => {
expect(response.status).to.eq(201);
expect(response.body).not.to.have.property("tooljet_database");
});
exportApp(workspaceId, appId, "?exportTJDB=true").then((response) => {
expect(response.status).to.eq(201);
expect(response.body).to.have.property("tooljet_database");
});
});
//All Apps details
allAppsDetails(workspaceId).then((response) => {
expect(response.status).to.eq(200);
});
});
});

View file

@ -0,0 +1,3 @@
{
"id": "bff6583db942c77249ba"
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -2127,7 +2127,7 @@
"encrypted": false
},
"host": {
"value": "35.202.183.199",
"value": "35.238.9.114",
"encrypted": false
},
"port": {

View file

@ -585,7 +585,7 @@
"encrypted": false
},
"host": {
"value": "35.202.183.199",
"value": "35.238.9.114",
"encrypted": false
},
"port": {

View file

@ -1701,7 +1701,7 @@
]
},
"list_rows": {},
"runOnPageLoad": true
"runOnPageLoad": false
},
"dataSourceId": "f4cf0089-aec2-4713-800e-3560e678220b",
"appVersionId": "b74fcff1-8cf1-40f8-a13d-c2d2a0b1ebf1",
@ -1862,7 +1862,7 @@
"encrypted": false
},
"host": {
"value": "35.202.183.199",
"value": "35.238.9.114",
"encrypted": false
},
"port": {

View file

@ -0,0 +1,72 @@
import { groupsSelector } from "Selectors/manageGroups";
import { navigateToManageGroups } from 'Support/utils/common';
export const apiRequest = (method, url, body = {}, headers = {}) => {
return cy.request({
method,
url,
body,
headers: {
Authorization: Cypress.env('AUTH_TOKEN'),
"Content-Type": "application/json",
...headers,
},
failOnStatusCode: false
});
};
export const createUser = (userData) => {
return apiRequest("POST", `${Cypress.env('API_URL')}/ext/users`, userData);
};
export const getUser = (userId) => {
return apiRequest("GET", `${Cypress.env('API_URL')}/ext/user/${userId}`);
};
export const getAllUsers = () => {
return apiRequest("GET", `${Cypress.env('API_URL')}/ext/users`);
};
export const updateUser = (userId, userData) => {
return apiRequest("PATCH", `${Cypress.env('API_URL')}/ext/user/${userId}`, userData);
};
export const updateUserRole = (workspaceId, userData) => {
return apiRequest("PUT", `${Cypress.env('API_URL')}/ext/update-user-role/workspace/${workspaceId}`, userData);
}
export const replaceUserWorkspace = (userId, workspaceId, userData) => {
return apiRequest("PATCH", `${Cypress.env('API_URL')}/ext/user/${userId}/workspace/${workspaceId}`, userData);
}
export const replaceUserWorkspacesRelations = (userId, userData) => {
return apiRequest("PUT", `${Cypress.env('API_URL')}/ext/user/${userId}/workspaces`, userData);
}
export const getAllWorkspaces = () => {
return apiRequest("GET", `${Cypress.env('API_URL')}/ext/workspaces`);
}
export const importApp = (workspaceId, appData, headers) => {
return apiRequest("POST", `${Cypress.env('API_URL')}/ext/import/workspace/${workspaceId}/apps`, appData, headers);
}
export const exportApp = (workspaceId, appId, endpoint, headers) => {
return apiRequest("POST", `${Cypress.env('API_URL')}/ext/export/workspace/${workspaceId}/apps/${appId}${endpoint}`, headers);
}
export const allAppsDetails = (workspaceIds) => {
return apiRequest("GET", `${Cypress.env('API_URL')}/ext/workspace/${workspaceIds}/apps`);
}
export const createGroup = (groupName) => {
cy.get(groupsSelector.createNewGroupButton).click();
cy.clearAndType(groupsSelector.groupNameInput, groupName);
cy.get(groupsSelector.createGroupButton).click();
}
export const validateUserInGroup = (email, workspaceSlug, groupName, shouldExist = true) => {
if (workspaceSlug) cy.visit(workspaceSlug);
navigateToManageGroups();
cy.get(groupsSelector.groupLink(groupName)).click();
cy.get(groupsSelector.usersLink).click();
const userRow = `[data-cy="${email}-user-row"]`;
cy.get(userRow).should(shouldExist ? "exist" : "not.exist");
};

View file

@ -25,7 +25,10 @@ export const verifySuccessfulSlugUpdate = (workspaceId, slug) => {
"have.text",
"Slug accepted!"
);
cy.get(commonWidgetSelector.appLinkSucessLabel).verifyVisibleElement(
cy.wait(500);
// cy.get(commonWidgetSelector.appLinkSucessLabel).should('be.visible');
cy.get(commonWidgetSelector.appLinkSucessLabel).should(
"have.text",
"Link updated successfully!"
);

View file

@ -32,10 +32,10 @@ export const deleteComponentAndVerify = (widgetName) => {
.last()
.realClick();
});
cy.verifyToastMessage(
`[class=go3958317564]`,
"Component deleted! (Ctrl + Z to undo)"
);
// cy.verifyToastMessage(
// `[class=go3958317564]`,
// "Component deleted! (Ctrl + Z to undo)"
// );
cy.notVisible(commonWidgetSelector.draggableWidget(widgetName));
};

View file

@ -40,7 +40,7 @@ export const verifyControlComponentAction = (widgetName, value) => {
export const addBasicData = (data) => {
openEditorSidebar(buttonText.defaultWidgetName);
verifyAndModifyParameter(buttonText.buttonTextLabel, data.widgetName);
verifyAndModifyParameter('Label', data.widgetName);
openAccordion(commonWidgetText.accordionEvents);
addDefaultEventHandler(data.alertMessage);

View file

@ -16,9 +16,7 @@ export const navigateToProfile = () => {
export const logout = () => {
cy.get(commonSelectors.settingsIcon).click();
cy.get(commonSelectors.logoutLink).click();
cy.intercept("GET", "/api/metadata").as("publicConfig");
cy.wait("@publicConfig");
cy.wait(500);
cy.wait(1000);
};
export const navigateToManageUsers = () => {
@ -183,10 +181,9 @@ export const manageUsersPagination = (email) => {
export const searchUser = (email) => {
cy.clearAndType(commonSelectors.inputUserSearch, email);
cy.wait(1000)
cy.wait(1000);
};
export const selectAppCardOption = (appName, appCardOption) => {
viewAppCardOptions(appName);
cy.get(appCardOption).should("be.visible").click({ force: true });
@ -221,7 +218,6 @@ export const pinInspector = () => {
}
});
cy.hideTooltip();
};
export const navigateToworkspaceConstants = () => {
@ -243,24 +239,3 @@ export const verifyTooltipDisabled = (selector, message) => {
cy.get(".tooltip-inner").last().should("have.text", message);
});
};
export const deleteAllGroupChips = () => {
cy.get('body').then(($body) => {
if ($body.find('[data-cy="group-chip"]').length > 0) {
cy.get('[data-cy="group-chip"]').then(($groupChip) => {
if ($groupChip.is(':visible')) {
cy.get('[data-cy="group-chip"]').first().click();
cy.get('[data-cy="delete-button"]').click();
cy.get('[data-cy="yes-button"]').click();
cy.wait(2000);
deleteAllGroupChips(); // Recursive call to delete next chip
} else {
cy.log("Group chip is present but not visible, skipping deletion");
}
});
} else {
cy.log("No group chips left to delete");
}
});
}

View file

@ -6,6 +6,7 @@ import { commonText } from "Texts/common";
import { dataSourceSelector } from "Selectors/dataSource";
import { dataSourceText } from "Texts/dataSource";
import { navigateToAppEditor } from "Support/utils/common";
import { verifyAppDelete } from "Support/utils/dashboard";
export const verifyCouldnotConnectWithAlert = (dangerText) => {
cy.get(postgreSqlSelector.connectionFailedText, {
@ -60,6 +61,15 @@ export const deleteDatasource = (datasourceName) => {
// " Databases"
// );
};
export const deleteAppandDatasourceAfterExecution = (
appName,
datasourceName
) => {
cy.backToApps();
cy.deleteApp(appName);
verifyAppDelete(appName);
deleteDatasource(datasourceName);
};
export const closeDSModal = () => {
cy.get("body").then(($body) => {
@ -96,9 +106,7 @@ export const addQueryN = (queryName, query, dbName) => {
export const addQuery = (queryName, query, dbName) => {
cy.get('[data-cy="show-ds-popover-button"]').click();
cy.get(".css-4e90k9").type(`${dbName}`);
cy.intercept("POST", "/api/data-queries/**").as(
"createQuery"
);
cy.intercept("POST", "/api/data-queries/**").as("createQuery");
cy.contains(`[id*="react-select-"]`, dbName).click();
cy.get('[data-cy="query-rename-input"]').clear().type(queryName);
@ -225,7 +233,14 @@ export const createDataQuery = (appName, url, key, value) => {
});
};
export const createRestAPIQuery = (queryName, dsName, key = '', value = '', url = "", run = true) => {
export const createRestAPIQuery = (
queryName,
dsName,
key = "",
value = "",
url = "",
run = true
) => {
cy.getCookie("tj_auth_token").then((cookie) => {
const headers = {
"Tj-Workspace-Id": Cypress.env("workspaceId"),

View file

@ -34,7 +34,7 @@ export const verifyValue = (node, type, children, index = 0) => {
};
export const deleteComponentFromInspector = (node) => {
cy.get('[data-cy="inspector-node-components"] > .node-key').click();
cy.get(`[data-cy="inspector-node-${node}"] > .node-key`).realHover().parent().find('[style="height: 13px; width: 13px;"] > img').click();
cy.get(`[data-cy="inspector-node-${node}"] > .node-key`).realHover().parent().find('[style="height: 13px; width: 13px;"] > img').last().click();
};
export const verifyfunctions = (node, type, index = 0) => {

View file

@ -646,7 +646,7 @@ export const createGroupAddAppAndUserToGroup = (groupName, email) => {
cy.request({
method: "POST",
url: `${Cypress.env("server_host")}/api/v2/group_permissions`,
url: `${Cypress.env("server_host")}/api/v2/group-permissions`,
headers: headers,
body: {
name: groupName,
@ -658,14 +658,14 @@ export const createGroupAddAppAndUserToGroup = (groupName, email) => {
cy.request({
method: "POST",
url: `${Cypress.env("server_host")}/api/v2/group_permissions/granular-permissions`,
url: `${Cypress.env("server_host")}/api/v2/group-permissions/${groupId}/granular-permissions`,
headers: headers,
body: {
name: "Apps",
type: "app",
groupId: groupId,
isAll: false,
createAppsPermissionsObject: {
createResourcePermissionObject: {
canEdit: true,
canView: false,
hideFromDashboard: false,
@ -676,19 +676,22 @@ export const createGroupAddAppAndUserToGroup = (groupName, email) => {
],
},
},
}).then((response) => {
expect(response.status).to.equal(201);
});
cy.wait(2000);
cy.task("dbConnection", {
dbconfig: Cypress.env("app_db"),
sql: `select id from users where email='${email}';`,
}).then((resp) => {
const userId = resp.rows[0].id;
cy.log(userId);
cy.request({
method: "POST",
url: `${Cypress.env("server_host")}/api/v2/group_permissions/group-user`,
url: `${Cypress.env("server_host")}/api/v2/group-permissions/${groupId}/users`,
headers: headers,
body: {
userIds: [userId],
@ -720,7 +723,7 @@ export const OpenGroupCardOption = (groupName) => {
export const duplicateMultipleGroups = (groupNames) => {
groupNames.forEach((groupName) => {
OpenGroupCardOption(groupName);
cy.wait(3000);
cy.wait(2000);
cy.get(commonSelectors.duplicateOption).click(); // Click on the duplicate option
cy.get(commonSelectors.confirmDuplicateButton).click(); // Confirm duplication if needed
});
@ -850,6 +853,9 @@ export const createGroupsAndAddUserInGroup = (groupName, email) => {
commonSelectors.toastMessage,
groupsText.groupCreatedToast
);
addUserInGroup(groupName, email);
};
export const addUserInGroup = (groupName, email) => {
cy.get(groupsSelector.groupLink(groupName)).click();
cy.clearAndType(groupsSelector.multiSelectSearchInput, email);
cy.wait(2000);
@ -859,7 +865,7 @@ export const createGroupsAndAddUserInGroup = (groupName, email) => {
commonSelectors.toastMessage,
groupsText.userAddedToast
);
};
}
export const inviteUserBasedOnRole = (firstName, email, role = "end-user") => {
fillUserInviteForm(firstName, email);

View file

@ -18,7 +18,7 @@ export const generalSettings = () => {
cy.get(ssoSelector.workspaceLoginPage.defaultSSO).click();
cy.get(ssoSelector.defaultGoogle).verifyVisibleElement("have.text", "Google");
cy.get(ssoSelector.defaultGithub).verifyVisibleElement("have.text", "Github");
cy.get(ssoSelector.defaultGithub).verifyVisibleElement("have.text", "Git");
cy.clearAndType(ssoSelector.allowedDomainInput, ssoText.allowedDomain);
cy.get(ssoSelector.saveButton).click();
@ -416,7 +416,7 @@ export const resetDomain = () => {
cy.request(
{
method: "PATCH",
url: `${Cypress.env("server_host")}/api/organizations`,
url: `${Cypress.env("server_host")}/api/login-configs/organization-general`,
headers: {
"Tj-Workspace-Id": Cypress.env("workspaceId"),
Cookie: `tj_auth_token=${cookie.value}`,

View file

@ -57,7 +57,7 @@ export const setHomePage = (pageName) => {
export const addNewPage = (pageName) => {
cy.get(multipageSelector.addPageIcon).click();
cy.get(".col-12 > .form-control").type(`{selectAll}{backspace}${pageName}`);
cy.get('[role="button"] > div > .form-control').type(`{selectAll}{backspace}${pageName}`);
cy.get(multipageSelector.addPageIcon).click();
cy.get(`[data-cy="pages-name-${pageName.toLowerCase()}"]`).click();
};

View file

@ -47,6 +47,8 @@ export const waitForQueryAction = (action) => {
export const chainQuery = (currentQuery, trigger) => {
cy.get(`[data-cy="list-query-${currentQuery}"]`).click();
cy.wait(1000);
cy.get('[data-cy="query-tab-settings"]').click();
selectEvent("Query Success", "Run Query");
cy.get('[data-cy="query-selection-field"]')
.click()
@ -55,8 +57,16 @@ export const chainQuery = (currentQuery, trigger) => {
};
export const addSuccessNotification = (notification) => {
changeQueryToggles("notification-on-success");
cy.get('[data-cy="success-message-input-field"]').clearAndTypeOnCodeMirror(
notification
);
cy.get('[data-cy="query-tab-settings"]').click();
cy.get('body').then(($body) => {
if (!$body.find('[data-cy="success-message-input-field"]').is(':visible')) {
changeQueryToggles("notification-on-success");
// cy.get('[data-cy="success-message-input-field"]').then(($input) => {
// cy.wrap($input).clearAndTypeOnCodeMirror(notification);
// });
}
});
cy.get('[data-cy="success-message-input-field"]').clearAndTypeOnCodeMirror(notification);
cy.get('[data-cy="query-tab-setup"]').click();
cy.wait(300);
};

View file

@ -0,0 +1,97 @@
export const createAndRunRestAPIQuery = (
queryName,
dsName,
method = "GET",
url = "",
headersList = [],
bodyList = [],
jsonBody = null,
run = true,
urlSuffix = ""
) => {
cy.getCookie("tj_auth_token").then((cookie) => {
const headers = {
"Tj-Workspace-Id": Cypress.env("workspaceId"),
Cookie: `tj_auth_token=${cookie.value}`,
};
cy.request({
method: "GET",
url: `${Cypress.env("server_host")}/api/apps/${Cypress.env("appId")}`,
headers,
}).then((response) => {
const editingVersionId = response.body.editing_version.id;
const data_source_id = Cypress.env(`${dsName}-id`);
const useJsonBody =
["POST", "PATCH", "PUT"].includes(method.toUpperCase()) &&
jsonBody !== null;
const queryOptions = {
method: method.toLowerCase(),
url: url + urlSuffix,
url_params: [["", ""]],
headers: headersList.length ? headersList : [["", ""]],
body: !useJsonBody && bodyList.length ? bodyList : [["", ""]],
json_body: useJsonBody ? jsonBody : null,
body_toggle: useJsonBody,
runOnPageLoad: run,
transformationLanguage: "javascript",
enableTransformation: false,
};
const requestBody = {
app_id: Cypress.env("appId"),
app_version_id: editingVersionId,
name: queryName,
kind: "restapi",
options: queryOptions,
data_source_id,
plugin_id: null,
};
cy.request({
method: "POST",
url: `${Cypress.env("server_host")}/api/data-queries/data-sources/${data_source_id}/versions/${editingVersionId}`,
headers,
body: requestBody,
}).then((createResponse) => {
expect(createResponse.status).to.equal(201);
const queryId = createResponse.body.id;
cy.log("Query created successfully:", queryId);
const createdOptions = createResponse.body.options;
expect(createdOptions.method).to.equal(queryOptions.method);
expect(createdOptions.url).to.equal(queryOptions.url);
expect(createdOptions.headers).to.deep.equal(queryOptions.headers);
if (useJsonBody) {
expect(createdOptions.json_body).to.deep.equal(
queryOptions.json_body
);
expect(createdOptions.body_toggle).to.equal(true);
} else {
expect(createdOptions.body).to.deep.equal(queryOptions.body);
expect(createdOptions.body_toggle).to.equal(false);
}
expect(createdOptions.runOnPageLoad).to.equal(run);
cy.log("Metadata verified successfully");
if (run) {
cy.request({
method: "POST",
url: `${Cypress.env("server_host")}/api/data-queries/${queryId}/run`,
headers,
}).then((runResponse) => {
expect([200, 201]).to.include(runResponse.status);
cy.log("Query executed successfully:", runResponse.body);
if (runResponse.body?.data.id) {
cy.writeFile("cypress/fixtures/restAPI/storedId.json", {
id: runResponse.body.data.id,
});
cy.log("Stored ID:", runResponse.body.data.id);
}
});
}
});
});
});
};

31
docker/ce-entrypoint.sh Executable file
View file

@ -0,0 +1,31 @@
#!/bin/bash
set -e
if [ -f "./.env" ]; then
export $(grep -v '^#' ./.env | xargs -d '\n') || true
fi
if [ -d "./server/dist" ]; then
SETUP_CMD='npm run db:setup:prod'
else
SETUP_CMD='npm run db:setup'
fi
if [ -f "./.env" ]; then
declare $(grep -v '^#' ./.env | xargs)
fi
if [ -z "$DATABASE_URL" ]; then
./server/scripts/wait-for-it.sh $PG_HOST:${PG_PORT:-5432} --strict --timeout=300 -- $SETUP_CMD
else
PG_HOST=$(echo "$DATABASE_URL" | awk -F'[/:@?]' '{print $6}')
PG_PORT=$(echo "$DATABASE_URL" | awk -F'[/:@?]' '{print $7}')
if [ -z "$DATABASE_PORT" ]; then
DATABASE_PORT="5432"
fi
./server/scripts/wait-for-it.sh "$PG_HOST:$PG_PORT" --strict --timeout=300 -- $SETUP_CMD
fi
exec "$@"

View file

@ -70,7 +70,6 @@ COPY --from=builder /app/frontend/build ./app/frontend/build
# copy server build
COPY --from=builder /app/server/package.json ./app/server/package.json
COPY --from=builder /app/server/.version ./app/server/.version
COPY --from=builder /app/server/entrypoint.sh ./app/server/entrypoint.sh
COPY --from=builder /app/server/node_modules ./app/server/node_modules
COPY --from=builder /app/server/templates ./app/server/templates
COPY --from=builder /app/server/scripts ./app/server/scripts
@ -78,16 +77,37 @@ COPY --from=builder /app/server/dist ./app/server/dist
WORKDIR /app
USER root
RUN wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add -
RUN echo "deb http://apt.postgresql.org/pub/repos/apt/ bullseye-pgdg main" | tee /etc/apt/sources.list.d/pgdg.list
RUN echo "deb http://deb.debian.org/debian"
RUN apt update && apt -y install postgresql-13 postgresql-client-13 supervisor
USER postgres
RUN service postgresql start && \
psql -c "create role tooljet with login superuser password 'postgres';"
USER root
# ENV defaults
ENV TOOLJET_HOST=http://localhost:80 \
PGRST_HOST=http://localhost:3000 \
PGRST_JWT_SECRET=r9iMKoe5CRMgvJBBtp4HrqN7QiPpUToj \
TOOLJET_DB=tooljet_db \
ENABLE_TOOLJET_DB=true \
PORT=80 \
ENV TOOLJET_HOST=http://localhost \
NODE_ENV=production \
LOCKBOX_MASTER_KEY=replace_with_lockbox_master_key \
SECRET_KEY_BASE=replace_with_secret_key_base \
ORM_LOGGING=all \
PG_DB=tooljet_production \
PG_USER=tooljet \
PG_PASS=postgres \
PG_HOST=localhost \
ENABLE_TOOLJET_DB=true \
TOOLJET_DB_HOST=localhost \
TOOLJET_DB_USER=tooljet \
TOOLJET_DB_PASS=postgres \
TOOLJET_DB=tooljet_db \
PGRST_HOST=http://localhost:3000 \
PGRST_DB_URI=postgres://tooljet:postgres@localhost/tooljet_db \
PGRST_JWT_SECRET=r9iMKoe5CRMgvJBBtp4HrqN7QiPpUToj \
PGRST_DB_PRE_CONFIG=postgrest.pre_config \
ORM_LOGGING=true \
DEPLOYMENT_PLATFORM=docker:local \
HOME=/home/appuser \
TERM=xterm
CMD ["/usr/bin/supervisord"]

View file

@ -88,12 +88,13 @@ COPY --from=builder /app/frontend/build ./app/frontend/build
# copy server build
COPY --from=builder /app/server/package.json ./app/server/package.json
COPY --from=builder /app/server/.version ./app/server/.version
COPY --from=builder /app/server/entrypoint.sh ./app/server/entrypoint.sh
COPY --from=builder /app/server/node_modules ./app/server/node_modules
COPY --from=builder /app/server/templates ./app/server/templates
COPY --from=builder /app/server/scripts ./app/server/scripts
COPY --from=builder /app/server/dist ./app/server/dist
COPY ./docker/ce-entrypoint.sh ./app/server/entrypoint.sh
# Define non-sudo user
RUN useradd --create-home --home-dir /home/appuser appuser \
&& chown -R appuser:0 /app \
@ -111,5 +112,4 @@ WORKDIR /app
# Dependencies for scripts outside nestjs
RUN npm install dotenv@10.0.0 joi@17.4.1
ENTRYPOINT ["./server/entrypoint.sh"]

View file

@ -99,7 +99,6 @@ COPY --from=builder /app/frontend/build ./app/frontend/build
COPY --from=builder /app/server/package.json ./app/server/package.json
COPY --from=builder /app/server/.version ./app/server/.version
COPY --from=builder /app/server/ee/keys ./app/server/ee/keys
COPY --from=builder /app/server/entrypoint.sh ./app/server/entrypoint.sh
COPY --from=builder /app/server/node_modules ./app/server/node_modules
COPY --from=builder /app/server/templates ./app/server/templates
COPY --from=builder /app/server/scripts ./app/server/scripts
@ -108,15 +107,37 @@ COPY --from=builder /app/server/dist ./app/server/dist
WORKDIR /app
# ENV defaults
ENV TOOLJET_HOST=http://localhost:80 \
PGRST_HOST=http://localhost:3000 \
PGRST_JWT_SECRET=r9iMKoe5CRMgvJBBtp4HrqN7QiPpUToj \
TOOLJET_DB=tooljet_db \
ENABLE_TOOLJET_DB=true \
PORT=80 \
USER root
RUN wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add -
RUN echo "deb http://apt.postgresql.org/pub/repos/apt/ bullseye-pgdg main" | tee /etc/apt/sources.list.d/pgdg.list
RUN echo "deb http://deb.debian.org/debian"
RUN apt update && apt -y install postgresql-13 postgresql-client-13 supervisor
USER postgres
RUN service postgresql start && \
psql -c "create role tooljet with login superuser password 'postgres';"
USER root
# ENV defaults
ENV TOOLJET_HOST=http://localhost \
NODE_ENV=production \
LOCKBOX_MASTER_KEY=replace_with_lockbox_master_key \
SECRET_KEY_BASE=replace_with_secret_key_base \
ORM_LOGGING=all \
PG_DB=tooljet_production \
PG_USER=tooljet \
PG_PASS=postgres \
PG_HOST=localhost \
ENABLE_TOOLJET_DB=true \
TOOLJET_DB_HOST=localhost \
TOOLJET_DB_USER=tooljet \
TOOLJET_DB_PASS=postgres \
TOOLJET_DB=tooljet_db \
PGRST_HOST=http://localhost:3000 \
PGRST_DB_URI=postgres://tooljet:postgres@localhost/tooljet_db \
PGRST_JWT_SECRET=r9iMKoe5CRMgvJBBtp4HrqN7QiPpUToj \
PGRST_DB_PRE_CONFIG=postgrest.pre_config \
ORM_LOGGING=true \
DEPLOYMENT_PLATFORM=docker:local \
REDIS_PASS= \
TERM=xterm
CMD ["/usr/bin/supervisord"]

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