Merge branch 'main' of https://github.com/ToolJet/ToolJet into fix/external-epi

This commit is contained in:
Rudra deep Biswas 2025-05-06 16:43:19 +05:30
commit ef20a0b9a5
349 changed files with 10884 additions and 2734 deletions

View file

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

View file

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

View file

@ -2,7 +2,7 @@ name: Cypress Platform
on:
pull_request_target:
types: [labeled, unlabeled, closed]
types: [labeled]
workflow_dispatch:
env:
@ -12,14 +12,9 @@ env:
jobs:
Cypress-Platform:
runs-on: ubuntu-22.04
if: |
github.event.action == 'labeled' &&
(
github.event.label.name == 'run-cypress' ||
github.event.label.name == 'run-ce-cypress-platform' ||
github.event.label.name == 'run-ee-cypress-platform'
)
if: contains(github.event.pull_request.labels.*.name, 'run-cypress') ||
contains(github.event.pull_request.labels.*.name, 'run-ce-cypress-platform') ||
contains(github.event.pull_request.labels.*.name, 'run-ee-cypress-platform')
strategy:
matrix:
edition: >-

View file

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

View file

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

View file

@ -1 +1 @@
3.9.0
3.12.0

View file

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

View file

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

View file

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

View file

@ -167,6 +167,10 @@ Cypress.Commands.add("deleteApp", (appName) => {
.click();
cy.get(commonSelectors.deleteAppOption).click();
cy.get(commonSelectors.buttonSelector(commonText.modalYesButton)).click();
cy.verifyToastMessage(
commonSelectors.toastMessage,
commonText.appDeletedToast
);
cy.wait("@appDeleted");
});
@ -223,9 +227,9 @@ Cypress.Commands.add(
.invoke("text")
.then((text) => {
cy.wrap(subject).realType(createBackspaceText(text)),
{
delay: 0,
};
{
delay: 0,
};
});
}
);
@ -398,7 +402,7 @@ Cypress.Commands.add("defaultWorkspaceLogin", () => {
// cy.intercept("GET", API_ENDPOINT).as("library_apps");
cy.visit("/my-workspace");
cy.wait(2000)
cy.wait(2000);
cy.get(commonSelectors.homePageLogo, { timeout: 10000 });
// cy.wait("@library_apps");
});
@ -428,7 +432,6 @@ Cypress.Commands.add(
}
);
Cypress.Commands.add("releaseApp", () => {
if (Cypress.env("environment") !== "Community") {
cy.get(commonEeSelectors.promoteButton).click();
@ -513,13 +516,58 @@ Cypress.Commands.overwrite(
}
);
Cypress.Commands.add("installMarketplacePlugin", (pluginName) => {
const MARKETPLACE_URL = `${Cypress.config("baseUrl")}/integrations/marketplace`;
cy.visit(MARKETPLACE_URL);
cy.wait(1000);
cy.get('[data-cy="-list-item"]').eq(0).click();
cy.wait(1000);
cy.get("body").then(($body) => {
if ($body.find(".plugins-card").length === 0) {
cy.log("No plugins found, proceeding to install...");
installPlugin(pluginName);
} else {
cy.get(".plugins-card").then(($cards) => {
const isInstalled = $cards.toArray().some((card) => {
return (
Cypress.$(card)
.find(".font-weight-medium.text-capitalize")
.text()
.trim() === pluginName
);
});
if (isInstalled) {
cy.log(`${pluginName} is already installed. Skipping installation.`);
cy.get(commonSelectors.globalDataSourceIcon).click();
} else {
installPlugin(pluginName);
cy.get(commonSelectors.globalDataSourceIcon).click();
}
});
}
});
function installPlugin(pluginName) {
cy.get('[data-cy="-list-item"]').eq(1).click();
cy.wait(1000);
cy.contains(".plugins-card", pluginName).within(() => {
cy.get(".marketplace-install").click();
cy.wait(1000);
});
}
});
Cypress.Commands.add("verifyElement", (selector, text, eqValue) => {
const element =
eqValue !== undefined ? cy.get(selector).eq(eqValue) : cy.get(selector);
element.should("be.visible").and("have.text", text);
});
Cypress.Commands.add("getAppId", (appName) => {
cy.task("dbConnection", {
dbconfig: Cypress.env("app_db"),
@ -529,3 +577,33 @@ Cypress.Commands.add("getAppId", (appName) => {
return appId;
});
});
Cypress.Commands.add("uninstallMarketplacePlugin", (pluginName) => {
const MARKETPLACE_URL = `${Cypress.config("baseUrl")}/integrations/marketplace`;
cy.visit(MARKETPLACE_URL);
cy.wait(1000);
cy.get('[data-cy="-list-item"]').eq(0).click();
cy.wait(1000);
cy.get(".plugins-card").each(($card) => {
cy.wrap($card)
.find(".font-weight-medium.text-capitalize")
.invoke("text")
.then((text) => {
if (text.trim() === pluginName) {
cy.wrap($card).find(".link-primary").contains("Remove").click();
cy.wait(1000);
cy.get('[data-cy="delete-plugin-title"]').should("be.visible");
cy.get('[data-cy="yes-button"]').click();
cy.wait(2000);
cy.log(`${pluginName} has been successfully uninstalled.`);
} else {
cy.log(`${pluginName} is not installed. Skipping uninstallation.`);
}
});
});
});

View file

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

View file

@ -4,7 +4,7 @@ export const postgreSqlText = {
allDataSources: () => {
return Cypress.env("marketplace_action")
? "All data sources (44)"
? "All data sources (45)"
: "All data sources (43)";
},
commonlyUsed: "Commonly used (5)",

View file

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

View file

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

View file

@ -43,7 +43,7 @@ describe("Editor title", () => {
cy.apiDeleteApp();
});
it("should verify titles", () => {
cy.url().should("include", "/tjs-workspace");
cy.url().should("include", "/tooljets-workspace");
// cy.title().should("eq", "Dashboard | ToolJet");
cy.title().should("eq", "ToolJet");
@ -56,7 +56,7 @@ describe("Editor title", () => {
cy.openInCurrentTab(commonWidgetSelector.previewButton);
cy.url().should("include", `/applications/${Cypress.env("appId")}`);
cy.title().should("eq", `${data.appName} | ToolJet`);
// cy.title().should("eq", `${data.appName} | ToolJet`);
// cy.title().should("eq", `Preview - ${data.appName} | ToolJet`);
cy.go("back");

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -66,7 +66,7 @@ describe("Add all Data sources to app", () => {
cy.apiLogin();
});
it("Should verify global data source page", () => {
it.skip("Should verify global data source page", () => {
cy.apiCreateWorkspace(data.workspaceName, data.workspaceSlug);
cy.visit(`${data.workspaceSlug}`);
@ -87,7 +87,7 @@ describe("Add all Data sources to app", () => {
);
});
it("Should add all data sources in data source page", () => {
it.skip("Should add all data sources in data source page", () => {
cy.visit(`${data.workspaceSlug}`);
dataSources.forEach((dsName) => {
@ -109,7 +109,7 @@ describe("Add all Data sources to app", () => {
});
});
it("Should add all data sources in the app", () => {
it.skip("Should add all data sources in the app", () => {
cy.visit(`${data.workspaceSlug}`);
cy.get(commonSelectors.dashboardIcon).click();
cy.get(commonSelectors.appCreateButton).click();
@ -135,7 +135,7 @@ describe("Add all Data sources to app", () => {
});
});
it("Should install all makretplace plugins and add them into the app", () => {
it.skip("Should install all makretplace plugins and add them into the app", () => {
cy.visit(`${data.workspaceSlug}`);
const dataSourcesMarketplace = [
"Plivo",
@ -189,12 +189,15 @@ describe("Add all Data sources to app", () => {
cy.wrap(dataSourcesMarketplace).each((dsName) => {
cy.get(commonSelectors.globalDataSourceIcon).click();
selectAndAddDataSource("databases", dsName, dsName);
cy.wait(500);
cy.wait(1000);
});
cy.get(commonSelectors.dashboardIcon).click();
cy.get(commonSelectors.appCreateButton).click();
cy.get(commonSelectors.appNameInput).click().type(data.dsNamefake1);
cy.get(commonSelectors.dashboardIcon).should("be.visible").click();
cy.get(commonSelectors.appCreateButton).should("be.visible").click();
cy.get(commonSelectors.appNameInput)
.should("be.visible")
.click()
.type(data.dsNamefake1);
cy.get(commonSelectors.createAppButton).click();
cy.skipWalkthrough();
@ -203,7 +206,7 @@ describe("Add all Data sources to app", () => {
cy.get(".css-4e90k9").type(
`cypress-${cyParamName(dsName)}-${cyParamName(dsName)}`
);
cy.wait(500);
cy.wait(1000);
cy.contains(
`[id*="react-select-"]`,
@ -212,7 +215,7 @@ describe("Add all Data sources to app", () => {
.should("be.visible")
.click();
cy.wait(500);
cy.wait(1000);
});
});
});

View file

@ -19,13 +19,14 @@ import {
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]", "");
data.queryName = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
describe("Data source Airtable", () => {
beforeEach(() => {
cy.apiLogin();
cy.defaultWorkspaceLogin();
cy.visit("/");
data.dsName = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
});
it("Should verify elements on connection AirTable form", () => {
@ -199,7 +200,7 @@ describe("Data source Airtable", () => {
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('[data-cy="query-rename-input"]').clear().type(data.queryName);
cy.get(airTableSelector.operationSelectDropdown)
.click()
@ -225,7 +226,7 @@ describe("Data source Airtable", () => {
cy.get(dataSourceSelector.queryPreviewButton).click();
cy.verifyToastMessage(
commonSelectors.toastMessage,
`Query (${data.dsName1}) completed.`
`Query (${data.queryName}) completed.`
);
// Verify Delete record operation
@ -277,7 +278,7 @@ describe("Data source Airtable", () => {
cy.get(dataSourceSelector.queryPreviewButton).click();
cy.verifyToastMessage(
commonSelectors.toastMessage,
`Query (${data.dsName1}) completed.`
`Query (${data.queryName}) completed.`
);
deleteAppandDatasourceAfterExecution(
data.dsName,

View file

@ -20,16 +20,15 @@ import {
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");
cy.visit("/");
data.dsName = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
});
it("Should verify elements on amazon athena connection form", () => {
it.skip("Should verify elements on amazon athena connection form", () => {
const Accesskey = Cypress.env("amazonathena_accessKey");
const Secretkey = Cypress.env("amazonathena_secretKey");
const DbName = Cypress.env("amazonathena_DbName");
@ -98,7 +97,7 @@ describe("Data source amazon athena", () => {
deleteDatasource(`cypress-${data.dsName}-Amazon-Athena`);
});
it("Should verify the functionality of amazon athena connection form.", () => {
it.skip("Should verify the functionality of amazon athena connection form.", () => {
const Accesskey = Cypress.env("amazonathena_accessKey");
const Secretkey = Cypress.env("amazonathena_secretKey");
const DbName = Cypress.env("amazonathena_DbName");
@ -135,7 +134,7 @@ describe("Data source amazon athena", () => {
deleteDatasource(`cypress-${data.dsName}-amazon-Athena`);
});
it("Should able to run the query with valid conection", () => {
it.skip("Should able to run the query with valid conection", () => {
const Accesskey = Cypress.env("amazonathena_accessKey");
const Secretkey = Cypress.env("amazonathena_secretKey");
const DbName = Cypress.env("amazonathena_DbName");
@ -189,11 +188,13 @@ describe("Data source amazon athena", () => {
cy.get(".css-4e90k9").type(`${data.dsName}`);
cy.contains(`[id*="react-select-"]`, data.dsName).click();
cy.get('[data-cy="query-rename-input"]').clear().type(data.dsName);
cy.get(`[data-cy="list-query-${data.dsName}"]`).should("be.visible");
cy.get('[data-cy="query-input-field"]').clearAndTypeOnCodeMirror(
"SHOW DATABASES;"
);
cy.get(
'[data-cy="query-input-field"] >>> .cm-editor >> .cm-content > .cm-line'
).should("have.text", "SHOW DATABASES;");
cy.get(dataSourceSelector.queryPreviewButton).click();
cy.verifyToastMessage(
commonSelectors.toastMessage,

View file

@ -20,16 +20,15 @@ import {
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");
cy.visit("/");
data.dsName = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
});
it("Should verify elements on amazonses connection form", () => {
it.skip("Should verify elements on amazonses connection form", () => {
const Accesskey = Cypress.env("amazonSes_accessKey");
const Secretkey = Cypress.env("amazonSes_secretKey");
@ -81,7 +80,7 @@ describe("Data source amazon ses", () => {
deleteDatasource(`cypress-${data.dsName}-Amazon-ses`);
});
it("Should verify the functionality of amazonses connection form.", () => {
it.skip("Should verify the functionality of amazonses connection form.", () => {
selectAndAddDataSource("databases", amazonSesText.AmazonSES, data.dsName);
cy.get(".react-select__dropdown-indicator").eq(1).click();
@ -113,7 +112,7 @@ describe("Data source amazon ses", () => {
deleteDatasource(`cypress-${data.dsName}-amazon-ses`);
});
it("Should able to run the query with valid conection", () => {
it.skip("Should able to run the query with valid conection", () => {
const email = "adish" + "@" + "tooljet.com";
selectAndAddDataSource("databases", amazonSesText.AmazonSES, data.dsName);

View file

@ -20,16 +20,15 @@ import {
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");
cy.visit("/");
data.dsName = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
});
it("Should verify elements on appwrite connection form", () => {
it.skip("Should verify elements on appwrite connection form", () => {
const Host = Cypress.env("appwrite_host");
const ProjectID = Cypress.env("appwrite_projectID");
const DatabaseID = Cypress.env("appwrite_databaseID");
@ -101,7 +100,7 @@ describe("Data source AppWrite", () => {
deleteDatasource(`cypress-${data.dsName}-Appwrite`);
});
it("Should verify the functionality of appwrite connection form.", () => {
it.skip("Should verify the functionality of appwrite connection form.", () => {
const Host = Cypress.env("appwrite_host");
const ProjectID = Cypress.env("appwrite_projectID");
const DatabaseID = Cypress.env("appwrite_databaseID");
@ -151,7 +150,7 @@ describe("Data source AppWrite", () => {
deleteDatasource(`cypress-${data.dsName}-Appwrite`);
});
it("Should be able to run the query with a valid connection", () => {
it.skip("Should be able to run the query with a valid connection", () => {
const Host = Cypress.env("appwrite_host");
const ProjectID = Cypress.env("appwrite_projectID");
const DatabaseID = Cypress.env("appwrite_databaseID");

View file

@ -20,16 +20,15 @@ import {
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");
cy.visit("/");
data.dsName = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
});
it("Should verify elements on AWS Lambda connection form", () => {
it.skip("Should verify elements on AWS Lambda connection form", () => {
const Accesskey = Cypress.env("awslamda_access");
const Secretkey = Cypress.env("awslamda_secret");
@ -81,9 +80,10 @@ describe("Data source AWS Lambda", () => {
);
deleteDatasource(`cypress-${data.dsName}-aws-lambda`);
cy.uninstallMarketplacePlugin("AWS Lambda");
});
it("Should verify the functionality of AWS Lambda connection form", () => {
it.skip("Should verify the functionality of AWS Lambda connection form", () => {
const Accesskey = Cypress.env("awslamda_access");
const Secretkey = Cypress.env("awslamda_secret");
@ -114,9 +114,10 @@ describe("Data source AWS Lambda", () => {
);
deleteDatasource(`cypress-${data.dsName}-aws-lambda`);
cy.uninstallMarketplacePlugin("AWS Lambda");
});
it("Should able to run the query with valid conection", () => {
it.skip("Should able to run the query with valid conection", () => {
const Accesskey = Cypress.env("awslamda_access");
const Secretkey = Cypress.env("awslamda_secret");

View file

@ -21,16 +21,15 @@ import {
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");
cy.visit("/");
data.dsName = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
});
it("Should verify elements on AWS Textract connection form", () => {
it.skip("Should verify elements on AWS Textract connection form", () => {
const Accesskey = Cypress.env("awstextract_access");
const Secretkey = Cypress.env("awstextract_secret");
@ -88,7 +87,7 @@ describe("Data source AWS Textract", () => {
deleteDatasource(`cypress-${data.dsName}-aws-textract`);
});
it("Should verify functionality of AWS Textract connection form", () => {
it.skip("Should verify functionality of AWS Textract connection form", () => {
const Accesskey = Cypress.env("awstextract_access");
const Secretkey = Cypress.env("awstextract_secret");
@ -123,9 +122,10 @@ describe("Data source AWS Textract", () => {
);
deleteDatasource(`cypress-${data.dsName}-aws-textract`);
cy.uninstallMarketplacePlugin("AWS Textract");
});
it("Should able to run the query with valid conection", () => {
it.skip("Should able to run the query with valid conection", () => {
const Accesskey = Cypress.env("awstextract_access");
const Secretkey = Cypress.env("awstextract_secret");

View file

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

View file

@ -20,16 +20,15 @@ import {
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");
cy.visit("/");
data.dsName = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
});
it("Should verify elements on baserow connection form", () => {
it.skip("Should verify elements on baserow connection form", () => {
const Apikey = Cypress.env("baserow_apikey");
cy.get(commonSelectors.globalDataSourceIcon).click();
@ -79,7 +78,7 @@ describe("Data source baserow", () => {
deleteDatasource(`cypress-${data.dsName}-baserow`);
});
it("Should verify the functionality of baserow connection form.", () => {
it.skip("Should verify the functionality of baserow connection form.", () => {
const Apikey = Cypress.env("baserow_apikey");
selectAndAddDataSource("databases", baseRowText.baserow, data.dsName);
@ -104,7 +103,7 @@ describe("Data source baserow", () => {
deleteDatasource(`cypress-${data.dsName}-baserow`);
});
it("Should be able to run the query with a valid connection", () => {
it.skip("Should be able to run the query with a valid connection", () => {
const baserowTableID = Cypress.env("baserow_tableid");
const baserowRowID = Cypress.env("baserow_rowid");
const Apikey = Cypress.env("baserow_apikey");

View file

@ -16,9 +16,8 @@ const data = {};
describe("Data source BigQuery", () => {
beforeEach(() => {
cy.appUILogin();
cy.defaultWorkspaceLogin();
cy.intercept("GET", "/api/v2/data_sources");
cy.apiLogin();
cy.visit("/");
data.dataSourceName = fake.lastName
.toLowerCase()
.replaceAll("[^A-Za-z]", "");

View file

@ -19,8 +19,8 @@ const data = {};
describe("Data sources", () => {
beforeEach(() => {
cy.appUILogin();
cy.defaultWorkspaceLogin();
cy.apiLogin();
cy.visit("/");
data.dataSourceName = fake.lastName
.toLowerCase()
.replaceAll("[^A-Za-z]", "");

View file

@ -19,8 +19,8 @@ const data = {};
describe("Data sources", () => {
beforeEach(() => {
cy.appUILogin();
cy.defaultWorkspaceLogin();
cy.apiLogin();
cy.visit("/");
data.dataSourceName = fake.lastName
.toLowerCase()
.replaceAll("[^A-Za-z]", "");

View file

@ -21,8 +21,8 @@ const data = {};
describe("Data sources", () => {
beforeEach(() => {
cy.appUILogin();
cy.defaultWorkspaceLogin();
cy.apiLogin();
cy.visit("/");
data.dataSourceName = fake.lastName
.toLowerCase()
.replaceAll("[^A-Za-z]", "");

View file

@ -19,8 +19,8 @@ const data = {};
describe("Data source DynamoDB", () => {
beforeEach(() => {
cy.appUILogin();
cy.defaultWorkspaceLogin();
cy.apiLogin();
cy.visit("/");
data.dataSourceName = fake.lastName
.toLowerCase()
.replaceAll("[^A-Za-z]", "");

View file

@ -17,9 +17,12 @@ import {
const data = {};
describe("Data source Elasticsearch", () => {
beforeEach(() => {
cy.appUILogin();
cy.defaultWorkspaceLogin();
data.lastName = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
cy.apiLogin();
cy.visit("/");
data.dataSourceName = fake.lastName
.toLowerCase()
.replaceAll("[^A-Za-z]", "");
});
it("Should verify elements on Elasticsearch connection form", () => {
@ -123,14 +126,14 @@ describe("Data source Elasticsearch", () => {
"have.text",
elasticsearchText.errorConnectionRefused
);
deleteDatasource(`cypress-${data.lastName}-elasticsearch`);
deleteDatasource(`cypress-${data.dataSourceName}-elasticsearch`);
});
it("Should verify the functionality of Elasticsearch connection form.", () => {
selectAndAddDataSource(
"databases",
elasticsearchText.elasticSearch,
data.lastName
data.dataSourceName
);
fillDataSourceTextField(
@ -210,12 +213,12 @@ describe("Data source Elasticsearch", () => {
);
cy.get(
`[data-cy="cypress-${data.lastName}-elasticsearch-button"]`
`[data-cy="cypress-${data.dataSourceName}-elasticsearch-button"]`
).verifyVisibleElement(
"have.text",
`cypress-${data.lastName}-elasticsearch`
`cypress-${data.dataSourceName}-elasticsearch`
);
deleteDatasource(`cypress-${data.lastName}-elasticsearch`);
deleteDatasource(`cypress-${data.dataSourceName}-elasticsearch`);
});
});

View file

@ -17,8 +17,8 @@ const data = {};
describe("Data source Firestore", () => {
beforeEach(() => {
cy.appUILogin();
cy.defaultWorkspaceLogin();
cy.apiLogin();
cy.visit("/");
data.dataSourceName = fake.lastName
.toLowerCase()
.replaceAll("[^A-Za-z]", "");

View file

@ -19,12 +19,12 @@ import {
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();
cy.visit("/");
data.dsName = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
});
it("Should verify elements on GraphQL connection form", () => {

View file

@ -20,13 +20,13 @@ import {
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();
cy.visit("/");
data.dsName = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
});
it("Should verify elements on HarperDB connection form", () => {
@ -102,6 +102,7 @@ describe("Data source HarperDB", () => {
);
deleteDatasource(`cypress-${data.dsName}-HarperDB`);
cy.uninstallMarketplacePlugin("HarperDB");
});
it("Should verify functionality of HarperDB connection form", () => {
@ -156,9 +157,10 @@ describe("Data source HarperDB", () => {
);
deleteDatasource(`cypress-${data.dsName}-HarperDB`);
cy.uninstallMarketplacePlugin("HarperDB");
});
it("Should be able to run the query with a valid connection", () => {
it.skip("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");

View file

@ -23,8 +23,8 @@ const data = {};
describe("Data sources", () => {
beforeEach(() => {
cy.appUILogin();
cy.defaultWorkspaceLogin();
cy.apiLogin();
cy.visit("/");
data.dataSourceName = fake.lastName
.toLowerCase()
.replaceAll("[^A-Za-z]", "");

View file

@ -19,8 +19,8 @@ const data = {};
describe("Data sources", () => {
beforeEach(() => {
cy.appUILogin();
cy.defaultWorkspaceLogin();
cy.apiLogin();
cy.visit("/");
data.dataSourceName = fake.lastName
.toLowerCase()
.replaceAll("[^A-Za-z]", "");

View file

@ -20,12 +20,12 @@ import {
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();
cy.visit("/");
data.dsName = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
});
it("Should verify elements on minio connection form", () => {
@ -157,7 +157,7 @@ describe("Data source minio", () => {
deleteDatasource(`cypress-${data.dsName}-minio`);
});
it("Should be able to run the query with a valid connection", () => {
it.skip("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");

View file

@ -27,8 +27,8 @@ const data = {};
describe("Data source MongoDB", () => {
beforeEach(() => {
cy.appUILogin();
cy.defaultWorkspaceLogin();
cy.apiLogin();
cy.visit("/");
data.dataSourceName = fake.lastName
.toLowerCase()
.replaceAll("[^A-Za-z]", "");
@ -133,7 +133,7 @@ describe("Data source MongoDB", () => {
"have.text",
mongoDbText.errorConnectionRefused
);
cy.get('[data-cy="query-select-dropdown"]').type(
cy.get('[data-cy="connection-type-select-dropdown"]').type(
mongoDbText.optionConnectUsingConnectionString
);
cy.get('[data-cy="label-connection-string"]').verifyVisibleElement(

View file

@ -26,8 +26,8 @@ const data = {};
describe("Data sources MySql", () => {
beforeEach(() => {
cy.appUILogin();
cy.defaultWorkspaceLogin();
cy.apiLogin();
cy.visit("/");
data.dataSourceName = fake.lastName
.toLowerCase()
.replaceAll("[^A-Za-z]", "");

View file

@ -15,7 +15,7 @@ import {
describe("Data sources", () => {
beforeEach(() => {
cy.appUILogin();
cy.apiLogin();
// cy.createApp();
});

View file

@ -20,14 +20,14 @@ const data = {};
describe("Data sources", () => {
beforeEach(() => {
cy.appUILogin();
cy.defaultWorkspaceLogin();
cy.apiLogin();
cy.visit("/");
data.dataSourceName = fake.lastName
.toLowerCase()
.replaceAll("[^A-Za-z]", "");
});
it("Should verify elements on connection form", () => {
it.skip("Should verify elements on connection form", () => {
cy.log(process.env.NODE_ENV);
cy.log(postgreSqlText.allDatabase());
cy.get(commonSelectors.globalDataSourceIcon).click();
@ -140,7 +140,7 @@ describe("Data sources", () => {
deleteDatasource(`cypress-${data.dataSourceName}-postgresql`);
});
it("Should verify the functionality of PostgreSQL connection form.", () => {
it.skip("Should verify the functionality of PostgreSQL connection form.", () => {
selectAndAddDataSource(
"databases",
postgreSqlText.postgreSQL,

View file

@ -23,7 +23,7 @@ data.dsName = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
describe("Data source Redis", () => {
beforeEach(() => {
cy.apiLogin();
cy.defaultWorkspaceLogin();
cy.visit("/");
});
it("Should verify elements on connection Redis form", () => {
@ -215,7 +215,7 @@ describe("Data source Redis", () => {
deleteDatasource(`cypress-${data.dsName}-redis`);
});
it("Should able to run the query with valid conection", () => {
it.skip("Should able to run the query with valid conection", () => {
selectAndAddDataSource("databases", redisText.redis, data.dsName);
fillDataSourceTextField(

View file

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

View file

@ -19,8 +19,8 @@ const data = {};
describe("Data sources", () => {
beforeEach(() => {
cy.appUILogin();
cy.defaultWorkspaceLogin();
cy.apiLogin();
cy.visit("/");
data.dataSourceName = fake.lastName
.toLowerCase()
.replaceAll("[^A-Za-z]", "");

View file

@ -20,7 +20,7 @@ const data = {};
describe("Data sources AWS S3", () => {
beforeEach(() => {
cy.apiLogin();
cy.defaultWorkspaceLogin();
cy.visit("/");
data.dataSourceName = fake.lastName
.toLowerCase()
.replaceAll("[^A-Za-z]", "");

View file

@ -15,7 +15,7 @@ import {
describe("Data sources", () => {
beforeEach(() => {
cy.appUILogin();
cy.apiLogin();
// cy.createApp();
});

View file

@ -13,8 +13,8 @@ const data = {};
describe("Data source SMTP", () => {
beforeEach(() => {
cy.appUILogin();
cy.defaultWorkspaceLogin();
cy.apiLogin();
cy.visit("/");
data.dataSourceName = fake.lastName
.toLowerCase()
.replaceAll("[^A-Za-z]", "");

View file

@ -20,8 +20,8 @@ import {
const data = {};
describe("Data sources", () => {
beforeEach(() => {
cy.appUILogin();
cy.defaultWorkspaceLogin();
cy.apiLogin();
cy.visit("/");
data.dataSourceName = fake.lastName
.toLowerCase()
.replaceAll("[^A-Za-z]", "");

View file

@ -21,8 +21,8 @@ const data = {};
describe("Data sources", () => {
beforeEach(() => {
cy.appUILogin();
cy.defaultWorkspaceLogin();
cy.apiLogin();
cy.visit("/");
data.dataSourceName = fake.lastName
.toLowerCase()
.replaceAll("[^A-Za-z]", "");

View file

@ -21,15 +21,15 @@ import { dataSourceSelector } from "../../../../../constants/selectors/dataSourc
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();
cy.visit("/");
data.dsName = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
});
it("Should verify elements on Twilio connection form", () => {
it.skip("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");
@ -89,7 +89,7 @@ describe("Data source Twilio", () => {
deleteDatasource(`cypress-${data.dsName}-twilio`);
});
it("Should verify functionality of Twilio connection form", () => {
it.skip("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");
@ -128,7 +128,7 @@ describe("Data source Twilio", () => {
deleteDatasource(`cypress-${data.dsName}-twilio`);
});
it("Should be able to run the query with a valid connection", () => {
it.skip("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");

View file

@ -20,7 +20,7 @@ const data = {};
describe("Data sources", () => {
beforeEach(() => {
cy.appUILogin();
cy.apiLogin();
data.dataSourceName = fake.lastName
.toLowerCase()
.replaceAll("[^A-Za-z]", "");

View file

@ -171,7 +171,7 @@ describe("dashboard", () => {
verifyTooltip(dashboardSelector.modeToggle, "Mode");
});
it("Should verify app card elements and app card operations", () => {
it.skip("Should verify app card elements and app card operations", () => {
const customLayout = {
desktop: { top: 100, left: 20 },
mobile: { width: 8, height: 50 },

View file

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

View file

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

View file

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

View file

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

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

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

View file

@ -53,6 +53,8 @@ export const modifyAndVerifyAppCardIcon = (appName) => {
};
export const verifyAppDelete = (appName) => {
cy.get("body").should("exist").and("be.visible");
cy.get('[data-cy="dashboard-section-header"]').should("be.visible");
cy.get("body").then(($title) => {
if (!$title.text().includes(commonText.introductionMessage)) {
cy.clearAndType(commonSelectors.homePageSearchBar, appName);

View file

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

View file

@ -853,6 +853,9 @@ export const createGroupsAndAddUserInGroup = (groupName, email) => {
commonSelectors.toastMessage,
groupsText.groupCreatedToast
);
addUserInGroup(groupName, email);
};
export const addUserInGroup = (groupName, email) => {
cy.get(groupsSelector.groupLink(groupName)).click();
cy.clearAndType(groupsSelector.multiSelectSearchInput, email);
cy.wait(2000);
@ -862,7 +865,7 @@ export const createGroupsAndAddUserInGroup = (groupName, email) => {
commonSelectors.toastMessage,
groupsText.userAddedToast
);
};
}
export const inviteUserBasedOnRole = (firstName, email, role = "end-user") => {
fillUserInviteForm(firstName, email);

View file

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

View file

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

View file

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

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

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

View file

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

View file

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

View file

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

View file

@ -145,12 +145,13 @@ COPY --from=builder /app/frontend/build ./app/frontend/build
COPY --from=builder /app/server/package.json ./app/server/package.json
COPY --from=builder /app/server/.version ./app/server/.version
COPY --from=builder /app/server/ee/keys ./app/server/ee/keys
COPY --from=builder /app/server/entrypoint.sh ./app/server/entrypoint.sh
COPY --from=builder /app/server/node_modules ./app/server/node_modules
COPY --from=builder /app/server/templates ./app/server/templates
COPY --from=builder /app/server/scripts ./app/server/scripts
COPY --from=builder /app/server/dist ./app/server/dist
COPY ./docker/ee/ee-entrypoint.sh ./app/server/ee-entrypoint.sh
# Define non-sudo user
RUN useradd --create-home --home-dir /home/appuser appuser \
&& chown -R appuser:0 /app \
@ -214,4 +215,4 @@ RUN npm install dotenv@10.0.0 joi@17.4.1
RUN npm cache clean --force
ENTRYPOINT ["./server/entrypoint.sh"]
ENTRYPOINT ["./server/ee-entrypoint.sh"]

View file

@ -0,0 +1,15 @@
#!/bin/bash
set -e
# Start Redis
# service redis-server start
# redis-server /etc/redis/redis.conf
# Start Postgres
service postgresql start
# Export the PORT variable to be used by the application
export PORT=${PORT:-80}
# Start Supervisor
exec supervisord -c /etc/supervisor/conf.d/supervisord.conf

View file

@ -22,7 +22,7 @@ echo "Starting Temporal Server..."
export PORT=${PORT:-80}
# Start Supervisor
/usr/bin/supervisord -n &
exec supervisord -c /etc/supervisor/conf.d/supervisord.conf &
# Wait for Temporal Server to be ready
echo "Waiting for Temporal Server to be ready..."

View file

@ -1,21 +1,31 @@
FROM tooljet/tooljet-ce:latest
FROM tooljet/tooljet:ee-lts-latest
# copy postgrest executable
COPY --from=postgrest/postgrest:v10.1.1.20221215 /bin/postgrest /bin
# Copy PostgREST executable
COPY --from=postgrest/postgrest:v12.2.0 /bin/postgrest /bin
# Install Postgres
# Install PostgreSQL
USER root
RUN wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add -
RUN echo "deb http://apt.postgresql.org/pub/repos/apt/ bullseye-pgdg main" | tee /etc/apt/sources.list.d/pgdg.list
RUN echo "deb http://deb.debian.org/debian"
RUN apt update && apt -y install postgresql-13 postgresql-client-13 supervisor
USER postgres
RUN service postgresql start && \
psql -c "create role tooljet with login superuser password 'postgres';"
USER root
# Install Redis
RUN apt update && apt -y install redis
# Create appuser home & ensure permission for supervisord and services
RUN mkdir -p /var/log/supervisor /var/run/postgresql /var/lib/postgresql /var/lib/redis && \
chown -R appuser:appuser /etc/supervisor /var/log/supervisor /var/lib/redis && \
chown -R postgres:postgres /var/run/postgresql /var/lib/postgresql
# Configure Supervisor to manage PostgREST, ToolJet, and Redis
RUN echo "[supervisord] \n" \
"nodaemon=true \n" \
"user=root \n" \
"\n" \
"[program:postgrest] \n" \
"command=/bin/postgrest \n" \
@ -23,12 +33,23 @@ RUN echo "[supervisord] \n" \
"autorestart=true \n" \
"\n" \
"[program:tooljet] \n" \
"user=appuser \n" \
"command=/bin/bash -c '/app/server/scripts/init-db-boot.sh' \n" \
"autostart=true \n" \
"autorestart=true \n" \
"stderr_logfile=/dev/stdout \n" \
"stderr_logfile_maxbytes=0 \n" \
"stdout_logfile=/dev/stdout \n" \
"stdout_logfile_maxbytes=0 \n" \
"\n" \
"[program:redis] \n" \
"user=appuser \n" \
"command=/usr/bin/redis-server \n" \
"autostart=true \n" \
"autorestart=true \n" \
"stderr_logfile=/dev/stdout \n" \
"stderr_logfile_maxbytes=0 \n" \
"stdout_logfile=/dev/stdout \n" \
"stdout_logfile_maxbytes=0 \n" | sed 's/ //' > /etc/supervisor/conf.d/supervisord.conf
# ENV defaults
@ -49,10 +70,17 @@ ENV TOOLJET_HOST=http://localhost \
PGRST_HOST=http://localhost:3000 \
PGRST_DB_URI=postgres://tooljet:postgres@localhost/tooljet_db \
PGRST_JWT_SECRET=r9iMKoe5CRMgvJBBtp4HrqN7QiPpUToj \
PGRST_DB_PRE_CONFIG=postgrest.pre_config \
ORM_LOGGING=true \
DEPLOYMENT_PLATFORM=docker:local \
HOME=/home/appuser \
REDIS_HOST=localhost \
REDIS_PORT=6379 \
REDIS_USER=default \
REDIS_PASS= \
TERM=xterm
# Prepare DB and start application
ENTRYPOINT service postgresql start 1> /dev/null && /usr/bin/supervisord
# Set the entrypoint
COPY ./docker/ee/ee-try-entrypoint-lts.sh /ee-try-entrypoint-lts.sh
RUN chmod +x /ee-try-entrypoint-lts
ENTRYPOINT ["/ee-try-entrypoint-lts.sh"]

View file

@ -0,0 +1,117 @@
FROM tooljet/tooljet:ee-latest
# Copy postgrest executable
COPY --from=postgrest/postgrest:v12.2.0 /bin/postgrest /bin
# Install Postgres
USER root
RUN wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add -
RUN echo "deb http://apt.postgresql.org/pub/repos/apt/ bullseye-pgdg main" | tee /etc/apt/sources.list.d/pgdg.list
RUN echo "deb http://deb.debian.org/debian"
RUN apt update && apt -y install postgresql-13 postgresql-client-13 supervisor
USER postgres
RUN service postgresql start && \
psql -c "create role tooljet with login superuser password 'postgres';"
USER root
RUN apt update && apt -y install redis
# Create appuser home & ensure permission for supervisord and services
RUN mkdir -p /var/log/supervisor /var/run/postgresql /var/lib/postgresql /var/lib/redis && \
chown -R appuser:appuser /etc/supervisor /var/log/supervisor /var/lib/redis && \
chown -R postgres:postgres /var/run/postgresql /var/lib/postgresql
# Install Temporal Server Binaries
RUN curl -OL https://github.com/temporalio/temporal/releases/download/v1.24.2/temporal_1.24.2_linux_amd64.tar.gz && \
tar -xzf temporal_1.24.2_linux_amd64.tar.gz && \
mv temporal-server /usr/bin/temporal-server && \
chmod +x /usr/bin/temporal-server && \
rm temporal_1.24.2_linux_amd64.tar.gz
# Install Temporal UI Server Binaries
RUN curl -OL https://github.com/temporalio/ui-server/releases/download/v2.28.0/ui-server_2.28.0_linux_amd64.tar.gz && \
tar -xzf ui-server_2.28.0_linux_amd64.tar.gz && \
mv ui-server /usr/bin/temporal-ui-server && \
chmod +x /usr/bin/temporal-ui-server && \
rm ui-server_2.28.0_linux_amd64.tar.gz
# Copy Temporal configuration files
COPY ./docker/ee/temporal-server.yaml /etc/temporal/temporal-server.yaml
COPY ./docker/ee/temporal-ui-server.yaml /etc/temporal/temporal-ui-server.yaml
# Install grpcurl
RUN apt update && apt install -y curl \
&& curl -sSL https://github.com/fullstorydev/grpcurl/releases/download/v1.8.0/grpcurl_1.8.0_linux_x86_64.tar.gz | tar -xzv -C /usr/local/bin grpcurl
# Configure Supervisor to manage PostgREST, ToolJet, and Redis
RUN echo "[supervisord] \n" \
"nodaemon=true \n" \
"user=root \n" \
"\n" \
"[program:postgrest] \n" \
"command=/bin/postgrest \n" \
"autostart=true \n" \
"autorestart=true \n" \
"\n" \
"[program:tooljet] \n" \
"user=appuser \n" \
"command=/bin/bash -c '/app/server/scripts/init-db-boot.sh' \n" \
"autostart=true \n" \
"autorestart=true \n" \
"stderr_logfile=/dev/stdout \n" \
"stderr_logfile_maxbytes=0 \n" \
"stdout_logfile=/dev/stdout \n" \
"stdout_logfile_maxbytes=0 \n" \
"\n" \
"[program:redis] \n" \
"user=appuser \n" \
"command=/usr/bin/redis-server \n" \
"autostart=true \n" \
"autorestart=true \n" \
"stderr_logfile=/dev/stdout \n" \
"stderr_logfile_maxbytes=0 \n" \
"stdout_logfile=/dev/stdout \n" \
"stdout_logfile_maxbytes=0 \n" | sed 's/ //' > /etc/supervisor/conf.d/supervisord.conf
# ENV defaults
ENV TOOLJET_HOST=http://localhost \
TOOLJET_SERVER_URL=http://localhost \
PORT=80 \
NODE_ENV=production \
LOCKBOX_MASTER_KEY=replace_with_lockbox_master_key \
SECRET_KEY_BASE=replace_with_secret_key_base \
PG_DB=tooljet_production \
PG_USER=tooljet \
PG_PASS=postgres \
PG_HOST=localhost \
ENABLE_TOOLJET_DB=true \
TOOLJET_DB_HOST=localhost \
TOOLJET_DB_USER=tooljet \
TOOLJET_DB_PASS=postgres \
TOOLJET_DB=tooljet_db \
PGRST_HOST=http://localhost:3000 \
PGRST_DB_URI=postgres://tooljet:postgres@localhost/tooljet_db \
PGRST_JWT_SECRET=r9iMKoe5CRMgvJBBtp4HrqN7QiPpUToj \
PGRST_DB_PRE_CONFIG=postgrest.pre_config \
ORM_LOGGING=true \
DEPLOYMENT_PLATFORM=docker:local \
HOME=/home/appuser \
REDIS_HOST=localhost \
REDIS_PORT=6379 \
REDIS_USER=default \
REDIS_PASS= \
ENABLE_MARKETPLACE_FEATURE=true \
TERM=xterm \
ENABLE_WORKFLOW_SCHEDULING=true \
TEMPORAL_SERVER_ADDRESS=localhost:7233 \
TEMPORAL_TASK_QUEUE_NAME_FOR_WORKFLOWS=tooljet-workflows \
TOOLJET_WORKFLOWS_TEMPORAL_NAMESPACE=default \
TEMPORAL_ADDRESS=localhost:7233 \
TEMPORAL_CORS_ORIGINS=http://localhost:8080
# Set the entrypoint
COPY ./docker/ee/ee-try-entrypoint.sh /ee-try-entrypoint.sh
RUN chmod +x /ee-try-entrypoint.sh
ENTRYPOINT ["/ee-try-entrypoint.sh"]

View file

@ -0,0 +1,75 @@
log:
stdout: true
level: info
persistence:
defaultStore: sqlite-default
visibilityStore: sqlite-visibility
numHistoryShards: 4
datastores:
sqlite-default:
sql:
pluginName: "sqlite"
databaseName: "/etc/temporal/default.db"
connectAddr: "localhost"
connectProtocol: "tcp"
connectAttributes:
cache: "private"
setup: true
sqlite-visibility:
sql:
pluginName: "sqlite"
databaseName: "/etc/temporal/visibility.db"
connectAddr: "localhost"
connectProtocol: "tcp"
connectAttributes:
cache: "private"
setup: true
global:
membership:
maxJoinDuration: 30s
broadcastAddress: "127.0.0.1"
pprof:
port: 7936
services:
frontend:
rpc:
grpcPort: 7233
membershipPort: 6933
bindOnLocalHost: true
httpPort: 7243
matching:
rpc:
grpcPort: 7235
membershipPort: 6935
bindOnLocalHost: true
history:
rpc:
grpcPort: 7234
membershipPort: 6934
bindOnLocalHost: true
worker:
rpc:
membershipPort: 6939
clusterMetadata:
enableGlobalNamespace: false
failoverVersionIncrement: 10
masterClusterName: "active"
currentClusterName: "active"
clusterInformation:
active:
enabled: true
initialFailoverVersion: 1
rpcName: "frontend"
rpcAddress: "localhost:7236"
httpAddress: "localhost:7243"
dcRedirectionPolicy:
policy: "noop"

View file

@ -0,0 +1,8 @@
temporalGrpcAddress: 127.0.0.1:7233 # Use the correct Temporal server address
host: 0.0.0.0
port: 8080
enableUi: true
cors:
allowOrigins:
- http://localhost:8080
defaultNamespace: default

View file

@ -1 +1 @@
3.9.0
3.12.0

View file

@ -0,0 +1,3 @@
<svg width="11" height="14" viewBox="0 0 11 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M3.33317 3.49967C3.33317 2.30306 4.30322 1.33301 5.49984 1.33301C6.69645 1.33301 7.6665 2.30306 7.6665 3.49967V4.33301H3.33317V3.49967ZM2.33317 4.37981V3.49967C2.33317 1.75077 3.75094 0.333008 5.49984 0.333008C7.24874 0.333008 8.6665 1.75077 8.6665 3.49967V4.37981C9.90027 4.61384 10.8332 5.69781 10.8332 6.99967V10.9997C10.8332 12.4724 9.63926 13.6663 8.1665 13.6663H2.83317C1.36041 13.6663 0.166504 12.4724 0.166504 10.9997V6.99967C0.166504 5.69781 1.09941 4.61384 2.33317 4.37981ZM6.83317 8.99967C6.83317 9.73605 6.23622 10.333 5.49984 10.333C4.76346 10.333 4.1665 9.73605 4.1665 8.99967C4.1665 8.2633 4.76346 7.66634 5.49984 7.66634C6.23622 7.66634 6.83317 8.2633 6.83317 8.99967Z" fill="#ACB2B9"/>
</svg>

After

Width:  |  Height:  |  Size: 855 B

View file

@ -0,0 +1,22 @@
import React from 'react';
const HorizontalDivider = ({ fill = '#D7DBDF', width = 24, className = '', viewBox = '0 0 49 48' }) => (
<svg xmlns="http://www.w3.org/2000/svg" width={width} height={width} viewBox={viewBox} fill="none">
<g clip-path="url(#clip0_0_153)">
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M0.888672 23.7143C0.888672 21.9785 2.29578 20.5714 4.03153 20.5714H41.7458C43.4816 20.5714 44.8887 21.9785 44.8887 23.7143C44.8887 25.45 43.4816 26.8571 41.7458 26.8571H4.03153C2.29578 26.8571 0.888672 25.45 0.888672 23.7143Z"
fill="#CCD1D5"
/>
<circle cx="22.8887" cy="23.7144" r="5.15332" fill="#4368E3" />
</g>
<defs>
<clipPath id="clip0_0_153">
<rect width="48" height="48" fill="white" transform="translate(0.888672)" />
</clipPath>
</defs>
</svg>
);
export default HorizontalDivider;

View file

@ -13,8 +13,6 @@ import Customcomponent from './customcomponent.jsx';
import Datepicker from './datepicker.jsx';
import DateTimePickerV2 from './datetimepickerV2.jsx';
import Daterangepicker from './daterangepicker.jsx';
import Divider from './divider.jsx';
import DividerHorizondal from './dividerhorizontal.jsx';
import Downstatistics from './downstatistics.jsx';
import Dropdown from './dropdown.jsx';
import Filepicker from './filepicker.jsx';
@ -59,6 +57,7 @@ import Upstatistics from './upstatistics.jsx';
import Verticaldivider from './verticaldivider.jsx';
import TimePicker from './timepicker.jsx';
import DatepickerV2 from './datepickerv2.jsx';
import HorizontalDivider from './horizontalDivider.jsx';
import PhoneInput from './phoneinput.jsx';
import EmailInput from './emailinput.jsx';
@ -108,9 +107,7 @@ const WidgetIcon = (props) => {
case 'daterangepicker':
return <Daterangepicker {...props} />;
case 'horizontaldivider':
return <Divider {...props} />;
case 'divider-horizondal':
return <DividerHorizondal {...props} />;
return <HorizontalDivider {...props} />;
case 'downstatistics':
return <Downstatistics {...props} />;
case 'dropdown':

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