Merge branch 'appbuilder/sprint-12' into enhance/override-codemirror-autocomplete-default-filter

This commit is contained in:
johnsoncherian 2025-05-14 23:29:52 +05:30
commit 93ef107040
4218 changed files with 484669 additions and 72502 deletions

View file

@ -2,6 +2,8 @@
# The application expects a separate .env.test for test environment configuration
# Get detailed information about each variable here: https://docs.tooljet.com/docs/setup/env-vars
# TOOLJET_EDITION=ee
TOOLJET_HOST=http://localhost:8082
LOCKBOX_MASTER_KEY=0000000000000000000000000000000000000000000000000000000000000000
SECRET_KEY_BASE=replace_with_secret_key_base

148
.gitconfig Normal file
View file

@ -0,0 +1,148 @@
[alias]
# This command does a checkout and pull the changes.
checkout-all = "!f() { \
git checkout \"$1\" && git pull; \
git submodule foreach --recursive \" \
if git show-ref --verify --quiet refs/heads/$1; then \
git checkout $1 && git pull; \
else \
echo 'Skipping submodule $(basename $PWD), branch $1 not found.'; \
fi\"; \
}; f"
# This command helps to pull changes for the base and submodule repos.
pull-all = "!f() { \
git pull && \
git submodule foreach 'git pull'; \
}; f"
# This command helps to stage the changes for the base and submodule repos.
add-all = "!f() { \
git add -A && \
git submodule foreach 'git add -A'; \
}; f"
# This command creates custom and pushes a new branch in the base and submodule repos.
create-branch-all = "!f() { \
branch_name=$1; \
if [ -z \"$branch_name\" ]; then \
echo \"Branch name required! Usage: git create-branch-all <branch_name>\"; \
return 1; \
fi; \
echo \"Creating new branch $branch_name in the base repo...\"; \
git checkout -b $branch_name && git push -u origin $branch_name; \
echo \"Creating new branch $branch_name in submodules...\"; \
git submodule foreach --quiet --recursive \"git checkout -b $branch_name && git push -u origin $branch_name\"; \
}; f"
# This command creates and pushes a new branch with the 'feature/' prefix in the base and submodule repos.
create-feature-all = "!f() { \
branch_name=$1; \
if [ -z \"$branch_name\" ]; then \
echo \"Feature name required! Usage: git create-feature-all <feature_name>\"; \
return 1; \
fi; \
feature_branch=\"feature/$branch_name\"; \
echo \"Creating new feature branch $feature_branch in the base repo...\"; \
git checkout -b $feature_branch && git push -u origin $feature_branch; \
echo \"Creating new feature branch $feature_branch in submodules...\"; \
git submodule foreach --quiet --recursive \"git checkout -b $feature_branch && git push -u origin $feature_branch\"; \
}; f"
# This command creates and pushes a new branch with the 'hot-fix/' prefix in the base and submodule repos.
create-hotfix-all = "!f() { \
branch_name=$1; \
if [ -z \"$branch_name\" ]; then \
echo \"Hotfix name required! Usage: git create-hotfix-all <hotfix_name>\"; \
return 1; \
fi; \
hotfix_branch=\"hot-fix/$branch_name\"; \
echo \"Creating new hotfix branch $hotfix_branch in the base repo...\"; \
git checkout -b $hotfix_branch && git push -u origin $hotfix_branch; \
echo \"Creating new hotfix branch $hotfix_branch in submodules...\"; \
git submodule foreach --quiet --recursive \"git checkout -b $hotfix_branch && git push -u origin $hotfix_branch\"; \
}; f"
# This command creates and pushes a new branch with the 'release/' prefix in the base and submodule repos.
create-release-all = "!f() { \
branch_name=$1; \
if [ -z \"$branch_name\" ]; then \
echo \"Release name required! Usage: git create-release-all <release_name>\"; \
return 1; \
fi; \
release_branch=\"release/$branch_name\"; \
echo \"Creating new release branch $release_branch in the base repo...\"; \
git checkout -b $release_branch && git push -u origin $release_branch; \
echo \"Creating new release branch $release_branch in submodules...\"; \
git submodule foreach --quiet --recursive \"git checkout -b $release_branch && git push -u origin $release_branch\"; \
}; f"
# This command creates and pushes a new branch with the 'revamp/' prefix in the base and submodule repos.
create-revamp-all = "!f() { \
branch_name=$1; \
if [ -z \"$branch_name\" ]; then \
echo \"Revamp name required! Usage: git create-revamp-all <revamp_name>\"; \
return 1; \
fi; \
revamp_branch=\"revamp/$branch_name\"; \
echo \"Creating new revamp branch $revamp_branch in the base repo...\"; \
git checkout -b $revamp_branch && git push -u origin $revamp_branch; \
echo \"Creating new revamp branch $revamp_branch in submodules...\"; \
git submodule foreach --quiet --recursive \"git checkout -b $revamp_branch && git push -u origin $revamp_branch\"; \
}; f"
# This command creates and pushes a new branch with the 'sprint/' prefix in the base and submodule repos.
create-sprint-all = "!f() { \
branch_name=$1; \
if [ -z \"$branch_name\" ]; then \
echo \"Sprint name required! Usage: git create-sprint-all <sprint_name>\"; \
return 1; \
fi; \
sprint_branch=\"sprint/$branch_name\"; \
echo \"Creating new sprint branch $sprint_branch in the base repo...\"; \
git checkout -b $sprint_branch && git push -u origin $sprint_branch; \
echo \"Creating new sprint branch $sprint_branch in submodules...\"; \
git submodule foreach --quiet --recursive \"git checkout -b $sprint_branch && git push -u origin $sprint_branch\"; \
}; f"
# This command creates and pushes a new tag in the base and submodule repos.
create-tag-all = "!f() { \
tag_name=$1; \
if [ -z \"$tag_name\" ]; then \
echo \"Tag name required! Usage: git create-tag-all <tag_name>\"; \
return 1; \
fi; \
echo \"Creating and pushing tag $tag_name in the base repo...\"; \
git tag $tag_name && git push origin $tag_name; \
echo \"Creating and pushing tag $tag_name in submodules...\"; \
git submodule foreach --quiet --recursive \"git tag $tag_name && git push origin $tag_name\"; \
}; f"
# This command stages and commits changes for the base and submodule repos.
commit-all = "!f() { \
commit_message=\"$1\"; \
if [ -z \"$commit_message\" ]; then \
echo \"Commit message required! Usage: git commit-all <commit_message>\"; \
return 1; \
fi; \
echo \"Committing changes in the base repo...\"; \
git commit -m \"$commit_message\"; \
echo \"Committing changes in submodules...\"; \
git submodule foreach --quiet --recursive \"git commit -m '$commit_message'\"; \
}; f"
# This command pushes commits for the base and submodule repos.
push-all = "!f() { \
echo \"Pushing changes in the base repo...\"; \
git push; \
echo \"Pushing changes in submodules...\"; \
git submodule foreach --quiet --recursive \"git push\"; \
}; f"
status-all = "!f() { \
echo \"Status of base repo...\"; \
git status; \
echo \"Status of submodules...\"; \
git submodule foreach --quiet --recursive \"git status\"; \
}; f"

View file

@ -2,8 +2,7 @@ name: Cypress App-Builder
on:
pull_request_target:
types: [labeled, unlabeled, closed]
types: [labeled]
workflow_dispatch:
env:
@ -13,8 +12,22 @@ env:
jobs:
Cypress-App-Builder:
runs-on: ubuntu-22.04
if: |
contains(github.event.pull_request.labels.*.name, 'run-cypress-app-builder-ce') ||
contains(github.event.pull_request.labels.*.name, 'run-cypress-app-builder-ee') ||
contains(github.event.pull_request.labels.*.name, 'run-cypress') ||
contains(github.event.pull_request.labels.*.name, 'run-cypress-ce')
if: ${{ github.event.action == 'labeled' && (github.event.label.name == 'run-cypress-app-builder' || github.event.label.name == 'run-cypress') }}
strategy:
matrix:
edition: >-
${{
contains(github.event.pull_request.labels.*.name, 'run-cypress-app-builder-ce') && fromJson('["ce"]') ||
contains(github.event.pull_request.labels.*.name, 'run-cypress-ce') && fromJson('["ce"]') ||
contains(github.event.pull_request.labels.*.name, 'run-cypress-app-builder-ee') && fromJson('["ee"]') ||
contains(github.event.pull_request.labels.*.name, 'run-cypress') && fromJson('["ce", "ee"]') ||
fromJson('[]')
}}
steps:
- name: Setup Node.js
@ -22,19 +35,25 @@ jobs:
with:
node-version: 18.18.2
- name: Set up Docker
uses: docker-practice/actions-setup-docker@master
- name: Run PosgtreSQL Database Docker Container
- name: Set up Git authentication for private submodules
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
git config --global url."https://x-access-token:${{ secrets.CUSTOM_GITHUB_TOKEN }}@github.com/".insteadOf "https://github.com/"
- name: Checkout
- 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
uses: docker-practice/actions-setup-docker@master
- name: Install and build dependencies
run: |
npm cache clean --force
@ -43,49 +62,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_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: |
@ -94,6 +123,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
@ -106,115 +147,48 @@ 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"
config-file: cypress-app-builder.config.js
- name: Capture Screenshots
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
if: always()
with:
name: screenshots
name: screenshots-appbuilder-${{ matrix.edition }}
path: cypress-tests/cypress/screenshots
Cypress-App-builder-Subpath:
runs-on: ubuntu-22.04
# Cypress-App-builder-Subpath:
# runs-on: ubuntu-22.04
# if: contains(github.event.pull_request.labels.*.name, 'run-cypress') ||
# contains(github.event.pull_request.labels.*.name, 'run-cypress-app-builder-subpath')
if: ${{ github.event.action == 'labeled' && github.event.label.name == 'run-cypress-app-builder-subpath' }}
# steps:
# - name: Checkout
# uses: actions/checkout@v3
# with:
# ref: ${{ github.event.pull_request.head.ref }}
steps:
- name: Checkout
uses: actions/checkout@v3
with:
ref: ${{ github.event.pull_request.head.ref }}
# - name: Create Cypress environment file
# id: create-json
# uses: jsdaniell/create-json@1.1.2
# with:
# name: "cypress.env.json"
# json: ${{ secrets.CYPRESS_SECRETS }}
# dir: "./cypress-tests"
# 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: App Builder subpath
# uses: cypress-io/github-action@v5
# with:
# working-directory: ./cypress-tests
# config: "baseUrl=http://localhost:80/apps/tooljet/"
# config-file: cypress-app-builder.config.js
- 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
with:
name: "cypress.env.json"
json: ${{ secrets.CYPRESS_SECRETS }}
dir: "./cypress-tests"
- name: App Builder subpath
uses: cypress-io/github-action@v5
with:
working-directory: ./cypress-tests
config: "baseUrl=http://localhost:80/apps/tooljet/"
config-file: cypress-app-builder.config.js
- name: Capture Screenshots
uses: actions/upload-artifact@v3
if: always()
with:
name: screenshots
path: cypress-tests/cypress/screenshots
# - name: Capture Screenshots
# uses: actions/upload-artifact@v4
# if: always()
# with:
# name: screenshots
# path: cypress-tests/cypress/screenshots

View file

@ -2,7 +2,7 @@ name: Cypress Marketplace
on:
pull_request_target:
types: [labeled, unlabeled, closed]
types: [labeled]
workflow_dispatch:
@ -14,7 +14,21 @@ jobs:
Cypress-Marketplace:
runs-on: ubuntu-22.04
if: ${{ github.event.action == 'labeled' && (github.event.label.name == 'run-cypress-marketplace' || github.event.label.name == 'run-cypress') }}
if: contains(github.event.pull_request.labels.*.name, 'run-cypress') ||
contains(github.event.pull_request.labels.*.name, 'run-cypress-marketplace-ce') ||
contains(github.event.pull_request.labels.*.name, 'run-cypress-marketplace-ee') ||
contains(github.event.pull_request.labels.*.name, 'run-cypress-ce')
strategy:
matrix:
edition: >-
${{
contains(github.event.pull_request.labels.*.name, 'run-cypress') && fromJson('["ce", "ee"]') ||
contains(github.event.pull_request.labels.*.name, 'run-cypress-ce') && fromJson('["ce"]') ||
contains(github.event.pull_request.labels.*.name, 'run-cypress-marketplace-ce') && fromJson('["ce"]') ||
contains(github.event.pull_request.labels.*.name, 'run-cypress-marketplace-ee') && fromJson('["ee"]') ||
fromJson('[]')
}}
steps:
- name: Checkout
@ -28,7 +42,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
@ -46,13 +60,26 @@ jobs:
- name: Set SAFE_BRANCH_NAME
run: echo "SAFE_BRANCH_NAME=$(echo ${{ env.BRANCH_NAME }} | tr '/' '-')" >> $GITHUB_ENV
- name: Build and Push Docker image
- name: Build CE Docker image
uses: docker/build-push-action@v4
with:
context: .
file: docker/production.Dockerfile
file: docker/ce-production.Dockerfile
push: true
tags: tooljet/tj-osv:${{ env.SAFE_BRANCH_NAME }}
tags: tooljet/tj-osv:${{ env.SAFE_BRANCH_NAME }}-ce
platforms: linux/amd64
env:
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
- name: Build EE Docker image
if: matrix.edition == 'ee'
uses: docker/build-push-action@v4
with:
context: .
file: docker/ee/ee-production.Dockerfile
push: true
tags: tooljet/tj-osv:${{ env.SAFE_BRANCH_NAME }}-ee
platforms: linux/amd64
env:
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
@ -60,6 +87,7 @@ jobs:
- 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
@ -83,15 +111,19 @@ jobs:
echo "SSO_GOOGLE_OAUTH2_CLIENT_ID=dummy" >> .env
echo "ENABLE_MARKETPLACE_FEATURE=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: 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
# Update docker-compose.yaml with the new image
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: |
@ -104,6 +136,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
@ -114,15 +149,24 @@ 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
uses: jsdaniell/create-json@1.1.2
with:
name: "cypress.env.json"
json: ${{ secrets.CYPRESS_SECRETS }}
json: ${{ secrets.CYPRESS_SECRETS_MARKETPLACE }}
dir: "./cypress-tests"
- name: Marketplace
@ -133,17 +177,17 @@ jobs:
config-file: cypress-marketplace.config.js
- name: Capture Screenshots
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
if: always()
with:
name: screenshots
path: cypress-tests/cypress/screenshots
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
@ -233,7 +277,7 @@ jobs:
config-file: cypress-marketplace.config.js
- name: Capture Screenshots
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
if: always()
with:
name: screenshots

View file

@ -2,8 +2,7 @@ name: Cypress Platform
on:
pull_request_target:
types: [labeled, unlabeled, closed]
types: [labeled]
workflow_dispatch:
env:
@ -13,8 +12,21 @@ env:
jobs:
Cypress-Platform:
runs-on: ubuntu-22.04
if: contains(github.event.pull_request.labels.*.name, 'run-cypress') ||
contains(github.event.pull_request.labels.*.name, 'run-cypress-platform-ce') ||
contains(github.event.pull_request.labels.*.name, 'run-cypress-platform-ee') ||
contains(github.event.pull_request.labels.*.name, 'run-cypress-ce')
if: ${{ github.event.action == 'labeled' && (github.event.label.name == 'run-cypress-workspace' || github.event.label.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-cypress-ce') && fromJson('["ce"]') ||
contains(github.event.pull_request.labels.*.name, 'run-cypress-platform-ce') && fromJson('["ce"]') ||
contains(github.event.pull_request.labels.*.name, 'run-cypress-platform-ee') && fromJson('["ee"]') ||
fromJson('[]')
}}
steps:
- name: Setup Node.js
@ -22,19 +34,25 @@ jobs:
with:
node-version: 18.18.2
- name: Set up Docker
uses: docker-practice/actions-setup-docker@master
- name: Run PosgtreSQL Database Docker Container
- name: Set up Git authentication for private submodules
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
git config --global url."https://x-access-token:${{ secrets.CUSTOM_GITHUB_TOKEN }}@github.com/".insteadOf "https://github.com/"
- name: Checkout
- 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
uses: docker-practice/actions-setup-docker@master
- name: Install and build dependencies
run: |
npm cache clean --force
@ -43,67 +61,71 @@ 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_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 "ENABLE_ONBOARDING_QUESTIONS_FOR_ALL_SIGN_UPS=true" >> .env
echo "PGRST_HOST=localhost:3001" >> .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 "ENABLE_PRIVATE_APP_EMBED=true" >> .env
echo "ENABLE_MARKETPLACE_FEATURE=true" >> .env
echo "ENABLE_MARKETPLACE_DEV_MODE=true" >> .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
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: |
npm run --prefix server db:create
npm run --prefix server db:reset
npm run --prefix server db:seed
sleep 5
- 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: |
timeout 1500 bash -c '
timeout 300 bash -c '
until curl --silent --fail http://localhost:8082; do
sleep 5
done'
- name: docker logs
run: sudo docker logs postgrest
- name: Postgres logs
run: docker logs postgrest
- name: Create Cypress environment file
id: create-json
@ -113,52 +135,93 @@ jobs:
json: ${{ secrets.CYPRESS_SECRETS }}
dir: "./cypress-tests"
- name: Platform
uses: cypress-io/github-action@v5
- name: Run Cypress tests
uses: cypress-io/github-action@v6
with:
working-directory: ./cypress-tests
config: "baseUrl=http://localhost:8082"
config-file: cypress-workspace.config.js
config-file: cypress-platform.config.js
- name: Capture Screenshots
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
if: always()
with:
name: screenshots
name: screenshots-${{ matrix.edition }}
path: cypress-tests/cypress/screenshots
Cypress-Platform-subpath:
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.label.name == 'run-ce-cypress-platform-subpath' ||
github.event.label.name == 'run-ee-cypress-platform-subpath'
)
if: ${{ github.event.action == 'labeled' && github.event.label.name == 'run-cypress-workspace-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: Checkout
- name: Setup Node.js
uses: actions/setup-node@v2
with:
node-version: 18.18.2
- 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 }}
# Create Docker Buildx builder with platform configuration
- name: Set up Docker Buildx
- 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
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
echo "DOCKER_CLI_EXPERIMENTAL=enabled" >> $GITHUB_ENV
echo "SAFE_BRANCH_NAME=$(echo ${{ env.BRANCH_NAME }} | tr '/' '-')" >> $GITHUB_ENV
- name: Set DOCKER_CLI_EXPERIMENTAL
run: echo "DOCKER_CLI_EXPERIMENTAL=enabled" >> $GITHUB_ENV
- name: Docker Login
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- 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: Build and Push Docker image
uses: docker/build-push-action@v4
with:
context: .
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_HOST=http://localhost:80" >> .env
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
echo "PG_DB=tooljet_development" >> .env
@ -173,39 +236,32 @@ jobs:
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 "ENABLE_ONBOARDING_QUESTIONS_FOR_ALL_SIGN_UPS=true" >> .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 "SUB_PATH=/apps/" >> .env
echo "ENABLE_MARKETPLACE_FEATURE=true" >> .env
echo "ENABLE_MARKETPLACE_DEV_MODE=true" >> .env
echo "ENABLE_PRIVATE_APP_EMBED=true" >> .env
echo "TOOLJET_DB_STATEMENT_TIMEOUT=60000" >> .env
echo "TOOLJET_DB_RECONFIG=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
echo "PGRST_DB_PRE_CONFIG=postgrest.pre_config" >> .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
- name: Deploy with Docker Compose
run: |
timeout 1500 bash -c '
until curl --silent --fail http://localhost:80/apps/tooljet/; do
sleep 5
done'
curl -LO https://tooljet-test.s3.us-west-1.amazonaws.com/docker-compose.yaml
mkdir postgres_data
sed -i '/^[[:space:]]*tooljet:/,/^$/ s|^\([[:space:]]*image:[[:space:]]*\).*|\1tooljet/tj-osv:${{ env.SAFE_BRANCH_NAME }}|' docker-compose.yaml
curl -L "https://github.com/docker/compose/releases/download/v2.10.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
docker-compose up -d
- name: Seeding
run: docker exec Tooljet-app npm run db:seed:prod
- name: Wait for server
run: |
timeout 300 bash -c 'until curl --silent --fail http://localhost:3000/apps/; do sleep 5; done'
- name: Create Cypress environment file
id: create-json
@ -215,16 +271,313 @@ jobs:
json: ${{ secrets.CYPRESS_SECRETS_SUBPATH }}
dir: "./cypress-tests"
- name: Platform-subpath
uses: cypress-io/github-action@v5
- name: Run Cypress tests
uses: cypress-io/github-action@v6
with:
working-directory: ./cypress-tests
config: "baseUrl=http://localhost:80/apps/tooljet/"
config-file: cypress-workspace.config.js
config: "baseUrl=http://localhost:3000/apps"
config-file: cypress-platform.config.js
- name: Capture Screenshots
uses: actions/upload-artifact@v3
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.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
uses: actions/setup-node@v2
with:
node-version: 18.18.2
- 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
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
echo "DOCKER_CLI_EXPERIMENTAL=enabled" >> $GITHUB_ENV
echo "SAFE_BRANCH_NAME=$(echo ${{ env.BRANCH_NAME }} | tr '/' '-')" >> $GITHUB_ENV
- name: Docker Login
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build and Push Docker image
uses: docker/build-push-action@v4
with:
context: .
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
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 "NODE_ENV=production" >> .env
echo "SERVE_CLIENT=true" >> .env
echo "ENABLE_MARKETPLACE_FEATURE=true" >> .env
echo "ENABLE_MARKETPLACE_DEV_MODE=true" >> .env
echo "ENABLE_PRIVATE_APP_EMBED=true" >> .env
echo "TOOLJET_DB_STATEMENT_TIMEOUT=60000" >> .env
echo "TOOLJET_DB_RECONFIG=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
echo "PGRST_DB_PRE_CONFIG=postgrest.pre_config" >> .env
- name: Deploy with Docker Compose
run: |
curl -LO https://tooljet-test.s3.us-west-1.amazonaws.com/docker-compose.yaml
mkdir postgres_data
sed -i '/^[[:space:]]*tooljet:/,/^$/ s|^\([[:space:]]*image:[[:space:]]*\).*|\1tooljet/tj-osv:${{ env.SAFE_BRANCH_NAME }}|' docker-compose.yaml
curl -L "https://github.com/docker/compose/releases/download/v2.10.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
docker-compose up -d
- name: Setup Nginx
run: |
sudo apt update
sudo apt install -y nginx
sudo systemctl stop apache2 || true
sudo apt remove apache2 -y || true
sudo cp cypress-tests/proxy.nginx /etc/nginx/sites-available/nginx-config
sudo ln -sf /etc/nginx/sites-available/nginx-config /etc/nginx/sites-enabled/nginx-config
sudo nginx -t
sudo systemctl start nginx
sudo systemctl reload nginx
sudo netstat -tulpn | grep 4001
- name: Wait for server
run: |
timeout 300 bash -c 'until curl --silent --fail http://localhost:4001/; do sleep 5; done'
- name: Create Cypress environment file
id: create-json
uses: jsdaniell/create-json@1.1.2
with:
name: "cypress.env.json"
json: ${{ secrets.CYPRESS_SECRETS_PROXY }}
dir: "./cypress-tests"
- name: Run Cypress tests
uses: cypress-io/github-action@v6
with:
working-directory: ./cypress-tests
config: "baseUrl=http://localhost:4001"
config-file: cypress-platform.config.js
- name: Capture Screenshots
uses: actions/upload-artifact@v4
if: always()
with:
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.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
uses: actions/setup-node@v2
with:
node-version: 18.18.2
- 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
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
echo "DOCKER_CLI_EXPERIMENTAL=enabled" >> $GITHUB_ENV
echo "SAFE_BRANCH_NAME=$(echo ${{ env.BRANCH_NAME }} | tr '/' '-')" >> $GITHUB_ENV
- name: Docker Login
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build and Push Docker image
uses: docker/build-push-action@v4
with:
context: .
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
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 "NODE_ENV=production" >> .env
echo "SERVE_CLIENT=true" >> .env
echo "SUB_PATH=/apps/" >> .env
echo "ENABLE_MARKETPLACE_FEATURE=true" >> .env
echo "ENABLE_MARKETPLACE_DEV_MODE=true" >> .env
echo "ENABLE_PRIVATE_APP_EMBED=true" >> .env
echo "TOOLJET_DB_STATEMENT_TIMEOUT=60000" >> .env
echo "TOOLJET_DB_RECONFIG=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
echo "PGRST_DB_PRE_CONFIG=postgrest.pre_config" >> .env
- name: Deploy with Docker Compose
run: |
curl -LO https://tooljet-test.s3.us-west-1.amazonaws.com/docker-compose.yaml
mkdir postgres_data
sed -i '/^[[:space:]]*tooljet:/,/^$/ s|^\([[:space:]]*image:[[:space:]]*\).*|\1tooljet/tj-osv:${{ env.SAFE_BRANCH_NAME }}|' docker-compose.yaml
curl -L "https://github.com/docker/compose/releases/download/v2.10.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
docker-compose up -d
- name: Setup Nginx
run: |
sudo apt update
sudo apt install -y nginx
sudo systemctl stop apache2 || true
sudo apt remove apache2 -y || true
sudo cp cypress-tests/subpath.nginx /etc/nginx/sites-available/nginx-config
sudo ln -sf /etc/nginx/sites-available/nginx-config /etc/nginx/sites-enabled/nginx-config
sudo nginx -t
sudo systemctl start nginx
sudo systemctl reload nginx
sudo netstat -tulpn | grep 4001
- name: Wait for server
run: |
timeout 300 bash -c 'until curl --silent --fail http://localhost:4001/apps/; do sleep 5; done'
- name: Create Cypress environment file
id: create-json
uses: jsdaniell/create-json@1.1.2
with:
name: "cypress.env.json"
json: ${{ secrets.CYPRESS_SECRETS_PROXY_SUBPATH }}
dir: "./cypress-tests"
- name: Run Cypress tests
uses: cypress-io/github-action@v6
with:
working-directory: ./cypress-tests
config: "baseUrl=http://localhost:4001/apps"
config-file: cypress-platform.config.js
- name: Capture Screenshots
uses: actions/upload-artifact@v4
if: always()
with:
name: screenshots-${{ matrix.edition }}
path: cypress-tests/cypress/screenshots

View file

@ -1,39 +0,0 @@
name: Documentation version release
on:
workflow_dispatch:
inputs:
create-branch:
description: "Branch name"
version:
description: "RELEASE_VERSION"
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Setup node 16.14
uses: actions/setup-node@v2
with:
node-version: 16.14
- run: cd docs && yarn install && npm run docusaurus docs:version ${{ github.event.inputs.version }}
- name: Create Pull Request
id: doc
uses: peter-evans/create-pull-request@v5
with:
title: "Creating a new version folder ${{ github.event.version }}"
body: "Created a new version folder for version: ${{ github.event.inputs.version }}"
branch: ${{ github.event.inputs.create-branch }}
base: "develop"
token: ${{ secrets.GITHUB }}
delete-branch : true
labels: versioned-docs, automated pr
commit-message: added new version folder

326
.github/workflows/docker-release.yml vendored Normal file
View file

@ -0,0 +1,326 @@
name: ToolJet Edition docker images builds
on:
release:
types: [published]
jobs:
build-tooljet-image-for-ce-edtion:
runs-on: ubuntu-latest
if: "${{ github.event.release }}"
steps:
- name: Checkout code to main for pre-release CE edition
if: "!contains(github.event.release.tag_name, 'ce-lts')"
uses: actions/checkout@v2
with:
ref: refs/heads/main
- name: Checkout code to LTS for CE LTS edition
if: "contains(github.event.release.tag_name, '-ce-lts')"
uses: actions/checkout@v2
with:
ref: refs/heads/lts-4.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@v2
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build and Push Docker image for pre-release tag
if: "!contains(github.event.release.tag_name, '-ce-lts')"
uses: docker/build-push-action@v4
with:
context: .
file: docker/ce-production.Dockerfile
push: true
tags: tooljet/tooljet-ce:${{ github.event.release.tag_name }},tooljet/tooljet-ce:ce-latest
platforms: linux/amd64
env:
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
- name: Build and Push Docker image for LTS tag
if: "contains(github.event.release.tag_name, '-ce-lts')"
uses: docker/build-push-action@v4
with:
context: .
file: docker/ce-production.Dockerfile
push: true
tags: tooljet/tooljet-ce:${{ github.event.release.tag_name }},tooljet/tooljet-ce:ce-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="ToolJet community image published:\n\`tooljet/tooljet-ce:${{ github.event.release.tag_name }}\`"
else
message="Job '${{ env.JOB_NAME }}' failed! tooljet/tooljet-ce:${{ github.event.release.tag_name }}"
fi
curl -X POST -H 'Content-type: application/json' --data "{\"text\":\"$message\"}" ${{ secrets.SLACK_WEBHOOK_URL }}
- name: Send Slack Notification
run: |
if [[ "${{ job.status }}" == "success" ]]; then
message="ToolJet community image published:\n\`tooljet/tooljet-ce:${{ github.event.release.tag_name }}\`"
else
message="Job '${{ env.JOB_NAME }}' failed! tooljet/tooljet-ce:${{ github.event.release.tag_name }}"
fi
curl -X POST -H 'Content-type: application/json' --data "{\"text\":\"$message\"}" ${{ secrets.SLACK_WEBHOOK_URL }}
build-tooljet-image-for-ee-edtion:
runs-on: ubuntu-latest
if: "${{ github.event.release }}"
steps:
- name: Checkout code to main for pre-release EE edition
if: "!contains(github.event.release.tag_name, 'ee-lts')"
uses: actions/checkout@v2
with:
ref: refs/heads/main
- name: Checkout code to LTS for EE LTS edition
if: "contains(github.event.release.tag_name, '-ee-lts')"
uses: actions/checkout@v2
with:
ref: refs/heads/lts-4.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@v2
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build and Push Docker image for pre-release tag
if: "!contains(github.event.release.tag_name, '-ee-lts')"
uses: docker/build-push-action@v4
with:
context: .
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
env:
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
- name: Build and Push Docker image for LTS tag
if: "contains(github.event.release.tag_name, '-ee-lts')"
uses: docker/build-push-action@v4
with:
context: .
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
env:
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
- name: Send Slack Notification
run: |
if [[ "${{ job.status }}" == "success" ]]; then
message="ToolJet enterprise image published:\n\`tooljet/tooljet-ee:${{ github.event.release.tag_name }}\`\n\`tooljet/tooljet:${{ github.event.release.tag_name }}\`"
else
message="Job '${{ env.JOB_NAME }}' failed! Image built:\n\`tooljet/tooljet-ee:${{ github.event.release.tag_name }}\`\n\`tooljet/tooljet:${{ github.event.release.tag_name }}\`"
fi
curl -X POST -H 'Content-type: application/json' --data "{\"text\":\"$message\"}" ${{ secrets.SLACK_WEBHOOK_URL }}
# commented out for now, since cloud modularisation is not yet ready
# build-tooljet-image-for-cloud-edtion:
# runs-on: ubuntu-latest
# if: "${{ github.event.release }}"
# steps:
# - name: Checkout code to LTS for Cloud LTS edition
# if: "contains(github.event.release.tag_name, '-cloud-lts')"
# uses: actions/checkout@v2
# with:
# ref: refs/heads/lts-4.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@v2
# with:
# username: ${{ secrets.DOCKER_USERNAME }}
# password: ${{ secrets.DOCKER_PASSWORD }}
# - name: Build and Push Docker image for LTS tag
# if: "contains(github.event.release.tag_name, '-cloud-lts')"
# uses: docker/build-push-action@v4
# with:
# context: .
# args: ${{ secrets.CUSTOM_GITHUB_TOKEN }}
# file: docker/cloud/cloud-server.Dockerfile
# push: true
# tags: tooljet/saas:${{ github.event.release.tag_name }}
# 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="ToolJet cloud image published:\n\`tooljet/saas:${{ github.event.release.tag_name }}\`"
# else
# message="Job '${{ env.JOB_NAME }}' failed! Image built:\n\`tooljet/saas:${{ github.event.release.tag_name }}\`"
# 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 }}

37
.github/workflows/docs-netlify.yml vendored Normal file
View file

@ -0,0 +1,37 @@
name: Deploy to Netlify
on:
workflow_dispatch:
push:
branches:
- develop
paths:
- docs/**
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Setup Node.js
uses: actions/setup-node@v2
with:
node-version: 18.18.2
- name: Install dependencies
run: npm install
working-directory: docs
- name: Build the project
run: GTM=${{ secrets.GTM }} ALGOLIA_API_KEY=${{ secrets.ALGOLIA_API_KEY }} npm run build
working-directory: docs
- name: Deploy to Netlify
run: |
npm install -g netlify-cli
netlify deploy --prod --dir=docs/build --auth=$NETLIFY_AUTH_TOKEN --site=${{ secrets.NETLIFY_SITE_ID }}
env:
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}

View file

@ -53,7 +53,7 @@ jobs:
],
"serviceDetails": {
"pullRequestPreviewsEnabled": "no",
"buildCommand": "bash build-latest-version.sh",
"buildCommand": "npm i && npm run build",
"publishPath": "build/",
"url": "https://tooljet-pr-${{ env.PR_NUMBER }}.onrender.com"
}

View file

@ -1,16 +0,0 @@
name: Deploy docs to Netlify
on:
workflow_dispatch:
push:
branches:
- develop
paths:
- docs/**
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Trigger hook to deploy docs on Netlify
run: curl -X POST -d {} ${{ secrets.NETLIFY_HOOK }}

View file

@ -11,13 +11,16 @@ on:
description: "RELEASE_VERSION"
jobs:
packer:
packer-ee:
runs-on: ubuntu-latest
name: packer
name: packer-ee
steps:
- name: Checkout Repository
uses: actions/checkout@v3
- name: Checkout code to lts-4.0
if: contains(github.event.release.tag_name, '-ee-lts')
uses: actions/checkout@v2
with:
ref: refs/heads/lts-4.0
- name: Setting tag
if: "${{ github.event.inputs.version != '' }}"
@ -28,7 +31,7 @@ jobs:
run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v2
uses: aws-actions/configure-aws-credentials@v1-node16
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
@ -40,7 +43,7 @@ jobs:
with:
command: init
target: .
working_directory: deploy/ec2
working_directory: deploy/ec2/ee
# validate templates
- name: Validate Template
@ -49,25 +52,35 @@ jobs:
command: validate
arguments: -syntax-only
target: .
working_directory: deploy/ec2
working_directory: deploy/ec2/ee
# Echo RENDER_GITHUB_PAT
- name: Set PACKER_GITHUB_PAT
run: echo "PACKER_GITHUB_PAT=${{ secrets.PACKER_GITHUB_PAT}}" >> $GITHUB_ENV
# Dynamically update setup_machine.sh with PAT
- name: Validate PAT
run: |
sed -i "s|git config --global url."https://x-access-token:CUSTOM_GITHUB_TOKEN@github.com/".insteadOf "https://github.com/"|git config --global url."https://x-access-token:${ secrets.CUSTOM_GITHUB_TOKEN }@github.com/".insteadOf "https://github.com/"|g" ./deploy/ec2/ee/setup_machine.sh
# build artifact
- name: Build Artifact
uses: hashicorp/packer-github-actions@master
with:
command: build
#The the below argument is specific for building EE AMI image
arguments: -color=false -on-error=abort -var ami_name=tooljet_${{ env.RELEASE_VERSION }}.ubuntu_focal
target: .
working_directory: deploy/ec2
working_directory: deploy/ec2/ee
env:
PACKER_LOG: 1
- name: Send Slack Notification
run: |
if [[ "${{ job.status }}" == "success" ]]; then
message="Job '${{ env.JOB_NAME }}' succeeded! AMI = tooljet_${{ env.RELEASE_VERSION }}.ubuntu_focal"
message="ToolJet enterprise AWS AMI published:\\n\`tooljet_${{ env.RELEASE_VERSION }}.ubuntu_focal\`"
else
message="Job '${{ env.JOB_NAME }}' failed! AMI = tooljet_${{ env.RELEASE_VERSION }}.ubuntu_focal"
message="ToolJet enterprise AWS AMI release failed! \\n\`tooljet_${{ env.RELEASE_VERSION }}.ubuntu_focal\`"
fi
curl -X POST -H 'Content-type: application/json' --data "{\"text\":\"$message\"}" ${{ secrets.SLACK_WEBHOOK_URL }}
curl -X POST -H 'Content-type: application/json' --data "{\"text\":\"$message\"}" ${{ secrets.SLACK_WEBHOOK_URL }}

File diff suppressed because it is too large Load diff

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

@ -1,65 +0,0 @@
name: Tooljet develop docker image build
on:
push:
branches:
- develop
workflow_dispatch:
inputs:
job-to-run:
description: Enter the job name (tooljet-develop-image)
options: ["tooljet-develop-image"]
required: true
jobs:
tooljet-develop-image:
runs-on: ubuntu-latest
if: |
${{ github.ref == 'refs/heads/develop' }} &&
${{ github.event_name == 'workflow_dispatch' && github.event.inputs.job-to-run == 'tooljet-develop-image' }}
steps:
- name: Checkout code
uses: actions/checkout@v2
with:
ref: refs/heads/develop
# 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@v2
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build and Push Docker image
uses: docker/build-push-action@v4
with:
context: .
file: docker/production.Dockerfile
push: true
tags: tooljet/tooljet-ce:develop
platforms: linux/amd64
env:
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
- name: Send Slack Notification on Failure
if: failure()
run: |
message="Job '${{ env.JOB_NAME }}' failed! tooljet/tooljet-ce:develop"
curl -X POST -H 'Content-type: application/json' --data "{\"text\":\"$message\"}" ${{ secrets.SLACK_WEBHOOK_URL_OPS_CHANNEL }}

View file

@ -1,217 +0,0 @@
name: Tooljet release docker images build
on:
release:
types: [published]
workflow_dispatch:
inputs:
job-to-run:
description: Enter the job name (tooljet-ce)
options: ["tooljet-ce"]
required: true
image:
description: "Enter the latest image tag"
required: true
jobs:
build-tooljet-ce-image:
runs-on: ubuntu-latest
if: "${{ github.event.release }}"
steps:
- name: Checkout code to main
if: "!contains(github.event.release.tag_name, 'ce-lts')"
uses: actions/checkout@v2
with:
ref: refs/heads/main
- name: Checkout code to LTS-2.50
if: "contains(github.event.release.tag_name, '2.50')"
uses: actions/checkout@v2
with:
ref: refs/heads/lts-2.50
- name: Checkout code to LTS-3.0
if: "contains(github.event.release.tag_name, '-ce-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@v2
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build and Push Docker image for beta tag
if: "!contains(github.event.release.tag_name, '-ce-lts')"
uses: docker/build-push-action@v4
with:
context: .
file: docker/production.Dockerfile
push: true
tags: tooljet/tooljet-ce:${{ github.event.release.tag_name }},tooljet/tooljet-ce:ce-latest
platforms: linux/amd64
env:
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
- name: Build and Push Docker image for LTS 2.50 tag
if: "contains(github.event.release.tag_name, '2.50')"
uses: docker/build-push-action@v4
with:
context: .
file: docker/production.Dockerfile
push: true
tags: tooljet/tooljet-ce:${{ github.event.release.tag_name }}
platforms: linux/amd64
env:
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
- name: Build and Push Docker image for LTS 3.0 tag
if: "contains(github.event.release.tag_name, '-ce-lts')"
uses: docker/build-push-action@v4
with:
context: .
file: docker/production.Dockerfile
push: true
tags: tooljet/tooljet-ce:${{ github.event.release.tag_name }},tooljet/tooljet-ce:ce-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="ToolJet community image published:\n\`tooljet/tooljet-ce:${{ github.event.release.tag_name }}\`"
else
message="Job '${{ env.JOB_NAME }}' failed! tooljet/tooljet-ce:${{ github.event.release.tag_name }}"
fi
curl -X POST -H 'Content-type: application/json' --data "{\"text\":\"$message\"}" ${{ secrets.SLACK_WEBHOOK_URL }}
# #Below code helps to trigger the workflow separately
tooljet-ce:
runs-on: ubuntu-latest
if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.job-to-run == 'tooljet-ce' }}
steps:
- name: Checkout code
uses: actions/checkout@v2
with:
ref: main
# 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@v2
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build and Push Docker image
if: "!contains(github.event.release.tag_name, 'CE-LTS')"
uses: docker/build-push-action@v4
with:
context: .
file: docker/production.Dockerfile
push: true
tags: tooljet/tooljet-ce:${{ github.event.inputs.image }},tooljet/tooljet-ce:latest
platforms: linux/amd64
env:
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
- name: Build and Push Docker image
if: "contains(github.event.release.tag_name, 'CE-LTS')"
uses: docker/build-push-action@v4
with:
context: .
file: docker/production.Dockerfile
push: true
tags: tooljet/tooljet-ce:${{ github.event.inputs.image }},tooljet/tooljet-ce:CE-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="ToolJet community image published:\n\`tooljet/tooljet-ce:${{ github.event.inputs.image }}\`"
else
message="Job '${{ env.JOB_NAME }}' failed! tooljet/tooljet-ce:${{ github.event.inputs.image }}"
fi
curl -X POST -H 'Content-type: application/json' --data "{\"text\":\"$message\"}" ${{ secrets.SLACK_WEBHOOK_URL }}
update-lts-machine:
runs-on: ubuntu-latest
needs: build-tooljet-ce-image
if: "contains(github.event.release.tag_name, 'CE-LTS')"
steps:
- name: SSH into GCP VM instance
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.GCP_CE_LTS_INSTANCE_IP }}
username: ${{ secrets.GCP_USERNAME }}
key: ${{ secrets.EC2_INSTANCE_SSH_KEY }}
script: |
ls -lah
# Stop the Docker containers
sudo docker-compose down
# Check remaining images
sudo docker images
# Remove the existing tooljet/* images
sudo docker images -a | grep 'tooljet/' | awk '{print $3}' | xargs sudo docker rmi -f
# Check remaining images
sudo docker images
# Update docker-compose.yml with the new image for tooljet service
sed -i '/^[[:space:]]*tooljet:/,/^[[:space:]]*[^[:space:]]/ { /^[[:space:]]*image:/s|image:.*|image: tooljet/tooljet-ce:'"${{ github.event.release.tag_name }}"'| }' docker-compose.yml
# check the updated docker-compose.yml file
cat docker-compose.yml
# Start the Docker containers
sudo docker-compose up -d
#View containers
sudo docker ps

View file

@ -1,40 +0,0 @@
name: LTS Test system deploy
on:
workflow_run:
workflows: ["Tooljet release docker images build"]
types:
- completed
jobs:
Build-and-update-image:
runs-on: ubuntu-22.04
steps:
- name: SSH into GCP VM instance
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.EC2_INSTANCE_IP }}
username: ${{ secrets.GCP_USERNAME }}
key: ${{ secrets.EC2_INSTANCE_SSH_KEY }}
script: |
ls -lah
# Stop the Docker containers
sudo docker-compose down
# Remove the existing tooljet/* images
sudo docker images -a | grep 'tooljet/' | awk '{print $3}' | xargs sudo docker rmi -f
# Check remaining images
sudo docker images
# Update docker-compose.yml with the new image for tooljet service
sed -i '/^[[:space:]]*tooljet:/,/^[[:space:]]*[^:]*$/ { /^[[:space:]]*image:[[:space:]]*tooljet\/tj-osv/s|\(image:[[:space:]]*\).*|\1tooljet/tj-osv:'"${{ env.SAFE_BRANCH_NAME }}"'| }' docker-compose.yaml
# Start the Docker containers
cat docker-compose.yaml
sudo docker-compose up -d
#View containers
sudo docker ps

View file

@ -1,132 +0,0 @@
name: Test system deploy
on:
pull_request_target:
types: [labeled, unlabeled, closed]
workflow_dispatch:
env:
PR_NUMBER: ${{ github.event.number }}
BRANCH_NAME: ${{ github.head_ref || github.ref_name }}
jobs:
Build-and-update-image:
runs-on: ubuntu-22.04
if: ${{ github.event.action == 'labeled' && github.event.label.name == 'test-system-deploy' }}
steps:
- name: Check authorization
run: |
allowed_user1=${{ secrets.ALLOWED_USER1_USERNAME }}
allowed_user2=${{ secrets.ALLOWED_USER2_USERNAME }}
allowed_user3=${{ secrets.ALLOWED_USER3_USERNAME }}
allowed_user4=${{ secrets.ALLOWED_USER4_USERNAME }}
allowed_user5=${{ secrets.ALLOWED_USER5_USERNAME }}
allowed_user6=${{ secrets.ALLOWED_USER6_USERNAME }}
allowed_user6=${{ secrets.ALLOWED_USER7_USERNAME }}
if [[ "${{ github.actor }}" != "$allowed_user1" && \
"${{ github.actor }}" != "$allowed_user2" && \
"${{ github.actor }}" != "$allowed_user3" && \
"${{ github.actor }}" != "$allowed_user4" && \
"${{ github.actor }}" != "$allowed_user5" && \
"${{ github.actor }}" != "$allowed_user6" && \
"${{ github.actor }}" != "$allowed_user7" ]]; then
echo "User not authorized to trigger this workflow"
exit 1
fi
- name: Checkout
uses: actions/checkout@v3
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: Docker Login
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Set SAFE_BRANCH_NAME
run: echo "SAFE_BRANCH_NAME=$(echo ${{ env.BRANCH_NAME }} | tr '/' '-')" >> $GITHUB_ENV
- name: Build and Push Docker image
uses: docker/build-push-action@v4
with:
context: .
file: docker/production.Dockerfile
push: true
tags: tooljet/tj-osv:${{ env.SAFE_BRANCH_NAME }}
platforms: linux/amd64
env:
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
- name: SSH into GCP VM instance
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.EC2_INSTANCE_IP }}
username: ${{ secrets.GCP_USERNAME }}
key: ${{ secrets.EC2_INSTANCE_SSH_KEY }}
script: |
ls -lah
# Stop the Docker containers
sudo docker-compose down
# Remove the existing tooljet/* images
sudo docker images -a | grep 'tooljet/' | awk '{print $3}' | xargs sudo docker rmi -f
# Check remaining images
sudo docker images
# Update docker-compose.yml with the new image for tooljet service
sed -i '/^[[:space:]]*tooljet:/,/^[[:space:]]*[^:]*$/ { /^[[:space:]]*image:[[:space:]]*tooljet\/tj-osv/s|\(image:[[:space:]]*\).*|\1tooljet/tj-osv:'"${{ env.SAFE_BRANCH_NAME }}"'| }' docker-compose.yaml
# Start the Docker containers
cat docker-compose.yaml
sudo docker-compose up -d
#View containers
sudo docker ps
- uses: actions/github-script@v6
with:
script: |
try {
await github.rest.issues.removeLabel({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
name: 'test-system-deploy'
})
} catch (e) {
console.log(e)
}
await github.rest.issues.addLabels({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
labels: ['test-system-deployed']
})

651
.github/workflows/vulnerability-ci.yml vendored Normal file
View file

@ -0,0 +1,651 @@
name: Vulnerability CI
# Controls when the workflow will run
on:
pull_request:
types: [labeled, unlabeled, closed]
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
# Schedule the workflow to run every two weeks once
schedule:
- cron: '30 5 * * 1'
jobs:
PeriodicVulnerability-CheckOn-frontend-code:
if: github.event_name == 'schedule'
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
with:
ref: refs/heads/main
- name: Use Node.js 18.18.2
uses: actions/setup-node@v3
with:
node-version: 18.18.2
- name: Install dependencies
run: npm --prefix frontend install
- name: Running security audit
run: npm --prefix server audit --json > Periodic-frontend-audit.json
continue-on-error: true
- name: Parse audit summary
id: parse-audit
run: |
vulnerabilities=$(jq '.metadata.vulnerabilities' Periodic-frontend-audit.json)
moderate=$(echo $vulnerabilities | jq '.moderate')
high=$(echo $vulnerabilities | jq '.high')
critical=$(echo $vulnerabilities | jq '.critical')
echo "::set-output name=moderate::$moderate"
echo "::set-output name=high::$high"
echo "::set-output name=critical::$critical"
- name: Upload audit report
uses: actions/upload-artifact@v4
with:
name: Periodic-frontend-audit-report
path: Periodic-frontend-audit.json
- name: Send Slack Notification
run: |
message="Periodic Security Audit Report Of Frontend directory\n
Node module vulnerabilities summary:\n
🔴 Critical: ${{ steps.parse-audit.outputs.critical }}\n
🟠 High: ${{ steps.parse-audit.outputs.high }}\n
🟡 Moderate: ${{ steps.parse-audit.outputs.moderate }}\n
\nDownload Audit Report: http://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}"
curl -X POST -H 'Content-type: application/json' --data "{\"text\":\"$message\"}" ${{ secrets.SLACK_WEBHOOK_URL_VUR }}
PeriodicVulnerability-CheckOn-server-code:
if: github.event_name == 'schedule'
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
with:
ref: refs/heads/main
- name: Use Node.js 18.18.2
uses: actions/setup-node@v3
with:
node-version: 18.18.2
- name: Install dependencies
run: npm --prefix server install
- name: Running security audit
run: npm --prefix server audit --json > Periodic-server-audit.json
continue-on-error: true
- name: Parse audit summary
id: parse-audit
run: |
vulnerabilities=$(jq '.metadata.vulnerabilities' Periodic-server-audit.json)
moderate=$(echo $vulnerabilities | jq '.moderate')
high=$(echo $vulnerabilities | jq '.high')
critical=$(echo $vulnerabilities | jq '.critical')
echo "::set-output name=moderate::$moderate"
echo "::set-output name=high::$high"
echo "::set-output name=critical::$critical"
- name: Upload audit report
uses: actions/upload-artifact@v4
with:
name: Periodic-server-audit-report
path: Periodic-server-audit.json
- name: Send Slack Notification
run: |
message="### Periodic Security Audit Report Of Server directory\n
Node module vulnerabilities summary:\n
🔴 Critical: ${{ steps.parse-audit.outputs.critical }}\n
🟠 High: ${{ steps.parse-audit.outputs.high }}\n
🟡 Moderate: ${{ steps.parse-audit.outputs.moderate }}\n
\nDownload Audit Report: http://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}"
curl -X POST -H 'Content-type: application/json' --data "{\"text\":\"$message\"}" ${{ secrets.SLACK_WEBHOOK_URL_VUR }}
PeriodicVulnerability-CheckOn-marketplace-code:
if: github.event_name == 'schedule'
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
with:
ref: refs/heads/main
- name: Use Node.js 18.18.2
uses: actions/setup-node@v3
with:
node-version: 18.18.2
- name: Install dependencies
run: npm --prefix marketplace install
- name: Running security audit
run: npm --prefix marketplace audit --json > Periodic-marketplace-audit.json
continue-on-error: true
- name: Parse audit summary
id: parse-audit
run: |
vulnerabilities=$(jq '.metadata.vulnerabilities' Periodic-marketplace-audit.json)
moderate=$(echo $vulnerabilities | jq '.moderate')
high=$(echo $vulnerabilities | jq '.high')
critical=$(echo $vulnerabilities | jq '.critical')
echo "::set-output name=moderate::$moderate"
echo "::set-output name=high::$high"
echo "::set-output name=critical::$critical"
- name: Upload audit report
uses: actions/upload-artifact@v4
with:
name: Periodic-marketplace-audit-report
path: Periodic-marketplace-audit.json
- name: Send Slack Notification
run: |
message="Periodic Security Audit Report Of Marketplace directory\n
Node module vulnerabilities summary:\n
🔴 Critical: ${{ steps.parse-audit.outputs.critical }}\n
🟠 High: ${{ steps.parse-audit.outputs.high }}\n
🟡 Moderate: ${{ steps.parse-audit.outputs.moderate }}\n
\nDownload Audit Report: http://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}"
curl -X POST -H 'Content-type: application/json' --data "{\"text\":\"$message\"}" ${{ secrets.SLACK_WEBHOOK_URL_VUR }}
PeriodicVulnerability-CheckOn-plugins-code:
if: github.event_name == 'schedule'
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
with:
ref: refs/heads/main
- name: Use Node.js 18.18.2
uses: actions/setup-node@v3
with:
node-version: 18.18.2
- name: Install dependencies
run: npm --prefix plugins install
- name: Running security audit
run: npm --prefix plugins audit --json > Periodic-plugins-audit.json
continue-on-error: true
- name: Parse audit summary
id: parse-audit
run: |
vulnerabilities=$(jq '.metadata.vulnerabilities' Periodic-plugins-audit.json)
moderate=$(echo $vulnerabilities | jq '.moderate')
high=$(echo $vulnerabilities | jq '.high')
critical=$(echo $vulnerabilities | jq '.critical')
echo "::set-output name=moderate::$moderate"
echo "::set-output name=high::$high"
echo "::set-output name=critical::$critical"
- name: Upload audit report
uses: actions/upload-artifact@v4
with:
name: Periodic-plugins-audit-report
path: Periodic-plugins-audit.json
- name: Send Slack Notification
run: |
message="Periodic Security Audit Report Of Plugins directory\n
Node module vulnerabilities summary:\n
🔴 Critical: ${{ steps.parse-audit.outputs.critical }}\n
🟠 High: ${{ steps.parse-audit.outputs.high }}\n
🟡 Moderate: ${{ steps.parse-audit.outputs.moderate }}\n
\nDownload Audit Report: http://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}"
curl -X POST -H 'Content-type: application/json' --data "{\"text\":\"$message\"}" ${{ secrets.SLACK_WEBHOOK_URL_VUR }}
PeriodicVulnerability-CheckOn-cypress-code:
if: github.event_name == 'schedule'
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
with:
ref: refs/heads/main
- name: Use Node.js 18.18.2
uses: actions/setup-node@v3
with:
node-version: 18.18.2
- name: Install dependencies
run: npm --prefix cypress-tests install
- name: Running security audit
run: npm --prefix cypress-tests audit --json > Periodic-cypress-audit.json
continue-on-error: true
- name: Parse audit summary
id: parse-audit
run: |
vulnerabilities=$(jq '.metadata.vulnerabilities' Periodic-cypress-audit.json)
moderate=$(echo $vulnerabilities | jq '.moderate')
high=$(echo $vulnerabilities | jq '.high')
critical=$(echo $vulnerabilities | jq '.critical')
echo "::set-output name=moderate::$moderate"
echo "::set-output name=high::$high"
echo "::set-output name=critical::$critical"
- name: Upload audit report
uses: actions/upload-artifact@v4
with:
name: Periodic-cypress-audit-report
path: Periodic-cypress-audit.json
- name: Send Slack Notification
run: |
message="Periodic Security Audit Report Of Cypress directory\n
Node module vulnerabilities summary:\n
🔴 Critical: ${{ steps.parse-audit.outputs.critical }}\n
🟠 High: ${{ steps.parse-audit.outputs.high }}\n
🟡 Moderate: ${{ steps.parse-audit.outputs.moderate }}\n
\nDownload Audit Report: http://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}"
curl -X POST -H 'Content-type: application/json' --data "{\"text\":\"$message\"}" ${{ secrets.SLACK_WEBHOOK_URL_VUR }}
PeriodicVulnerability-CheckOn-root-code:
if: github.event_name == 'schedule'
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
with:
ref: refs/heads/main
- name: Use Node.js 18.18.2
uses: actions/setup-node@v3
with:
node-version: 18.18.2
- name: Install dependencies
run: npm install
- name: Running security audit
run: npm audit --json > Periodic-root-audit.json
continue-on-error: true
- name: Parse audit summary
id: parse-audit
run: |
vulnerabilities=$(jq '.metadata.vulnerabilities' Periodic-root-audit.json)
moderate=$(echo $vulnerabilities | jq '.moderate')
high=$(echo $vulnerabilities | jq '.high')
critical=$(echo $vulnerabilities | jq '.critical')
echo "::set-output name=moderate::$moderate"
echo "::set-output name=high::$high"
echo "::set-output name=critical::$critical"
- name: Upload audit report
uses: actions/upload-artifact@v4
with:
name: Periodic-root-audit-report
path: Periodic-root-audit.json
- name: Send Slack Notification
run: |
message="Periodic Security Audit Report Of Root directory\n
Node module vulnerabilities summary:\n
🔴 Critical: ${{ steps.parse-audit.outputs.critical }}\n
🟠 High: ${{ steps.parse-audit.outputs.high }}\n
🟡 Moderate: ${{ steps.parse-audit.outputs.moderate }}\n
\nDownload Audit Report: http://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}"
curl -X POST -H 'Content-type: application/json' --data "{\"text\":\"$message\"}" ${{ secrets.SLACK_WEBHOOK_URL_VUR }}
ManualVulnerability-CheckOn-frontend-code:
if: ${{ github.event.action == 'labeled' && (github.event.label.name == 'frontend-vulnerability' || github.event.label.name == 'check-vulnerability') }}
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
with:
ref: ${{ github.event.pull_request.head.ref }}
- name: Use Node.js 18.18.2
uses: actions/setup-node@v3
with:
node-version: 18.18.2
- name: Install dependencies
run: npm --prefix frontend install
- name: Running security audit
run: npm --prefix frontend audit --json > frontend-audit.json
continue-on-error: true
- name: Parse audit summary
id: parse-audit
run: |
vulnerabilities=$(jq '.metadata.vulnerabilities' frontend-audit.json)
moderate=$(echo $vulnerabilities | jq '.moderate')
high=$(echo $vulnerabilities | jq '.high')
critical=$(echo $vulnerabilities | jq '.critical')
echo "::set-output name=moderate::$moderate"
echo "::set-output name=high::$high"
echo "::set-output name=critical::$critical"
- name: Upload audit report
uses: actions/upload-artifact@v4
with:
name: frontend-audit-report
path: frontend-audit.json
- name: Create or update PR comment
uses: peter-evans/create-or-update-comment@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
repository: ${{ github.repository }}
issue-number: ${{ github.event.pull_request.number }}
body: |
### Security Audit Report Of Frontend directory
**Node module vulnerabilities summary:**
🔴 Critical: ${{ steps.parse-audit.outputs.critical }}
🟠 High: ${{ steps.parse-audit.outputs.high }}
🟡 Moderate: ${{ steps.parse-audit.outputs.moderate }}
Please find the JSON file in the [summary page](${{ github.frontend_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}).
ManualVulnerability-CheckOn-server-code:
if: ${{ github.event.action == 'labeled' && (github.event.label.name == 'server-vulnerability' || github.event.label.name == 'check-vulnerability') }}
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
with:
ref: ${{ github.event.pull_request.head.ref }}
- name: Use Node.js 18.18.2
uses: actions/setup-node@v3
with:
node-version: 18.18.2
- name: Install dependencies
run: npm --prefix server install
- name: Running security audit
run: npm --prefix server audit --json > server-audit.json
continue-on-error: true
- name: Parse audit summary
id: parse-audit
run: |
vulnerabilities=$(jq '.metadata.vulnerabilities' server-audit.json)
moderate=$(echo $vulnerabilities | jq '.moderate')
high=$(echo $vulnerabilities | jq '.high')
critical=$(echo $vulnerabilities | jq '.critical')
echo "::set-output name=moderate::$moderate"
echo "::set-output name=high::$high"
echo "::set-output name=critical::$critical"
- name: Upload audit report
uses: actions/upload-artifact@v4
with:
name: server-audit-report
path: server-audit.json
- name: Create or update PR comment
uses: peter-evans/create-or-update-comment@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
repository: ${{ github.repository }}
issue-number: ${{ github.event.pull_request.number }}
body: |
### Security Audit Report Of Server directory
**Node module vulnerabilities summary:**
🔴 Critical: ${{ steps.parse-audit.outputs.critical }}
🟠 High: ${{ steps.parse-audit.outputs.high }}
🟡 Moderate: ${{ steps.parse-audit.outputs.moderate }}
Please find the JSON file in the [summary page](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}).
ManualVulnerability-CheckOn-marketplace-code:
if: ${{ github.event.action == 'labeled' && (github.event.label.name == 'marketplace-vulnerability' || github.event.label.name == 'check-vulnerability') }}
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
with:
ref: ${{ github.event.pull_request.head.ref }}
- name: Use Node.js 18.18.2
uses: actions/setup-node@v3
with:
node-version: 18.18.2
- name: Install dependencies
run: npm --prefix marketplace install
- name: Running security audit
run: npm --prefix marketplace audit --json > marketplace-audit.json
continue-on-error: true
- name: Parse audit summary
id: parse-audit
run: |
vulnerabilities=$(jq '.metadata.vulnerabilities' marketplace-audit.json)
moderate=$(echo $vulnerabilities | jq '.moderate')
high=$(echo $vulnerabilities | jq '.high')
critical=$(echo $vulnerabilities | jq '.critical')
echo "::set-output name=moderate::$moderate"
echo "::set-output name=high::$high"
echo "::set-output name=critical::$critical"
- name: Upload audit report
uses: actions/upload-artifact@v4
with:
name: marketplace-audit-report
path: marketplace-audit.json
- name: Create or update PR comment
uses: peter-evans/create-or-update-comment@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
repository: ${{ github.repository }}
issue-number: ${{ github.event.pull_request.number }}
body: |
### Security Audit Report Of Marketplace directory
**Node module vulnerabilities summary:**
🔴 Critical: ${{ steps.parse-audit.outputs.critical }}
🟠 High: ${{ steps.parse-audit.outputs.high }}
🟡 Moderate: ${{ steps.parse-audit.outputs.moderate }}
Please find the JSON file in the [summary page](${{ github.marketplace_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}).
ManualVulnerability-CheckOn-plugins-code:
if: ${{ github.event.action == 'labeled' && (github.event.label.name == 'plugins-vulnerability' || github.event.label.name == 'check-vulnerability') }}
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
with:
ref: ${{ github.event.pull_request.head.ref }}
- name: Use Node.js 18.18.2
uses: actions/setup-node@v3
with:
node-version: 18.18.2
- name: Install dependencies
run: npm --prefix plugins install
- name: Running security audit
run: npm --prefix plugins audit --json > plugins-audit.json
continue-on-error: true
- name: Parse audit summary
id: parse-audit
run: |
vulnerabilities=$(jq '.metadata.vulnerabilities' plugins-audit.json)
moderate=$(echo $vulnerabilities | jq '.moderate')
high=$(echo $vulnerabilities | jq '.high')
critical=$(echo $vulnerabilities | jq '.critical')
echo "::set-output name=moderate::$moderate"
echo "::set-output name=high::$high"
echo "::set-output name=critical::$critical"
- name: Upload audit report
uses: actions/upload-artifact@v4
with:
name: plugins-audit-report
path: plugins-audit.json
- name: Create or update PR comment
uses: peter-evans/create-or-update-comment@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
repository: ${{ github.repository }}
issue-number: ${{ github.event.pull_request.number }}
body: |
### Security Audit Report Of Plugins directory
**Node module vulnerabilities summary:**
🔴 Critical: ${{ steps.parse-audit.outputs.critical }}
🟠 High: ${{ steps.parse-audit.outputs.high }}
🟡 Moderate: ${{ steps.parse-audit.outputs.moderate }}
Please find the JSON file in the [summary page](${{ github.plugins_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}).
ManualVulnerability-CheckOn-cypress-code:
if: ${{ github.event.action == 'labeled' && (github.event.label.name == 'cypress-vulnerability' || github.event.label.name == 'check-vulnerability') }}
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
with:
ref: ${{ github.event.pull_request.head.ref }}
- name: Use Node.js 18.18.2
uses: actions/setup-node@v3
with:
node-version: 18.18.2
- name: Install dependencies
run: npm --prefix cypress-tests install
- name: Running security audit
run: npm --prefix cypress-tests audit --json > cypress-audit.json
continue-on-error: true
- name: Parse audit summary
id: parse-audit
run: |
vulnerabilities=$(jq '.metadata.vulnerabilities' cypress-audit.json)
moderate=$(echo $vulnerabilities | jq '.moderate')
high=$(echo $vulnerabilities | jq '.high')
critical=$(echo $vulnerabilities | jq '.critical')
echo "::set-output name=moderate::$moderate"
echo "::set-output name=high::$high"
echo "::set-output name=critical::$critical"
- name: Upload audit report
uses: actions/upload-artifact@v4
with:
name: cypress-audit-report
path: cypress-audit.json
- name: Create or update PR comment
uses: peter-evans/create-or-update-comment@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
repository: ${{ github.repository }}
issue-number: ${{ github.event.pull_request.number }}
body: |
### Security Audit Report Of Cypress directory
**Node module vulnerabilities summary:**
🔴 Critical: ${{ steps.parse-audit.outputs.critical }}
🟠 High: ${{ steps.parse-audit.outputs.high }}
🟡 Moderate: ${{ steps.parse-audit.outputs.moderate }}
Please find the JSON file in the [summary page](${{ github.cypress_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}).
ManualVulnerability-CheckOn-root-code:
if: ${{ github.event.action == 'labeled' && (github.event.label.name == 'root-vulnerability' || github.event.label.name == 'check-vulnerability') }}
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
with:
ref: ${{ github.event.pull_request.head.ref }}
- name: Use Node.js 18.18.2
uses: actions/setup-node@v3
with:
node-version: 18.18.2
- name: Install dependencies
run: npm install
- name: Running security audit
run: npm audit --json > root-audit.json
continue-on-error: true
- name: Parse audit summary
id: parse-audit
run: |
vulnerabilities=$(jq '.metadata.vulnerabilities' root-audit.json)
moderate=$(echo $vulnerabilities | jq '.moderate')
high=$(echo $vulnerabilities | jq '.high')
critical=$(echo $vulnerabilities | jq '.critical')
echo "::set-output name=moderate::$moderate"
echo "::set-output name=high::$high"
echo "::set-output name=critical::$critical"
- name: Upload audit report
uses: actions/upload-artifact@v4
with:
name: root-audit-report
path: root-audit.json
- name: Create or update PR comment
uses: peter-evans/create-or-update-comment@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
repository: ${{ github.repository }}
issue-number: ${{ github.event.pull_request.number }}
body: |
### Security Audit Report Of Root directory
**Node module vulnerabilities summary:**
🔴 Critical: ${{ steps.parse-audit.outputs.critical }}
🟠 High: ${{ steps.parse-audit.outputs.high }}
🟡 Moderate: ${{ steps.parse-audit.outputs.moderate }}
Please find the JSON file in the [summary page](${{ github.root_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}).

8
.gitmodules vendored Normal file
View file

@ -0,0 +1,8 @@
[submodule "frontend/ee"]
path = frontend/ee
url = https://github.com/ToolJet/ee-frontend.git
branch = main
[submodule "server/ee"]
path = server/ee
url = https://github.com/ToolJet/ee-server.git
branch = main

View file

@ -1,4 +1,4 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
npx lint-staged
#npx lint-staged

View file

@ -1 +1 @@
3.2.0-ce
3.12.0

18
.vscode/launch.json vendored
View file

@ -11,7 +11,21 @@
{
"type": "node",
"request": "launch",
"name": "Server",
"name": "Server (Dev Mode)",
"runtimeExecutable": "npm",
"runtimeArgs": [
"run",
"start:dev"
],
"sourceMaps": true,
"cwd": "${workspaceRoot}/server",
"console": "integratedTerminal",
"skipFiles": ["<node_internals>/**"]
},
{
"type": "node",
"request": "launch",
"name": "Server (Original)",
"args": [
"${workspaceFolder}/server/src/main.ts"
],
@ -49,7 +63,7 @@
"remoteRoot": "/app/server",
"sourceMaps": true,
"skipFiles": ["<node_internals>/**"]
},
}
}
]
}

View file

@ -1,6 +0,0 @@
# you can list packages
libaio1
# or include links to specific .deb files
# or add custom apt repos (only required if using packages outside of the standard Ubuntu APT repositories)

View file

@ -1 +0,0 @@
web: npm run db:migrate && npm run start:prod --prefix server

View file

@ -46,13 +46,7 @@ ToolJet is an **open-source low-code framework** to build and deploy internal to
<hr>
## Quickstart
The easiest way to get started with ToolJet is by creating a [ToolJet Cloud](https://tooljet.com) account. ToolJet Cloud offers a hosted solution of ToolJet. If you want to self-host ToolJet, kindly proceed to [deployment documentation](https://docs.tooljet.com/docs/setup/).
You can deploy ToolJet on DigitalOcean using one-click-deployment.
<p align="center">
<a href="https://cloud.digitalocean.com/apps/new?repo=https://github.com/ToolJet/ToolJet/tree/main"><img src="https://www.deploytodo.com/do-btn-blue.svg" alt="Deploy to DigitalOcean" height=32></a>
</p>
The easiest way to get started with ToolJet is by creating a [ToolJet Cloud](https://tooljet.ai) account. ToolJet Cloud offers a hosted solution of ToolJet. If you want to self-host ToolJet, kindly proceed to [deployment documentation](https://docs.tooljet.ai/docs/setup/).
### Try using Docker
Want to give ToolJet a quick spin on your local machine? You can run the following command from your terminal to have ToolJet up and running right away.
@ -65,42 +59,42 @@ docker run \
-p 80:80 \
--platform linux/amd64 \
-v tooljet_data:/var/lib/postgresql/13/main \
tooljet/try:EE-LTS-latest
tooljet/try:ee-lts-latest
```
*For users upgrading their ToolJet version, we recommend choosing the LTS version over the latest version. The LTS version ensures stability with production bug fixes, security patches, and performance enhancements.*
## Tutorials and examples
[Time Tracker Application](https://docs.tooljet.com/docs/#quickstart-guide)<br>
[Build your own CMS using low-code](https://blog.tooljet.com/build-cms-using-lowcode-and-mongodb/)<br>
[AWS S3 Browser](https://blog.tooljet.com/build-an-aws-s3-broswer-with-tooljet/)<br>
[Time Tracker Application](https://docs.tooljet.ai/docs/#quickstart-guide)<br>
[Build your own CMS using low-code](https://blog.tooljet.ai/build-cms-using-lowcode-and-mongodb/)<br>
[AWS S3 Browser](https://blog.tooljet.ai/build-an-aws-s3-broswer-with-tooljet/)<br>
## Documentation
Documentation is available at https://docs.tooljet.com.
Documentation is available at https://docs.tooljet.ai.
- [Getting Started](https://docs.tooljet.com)<br>
- [Data source Reference](https://docs.tooljet.com/docs/data-sources/airtable/)<br>
- [Component Reference](https://docs.tooljet.com/docs/widgets/button)
- [Getting Started](https://docs.tooljet.ai)<br>
- [Data source Reference](https://docs.tooljet.ai/docs/data-sources/airtable/)<br>
- [Component Reference](https://docs.tooljet.ai/docs/widgets/button)
## Self-hosted
You can use ToolJet Cloud for a fully managed solution. If you want to self-host ToolJet, we have guides on deploying ToolJet on Kubernetes, AWS EC2, Docker, and more.
| Provider | Documentation |
| :------------- | :------------- |
| Digital Ocean | [Link](https://docs.tooljet.com/docs/setup/digitalocean) |
| Docker | [Link](https://docs.tooljet.com/docs/setup/docker) |
| AWS EC2 | [Link](https://docs.tooljet.com/docs/setup/ec2) |
| AWS ECS | [Link](https://docs.tooljet.com/docs/setup/ecs) |
| OpenShift | [Link](https://docs.tooljet.com/docs/setup/openshift) |
| Helm | [Link](https://docs.tooljet.com/docs/setup/helm) |
| AWS EKS (Kubernetes) | [Link](https://docs.tooljet.com/docs/setup/kubernetes) |
| GCP GKE (Kubernetes) | [Link](https://docs.tooljet.com/docs/setup/kubernetes-gke) |
| Azure AKS (Kubernetes) | [Link](https://docs.tooljet.com/docs/setup/kubernetes-aks) |
| Azure Container | [Link](https://docs.tooljet.com/docs/setup/azure-container) |
| Google Cloud Run | [Link](https://docs.tooljet.com/docs/setup/google-cloud-run) |
| Deploying ToolJet client | [Link](https://docs.tooljet.com/docs/setup/client) |
| Deploying ToolJet on a Subpath | [Link](https://docs.tooljet.com/docs/setup/tooljet-subpath/) |
| Digital Ocean | [Link](https://docs.tooljet.ai/docs/setup/digitalocean) |
| Docker | [Link](https://docs.tooljet.ai/docs/setup/docker) |
| AWS EC2 | [Link](https://docs.tooljet.ai/docs/setup/ec2) |
| AWS ECS | [Link](https://docs.tooljet.ai/docs/setup/ecs) |
| OpenShift | [Link](https://docs.tooljet.ai/docs/setup/openshift) |
| Helm | [Link](https://docs.tooljet.ai/docs/setup/helm) |
| AWS EKS (Kubernetes) | [Link](https://docs.tooljet.ai/docs/setup/kubernetes) |
| GCP GKE (Kubernetes) | [Link](https://docs.tooljet.ai/docs/setup/kubernetes-gke) |
| Azure AKS (Kubernetes) | [Link](https://docs.tooljet.ai/docs/setup/kubernetes-aks) |
| Azure Container | [Link](https://docs.tooljet.ai/docs/setup/azure-container) |
| Google Cloud Run | [Link](https://docs.tooljet.ai/docs/setup/google-cloud-run) |
| Deploying ToolJet client | [Link](https://docs.tooljet.ai/docs/setup/client) |
| Deploying ToolJet on a Subpath | [Link](https://docs.tooljet.ai/docs/setup/tooljet-subpath/) |
## Marketplace
ToolJet can now be found on both AWS and Azure Marketplaces, making it simpler than ever to access and deploy our app-building platform.
@ -108,9 +102,9 @@ ToolJet can now be found on both AWS and Azure Marketplaces, making it simpler t
Find ToolJet on AWS Marketplace [here](https://aws.amazon.com/marketplace/pp/prodview-fxjto27jkpqfg?sr=0-1&ref_=beagle&applicationId=AWSMPContessa) and explore seamless integration on Azure Marketplace [here](https://azuremarketplace.microsoft.com/en-us/marketplace/apps/tooljetsolutioninc1679496832216.tooljet?tab=Overview).
## Community support
For general help using ToolJet, please refer to the official [documentation](https://docs.tooljet.com/docs/). For additional help, you can use one of these channels to ask a question:
For general help using ToolJet, please refer to the official [documentation](https://docs.tooljet.ai/docs/). For additional help, you can use one of these channels to ask a question:
- [Slack](https://tooljet.com/slack) - Discussions with the community and the team.
- [Slack](https://tooljet.ai/slack) - Discussions with the community and the team.
- [GitHub](https://github.com/ToolJet/ToolJet/issues) - For bug reports and feature requests.
- [𝕏 (Twitter)](https://twitter.com/ToolJet) - Get the product updates quickly.

View file

@ -1,82 +0,0 @@
{
"name": "ToolJet",
"description": "ToolJet is an open-source low-code framework to build and deploy internal tools.",
"website": "https://tooljet.io/",
"repository": "https://github.com/tooljet/tooljet",
"logo": "https://tooljet.com/blue-logo.png",
"success_url": "/",
"scripts": {
"postdeploy": "export NODE_OPTIONS=\"--max_old_space_size=1024\"; npm run db:migrate"
},
"env": {
"NODE_ENV": {
"description": "Environment [production/development]",
"value": "production"
},
"TOOLJET_HOST": {
"description": "Public URL of ToolJet installation. This is usually https://<app-name-in-first-step>.herokuapp.com",
"value": "https://<app-name-in-first-step>.herokuapp.com"
},
"TOOLJET_SERVER_URL": {
"description": "URL of ToolJet server installation. (This is same as the TOOLJET_HOST for Heroku deployments)",
"value": "https://<app-name-in-first-step>.herokuapp.com"
},
"LOCKBOX_MASTER_KEY": {
"description": "Master key for encrypting datasource credentials.",
"value": ""
},
"SECRET_KEY_BASE": {
"description": "Used by ToolJet server as the input secret to the application's key generator.",
"value": ""
},
"NODE_OPTIONS": {
"description": "Node options configured to increase node memory to support app build",
"value": "--max-old-space-size=4096"
},
"DISABLE_SIGNUPS": {
"description": "Disable sign up in login page only applicable if Multi-Workspace feature is turned on",
"value": "false"
},
"ENABLE_TOOLJET_DB": {
"description": "To enable Tooljet Database feature",
"value": "false"
},
"DEPLOYMENT_PLATFORM": {
"description": "Platform ToolJet is deployed on",
"value": "heroku"
}
},
"formation": {
"web": {
"quantity": 1,
"size": "standard-2x"
}
},
"image": "heroku/nodejs",
"addons": [
{
"plan": "heroku-postgresql",
"options": {
"version": "13"
}
}
],
"buildpacks": [
{
"url": "heroku/nodejs"
},
{
"url": "heroku-community/apt"
},
{
"url": "https://github.com/featurist/oracle-client-buildpack.git"
}
],
"environments": {
"test": {
"scripts": {
"test": "npm run test --prefix server && npm run test:e2e --prefix server"
}
}
}
}

View file

@ -62,7 +62,7 @@ module.exports = defineConfig({
});
on("task", {
updateId({ 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

@ -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", {
updateId({ dbconfig, sql }) {
dbConnection ({ dbconfig, sql }) {
const client = new pg.Pool(dbconfig);
return client.query(sql);
},

View file

@ -0,0 +1,115 @@
const { defineConfig } = require("cypress");
const { rmdir } = require("fs");
const fs = require("fs");
const XLSX = require("node-xlsx");
const pg = require("pg");
const path = require("path");
const pdf = require("pdf-parse");
const environments = {
'run-cypress-platform': {
baseUrl: "http://localhost:8082",
configFile: "cypress-platform.config.js"
},
'run-cypress-platform-subpath': {
baseUrl: "http://localhost:3000/apps",
configFile: "cypress-platform.config.js"
},
'run-cypress-platform-proxy': {
baseUrl: "http://localhost:4001",
configFile: "cypress-platform.config.js"
},
'run-cypress-platform-proxy-subpath': {
baseUrl: "http://localhost:4001/apps",
configFile: "cypress-platform.config.js"
}
};
const githubLabel = process.env.GITHUB_LABEL || 'run-cypress-platform';
const environment = environments[githubLabel];
module.exports = defineConfig({
execTimeout: 1800000,
defaultCommandTimeout: 30000,
requestTimeout: 30000,
pageLoadTimeout: 30000,
responseTimeout: 30000,
viewportWidth: 1440,
viewportHeight: 960,
chromeWebSecurity: false,
trashAssetsBeforeRuns: true,
e2e: {
setupNodeEvents (on, config) {
config.baseUrl = environment.baseUrl;
on("task", {
readPdf (pathToPdf) {
return new Promise((resolve) => {
const pdfPath = path.resolve(pathToPdf);
let dataBuffer = fs.readFileSync(pdfPath);
pdf(dataBuffer).then(function ({ text }) {
resolve(text);
});
});
},
});
on("task", {
readXlsx (filePath) {
return new Promise((resolve, reject) => {
try {
let dataBuffer = fs.readFileSync(filePath);
const jsonData = XLSX.parse(dataBuffer);
resolve(jsonData[0]["data"].toString());
} catch (e) {
reject(e);
}
});
},
});
on("task", {
deleteFolder (folderName) {
return new Promise((resolve, reject) => {
rmdir(folderName, { maxRetries: 10, recursive: true }, (err) => {
if (err) {
console.error(err);
return reject(err);
}
resolve(null);
});
});
},
});
on("task", {
dbConnection ({ dbconfig, sql }) {
const client = new pg.Pool(dbconfig);
return client.query(sql);
},
});
return require("./cypress/plugins/index.js")(on, config);
},
downloadsFolder: "cypress/downloads",
experimentalRunAllSpecs: true,
experimentalModfyObstructiveThirdPartyCode: true,
baseUrl: environment.baseUrl,
configFile: environment.configFile,
specPattern: [
"cypress/e2e/happyPath/platform/firstUser/firstUserOnboarding.cy.js",
"cypress/e2e/happyPath/platform/ceTestcases/apps/appSlug.cy.js",
"cypress/e2e/happyPath/platform/ceTestcases/**/!(*appSlug).cy.js",
"cypress/e2e/happyPath/platform/commonTestcases/**/*.cy.js",
],
numTestsKeptInMemory: 1,
redirectionLimit: 15,
experimentalMemoryManagement: true,
video: false,
videoUploadOnPasses: false,
retries: {
runMode: 2,
openMode: 0,
},
},
});

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", {
updateId({ dbconfig, sql }) {
dbConnection ({ dbconfig, sql }) {
const client = new pg.Pool(dbconfig);
return client.query(sql);
},

View file

@ -1,95 +0,0 @@
const { defineConfig } = require("cypress");
const { rmdir } = require("fs");
const fs = require("fs");
const XLSX = require("node-xlsx");
const pg = require("pg");
const path = require("path");
const pdf = require("pdf-parse");
module.exports = defineConfig({
execTimeout: 1800000,
defaultCommandTimeout: 30000,
requestTimeout: 10000,
pageLoadTimeout: 20000,
responseTimeout: 10000,
viewportWidth: 1440,
viewportHeight: 960,
chromeWebSecurity: false,
trashAssetsBeforeRuns: true,
e2e: {
setupNodeEvents (on, config) {
on("task", {
readPdf (pathToPdf) {
return new Promise((resolve) => {
const pdfPath = path.resolve(pathToPdf);
let dataBuffer = fs.readFileSync(pdfPath);
pdf(dataBuffer).then(function ({ text }) {
resolve(text);
});
});
},
});
on("task", {
readXlsx (filePath) {
return new Promise((resolve, reject) => {
try {
let dataBuffer = fs.readFileSync(filePath);
const jsonData = XLSX.parse(dataBuffer);
// jsonData= jsonData[0].data
resolve(jsonData[0]["data"].toString());
} catch (e) {
reject(e);
}
});
},
});
on("task", {
deleteFolder (folderName) {
return new Promise((resolve, reject) => {
rmdir(folderName, { maxRetries: 10, recursive: true }, (err) => {
if (err) {
console.error(err);
return reject(err);
}
resolve(null);
});
});
},
});
on("task", {
updateId ({ dbconfig, sql }) {
const client = new pg.Pool(dbconfig);
return client.query(sql);
},
});
return require("./cypress/plugins/index.js")(on, config);
},
downloadsFolder: "cypress/downloads",
experimentalRunAllSpecs: true,
experimentalModfyObstructiveThirdPartyCode: true,
experimentalRunAllSpecs: true,
baseUrl: "http://localhost:8082",
specPattern: [
"cypress/e2e/happyPath/platform/ceTestcases/editor/appSlug.cy.js",
"cypress/e2e/happyPath/platform/ceTestcases/editor/privateAndPublicApp.cy.js",
"cypress/e2e/happyPath/platform/commonTestcases/**/*.cy.js",
"cypress/e2e/happyPath/platform/ceTestcases/**/!(*appSlug|privateAndPublicApp).cy.js"
],
numTestsKeptInMemory: 1,
redirectionLimit: 15,
experimentalRunAllSpecs: true,
experimentalMemoryManagement: true,
video: false,
videoUploadOnPasses: false,
retries: {
runMode: 2,
openMode: 0,
},
},
});

View file

@ -10,9 +10,9 @@ const pdf = require("pdf-parse");
module.exports = defineConfig({
execTimeout: 1800000,
defaultCommandTimeout: 30000,
requestTimeout: 10000,
pageLoadTimeout: 20000,
responseTimeout: 10000,
requestTimeout: 30000,
pageLoadTimeout: 30000,
responseTimeout: 30000,
viewportWidth: 1440,
viewportHeight: 960,
chromeWebSecurity: false,
@ -66,12 +66,22 @@ module.exports = defineConfig({
});
on("task", {
updateId ({ dbconfig, sql }) {
dbConnection ({ dbconfig, sql }) {
const client = new pg.Pool(dbconfig);
return client.query(sql);
},
});
on('before:browser:launch', (browser = {}, launchOptions) => {
if (browser.name === 'chrome' && browser.isHeadless === false) {
launchOptions.args.push(
'--disable-features=AutofillAccountStorage,PasswordManager',
'--disable-save-password-bubble',
'--disable-password-generation',
'--disable-password-manager-reauthentication'
);
}
return launchOptions;
});
require("@cypress/code-coverage/task")(on, config);
// return config;
@ -82,7 +92,7 @@ module.exports = defineConfig({
experimentalModfyObstructiveThirdPartyCode: true,
experimentalRunAllSpecs: true,
baseUrl: "http://localhost:8082",
specPattern: "cypress/e2e/happyPath/platform/**/**/*.cy.js",
specPattern: "cypress/e2e/happyPath/**/*.cy.js",
downloadsFolder: "cypress/downloads",
numTestsKeptInMemory: 0,
redirectionLimit: 10,

View file

@ -1,3 +1,5 @@
const envVar = Cypress.env("environment");
Cypress.Commands.add(
"apiLogin",
(
@ -12,7 +14,7 @@ Cypress.Commands.add(
body: {
email: userEmail,
password: userPassword,
redirectTo: redirection
redirectTo: redirection,
},
})
.its("body")
@ -50,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",
@ -61,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");
@ -75,14 +101,17 @@ Cypress.Commands.add("apiCreateApp", (appName = "testApp") => {
Cookie: `tj_auth_token = ${cookie.value}`,
},
body: {
created_at: "",
id: "",
is_maintenance_on: false,
is_public: null,
type: "front-end",
name: appName,
is_maintenance_on: false,
organization_id: "",
updated_at: "",
user_id: "",
created_at: "",
updated_at: "",
id: "",
is_public: null,
workflow_enabled: false,
creation_mode: "DEFAULT",
},
}).then((response) => {
{
@ -123,14 +152,24 @@ Cypress.Commands.add("apiDeleteApp", (appId = Cypress.env("appId")) => {
Cypress.Commands.add(
"openApp",
(
slug = "",
workspaceId = Cypress.env("workspaceId"),
appId = Cypress.env("appId"),
componentSelector = "[data-cy='empty-editor-text']"
) => {
cy.intercept("GET", "/api/apps/*").as("getAppData");
cy.window({ log: false }).then((win) => {
win.localStorage.setItem("walkthroughCompleted", "true");
});
cy.visit(`/${workspaceId}/apps/${appId}`);
cy.visit(`/${workspaceId}/apps/${appId}/${slug}`);
cy.wait("@getAppData").then((interception) => {
const responseData = interception.response.body;
Cypress.env("editingVersionId", responseData.editing_version.id);
Cypress.env("environmentId", responseData.editorEnvironment.id);
});
cy.get(componentSelector, { timeout: 10000 });
}
);
@ -153,16 +192,17 @@ Cypress.Commands.add("apiCreateWorkspace", (workspaceName, workspaceSlug) => {
{ log: false }
).then((response) => {
expect(response.status).to.equal(201);
return response;
});
});
});
Cypress.Commands.add("logoutApi", () => {
Cypress.Commands.add("apiLogout", () => {
cy.getCookie("tj_auth_token").then((cookie) => {
cy.request(
{
method: "GET",
url: `${Cypress.env("server_host")}/api/logout`,
url: `${Cypress.env("server_host")}/api/session/logout`,
headers: {
"Tj-Workspace-Id": Cypress.env("workspaceId"),
Cookie: `tj_auth_token=${cookie.value}`,
@ -175,51 +215,73 @@ Cypress.Commands.add("logoutApi", () => {
});
});
Cypress.Commands.add("userInviteApi", (userName, userEmail) => {
cy.getCookie("tj_auth_token").then((cookie) => {
cy.request(
{
method: "POST",
url: `${Cypress.env("server_host")}/api/organization_users`,
headers: {
"Tj-Workspace-Id": Cypress.env("workspaceId"),
Cookie: `tj_auth_token=${cookie.value}`,
},
body: {
first_name: userName,
Cypress.Commands.add(
"apiUserInvite",
(userName, userEmail, userRole = "end-user", metaData = {}) => {
const requestBody =
envVar === "Enterprise"
? {
email: userEmail,
firstName: userName,
groups: [],
role: "end-user",
},
},
{ log: false }
).then((response) => {
expect(response.status).to.equal(201);
});
});
});
lastName: "",
role: userRole,
userMetadata: metaData,
}
: {
email: userEmail,
firstName: userName,
groups: [],
lastName: "",
role: userRole,
userMetadata: metaData,
};
Cypress.Commands.add("addQueryApi", (queryName, query, dataQueryId) => {
cy.getCookie("tj_auth_token").then((cookie) => {
cy.request(
{
method: "POST",
url: `${Cypress.env("server_host")}/api/organization-users`,
headers: {
"Tj-Workspace-Id": Cypress.env("workspaceId"),
Cookie: `tj_auth_token=${cookie.value}`,
},
body: requestBody,
},
{ log: false }
).then((response) => {
expect(response.status).to.equal(201);
});
});
}
);
Cypress.Commands.add("apiAddQuery", (queryName, query, dataQueryId) => {
cy.getCookie("tj_auth_token").then((cookie) => {
const headers = {
"Tj-Workspace-Id": Cypress.env("workspaceId"),
Cookie: `tj_auth_token=${cookie.value}`,
};
cy.request({
method: "PATCH",
url: `${Cypress.env("server_host")}/api/data_queries/${dataQueryId}`,
headers: headers,
body: {
name: queryName,
options: {
mode: "sql",
transformationLanguage: "javascript",
enableTransformation: false,
query: query,
cy.apiGetAppData(Cypress.env("appId")).then((appData) => {
const editingVersionId = appData.editing_version.id;
cy.request({
method: "PATCH",
url: `${Cypress.env("server_host")}/api/data-queries/${dataQueryId}/versions/${editingVersionId}`,
headers: headers,
body: {
name: queryName,
options: {
mode: "sql",
transformationLanguage: "javascript",
enableTransformation: false,
query: query,
},
},
},
}).then((patchResponse) => {
expect(patchResponse.status).to.equal(200);
}).then((patchResponse) => {
expect(patchResponse.status).to.equal(200);
});
});
});
});
@ -227,6 +289,7 @@ Cypress.Commands.add("addQueryApi", (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");
@ -246,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,
@ -274,140 +337,403 @@ Cypress.Commands.add(
}
);
Cypress.Commands.add(
"apiAddComponentToApp",
(
appName,
componentName,
layoutConfig = {},
componentType = "Text",
componentValue = "default"
) => {
cy.getAppId(appName).then((appId) => {
const defaultLayout = {
desktop: { top: 90, left: 9, width: 6, height: 40 },
mobile: { top: 90, left: 9, width: 6, height: 40 },
};
// Cypress.Commands.add("addComponentToApp", (appName, componentName, layoutConfig = {}) => {
const layouts = {
desktop: { ...defaultLayout.desktop, ...layoutConfig.desktop },
mobile: { ...defaultLayout.mobile, ...layoutConfig.mobile },
};
// cy.task("updateId", {
// dbconfig: Cypress.env("app_db"),
// sql: `select id from apps where name='${appName}';`,
// }).then((resp) => {
// appId = resp.rows[0]id;
// // Default layout values
// const defaultLayout = {
// desktop: { top: 90, left: 9, width: 6, height: 40 },
// mobile: { top: 90, left: 9, width: 6, height: 40 },
// };
// // Merge default layout with the provided configuration
// const layouts = {
// desktop: { ...defaultLayout.desktop, ...layoutConfig.desktop },
// mobile: { ...defaultLayout.mobile, ...layoutConfig.mobile },
// };
// cy.getCookie("tj_auth_token", { log: false }).then((cookie) => {
// Cypress.env("authToken", `tj_auth_token=${cookie.value}`);
// cy.request({
// method: "GET",
// url: `${Cypress.env("server_host")}/api/v2/apps/${appId}`,
// headers: {
// "Tj-Workspace-Id": Cypress.env("workspaceId"),
// Cookie: `tj_auth_token=${cookie.value}`,
// },
// }).then((response) => {
// expect(response.status).to.eq(200);
// const { id: editingVersionId, home_page_id: homePageId } = response.body.editing_version;
// const componentId = crypto.randomUUID ? crypto.randomUUID() : require("uuid").v4();
// const requestBody = {
// is_user_switched_version: false,
// pageId: homePageId,
// diff: {
// [componentId]: {
// name: componentName,
// layouts: layouts,
// type: "Text",
// },
// },
// };
// cy.request({
// method: "POST",
// url: `${Cypress.env("server_host")}/api/v2/apps/$${appId}/versions/${editingVersionId}/components`,
// headers: {
// "Content-Type": "application/json",
// "Tj-Workspace-Id": Cypress.env("workspaceId"),
// Cookie: `tj_auth_token=${cookie.value}`,
// },
// body: requestBody,
// }).then((postResponse) => {
// expect(postResponse.status).to.eq(201);
// cy.log(`Component ${componentId} added successfully`);
// });
// });
// });
// });
// });
Cypress.Commands.add("addComponentToApp", (appName, componentName, layoutConfig = {}) => {
cy.task("updateId", {
dbconfig: Cypress.env("app_db"),
sql: `select id from apps where name='${appName}';`,
}).then((resp) => {
const appId = resp.rows[0]?.id; // Safely access the id field
if (!appId) {
throw new Error(`App ID not found for appName: ${appName}`);
}
// Default layout values
const defaultLayout = {
desktop: { top: 90, left: 9, width: 6, height: 40 },
mobile: { top: 90, left: 9, width: 6, height: 40 },
};
// Merge default layout with the provided configuration
const layouts = {
desktop: { ...defaultLayout.desktop, ...layoutConfig.desktop },
mobile: { ...defaultLayout.mobile, ...layoutConfig.mobile },
};
cy.getCookie("tj_auth_token", { log: false }).then((cookie) => {
Cypress.env("authToken", `tj_auth_token=${cookie.value}`);
cy.request({
method: "GET",
url: `${Cypress.env("server_host")}/api/v2/apps/${appId}`,
headers: {
"Tj-Workspace-Id": Cypress.env("workspaceId"),
Cookie: `tj_auth_token=${cookie.value}`,
},
}).then((response) => {
expect(response.status).to.eq(200);
const { id: editingVersionId, home_page_id: homePageId } = response.body.editing_version;
const componentId = crypto.randomUUID ? crypto.randomUUID() : require("uuid").v4();
const requestBody = {
is_user_switched_version: false,
pageId: homePageId,
diff: {
[componentId]: {
name: componentName,
layouts: layouts,
type: "Text",
},
},
};
cy.getCookie("tj_auth_token", { log: false }).then((cookie) => {
Cypress.env("authToken", `tj_auth_token=${cookie.value}`);
cy.request({
method: "POST",
url: `${Cypress.env("server_host")}/api/v2/apps/${appId}/versions/${editingVersionId}/components`,
method: "GET",
url: `${Cypress.env("server_host")}/api/apps/${appId}`,
headers: {
"Content-Type": "application/json",
"Tj-Workspace-Id": Cypress.env("workspaceId"),
Cookie: `tj_auth_token=${cookie.value}`,
},
body: requestBody,
}).then((postResponse) => {
expect(postResponse.status).to.eq(201);
cy.log(`Component ${componentId} added successfully`);
}).then((response) => {
expect(response.status).to.eq(200);
const { id: editingVersionId, home_page_id: homePageId } =
response.body.editing_version;
const componentId = crypto.randomUUID
? crypto.randomUUID()
: require("uuid").v4();
let finalProperties = {};
if (componentType === "Text") {
finalProperties = {
text: { value: `${componentValue}` },
};
} else if (componentType === "TextInput") {
finalProperties = {
value: { value: `${componentValue}` },
};
}
const requestBody = {
is_user_switched_version: false,
pageId: homePageId,
diff: {
[componentId]: {
name: componentName,
layouts: layouts,
type: componentType,
properties: finalProperties,
},
},
};
cy.request({
method: "POST",
url: `${Cypress.env("server_host")}/api/v2/apps/${appId}/versions/${editingVersionId}/components`,
headers: {
"Content-Type": "application/json",
"Tj-Workspace-Id": Cypress.env("workspaceId"),
Cookie: `tj_auth_token=${cookie.value}`,
},
body: requestBody,
}).then((postResponse) => {
expect(postResponse.status).to.eq(201);
cy.log(`Component ${componentId} added successfully`);
});
});
});
});
}
);
Cypress.Commands.add("apiGetEnvironments", () => {
cy.getAuthHeaders().then((headers) => {
cy.request({
method: "GET",
url: `${Cypress.env("server_host")}/api/app-environments`,
headers: headers,
}).then((response) => {
expect(response.status).to.equal(200);
return response.body.environments;
});
});
});
Cypress.Commands.add(
"apiCreateWsConstant",
(constantName, value, types = [], environmentNames = []) => {
cy.apiGetEnvironments().then((environments) => {
const envIds = environmentNames
.map((name) => environments.find((env) => env.name === name)?.id)
.filter(Boolean);
cy.getAuthHeaders().then((headers) => {
types.forEach((type) => {
cy.request({
method: "POST",
url: `${Cypress.env("server_host")}/api/organization-constants`,
headers: headers,
body: {
constant_name: constantName,
value: value,
type: type,
environments: envIds,
},
}).then((createResponse) => {
expect(createResponse.status).to.equal(201);
});
});
});
});
}
);
Cypress.Commands.add("apiMakeAppPublic", (appId = Cypress.env("appId")) => {
cy.getAuthHeaders().then((headers) => {
cy.request({
method: "PUT",
url: `${Cypress.env("server_host")}/api/apps/${appId}`,
headers: headers,
body: {
app: { is_public: true },
},
log: false,
}).then((response) => {
expect(response.status).to.equal(200);
});
});
});
Cypress.Commands.add("apiDeleteGranularPermission", (groupName) => {
cy.getAuthHeaders().then((headers) => {
// Fetch group permissions
cy.request({
method: "GET",
url: `${Cypress.env("server_host")}/api/v2/group-permissions`,
headers: headers,
log: false,
}).then((response) => {
expect(response.status).to.equal(200);
const group = response.body.groupPermissions.find(
(g) => g.name === groupName
);
if (!group) throw new Error(`Group with name ${groupName} not found`);
const groupId = group.id;
// Fetch granular permissions for the specific group
cy.request({
method: "GET",
url: `${Cypress.env("server_host")}/api/v2/group-permissions/${groupId}/granular-permissions`,
headers,
log: false,
}).then((granularResponse) => {
expect(granularResponse.status).to.equal(200);
const granularPermissionId = granularResponse.body[0].id;
// Delete the granular permission
cy.request({
method: "DELETE",
url: `${Cypress.env("server_host")}/api/v2/group-permissions/granular-permissions/${granularPermissionId}`,
headers,
log: false,
}).then((deleteResponse) => {
expect(deleteResponse.status).to.equal(200);
});
});
});
});
});
Cypress.Commands.add(
"apiCreateGranularPermission",
(
groupName,
name,
canEdit = false,
canView = true,
hideFromDashboard = false,
resourcesToAdd = []
) => {
cy.getAuthHeaders().then((headers) => {
// Fetch group permissions
cy.request({
method: "GET",
url: `${Cypress.env("server_host")}/api/v2/group-permissions`,
headers: headers,
log: false,
}).then((response) => {
expect(response.status).to.equal(200);
const group = response.body.groupPermissions.find(
(g) => g.name === groupName
);
if (!group) throw new Error(`Group with name ${groupName} not found`);
const groupId = group.id;
// Create granular permission
cy.request({
method: "POST",
url: `${Cypress.env("server_host")}/api/v2/group-permissions/granular-permissions`,
headers: headers,
body: {
name,
type: "app",
groupId,
isAll: true,
createAppsPermissionsObject: {
canEdit,
canView,
hideFromDashboard,
resourcesToAdd,
},
},
log: false,
}).then((res) => {
expect(res.status).to.equal(201);
});
});
});
}
);
Cypress.Commands.add("apiReleaseApp", (appName) => {
cy.getAppId(appName).then((appId) => {
cy.getAuthHeaders().then((headers) => {
cy.request({
method: "GET",
url: `${Cypress.env("server_host")}/api/apps/${appId}`,
headers,
})
.then((response) => {
expect(response.status).to.eq(200);
const editingVersionId = response.body.editing_version.id;
cy.request({
method: "PUT",
url: `${Cypress.env("server_host")}/api/apps/${appId}/release`,
headers: headers,
body: {
versionToBeReleased: editingVersionId,
},
});
})
.then((res) => {
expect(res.status).to.eq(200);
});
});
});
});
Cypress.Commands.add("apiAddAppSlug", (appName, slug) => {
cy.getAppId(appName).then((appId) => {
cy.getAuthHeaders().then((headers) => {
cy.request({
method: "PUT",
url: `${Cypress.env("server_host")}/api/apps/${appId}`,
headers: headers,
body: {
app: {
slug: slug,
},
},
}).then((response) => {
expect(response.status).to.eq(200);
cy.log("App slug updated successfully");
});
});
});
});
Cypress.Commands.add("apiGetTableIdByName", (tableName) => {
cy.getAuthHeaders().then((headers) => {
cy.request({
method: "GET",
url: `${Cypress.env("server_host")}/api/tooljet-db/organizations/${Cypress.env("workspaceId")}/tables`,
headers: headers,
}).then((response) => {
expect(response.status).to.eq(200);
const table = response.body.result.find(
(t) => t.table_name === tableName
);
return table.id;
});
});
});
Cypress.Commands.add("apiAddDataToTable", (tableName, data) => {
cy.apiGetTableIdByName(tableName).then((tableId) => {
cy.getAuthHeaders().then((headers) => {
cy.request({
method: "POST",
url: `${Cypress.env("server_host")}/api/tooljet-db/proxy/${tableId}`,
headers: headers,
body: data,
}).then((response) => {
expect(response.status).to.eq(201);
cy.log("Data added to table successfully");
});
});
});
});
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/${workspaceId}`,
headers: headers,
}).then((response) => {
expect(response.status).to.equal(200);
const dataSource = response.body.data_sources.find(
(ds) => ds.name === dataSourceName
);
return dataSource.id;
});
});
});
Cypress.Commands.add("getAuthHeaders", () => {
cy.getCookie("tj_auth_token").then((cookie) => {
return {
"Tj-Workspace-Id": Cypress.env("workspaceId"),
Cookie: `tj_auth_token=${cookie.value}`,
};
});
});
Cypress.Commands.add(
"apiUpdateDataSource",
(dataSourceName, envName, updateData) => {
cy.getAuthHeaders().then((headers) => {
cy.apiGetEnvironments().then((environments) => {
const environment = environments.find((env) => env.name === envName);
cy.apiGetDataSourceIdByName(dataSourceName).then((dataSourceId) => {
const environmentId = environment.id;
const defaultData = {
name: dataSourceName,
options: [
{ key: "connection_type", value: "manual", encrypted: false },
{ key: "host", value: "9.234.17.31" },
{ key: "port", value: 5432 },
{ key: "database", value: "student" },
{ key: "username", value: "postgres" },
{ key: "password", value: "", encrypted: true }, // Default password to be overridden
{ key: "ssl_enabled", value: false, encrypted: false },
{ key: "ssl_certificate", value: "none", encrypted: false },
],
};
const mergedData = {
...defaultData,
...updateData,
options: defaultData.options.map((option) => {
const updatedOption = updateData.options?.find(
(o) => o.key === option.key
);
return updatedOption ? { ...option, ...updatedOption } : option;
}),
};
cy.request({
method: "PUT",
url: `${Cypress.env("server_host")}/api/data-sources/${dataSourceId}?environment_id=${environmentId}`,
headers: headers,
body: mergedData,
}).then((updateResponse) => {
expect(updateResponse.status).to.equal(200);
cy.log(`Datasource "${dataSourceName}" updated successfully.`);
});
});
});
});
}
);
Cypress.Commands.add("apiGetAppData", (appId = Cypress.env("appId")) => {
cy.getAuthHeaders().then((headers) => {
cy.request({
method: "GET",
url: `${Cypress.env("server_host")}/api/apps/${appId}`,
headers: headers,
}).then((response) => {
expect(response.status).to.equal(200);
return response.body;
});
});
});

View file

@ -6,27 +6,27 @@ import { passwordInputText } from "Texts/passwordInput";
import { importSelectors } from "Selectors/exportImport";
import { importText } from "Texts/exportImport";
import { onboardingSelectors } from "Selectors/onboarding";
import { selectAppCardOption } from "Support/utils/common";
const API_ENDPOINT =
Cypress.env("environment") === "Community"
? "/api/library_apps"
: "/api/library_apps/";
Cypress.Commands.add(
"appUILogin",
(email = "dev@tooljet.io", password = "password") => {
cy.visit("/");
cy.wait(3000);
cy.clearAndType(onboardingSelectors.loginEmailInput, email);
cy.clearAndType(onboardingSelectors.loginPasswordInput, password);
cy.get(onboardingSelectors.signInButton).click();
cy.intercept("GET", "api/library_apps").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");
}
);
Cypress.Commands.add("clearAndType", (selector, text) => {
cy.get(selector).clear().type(text, { log: false });
cy.get(selector, { timeout: 20000 }).clear();
cy.get(selector).type(text, { log: false });
});
Cypress.Commands.add("forceClickOnCanvas", () => {
@ -76,12 +76,13 @@ Cypress.Commands.add(
"dragAndDropWidget",
(
widgetName,
positionX = 190,
positionX = 80,
positionY = 80,
widgetName2 = widgetName,
canvas = commonSelectors.canvas
) => {
const dataTransfer = new DataTransfer();
cy.forceClickOnCanvas();
cy.clearAndType(commonSelectors.searchField, widgetName);
cy.get(commonWidgetSelector.widgetBox(widgetName2)).trigger(
@ -97,53 +98,78 @@ Cypress.Commands.add(
}
);
Cypress.Commands.add(
"clearAndTypeOnCodeMirror",
{
prevSubject: "optional",
},
{ prevSubject: "optional" },
(subject, value) => {
cy.wrap(subject)
.realClick()
.find("pre.CodeMirror-line")
.find(".cm-line")
.invoke("text")
.then((text) => {
cy
.wrap(subject)
cy.wrap(subject)
.last()
.click()
.type(createBackspaceText(text), { delay: 0 }),
{
delay: 0,
};
.type(createBackspaceText(text), { delay: 0 });
});
if (!Array.isArray(value)) {
cy.wrap(subject).last().type(value, {
const splitIntoFlatArray = (value) => {
const regex = /(\{|\}|\(|\)|\[|\]|,|:|;|=>|'[^']*'|[a-zA-Z0-9._]+|\s+)/g;
let prefix = "";
return (
value.match(regex)?.reduce((acc, part) => {
if (part === "{{" || part === "((") {
prefix = "{backspace}{backspace}";
acc.push(part);
} else if (part === "{" || part === "(" || part === "[") {
acc.push(prefix + part);
prefix = "{backspace}";
} else if (part === "}}") {
acc.push(prefix + part);
} else if (part === " ") {
acc.push(prefix + " ");
} else if (part === ":") {
acc.push(prefix + ":");
} else {
acc.push(prefix + part);
prefix = "";
}
return acc;
}, []) || []
);
};
if (Array.isArray(value)) {
cy.wrap(subject).last().realType(value, {
parseSpecialCharSequences: false,
delay: 0,
force: true,
});
} else {
cy.wrap(subject)
.last()
.type(value[1], {
parseSpecialCharSequences: false,
delay: 0,
})
.type(`{home}${value[0]}`, { delay: 0 });
splitIntoFlatArray(value).forEach((i) => {
cy.wrap(subject)
.last()
.click()
.realType(
`{end}{end}{end}{end}{end}{end}{end}{end}{end}{end}{end}{end}{end}{end}{end}{end}{end}{end}{end}{end}${i}`,
{ parseSpecialCharSequences: false, delay: 0, force: true }
);
});
}
}
);
Cypress.Commands.add("deleteApp", (appName) => {
cy.intercept("DELETE", "/api/apps/*").as("appDeleted");
cy.get(commonSelectors.appCard(appName))
.realHover()
.find(commonSelectors.appCardOptionsButton)
.realHover()
.click();
cy.get(commonSelectors.deleteAppOption).click();
selectAppCardOption(
appName,
commonSelectors.appCardOptions(commonText.deleteAppOption)
);
cy.get(commonSelectors.buttonSelector(commonText.modalYesButton)).click();
cy.verifyToastMessage(
commonSelectors.toastMessage,
commonText.appDeletedToast
);
cy.wait("@appDeleted");
});
@ -154,9 +180,9 @@ Cypress.Commands.add(
},
(subject, assertion, value, ...arg) => {
return cy
.wrap(subject)
.scrollIntoView()
.should("be.visible")
.wrap(subject, { timeout: 10000 })
.scrollIntoView({ timeout: 10000 })
.should("be.visible", { timeout: 10000 })
.and(assertion, value, ...arg);
}
);
@ -171,6 +197,14 @@ Cypress.Commands.add("modifyCanvasSize", (x, y) => {
cy.forceClickOnCanvas();
});
Cypress.Commands.add("createAppFromTemplate", (appName) => {
cy.get('[data-cy="import-dropdown-menu"]').click();
cy.get('[data-cy="choose-from-template-button"]').click();
cy.get(`[data-cy="${appName}-list-item"]`).click();
cy.get('[data-cy="create-application-from-template-button"]').click();
cy.get('[data-cy="app-name-label"]').should("have.text", "App Name");
});
Cypress.Commands.add("renameApp", (appName) => {
cy.get(commonSelectors.appNameInput).type(
`{selectAll}{backspace}${appName}`,
@ -188,7 +222,7 @@ Cypress.Commands.add(
(subject, value) => {
cy.wrap(subject)
.realClick()
.find("pre.CodeMirror-line")
.find(".cm-line")
.invoke("text")
.then((text) => {
cy.wrap(subject).realType(createBackspaceText(text)),
@ -269,19 +303,19 @@ Cypress.Commands.add("skipEditorPopover", () => {
});
Cypress.Commands.add("waitForAppLoad", () => {
const API_ENDPOINT =
Cypress.env("environment") === "Community"
? "/api/v2/data_sources"
: "/api/app-environments**";
// const API_ENDPOINT =
// Cypress.env("environment") === "Community"
// ? "/api/v2/data_sources"
// : "/api/app-environments**";
const TIMEOUT = 15000;
// const TIMEOUT = 15000;
cy.intercept("GET", API_ENDPOINT).as("appDs");
cy.wait("@appDs", { timeout: TIMEOUT });
cy.intercept("GET", "/api/data-queries/**").as("appDs");
cy.wait("@appDs", { timeout: 15000 });
});
Cypress.Commands.add("visitTheWorkspace", (workspaceName) => {
cy.task("updateId", {
cy.task("dbConnection", {
dbconfig: Cypress.env("app_db"),
sql: `select id from organizations where name='${workspaceName}';`,
}).then((resp) => {
@ -363,28 +397,38 @@ Cypress.Commands.add("getPosition", (componentName) => {
});
Cypress.Commands.add("defaultWorkspaceLogin", () => {
cy.apiLogin();
cy.intercept("GET", "/api/library_apps").as(
"library_apps"
);
cy.visit("/my-workspace");
// cy.get(commonSelectors.homePageLogo, { timeout: 10000 });
cy.wait("@library_apps");
cy.task("dbConnection", {
dbconfig: Cypress.env("app_db"),
sql: `
SELECT id FROM organizations WHERE name = 'My workspace';`,
}).then((resp) => {
const workspaceId = resp.rows[0].id;
cy.apiLogin(
"dev@tooljet.io",
"password",
workspaceId,
"/my-workspace"
).then(() => {
cy.visit("/");
cy.wait(2000);
cy.get(commonSelectors.homePageLogo, { timeout: 10000 });
});
});
});
Cypress.Commands.add(
"visitSlug",
({ actualUrl, currentUrl = "http://localhost:8082/error/unknown" }) => {
cy.visit(actualUrl);
cy.wait(3000);
Cypress.Commands.add("visitSlug", ({ actualUrl }) => {
cy.visit(actualUrl);
cy.wait(1000);
cy.url().then((currentUrl) => {
if (currentUrl !== actualUrl) {
cy.visit(actualUrl);
cy.wait(1000);
}
});
});
cy.url().then((url) => {
if (url === currentUrl) {
cy.visit(actualUrl);
}
});
}
);
Cypress.Commands.add("releaseApp", () => {
if (Cypress.env("environment") !== "Community") {
@ -406,10 +450,13 @@ Cypress.Commands.add("releaseApp", () => {
Cypress.Commands.add("backToApps", () => {
cy.get(commonSelectors.editorPageLogo).click();
cy.get(commonSelectors.backToAppOption).click();
cy.intercept("GET", API_ENDPOINT).as("library_apps");
cy.get(commonSelectors.homePageLogo, { timeout: 10000 });
cy.wait("@library_apps");
});
Cypress.Commands.add("removeAssignedApps", () => {
cy.task("updateId", {
cy.task("dbConnection", {
dbconfig: Cypress.env("app_db"),
sql: `DELETE FROM app_group_permissions;`,
});
@ -433,20 +480,6 @@ Cypress.Commands.add("verifyLabel", (labelName) => {
);
});
Cypress.Commands.add(
"visitSlug",
({ actualUrl, currentUrl = "http://localhost:8082/error/unknown" }) => {
cy.visit(actualUrl);
cy.wait(3000);
cy.url().then((url) => {
if (url === currentUrl) {
cy.visit(actualUrl);
}
});
}
);
Cypress.Commands.add(
"verifyCssProperty",
(selector, property, expectedValue) => {
@ -462,8 +495,113 @@ Cypress.Commands.add("skipWalkthrough", () => {
Cypress.Commands.add("appPrivacy", (appName, isPublic) => {
const isPublicValue = isPublic ? "true" : "false";
cy.task("updateId", {
cy.task("dbConnection", {
dbconfig: Cypress.env("app_db"),
sql: `UPDATE apps SET is_public = ${isPublicValue} WHERE name = '${appName}';`,
});
});
Cypress.Commands.overwrite(
"intercept",
(originalFn, method, endpoint, ...rest) => {
const isSubpath = Cypress.config("baseUrl")?.includes("/apps");
const cleanEndpoint = endpoint.startsWith("/apps")
? endpoint.replace("/apps", "")
: endpoint;
const fullUrl = isSubpath ? `/apps${cleanEndpoint}` : cleanEndpoint;
return originalFn(method, fullUrl, ...rest);
}
);
Cypress.Commands.add("installMarketplacePlugin", (pluginName) => {
const MARKETPLACE_URL = `${Cypress.config("baseUrl")}/integrations/marketplace`;
cy.visit(MARKETPLACE_URL);
cy.wait(1000);
cy.get('[data-cy="-list-item"]').eq(0).click();
cy.wait(1000);
cy.get("body").then(($body) => {
if ($body.find(".plugins-card").length === 0) {
cy.log("No plugins found, proceeding to install...");
installPlugin(pluginName);
} else {
cy.get(".plugins-card").then(($cards) => {
const isInstalled = $cards.toArray().some((card) => {
return (
Cypress.$(card)
.find(".font-weight-medium.text-capitalize")
.text()
.trim() === pluginName
);
});
if (isInstalled) {
cy.log(`${pluginName} is already installed. Skipping installation.`);
cy.get(commonSelectors.globalDataSourceIcon).click();
} else {
installPlugin(pluginName);
cy.get(commonSelectors.globalDataSourceIcon).click();
}
});
}
});
function installPlugin (pluginName) {
cy.get('[data-cy="-list-item"]').eq(1).click();
cy.wait(1000);
cy.contains(".plugins-card", pluginName).within(() => {
cy.get(".marketplace-install").click();
cy.wait(1000);
});
}
});
Cypress.Commands.add("verifyElement", (selector, text, eqValue) => {
const element =
eqValue !== undefined ? cy.get(selector).eq(eqValue) : cy.get(selector);
element.should("be.visible").and("have.text", text);
});
Cypress.Commands.add("getAppId", (appName) => {
cy.task("dbConnection", {
dbconfig: Cypress.env("app_db"),
sql: `select id from apps where name='${appName}';`,
}).then((resp) => {
const appId = resp.rows[0]?.id;
return appId;
});
});
Cypress.Commands.add("uninstallMarketplacePlugin", (pluginName) => {
const MARKETPLACE_URL = `${Cypress.config("baseUrl")}/integrations/marketplace`;
cy.visit(MARKETPLACE_URL);
cy.wait(1000);
cy.get('[data-cy="-list-item"]').eq(0).click();
cy.wait(1000);
cy.get(".plugins-card").each(($card) => {
cy.wrap($card)
.find(".font-weight-medium.text-capitalize")
.invoke("text")
.then((text) => {
if (text.trim() === pluginName) {
cy.wrap($card).find(".link-primary").contains("Remove").click();
cy.wait(1000);
cy.get('[data-cy="delete-plugin-title"]').should("be.visible");
cy.get('[data-cy="yes-button"]').click();
cy.wait(2000);
cy.log(`${pluginName} has been successfully uninstalled.`);
} else {
cy.log(`${pluginName} is not installed. Skipping uninstallation.`);
}
});
});
});

View file

@ -0,0 +1,62 @@
export const pluginSelectors = {
regionField: '[data-cy="region-section"] .react-select__control',
regionFieldValue: '[data-cy="region-section"] .react-select__single-value',
amazonsesAccesKey: '[data-cy="access-key-text-field"]',
operationDropdown: '[data-cy="operation-select-dropdown"]',
sendEmailInputField: '[data-cy="send-mail-to-input-field"]',
ccEmailInputField: '[data-cy="cc-to-input-field"]',
bccEmailInputField: '[data-cy="bcc-to-input-field"]',
sendEmailFromInputField: '[data-cy="send-mail-from-input-field"]',
emailSubjetInputField: '[data-cy="subject-input-field"]',
emailbodyInputField: '[data-cy="body-input-field"]',
amazonAthenaDbName: '[data-cy="database-text-field"]',
};
export const baserowSelectors = {
hostField: '[data-cy="host-select-dropdown"]',
baserowApiKey: '[data-cy="api-token-text-field"]',
table: '[data-cy="table-id-input-field"]',
rowIdinputfield: '[data-cy="row-id-input-field"]',
};
export const appWriteSelectors = {
projectID: '[data-cy="project-id-text-field"]',
collectionId: '[data-cy="collectionid-input-field"]',
documentId: '[data-cy="documentid-input-field"]',
bodyInput: '[data-cy="body-input-field"]',
};
export const twilioSelectors = {
toNumberInputField: '[data-cy="to-number-input-field"]',
bodyInput: '[data-cy="body-input-field"]',
};
export const minioSelectors = {
sslToggle: 'data-cy="ssl-enabled-toggle-input"',
bucketNameInputField: '[data-cy="bucket-input-field"]',
objectNameInputField: '[data-cy="objectname-input-field"]',
contentTypeInputField: '[data-cy="contenttype-input-field"]',
dataInput: '[data-cy="data-input-field"]',
};
export const harperDbSelectors = {
recordsInputField: '[data-cy="records-input-field"]',
hashValueInputField: '[data-cy="hash-values-input-field"]',
attributesInputField: '[data-cy="attributes-input-field"]',
searchValueInputField: '[data-cy="search-value-input-field"]',
searchAttributeInputField: '[data-cy="search-attribute-input-field"]',
conditionInputField: '[data-cy="conditions-input-field"]',
sqlQueryInputField: '[data-cy="sql-query-input-field"]',
schemaInputField: '[data-cy="schema-input-field"]',
TableInputField: '[data-cy="table-input-field"]',
};
export const awsTextractSelectors = {
documentInputField: '[data-cy="document-input-field"]',
bucketNameInputField: '[data-cy="bucket-input-field"]',
keyNameInputField: '[data-cy="key-input-field"]',
};
export const graphQLSelectors = {
urlInputField: '[data-cy="url-text-field"]',
};

View file

@ -5,5 +5,5 @@ export const s3Selector = {
regionLabel: '[data-cy="label-region"]',
customEndpointLabel: '[data-cy="label-custom-endpoint"]',
customEndpointInput: '[data-cy="undefined-text-field"]',
dataSourceNameInput: '[data-cy="data-source-name-input-filed"]',
dataSourceNameInput: '[data-cy="data-source-name-input-field"]',
};

View file

@ -5,15 +5,21 @@ export const cyParamName = (paramName = "") => {
export const commonSelectors = {
toastMessage: ".go3958317564",
oldToastMessage: ".go318386747",
newToastMessage: '.drawer-container > [style="position: fixed; z-index: 9999; inset: 16px; pointer-events: none;"] > .go4109123758 > .go2072408551 > .go3958317564',
appSlugAccept: '[data-cy="app-slug-accepted-label"]',
newToastMessage:
'.drawer-container > [style="position: fixed; z-index: 9999; inset: 16px; pointer-events: none;"] > .go4109123758 > .go2072408551 > .go3958317564',
toastCloseButton: '[data-cy="toast-close-button"]',
editButton: "[data-cy=edit-button]",
workspaceConstantNameInput: '[data-cy="name-input-field"]',
workspaceConstantValueInput: '[data-cy="value-input-field"]',
fileSelector: "[data-cy=uploaded-file-data]",
searchField: "[data-cy='widget-search-box-search-bar']",
firstWidget: "[data-cy=widget-list]:eq(0)",
canvas: "[data-cy=real-canvas]",
appCardOptionsButton: "[data-cy=app-card-menu-icon]",
autoSave: "[data-cy=autosave-indicator]",
nameInputFieldd: "[data-cy=name-input-field]",
valueInputFieldd: "[data-cy=value-input-field]",
skipButton: ".driver-close-btn",
skipInstallationModal: "[data-cy=skip-button]",
homePageLogo: "[data-cy=home-page-logo]",
@ -132,6 +138,7 @@ export const commonSelectors = {
userAccountNameAvatar: '[data-cy="user-account-name-avatar"]',
workspaceNameInputLabel: '[data-cy="onboarding-workspace-name-label"]',
workspaceNameInputField: '[data-cy="onboarding-workspace-name-input"]',
workspaceNameinput: '[data-cy="workspace-name-input-field"]',
backArrow: '[data-cy="back-arrow"]',
backArrowText: '[data-cy="back-arrow-text"]',
onboardingPorgressBubble: '[data-cy="onboarding-progress-bubbles"]',
@ -166,8 +173,11 @@ export const commonSelectors = {
resetPasswordPageDescription: '[data-cy="reset-password-page-description"]',
backToLoginButton: '[data-cy="back-to-login"]',
breadcrumbTitle: '[data-cy="app-header-label"]>>',
// breadcrumbPageTitle: '[data-cy="app-header-label"]',
breadcrumbPageTitle: '[data-cy="breadcrumb-page-title"]',
labelFullNameInput: '[data-cy="name-label"]',
duplicateOption: '[data-cy="duplicate-group-card-option"]',
confirmDuplicateButton: '[data-cy="confim-button"]',
inputFieldFullName: '[data-cy="name-input"]',
labelEmailInput: '[data-cy="email-label"]',
inputFieldEmailAddress: '[data-cy="email-input"]',
@ -176,7 +186,7 @@ export const commonSelectors = {
globalDataSourceIcon: '[data-cy="icon-global-datasources"]',
addNewDataSourceButton: '[data-cy="add-new-data-source-button"]',
saveButton: '[data-cy="save-button"]',
appEditButton: '[data-cy="edit-button"]',
onboardingRadioButton: (radioButtonText) => {
return `[data-cy="${cyParamName(radioButtonText)}-radio-button"]`;
},
@ -250,7 +260,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"]',
@ -272,7 +282,7 @@ export const commonSelectors = {
export const commonWidgetSelector = {
widgetBox: (widgetName) => {
return `[data-cy=widget-list-box-${cyParamName(widgetName)}]`;
return `[data-cy=widget-list-box-${cyParamName(widgetName)}]:eq(0)`;
},
draggableWidget: (widgetName) => {
@ -333,9 +343,11 @@ export const commonWidgetSelector = {
buttonCloseEditorSideBar: "[data-cy='inspector-close-icon']",
buttonStylesEditorSideBar: "#inspector-tab-styles",
WidgetNameInputField: "[data-cy=edit-widget-name]",
constantInspectorIcon: '[data-cy="inspector-node-constants"] > .node-key',
inspectorIcon: '[data-cy="left-sidebar-inspect-button"]',
tooltipInputField: "[data-cy='tooltip-input-field']",
tooltipLabel: "[id=button-tooltip]",
homePageLogo: '[data-cy="home-page-logo"]',
noEventHandlerMessage: "[data-cy='no-items-banner']",
addEventHandlerLink: "[data-cy='add-event-handler']",
@ -357,7 +369,7 @@ export const commonWidgetSelector = {
inspectorNodeComponents: "[data-cy='inspector-node-components']> .node-key",
nodeComponentValue: "[data-cy='inspector-node-value']> .mx-2",
nodeComponentValues: "[data-cy='inspector-node-values']> .node-key",
slugAccept: '[data-cy="app-slug-accepted-label"]',
widgetDocumentationLink: "[data-cy='widget-documentation-link']",
boxShadowDefaultParam: ["x", "y", "blur", "spread"],
@ -366,7 +378,8 @@ export const commonWidgetSelector = {
boxShadowColorPicker: "[data-cy='box-shadow-picker']",
textInputWidget: '[data-cy="draggable-widget-textinput1"]',
previewButton: `[data-cy="preview-link-button"]`,
defaultValueInputField: '[data-cy="default-value-input-field"]',
alertInfoText: '[data-cy="alert-info-text"]',
shareAppButton: '[data-cy="share-button-link"]',
shareModalElements: {
modalHeader: '[data-cy="modal-header"]',
@ -383,7 +396,7 @@ export const commonWidgetSelector = {
modalCloseButton: '[data-cy="modal-close-button"]',
iframeLinkLabel: '[data-cy="iframe-link-label"]',
ifameLinkCopyButton: '[data-cy="iframe-link-copy-button"]',
appSlugLabel: '[data-cy="input-field-label"]',
appSlugLabel: '[data-cy="unique-app-slug-field-label"]',
appSlugInput: '[data-cy="app-slug-input-field"]',
appSlugInfoLabel: '[data-cy="helper-text"]',
appLinkLabel: '[data-cy="app-link-label"]',

View file

@ -14,7 +14,7 @@ export const dataSourceSelector = {
dataSourceSearchInputField: '[data-cy="home-page-search-bar"]',
postgresDataSource: "[data-cy='data-source-postgresql']",
dataSourceNameInputField: '[data-cy="data-source-name-input-filed"]',
dataSourceNameInputField: '[data-cy="added-ds-search-bar"]',
labelHost: '[data-cy="label-host"]',
labelPort: '[data-cy="label-port"]',
labelSsl: '[data-cy="label-ssl"]',
@ -52,10 +52,16 @@ export const dataSourceSelector = {
labelTransformation: '[data-cy="label-query-transformation"]',
toggleTransformation: '[data-cy="transformation-toggle-switch"]',
inputFieldTransformation: '[data-cy="transformation-input-input-field"]',
editorVariablePreview: '[data-cy="variable-preview"]',
baseUrlTextField: '[data-cy="base-url-text-field"]',
previewJsonDataContainer: '[data-cy="preview-json-data-container"]',
editorDSPopover: '[data-cy="show-ds-popover-button"]',
runjsQuery: '[data-cy="ds-run javascript code"]',
runjsInputField: '[data-cy="runjs-input-field"]',
headerQueryPreview: ".py-2",
previewTabJson: '[data-cy="preview-tab-json"]',
previewTabRaw: '[data-cy="preview-tab-raw"]',
previewTabRawContainer: '[data-cy="preview-raw-data-container"]',
operationsDropDownLabel: '[data-cy="operation-dropdown-label"]',
labelTableNameInputField: '[data-cy="label-table"]',
@ -91,7 +97,7 @@ export const dataSourceSelector = {
eventQuerySelectionField: '[data-cy="query-selection-field"]',
addedDsSearchIcon: '[data-cy="added-ds-search-icon"]',
AddedDsSearchBar: '[data-cy="added-ds-search-bar"]',
dsNameInputField: '[data-cy="data-source-name-input-filed"]',
dsNameInputField: '[data-cy="data-source-name-input-field"]',
unSavedModalTitle: '[data-cy="unsaved-changes-title"]',
eventQuerySelectionField: '[data-cy="query-selection-field"]',
connectionAlertText: '[data-cy="connection-alert-text"]',

View file

@ -32,6 +32,9 @@ export const exportAppModalSelectors = {
versionRadioButton: (versionText) => {
return `[data-cy="${cyParamName(versionText)}-radio-button"]`;
},
versionCreatedTime: (versionText) => {
return `[data-cy="${versionText}-version-wrapper"] > .d-flex > [data-cy="created-date-label"]`;
}
};
export const importSelectors = {

View file

@ -6,25 +6,44 @@ export const groupsSelector = {
createNewGroupButton: "[data-cy=create-new-group-button]",
tableHeader: "[data-cy=table-header]",
groupName: "[data-cy=group-name]",
addNewGroupModalTitle: '[data-cy="create-new-group-title"]',
addNewGroupModalTitle: '[data-cy="add-new-group-title"]',
groupNameInput: "[data-cy=group-name-input]",
cancelButton: "[data-cy=cancel-button]",
workspaceVarCreateLabel: '[data-cy="workspace-variable-create-label"]',
createGroupButton: "[data-cy=create-group-button]",
adminListItem: '[data-cy="admin-list-item"]',
adminTitle: '[data-cy="admin-title"]',
appCreateHelperText: '[data-cy="app-create-helper-text"]',
appDeleteHelperText: '[data-cy="app-delete-helper-text"]',
resourceHeader: '[data-cy="resource-header"]',
builderListItem: '[data-cy="builder-list-item"]',
builderTitle: '[data-cy="builder-title"]',
enduserListItem: '[data-cy="end-user-list-item]',
enduserTitle: '[data-cy="end-user-title"]',
userGroup: "[data-cy=user-groups]",
appsLink: "[data-cy=apps-link]",
usersLink: "[data-cy=users-link]",
tableslink: "[data-cy=tables-link]",
permissionsLink: "[data-cy=permissions-link]",
granularLink: "[data-cy=granular-access-link]",
searchBox: '[data-cy="select-search"]',
appSearchBox: "[data-cy=select-search]>>>>>.dropdown-heading-value > .gray",
searchBoxOptions: ".panel-content",
appAddButton: "[data-cy=add-button]",
addButton: '[data-cy="add-button"]',
nameTableHeader: ".active [data-cy=name-header]",
nameTableHeader: '.active [data-cy="name-header"]',
permissionstableHedaer: ".active [data-cy=permissions-header]",
permissionsTableHeader: ".active [data-cy=permissions-header]",
emailTableHeader: "[data-cy=email-header]",
resourcesTableHeader: "[data-cy=resource-header]",
resourcesApps: "[data-cy=resource-apps]",
resourceLabel: '[data-cy="resource-label"]',
allAppsRadio: '[data-cy="all-apps-radio"]',
allAppsLabel: '[data-cy="all-apps-label"]',
allAppsHelperText: '[data-cy="all-apps-info-text"]',
customradio: '[data-cy="custom-radio"]',
customLabel: '[data-cy="custom-label"]',
customHelperText: '[data-cy="custom-info-text"]',
resourcesFolders: "[data-cy=resource-folders]",
resourcesWorkspaceVar: '[data-cy="resource-workspace-variable"]',
appsCreateCheck: "[data-cy=app-create-checkbox]",
@ -33,14 +52,48 @@ export const groupsSelector = {
appsDeleteLabel: "[data-cy=app-delete-label]",
foldersCreateCheck: "[data-cy=folder-create-checkbox]",
foldersCreateLabel: "[data-cy=folder-create-label]",
foldersHelperText: '[data-cy="folder-helper-text"]',
workspaceVarCheckbox: '[data-cy="env-variable-checkbox"]',
appsText: '[data-cy="apps-text"]',
appEditRadio: '[data-cy="app-edit-radio"]',
appEditLabel: '[data-cy="app-edit-label"]',
appEditHelperText: '[data-cy="app-edit-helper-text"]',
appViewRadio: '[data-cy="app-view-radio"]',
appViewLabel: '[data-cy="app-view-label"]',
appViewHelperText: '[data-cy="app-view-helper-text"]',
appHideCheckbox: '[data-cy="app-hide-from-dashboard-radio"]',
appHideHelperText: '[data-cy="app-hide-from-dashboard-helper-text"]',
appHideLabel: '[data-cy="app-hide-from-dashboard-label"]',
appHidePermissionModalLabel: '[data-cy="hide-from-dashboard-permission-label"]',
appHidePermissionModalHelperText: '[data-cy="hide-from-dashboard-permission-info-text"]',
addAppButton: '[data-cy="add-apps-buton"]',
addEditPermissionModal: '[data-cy = "add-edit-permission-modal"]',
addEditPermissionModalTitle: '[data-cy="modal-title"]',
permissionNameLabel: '[data-cy="permission-name-label"]',
permissionNameInput: '[data-cy="permission-name-input"]',
permissionNameHelperText: '[data-cy="permission-name-help-text"]',
permissionLabel: '[data-cy="permission-label"]',
editPermissionLabel: '[data-cy="edit-permission-label"]',
editPermissionHelperText: '[data-cy="edit-permission-info-text"]',
viewPermissionLabel: '[data-cy="view-permission-label"]',
viewPermissionHelperText: '[data-cy="view-permission-info-text"]',
hidePermissionInput: '[data-cy="hide-from-dashboard-permission-input"]',
editPermissionRadio: '[data-cy="edit-permission-radio"]',
viewPermissionRadio: '[data-cy="view-permission-radio"]',
deletePermissionIcon: '[data-cy="delete-button"]',
deleteMessage: '[data-cy="modal-message"]',
yesButton: '[data-cy="yes-button"]',
confirmText: "[data-cy=modal-message]",
confirmCancelButton: "[data-cy=confirm-cancel-button]",
confirmYesButton: "[data-cy=confirm-yes-button]",
addAppsButton: 'data-cy="[add-apps-buton"]',
multiSelectSearch: '[data-cy="multi-select-search"]',
multiSelectSearchInput:
'[data-cy="multi-select-search"]>>>>.select-search__input',
addUserButton: '[data-cy="undefined-group-add-button"]',
workspaceCreateLabel: '[data-cy="workspace-variable-create-label"]',
workspaceVarCreateLabel: '[data-cy="workspace-variable-create-label"]',
workspaceHelperText: '[data-cy="workspace-constants-helper-text"]',
selectAddButton: '[data-cy="add-button"]',
textDefaultGroup: '[data-cy="text-default-group"]',
helperTextNoAppsAdded: '[data-cy="helper-text-no-apps-added"]',
@ -49,6 +102,10 @@ export const groupsSelector = {
helperTextAdminAppAccess: '[data-cy="helper-text-admin-app-access"]',
helperTextAdminPermissions: '[data-cy="helper-text-admin-permissions"]',
updateGroupNameModalTitle: '[data-cy="update-group-title"]',
editGranularPermissionIcon: '[data-cy="edit-permission-button"]',
granularAccessPermission: '[data-cy="granular-access-permission"]',
groupChip: '[data-cy="group-chip"]',
resourceContainer: '[data-cy="resources-container"]',
groupLink: (groupname) => {
return `[data-cy="${cyParamName(groupname)}-list-item"]`;
},
@ -80,5 +137,20 @@ export const groupsSelector = {
duplicatedGroupLink: (groupName) => {
return `[data-cy="${cyParamName(groupName)}_copy-list-item"]`
},
userRoleLabel: '[data-cy="user-role-label"]',
warningText: '[data-cy="warning-text"]',
modalHeader: '[data-cy="modal-header"]',
modalMessage: '[data-cy="modal-message"]',
changeRoleModalHeader: '[data-cy="modal-title"]:eq(1)',
changeRoleModalMessage: '[data-cy="modal-body"]',
emptyPagePermissionTitle: '[data-cy="empty-page-title"]',
userEmptyPageIcon: '[data-cy="user-empty-page-icon"]',
userEmptyPageTitle: '[data-cy="user-empty-page"]',
userEmptyPageHelperText: '[data-cy="user-empty-page-info-text"]',
granularEmptyPageIcon: '[data-cy="empty-page-svg"]',
emptyPagePermissionHelperText: '[data-cy="empty-page-info-text"]',
groupNameUpdateLink: '[data-cy="group-name-update-link"]',
};

View file

@ -32,7 +32,7 @@ export const ssoSelector = {
redirectUrlLabel: "[data-cy=redirect-url-label]",
redirectUrl: "[data-cy=redirect-url]",
googleTile: '[data-cy="google-sign-in-text"]',
googleIcon: "[data-cy=google-sso-icon]",
googleIcon: "[data-cy=google-sso-button]",
googleSSOText: "[data-cy=google-sso-button-text]",
git: '[data-cy="github-sso-card"]',
gitEnableToggle: '[data-cy="github-toggle-input"]',
@ -41,8 +41,8 @@ export const ssoSelector = {
encriptedLabel: "[data-cy=encripted-label]",
clientSecretInput: "[data-cy=client-secret-input]",
gitTile: "[data-cy=git-tile]",
gitIcon: "[data-cy=git-sso-icon]",
gitSignInText: "[data-cy=git-sso-text]",
gitIcon: "[data-cy='git-sso-button-text']",
gitSignInText: "[data-cy='git-sso-button-text']",
gitSSOText: "[data-cy=git-sso-button-text]",
password: "[data-cy=left-menu-items] :eq(3)",
passwordEnableToggle: '[data-cy="password-enable-toggle"]',

View file

@ -17,7 +17,7 @@ export const usersSelector = {
adminUserEmail: "[data-cy=user-email]",
userState: "[data-cy=user-state]:eq(0)",
addUsersCardTitle: '[data-cy="add-users-card-title"]',
userNameInput: '[data-cy="name-input"]',
inputFieldName: "[data-cy=first-name-input]",
lastNameInput: "[data-cy=last-name-input]",
emailLabel: "[data-cy=email-label]",
@ -62,7 +62,8 @@ export const usersSelector = {
inputFieldBulkUpload: '[data-cy="input-field-bulk-upload"]',
copyInvitationLink: '[data-cy="copy-invitation-link"]',
uploadedFileData: '[data-cy="uploaded-file-data"]',
toastCloseButton:'.drawer-container > [style="position: fixed; z-index: 9999; inset: 16px; pointer-events: none;"] > .go4109123758 > .go2072408551 > [data-cy="toast-close-button"]',
modalClose: '.tj-base-btn.tj-large-btn.tj-primary-btn.close-btn',
toastCloseButton: '.drawer-container > [style="position: fixed; z-index: 9999; inset: 16px; pointer-events: none;"] > .go4109123758 > .go2072408551 > [data-cy="toast-close-button"]',
userName: (userName) => {
return `[data-cy="${cyParamName(userName)}-user-name"]`;
},

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

@ -17,4 +17,56 @@ export const onboardingSelectors = {
signupNameLabel: '[data-cy="name-label"]',
forgotEmailInput: '[data-cy="email-input-field-input"]',
createAnAccountLink: '[data-cy="create-an-account-link"]',
welcomeHeader: '[data-cy="welcome-to-tooljet!-header"]',
pageDescription: '[data-cy="onboarding-page-description"]',
setUpToolJetButton: '[data-cy="set-up-tooljet-button"]',
adminSetup: '[data-cy="admin-setup"]',
userNameInputLabel: '[data-cy="user-name-input-label"]',
nameInputField: '[data-cy="name-input-field"]',
emailInputLabel: '[data-cy="email-input-label"]',
// emailInput: '[data-cy="email-input"]',
passwordLabel: '[data-cy="password-label"]',
// passwordInput: '[data-cy="password-input"]',
passwordHelperText: '[data-cy="password-helper-text"]',
termsOfServiceLink: '[data-cy="terms-of-service-link"]',
privacyPolicyLink: '[data-cy="privacy-policy-link"]',
signUpTermsHelperText: '[data-cy="sign-up-terms-helper-text"]',
continueButton: '[data-cy="continue-button"]',
companyNameInput: '[data-cy="onboarding-company-name-input"]',
buildPurposeInput: '[data-cy="onboarding-build-purpose"]',
onboardingSubmitButton: '[data-cy="onboarding-submit-button"]',
workspaceNameInputLabel: '[data-cy="workspace-name-input-label"]',
workspaceNameInputField: '[data-cy="workspace-name-input-field"]',
OnbordingContinue: '[data-cy="onboarding-continue"]',
pricingPlanToggle: '[data-cy="plan-toggle"]',
planToggleLabel: '[data-cy="plan-toggle-label"]',
builderPrice: '[data-cy="builder-price"]',
endUserPrice: '[data-cy="enduser-price"]',
declineButton: '[data-cy="decline-button"]',
skipButton: '[data-cy="skip-button"]',
backLogo: '[data-cy="back-logo"]',
backToApps: '[data-cy="back-to-apps"]',
workspaceName: '[data-cy="workspace-name"]',
sampleAppHeader: '[data-cy="we\'ve-created-a-sample-application-for-you!-header"]',
stepsDetails: '[data-cy="steps-details"]',
infoDescription: '[data-cy="info-description"]',
comparePlansTitle: '[data-cy="compare-plans-title"]',
basicPlanTitle: '[data-cy="basic-plan-title"]',
planPrice: '[data-cy="plan-price"]',
pricePeriod: '[data-cy="price-period"]',
flexibleTitle: '[data-cy="flexible-title"]',
businessTitle: '[data-cy="business-title"]',
enterpriseTitle: '[data-cy="enterprise-title"]',
customPricingHeader: '[data-cy="custom-pricing-header"]',
noCreditCardBanner: '[data-cy="no-credit-card-banner"]',
beforeDiveInHeader: '[data-cy="before-we-dive-in,-would-you-like-to-start-your-free-trial?-header"]',
tellUsAbit: '[data-cy="tell-us-a-bit-about-yourself-header"]',
trialButton: '[data-cy="start-your-14-day-trial-button"]',
comparePlanDescription: '[data-cy="compare-plans-description"]',
onPremiseLink: '[data-cy="onpremise-link"]',
priceDescription: '[data-cy="price-description"]',
currentPlan: '[data-cy="current-plan"]',
upgradeButton: '[data-cy="upgrade-button"]',
planToggleInput: '[data-cy="plan-toggle-input"]',
discountDetails: '[data-cy="discount-details"]',
}

View file

@ -12,7 +12,7 @@ export const postgreSqlSelector = {
dataSourceSearchInputField: '[data-cy="home-page-search-bar"]',
postgresDataSource: "[data-cy='data-source-postgresql']",
dataSourceNameInputField: '[data-cy="data-source-name-input-filed"]',
dataSourceNameInputField: '[data-cy="data-source-name-input-field"]',
labelHost: '[data-cy="label-host"]',
labelPort: '[data-cy="label-port"]',
labelSsl: '[data-cy="label-ssl"]',
@ -88,3 +88,11 @@ export const postgreSqlSelector = {
eventQuerySelectionField: '[data-cy="query-selection-field"]',
};
export const airTableSelector = {
operationSelectDropdown: '[data-cy="operation-select-dropdown"]',
baseIdInputField: '[data-cy="base-id-input-field"]',
tableNameInputField: '[data-cy="table-name-input-field"]',
recordIdInputField: '[data-cy="record-id-input-field"]',
bodyInputField: '[data-cy="body-input-field"]',
};

View file

@ -0,0 +1,44 @@
export const cyParamName = (paramName = "") => {
return String(paramName)
.toLowerCase()
.replace(/\(s\)/g, "")
.replace(/\s+/g, "-");
};
export const restAPISelector = {
accordionHeader: (header) => {
return `[data-cy="widget-accordion-${cyParamName(header)}"]`;
},
subHeaderLabel: (header) => {
return `[data-cy="label-${cyParamName(header)}"]`;
},
subSection: (header) => {
return `[data-cy="${cyParamName(header)}-section"]`;
},
keyInputField: (header, index) => {
return `[data-cy="${cyParamName(header)}-key-input-field-${cyParamName(index)}"]`;
},
valueInputField: (header, index) => {
return `[data-cy="${cyParamName(header)}-value-input-field-${cyParamName(index)}"]`;
},
deleteButton: (header, index) => {
return `[data-cy="${cyParamName(header)}-delete-button-${cyParamName(index)}"]`;
},
addMoreButton: (header) => {
return `[data-cy="${cyParamName(header)}-add-button"]`;
},
dropdownLabel: (label) => {
return `[data-cy="${cyParamName(label)}-dropdown-label"]`;
},
inputField: (fieldName) => {
return `[data-cy="${cyParamName(fieldName)}-input-field"]`;
},
button: (buttonName) => {
return `[data-cy="button-${cyParamName(buttonName)}"]`;
},
authenticationAllUsersToggleSwitch:
'[data-cy="authentication-required-for-all-users-toggle-switch"]',
retryNetworkToggleSwitch: '[data-cy="retry-network-errors-toggle-input"]',
retryNetworkToggleText: '[data-cy="retry-network-errors-toggle-text"]',
retryNetworkToggleSubtext: '[data-cy="retry-network-errors-toggle-subtext"]',
readDocumentationLinkText: '[data-cy="link-read-documentation"]',
};

View file

@ -5,5 +5,6 @@ export const editVersionSelectors = {
};
export const confirmVersionModalSelectors = {
modalMessage: '[data-cy="modal-message"]',
modal: '[data-cy="confirm-dialogue-box-text"]',
yesButton: '[data-cy="yes-button"]',
};

View file

@ -1,20 +1,30 @@
export const cyParamName = (paramName = "") => {
return paramName.toLowerCase().replace(/\s+/g, "-");
};
import { cyParamName } from "./common";
export const workspaceConstantsSelectors = {
workspaceConstantsHelperText: '[data-cy="workspace-constant-helper-text"]',
emptyStateImage: '[data-cy="empty-state-image"]',
emptyStateHeader: '[data-cy="empty-state-header"]',
emptyStateText: '[data-cy="empty-state-text"]',
addNewConstantButton: '[data-cy="add-new-constant-button"]',
addNewConstantButton: '[data-cy="form-add-new-constant-button"]',
contantFormTitle: '[data-cy="constant-form-title"]',
addConstantButton: '[data-cy="add-constant-button"]',
envName: '[data-cy="env-name"]',
constantsTableNameHeader: '[data-cy="workspace-variable-table-name-header"]',
constantsTableValueHeader:
'[data-cy="workspace-variable-table-value-header"]',
nameInputFiled: '[data-cy="name-input-field"]',
nameFieldLabel: '[data-cy="name-label"]',
nameFieldHelperText: '[data-cy="name-info"]',
typeLabel: '[data-cy="type-label"]',
globalConstLabel: '[data-cy="global-constants-label"]',
globalConstHelperText: '[data-cy="global-constants-info"]',
secretsConstLabel: '[data-cy="secrets-constants-label"]',
secretsConstHelperText: '[data-cy="secrets-constants-info"]',
valueLabel: '[data-cy="value-label"]',
alertInfoText: '[data-cy="alert-info-text"]',
tableAddNewConstButton: '[data-cy="table-add-new-constant-button"]',
searchField: '[data-cy="-search-bar"]',
constantName: (constName) => {
return `[data-cy="${cyParamName(constName)}-workspace-constant-name"]`;
},
@ -30,4 +40,7 @@ export const workspaceConstantsSelectors = {
constHideButton: (constName) => {
return `[data-cy="${cyParamName(constName)}-constant-visibility"]`;
},
constantsType: (type) => {
return `[data-cy="${cyParamName(type)}-constants-input"]`;
},
};

View file

@ -0,0 +1,6 @@
export const airtableText = {
airtable: "Airtable",
cypressairtable: "cypress-Airtable",
ApiKey: "Personal access token",
apikeyPlaceholder: "**************",
};

View file

@ -0,0 +1,8 @@
export const amazonAthenaText = {
AmazonAthena: "Amazon Athena",
cypressAmazonAthena: "cypress-Amazon Athena",
labelAccesskey: "Access key",
labelSecretKey: "Secret key",
placeholderEnteraAccessKey: "Enter access key",
placeholderSecretKey:"**************",
};

View file

@ -0,0 +1,8 @@
export const amazonSesText = {
AmazonSES: "Amazon SES",
cypressAmazonSES: "cypress-Amazon SES",
labelAccesskey: "Access key",
labelSecretKey: "Secret key",
placeholderAccessKey: "Enter access key",
placeholderSecretKey:"**************",
};

View file

@ -0,0 +1,12 @@
export const appwriteText = {
appwrite: "Appwrite",
cypressAppwrite: "cypress-Appwrite",
host: "Host",
ProjectID: "Project ID",
DatabaseID: "Database ID",
SecretKey: "Secret Key",
SecretKeyPlaceholder: "**************",
hostPlaceholder: "Appwrite database host/endpoint",
projectIdPlaceholder: "Appwrite project id",
databaseIdPlaceholder: "Appwrite Database id",
};

View file

@ -0,0 +1,8 @@
export const awsLambdaText = {
awsLambda: "AWS Lambda",
cypressawsLambda: "cypress-aws-lambda",
labelAccesskey: "Access key",
labelSecretKey: "Secret key",
placeholderAccessKey: "Enter access key",
placeholderSecretKey: "**************",
};

View file

@ -0,0 +1,12 @@
export const awsTextractText = {
awsTextract: "AWS Textract",
cypressawsLambda: "cypress-aws-textract",
labelAccesskey: "Access key",
labelSecretKey: "Secret key",
placeholderAccessKey: "Enter access key",
placeholderSecretKey: "**************",
documentName:
"JVBERi0xLjQKJeLjz9MKMSAwIG9iago8PCAvVHlwZSAvQ2F0YWxvZyAvUGFnZXMgMiAwIFIgPj4KZW5kb2JqCjIgMCBvYmoKPDwgL1R5cGUgL1BhZ2VzIC9LaWRzIFszIDAgUl0gL0NvdW50IDEgPj4KZW5kb2JqCjMgMCBvYmoKPDwgL1R5cGUgL1BhZ2UgL1BhcmVudCAyIDAgUiAvUmVzb3VyY2VzIDw8IC9Gb250IDw8IC9GMSA0IDAgUiA+PiA+PiAvQ29udGVudHMgNSAwIFIgPj4KZW5kb2JqCjQgMCBvYmoKPDwgL1R5cGUgL0ZvbnQgL1N1YnR5cGUgL1R5cGUxIC9CYXNlRm9udCAvSGVsdmV0aWNhLUJvbGQgPj4KZW5kb2JqCjUgMCBvYmoKPDwgL0xlbmd0aCAxMjUgPj4Kc3RyZWFtCkJUIC9GMSAxMiBUZiAxMDAgNzAwIFRkICgoSGVsbG8sIEFtYXpvbiBUZXh0cmFjdCEpIFRqIEVUCmVuZHN0cmVhbQplbmRvYmoKeHJlZgowIDYKMDAwMDAwMDAwMCA2NTUzNSBmIAowMDAwMDAwMDExIDAwMDAwIG4gCjAwMDAwMDAwNTQgMDAwMDAgbgAKMDAwMDAwMDEwMyAwMDAwMCBuIAowMDAwMDAwMTcyIDAwMDAwIG4gCnRyYWlsZXIKPDwgL1NpemUgNiAvUm9vdCAxIDAgUiA+PgpzdGFydHhyZWYKMjIzCiUlRU9G",
bucketName: "reimbursement-receipt-files",
keyName: "reimbursement_receipt_1718364944018.png",
};

View file

@ -0,0 +1,6 @@
export const baseRowText = {
baserow: "baserow",
cypressBaseRow: "cypress-baserow",
lableApiToken: "API token",
placeholderApiToken:"**************",
};

View file

@ -27,6 +27,7 @@ export const commonText = {
folderCreatedToast: "Folder created.",
createFolder: "Create folder",
AddedToFolderToast: "Added to folder.",
appCreatedToast: "App created successfully!",
appRemovedFromFolderMessage:
"The app will be removed from this folder, do you want to continue?",
appRemovedFromFolderTaost: "Removed from folder.",
@ -51,6 +52,7 @@ export const commonText = {
`Are you sure you want to delete the folder ${folderName}? Apps within the folder will not be deleted.`;
},
closeButton: "modal close",
cloneAppErrorToast: "You do not have create datasource permissions to perform this action",
workEmailLabel: "Email",
emailInputError: "Email is invalid",
passwordLabel: "Password *",
@ -171,7 +173,7 @@ export const commonText = {
// iframeLinkLabel: "Get embeddable link for this application",
// ifameLinkCopyButton: "copy",
},
groupInputFieldLabel: "Select Group",
groupInputFieldLabel: "Select groups",
documentationLink: "Read Documentation",
constantsNameError:
"Constant name should start with a letter or underscore and can only contain letters, numbers and underscores",
@ -179,7 +181,7 @@ export const commonText = {
"Value should be less than 10000 characters and cannot be empty",
createApp: "Create app",
appName: "App Name",
appName: "App name",
enterAppName: "Enter app name",
appNameInfoLabel: "App name must be unique and max 50 characters",
renameApp: "Rename app",

View file

@ -2,9 +2,18 @@ export const dataSourceText = {
labelDataSources: "Datasources",
labelAddDataSource: "+ add data source",
allDataSources: "All data sources (42)",
allDatabase: "Databases (18)",
allApis: "APIs (20)",
allDataSources: () => {
return Cypress.env("marketplace_action")
? "All data sources (44)"
: "All data sources (42)";
},
commonlyUsed: "Commonly used (5)",
allDatabase: () => {
return Cypress.env("marketplace_action")
? "Databases (20)"
: "Databases (18)";
},
allApis: "APIs (21)",
allCloudStorage: "Cloud Storages (4)",
pluginsLabelAndCount: "Plugins (0)",
@ -12,11 +21,11 @@ export const dataSourceText = {
labelHost: "Host",
labelPort: "Port",
labelSSL: "SSL",
labelDbName: "Database Name",
labelDbName: "Database name",
labelUserName: "Username",
labelPassword: "Password",
label: "Encrypted",
sslCertificate: "SSL Certificate",
sslCertificate: "SSL certificate",
whiteListIpText:
"Please white-list our IP address if the data source is not publicly accessible",
textCopy: "Copy",
@ -71,4 +80,11 @@ export const dataSourceText = {
labelNoEventhandler: "No event handlers",
toastDSSaved: "Data Source Saved",
unSavedModalTitle: "Unsaved Changes",
sslCertificateLabel: "SSL Certificate",
caCertificateOption: "CA certificate",
clientCertificateOption: "Client certificate",
clientKeyLabel: "Client Key",
clientCertLabel: "Client Cert",
caCertLabel: "CA Cert",
};

View file

@ -1,7 +1,7 @@
export const appVersionText = {
createNewVersion: "Create new version",
createVersion: "Create Version",
versionNameLabel: "Version Name",
versionNameLabel: "Version name",
createVersionFromLabel: "Create version from",
emptyToastMessage: "Version name should not be empty",
createdToastMessage: "Version Created",

View file

@ -0,0 +1,6 @@
export const GraphQLText = {
GraphQL: "GraphQL",
cypressGraphQL: "cypress-GraphQL",
urlInputLabel: "URL",
urlInputPlaceholder: "https://api.example.com/v1/graphql",
};

View file

@ -0,0 +1,21 @@
export const harperDbText = {
harperDb: "HarperDB",
cypressHarperDB: "cypressHarperDB",
hostLabel: "Host",
hostInputPlaceholder: "Enter host",
portLabel: "Port",
portPlaceholder: "Enter port",
userNameLabel: "Username",
passwordlabel: "Password",
userNamePlaceholder: "Enter username",
passwordPlaceholder: "**************",
recordsValue: `[{id: 10, name: 'QA', age: 24}]`,
hashValue: "[10]",
attributesValue: "['name']",
searchAttributeValue: "name",
searchValue: "QA",
condtionValue: `[{'search_attribute': 'name', 'search_type': 'between', 'search_value': [1, 5]}, {'search_attribute': 'name', 'search_type': 'equals', 'search_value': 'QA'}]`,
sqlValue: "SELECT * FROM test_schema.test_table",
schemaValue: "test_schema",
tableValue: "test_table",
};

View file

@ -1,36 +1,41 @@
export const groupsText = {
pageTitle: "User Groups",
createNewGroupButton: "Create new group",
createNewGroupButton: "Add new group",
tableHeader: "Name",
allUsers: "All users",
admin: "Admin",
cardTitle: "Create new group",
cardTitle: "Add new group",
cancelButton: "Cancel",
createGroupButton: "Create Group",
groupNameExistToast: "Group name already exist",
testGroup: "Test",
groupCreatedToast: "Group has been created",
userGroup: "User group",
appsLink: "Apps",
appsLink: " Apps",
usersLink: "Users",
permissionsLink: "Permissions",
addButton: "Add apps",
addUsersButton: "Add users",
userNameTableHeader: "User name",
permissionstableHedaer: "Permissions",
permissionsTableHeader: "Permissions",
granularAccessPermissionHeader: 'Permission',
emailTableHeader: "Email id",
resourcesTableHeader: "Resources",
resourcesTableHeader: "Resource",
resourcesApps: "Apps",
resourcesFolders: "Folder",
createLabel: "Create",
folderCreateLabel: "Create/Update/Delete",
folderHelperText: "All operations on folders",
deleteLabel: "Delete",
deleteMessage: "This permission will be permanently deleted. Do you want to continue?",
permissionUpdatedToast: "Group permissions updated",
confirmText:
"This group will be permanently deleted. Do you want to continue?",
confirmCancelButton: "Cancel",
confirmYesButton: "Yes",
resourcesWorkspaceVar: "Workspace constants/variables",
workspaceCreateLabel: "Create/Update/Delete",
workspaceHelperText: "All operations on workspace constants",
textDefaultGroup: "Default group",
textAppName: "App name",
helperTextNoAppsAdded: "No apps are added to the group",
@ -46,4 +51,58 @@ export const groupsText = {
groupNameUpdateSucessToast: "Group name updated successfully",
editGroupNameButton: "Rename",
deleteGroupButton: "Delete group",
editPermissionModalTitle: "Edit app permissions",
addPermissionModalTitle: "Add apps permissions",
appCreateHelperText: 'Create apps in this workspace',
appDeleteHelperText: 'Delete any app in this workspace',
appEditLabelText: 'Edit',
appEditHelperText: 'Access to app builder',
appViewLabel: 'View',
appViewHelperText: "Only access released version of apps",
appHideHelperText: "App will be accessible by URL only",
appHideLabel: "Hide from dashboard",
appHideLabelPermissionModal: "Hide from dashbaord",
groupChipText: 'All apps',
adminAccessHelperText: " Admin has all permissions. This is not editableread documentation to know more !",
enduserAccessHelperText: " End-user can only have permission to view appsread documentation to know more !",
nameTableHeader: 'Name',
permissionTableHeader: 'Permission',
permissionNameLabel: 'Permission name',
permissionNameHelperText: 'Permission name must be unique and max 50 characters',
permissionLabel: 'Permission',
editPermissionLabel: 'Edit',
editPermissionHelperText: 'Access to app builder',
viewPermissionLabel: 'View',
viewPermissionHelperText: 'Only access released version of apps',
resourcesheader: 'Resources',
allAppsLabel: 'All apps',
allAppsHelperText: 'This will select all apps in the workspace including any new apps created',
customLabel: 'Custom',
customHelperText: 'Select specific applications you want to add to the group',
updateButtonText: 'Update',
addButtonText: 'Add',
userRole: 'User role',
warningText: "Users must be always be part of one default group. This will define the user count in your plan.",
continueButtonText: "Continue",
roleUpdateToastMessage: "Role updated successfully",
endUserToBuilderMessage: "Changing the user role from end-user to builder will grant access the user access to all resources.Are you sure you want to continue?",
endUserToAdminMessage: "Changing the user role from end-user to admin will grant the user access to all resources and settings.Are you sure you want to continue?",
builderToEnduserMessage: "Changing the user role from builder to end-user will revoke their access to edit all resources.Are you sure you want to continue?",
builderToAdminMessage: "Changing user role from builder to admin will grant access to all resources and settings.Are you sure you want to continue?",
adminToBuilderMessage: "Changing your user default group from admin to builder will revoke your access to settings.Are you sure you want to continue?",
adminToEnduserMessage: "Changing the user role from admin to end-user will revoke their access to edit all resources and settings.Are you sure you want to continue?",
modalHeader: "Can not remove last active admin",
modalMessage: "Cannot change role of last present admin, please add another admin and change the role",
userAddedToast: "Users added to the group",
changeUserRoleHeader: " Change in user role",
changeUserRoleMessage: "Granting this permission to the user group will result in a role change for the following user(s) from end-users to builders. Are you sure you want to continue?",
cantCreatePermissionModalHeader: "Cannot create permissions",
cantCreatePermissionModalMessage: "End-users can only be granted permission to view apps. If you wish to add this permission, kindly change the following users role from end-user to builder",
deletePermissionToast: "Deleted permission successfully",
createPermissionToast: "Permission created successfully!",
userEmptyPageTitle: "No users added yet",
userEmptyPageHelperText: "Add users to this group to configure permissions for them!",
emptyPagePermissionTitle: "No permissions added yet",
emptyPagePermissionHelperText: "Add assets to configure granular, asset-level permissions for this user group",
};

View file

@ -57,7 +57,7 @@ export const usersText = {
buttonUploadCsvFile: "Upload CSV file",
helperTextBulkUpload:
"Download the ToolJet template to add user details or format your file in the same as the template. ToolJet wont be able to recognise files in any other format. ",
"Download the template to add user details or format your file in the same way as the template. Files in any other format may not be recognized. ",
helperTextSelectFile: "Select a CSV file to upload",
helperTextDropFile: "Or drag and drop it here",
};

View file

@ -0,0 +1,14 @@
export const minioText = {
minio: "Minio",
cypressMinio: "cypressMinio",
hostLabel: "Host",
hostInputPlaceholder: "Enter host",
portLabel: "Port",
portPlaceholder: "Enter port",
labelAccesskey: "Access key",
labelSecretKey: "Secret key",
placeholderAccessKey: "Enter access key",
placeholderSecretKey: "**************",
bucketName: `my-second-bucket`,
objectName: `mybucket`,
};

View file

@ -0,0 +1,34 @@
export const onboardingText = {
welcomeHeader: "Welcome to ToolJet!",
pageDescription: "Let's set up your admin account and workspace to get started!",
setUpToolJetButton: "Set up ToolJet",
userNameInputLabel: "User Name",
nameInputLabel: "Name",
emailInputLabel: "Email",
passwordLabel: "Password",
passwordHelper: "Password must be at least 8 characters.",
termsOfServiceLink: "Terms of Service",
privacyPolicyLink: "Privacy Policy",
signUpTermsHelperTextCommunity: "By signing up you are agreeing to the terms and conditions.",
signUpTermsHelperTextEnterprise: "By signing up you are agreeing to the",
companyNameInputPlaceholder: "Company Name",
buildPurposePlaceholder: "Purpose of building",
workspaceNameInputLabelText: "Workspace Name",
sampleAppHeaderText: "We've created a sample application for you!",
sampleAppDescriptionText: "The sample application comes with a sample PostgreSQL database for you to play around with. You can also get started quickly with pre-built applications from our template collection!",
freeTrialHeaderText: "Before we dive in, would you like to start your free trial?",
monthlyPricingText: "Monthly",
planToggleLabelText: "Monthly",
builderPriceText: "$30",
endUserPriceText: "$10",
comparePlansText: "Compare plans",
basicPlanText: "Basic Plan",
flexibleText: "Flexible",
businessText: "Business",
enterpriseText: "Enterprise",
customPricingText: "Custom pricing",
noCreditCardText: "No credit card required!",
priceMonthlyText: "/month",
defaultPrice: "$0",
infoDescriptionText: "Build & scale your internal tools faster than ever with our advanced features."
};

View file

@ -4,8 +4,8 @@ export const postgreSqlText = {
allDataSources: () => {
return Cypress.env("marketplace_action")
? "All data sources (44)"
: "All data sources (42)";
? "All data sources (45)"
: "All data sources (43)";
},
commonlyUsed: "Commonly used (5)",
allDatabase: () => {
@ -13,18 +13,18 @@ export const postgreSqlText = {
? "Databases (20)"
: "Databases (18)";
},
allApis: "APIs (20)",
allApis: "APIs (21)",
allCloudStorage: "Cloud Storages (4)",
postgreSQL: "PostgreSQL",
labelHost: "Host",
labelPort: "Port",
labelSSL: "SSL",
labelDbName: "Database Name",
labelDbName: "Database name",
labelUserName: "Username",
labelPassword: "Password",
label: "Encrypted",
sslCertificate: "SSL Certificate",
sslCertificate: "SSL certificate",
whiteListIpText:
"Please white-list our IP address if the data source is not publicly accessible",
textCopy: "Copy",

View file

@ -2,8 +2,7 @@ export const redisText = {
redis: "Redis",
cypressRedis: "cypress-redis",
errorMaxRetries:
'Reached the max retries per request limit (which is 1). Refer to "maxRetriesPerRequest" option for details.',
errorPort: "Port should be >= 0 and < 65536. Received type number (108299).",
errorInvalidUserOrPassword: "WRONGPASS invalid username-password pair",
errorMaxRetries: "Connection could not be established",
errorPort: "Connection could not be established",
errorInvalidUserOrPassword: "Connection could not be established",
};

View file

@ -0,0 +1,58 @@
export const restAPIText = {
restAPI: "REST API",
credentialsText: "CREDENTIALS",
baseUrlLabel: "Base URL",
headersLabel: "Headers",
urlParametesLabel: "URL parameters",
bodyLabel: "Body",
cookiesLabel: "Cookies",
authenticationText: "AUTHENTICATION",
authenticationTypeLabel: "Authentication type",
noneText: "None",
editButtonText: "Edit",
basicAuth: {
basicText: "Basic",
usernameLabel: "Username",
passwordLabel: "Password",
},
bearerAuth: {
bearerText: "Bearer",
tokenLabel: "Token",
},
oAuthText: "OAuth 2.0",
grantTypeLabel: "Grant type",
authorizationCode: {
authorizationCodeLabel: "Authorization code",
addAccessTokenLabel: "Add access token to",
headerPrefixLabel: "Header prefix",
requestHeader: "Request header",
accessTokenURLLabel: "Access token URL",
accessTokenURLCustomHeadersLabel: "Access token URL custom headers",
clientIDLabel: "Client ID",
clientSecretLabel: "Client secret",
scopeLabel: "Scope(s)",
customQueryParametersLabel: "Custom query parameters",
authorizationURLLabel: "Authorization URL",
customAuthenticationParametersLabel: "Custom authentication parameters",
clientAuthentication: "Client authentication",
sendBasicAuthheaderOption: "Send as basic auth header",
sendClientCredentialsBodyOption: "Send client credentials in body",
authenticationRequiredUsersToggle: "Authentication required for all users",
},
clientCredentials: {
clientCredentialsLabel: "Client credentials",
accessTokenURLLabel: "Access token URL",
accessTokenURLCustomHeadersLabel: "Access token URL custom headers",
clientIDLabel: "Client ID",
clientSecretLabel: "Client secret",
scopeLabel: "Scope(s)",
audiencelabel: "Audience",
},
authenticationHeader: "Authentication",
secureSocketsLayerText: "SECURE SOCKETS LAYER",
generalSettingsText: "GENERAL SETTINGS",
retryNetworkErrorsToggleLabel: "Retry on network errors",
retryToggleHelperText:
"By default, ToolJet tries to hit API endpoint 3 times before declaring query failed as server did not respond",
};

View file

@ -0,0 +1,11 @@
export const twilioText = {
twilio: "Twilio",
cypresstwilio: "cypress-Twilio",
authTokenLabel: "Auth Token",
authTokenPlaceholder: "**************",
accountSidLabel: "Account SID",
accountSidPlaceholder: "Account SID for Twilio",
messagingSIDLabel: "Messaging Service SID",
messagingSIDPalceholder: "Messaging Service SID for Twilio",
messageText: "Sending test message to check twilio",
};

View file

@ -17,6 +17,21 @@ export const deleteVersionText = {
},
};
export const onlydeleteVersionText = {
deleteModalText: (text) => {
return `Deleting a version will permanently remove it from all environments.Are you sure you want to delete this version - ${cyParamName(
text
)}?`;
// `Are you sure you want to delete this version - ${cyParamName(
// text
// )}?`;
},
deleteToastMessage: (version) => {
return `Cannot delete only version of app`;
},
};
export const releasedVersionText = {
cannotUpdateReleasedVersionToastMessage:
"You cannot update a released version",
@ -28,7 +43,7 @@ export const releasedVersionText = {
cannotDeleteReleasedVersionToastMessage:
"You cannot delete a released version",
releasedAppText:
"This is a released app. Create a new version to make changes.",
"App cannot be edited after promotion. Please create a new version from Development to make any changes.",
releasedVersionConfirmText:
"Are you sure you want to release this version of the app?",
buttonReleaseApp: "Release App",

View file

@ -1,10 +1,20 @@
export const workspaceConstantsText = {
workspaceConstantsHelperText:
"To resolve a Workspace constant use {{constants.access_token}}",
"To resolve a global workspace constant use {{constants.access_token}}",
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.",
addNewConstantButton: "Create new constant",
"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: "Constant has been created",
constantCreatedToast: (type) => { return `${type} constant created successfully!` },
secretConstantCreatedToast: "Secret constant created successfully!",
constantsExisitToast: (type) => { return `${type} constant already exists!` },
workspaceConstantsHelperText: "To resolve a global workspace constant use",
nameFieldHelperText: 'Name must be unique and max 50 characters',
globalConstHelperText: 'The values can be used anywhere in the product',
secretsConstHelperText: 'The values are hidden and can only be used in data sources and queries',
addConstantButton: 'Add constant',
noResultFoundHeader: 'No workspace constants found',
secretsHiddenText: 'Values of secret constants are hidden',
};

View file

@ -0,0 +1,29 @@
import { fake } from "Fixtures/fake";
import { addAndVerifyOnSingleLine } from "Support/utils/editor/codehinter";
import { commonSelectors, commonWidgetSelector } from "Selectors/common";
import {
openEditorSidebar,
} from "Support/utils/commonWidget";
describe("Editor- CodeHinter", () => {
let currentVersion = "";
let newVersion = [];
let versionFrom = "";
beforeEach(() => {
cy.apiLogin();
cy.apiCreateApp(`${fake.companyName}-inspector-App`);
cy.apiOpenApp();
});
it.only("should verify singleLine: non dynamic values", () => {
cy.dragAndDropWidget("Text", 500, 500);
addAndVerifyOnSingleLine(`{{globals.currentUser.email}} {{globals.currentUser.firstName}} {{globals.currentUser.lastName}} {{globals.currentUser.id}} {{globals.currentUser.avatarId}} {{globals.currentUser.groups[0]}} {{globals.currentUser.groups[1]}} {{globals.currentUser.groups[2]}} {{globals.currentUser.role}} {{globals.currentUser.ssoUserInfo}} {{globals.environment.id}} {{globals.environment.name}} {{globals.mode.value}} {{globals.theme.name}} {{globals.urlparams}} {{page.handle}} {{page.id}} {{page.name}}`)
cy.get('[data-cy=draggable-widget-text1]:eq(0)').invoke('text').then((text => { cy.log(text) }))
});
it("should verify singleLine: dynamic values", () => {
});
it("should verify multiLine: non dynamic values", () => {
});
it("should verify multiLine: dynamic values", () => {
});
});

View file

@ -0,0 +1,235 @@
import { fake } from "Fixtures/fake";
import { addAndVerifyOnSingleLine } from "Support/utils/editor/codehinter";
import { commonSelectors, commonWidgetSelector } from "Selectors/common";
import {
openEditorSidebar,
} from "Support/utils/commonWidget";
describe.only('Tooljet Resolution Cases', () => {
beforeEach(() => {
cy.apiLogin();
cy.apiCreateApp(`${fake.companyName}-inspector-App`);
cy.openApp();
});
it.only('Basic Component and Query Value Access', () => {
cy.dragAndDropWidget("Text Input", 100, 200);
cy.dragAndDropWidget("Text", 100, 100);
addAndVerifyOnSingleLine('{{components.textinput1.value}}');
cy.get(commonWidgetSelector.draggableWidget("textinput1")).type("Hello World");
cy.get(commonWidgetSelector.draggableWidget("text1")).should('have.text', 'Hello World');
cy.pause()
// Example 2
// cy.dragAndDropWidget('Table', 100, 300);
// addAndVerifyOnSingleLine('{{queries.user.data}}', 'data');
// // Example 3
// cy.dragAndDropWidget('Text', 200, 100);
// addAndVerifyOnSingleLine('{{queries.name.data.hello}}');
// // Example 4
// cy.dragAndDropWidget('Text', 300, 100);
// addAndVerifyOnSingleLine('{{queries.products[components.dropdown1.value]?.details.price}}');
// Example 5
cy.dragAndDropWidget('Text', 400, 100);
addAndVerifyOnSingleLine('{{globals.currentUser.email}}');
cy.get(commonWidgetSelector.draggableWidget("text2")).should('have.text', 'dev@tooljet.io');
// Example 6
cy.dragAndDropWidget('Text', 500, 100);
addAndVerifyOnSingleLine('{{page.variables.pageTitle}}');
// Example 7
cy.dragAndDropWidget('variables.userId');
addAndVerifyOnSingleLine('{{variables.userId}}');
// Example 8
cy.dragAndDropWidget('queries.localeHelper.data.PRFieldHint');
addAndVerifyOnSingleLine('{{queries.localeHelper.data.PRFieldHint}}');
// Example 9
cy.dragAndDropWidget('queries.8256e53e-061f-4108-8ab5-d9a0db607e8f.data.countryFieldHint');
addAndVerifyOnSingleLine('{{queries.8256e53e-061f-4108-8ab5-d9a0db607e8f.data.countryFieldHint}}');
// Example 10
cy.dragAndDropWidget('page.otherProperty.someValue');
addAndVerifyOnSingleLine('{{page.otherProperty.someValue}}');
});
it('Dynamic Access Using Brackets', () => {
// Example 1
cy.dragAndDropWidget('components[components.text1.data].value');
addAndVerifyOnSingleLine('{{components[components.text1.data].value}}');
// Example 2
cy.dragAndDropWidget('queries[ ${components.dropdown1.value}].data.users');
addAndVerifyOnSingleLine('{{queries[ ${components.dropdown1.value}].data.users}}');
// Example 3
cy.dragAndDropWidget('queries["components.dropdown.value"]?.data');
addAndVerifyOnSingleLine('{{queries["components.dropdown.value"]?.data}}');
// Example 4
cy.dragAndDropWidget('components[queries.products.data].value');
addAndVerifyOnSingleLine('{{components[queries.products.data].value}}');
// Example 5
cy.dragAndDropWidget('queries[queries.user.data.fieldKey]?.data');
addAndVerifyOnSingleLine('{{queries[queries.user.data.fieldKey]?.data}}');
});
it('Logical Operators and Conditionals', () => {
// Example 1
cy.dragAndDropWidget('components.text1.value || queries.user.data');
addAndVerifyOnSingleLine('{{components.text1.value || queries.user.data}}');
// Example 2
cy.dragAndDropWidget('queries.currency.data?.currency || globals.defaultCurrency');
addAndVerifyOnSingleLine('{{queries.currency.data?.currency || globals.defaultCurrency}}');
// Example 3
cy.dragAndDropWidget('components.text1.value ? components.text1.value + " - active" : "Inactive"');
addAndVerifyOnSingleLine('{{components.text1.value ? components.text1.value + " - active" : "Inactive"}}');
// Example 4
cy.dragAndDropWidget('(components.numberinput1.value || 0).toFixed(2).toString().padStart(8, "0")');
addAndVerifyOnSingleLine('{{(components.numberinput1.value || 0).toFixed(2).toString().padStart(8, "0")}}');
});
it('String Manipulation', () => {
// Example 1
cy.dragAndDropWidget('components.text1.value.toUpperCase()');
addAndVerifyOnSingleLine('{{components.text1.value.toUpperCase()}}');
// Example 2
cy.dragAndDropWidget('variables.userId.substring(0, 5)');
addAndVerifyOnSingleLine('{{variables.userId.substring(0, 5)}}');
// Example 3
cy.dragAndDropWidget('Hello {{components.text1.value}}');
addAndVerifyOnSingleLine('Hello {{components.text1.value}}');
// Example 4
cy.dragAndDropWidget('Hello {{components.text1.value + "!"}}');
addAndVerifyOnSingleLine('Hello {{components.text1.value + "!"}}');
// Example 5
cy.dragAndDropWidget('components.text1.data?.toString() || "default"');
addAndVerifyOnSingleLine('{{components.text1.data?.toString() || "default"}}');
// Example 6
cy.dragAndDropWidget('components.text1.value + " " + components.text2.value');
addAndVerifyOnSingleLine('{{components.text1.value + " " + components.text2.value}}');
// Example 7
cy.dragAndDropWidget('"Real time Range 1 : <b>" + components.rangeslider2.value[0] + "</b>"');
addAndVerifyOnSingleLine('{{"Real time Range 1 : <b>" + components.rangeslider2.value[0] + "</b>"}}');
});
it('Arrays and Iterations', () => {
// Example 1
cy.dragAndDropWidget('queries.orders.data.map(order => order.id).join(", ")');
addAndVerifyOnSingleLine('{{queries.orders.data.map(order => order.id).join(", ")}}');
// Example 2
cy.dragAndDropWidget('Array.from({length: queries?.tooljetdbGetProducts?.data?.filter(product => product.id == components.dropdown1.value)[0]?.quantity ?? 0}, (_, i) => i + 1)');
addAndVerifyOnSingleLine('{{Array.from({length: queries?.tooljetdbGetProducts?.data?.filter(product => product.id == components.dropdown1.value)[0]?.quantity ?? 0}, (_, i) => i + 1)}}');
// Example 3
cy.dragAndDropWidget('queries.user?.data?.filter(item => item.id === components.selected.value)');
addAndVerifyOnSingleLine('{{queries.user?.data?.filter(item => item.id === components.selected.value)}}');
// Example 4
cy.dragAndDropWidget('queries.products.data.find(p => p.id === variables.productId)?.name || "Unknown"');
addAndVerifyOnSingleLine('{{queries.products.data.find(p => p.id === variables.productId)?.name || "Unknown"}}');
// Example 5
cy.dragAndDropWidget('queries.data.items.filter(item => item.active).length');
addAndVerifyOnSingleLine('{{queries.data.items.filter(item => item.active).length}}');
});
it('Numeric Operations', () => {
// Example 1
cy.dragAndDropWidget('10 * (components.pagination1.currentPageIndex - 1)');
addAndVerifyOnSingleLine('{{10 * (components.pagination1.currentPageIndex - 1)}}');
// Example 2
cy.dragAndDropWidget('components?.pagination1?.currentPageIndex + 1');
addAndVerifyOnSingleLine('{{components?.pagination1?.currentPageIndex + 1}}');
});
it('Nested Property Access', () => {
// Example 1
cy.dragAndDropWidget('queries.user[components.text1.data].extra.field');
addAndVerifyOnSingleLine('{{queries.user[components.text1.data].extra.field}}');
// Example 2
cy.dragAndDropWidget('queries.user[components.button1.data].extra.field');
addAndVerifyOnSingleLine('{{queries.user[components.button1.data].extra.field}}');
// Example 3
cy.dragAndDropWidget('queries.user.data[0]');
addAndVerifyOnSingleLine('{{queries.user.data[0]}}');
// Example 4
cy.dragAndDropWidget('components.text1.data');
addAndVerifyOnSingleLine('{{components.text1.data}}');
});
it('Complex Template Strings', () => {
// Example 1
cy.dragAndDropWidget('Hello {{components.text1.value}} {{variables.userId}} {{globals.apiKey}}');
addAndVerifyOnSingleLine('Hello {{components.text1.value}} {{variables.userId}} {{globals.apiKey}}');
// Example 2
cy.dragAndDropWidget('page.variables.pageTitle');
addAndVerifyOnSingleLine('{{page.variables.pageTitle}}');
// Example 3
cy.dragAndDropWidget('components.text1.value + variables.userId + globals.apiKey + page.variables.pageTitle');
addAndVerifyOnSingleLine('{{components.text1.value + variables.userId + globals.apiKey + page.variables.pageTitle}}');
});
it('Nullable/Optional Chaining', () => {
// Example 1
cy.dragAndDropWidget('components?.text1?.value');
addAndVerifyOnSingleLine('{{components?.text1?.value}}');
// Example 2
cy.dragAndDropWidget('components?.text1["value"]');
addAndVerifyOnSingleLine('{{components?.text1["value"]}}');
// Example 3
cy.dragAndDropWidget('queries["user"]?.data');
addAndVerifyOnSingleLine('{{queries["user"]?.data}}');
// Example 4
cy.dragAndDropWidget('queries?.tooljetdbGetProducts?.data?.filter');
addAndVerifyOnSingleLine('{{queries?.tooljetdbGetProducts?.data?.filter}}');
});
it('Need to be Verified', () => {
// Example 1
cy.dragAndDropWidget('components[queries.user.data[0]].value');
addAndVerifyOnSingleLine('{{components[queries.user.data[0]].value}}');
// Example 2
cy.dragAndDropWidget('queries.products.data.find(p => p.id === variables.productId)?.name || "Unknown"');
addAndVerifyOnSingleLine('{{queries.products.data.find(p => p.id === variables.productId)?.name || "Unknown"}}');
// Example 3
cy.dragAndDropWidget('queries[ ${components.dropdown1.value}_${components.dropdown2.value}]?.data');
addAndVerifyOnSingleLine('{{queries[ ${components.dropdown1.value}_${components.dropdown2.value}]?.data}}');
// Example 4
cy.dragAndDropWidget('Array.from({length: queries?.tooljetdbGetProducts?.data?.filter(product => product.id == components.dropdown1.value)[0]?.quantity ?? 0}, (_, i) => i + 1)');
addAndVerifyOnSingleLine('{{Array.from({length: queries?.tooljetdbGetProducts?.data?.filter(product => product.id == components.dropdown1.value)[0]?.quantity ?? 0}, (_, i) => i + 1)}}');
// Example 5
cy.dragAndDropWidget('queries["components.dropdown.value"]?.data');
addAndVerifyOnSingleLine('{{queries["components.dropdown.value"]?.data}}');
});
});

View file

@ -32,7 +32,7 @@ import {
addSupportCSAData,
} from "Support/utils/events";
describe("Editor- Test Button widget", () => {
describe("Editor- Test Button widget ", () => {
beforeEach(() => {
cy.apiLogin();
cy.apiCreateApp(`${fake.companyName}-button-App`);

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

@ -1,197 +0,0 @@
import { fake } from "Fixtures/fake";
import {
verifyMultipleComponentValuesFromInspector,
verifyComponentValueFromInspector,
} from "Support/utils/commonWidget";
import {
verifyNodeData,
openNode,
verifyValue,
deleteComponentFromInspector,
} from "Support/utils/inspector";
import { commonSelectors, commonWidgetSelector } from "Selectors/common";
import { addNewPage } from "Support/utils/multipage";
import {
selectCSA,
selectEvent,
addSupportCSAData,
} from "Support/utils/events";
import { multipageSelector } from "Selectors/multipage";
import { navigateToCreateNewVersionModal } from "Support/utils/version";
import { createNewVersion } from "Support/utils/exportImport";
describe("Editor- Inspector", () => {
let currentVersion = "";
let newVersion = [];
let versionFrom = "";
beforeEach(() => {
cy.apiLogin();
cy.apiCreateApp(`${fake.companyName}-inspector-App`);
cy.openApp();
});
it("should verify the values of inspector", () => {
const countGlobal =
Cypress.env("environment") === "Community" ? "4 entries " : "5 entries ";
const countUser =
Cypress.env("environment") === "Community" ? "4 entries " : "5 entries ";
cy.get(commonWidgetSelector.sidebarinspector).click();
cy.get(".tooltip-inner").invoke("hide");
verifyNodeData("queries", "Object", "0 entry ");
verifyNodeData("components", "Object", "0 entry ");
verifyNodeData("globals", "Object", countGlobal);
verifyNodeData("variables", "Object", "0 entry ");
verifyNodeData("page", "Object", "4 entries ");
openNode("globals");
verifyNodeData("theme", "Object", "1 entry ");
verifyNodeData("urlparams", "Object", "0 entry ");
verifyNodeData("currentUser", "Object", countUser);
openNode("theme");
verifyValue("name", "String", `"light"`);
openNode("currentUser");
verifyValue("email", "String", `"dev@tooljet.io"`);
verifyValue("firstName", "String", `"The"`);
verifyValue("lastName", "String", `"Developer"`);
verifyNodeData("groups", "Array", "2 items ");
if (Cypress.env("environment") !== "Community") {
cy.get(
'[data-cy="inspector-node-ssouserinfo"] > .node-key'
).verifyVisibleElement("have.text", "ssoUserInfo");
cy.get(
'[data-cy="inspector-node-ssouserinfo"] > .mx-2'
).verifyVisibleElement("have.text", "undefined");
openNode("theme");
openNode("environment");
verifyValue("name", "String", `"development"`);
cy.get('[data-cy="inspector-node-id"] > .node-key').verifyVisibleElement(
"have.text",
"id"
);
}
openNode("mode");
verifyValue("value", "String", `"edit"`);
openNode("groups");
verifyValue("0", "String", `"all_users"`);
verifyValue("1", "String", `"admin"`);
verifyNodeData("constants", "Object", "0 entry ");
openNode("globals");
openNode("page");
verifyValue("handle", "String", `"home"`);
verifyValue("name", "String", `"Home"`);
cy.get(multipageSelector.sidebarPageButton).click();
addNewPage("test_page");
cy.dragAndDropWidget("Button", 500, 500);
selectEvent("On click", "Switch page");
cy.get('[data-cy="switch-page-label-and-input"] > .select-search')
.click()
.type("home{enter}");
cy.get('[data-cy="button-add-query-param"]').click();
cy.wait(3000);
cy.get("body").then(($body) => {
if (
$body.find('[data-cy="event-query-param-key-input-field"]').length == 0
) {
cy.get('[data-cy="button-add-query-param"]').click();
}
});
addSupportCSAData("query-param-key", "key");
addSupportCSAData("query-param-value", "value");
cy.get('[data-cy="switch-page-label-and-input"] > .select-search')
.click()
.type("home{enter}");
cy.get('[data-cy="real-canvas"]').click("topRight", { force: true });
cy.dragAndDropWidget("Button", 500, 300);
selectEvent("On click", "Set variable");
addSupportCSAData("key", "globalVar");
addSupportCSAData("variable", "globalVar");
cy.forceClickOnCanvas();
cy.waitForAutoSave();
cy.get(commonWidgetSelector.draggableWidget("button2")).click();
cy.get('[data-cy="real-canvas"]').click("topRight", { force: true });
cy.dragAndDropWidget("Button", 500, 400);
selectEvent("On click", "Set page variable");
addSupportCSAData("key", "pageVar");
addSupportCSAData("variable", "pageVar");
cy.forceClickOnCanvas();
cy.waitForAutoSave();
cy.get(commonWidgetSelector.draggableWidget("button3")).click();
cy.get(commonWidgetSelector.sidebarinspector).click();
openNode("variables");
verifyValue("globalVar", "String", `"globalVar"`);
openNode("page");
openNode("variables", 1);
verifyValue("pageVar", "String", `"pageVar"`);
verifyValue("handle", "String", `"test-page"`);
verifyValue("name", "String", `"test_page"`);
openNode("components");
verifyNodeData("button1", "Object", "7 entries ");
verifyNodeData("button2", "Object", "7 entries ");
verifyNodeData("button3", "Object", "7 entries ");
cy.get('[data-cy="real-canvas"]').click("topRight", { force: true });
cy.get(commonWidgetSelector.draggableWidget("button1")).click();
cy.get(commonWidgetSelector.sidebarinspector).click();
openNode("page");
verifyValue("handle", "String", `"home"`);
verifyValue("name", "String", `"Home"`);
openNode("globals");
verifyNodeData("urlparams", "Object", "1 entry ");
openNode("urlparams");
verifyValue("key", "String", `"value"`);
cy.get(`[data-cy="inspector-node-key"] > .mx-1`).realHover();
cy.get('[data-cy="copy-path-to-clipboard"]').realClick();
cy.realPress("Escape");
cy.window().then((win) => {
win.navigator.clipboard.readText().then((text) => {
expect(text).to.eq("{{globals.urlparams.key}}");
});
});
cy.get('[data-cy="copy-value-to-clicpboard"]').realClick();
cy.realPress("Escape");
cy.window().then((win) => {
win.navigator.clipboard.readText().then((text) => {
expect(text).to.eq(`"value"`);
});
});
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.notVisible(commonWidgetSelector.draggableWidget("button1"));
cy.apiDeleteApp();
});
it("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)"
);
navigateToCreateNewVersionModal((currentVersion = "v1"));
createNewVersion((newVersion = ["v2"]), (versionFrom = "v1"));
cy.notVisible(commonWidgetSelector.draggableWidget("button1"));
});
});

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

@ -0,0 +1,165 @@
import { fake } from "Fixtures/fake";
import { commonSelectors, commonWidgetSelector } from "Selectors/common";
import {
addCSA,
verifyCSA
} from "Support/utils/editor/textInput";
import { addMultiEventsWithAlert } from "Support/utils/events";
import { openAndVerifyNode, openNode, verifyfunctions, verifyNodes, verifyValue } from "Support/utils/inspector";
describe('Button Component Tests', () => {
const functions = [
{
"key": "setText",
"type": "Function"
},
{
"key": "click",
"type": "Function"
},
{
"key": "disable",
"type": "Function"
},
{
"key": "visibility",
"type": "Function"
},
{
"key": "setVisibility",
"type": "Function"
},
{
"key": "setDisable",
"type": "Function"
},
{
"key": "loading",
"type": "Function"
},
{
"key": "setLoading",
"type": "Function"
}
]
const exposedValues = [{
"key": "buttonText",
"type": "String",
"value": "\"Button\""
},
{
"key": "isVisible",
"type": "Boolean",
"value": "true"
},
{
"key": "isDisabled",
"type": "Boolean",
"value": "false"
},
{
"key": "isLoading",
"type": "Boolean",
"value": "false"
},
// {
// "key": "id",
// "type": "String",
// "value": "\"d9f805c-a8d9-4c5a-ad09-badd6c2216ba\""
// }
]
beforeEach(() => {
cy.apiLogin();
cy.apiCreateApp(`${fake.companyName}-Button-App`);
cy.openApp();
cy.dragAndDropWidget("Button", 50, 50);
cy.get('[data-cy="query-manager-toggle-button"]').click();
});
it('should verify all the exposed values on inspector', () => {
cy.get(commonWidgetSelector.sidebarinspector).click();
cy.get(".tooltip-inner").invoke("hide");
openNode("components");
openAndVerifyNode("button1", exposedValues, verifyValue);
verifyNodes(functions, verifyfunctions);
//id is pending
});
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" },
];
addMultiEventsWithAlert(events);
const textInputSelector = '[data-cy="draggable-widget-button1"]';
const verifyTextInputEvents = (selector) => {
cy.get(selector).realHover()
cy.verifyToastMessage(commonSelectors.toastMessage, 'On hover Event', false);
cy.get(selector).click();
cy.verifyToastMessage(commonSelectors.toastMessage, 'On Click Event', false);
};
verifyTextInputEvents(textInputSelector);
});
it.skip('should verify all the CSA from button', () => {
addMultiEventsWithAlert([
{ event: "On hover", message: "On hover Event" },
{ event: "On Click", message: "On Click Event" },
]);
const actions = [
{ event: "On click", action: "Set visibility", valueToggle: "{{false}}" }, //b2
{ event: "On click", action: "Visibility(deprecated)", valueToggle: "{{true}}" },//b3
{ event: "On click", action: "Disable(deprecated)", valueToggle: "{{true}}" },//b4
{ event: "On click", action: "Set disable", valueToggle: "{{false}}" },//b5
{ event: "On click", action: "Set text", value: "New Button Text" },//b6
{ event: "On click", action: "Click" },//b7
{ event: "On click", action: "Set loading", valueToggle: "{{true}}" },//b8
{ event: "On click", action: "Loading(deprecated)", valueToggle: "{{false}}" },//b9
];
addCSA("button1", actions);
let component = "button1";
cy.get(commonWidgetSelector.draggableWidget("button2")).click();
cy.get(commonWidgetSelector.draggableWidget(component)).should("not.be.visible");
cy.get(commonWidgetSelector.draggableWidget("button3")).click();
cy.get(commonWidgetSelector.draggableWidget(component)).should("be.visible");
cy.get(commonWidgetSelector.draggableWidget("button4")).click();
cy.get(commonWidgetSelector.draggableWidget(component)).parent().should("have.attr", "disabled");
cy.get(commonWidgetSelector.draggableWidget("button5")).click();
cy.get(commonWidgetSelector.draggableWidget(component)).parent().should("not.have.attr", "disabled");
cy.get(commonWidgetSelector.draggableWidget("button6")).click();
cy.get(commonWidgetSelector.draggableWidget(component)).should("have.text", "New Button Text");
cy.get(commonWidgetSelector.draggableWidget("button7")).click();
cy.verifyToastMessage(commonSelectors.toastMessage, 'On Click Event', false);
cy.get(commonWidgetSelector.draggableWidget("button8")).click();
cy.get(commonWidgetSelector.draggableWidget(component))
.parent()
.within(() => {
cy.get(".tj-widget-loader").should("be.visible");
});
cy.get(commonWidgetSelector.draggableWidget("button9")).click();
cy.notVisible(".tj-widget-loader");
});
// afterEach(() => {
// cy.apiDeleteApp();
// });
});

View file

@ -0,0 +1,178 @@
import { fake } from "Fixtures/fake";
import { commonSelectors, commonWidgetSelector } from "Selectors/common";
import {
addCSA,
verifyCSA
} from "Support/utils/editor/textInput";
import { addMultiEventsWithAlert } from "Support/utils/events";
import { openAndVerifyNode, openNode, verifyfunctions, verifyNodes, verifyValue } from "Support/utils/inspector";
describe('Checkbox Component Tests', () => {
const functions = [
{
"key": "setValue",
"type": "Function"
},
{
"key": "toggle",
"type": "Function"
},
{
"key": "setChecked",
"type": "Function"
},
{
"key": "setVisibility",
"type": "Function"
},
{
"key": "setDisable",
"type": "Function"
},
{
"key": "setLoading",
"type": "Function"
}
]
const exposedValues = [{
"key": "label",
"type": "String",
"value": "\"Label\""
},
{
"key": "isVisible",
"type": "Boolean",
"value": "true"
},
{
"key": "isDisabled",
"type": "Boolean",
"value": "false"
},
{
"key": "isMandatory",
"type": "Boolean",
"value": "false"
},
{
"key": "value",
"type": "Boolean",
"value": "false"
},
{
"key": "isLoading",
"type": "Boolean",
"value": "false"
},
{
"key": "isValid",
"type": "Boolean",
"value": "true"
},
// {
// "key": "id",
// "type": "String",
// "value": "\"d9f805c-a8d9-4c5a-ad09-badd6c2216ba\""
// }
]
beforeEach(() => {
cy.apiLogin();
cy.apiCreateApp(`${fake.companyName}-Checkbox-App`);
cy.openApp();
cy.dragAndDropWidget("Checkbox", 50, 50);
cy.get('[data-cy="query-manager-toggle-button"]').click();
});
it('should verify all the exposed values on inspector', () => {
cy.get(commonWidgetSelector.sidebarinspector).click();
cy.get(".tooltip-inner").invoke("hide");
openNode("components");
openAndVerifyNode("checkbox1", exposedValues, verifyValue);
verifyNodes(functions, verifyfunctions);
//id is pending
});
it.skip('should verify all the events from the Checkbox', () => {
const events = [
{ event: "On Change", message: "On Change Event" },
];
addMultiEventsWithAlert(events, false);
const textInputSelector = '[data-cy="draggable-widget-checkbox1"]';
const verifyTextInputEvents = (selector) => {
cy.forceClickOnCanvas();
cy.get(selector).find('input').click({ force: true });
cy.verifyToastMessage(commonSelectors.toastMessage, 'On Change Event', false);
// cy.get(selector).click();
// cy.verifyToastMessage(commonSelectors.toastMessage, 'On Click Event', false);
};
verifyTextInputEvents(textInputSelector);
});
it.skip('should verify all the CSA from Checkbox', () => {
const events = [
{ event: "On Change", message: "On Change Event" },
];
addMultiEventsWithAlert(events, false);
const actions = [
{ event: "On click", action: "Set visibility", valueToggle: "{{false}}" }, //b2
{ event: "On click", action: "Set visibility", valueToggle: "{{true}}" },//b3
{ event: "On click", action: "Set disable", valueToggle: "{{true}}" },//b4
{ event: "On click", action: "Set disable", valueToggle: "{{false}}" },//b5
{ event: "On click", action: "Set checked", value: "true" },//b6
{ event: "On click", action: "Toggle" },//b7
{ event: "On click", action: "Set loading", valueToggle: "{{true}}" },//b8
{ event: "On click", action: "Set loading", valueToggle: "{{false}}" },//b9
];
addCSA("checkbox1", actions);
let component = "checkbox1";
cy.get(commonWidgetSelector.draggableWidget("button1")).click();
cy.get(commonWidgetSelector.draggableWidget(component)).should("not.be.visible");
cy.get(commonWidgetSelector.draggableWidget("button2")).click();
cy.get(commonWidgetSelector.draggableWidget(component)).should("be.visible");
cy.get(commonWidgetSelector.draggableWidget("button3")).click();
cy.get(commonWidgetSelector.draggableWidget(component)).should("have.attr", "data-disabled", 'true');
cy.get(commonWidgetSelector.draggableWidget("button4")).click();
cy.get(commonWidgetSelector.draggableWidget(component)).should("have.attr", "data-disabled", 'false');
// cy.get(commonWidgetSelector.draggableWidget("button5")).click();
// cy.get(commonWidgetSelector.draggableWidget(component)).should("have.text", "New Button Text");
cy.get(commonWidgetSelector.draggableWidget("button5")).click();
cy.get(commonWidgetSelector.draggableWidget(component)).find('input').should('be.checked')
// cy.verifyToastMessage(commonSelectors.toastMessage, 'On Change Event', false);
cy.get(commonWidgetSelector.draggableWidget("button6")).click();
cy.verifyToastMessage(commonSelectors.toastMessage, 'On Change Event', false);
cy.get(commonWidgetSelector.draggableWidget("button7")).click();
cy.get(commonWidgetSelector.draggableWidget(component))
.parent()
.within(() => {
cy.get(".tj-widget-loader").should("be.visible");
});
cy.get(commonWidgetSelector.draggableWidget("button8")).click();
cy.notVisible(".tj-widget-loader");
});
// afterEach(() => {
// cy.apiDeleteApp();
// });
});

View file

@ -0,0 +1,192 @@
import { fake } from "Fixtures/fake";
import { commonSelectors, commonWidgetSelector } from "Selectors/common";
import {
addCSA,
verifyCSA
} from "Support/utils/editor/textInput";
import { addMultiEventsWithAlert } from "Support/utils/events";
import { openAndVerifyNode, openNode, verifyfunctions, verifyNodes, verifyValue } from "Support/utils/inspector";
describe('Dropdown Component Tests', () => {
const functions = [
{
"key": "clear",
"type": "Function"
},
{
"key": "selectOption",
"type": "Function"
}, ,
{
"key": "setVisibility",
"type": "Function"
},
{
"key": "setDisable",
"type": "Function"
},
{
"key": "setLoading",
"type": "Function"
},
{
"key": "selectedOption",
"type": "Object"
},
{
"key": "options",
"type": "Array"
},
]
const exposedValues = [{
"key": "searchText",
"type": "String",
"value": "\"\""
},
{
"key": "label",
"type": "String",
"value": "\"Select\""
},
{
"key": "isVisible",
"type": "Boolean",
"value": "true"
},
{
"key": "isDisabled",
"type": "Boolean",
"value": "false"
},
{
"key": "isMandatory",
"type": "Boolean",
"value": "false"
},
{
"key": "isLoading",
"type": "Boolean",
"value": "false"
},
{
"key": "isValid",
"type": "Boolean",
"value": "true"
},
{
"key": "value",
"type": "String",
"value": "2"
}
// {
// "key": "id",
// "type": "String",
// "value": "\"d9f805c-a8d9-4c5a-ad09-badd6c2216ba\""
// }
]
beforeEach(() => {
cy.apiLogin();
cy.apiCreateApp(`${fake.companyName}-Dropdown-App`);
cy.openApp();
cy.dragAndDropWidget("Dropdown", 50, 50);
cy.get('[data-cy="query-manager-toggle-button"]').click();
});
it('should verify all the exposed values on inspector', () => {
cy.get(commonWidgetSelector.sidebarinspector).click();
cy.get(".tooltip-inner").invoke("hide");
openNode("components");
openAndVerifyNode("dropdown1", exposedValues, verifyValue);
verifyNodes(functions, verifyfunctions);
//id is pending
});
it('should verify all the events from the dropdown', () => {
const events = [
{ event: "On Focus", message: "On Focus Event" },
{ event: "On Blur", message: "On Blur Event" },
{ event: "On select", message: "On select Event" },
{ event: "On search text changes", message: "On search Event" }
];
addMultiEventsWithAlert(events, false);
const textInputSelector = '[data-cy="draggable-widget-dropdown1"]';
const verifyTextInputEvents = (selector) => {
cy.get(selector).click();
cy.verifyToastMessage(commonSelectors.toastMessage, 'On Focus Event', false);
// cy.get(selector).type('r');
// cy.verifyToastMessage(commonSelectors.toastMessage, 'On Change Event', false);
// cy.get(selector).type('{enter}');
// cy.verifyToastMessage(commonSelectors.toastMessage, 'On Enter Event', false);
cy.forceClickOnCanvas();
cy.verifyToastMessage(commonSelectors.toastMessage, 'On Blur Event', false);
};
verifyTextInputEvents(textInputSelector);
});
it('should verify all the CSA from dropdown', () => {
const events = [
{ event: "On Change", message: "On Change Event" },
];
addMultiEventsWithAlert(events, false);
const actions = [
{ event: "On click", action: "Set visibility", valueToggle: "{{false}}" }, //b2
{ event: "On click", action: "Set visibility", valueToggle: "{{true}}" },//b3
{ event: "On click", action: "Set disable", valueToggle: "{{true}}" },//b4
{ event: "On click", action: "Set disable", valueToggle: "{{false}}" },//b5
{ event: "On click", action: "Set value", value: "true" },//b6
{ event: "On click", action: "Toggle" },//b7
{ event: "On click", action: "Set loading", valueToggle: "{{true}}" },//b8
{ event: "On click", action: "Set loading", valueToggle: "{{false}}" },//b9
];
addCSA("dropdown1", actions);
let component = "dropdown1";
cy.get(commonWidgetSelector.draggableWidget("button1")).click();
cy.get(commonWidgetSelector.draggableWidget(component)).should("not.be.visible");
cy.get(commonWidgetSelector.draggableWidget("button2")).click();
cy.get(commonWidgetSelector.draggableWidget(component)).should("be.visible");
cy.get(commonWidgetSelector.draggableWidget("button3")).click();
cy.get(commonWidgetSelector.draggableWidget(component)).should("have.attr", "data-disabled", 'true');
cy.get(commonWidgetSelector.draggableWidget("button4")).click();
cy.get(commonWidgetSelector.draggableWidget(component)).should("have.attr", "data-disabled", 'false');
cy.get(commonWidgetSelector.draggableWidget("button5")).click();
cy.get(commonWidgetSelector.draggableWidget(component)).should("have.text", "New Button Text");
cy.get(commonWidgetSelector.draggableWidget("button6")).click();
cy.verifyToastMessage(commonSelectors.toastMessage, 'On Click Event', false);
cy.get(commonWidgetSelector.draggableWidget("button7")).click();
cy.get(commonWidgetSelector.draggableWidget(component))
.parent()
.within(() => {
cy.get(".tj-widget-loader").should("be.visible");
});
cy.get(commonWidgetSelector.draggableWidget("button9")).click();
cy.notVisible(".tj-widget-loader");
});
// afterEach(() => {
// cy.apiDeleteApp();
// });
});

View file

@ -0,0 +1,145 @@
import { fake } from "Fixtures/fake";
import { commonSelectors, commonWidgetSelector } from "Selectors/common";
import { multipageSelector } from "Selectors/multipage";
import {
randomString
} from "Support/utils/editor/textInput";
import {
addInputOnQueryField,
query,
selectQueryFromLandingPage
} from "Support/utils/queries";
import { deleteDownloadsFolder } from "Support/utils/common";
import {
resizeQueryPanel
} from "Support/utils/dataSource";
import { openNode, verifyNodeData, verifyValue } from "Support/utils/inspector";
import {
addNewPage
} from "Support/utils/multipage";
describe("Global Actions", () => {
beforeEach(() => {
cy.apiLogin();
cy.apiCreateApp(`${fake.companyName}-gloabalActions-App`);
cy.openApp();
cy.viewport(1800, 1800);
cy.dragAndDropWidget("Button");
resizeQueryPanel("80");
deleteDownloadsFolder();
});
it("should verify actions", () => {
const data = {};
data.customText = randomString(12);
selectQueryFromLandingPage("runjs", "JavaScript");
addInputOnQueryField(
"runjs",
`setTimeout(() => {
actions.setVariable('var', 'test');
actions.setPageVariable('pageVar', 'pageTest');
}, [0]) `
);
query("run");
cy.get(commonWidgetSelector.sidebarinspector).click();
cy.get(".tooltip-inner").invoke("hide");
verifyNodeData("variables", "Object", "1 entry ");
openNode("variables", 0);
verifyValue("var", "String", `"test"`);
openNode("page");
openNode("variables", 1);
verifyValue("pageVar", "String", `"pageTest"`);
addInputOnQueryField(
"runjs",
`setTimeout(() => {
actions.unSetVariable('var');
actions.unsetPageVariable('pageVar');
}, [0]) `
);
query("run");
cy.get(commonWidgetSelector.sidebarinspector).click();
cy.get(".tooltip-inner").invoke("hide");
verifyNodeData("variables", "Object", "0 entry ");
openNode("page");
openNode("variables", 1);
verifyNodeData("variables", "Object", "0 entry ", 1);
addInputOnQueryField(
"runjs",
"actions.showAlert('success', 'alert from runjs');"
);
query("run");
cy.verifyToastMessage(commonSelectors.toastMessage, "alert from runjs");
cy.get(multipageSelector.sidebarPageButton).click();
addNewPage("test_page");
cy.url().should("contain", "/test-page");
addInputOnQueryField("runjs", "actions.switchPage('home');");
query("run");
cy.url().should("contain", "/home");
cy.get('[data-cy="real-canvas"]').click("topRight", { force: true });
cy.dragAndDropWidget("Modal", 200, 300);
cy.waitForAutoSave();
addInputOnQueryField("runjs", "actions.showModal('modal1');");
query("run");
cy.get('.text-widget-section > div').should("be.visible");
addInputOnQueryField("runjs", "actions.closeModal('modal1');");
query("run");
cy.wait(200);
cy.notVisible('[data-cy="modal-title"]');
addInputOnQueryField(
"runjs",
"actions.copyToClipboard('data from runjs');"
);
query("run");
cy.window().then((win) => {
win.navigator.clipboard.readText().then((text) => {
expect(text).to.eq("data from runjs");
});
});
addInputOnQueryField(
"runjs",
"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"
);
});
addInputOnQueryField(
"runjs",
"actions.generateFile('runjscsv', 'csv', [{ name: 'John', email: 'john@tooljet.com' }])"
);
query("run");
cy.readFile("cypress/downloads/runjscsv.csv", "utf-8")
.should("contain", "name,email")
.and("contain", "John,john@tooljet.com");
// addInputOnQueryField(
// "runjs",
// "actions.goToApp('111234')"
// );
// query("run");
addInputOnQueryField("runjs", "actions.logout()");
query("run");
cy.get('[data-cy="sign-in-header"]').should("be.visible");
});
});

View file

@ -0,0 +1,195 @@
import { fake } from "Fixtures/fake";
import { commonSelectors, commonWidgetSelector } from "Selectors/common";
import {
addCSA,
verifyCSA
} from "Support/utils/editor/textInput";
import { addMultiEventsWithAlert } from "Support/utils/events";
import { openAndVerifyNode, openNode, verifyfunctions, verifyNodes, verifyValue } from "Support/utils/inspector";
describe('Multiselect Component Tests', () => {
const functions = [
{
"key": "clear",
"type": "Function"
},
{
"key": "selectOption",
"type": "Function"
}, {
"key": "deselectOptions",
"type": "Function"
},
{
"key": "setVisibility",
"type": "Function"
},
{
"key": "setDisable",
"type": "Function"
},
{
"key": "setLoading",
"type": "Function"
},
{
"key": "selectedOption",
"type": "Object"
},
{
"key": "options",
"type": "Array"
},
]
const exposedValues = [{
"key": "searchText",
"type": "String",
"value": "\"\""
},
{
"key": "label",
"type": "String",
"value": "\"Select\""
},
{
"key": "isVisible",
"type": "Boolean",
"value": "true"
},
{
"key": "isDisabled",
"type": "Boolean",
"value": "false"
},
{
"key": "isMandatory",
"type": "Boolean",
"value": "false"
},
{
"key": "isLoading",
"type": "Boolean",
"value": "false"
},
{
"key": "isValid",
"type": "Boolean",
"value": "true"
},
{
"key": "value",
"type": "String",
"value": "2"
}
// {
// "key": "id",
// "type": "String",
// "value": "\"d9f805c-a8d9-4c5a-ad09-badd6c2216ba\""
// }
]
beforeEach(() => {
cy.apiLogin();
cy.apiCreateApp(`${fake.companyName}-Multiselect-App`);
cy.openApp();
cy.dragAndDropWidget("Multiselect", 50, 50);
cy.get('[data-cy="query-manager-toggle-button"]').click();
});
it('should verify all the exposed values on inspector', () => {
cy.get(commonWidgetSelector.sidebarinspector).click();
cy.get(".tooltip-inner").invoke("hide");
openNode("components");
openAndVerifyNode("multiselect1", exposedValues, verifyValue);
verifyNodes(functions, verifyfunctions);
//id is pending
});
it('should verify all the events from the Multiselect', () => {
const events = [
{ event: "On Focus", message: "On Focus Event" },
{ event: "On Blur", message: "On Blur Event" },
{ event: "On select", message: "On select Event" },
{ event: "On search text changes", message: "On search Event" }
];
addMultiEventsWithAlert(events, false);
const textInputSelector = '[data-cy="draggable-widget-dropdown1"]';
const verifyTextInputEvents = (selector) => {
cy.get(selector).click();
cy.verifyToastMessage(commonSelectors.toastMessage, 'On Focus Event', false);
// cy.get(selector).type('r');
// cy.verifyToastMessage(commonSelectors.toastMessage, 'On Change Event', false);
// cy.get(selector).type('{enter}');
// cy.verifyToastMessage(commonSelectors.toastMessage, 'On Enter Event', false);
cy.forceClickOnCanvas();
cy.verifyToastMessage(commonSelectors.toastMessage, 'On Blur Event', false);
};
verifyTextInputEvents(textInputSelector);
});
it.only('should verify all the CSA from multiselect', () => {
const events = [
{ event: "On Change", message: "On Change Event" },
];
addMultiEventsWithAlert(events, false);
const actions = [
{ event: "On click", action: "Set visibility", valueToggle: "{{false}}" }, //b2
{ event: "On click", action: "Set visibility", valueToggle: "{{true}}" },//b3
{ event: "On click", action: "Set disable", valueToggle: "{{true}}" },//b4
{ event: "On click", action: "Set disable", valueToggle: "{{false}}" },//b5
{ event: "On click", action: "Set value", value: "true" },//b6
{ event: "On click", action: "Toggle" },//b7
{ event: "On click", action: "Set loading", valueToggle: "{{true}}" },//b8
{ event: "On click", action: "Set loading", valueToggle: "{{false}}" },//b9
];
addCSA("multiselect1", actions);
let component = "multiselect1";
cy.get(commonWidgetSelector.draggableWidget("button1")).click();
cy.get(commonWidgetSelector.draggableWidget(component)).should("not.be.visible");
cy.get(commonWidgetSelector.draggableWidget("button2")).click();
cy.get(commonWidgetSelector.draggableWidget(component)).should("be.visible");
cy.get(commonWidgetSelector.draggableWidget("button3")).click();
cy.get(commonWidgetSelector.draggableWidget(component)).should("have.attr", "data-disabled", 'true');
cy.get(commonWidgetSelector.draggableWidget("button4")).click();
cy.get(commonWidgetSelector.draggableWidget(component)).should("have.attr", "data-disabled", 'false');
cy.get(commonWidgetSelector.draggableWidget("button5")).click();
cy.get(commonWidgetSelector.draggableWidget(component)).should("have.text", "New Button Text");
cy.get(commonWidgetSelector.draggableWidget("button6")).click();
cy.verifyToastMessage(commonSelectors.toastMessage, 'On Click Event', false);
cy.get(commonWidgetSelector.draggableWidget("button7")).click();
cy.get(commonWidgetSelector.draggableWidget(component))
.parent()
.within(() => {
cy.get(".tj-widget-loader").should("be.visible");
});
cy.get(commonWidgetSelector.draggableWidget("button9")).click();
cy.notVisible(".tj-widget-loader");
});
// afterEach(() => {
// cy.apiDeleteApp();
// });
});

View file

@ -0,0 +1,152 @@
import { fake } from "Fixtures/fake";
import { commonSelectors, commonWidgetSelector } from "Selectors/common";
import {
addCSA,
verifyCSA
} from "Support/utils/editor/textInput";
import { addMultiEventsWithAlert } from "Support/utils/events";
import { openAndVerifyNode, openNode, verifyfunctions, verifyNodes, verifyValue } from "Support/utils/inspector";
describe('Number Input Component Tests', () => {
const functions = [
{
"key": "setText",
"type": "Function"
},
{
"key": "clear",
"type": "Function"
},
{
"key": "setFocus",
"type": "Function"
},
{
"key": "setBlur",
"type": "Function"
},
{
"key": "setVisibility",
"type": "Function"
},
{
"key": "setDisable",
"type": "Function"
},
{
"key": "setLoading",
"type": "Function"
}
]
const exposedValues = [{
"key": "value",
"type": "Number",
"value": "0"
},
{
"key": "isMandatory",
"type": "Boolean",
"value": "false"
},
{
"key": "isVisible",
"type": "Boolean",
"value": "true"
},
{
"key": "isDisabled",
"type": "Boolean",
"value": "false"
},
{
"key": "isLoading",
"type": "Boolean",
"value": "false"
},
{
"key": "label",
"type": "String",
"value": "\"Label\""
},
{
"key": "isValid",
"type": "Boolean",
"value": "true"
},
// {
// "key": "id",
// "type": "String",
// "value": "\"d9f805c-a8d9-4c5a-ad09-badd6c2216ba\""
// }
]
beforeEach(() => {
cy.apiLogin();
cy.apiCreateApp(`${fake.companyName}-Numberinput-App`);
cy.openApp();
cy.dragAndDropWidget("Number Input", 50, 50);
cy.get('[data-cy="query-manager-toggle-button"]').click();
});
it('should verify all the exposed values on inspector', () => {
cy.get(commonWidgetSelector.sidebarinspector).click();
cy.get(".tooltip-inner").invoke("hide");
openNode("components");
openAndVerifyNode("numberinput1", exposedValues, verifyValue);
verifyNodes(functions, verifyfunctions);
//id is pending
});
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" },
{ event: "On Change", message: "On Change Event" },
{ event: "On Enter", message: "On Enter Event" }
];
addMultiEventsWithAlert(events);
const inputSelector = '[data-cy="draggable-widget-numberinput1"]';
const inputEvents = (selector) => {
cy.get(selector).click();
cy.verifyToastMessage(commonSelectors.toastMessage, 'On Focus Event', false);
cy.get(selector).type('1');
cy.verifyToastMessage(commonSelectors.toastMessage, 'On Change Event', false);
cy.get(selector).type('{enter}');
cy.verifyToastMessage(commonSelectors.toastMessage, 'On Enter Event', false);
cy.forceClickOnCanvas();
cy.verifyToastMessage(commonSelectors.toastMessage, 'On Blur Event', false);
};
inputEvents(inputSelector);
});
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
{ event: "On click", action: "Set disable", valueToggle: "{{true}}" },//b3
{ event: "On click", action: "Set disable", valueToggle: "{{false}}" },//b4
{ event: "On click", action: "Set text", value: "1199999" },//b5
{ event: "On click", action: "Clear" },//b6
{ event: "On click", action: "Set focus" },//b7
{ event: "On click", action: "Set blur" },//b8
{ event: "On click", action: "Set loading", valueToggle: "{{true}}" },//b9
];
addCSA("numberinput1", actions);
verifyCSA('numberinput1');
});
// afterEach(() => {
// cy.apiDeleteApp();
// });
});

View file

@ -0,0 +1,152 @@
import { fake } from "Fixtures/fake";
import { commonSelectors, commonWidgetSelector } from "Selectors/common";
import {
addCSA,
verifyCSA
} from "Support/utils/editor/textInput";
import { addMultiEventsWithAlert } from "Support/utils/events";
import { openAndVerifyNode, openNode, verifyfunctions, verifyNodes, verifyValue } from "Support/utils/inspector";
describe('Password Input Component Tests', () => {
const functions = [
{
"key": "setText",
"type": "Function"
},
{
"key": "clear",
"type": "Function"
},
{
"key": "setFocus",
"type": "Function"
},
{
"key": "setBlur",
"type": "Function"
},
{
"key": "setVisibility",
"type": "Function"
},
{
"key": "setDisable",
"type": "Function"
},
{
"key": "setLoading",
"type": "Function"
}
]
const exposedValues = [{
"key": "value",
"type": "String",
"value": "\"\""
},
{
"key": "isMandatory",
"type": "Boolean",
"value": "false"
},
{
"key": "isVisible",
"type": "Boolean",
"value": "true"
},
{
"key": "isDisabled",
"type": "Boolean",
"value": "false"
},
{
"key": "isLoading",
"type": "Boolean",
"value": "false"
},
{
"key": "label",
"type": "String",
"value": "\"Label\""
},
{
"key": "isValid",
"type": "Boolean",
"value": "true"
},
// {
// "key": "id",
// "type": "String",
// "value": "\"d9f805c-a8d9-4c5a-ad09-badd6c2216ba\""
// }
]
beforeEach(() => {
cy.apiLogin();
cy.apiCreateApp(`${fake.companyName}-Passwordinput-App`);
cy.openApp();
cy.dragAndDropWidget("Password Input", 50, 50);
cy.get('[data-cy="query-manager-toggle-button"]').click();
});
it('should verify all the exposed values on inspector', () => {
cy.get(commonWidgetSelector.sidebarinspector).click();
cy.get(".tooltip-inner").invoke("hide");
openNode("components");
openAndVerifyNode("passwordinput1", exposedValues, verifyValue);
verifyNodes(functions, verifyfunctions);
//id is pending
});
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" },
{ event: "On Change", message: "On Change Event" },
{ event: "On Enter", message: "On Enter Event" }
];
addMultiEventsWithAlert(events);
const inputSelector = '[data-cy="draggable-widget-passwordinput1"]';
const inputEvents = (selector) => {
cy.get(selector).click();
cy.verifyToastMessage(commonSelectors.toastMessage, 'On Focus Event', false);
cy.get(selector).type('r');
cy.verifyToastMessage(commonSelectors.toastMessage, 'On Change Event', false);
cy.get(selector).type('{enter}');
cy.verifyToastMessage(commonSelectors.toastMessage, 'On Enter Event', false);
cy.forceClickOnCanvas();
cy.verifyToastMessage(commonSelectors.toastMessage, 'On Blur Event', false);
};
inputEvents(inputSelector);
});
it('should verify all the CSA from password input', () => {
const actions = [
{ event: "On click", action: "Set visibility", valueToggle: "{{false}}" }, //b1
{ event: "On click", action: "Set visibility", valueToggle: "{{true}}" },//b2
{ event: "On click", action: "Set disable", valueToggle: "{{true}}" },//b3
{ event: "On click", action: "Set disable", valueToggle: "{{false}}" },//b4
{ event: "On click", action: "Set text", value: "1199999" },//b5
{ event: "On click", action: "Clear" },//b6
{ event: "On click", action: "Set focus" },//b7
{ event: "On click", action: "Set blur" },//b8
{ event: "On click", action: "Set loading", valueToggle: "{{true}}" },//b9
];
addCSA("passwordinput1", actions);
verifyCSA('passwordinput1');
});
// afterEach(() => {
// cy.apiDeleteApp();
// });
});

View file

@ -0,0 +1,160 @@
import { fake } from "Fixtures/fake";
import { commonSelectors, commonWidgetSelector } from "Selectors/common";
import {
addCSA,
verifyCSA
} from "Support/utils/editor/textInput";
import { addMultiEventsWithAlert } from "Support/utils/events";
import { openAndVerifyNode, openNode, verifyfunctions, verifyNodes, verifyValue } from "Support/utils/inspector";
describe('Text Input Component Tests', () => {
const functions = [
{
"key": "setText",
"type": "Function"
},
{
"key": "clear",
"type": "Function"
},
{
"key": "setFocus",
"type": "Function"
},
{
"key": "setBlur",
"type": "Function"
},
{
"key": "disable",
"type": "Function"
},
{
"key": "visibility",
"type": "Function"
},
{
"key": "setVisibility",
"type": "Function"
},
{
"key": "setDisable",
"type": "Function"
},
{
"key": "setLoading",
"type": "Function"
}
]
const exposedValues = [{
"key": "value",
"type": "String",
"value": "\"\""
},
{
"key": "isMandatory",
"type": "Boolean",
"value": "false"
},
{
"key": "isVisible",
"type": "Boolean",
"value": "true"
},
{
"key": "isDisabled",
"type": "Boolean",
"value": "false"
},
{
"key": "isLoading",
"type": "Boolean",
"value": "false"
},
{
"key": "label",
"type": "String",
"value": "\"Label\""
},
{
"key": "isValid",
"type": "Boolean",
"value": "true"
},
// {
// "key": "id",
// "type": "String",
// "value": "\"d9f805c-a8d9-4c5a-ad09-badd6c2216ba\""
// }
]
beforeEach(() => {
cy.apiLogin();
cy.apiCreateApp(`${fake.companyName}-Textinput-App`);
cy.openApp();
cy.dragAndDropWidget("Text Input", 50, 50);
cy.get('[data-cy="query-manager-toggle-button"]').click();
});
it.skip('should verify all the exposed values on inspector', () => {
cy.get(commonWidgetSelector.sidebarinspector).click();
cy.get(".tooltip-inner").invoke("hide");
openNode("components");
openAndVerifyNode("textinput1", exposedValues, verifyValue);
verifyNodes(functions, verifyfunctions);
//id is pending
});
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" },
{ event: "On Change", message: "On Change Event" },
{ event: "On Enter", message: "On Enter Event" }
];
addMultiEventsWithAlert(events);
const textInputSelector = '[data-cy="draggable-widget-textinput1"]';
const verifyTextInputEvents = (selector) => {
cy.get(selector).click();
cy.verifyToastMessage(commonSelectors.toastMessage, 'On Focus Event', false);
cy.get(selector).type('r');
cy.verifyToastMessage(commonSelectors.toastMessage, 'On Change Event', false);
cy.get(selector).type('{enter}');
cy.verifyToastMessage(commonSelectors.toastMessage, 'On Enter Event', false);
cy.forceClickOnCanvas();
cy.verifyToastMessage(commonSelectors.toastMessage, 'On Blur Event', false);
};
verifyTextInputEvents(textInputSelector);
});
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
{ event: "On click", action: "Disable", valueToggle: "{{true}}" },//b3
{ event: "On click", action: "Set disable", valueToggle: "{{false}}" },//b4
{ event: "On click", action: "Set text", value: "1199999" },//b5
{ event: "On click", action: "Clear" },//b6
{ event: "On click", action: "Set focus" },//b7
{ event: "On click", action: "Set blur" },//b8
{ event: "On click", action: "Set loading", valueToggle: "{{true}}" },//b9
];
addCSA("textinput1", actions);
verifyCSA('textinput1');
});
// afterEach(() => {
// cy.apiDeleteApp();
// });
});

View file

@ -0,0 +1,172 @@
import { fake } from "Fixtures/fake";
import { commonSelectors, commonWidgetSelector } from "Selectors/common";
import {
addCSA,
verifyCSA
} from "Support/utils/editor/textInput";
import { addMultiEventsWithAlert } from "Support/utils/events";
import { openAndVerifyNode, openNode, verifyfunctions, verifyNodes, verifyValue } from "Support/utils/inspector";
describe('ToggleSwitch Component Tests', () => {
const functions = [
{
"key": "setValue",
"type": "Function"
},
{
"key": "toggle",
"type": "Function"
}, ,
{
"key": "setVisibility",
"type": "Function"
},
{
"key": "setDisable",
"type": "Function"
},
{
"key": "setLoading",
"type": "Function"
}
]
const exposedValues = [{
"key": "label",
"type": "String",
"value": "\"Label\""
},
{
"key": "isVisible",
"type": "Boolean",
"value": "true"
},
{
"key": "isDisabled",
"type": "Boolean",
"value": "false"
},
{
"key": "isMandatory",
"type": "Boolean",
"value": "false"
},
{
"key": "value",
"type": "Boolean",
"value": "false"
},
{
"key": "isLoading",
"type": "Boolean",
"value": "false"
},
{
"key": "isValid",
"type": "Boolean",
"value": "true"
},
// {
// "key": "id",
// "type": "String",
// "value": "\"d9f805c-a8d9-4c5a-ad09-badd6c2216ba\""
// }
]
beforeEach(() => {
cy.apiLogin();
cy.apiCreateApp(`${fake.companyName}-Toggle-App`);
cy.openApp();
cy.dragAndDropWidget("Toggle Switch", 50, 50);
cy.get('[data-cy="query-manager-toggle-button"]').click();
});
it('should verify all the exposed values on inspector', () => {
cy.get(commonWidgetSelector.sidebarinspector).click();
cy.get(".tooltip-inner").invoke("hide");
openNode("components");
openAndVerifyNode("toggleswitch1", exposedValues, verifyValue);
verifyNodes(functions, verifyfunctions);
//id is pending
});
it('should verify all the events from the Toggle', () => {
const events = [
{ event: "On Change", message: "On Change Event" },
];
addMultiEventsWithAlert(events, false);
const textInputSelector = '[data-cy="draggable-widget-toggleswitch1"]';
const verifyTextInputEvents = (selector) => {
cy.forceClickOnCanvas();
cy.get(selector).find('input').click({ force: true });
cy.verifyToastMessage(commonSelectors.toastMessage, 'On Change Event', false);
// cy.get(selector).click();
// cy.verifyToastMessage(commonSelectors.toastMessage, 'On Click Event', false);
};
verifyTextInputEvents(textInputSelector);
});
it.only('should verify all the CSA from toggle', () => {
const events = [
{ event: "On Change", message: "On Change Event" },
];
addMultiEventsWithAlert(events, false);
const actions = [
{ event: "On click", action: "Set visibility", valueToggle: "{{false}}" }, //b2
{ event: "On click", action: "Set visibility", valueToggle: "{{true}}" },//b3
{ event: "On click", action: "Set disable", valueToggle: "{{true}}" },//b4
{ event: "On click", action: "Set disable", valueToggle: "{{false}}" },//b5
{ event: "On click", action: "Set value", value: "true" },//b6
{ event: "On click", action: "Toggle" },//b7
{ event: "On click", action: "Set loading", valueToggle: "{{true}}" },//b8
{ event: "On click", action: "Set loading", valueToggle: "{{false}}" },//b9
];
addCSA("toggleswitch1", actions);
let component = "toggleswitch1";
cy.get(commonWidgetSelector.draggableWidget("button1")).click();
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();
cy.get(commonWidgetSelector.draggableWidget(component)).should("have.attr", "data-disabled", 'true');
cy.get(commonWidgetSelector.draggableWidget("button4")).click();
cy.get(commonWidgetSelector.draggableWidget(component)).should("have.attr", "data-disabled", 'false');
cy.get(commonWidgetSelector.draggableWidget("button5")).click();
cy.get(commonWidgetSelector.draggableWidget(component)).should("have.text", "New Button Text");
cy.get(commonWidgetSelector.draggableWidget("button6")).click();
cy.verifyToastMessage(commonSelectors.toastMessage, 'On Click Event', false);
cy.get(commonWidgetSelector.draggableWidget("button7")).click();
cy.get(commonWidgetSelector.draggableWidget(component))
.parent()
.within(() => {
cy.get(".tj-widget-loader").should("be.visible");
});
cy.get(commonWidgetSelector.draggableWidget("button9")).click();
cy.notVisible(".tj-widget-loader");
});
// afterEach(() => {
// cy.apiDeleteApp();
// });
});

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

@ -0,0 +1,164 @@
import { fake } from "Fixtures/fake";
import { commonWidgetSelector } from "Selectors/common";
import { multipageSelector } from "Selectors/multipage";
import { addSupportCSAData, selectEvent } from "Support/utils/events";
import { createNewVersion } from "Support/utils/exportImport";
import { deleteComponentFromInspector, openNode, verifyNodeData, verifyValue, verifyNodes, openAndVerifyNode } from "Support/utils/inspector";
import { addNewPage } from "Support/utils/multipage";
import { navigateToCreateNewVersionModal } from "Support/utils/version";
import testData from "Fixtures/inspectorItems.json";
describe("Editor- Inspector", () => {
let currentVersion = "";
let newVersion = [];
let versionFrom = "";
beforeEach(() => {
cy.apiLogin();
cy.apiCreateApp(`${fake.companyName}-inspector-App`);
cy.openApp("?key=value");
cy.viewport(1800, 1800);
});
it("should verify the values of inspector", () => {
cy.get(commonWidgetSelector.sidebarinspector).click();
cy.get(".tooltip-inner").invoke("hide");
openAndVerifyNode("globals", testData.globalsNodes, verifyNodeData);
openAndVerifyNode("currentUser", testData.currentUserNodes, verifyValue);
openAndVerifyNode("theme", testData.themeNodes, verifyValue);
openAndVerifyNode("mode", testData.modeNodes, verifyValue);
openAndVerifyNode("urlparams", testData.urlparamsNode, verifyValue);
if (Cypress.env("environment") !== "Community") {
const ssoUserInfoNode = '[data-cy="inspector-node-ssouserinfo"]';
const inspectorNodeId = '[data-cy="inspector-node-id"]';
cy.get(`${ssoUserInfoNode} > .node-key`).should("have.text", "ssoUserInfo");
cy.get(`${ssoUserInfoNode} > .mx-2`).should("have.text", "undefined");
openNode("theme");
openNode("environment");
verifyValue("name", "String", `"development"`);
cy.get(`${inspectorNodeId} > .node-key`).should("have.text", "id");
}
cy.apiDeleteApp();
});
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", 100, 100);
selectEvent("On click", "Switch page");
cy.get('[data-cy="switch-page-label-and-input"] > .select-search').click().type("home{enter}");
cy.get('[data-cy="button-add-query-param"]').click();
cy.wait(3000);
cy.get("body").then(($body) => {
if ($body.find('[data-cy="event-query-param-key-input-field"]').length == 0) {
cy.get('[data-cy="button-add-query-param"]').click();
}
});
addSupportCSAData("event-query-param-key", "key");
addSupportCSAData("event-query-param-value", "value");
cy.get('[data-cy="switch-page-label-and-input"] > .select-search').click().type("home{enter}");
cy.get('[data-cy="real-canvas"]').click("topRight", { force: true });
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();
cy.get(commonWidgetSelector.draggableWidget("button2")).click();
cy.get('[data-cy="real-canvas"]').click("topRight", { force: true });
cy.dragAndDropWidget("Button", 500, 400);
selectEvent("On click", "Set page variable");
addSupportCSAData("key", "pageVar");
addSupportCSAData("variable", "pageVar");
cy.forceClickOnCanvas();
cy.waitForAutoSave();
cy.get(commonWidgetSelector.draggableWidget("button3")).click();
cy.get(commonWidgetSelector.sidebarinspector).click();
openAndVerifyNode("variables", testData.variablesNodes, verifyValue);
cy.forceClickOnCanvas()
cy.wait(500)
cy.get(commonWidgetSelector.sidebarinspector).click();
cy.get(".tooltip-inner").invoke("hide");
// openNode("page");
openAndVerifyNode("page", testData.testPageNodes, verifyValue);
openNode("variables", 1);
verifyValue("pageVar", "String", `"pageVar"`);
openAndVerifyNode("components", testData.componentsNodes, verifyNodeData);
cy.get('[data-cy="real-canvas"]').click("topRight", { force: true });
cy.get(commonWidgetSelector.draggableWidget("button1")).click();
cy.get(commonWidgetSelector.sidebarinspector).click();
openAndVerifyNode("page", testData.pageNodes, verifyValue);
openNode("globals");
openNode("urlparams");
verifyValue("key", "String", `"value"`);
cy.get(`[data-cy="inspector-node-key"] > .mx-1`)
.realHover()
.parent()
.find('[data-cy="copy-path-to-clipboard"]')
.realClick();
cy.realPress("Escape");
cy.window().then((win) => {
win.navigator.clipboard.readText().then((text) => {
expect(text).to.eq("{{globals.urlparams.key}}");
});
});
cy.get(`[data-cy="inspector-node-key"] > .mx-1`)
.realHover()
.parent()
.find('[data-cy="copy-value-to-clicpboard"]')
.realClick();
cy.realPress("Escape");
cy.window().then((win) => {
win.navigator.clipboard.readText().then((text) => {
expect(text).to.eq(`"value"`);
});
});
cy.dragAndDropWidget("Button", 500, 300);
cy.get(commonWidgetSelector.sidebarinspector).click();
openNode("components");
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.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! (ctrl + Z to undo)");
navigateToCreateNewVersionModal((currentVersion = "v1"));
createNewVersion((newVersion = ["v2"]), (versionFrom = "v1"));
cy.notVisible(commonWidgetSelector.draggableWidget("button1"));
cy.apiDeleteApp();
});
});

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

@ -1,65 +1,29 @@
import { fake } from "Fixtures/fake";
import { textInputText } from "Texts/textInput";
import { commonWidgetText, widgetValue, customValidation } from "Texts/common";
import { commonSelectors, commonWidgetSelector } from "Selectors/common";
import { multipageSelector } from "Selectors/multipage";
import { buttonText } from "Texts/button";
import {
verifyControlComponentAction,
randomString,
openEditorSidebar
} from "Support/utils/commonWidget";
import {
randomString
} from "Support/utils/editor/textInput";
import {
openAccordion,
verifyAndModifyParameter,
openEditorSidebar,
verifyAndModifyToggleFx,
addDefaultEventHandler,
verifyComponentValueFromInspector,
selectColourFromColourPicker,
verifyBoxShadowCss,
verifyLayout,
verifyTooltip,
editAndVerifyWidgetName,
verifyPropertiesGeneralAccordion,
verifyStylesGeneralAccordion,
randomNumber,
closeAccordions,
} from "Support/utils/commonWidget";
import { dataCsvAssertionHelper } from "Support/utils/table";
import {
selectCSA,
selectEvent,
addSupportCSAData,
selectEvent
} from "Support/utils/events";
import {
selectQueryFromLandingPage,
deleteQuery,
query,
changeQueryToggles,
renameQueryFromEditor,
addInputOnQueryField,
changeQueryToggles,
query,
renameQueryFromEditor,
selectQueryFromLandingPage
} from "Support/utils/queries";
import {
verifyCouldnotConnectWithAlert,
resizeQueryPanel,
verifypreview,
addInput,
} from "Support/utils/dataSource";
import {
hideOrUnhidePageMenu,
addEventHandler,
addNewPage,
setHomePage,
hideOrUnhidePage,
detetePage,
modifyPageHandle,
clearSearch,
searchPage,
} from "Support/utils/multipage";
import { verifyNodeData, openNode, verifyValue } from "Support/utils/inspector";
import { deleteDownloadsFolder } from "Support/utils/common";
import {
resizeQueryPanel,
verifypreview
} from "Support/utils/dataSource";
import { openNode, verifyValue } from "Support/utils/inspector";
describe("RunJS", () => {
beforeEach(() => {
@ -90,124 +54,7 @@ describe("RunJS", () => {
cy.apiDeleteApp();
});
it("should verify actions", () => {
const data = {};
data.customText = randomString(12);
selectQueryFromLandingPage("runjs", "JavaScript");
addInputOnQueryField(
"runjs",
`setTimeout(() => {
actions.setVariable('var', 'test');
actions.setPageVariable('pageVar', 'pageTest');
}, [0]) `
);
query("run");
cy.get(commonWidgetSelector.sidebarinspector).click();
cy.get(".tooltip-inner").invoke("hide");
verifyNodeData("variables", "Object", "1 entry ");
openNode("variables", 0);
verifyValue("var", "String", `"test"`);
openNode("page");
openNode("variables", 1);
verifyValue("pageVar", "String", `"pageTest"`);
addInputOnQueryField(
"runjs",
`setTimeout(() => {
actions.unSetVariable('var');
actions.unsetPageVariable('pageVar');
}, [0]) `
);
query("run");
cy.get(commonWidgetSelector.sidebarinspector).click();
cy.get(".tooltip-inner").invoke("hide");
verifyNodeData("variables", "Object", "0 entry ");
openNode("page");
openNode("variables", 1);
verifyNodeData("variables", "Object", "0 entry ", 1);
addInputOnQueryField(
"runjs",
"actions.showAlert('success', 'alert from runjs');"
);
query("run");
cy.verifyToastMessage(commonSelectors.toastMessage, "alert from runjs");
cy.get(multipageSelector.sidebarPageButton).click();
addNewPage("test_page");
cy.url().should("contain", "/test-page");
addInputOnQueryField("runjs", "actions.switchPage('home');");
query("run");
cy.url().should("contain", "/home");
cy.get('[data-cy="real-canvas"]').click("topRight", { force: true });
cy.dragAndDropWidget("Modal", 200, 300);
cy.waitForAutoSave();
addInputOnQueryField("runjs", "actions.showModal('modal1');");
query("run");
cy.get('[data-cy="modal-title"]').should("be.visible");
addInputOnQueryField("runjs", "actions.closeModal('modal1');");
query("run");
cy.wait(200);
cy.notVisible('[data-cy="modal-title"]');
addInputOnQueryField(
"runjs",
"actions.copyToClipboard('data from runjs');"
);
query("run");
cy.window().then((win) => {
win.navigator.clipboard.readText().then((text) => {
expect(text).to.eq("data from runjs");
});
});
addInputOnQueryField(
"runjs",
"actions.setLocalStorage('localStorage','data from runjs');"
);
query("run");
cy.getAllLocalStorage().then((result) => {
expect(result[Cypress.config().baseUrl].localStorage).to.deep.equal(
"data from runjs"
);
});
addInputOnQueryField(
"runjs",
"actions.generateFile('runjscsv', 'csv', [{ name: 'John', email: 'john@tooljet.com' }])"
);
query("run");
cy.readFile("cypress/downloads/runjscsv.csv", "utf-8")
.should("contain", "name,email")
.and("contain", "John,john@tooljet.com");
// addInputOnQueryField(
// "runjs",
// "actions.goToApp('111234')"
// );
// query("run");
addInputOnQueryField("runjs", "actions.logout()");
query("run");
cy.get('[data-cy="sign-in-header"]').should("be.visible");
cy.apiLogin();
cy.openApp(
Cypress.env("workspaceId"),
Cypress.env("appId"),
'[data-cy="draggable-widget-modal1-launch-button"]'
);
});
it("should verify global and page data", () => {
it.skip("should verify global and page data", () => {
const data = {};
data.customText = randomString(12);
@ -275,7 +122,7 @@ describe("RunJS", () => {
);
query("run");
openEditorSidebar("button1");
selectEvent("On Click", "Run query", 1);
selectEvent("On Click", "Run query");
cy.get('[data-cy="query-selection-field"]').type("runjs1{enter}");
cy.get(commonWidgetSelector.draggableWidget("button1")).click();
@ -300,18 +147,21 @@ describe("RunJS", () => {
"runjs",
"actions.showAlert('success', 'alert from runjs');"
);
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();
cy.verifyToastMessage(
commonSelectors.toastMessage,
"alert from runjs",
false
);
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(
@ -322,10 +172,12 @@ describe("RunJS", () => {
cy.verifyToastMessage(commonSelectors.toastMessage, "alert from runjs");
resizeQueryPanel("80");
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="runjs-input-field"]').realClick();
cy.wait(1000);
cy.waitForAutoSave();

View file

@ -1,64 +1,33 @@
import { fake } from "Fixtures/fake";
import { textInputText } from "Texts/textInput";
import { commonWidgetText, widgetValue, customValidation } from "Texts/common";
import { commonSelectors, commonWidgetSelector } from "Selectors/common";
import { multipageSelector } from "Selectors/multipage";
import { buttonText } from "Texts/button";
import {
verifyControlComponentAction,
randomString,
openEditorSidebar
} from "Support/utils/commonWidget";
import {
randomString
} from "Support/utils/editor/textInput";
import {
openAccordion,
verifyAndModifyParameter,
openEditorSidebar,
verifyAndModifyToggleFx,
addDefaultEventHandler,
verifyComponentValueFromInspector,
selectColourFromColourPicker,
verifyBoxShadowCss,
verifyLayout,
verifyTooltip,
editAndVerifyWidgetName,
verifyPropertiesGeneralAccordion,
verifyStylesGeneralAccordion,
randomNumber,
closeAccordions,
} from "Support/utils/commonWidget";
import { dataCsvAssertionHelper } from "Support/utils/table";
import {
selectCSA,
selectEvent,
addSupportCSAData,
selectEvent
} from "Support/utils/events";
import {
selectQueryFromLandingPage,
query,
changeQueryToggles,
renameQueryFromEditor,
addInputOnQueryField,
changeQueryToggles,
query,
renameQueryFromEditor,
selectQueryFromLandingPage,
waitForQueryAction,
} from "Support/utils/queries";
import {
verifyCouldnotConnectWithAlert,
resizeQueryPanel,
verifypreview,
addInput,
verifypreview
} from "Support/utils/dataSource";
import { openNode, verifyNodeData, verifyValue } from "Support/utils/inspector";
import {
hideOrUnhidePageMenu,
addEventHandler,
addNewPage,
setHomePage,
hideOrUnhidePage,
detetePage,
modifyPageHandle,
clearSearch,
searchPage,
addNewPage
} from "Support/utils/multipage";
import { verifyNodeData, openNode, verifyValue } from "Support/utils/inspector";
describe("runpy", () => {
beforeEach(() => {
@ -90,7 +59,7 @@ describe("runpy", () => {
cy.apiDeleteApp();
});
it("should verify actions", () => {
it.skip("should verify actions", () => {
const data = {};
data.customText = randomString(12);
@ -151,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");
@ -175,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");
@ -186,17 +155,12 @@ actions.unsetPageVariable('pageVar')`
);
});
// addInputOnQueryField(
// addInputOnQueryField( //Need fix asap
// "runpy",
// "actions.generateFile('runpycsv', 'csv', [{ 'name': 'John', 'email': 'john@tooljet.com' }])"
// );
// query("run");
// cy.verifyToastMessage(
// commonSelectors.toastMessage,
// "Query (runpy1) completed."
// );
// cy.wait(3000);
// cy.readFile("cypress/downloads/runpycsv.csv", "utf-8")
@ -210,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");
@ -220,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);
@ -286,7 +250,7 @@ actions.unsetPageVariable('pageVar')`
query("run");
openEditorSidebar("button1");
selectEvent("On Click", "Run query", 1);
selectEvent("On Click", "Run query");
cy.get('[data-cy="query-selection-field"]').type("runpy1{enter}");
cy.get(commonWidgetSelector.draggableWidget("button1")).click();
cy.verifyToastMessage(commonSelectors.toastMessage, "alert from runpy");
@ -309,17 +273,20 @@ actions.unsetPageVariable('pageVar')`
"runpy",
"actions.showAlert('success', 'alert from runpy');"
);
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();
changeQueryToggles("confirmation-before-run");
cy.wait("@editQuery");
// cy.wait("@editQuery");
cy.wait(200);
cy.waitForAutoSave();
cy.reload();
@ -330,12 +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();
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

@ -0,0 +1,221 @@
import { fake } from "Fixtures/fake";
import { postgreSqlSelector } from "Selectors/postgreSql";
import { postgreSqlText } from "Texts/postgreSql";
import { commonSelectors } from "Selectors/common";
import { selectAndAddDataSource } from "Support/utils/postgreSql";
import { closeDSModal } from "Support/utils/dataSource";
const data = {};
data.dsNamefake = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
data.dsNamefake1 = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
const cyParamName = (name) => name.toLowerCase().replace(/[^a-z0-9]/g, "-");
data.workspaceName = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
data.workspaceSlug = fake.lastName.toLowerCase().replace(/\s+/g, "-");
const dataSources = [
"BigQuery",
"ClickHouse",
"CosmosDB",
"CouchDB",
"Databricks",
"DynamoDB",
"Elasticsearch",
"Firestore",
"InfluxDB",
"MariaDB",
"MongoDB",
"SQL Server",
"MySQL",
"Oracle DB",
"PostgreSQL",
"Redis",
"RethinkDB",
"SAP HANA",
"Snowflake",
"TypeSense",
"Airtable",
"Amazon SES",
"Appwrite",
"Amazon Athena",
"Baserow",
// "Google Sheets", need to remove
"GraphQL",
// "gRPC", need to remove
"Mailgun",
"n8n",
"Notion",
"OpenAPI",
"REST API",
"SendGrid",
// "Slack", need to remove
"SMTP",
"Stripe",
"Twilio",
"Woocommerce",
//"Zendesk", need to remove
"Azure Blob Storage",
"GCS",
"Minio",
"AWS S3",
];
describe("Add all Data sources to app", () => {
beforeEach(() => {
cy.apiLogin();
});
it.skip("Should verify global data source page", () => {
cy.apiCreateWorkspace(data.workspaceName, data.workspaceSlug);
cy.visit(`${data.workspaceSlug}`);
cy.get(commonSelectors.globalDataSourceIcon).click();
closeDSModal();
cy.get(postgreSqlSelector.allDatasourceLabelAndCount).should(
"have.text",
postgreSqlText.allDataSources()
);
cy.get(postgreSqlSelector.commonlyUsedLabelAndCount).should(
"have.text",
postgreSqlText.commonlyUsed
);
cy.get(postgreSqlSelector.cloudStorageLabelAndCount).should(
"have.text",
postgreSqlText.allCloudStorage
);
});
it.skip("Should add all data sources in data source page", () => {
cy.visit(`${data.workspaceSlug}`);
dataSources.forEach((dsName) => {
cy.get(commonSelectors.globalDataSourceIcon).click();
selectAndAddDataSource("databases", dsName, dsName); // Using the correct fake name
// Test connection
// cy.get(postgreSqlSelector.buttonTestConnection).click();
// cy.get(postgreSqlSelector.textConnectionVerified, {
// timeout: 10000,
// }).should("have.text", postgreSqlText.labelConnectionVerified);
// // Save data source
// cy.get(postgreSqlSelector.buttonSave).click();
// cy.verifyToastMessage(
// commonSelectors.toastMessage,
// `Data Source ${dsName} saved.`
// );
});
});
it.skip("Should add all data sources in the app", () => {
cy.visit(`${data.workspaceSlug}`);
cy.get(commonSelectors.dashboardIcon).click();
cy.get(commonSelectors.appCreateButton).click();
cy.get(commonSelectors.appNameInput).click().type(data.dsNamefake);
cy.get(commonSelectors.createAppButton).click();
cy.skipWalkthrough();
cy.wrap(dataSources).each((dsName) => {
cy.get('[data-cy="show-ds-popover-button"]').click();
cy.get(".css-4e90k9").type(
`cypress-${cyParamName(dsName)}-${cyParamName(dsName)}`
);
cy.wait(500);
cy.contains(
`[id*="react-select-"]`,
`cypress-${cyParamName(dsName)}-${cyParamName(dsName)}`
)
.should("be.visible")
.click();
cy.wait(500);
});
});
it.skip("Should install all makretplace plugins and add them into the app", () => {
cy.visit(`${data.workspaceSlug}`);
const dataSourcesMarketplace = [
"Plivo",
"GitHub",
"OpenAI",
"AWS Textract",
"HarperDB",
"AWS Redshift",
"PocketBase",
"AWS Lambda",
"Supabase",
"Engagespot",
// "Salesforce", need to remove
"Presto",
"Jira",
// "Sharepoint", need to remove
"Portkey",
"Pinecone",
"Hugging Face",
"Cohere",
"Gemini",
"Mistral",
"Anthropic",
"Qdrant",
"Weaviate DB",
];
cy.get(commonSelectors.globalDataSourceIcon).click();
cy.window().then((win) => {
cy.stub(win, "open").callsFake((url) => {
win.location.href = url;
});
});
cy.get('[data-cy="data-source-add-plugin"]').click();
cy.get(".marketplace-install").each(($el) => {
cy.wrap($el).click();
cy.wait(500);
cy.get(commonSelectors.toastMessage).should("include.text", "installed");
});
cy.wait(1000);
cy.get(commonSelectors.globalDataSourceIcon).click();
cy.get(commonSelectors.pageSectionHeader).should(
"have.text",
"Data sources"
);
cy.wrap(dataSourcesMarketplace).each((dsName) => {
cy.get(commonSelectors.globalDataSourceIcon).click();
selectAndAddDataSource("databases", dsName, dsName);
cy.wait(1000);
});
cy.get(commonSelectors.dashboardIcon).should("be.visible").click();
cy.get(commonSelectors.appCreateButton).should("be.visible").click();
cy.get(commonSelectors.appNameInput)
.should("be.visible")
.click()
.type(data.dsNamefake1);
cy.get(commonSelectors.createAppButton).click();
cy.skipWalkthrough();
cy.wrap(dataSourcesMarketplace).each((dsName) => {
cy.get('[data-cy="show-ds-popover-button"]').click();
cy.get(".css-4e90k9").type(
`cypress-${cyParamName(dsName)}-${cyParamName(dsName)}`
);
cy.wait(1000);
cy.contains(
`[id*="react-select-"]`,
`cypress-${cyParamName(dsName)}-${cyParamName(dsName)}`
)
.should("be.visible")
.click();
cy.wait(1000);
});
});
});

View file

@ -0,0 +1,289 @@
import { fake } from "Fixtures/fake";
import { postgreSqlSelector, airTableSelector } from "Selectors/postgreSql";
import { postgreSqlText } from "Texts/postgreSql";
import { airtableText } from "Texts/airTable";
import { commonSelectors } from "Selectors/common";
import { commonText } from "Texts/common";
import {
fillDataSourceTextField,
selectAndAddDataSource,
} from "Support/utils/postgreSql";
import {
deleteDatasource,
closeDSModal,
deleteAppandDatasourceAfterExecution,
} from "Support/utils/dataSource";
import { dataSourceSelector } from "../../../../../constants/selectors/dataSource";
const data = {};
data.queryName = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
describe("Data source Airtable", () => {
beforeEach(() => {
cy.apiLogin();
cy.visit("/");
data.dsName = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
});
it("Should verify elements on connection AirTable form", () => {
cy.get(commonSelectors.globalDataSourceIcon).click();
closeDSModal();
cy.get(postgreSqlSelector.allDatasourceLabelAndCount).should(
"have.text",
postgreSqlText.allDataSources()
);
cy.get(postgreSqlSelector.commonlyUsedLabelAndCount).should(
"have.text",
postgreSqlText.commonlyUsed
);
cy.get(postgreSqlSelector.databaseLabelAndCount).should(
"have.text",
postgreSqlText.allDatabase()
);
cy.get(postgreSqlSelector.apiLabelAndCount).should(
"have.text",
postgreSqlText.allApis
);
cy.get(postgreSqlSelector.cloudStorageLabelAndCount).should(
"have.text",
postgreSqlText.allCloudStorage
);
selectAndAddDataSource("databases", airtableText.airtable, data.dsName);
cy.get(postgreSqlSelector.buttonSave).verifyVisibleElement(
"have.text",
postgreSqlText.buttonTextSave
);
cy.verifyToastMessage(
commonSelectors.toastMessage,
postgreSqlText.toastDSSaved
);
deleteDatasource(`cypress-${data.dsName}-airtable`);
});
it("Should verify the functionality of AirTable connection form.", () => {
selectAndAddDataSource("databases", airtableText.airtable, data.dsName);
fillDataSourceTextField(
airtableText.ApiKey,
airtableText.apikeyPlaceholder,
Cypress.env("airTable_apikey")
);
cy.get(postgreSqlSelector.buttonSave).click();
cy.verifyToastMessage(
commonSelectors.toastMessage,
postgreSqlText.toastDSSaved
);
cy.get(commonSelectors.globalDataSourceIcon).click();
cy.get(
`[data-cy="cypress-${data.dsName}-airtable-button"]`
).verifyVisibleElement("have.text", `cypress-${data.dsName}-airtable`);
deleteDatasource(`cypress-${data.dsName}-airtable`);
});
it("Should able to run the query with valid conection", () => {
const airTable_apiKey = Cypress.env("airTable_apikey");
const airTable_baseId = Cypress.env("airtabelbaseId");
const airTable_tableName = Cypress.env("airtable_tableName");
const airTable_recordID = Cypress.env("airtable_recordId");
selectAndAddDataSource("databases", airtableText.airtable, data.dsName);
fillDataSourceTextField(
airtableText.ApiKey,
airtableText.apikeyPlaceholder,
airTable_apiKey
);
cy.wait(1000);
cy.get(postgreSqlSelector.buttonSave).click();
cy.verifyToastMessage(
commonSelectors.toastMessage,
postgreSqlText.toastDSSaved
);
cy.get(commonSelectors.globalDataSourceIcon).click();
cy.get(
`[data-cy="cypress-${data.dsName}-airtable-button"]`
).verifyVisibleElement("have.text", `cypress-${data.dsName}-airtable`);
cy.get(commonSelectors.dashboardIcon).click();
cy.get(commonSelectors.appCreateButton).click();
cy.get(commonSelectors.appNameInput).click().type(data.dsName);
cy.get(commonSelectors.createAppButton).click();
cy.skipWalkthrough();
cy.get('[data-cy="show-ds-popover-button"]').click();
cy.get(".css-4e90k9").type(`${data.dsName}`);
cy.contains(`[id*="react-select-"]`, data.dsName).click();
cy.get('[data-cy="query-rename-input"]').clear().type(data.dsName);
// Verfiy List Recored operation
cy.get(airTableSelector.operationSelectDropdown)
.click()
.type("List records{enter}");
cy.get(airTableSelector.baseIdInputField).clearAndTypeOnCodeMirror(
airTable_baseId
);
cy.get(airTableSelector.tableNameInputField).clearAndTypeOnCodeMirror(
airTable_tableName
);
cy.get(dataSourceSelector.queryPreviewButton).click();
cy.verifyToastMessage(
commonSelectors.toastMessage,
`Query (${data.dsName}) completed.`
);
// Verfiy Retrieve record operation
cy.get(airTableSelector.operationSelectDropdown)
.click()
.type("Retrieve record{enter}");
cy.get(airTableSelector.baseIdInputField).clearAndTypeOnCodeMirror(
airTable_baseId
);
cy.get(airTableSelector.tableNameInputField).clearAndTypeOnCodeMirror(
airTable_tableName
);
cy.get(airTableSelector.recordIdInputField).clearAndTypeOnCodeMirror(
airTable_recordID
);
cy.get(dataSourceSelector.queryPreviewButton).click();
cy.verifyToastMessage(
commonSelectors.toastMessage,
`Query (${data.dsName}) completed.`
);
// Verfiy Create record operation
cy.get(airTableSelector.operationSelectDropdown)
.click()
.type("Create record{enter}");
cy.get(airTableSelector.baseIdInputField).clearAndTypeOnCodeMirror(
airTable_baseId
);
cy.get(airTableSelector.tableNameInputField).clearAndTypeOnCodeMirror(
airTable_tableName
);
cy.get(airTableSelector.bodyInputField)
.realClick()
.realType('[{"', { force: true, delay: 0 })
.realType("fields", { force: true, delay: 0 })
.realType('": {}', { force: true, delay: 0 });
cy.get(dataSourceSelector.queryPreviewButton).click();
cy.verifyToastMessage(
commonSelectors.toastMessage,
`Query (${data.dsName}) completed.`
);
// Verfiy Update record operation
cy.get('[data-cy="show-ds-popover-button"]').click();
cy.get(".css-4e90k9").type(`${data.dsName}`);
cy.contains(`[id*="react-select-"]`, data.dsName).click();
cy.get('[data-cy="query-rename-input"]').clear().type(data.queryName);
cy.get(airTableSelector.operationSelectDropdown)
.click()
.type("Update record{enter}");
cy.get(airTableSelector.baseIdInputField).clearAndTypeOnCodeMirror(
airTable_baseId
);
cy.get(airTableSelector.tableNameInputField).clearAndTypeOnCodeMirror(
airTable_tableName
);
cy.get(airTableSelector.recordIdInputField).clearAndTypeOnCodeMirror(
airTable_recordID
);
cy.get(airTableSelector.bodyInputField)
.realClick()
.realType("{", { force: true, delay: 0 })
.realType("{enter}", { force: true, delay: 0 })
.realType('"Phone Number": "555_98"', { force: true, delay: 0 });
cy.get(dataSourceSelector.queryPreviewButton).click();
cy.verifyToastMessage(
commonSelectors.toastMessage,
`Query (${data.queryName}) completed.`
);
// Verify Delete record operation
cy.get(airTableSelector.operationSelectDropdown)
.click()
.type("Delete record{enter}");
const recordId = Cypress._.uniqueId("recDummy_");
cy.request({
method: "POST",
url: `https://api.airtable.com/v0/${airTable_baseId}/${airTable_tableName}`,
headers: {
Authorization: `Bearer ${Cypress.env("airTable_apikey")}`,
"Content-Type": "application/json",
},
body: {
records: [
{
fields: {
"Employee ID": "E005",
"First Name": "test",
"Last Name": "abc",
Email: "doe@example.com",
"Phone Number": "555-12",
},
},
],
},
}).then((createResponse) => {
const newRecordId = createResponse.body.records[0].id;
cy.get(airTableSelector.operationSelectDropdown)
.click()
.type("Delete record{enter}");
cy.get(airTableSelector.baseIdInputField).clearAndTypeOnCodeMirror(
airTable_baseId
);
cy.get(airTableSelector.tableNameInputField).clearAndTypeOnCodeMirror(
airTable_tableName
);
cy.get(airTableSelector.recordIdInputField).clearAndTypeOnCodeMirror(
newRecordId
);
cy.get(dataSourceSelector.queryPreviewButton).click();
cy.verifyToastMessage(
commonSelectors.toastMessage,
`Query (${data.queryName}) completed.`
);
deleteAppandDatasourceAfterExecution(
data.dsName,
`cypress-${data.dsName}-airtable`
);
});
});
});

View file

@ -0,0 +1,208 @@
import { fake } from "Fixtures/fake";
import { postgreSqlSelector } from "Selectors/postgreSql";
import { pluginSelectors } from "Selectors/plugins";
import { postgreSqlText } from "Texts/postgreSql";
import { amazonSesText } from "Texts/amazonSes";
import { amazonAthenaText } from "Texts/amazonAthena";
import { commonSelectors } from "Selectors/common";
import { commonText } from "Texts/common";
import {
fillDataSourceTextField,
selectAndAddDataSource,
} from "Support/utils/postgreSql";
import {
deleteDatasource,
closeDSModal,
deleteAppandDatasourceAfterExecution,
} from "Support/utils/dataSource";
import { dataSourceSelector } from "../../../../../constants/selectors/dataSource";
const data = {};
describe("Data source amazon athena", () => {
beforeEach(() => {
cy.apiLogin();
cy.visit("/");
data.dsName = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
});
it.skip("Should verify elements on amazon athena connection form", () => {
const Accesskey = Cypress.env("amazonathena_accessKey");
const Secretkey = Cypress.env("amazonathena_secretKey");
const DbName = Cypress.env("amazonathena_DbName");
cy.get(commonSelectors.globalDataSourceIcon).click();
closeDSModal();
cy.get(postgreSqlSelector.allDatasourceLabelAndCount).should(
"have.text",
postgreSqlText.allDataSources()
);
cy.get(postgreSqlSelector.commonlyUsedLabelAndCount).should(
"have.text",
postgreSqlText.commonlyUsed
);
cy.get(postgreSqlSelector.databaseLabelAndCount).should(
"have.text",
postgreSqlText.allDatabase()
);
cy.get(postgreSqlSelector.apiLabelAndCount).should(
"have.text",
postgreSqlText.allApis
);
cy.get(postgreSqlSelector.cloudStorageLabelAndCount).should(
"have.text",
postgreSqlText.allCloudStorage
);
selectAndAddDataSource(
"databases",
amazonAthenaText.AmazonAthena,
data.dsName
);
cy.get(pluginSelectors.amazonAthenaDbName).click().type(DbName);
cy.get(pluginSelectors.amazonsesAccesKey).click().type(" ");
fillDataSourceTextField(
amazonSesText.labelSecretKey,
amazonAthenaText.placeholderSecretKey,
Secretkey
);
cy.get(".react-select__dropdown-indicator").eq(1).click();
cy.get(".react-select__option").contains("US West (N. California)").click();
cy.get(postgreSqlSelector.buttonTestConnection)
.verifyVisibleElement(
"have.text",
postgreSqlText.buttonTextTestConnection
)
.click();
cy.get(postgreSqlSelector.connectionFailedText).verifyVisibleElement(
"have.text",
postgreSqlText.couldNotConnect
);
cy.get(postgreSqlSelector.buttonSave)
.verifyVisibleElement("have.text", postgreSqlText.buttonTextSave)
.click();
cy.verifyToastMessage(
commonSelectors.toastMessage,
postgreSqlText.toastDSSaved
);
deleteDatasource(`cypress-${data.dsName}-Amazon-Athena`);
});
it.skip("Should verify the functionality of amazon athena connection form.", () => {
const Accesskey = Cypress.env("amazonathena_accessKey");
const Secretkey = Cypress.env("amazonathena_secretKey");
const DbName = Cypress.env("amazonathena_DbName");
selectAndAddDataSource(
"databases",
amazonAthenaText.AmazonAthena,
data.dsName
);
cy.get(pluginSelectors.amazonAthenaDbName).click().type(DbName);
cy.get(pluginSelectors.amazonsesAccesKey).click().type(Accesskey);
fillDataSourceTextField(
amazonSesText.labelSecretKey,
amazonAthenaText.placeholderSecretKey,
Secretkey
);
cy.get(".react-select__dropdown-indicator").eq(1).click();
cy.get(".react-select__option").contains("US West (N. California)").click();
cy.get(postgreSqlSelector.buttonTestConnection).click();
cy.get(postgreSqlSelector.textConnectionVerified, {
timeout: 10000,
}).should("have.text", postgreSqlText.labelConnectionVerified);
cy.get(postgreSqlSelector.buttonSave).click();
cy.verifyToastMessage(
commonSelectors.toastMessage,
postgreSqlText.toastDSSaved
);
deleteDatasource(`cypress-${data.dsName}-amazon-Athena`);
});
it.skip("Should able to run the query with valid conection", () => {
const Accesskey = Cypress.env("amazonathena_accessKey");
const Secretkey = Cypress.env("amazonathena_secretKey");
const DbName = Cypress.env("amazonathena_DbName");
selectAndAddDataSource(
"databases",
amazonAthenaText.AmazonAthena,
data.dsName
);
cy.get(pluginSelectors.amazonAthenaDbName).click().type(DbName);
fillDataSourceTextField(
amazonAthenaText.labelAccesskey,
amazonAthenaText.placeholderEnteraAccessKey,
Cypress.env("amazonathena_accessKey")
);
fillDataSourceTextField(
amazonAthenaText.labelSecretKey,
amazonAthenaText.placeholderSecretKey,
Cypress.env("amazonathena_secretKey")
);
cy.get(".react-select__dropdown-indicator").eq(1).click();
cy.get(".react-select__option").contains("US West (N. California)").click();
cy.get(postgreSqlSelector.buttonTestConnection).click();
cy.get(postgreSqlSelector.textConnectionVerified, {
timeout: 10000,
}).should("have.text", postgreSqlText.labelConnectionVerified);
cy.get(postgreSqlSelector.buttonSave).click();
cy.verifyToastMessage(
commonSelectors.toastMessage,
postgreSqlText.toastDSSaved
);
cy.get(commonSelectors.globalDataSourceIcon).click();
cy.get(
`[data-cy="cypress-${data.dsName}-amazon-athena-button"]`
).verifyVisibleElement("have.text", `cypress-${data.dsName}-amazon-athena`);
cy.wait(1000);
cy.get(commonSelectors.dashboardIcon).click();
cy.get(commonSelectors.appCreateButton).click();
cy.get(commonSelectors.appNameInput).click().type(data.dsName);
cy.get(commonSelectors.createAppButton).click();
cy.skipWalkthrough();
cy.get('[data-cy="show-ds-popover-button"]').click();
cy.get(".css-4e90k9").type(`${data.dsName}`);
cy.contains(`[id*="react-select-"]`, data.dsName).click();
cy.get('[data-cy="query-rename-input"]').clear().type(data.dsName);
cy.get(`[data-cy="list-query-${data.dsName}"]`).should("be.visible");
cy.get('[data-cy="query-input-field"]').clearAndTypeOnCodeMirror(
"SHOW DATABASES;"
);
cy.get(
'[data-cy="query-input-field"] >>> .cm-editor >> .cm-content > .cm-line'
).should("have.text", "SHOW DATABASES;");
cy.get(dataSourceSelector.queryPreviewButton).click();
cy.verifyToastMessage(
commonSelectors.toastMessage,
`Query (${data.dsName}) completed.`
);
deleteAppandDatasourceAfterExecution(
data.dsName,
`cypress-${data.dsName}-amazon-Athena`
);
});
});

View file

@ -0,0 +1,204 @@
import { fake } from "Fixtures/fake";
import { postgreSqlSelector } from "Selectors/postgreSql";
import { pluginSelectors } from "Selectors/plugins";
import { postgreSqlText } from "Texts/postgreSql";
import { amazonSesText } from "Texts/amazonSes";
import { commonSelectors } from "Selectors/common";
import { commonText } from "Texts/common";
import {
fillDataSourceTextField,
selectAndAddDataSource,
} from "Support/utils/postgreSql";
import {
deleteDatasource,
closeDSModal,
deleteAppandDatasourceAfterExecution,
} from "Support/utils/dataSource";
import { dataSourceSelector } from "../../../../../constants/selectors/dataSource";
const data = {};
describe("Data source amazon ses", () => {
beforeEach(() => {
cy.apiLogin();
cy.visit("/");
data.dsName = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
});
it.skip("Should verify elements on amazonses connection form", () => {
const Accesskey = Cypress.env("amazonSes_accessKey");
const Secretkey = Cypress.env("amazonSes_secretKey");
cy.get(commonSelectors.globalDataSourceIcon).click();
closeDSModal();
cy.get(postgreSqlSelector.allDatasourceLabelAndCount).should(
"have.text",
postgreSqlText.allDataSources()
);
cy.get(postgreSqlSelector.commonlyUsedLabelAndCount).should(
"have.text",
postgreSqlText.commonlyUsed
);
cy.get(postgreSqlSelector.databaseLabelAndCount).should(
"have.text",
postgreSqlText.allDatabase()
);
cy.get(postgreSqlSelector.apiLabelAndCount).should(
"have.text",
postgreSqlText.allApis
);
cy.get(postgreSqlSelector.cloudStorageLabelAndCount).should(
"have.text",
postgreSqlText.allCloudStorage
);
selectAndAddDataSource("databases", amazonSesText.AmazonSES, data.dsName);
cy.get(".react-select__dropdown-indicator").eq(1).click();
cy.get(".react-select__option").contains("US West (N. California)").click();
cy.get(pluginSelectors.amazonsesAccesKey).click().type(Accesskey);
fillDataSourceTextField(
amazonSesText.labelSecretKey,
"**************",
Secretkey
);
cy.get(postgreSqlSelector.buttonSave)
.verifyVisibleElement("have.text", postgreSqlText.buttonTextSave)
.click();
cy.verifyToastMessage(
commonSelectors.toastMessage,
postgreSqlText.toastDSSaved
);
deleteDatasource(`cypress-${data.dsName}-Amazon-ses`);
});
it.skip("Should verify the functionality of amazonses connection form.", () => {
selectAndAddDataSource("databases", amazonSesText.AmazonSES, data.dsName);
cy.get(".react-select__dropdown-indicator").eq(1).click();
cy.get(".react-select__option").contains("US West (N. California)").click();
fillDataSourceTextField(
amazonSesText.labelAccesskey,
amazonSesText.placeholderAccessKey,
Cypress.env("amazonSes_accessKey")
);
fillDataSourceTextField(
amazonSesText.labelSecretKey,
amazonSesText.placeholderSecretKey,
Cypress.env("amazonSes_secretKey")
);
cy.get(postgreSqlSelector.buttonSave).click();
cy.verifyToastMessage(
commonSelectors.toastMessage,
postgreSqlText.toastDSSaved
);
cy.get(commonSelectors.globalDataSourceIcon).click();
cy.get(
`[data-cy="cypress-${data.dsName}-amazon-ses-button"]`
).verifyVisibleElement("have.text", `cypress-${data.dsName}-amazon-ses`);
deleteDatasource(`cypress-${data.dsName}-amazon-ses`);
});
it.skip("Should able to run the query with valid conection", () => {
const email = "adish" + "@" + "tooljet.com";
selectAndAddDataSource("databases", amazonSesText.AmazonSES, data.dsName);
cy.get(".react-select__dropdown-indicator").eq(1).click();
cy.get(".react-select__option").contains("US West (N. California)").click();
fillDataSourceTextField(
amazonSesText.labelAccesskey,
amazonSesText.placeholderAccessKey,
Cypress.env("amazonSes_accessKey")
);
fillDataSourceTextField(
amazonSesText.labelSecretKey,
amazonSesText.placeholderSecretKey,
Cypress.env("amazonSes_secretKey")
);
cy.get(postgreSqlSelector.buttonSave).click();
cy.verifyToastMessage(
commonSelectors.toastMessage,
postgreSqlText.toastDSSaved
);
cy.get(commonSelectors.globalDataSourceIcon).click();
cy.get(
`[data-cy="cypress-${data.dsName}-amazon-ses-button"]`
).verifyVisibleElement("have.text", `cypress-${data.dsName}-amazon-ses`);
cy.wait(1000);
cy.get(commonSelectors.dashboardIcon).click();
cy.get(commonSelectors.appCreateButton).click();
cy.get(commonSelectors.appNameInput).click().type(data.dsName);
cy.get(commonSelectors.createAppButton).click();
cy.skipWalkthrough();
cy.get('[data-cy="show-ds-popover-button"]').click();
cy.get(".css-4e90k9").type(`${data.dsName}`);
cy.contains(`[id*="react-select-"]`, data.dsName).click();
cy.get('[data-cy="query-rename-input"]').clear().type(data.dsName);
cy.get(pluginSelectors.operationDropdown)
.click()
.type("Email service{enter}");
cy.wait(500);
cy.get(pluginSelectors.sendEmailInputField)
.realClick()
.realType('{{["', { force: true, delay: 0 })
.realType("mekhla@tooljet.com", { force: true, delay: 0 });
cy.get(pluginSelectors.ccEmailInputField)
.realClick()
.realType('{{["', { force: true, delay: 0 })
.realType("mani@tooljet.com", { force: true, delay: 0 });
cy.get(pluginSelectors.bccEmailInputField)
.realClick()
.realType('{{["', { force: true, delay: 0 })
.realType("midhun@tooljet.com", { force: true, delay: 0 });
cy.get(pluginSelectors.sendEmailFromInputField)
.realClick()
.realType("adish", { force: true, delay: 0 })
.realType("@", { force: true, delay: 0 })
.realType("tooljet.com", { force: true, delay: 0 });
cy.get(pluginSelectors.emailSubjetInputField).clearAndTypeOnCodeMirror(
"Testmail for amazon ses"
);
cy.get(pluginSelectors.emailbodyInputField).clearAndTypeOnCodeMirror(
"Body text for amazon ses"
);
cy.wait(1000);
cy.get(dataSourceSelector.queryPreviewButton).click();
cy.verifyToastMessage(
commonSelectors.toastMessage,
`Query (${data.dsName}) completed.`
);
deleteAppandDatasourceAfterExecution(
data.dsName,
`cypress-${data.dsName}-amazon-ses`
);
});
});

View file

@ -0,0 +1,314 @@
import { fake } from "Fixtures/fake";
import { postgreSqlSelector } from "Selectors/postgreSql";
import { postgreSqlText } from "Texts/postgreSql";
import { appwriteText } from "Texts/appWrite";
import { appWriteSelectors } from "Selectors/Plugins";
import { commonSelectors } from "Selectors/common";
import { commonText } from "Texts/common";
import {
fillDataSourceTextField,
selectAndAddDataSource,
} from "Support/utils/postgreSql";
import {
deleteDatasource,
closeDSModal,
deleteAppandDatasourceAfterExecution,
} from "Support/utils/dataSource";
import { dataSourceSelector } from "../../../../../constants/selectors/dataSource";
const data = {};
describe("Data source AppWrite", () => {
beforeEach(() => {
cy.apiLogin();
cy.visit("/");
data.dsName = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
});
it.skip("Should verify elements on appwrite connection form", () => {
const Host = Cypress.env("appwrite_host");
const ProjectID = Cypress.env("appwrite_projectID");
const DatabaseID = Cypress.env("appwrite_databaseID");
const SecretKey = Cypress.env("appwrite_secretkey");
cy.get(commonSelectors.globalDataSourceIcon).click();
closeDSModal();
cy.get(postgreSqlSelector.allDatasourceLabelAndCount).should(
"have.text",
postgreSqlText.allDataSources()
);
cy.get(postgreSqlSelector.commonlyUsedLabelAndCount).should(
"have.text",
postgreSqlText.commonlyUsed
);
cy.get(postgreSqlSelector.databaseLabelAndCount).should(
"have.text",
postgreSqlText.allDatabase()
);
cy.get(postgreSqlSelector.apiLabelAndCount).should(
"have.text",
postgreSqlText.allApis
);
cy.get(postgreSqlSelector.cloudStorageLabelAndCount).should(
"have.text",
postgreSqlText.allCloudStorage
);
selectAndAddDataSource("databases", appwriteText.appwrite, data.dsName);
fillDataSourceTextField(
appwriteText.host,
appwriteText.hostPlaceholder,
Host
);
fillDataSourceTextField(
appwriteText.ProjectID,
appwriteText.projectIdPlaceholder,
ProjectID
);
fillDataSourceTextField(
appwriteText.DatabaseID,
appwriteText.databaseIdPlaceholder,
DatabaseID
);
fillDataSourceTextField(
appwriteText.SecretKey,
appwriteText.SecretKeyPlaceholder,
SecretKey
);
cy.get(postgreSqlSelector.buttonTestConnection).click();
cy.get(postgreSqlSelector.textConnectionVerified, {
timeout: 10000,
}).should("have.text", postgreSqlText.labelConnectionVerified);
cy.get(postgreSqlSelector.buttonSave)
.verifyVisibleElement("have.text", postgreSqlText.buttonTextSave)
.click();
cy.verifyToastMessage(
commonSelectors.toastMessage,
postgreSqlText.toastDSSaved
);
deleteDatasource(`cypress-${data.dsName}-Appwrite`);
});
it.skip("Should verify the functionality of appwrite connection form.", () => {
const Host = Cypress.env("appwrite_host");
const ProjectID = Cypress.env("appwrite_projectID");
const DatabaseID = Cypress.env("appwrite_databaseID");
const SecretKey = Cypress.env("appwrite_secretkey");
cy.get(commonSelectors.globalDataSourceIcon).click();
closeDSModal();
selectAndAddDataSource("databases", appwriteText.appwrite, data.dsName);
fillDataSourceTextField(
appwriteText.host,
appwriteText.hostPlaceholder,
Host
);
fillDataSourceTextField(
appwriteText.ProjectID,
appwriteText.projectIdPlaceholder,
ProjectID
);
fillDataSourceTextField(
appwriteText.DatabaseID,
appwriteText.databaseIdPlaceholder,
DatabaseID
);
fillDataSourceTextField(
appwriteText.SecretKey,
appwriteText.SecretKeyPlaceholder,
SecretKey
);
cy.get(postgreSqlSelector.buttonTestConnection).click();
cy.get(postgreSqlSelector.textConnectionVerified, {
timeout: 10000,
}).should("have.text", postgreSqlText.labelConnectionVerified);
cy.get(postgreSqlSelector.buttonSave)
.verifyVisibleElement("have.text", postgreSqlText.buttonTextSave)
.click();
cy.verifyToastMessage(
commonSelectors.toastMessage,
postgreSqlText.toastDSSaved
);
deleteDatasource(`cypress-${data.dsName}-Appwrite`);
});
it.skip("Should be able to run the query with a valid connection", () => {
const Host = Cypress.env("appwrite_host");
const ProjectID = Cypress.env("appwrite_projectID");
const DatabaseID = Cypress.env("appwrite_databaseID");
const SecretKey = Cypress.env("appwrite_secretkey");
const CollectionID = Cypress.env("appwrite_collectionID");
cy.get(commonSelectors.globalDataSourceIcon).click();
closeDSModal();
selectAndAddDataSource("databases", appwriteText.appwrite, data.dsName);
fillDataSourceTextField(
appwriteText.host,
appwriteText.hostPlaceholder,
Host
);
fillDataSourceTextField(
appwriteText.ProjectID,
appwriteText.projectIdPlaceholder,
ProjectID
);
fillDataSourceTextField(
appwriteText.DatabaseID,
appwriteText.databaseIdPlaceholder,
DatabaseID
);
fillDataSourceTextField(
appwriteText.SecretKey,
appwriteText.SecretKeyPlaceholder,
SecretKey
);
cy.get(postgreSqlSelector.buttonTestConnection).click();
cy.get(postgreSqlSelector.textConnectionVerified, {
timeout: 10000,
}).should("have.text", postgreSqlText.labelConnectionVerified);
cy.get(postgreSqlSelector.buttonSave)
.verifyVisibleElement("have.text", postgreSqlText.buttonTextSave)
.click();
cy.verifyToastMessage(
commonSelectors.toastMessage,
postgreSqlText.toastDSSaved
);
cy.get(commonSelectors.globalDataSourceIcon).click();
cy.get(
`[data-cy="cypress-${data.dsName}-appwrite-button"]`
).verifyVisibleElement("have.text", `cypress-${data.dsName}-appwrite`);
cy.wait(1000);
cy.get(commonSelectors.dashboardIcon).click();
cy.get(commonSelectors.appCreateButton).click();
cy.get(commonSelectors.appNameInput).click().type(data.dsName);
cy.get(commonSelectors.createAppButton).click();
cy.skipWalkthrough();
cy.get('[data-cy="show-ds-popover-button"]').click();
cy.get(".css-4e90k9").type(`${data.dsName}`);
cy.contains(`[id*="react-select-"]`, data.dsName).click();
cy.get('[data-cy="query-rename-input"]').clear().type(data.dsName);
// Create API document for delete operation
cy.request({
method: "POST",
url: `https://cloud.appwrite.io/v1/databases/${DatabaseID}/collections/${CollectionID}/documents`,
headers: {
"X-Appwrite-Project": ProjectID,
"X-Appwrite-Key": SecretKey,
"Content-Type": "application/json",
},
body: {
documentId: "unique()",
data: {
User_name: "test",
User_ID: 30,
},
permissions: ['read("any")'],
},
}).then((response) => {
expect(response.status).to.eq(201);
cy.wrap(response.body.$id).as("documentId");
});
// Verify all operations
const operations = [
"List documents",
"Get document",
"Add Document to Collection",
"Update document",
"Delete document",
];
cy.get("@documentId").then((documentId) => {
operations.forEach((operation) => {
cy.get(".react-select__input")
.eq(1)
.type(`${operation}{enter}`, { force: true });
if (operation === "Get document") {
cy.get(appWriteSelectors.collectionId).clearAndTypeOnCodeMirror(
CollectionID
);
cy.get(appWriteSelectors.documentId).clearAndTypeOnCodeMirror(
Cypress.env("appwrite_documentID")
);
}
if (operation === "Add Document to Collection") {
cy.get(appWriteSelectors.collectionId).clearAndTypeOnCodeMirror(
CollectionID
);
cy.get(appWriteSelectors.bodyInput).clearAndTypeOnCodeMirror(
'{"User_name": "John Updated", "User_ID": 35}'
);
}
if (operation === "Update document") {
cy.get(appWriteSelectors.collectionId).clearAndTypeOnCodeMirror(
CollectionID
);
cy.get(appWriteSelectors.documentId).clearAndTypeOnCodeMirror(
Cypress.env("appwrite_documentID")
);
cy.get(appWriteSelectors.bodyInput).clearAndTypeOnCodeMirror(
'{"User_name": "John Updated", "User_ID": 35}'
);
}
if (operation === "List documents") {
cy.get(appWriteSelectors.collectionId).clearAndTypeOnCodeMirror(
CollectionID
);
}
if (operation === "Delete document") {
cy.get(appWriteSelectors.collectionId).clearAndTypeOnCodeMirror(
CollectionID
);
cy.get(appWriteSelectors.documentId).clearAndTypeOnCodeMirror(
documentId
);
}
cy.get(dataSourceSelector.queryPreviewButton).click();
cy.verifyToastMessage(
commonSelectors.toastMessage,
`Query (${data.dsName}) completed.`
);
});
deleteAppandDatasourceAfterExecution(
data.dsName,
`cypress-${data.dsName}-Appwrite`
);
});
});
});

View file

@ -0,0 +1,188 @@
import { fake } from "Fixtures/fake";
import { postgreSqlSelector } from "Selectors/postgreSql";
import { pluginSelectors } from "Selectors/plugins";
import { postgreSqlText } from "Texts/postgreSql";
import { awsLambdaText } from "Texts/awsLambda";
import { commonSelectors } from "Selectors/common";
import { commonText } from "Texts/common";
import {
fillDataSourceTextField,
selectAndAddDataSource,
} from "Support/utils/postgreSql";
import {
deleteDatasource,
closeDSModal,
deleteAppandDatasourceAfterExecution,
} from "Support/utils/dataSource";
import { dataSourceSelector } from "../../../../../constants/selectors/dataSource";
const data = {};
describe("Data source AWS Lambda", () => {
beforeEach(() => {
cy.apiLogin();
cy.visit("/");
data.dsName = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
});
it.skip("Should verify elements on AWS Lambda connection form", () => {
const Accesskey = Cypress.env("awslamda_access");
const Secretkey = Cypress.env("awslamda_secret");
cy.get(commonSelectors.globalDataSourceIcon).click();
closeDSModal();
cy.get(postgreSqlSelector.allDatasourceLabelAndCount).should(
"have.text",
postgreSqlText.allDataSources()
);
cy.get(postgreSqlSelector.commonlyUsedLabelAndCount).should(
"have.text",
postgreSqlText.commonlyUsed
);
cy.get(postgreSqlSelector.databaseLabelAndCount).should(
"have.text",
postgreSqlText.allDatabase()
);
cy.get(postgreSqlSelector.apiLabelAndCount).should(
"have.text",
postgreSqlText.allApis
);
cy.get(postgreSqlSelector.cloudStorageLabelAndCount).should(
"have.text",
postgreSqlText.allCloudStorage
);
cy.installMarketplacePlugin("AWS Lambda");
selectAndAddDataSource("databases", awsLambdaText.awsLambda, data.dsName);
cy.get(".react-select__dropdown-indicator").eq(1).click();
cy.get(".react-select__option").contains("US West (N. California)").click();
cy.get(pluginSelectors.amazonsesAccesKey).click().type(Accesskey);
fillDataSourceTextField(
awsLambdaText.labelSecretKey,
"**************",
Secretkey
);
cy.get(postgreSqlSelector.buttonSave)
.verifyVisibleElement("have.text", postgreSqlText.buttonTextSave)
.click();
cy.verifyToastMessage(
commonSelectors.toastMessage,
postgreSqlText.toastDSSaved
);
deleteDatasource(`cypress-${data.dsName}-aws-lambda`);
cy.uninstallMarketplacePlugin("AWS Lambda");
});
it.skip("Should verify the functionality of AWS Lambda connection form", () => {
const Accesskey = Cypress.env("awslamda_access");
const Secretkey = Cypress.env("awslamda_secret");
cy.get(commonSelectors.globalDataSourceIcon).click();
closeDSModal();
cy.installMarketplacePlugin("AWS Lambda");
selectAndAddDataSource("databases", awsLambdaText.awsLambda, data.dsName);
cy.get(".react-select__dropdown-indicator").eq(1).click();
cy.get(".react-select__option").contains("US West (N. California)").click();
cy.get(pluginSelectors.amazonsesAccesKey).click().type(Accesskey);
fillDataSourceTextField(
awsLambdaText.labelSecretKey,
"**************",
Secretkey
);
cy.get(postgreSqlSelector.buttonSave)
.verifyVisibleElement("have.text", postgreSqlText.buttonTextSave)
.click();
cy.verifyToastMessage(
commonSelectors.toastMessage,
postgreSqlText.toastDSSaved
);
deleteDatasource(`cypress-${data.dsName}-aws-lambda`);
cy.uninstallMarketplacePlugin("AWS Lambda");
});
it.skip("Should able to run the query with valid conection", () => {
const Accesskey = Cypress.env("awslamda_access");
const Secretkey = Cypress.env("awslamda_secret");
cy.get(commonSelectors.globalDataSourceIcon).click();
closeDSModal();
cy.installMarketplacePlugin("AWS Lambda");
selectAndAddDataSource("databases", awsLambdaText.awsLambda, data.dsName);
cy.get(".react-select__dropdown-indicator").eq(1).click();
cy.get(".react-select__option")
.contains("US West (N. California)")
.wait(500)
.click();
cy.get(pluginSelectors.amazonsesAccesKey).click().type(Accesskey);
fillDataSourceTextField(
awsLambdaText.labelSecretKey,
"**************",
Secretkey
);
cy.get(postgreSqlSelector.buttonSave)
.verifyVisibleElement("have.text", postgreSqlText.buttonTextSave)
.click();
cy.verifyToastMessage(
commonSelectors.toastMessage,
postgreSqlText.toastDSSaved
);
cy.get(commonSelectors.dashboardIcon).click();
cy.get(commonSelectors.appCreateButton).click();
cy.get(commonSelectors.appNameInput).click().type(data.dsName);
cy.get(commonSelectors.createAppButton).click();
cy.skipWalkthrough();
cy.get('[data-cy="show-ds-popover-button"]').click();
cy.get(".css-4e90k9").type(`${data.dsName}`);
cy.contains(`[id*="react-select-"]`, data.dsName).click();
cy.get('[data-cy="query-rename-input"]').clear().type(data.dsName);
cy.get(pluginSelectors.operationDropdown)
.click()
.type("Invoke Lambda Function{enter}");
cy.wait(500);
cy.get(
'[data-cy="function-name-section"] .cm-content'
).clearAndTypeOnCodeMirror("testAwslambdaPlugin");
cy.wait(500);
cy.get(dataSourceSelector.queryPreviewButton).click();
cy.verifyToastMessage(
commonSelectors.toastMessage,
`Query (${data.dsName}) completed.`
);
deleteAppandDatasourceAfterExecution(
data.dsName,
`cypress-${data.dsName}-aws-lambda`
);
cy.uninstallMarketplacePlugin("AWS Lambda");
});
});

View file

@ -0,0 +1,225 @@
import { fake } from "Fixtures/fake";
import { postgreSqlSelector } from "Selectors/postgreSql";
import { pluginSelectors } from "Selectors/plugins";
import { awsTextractSelectors } from "Selectors/Plugins";
import { postgreSqlText } from "Texts/postgreSql";
import { awsTextractText } from "Texts/awsTextract";
import { commonSelectors } from "Selectors/common";
import { commonText } from "Texts/common";
import {
fillDataSourceTextField,
selectAndAddDataSource,
} from "Support/utils/postgreSql";
import {
deleteDatasource,
closeDSModal,
deleteAppandDatasourceAfterExecution,
} from "Support/utils/dataSource";
import { dataSourceSelector } from "../../../../../constants/selectors/dataSource";
const data = {};
describe("Data source AWS Textract", () => {
beforeEach(() => {
cy.apiLogin();
cy.visit("/");
data.dsName = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
});
it.skip("Should verify elements on AWS Textract connection form", () => {
const Accesskey = Cypress.env("awstextract_access");
const Secretkey = Cypress.env("awstextract_secret");
cy.get(commonSelectors.globalDataSourceIcon).click();
closeDSModal();
cy.get(postgreSqlSelector.allDatasourceLabelAndCount).should(
"have.text",
postgreSqlText.allDataSources()
);
cy.get(postgreSqlSelector.commonlyUsedLabelAndCount).should(
"have.text",
postgreSqlText.commonlyUsed
);
cy.get(postgreSqlSelector.databaseLabelAndCount).should(
"have.text",
postgreSqlText.allDatabase()
);
cy.get(postgreSqlSelector.apiLabelAndCount).should(
"have.text",
postgreSqlText.allApis
);
cy.get(postgreSqlSelector.cloudStorageLabelAndCount).should(
"have.text",
postgreSqlText.allCloudStorage
);
cy.installMarketplacePlugin("AWS Textract");
selectAndAddDataSource(
"databases",
awsTextractText.awsTextract,
data.dsName
);
cy.get(".react-select__dropdown-indicator").eq(1).click();
cy.get(".react-select__option").contains("US West (N. California)").click();
cy.get(pluginSelectors.amazonsesAccesKey).click().type(Accesskey);
fillDataSourceTextField(
awsTextractText.labelSecretKey,
"**************",
Secretkey
);
cy.get(postgreSqlSelector.buttonSave)
.verifyVisibleElement("have.text", postgreSqlText.buttonTextSave)
.click();
cy.verifyToastMessage(
commonSelectors.toastMessage,
postgreSqlText.toastDSSaved
);
deleteDatasource(`cypress-${data.dsName}-aws-textract`);
});
it.skip("Should verify functionality of AWS Textract connection form", () => {
const Accesskey = Cypress.env("awstextract_access");
const Secretkey = Cypress.env("awstextract_secret");
cy.get(commonSelectors.globalDataSourceIcon).click();
closeDSModal();
cy.installMarketplacePlugin("AWS Textract");
selectAndAddDataSource(
"databases",
awsTextractText.awsTextract,
data.dsName
);
cy.get(".react-select__dropdown-indicator").eq(1).click();
cy.get(".react-select__option").contains("US West (N. California)").click();
cy.get(pluginSelectors.amazonsesAccesKey).click().type(Accesskey);
fillDataSourceTextField(
awsTextractText.labelSecretKey,
"**************",
Secretkey
);
cy.get(postgreSqlSelector.buttonSave)
.verifyVisibleElement("have.text", postgreSqlText.buttonTextSave)
.click();
cy.verifyToastMessage(
commonSelectors.toastMessage,
postgreSqlText.toastDSSaved
);
deleteDatasource(`cypress-${data.dsName}-aws-textract`);
cy.uninstallMarketplacePlugin("AWS Textract");
});
it.skip("Should able to run the query with valid conection", () => {
const Accesskey = Cypress.env("awstextract_access");
const Secretkey = Cypress.env("awstextract_secret");
cy.get(commonSelectors.globalDataSourceIcon).click();
closeDSModal();
cy.installMarketplacePlugin("AWS Textract");
selectAndAddDataSource(
"databases",
awsTextractText.awsTextract,
data.dsName
);
cy.get(".react-select__dropdown-indicator").eq(1).click();
cy.get(".react-select__option")
.contains("US West (N. California)")
.wait(500)
.click();
cy.get(pluginSelectors.amazonsesAccesKey).click().type(Accesskey);
fillDataSourceTextField(
awsTextractText.labelSecretKey,
"**************",
Secretkey
);
cy.get(postgreSqlSelector.buttonSave)
.verifyVisibleElement("have.text", postgreSqlText.buttonTextSave)
.click();
cy.verifyToastMessage(
commonSelectors.toastMessage,
postgreSqlText.toastDSSaved
);
cy.get(commonSelectors.dashboardIcon).click();
cy.get(commonSelectors.appCreateButton).click();
cy.get(commonSelectors.appNameInput).click().type(data.dsName);
cy.get(commonSelectors.createAppButton).click();
cy.skipWalkthrough();
cy.get('[data-cy="show-ds-popover-button"]').click();
cy.get(".css-4e90k9").type(`${data.dsName}`);
cy.contains(`[id*="react-select-"]`, data.dsName).click();
cy.get('[data-cy="query-rename-input"]').clear().type(data.dsName);
// Verifying analyze document operation
cy.get(pluginSelectors.operationDropdown)
.click()
.wait(500)
.type("Analyze Document{enter}");
cy.wait(500);
cy.get(awsTextractSelectors.documentInputField).clearAndTypeOnCodeMirror(
awsTextractText.documentName
);
cy.wait(500);
cy.get(dataSourceSelector.queryPreviewButton).click();
cy.verifyToastMessage(
commonSelectors.toastMessage,
`Query (${data.dsName}) completed.`
);
// Verifying Analyze document stored in AWS S3 operation
cy.get(pluginSelectors.operationDropdown)
.click()
.wait(500)
.type("Analyze document stored in AWS S3{enter}");
cy.wait(500);
cy.get(awsTextractSelectors.bucketNameInputField).clearAndTypeOnCodeMirror(
awsTextractText.bucketName
);
cy.get(awsTextractSelectors.keyNameInputField).clearAndTypeOnCodeMirror(
awsTextractText.keyName
);
cy.wait(500);
cy.get(dataSourceSelector.queryPreviewButton).click();
cy.verifyToastMessage(
commonSelectors.toastMessage,
`Query (${data.dsName}) completed.`
);
deleteAppandDatasourceAfterExecution(
data.dsName,
`cypress-${data.dsName}-aws-textract`
);
cy.uninstallMarketplacePlugin("AWS Textract");
});
});

View file

@ -17,8 +17,8 @@ data.customText = fake.randomSentence;
describe("Data source Azure Blob Storage", () => {
beforeEach(() => {
cy.appUILogin();
cy.intercept("GET", "/api/v2/data_sources");
cy.apiLogin();
cy.visit("/");
data.dataSourceName = fake.lastName
.toLowerCase()
.replaceAll("[^A-Za-z]", "");
@ -138,7 +138,7 @@ describe("Data source Azure Blob Storage", () => {
);
cy.get(dataSourceSelector.connectionAlertText).verifyVisibleElement(
"have.text",
azureBlobStorageText.unableExtractAccountNameText
"Invalid URL"
);
fillDataSourceTextField(

View file

@ -0,0 +1,217 @@
import { fake } from "Fixtures/fake";
import { postgreSqlSelector } from "Selectors/postgreSql";
import { pluginSelectors, baserowSelectors } from "Selectors/plugins";
import { postgreSqlText } from "Texts/postgreSql";
import { baseRowText } from "Texts/baseRow";
import { commonSelectors } from "Selectors/common";
import { commonText } from "Texts/common";
import {
fillDataSourceTextField,
selectAndAddDataSource,
} from "Support/utils/postgreSql";
import {
deleteDatasource,
closeDSModal,
deleteAppandDatasourceAfterExecution,
} from "Support/utils/dataSource";
import { dataSourceSelector } from "../../../../../constants/selectors/dataSource";
const data = {};
describe("Data source baserow", () => {
beforeEach(() => {
cy.apiLogin();
cy.visit("/");
data.dsName = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
});
it.skip("Should verify elements on baserow connection form", () => {
const Apikey = Cypress.env("baserow_apikey");
cy.get(commonSelectors.globalDataSourceIcon).click();
closeDSModal();
cy.get(postgreSqlSelector.allDatasourceLabelAndCount).should(
"have.text",
postgreSqlText.allDataSources()
);
cy.get(postgreSqlSelector.commonlyUsedLabelAndCount).should(
"have.text",
postgreSqlText.commonlyUsed
);
cy.get(postgreSqlSelector.databaseLabelAndCount).should(
"have.text",
postgreSqlText.allDatabase()
);
cy.get(postgreSqlSelector.apiLabelAndCount).should(
"have.text",
postgreSqlText.allApis
);
cy.get(postgreSqlSelector.cloudStorageLabelAndCount).should(
"have.text",
postgreSqlText.allCloudStorage
);
selectAndAddDataSource("databases", baseRowText.baserow, data.dsName);
fillDataSourceTextField(
baseRowText.lableApiToken,
baseRowText.placeholderApiToken,
Apikey
);
cy.get(".react-select__control").eq(1).click();
cy.get(".react-select__option").contains("Baserow Cloud").click();
cy.get(postgreSqlSelector.buttonSave)
.verifyVisibleElement("have.text", postgreSqlText.buttonTextSave)
.click();
cy.verifyToastMessage(
commonSelectors.toastMessage,
postgreSqlText.toastDSSaved
);
deleteDatasource(`cypress-${data.dsName}-baserow`);
});
it.skip("Should verify the functionality of baserow connection form.", () => {
const Apikey = Cypress.env("baserow_apikey");
selectAndAddDataSource("databases", baseRowText.baserow, data.dsName);
fillDataSourceTextField(
baseRowText.lableApiToken,
baseRowText.placeholderApiToken,
Apikey
);
cy.get(".react-select__control").eq(1).click();
cy.get(".react-select__option").contains("Baserow Cloud").click();
cy.get(postgreSqlSelector.buttonSave)
.verifyVisibleElement("have.text", postgreSqlText.buttonTextSave)
.click();
cy.verifyToastMessage(
commonSelectors.toastMessage,
postgreSqlText.toastDSSaved
);
deleteDatasource(`cypress-${data.dsName}-baserow`);
});
it.skip("Should be able to run the query with a valid connection", () => {
const baserowTableID = Cypress.env("baserow_tableid");
const baserowRowID = Cypress.env("baserow_rowid");
const Apikey = Cypress.env("baserow_apikey");
selectAndAddDataSource("databases", baseRowText.baserow, data.dsName);
fillDataSourceTextField(
baseRowText.lableApiToken,
baseRowText.placeholderApiToken,
Apikey
);
cy.get(".react-select__control").eq(1).click();
cy.get(".react-select__option").contains("Baserow Cloud").click();
cy.get(postgreSqlSelector.buttonSave)
.verifyVisibleElement("have.text", postgreSqlText.buttonTextSave)
.click();
cy.verifyToastMessage(
commonSelectors.toastMessage,
postgreSqlText.toastDSSaved
);
cy.get(commonSelectors.globalDataSourceIcon).click();
cy.get(
`[data-cy="cypress-${data.dsName}-baserow-button"]`
).verifyVisibleElement("have.text", `cypress-${data.dsName}-baserow`);
cy.wait(1000);
cy.log("Baserow Table ID:", baserowTableID);
cy.log("Row ID:", baserowRowID);
cy.log("API Key:", Apikey);
if (!baserowTableID || !Apikey) {
throw new Error("Missing required environment variables!");
}
cy.request({
method: "POST",
url: `https://api.baserow.io/api/database/rows/table/${baserowTableID}/`,
headers: { Authorization: `Token ${Apikey}` },
body: {
field_1: "Sample Data",
field_2: "Another Value",
},
}).then((response) => {
expect(response.status).to.eq(200);
const rowId = response.body.id;
cy.get(commonSelectors.dashboardIcon).click();
cy.get(commonSelectors.appCreateButton).click();
cy.get(commonSelectors.appNameInput).click().type(data.dsName);
cy.get(commonSelectors.createAppButton).click();
cy.skipWalkthrough();
cy.get('[data-cy="show-ds-popover-button"]').click();
cy.get(".css-4e90k9").type(`${data.dsName}`);
cy.contains(`[id*="react-select-"]`, data.dsName).click();
cy.get('[data-cy="query-rename-input"]').clear().type(data.dsName);
// Verify delete operation (Need to uncomment after bug fixes)
// cy.get('[data-cy="operation-select-dropdown"]').click();
// cy.get(".react-select__option").contains("Delete row").click();
// cy.get(baserowSelectors.baserowTabelId).clearAndTypeOnCodeMirror(baserowTableID);
// cy.get(baserowSelectors.rowIdinputfield).clearAndTypeOnCodeMirror(rowId.toString());
// cy.get(dataSourceSelector.queryPreviewButton).click();
// cy.verifyToastMessage(commonSelectors.toastMessage, `Query (${data.dsName}) completed.`);
});
// Verify other operations
const operations = [
"List fields",
"List rows",
"Get row",
"Create row",
"Update row",
"Move row",
];
operations.forEach((operation) => {
cy.get(pluginSelectors.operationDropdown).click();
cy.get(".react-select__option").contains(operation).click();
cy.get(baserowSelectors.table).clearAndTypeOnCodeMirror(baserowTableID);
if (operation === "Get row") {
cy.get(baserowSelectors.rowIdinputfield).clearAndTypeOnCodeMirror(
baserowRowID
);
}
if (operation === "Move row") {
cy.get('[data-cy="before-id-input-field"]').clearAndTypeOnCodeMirror(
"1"
);
}
cy.get(dataSourceSelector.queryPreviewButton).click();
cy.verifyToastMessage(
commonSelectors.toastMessage,
`Query (${data.dsName}) completed.`
);
});
deleteAppandDatasourceAfterExecution(
data.dsName,
`cypress-${data.dsName}-baserow`
);
});
});

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