mirror of
https://github.com/ToolJet/ToolJet
synced 2026-05-23 17:08:34 +00:00
Merge branch 'appbuilder/sprint-11' into feat/server-side-resolver
This commit is contained in:
commit
9a347ba209
1812 changed files with 122048 additions and 16760 deletions
2
.github/workflows/cypress-platform.yml
vendored
2
.github/workflows/cypress-platform.yml
vendored
|
|
@ -79,7 +79,7 @@ jobs:
|
|||
|
||||
- name: Set up environment variables
|
||||
run: |
|
||||
echo "TOOLJET_EDITION=${{ matrix.edition == 'ee' && 'EE' || 'CE' }}" >> .env
|
||||
echo "TOOLJET_EDITION=${{ matrix.edition == 'ee' && 'ee' || 'ce' }}" >> .env
|
||||
echo "TOOLJET_HOST=http://localhost:8082" >> .env
|
||||
echo "LOCKBOX_MASTER_KEY=cd97331a419c09387bef49787f7da8d2a81d30733f0de6bed23ad8356d2068b2" >> .env
|
||||
echo "SECRET_KEY_BASE=7073b9a35a15dd20914ae17e36a693093f25b74b96517a5fec461fc901c51e011cd142c731bee48c5081ec8bac321c1f259ef097ef2a16f25df17a3798c03426" >> .env
|
||||
|
|
|
|||
106
.github/workflows/docker-release.yml
vendored
106
.github/workflows/docker-release.yml
vendored
|
|
@ -11,7 +11,7 @@ jobs:
|
|||
|
||||
steps:
|
||||
|
||||
- name: Checkout code to main for Beta CE edition
|
||||
- name: Checkout code to main for pre-release CE edition
|
||||
if: "!contains(github.event.release.tag_name, 'ce-lts')"
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
|
|
@ -44,7 +44,7 @@ jobs:
|
|||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
|
||||
- name: Build and Push Docker image for Beta tag
|
||||
- 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:
|
||||
|
|
@ -98,7 +98,7 @@ jobs:
|
|||
if: "${{ github.event.release }}"
|
||||
|
||||
steps:
|
||||
- name: Checkout code to main for Beta EE edition
|
||||
- name: Checkout code to main for pre-release EE edition
|
||||
if: "!contains(github.event.release.tag_name, 'ee-lts')"
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
|
|
@ -132,13 +132,13 @@ jobs:
|
|||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
|
||||
|
||||
- name: Build and Push Docker image for Beta tag
|
||||
- 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: .
|
||||
args: ${{ secrets.CUSTOM_GITHUB_TOKEN }}
|
||||
file: docker/ee-production.Dockerfile
|
||||
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
|
||||
|
|
@ -172,61 +172,61 @@ jobs:
|
|||
curl -X POST -H 'Content-type: application/json' --data "{\"text\":\"$message\"}" ${{ secrets.SLACK_WEBHOOK_URL }}
|
||||
|
||||
|
||||
build-tooljet-image-for-cloud-edtion:
|
||||
# commented out for now, since cloud modularisation is not yet ready
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
if: "${{ github.event.release }}"
|
||||
# build-tooljet-image-for-cloud-edtion:
|
||||
|
||||
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
|
||||
# runs-on: ubuntu-latest
|
||||
# if: "${{ github.event.release }}"
|
||||
|
||||
# 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
|
||||
# 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
|
||||
|
||||
- name: Set DOCKER_CLI_EXPERIMENTAL
|
||||
run: echo "DOCKER_CLI_EXPERIMENTAL=enabled" >> $GITHUB_ENV
|
||||
# # 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: use mybuilder buildx
|
||||
run: docker buildx use mybuilder
|
||||
# - 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 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: Docker Login
|
||||
# uses: docker/login-action@v2
|
||||
# with:
|
||||
# username: ${{ secrets.DOCKER_USERNAME }}
|
||||
# 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 }}
|
||||
# - 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 }}
|
||||
|
|
|
|||
37
.github/workflows/docs-netlify.yml
vendored
Normal file
37
.github/workflows/docs-netlify.yml
vendored
Normal 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 }}
|
||||
2
.github/workflows/docs-pr-app.yml
vendored
2
.github/workflows/docs-pr-app.yml
vendored
|
|
@ -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"
|
||||
}
|
||||
|
|
|
|||
16
.github/workflows/netlify.yml
vendored
16
.github/workflows/netlify.yml
vendored
|
|
@ -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 }}
|
||||
34
.github/workflows/render-preview-deploy.yml
vendored
34
.github/workflows/render-preview-deploy.yml
vendored
|
|
@ -13,12 +13,42 @@ permissions:
|
|||
jobs:
|
||||
|
||||
# Community Edition
|
||||
|
||||
create-ce-review-app:
|
||||
if: ${{ github.event.action == 'labeled' && (github.event.label.name == 'create-ce-review-app' || github.event.label.name == 'review-app') }}
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Sync repo
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Check if Forked Repository
|
||||
id: check_repo
|
||||
run: |
|
||||
if [[ "${{ github.event.pull_request.head.repo.fork }}" == "true" ]]; then
|
||||
echo "is_fork=true" >> $GITHUB_ENV
|
||||
echo "FORKED_OWNER=${{ github.event.pull_request.head.repo.owner.login }}" >> $GITHUB_ENV
|
||||
else
|
||||
echo "is_fork=false" >> $GITHUB_ENV
|
||||
fi
|
||||
|
||||
- name: Set Repository URL
|
||||
run: |
|
||||
if [[ "$is_fork" == "true" ]]; then
|
||||
echo "REPO_URL=https://github.com/${FORKED_OWNER}/ToolJet" >> $GITHUB_ENV
|
||||
else
|
||||
echo "REPO_URL=https://github.com/ToolJet/ToolJet" >> $GITHUB_ENV
|
||||
fi
|
||||
|
||||
- name: Fetch and Checkout Forked Branch
|
||||
if: env.is_fork == 'true'
|
||||
run: |
|
||||
git fetch origin pull/${{ github.event.number }}/head:${{ env.BRANCH_NAME }}
|
||||
git checkout ${{ env.BRANCH_NAME }}
|
||||
|
||||
- name: Checkout Default Branch
|
||||
if: env.is_fork == 'false'
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Creating deployment for CE
|
||||
id: create-ce-deployment
|
||||
run: |
|
||||
|
|
@ -34,7 +64,7 @@ jobs:
|
|||
"name": "ToolJet CE PR #${{ env.PR_NUMBER }}",
|
||||
"notifyOnFail": "default",
|
||||
"ownerId": "tea-caeo4bj19n072h3dddc0",
|
||||
"repo": "https://github.com/ToolJet/ToolJet",
|
||||
"repo": "'"$REPO_URL"'",
|
||||
"slug": "tooljet-ce-pr-${{ env.PR_NUMBER }}",
|
||||
"suspended": "not_suspended",
|
||||
"suspenders": [],
|
||||
|
|
|
|||
|
|
@ -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
|
||||
651
.github/workflows/vulnerability-ci.yml
vendored
Normal file
651
.github/workflows/vulnerability-ci.yml
vendored
Normal 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 */14 * *'
|
||||
|
||||
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 }}).
|
||||
2
.version
2
.version
|
|
@ -1 +1 @@
|
|||
3.7.0
|
||||
3.11.0
|
||||
|
|
|
|||
54
README.md
54
README.md
|
|
@ -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.
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
},
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ module.exports = defineConfig({
|
|||
});
|
||||
|
||||
on("task", {
|
||||
updateId ({ dbconfig, sql }) {
|
||||
dbConnection ({ dbconfig, sql }) {
|
||||
const client = new pg.Pool(dbconfig);
|
||||
return client.query(sql);
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
},
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ module.exports = defineConfig({
|
|||
});
|
||||
|
||||
on("task", {
|
||||
updateId ({ dbconfig, sql }) {
|
||||
dbConnection ({ dbconfig, sql }) {
|
||||
const client = new pg.Pool(dbconfig);
|
||||
return client.query(sql);
|
||||
},
|
||||
|
|
@ -92,7 +92,11 @@ module.exports = defineConfig({
|
|||
experimentalModfyObstructiveThirdPartyCode: true,
|
||||
experimentalRunAllSpecs: true,
|
||||
baseUrl: "http://localhost:8082",
|
||||
specPattern: "cypress/e2e/happyPath/**/*.cy.js",
|
||||
specPattern: [
|
||||
"cypress/e2e/happyPath/platform/ceTestcases/userFlow/firstUserOnboarding.cy.js",
|
||||
"cypress/e2e/happyPath/platform/ceTestcases/!(userFlow)/**/*.cy.js",
|
||||
"cypress/e2e/happyPath/platform/commonTestcases/**/*.cy.js",
|
||||
],
|
||||
downloadsFolder: "cypress/downloads",
|
||||
numTestsKeptInMemory: 0,
|
||||
redirectionLimit: 10,
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
const envVar = Cypress.env("environment");
|
||||
|
||||
Cypress.Commands.add(
|
||||
"apiLogin",
|
||||
(
|
||||
|
|
@ -75,14 +77,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) => {
|
||||
{
|
||||
|
|
@ -128,7 +133,7 @@ Cypress.Commands.add(
|
|||
appId = Cypress.env("appId"),
|
||||
componentSelector = "[data-cy='empty-editor-text']"
|
||||
) => {
|
||||
cy.intercept("GET", "/api/v2/apps/*").as("getAppData");
|
||||
cy.intercept("GET", "/api/apps/*").as("getAppData");
|
||||
cy.window({ log: false }).then((win) => {
|
||||
win.localStorage.setItem("walkthroughCompleted", "true");
|
||||
});
|
||||
|
|
@ -175,7 +180,7 @@ Cypress.Commands.add("apiLogout", () => {
|
|||
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}`,
|
||||
|
|
@ -190,22 +195,36 @@ Cypress.Commands.add("apiLogout", () => {
|
|||
|
||||
Cypress.Commands.add(
|
||||
"apiUserInvite",
|
||||
(userName, userEmail, userRole = "end-user") => {
|
||||
(userName, userEmail, userRole = "end-user", metaData = {}) => {
|
||||
const requestBody =
|
||||
envVar === "Enterprise"
|
||||
? {
|
||||
email: userEmail,
|
||||
firstName: userName,
|
||||
groups: [],
|
||||
lastName: "",
|
||||
role: userRole,
|
||||
userMetadata: metaData,
|
||||
}
|
||||
: {
|
||||
email: userEmail,
|
||||
firstName: userName,
|
||||
groups: [],
|
||||
lastName: "",
|
||||
role: userRole,
|
||||
userMetadata: metaData,
|
||||
};
|
||||
|
||||
cy.getCookie("tj_auth_token").then((cookie) => {
|
||||
cy.request(
|
||||
{
|
||||
method: "POST",
|
||||
url: `${Cypress.env("server_host")}/api/organization_users`,
|
||||
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,
|
||||
email: userEmail,
|
||||
groups: [],
|
||||
role: userRole,
|
||||
},
|
||||
body: requestBody,
|
||||
},
|
||||
{ log: false }
|
||||
).then((response) => {
|
||||
|
|
@ -221,21 +240,26 @@ Cypress.Commands.add("apiAddQuery", (queryName, query, dataQueryId) => {
|
|||
"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);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -262,7 +286,7 @@ Cypress.Commands.add(
|
|||
|
||||
cy.request({
|
||||
method: "POST",
|
||||
url: `${Cypress.env("server_host")}/api/data_queries`,
|
||||
url: `${Cypress.env("server_host")}/api/data-queries`,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Cookie: authToken,
|
||||
|
|
@ -315,7 +339,7 @@ Cypress.Commands.add(
|
|||
|
||||
cy.request({
|
||||
method: "GET",
|
||||
url: `${Cypress.env("server_host")}/api/v2/apps/${appId}`,
|
||||
url: `${Cypress.env("server_host")}/api/apps/${appId}`,
|
||||
headers: {
|
||||
"Tj-Workspace-Id": Cypress.env("workspaceId"),
|
||||
Cookie: `tj_auth_token=${cookie.value}`,
|
||||
|
|
@ -432,11 +456,10 @@ Cypress.Commands.add("apiMakeAppPublic", (appId = Cypress.env("appId")) => {
|
|||
|
||||
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`,
|
||||
url: `${Cypress.env("server_host")}/api/v2/group-permissions`,
|
||||
headers: headers,
|
||||
log: false,
|
||||
}).then((response) => {
|
||||
|
|
@ -451,7 +474,7 @@ Cypress.Commands.add("apiDeleteGranularPermission", (groupName) => {
|
|||
// Fetch granular permissions for the specific group
|
||||
cy.request({
|
||||
method: "GET",
|
||||
url: `${Cypress.env("server_host")}/api/v2/group_permissions/${groupId}/granular-permissions`,
|
||||
url: `${Cypress.env("server_host")}/api/v2/group-permissions/${groupId}/granular-permissions`,
|
||||
headers,
|
||||
log: false,
|
||||
}).then((granularResponse) => {
|
||||
|
|
@ -461,7 +484,7 @@ Cypress.Commands.add("apiDeleteGranularPermission", (groupName) => {
|
|||
// Delete the granular permission
|
||||
cy.request({
|
||||
method: "DELETE",
|
||||
url: `${Cypress.env("server_host")}/api/v2/group_permissions/granular-permissions/${granularPermissionId}`,
|
||||
url: `${Cypress.env("server_host")}/api/v2/group-permissions/granular-permissions/${granularPermissionId}`,
|
||||
headers,
|
||||
log: false,
|
||||
}).then((deleteResponse) => {
|
||||
|
|
@ -483,11 +506,10 @@ Cypress.Commands.add(
|
|||
resourcesToAdd = []
|
||||
) => {
|
||||
cy.getAuthHeaders().then((headers) => {
|
||||
|
||||
// Fetch group permissions
|
||||
cy.request({
|
||||
method: "GET",
|
||||
url: `${Cypress.env("server_host")}/api/v2/group_permissions`,
|
||||
url: `${Cypress.env("server_host")}/api/v2/group-permissions`,
|
||||
headers: headers,
|
||||
log: false,
|
||||
}).then((response) => {
|
||||
|
|
@ -502,7 +524,7 @@ Cypress.Commands.add(
|
|||
// Create granular permission
|
||||
cy.request({
|
||||
method: "POST",
|
||||
url: `${Cypress.env("server_host")}/api/v2/group_permissions/granular-permissions`,
|
||||
url: `${Cypress.env("server_host")}/api/v2/group-permissions/granular-permissions`,
|
||||
headers: headers,
|
||||
body: {
|
||||
name,
|
||||
|
|
@ -528,10 +550,9 @@ Cypress.Commands.add(
|
|||
Cypress.Commands.add("apiReleaseApp", (appName) => {
|
||||
cy.getAppId(appName).then((appId) => {
|
||||
cy.getAuthHeaders().then((headers) => {
|
||||
|
||||
cy.request({
|
||||
method: "GET",
|
||||
url: `${Cypress.env("server_host")}/api/v2/apps/${appId}`,
|
||||
url: `${Cypress.env("server_host")}/api/apps/${appId}`,
|
||||
headers,
|
||||
})
|
||||
.then((response) => {
|
||||
|
|
@ -539,7 +560,7 @@ Cypress.Commands.add("apiReleaseApp", (appName) => {
|
|||
const editingVersionId = response.body.editing_version.id;
|
||||
cy.request({
|
||||
method: "PUT",
|
||||
url: `${Cypress.env("server_host")}/api/v2/apps/${appId}/release`,
|
||||
url: `${Cypress.env("server_host")}/api/apps/${appId}/release`,
|
||||
headers: headers,
|
||||
body: {
|
||||
versionToBeReleased: editingVersionId,
|
||||
|
|
@ -556,7 +577,6 @@ Cypress.Commands.add("apiReleaseApp", (appName) => {
|
|||
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}`,
|
||||
|
|
@ -576,7 +596,6 @@ Cypress.Commands.add("apiAddAppSlug", (appName, slug) => {
|
|||
|
||||
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`,
|
||||
|
|
@ -594,7 +613,6 @@ Cypress.Commands.add("apiGetTableIdByName", (tableName) => {
|
|||
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}`,
|
||||
|
|
@ -612,7 +630,7 @@ Cypress.Commands.add("apiGetDataSourceIdByName", (dataSourceName) => {
|
|||
cy.getAuthHeaders().then((headers) => {
|
||||
cy.request({
|
||||
method: "GET",
|
||||
url: `${Cypress.env("server_host")}/api/v2/data_sources`,
|
||||
url: `${Cypress.env("server_host")}/api/data-sources`,
|
||||
headers: headers,
|
||||
}).then((response) => {
|
||||
expect(response.status).to.equal(200);
|
||||
|
|
@ -670,7 +688,7 @@ Cypress.Commands.add(
|
|||
|
||||
cy.request({
|
||||
method: "PUT",
|
||||
url: `${Cypress.env("server_host")}/api/v2/data_sources/${dataSourceId}?environment_id=${environmentId}`,
|
||||
url: `${Cypress.env("server_host")}/api/data-sources/${dataSourceId}?environment_id=${environmentId}`,
|
||||
headers: headers,
|
||||
body: mergedData,
|
||||
}).then((updateResponse) => {
|
||||
|
|
@ -683,3 +701,15 @@ Cypress.Commands.add(
|
|||
}
|
||||
);
|
||||
|
||||
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;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -7,13 +7,14 @@ import { importSelectors } from "Selectors/exportImport";
|
|||
import { importText } from "Texts/exportImport";
|
||||
import { onboardingSelectors } from "Selectors/onboarding";
|
||||
|
||||
const API_ENDPOINT =
|
||||
Cypress.env("environment") === "Community"
|
||||
? "/api/library_apps"
|
||||
: "/api/library_apps/";
|
||||
|
||||
Cypress.Commands.add(
|
||||
"appUILogin",
|
||||
(email = "dev@tooljet.io", password = "password") => {
|
||||
const API_ENDPOINT =
|
||||
Cypress.env("environment") === "Community"
|
||||
? "/api/library_apps/"
|
||||
: "/api/library_apps";
|
||||
cy.visit("/");
|
||||
cy.wait(1000);
|
||||
cy.clearAndType(onboardingSelectors.loginEmailInput, email);
|
||||
|
|
@ -142,13 +143,11 @@ Cypress.Commands.add(
|
|||
};
|
||||
|
||||
if (Array.isArray(value)) {
|
||||
cy.wrap(subject)
|
||||
.last()
|
||||
.realType(value, {
|
||||
parseSpecialCharSequences: false,
|
||||
delay: 0,
|
||||
force: true,
|
||||
});
|
||||
cy.wrap(subject).last().realType(value, {
|
||||
parseSpecialCharSequences: false,
|
||||
delay: 0,
|
||||
force: true,
|
||||
});
|
||||
} else {
|
||||
splitIntoFlatArray(value).forEach((i) => {
|
||||
cy.wrap(subject)
|
||||
|
|
@ -305,19 +304,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) => {
|
||||
|
|
@ -399,20 +398,13 @@ Cypress.Commands.add("getPosition", (componentName) => {
|
|||
});
|
||||
|
||||
Cypress.Commands.add("defaultWorkspaceLogin", () => {
|
||||
cy.task("updateId", {
|
||||
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");
|
||||
cy.apiLogin();
|
||||
|
||||
cy.visit("/");
|
||||
cy.intercept("GET", "/api/library_apps").as("library_apps");
|
||||
cy.get(commonSelectors.homePageLogo, { timeout: 10000 });
|
||||
cy.wait("@library_apps");
|
||||
});
|
||||
cy.visit("/my-workspace");
|
||||
cy.intercept("GET", API_ENDPOINT).as("library_apps");
|
||||
cy.get(commonSelectors.homePageLogo, { timeout: 10000 });
|
||||
cy.wait("@library_apps");
|
||||
// });
|
||||
});
|
||||
|
||||
Cypress.Commands.add(
|
||||
|
|
@ -458,13 +450,13 @@ Cypress.Commands.add("releaseApp", () => {
|
|||
Cypress.Commands.add("backToApps", () => {
|
||||
cy.get(commonSelectors.editorPageLogo).click();
|
||||
cy.get(commonSelectors.backToAppOption).click();
|
||||
cy.intercept("GET", "/api/library_apps/").as("library_apps");
|
||||
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;`,
|
||||
});
|
||||
|
|
@ -503,7 +495,7 @@ 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}';`,
|
||||
});
|
||||
|
|
@ -535,10 +527,12 @@ Cypress.Commands.add("loginWithCredentials", (email, password) => {
|
|||
cy.clearAndType(onboardingSelectors.loginEmailInput, email);
|
||||
cy.clearAndType(onboardingSelectors.loginPasswordInput, password);
|
||||
cy.get(onboardingSelectors.signInButton).click();
|
||||
cy.wait(3000);
|
||||
cy.get(commonSelectors.pageLogo).should("be.visible");
|
||||
});
|
||||
|
||||
Cypress.Commands.add("getAppId", (appName) => {
|
||||
cy.task("updateId", {
|
||||
cy.task("dbConnection", {
|
||||
dbconfig: Cypress.env("app_db"),
|
||||
sql: `select id from apps where name='${appName}';`,
|
||||
}).then((resp) => {
|
||||
|
|
|
|||
62
cypress-tests/cypress/constants/selectors/Plugins.js
Normal file
62
cypress-tests/cypress/constants/selectors/Plugins.js
Normal 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"]',
|
||||
};
|
||||
|
|
@ -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"]',
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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"]',
|
||||
|
|
@ -97,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"]',
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ 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"]',
|
||||
|
|
|
|||
|
|
@ -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"]',
|
||||
};
|
||||
|
|
|
|||
44
cypress-tests/cypress/constants/selectors/restAPI.js
Normal file
44
cypress-tests/cypress/constants/selectors/restAPI.js
Normal 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-more-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"]',
|
||||
};
|
||||
6
cypress-tests/cypress/constants/texts/airTable.js
Normal file
6
cypress-tests/cypress/constants/texts/airTable.js
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
export const airtableText = {
|
||||
airtable: "Airtable",
|
||||
cypressairtable: "cypress-Airtable",
|
||||
ApiKey: "Personal access token",
|
||||
apikeyPlaceholder: "**************",
|
||||
};
|
||||
8
cypress-tests/cypress/constants/texts/amazonAthena.js
Normal file
8
cypress-tests/cypress/constants/texts/amazonAthena.js
Normal 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:"**************",
|
||||
};
|
||||
8
cypress-tests/cypress/constants/texts/amazonSes.js
Normal file
8
cypress-tests/cypress/constants/texts/amazonSes.js
Normal 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:"**************",
|
||||
};
|
||||
12
cypress-tests/cypress/constants/texts/appwrite.js
Normal file
12
cypress-tests/cypress/constants/texts/appwrite.js
Normal 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",
|
||||
};
|
||||
8
cypress-tests/cypress/constants/texts/awsLambda.js
Normal file
8
cypress-tests/cypress/constants/texts/awsLambda.js
Normal 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: "**************",
|
||||
};
|
||||
12
cypress-tests/cypress/constants/texts/awsTextract.js
Normal file
12
cypress-tests/cypress/constants/texts/awsTextract.js
Normal 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",
|
||||
};
|
||||
6
cypress-tests/cypress/constants/texts/baseRow.js
Normal file
6
cypress-tests/cypress/constants/texts/baseRow.js
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
export const baseRowText = {
|
||||
baserow: "baserow",
|
||||
cypressBaseRow: "cypress-baserow",
|
||||
lableApiToken: "API token",
|
||||
placeholderApiToken:"**************",
|
||||
};
|
||||
|
|
@ -173,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",
|
||||
|
|
@ -181,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",
|
||||
|
|
|
|||
|
|
@ -80,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",
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
6
cypress-tests/cypress/constants/texts/graphQL.js
Normal file
6
cypress-tests/cypress/constants/texts/graphQL.js
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
export const GraphQLText = {
|
||||
GraphQL: "GraphQL",
|
||||
cypressGraphQL: "cypress-GraphQL",
|
||||
urlInputLabel: "URL",
|
||||
urlInputPlaceholder: "https://api.example.com/v1/graphql",
|
||||
};
|
||||
21
cypress-tests/cypress/constants/texts/harperDb.js
Normal file
21
cypress-tests/cypress/constants/texts/harperDb.js
Normal 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",
|
||||
};
|
||||
|
|
@ -1,10 +1,10 @@
|
|||
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",
|
||||
|
|
@ -52,7 +52,7 @@ export const groupsText = {
|
|||
editGroupNameButton: "Rename",
|
||||
deleteGroupButton: "Delete group",
|
||||
editPermissionModalTitle: "Edit app permissions",
|
||||
addPermissionModalTitle: "Add app permissions",
|
||||
addPermissionModalTitle: "Add apps permissions",
|
||||
appCreateHelperText: 'Create apps in this workspace',
|
||||
appDeleteHelperText: 'Delete any app in this workspace',
|
||||
appEditLabelText: 'Edit',
|
||||
|
|
@ -63,7 +63,7 @@ export const groupsText = {
|
|||
appHideLabel: "Hide from dashboard",
|
||||
appHideLabelPermissionModal: "Hide from dashbaord",
|
||||
groupChipText: 'All apps',
|
||||
adminAccessHelperText: " Admin has edit access to all apps. These are not editableread documentation to know more !",
|
||||
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',
|
||||
|
|
@ -85,19 +85,19 @@ export const groupsText = {
|
|||
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: "Updating the user's details will change their role from end-user to builder. Are you sure you want to continue?",
|
||||
endUserToAdminMessage: "Updating the user's details will change their role from end-user to admin. Are you sure you want to continue?",
|
||||
builderToEnduserMessage: "This will also remove the user from any custom groups with builder-like permissions.Are you sure you want to continue?",
|
||||
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 your user group from admin to end-user 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: "Cannot assign builder level permission to end users",
|
||||
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",
|
||||
|
|
|
|||
|
|
@ -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 won’t 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",
|
||||
};
|
||||
|
|
|
|||
14
cypress-tests/cypress/constants/texts/minio.js
Normal file
14
cypress-tests/cypress/constants/texts/minio.js
Normal 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`,
|
||||
};
|
||||
|
|
@ -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",
|
||||
};
|
||||
|
|
|
|||
58
cypress-tests/cypress/constants/texts/restAPI.js
Normal file
58
cypress-tests/cypress/constants/texts/restAPI.js
Normal 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",
|
||||
};
|
||||
11
cypress-tests/cypress/constants/texts/twilio.js
Normal file
11
cypress-tests/cypress/constants/texts/twilio.js
Normal 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",
|
||||
};
|
||||
|
|
@ -8,7 +8,11 @@ export const editVersionText = {
|
|||
|
||||
export const deleteVersionText = {
|
||||
deleteModalText: (text) => {
|
||||
return `Are you sure you want to delete this version - ${cyParamName(
|
||||
// return `Are you sure you want to delete this version - ${cyParamName(
|
||||
// text
|
||||
// )}?`;
|
||||
|
||||
return `Deleting a version will permanently remove it from all environments.Are you sure you want to delete this version - ${cyParamName(
|
||||
text
|
||||
)}?`;
|
||||
},
|
||||
|
|
@ -19,9 +23,13 @@ export const deleteVersionText = {
|
|||
|
||||
export const onlydeleteVersionText = {
|
||||
deleteModalText: (text) => {
|
||||
return `Are you sure you want to delete this version - ${cyParamName(
|
||||
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`;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,218 @@
|
|||
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("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("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("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("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(500);
|
||||
});
|
||||
|
||||
cy.get(commonSelectors.dashboardIcon).click();
|
||||
cy.get(commonSelectors.appCreateButton).click();
|
||||
cy.get(commonSelectors.appNameInput).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(500);
|
||||
|
||||
cy.contains(
|
||||
`[id*="react-select-"]`,
|
||||
`cypress-${cyParamName(dsName)}-${cyParamName(dsName)}`
|
||||
)
|
||||
.should("be.visible")
|
||||
.click();
|
||||
|
||||
cy.wait(500);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,288 @@
|
|||
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.dsName = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
|
||||
data.dsName1 = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
|
||||
|
||||
describe("Data source Airtable", () => {
|
||||
beforeEach(() => {
|
||||
cy.apiLogin();
|
||||
cy.defaultWorkspaceLogin();
|
||||
});
|
||||
|
||||
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.dsName1);
|
||||
|
||||
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.dsName1}) 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.dsName1}) completed.`
|
||||
);
|
||||
deleteAppandDatasourceAfterExecution(
|
||||
data.dsName,
|
||||
`cypress-${data.dsName}-airtable`
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,207 @@
|
|||
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 = {};
|
||||
data.dsName = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
|
||||
|
||||
describe("Data source amazon athena", () => {
|
||||
beforeEach(() => {
|
||||
cy.apiLogin();
|
||||
cy.defaultWorkspaceLogin();
|
||||
cy.intercept("POST", "/api/data_queries").as("createQuery");
|
||||
});
|
||||
|
||||
it("Should verify elements on amazon athena connection form", () => {
|
||||
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("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("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="query-input-field"]').clearAndTypeOnCodeMirror(
|
||||
"SHOW DATABASES;"
|
||||
);
|
||||
|
||||
cy.get(dataSourceSelector.queryPreviewButton).click();
|
||||
cy.verifyToastMessage(
|
||||
commonSelectors.toastMessage,
|
||||
`Query (${data.dsName}) completed.`
|
||||
);
|
||||
deleteAppandDatasourceAfterExecution(
|
||||
data.dsName,
|
||||
`cypress-${data.dsName}-amazon-Athena`
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,205 @@
|
|||
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 = {};
|
||||
data.dsName = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
|
||||
|
||||
describe("Data source amazon ses", () => {
|
||||
beforeEach(() => {
|
||||
cy.apiLogin();
|
||||
cy.defaultWorkspaceLogin();
|
||||
cy.intercept("POST", "/api/data_queries").as("createQuery");
|
||||
});
|
||||
|
||||
it("Should verify elements on amazonses connection form", () => {
|
||||
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("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("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`
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,315 @@
|
|||
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 = {};
|
||||
data.dsName = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
|
||||
|
||||
describe("Data source AppWrite", () => {
|
||||
beforeEach(() => {
|
||||
cy.apiLogin();
|
||||
cy.defaultWorkspaceLogin();
|
||||
cy.intercept("POST", "/api/data_queries").as("createQuery");
|
||||
});
|
||||
|
||||
it("Should verify elements on appwrite connection form", () => {
|
||||
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("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("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`
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,187 @@
|
|||
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 = {};
|
||||
data.dsName = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
|
||||
|
||||
describe("Data source AWS Lambda", () => {
|
||||
beforeEach(() => {
|
||||
cy.apiLogin();
|
||||
cy.defaultWorkspaceLogin();
|
||||
cy.intercept("POST", "/api/data_queries").as("createQuery");
|
||||
});
|
||||
|
||||
it("Should verify elements on AWS Lambda connection form", () => {
|
||||
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`);
|
||||
});
|
||||
|
||||
it("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`);
|
||||
});
|
||||
|
||||
it("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");
|
||||
});
|
||||
});
|
||||
|
|
@ -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 = {};
|
||||
data.dsName = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
|
||||
|
||||
describe("Data source AWS Textract", () => {
|
||||
beforeEach(() => {
|
||||
cy.apiLogin();
|
||||
cy.defaultWorkspaceLogin();
|
||||
cy.intercept("POST", "/api/data_queries").as("createQuery");
|
||||
});
|
||||
|
||||
it("Should verify elements on AWS Textract connection form", () => {
|
||||
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("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`);
|
||||
});
|
||||
|
||||
it("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");
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,218 @@
|
|||
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 = {};
|
||||
data.dsName = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
|
||||
|
||||
describe("Data source baserow", () => {
|
||||
beforeEach(() => {
|
||||
cy.apiLogin();
|
||||
cy.defaultWorkspaceLogin();
|
||||
cy.intercept("POST", "/api/data_queries").as("createQuery");
|
||||
});
|
||||
|
||||
it("Should verify elements on baserow connection form", () => {
|
||||
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("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("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`
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,153 @@
|
|||
import { fake } from "Fixtures/fake";
|
||||
import { postgreSqlSelector } from "Selectors/postgreSql";
|
||||
import { postgreSqlText } from "Texts/postgreSql";
|
||||
import { GraphQLText } from "Texts/graphQL";
|
||||
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.dsName = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
|
||||
|
||||
describe("Data source GraphQL", () => {
|
||||
beforeEach(() => {
|
||||
cy.apiLogin();
|
||||
cy.defaultWorkspaceLogin();
|
||||
});
|
||||
|
||||
it("Should verify elements on GraphQL connection form", () => {
|
||||
const Url = Cypress.env("GraphQl_Url");
|
||||
|
||||
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", GraphQLText.GraphQL, data.dsName);
|
||||
|
||||
fillDataSourceTextField(
|
||||
GraphQLText.urlInputLabel,
|
||||
GraphQLText.urlInputPlaceholder,
|
||||
Url
|
||||
);
|
||||
|
||||
cy.get(postgreSqlSelector.buttonSave)
|
||||
.verifyVisibleElement("have.text", postgreSqlText.buttonTextSave)
|
||||
.click();
|
||||
cy.verifyToastMessage(
|
||||
commonSelectors.toastMessage,
|
||||
postgreSqlText.toastDSSaved
|
||||
);
|
||||
|
||||
deleteDatasource(`cypress-${data.dsName}-GraphQL`);
|
||||
});
|
||||
|
||||
it("Should verify the functionality of GraphQL connection form", () => {
|
||||
const Url = Cypress.env("GraphQl_Url");
|
||||
|
||||
cy.get(commonSelectors.globalDataSourceIcon).click();
|
||||
closeDSModal();
|
||||
|
||||
selectAndAddDataSource("databases", GraphQLText.GraphQL, data.dsName);
|
||||
|
||||
fillDataSourceTextField(
|
||||
GraphQLText.urlInputLabel,
|
||||
GraphQLText.urlInputPlaceholder,
|
||||
Url
|
||||
);
|
||||
|
||||
cy.get(postgreSqlSelector.buttonSave)
|
||||
.verifyVisibleElement("have.text", postgreSqlText.buttonTextSave)
|
||||
.click();
|
||||
cy.verifyToastMessage(
|
||||
commonSelectors.toastMessage,
|
||||
postgreSqlText.toastDSSaved
|
||||
);
|
||||
|
||||
deleteDatasource(`cypress-${data.dsName}-GraphQL`);
|
||||
});
|
||||
|
||||
it("Should able to run the query with valid conection", () => {
|
||||
const Url = Cypress.env("GraphQl_Url");
|
||||
|
||||
cy.get(commonSelectors.globalDataSourceIcon).click();
|
||||
closeDSModal();
|
||||
|
||||
selectAndAddDataSource("databases", GraphQLText.GraphQL, data.dsName);
|
||||
|
||||
fillDataSourceTextField(
|
||||
GraphQLText.urlInputLabel,
|
||||
GraphQLText.urlInputPlaceholder,
|
||||
Url
|
||||
);
|
||||
|
||||
cy.get(postgreSqlSelector.buttonSave)
|
||||
.verifyVisibleElement("have.text", postgreSqlText.buttonTextSave)
|
||||
.click();
|
||||
cy.verifyToastMessage(
|
||||
commonSelectors.toastMessage,
|
||||
postgreSqlText.toastDSSaved
|
||||
);
|
||||
|
||||
cy.get(commonSelectors.globalDataSourceIcon).click();
|
||||
|
||||
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="query-input-field"]').clearAndTypeOnCodeMirror(
|
||||
`{
|
||||
allFilms {
|
||||
films { title director }
|
||||
}
|
||||
}`
|
||||
);
|
||||
cy.get(dataSourceSelector.queryPreviewButton).click();
|
||||
cy.verifyToastMessage(
|
||||
commonSelectors.toastMessage,
|
||||
`Query (${data.dsName}) completed.`
|
||||
);
|
||||
deleteAppandDatasourceAfterExecution(
|
||||
data.dsName,
|
||||
`cypress-${data.dsName}-GraphQL`
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,343 @@
|
|||
import { fake } from "Fixtures/fake";
|
||||
import { postgreSqlSelector } from "Selectors/postgreSql";
|
||||
import { postgreSqlText } from "Texts/postgreSql";
|
||||
import { harperDbText } from "Texts/harperDb";
|
||||
import { harperDbSelectors } 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 = {};
|
||||
data.dsName = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
|
||||
data.dsName1 = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
|
||||
|
||||
describe("Data source HarperDB", () => {
|
||||
beforeEach(() => {
|
||||
cy.apiLogin();
|
||||
cy.defaultWorkspaceLogin();
|
||||
});
|
||||
|
||||
it("Should verify elements on HarperDB connection form", () => {
|
||||
const Host = Cypress.env("harperdb_host");
|
||||
const Port = Cypress.env("harperdb_port");
|
||||
const Username = Cypress.env("harperdb_username");
|
||||
const Password = Cypress.env("harperdb_password");
|
||||
|
||||
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("HarperDB");
|
||||
|
||||
selectAndAddDataSource("databases", harperDbText.harperDb, data.dsName);
|
||||
|
||||
fillDataSourceTextField(
|
||||
harperDbText.hostLabel,
|
||||
harperDbText.hostInputPlaceholder,
|
||||
Host
|
||||
);
|
||||
|
||||
fillDataSourceTextField(
|
||||
harperDbText.portLabel,
|
||||
harperDbText.portPlaceholder,
|
||||
Port
|
||||
);
|
||||
|
||||
fillDataSourceTextField(
|
||||
harperDbText.userNameLabel,
|
||||
harperDbText.userNamePlaceholder,
|
||||
Username
|
||||
);
|
||||
|
||||
fillDataSourceTextField(
|
||||
harperDbText.passwordlabel,
|
||||
harperDbText.passwordPlaceholder,
|
||||
Password
|
||||
);
|
||||
|
||||
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}-HarperDB`);
|
||||
});
|
||||
|
||||
it("Should verify functionality of HarperDB connection form", () => {
|
||||
const Host = Cypress.env("harperdb_host");
|
||||
const Port = Cypress.env("harperdb_port");
|
||||
const Username = Cypress.env("harperdb_username");
|
||||
const Password = Cypress.env("harperdb_password");
|
||||
|
||||
cy.get(commonSelectors.globalDataSourceIcon).click();
|
||||
closeDSModal();
|
||||
|
||||
cy.installMarketplacePlugin("HarperDB");
|
||||
|
||||
selectAndAddDataSource("databases", harperDbText.harperDb, data.dsName);
|
||||
|
||||
fillDataSourceTextField(
|
||||
harperDbText.hostLabel,
|
||||
harperDbText.hostInputPlaceholder,
|
||||
Host
|
||||
);
|
||||
|
||||
fillDataSourceTextField(
|
||||
harperDbText.portLabel,
|
||||
harperDbText.portPlaceholder,
|
||||
Port
|
||||
);
|
||||
|
||||
fillDataSourceTextField(
|
||||
harperDbText.userNameLabel,
|
||||
harperDbText.userNamePlaceholder,
|
||||
Username
|
||||
);
|
||||
|
||||
fillDataSourceTextField(
|
||||
harperDbText.passwordlabel,
|
||||
harperDbText.passwordPlaceholder,
|
||||
Password
|
||||
);
|
||||
|
||||
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}-HarperDB`);
|
||||
});
|
||||
|
||||
it("Should be able to run the query with a valid connection", () => {
|
||||
const Host = Cypress.env("harperdb_host");
|
||||
const Port = Cypress.env("harperdb_port");
|
||||
const Username = Cypress.env("harperdb_username");
|
||||
const Password = Cypress.env("harperdb_password");
|
||||
|
||||
cy.get(commonSelectors.globalDataSourceIcon).click();
|
||||
closeDSModal();
|
||||
|
||||
cy.installMarketplacePlugin("HarperDB");
|
||||
|
||||
selectAndAddDataSource("databases", harperDbText.harperDb, data.dsName);
|
||||
|
||||
fillDataSourceTextField(
|
||||
harperDbText.hostLabel,
|
||||
harperDbText.hostInputPlaceholder,
|
||||
Host
|
||||
);
|
||||
|
||||
fillDataSourceTextField(
|
||||
harperDbText.portLabel,
|
||||
harperDbText.portPlaceholder,
|
||||
Port
|
||||
);
|
||||
|
||||
fillDataSourceTextField(
|
||||
harperDbText.userNameLabel,
|
||||
harperDbText.userNamePlaceholder,
|
||||
Username
|
||||
);
|
||||
|
||||
fillDataSourceTextField(
|
||||
harperDbText.passwordlabel,
|
||||
harperDbText.passwordPlaceholder,
|
||||
Password
|
||||
);
|
||||
|
||||
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.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 NoSQL Operation
|
||||
|
||||
cy.get(".react-select__input")
|
||||
.eq(1)
|
||||
.click({ force: true })
|
||||
.wait(500)
|
||||
.type(`NoSQL mode{enter}`, { force: true });
|
||||
|
||||
const operationsDB = [
|
||||
"Insert",
|
||||
"Update",
|
||||
"Search By Hash",
|
||||
"Search By Value",
|
||||
"Search By Condition",
|
||||
"Delete",
|
||||
];
|
||||
|
||||
operationsDB.forEach((operation) => {
|
||||
cy.get(".react-select__input")
|
||||
.eq(2)
|
||||
.click({ force: true })
|
||||
.wait(500)
|
||||
.type(`${operation}{enter}`, { force: true });
|
||||
|
||||
const commonFields = {
|
||||
"schema-input-field": harperDbText.schemaValue,
|
||||
"table-input-field": harperDbText.tableValue,
|
||||
};
|
||||
|
||||
Object.entries(commonFields).forEach(([field, value]) => {
|
||||
cy.get(`[data-cy="${field}"]`).clearAndTypeOnCodeMirror(value);
|
||||
});
|
||||
|
||||
if (["Insert", "Update"].includes(operation)) {
|
||||
cy.get(harperDbSelectors.recordsInputField).clearAndTypeOnCodeMirror(
|
||||
harperDbText.recordsValue
|
||||
);
|
||||
}
|
||||
|
||||
if (operation === "Search By Hash") {
|
||||
cy.get(harperDbSelectors.hashValueInputField).clearAndTypeOnCodeMirror(
|
||||
harperDbText.hashValue
|
||||
);
|
||||
cy.get(harperDbSelectors.attributesInputField).clearAndTypeOnCodeMirror(
|
||||
harperDbText.attributesValue
|
||||
);
|
||||
}
|
||||
|
||||
if (operation === "Search By Value") {
|
||||
cy.get(
|
||||
harperDbSelectors.searchAttributeInputField
|
||||
).clearAndTypeOnCodeMirror(harperDbText.searchAttributeValue);
|
||||
|
||||
cy.get(
|
||||
harperDbSelectors.searchValueInputField
|
||||
).clearAndTypeOnCodeMirror(harperDbText.searchValue);
|
||||
cy.get(harperDbSelectors.attributesInputField).clearAndTypeOnCodeMirror(
|
||||
harperDbText.attributesValue
|
||||
);
|
||||
}
|
||||
|
||||
if (operation === "Search By Condition") {
|
||||
cy.get(".react-select__input")
|
||||
.eq(3)
|
||||
.click({ force: true })
|
||||
.wait(500)
|
||||
.type("Or{enter}", { force: true });
|
||||
|
||||
cy.get(harperDbSelectors.attributesInputField).clearAndTypeOnCodeMirror(
|
||||
harperDbText.attributesValue
|
||||
);
|
||||
cy.get(harperDbSelectors.conditionInputField).clearAndTypeOnCodeMirror(
|
||||
harperDbText.condtionValue
|
||||
);
|
||||
}
|
||||
|
||||
if (operation === "Delete") {
|
||||
cy.get(harperDbSelectors.hashValueInputField).clearAndTypeOnCodeMirror(
|
||||
harperDbText.hashValue
|
||||
);
|
||||
}
|
||||
|
||||
cy.get(dataSourceSelector.queryPreviewButton).click();
|
||||
cy.verifyToastMessage(
|
||||
commonSelectors.toastMessage,
|
||||
`Query (${data.dsName}) completed.`
|
||||
);
|
||||
});
|
||||
|
||||
// Verifying SQL 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.dsName1);
|
||||
|
||||
cy.get(".react-select__input")
|
||||
.eq(1)
|
||||
.should("be.visible")
|
||||
.click({ force: true })
|
||||
.wait(500)
|
||||
.type(`SQL mode{enter}`, { force: true });
|
||||
|
||||
cy.wait(1000);
|
||||
|
||||
cy.get(harperDbSelectors.sqlQueryInputField).clearAndTypeOnCodeMirror(
|
||||
harperDbText.sqlValue
|
||||
);
|
||||
|
||||
cy.get(dataSourceSelector.queryPreviewButton).click();
|
||||
|
||||
cy.verifyToastMessage(
|
||||
commonSelectors.toastMessage,
|
||||
`Query (${data.dsName1}) completed.`
|
||||
);
|
||||
deleteAppandDatasourceAfterExecution(
|
||||
data.dsName,
|
||||
`cypress-${data.dsName}-HarperDB`
|
||||
);
|
||||
cy.uninstallMarketplacePlugin("HarperDB");
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,285 @@
|
|||
import { fake } from "Fixtures/fake";
|
||||
import { postgreSqlSelector } from "Selectors/postgreSql";
|
||||
import { postgreSqlText } from "Texts/postgreSql";
|
||||
import { minioText } from "Texts/minio";
|
||||
import { minioSelectors } 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 = {};
|
||||
data.dsName = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
|
||||
|
||||
describe("Data source minio", () => {
|
||||
beforeEach(() => {
|
||||
cy.apiLogin();
|
||||
cy.defaultWorkspaceLogin();
|
||||
});
|
||||
|
||||
it("Should verify elements on minio connection form", () => {
|
||||
const Host = Cypress.env("minio_host");
|
||||
const Port = Cypress.env("minio_port");
|
||||
const AccessKey = Cypress.env("minio_accesskey");
|
||||
const SecretKey = Cypress.env("minio_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", minioText.minio, data.dsName);
|
||||
|
||||
fillDataSourceTextField(
|
||||
minioText.hostLabel,
|
||||
minioText.hostInputPlaceholder,
|
||||
Host
|
||||
);
|
||||
|
||||
fillDataSourceTextField(
|
||||
minioText.portLabel,
|
||||
minioText.portPlaceholder,
|
||||
Port
|
||||
);
|
||||
|
||||
cy.get(`[${minioSelectors.sslToggle}]`).click();
|
||||
|
||||
fillDataSourceTextField(
|
||||
minioText.labelAccesskey,
|
||||
minioText.placeholderAccessKey,
|
||||
AccessKey
|
||||
);
|
||||
|
||||
fillDataSourceTextField(
|
||||
minioText.labelSecretKey,
|
||||
minioText.placeholderSecretKey,
|
||||
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}-minio`);
|
||||
});
|
||||
|
||||
it("Should verify functionality of minio connection form", () => {
|
||||
const Host = Cypress.env("minio_host");
|
||||
const Port = Cypress.env("minio_port");
|
||||
const AccessKey = Cypress.env("minio_accesskey");
|
||||
const SecretKey = Cypress.env("minio_secretkey");
|
||||
|
||||
cy.get(commonSelectors.globalDataSourceIcon).click();
|
||||
closeDSModal();
|
||||
|
||||
selectAndAddDataSource("databases", minioText.minio, data.dsName);
|
||||
|
||||
fillDataSourceTextField(
|
||||
minioText.hostLabel,
|
||||
minioText.hostInputPlaceholder,
|
||||
Host
|
||||
);
|
||||
|
||||
fillDataSourceTextField(
|
||||
minioText.portLabel,
|
||||
minioText.portPlaceholder,
|
||||
Port
|
||||
);
|
||||
|
||||
cy.get(`[${minioSelectors.sslToggle}]`).click();
|
||||
|
||||
fillDataSourceTextField(
|
||||
minioText.labelAccesskey,
|
||||
minioText.placeholderAccessKey,
|
||||
AccessKey
|
||||
);
|
||||
|
||||
fillDataSourceTextField(
|
||||
minioText.labelSecretKey,
|
||||
minioText.placeholderSecretKey,
|
||||
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}-minio`);
|
||||
});
|
||||
|
||||
it("Should be able to run the query with a valid connection", () => {
|
||||
const Host = Cypress.env("minio_host");
|
||||
const Port = Cypress.env("minio_port");
|
||||
const AccessKey = Cypress.env("minio_accesskey");
|
||||
const SecretKey = Cypress.env("minio_secretkey");
|
||||
|
||||
cy.get(commonSelectors.globalDataSourceIcon).click();
|
||||
closeDSModal();
|
||||
|
||||
selectAndAddDataSource("databases", minioText.minio, data.dsName);
|
||||
|
||||
fillDataSourceTextField(
|
||||
minioText.hostLabel,
|
||||
minioText.hostInputPlaceholder,
|
||||
Host
|
||||
);
|
||||
|
||||
fillDataSourceTextField(
|
||||
minioText.portLabel,
|
||||
minioText.portPlaceholder,
|
||||
Port
|
||||
);
|
||||
|
||||
cy.get(`[${minioSelectors.sslToggle}]`).click();
|
||||
|
||||
fillDataSourceTextField(
|
||||
minioText.labelAccesskey,
|
||||
minioText.placeholderAccessKey,
|
||||
AccessKey
|
||||
);
|
||||
|
||||
fillDataSourceTextField(
|
||||
minioText.labelSecretKey,
|
||||
minioText.placeholderSecretKey,
|
||||
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.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);
|
||||
|
||||
const operationsMinio = [
|
||||
"List buckets",
|
||||
"Put object",
|
||||
"List objects in a bucket",
|
||||
"Read object",
|
||||
"Presigned url for download",
|
||||
"Presigned url for upload",
|
||||
"Remove object",
|
||||
];
|
||||
|
||||
operationsMinio.forEach((operation) => {
|
||||
cy.get(".react-select__input")
|
||||
.eq(1)
|
||||
.type(`${operation}{enter}`, { force: true });
|
||||
|
||||
if (operation === "List objects in a bucket") {
|
||||
cy.get(minioSelectors.bucketNameInputField).clearAndTypeOnCodeMirror(
|
||||
minioText.bucketName
|
||||
);
|
||||
}
|
||||
if (operation === "Read object" || operation === "Remove object") {
|
||||
cy.get(minioSelectors.bucketNameInputField).clearAndTypeOnCodeMirror(
|
||||
minioText.bucketName
|
||||
);
|
||||
cy.get(minioSelectors.objectNameInputField).clearAndTypeOnCodeMirror(
|
||||
minioText.objectName
|
||||
);
|
||||
}
|
||||
if (operation === "Put object") {
|
||||
cy.get(minioSelectors.bucketNameInputField).clearAndTypeOnCodeMirror(
|
||||
minioText.bucketName
|
||||
);
|
||||
cy.get(minioSelectors.objectNameInputField).clearAndTypeOnCodeMirror(
|
||||
minioText.objectName
|
||||
);
|
||||
cy.get(minioSelectors.contentTypeInputField).clearAndTypeOnCodeMirror(
|
||||
'"string"'
|
||||
);
|
||||
cy.get(minioSelectors.dataInput).clearAndTypeOnCodeMirror(`test`);
|
||||
}
|
||||
if (
|
||||
operation === "Presigned url for download" ||
|
||||
operation === "Presigned url for upload"
|
||||
) {
|
||||
cy.get(minioSelectors.bucketNameInputField).clearAndTypeOnCodeMirror(
|
||||
minioText.bucketName
|
||||
);
|
||||
cy.get(minioSelectors.objectNameInputField).clearAndTypeOnCodeMirror(
|
||||
minioText.objectName
|
||||
);
|
||||
}
|
||||
|
||||
cy.get(dataSourceSelector.queryPreviewButton).click();
|
||||
cy.verifyToastMessage(
|
||||
commonSelectors.toastMessage,
|
||||
`Query (${data.dsName}) completed.`
|
||||
);
|
||||
});
|
||||
deleteAppandDatasourceAfterExecution(
|
||||
data.dsName,
|
||||
`cypress-${data.dsName}-minio`
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
@ -123,7 +123,7 @@ describe("Data sources", () => {
|
|||
);
|
||||
|
||||
cy.clearAndType(
|
||||
'[data-cy="data-source-name-input-filed"]',
|
||||
'[data-cy="data-source-name-input-field"]',
|
||||
postgreSqlText.psqlName
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -11,26 +11,22 @@ import {
|
|||
} from "Support/utils/postgreSql";
|
||||
|
||||
import {
|
||||
verifyCouldnotConnectWithAlert,
|
||||
deleteDatasource,
|
||||
closeDSModal,
|
||||
addQuery,
|
||||
addDsAndAddQuery,
|
||||
deleteAppandDatasourceAfterExecution,
|
||||
} from "Support/utils/dataSource";
|
||||
|
||||
import { openQueryEditor } from "Support/utils/dataSource";
|
||||
import { dataSourceSelector } from "../../../../../constants/selectors/dataSource";
|
||||
|
||||
const data = {};
|
||||
data.dsName = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
|
||||
|
||||
describe("Data source Redis", () => {
|
||||
beforeEach(() => {
|
||||
cy.appUILogin();
|
||||
cy.intercept("POST", "/api/data_queries").as("createQuery");
|
||||
cy.apiLogin();
|
||||
cy.defaultWorkspaceLogin();
|
||||
});
|
||||
|
||||
it("Should verify elements on connection Redison form", () => {
|
||||
it("Should verify elements on connection Redis form", () => {
|
||||
cy.get(commonSelectors.globalDataSourceIcon).click();
|
||||
closeDSModal();
|
||||
|
||||
|
|
@ -114,7 +110,7 @@ describe("Data source Redis", () => {
|
|||
deleteDatasource(`cypress-${data.dsName}-redis`);
|
||||
});
|
||||
|
||||
it("Should verify the functionality of Redis connection form.", () => {
|
||||
it("Should verify the functionality of Redis connection form", () => {
|
||||
selectAndAddDataSource("databases", redisText.redis, data.dsName);
|
||||
|
||||
fillDataSourceTextField(
|
||||
|
|
@ -143,7 +139,7 @@ describe("Data source Redis", () => {
|
|||
cy.get(postgreSqlSelector.buttonTestConnection).click();
|
||||
cy.get('[data-cy="connection-alert-text"]').should(
|
||||
"have.text",
|
||||
"WRONGPASS invalid username-password pair or user is disabled."
|
||||
redisText.errorInvalidUserOrPassword
|
||||
);
|
||||
fillDataSourceTextField(
|
||||
postgreSqlText.labelHost,
|
||||
|
|
@ -176,7 +172,7 @@ describe("Data source Redis", () => {
|
|||
cy.get(postgreSqlSelector.buttonTestConnection).click();
|
||||
cy.get('[data-cy="connection-alert-text"]').should(
|
||||
"have.text",
|
||||
"WRONGPASS invalid username-password pair or user is disabled."
|
||||
redisText.errorInvalidUserOrPassword
|
||||
);
|
||||
|
||||
fillDataSourceTextField(
|
||||
|
|
@ -193,7 +189,7 @@ describe("Data source Redis", () => {
|
|||
cy.get(postgreSqlSelector.buttonTestConnection).click();
|
||||
cy.get('[data-cy="connection-alert-text"]').should(
|
||||
"have.text",
|
||||
"WRONGPASS invalid username-password pair or user is disabled."
|
||||
redisText.errorInvalidUserOrPassword
|
||||
);
|
||||
|
||||
fillDataSourceTextField(
|
||||
|
|
@ -256,5 +252,9 @@ describe("Data source Redis", () => {
|
|||
cy.skipWalkthrough();
|
||||
|
||||
addDsAndAddQuery("redis", `TIME`, `cypress-${data.dsName}-redis`);
|
||||
deleteAppandDatasourceAfterExecution(
|
||||
data.dsName,
|
||||
`cypress-${data.dsName}-redis`
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -0,0 +1,383 @@
|
|||
import { fake } from "Fixtures/fake";
|
||||
import { commonSelectors } from "Selectors/common";
|
||||
import { closeDSModal, deleteDatasource } from "Support/utils/dataSource";
|
||||
import { postgreSqlSelector } from "Selectors/postgreSql";
|
||||
import { postgreSqlText } from "Texts/postgreSql";
|
||||
import { restAPISelector } from "Selectors/restAPI";
|
||||
import { restAPIText } from "Texts/restAPI";
|
||||
import { fillDataSourceTextField } from "Support/utils/postgreSql";
|
||||
|
||||
const data = {};
|
||||
const authenticationDropdownSelector =
|
||||
".dynamic-form-element > .css-nwhe5y-container > .react-select__control";
|
||||
const grantTypeDropdown =
|
||||
":nth-child(1) > :nth-child(2) > .react-select__control";
|
||||
const addAccessTokenDropdown =
|
||||
":nth-child(9) > .css-nwhe5y-container > .react-select__control";
|
||||
const clientAuthenticationDropdown =
|
||||
":nth-child(14) > .css-nwhe5y-container > .react-select__control";
|
||||
|
||||
describe("Data source Rest API", () => {
|
||||
beforeEach(() => {
|
||||
cy.defaultWorkspaceLogin();
|
||||
cy.intercept("GET", "/api/v2/data_sources");
|
||||
data.dataSourceName = fake.lastName
|
||||
.toLowerCase()
|
||||
.replaceAll("[^A-Za-z]", "");
|
||||
});
|
||||
it("Should verify elements on Rest API connection 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
|
||||
);
|
||||
|
||||
cy.apiCreateGDS(
|
||||
`${Cypress.env("server_host")}/api/data-sources`,
|
||||
`cypress-${data.dataSourceName}-restapi`,
|
||||
"restapi",
|
||||
[
|
||||
{ key: "url", value: "" },
|
||||
{ key: "auth_type", value: "none" },
|
||||
{ key: "grant_type", value: "authorization_code" },
|
||||
{ key: "add_token_to", value: "header" },
|
||||
{ key: "header_prefix", value: "Bearer " },
|
||||
{ key: "access_token_url", value: "" },
|
||||
{ key: "client_id", value: "" },
|
||||
{ key: "client_secret", value: "", encrypted: true },
|
||||
{ key: "audience", value: "" },
|
||||
{ key: "scopes", value: "read, write" },
|
||||
{ key: "username", value: "", encrypted: false },
|
||||
{ key: "password", value: "", encrypted: true },
|
||||
{ key: "bearer_token", value: "", encrypted: true },
|
||||
{ key: "auth_url", value: "" },
|
||||
{ key: "client_auth", value: "header" },
|
||||
{ key: "headers", value: [["", ""]] },
|
||||
{ key: "custom_query_params", value: [["", ""]], encrypted: false },
|
||||
{ key: "custom_auth_params", value: [["", ""]] },
|
||||
{
|
||||
key: "access_token_custom_headers",
|
||||
value: [["", ""]],
|
||||
encrypted: false,
|
||||
},
|
||||
{ key: "multiple_auth_enabled", value: false, encrypted: false },
|
||||
{ key: "ssl_certificate", value: "none", encrypted: false },
|
||||
{ key: "retry_network_errors", value: true, encrypted: false },
|
||||
]
|
||||
);
|
||||
cy.reload();
|
||||
cy.get(`[data-cy="cypress-${data.dataSourceName}-restapi-button"]`)
|
||||
.should("be.visible")
|
||||
.click();
|
||||
cy.get(restAPISelector.inputField("data-source-name")).should(
|
||||
"have.value",
|
||||
`cypress-${data.dataSourceName}-restapi`
|
||||
);
|
||||
cy.get(restAPISelector.subHeaderLabel(restAPIText.credentialsText)).should(
|
||||
"have.text",
|
||||
restAPIText.credentialsText
|
||||
);
|
||||
const sections = [
|
||||
restAPIText.baseUrlLabel,
|
||||
restAPIText.headersLabel,
|
||||
restAPIText.urlParametesLabel,
|
||||
restAPIText.bodyLabel,
|
||||
restAPIText.cookiesLabel,
|
||||
];
|
||||
|
||||
sections.forEach((section) => {
|
||||
cy.get(restAPISelector.subHeaderLabel(section)).should(
|
||||
"have.text",
|
||||
section
|
||||
);
|
||||
|
||||
if (section !== restAPIText.baseUrlLabel) {
|
||||
cy.get(restAPISelector.keyInputField(section, 0)).should("be.visible");
|
||||
cy.get(restAPISelector.valueInputField(section, 0)).should(
|
||||
"be.visible"
|
||||
);
|
||||
cy.get(restAPISelector.deleteButton(section, 0)).should("be.visible");
|
||||
cy.get(restAPISelector.addMoreButton(section)).should("be.visible");
|
||||
} else {
|
||||
cy.get('[data-cy="base-url-text-field"]').should("be.visible");
|
||||
}
|
||||
});
|
||||
|
||||
cy.get(
|
||||
restAPISelector.subHeaderLabel(restAPIText.authenticationText)
|
||||
).should("have.text", restAPIText.authenticationText);
|
||||
cy.get(
|
||||
restAPISelector.subHeaderLabel(restAPIText.authenticationTypeLabel)
|
||||
).should("have.text", restAPIText.authenticationTypeLabel);
|
||||
|
||||
cy.get(authenticationDropdownSelector).click();
|
||||
cy.contains(
|
||||
`[id*="react-select-"]`,
|
||||
restAPIText.basicAuth.basicText
|
||||
).click();
|
||||
cy.get(authenticationDropdownSelector).should(
|
||||
"have.text",
|
||||
restAPIText.basicAuth.basicText
|
||||
);
|
||||
|
||||
cy.get(
|
||||
restAPISelector.subHeaderLabel(restAPIText.basicAuth.usernameLabel)
|
||||
).should("have.text", restAPIText.basicAuth.usernameLabel);
|
||||
cy.get(
|
||||
restAPISelector.inputField(restAPIText.basicAuth.usernameLabel)
|
||||
).should("be.visible");
|
||||
cy.get(
|
||||
restAPISelector.subHeaderLabel(restAPIText.basicAuth.passwordLabel)
|
||||
).should("have.text", restAPIText.basicAuth.passwordLabel);
|
||||
cy.get(restAPISelector.button(restAPIText.editButtonText)).should(
|
||||
"be.visible"
|
||||
);
|
||||
cy.get(
|
||||
restAPISelector.inputField(restAPIText.basicAuth.passwordLabel)
|
||||
).should("be.visible");
|
||||
|
||||
cy.get(authenticationDropdownSelector).click();
|
||||
cy.contains(`[id*="react-select-"]`, restAPIText.bearerAuth.bearerText)
|
||||
.should("be.visible")
|
||||
.click();
|
||||
cy.get(authenticationDropdownSelector).should(
|
||||
"have.text",
|
||||
restAPIText.bearerAuth.bearerText
|
||||
);
|
||||
cy.get(
|
||||
restAPISelector.subHeaderLabel(restAPIText.bearerAuth.tokenLabel)
|
||||
).should("have.text", restAPIText.bearerAuth.tokenLabel);
|
||||
cy.get(
|
||||
restAPISelector.inputField(restAPIText.bearerAuth.tokenLabel)
|
||||
).should("be.visible");
|
||||
|
||||
cy.get(authenticationDropdownSelector).click();
|
||||
cy.contains(`[id*="react-select-"]`, restAPIText.oAuthText).click();
|
||||
cy.get(authenticationDropdownSelector).should(
|
||||
"have.text",
|
||||
restAPIText.oAuthText
|
||||
);
|
||||
cy.get(restAPISelector.subHeaderLabel(restAPIText.grantTypeLabel)).should(
|
||||
"have.text",
|
||||
restAPIText.grantTypeLabel
|
||||
);
|
||||
cy.get(grantTypeDropdown).click();
|
||||
cy.contains(
|
||||
`[id*="react-select-"]`,
|
||||
restAPIText.authorizationCode.authorizationCodeLabel
|
||||
)
|
||||
.should("be.visible")
|
||||
.click();
|
||||
cy.get(grantTypeDropdown).should(
|
||||
"contain",
|
||||
restAPIText.authorizationCode.authorizationCodeLabel
|
||||
);
|
||||
cy.get(
|
||||
restAPISelector.inputField(
|
||||
restAPIText.authorizationCode.headerPrefixLabel
|
||||
)
|
||||
).should(($input) => {
|
||||
expect($input.val().trim()).to.equal(restAPIText.bearerAuth.bearerText);
|
||||
});
|
||||
cy.get(
|
||||
restAPISelector.inputField(
|
||||
restAPIText.authorizationCode.accessTokenURLLabel
|
||||
)
|
||||
)
|
||||
.invoke("attr", "placeholder")
|
||||
.should("eq", "https://api.example.com/oauth/token");
|
||||
cy.get(
|
||||
restAPISelector.inputField(restAPIText.authorizationCode.clientIDLabel)
|
||||
).should("be.visible");
|
||||
cy.get(restAPISelector.button(restAPIText.editButtonText)).should(
|
||||
"be.visible"
|
||||
);
|
||||
cy.get(
|
||||
restAPISelector.inputField(
|
||||
restAPIText.authorizationCode.clientSecretLabel
|
||||
)
|
||||
).should("be.visible");
|
||||
Object.entries(restAPIText.authorizationCode).forEach(([key, value]) => {
|
||||
if (
|
||||
key !== "authorizationCodeLabel" &&
|
||||
key !== "requestHeader" &&
|
||||
key !== "sendBasicAuthheaderOption" &&
|
||||
key !== "sendClientCredentialsBodyOption"
|
||||
) {
|
||||
cy.get(
|
||||
restAPISelector.subHeaderLabel(restAPIText.authorizationCode[key])
|
||||
).should("have.text", value);
|
||||
}
|
||||
});
|
||||
cy.get(addAccessTokenDropdown)
|
||||
.should("be.visible")
|
||||
.and("contain", restAPIText.authorizationCode.requestHeader);
|
||||
cy.get(
|
||||
restAPISelector.inputField(restAPIText.authorizationCode.scopeLabel)
|
||||
).should("be.visible");
|
||||
|
||||
const authorizationCodeSections = [
|
||||
restAPIText.authorizationCode.accessTokenURLCustomHeadersLabel,
|
||||
restAPIText.authorizationCode.customQueryParametersLabel,
|
||||
restAPIText.authorizationCode.customAuthenticationParametersLabel,
|
||||
];
|
||||
authorizationCodeSections.forEach((authorizationCodeSections) => {
|
||||
cy.get(
|
||||
restAPISelector.subHeaderLabel(authorizationCodeSections)
|
||||
).verifyVisibleElement("have.text", authorizationCodeSections);
|
||||
if (authorizationCodeSections !== restAPIText.baseUrlLabel) {
|
||||
cy.get(
|
||||
restAPISelector.keyInputField(authorizationCodeSections, 0)
|
||||
).should("be.visible");
|
||||
cy.get(
|
||||
restAPISelector.valueInputField(authorizationCodeSections, 0)
|
||||
).should("be.visible");
|
||||
cy.get(
|
||||
restAPISelector.deleteButton(authorizationCodeSections, 0)
|
||||
).should("be.visible");
|
||||
cy.get(restAPISelector.addMoreButton(authorizationCodeSections)).should(
|
||||
"be.visible"
|
||||
);
|
||||
} else {
|
||||
cy.get('[data-cy="base-url-text-field"]').should("be.visible");
|
||||
}
|
||||
});
|
||||
cy.get(clientAuthenticationDropdown).click();
|
||||
cy.contains(
|
||||
`[id*="react-select-"]`,
|
||||
restAPIText.authorizationCode.sendClientCredentialsBodyOption
|
||||
).should("be.visible");
|
||||
cy.contains(
|
||||
`[id*="react-select-"]`,
|
||||
restAPIText.authorizationCode.sendBasicAuthheaderOption
|
||||
)
|
||||
.should("be.visible")
|
||||
.click();
|
||||
cy.get(clientAuthenticationDropdown).should(
|
||||
"have.text",
|
||||
restAPIText.authorizationCode.sendBasicAuthheaderOption
|
||||
);
|
||||
cy.get(
|
||||
restAPISelector.subHeaderLabel(
|
||||
restAPIText.authorizationCode.authenticationRequiredUsersToggle
|
||||
)
|
||||
).verifyVisibleElement(
|
||||
"have.text",
|
||||
restAPIText.authorizationCode.authenticationRequiredUsersToggle
|
||||
);
|
||||
cy.get(restAPISelector.authenticationAllUsersToggleSwitch).should(
|
||||
"be.visible"
|
||||
);
|
||||
cy.get(grantTypeDropdown).click();
|
||||
cy.contains(
|
||||
`[id*="react-select-"]`,
|
||||
restAPIText.clientCredentials.clientCredentialsLabel
|
||||
)
|
||||
.should("be.visible")
|
||||
.click();
|
||||
cy.get(grantTypeDropdown).should(
|
||||
"contain",
|
||||
restAPIText.clientCredentials.clientCredentialsLabel
|
||||
);
|
||||
Object.entries(restAPIText.clientCredentials).forEach(([key, value]) => {
|
||||
if (key !== "clientCredentialsLabel") {
|
||||
cy.get(
|
||||
restAPISelector.subHeaderLabel(restAPIText.clientCredentials[key])
|
||||
).should("have.text", value);
|
||||
}
|
||||
});
|
||||
|
||||
cy.get(
|
||||
restAPISelector.subHeaderLabel(restAPIText.secureSocketsLayerText)
|
||||
).should("have.text", restAPIText.secureSocketsLayerText);
|
||||
cy.get(restAPISelector.dropdownLabel("SSL Certificate")).should(
|
||||
"have.text",
|
||||
"SSL Certificate"
|
||||
);
|
||||
cy.get(
|
||||
restAPISelector.subHeaderLabel(restAPIText.generalSettingsText)
|
||||
).should("have.text", restAPIText.generalSettingsText);
|
||||
cy.get(restAPISelector.retryNetworkToggleSwitch).should("be.visible");
|
||||
cy.get(restAPISelector.retryNetworkToggleText).should(
|
||||
"have.text",
|
||||
restAPIText.retryNetworkErrorsToggleLabel
|
||||
);
|
||||
cy.get(restAPISelector.retryNetworkToggleSubtext).should(
|
||||
"have.text",
|
||||
restAPIText.retryToggleHelperText
|
||||
);
|
||||
cy.get(restAPISelector.readDocumentationLinkText).should(
|
||||
"have.text",
|
||||
postgreSqlText.readDocumentation
|
||||
);
|
||||
cy.contains("Save").click();
|
||||
cy.verifyToastMessage(commonSelectors.toastMessage, "Data Source Saved");
|
||||
deleteDatasource(`cypress-${data.dataSourceName}-restapi`);
|
||||
});
|
||||
it("Should verify connection for Rest API", () => {
|
||||
cy.apiCreateGDS(
|
||||
`${Cypress.env("server_host")}/api/data-sources`,
|
||||
`cypress-${data.dataSourceName}-restapi`,
|
||||
"restapi",
|
||||
[
|
||||
{ key: "url", value: Cypress.env("restAPI_BaseURL") },
|
||||
{ key: "auth_type", value: "none" },
|
||||
{ key: "grant_type", value: "authorization_code" },
|
||||
{ key: "add_token_to", value: "header" },
|
||||
{ key: "header_prefix", value: "Bearer " },
|
||||
{ key: "access_token_url", value: "" },
|
||||
{ key: "client_id", value: "" },
|
||||
{ key: "client_secret", value: "", encrypted: true },
|
||||
{ key: "audience", value: "" },
|
||||
{ key: "scopes", value: "read, write" },
|
||||
{ key: "username", value: "", encrypted: false },
|
||||
{ key: "password", value: "", encrypted: true },
|
||||
{ key: "bearer_token", value: "", encrypted: true },
|
||||
{ key: "auth_url", value: "" },
|
||||
{ key: "client_auth", value: "header" },
|
||||
{ key: "headers", value: [["", ""]] },
|
||||
{ key: "custom_query_params", value: [["", ""]], encrypted: false },
|
||||
{ key: "custom_auth_params", value: [["", ""]] },
|
||||
{
|
||||
key: "access_token_custom_headers",
|
||||
value: [["", ""]],
|
||||
encrypted: false,
|
||||
},
|
||||
{ key: "multiple_auth_enabled", value: false, encrypted: false },
|
||||
{ key: "ssl_certificate", value: "none", encrypted: false },
|
||||
{ key: "retry_network_errors", value: true, encrypted: false },
|
||||
]
|
||||
);
|
||||
cy.reload();
|
||||
// cy.apiCreateApp(`${fake.companyName}-restAPI-App`);
|
||||
// cy.apiAddQueryToApp(
|
||||
// "restapi1",
|
||||
// {
|
||||
// method: "get",
|
||||
// url: "",
|
||||
// url_params: [["", ""]],
|
||||
// headers: [["", ""]],
|
||||
// cookies: [["", ""]],
|
||||
// },
|
||||
// `cypress-${data.dataSourceName}-restapi`,
|
||||
// "restapi"
|
||||
// );
|
||||
});
|
||||
});
|
||||
|
|
@ -19,7 +19,8 @@ const data = {};
|
|||
|
||||
describe("Data sources AWS S3", () => {
|
||||
beforeEach(() => {
|
||||
cy.appUILogin();
|
||||
cy.apiLogin();
|
||||
cy.defaultWorkspaceLogin();
|
||||
data.dataSourceName = fake.lastName
|
||||
.toLowerCase()
|
||||
.replaceAll("[^A-Za-z]", "");
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@ describe("Data sources", () => {
|
|||
selectAndAddDataSource(postgreSqlText.postgreSQL);
|
||||
|
||||
cy.clearAndType(
|
||||
'[data-cy="data-source-name-input-filed"]',
|
||||
'[data-cy="data-source-name-input-field"]',
|
||||
postgreSqlText.psqlName
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,197 @@
|
|||
import { fake } from "Fixtures/fake";
|
||||
import { postgreSqlSelector } from "Selectors/postgreSql";
|
||||
import { postgreSqlText } from "Texts/postgreSql";
|
||||
import { twilioText } from "Texts/twilio";
|
||||
import { twilioSelectors } 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";
|
||||
import { pluginSelectors } from "Selectors/plugins";
|
||||
|
||||
const data = {};
|
||||
data.dsName = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
|
||||
|
||||
describe("Data source Twilio", () => {
|
||||
beforeEach(() => {
|
||||
cy.apiLogin();
|
||||
cy.defaultWorkspaceLogin();
|
||||
});
|
||||
|
||||
it("Should verify elements on Twilio connection form", () => {
|
||||
const AuthToken = Cypress.env("twilio_auth_token");
|
||||
const AccountSID = Cypress.env("twilio_account_SID");
|
||||
const MessageSID = Cypress.env("twilio_messaging_service_SID");
|
||||
|
||||
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", twilioText.twilio, data.dsName);
|
||||
|
||||
fillDataSourceTextField(
|
||||
twilioText.authTokenLabel,
|
||||
twilioText.authTokenPlaceholder,
|
||||
AuthToken
|
||||
);
|
||||
|
||||
fillDataSourceTextField(
|
||||
twilioText.accountSidLabel,
|
||||
twilioText.accountSidPlaceholder,
|
||||
AccountSID
|
||||
);
|
||||
|
||||
fillDataSourceTextField(
|
||||
twilioText.messagingSIDLabel,
|
||||
twilioText.messagingSIDPalceholder,
|
||||
MessageSID
|
||||
);
|
||||
|
||||
cy.get(postgreSqlSelector.buttonSave)
|
||||
.verifyVisibleElement("have.text", postgreSqlText.buttonTextSave)
|
||||
.click();
|
||||
cy.verifyToastMessage(
|
||||
commonSelectors.toastMessage,
|
||||
postgreSqlText.toastDSSaved
|
||||
);
|
||||
|
||||
deleteDatasource(`cypress-${data.dsName}-twilio`);
|
||||
});
|
||||
|
||||
it("Should verify functionality of Twilio connection form", () => {
|
||||
const AuthToken = Cypress.env("twilio_auth_token");
|
||||
const AccountSID = Cypress.env("twilio_account_SID");
|
||||
const MessageSID = Cypress.env("twilio_messaging_service_SID");
|
||||
|
||||
cy.get(commonSelectors.globalDataSourceIcon).click();
|
||||
closeDSModal();
|
||||
|
||||
selectAndAddDataSource("databases", twilioText.twilio, data.dsName);
|
||||
|
||||
fillDataSourceTextField(
|
||||
twilioText.authTokenLabel,
|
||||
twilioText.authTokenPlaceholder,
|
||||
AuthToken
|
||||
);
|
||||
|
||||
fillDataSourceTextField(
|
||||
twilioText.accountSidLabel,
|
||||
twilioText.accountSidPlaceholder,
|
||||
AccountSID
|
||||
);
|
||||
|
||||
fillDataSourceTextField(
|
||||
twilioText.messagingSIDLabel,
|
||||
twilioText.messagingSIDPalceholder,
|
||||
MessageSID
|
||||
);
|
||||
|
||||
cy.get(postgreSqlSelector.buttonSave)
|
||||
.verifyVisibleElement("have.text", postgreSqlText.buttonTextSave)
|
||||
.click();
|
||||
cy.verifyToastMessage(
|
||||
commonSelectors.toastMessage,
|
||||
postgreSqlText.toastDSSaved
|
||||
);
|
||||
|
||||
deleteDatasource(`cypress-${data.dsName}-twilio`);
|
||||
});
|
||||
|
||||
it("Should be able to run the query with a valid connection", () => {
|
||||
const AuthToken = Cypress.env("twilio_auth_token");
|
||||
const AccountSID = Cypress.env("twilio_account_SID");
|
||||
const MessageSID = Cypress.env("twilio_messaging_service_SID");
|
||||
const MessageNumber = Cypress.env("twilio_message_number");
|
||||
|
||||
cy.get(commonSelectors.globalDataSourceIcon).click();
|
||||
closeDSModal();
|
||||
|
||||
selectAndAddDataSource("databases", twilioText.twilio, data.dsName);
|
||||
|
||||
fillDataSourceTextField(
|
||||
twilioText.authTokenLabel,
|
||||
twilioText.authTokenPlaceholder,
|
||||
AuthToken
|
||||
);
|
||||
|
||||
fillDataSourceTextField(
|
||||
twilioText.accountSidLabel,
|
||||
twilioText.accountSidPlaceholder,
|
||||
AccountSID
|
||||
);
|
||||
|
||||
fillDataSourceTextField(
|
||||
twilioText.messagingSIDLabel,
|
||||
twilioText.messagingSIDPalceholder,
|
||||
MessageSID
|
||||
);
|
||||
|
||||
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("Send SMS{enter}");
|
||||
|
||||
cy.get(twilioSelectors.toNumberInputField).clearAndTypeOnCodeMirror(
|
||||
MessageNumber
|
||||
);
|
||||
cy.get(twilioSelectors.bodyInput).clearAndTypeOnCodeMirror(
|
||||
twilioText.messageText
|
||||
);
|
||||
cy.get(dataSourceSelector.queryPreviewButton).click();
|
||||
cy.verifyToastMessage(
|
||||
commonSelectors.toastMessage,
|
||||
`Query (${data.dsName}) completed.`
|
||||
);
|
||||
deleteAppandDatasourceAfterExecution(
|
||||
data.dsName,
|
||||
`cypress-${data.dsName}-twilio`
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
@ -107,7 +107,7 @@ describe("App Import Functionality", () => {
|
|||
);
|
||||
cy.get(commonSelectors.appNameLabel).verifyVisibleElement(
|
||||
"have.text",
|
||||
"App Name"
|
||||
"App name"
|
||||
);
|
||||
cy.get(commonSelectors.appNameInput)
|
||||
.should("be.visible")
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ describe("App Slug", () => {
|
|||
beforeEach(() => {
|
||||
data.slug = `${fake.companyName.toLowerCase()}-app`;
|
||||
data.appName = `${fake.companyName} App`;
|
||||
cy.log(Cypress.env("workspaceId"));
|
||||
cy.defaultWorkspaceLogin();
|
||||
});
|
||||
|
||||
|
|
@ -24,6 +25,8 @@ describe("App Slug", () => {
|
|||
cy.apiCreateApp(data.appName);
|
||||
cy.wait(1000);
|
||||
cy.apiLogout();
|
||||
cy.log(Cypress.env("workspaceId"));
|
||||
|
||||
});
|
||||
|
||||
it("Verify app slug cases in global settings", () => {
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ import { setSignupStatus } from "Support/utils/manageSSO";
|
|||
import { onboardingSelectors } from "Selectors/onboarding";
|
||||
import { commonText } from "Texts/common";
|
||||
import {
|
||||
verifyConfirmEmailPage,
|
||||
userSignUp,
|
||||
addNewUser,
|
||||
} from "Support/utils/onboarding";
|
||||
|
|
@ -33,6 +32,8 @@ describe("Private and Public apps", {
|
|||
|
||||
cy.defaultWorkspaceLogin();
|
||||
cy.skipWalkthrough();
|
||||
cy.log(data.appName, "text1")
|
||||
|
||||
});
|
||||
|
||||
it("Verify private and public app share functionality", () => {
|
||||
|
|
@ -85,7 +86,8 @@ describe("Private and Public apps", {
|
|||
cy.get(onboardingSelectors.signInButton, { timeout: 20000 }).should("be.visible");
|
||||
cy.wait(2000);
|
||||
cy.loginWithCredentials("dev@tooljet.io", "password");
|
||||
cy.get(commonWidgetSelector.draggableWidget("text1")).should("be.visible");
|
||||
// cy.get(commonWidgetSelector.draggableWidget("text1")).should("be.visible");
|
||||
cy.get('.text-widget-section > div').should("be.visible");
|
||||
|
||||
// Test public access
|
||||
cy.get(commonSelectors.viewerPageLogo).click();
|
||||
|
|
@ -104,7 +106,9 @@ describe("Private and Public apps", {
|
|||
cy.visitSlug({
|
||||
actualUrl: `${Cypress.config("baseUrl")}/applications/${data.slug}`,
|
||||
});
|
||||
cy.get(commonWidgetSelector.draggableWidget("text1")).should("be.visible");
|
||||
// cy.get(commonWidgetSelector.draggableWidget("text1")).should("be.visible");
|
||||
cy.get('.text-widget-section > div').should("be.visible");
|
||||
|
||||
});
|
||||
|
||||
it("Verify app private and public app visibility for the same workspace user", () => {
|
||||
|
|
@ -120,13 +124,17 @@ describe("Private and Public apps", {
|
|||
|
||||
cy.wait(2000);
|
||||
cy.loginWithCredentials(data.email, "password");
|
||||
cy.get(commonWidgetSelector.draggableWidget("text1")).should("be.visible");
|
||||
|
||||
// cy.get(commonWidgetSelector.draggableWidget("text1")).should("be.visible");
|
||||
cy.get('.text-widget-section > div').should("be.visible", { timeout: 20000 });
|
||||
|
||||
// Test with private app valid session
|
||||
cy.visitSlug({
|
||||
actualUrl: `${Cypress.config("baseUrl")}/applications/${data.slug}`,
|
||||
});
|
||||
cy.get(commonWidgetSelector.draggableWidget("text1")).should("be.visible");
|
||||
// cy.get(commonWidgetSelector.draggableWidget("text1")).should("be.visible");
|
||||
cy.get('.text-widget-section > div').should("be.visible");
|
||||
|
||||
cy.get(commonSelectors.viewerPageLogo).click();
|
||||
|
||||
// Test public access
|
||||
|
|
@ -137,14 +145,18 @@ describe("Private and Public apps", {
|
|||
cy.visitSlug({
|
||||
actualUrl: `${Cypress.config("baseUrl")}/applications/${data.slug}`,
|
||||
});
|
||||
cy.get(commonWidgetSelector.draggableWidget("text1")).should("be.visible");
|
||||
// cy.get(commonWidgetSelector.draggableWidget("text1")).should("be.visible");
|
||||
cy.get('.text-widget-section > div').should("be.visible");
|
||||
|
||||
|
||||
// Test with public app with valid session
|
||||
cy.apiLogin(data.email, "password");
|
||||
cy.visitSlug({
|
||||
actualUrl: `${Cypress.config("baseUrl")}/applications/${data.slug}`,
|
||||
});
|
||||
cy.get(commonWidgetSelector.draggableWidget("text1")).should("be.visible");
|
||||
// cy.get(commonWidgetSelector.draggableWidget("text1")).should("be.visible");
|
||||
cy.get('.text-widget-section > div').should("be.visible");
|
||||
|
||||
});
|
||||
|
||||
it("Verify app private and public app visibility for the same instance user", () => {
|
||||
|
|
@ -168,14 +180,18 @@ describe("Private and Public apps", {
|
|||
cy.visitSlug({
|
||||
actualUrl: `${Cypress.config("baseUrl")}/applications/${data.slug}`,
|
||||
});
|
||||
cy.get(commonWidgetSelector.draggableWidget("text1")).should("be.visible");
|
||||
// cy.get(commonWidgetSelector.draggableWidget("text1")).should("be.visible");
|
||||
cy.get('.text-widget-section > div').should("be.visible");
|
||||
|
||||
|
||||
// Verify public app with valid session
|
||||
cy.apiLogin(data.email, "password");
|
||||
cy.visitSlug({
|
||||
actualUrl: `${Cypress.config("baseUrl")}/applications/${data.slug}`,
|
||||
});
|
||||
cy.get(commonWidgetSelector.draggableWidget("text1")).should("be.visible");
|
||||
// cy.get(commonWidgetSelector.draggableWidget("text1")).should("be.visible");
|
||||
cy.get('.text-widget-section > div').should("be.visible");
|
||||
|
||||
});
|
||||
|
||||
it("Should redirect to workspace login and handle signup flow of existing and non-existing user", () => {
|
||||
|
|
@ -193,18 +209,24 @@ describe("Private and Public apps", {
|
|||
);
|
||||
|
||||
// Test signup flow
|
||||
cy.intercept("POST", "/api/onboarding/signup").as("signup");
|
||||
cy.get(commonSelectors.createAnAccountLink).click();
|
||||
cy.wait(3000);
|
||||
cy.clearAndType(commonSelectors.inputFieldFullName, data.firstName);
|
||||
cy.clearAndType(commonSelectors.inputFieldEmailAddress, data.email);
|
||||
cy.clearAndType(onboardingSelectors.loginPasswordInput, "password");
|
||||
cy.get(commonSelectors.signUpButton).click();
|
||||
verifyConfirmEmailPage(data.email);
|
||||
|
||||
cy.wait('@signup').then((interception) => {
|
||||
expect(interception.response.statusCode).to.eq(201);
|
||||
});
|
||||
|
||||
// Process invitation
|
||||
onboardUserFromAppLink(data.email, data.slug);
|
||||
|
||||
cy.get(commonWidgetSelector.draggableWidget("text1")).should("be.visible");
|
||||
// cy.get(commonWidgetSelector.draggableWidget("text1")).should("be.visible");
|
||||
cy.get('.text-widget-section > div').should("be.visible");
|
||||
|
||||
cy.get('[data-cy="viewer-page-logo"]').click();
|
||||
logout();
|
||||
|
||||
|
|
@ -242,10 +264,14 @@ describe("Private and Public apps", {
|
|||
cy.clearAndType(commonSelectors.inputFieldEmailAddress, data.email);
|
||||
cy.clearAndType(onboardingSelectors.loginPasswordInput, "password");
|
||||
cy.get(commonSelectors.signUpButton).click();
|
||||
verifyConfirmEmailPage(data.email);
|
||||
cy.wait('@signup').then((interception) => {
|
||||
expect(interception.response.statusCode).to.eq(201);
|
||||
});
|
||||
|
||||
onboardUserFromAppLink(data.email, data.slug, data.workspaceName, false);
|
||||
cy.get(commonWidgetSelector.draggableWidget("text1")).should("be.visible");
|
||||
// cy.get(commonWidgetSelector.draggableWidget("text1")).should("be.visible");
|
||||
cy.get('.text-widget-section > div').should("be.visible");
|
||||
|
||||
});
|
||||
|
||||
it("Should verify restricted app access", () => {
|
||||
|
|
|
|||
|
|
@ -111,7 +111,10 @@ describe("App Version", () => {
|
|||
onlydeleteVersionText.deleteToastMessage("v3")
|
||||
);
|
||||
cy.get(appVersionSelectors.currentVersionField("v2")).should("be.visible");
|
||||
cy.get(commonWidgetSelector.draggableWidget("text1")).should("be.visible");
|
||||
cy.wait(3000);
|
||||
|
||||
// cy.reload();
|
||||
// cy.get(commonWidgetSelector.draggableWidget("text1")).should("be.visible", { timeout: 10000 });
|
||||
|
||||
// Preview and release verification
|
||||
cy.openInCurrentTab(commonWidgetSelector.previewButton);
|
||||
|
|
@ -120,7 +123,7 @@ describe("App Version", () => {
|
|||
releasedVersionAndVerify("v2");
|
||||
});
|
||||
|
||||
it("should verify version management with components and queries", () => {
|
||||
it.only("should verify version management with components and queries", () => {
|
||||
// Initial setup with component and datasource
|
||||
cy.apiAddComponentToApp(
|
||||
data.appName,
|
||||
|
|
@ -132,7 +135,7 @@ describe("App Version", () => {
|
|||
cy.waitForAutoSave();
|
||||
|
||||
cy.apiCreateGDS(
|
||||
`${Cypress.env("server_host")}/api/v2/data_sources`,
|
||||
`${Cypress.env("server_host")}/api/data-sources`,
|
||||
data.datasourceName,
|
||||
"restapi",
|
||||
[{ key: "url", value: "https://jsonplaceholder.typicode.com/users" }]
|
||||
|
|
|
|||
|
|
@ -183,7 +183,7 @@ describe("Datasource Manager", () => {
|
|||
data.dsName1
|
||||
);
|
||||
|
||||
cy.intercept("GET", "/api/v2/data_sources").as("datasource");
|
||||
// cy.intercept("GET", "/api/v2/data_sources").as("datasource");
|
||||
fillConnectionForm(
|
||||
{
|
||||
Host: Cypress.env("pg_host"),
|
||||
|
|
@ -194,7 +194,8 @@ describe("Datasource Manager", () => {
|
|||
},
|
||||
".form-switch"
|
||||
);
|
||||
cy.wait("@datasource");
|
||||
// cy.wait("@datasource");
|
||||
cy.wait(1000);
|
||||
|
||||
cy.apiCreateApp(data.appName);
|
||||
cy.openApp();
|
||||
|
|
@ -223,7 +224,7 @@ describe("Datasource Manager", () => {
|
|||
cy.get('[data-cy="databases-datasource-button"]').should("be.visible");
|
||||
|
||||
cy.apiCreateGDS(
|
||||
`${Cypress.env("server_host")}/api/v2/data_sources`,
|
||||
`${Cypress.env("server_host")}/api/data-sources`,
|
||||
`cypress-${data.dsName2}-postgresql`,
|
||||
"postgresql",
|
||||
[
|
||||
|
|
|
|||
|
|
@ -3,7 +3,12 @@ import { commonText } from "Texts/common";
|
|||
import { onboardingSelectors } from "Selectors/onboarding";
|
||||
import { onboardingText } from "Texts/onboarding";
|
||||
import { logout } from "Support/utils/common";
|
||||
import { bannerElementsVerification } from "Support/utils/onboarding";
|
||||
import {
|
||||
bannerElementsVerification,
|
||||
onboardingStepOne,
|
||||
onboardingStepTwo,
|
||||
onboardingStepThree,
|
||||
} from "Support/utils/onboarding";
|
||||
|
||||
describe("Self host onboarding", () => {
|
||||
const envVar = Cypress.env("environment");
|
||||
|
|
@ -24,9 +29,11 @@ describe("Self host onboarding", () => {
|
|||
"have.text",
|
||||
"Let's set up your admin account and workspace to get started!"
|
||||
);
|
||||
cy.get('[data-cy="set-up-tooljet-button"]')
|
||||
.verifyVisibleElement("have.text", "Set up ToolJet")
|
||||
.click();
|
||||
cy.get('[data-cy="set-up-tooljet-button"]').verifyVisibleElement(
|
||||
"have.text",
|
||||
"Set up ToolJet"
|
||||
);
|
||||
cy.get('[data-cy="set-up-tooljet-button"]').click();
|
||||
}
|
||||
|
||||
const commonElements = [
|
||||
|
|
@ -72,7 +79,8 @@ describe("Self host onboarding", () => {
|
|||
if (envVar === "Community") {
|
||||
cy.get(commonSelectors.signUpTermsHelperText).should(($el) => {
|
||||
expect($el.contents().first().text().trim()).to.eq(
|
||||
commonText.selfHostSignUpTermsHelperText
|
||||
// commonText.selfHostSignUpTermsHelperText
|
||||
"By signing up you are agreeing to the"
|
||||
);
|
||||
});
|
||||
} else if (envVar === "Enterprise") {
|
||||
|
|
@ -110,68 +118,16 @@ describe("Self host onboarding", () => {
|
|||
|
||||
if (envVar === "Enterprise") {
|
||||
bannerElementsVerification();
|
||||
|
||||
const companyPageTexts = [
|
||||
{
|
||||
selector: onboardingSelectors.tellUsAbit,
|
||||
text: "Tell us a bit about yourself",
|
||||
},
|
||||
{
|
||||
selector: onboardingSelectors.pageDescription,
|
||||
text: "This information will help us improve ToolJet",
|
||||
},
|
||||
{
|
||||
selector: '[data-cy="onboarding-company-name-label"]',
|
||||
text: "Company name *",
|
||||
},
|
||||
{
|
||||
selector: '[data-cy="onboarding-build-purpose-label"]',
|
||||
text: "What would you like to build on ToolJet? *",
|
||||
},
|
||||
];
|
||||
|
||||
companyPageTexts.forEach((item) => {
|
||||
cy.get(item.selector).should("be.visible").and("have.text", item.text);
|
||||
});
|
||||
|
||||
cy.get(onboardingSelectors.companyNameInput).should("be.visible");
|
||||
cy.get(onboardingSelectors.buildPurposeInput).should("be.visible");
|
||||
cy.get(onboardingSelectors.onboardingSubmitButton).verifyVisibleElement(
|
||||
"have.attr",
|
||||
"disabled"
|
||||
);
|
||||
|
||||
cy.get(onboardingSelectors.companyNameInput).type("Tooljet");
|
||||
cy.get(onboardingSelectors.onboardingSubmitButton).should(
|
||||
"have.attr",
|
||||
"disabled"
|
||||
);
|
||||
cy.get(onboardingSelectors.buildPurposeInput).type("Exploring");
|
||||
cy.get(onboardingSelectors.onboardingSubmitButton).verifyVisibleElement(
|
||||
"have.text",
|
||||
"Continue"
|
||||
);
|
||||
cy.get(onboardingSelectors.onboardingSubmitButton)
|
||||
.should("be.enabled")
|
||||
.click();
|
||||
onboardingStepOne();
|
||||
}
|
||||
|
||||
bannerElementsVerification();
|
||||
cy.get(commonSelectors.setUpworkspaceCheckPoint)
|
||||
.should("be.visible")
|
||||
.and("have.text", "Set up your workspace!");
|
||||
onboardingStepTwo();
|
||||
|
||||
cy.get(onboardingSelectors.pageDescription).verifyVisibleElement(
|
||||
"have.text",
|
||||
"Set up workspaces to manage users, applications & resources across various teams"
|
||||
);
|
||||
cy.get(commonSelectors.workspaceNameInputLabel)
|
||||
.should("be.visible")
|
||||
.and("have.text", commonText.workspaceNameInputLabel);
|
||||
cy.clearAndType(commonSelectors.workspaceNameInputField, "My workspace");
|
||||
cy.get(commonSelectors.OnbordingContinue)
|
||||
.verifyVisibleElement("have.text", "Continue")
|
||||
.click();
|
||||
// if (envVar === "Enterprise") {
|
||||
// bannerElementsVerification();
|
||||
// onboardingStepTwo();
|
||||
// }
|
||||
|
||||
if (envVar === "Enterprise") {
|
||||
bannerElementsVerification();
|
||||
|
|
@ -317,25 +273,15 @@ describe("Self host onboarding", () => {
|
|||
cy.get(onboardingSelectors.declineButton).click();
|
||||
|
||||
bannerElementsVerification();
|
||||
cy.get(
|
||||
`[data-cy="we've-created-a-sample-application-for-you!-header"]`
|
||||
).verifyVisibleElement(
|
||||
"have.text",
|
||||
"We've created a sample application for you!"
|
||||
);
|
||||
cy.get(onboardingSelectors.pageDescription).verifyVisibleElement(
|
||||
"have.text",
|
||||
"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!"
|
||||
);
|
||||
|
||||
cy.get(onboardingSelectors.onboardingSubmitButton)
|
||||
.verifyVisibleElement("have.text", "Continue")
|
||||
.click();
|
||||
onboardingStepThree();
|
||||
}
|
||||
|
||||
cy.get(commonSelectors.skipbutton).click();
|
||||
cy.get(commonSelectors.backLogo).click();
|
||||
cy.get(commonSelectors.backtoapps).click();
|
||||
cy.backToApps();
|
||||
|
||||
if (envVar === "Enterprise") {
|
||||
cy.get(".btn-close").click();
|
||||
}
|
||||
|
||||
if (envVar === "Enterprise") {
|
||||
cy.get(".btn-close").click();
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ describe("Login functionality", () => {
|
|||
let user;
|
||||
const invalidEmail = fake.email;
|
||||
const invalidPassword = fake.password;
|
||||
const envVar = Cypress.env("environment");
|
||||
|
||||
beforeEach(() => {
|
||||
cy.fixture("credentials/login.json").then((login) => {
|
||||
|
|
@ -49,6 +50,9 @@ describe("Login functionality", () => {
|
|||
|
||||
it("Should be able to login with valid credentials", () => {
|
||||
cy.appUILogin(user.email, user.password);
|
||||
if (envVar === "Enterprise") {
|
||||
cy.get(".btn-close").click();
|
||||
}
|
||||
cy.get(commonSelectors.settingsIcon).click();
|
||||
cy.get(dashboardSelector.logoutLink);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ describe("User signup", () => {
|
|||
cy.wait(500);
|
||||
verifyConfirmEmailPage(data.email);
|
||||
|
||||
cy.task("updateId", {
|
||||
cy.task("dbConnection", {
|
||||
dbconfig: Cypress.env("app_db"),
|
||||
sql: `select invitation_token from users where email='${data.email}';`,
|
||||
}).then((resp) => {
|
||||
|
|
@ -67,9 +67,8 @@ describe("User signup", () => {
|
|||
data.workspaceName = fake.companyName;
|
||||
|
||||
cy.visit("/");
|
||||
cy.wait(8000);
|
||||
cy.get(onboardingSelectors.createAnAccountLink).click();
|
||||
cy.wait(6000);
|
||||
cy.wait(2000);
|
||||
cy.get(onboardingSelectors.nameInput).clear();
|
||||
cy.get(onboardingSelectors.nameInput).type(data.fullName);
|
||||
cy.clearAndType(onboardingSelectors.signupEmailInput, data.email);
|
||||
|
|
@ -77,14 +76,17 @@ describe("User signup", () => {
|
|||
onboardingSelectors.loginPasswordInput,
|
||||
commonText.password
|
||||
);
|
||||
cy.intercept("POST", "/api/onboarding/signup").as("signup");
|
||||
cy.get(commonSelectors.signUpButton).click();
|
||||
cy.wait(8000);
|
||||
cy.get(commonSelectors.resendEmailButton).click();
|
||||
cy.task("updateId", {
|
||||
|
||||
cy.wait("@signup")
|
||||
cy.get('[data-cy="check-your-mail-header"]').should("be.visible");
|
||||
cy.task("dbConnection", {
|
||||
dbconfig: Cypress.env("app_db"),
|
||||
sql: `select invitation_token from users where email='${data.email}';`,
|
||||
}).then((resp) => {
|
||||
invitationLink = `/invitations/${resp.rows[0].invitation_token}`;
|
||||
cy.visit(invitationLink);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -11,15 +11,8 @@ import {
|
|||
inviteUserWithUserRole,
|
||||
fetchAndVisitInviteLink,
|
||||
} from "Support/utils/manageUsers";
|
||||
import { addNewUser, visitWorkspaceInvitation, addNewUsertoworkspace } from "Support/utils/onboarding";
|
||||
import { commonText } from "Texts/common";
|
||||
import { setSignupStatus } from "Support/utils/manageSSO";
|
||||
import { ssoSelector } from "Selectors/manageSSO";
|
||||
import {
|
||||
SignUpPageElements,
|
||||
signUpLink,
|
||||
verifyOnboardingQuestions,
|
||||
} from "Support/utils/onboarding";
|
||||
import { visitWorkspaceInvitation, addNewUser } from "Support/utils/onboarding";
|
||||
|
||||
import {
|
||||
navigateToManageUsers,
|
||||
|
|
@ -38,11 +31,16 @@ let invitationToken,
|
|||
url = "";
|
||||
|
||||
const data = {};
|
||||
const envVar = Cypress.env("environment");
|
||||
|
||||
describe("user invite flow cases", () => {
|
||||
beforeEach(() => {
|
||||
cy.defaultWorkspaceLogin();
|
||||
if (envVar === "Enterprise") {
|
||||
cy.get(".btn-close").click();
|
||||
}
|
||||
});
|
||||
|
||||
it("Should verify the Manage users page", () => {
|
||||
data.firstName = fake.firstName;
|
||||
data.email = fake.email.toLowerCase().replaceAll("[^A-Za-z]", "");
|
||||
|
|
@ -202,7 +200,7 @@ describe("user invite flow cases", () => {
|
|||
});
|
||||
});
|
||||
|
||||
it("Should verify the user onboarding with groups", () => {
|
||||
it.skip("Should verify the user onboarding with groups", () => {
|
||||
data.firstName = fake.firstName;
|
||||
data.email = fake.email.toLowerCase().replaceAll("[^A-Za-z]", "");
|
||||
data.groupName1 = fake.firstName.replaceAll("[^A-Za-z]", "");
|
||||
|
|
@ -264,6 +262,8 @@ describe("user invite flow cases", () => {
|
|||
cy.wait(1000);
|
||||
|
||||
cy.defaultWorkspaceLogin();
|
||||
cy.get(commonSelectors.homePageLogo, { timeout: 10000 }).should("be.visible");
|
||||
|
||||
navigateToManageGroups();
|
||||
cy.get(groupsSelector.groupLink(data.groupName1)).click();
|
||||
cy.get(groupsSelector.usersLink).click();
|
||||
|
|
@ -350,10 +350,19 @@ describe("user invite flow cases", () => {
|
|||
"have.text",
|
||||
data.email
|
||||
);
|
||||
cy.get('[data-cy="modal-body"]>').verifyVisibleElement(
|
||||
"have.text",
|
||||
"Updating the user's details will change their role from end-user to admin. Are you sure you want to continue?"
|
||||
);
|
||||
|
||||
if (envVar === "Enterprise") {
|
||||
cy.get('[data-cy="modal-body"]>').verifyVisibleElement(
|
||||
"have.text",
|
||||
"Changing user default group from end-user to admin will affect the count of users covered by your plan.Are you sure you want to continue?"
|
||||
);
|
||||
} else {
|
||||
cy.get('[data-cy="modal-body"]>').verifyVisibleElement(
|
||||
"have.text",
|
||||
"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?"
|
||||
);
|
||||
}
|
||||
|
||||
cy.get('.modal-footer > [data-cy="cancel-button"]').verifyVisibleElement(
|
||||
"have.text",
|
||||
"Cancel"
|
||||
|
|
@ -427,153 +436,4 @@ describe("user invite flow cases", () => {
|
|||
"Builder"
|
||||
);
|
||||
});
|
||||
|
||||
it("Should verify exisiting user invite flow", () => {
|
||||
data.firstName = fake.firstName;
|
||||
data.email = fake.email.toLowerCase().replaceAll("[^A-Za-z]", "");
|
||||
const workspaceName = data.firstName.toLowerCase();
|
||||
|
||||
addNewUser(data.firstName, data.email);
|
||||
logout();
|
||||
|
||||
cy.defaultWorkspaceLogin();
|
||||
cy.apiCreateWorkspace(workspaceName, workspaceName);
|
||||
cy.visit(workspaceName);
|
||||
|
||||
navigateToManageUsers();
|
||||
fillUserInviteForm(data.firstName, data.email);
|
||||
cy.get(usersSelector.buttonInviteUsers).click();
|
||||
cy.wait(2000);
|
||||
visitWorkspaceInvitation(data.email, workspaceName);
|
||||
cy.wait(3000);
|
||||
cy.clearAndType(onboardingSelectors.loginEmailInput, data.email);
|
||||
cy.clearAndType(onboardingSelectors.loginPasswordInput, "password");
|
||||
cy.get(onboardingSelectors.signInButton).click();
|
||||
cy.get(usersSelector.acceptInvite).click();
|
||||
cy.verifyToastMessage(commonSelectors.toastMessage, usersText.inviteToast);
|
||||
logout();
|
||||
|
||||
cy.defaultWorkspaceLogin();
|
||||
navigateToManageUsers();
|
||||
searchUser(data.email);
|
||||
cy.contains("td", data.email)
|
||||
.parent()
|
||||
.within(() => {
|
||||
cy.get("td small").should("have.text", usersText.activeStatus);
|
||||
});
|
||||
});
|
||||
|
||||
it("should verify the user signup after invited in a workspace", () => {
|
||||
data.firstName = fake.firstName;
|
||||
data.email = fake.email.toLowerCase().replaceAll("[^A-Za-z]", "");
|
||||
data.signUpName = fake.firstName;
|
||||
data.workspaceName = fake.companyName;
|
||||
|
||||
setSignupStatus(true);
|
||||
navigateToManageUsers();
|
||||
fillUserInviteForm(data.firstName, data.email);
|
||||
cy.get(usersSelector.buttonInviteUsers).click();
|
||||
cy.apiLogout();
|
||||
|
||||
cy.visit("/");
|
||||
cy.get(commonSelectors.createAnAccountLink).click();
|
||||
SignUpPageElements();
|
||||
cy.wait(3000);
|
||||
cy.clearAndType(onboardingSelectors.nameInput, data.signUpName);
|
||||
cy.clearAndType(onboardingSelectors.signupEmailInput, data.email);
|
||||
cy.clearAndType(
|
||||
onboardingSelectors.loginPasswordInput,
|
||||
commonText.password
|
||||
);
|
||||
cy.get(commonSelectors.signUpButton).click();
|
||||
cy.wait(1000);
|
||||
signUpLink(data.email);
|
||||
cy.wait(1000);
|
||||
visitWorkspaceInvitation(data.email, "My workspace");
|
||||
cy.clearAndType(onboardingSelectors.signupEmailInput, data.email);
|
||||
cy.clearAndType(onboardingSelectors.loginPasswordInput, usersText.password);
|
||||
cy.get(onboardingSelectors.signInButton).click();
|
||||
cy.wait(3000);
|
||||
cy.get(commonSelectors.invitedUserName).verifyVisibleElement(
|
||||
"have.text",
|
||||
data.signUpName
|
||||
);
|
||||
cy.get(commonSelectors.acceptInviteButton).click();
|
||||
});
|
||||
|
||||
it("should verify the user signup with same creds after invited in a workspace", () => {
|
||||
data.firstName = fake.firstName;
|
||||
data.email = fake.email.toLowerCase().replaceAll("[^A-Za-z]", "");
|
||||
data.signUpName = fake.firstName;
|
||||
data.workspaceName = fake.companyName;
|
||||
|
||||
setSignupStatus(true);
|
||||
navigateToManageUsers();
|
||||
fillUserInviteForm(data.firstName, data.email);
|
||||
cy.get(usersSelector.buttonInviteUsers).click();
|
||||
logout();
|
||||
|
||||
cy.get(commonSelectors.createAnAccountLink).click();
|
||||
SignUpPageElements();
|
||||
cy.wait(5000);
|
||||
|
||||
cy.clearAndType(onboardingSelectors.nameInput, data.signUpName);
|
||||
cy.clearAndType(onboardingSelectors.signupEmailInput, data.email);
|
||||
cy.clearAndType(
|
||||
onboardingSelectors.loginPasswordInput,
|
||||
commonText.password
|
||||
);
|
||||
cy.get(commonSelectors.signUpButton).click();
|
||||
cy.verifyToastMessage(
|
||||
commonSelectors.toastMessage,
|
||||
"The user is already registered. Please check your inbox for the activation link"
|
||||
);
|
||||
});
|
||||
|
||||
it("should verify exisiting user workspace signup from instance using form", () => {
|
||||
data.firstName = fake.firstName;
|
||||
data.email = fake.email.toLowerCase().replaceAll("[^A-Za-z]", "");
|
||||
data.signUpName = fake.firstName;
|
||||
data.workspaceName = fake.firstName.toLowerCase();
|
||||
|
||||
setSignupStatus(true);
|
||||
navigateToManageUsers();
|
||||
addNewUser(data.firstName, data.email);
|
||||
logout();
|
||||
cy.wait(3000);
|
||||
cy.get(commonSelectors.createAnAccountLink).click();
|
||||
cy.wait(1000);
|
||||
cy.clearAndType(onboardingSelectors.nameInput, data.firstName);
|
||||
cy.clearAndType(onboardingSelectors.signupEmailInput, data.email);
|
||||
cy.clearAndType(
|
||||
onboardingSelectors.loginPasswordInput,
|
||||
commonText.password
|
||||
);
|
||||
cy.get(commonSelectors.signUpButton).click();
|
||||
cy.verifyToastMessage(
|
||||
commonSelectors.toastMessage,
|
||||
"User already exists in the workspace."
|
||||
);
|
||||
cy.apiLogin();
|
||||
cy.apiCreateWorkspace(data.workspaceName, data.workspaceName);
|
||||
cy.visit(`${data.workspaceName}`);
|
||||
cy.wait(3000);
|
||||
setSignupStatus(true, data.workspaceName);
|
||||
logout();
|
||||
|
||||
cy.get(commonSelectors.createAnAccountLink).click();
|
||||
cy.wait(3000);
|
||||
cy.clearAndType(onboardingSelectors.nameInput, data.firstName);
|
||||
cy.clearAndType(onboardingSelectors.signupEmailInput, data.email);
|
||||
cy.clearAndType(
|
||||
onboardingSelectors.loginPasswordInput,
|
||||
commonText.password
|
||||
);
|
||||
cy.get(commonSelectors.signUpButton).click();
|
||||
|
||||
cy.defaultWorkspaceLogin();
|
||||
visitWorkspaceInvitation(data.email, data.workspaceName);
|
||||
cy.verifyToastMessage(commonSelectors.toastMessage, usersText.inviteToast);
|
||||
logout();
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ describe("Password reset functionality", () => {
|
|||
});
|
||||
|
||||
// Get and visit reset password link
|
||||
cy.task("updateId", {
|
||||
cy.task("dbConnection", {
|
||||
dbconfig: Cypress.env("app_db"),
|
||||
sql: `select forgot_password_token from users where email='${data.email}';`,
|
||||
}).then((resp) => {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,195 @@
|
|||
import { commonSelectors } from "Selectors/common";
|
||||
import { fake } from "Fixtures/fake";
|
||||
import { usersText } from "Texts/manageUsers";
|
||||
import { usersSelector } from "Selectors/manageUsers";
|
||||
import { fillUserInviteForm } from "Support/utils/manageUsers";
|
||||
import { commonText } from "Texts/common";
|
||||
import { setSignupStatus } from "Support/utils/manageSSO";
|
||||
import {
|
||||
SignUpPageElements,
|
||||
signUpLink,
|
||||
verifyOnboardingQuestions,
|
||||
visitWorkspaceInvitation,
|
||||
addNewUser,
|
||||
enableInstanceSignUp,
|
||||
} from "Support/utils/onboarding";
|
||||
|
||||
import {
|
||||
navigateToManageUsers,
|
||||
logout,
|
||||
searchUser,
|
||||
} from "Support/utils/common";
|
||||
|
||||
import { onboardingSelectors } from "Selectors/onboarding";
|
||||
|
||||
const data = {};
|
||||
const envVar = Cypress.env("environment");
|
||||
|
||||
describe("inviteflow edge cases", () => {
|
||||
beforeEach(() => {
|
||||
cy.defaultWorkspaceLogin();
|
||||
if (envVar === "Enterprise") {
|
||||
cy.get(".btn-close").click();
|
||||
}
|
||||
});
|
||||
|
||||
it("Should verify exisiting user invite flow", () => {
|
||||
data.firstName = fake.firstName;
|
||||
data.email = fake.email.toLowerCase().replaceAll("[^A-Za-z]", "");
|
||||
const workspaceName = data.firstName.toLowerCase();
|
||||
|
||||
addNewUser(data.firstName, data.email);
|
||||
logout();
|
||||
|
||||
cy.defaultWorkspaceLogin();
|
||||
cy.apiCreateWorkspace(workspaceName, workspaceName);
|
||||
cy.visit(workspaceName);
|
||||
|
||||
navigateToManageUsers();
|
||||
fillUserInviteForm(data.firstName, data.email);
|
||||
cy.get(usersSelector.buttonInviteUsers).click();
|
||||
cy.wait(2000);
|
||||
visitWorkspaceInvitation(data.email, workspaceName);
|
||||
cy.wait(3000);
|
||||
cy.clearAndType(onboardingSelectors.loginEmailInput, data.email);
|
||||
cy.clearAndType(onboardingSelectors.loginPasswordInput, "password");
|
||||
cy.get(onboardingSelectors.signInButton).click();
|
||||
cy.get(usersSelector.acceptInvite).click();
|
||||
cy.verifyToastMessage(commonSelectors.toastMessage, usersText.inviteToast);
|
||||
logout();
|
||||
|
||||
cy.defaultWorkspaceLogin();
|
||||
navigateToManageUsers();
|
||||
searchUser(data.email);
|
||||
cy.contains("td", data.email)
|
||||
.parent()
|
||||
.within(() => {
|
||||
cy.get("td small").should("have.text", usersText.activeStatus);
|
||||
});
|
||||
});
|
||||
|
||||
it("should verify the user signup after invited in a workspace", () => {
|
||||
data.firstName = fake.firstName;
|
||||
data.email = fake.email.toLowerCase().replaceAll("[^A-Za-z]", "");
|
||||
data.signUpName = fake.firstName;
|
||||
data.workspaceName = fake.companyName;
|
||||
|
||||
enableInstanceSignUp();
|
||||
setSignupStatus(true);
|
||||
navigateToManageUsers();
|
||||
fillUserInviteForm(data.firstName, data.email);
|
||||
cy.get(usersSelector.buttonInviteUsers).click();
|
||||
cy.apiLogout();
|
||||
|
||||
cy.visit("/");
|
||||
cy.get(commonSelectors.createAnAccountLink).click();
|
||||
SignUpPageElements();
|
||||
cy.wait(3000);
|
||||
cy.clearAndType(onboardingSelectors.nameInput, data.signUpName);
|
||||
cy.clearAndType(onboardingSelectors.signupEmailInput, data.email);
|
||||
cy.clearAndType(
|
||||
onboardingSelectors.loginPasswordInput,
|
||||
commonText.password
|
||||
);
|
||||
cy.get(commonSelectors.signUpButton).click();
|
||||
cy.wait(1000);
|
||||
signUpLink(data.email);
|
||||
if (envVar === "Enterprise") {
|
||||
verifyOnboardingQuestions(data.workspaceName);
|
||||
cy.wait(1000);
|
||||
cy.get(commonSelectors.skipbutton).click();
|
||||
cy.backToApps();
|
||||
}
|
||||
cy.wait(1000);
|
||||
visitWorkspaceInvitation(data.email, "My workspace");
|
||||
cy.clearAndType(onboardingSelectors.signupEmailInput, data.email);
|
||||
cy.clearAndType(onboardingSelectors.loginPasswordInput, usersText.password);
|
||||
cy.get(onboardingSelectors.signInButton).click();
|
||||
cy.wait(3000);
|
||||
cy.get(commonSelectors.invitedUserName).verifyVisibleElement(
|
||||
"have.text",
|
||||
data.signUpName
|
||||
);
|
||||
cy.get(commonSelectors.acceptInviteButton).click();
|
||||
cy.get(commonSelectors.workspaceName).verifyVisibleElement(
|
||||
"have.text",
|
||||
"My workspace"
|
||||
);
|
||||
});
|
||||
|
||||
it("should verify the user signup with same creds after invited in a workspace", () => {
|
||||
data.firstName = fake.firstName;
|
||||
data.email = fake.email.toLowerCase().replaceAll("[^A-Za-z]", "");
|
||||
data.signUpName = fake.firstName;
|
||||
data.workspaceName = fake.companyName;
|
||||
|
||||
setSignupStatus(true);
|
||||
navigateToManageUsers();
|
||||
fillUserInviteForm(data.firstName, data.email);
|
||||
cy.get(usersSelector.buttonInviteUsers).click();
|
||||
logout();
|
||||
|
||||
cy.get(commonSelectors.createAnAccountLink).click();
|
||||
SignUpPageElements();
|
||||
cy.wait(5000);
|
||||
|
||||
cy.clearAndType(onboardingSelectors.nameInput, data.signUpName);
|
||||
cy.clearAndType(onboardingSelectors.signupEmailInput, data.email);
|
||||
cy.clearAndType(
|
||||
onboardingSelectors.loginPasswordInput,
|
||||
commonText.password
|
||||
);
|
||||
cy.get(commonSelectors.signUpButton).click();
|
||||
cy.verifyToastMessage(
|
||||
commonSelectors.toastMessage,
|
||||
"The user is already registered. Please check your inbox for the activation link"
|
||||
);
|
||||
});
|
||||
|
||||
it("should verify exisiting user workspace signup from instance using form", () => {
|
||||
data.firstName = fake.firstName;
|
||||
data.email = fake.email.toLowerCase().replaceAll("[^A-Za-z]", "");
|
||||
data.signUpName = fake.firstName;
|
||||
data.workspaceName = fake.firstName.toLowerCase();
|
||||
|
||||
setSignupStatus(true);
|
||||
navigateToManageUsers();
|
||||
addNewUser(data.firstName, data.email);
|
||||
logout();
|
||||
cy.wait(3000);
|
||||
cy.get(commonSelectors.createAnAccountLink).click();
|
||||
cy.wait(1000);
|
||||
cy.clearAndType(onboardingSelectors.nameInput, data.firstName);
|
||||
cy.clearAndType(onboardingSelectors.signupEmailInput, data.email);
|
||||
cy.clearAndType(
|
||||
onboardingSelectors.loginPasswordInput,
|
||||
commonText.password
|
||||
);
|
||||
cy.get(commonSelectors.signUpButton).click();
|
||||
cy.verifyToastMessage(
|
||||
commonSelectors.toastMessage,
|
||||
"User already exists in the workspace."
|
||||
);
|
||||
cy.apiLogin();
|
||||
cy.apiCreateWorkspace(data.workspaceName, data.workspaceName);
|
||||
cy.visit(`${data.workspaceName}`);
|
||||
cy.wait(3000);
|
||||
setSignupStatus(true, data.workspaceName);
|
||||
logout();
|
||||
|
||||
cy.get(commonSelectors.createAnAccountLink).click();
|
||||
cy.wait(3000);
|
||||
cy.clearAndType(onboardingSelectors.nameInput, data.firstName);
|
||||
cy.clearAndType(onboardingSelectors.signupEmailInput, data.email);
|
||||
cy.clearAndType(
|
||||
onboardingSelectors.loginPasswordInput,
|
||||
commonText.password
|
||||
);
|
||||
cy.get(commonSelectors.signUpButton).click();
|
||||
|
||||
cy.defaultWorkspaceLogin();
|
||||
visitWorkspaceInvitation(data.email, data.workspaceName);
|
||||
cy.verifyToastMessage(commonSelectors.toastMessage, usersText.inviteToast);
|
||||
logout();
|
||||
});
|
||||
});
|
||||
|
|
@ -262,8 +262,8 @@ describe("App creation", () => {
|
|||
|
||||
cy.get(importSelectors.dropDownMenu).click();
|
||||
cy.get(commonSelectors.chooseFromTemplateButton).click();
|
||||
cy.clearAndType('[data-cy="search-input-field"]', "Admin portal");
|
||||
cy.get('[data-cy="admin-portal-list-item"]').click();
|
||||
cy.clearAndType('[data-cy="search-input-field"]', "Admin panel");
|
||||
cy.get('[data-cy="admin-panel-tooljet-db-list-item"]').click();
|
||||
cy.get('[data-cy="create-application-from-template-button"]').click()
|
||||
|
||||
cy.wait(1000);
|
||||
|
|
@ -277,7 +277,7 @@ describe("App creation", () => {
|
|||
);
|
||||
cy.get(commonSelectors.appNameInput).verifyVisibleElement(
|
||||
"have.value",
|
||||
"Admin portal"
|
||||
"Admin Panel (ToolJet Database)"
|
||||
);
|
||||
cy.get(commonSelectors.appNameInfoLabel).verifyVisibleElement(
|
||||
"have.text",
|
||||
|
|
|
|||
|
|
@ -49,11 +49,11 @@ describe("dashboard", () => {
|
|||
});
|
||||
|
||||
it("should verify the elements on empty dashboard", () => {
|
||||
cy.intercept("GET", "/api/apps?page=1&folder=&searchKey=", {
|
||||
cy.intercept("GET", "/api/apps?page=1&folder=&searchKey=&type=front-end", {
|
||||
fixture: "intercept/emptyDashboard.json",
|
||||
}).as("emptyDashboard");
|
||||
|
||||
cy.intercept("GET", "/api/folders?searchKey=", {
|
||||
cy.intercept("GET", "/api/folder-apps?searchKey=&type=front-end", {
|
||||
body: { folders: [] },
|
||||
}).as("folders");
|
||||
|
||||
|
|
@ -87,7 +87,7 @@ describe("dashboard", () => {
|
|||
cy.get(commonSelectors.createNewFolderButton).should("be.visible");
|
||||
cy.get(commonSelectors.allApplicationLink).verifyVisibleElement(
|
||||
"have.text",
|
||||
commonText.allApplicationLink
|
||||
commonText.allApplicationsLink
|
||||
);
|
||||
|
||||
cy.get(commonSelectors.notificationsIcon).should("be.visible").click();
|
||||
|
|
@ -312,6 +312,7 @@ describe("dashboard", () => {
|
|||
|
||||
cy.get(commonSelectors.appCard(data.cloneAppName)).should("be.visible");
|
||||
|
||||
cy.wait(3000)
|
||||
viewAppCardOptions(data.cloneAppName);
|
||||
cy.get(commonSelectors.appCardOptions(commonText.exportAppOption)).click();
|
||||
cy.get(commonSelectors.exportAllButton).click();
|
||||
|
|
@ -519,7 +520,7 @@ describe("dashboard", () => {
|
|||
|
||||
it("should verify the elements on empty dashboard for end user", () => {
|
||||
cy.defaultWorkspaceLogin();
|
||||
cy.intercept("GET", "/api/apps?page=1&folder=&searchKey=", {
|
||||
cy.intercept("GET", "/api/apps?page=1&folder=&searchKey=&type=front-end", {
|
||||
fixture: "intercept/emptyDashboard.json",
|
||||
}).as("emptyDashboard")
|
||||
roleBasedOnboarding(data.firstName, data.email, "end-user");
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ import {
|
|||
exportAppModalSelectors,
|
||||
importSelectors,
|
||||
} from "Selectors/exportImport";
|
||||
import { dashboardText } from "../../../../../../constants/texts/dashboard";
|
||||
|
||||
describe("Manage Groups", () => {
|
||||
let data = {};
|
||||
|
|
@ -114,9 +115,9 @@ describe("Manage Groups", () => {
|
|||
cy.get(commonSelectors.cloneAppButton).click();
|
||||
cy.verifyToastMessage(
|
||||
commonSelectors.toastMessage,
|
||||
commonText.cloneAppErrorToast
|
||||
dashboardText.appClonedToast
|
||||
);
|
||||
cy.get(commonSelectors.cancelButton).click();
|
||||
// cy.get(commonSelectors.cancelButton).click();
|
||||
cy.apiLogout();
|
||||
|
||||
cy.apiLogin();
|
||||
|
|
|
|||
|
|
@ -202,7 +202,6 @@ describe("Manage Groups", () => {
|
|||
testDuplicateGroup();
|
||||
createNewGroup();
|
||||
|
||||
// Verify permissions section
|
||||
cy.get(groupsSelector.permissionsLink).click();
|
||||
verifyPermissionSection();
|
||||
|
||||
|
|
@ -220,8 +219,8 @@ describe("Manage Groups", () => {
|
|||
cy.get(`[data-cy="${groupName.toLowerCase()}-text"]`).click();
|
||||
cy.get(`${groupsSelector.addEditPermissionModalTitle}:eq(2)`)
|
||||
.verifyVisibleElement("have.text", groupsText.editPermissionModalTitle);
|
||||
verifyModalFields(true, groupName);
|
||||
cy.get(groupsSelector.editPermissionRadio).check();
|
||||
verifyModalFields(true, groupName);
|
||||
cy.get(groupsSelector.confimButton).click();
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -466,7 +466,7 @@ describe("Manage Groups", () => {
|
|||
cy.wait(500);
|
||||
|
||||
cy.apiCreateGDS(
|
||||
`${Cypress.env('server_host')}/api/v2/data_sources`,
|
||||
`${Cypress.env('server_host')}/api/data-sources`,
|
||||
`cypress-${data.dsName}-qc-postgresql`,
|
||||
"postgresql",
|
||||
[
|
||||
|
|
|
|||
|
|
@ -111,24 +111,21 @@ export const onboardUserFromAppLink = (
|
|||
WHERE u.email = '${email}' AND o.name = '${workspaceName}';
|
||||
`;
|
||||
|
||||
return cy
|
||||
.task("updateId", { dbconfig: dbConfig, sql: query })
|
||||
.then((resp) => {
|
||||
if (!resp.rows || resp.rows.length === 0) {
|
||||
throw new Error(
|
||||
`No records found for email: ${email} and workspace: ${workspaceName}`
|
||||
);
|
||||
}
|
||||
cy.task("dbConnection", { dbconfig: dbConfig, sql: query }).then((resp) => {
|
||||
if (!resp.rows || resp.rows.length === 0) {
|
||||
throw new Error(
|
||||
`No records found for email: ${email} and workspace: ${workspaceName}`
|
||||
);
|
||||
}
|
||||
|
||||
const { invitation_token, workspace_id, organization_token } =
|
||||
resp.rows[0];
|
||||
const token = isNonExistingUser ? organization_token : invitation_token;
|
||||
const url = isNonExistingUser
|
||||
? `${Cypress.config("baseUrl")}/invitations/${invitation_token}/workspaces/${organization_token}?oid=${workspace_id}&redirectTo=%2Fapplications%2F${slug}`
|
||||
: `${Cypress.config("baseUrl")}/organization-invitations/${token}?oid=${workspace_id}&redirectTo=%2Fapplications%2F${slug}`;
|
||||
const { invitation_token, workspace_id, organization_token } = resp.rows[0];
|
||||
const token = isNonExistingUser ? organization_token : invitation_token;
|
||||
const url = isNonExistingUser
|
||||
? `${Cypress.config("baseUrl")}/invitations/${invitation_token}/workspaces/${organization_token}?oid=${workspace_id}&redirectTo=%2Fapplications%2F${slug}`
|
||||
: `${Cypress.config("baseUrl")}/organization-invitations/${token}?oid=${workspace_id}&redirectTo=%2Fapplications%2F${slug}`;
|
||||
|
||||
cy.visit(url);
|
||||
});
|
||||
cy.visit(url);
|
||||
});
|
||||
};
|
||||
|
||||
export const resolveHost = () => {
|
||||
|
|
@ -138,9 +135,8 @@ export const resolveHost = () => {
|
|||
"http://localhost:8082": "http://localhost:8082",
|
||||
"http://localhost:3000/apps": "http://localhost:3000/apps",
|
||||
"http://localhost:4001": "http://localhost:3000",
|
||||
"http://localhost:4001/apps": "http://localhost:3000/apps"
|
||||
"http://localhost:4001/apps": "http://localhost:3000/apps",
|
||||
};
|
||||
|
||||
return urlMapping[baseUrl];
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ export const navigateToAppEditor = (appName) => {
|
|||
.find(commonSelectors.editButton)
|
||||
.click({ force: true });
|
||||
if (Cypress.env("environment") === "Community") {
|
||||
cy.intercept("GET", "/api/v2/data_sources").as("appDs");
|
||||
cy.intercept("GET", "/api/data-sources").as("appDs");
|
||||
cy.wait("@appDs", { timeout: 15000 });
|
||||
cy.skipEditorPopover();
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ export const addQueryN = (queryName, query, dbName) => {
|
|||
cy.clearAndType('[data-cy="gds-querymanager-search-bar"]', `${dbName}`);
|
||||
}
|
||||
});
|
||||
cy.intercept("POST", "/api/data_queries").as("createQuery");
|
||||
cy.intercept("POST", "/api/data-queries/**").as("createQuery");
|
||||
|
||||
cy.get(`[data-cy="${dbName}-add-query-card"] > .text-truncate`).click();
|
||||
cy.get('[data-cy="query-rename-input"]').clear().type(queryName);
|
||||
|
|
@ -96,7 +96,7 @@ export const addQueryN = (queryName, query, dbName) => {
|
|||
export const addQuery = (queryName, query, dbName) => {
|
||||
cy.get('[data-cy="show-ds-popover-button"]').click();
|
||||
cy.get(".css-4e90k9").type(`${dbName}`);
|
||||
cy.intercept("POST", "/api/data_queries").as(
|
||||
cy.intercept("POST", "/api/data-queries/**").as(
|
||||
"createQuery"
|
||||
);
|
||||
cy.contains(`[id*="react-select-"]`, dbName).click();
|
||||
|
|
@ -132,7 +132,7 @@ export const addQueryAndOpenEditor = (queryName, query, dbName, appName) => {
|
|||
cy.get('[data-cy="show-ds-popover-button"]').click();
|
||||
cy.get(".css-4e90k9").type(`${dbName}`);
|
||||
cy.get(".css-4e90k9").type(`${dbName}`);
|
||||
cy.intercept("POST", "/api/data_queries").as("createQuery");
|
||||
cy.intercept("POST", "/api/data-queries").as("createQuery");
|
||||
cy.contains(`[id*="react-select-"]`, dbName).click();
|
||||
|
||||
cy.get('[data-cy="query-rename-input"]').clear().type(queryName);
|
||||
|
|
@ -177,13 +177,13 @@ export const selectDatasource = (datasourceName) => {
|
|||
|
||||
export const createDataQuery = (appName, url, key, value) => {
|
||||
let appId, versionId;
|
||||
cy.task("updateId", {
|
||||
cy.task("dbConnection", {
|
||||
dbconfig: Cypress.env("app_db"),
|
||||
sql: `select id from apps where name='${appName}';`,
|
||||
}).then((resp) => {
|
||||
appId = resp.rows[0].id;
|
||||
|
||||
cy.task("updateId", {
|
||||
cy.task("dbConnection", {
|
||||
dbconfig: Cypress.env("app_db"),
|
||||
sql: `select id from app_versions where app_id='${appId}';`,
|
||||
}).then((resp) => {
|
||||
|
|
@ -197,7 +197,7 @@ export const createDataQuery = (appName, url, key, value) => {
|
|||
|
||||
cy.request({
|
||||
method: "POST",
|
||||
url: `${Cypress.env("server_host")}/api/data_queries`,
|
||||
url: `${Cypress.env("server_host")}/api/data-queries`,
|
||||
headers: headers,
|
||||
body: {
|
||||
app_id: appId,
|
||||
|
|
@ -235,7 +235,7 @@ export const createRestAPIQuery = (queryName, dsName, key = '', value = '', url
|
|||
cy.log(Cypress.env("appId"));
|
||||
cy.request({
|
||||
method: "GET",
|
||||
url: `${Cypress.env("server_host")}/api/v2/apps/${Cypress.env("appId")}`,
|
||||
url: `${Cypress.env("server_host")}/api/apps/${Cypress.env("appId")}`,
|
||||
headers: headers,
|
||||
}).then((response) => {
|
||||
const editingVersionId = response.body.editing_version.id;
|
||||
|
|
@ -265,7 +265,7 @@ export const createRestAPIQuery = (queryName, dsName, key = '', value = '', url
|
|||
|
||||
cy.request({
|
||||
method: "POST",
|
||||
url: `${Cypress.env("server_host")}/api/data_queries`,
|
||||
url: `${Cypress.env("server_host")}/api/data-queries/data-sources/${data_source_id}/versions/${editingVersionId}`,
|
||||
headers: headers,
|
||||
body: requestBody,
|
||||
}).then((response) => {
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import { navigateToManageGroups } from "Support/utils/common";
|
|||
import { cyParamName } from "Selectors/common";
|
||||
import { fake } from "Fixtures/fake";
|
||||
import { onboardingSelectors } from "Selectors/onboarding";
|
||||
import { fetchAndVisitInviteLink } from "Support/utils/onboarding";
|
||||
import { fetchAndVisitInviteLink } from "Support/utils/manageUsers";
|
||||
import { usersSelector } from "Selectors/manageUsers";
|
||||
import { fillUserInviteForm } from "Support/utils/manageUsers";
|
||||
import { navigateToManageUsers, logout } from "Support/utils/common";
|
||||
|
|
@ -335,7 +335,7 @@ export const manageGroupsElements = () => {
|
|||
);
|
||||
|
||||
cy.verifyElement(groupsSelector.confimButton, groupsText.updateButtonText);
|
||||
cy.get(groupsSelector.confimButton).should("be.enabled");
|
||||
cy.get(groupsSelector.confimButton).should("be.disabled");
|
||||
cy.verifyElement(groupsSelector.cancelButton, groupsText.cancelButton);
|
||||
cy.get(groupsSelector.cancelButton).click();
|
||||
|
||||
|
|
@ -542,7 +542,7 @@ export const manageGroupsElements = () => {
|
|||
);
|
||||
|
||||
cy.verifyElement(groupsSelector.confimButton, groupsText.updateButtonText);
|
||||
cy.get(groupsSelector.confimButton).should("be.enabled");
|
||||
cy.get(groupsSelector.confimButton).should("be.disabled");
|
||||
cy.verifyElement(groupsSelector.cancelButton, groupsText.cancelButton);
|
||||
cy.get(groupsSelector.cancelButton).click();
|
||||
//Add Modal
|
||||
|
|
@ -680,7 +680,7 @@ export const createGroupAddAppAndUserToGroup = (groupName, email) => {
|
|||
expect(response.status).to.equal(201);
|
||||
});
|
||||
|
||||
cy.task("updateId", {
|
||||
cy.task("dbConnection", {
|
||||
dbconfig: Cypress.env("app_db"),
|
||||
sql: `select id from users where email='${email}';`,
|
||||
}).then((resp) => {
|
||||
|
|
@ -864,7 +864,7 @@ export const createGroupsAndAddUserInGroup = (groupName, email) => {
|
|||
export const inviteUserBasedOnRole = (firstName, email, role = "end-user") => {
|
||||
fillUserInviteForm(firstName, email);
|
||||
|
||||
cy.get(".css-1dyz3mf").type(`${role}{enter}`);
|
||||
cy.get(".css-1mlj61j").type(`${role}{enter}`);
|
||||
cy.get(usersSelector.buttonInviteUsers).click();
|
||||
cy.wait(500);
|
||||
|
||||
|
|
|
|||
|
|
@ -317,12 +317,12 @@ export const invitePageElements = () => {
|
|||
.and("equal", "https://www.tooljet.com/privacy");
|
||||
};
|
||||
|
||||
export const updateId = () => {
|
||||
cy.task("updateId", {
|
||||
export const dbConnection = () => {
|
||||
cy.task("dbConnection", {
|
||||
dbconfig: Cypress.config("db"),
|
||||
sql: "update sso_configs set id='5edf41b2-ff2b-4932-9e2a-08aef4a303cc' where sso='google';",
|
||||
});
|
||||
cy.task("updateId", {
|
||||
cy.task("dbConnection", {
|
||||
dbconfig: Cypress.config("db"),
|
||||
sql: "update sso_configs set id='9628dee2-6fa9-4aca-9c98-ef950601c83e' where sso='git';",
|
||||
});
|
||||
|
|
@ -331,18 +331,18 @@ export const updateId = () => {
|
|||
export const setSSOStatus = (workspaceName, ssoType, enabled) => {
|
||||
let workspaceId;
|
||||
|
||||
cy.task("updateId", {
|
||||
cy.task("dbConnection", {
|
||||
dbconfig: Cypress.env("app_db"),
|
||||
sql: `SELECT id FROM organizations WHERE name = '${workspaceName}'`,
|
||||
}).then((resp) => {
|
||||
workspaceId = resp.rows[0].id;
|
||||
|
||||
cy.task("updateId", {
|
||||
cy.task("dbConnection", {
|
||||
dbconfig: Cypress.env("app_db"),
|
||||
sql: `SELECT * FROM sso_configs WHERE organization_id = '${workspaceId}' AND sso = '${ssoType}'`,
|
||||
}).then((ssoConfigResp) => {
|
||||
if (ssoConfigResp.rows.length > 0) {
|
||||
cy.task("updateId", {
|
||||
cy.task("dbConnection", {
|
||||
dbconfig: Cypress.env("app_db"),
|
||||
sql: `UPDATE sso_configs SET enabled = ${enabled ? "true" : "false"
|
||||
} WHERE organization_id = '${workspaceId}' AND sso = '${ssoType}'`,
|
||||
|
|
@ -372,7 +372,7 @@ export const defaultSSO = (enable) => {
|
|||
};
|
||||
|
||||
export const setSignupStatus = (enable, workspaceName = 'My workspace') => {
|
||||
cy.task("updateId", {
|
||||
cy.task("dbConnection", {
|
||||
dbconfig: Cypress.env("app_db"),
|
||||
sql: `SELECT id FROM organizations WHERE name = '${workspaceName}'`,
|
||||
}).then((resp) => {
|
||||
|
|
@ -381,7 +381,7 @@ export const setSignupStatus = (enable, workspaceName = 'My workspace') => {
|
|||
cy.getCookie("tj_auth_token").then((cookie) => {
|
||||
cy.request({
|
||||
method: "PATCH",
|
||||
url: `${Cypress.env("server_host")}/api/organizations`,
|
||||
url: `${Cypress.env("server_host")}/api/login-configs/organization-general`,
|
||||
headers: {
|
||||
"Tj-Workspace-Id": workspaceId,
|
||||
Cookie: `tj_auth_token=${cookie.value}`,
|
||||
|
|
@ -396,13 +396,13 @@ export const setSignupStatus = (enable, workspaceName = 'My workspace') => {
|
|||
|
||||
export const deleteOrganisationSSO = (workspaceName, services) => {
|
||||
let workspaceId;
|
||||
cy.task("updateId", {
|
||||
cy.task("dbConnection", {
|
||||
dbconfig: Cypress.env("app_db"),
|
||||
sql: `select id from organizations where name='${workspaceName}';`,
|
||||
}).then((resp) => {
|
||||
workspaceId = resp.rows[0].id;
|
||||
|
||||
cy.task("updateId", {
|
||||
cy.task("dbConnection", {
|
||||
dbconfig: Cypress.env("app_db"),
|
||||
sql: `DELETE FROM sso_configs WHERE organization_id = '${workspaceId}' AND sso IN (${services
|
||||
.map((service) => `'${service}'`)
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import { ssoText } from "Texts/manageSSO";
|
|||
import * as common from "Support/utils/common";
|
||||
import { commonText } from "Texts/common";
|
||||
import { onboardingSelectors } from "Selectors/onboarding";
|
||||
const envVar = Cypress.env("environment");
|
||||
|
||||
export const manageUsersElements = () => {
|
||||
cy.get(commonSelectors.breadcrumbTitle).should(($el) => {
|
||||
|
|
@ -114,10 +115,17 @@ export const manageUsersElements = () => {
|
|||
);
|
||||
cy.get(usersSelector.buttonUploadCsvFile).click();
|
||||
|
||||
cy.get(usersSelector.helperTextBulkUpload).verifyVisibleElement(
|
||||
"have.text",
|
||||
usersText.helperTextBulkUpload
|
||||
);
|
||||
if (envVar === "Enterprise") {
|
||||
cy.get(usersSelector.helperTextBulkUpload).verifyVisibleElement(
|
||||
"have.text",
|
||||
"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. "
|
||||
);
|
||||
} else {
|
||||
cy.get(usersSelector.helperTextBulkUpload).verifyVisibleElement(
|
||||
"have.text",
|
||||
usersText.helperTextBulkUpload
|
||||
);
|
||||
}
|
||||
cy.get(usersSelector.buttonDownloadTemplate).verifyVisibleElement(
|
||||
"have.text",
|
||||
usersText.buttonDownloadTemplate
|
||||
|
|
@ -320,44 +328,46 @@ export const inviteUserWithUserGroups = (
|
|||
};
|
||||
|
||||
export const fetchAndVisitInviteLink = (email) => {
|
||||
let invitationToken,
|
||||
organizationToken,
|
||||
workspaceId,
|
||||
userId,
|
||||
url = "";
|
||||
let invitationToken, organizationToken, workspaceId, userId;
|
||||
|
||||
cy.task("updateId", {
|
||||
cy.task("dbConnection", {
|
||||
dbconfig: Cypress.env("app_db"),
|
||||
sql: `select invitation_token from users where email='${email}';`,
|
||||
}).then((resp) => {
|
||||
invitationToken = resp.rows[0].invitation_token;
|
||||
})
|
||||
.then((resp) => {
|
||||
invitationToken = resp.rows[0]?.invitation_token;
|
||||
|
||||
cy.task("updateId", {
|
||||
dbconfig: Cypress.env("app_db"),
|
||||
sql: "select id from organizations where name='My workspace';",
|
||||
}).then((resp) => {
|
||||
workspaceId = resp.rows[0].id;
|
||||
cy.task("dbConnection", {
|
||||
dbconfig: Cypress.env("app_db"),
|
||||
sql: "select id from organizations where name='My workspace';",
|
||||
});
|
||||
})
|
||||
.then((resp) => {
|
||||
workspaceId = resp.rows[0]?.id;
|
||||
|
||||
cy.task("updateId", {
|
||||
cy.task("dbConnection", {
|
||||
dbconfig: Cypress.env("app_db"),
|
||||
sql: `select id from users where email='${email}';`,
|
||||
}).then((resp) => {
|
||||
userId = resp.rows[0].id;
|
||||
|
||||
cy.task("updateId", {
|
||||
dbconfig: Cypress.env("app_db"),
|
||||
sql: `select invitation_token from organization_users where user_id='${userId}';`,
|
||||
}).then((resp) => {
|
||||
organizationToken = resp.rows[1].invitation_token;
|
||||
|
||||
url = `/invitations/${invitationToken}/workspaces/${organizationToken}?oid=${workspaceId}`;
|
||||
cy.apiLogout();
|
||||
cy.wait(1000);
|
||||
cy.visit(url);
|
||||
});
|
||||
});
|
||||
})
|
||||
.then((resp) => {
|
||||
userId = resp.rows[0]?.id;
|
||||
|
||||
cy.task("dbConnection", {
|
||||
dbconfig: Cypress.env("app_db"),
|
||||
sql: `select invitation_token from organization_users where user_id='${userId}';`,
|
||||
});
|
||||
})
|
||||
.then((resp) => {
|
||||
organizationToken =
|
||||
resp.rows?.[1]?.invitation_token || resp.rows?.[0]?.invitation_token;
|
||||
|
||||
const url = `/invitations/${invitationToken}/workspaces/${organizationToken}?oid=${workspaceId}`;
|
||||
|
||||
cy.apiLogout();
|
||||
cy.wait(1000);
|
||||
cy.visit(url);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
export const inviteUserWithUserRole = (firstName, email, role) => {
|
||||
|
|
@ -389,4 +399,5 @@ export const inviteUserWithUserRole = (firstName, email, role) => {
|
|||
cy.get(commonSelectors.signUpButton).click();
|
||||
cy.wait(2000);
|
||||
cy.get(commonSelectors.acceptInviteButton).click();
|
||||
cy.get(commonSelectors.homePageLogo, { timeout: 10000 }).should("be.visible");
|
||||
};
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ export const connectMongo = () => {
|
|||
selectAndAddDataSource(mongoDbText.mongoDb);
|
||||
|
||||
cy.clearAndType(
|
||||
'[data-cy="data-source-name-input-filed"]',
|
||||
'[data-cy="data-source-name-input-field"]',
|
||||
mongoDbText.cypressMongoDb
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { commonSelectors } from "../../constants/selectors/common";
|
|||
|
||||
export const searchPage = (pageName) => {
|
||||
cy.get('[title="Search"]').click();
|
||||
cy.get('[data-cy="search-input-filed"]').type(pageName);
|
||||
cy.get('[data-cy="search-input-field"]').type(pageName);
|
||||
};
|
||||
|
||||
export const clearSearch = () => {
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import { navigateToManageUsers, logout } from "Support/utils/common";
|
|||
import { ssoSelector } from "Selectors/manageSSO";
|
||||
import { ssoText } from "Texts/manageSSO";
|
||||
import { onboardingSelectors } from "Selectors/onboarding";
|
||||
import { fetchAndVisitInviteLink } from "Support/utils/manageUsers";
|
||||
|
||||
export const verifyConfirmEmailPage = (email) => {
|
||||
cy.get(commonSelectors.pageLogo).should("be.visible");
|
||||
|
|
@ -39,72 +40,11 @@ export const verifyConfirmEmailPage = (email) => {
|
|||
);
|
||||
};
|
||||
|
||||
export const verifyOnboardingQuestions = (fullName, workspaceName) => {
|
||||
cy.wait(5000);
|
||||
cy.get(commonSelectors.pageLogo).should("be.visible");
|
||||
cy.get(commonSelectors.userAccountNameAvatar).should("be.visible");
|
||||
cy.get(commonSelectors.createAccountCheckMark).should("be.visible");
|
||||
cy.get(commonSelectors.createAccountCheckPoint).verifyVisibleElement(
|
||||
"have.text",
|
||||
commonText.createAccountCheckPoint
|
||||
);
|
||||
cy.get(commonSelectors.verifyEmailCheckMark).should("be.visible");
|
||||
cy.get(commonSelectors.verifyEmailCheckPoint).verifyVisibleElement(
|
||||
"have.text",
|
||||
commonText.verifyEmailCheckPoint
|
||||
);
|
||||
cy.get(commonSelectors.setUpworkspaceCheckPoint).verifyVisibleElement(
|
||||
"have.text",
|
||||
commonText.setUpworkspaceCheckPoint
|
||||
);
|
||||
|
||||
cy.get(commonSelectors.onboardingPorgressBubble).should("be.visible");
|
||||
cy.get(commonSelectors.onboardingPageHeader).verifyVisibleElement(
|
||||
"have.text",
|
||||
commonText.companyPageHeader(fullName)
|
||||
);
|
||||
cy.get(commonSelectors.onboardingPageSubHeader).verifyVisibleElement(
|
||||
"have.text",
|
||||
commonText.onboardingPageSubHeader
|
||||
);
|
||||
cy.get(commonSelectors.companyNameInputField).should("be.visible");
|
||||
cy.get(commonSelectors.continueButton).verifyVisibleElement(
|
||||
"have.text",
|
||||
commonText.continueButton
|
||||
);
|
||||
cy.get(commonSelectors.continueButton).should("be.disabled");
|
||||
cy.clearAndType(commonSelectors.companyNameInputField, workspaceName);
|
||||
cy.get(commonSelectors.continueButton).should("be.enabled").click();
|
||||
|
||||
cy.get(commonSelectors.backArrow).should("be.visible");
|
||||
cy.get(commonSelectors.backArrowText).verifyVisibleElement(
|
||||
"have.text",
|
||||
commonText.backArrowText
|
||||
);
|
||||
cy.get(commonSelectors.onboardingPageHeader).verifyVisibleElement(
|
||||
"have.text",
|
||||
commonText.userRolePageHeader
|
||||
);
|
||||
verifyandModifyUserRole();
|
||||
|
||||
cy.get(commonSelectors.backArrow).should("be.visible");
|
||||
cy.get(commonSelectors.onboardingPageHeader).verifyVisibleElement(
|
||||
"have.text",
|
||||
commonText.sizeOftheCompanyHeader
|
||||
);
|
||||
verifyandModifySizeOftheCompany();
|
||||
|
||||
cy.get(commonSelectors.backArrow).should("be.visible");
|
||||
cy.get(commonSelectors.onboardingPageHeader).verifyVisibleElement(
|
||||
"have.text",
|
||||
"Enter your phone number"
|
||||
);
|
||||
|
||||
cy.get(".form-control").should("be.visible");
|
||||
cy.get(".tj-onboarding-phone-input-wrapper")
|
||||
.find("input")
|
||||
.type("919876543210");
|
||||
cy.get(commonSelectors.continueButton).click();
|
||||
export const verifyOnboardingQuestions = (workspaceName) => {
|
||||
bannerElementsVerification();
|
||||
onboardingStepOne();
|
||||
onboardingStepTwo(workspaceName);
|
||||
onboardingStepThree();
|
||||
};
|
||||
|
||||
export const verifyInvalidInvitationLink = () => {
|
||||
|
|
@ -128,13 +68,15 @@ export const verifyInvalidInvitationLink = () => {
|
|||
|
||||
export const userSignUp = (fullName, email, workspaceName = "test") => {
|
||||
let invitationLink;
|
||||
cy.intercept("GET", "/api/organizations/public-configs").as("publicConfig");
|
||||
cy.intercept("GET", "/api/login-configs/public").as("publicConfig");
|
||||
cy.visit("/");
|
||||
cy.wait("@publicConfig");
|
||||
cy.wait(2000)
|
||||
cy.wait(2000);
|
||||
cy.get(commonSelectors.createAnAccountLink, { timout: 10000 }).click();
|
||||
cy.wait(2000);
|
||||
cy.get(onboardingSelectors.nameInput, { timeout: 1000 }).should("not.be.disabled");
|
||||
cy.get(onboardingSelectors.nameInput, { timeout: 1000 }).should(
|
||||
"not.be.disabled"
|
||||
);
|
||||
cy.get(onboardingSelectors.nameInput).clear();
|
||||
cy.get(onboardingSelectors.nameInput).type(fullName);
|
||||
cy.clearAndType(onboardingSelectors.loginEmailInput, email);
|
||||
|
|
@ -142,7 +84,7 @@ export const userSignUp = (fullName, email, workspaceName = "test") => {
|
|||
cy.get(commonSelectors.signUpButton).click();
|
||||
|
||||
cy.wait(2500);
|
||||
cy.task("updateId", {
|
||||
cy.task("dbConnection", {
|
||||
dbconfig: Cypress.env("app_db"),
|
||||
sql: `select invitation_token from users where email='${email}';`,
|
||||
}).then((resp) => {
|
||||
|
|
@ -151,52 +93,14 @@ export const userSignUp = (fullName, email, workspaceName = "test") => {
|
|||
cy.wait(2500);
|
||||
});
|
||||
if (Cypress.env("environment") !== "Community") {
|
||||
cy.clearAndType('[data-cy="onboarding-workspace-name-input"]', workspaceName);
|
||||
cy.clearAndType(
|
||||
'[data-cy="onboarding-workspace-name-input"]',
|
||||
workspaceName
|
||||
);
|
||||
cy.get('[data-cy="onboarding-submit-button"]').click();
|
||||
}
|
||||
};
|
||||
|
||||
export const fetchAndVisitInviteLink = (email) => {
|
||||
let invitationToken,
|
||||
organizationToken,
|
||||
workspaceId,
|
||||
userId,
|
||||
url = "";
|
||||
|
||||
cy.task("updateId", {
|
||||
dbconfig: Cypress.env("app_db"),
|
||||
sql: `select invitation_token from users where email='${email}';`,
|
||||
}).then((resp) => {
|
||||
invitationToken = resp.rows[0].invitation_token;
|
||||
|
||||
cy.task("updateId", {
|
||||
dbconfig: Cypress.env("app_db"),
|
||||
sql: "select id from organizations where name='My workspace';",
|
||||
}).then((resp) => {
|
||||
workspaceId = resp.rows[0].id;
|
||||
|
||||
cy.task("updateId", {
|
||||
dbconfig: Cypress.env("app_db"),
|
||||
sql: `select id from users where email='${email}';`,
|
||||
}).then((resp) => {
|
||||
userId = resp.rows[0].id;
|
||||
|
||||
cy.task("updateId", {
|
||||
dbconfig: Cypress.env("app_db"),
|
||||
sql: `select invitation_token from organization_users where user_id='${userId}';`,
|
||||
}).then((resp) => {
|
||||
organizationToken = resp.rows[1].invitation_token;
|
||||
url = `/invitations/${invitationToken}/workspaces/${organizationToken}?oid=${workspaceId}`;
|
||||
cy.apiLogout();
|
||||
cy.wait(1000);
|
||||
cy.visit(url);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
export const inviteUser = (firstName, email) => {
|
||||
cy.apiUserInvite(firstName, email);
|
||||
fetchAndVisitInviteLink(email);
|
||||
|
|
@ -227,23 +131,22 @@ export const roleBasedOnboarding = (firstName, email, userRole) => {
|
|||
cy.get(commonSelectors.acceptInviteButton).click();
|
||||
};
|
||||
|
||||
|
||||
export const visitWorkspaceInvitation = (email, workspaceName) => {
|
||||
let workspaceId, userId, url, organizationToken;
|
||||
|
||||
cy.task("updateId", {
|
||||
cy.task("dbConnection", {
|
||||
dbconfig: Cypress.env("app_db"),
|
||||
sql: `select id from organizations where name='${workspaceName}';`,
|
||||
}).then((resp) => {
|
||||
workspaceId = resp.rows[0].id;
|
||||
|
||||
cy.task("updateId", {
|
||||
cy.task("dbConnection", {
|
||||
dbconfig: Cypress.env("app_db"),
|
||||
sql: `select id from users where email='${email}';`,
|
||||
}).then((resp) => {
|
||||
userId = resp.rows[0].id;
|
||||
|
||||
cy.task("updateId", {
|
||||
cy.task("dbConnection", {
|
||||
dbconfig: Cypress.env("app_db"),
|
||||
sql: `select invitation_token from organization_users where organization_id= '${workspaceId}' AND user_id='${userId}';`,
|
||||
}).then((resp) => {
|
||||
|
|
@ -324,13 +227,14 @@ export const SignUpPageElements = () => {
|
|||
|
||||
export const signUpLink = (email) => {
|
||||
let invitationLink;
|
||||
cy.task("updateId", {
|
||||
cy.task("dbConnection", {
|
||||
dbconfig: Cypress.env("app_db"),
|
||||
sql: `select invitation_token from users where email='${email}';`,
|
||||
}).then((resp) => {
|
||||
invitationLink = `/invitations/${resp.rows[0].invitation_token}`;
|
||||
cy.visit(invitationLink);
|
||||
cy.wait(3000);
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
|
|
@ -343,4 +247,94 @@ export const bannerElementsVerification = () => {
|
|||
bannerElements.forEach((element) => {
|
||||
cy.get(element.selector).should("be.visible");
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
export const enableInstanceSignUp = (allow = true) => {
|
||||
const value = allow ? "true" : "false";
|
||||
cy.task("dbConnection", {
|
||||
dbconfig: Cypress.env("app_db"),
|
||||
sql: `UPDATE instance_settings SET value = '${value}' WHERE key = 'ALLOW_PERSONAL_WORKSPACE';
|
||||
UPDATE instance_settings SET value = '${value}' WHERE key = 'ENABLE_SIGNUP';`,
|
||||
});
|
||||
};
|
||||
|
||||
export const onboardingStepOne = () => {
|
||||
const companyPageTexts = [
|
||||
{
|
||||
selector: onboardingSelectors.tellUsAbit,
|
||||
text: "Tell us a bit about yourself",
|
||||
},
|
||||
{
|
||||
selector: onboardingSelectors.pageDescription,
|
||||
text: "This information will help us improve ToolJet",
|
||||
},
|
||||
{
|
||||
selector: '[data-cy="onboarding-company-name-label"]',
|
||||
text: "Company name *",
|
||||
},
|
||||
{
|
||||
selector: '[data-cy="onboarding-build-purpose-label"]',
|
||||
text: "What would you like to build on ToolJet? *",
|
||||
},
|
||||
];
|
||||
|
||||
companyPageTexts.forEach((item) => {
|
||||
cy.get(item.selector).should("be.visible").and("have.text", item.text);
|
||||
});
|
||||
|
||||
cy.get(onboardingSelectors.companyNameInput).should("be.visible");
|
||||
cy.get(onboardingSelectors.buildPurposeInput).should("be.visible");
|
||||
cy.get(onboardingSelectors.onboardingSubmitButton).verifyVisibleElement(
|
||||
"have.attr",
|
||||
"disabled"
|
||||
);
|
||||
|
||||
cy.get(onboardingSelectors.companyNameInput).type("Tooljet");
|
||||
cy.get(onboardingSelectors.onboardingSubmitButton).should(
|
||||
"have.attr",
|
||||
"disabled"
|
||||
);
|
||||
cy.get(onboardingSelectors.buildPurposeInput).type("Exploring");
|
||||
cy.get(onboardingSelectors.onboardingSubmitButton).verifyVisibleElement(
|
||||
"have.text",
|
||||
"Continue"
|
||||
);
|
||||
cy.get(onboardingSelectors.onboardingSubmitButton)
|
||||
.should("be.enabled")
|
||||
.click();
|
||||
};
|
||||
|
||||
export const onboardingStepTwo = (workspaceName = "My workspace") => {
|
||||
cy.get(commonSelectors.setUpworkspaceCheckPoint)
|
||||
.should("be.visible")
|
||||
.and("have.text", "Set up your workspace!");
|
||||
|
||||
cy.get(onboardingSelectors.pageDescription).verifyVisibleElement(
|
||||
"have.text",
|
||||
"Set up workspaces to manage users, applications & resources across various teams"
|
||||
);
|
||||
cy.get(commonSelectors.workspaceNameInputLabel)
|
||||
.should("be.visible")
|
||||
.and("have.text", commonText.workspaceNameInputLabel);
|
||||
cy.clearAndType(commonSelectors.workspaceNameInputField, workspaceName);
|
||||
cy.get(commonSelectors.OnbordingContinue)
|
||||
.verifyVisibleElement("have.text", "Continue")
|
||||
.click();
|
||||
};
|
||||
|
||||
export const onboardingStepThree = () => {
|
||||
cy.get(
|
||||
`[data-cy="we've-created-a-sample-application-for-you!-header"]`
|
||||
).verifyVisibleElement(
|
||||
"have.text",
|
||||
"We've created a sample application for you!"
|
||||
);
|
||||
cy.get(onboardingSelectors.pageDescription).verifyVisibleElement(
|
||||
"have.text",
|
||||
"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!"
|
||||
);
|
||||
|
||||
cy.get(onboardingSelectors.onboardingSubmitButton)
|
||||
.verifyVisibleElement("have.text", "Continue")
|
||||
.click();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -65,10 +65,9 @@ export const selectAndAddDataSource = (
|
|||
).click();
|
||||
});
|
||||
|
||||
cy.wait(1000)
|
||||
cy.get(postgreSqlSelector.buttonSave).should("be.disabled")
|
||||
cy.clearAndType(
|
||||
'[data-cy="data-source-name-input-filed"]',
|
||||
'[data-cy="data-source-name-input-field"]',
|
||||
cyParamName(`cypress-${dataSourceName}-${dataSource}`)
|
||||
);
|
||||
cy.get(postgreSqlSelector.buttonSave).click();
|
||||
|
|
|
|||
|
|
@ -7,10 +7,7 @@ import {
|
|||
confirmVersionModalSelectors,
|
||||
editVersionSelectors,
|
||||
} from "Selectors/version";
|
||||
import {
|
||||
deleteVersionText,
|
||||
releasedVersionText,
|
||||
} from "Texts/version";
|
||||
import { deleteVersionText, releasedVersionText } from "Texts/version";
|
||||
import { verifyComponent } from "Support/utils/basicComponents";
|
||||
|
||||
export const navigateToCreateNewVersionModal = (value) => {
|
||||
|
|
@ -98,9 +95,16 @@ export const deleteVersionAndVerify = (value, toastMessageText) => {
|
|||
.click({ force: true });
|
||||
});
|
||||
|
||||
cy.get(commonSelectors.modalMessage).verifyVisibleElement("have.text", deleteVersionText.deleteModalText(value))
|
||||
cy.get(commonSelectors.modalMessage).verifyVisibleElement(
|
||||
"have.text",
|
||||
deleteVersionText.deleteModalText(value)
|
||||
);
|
||||
cy.get(confirmVersionModalSelectors.yesButton).click();
|
||||
cy.verifyToastMessage(commonSelectors.toastMessage, deleteVersionText.deleteToastMessage(value), false);
|
||||
cy.verifyToastMessage(
|
||||
commonSelectors.toastMessage,
|
||||
deleteVersionText.deleteToastMessage(value),
|
||||
false
|
||||
);
|
||||
};
|
||||
|
||||
export const verifyDuplicateVersion = (newVersion = [], version) => {
|
||||
|
|
@ -111,7 +115,8 @@ export const verifyDuplicateVersion = (newVersion = [], version) => {
|
|||
cy.get(appVersionSelectors.createNewVersionButton).click();
|
||||
cy.verifyToastMessage(
|
||||
commonSelectors.toastMessage,
|
||||
appVersionText.versionNameAlreadyExists
|
||||
// appVersionText.versionNameAlreadyExists
|
||||
"Already exists!"
|
||||
);
|
||||
};
|
||||
|
||||
|
|
@ -139,7 +144,7 @@ export const verifyVersionAfterPreview = (currentVersion) => {
|
|||
.click();
|
||||
cy.url().should("include", "/home");
|
||||
cy.wait(2000);
|
||||
cy.get('[data-cy^="draggable-widget-table"]').should('be.visible')
|
||||
cy.get('[data-cy^="draggable-widget-table"]').should("be.visible");
|
||||
cy.url().should("include", `version=${currentVersion}`);
|
||||
cy.get('[data-cy="viewer-page-logo"]').click();
|
||||
cy.wait(8000);
|
||||
|
|
@ -149,5 +154,5 @@ export const switchVersionAndVerify = (currentVersion, newVersion) => {
|
|||
cy.get(appVersionSelectors.currentVersionField(currentVersion))
|
||||
.should("be.visible")
|
||||
.click();
|
||||
cy.get('.app-version-name').contains(newVersion).click();
|
||||
}
|
||||
cy.get(".app-version-name").contains(newVersion).click();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
# 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_HOST=http://localhost:80
|
||||
TOOLJET_HOST=http://localhost:8082
|
||||
LOCKBOX_MASTER_KEY= # replace_with_lockbox_master_key
|
||||
SECRET_KEY_BASE= # replace_with_secret_key_base
|
||||
|
||||
|
|
|
|||
|
|
@ -62,8 +62,40 @@ FROM debian:11
|
|||
RUN apt-get update -yq \
|
||||
&& apt-get install curl gnupg zip -yq \
|
||||
&& apt-get install -yq build-essential \
|
||||
&& apt -y install redis \
|
||||
&& apt-get clean -y
|
||||
|
||||
# Install required dependencies for downloading and extracting files
|
||||
RUN apt-get update && apt-get install -y \
|
||||
curl tar xz-utils postgresql postgresql-contrib postgresql-client && \
|
||||
apt-get clean && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Install PostgREST from official Docker image
|
||||
COPY --from=postgrest/postgrest:v12.2.0 /bin/postgrest /bin
|
||||
|
||||
RUN apt-get update && apt-get install -y supervisor
|
||||
|
||||
# Create supervisord configuration file
|
||||
RUN echo "[supervisord]\n" \
|
||||
"nodaemon=true\n" \
|
||||
"\n" \
|
||||
"[program:postgrest]\n" \
|
||||
"command=/bin/postgrest \n" \
|
||||
"autostart=true\n" \
|
||||
"autorestart=true\n" \
|
||||
"stdout_logfile=/dev/stdout\n" \
|
||||
"stderr_logfile=/dev/stderr\n" \
|
||||
"stdout_logfile_maxbytes=0\n" \
|
||||
"stderr_logfile_maxbytes=0\n" \
|
||||
"\n" | sed 's/ //' > /etc/supervisor/conf.d/supervisord.conf
|
||||
|
||||
# Create a wrapper for PostgREST to prefix its logs
|
||||
RUN mv /bin/postgrest /bin/postgrest-original && \
|
||||
echo '#!/bin/bash\n\
|
||||
exec /bin/postgrest-original "$@" 2>&1 | sed "s/^/[PostgREST] /"\n\
|
||||
' > /bin/postgrest && \
|
||||
chmod +x /bin/postgrest
|
||||
|
||||
|
||||
RUN curl -O https://nodejs.org/dist/v18.18.2/node-v18.18.2-linux-x64.tar.xz \
|
||||
&& tar -xf node-v18.18.2-linux-x64.tar.xz \
|
||||
|
|
@ -152,6 +184,25 @@ RUN mkdir -p /tmp/.npm/npm-cache/_logs \
|
|||
&& chmod g+s /tmp/.npm/npm-cache/_logs \
|
||||
&& chmod -R g=u /tmp/.npm/npm-cache/_logs
|
||||
|
||||
# Create Redis data, log, and configuration directories
|
||||
RUN mkdir -p /var/lib/redis /var/log/redis /etc/redis \
|
||||
&& chown -R appuser:0 /var/lib/redis /var/log/redis /etc/redis \
|
||||
&& chmod g+s /var/lib/redis /var/log/redis /etc/redis \
|
||||
&& chmod -R g=u /var/lib/redis /var/log/redis /etc/redis
|
||||
|
||||
# Set permissions for PostgREST binary
|
||||
RUN chown appuser:0 /bin/postgrest && chmod u+x /bin/postgrest && chmod g=u /bin/postgrest
|
||||
|
||||
RUN touch /tmp/postgrest.conf \
|
||||
&& chown appuser:0 /tmp/postgrest.conf \
|
||||
&& chmod 640 /tmp/postgrest.conf
|
||||
|
||||
# Create PostgREST data, log, and configuration directories
|
||||
RUN mkdir -p /var/lib/postgrest /var/log/postgrest /etc/postgrest \
|
||||
&& chown -R appuser:0 /var/lib/postgrest /var/log/postgrest /etc/postgrest \
|
||||
&& chmod g+s /var/lib/postgrest /var/log/postgrest /etc/postgrest \
|
||||
&& chmod -R g=u /var/lib/postgrest /var/log/postgrest /etc/postgrest
|
||||
|
||||
ENV HOME=/home/appuser
|
||||
|
||||
# Switch back to appuser
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
<h1 align="center">ToolJet Documentation</h1>
|
||||
</p>
|
||||
|
||||
The directory "ToolJet/docs/" holds the code and markdown source files for the ToolJet documentation website, which is accessible at [docs.tooljet.com](docs.tooljet.com)
|
||||
The directory "ToolJet/docs/" holds the code and markdown source files for the ToolJet documentation website, which is accessible at [docs.tooljet.ai](docs.tooljet.ai)
|
||||
|
||||
## Index
|
||||
- [Feedback](#feedback)
|
||||
|
|
@ -26,7 +26,7 @@ In case you encounter any issues with the ToolJet product, please select the rel
|
|||
To contribute to ToolJet documentation, you need to fork this repository and submit a pull request for the Markdown and/or image changes that you're proposing.
|
||||
|
||||
### Repository organization
|
||||
The content in this directory follows the organization of documentation at https://docs.tooljet.com
|
||||
The content in this directory follows the organization of documentation at https://docs.tooljet.ai
|
||||
|
||||
This directory contains the following folders:
|
||||
|
||||
|
|
@ -41,15 +41,15 @@ This directory contains the following folders:
|
|||
├── versioned_docs
|
||||
│ ├── version-x.x.x # Current/latest version (set it on docusauras.config.js)
|
||||
│ │ ├── Enterprise
|
||||
│ │ │ └── multi-environment.md # https://docs.tooljet.com/docs/Enterprise/multi-environment
|
||||
│ │ └── tooljet-database.md. # https://docs.tooljet.com/docs/tooljet-database
|
||||
│ │ │ └── multi-environment.md # https://docs.tooljet.ai/docs/Enterprise/multi-environment
|
||||
│ │ └── tooljet-database.md. # https://docs.tooljet.ai/docs/tooljet-database
|
||||
│ └── version-2.0.0
|
||||
│ │ ├── Enterprise
|
||||
│ │ │ └── multi-environment.md # https://docs.tooljet.com/docs/2.0.0/Enterprise/multi-environment
|
||||
│ │ │ └── multi-environment.md # https://docs.tooljet.ai/docs/2.0.0/Enterprise/multi-environment
|
||||
│ │ └── tooljet-database.md
|
||||
│ └── version-1.0.0
|
||||
│ ├── Enterprise
|
||||
│ │ └── multi-environment.md # https://docs.tooljet.com/docs/1.0.0/Enterprise/multi-environment
|
||||
│ │ └── multi-environment.md # https://docs.tooljet.ai/docs/1.0.0/Enterprise/multi-environment
|
||||
│ └── tooljet-database.md
|
||||
├── versioned_sidebars # includes sidebar for the specific versions
|
||||
│ ├── version-x.x.x-sidebars.json
|
||||
|
|
|
|||
|
|
@ -1,31 +1,17 @@
|
|||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
CONFIG_FILE="docusaurus.config.js"
|
||||
VERSIONS_FILE="versions.json"
|
||||
|
||||
# Extract lastVersion from docusaurus.config.js using sed
|
||||
LAST_VERSION=$(sed -n "s/.*lastVersion: *'\\([^']*\\)'.*/\\1/p" "$CONFIG_FILE")
|
||||
if [ -z "$LAST_VERSION" ]; then
|
||||
echo "Error: lastVersion not found in $CONFIG_FILE"
|
||||
# Ensure versions.json exists
|
||||
if [ ! -f "$VERSIONS_FILE" ]; then
|
||||
echo "Error: $VERSIONS_FILE not found."
|
||||
exit 1
|
||||
fi
|
||||
echo "Found lastVersion: $LAST_VERSION"
|
||||
|
||||
# Extract all version numbers from the entire file
|
||||
ALL_VERSIONS=$(grep -oE "'[0-9]+\.[0-9]+\.[0-9]+(-[A-Za-z]+)?'" "$CONFIG_FILE" | sed "s/'//g" | sort -u -V -r)
|
||||
if [ -z "$ALL_VERSIONS" ]; then
|
||||
echo "Error: No versions found in $CONFIG_FILE"
|
||||
exit 1
|
||||
fi
|
||||
echo "Found raw versions:"
|
||||
echo "$ALL_VERSIONS"
|
||||
|
||||
# Convert the extracted versions into a JSON array format
|
||||
VERSION_ARRAY=$(echo "$ALL_VERSIONS" | jq -R -s -c 'split("\n")[:-1] + ["'"$LAST_VERSION"'"] | unique')
|
||||
echo "Updating versions.json with: $VERSION_ARRAY"
|
||||
|
||||
# Update versions.json with combined data
|
||||
echo $VERSION_ARRAY | jq . > versions.json
|
||||
# Output existing versions from versions.json for reference
|
||||
echo "Using versions from $VERSIONS_FILE:"
|
||||
jq . "$VERSIONS_FILE"
|
||||
|
||||
# Install dependencies and build the project
|
||||
npm i && npm run build
|
||||
|
|
|
|||
|
|
@ -1,5 +0,0 @@
|
|||
{
|
||||
"label": "Enterprise",
|
||||
"position": 9,
|
||||
"collapsed": true
|
||||
}
|
||||
|
|
@ -1,320 +0,0 @@
|
|||
---
|
||||
id: superadmin
|
||||
title: Super Admin
|
||||
---
|
||||
|
||||
<div className='badge badge--primary heading-badge'>Available on: Paid plans</div>
|
||||
|
||||
A Super Admin is the user who has full access to all the Workspaces, Users, and Groups of an instance. An instance can have more than one Super Admin. A Super Admin has full control over other users' workspaces and can create users, groups, and other super admins.
|
||||
|
||||
The user details entered while setting up ToolJet will have Super Admin privileges.
|
||||
|
||||
<div style={{paddingTop:'24px', paddingBottom:'24px'}}>
|
||||
|
||||
## How Super Admin is Different from Admin
|
||||
|
||||
| <div style={{ width:"100px"}}>Privilege </div>| Admin | Super Admin |
|
||||
| --------- | ----- | ----------- |
|
||||
| Manage Users in their workspace (Invite/Archive/Unarchive) | ✅ | ✅ |
|
||||
| Manage Groups in their workspace (Create Group/Add or Delete Users from groups/ Modify Group Permissions) | ✅ | ✅ |
|
||||
| Manage SSO in their workspace | ✅ | ✅ |
|
||||
| Manage Workspace Variables in their workspace | ✅ | ✅ |
|
||||
| Manage Workspace Constants in their workspace | ✅ | ✅ |
|
||||
| [Manage data sources for the user group in their workspace](/docs/data-sources/overview#user-permissions) | ✅ | ✅ |
|
||||
| [Access any user's personal workspace (create, edit or delete apps)](#access-any-workspace) | ❌ | ✅ |
|
||||
| [Archive Admin or any user of any workspace](#archiveunarchive-users) | ❌ | ✅ |
|
||||
| [Access any user's ToolJet database (create, edit or delete database)](#access-tooljet-db-in-any-workspace) | ❌ | ✅ |
|
||||
| [Manage any workspace's setting (Groups/SSO/Workspace constants)](#manage-workspace-settings-groupsssoworkspace-constants) | ❌ | ✅ |
|
||||
| [Manage all users from all the workspaces in the instance](#manage-all-users-in-the-instance) | ❌ | ✅ |
|
||||
| [Archive/Unarchive any user from all the workspaces in the instance](#archiving-a-user-from-all-the-workspaces-instance-level) | ❌ | ✅ |
|
||||
| [Reset password of any user](#reset-password-of-any-user) | ❌ | ✅ |
|
||||
| [Edit name of any user](#edit-name) | ❌ | ✅ |
|
||||
| [Make any user Super Admin](#make-the-user-super-admin) | ❌ | ✅ |
|
||||
| [Manage all workspaces in the instance(Archive/Unarchive)](#all-workspaces) | ❌ | ✅ |
|
||||
| [Restrict creation of personal workspace of users](#restrict-creation-of-personal-workspace-of-users) | ❌ | ✅ |
|
||||
| [Configure instance level login](#instance-login) | ❌ | ✅ |
|
||||
| [Enable Multiplayer editing](#enable-multiplayer-editing) | ❌ | ✅ |
|
||||
| [Implement White Labelling](#white-labelling) | ❌ | ✅ |
|
||||
|
||||
</div>
|
||||
|
||||
<div style={{paddingTop:'24px', paddingBottom:'24px'}}>
|
||||
|
||||
## Super Admin features
|
||||
|
||||
### Access any workspace
|
||||
|
||||
If a user is a Super Admin, they can switch to any workspace created by any user within the instance using the Workspace Switcher located in the bottom left corner of the screen.
|
||||
|
||||
The dropdown will display all workspaces, including those created by both Super Admins and any other users.
|
||||
|
||||
<div style={{textAlign: 'center'}}>
|
||||
<img style={{ border:'0', marginBottom:'15px', borderRadius:'5px', boxShadow: '0px 1px 3px rgba(0, 0, 0, 0.2)' }} className="screenshot-full" src="/img/enterprise/superadmin/workspaceswitcher.png" alt="Superadmin: settings" />
|
||||
</div>
|
||||
|
||||
### Create, Edit or Delete apps from any user's personal workspace
|
||||
|
||||
Once the Super Admin access the workspace of any other user, they can create, edit or delete app on the workspace.
|
||||
|
||||
This also includes - modifying folders and importing, exporting, or cloning apps to any user's workspace.
|
||||
|
||||
### Archive/Unarchive Users
|
||||
|
||||
Super Admin can not only archive/unarchive users/admins on their workspace but also from the workspaces of any other user.
|
||||
|
||||
If a user is Super Admin, they just need to open the workspace in which they want to archive or unarchive a user. Then go to the **Workspace Settings** from the sidebar -> **Manage Users** -> **Archive/Unarchive** any user/admin
|
||||
|
||||
<div style={{textAlign: 'center'}}>
|
||||
<img style={{ border:'0', marginBottom:'15px', borderRadius:'5px', boxShadow: '0px 1px 3px rgba(0, 0, 0, 0.2)' }} className="screenshot-full" src="/img/enterprise/superadmin/archiveusersa.png" alt="Superadmin: settings" />
|
||||
</div>
|
||||
|
||||
### Access ToolJet DB in any workspace
|
||||
|
||||
Super Admins have access to the database of any user's workspace - just like Super Admins can access any application in any workspace. They have full access to modify or create any table in the ToolJet DB of any workspace.
|
||||
|
||||
### Manage Workspace Settings (Groups/SSO/Workspace constants)
|
||||
|
||||
Super Admins have all the privileges that an Admin of a workspace have, Super Admins can:
|
||||
- **✅ Manage Groups**: Creating/Deleting/Updating a Group in any workspace
|
||||
- **✅ Manage SSO**: Full control over General Settings, Password login and other SSO options
|
||||
- **✅ Workspace Variables**: Adding, updating or deleting workspace variables
|
||||
- **✅ Workspace Constants**: Adding, updating or deleting workspace constants
|
||||
- **✅ Copilot**: Enabling or disabling Copilot
|
||||
- **✅ Custom Styles**: Adding or modifying custom styles
|
||||
|
||||
</div>
|
||||
|
||||
<div style={{paddingTop:'24px', paddingBottom:'24px'}}>
|
||||
|
||||
## Settings
|
||||
|
||||
Only Super Admins can access the Settings. To access the Settings page, click on the **⚙️** button and select **Settings** from the dropdown.
|
||||
|
||||
- **[All Users](#all-users)**
|
||||
- **[All workspaces](#all-workspaces)**
|
||||
- **[Manage instance settings](#manage-instance-settings)**
|
||||
- **[License](#license)**
|
||||
- **[White labelling](#white-labelling)**
|
||||
|
||||
<div style={{textAlign: 'center'}}>
|
||||
<img style={{ border:'0', borderRadius:'5px', boxShadow: '0px 1px 3px rgba(0, 0, 0, 0.2)' }} className="screenshot-full" src="/img/enterprise/superadmin/settings.png" alt="Superadmin: settings" />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div style={{paddingTop:'24px', paddingBottom:'24px'}}>
|
||||
|
||||
## All Users
|
||||
|
||||
### Manage all Users in the Instance
|
||||
|
||||
**All Users** settings can be used to check the list of all the users available on all the workspaces in the instance. Super Admins can also promote/demote any user to/from Super Admin from this page. They can also archive/unarchive any user at an instance level from this setting.
|
||||
|
||||
<div style={{textAlign: 'center'}}>
|
||||
<img style={{ border:'0', marginBottom:'15px', borderRadius:'5px', boxShadow: '0px 1px 3px rgba(0, 0, 0, 0.2)' }} className="screenshot-full" src="/img/enterprise/superadmin/allusers1.png" alt="Superadmin: settings" />
|
||||
</div>
|
||||
|
||||
### Archiving a User from all the Workspaces (Instance Level)
|
||||
|
||||
Super Admins have the authority to deactivate any user at instance level. This will remove the user from all the workspaces in the instance.
|
||||
|
||||
To archive a user, go to the **All Users** settings, click on the kebab menu next to the user that is to be archived and select **Archive** option. Once the user is archived, the status will change from **Active** to **Archived**. The user will not be able to login to any workspace in the instance.
|
||||
|
||||
<div style={{textAlign: 'center'}}>
|
||||
<img style={{ border:'0', borderRadius:'5px', boxShadow: '0px 1px 3px rgba(0, 0, 0, 0.2)' }} className="screenshot-full" src="/img/enterprise/superadmin/archiveinstance.png" alt="Superadmin: settings" />
|
||||
</div>
|
||||
|
||||
<br/>
|
||||
|
||||
**Unarchiving** a user from **All Users** settings will unarchive the user from the instance and not at workspace level.
|
||||
|
||||
**Info**: The user will be unarchived from instance level automatically if a workspace admin unarchives the user from their workspace.
|
||||
|
||||
<div style={{textAlign: 'center'}}>
|
||||
<img style={{ border:'0', marginBottom:'15px', borderRadius:'5px', boxShadow: '0px 1px 3px rgba(0, 0, 0, 0.2)' }} className="screenshot-full" src="/img/enterprise/superadmin/unarchiveinstance.png" alt="Superadmin: settings" />
|
||||
</div>
|
||||
|
||||
### Reset Password of any User
|
||||
|
||||
Super Admins can reset the password of any user from the **All Users** settings. To reset the password, click on the kebab menu next to the user and select **Reset Password** option. A pop-up will appear asking either to auto-generate a password or to enter a new password.
|
||||
|
||||
### Edit User Details
|
||||
|
||||
Super Admins can edit the details of any user from the **All Users** settings. To edit the details, click on the kebab menu next to the user and select **Edit user details** option.
|
||||
|
||||
#### Edit name
|
||||
|
||||
On selecting the **Edit user details** option, a drawer will open from the right. Super Admins can edit the name of the user from this drawer. Once the changes are made, click on the **Update** button.
|
||||
|
||||
#### Make the user Super Admin
|
||||
|
||||
From the **Edit user details** drawer, Super Admins can make any user as Super Admin or remove any Super Admin from the **All Users** settings. To make a user Super Admin, toggle on the **Super Admin** radio button. The user will become Super Admin and the Type column will update from **`Workspace`** to **`Instance`**.
|
||||
|
||||
<div style={{textAlign: 'center'}}>
|
||||
<img style={{ border:'0', marginBottom:'15px', borderRadius:'5px', boxShadow: '0px 1px 3px rgba(0, 0, 0, 0.2)' }} className="screenshot-full" src="/img/enterprise/superadmin/edituserdetailsinstance.png" alt="Superadmin: settings" />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div style={{paddingTop:'24px', paddingBottom:'24px'}}>
|
||||
|
||||
## All Workspaces
|
||||
|
||||
The All Workspaces tab provides a comprehensive view of all workspaces within the ToolJet instance. Super Admins can use this functionality to monitor and manage workspaces collectively, ensuring efficient administration and organization-wide oversight.
|
||||
|
||||
Super Admins have the authority to **archive** or **unarchive** workspaces of any user in the instance as needed. Archiving a workspace essentially sets it to an inactive state, removing it from active use. Conversely, unarchiving reactivates a previously archived workspace, making it accessible once again.
|
||||
|
||||
<div style={{textAlign: 'center'}}>
|
||||
<img style={{ border:'0', borderRadius:'5px', boxShadow: '0px 1px 3px rgba(0, 0, 0, 0.2)' }} className="screenshot-full" src="/img/enterprise/superadmin/workspaces1.png" alt="Superadmin: settings" />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div style={{paddingTop:'24px', paddingBottom:'24px'}}>
|
||||
|
||||
### Current Workspace
|
||||
|
||||
The **Current Workspace** label will be displayed next to the workspace that the Super Admin has currently opened. If the Super Admin archives the current workspace, they will be prompted to switch to another active workspace to ensure continuous accessibility.
|
||||
|
||||
</div>
|
||||
|
||||
<div style={{paddingTop:'24px', paddingBottom:'24px'}}>
|
||||
|
||||
### Open Active Workspaces
|
||||
|
||||
In the list of active workspaces, there is an option to open the workspace directly. This feature helps superadmins to quickly navigate to the workspace on the new tab of the browser and manage the workspace.
|
||||
|
||||
</div>
|
||||
|
||||
<div style={{paddingTop:'24px', paddingBottom:'24px'}}>
|
||||
|
||||
### Archive Workspaces
|
||||
|
||||
The **Archive** button on the right of the workspace name allows Super Admins to archive the workspace. Once archived, the workspace will be moved to the **Archived Workspaces** section.
|
||||
|
||||
**Impact**:
|
||||
- The apps on the archived workspace won't be accessable through the URL
|
||||
- Users will be logged out if they don't have access to any active workspace
|
||||
|
||||
</div>
|
||||
|
||||
<div style={{paddingTop:'24px', paddingBottom:'24px'}}>
|
||||
|
||||
### Archived Workspaces
|
||||
|
||||
The **Archived** section displays a list of all archived workspaces. Super Admins can unarchive any workspace from this section by clicking the **Unarchive** button.
|
||||
|
||||
<div style={{textAlign: 'center'}}>
|
||||
<img style={{ border:'0', borderRadius:'5px', boxShadow: '0px 1px 3px rgba(0, 0, 0, 0.2)' }} className="screenshot-full" src="/img/enterprise/superadmin/workspaces2.png" alt="Superadmin: settings" />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div style={{paddingTop:'24px', paddingBottom:'24px'}}>
|
||||
|
||||
## Manage Instance Settings
|
||||
|
||||
<div style={{textAlign: 'center'}}>
|
||||
<img style={{ border:'0', borderRadius:'5px', boxShadow: '0px 1px 3px rgba(0, 0, 0, 0.2)' }} className="screenshot-full" src="/img/enterprise/superadmin/instanceoptions.png" alt="Superadmin: settings" />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div style={{paddingTop:'24px', paddingBottom:'24px'}}>
|
||||
|
||||
### Restrict Creation of Personal Workspace of Users
|
||||
|
||||
When a user joins a workspace, they are provided with their own personal workspace and option to create new workspaces.
|
||||
|
||||
Super Admins can **control** this behavior from the Manage Settings page, they can **toggle off** the option to **Allow personal workspace**. Now whenever a user joins a workspace they won't be provided a personal workspace nor they will be able to create a new workspace in the instance.
|
||||
|
||||
</div>
|
||||
|
||||
<div style={{paddingTop:'24px', paddingBottom:'24px'}}>
|
||||
|
||||
### Enable Multiplayer Editing
|
||||
|
||||
Super Admins can enable multiplayer editing from the Manage Settings page. Once enabled, users will be able to edit the same app simultaneously resulting in real-time collaboration.
|
||||
|
||||
</div>
|
||||
|
||||
<div style={{paddingTop:'24px', paddingBottom:'24px'}}>
|
||||
|
||||
### Comments
|
||||
|
||||
Super Admins can enable comments from the Manage Settings page. Once enabled, users will be able to collaborate by adding comments anywhere on the canvas.
|
||||
|
||||
</div>
|
||||
|
||||
<div style={{paddingTop:'24px', paddingBottom:'24px'}}>
|
||||
|
||||
## White Labelling
|
||||
This feature allows you to customize the ToolJet instance with your own branding. You can change the logo, favicon, and the name of the instance.
|
||||
|
||||
Check out the [White labelling](/docs/enterprise/white-label/) page for more details.
|
||||
|
||||
</div>
|
||||
|
||||
<div style={{paddingTop:'24px', paddingBottom:'24px'}}>
|
||||
|
||||
## Instance Login
|
||||
|
||||
Instance login configuration at the Settings level allows super admins to set up and manage the default login method for all workspaces within the instance. This ensures a standardized login experience unless individual workspace admins choose to configure a different method for their specific workspace.
|
||||
|
||||
</div>
|
||||
|
||||
<div style={{paddingTop:'24px', paddingBottom:'24px'}}>
|
||||
|
||||
### Access and Permissions
|
||||
|
||||
Only super admins have the authority to configure **Instance login** settings. This ensures centralized control over the default login method across the entire instance.
|
||||
|
||||
</div>
|
||||
|
||||
<div style={{paddingTop:'24px', paddingBottom:'24px'}}>
|
||||
|
||||
### Super Admin URL
|
||||
|
||||
This URL serves as a fail-safe in scenarios where password login is disabled, SSO is not configured, or a paid plan expires. Importantly, this URL exclusively supports password login and is accessible only by the super admin, preventing any unauthorized access.
|
||||
|
||||
The default URL for super admin login is `https://<domain>/login/super-admin`. This URL can be accessed by the super admin to log in to the instance and manage the settings.
|
||||
|
||||
</div>
|
||||
|
||||
<div style={{paddingTop:'24px', paddingBottom:'24px'}}>
|
||||
|
||||
### Enable sign-up
|
||||
|
||||
The "Enable Sign Up" option allows users to sign up without being invited. It is important to note that this feature includes both password login and SSO, providing a seamless onboarding experience for users.
|
||||
|
||||
</div>
|
||||
|
||||
<div style={{paddingTop:'24px', paddingBottom:'24px'}}>
|
||||
|
||||
### Password login
|
||||
|
||||
Super admins can enable or disable password login for the entire instance. This setting ensures that all workspaces within the instance adhere to the same login method, unless individual workspace admins choose to configure a different method for their specific workspace.
|
||||
|
||||
</div>
|
||||
|
||||
<div style={{paddingTop:'24px', paddingBottom:'24px'}}>
|
||||
|
||||
### Enable Workspace Configuration
|
||||
|
||||
Turning off this option restricts workspace admins from configuring the login method for their workspace. This configuration hides the Workspace Login option from the workspace settings tab.
|
||||
|
||||
<div style={{textAlign: 'center'}}>
|
||||
<img style={{ border:'0', borderRadius:'5px', boxShadow: '0px 1px 3px rgba(0, 0, 0, 0.2)' }} className="screenshot-full" src="/img/enterprise/superadmin/instancelogin.png" alt="Superadmin: settings" />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div style={{paddingTop:'24px', paddingBottom:'24px'}}>
|
||||
|
||||
## License
|
||||
|
||||
Manage the instance license via the **Settings** page. Super Admins have the capability to update the instance's license key from this page.
|
||||
|
||||
Check out the [License](/docs/org-management/licensing/self-hosted) page for more details.
|
||||
|
||||
</div>
|
||||
|
|
@ -1,59 +0,0 @@
|
|||
---
|
||||
id: white-label
|
||||
title: White Label
|
||||
---
|
||||
|
||||
<div className='badge badge--primary heading-badge'>Available on: Paid plans</div>
|
||||
|
||||
The White Label feature allows you to completely remove ToolJet's branding from the ToolJet platform, allowing you to replace it with your own customized logo, favicon and page title. This feature grants you full control over the visual identity of your ToolJet-powered application, ensuring a seamless and personalized user experience.
|
||||
|
||||
With this feature, you gain the ability to rebrand the following key elements:
|
||||
|
||||
- **Application Logo**: This includes the logo displayed on the login screen, dashboard, and app-editor.
|
||||
|
||||
<div style={{textAlign: 'center'}}>
|
||||
<img style={{ border:'0', borderRadius:'5px', boxShadow: '0px 1px 3px rgba(0, 0, 0, 0.2)' }} className="screenshot-full" src="/img/enterprise/white-label/whitelabeln1.png" alt="ToolJet - Enterprise - White label" />
|
||||
</div>
|
||||
|
||||
- **Favicon**: The small icon associated with your application. It is displayed in the browser tab.
|
||||
|
||||
- **Page Title**: This is the text displayed in the browser tab.
|
||||
|
||||
Example, we have set a favicon image and page title as `Bon Ton` in the below image.
|
||||
|
||||
<div style={{textAlign: 'center'}}>
|
||||
<img style={{ border:'0', borderRadius:'5px', boxShadow: '0px 1px 3px rgba(0, 0, 0, 0.2)' }} className="screenshot-full" src="/img/enterprise/white-label/title-and-favicon.png" alt="ToolJet - Enterprise - White label" />
|
||||
</div>
|
||||
|
||||
<div style={{paddingTop:'24px', paddingBottom:'24px'}}>
|
||||
|
||||
## Configuration
|
||||
|
||||
To enable white labelling, click on the gear icon on the bottom left of the dashboard and select `Settings`. From the settings page, click on the `White labelling` tab. On the White labelling page, you'll be able to configure the following:
|
||||
|
||||
- **Application Logo**: Add the URL of the image you want to use as your application logo. Preferred dimensions of the logo are: width `130px` and height `26px`.
|
||||
- **Favicon**: Enter the URL of the image you want to use as your application's favicon. Preferred dimensions of the favicon are: width `32px` and height `32px` or `16px` and height `16px`.
|
||||
- **Page Title**: Enter the text you want to display as your application's title. Preferred title length are 50-60 characters.
|
||||
|
||||
<div style={{textAlign: 'center'}}>
|
||||
<img style={{ border:'0', borderRadius:'5px', boxShadow: '0px 1px 3px rgba(0, 0, 0, 0.2)' }} className="screenshot-full" src="/img/enterprise/white-label/settings.png" alt="ToolJet - Enterprise - White label" />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div style={{paddingTop:'24px', paddingBottom:'24px'}}>
|
||||
|
||||
## ToolJet Cloud
|
||||
|
||||
If you are using ToolJet Cloud, click on the gear icon on the bottom left of the dashboard and select `Settings`. From the settings page, click on the `White labelling` tab. On the White labelling page, you'll be able to configure the following:
|
||||
|
||||
- **Application Logo**: Add the URL of the image you want to use as your application logo. Preferred dimensions of the logo are: width `130px` and height `26px`.
|
||||
- **Page Title**: Enter the text you want to display as your application's title. Preferred title length are 50-60 characters.
|
||||
- **Favicon**: Enter the URL of the image you want to use as your application's favicon. Preferred dimensions of the favicon are: width `32px` and height `32px` or `16px` and height `16px`.
|
||||
|
||||
<div style={{textAlign: 'center'}}>
|
||||
<img style={{ border:'0', borderRadius:'5px', boxShadow: '0px 1px 3px rgba(0, 0, 0, 0.2)' }} className="screenshot-full" src="/img/enterprise/white-label/cloud1.png" alt="ToolJet - Enterprise - White label" />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
|
@ -7,7 +7,7 @@ Control component action invokes the component specific actions. Component speci
|
|||
|
||||
You can find the component specific actions for the specific component in their respective documentation. For example, you can find the component specific actions for the **Bounded Box** component in the [Bounded Box](/docs/widgets/bounded-box) documentation.
|
||||
|
||||
<details>
|
||||
<details id="tj-dropdown">
|
||||
<summary>Currently, Component specific actions are supported only by the below listed components.</summary>
|
||||
<div>
|
||||
<ul>
|
||||
|
|
|
|||
131
docs/docs/app-builder/anti-patterns.md
Normal file
131
docs/docs/app-builder/anti-patterns.md
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
---
|
||||
id: anti-patterns
|
||||
title: Anti-Patterns to Avoid
|
||||
---
|
||||
|
||||
When building applications with ToolJet, it's essential to follow best practices to ensure your apps are efficient, maintainable, and provide a smooth user experience. This documentation outlines common anti-patterns to avoid while using ToolJet and offers solutions to optimize your applications.
|
||||
|
||||
---
|
||||
|
||||
## 1. Unmanaged Component Naming
|
||||
|
||||
- **Anti-Pattern**: Using default or non-descriptive names for components.
|
||||
- **Solution**: **Rename all components with meaningful names to make the apps more manageable as they grow.**
|
||||
- **Reason**: Descriptive names improve readability, making it easier for you and others to understand and maintain the app's structure.
|
||||
|
||||
---
|
||||
|
||||
## 2. Exceeding Component Limits
|
||||
|
||||
- **Anti-Pattern**: Having more than 2,500 components in a single app.
|
||||
- **Solution**: **Limit each app to a maximum of 2,500 components.**
|
||||
- **Reason**: Exceeding this number can slow down the app builder and live apps, impacting both development speed and user experience.
|
||||
|
||||
---
|
||||
|
||||
## 3. Client-Side Operations for Large Data Sets
|
||||
|
||||
- **Anti-Pattern**: Handling large data sets with client-side operations on the Table component.
|
||||
- **Solution**: **Implement [server-side operations](/docs/widgets/table/serverside-operations/overview) for handling large data sets.**
|
||||
- **Reason**: Server-side operations reduces the amount of data loaded at once, improving load times and performance.
|
||||
|
||||
---
|
||||
|
||||
## 4. Simultaneous Execution of Multiple JavaScript Queries
|
||||
|
||||
- **Anti-Pattern**: Triggering a large amount of JavaScript queries simultaneously through a single event. For example, using an event to trigger a **Run JavaScript code** query that contains code to execute 15-20 other **Run JavaScript code** queries within the application.
|
||||
- **Solution**: **Limit the number of simultaneous JavaScript queries triggered by a single event.**
|
||||
- **Reason**: Triggering numerous Run JavaScript queries at the same time can significantly degrade browser performance as it each JavaScript query creates **[new execution environment](https://developer.mozilla.org/en-US/docs/Web/API/HTML_DOM_API/Microtask_guide/In_depth#javascript_execution_contexts)** within the browser. JavaScript in browsers runs on a single main thread. When multiple scripts are executed concurrently, they compete for execution time on this thread.
|
||||
|
||||
---
|
||||
|
||||
## 5. Storing Base64 Data in Variables
|
||||
|
||||
- **Anti-Pattern**: Capturing and storing Base64 data directly in variables.
|
||||
- **Solution**: **Store large data, like base64 images, in a database and retrieve it as needed.**
|
||||
- **Reason**: Storing Base64 data in variables can consume significant memory and slow down the app. Retrieving data from a database as needed optimizes performance.
|
||||
|
||||
---
|
||||
|
||||
## 6. Loading All Tabs Simultaneously
|
||||
|
||||
- **Anti-Pattern**: Loading all items in the Tab component at once when there are numerous tabs.
|
||||
- **Solution**: **Enable the “Render only active tabs” option.**
|
||||
- **Reason**: This prevents unnecessary loading of inactive tabs, reducing initial load times and improving performance.
|
||||
|
||||
---
|
||||
|
||||
## 7. Excessive Number of Pages in an App
|
||||
|
||||
- **Anti-Pattern**: Including too many pages within a single app.
|
||||
- **Solution**: **Limit the number of pages per app to maintain optimal performance.**
|
||||
- **Reason**: An excessive number of pages can slow down the app and make it difficult to manage. Organize content efficiently and consider splitting the app if necessary.
|
||||
|
||||
---
|
||||
|
||||
## 8. Using Non-Blocking Commands in JavaScript for Synchronous Operations
|
||||
|
||||
- **Anti-Pattern**: Using non-blocking commands like `Promise.all` and `setTimeout` in the **Run JavaScript code** query when an accurate isLoading state is needed.
|
||||
- **Solution**: **Avoid non-blocking operations in JavaScript Queries if you require an accurate isLoading status. Ensure your code is synchronous within the Run JavaScript code query.**
|
||||
- **Reason**: Non-blocking operations can cause **Run JavaScript code** query to exit before these commands complete, leading to an incorrect isLoading status and potentially confusing users.
|
||||
|
||||
---
|
||||
|
||||
## 9. Triggering Unnecessary Queries on Page Load
|
||||
|
||||
- **Anti-Pattern**: Triggering all queries on page load, regardless of their necessity.
|
||||
- **Solution**: **For multi-page apps, only trigger queries on page load that are needed for the specific page.**
|
||||
- **Reason**: Loading unnecessary data consumes resources and slows down page load times. Optimizing queries enhances performance.
|
||||
|
||||
---
|
||||
|
||||
## 10. Using Actions inside Loop Functions
|
||||
- **Anti-Pattern**: Using actions inside loop functions.
|
||||
|
||||
Example:
|
||||
You have a Table displaying data from `{{page.variables.data}}` and a **Save Changes** button that updates the data. When users edit rows and click **Save Changes**, you might initially implement the update like this:
|
||||
|
||||
```javascript
|
||||
const data = page.variables.data;
|
||||
Object.values(components.table1.dataUpdates).forEach(ele => {
|
||||
data[ele.id] = ele;
|
||||
actions.setPageVariable("data", data);
|
||||
});
|
||||
```
|
||||
|
||||
The setPageVariable action is executed inside the loop for each row update. This causes the table to re-render every time the variable is updated, leading to significant performance degradation, especially when multiple rows or cells are updated simultaneously.
|
||||
|
||||
- **Solution**: **Modify your code to update the page variable once after all changes are processed**:
|
||||
|
||||
```javascript
|
||||
const data = page.variables.data;
|
||||
Object.values(components.table1.dataUpdates).forEach(ele => {
|
||||
data[ele.id] = ele;
|
||||
});
|
||||
actions.setPageVariable("data", data);
|
||||
```
|
||||
|
||||
- **Reason**: By updating the variable after the loop completes, the table re-renders only once. This reduces unnecessary processing and significantly improves performance when handling multiple updates.
|
||||
|
||||
---
|
||||
|
||||
## 11. Direct Mutation of Data
|
||||
|
||||
- **Anti-Pattern**: Directly mutating data structures through JavaScript code, such as using `queries.getEmployees.data = []`.
|
||||
- **Solution**: Always use ToolJet's built in **[actions](/docs/how-to/run-actions-from-runjs/)** to manipulate data.
|
||||
- **Reason**: Direct mutation of data can lead to unexpected bugs and make debugging more complex.
|
||||
|
||||
---
|
||||
|
||||
## 12. Naming Component/Query with Hyphen or Space
|
||||
|
||||
- **Anti-Pattern**: Naming components or queries with hyphens or spaces in between, such as `run-py1` or `my query`.
|
||||
- **Solution**: **Use names without hyphens or spaces**, or reference them using bracket notation (e.g., `{{queries['run-py1'].isLoading}}`).
|
||||
- **Reason**: Hyphens and spaces can cause syntax issues. Using bracket notation or avoiding these characters ensures consistency and prevents errors in query or component references.
|
||||
|
||||
---
|
||||
|
||||
## Conclusion
|
||||
|
||||
Avoiding these anti-patterns when using ToolJet ensures that your applications are efficient, responsive, and maintainable. By following these best practices, you can enhance user experience and simplify app management. Always consider the impact of your development choices on both performance and scalability.
|
||||
|
||||
|
|
@ -3,7 +3,15 @@ id: customstyles
|
|||
title: Custom Styles
|
||||
---
|
||||
|
||||
<div className='badge badge--primary heading-badge'>Available on: Paid plans</div>
|
||||
<div className="badge badge--primary heading-badge">
|
||||
<img
|
||||
src="/img/badge-icons/premium.svg"
|
||||
alt="Icon"
|
||||
width="16"
|
||||
height="16"
|
||||
/>
|
||||
<span>Paid feature</span>
|
||||
</div>
|
||||
|
||||
The Custom Styles feature in ToolJet allows users to apply their own CSS, overriding the default app styles. This enables easy customization of app appearance, and maintains consistent themes across all ToolJet apps. By using standardized styles, users avoid the repetitive task of manually styling components for each new app, enhancing development efficiency and ensuring visual coherence for a seamless user experience
|
||||
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ Debugger consists of two main sections:
|
|||
|
||||
To configure the app's global settings, click on the kebab menu(three vertical dots) on the left of the app name. Global settings include:
|
||||
|
||||
- **Unique app slug**: The unique slug of the application. This slug is used in the URL of the application. By default, the slug is the `app id` of the application. You can change the slug to a custom value. For example, if the slug is `7b56293b-be5a-401f-8806-b71625f8ee0d` you can change it to `<unique-name>` then the new URL of the application will be `https://app.tooljet.com/<workspace-name>/apps/<unique-name>/`
|
||||
- **Unique app slug**: The unique slug of the application. This slug is used in the URL of the application. By default, the slug is the `app id` of the application. You can change the slug to a custom value. For example, if the slug is `7b56293b-be5a-401f-8806-b71625f8ee0d` you can change it to `<unique-name>` then the new URL of the application will be `https://app.tooljet.ai/<workspace-name>/apps/<unique-name>/`
|
||||
- **App link**: The link to the application. This link can be used to share the application with other users of the workspace. If you want to share the application with users outside the workspace, you can make the application public from the **[Share](/docs/app-builder/share)** modal.
|
||||
- **Hide header for launched apps**: Toggle this on to the hide the tooljet's header when the applications are launched
|
||||
- **Maintenance mode**: Toggle this on to put the application in maintenance mode. When in **maintenance mode**, on launching the app, the user will get an error message that **the app is under maintenance**.
|
||||
|
|
|
|||
|
|
@ -15,13 +15,13 @@ Getting started is straightforward – design your interface, connect your data
|
|||
|
||||
Explore these hands-on guides to start building your first app. The step-by-step guides will walk you through the App-Builder's essential features:
|
||||
|
||||
- **[Create UIs Using Pre-Built Components](/docs/beta/app-builder/walkthrough/create-ui)**
|
||||
- **[Create Queries to Interact With Data Sources](/docs/beta/app-builder/walkthrough/create-queries)**
|
||||
- **[Use Custom Code](/docs/beta/app-builder/walkthrough/using-code)**
|
||||
- **[Access and Referring Values Withing The App-Builder](/docs/beta/app-builder/walkthrough/accessing-values)**
|
||||
- **[Create and Managing Variables](/docs/beta/app-builder/walkthrough/variables)**
|
||||
- **[Create UIs Using Pre-Built Components](/docs/app-builder/walkthrough/create-ui)**
|
||||
- **[Create Queries to Interact With Data Sources](/docs/app-builder/walkthrough/create-queries)**
|
||||
- **[Use Custom Code](/docs/app-builder/walkthrough/using-code)**
|
||||
- **[Access and Referring Values Within The App-Builder](/docs/app-builder/walkthrough/accessing-values)**
|
||||
- **[Create and Managing Variables](/docs/app-builder/walkthrough/variables)**
|
||||
- **[Use Gitsync to Sync your Application with a Git Repository](/docs/gitsync)**
|
||||
- **[Versioning and Release](/docs/tutorial/versioning-and-release)**
|
||||
- **[Import and Export Apps](/docs/beta/app-builder/walkthrough/importing-exporting-applications)**
|
||||
- **[Versioning and Release](/docs/development-lifecycle/release/version-control)**
|
||||
- **[Import and Export Apps](/docs/app-builder/importing-exporting-applications)**
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ id: query-panel
|
|||
title: Query Panel
|
||||
---
|
||||
|
||||
The Query Panel, located at the bottom of the app-builder, allows you to create and manage queries to interact with connected **data sources**. It provides the capability to perform API requests, query **[databases](../data-sources/overview)**, and apply **[transformations](../tutorial/transformations)** or data manipulation using **[JavaScript](../data-sources/run-js)** and **[Python](../data-sources/run-py)**.
|
||||
The Query Panel, located at the bottom of the app-builder, allows you to create and manage queries to interact with connected **data sources**. It provides the capability to perform API requests, query **[databases](/docs/data-sources/overview)**, and apply **[transformations](/docs/tutorial/transformations)** or data manipulation using **[JavaScript](/docs/data-sources/run-js)** and **[Python](/docs/data-sources/run-py)**.
|
||||
|
||||
The Query Panel consists of two sections:
|
||||
- The **[Query Manager](#query-manager)** on the left side, which displays a list of all the created queries.
|
||||
|
|
@ -72,7 +72,7 @@ For each parameter, you need to specify:
|
|||
|
||||
**Syntax for utilizing the parameter:** Employ `parameters.<identifier>` in your query. It's important to note that parameters can only be utilized within the specific query where they are defined.
|
||||
|
||||
Learn more about **[Using Custom Parameters](../how-to/use-custom-parameters)**.
|
||||
Learn more about **[Using Custom Parameters](/docs/how-to/use-custom-parameters)**.
|
||||
|
||||
<img className="screenshot-full" src="/img/v2-beta/app-builder/querypanel/newui3/queryparams-v2.png" alt="Custom Parameters" style={{marginBottom:'15px'}}/>
|
||||
|
||||
|
|
@ -111,7 +111,7 @@ In cases where multiple data sources of the same type are connected, easily swit
|
|||
|
||||
### Transformation
|
||||
|
||||
Queries can be enhanced with transformations to modify the query results. ToolJet supports transformations using two programming languages: JavaScript & Python. Refer to the detailed documentation on **[Transformations](../tutorial/transformations)** for more information.
|
||||
Queries can be enhanced with transformations to modify the query results. ToolJet supports transformations using two programming languages: JavaScript & Python. Refer to the detailed documentation on **[Transformations](/docs/tutorial/transformations)** for more information.
|
||||
|
||||
<img className="screenshot-full" src="/img/v2-beta/app-builder/querypanel/newui2/transform-v2.png" alt="Query Editor" style={{marginBottom:'15px'}}/>
|
||||
|
||||
|
|
@ -144,7 +144,7 @@ The Result:
|
|||
- The component displaying the to-do data will be update with the lates data.
|
||||
|
||||
:::info
|
||||
Learn more about [Event Handlers and Actions](../widgets/overview#component-event-handlers).
|
||||
Learn more about [Event Handlers and Actions](/docs/widgets/overview#component-event-handlers).
|
||||
:::
|
||||
|
||||
<img className="screenshot-full" src="/img/v2-beta/app-builder/querypanel/newui2/events-v2.png" alt="Query Editor" />
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ The Developer Details icon will show a profile picture of the currently active d
|
|||
You can use the Env dropdown menu to select an environment for your app: Development, Staging, or Production. This feature facilitates seamless transition through the app development cycle.
|
||||
|
||||
:::tip
|
||||
Learn more about multi-environment configuration **[here](/docs/release-management/multi-environment/)**.
|
||||
Learn more about multi-environment configuration **[here](/docs/development-lifecycle/environment/self-hosted/multi-environment)**.
|
||||
:::
|
||||
|
||||
<div style={{textAlign: 'center'}}>
|
||||
|
|
@ -64,7 +64,7 @@ Learn more about multi-environment configuration **[here](/docs/release-manageme
|
|||
You can manage application versions through the Version Manager. You can use this dropdown to edit a version name or adding/removing versions.
|
||||
|
||||
:::tip
|
||||
Versioning is also helpful when working with **[multiple environments](/docs/release-management/multi-environment/)** like development, staging and production.
|
||||
Versioning is also helpful when working with **[multiple environments](/docs/development-lifecycle/environment/self-hosted/multi-environment)** like development, staging and production.
|
||||
:::
|
||||
|
||||
<div style={{textAlign: 'center'}}>
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue