Merge pull request #25866 from appsmithorg/release_v1.9.31
This commit is contained in:
commit
23fa634474
2
.github/config.json
vendored
2
.github/config.json
vendored
File diff suppressed because one or more lines are too long
243
.github/workflows/ad-hoc-deploy-preview.yml
vendored
Normal file
243
.github/workflows/ad-hoc-deploy-preview.yml
vendored
Normal file
|
|
@ -0,0 +1,243 @@
|
|||
name: Ad-hoc DP | Build Push Deploy from branch ( To be used by ops.appsmith.com API layer only)
|
||||
|
||||
on:
|
||||
# This workflow is only triggered by the `/build-deploy-preview` command dispatch
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
branch:
|
||||
description: "Github Branch to be deployed"
|
||||
required: true
|
||||
default: "release"
|
||||
skip-tests:
|
||||
description: "Flag to skip Cypress tests"
|
||||
required: true
|
||||
default: "true"
|
||||
uid:
|
||||
description: "Unique ID to store the run data in the db"
|
||||
required: false
|
||||
sub-domain-name:
|
||||
description: "Sub-domain for dp.appsmith.com to by used by this deploy preview (This will also be the image name and the k8s namespace identifier)"
|
||||
required: true
|
||||
jobs:
|
||||
# write-job-details-to-db:
|
||||
# runs-on: ubuntu-latest
|
||||
# steps:
|
||||
# - name: Install mongosh
|
||||
# run: |
|
||||
# sudo apt-get update
|
||||
# sudo apt-get install -y wget gnupg
|
||||
# wget -qO - https://www.mongodb.org/static/pgp/server-5.0.asc | sudo apt-key add -
|
||||
# echo "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu jammy/mongodb-org/5.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-6.0.list
|
||||
# sudo apt-get update
|
||||
# sudo apt-get install -y mongodb-mongosh
|
||||
# - name: Update job data to mongoDB
|
||||
# run: |
|
||||
# # mongosh '' --eval 'db.appsmiht-ce-github-dp-runs.insert( { run_id: ${{ github.run_id }}, uid: ${{ github.event.inputs.uid }}, status: "Started" } )'
|
||||
# mongosh '' --eval 'db.appsmiht-ce-github-dp-runs.update(
|
||||
# { _id: ${{ github.event.inputs.uid }} },
|
||||
# {
|
||||
# $set: {
|
||||
# run_id: ${{ github.run_id }},
|
||||
# status: "BUILD IN PROGRESS"
|
||||
# }
|
||||
# }
|
||||
# )'
|
||||
# #TODO Add mongo URI as secret
|
||||
|
||||
server-build:
|
||||
name: server-build
|
||||
uses: ./.github/workflows/server-build.yml
|
||||
secrets: inherit
|
||||
with:
|
||||
branch: ${{ github.event.inputs.branch }}
|
||||
skip-tests: ${{ github.event.inputs.skip-tests }}
|
||||
|
||||
client-build:
|
||||
name: client-build
|
||||
uses: ./.github/workflows/client-build.yml
|
||||
secrets: inherit
|
||||
with:
|
||||
branch: ${{ github.event.inputs.branch }}
|
||||
skip-tests: ${{ github.event.inputs.skip-tests }}
|
||||
|
||||
rts-build:
|
||||
name: rts-build
|
||||
uses: ./.github/workflows/rts-build.yml
|
||||
secrets: inherit
|
||||
with:
|
||||
branch: ${{ github.event.inputs.branch }}
|
||||
|
||||
push-image:
|
||||
needs: [client-build, rts-build, server-build]
|
||||
runs-on: ubuntu-latest
|
||||
if: success()
|
||||
steps:
|
||||
# - name: Install mongosh
|
||||
# run: |
|
||||
# sudo apt-get update
|
||||
# sudo apt-get install -y wget gnupg
|
||||
# wget -qO - https://www.mongodb.org/static/pgp/server-5.0.asc | sudo apt-key add -
|
||||
# echo "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu jammy/mongodb-org/5.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-6.0.list
|
||||
# sudo apt-get update
|
||||
# sudo apt-get install -y mongodb-mongosh
|
||||
# - name: Update job data to mongoDB
|
||||
# run: |
|
||||
# # mongosh '' --eval 'db.appsmiht-ce-github-dp-runs.insert( { run_id: ${{ github.run_id }}, uid: ${{ github.event.inputs.uid }}, status: "Started" } )'
|
||||
# mongosh '' --eval 'db.appsmiht-ce-github-dp-runs.update(
|
||||
# { _id: ${{ github.event.inputs.uid }} },
|
||||
# {
|
||||
# $set: {
|
||||
# status: "BUILD SUCCESSFUL"
|
||||
# }
|
||||
# }
|
||||
# )'
|
||||
- name: Set up Depot CLI
|
||||
uses: depot/setup-action@v1
|
||||
|
||||
# Check out merge commit
|
||||
- name: Checkout PR
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
ref: "refs/pull/${{ github.event.client_payload.pull_request.number }}/merge"
|
||||
|
||||
# Timestamp will be used to create cache key
|
||||
- id: timestamp
|
||||
run: echo "timestamp=$(date +'%Y-%m-%dT%H:%M:%S')" >> $GITHUB_OUTPUT
|
||||
|
||||
# get Git-hash will be used to create cache key
|
||||
- id: git_hash
|
||||
run: echo "git_hash=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Download the client build artifact
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: client-build
|
||||
path: app/client
|
||||
|
||||
- name: Unpack the client build artifact
|
||||
if: steps.run_result.outputs.run_result != 'success'
|
||||
run: |
|
||||
mkdir -p app/client/build
|
||||
tar -xvf app/client/build.tar -C app/client/build
|
||||
|
||||
- name: Download the server build artifact
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: server-build
|
||||
path: app/server/dist
|
||||
|
||||
- name: Download the rts build artifact
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: rts-dist
|
||||
path: app/client/packages/rts/dist
|
||||
|
||||
- name: Untar the rts folder
|
||||
run: |
|
||||
tar -xvf app/client/packages/rts/dist/rts-dist.tar -C app/client/packages/rts/
|
||||
echo "Cleaning up the tar files"
|
||||
rm app/client/packages/rts/dist/rts-dist.tar
|
||||
|
||||
- name: Push to Docker Hub
|
||||
uses: docker/build-push-action@v1
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_HUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
|
||||
repository: ${{ vars.DOCKER_HUB_ORGANIZATION }}/appsmith-dp
|
||||
tags: ${{ github.event.inputs.sub-domain-name }}
|
||||
outputs:
|
||||
imageHash: ${{ github.event.inputs.sub-domain-name }}
|
||||
|
||||
build-deploy-preview:
|
||||
needs: [push-image]
|
||||
runs-on: ubuntu-latest
|
||||
defaults:
|
||||
run:
|
||||
working-directory: "."
|
||||
|
||||
if: success()
|
||||
steps:
|
||||
- name: Install mongosh
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y wget gnupg
|
||||
wget -qO - https://www.mongodb.org/static/pgp/server-5.0.asc | sudo apt-key add -
|
||||
echo "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu jammy/mongodb-org/5.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-6.0.list
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y mongodb-mongosh
|
||||
- name: Update job data to mongoDB
|
||||
run: |
|
||||
# mongosh '' --eval 'db.appsmiht-ce-github-dp-runs.insert( { run_id: ${{ github.run_id }}, uid: ${{ github.event.inputs.uid }}, status: "Started" } )'
|
||||
# mongosh '' --eval 'db.appsmiht-ce-github-dp-runs.update(
|
||||
# { _id: ${{ github.event.inputs.uid }} },
|
||||
# {
|
||||
# $set: {
|
||||
# status: "DEPLOYMENT IN PROGRESS"
|
||||
# }
|
||||
# }
|
||||
# )'
|
||||
- name: Set up Depot CLI
|
||||
uses: depot/setup-action@v1
|
||||
- name: Checkout PR
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
ref: "refs/pull/${{ github.event.client_payload.pull_request.number }}/merge"
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Install relevant packages
|
||||
run: |
|
||||
which aws
|
||||
sudo apt update -q && sudo apt install -y curl unzip less jq
|
||||
curl -LO https://storage.googleapis.com/kubernetes-release/release/v1.23.6/bin/linux/amd64/kubectl && \
|
||||
sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl && \
|
||||
curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 && \
|
||||
chmod 700 get_helm.sh; ./get_helm.sh
|
||||
|
||||
- name: Deploy Helm chart
|
||||
env:
|
||||
AWS_ROLE_ARN: ${{ secrets.APPSMITH_EKS_AWS_ROLE_ARN }}
|
||||
AWS_ACCESS_KEY_ID: ${{ secrets.APPSMITH_CI_AWS_SECRET_ACCESS_KEY_ID }}
|
||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.APPSMITH_CI_AWS_SECRET_ACCESS_KEY }}
|
||||
IMAGE_HASH: ${{ needs.push-image.outputs.imageHash }}
|
||||
AWS_RELEASE_CERT: ${{ secrets.APPSMITH_AWS_RELEASE_CERT_RELEASE }}
|
||||
DOCKER_HUB_ORGANIZATION: ${{ vars.DOCKER_HUB_ORGANIZATION }}
|
||||
DOCKER_HUB_USERNAME: ${{ secrets.DOCKER_HUB_USERNAME }}
|
||||
DOCKER_HUB_ACCESS_TOKEN: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
|
||||
SUB_DOMAIN_NAME: ${{ github.event.inputs.sub-domain-name }}
|
||||
# RECREATE: ${{ github.event.client_payload.slash_command.args.named.recreate }}
|
||||
DB_USERNAME: ${{ secrets.DB_USERNAME }}
|
||||
DB_PASSWORD: ${{ secrets.DB_PASSWORD }}
|
||||
DB_URL: ${{ secrets.DB_URL }}
|
||||
run: |
|
||||
echo "environment variables set to deploy the image" $IMAGE_HASH
|
||||
/bin/bash ./scripts/build_dp_form_branch.sh
|
||||
|
||||
update-db-on-completion:
|
||||
needs: [build-deploy-preview]
|
||||
runs-on: ubuntu-latest
|
||||
if: success()
|
||||
steps:
|
||||
- run: echo "Workflow completed successfully!"
|
||||
|
||||
# This step creates a comment on the PR with a link to this workflow run.
|
||||
# - name: Install mongosh
|
||||
# run: |
|
||||
# sudo apt-get update
|
||||
# sudo apt-get install -y wget gnupg
|
||||
# wget -qO - https://www.mongodb.org/static/pgp/server-5.0.asc | sudo apt-key add -
|
||||
# echo "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu jammy/mongodb-org/5.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-6.0.list
|
||||
# sudo apt-get update
|
||||
# sudo apt-get install -y mongodb-mongosh
|
||||
# - name: Update job data to mongoDB
|
||||
# run: |
|
||||
# # mongosh '' --eval 'db.appsmiht-ce-github-dp-runs.insert( { run_id: ${{ github.run_id }}, uid: ${{ github.event.inputs.uid }}, status: "Started" } )'
|
||||
# mongosh '' --eval 'db.appsmiht-ce-github-dp-runs.update(
|
||||
# { _id: ${{ github.event.inputs.uid }} },
|
||||
# {
|
||||
# $set: {
|
||||
# status: "DEPLOYMENT COMPLETE"
|
||||
# url: https://${{ github.event.inputs.sub-domain-name }}.dp.appsmith.com
|
||||
# }
|
||||
# }
|
||||
# )'
|
||||
|
||||
1
.github/workflows/build-chromatic.yml
vendored
1
.github/workflows/build-chromatic.yml
vendored
|
|
@ -46,3 +46,4 @@ jobs:
|
|||
projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}
|
||||
workingDir: ./app/client/packages/storybook
|
||||
exitOnceUploaded: true
|
||||
buildScriptName: "build"
|
||||
|
|
|
|||
8
.github/workflows/build-client-server.yml
vendored
8
.github/workflows/build-client-server.yml
vendored
|
|
@ -179,8 +179,8 @@ jobs:
|
|||
|
||||
ci-test-limited-result:
|
||||
needs: [file-check, ci-test-limited]
|
||||
# Only run if the ci-test-limited with matrices step is successful
|
||||
if: needs.ci-test-limited.result != 'skipped'
|
||||
# Only run if the file-check.runId == 0
|
||||
if: always() && needs.file-check.outputs.runId == '0'
|
||||
runs-on: ubuntu-latest
|
||||
defaults:
|
||||
run:
|
||||
|
|
@ -278,8 +278,8 @@ jobs:
|
|||
|
||||
ci-test-limited-result-existing:
|
||||
needs: [file-check, ci-test-limited-existing-docker-image]
|
||||
# Only run if the ci-test-limited with matrices step is successful
|
||||
if: needs.ci-test-limited-existing-docker-image.result != 'skipped'
|
||||
# Only run if the file-check.runId !=0
|
||||
if: always() && needs.file-check.outputs.runId != '0'
|
||||
runs-on: ubuntu-latest
|
||||
defaults:
|
||||
run:
|
||||
|
|
|
|||
6
.github/workflows/build-docker-image.yml
vendored
6
.github/workflows/build-docker-image.yml
vendored
|
|
@ -77,7 +77,11 @@ jobs:
|
|||
if: steps.run_result.outputs.run_result != 'success'
|
||||
working-directory: "."
|
||||
run: |
|
||||
docker build -t cicontainer .
|
||||
declare -a args
|
||||
if [[ "${{ inputs.pr }}" != 0 ]]; then
|
||||
args+=(--cache-from "${{ vars.DOCKER_HUB_ORGANIZATION }}/appsmith-${{ vars.EDITION }}:release")
|
||||
fi
|
||||
docker build -t cicontainer "${args[@]}" .
|
||||
|
||||
# Saving the docker image to tar file
|
||||
- name: Save Docker image to tar file
|
||||
|
|
|
|||
449
.github/workflows/ci-test-hosted.yml
vendored
Normal file
449
.github/workflows/ci-test-hosted.yml
vendored
Normal file
|
|
@ -0,0 +1,449 @@
|
|||
name: Appsmith CI Test Workflow For Hosted Instance
|
||||
|
||||
on:
|
||||
# Schedule to run the workflow everyday at 7 AM or UTC (1.30 AM) only on weekday
|
||||
schedule:
|
||||
- cron: "30 1 * * 1-5"
|
||||
# This line enables manual triggering of this workflow.
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
pr:
|
||||
description: "This is the PR number in case the workflow is being called in a pull request"
|
||||
required: false
|
||||
type: number
|
||||
default: 0
|
||||
workflow_call:
|
||||
inputs:
|
||||
pr:
|
||||
description: "This is the PR number in case the workflow is being called in a pull request"
|
||||
required: false
|
||||
type: number
|
||||
|
||||
jobs:
|
||||
ci-test:
|
||||
runs-on: ubuntu-latest
|
||||
if: |
|
||||
github.event.pull_request.head.repo.full_name == github.repository ||
|
||||
github.event_name == 'push' ||
|
||||
github.event_name == 'workflow_dispatch' ||
|
||||
github.event_name == 'repository_dispatch' ||
|
||||
github.event_name == 'schedule'
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
# Service containers to run with this job. Required for running tests
|
||||
services:
|
||||
# Label used to access the service container
|
||||
redis:
|
||||
# Docker Hub image for Redis
|
||||
image: redis
|
||||
ports:
|
||||
# Opens tcp port 6379 on the host and service container
|
||||
- 6379:6379
|
||||
mongo:
|
||||
image: mongo
|
||||
ports:
|
||||
- 27017:27017
|
||||
|
||||
steps:
|
||||
- name: Set up Depot CLI
|
||||
uses: depot/setup-action@v1
|
||||
|
||||
# Check out merge commit
|
||||
- name: Fork based /ok-to-test checkout
|
||||
if: inputs.pr != 0
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
ref: "refs/pull/${{ inputs.pr }}/merge"
|
||||
|
||||
# Checkout the code in the current branch in case the workflow is called because of a branch push event
|
||||
- name: Checkout the head commit of the branch
|
||||
if: inputs.pr == 0 || github.event_name == 'schedule'
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
# Timestamp will be used to create cache key
|
||||
- id: timestamp
|
||||
run: echo "::set-output name=timestamp::$(date +'%Y-%m-%dT%H:%M:%S')"
|
||||
|
||||
# In case this is second attempt try restoring status of the prior attempt from cache
|
||||
- name: Restore the previous run result
|
||||
id: cache-appsmith
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/run_result
|
||||
key: ${{ github.run_id }}-${{ github.job }}
|
||||
restore-keys: |
|
||||
${{ github.run_id }}-${{ github.job }}
|
||||
|
||||
- name: Get the previous run result
|
||||
if: steps.cache-appsmith.outputs.cache-hit == 'true'
|
||||
id: run_result
|
||||
run: |
|
||||
run_result_env=$(cat ~/run_result)
|
||||
echo "run_result=$run_result_env" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Dump steps context
|
||||
env:
|
||||
STEPS_CONTEXT: ${{ toJson(steps) }}
|
||||
run: echo "$STEPS_CONTEXT"
|
||||
|
||||
# In case this is second attempt try restoring failed tests
|
||||
- name: Restore the previous failed combine result
|
||||
if: steps.run_result.outputs.run_result == 'failedtest'
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: failed_spec_ci
|
||||
path: ~/failed_spec_ci
|
||||
|
||||
# failed_spec_env will contain list of all failed specs
|
||||
# We are using environment variable instead of regular to support multiline
|
||||
- name: Get failed_spec
|
||||
id: failed_spec
|
||||
if: steps.run_result.outputs.run_result == 'failedtest'
|
||||
working-directory: app/client
|
||||
run: |
|
||||
echo "failed_spec_env<<EOF" >> $GITHUB_ENV
|
||||
while IFS= read -r line
|
||||
do
|
||||
spec_name=$(echo $line | awk -F'/' '{print $NF}')
|
||||
failed_spec_env=$(find . -name $spec_name | sed 's|./||')
|
||||
echo "$failed_spec_env" >> $GITHUB_ENV
|
||||
done < ~/failed_spec_ci/failed_spec_ci
|
||||
echo "EOF" >> $GITHUB_ENV
|
||||
|
||||
- if: steps.run_result.outputs.run_result != 'success' && steps.run_result.outputs.run_result != 'failedtest'
|
||||
run: echo "Starting full run" && exit 0
|
||||
|
||||
- if: steps.run_result.outputs.run_result == 'failedtest'
|
||||
run: echo "Rerunning failed tests" && exit 0
|
||||
|
||||
- name: cat run_result
|
||||
run: echo ${{ steps.run_result.outputs.run_result }}
|
||||
|
||||
- name: Use Node.js 16.14.0
|
||||
if: steps.run_result.outputs.run_result != 'success'
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: "16.14.0"
|
||||
|
||||
# actions/setup-node@v3 doesn’t work properly with Yarn 3
|
||||
# when the project lives in a subdirectory: https://github.com/actions/setup-node/issues/488
|
||||
# Restoring the cache manually instead
|
||||
- name: Restore Yarn cache
|
||||
if: steps.run_result.outputs.run_result != 'success'
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: app/client/.yarn/cache
|
||||
key: v1-yarn3-${{ hashFiles('app/client/yarn.lock') }}
|
||||
restore-keys: |
|
||||
v1-yarn3-
|
||||
|
||||
# Install all the dependencies
|
||||
- name: Install dependencies
|
||||
if: steps.run_result.outputs.run_result != 'success'
|
||||
working-directory: app/client
|
||||
run: |
|
||||
yarn install --immutable
|
||||
|
||||
- name: Setting up the cypress tests
|
||||
if: steps.run_result.outputs.run_result != 'success'
|
||||
shell: bash
|
||||
env:
|
||||
APPSMITH_SSL_CERTIFICATE: ${{ secrets.APPSMITH_SSL_CERTIFICATE }}
|
||||
APPSMITH_SSL_KEY: ${{ secrets.APPSMITH_SSL_KEY }}
|
||||
CYPRESS_URL: ${{ secrets.CYPRESS_URL }}
|
||||
CYPRESS_USERNAME: ${{ secrets.CYPRESS_USERNAME }}
|
||||
CYPRESS_PASSWORD: ${{ secrets.CYPRESS_PASSWORD }}
|
||||
CYPRESS_TESTUSERNAME1: ${{ secrets.CYPRESS_TESTUSERNAME1 }}
|
||||
CYPRESS_TESTPASSWORD1: ${{ secrets.CYPRESS_TESTPASSWORD1 }}
|
||||
CYPRESS_TESTUSERNAME2: ${{ secrets.CYPRESS_TESTUSERNAME2 }}
|
||||
CYPRESS_TESTPASSWORD2: ${{ secrets.CYPRESS_TESTPASSWORD1 }}
|
||||
CYPRESS_TESTUSERNAME3: ${{ secrets.CYPRESS_TESTUSERNAME3 }}
|
||||
CYPRESS_TESTPASSWORD3: ${{ secrets.CYPRESS_TESTPASSWORD3 }}
|
||||
CYPRESS_TESTUSERNAME4: ${{ secrets.CYPRESS_TESTUSERNAME4 }}
|
||||
CYPRESS_TESTPASSWORD4: ${{ secrets.CYPRESS_TESTPASSWORD4 }}
|
||||
CYPRESS_S3_ACCESS_KEY: ${{ secrets.CYPRESS_S3_ACCESS_KEY }}
|
||||
CYPRESS_S3_SECRET_KEY: ${{ secrets.CYPRESS_S3_SECRET_KEY }}
|
||||
CYPRESS_GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
||||
CYPRESS_AIRTABLE_BEARER: ${{ secrets.AIRTABLE_BEARER }}
|
||||
CYPRESS_FIRESTORE_PRIVATE_KEY: ${{ secrets.FIRESTORE_PRIVATE_KEY }}
|
||||
CYPRESS_GITHUB_PERSONAL_ACCESS_TOKEN: ${{ secrets.CYPRESS_GITHUB_PERSONAL_ACCESS_TOKEN }}
|
||||
CYPRESS_TEST_GITHUB_USER_NAME: ${{ secrets.CYPRESS_TEST_GITHUB_USER_NAME }}
|
||||
CYPRESS_APPSMITH_OAUTH2_GOOGLE_CLIENT_ID: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_GOOGLE_CLIENT_ID }}
|
||||
CYPRESS_APPSMITH_OAUTH2_GOOGLE_CLIENT_SECRET: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_GOOGLE_CLIENT_SECRET }}
|
||||
CYPRESS_APPSMITH_OAUTH2_GITHUB_CLIENT_ID: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_GITHUB_CLIENT_ID }}
|
||||
CYPRESS_APPSMITH_OAUTH2_GITHUB_CLIENT_SECRET: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_GITHUB_CLIENT_SECRET }}
|
||||
CYPRESS_OAUTH_SAML_EMAIL: ${{ secrets.CYPRESS_OAUTH_SAML_EMAIL }}
|
||||
CYPRESS_OAUTH_SAML_ENTITY_ID: ${{ secrets.CYPRESS_OAUTH_SAML_ENTITY_ID }}
|
||||
CYPRESS_OAUTH_SAML_METADATA_URL: ${{ secrets.CYPRESS_OAUTH_SAML_METADATA_URL }}
|
||||
CYPRESS_OAUTH_SAML_METADATA_XML: ${{ secrets.CYPRESS_OAUTH_SAML_METADATA_XML }}
|
||||
CYPRESS_OAUTH_SAML_PUB_CERT: ${{ secrets.CYPRESS_OAUTH_SAML_PUB_CERT }}
|
||||
CYPRESS_OAUTH_SAML_SSO_URL: ${{ secrets.CYPRESS_OAUTH_SAML_SSO_URL }}
|
||||
CYPRESS_OAUTH_SAML_REDIRECT_URL: ${{ secrets.CYPRESS_OAUTH_SAML_REDIRECT_URL }}
|
||||
CYPRESS_APPSMITH_OAUTH2_OIDC_CLIENT_ID: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_CLIENT_ID }}
|
||||
CYPRESS_APPSMITH_OAUTH2_OIDC_CLIENT_SECRET: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_CLIENT_SECRET }}
|
||||
CYPRESS_APPSMITH_OAUTH2_OIDC_AUTH_URL: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_AUTH_URL }}
|
||||
CYPRESS_APPSMITH_OAUTH2_OIDC_TOKEN_URL: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_TOKEN_URL }}
|
||||
CYPRESS_APPSMITH_OAUTH2_OIDC_USER_INFO: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_USER_INFO }}
|
||||
CYPRESS_APPSMITH_OAUTH2_OIDC_JWKS_URL: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_JWKS_URL }}
|
||||
CYPRESS_EXCLUDE_TAGS: "airgap"
|
||||
CYPRESS_AIRGAPPED: false
|
||||
APPSMITH_DISABLE_TELEMETRY: true
|
||||
APPSMITH_GOOGLE_MAPS_API_KEY: ${{ secrets.APPSMITH_GOOGLE_MAPS_API_KEY }}
|
||||
POSTGRES_PASSWORD: postgres
|
||||
CYPRESS_VERIFY_TIMEOUT: 100000
|
||||
run: |
|
||||
cd app/client
|
||||
chmod a+x ./cypress/setup-test-ci.sh
|
||||
./cypress/setup-test-ci.sh
|
||||
|
||||
- uses: browser-actions/setup-chrome@latest
|
||||
with:
|
||||
chrome-version: stable
|
||||
- run: |
|
||||
echo "BROWSER_PATH=$(which chrome)" >> $GITHUB_ENV
|
||||
|
||||
# - name: Set Pull Request Title
|
||||
# env:
|
||||
# EVENT_COMMITS: ${{ toJson(github.event.commits[0].message) }}
|
||||
# run: |
|
||||
# echo "${{ env.EVENT_COMMITS }}" | awk -F '\\\\n' '{print $1}'
|
||||
|
||||
- name: Save Git values
|
||||
# pass env variables from this step to other steps
|
||||
# using GitHub Actions environment file
|
||||
# https://docs.github.com/en/actions/learn-github-actions/workflow-commands-for-github-actions#environment-files
|
||||
run: |
|
||||
PR_NUMBER=${{ inputs.pr }}
|
||||
echo COMMIT_INFO_BRANCH=$(git rev-parse --abbrev-ref HEAD) >> $GITHUB_ENV
|
||||
echo COMMIT_INFO_MESSAGE=OkToTest run on PR# ${{ inputs.pr }} >> $GITHUB_ENV
|
||||
echo COMMIT_INFO_EMAIL=$(git show -s --pretty=%ae) >> $GITHUB_ENV
|
||||
echo COMMIT_INFO_AUTHOR=$(git show -s --pretty=%an) >> $GITHUB_ENV
|
||||
echo COMMIT_INFO_SHA=$(git show -s --pretty=%H) >> $GITHUB_ENV
|
||||
echo COMMIT_INFO_TIMESTAMP=$(git show -s --pretty=%ct) >> $GITHUB_ENV
|
||||
echo COMMIT_INFO_REMOTE=$(git config --get remote.origin.url) >> $GITHUB_ENV
|
||||
# delete the .git folder afterwords to use the environment values
|
||||
rm -rf .git
|
||||
|
||||
- name: Show Git values
|
||||
run: |
|
||||
echo Branch $COMMIT_INFO_BRANCH
|
||||
echo Message $COMMIT_INFO_MESSAGE
|
||||
echo Email $COMMIT_INFO_EMAIL
|
||||
echo Author $COMMIT_INFO_AUTHOR
|
||||
echo SHA $COMMIT_INFO_SHA
|
||||
echo Timestamp $COMMIT_INFO_TIMESTAMP
|
||||
echo Remote $COMMIT_INFO_REMOTE
|
||||
|
||||
- name: Set Commit Message
|
||||
env:
|
||||
EVENT_COMMITS: ${{ toJson(github.event.commits[0].message) }}
|
||||
run: |
|
||||
if [[ ${{ github.event_name }} == 'schedule' ]]; then
|
||||
echo "COMMIT_INFO_MESSAGE=Scheduled workflow run for gsheet tests" >> $GITHUB_ENV
|
||||
else
|
||||
echo "COMMIT_INFO_MESSAGE=$(echo \"${{ env.EVENT_COMMITS }}\" | awk -F '\\\\n' '{print $1}' | sed 's/^\"//')" >> $GITHUB_ENV
|
||||
fi
|
||||
|
||||
- name: Run the cypress test
|
||||
if: steps.run_result.outputs.run_result != 'success' && steps.run_result.outputs.run_result != 'failedtest'
|
||||
id: cypress_test
|
||||
uses: cypress-io/github-action@v5
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
|
||||
CYPRESS_PROJECT_ID: ${{ secrets.CYPRESS_PROJECT_ID }}
|
||||
CYPRESS_USERNAME: ${{ secrets.CYPRESS_USERNAME }}
|
||||
CYPRESS_PASSWORD: ${{ secrets.CYPRESS_PASSWORD }}
|
||||
CYPRESS_TESTUSERNAME1: ${{ secrets.CYPRESS_TESTUSERNAME1 }}
|
||||
CYPRESS_TESTPASSWORD1: ${{ secrets.CYPRESS_TESTPASSWORD1 }}
|
||||
CYPRESS_TESTUSERNAME2: ${{ secrets.CYPRESS_TESTUSERNAME2 }}
|
||||
CYPRESS_TESTPASSWORD2: ${{ secrets.CYPRESS_TESTPASSWORD1 }}
|
||||
CYPRESS_TESTUSERNAME3: ${{ secrets.CYPRESS_TESTUSERNAME3 }}
|
||||
CYPRESS_TESTPASSWORD3: ${{ secrets.CYPRESS_TESTPASSWORD3 }}
|
||||
CYPRESS_TESTUSERNAME4: ${{ secrets.CYPRESS_TESTUSERNAME4 }}
|
||||
CYPRESS_TESTPASSWORD4: ${{ secrets.CYPRESS_TESTPASSWORD4 }}
|
||||
CYPRESS_S3_ACCESS_KEY: ${{ secrets.CYPRESS_S3_ACCESS_KEY }}
|
||||
CYPRESS_S3_SECRET_KEY: ${{ secrets.CYPRESS_S3_SECRET_KEY }}
|
||||
CYPRESS_GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
||||
CYPRESS_AIRTABLE_BEARER: ${{ secrets.AIRTABLE_BEARER }}
|
||||
CYPRESS_FIRESTORE_PRIVATE_KEY: ${{ secrets.FIRESTORE_PRIVATE_KEY }}
|
||||
CYPRESS_GITHUB_PERSONAL_ACCESS_TOKEN: ${{ secrets.CYPRESS_GITHUB_PERSONAL_ACCESS_TOKEN }}
|
||||
CYPRESS_TEST_GITHUB_USER_NAME: ${{ secrets.CYPRESS_TEST_GITHUB_USER_NAME }}
|
||||
CYPRESS_APPSMITH_OAUTH2_GOOGLE_CLIENT_ID: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_GOOGLE_CLIENT_ID }}
|
||||
CYPRESS_APPSMITH_OAUTH2_GOOGLE_CLIENT_SECRET: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_GOOGLE_CLIENT_SECRET }}
|
||||
CYPRESS_APPSMITH_OAUTH2_GITHUB_CLIENT_ID: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_GITHUB_CLIENT_ID }}
|
||||
CYPRESS_APPSMITH_OAUTH2_GITHUB_CLIENT_SECRET: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_GITHUB_CLIENT_SECRET }}
|
||||
CYPRESS_OAUTH_SAML_EMAIL: ${{ secrets.CYPRESS_OAUTH_SAML_EMAIL }}
|
||||
CYPRESS_OAUTH_SAML_ENTITY_ID: ${{ secrets.CYPRESS_OAUTH_SAML_ENTITY_ID }}
|
||||
CYPRESS_OAUTH_SAML_METADATA_URL: ${{ secrets.CYPRESS_OAUTH_SAML_METADATA_URL }}
|
||||
CYPRESS_OAUTH_SAML_METADATA_XML: ${{ secrets.CYPRESS_OAUTH_SAML_METADATA_XML }}
|
||||
CYPRESS_OAUTH_SAML_PUB_CERT: ${{ secrets.CYPRESS_OAUTH_SAML_PUB_CERT }}
|
||||
CYPRESS_OAUTH_SAML_SSO_URL: ${{ secrets.CYPRESS_OAUTH_SAML_SSO_URL }}
|
||||
CYPRESS_OAUTH_SAML_REDIRECT_URL: ${{ secrets.CYPRESS_OAUTH_SAML_REDIRECT_URL }}
|
||||
CYPRESS_APPSMITH_OAUTH2_OIDC_CLIENT_ID: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_CLIENT_ID }}
|
||||
CYPRESS_APPSMITH_OAUTH2_OIDC_CLIENT_SECRET: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_CLIENT_SECRET }}
|
||||
CYPRESS_APPSMITH_OAUTH2_OIDC_AUTH_URL: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_AUTH_URL }}
|
||||
CYPRESS_APPSMITH_OAUTH2_OIDC_TOKEN_URL: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_TOKEN_URL }}
|
||||
CYPRESS_APPSMITH_OAUTH2_OIDC_USER_INFO: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_USER_INFO }}
|
||||
CYPRESS_APPSMITH_OAUTH2_OIDC_JWKS_URL: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_JWKS_URL }}
|
||||
CYPRESS_EXCLUDE_TAGS: "airgap"
|
||||
CYPRESS_AIRGAPPED: false
|
||||
APPSMITH_DISABLE_TELEMETRY: true
|
||||
APPSMITH_GOOGLE_MAPS_API_KEY: ${{ secrets.APPSMITH_GOOGLE_MAPS_API_KEY }}
|
||||
COMMIT_INFO_MESSAGE: ${{ env.COMMIT_INFO_MESSAGE }}
|
||||
CYPRESS_VERIFY_TIMEOUT: 100000
|
||||
with:
|
||||
browser: ${{ env.BROWSER_PATH }}
|
||||
record: true
|
||||
install: false
|
||||
parallel: true
|
||||
config-file: cypress_ci_hosted.config.ts
|
||||
group: "Chrome-Fat Container tests"
|
||||
spec: "cypress/e2e/GSheet/**/**/*"
|
||||
working-directory: app/client
|
||||
# tag will be either "push" or "pull_request"
|
||||
tag: ${{ github.event_name }}
|
||||
env: "NODE_ENV=development"
|
||||
|
||||
# In case of second attempt only run failed specs
|
||||
- name: Run the cypress test with failed tests
|
||||
if: steps.run_result.outputs.run_result == 'failedtest'
|
||||
id: cypress_test_failedtest
|
||||
uses: cypress-io/github-action@v5
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
|
||||
CYPRESS_PROJECT_ID: ${{ secrets.CYPRESS_PROJECT_ID }}
|
||||
CYPRESS_USERNAME: ${{ secrets.CYPRESS_USERNAME }}
|
||||
CYPRESS_PASSWORD: ${{ secrets.CYPRESS_PASSWORD }}
|
||||
CYPRESS_TESTUSERNAME1: ${{ secrets.CYPRESS_TESTUSERNAME1 }}
|
||||
CYPRESS_TESTPASSWORD1: ${{ secrets.CYPRESS_TESTPASSWORD1 }}
|
||||
CYPRESS_TESTUSERNAME2: ${{ secrets.CYPRESS_TESTUSERNAME2 }}
|
||||
CYPRESS_TESTPASSWORD2: ${{ secrets.CYPRESS_TESTPASSWORD1 }}
|
||||
CYPRESS_TESTUSERNAME3: ${{ secrets.CYPRESS_TESTUSERNAME3 }}
|
||||
CYPRESS_TESTPASSWORD3: ${{ secrets.CYPRESS_TESTPASSWORD3 }}
|
||||
CYPRESS_TESTUSERNAME4: ${{ secrets.CYPRESS_TESTUSERNAME4 }}
|
||||
CYPRESS_TESTPASSWORD4: ${{ secrets.CYPRESS_TESTPASSWORD4 }}
|
||||
CYPRESS_S3_ACCESS_KEY: ${{ secrets.CYPRESS_S3_ACCESS_KEY }}
|
||||
CYPRESS_S3_SECRET_KEY: ${{ secrets.CYPRESS_S3_SECRET_KEY }}
|
||||
CYPRESS_GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
||||
CYPRESS_AIRTABLE_BEARER: ${{ secrets.AIRTABLE_BEARER }}
|
||||
CYPRESS_FIRESTORE_PRIVATE_KEY: ${{ secrets.FIRESTORE_PRIVATE_KEY }}
|
||||
CYPRESS_GITHUB_PERSONAL_ACCESS_TOKEN: ${{ secrets.CYPRESS_GITHUB_PERSONAL_ACCESS_TOKEN }}
|
||||
CYPRESS_TEST_GITHUB_USER_NAME: ${{ secrets.CYPRESS_TEST_GITHUB_USER_NAME }}
|
||||
CYPRESS_APPSMITH_OAUTH2_GOOGLE_CLIENT_ID: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_GOOGLE_CLIENT_ID }}
|
||||
CYPRESS_APPSMITH_OAUTH2_GOOGLE_CLIENT_SECRET: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_GOOGLE_CLIENT_SECRET }}
|
||||
CYPRESS_APPSMITH_OAUTH2_GITHUB_CLIENT_ID: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_GITHUB_CLIENT_ID }}
|
||||
CYPRESS_APPSMITH_OAUTH2_GITHUB_CLIENT_SECRET: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_GITHUB_CLIENT_SECRET }}
|
||||
CYPRESS_OAUTH_SAML_EMAIL: ${{ secrets.CYPRESS_OAUTH_SAML_EMAIL }}
|
||||
CYPRESS_OAUTH_SAML_ENTITY_ID: ${{ secrets.CYPRESS_OAUTH_SAML_ENTITY_ID }}
|
||||
CYPRESS_OAUTH_SAML_METADATA_URL: ${{ secrets.CYPRESS_OAUTH_SAML_METADATA_URL }}
|
||||
CYPRESS_OAUTH_SAML_METADATA_XML: ${{ secrets.CYPRESS_OAUTH_SAML_METADATA_XML }}
|
||||
CYPRESS_OAUTH_SAML_PUB_CERT: ${{ secrets.CYPRESS_OAUTH_SAML_PUB_CERT }}
|
||||
CYPRESS_OAUTH_SAML_SSO_URL: ${{ secrets.CYPRESS_OAUTH_SAML_SSO_URL }}
|
||||
CYPRESS_OAUTH_SAML_REDIRECT_URL: ${{ secrets.CYPRESS_OAUTH_SAML_REDIRECT_URL }}
|
||||
CYPRESS_APPSMITH_OAUTH2_OIDC_CLIENT_ID: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_CLIENT_ID }}
|
||||
CYPRESS_APPSMITH_OAUTH2_OIDC_CLIENT_SECRET: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_CLIENT_SECRET }}
|
||||
CYPRESS_APPSMITH_OAUTH2_OIDC_AUTH_URL: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_AUTH_URL }}
|
||||
CYPRESS_APPSMITH_OAUTH2_OIDC_TOKEN_URL: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_TOKEN_URL }}
|
||||
CYPRESS_APPSMITH_OAUTH2_OIDC_USER_INFO: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_USER_INFO }}
|
||||
CYPRESS_APPSMITH_OAUTH2_OIDC_JWKS_URL: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_JWKS_URL }}
|
||||
CYPRESS_EXCLUDE_TAGS: "airgap"
|
||||
CYPRESS_AIRGAPPED: false
|
||||
APPSMITH_DISABLE_TELEMETRY: true
|
||||
APPSMITH_GOOGLE_MAPS_API_KEY: ${{ secrets.APPSMITH_GOOGLE_MAPS_API_KEY }}
|
||||
COMMIT_INFO_MESSAGE: ${{ env.COMMIT_INFO_MESSAGE }}
|
||||
with:
|
||||
browser: ${{ env.BROWSER_PATH }}
|
||||
record: true
|
||||
install: false
|
||||
parallel: true
|
||||
config-file: cypress_ci_hosted.config.ts
|
||||
group: "Chrome-Fat Container tests"
|
||||
spec: ${{ env.failed_spec_env }}
|
||||
working-directory: app/client
|
||||
# tag will be either "push" or "pull_request"
|
||||
tag: ${{ github.event_name }}
|
||||
env: "NODE_ENV=development"
|
||||
|
||||
- name: Collect CI container logs
|
||||
if: failure()
|
||||
working-directory: "."
|
||||
run: |
|
||||
mkdir -p ~/dockerlogs
|
||||
docker logs appsmith 2>&1 > ~/dockerlogs.txt
|
||||
|
||||
# Upload docker logs
|
||||
- name: Upload failed test list artifact
|
||||
if: failure()
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: dockerlogs
|
||||
path: ~/dockerlogs.txt
|
||||
|
||||
# Set status = failedtest
|
||||
- name: Set fail if there are test failures
|
||||
if: failure()
|
||||
run: |
|
||||
echo "run_result=failedtest" >> $GITHUB_OUTPUT
|
||||
echo "failedtest" > ~/run_result
|
||||
|
||||
# add list failed tests to a file
|
||||
- name: In case of test failures copy them to a file
|
||||
if: failure()
|
||||
run: |
|
||||
cd ${{ github.workspace }}/app/client/cypress/
|
||||
find screenshots -type f \( -iname "*\(attempt 2\).png" -o -iname "*before all hook*" -o -iname "*after all hook*" \) | sed 's/screenshots/cypress\/e2e/g'| sed 's:/[^/]*$::' | sort -u > ~/failed_spec_ci
|
||||
|
||||
# reset the failed_spec_ci file in case of success
|
||||
- name: In case of test success reset the failed_spec_ci file
|
||||
if: success()
|
||||
run: |
|
||||
touch ~/failed_spec_ci
|
||||
|
||||
# Upload failed test list using common path for all matrix job
|
||||
- name: Upload failed test list artifact
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: failed_spec_ci
|
||||
path: ~/failed_spec_ci
|
||||
|
||||
# Force store previous run result to cache
|
||||
- name: Store the previous run result
|
||||
if: failure()
|
||||
uses: actions/cache/save@v3
|
||||
with:
|
||||
path: |
|
||||
~/run_result
|
||||
key: ${{ github.run_id }}-${{ github.job }}
|
||||
|
||||
- name: get cypress url dashboard url
|
||||
id: dashboard_url
|
||||
if: always()
|
||||
run: |
|
||||
if [[ "${{steps.run_result.outputs.run_result }}" != "success" && "${{steps.run_result.outputs.run_result }}" != "failedtest" ]]; then
|
||||
echo ${{ steps.cypress_test.outputs.resultsUrl }} >> ~/cypress_url
|
||||
elif [[ "${{steps.run_result.outputs.run_result }}" == "failedtest" ]]; then
|
||||
echo ${{ steps.cypress_test_failedtest.outputs.resultsUrl }} >> ~/cypress_url
|
||||
fi
|
||||
|
||||
# Upload the log artifact so that it can be used by the test & deploy job in the workflow
|
||||
- name: Upload server logs bundle on failure
|
||||
uses: actions/upload-artifact@v3
|
||||
if: failure()
|
||||
with:
|
||||
name: server-logs-${{ matrix.job }}
|
||||
path: app/server/server-logs.log
|
||||
|
||||
# Set status = success
|
||||
- name: Save the status of the run
|
||||
run: |
|
||||
echo "run_result=success" >> $GITHUB_OUTPUT
|
||||
echo "success" > ~/run_result
|
||||
44
.github/workflows/ci-test.yml
vendored
44
.github/workflows/ci-test.yml
vendored
|
|
@ -44,6 +44,12 @@ jobs:
|
|||
- name: Set up Depot CLI
|
||||
uses: depot/setup-action@v1
|
||||
|
||||
- name: Login to DockerHub
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_HUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
|
||||
|
||||
# Check out merge commit
|
||||
- name: Fork based /ok-to-test checkout
|
||||
if: inputs.pr != 0
|
||||
|
|
@ -135,22 +141,52 @@ jobs:
|
|||
run: |
|
||||
mkdir -p cicontainerlocal/stacks/configuration/
|
||||
|
||||
- name: Run Appsmith & TED docker image
|
||||
- name: Run Appsmith, CS & TED docker image
|
||||
if: steps.run_result.outputs.run_result != 'success'
|
||||
working-directory: "."
|
||||
run: |
|
||||
sudo /etc/init.d/ssh stop ;
|
||||
mkdir -p ~/git-server/keys
|
||||
mkdir -p ~/git-server/repos
|
||||
docker run --name test-event-driver -d -p 22:22 -p 5001:5001 -p 3306:3306 \
|
||||
-p 5432:5432 -p 28017:27017 -p 25:25 -p 5000:5000 -p 3001:3000 -p 6001:6001 --privileged --pid=host --ipc=host --volume /:/host -v ~/git-server/keys:/git-server/keys \
|
||||
-v ~/git-server/repos:/git-server/repos appsmith/test-event-driver:latest
|
||||
docker run --name test-event-driver -d \
|
||||
-p 22:22 -p 5001:5001 -p 3306:3306 -p 5432:5432 -p 28017:27017 -p 25:25 -p 5000:5000 -p 3001:3000 -p 6001:6001 \
|
||||
--privileged --pid=host --ipc=host --volume /:/host -v ~/git-server/keys:/git-server/keys \
|
||||
-v ~/git-server/repos:/git-server/repos \
|
||||
appsmith/test-event-driver:latest
|
||||
docker run --name cloud-services -d -p 8000:80 -p 8090:8090 \
|
||||
--privileged --pid=host --ipc=host --add-host=host.docker.internal:host-gateway\
|
||||
-e APPSMITH_CLOUD_SERVICES_MONGODB_URI=mongodb://host.docker.internal:27017 \
|
||||
-e APPSMITH_CLOUD_SERVICES_MONGODB_DATABASE=cs \
|
||||
-e APPSMITH_CLOUD_SERVICES_MONGODB_AUTH_DATABASE=admin \
|
||||
-e APPSMITH_REDIS_URL=redis://host.docker.internal:6379/ \
|
||||
-e APPSMITH_APPS_API_KEY=dummy-api-key \
|
||||
-e APPSMITH_REMOTE_API_KEY=dummy-api-key \
|
||||
-e APPSMITH_GITHUB_API_KEY=dummy-appsmith-gh-api-key \
|
||||
-e APPSMITH_JWT_SECRET=appsmith-cloud-services-jwt-secret-dummy-key \
|
||||
-e APPSMITH_ENCRYPTION_SALT=encryption-salt \
|
||||
-e APPSMITH_ENCRYPTION_PASSWORD=encryption-password \
|
||||
-e APPSMITH_CLOUD_SERVICES_URL=https://cs-dev.appsmith.com \
|
||||
-e APPSMITH_CUSTOMER_PORTAL_URL=https://dev.appsmith.com \
|
||||
-e APPSMITH_CLOUD_SERVICES_BASE_URL=https://cs-dev.appsmith.com \
|
||||
-e APPSMITH_CLOUD_SERVER_BASE_URL=https://release.app.appsmith.com \
|
||||
-e AUTH0_ISSUER_URL=https://login.release-customer.appsmith.com/ \
|
||||
-e AUTH0_CLIENT_ID=dummy-client-id \
|
||||
-e AUTH0_CLIENT_SECRET=dummy-secret-id \
|
||||
-e AUTH0_AUDIENCE_URL=https://login.local-customer.appsmith.com/ \
|
||||
-e CLOUDSERVICES_URL=cs-dev.appsmith.com \
|
||||
-e CUSTOMER_URL=dev.appsmith.com \
|
||||
-e ENTERPRISE_USER_NAME=ent-user@appsmith.com \
|
||||
-e ENTERPRISE_USER_PASSWORD=ent_user_password \
|
||||
-e ENTERPRISE_ADMIN_NAME=ent-admin@appsmith.com \
|
||||
-e ENTERPRISE_ADMIN_PASSWORD=ent_admin_password \
|
||||
appsmith/cloud-services:release
|
||||
cd cicontainerlocal
|
||||
docker run -d --name appsmith -p 80:80 -p 9001:9001 \
|
||||
-v "$PWD/stacks:/appsmith-stacks" \
|
||||
-e APPSMITH_DISABLE_TELEMETRY=true \
|
||||
-e APPSMITH_INTERCOM_APP_ID=DUMMY_VALUE \
|
||||
-e APPSMITH_CLOUD_SERVICES_BASE_URL=http://host.docker.internal:5001 \
|
||||
-e APPSMITH_CLOUD_SERVICES_SIGNATURE_BASE_URL=http://host.docker.internal:8090 \
|
||||
--add-host=host.docker.internal:host-gateway --add-host=api.segment.io:host-gateway --add-host=t.appsmith.com:host-gateway \
|
||||
cicontainer
|
||||
|
||||
|
|
|
|||
23
.github/workflows/client-build.yml
vendored
23
.github/workflows/client-build.yml
vendored
|
|
@ -1,8 +1,6 @@
|
|||
name: Client Build
|
||||
|
||||
on:
|
||||
# This line enables manual triggering of this workflow.
|
||||
workflow_dispatch:
|
||||
workflow_call:
|
||||
inputs:
|
||||
pr:
|
||||
|
|
@ -19,12 +17,11 @@ on:
|
|||
required: false
|
||||
type: string
|
||||
default: "false"
|
||||
branch:
|
||||
description: "This is the branch to be used for the build."
|
||||
required: false
|
||||
type: string
|
||||
|
||||
pull_request:
|
||||
branches: [release, master]
|
||||
paths:
|
||||
- "app/client/**"
|
||||
- "!app/client/cypress/manual_TestSuite/**"
|
||||
|
||||
# Change the working directory for all the jobs in this workflow
|
||||
defaults:
|
||||
|
|
@ -32,7 +29,7 @@ defaults:
|
|||
working-directory: app/client
|
||||
|
||||
jobs:
|
||||
build:
|
||||
client-build:
|
||||
runs-on: ubuntu-latest-8-cores
|
||||
# Only run this workflow for internally triggered events
|
||||
if: |
|
||||
|
|
@ -58,10 +55,16 @@ jobs:
|
|||
fetch-depth: 0
|
||||
ref: refs/pull/${{ inputs.pr }}/merge
|
||||
|
||||
# Check out the specified branch in case this workflow is called by another workflow
|
||||
- name: Checkout the specified branch
|
||||
if: inputs.pr == 0 && inputs.branch != ''
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
ref: ${{ inputs.branch }}
|
||||
|
||||
# Checkout the code in the current branch in case the workflow is called because of a branch push event
|
||||
- name: Checkout the head commit of the branch
|
||||
if: inputs.pr == 0
|
||||
|
||||
if: inputs.pr == 0 && inputs.branch == ''
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
|
|
|||
25
.github/workflows/client-lint.yml
vendored
25
.github/workflows/client-lint.yml
vendored
|
|
@ -1,8 +1,6 @@
|
|||
name: Client Lint
|
||||
|
||||
on:
|
||||
# This line enables manual triggering of this workflow.
|
||||
workflow_dispatch:
|
||||
workflow_call:
|
||||
inputs:
|
||||
pr:
|
||||
|
|
@ -15,26 +13,14 @@ on:
|
|||
type: string
|
||||
default: "false"
|
||||
|
||||
pull_request:
|
||||
branches: [release, master]
|
||||
paths:
|
||||
- "app/client/**"
|
||||
- "!app/client/cypress/manual_TestSuite/**"
|
||||
|
||||
# Change the working directory for all the jobs in this workflow
|
||||
defaults:
|
||||
run:
|
||||
working-directory: app/client
|
||||
|
||||
jobs:
|
||||
build:
|
||||
client-lint:
|
||||
runs-on: ubuntu-latest-8-cores
|
||||
# Only run this workflow for internally triggered events
|
||||
if: |
|
||||
github.event.pull_request.head.repo.full_name == github.repository ||
|
||||
github.event_name == 'push' ||
|
||||
github.event_name == 'workflow_dispatch' ||
|
||||
github.event_name == 'repository_dispatch'
|
||||
defaults:
|
||||
run:
|
||||
working-directory: app/client
|
||||
|
|
@ -47,20 +33,11 @@ jobs:
|
|||
|
||||
# Check out merge commit with the base branch in case this workflow is invoked via pull request
|
||||
- name: Checkout the merged commit from PR and base branch
|
||||
if: inputs.pr != 0
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
ref: refs/pull/${{ inputs.pr }}/merge
|
||||
|
||||
# Checkout the code in the current branch in case the workflow is called because of a branch push event
|
||||
- name: Checkout the head commit of the branch
|
||||
if: inputs.pr == 0
|
||||
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
# In case this is second attempt try restoring status of the prior attempt from cache
|
||||
- name: Restore the previous run result
|
||||
uses: actions/cache@v3
|
||||
|
|
|
|||
25
.github/workflows/client-unit-tests.yml
vendored
25
.github/workflows/client-unit-tests.yml
vendored
|
|
@ -1,8 +1,6 @@
|
|||
name: Client Unit Tests
|
||||
|
||||
on:
|
||||
# This line enables manual triggering of this workflow.
|
||||
workflow_dispatch:
|
||||
workflow_call:
|
||||
inputs:
|
||||
pr:
|
||||
|
|
@ -15,26 +13,14 @@ on:
|
|||
type: string
|
||||
default: "false"
|
||||
|
||||
pull_request:
|
||||
branches: [release, master]
|
||||
paths:
|
||||
- "app/client/**"
|
||||
- "!app/client/cypress/manual_TestSuite/**"
|
||||
|
||||
# Change the working directory for all the jobs in this workflow
|
||||
defaults:
|
||||
run:
|
||||
working-directory: app/client
|
||||
|
||||
jobs:
|
||||
build:
|
||||
client-unit-tests:
|
||||
runs-on: ubuntu-latest-8-cores
|
||||
# Only run this workflow for internally triggered events
|
||||
if: |
|
||||
github.event.pull_request.head.repo.full_name == github.repository ||
|
||||
github.event_name == 'push' ||
|
||||
github.event_name == 'workflow_dispatch' ||
|
||||
github.event_name == 'repository_dispatch'
|
||||
defaults:
|
||||
run:
|
||||
working-directory: app/client
|
||||
|
|
@ -47,20 +33,11 @@ jobs:
|
|||
|
||||
# Check out merge commit with the base branch in case this workflow is invoked via pull request
|
||||
- name: Checkout the merged commit from PR and base branch
|
||||
if: inputs.pr != 0
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
ref: refs/pull/${{ inputs.pr }}/merge
|
||||
|
||||
# Checkout the code in the current branch in case the workflow is called because of a branch push event
|
||||
- name: Checkout the head commit of the branch
|
||||
if: inputs.pr == 0
|
||||
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
# In case this is second attempt try restoring status of the prior attempt from cache
|
||||
- name: Restore the previous run result
|
||||
uses: actions/cache@v3
|
||||
|
|
|
|||
53
.github/workflows/docs/integration-tests-command.md
vendored
Normal file
53
.github/workflows/docs/integration-tests-command.md
vendored
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
# Appsmith External Integration Test Workflow
|
||||
|
||||
## Workflow Triggers
|
||||
|
||||
This workflow is triggered by the "ok to test" command dispatch. It listens for the `repository_dispatch` event with the type `ok-to-test-command`.
|
||||
|
||||
## Workflow Jobs
|
||||
|
||||
### `notify`
|
||||
|
||||
This job is responsible for notifying about the ongoing test run. It creates a comment on the associated pull request with details about the workflow run, commit, and links to various test results.
|
||||
|
||||
### `server-build`
|
||||
|
||||
The `server-build` job builds the server-side code. It uses the configuration defined in the `.github/workflows/server-build.yml` file. The job is skipped for running tests.
|
||||
|
||||
### `client-build`
|
||||
|
||||
The `client-build` job builds the client-side codebase. It uses the configuration from the `.github/workflows/client-build.yml` file and checks for test files.
|
||||
|
||||
### `rts-build`
|
||||
|
||||
The `rts-build` job builds the "rts" (real-time suggestions) package of the client-side codebase. It uses the configuration defined in the `.github/workflows/rts-build.yml` file.
|
||||
|
||||
### `test-shared-modules`
|
||||
|
||||
The `test-shared-modules` job runs tests for shared modules. It uses the configuration from the `.github/workflows/shared-modules.yml` file.
|
||||
|
||||
### `test-appsmithctl`
|
||||
|
||||
The `test-appsmithctl` job runs tests for the `appsmithctl` utility. It uses the configuration from the `.github/workflows/appsmithctl.yml` file.
|
||||
|
||||
### `build-docker-image`
|
||||
|
||||
The `build-docker-image` job builds and pushes the Docker image for the application. It depends on the successful completion of the `client-build`, `server-build`, and `rts-build` jobs. The Docker image is built with support for both `linux/arm64` and `linux/amd64` platforms.
|
||||
|
||||
### `ci-test`
|
||||
|
||||
The `ci-test` job runs continuous integration tests on the Docker image. It depends on the successful completion of the `build-docker-image` job.
|
||||
|
||||
### `perf-test`
|
||||
|
||||
The `perf-test` job performs performance tests on the Docker image. It depends on the successful completion of the `build-docker-image` job.
|
||||
|
||||
### `ci-test-result`
|
||||
|
||||
The `ci-test-result` job collects the results from the `ci-test` and `perf-test` jobs and generates a report. It always runs, and it processes the test results against known failures. The results are then added as a comment on the associated pull request.
|
||||
|
||||
### `package`
|
||||
|
||||
The `package` job creates a package for release. It runs only if all previous steps are successful and the reference is either the `release` or `master` branch. The package result is then marked as complete.
|
||||
|
||||
Please note that this documentation is based on the information provided in the workflow file. For any specific details and further customization, refer to the actual content of the included `.yml` files for each job.
|
||||
60
.github/workflows/docs/quality-checks.md
vendored
Normal file
60
.github/workflows/docs/quality-checks.md
vendored
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
# GitHub Workflow Documentation: Quality Checks
|
||||
|
||||
## Overview
|
||||
|
||||
The "Quality checks" GitHub workflow is designed to perform various quality checks on your codebase, particularly when there's a pull request targeting the "release" or "master" branches. The workflow makes use of multiple jobs, each focusing on a specific quality check task.
|
||||
|
||||
## Workflow Triggers
|
||||
|
||||
The workflow is triggered automatically when a pull request is opened or updated, but only for pull requests targeting the "release" or "master" branches.
|
||||
|
||||
```yaml
|
||||
on:
|
||||
pull_request:
|
||||
branches: [release, master]
|
||||
```
|
||||
|
||||
## Workflow Jobs
|
||||
|
||||
### `path-filter`
|
||||
|
||||
The first job, named `path-filter`, filters the files changed in the pull request to determine which quality checks are applicable. It identifies files related to the server, client, and Cypress tests and sets appropriate output variables accordingly.
|
||||
|
||||
Steps:
|
||||
|
||||
1. Checks out the merged commit from the pull request and the base branch.
|
||||
2. Uses the `dorny/paths-filter` action to filter files and set output variables for "server," "client," and "cypress" changes.
|
||||
|
||||
### `server-spotless`
|
||||
|
||||
This job, named `server-spotless`, performs a code formatting check on the server-side codebase. It only runs if changes related to the server were detected by the `path-filter` job.
|
||||
|
||||
### `server-unit-tests`
|
||||
|
||||
The `server-unit-tests` job is responsible for running unit tests on the server-side code. It runs if changes related to the server were detected by the `path-filter` job.
|
||||
|
||||
### `client-build`
|
||||
|
||||
The `client-build` job handles the build process for the client-side codebase. It runs if changes related to the client were detected by the `path-filter` job.
|
||||
|
||||
### `client-prettier`
|
||||
|
||||
The `client-prettier` job performs code formatting checks on the client-side codebase using Prettier. It runs if changes related to the client were detected by the `path-filter` job.
|
||||
|
||||
### `client-unit-tests`
|
||||
|
||||
The `client-unit-tests` job runs unit tests for the client-side codebase. It runs if changes related to the client were detected by the `path-filter` job.
|
||||
|
||||
### `client-lint`
|
||||
|
||||
The `client-lint` job checks the client-side code for linting issues. It runs if changes related to the client were detected by the `path-filter` job.
|
||||
|
||||
### `qc-result`
|
||||
|
||||
The final job, `qc-result`, collects the results from all the previous jobs and determines whether the quality checks passed or failed. It always runs, regardless of the results of the previous jobs.
|
||||
|
||||
Steps:
|
||||
|
||||
1. Uses a Bash script to check the results of each job.
|
||||
2. If any of the previous jobs' results are "failure," the script echoes "Quality checks failed" and exits with an error code (1).
|
||||
3. In any other non-failing scenario (skipped steps or successful steps), the script echoes "Quality checks successful" and exits with a success code (0).
|
||||
60
.github/workflows/docs/test-build-docker-image.md
vendored
Normal file
60
.github/workflows/docs/test-build-docker-image.md
vendored
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
# Test, build and push Docker Image
|
||||
|
||||
This GitHub workflow is triggered manually (`workflow_dispatch`) and automatically for pushes to the `release` and `master` branches. It is designed to perform various steps, including building and pushing Docker images, running tests, and creating release images.
|
||||
|
||||
## Workflow Triggers
|
||||
|
||||
The workflow can be manually triggered via the GitHub Actions UI by selecting "Run Workflow" from the actions dropdown. Additionally, it is triggered automatically for pushes to the `release` and `master` branches.
|
||||
|
||||
```yaml
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches: [release, master]
|
||||
paths:
|
||||
- "app/client/**"
|
||||
- "app/server/**"
|
||||
- "app/client/packages/rts/**"
|
||||
- "!app/client/cypress/manual_TestSuite/**"
|
||||
```
|
||||
|
||||
## Workflow Jobs
|
||||
|
||||
### `server-build`
|
||||
|
||||
This job, named `server-build`, is responsible for building the server-side code. It uses the configuration defined in `.github/workflows/server-build.yml`. It inherits secrets from the repository.
|
||||
|
||||
### `client-build`
|
||||
|
||||
The `client-build` job builds the client-side codebase. It uses the configuration from `.github/workflows/client-build.yml` and inherits secrets from the repository.
|
||||
|
||||
### `rts-build`
|
||||
|
||||
The `rts-build` job builds the "rts" (real-time suggestions) package of the client-side codebase. It uses the configuration defined in `.github/workflows/rts-build.yml` and inherits secrets from the repository.
|
||||
|
||||
### `build-docker-image`
|
||||
|
||||
This job, named `build-docker-image`, creates and pushes the Docker image for the application. It is dependent on the success of the `client-build`, `server-build`, and `rts-build` jobs. The Docker image is built with two platforms: `linux/arm64` and `linux/amd64`.
|
||||
|
||||
### `perf-test`
|
||||
|
||||
The `perf-test` job performs performance tests on the Docker image. It depends on the successful completion of the `build-docker-image` job.
|
||||
|
||||
### `ci-test`
|
||||
|
||||
The `ci-test` job runs continuous integration tests on the Docker image. It depends on the successful completion of the `build-docker-image` job.
|
||||
|
||||
### `ci-test-result`
|
||||
|
||||
The `ci-test-result` job collects the results from the `ci-test` job and determines whether the integration tests have passed or failed. It always runs, and it is triggered under the following conditions:
|
||||
- Manual workflow dispatch.
|
||||
- Push event to the repository.
|
||||
- Pull request review event with an approved review and originating from the same repository.
|
||||
|
||||
### `package-release`
|
||||
|
||||
The `package-release` job is responsible for creating a Docker image for release. It runs as soon as the docker image is ready, but only for the `release` branch. It uses OIDC token authentication between Depot and GitHub.
|
||||
|
||||
### `package-master`
|
||||
|
||||
The `package-master` job creates a Docker image for the `master` branch. It runs only if the tests are successful and is used for nightly builds. It uses OIDC token authentication between Depot and GitHub.
|
||||
64
.github/workflows/formatting-checks.yml
vendored
64
.github/workflows/formatting-checks.yml
vendored
|
|
@ -1,64 +0,0 @@
|
|||
name: Formatting checks
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [release, master]
|
||||
|
||||
jobs:
|
||||
path-filter:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
server: ${{ steps.filter.outputs.server }}
|
||||
client: ${{ steps.filter.outputs.client }}
|
||||
steps:
|
||||
# Check out merge commit with the base branch in case this workflow is invoked via pull request
|
||||
- name: Checkout the merged commit from PR and base branch
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
ref: refs/pull/${{ github.event.pull_request.number }}/merge
|
||||
|
||||
- uses: dorny/paths-filter@v2
|
||||
id: filter
|
||||
with:
|
||||
filters: |
|
||||
server:
|
||||
- 'app/server/**'
|
||||
client:
|
||||
- 'app/client/**'
|
||||
|
||||
server-formatting:
|
||||
name: server-formatting
|
||||
needs: path-filter
|
||||
if: needs.path-filter.outputs.server == 'true'
|
||||
uses: ./.github/workflows/server-spotless.yml
|
||||
secrets: inherit
|
||||
with:
|
||||
pr: ${{ github.event.pull_request.number }}
|
||||
|
||||
client-formatting:
|
||||
name: client-formatting
|
||||
needs: path-filter
|
||||
if: needs.path-filter.outputs.client == 'true'
|
||||
uses: ./.github/workflows/client-prettier.yml
|
||||
secrets: inherit
|
||||
with:
|
||||
pr: ${{ github.event.pull_request.number }}
|
||||
|
||||
formatting-result:
|
||||
name: formatting-result
|
||||
needs: [server-formatting, client-formatting]
|
||||
if: always()
|
||||
runs-on: ubuntu-latest
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
steps:
|
||||
- name: Return status for formatting checks
|
||||
run: |
|
||||
if [[ "${{ needs.server-formatting.result }}" == "failure" || "${{ needs.client-formatting.result }}" == "failure" ]]; then
|
||||
echo "Formatting checks failed";
|
||||
exit 1;
|
||||
else
|
||||
echo "Formatting checks successful";
|
||||
exit 0;
|
||||
fi
|
||||
37
.github/workflows/integration-tests-command.yml
vendored
37
.github/workflows/integration-tests-command.yml
vendored
|
|
@ -20,35 +20,14 @@ jobs:
|
|||
Commit: `${{ github.event.client_payload.slash_command.args.named.sha }}`.
|
||||
PR: ${{ github.event.client_payload.pull_request.number }}.
|
||||
Perf tests will be available at <https://app.appsmith.com/app/performance-infra-dashboard/pr-details-638dd7cd2913ba43778b915e?pr=${{ github.event.client_payload.pull_request.number }}&runId=${{ github.run_id }}_${{github.run_attempt}}>
|
||||
changeset:
|
||||
runs-on: ubuntu-latest
|
||||
# Required permissions
|
||||
permissions:
|
||||
pull-requests: read
|
||||
# Set job outputs to values from filter step
|
||||
outputs:
|
||||
backend: ${{ steps.filter.outputs.backend }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: dorny/paths-filter@v2
|
||||
id: filter
|
||||
with:
|
||||
base: ${{ github.event.client_payload.pull_request.base.ref }}
|
||||
ref: ${{ github.event.client_payload.pull_request.head.sha }}
|
||||
filters: |
|
||||
backend:
|
||||
- 'app/server/**'
|
||||
|
||||
|
||||
server-build:
|
||||
name: server-build
|
||||
needs: [changeset]
|
||||
uses: ./.github/workflows/server-build.yml
|
||||
secrets: inherit
|
||||
with:
|
||||
pr: ${{ github.event.client_payload.pull_request.number }}
|
||||
skip-tests: ${{ needs.changeset.outputs.backend == 'false' }}
|
||||
skip-tests: true
|
||||
|
||||
client-build:
|
||||
name: client-build
|
||||
|
|
@ -158,12 +137,18 @@ jobs:
|
|||
path: ~/failed_spec_ci
|
||||
|
||||
# In case for any ci job failure, create combined failed spec
|
||||
- name: "combine all specs for CI"
|
||||
- name: combine all specs for CI
|
||||
id: combine_ci
|
||||
if: needs.ci-test.result != 'success'
|
||||
run: |
|
||||
echo "Debugging: failed specs in ~/failed_spec_ci/failed_spec_ci*"
|
||||
cat ~/failed_spec_ci/failed_spec_ci*
|
||||
cat ~/failed_spec_ci/failed_spec_ci* | sort -u >> ~/combined_failed_spec_ci
|
||||
if [[ -z $(grep '[^[:space:]]' ~/combined_failed_spec_ci) ]] ; then
|
||||
echo "specs_failed=0" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "specs_failed=1" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
# Upload combined failed CI spec list to a file
|
||||
# This is done for debugging.
|
||||
|
|
@ -191,7 +176,7 @@ jobs:
|
|||
echo "EOF" >> $GITHUB_ENV
|
||||
|
||||
- name: Add a comment on the PR with new CI failures
|
||||
if: needs.ci-test.result != 'success'
|
||||
if: needs.ci-test.result != 'success' && steps.combine_ci.outputs.specs_failed == '1'
|
||||
uses: peter-evans/create-or-update-comment@v1
|
||||
with:
|
||||
issue-number: ${{ github.event.client_payload.pull_request.number }}
|
||||
|
|
@ -203,7 +188,7 @@ jobs:
|
|||
To know the list of identified flaky tests - <a href="https://app.appsmith.com/applications/613868bedd7786286ddd4a6a/pages/63ec710e8e503f763651791a" target="_blank">Refer here</a>
|
||||
|
||||
- name: Add a comment on the PR when ci-test is success
|
||||
if: needs.ci-test.result == 'success'
|
||||
if: needs.ci-test.result == 'success' || steps.combine_ci.outputs.specs_failed == '0'
|
||||
uses: peter-evans/create-or-update-comment@v1
|
||||
with:
|
||||
issue-number: ${{ github.event.client_payload.pull_request.number }}
|
||||
|
|
|
|||
|
|
@ -90,17 +90,28 @@ jobs:
|
|||
run: vercel build --yes --token=${{ secrets.VERCEL_TOKEN }}
|
||||
|
||||
- name: Deploy Project Artifacts to Vercel
|
||||
id: set-dpurl
|
||||
run: |
|
||||
vercel deploy --prebuilt --token=${{ secrets.VERCEL_TOKEN }} >> ~/run_result.txt
|
||||
echo "::set-output name=dpurl::$(cat ~/run_result.txt)"
|
||||
vercel deploy --prebuilt --token=${{ secrets.VERCEL_TOKEN }} | tee -a ~/run_result.txt
|
||||
|
||||
- name: vercel-notify
|
||||
uses: peter-evans/create-or-update-comment@v2
|
||||
- uses: actions/github-script@v6
|
||||
with:
|
||||
issue-number: ${{ github.event.client_payload.pull_request.number }}
|
||||
body: |
|
||||
Deploy-Preview-URL: ${{ steps.set-dpurl.outputs.dpurl }}
|
||||
script: |
|
||||
const dpUrl = require("fs").readFileSync(process.env.HOME + "/run_result.txt", "utf8")
|
||||
const bodyLines = ["Deploy-Preview-URL: " + dpUrl]
|
||||
if (context.repo.repo === "appsmith") {
|
||||
bodyLines.push(
|
||||
"",
|
||||
"🚨 *Note*: The release environment runs EE code, so using a frontend-only DP on this repo, will",
|
||||
"likely behave unexpectedly. Consider using a full DP instead.",
|
||||
"[Learn more](https://notion.so/031b87bce3404e3a95240d4c14c82e46).",
|
||||
)
|
||||
}
|
||||
github.rest.issues.createComment({
|
||||
issue_number: context.payload.pull_request.number,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
body: bodyLines.join("\n"),
|
||||
})
|
||||
|
||||
|
||||
push-image:
|
||||
|
|
|
|||
107
.github/workflows/quality-checks.yml
vendored
Normal file
107
.github/workflows/quality-checks.yml
vendored
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
name: Quality checks
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [release, master]
|
||||
|
||||
jobs:
|
||||
path-filter:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
server: ${{ steps.filter.outputs.server }}
|
||||
client: ${{ steps.filter.outputs.client == 'true' && steps.filter.outputs.not-cypress-manual == 'true' }}
|
||||
steps:
|
||||
# Check out merge commit with the base branch in case this workflow is invoked via pull request
|
||||
- name: Checkout the merged commit from PR and base branch
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
ref: refs/pull/${{ github.event.pull_request.number }}/merge
|
||||
|
||||
- uses: dorny/paths-filter@v2
|
||||
id: filter
|
||||
with:
|
||||
filters: |
|
||||
server:
|
||||
- 'app/server/**'
|
||||
client:
|
||||
- 'app/client/**'
|
||||
not-cypress-manual:
|
||||
- '!app/client/cypress/manual_TestSuite/**'
|
||||
|
||||
server-spotless:
|
||||
name: server-spotless
|
||||
needs: path-filter
|
||||
if: needs.path-filter.outputs.server == 'true'
|
||||
uses: ./.github/workflows/server-spotless.yml
|
||||
secrets: inherit
|
||||
with:
|
||||
pr: ${{ github.event.pull_request.number }}
|
||||
|
||||
server-unit-tests:
|
||||
name: server-unit-tests
|
||||
needs: path-filter
|
||||
if: needs.path-filter.outputs.server == 'true'
|
||||
uses: ./.github/workflows/server-build.yml
|
||||
secrets: inherit
|
||||
with:
|
||||
pr: ${{ github.event.pull_request.number }}
|
||||
|
||||
client-build:
|
||||
name: client-build
|
||||
needs: path-filter
|
||||
if: needs.path-filter.outputs.client == 'true'
|
||||
uses: ./.github/workflows/client-build.yml
|
||||
secrets: inherit
|
||||
with:
|
||||
pr: ${{ github.event.pull_request.number }}
|
||||
|
||||
client-prettier:
|
||||
name: client-prettier
|
||||
needs: path-filter
|
||||
if: needs.path-filter.outputs.client == 'true'
|
||||
uses: ./.github/workflows/client-prettier.yml
|
||||
secrets: inherit
|
||||
with:
|
||||
pr: ${{ github.event.pull_request.number }}
|
||||
|
||||
client-unit-tests:
|
||||
name: client-unit-tests
|
||||
needs: path-filter
|
||||
if: needs.path-filter.outputs.client == 'true'
|
||||
uses: ./.github/workflows/client-unit-tests.yml
|
||||
secrets: inherit
|
||||
with:
|
||||
pr: ${{ github.event.pull_request.number }}
|
||||
|
||||
client-lint:
|
||||
name: client-lint
|
||||
needs: path-filter
|
||||
if: needs.path-filter.outputs.client == 'true'
|
||||
uses: ./.github/workflows/client-lint.yml
|
||||
secrets: inherit
|
||||
with:
|
||||
pr: ${{ github.event.pull_request.number }}
|
||||
|
||||
qc-result:
|
||||
name: qc-result
|
||||
needs: [server-spotless, server-unit-tests, client-build, client-prettier, client-unit-tests, client-lint]
|
||||
if: always()
|
||||
runs-on: ubuntu-latest
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
steps:
|
||||
- name: Return status for quality checks
|
||||
run: |
|
||||
if [[ "${{ needs.server-spotless.result }}" == "failure" || \
|
||||
"${{ needs.server-unit-tests.result }}" == "failure" || \
|
||||
"${{ needs.client-build.result }}" == "failure" || \
|
||||
"${{ needs.client-prettier.result }}" == "failure" || \
|
||||
"${{ needs.client-unit-tests.result }}" == "failure" || \
|
||||
"${{ needs.client-lint.result }}" == "failure" ]]; then
|
||||
echo "Quality checks failed";
|
||||
exit 1;
|
||||
else
|
||||
echo "Quality checks successful";
|
||||
exit 0;
|
||||
fi
|
||||
14
.github/workflows/rts-build.yml
vendored
14
.github/workflows/rts-build.yml
vendored
|
|
@ -10,6 +10,10 @@ on:
|
|||
description: "This is the PR number in case the workflow is being called in a pull request"
|
||||
required: false
|
||||
type: number
|
||||
branch:
|
||||
description: "This is the branch to be used for the build."
|
||||
required: false
|
||||
type: string
|
||||
|
||||
pull_request:
|
||||
branches: [release, master]
|
||||
|
|
@ -44,9 +48,17 @@ jobs:
|
|||
fetch-depth: 0
|
||||
ref: refs/pull/${{ inputs.pr }}/merge
|
||||
|
||||
# Check out the specified branch in case this workflow is called by another workflow
|
||||
- name: Checkout the specified branch
|
||||
if: inputs.pr == 0 && inputs.branch != ''
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
ref: ${{ inputs.branch }}
|
||||
|
||||
|
||||
# Checkout the code in the current branch in case the workflow is called because of a branch push event
|
||||
- name: Checkout the head commit of the branch
|
||||
if: inputs.pr == 0
|
||||
if: inputs.pr == 0 && inputs.branch == ''
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
|
|
|||
29
.github/workflows/server-build.yml
vendored
29
.github/workflows/server-build.yml
vendored
|
|
@ -2,8 +2,6 @@
|
|||
name: Appsmith Server Workflow
|
||||
|
||||
on:
|
||||
# This line enables manual triggering of this workflow.
|
||||
workflow_dispatch:
|
||||
workflow_call:
|
||||
inputs:
|
||||
pr:
|
||||
|
|
@ -15,12 +13,10 @@ on:
|
|||
required: false
|
||||
type: string
|
||||
default: "false"
|
||||
|
||||
|
||||
pull_request:
|
||||
branches: [release, master]
|
||||
paths:
|
||||
- "app/server/**"
|
||||
branch:
|
||||
description: "This is the branch to be used for the build."
|
||||
required: false
|
||||
type: string
|
||||
|
||||
# Change the working directory for all the jobs in this workflow
|
||||
defaults:
|
||||
|
|
@ -28,14 +24,8 @@ defaults:
|
|||
working-directory: app/server
|
||||
|
||||
jobs:
|
||||
build:
|
||||
server-unit-tests:
|
||||
runs-on: ubuntu-latest-8-cores
|
||||
# Only run this workflow for internally triggered events
|
||||
if: |
|
||||
github.event.pull_request.head.repo.full_name == github.repository ||
|
||||
github.event_name == 'push' ||
|
||||
github.event_name == 'workflow_dispatch' ||
|
||||
github.event_name == 'repository_dispatch'
|
||||
|
||||
# Service containers to run with this job. Required for running tests
|
||||
services:
|
||||
|
|
@ -60,10 +50,17 @@ jobs:
|
|||
fetch-depth: 0
|
||||
ref: refs/pull/${{ inputs.pr }}/merge
|
||||
|
||||
# Check out the specified branch in case this workflow is called by another workflow
|
||||
- name: Checkout the specified branch
|
||||
if: inputs.pr == 0 && inputs.branch != ''
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
ref: ${{ inputs.branch }}
|
||||
|
||||
# Checkout the code in the current branch in case the workflow is called because of a branch push event
|
||||
- name: Check out the head commit of the branch
|
||||
uses: actions/checkout@v3
|
||||
if: inputs.pr == 0
|
||||
if: inputs.pr == 0 && inputs.branch == ''
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
|
|
|
|||
119
.github/workflows/test-build-docker-image.yml
vendored
119
.github/workflows/test-build-docker-image.yml
vendored
|
|
@ -135,37 +135,19 @@ jobs:
|
|||
exit 1;
|
||||
fi
|
||||
|
||||
package:
|
||||
needs: ci-test
|
||||
|
||||
package-release:
|
||||
needs: build-docker-image
|
||||
runs-on: ubuntu-latest
|
||||
# Set permissions since we're using OIDC token authentication between Depot and GitHub
|
||||
permissions:
|
||||
contents: read
|
||||
id-token: write
|
||||
|
||||
# Run this job irrespective of tests failing, if this is the release branch; or only if the tests pass, if this is the master branch.
|
||||
if: (success() && github.ref == 'refs/heads/master') ||
|
||||
( always() &&
|
||||
(
|
||||
github.event_name == 'workflow_dispatch' ||
|
||||
github.event_name == 'push' ||
|
||||
(
|
||||
github.event_name == 'pull_request_review' &&
|
||||
github.event.review.state == 'approved' &&
|
||||
github.event.pull_request.head.repo.full_name == github.repository
|
||||
)
|
||||
) &&
|
||||
github.ref == 'refs/heads/release'
|
||||
)
|
||||
# Run this job as soon as the docker image is ready, if this is the release branch
|
||||
if: ( always() && github.ref == 'refs/heads/release' )
|
||||
|
||||
steps:
|
||||
# Checkout the code
|
||||
- name: Checkout the merged commit from PR and base branch
|
||||
if: github.event_name == 'pull_request_review'
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
ref: refs/pull/${{ github.event.pull_request.number }}/merge
|
||||
|
||||
- name: Checkout the head commit of the branch
|
||||
if: github.event_name == 'push' || github.event_name == 'workflow_dispatch'
|
||||
uses: actions/checkout@v3
|
||||
|
|
@ -200,12 +182,6 @@ jobs:
|
|||
echo "Cleaning up the tar files"
|
||||
rm app/client/packages/rts/dist/rts-dist.tar
|
||||
|
||||
# Here, the GITHUB_REF is of type /refs/head/<branch_name>. We extract branch_name from this by removing the
|
||||
# first 11 characters. This can be used to build images for several branches
|
||||
- name: Get the version to tag the Docker image
|
||||
id: vars
|
||||
run: echo tag=$(echo ${GITHUB_REF:11}) >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Set up Depot CLI
|
||||
uses: depot/setup-action@v1
|
||||
|
||||
|
|
@ -216,7 +192,7 @@ jobs:
|
|||
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
|
||||
|
||||
- name: Build and push release image to Docker Hub
|
||||
if: success() && github.ref == 'refs/heads/release' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch')
|
||||
if: success()
|
||||
uses: depot/build-push-action@v1
|
||||
with:
|
||||
context: .
|
||||
|
|
@ -225,10 +201,65 @@ jobs:
|
|||
build-args: |
|
||||
APPSMITH_SEGMENT_CE_KEY=${{ secrets.APPSMITH_SEGMENT_CE_KEY_RELEASE }}
|
||||
tags: |
|
||||
${{ vars.DOCKER_HUB_ORGANIZATION }}/appsmith-ce:${{steps.vars.outputs.tag}}
|
||||
${{ vars.DOCKER_HUB_ORGANIZATION }}/appsmith-ce:release
|
||||
|
||||
package-master:
|
||||
needs: ci-test
|
||||
runs-on: ubuntu-latest
|
||||
# Set permissions since we're using OIDC token authentication between Depot and GitHub
|
||||
permissions:
|
||||
contents: read
|
||||
id-token: write
|
||||
|
||||
# Run this job irrespective of tests failing, if this is the release branch; or only if the tests pass, if this is the master branch.
|
||||
if: ( success() && github.ref == 'refs/heads/master' )
|
||||
|
||||
steps:
|
||||
- name: Checkout the head commit of the branch
|
||||
if: github.event_name == 'push' || github.event_name == 'workflow_dispatch'
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Download the react build artifact
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: client-build
|
||||
path: app/client
|
||||
|
||||
- name: Unpack the client build artifact
|
||||
if: steps.run_result.outputs.run_result != 'success'
|
||||
run: |
|
||||
mkdir -p app/client/build
|
||||
tar -xvf app/client/build.tar -C app/client/build
|
||||
|
||||
- name: Download the server build artifact
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: server-build
|
||||
path: app/server/dist
|
||||
|
||||
- name: Download the rts build artifact
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: rts-dist
|
||||
path: app/client/packages/rts/dist
|
||||
|
||||
- name: Untar the rts folder
|
||||
run: |
|
||||
tar -xvf app/client/packages/rts/dist/rts-dist.tar -C app/client/packages/rts/
|
||||
echo "Cleaning up the tar files"
|
||||
rm app/client/packages/rts/dist/rts-dist.tar
|
||||
|
||||
- name: Set up Depot CLI
|
||||
uses: depot/setup-action@v1
|
||||
|
||||
- name: Login to DockerHub
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_HUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
|
||||
|
||||
- name: Build and push master image to Docker Hub with commit tag
|
||||
if: success() && github.ref == 'refs/heads/master' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch')
|
||||
if: success()
|
||||
uses: depot/build-push-action@v1
|
||||
with:
|
||||
context: .
|
||||
|
|
@ -238,26 +269,4 @@ jobs:
|
|||
APPSMITH_SEGMENT_CE_KEY=${{ secrets.APPSMITH_SEGMENT_CE_KEY }}
|
||||
tags: |
|
||||
${{ vars.DOCKER_HUB_ORGANIZATION }}/appsmith-ce:${{ github.sha }}
|
||||
${{ vars.DOCKER_HUB_ORGANIZATION }}/appsmith-ce:nightly
|
||||
|
||||
# - name: Check and push CI image to Docker Hub with commit tag
|
||||
# if: success() && (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/release') && (github.event_name == 'push' || github.event_name == 'workflow_dispatch')
|
||||
# working-directory: "."
|
||||
# run: |
|
||||
# if [[ "${{ github.ref }}" == "refs/heads/master" ]]; then
|
||||
# tag=nightly
|
||||
# else
|
||||
# tag="${{ steps.vars.outputs.tag }}"
|
||||
# fi
|
||||
# docker run --detach --publish 80:80 --name appsmith \
|
||||
# "${{ vars.DOCKER_HUB_ORGANIZATION }}/appsmith-ce:$tag"
|
||||
# sleep 180
|
||||
# cd deploy/docker
|
||||
# if bash run-test.sh; then
|
||||
# echo "Fat container test passed. Pushing image."
|
||||
# docker push --all-tags ${{ vars.DOCKER_HUB_ORGANIZATION }}/appsmith-ce
|
||||
# else
|
||||
# echo "Fat container test FAILED. Not pushing image."
|
||||
# # Temporarily pushing even if test fails.
|
||||
# docker push --all-tags ${{ vars.DOCKER_HUB_ORGANIZATION }}/appsmith-ce
|
||||
# fi
|
||||
${{ vars.DOCKER_HUB_ORGANIZATION }}/appsmith-ce:nightly
|
||||
|
|
@ -27,7 +27,7 @@ RUN curl --silent --show-error --location https://www.mongodb.org/static/pgp/ser
|
|||
&& echo "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/5.0 multiverse" | tee /etc/apt/sources.list.d/mongodb-org-5.0.list \
|
||||
&& curl --silent --show-error --location https://deb.nodesource.com/setup_16.x | bash - \
|
||||
&& echo "deb http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" | tee /etc/apt/sources.list.d/pgdg.list \
|
||||
&& curl --silent --show-error --location https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add - \
|
||||
&& curl --silent --show-error --location https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add - \
|
||||
&& apt update \
|
||||
&& apt-get install --no-install-recommends --yes mongodb-org=5.0.14 nodejs redis build-essential postgresql-13 \
|
||||
&& apt-get clean \
|
||||
|
|
@ -51,6 +51,10 @@ VOLUME [ "/appsmith-stacks" ]
|
|||
# Add backend server - Application Layer
|
||||
ARG JAR_FILE=./app/server/dist/server-*.jar
|
||||
ARG PLUGIN_JARS=./app/server/dist/plugins/*.jar
|
||||
|
||||
ARG APPSMITH_CLOUD_SERVICES_BASE_URL
|
||||
ENV APPSMITH_CLOUD_SERVICES_BASE_URL=${APPSMITH_CLOUD_SERVICES_BASE_URL}
|
||||
|
||||
ARG APPSMITH_SEGMENT_CE_KEY
|
||||
ENV APPSMITH_SEGMENT_CE_KEY=${APPSMITH_SEGMENT_CE_KEY}
|
||||
#Create the plugins directory
|
||||
|
|
|
|||
16
README.md
16
README.md
|
|
@ -182,8 +182,8 @@ Lets build great software together.
|
|||
[](https://github.com/aswathkk)
|
||||
[](https://github.com/sbalaji1192)
|
||||
[](https://github.com/SatishGandham)
|
||||
[](https://github.com/rahulramesha)
|
||||
[](https://github.com/sarojsarab)
|
||||
[](https://github.com/rahulramesha)
|
||||
[](https://github.com/prsidhu)
|
||||
[](https://github.com/yatinappsmith)
|
||||
[](https://github.com/somangshu)
|
||||
|
|
@ -191,26 +191,26 @@ Lets build great software together.
|
|||
[](https://github.com/pranavkanade)
|
||||
[](https://github.com/AmanAgarwal041)
|
||||
[](https://github.com/Parthvi12)
|
||||
[](https://github.com/albinAppsmith)
|
||||
[](https://github.com/ayushpahwa)
|
||||
[](https://github.com/albinAppsmith)
|
||||
[](https://github.com/marks0351)
|
||||
[](https://github.com/berzerkeer)
|
||||
[](https://github.com/sneha122)
|
||||
[](https://github.com/pratapaprasanna)
|
||||
[](https://github.com/ashit-rath)
|
||||
[](https://github.com/keyurparalkar)
|
||||
[](https://github.com/pratapaprasanna)
|
||||
[](https://github.com/Vijetha-Kaja)
|
||||
[](https://github.com/ChandanBalajiBP)
|
||||
[](https://github.com/vishnu-gp)
|
||||
[](https://github.com/areyabhishek)
|
||||
[](https://github.com/nsarupr)
|
||||
[](https://github.com/dhruvikn)
|
||||
[](https://github.com/sum35h)
|
||||
[](https://github.com/sondermanish)
|
||||
[](https://github.com/sum35h)
|
||||
[](https://github.com/dhruvikn)
|
||||
[](https://github.com/NilanshBansal)
|
||||
[](https://github.com/rajatagrawal)
|
||||
[](https://github.com/megaconfidence)
|
||||
[](https://github.com/tanvibhakta)
|
||||
[](https://github.com/rajatagrawal)
|
||||
[](https://github.com/subrata71)
|
||||
[](https://github.com/Druthi)
|
||||
[](https://github.com/ichik)
|
||||
|
|
@ -218,17 +218,17 @@ Lets build great software together.
|
|||
[](https://github.com/vsvamsi1)
|
||||
[](https://github.com/rahulbarwal)
|
||||
[](https://github.com/ankitsrivas14)
|
||||
[](https://github.com/tkAppsmith)
|
||||
[](https://github.com/dipyamanbiswas07)
|
||||
[](https://github.com/rohitagarwal88)
|
||||
[](https://github.com/tkAppsmith)
|
||||
[](https://github.com/brayn003)
|
||||
[](https://github.com/ramsaptami)
|
||||
[](https://github.com/Pranay105)
|
||||
[](https://github.com/gitstart-appsmith)
|
||||
[](https://github.com/rohan-arthur)
|
||||
[](https://github.com/sharanya-appsmith)
|
||||
[](https://github.com/vivonk)
|
||||
[](https://github.com/kocharrahul7)
|
||||
[](https://github.com/sharanya-appsmith)
|
||||
[](https://github.com/abm17)
|
||||
[](https://github.com/jacquesikot)
|
||||
[](https://github.com/RakshaKShetty)
|
||||
|
|
|
|||
300
app/client/cypress/e2e/GSheet/AllAccess_Spec.ts
Normal file
300
app/client/cypress/e2e/GSheet/AllAccess_Spec.ts
Normal file
|
|
@ -0,0 +1,300 @@
|
|||
/// <reference types="Cypress" />
|
||||
import { GSHEET_DATA } from "../../fixtures/test-data-gsheet";
|
||||
import {
|
||||
homePage,
|
||||
gsheetHelper,
|
||||
dataSources,
|
||||
agHelper,
|
||||
entityExplorer,
|
||||
} from "../../support/Objects/ObjectsCore";
|
||||
|
||||
const workspaceName = "gsheet apps";
|
||||
const dataSourceName = "gsheet";
|
||||
let appName = "gsheet-app";
|
||||
let spreadSheetName = "test-sheet";
|
||||
describe("GSheet-Functional Tests With All Access", function () {
|
||||
before("Setup app and spreadsheet", function () {
|
||||
//Add a new app and an add new spreadsheet query
|
||||
//Setting up the spreadsheet name
|
||||
const uuid = Cypress._.random(0, 10000);
|
||||
spreadSheetName = spreadSheetName + "_" + uuid;
|
||||
appName = appName + "-" + uuid;
|
||||
|
||||
//Adding query to insert a new spreadsheet
|
||||
homePage.NavigateToHome();
|
||||
homePage.CreateAppInWorkspace(workspaceName);
|
||||
homePage.RenameApplication(appName);
|
||||
gsheetHelper.AddNewSpreadsheetQuery(
|
||||
dataSourceName,
|
||||
spreadSheetName,
|
||||
JSON.stringify([GSHEET_DATA[0]]),
|
||||
);
|
||||
cy.get("@postExecute").then((interception: any) => {
|
||||
expect(
|
||||
interception.response.body.data.body.properties.title,
|
||||
).to.deep.equal(spreadSheetName);
|
||||
});
|
||||
});
|
||||
|
||||
it("1. Add and verify fetch details query", () => {
|
||||
entityExplorer.CreateNewDsQuery(dataSourceName);
|
||||
agHelper.RenameWithInPane("Fetch_Details");
|
||||
dataSources.ValidateNSelectDropdown(
|
||||
"Operation",
|
||||
"Fetch Many",
|
||||
"Fetch Details",
|
||||
);
|
||||
dataSources.ValidateNSelectDropdown("Entity", "Spreadsheet");
|
||||
agHelper.Sleep(500);
|
||||
dataSources.ValidateNSelectDropdown("Spreadsheet", "", spreadSheetName);
|
||||
dataSources.RunQuery();
|
||||
cy.get("@postExecute").then((interception: any) => {
|
||||
expect(interception.response.body.data.body.name).to.deep.equal(
|
||||
spreadSheetName,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it("2. Verify Insert one and Insert many queries", () => {
|
||||
// add insert one query and verify
|
||||
gsheetHelper.AddInsertOrUpdateQuery(
|
||||
"Insert One",
|
||||
dataSourceName,
|
||||
spreadSheetName,
|
||||
JSON.stringify(GSHEET_DATA[1]),
|
||||
);
|
||||
cy.get("@postExecute").then((interception: any) => {
|
||||
expect(interception.response.body.data.body.message).to.deep.equal(
|
||||
"Inserted row successfully!",
|
||||
);
|
||||
});
|
||||
|
||||
// add insert many query and verify
|
||||
gsheetHelper.AddInsertOrUpdateQuery(
|
||||
"Insert Many",
|
||||
dataSourceName,
|
||||
spreadSheetName,
|
||||
JSON.stringify(GSHEET_DATA.slice(2, 10)),
|
||||
);
|
||||
cy.get("@postExecute").then((interception: any) => {
|
||||
expect(interception.response.body.data.body.message).to.deep.equal(
|
||||
"Inserted rows successfully!",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it("3. Verify Update one and Update many queries", () => {
|
||||
// add update one query and verify
|
||||
gsheetHelper.AddInsertOrUpdateQuery(
|
||||
"Update One",
|
||||
dataSourceName,
|
||||
spreadSheetName,
|
||||
JSON.stringify(GSHEET_DATA[1]),
|
||||
);
|
||||
cy.get("@postExecute").then((interception: any) => {
|
||||
expect(interception.response.body.data.body.message).to.deep.equal(
|
||||
"Updated sheet successfully!",
|
||||
);
|
||||
});
|
||||
|
||||
// add update many query and verify
|
||||
gsheetHelper.AddInsertOrUpdateQuery(
|
||||
"Update Many",
|
||||
dataSourceName,
|
||||
spreadSheetName,
|
||||
JSON.stringify(GSHEET_DATA.slice(2, 4)),
|
||||
);
|
||||
cy.get("@postExecute").then((interception: any) => {
|
||||
expect(interception.response.body.data.body.message).to.deep.equal(
|
||||
"Updated sheet successfully!",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it("4. Verify Fetch many query", () => {
|
||||
// Add simple Fetch many query and verify
|
||||
gsheetHelper.EnterBasicQueryValues(
|
||||
"Fetch Many",
|
||||
dataSourceName,
|
||||
spreadSheetName,
|
||||
);
|
||||
dataSources.RunQueryNVerifyResponseViews(GSHEET_DATA.length);
|
||||
dataSources.AssertQueryTableResponse(0, GSHEET_DATA[0].uniq_id);
|
||||
dataSources.AssertQueryTableResponse(1, "ホーンビィ 2014 カタログ"); // Asserting other language
|
||||
dataSources.AssertQueryTableResponse(2, "₹, $, €, ¥, £"); // Asserting different symbols
|
||||
dataSources.AssertQueryTableResponse(3, "!@#$%^&*"); // Asserting special chars
|
||||
|
||||
// Update query to fetch only 1 column and verify
|
||||
gsheetHelper.SelectMultiDropDownValue("Columns", "product_name");
|
||||
dataSources.RunQuery();
|
||||
dataSources.RunQueryNVerifyResponseViews(GSHEET_DATA.length);
|
||||
dataSources.AssertQueryTableResponse(0, GSHEET_DATA[0].product_name);
|
||||
|
||||
//Remove column filter and add Sort By Ascending and verify
|
||||
gsheetHelper.SelectMultiDropDownValue("Columns", "product_name"); //unselect the Columns dd value
|
||||
agHelper.EnterValue("price", {
|
||||
propFieldName: "",
|
||||
directInput: false,
|
||||
inputFieldName: "Sort By",
|
||||
});
|
||||
dataSources.RunQueryNVerifyResponseViews(GSHEET_DATA.length);
|
||||
dataSources.AssertQueryTableResponse(0, "5afbaf65680c9f378af5b3a3ae22427e");
|
||||
dataSources.AssertQueryTableResponse(
|
||||
1,
|
||||
"ラーニング カーブ チャギントン インタラクティブ チャッツワース",
|
||||
); // Asserting other language
|
||||
dataSources.AssertQueryTableResponse(2, "₹, $, €, ¥, £"); // Asserting different symbols
|
||||
dataSources.AssertQueryTableResponse(3, "!@#$%^&*"); // Asserting special chars
|
||||
|
||||
// Sort by descending and verify
|
||||
dataSources.ClearSortByOption(); //clearing previous sort option
|
||||
dataSources.EnterSortByValues("price", "Descending");
|
||||
dataSources.RunQuery();
|
||||
dataSources.RunQueryNVerifyResponseViews(GSHEET_DATA.length);
|
||||
dataSources.AssertQueryTableResponse(
|
||||
1,
|
||||
"ホーンビー ゲージ ウェスタン エクスプレス デジタル トレイン セット (eLink および TTS ロコ トレイン セット付き)",
|
||||
); // Asserting other language
|
||||
dataSources.AssertQueryTableResponse(
|
||||
4,
|
||||
"Hornby Gauge Western Express Digital Train Set with eLink and TTS Loco Train Set",
|
||||
);
|
||||
|
||||
// Filter by where clause and verify
|
||||
agHelper.TypeDynamicInputValueNValidate(
|
||||
"price",
|
||||
dataSources._nestedWhereClauseKey(0),
|
||||
);
|
||||
agHelper.TypeDynamicInputValueNValidate(
|
||||
"100",
|
||||
dataSources._nestedWhereClauseValue(0),
|
||||
);
|
||||
dataSources.RunQuery();
|
||||
dataSources.RunQueryNVerifyResponseViews(8);
|
||||
dataSources.AssertQueryTableResponse(0, "87bbb472ef9d90dcef140a551665c929");
|
||||
|
||||
// Currently commenting this until https://github.com/appsmithorg/appsmith/issues/25447 is fixed.
|
||||
// Filter by cell range and verify
|
||||
// dataSources.ValidateNSelectDropdown(
|
||||
// "Filter Format",
|
||||
// "Where Clause",
|
||||
// "Cell range",
|
||||
// );
|
||||
// agHelper.EnterValue("A2:A5", {
|
||||
// propFieldName: "",
|
||||
// directInput: false,
|
||||
// inputFieldName: "Cell range",
|
||||
// });
|
||||
// dataSources.RunQuery();
|
||||
// dataSources.RunQueryNVerifyResponseViews(8);
|
||||
// dataSources.AssertQueryTableResponse(0, "eac7efa5dbd3d667f26eb3d3ab504464");
|
||||
});
|
||||
|
||||
it("5. Update a record which is not present and verify the error", () => {
|
||||
//preparing data
|
||||
let data = GSHEET_DATA[1];
|
||||
data.rowIndex = "15";
|
||||
|
||||
// add update one query and verify
|
||||
gsheetHelper.EnterBasicQueryValues(
|
||||
"Update One",
|
||||
dataSourceName,
|
||||
spreadSheetName,
|
||||
false,
|
||||
);
|
||||
agHelper.EnterValue(JSON.stringify(data), {
|
||||
propFieldName: "",
|
||||
directInput: false,
|
||||
inputFieldName: "Update row object",
|
||||
});
|
||||
dataSources.RunQuery({
|
||||
expectedStatus: false,
|
||||
});
|
||||
cy.get("@postExecute").then((interception: any) => {
|
||||
expect(interception.response.body.data.body).to.deep.equal(
|
||||
"No data found at this row index.",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it("6. Convert field to JS and verify", () => {
|
||||
// Switch js on sheet name then run query and verify
|
||||
gsheetHelper.EnterBasicQueryValues(
|
||||
"Fetch Many",
|
||||
dataSourceName,
|
||||
spreadSheetName,
|
||||
false,
|
||||
);
|
||||
agHelper.GetNClick(
|
||||
dataSources._getJSONswitchLocator("Sheet name"),
|
||||
0,
|
||||
true,
|
||||
);
|
||||
dataSources.RunQueryNVerifyResponseViews(10);
|
||||
dataSources.AssertQueryTableResponse(0, "eac7efa5dbd3d667f26eb3d3ab504464");
|
||||
|
||||
//Enter a wrong sheet name then run query and verify
|
||||
agHelper.EnterValue("Sheet 2", {
|
||||
propFieldName: "",
|
||||
directInput: false,
|
||||
inputFieldName: "Sheet name",
|
||||
});
|
||||
dataSources.RunQuery({
|
||||
expectedStatus: false,
|
||||
});
|
||||
cy.get("@postExecute").then((interception: any) => {
|
||||
expect(interception.response.body.data.body).to.deep.equal(
|
||||
"Unable to parse range: 'Sheet 2'!1:1",
|
||||
);
|
||||
});
|
||||
|
||||
//Covert sheet name field to dropdown then run query and verify
|
||||
agHelper.HoverElement(dataSources._getJSONswitchLocator("Sheet name"));
|
||||
agHelper.AssertTooltip("Clear the field to toggle back");
|
||||
agHelper.EnterValue("", {
|
||||
propFieldName: "",
|
||||
directInput: false,
|
||||
inputFieldName: "Sheet name",
|
||||
}); //Clearing the sheet name field
|
||||
agHelper.GetNClick(
|
||||
dataSources._getJSONswitchLocator("Sheet name"),
|
||||
0,
|
||||
true,
|
||||
); // Converting the field to dropdown
|
||||
dataSources.ValidateNSelectDropdown("Sheet name", "", "Sheet1");
|
||||
dataSources.RunQueryNVerifyResponseViews(10);
|
||||
dataSources.AssertQueryTableResponse(0, "eac7efa5dbd3d667f26eb3d3ab504464");
|
||||
});
|
||||
|
||||
it("7. Verify Delete query", function () {
|
||||
// Delete spreadsheet and app
|
||||
gsheetHelper.EnterBasicQueryValues(
|
||||
"Delete One",
|
||||
dataSourceName,
|
||||
spreadSheetName,
|
||||
);
|
||||
agHelper.EnterValue(GSHEET_DATA[0].rowIndex, {
|
||||
propFieldName: "",
|
||||
directInput: false,
|
||||
inputFieldName: "Row Index",
|
||||
});
|
||||
dataSources.RunQuery();
|
||||
cy.get("@postExecute").then((interception: any) => {
|
||||
expect(interception.response.body.data.body.message).to.deep.equal(
|
||||
"Deleted row successfully!",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
after("Delete spreadsheet and app", function () {
|
||||
// Delete spreadsheet and app
|
||||
gsheetHelper.DeleteSpreadsheetQuery(dataSourceName, spreadSheetName);
|
||||
cy.get("@postExecute").then((interception: any) => {
|
||||
expect(interception.response.body.data.body.message).to.deep.equal(
|
||||
"Deleted spreadsheet successfully!",
|
||||
);
|
||||
});
|
||||
homePage.NavigateToHome();
|
||||
homePage.DeleteApplication(appName);
|
||||
});
|
||||
});
|
||||
314
app/client/cypress/e2e/GSheet/ReadNWrite_Access_Spec.ts
Normal file
314
app/client/cypress/e2e/GSheet/ReadNWrite_Access_Spec.ts
Normal file
|
|
@ -0,0 +1,314 @@
|
|||
/// <reference types="Cypress" />
|
||||
import { GSHEET_DATA } from "../../fixtures/test-data-gsheet";
|
||||
import {
|
||||
homePage,
|
||||
gsheetHelper,
|
||||
dataSources,
|
||||
agHelper,
|
||||
entityExplorer,
|
||||
} from "../../support/Objects/ObjectsCore";
|
||||
|
||||
describe("GSheet-Functional Tests With Read/Write Access", function () {
|
||||
const workspaceName = "gsheet apps";
|
||||
const dataSourceName = {
|
||||
allAccess: "gsheet",
|
||||
readNWrite: "gsheet-read-write",
|
||||
};
|
||||
let appName = "gsheet-app";
|
||||
let spreadSheetName = "test-sheet";
|
||||
|
||||
before("Setup app and spreadsheet", function () {
|
||||
//Add a new app and an add new spreadsheet query
|
||||
//Setting up the spreadsheet name
|
||||
const uuid = Cypress._.random(0, 10000);
|
||||
spreadSheetName = spreadSheetName + "_" + uuid;
|
||||
appName = appName + "-" + uuid;
|
||||
|
||||
//Adding query to insert a new spreadsheet
|
||||
homePage.NavigateToHome();
|
||||
homePage.CreateAppInWorkspace(workspaceName);
|
||||
homePage.RenameApplication(appName);
|
||||
gsheetHelper.AddNewSpreadsheetQuery(
|
||||
dataSourceName.readNWrite,
|
||||
spreadSheetName,
|
||||
JSON.stringify([GSHEET_DATA[0]]),
|
||||
);
|
||||
cy.get("@postExecute").then((interception: any) => {
|
||||
expect(
|
||||
interception.response.body.data.body.properties.title,
|
||||
).to.deep.equal(spreadSheetName);
|
||||
});
|
||||
});
|
||||
|
||||
it("1. Add and verify fetch details query", () => {
|
||||
entityExplorer.CreateNewDsQuery(dataSourceName.readNWrite);
|
||||
agHelper.RenameWithInPane("Fetch_Details");
|
||||
dataSources.ValidateNSelectDropdown(
|
||||
"Operation",
|
||||
"Fetch Many",
|
||||
"Fetch Details",
|
||||
);
|
||||
dataSources.ValidateNSelectDropdown("Entity", "Spreadsheet");
|
||||
agHelper.Sleep(500);
|
||||
dataSources.ValidateNSelectDropdown("Spreadsheet", "", spreadSheetName);
|
||||
dataSources.RunQuery();
|
||||
cy.get("@postExecute").then((interception: any) => {
|
||||
expect(interception.response.body.data.body.name).to.deep.equal(
|
||||
spreadSheetName,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it("2. Verify Insert one and Insert many queries", () => {
|
||||
// add insert one query and verify
|
||||
gsheetHelper.AddInsertOrUpdateQuery(
|
||||
"Insert One",
|
||||
dataSourceName.readNWrite,
|
||||
spreadSheetName,
|
||||
JSON.stringify(GSHEET_DATA[1]),
|
||||
);
|
||||
cy.get("@postExecute").then((interception: any) => {
|
||||
expect(interception.response.body.data.body.message).to.deep.equal(
|
||||
"Inserted row successfully!",
|
||||
);
|
||||
});
|
||||
// add insert many query and verify
|
||||
gsheetHelper.AddInsertOrUpdateQuery(
|
||||
"Insert Many",
|
||||
dataSourceName.readNWrite,
|
||||
spreadSheetName,
|
||||
JSON.stringify(GSHEET_DATA.slice(2, 10)),
|
||||
);
|
||||
cy.get("@postExecute").then((interception: any) => {
|
||||
expect(interception.response.body.data.body.message).to.deep.equal(
|
||||
"Inserted rows successfully!",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it("3. Verify Update one and Update many queries", () => {
|
||||
// add update one query and verify
|
||||
gsheetHelper.AddInsertOrUpdateQuery(
|
||||
"Update One",
|
||||
dataSourceName.readNWrite,
|
||||
spreadSheetName,
|
||||
JSON.stringify(GSHEET_DATA[1]),
|
||||
);
|
||||
cy.get("@postExecute").then((interception: any) => {
|
||||
expect(interception.response.body.data.body.message).to.deep.equal(
|
||||
"Updated sheet successfully!",
|
||||
);
|
||||
});
|
||||
// add update many query and verify
|
||||
gsheetHelper.AddInsertOrUpdateQuery(
|
||||
"Update Many",
|
||||
dataSourceName.readNWrite,
|
||||
spreadSheetName,
|
||||
JSON.stringify(GSHEET_DATA.slice(2, 4)),
|
||||
);
|
||||
cy.get("@postExecute").then((interception: any) => {
|
||||
expect(interception.response.body.data.body.message).to.deep.equal(
|
||||
"Updated sheet successfully!",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it("4. Verify Fetch many query", () => {
|
||||
// Add simple Fetch many query and verify
|
||||
gsheetHelper.EnterBasicQueryValues(
|
||||
"Fetch Many",
|
||||
dataSourceName.readNWrite,
|
||||
spreadSheetName,
|
||||
);
|
||||
dataSources.RunQueryNVerifyResponseViews(GSHEET_DATA.length);
|
||||
dataSources.AssertQueryTableResponse(0, GSHEET_DATA[0].uniq_id);
|
||||
dataSources.AssertQueryTableResponse(1, "ホーンビィ 2014 カタログ"); // Asserting other language
|
||||
dataSources.AssertQueryTableResponse(2, "₹, $, €, ¥, £"); // Asserting different symbols
|
||||
dataSources.AssertQueryTableResponse(3, "!@#$%^&*"); // Asserting special chars
|
||||
// Update query to fetch only 1 column and verify
|
||||
gsheetHelper.SelectMultiDropDownValue("Columns", "product_name");
|
||||
dataSources.RunQuery();
|
||||
dataSources.RunQueryNVerifyResponseViews(GSHEET_DATA.length);
|
||||
dataSources.AssertQueryTableResponse(0, GSHEET_DATA[0].product_name);
|
||||
//Remove column filter and add Sort By Ascending and verify
|
||||
gsheetHelper.SelectMultiDropDownValue("Columns", "product_name"); //unselect the Columns dd value
|
||||
agHelper.EnterValue("price", {
|
||||
propFieldName: "",
|
||||
directInput: false,
|
||||
inputFieldName: "Sort By",
|
||||
});
|
||||
dataSources.RunQueryNVerifyResponseViews(GSHEET_DATA.length);
|
||||
dataSources.AssertQueryTableResponse(0, "5afbaf65680c9f378af5b3a3ae22427e");
|
||||
dataSources.AssertQueryTableResponse(
|
||||
1,
|
||||
"ラーニング カーブ チャギントン インタラクティブ チャッツワース",
|
||||
); // Asserting other language
|
||||
dataSources.AssertQueryTableResponse(2, "₹, $, €, ¥, £"); // Asserting different symbols
|
||||
dataSources.AssertQueryTableResponse(3, "!@#$%^&*"); // Asserting special chars
|
||||
// Sort by descending and verify
|
||||
dataSources.ClearSortByOption(); //clearing previous sort option
|
||||
dataSources.EnterSortByValues("price", "Descending");
|
||||
dataSources.RunQuery();
|
||||
dataSources.RunQueryNVerifyResponseViews(GSHEET_DATA.length);
|
||||
dataSources.AssertQueryTableResponse(
|
||||
1,
|
||||
"ホーンビー ゲージ ウェスタン エクスプレス デジタル トレイン セット (eLink および TTS ロコ トレイン セット付き)",
|
||||
); // Asserting other language
|
||||
dataSources.AssertQueryTableResponse(
|
||||
4,
|
||||
"Hornby Gauge Western Express Digital Train Set with eLink and TTS Loco Train Set",
|
||||
);
|
||||
// Filter by where clause and verify
|
||||
agHelper.TypeDynamicInputValueNValidate(
|
||||
"price",
|
||||
dataSources._nestedWhereClauseKey(0),
|
||||
);
|
||||
agHelper.TypeDynamicInputValueNValidate(
|
||||
"100",
|
||||
dataSources._nestedWhereClauseValue(0),
|
||||
);
|
||||
dataSources.RunQuery();
|
||||
dataSources.RunQueryNVerifyResponseViews(8);
|
||||
dataSources.AssertQueryTableResponse(0, "87bbb472ef9d90dcef140a551665c929");
|
||||
// Currently commenting this until https://github.com/appsmithorg/appsmith/issues/25447 is fixed.
|
||||
// Filter by cell range and verify
|
||||
// dataSources.ValidateNSelectDropdown(
|
||||
// "Filter Format",
|
||||
// "Where Clause",
|
||||
// "Cell range",
|
||||
// );
|
||||
// agHelper.EnterValue("A2:A5", {
|
||||
// propFieldName: "",
|
||||
// directInput: false,
|
||||
// inputFieldName: "Cell range",
|
||||
// });
|
||||
// dataSources.RunQuery();
|
||||
// dataSources.RunQueryNVerifyResponseViews(8);
|
||||
// dataSources.AssertQueryTableResponse(0, "eac7efa5dbd3d667f26eb3d3ab504464");
|
||||
});
|
||||
|
||||
it("5. Update a record which is not present and verify the error", () => {
|
||||
//preparing data
|
||||
let data = GSHEET_DATA[1];
|
||||
data.rowIndex = "15";
|
||||
// add update one query and verify
|
||||
gsheetHelper.EnterBasicQueryValues(
|
||||
"Update One",
|
||||
dataSourceName.readNWrite,
|
||||
spreadSheetName,
|
||||
false,
|
||||
);
|
||||
agHelper.EnterValue(JSON.stringify(data), {
|
||||
propFieldName: "",
|
||||
directInput: false,
|
||||
inputFieldName: "Update row object",
|
||||
});
|
||||
dataSources.RunQuery({
|
||||
expectedStatus: false,
|
||||
});
|
||||
cy.get("@postExecute").then((interception: any) => {
|
||||
expect(interception.response.body.data.body).to.deep.equal(
|
||||
"No data found at this row index.",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it("6. Convert field to JS and verify", () => {
|
||||
// Switch js on sheet name then run query and verify
|
||||
gsheetHelper.EnterBasicQueryValues(
|
||||
"Fetch Many",
|
||||
dataSourceName.readNWrite,
|
||||
spreadSheetName,
|
||||
false,
|
||||
);
|
||||
agHelper.GetNClick(
|
||||
dataSources._getJSONswitchLocator("Sheet name"),
|
||||
0,
|
||||
true,
|
||||
);
|
||||
dataSources.RunQueryNVerifyResponseViews(10);
|
||||
dataSources.AssertQueryTableResponse(0, "eac7efa5dbd3d667f26eb3d3ab504464");
|
||||
//Enter a wrong sheet name then run query and verify
|
||||
agHelper.EnterValue("Sheet 2", {
|
||||
propFieldName: "",
|
||||
directInput: false,
|
||||
inputFieldName: "Sheet name",
|
||||
});
|
||||
dataSources.RunQuery({
|
||||
expectedStatus: false,
|
||||
});
|
||||
cy.get("@postExecute").then((interception: any) => {
|
||||
expect(interception.response.body.data.body).to.deep.equal(
|
||||
"Unable to parse range: 'Sheet 2'!1:1",
|
||||
);
|
||||
});
|
||||
//Covert sheet name field to dropdown then run query and verify
|
||||
agHelper.HoverElement(dataSources._getJSONswitchLocator("Sheet name"));
|
||||
agHelper.AssertTooltip("Clear the field to toggle back");
|
||||
agHelper.EnterValue("", {
|
||||
propFieldName: "",
|
||||
directInput: false,
|
||||
inputFieldName: "Sheet name",
|
||||
}); //Clearing the sheet name field
|
||||
agHelper.GetNClick(
|
||||
dataSources._getJSONswitchLocator("Sheet name"),
|
||||
0,
|
||||
true,
|
||||
); // Converting the field to dropdown
|
||||
dataSources.ValidateNSelectDropdown("Sheet name", "", "Sheet1");
|
||||
dataSources.RunQueryNVerifyResponseViews(10);
|
||||
dataSources.AssertQueryTableResponse(0, "eac7efa5dbd3d667f26eb3d3ab504464");
|
||||
});
|
||||
|
||||
it("7. Delete row with Read/Write | All google sheets permission", () => {
|
||||
gsheetHelper.EnterBasicQueryValues(
|
||||
"Delete One",
|
||||
dataSourceName.readNWrite,
|
||||
spreadSheetName,
|
||||
);
|
||||
agHelper.EnterValue(GSHEET_DATA[0].rowIndex, {
|
||||
propFieldName: "",
|
||||
directInput: false,
|
||||
inputFieldName: "Row Index",
|
||||
});
|
||||
dataSources.RunQuery();
|
||||
cy.get("@postExecute").then((interception: any) => {
|
||||
expect(interception.response.body.data.body.message).to.deep.equal(
|
||||
"Deleted row successfully!",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it("8. Delete spreadsheet with Read/Write | All google sheets permission", () => {
|
||||
gsheetHelper.EnterBasicQueryValues(
|
||||
"Delete One",
|
||||
dataSourceName.readNWrite,
|
||||
spreadSheetName,
|
||||
false,
|
||||
"Spreadsheet",
|
||||
);
|
||||
dataSources.RunQuery({
|
||||
expectedStatus: false,
|
||||
});
|
||||
cy.get("@postExecute").then((interception: any) => {
|
||||
expect(interception.response.body.data.body).to.deep.equal(
|
||||
"Request had insufficient authentication scopes.",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
after("Delete spreadsheet and app", function () {
|
||||
// Delete spreadsheet and app
|
||||
gsheetHelper.DeleteSpreadsheetQuery(
|
||||
dataSourceName.allAccess,
|
||||
spreadSheetName,
|
||||
);
|
||||
cy.get("@postExecute").then((interception: any) => {
|
||||
expect(interception.response.body.data.body.message).to.deep.equal(
|
||||
"Deleted spreadsheet successfully!",
|
||||
);
|
||||
});
|
||||
homePage.NavigateToHome();
|
||||
homePage.DeleteApplication(appName);
|
||||
});
|
||||
});
|
||||
296
app/client/cypress/e2e/GSheet/ReadOnly_Access_Spec.ts
Normal file
296
app/client/cypress/e2e/GSheet/ReadOnly_Access_Spec.ts
Normal file
|
|
@ -0,0 +1,296 @@
|
|||
/// <reference types="Cypress" />
|
||||
import { GSHEET_DATA } from "../../fixtures/test-data-gsheet";
|
||||
import {
|
||||
homePage,
|
||||
gsheetHelper,
|
||||
dataSources,
|
||||
agHelper,
|
||||
entityExplorer,
|
||||
} from "../../support/Objects/ObjectsCore";
|
||||
|
||||
describe("GSheet-Functional Tests With Read Access", function () {
|
||||
const workspaceName = "gsheet apps";
|
||||
const dataSourceName = {
|
||||
allAccess: "gsheet",
|
||||
readOnly: "gsheet-read",
|
||||
};
|
||||
let appName = "gsheet-app";
|
||||
let spreadSheetName = "test-sheet";
|
||||
|
||||
before("Setup app and spreadsheet", function () {
|
||||
//Add a new app and an add new spreadsheet query
|
||||
//Setting up the spreadsheet name
|
||||
const uuid = Cypress._.random(0, 10000);
|
||||
spreadSheetName = spreadSheetName + "_" + uuid;
|
||||
appName = appName + "-" + uuid;
|
||||
|
||||
//Adding query to insert a new spreadsheet
|
||||
homePage.NavigateToHome();
|
||||
homePage.CreateAppInWorkspace(workspaceName);
|
||||
homePage.RenameApplication(appName);
|
||||
gsheetHelper.AddNewSpreadsheetQuery(
|
||||
dataSourceName.allAccess,
|
||||
spreadSheetName,
|
||||
JSON.stringify(GSHEET_DATA),
|
||||
);
|
||||
cy.get("@postExecute").then((interception: any) => {
|
||||
expect(
|
||||
interception.response.body.data.body.properties.title,
|
||||
).to.deep.equal(spreadSheetName);
|
||||
});
|
||||
});
|
||||
|
||||
it("1. Add and verify fetch details query", () => {
|
||||
entityExplorer.CreateNewDsQuery(dataSourceName.readOnly);
|
||||
agHelper.RenameWithInPane("Fetch_Details");
|
||||
dataSources.ValidateNSelectDropdown(
|
||||
"Operation",
|
||||
"Fetch Many",
|
||||
"Fetch Details",
|
||||
);
|
||||
dataSources.ValidateNSelectDropdown("Entity", "Spreadsheet");
|
||||
agHelper.Sleep(500);
|
||||
dataSources.ValidateNSelectDropdown("Spreadsheet", "", spreadSheetName);
|
||||
dataSources.RunQuery();
|
||||
cy.get("@postExecute").then((interception: any) => {
|
||||
expect(interception.response.body.data.body.name).to.deep.equal(
|
||||
spreadSheetName,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it("2. Verify error responses for Insert one and Insert many queries for read only access", () => {
|
||||
// add insert one query and verify
|
||||
gsheetHelper.AddInsertOrUpdateQuery(
|
||||
"Insert One",
|
||||
dataSourceName.readOnly,
|
||||
spreadSheetName,
|
||||
JSON.stringify(GSHEET_DATA[1]),
|
||||
false,
|
||||
);
|
||||
dataSources.RunQuery({ expectedStatus: false });
|
||||
cy.get("@postExecute").then((interception: any) => {
|
||||
expect(interception.response.body.data.body).to.deep.equal(
|
||||
"Request had insufficient authentication scopes.",
|
||||
);
|
||||
});
|
||||
// add insert many query and verify
|
||||
gsheetHelper.AddInsertOrUpdateQuery(
|
||||
"Insert Many",
|
||||
dataSourceName.readOnly,
|
||||
spreadSheetName,
|
||||
JSON.stringify(GSHEET_DATA.slice(2, 10)),
|
||||
false,
|
||||
);
|
||||
dataSources.RunQuery({ expectedStatus: false });
|
||||
cy.get("@postExecute").then((interception: any) => {
|
||||
expect(interception.response.body.data.body).to.deep.equal(
|
||||
"Request had insufficient authentication scopes.",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it("3. Verify error responses for Update one and Update many queries for Access only ", () => {
|
||||
// add update one query and verify
|
||||
gsheetHelper.AddInsertOrUpdateQuery(
|
||||
"Update One",
|
||||
dataSourceName.readOnly,
|
||||
spreadSheetName,
|
||||
JSON.stringify(GSHEET_DATA[1]),
|
||||
false,
|
||||
);
|
||||
dataSources.RunQuery({ expectedStatus: false });
|
||||
cy.get("@postExecute").then((interception: any) => {
|
||||
expect(interception.response.body.data.body).to.deep.equal(
|
||||
"Request had insufficient authentication scopes.",
|
||||
);
|
||||
});
|
||||
// add update many query and verify
|
||||
gsheetHelper.AddInsertOrUpdateQuery(
|
||||
"Update Many",
|
||||
dataSourceName.readOnly,
|
||||
spreadSheetName,
|
||||
JSON.stringify(GSHEET_DATA.slice(2, 4)),
|
||||
false,
|
||||
);
|
||||
dataSources.RunQuery({ expectedStatus: false });
|
||||
cy.get("@postExecute").then((interception: any) => {
|
||||
expect(interception.response.body.data.body).to.deep.equal(
|
||||
"Request had insufficient authentication scopes.",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it("4. Verify Fetch many query", () => {
|
||||
// Add simple Fetch many query and verify
|
||||
gsheetHelper.EnterBasicQueryValues(
|
||||
"Fetch Many",
|
||||
dataSourceName.readOnly,
|
||||
spreadSheetName,
|
||||
);
|
||||
dataSources.RunQueryNVerifyResponseViews(GSHEET_DATA.length);
|
||||
dataSources.AssertQueryTableResponse(0, GSHEET_DATA[0].uniq_id);
|
||||
dataSources.AssertQueryTableResponse(1, "ホーンビィ 2014 カタログ"); // Asserting other language
|
||||
dataSources.AssertQueryTableResponse(2, "₹, $, €, ¥, £"); // Asserting different symbols
|
||||
dataSources.AssertQueryTableResponse(3, "!@#$%^&*"); // Asserting special chars
|
||||
// Update query to fetch only 1 column and verify
|
||||
gsheetHelper.SelectMultiDropDownValue("Columns", "product_name");
|
||||
dataSources.RunQuery();
|
||||
dataSources.RunQueryNVerifyResponseViews(GSHEET_DATA.length);
|
||||
dataSources.AssertQueryTableResponse(0, GSHEET_DATA[0].product_name);
|
||||
//Remove column filter and add Sort By Ascending and verify
|
||||
gsheetHelper.SelectMultiDropDownValue("Columns", "product_name"); //unselect the Columns dd value
|
||||
agHelper.EnterValue("price", {
|
||||
propFieldName: "",
|
||||
directInput: false,
|
||||
inputFieldName: "Sort By",
|
||||
});
|
||||
dataSources.RunQueryNVerifyResponseViews(GSHEET_DATA.length);
|
||||
dataSources.AssertQueryTableResponse(0, "5afbaf65680c9f378af5b3a3ae22427e");
|
||||
dataSources.AssertQueryTableResponse(
|
||||
1,
|
||||
"ラーニング カーブ チャギントン インタラクティブ チャッツワース",
|
||||
); // Asserting other language
|
||||
dataSources.AssertQueryTableResponse(2, "₹, $, €, ¥, £"); // Asserting different symbols
|
||||
dataSources.AssertQueryTableResponse(3, "!@#$%^&*"); // Asserting special chars
|
||||
// Sort by descending and verify
|
||||
dataSources.ClearSortByOption(); //clearing previous sort option
|
||||
dataSources.EnterSortByValues("price", "Descending");
|
||||
dataSources.RunQuery();
|
||||
dataSources.RunQueryNVerifyResponseViews(GSHEET_DATA.length);
|
||||
dataSources.AssertQueryTableResponse(
|
||||
1,
|
||||
"ホーンビー ゲージ ウェスタン エクスプレス デジタル トレイン セット (eLink および TTS ロコ トレイン セット付き)",
|
||||
); // Asserting other language
|
||||
dataSources.AssertQueryTableResponse(
|
||||
4,
|
||||
"Hornby Gauge Western Express Digital Train Set with eLink and TTS Loco Train Set",
|
||||
);
|
||||
// Filter by where clause and verify
|
||||
agHelper.TypeDynamicInputValueNValidate(
|
||||
"price",
|
||||
dataSources._nestedWhereClauseKey(0),
|
||||
);
|
||||
agHelper.TypeDynamicInputValueNValidate(
|
||||
"100",
|
||||
dataSources._nestedWhereClauseValue(0),
|
||||
);
|
||||
dataSources.RunQuery();
|
||||
dataSources.RunQueryNVerifyResponseViews(8);
|
||||
dataSources.AssertQueryTableResponse(0, "87bbb472ef9d90dcef140a551665c929");
|
||||
// Currently commenting this until https://github.com/appsmithorg/appsmith/issues/25447 is fixed.
|
||||
// Filter by cell range and verify
|
||||
// dataSources.ValidateNSelectDropdown(
|
||||
// "Filter Format",
|
||||
// "Where Clause",
|
||||
// "Cell range",
|
||||
// );
|
||||
// agHelper.EnterValue("A2:A5", {
|
||||
// propFieldName: "",
|
||||
// directInput: false,
|
||||
// inputFieldName: "Cell range",
|
||||
// });
|
||||
// dataSources.RunQuery();
|
||||
// dataSources.RunQueryNVerifyResponseViews(8);
|
||||
// dataSources.AssertQueryTableResponse(0, "eac7efa5dbd3d667f26eb3d3ab504464");
|
||||
});
|
||||
|
||||
it("5. Convert field to JS and verify", () => {
|
||||
// Switch js on sheet name then run query and verify
|
||||
gsheetHelper.EnterBasicQueryValues(
|
||||
"Fetch Many",
|
||||
dataSourceName.readOnly,
|
||||
spreadSheetName,
|
||||
false,
|
||||
);
|
||||
agHelper.GetNClick(
|
||||
dataSources._getJSONswitchLocator("Sheet name"),
|
||||
0,
|
||||
true,
|
||||
);
|
||||
dataSources.RunQueryNVerifyResponseViews(10);
|
||||
dataSources.AssertQueryTableResponse(0, "eac7efa5dbd3d667f26eb3d3ab504464");
|
||||
//Enter a wrong sheet name then run query and verify
|
||||
agHelper.EnterValue("Sheet 2", {
|
||||
propFieldName: "",
|
||||
directInput: false,
|
||||
inputFieldName: "Sheet name",
|
||||
});
|
||||
dataSources.RunQuery({
|
||||
expectedStatus: false,
|
||||
});
|
||||
cy.get("@postExecute").then((interception: any) => {
|
||||
expect(interception.response.body.data.body).to.deep.equal(
|
||||
"Unable to parse range: 'Sheet 2'!1:1",
|
||||
);
|
||||
});
|
||||
//Covert sheet name field to dropdown then run query and verify
|
||||
agHelper.HoverElement(dataSources._getJSONswitchLocator("Sheet name"));
|
||||
agHelper.AssertTooltip("Clear the field to toggle back");
|
||||
agHelper.EnterValue("", {
|
||||
propFieldName: "",
|
||||
directInput: false,
|
||||
inputFieldName: "Sheet name",
|
||||
}); //Clearing the sheet name field
|
||||
agHelper.GetNClick(
|
||||
dataSources._getJSONswitchLocator("Sheet name"),
|
||||
0,
|
||||
true,
|
||||
); // Converting the field to dropdown
|
||||
dataSources.ValidateNSelectDropdown("Sheet name", "", "Sheet1");
|
||||
dataSources.RunQueryNVerifyResponseViews(10);
|
||||
dataSources.AssertQueryTableResponse(0, "eac7efa5dbd3d667f26eb3d3ab504464");
|
||||
});
|
||||
|
||||
it("6. Delete row with Read | All google sheets permission", () => {
|
||||
gsheetHelper.EnterBasicQueryValues(
|
||||
"Delete One",
|
||||
dataSourceName.readOnly,
|
||||
spreadSheetName,
|
||||
);
|
||||
agHelper.EnterValue(GSHEET_DATA[0].rowIndex, {
|
||||
propFieldName: "",
|
||||
directInput: false,
|
||||
inputFieldName: "Row Index",
|
||||
});
|
||||
dataSources.RunQuery({ expectedStatus: false });
|
||||
cy.get("@postExecute").then((interception: any) => {
|
||||
expect(interception.response.body.data.body).to.deep.equal(
|
||||
"Request had insufficient authentication scopes.",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it("7. Delete spreadsheet with Read | All google sheets permission", () => {
|
||||
gsheetHelper.EnterBasicQueryValues(
|
||||
"Delete One",
|
||||
dataSourceName.readOnly,
|
||||
spreadSheetName,
|
||||
false,
|
||||
"Spreadsheet",
|
||||
);
|
||||
dataSources.RunQuery({
|
||||
expectedStatus: false,
|
||||
});
|
||||
cy.get("@postExecute").then((interception: any) => {
|
||||
expect(interception.response.body.data.body).to.deep.equal(
|
||||
"Request had insufficient authentication scopes.",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
after("Delete spreadsheet and app", function () {
|
||||
// Delete spreadsheet and app
|
||||
gsheetHelper.DeleteSpreadsheetQuery(
|
||||
dataSourceName.allAccess,
|
||||
spreadSheetName,
|
||||
);
|
||||
cy.get("@postExecute").then((interception: any) => {
|
||||
expect(interception.response.body.data.body.message).to.deep.equal(
|
||||
"Deleted spreadsheet successfully!",
|
||||
);
|
||||
});
|
||||
homePage.NavigateToHome();
|
||||
homePage.DeleteApplication(appName);
|
||||
});
|
||||
});
|
||||
299
app/client/cypress/e2e/GSheet/SelectedSheet_Access_Spec.ts
Normal file
299
app/client/cypress/e2e/GSheet/SelectedSheet_Access_Spec.ts
Normal file
|
|
@ -0,0 +1,299 @@
|
|||
/// <reference types="Cypress" />
|
||||
import { GSHEET_DATA } from "../../fixtures/test-data-gsheet";
|
||||
import {
|
||||
homePage,
|
||||
gsheetHelper,
|
||||
dataSources,
|
||||
agHelper,
|
||||
entityExplorer,
|
||||
} from "../../support/Objects/ObjectsCore";
|
||||
|
||||
const workspaceName = "gsheet apps";
|
||||
const dataSourceName = "gsheet-selected";
|
||||
let appName = "gsheet-app";
|
||||
let spreadSheetName = "test-sheet-automation-selected";
|
||||
describe("GSheet-Functional Tests With Selected Access", function () {
|
||||
before("Setup app", function () {
|
||||
//Setting up app name
|
||||
const uuid = Cypress._.random(0, 10000);
|
||||
appName = appName + "-" + uuid;
|
||||
|
||||
//Adding app
|
||||
homePage.NavigateToHome();
|
||||
homePage.CreateAppInWorkspace(workspaceName);
|
||||
homePage.RenameApplication(appName);
|
||||
});
|
||||
|
||||
it("1. Add and verify fetch details query", () => {
|
||||
entityExplorer.CreateNewDsQuery(dataSourceName);
|
||||
agHelper.RenameWithInPane("Fetch_Details");
|
||||
dataSources.ValidateNSelectDropdown(
|
||||
"Operation",
|
||||
"Fetch Many",
|
||||
"Fetch Details",
|
||||
);
|
||||
dataSources.ValidateNSelectDropdown("Entity", "Spreadsheet");
|
||||
agHelper.Sleep(500);
|
||||
dataSources.ValidateNSelectDropdown("Spreadsheet", "", spreadSheetName);
|
||||
dataSources.RunQuery();
|
||||
cy.get("@postExecute").then((interception: any) => {
|
||||
expect(interception.response.body.data.body.name).to.deep.equal(
|
||||
spreadSheetName,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it("2. Verify Insert One and Insert Many queries", () => {
|
||||
// add insert one query and verify
|
||||
gsheetHelper.AddInsertOrUpdateQuery(
|
||||
"Insert One",
|
||||
dataSourceName,
|
||||
spreadSheetName,
|
||||
JSON.stringify(GSHEET_DATA[0]),
|
||||
);
|
||||
cy.get("@postExecute").then((interception: any) => {
|
||||
expect(interception.response.body.data.body.message).to.deep.equal(
|
||||
"Inserted row successfully!",
|
||||
);
|
||||
});
|
||||
|
||||
// add insert many query and verify
|
||||
gsheetHelper.AddInsertOrUpdateQuery(
|
||||
"Insert Many",
|
||||
dataSourceName,
|
||||
spreadSheetName,
|
||||
JSON.stringify(GSHEET_DATA.slice(1, 10)),
|
||||
);
|
||||
cy.get("@postExecute").then((interception: any) => {
|
||||
expect(interception.response.body.data.body.message).to.deep.equal(
|
||||
"Inserted rows successfully!",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it("3. Verify Update one and Update many queries", () => {
|
||||
// add update one query and verify
|
||||
gsheetHelper.AddInsertOrUpdateQuery(
|
||||
"Update One",
|
||||
dataSourceName,
|
||||
spreadSheetName,
|
||||
JSON.stringify(GSHEET_DATA[1]),
|
||||
);
|
||||
cy.get("@postExecute").then((interception: any) => {
|
||||
expect(interception.response.body.data.body.message).to.deep.equal(
|
||||
"Updated sheet successfully!",
|
||||
);
|
||||
});
|
||||
|
||||
// add update many query and verify
|
||||
gsheetHelper.AddInsertOrUpdateQuery(
|
||||
"Update Many",
|
||||
dataSourceName,
|
||||
spreadSheetName,
|
||||
JSON.stringify(GSHEET_DATA.slice(2, 4)),
|
||||
);
|
||||
cy.get("@postExecute").then((interception: any) => {
|
||||
expect(interception.response.body.data.body.message).to.deep.equal(
|
||||
"Updated sheet successfully!",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it("4. Verify Fetch many query", () => {
|
||||
// Add simple Fetch many query and verify
|
||||
gsheetHelper.EnterBasicQueryValues(
|
||||
"Fetch Many",
|
||||
dataSourceName,
|
||||
spreadSheetName,
|
||||
);
|
||||
dataSources.RunQueryNVerifyResponseViews(GSHEET_DATA.length);
|
||||
dataSources.AssertQueryTableResponse(0, GSHEET_DATA[0].uniq_id);
|
||||
dataSources.AssertQueryTableResponse(1, "ホーンビィ 2014 カタログ"); // Asserting other language
|
||||
dataSources.AssertQueryTableResponse(2, "₹, $, €, ¥, £"); // Asserting different symbols
|
||||
dataSources.AssertQueryTableResponse(3, "!@#$%^&*"); // Asserting special chars
|
||||
|
||||
// Update query to fetch only 1 column and verify
|
||||
gsheetHelper.SelectMultiDropDownValue("Columns", "product_name");
|
||||
dataSources.RunQuery();
|
||||
dataSources.RunQueryNVerifyResponseViews(GSHEET_DATA.length);
|
||||
dataSources.AssertQueryTableResponse(0, GSHEET_DATA[0].product_name);
|
||||
|
||||
//Remove column filter and add Sort By Ascending and verify
|
||||
gsheetHelper.SelectMultiDropDownValue("Columns", "product_name"); //unselect the Columns dd value
|
||||
agHelper.EnterValue("price", {
|
||||
propFieldName: "",
|
||||
directInput: false,
|
||||
inputFieldName: "Sort By",
|
||||
});
|
||||
dataSources.RunQueryNVerifyResponseViews(GSHEET_DATA.length);
|
||||
dataSources.AssertQueryTableResponse(0, "5afbaf65680c9f378af5b3a3ae22427e");
|
||||
dataSources.AssertQueryTableResponse(
|
||||
1,
|
||||
"ラーニング カーブ チャギントン インタラクティブ チャッツワース",
|
||||
); // Asserting other language
|
||||
dataSources.AssertQueryTableResponse(2, "₹, $, €, ¥, £"); // Asserting different symbols
|
||||
dataSources.AssertQueryTableResponse(3, "!@#$%^&*"); // Asserting special chars
|
||||
|
||||
// Sort by descending and verify
|
||||
dataSources.ClearSortByOption(); //clearing previous sort option
|
||||
dataSources.EnterSortByValues("price", "Descending");
|
||||
dataSources.RunQuery();
|
||||
dataSources.RunQueryNVerifyResponseViews(GSHEET_DATA.length);
|
||||
dataSources.AssertQueryTableResponse(
|
||||
1,
|
||||
"ホーンビー ゲージ ウェスタン エクスプレス デジタル トレイン セット (eLink および TTS ロコ トレイン セット付き)",
|
||||
); // Asserting other language
|
||||
dataSources.AssertQueryTableResponse(
|
||||
4,
|
||||
"Hornby Gauge Western Express Digital Train Set with eLink and TTS Loco Train Set",
|
||||
);
|
||||
|
||||
// Filter by where clause and verify
|
||||
agHelper.TypeDynamicInputValueNValidate(
|
||||
"price",
|
||||
dataSources._nestedWhereClauseKey(0),
|
||||
);
|
||||
agHelper.TypeDynamicInputValueNValidate(
|
||||
"100",
|
||||
dataSources._nestedWhereClauseValue(0),
|
||||
);
|
||||
dataSources.RunQuery();
|
||||
dataSources.RunQueryNVerifyResponseViews(8);
|
||||
dataSources.AssertQueryTableResponse(0, "87bbb472ef9d90dcef140a551665c929");
|
||||
|
||||
// Currently commenting this until https://github.com/appsmithorg/appsmith/issues/25447 is fixed.
|
||||
// Filter by cell range and verify
|
||||
// dataSources.ValidateNSelectDropdown(
|
||||
// "Filter Format",
|
||||
// "Where Clause",
|
||||
// "Cell range",
|
||||
// );
|
||||
// agHelper.EnterValue("A2:A5", {
|
||||
// propFieldName: "",
|
||||
// directInput: false,
|
||||
// inputFieldName: "Cell range",
|
||||
// });
|
||||
// dataSources.RunQuery();
|
||||
// dataSources.RunQueryNVerifyResponseViews(8);
|
||||
// dataSources.AssertQueryTableResponse(0, "eac7efa5dbd3d667f26eb3d3ab504464");
|
||||
});
|
||||
|
||||
it("5. Update a record which is not present and verify the error", () => {
|
||||
//preparing data
|
||||
const data = GSHEET_DATA[1];
|
||||
data.rowIndex = "15";
|
||||
|
||||
// add update one query and verify
|
||||
gsheetHelper.EnterBasicQueryValues(
|
||||
"Update One",
|
||||
dataSourceName,
|
||||
spreadSheetName,
|
||||
false,
|
||||
);
|
||||
agHelper.EnterValue(JSON.stringify(data), {
|
||||
propFieldName: "",
|
||||
directInput: false,
|
||||
inputFieldName: "Update row object",
|
||||
});
|
||||
dataSources.RunQuery({
|
||||
expectedStatus: false,
|
||||
});
|
||||
cy.get("@postExecute").then((interception: any) => {
|
||||
expect(interception.response.body.data.body).to.deep.equal(
|
||||
"No data found at this row index.",
|
||||
);
|
||||
});
|
||||
|
||||
//reset the row index
|
||||
data.rowIndex = "1";
|
||||
});
|
||||
|
||||
it("6. Convert field to JS and verify", () => {
|
||||
// Switch js on sheet name then run query and verify
|
||||
gsheetHelper.EnterBasicQueryValues(
|
||||
"Fetch Many",
|
||||
dataSourceName,
|
||||
spreadSheetName,
|
||||
false,
|
||||
);
|
||||
agHelper.GetNClick(
|
||||
dataSources._getJSONswitchLocator("Sheet name"),
|
||||
0,
|
||||
true,
|
||||
);
|
||||
dataSources.RunQueryNVerifyResponseViews(10);
|
||||
dataSources.AssertQueryTableResponse(0, "eac7efa5dbd3d667f26eb3d3ab504464");
|
||||
|
||||
//Enter a wrong sheet name then run query and verify
|
||||
agHelper.EnterValue("Sheet 2", {
|
||||
propFieldName: "",
|
||||
directInput: false,
|
||||
inputFieldName: "Sheet name",
|
||||
});
|
||||
dataSources.RunQuery({
|
||||
expectedStatus: false,
|
||||
});
|
||||
cy.get("@postExecute").then((interception: any) => {
|
||||
expect(interception.response.body.data.body).to.deep.equal(
|
||||
"Unable to parse range: 'Sheet 2'!1:1",
|
||||
);
|
||||
});
|
||||
|
||||
//Covert sheet name field to dropdown then run query and verify
|
||||
agHelper.HoverElement(dataSources._getJSONswitchLocator("Sheet name"));
|
||||
agHelper.AssertTooltip("Clear the field to toggle back");
|
||||
agHelper.EnterValue("", {
|
||||
propFieldName: "",
|
||||
directInput: false,
|
||||
inputFieldName: "Sheet name",
|
||||
}); //Clearing the sheet name field
|
||||
agHelper.GetNClick(
|
||||
dataSources._getJSONswitchLocator("Sheet name"),
|
||||
0,
|
||||
true,
|
||||
); // Converting the field to dropdown
|
||||
dataSources.ValidateNSelectDropdown("Sheet name", "", "Sheet1");
|
||||
dataSources.RunQueryNVerifyResponseViews(10);
|
||||
dataSources.AssertQueryTableResponse(0, "eac7efa5dbd3d667f26eb3d3ab504464");
|
||||
});
|
||||
|
||||
it("7. Verify Delete query", function () {
|
||||
// Delete spreadsheet and app
|
||||
gsheetHelper.EnterBasicQueryValues(
|
||||
"Delete One",
|
||||
dataSourceName,
|
||||
spreadSheetName,
|
||||
);
|
||||
GSHEET_DATA.reverse().forEach((d) => {
|
||||
agHelper.EnterValue(d.rowIndex, {
|
||||
propFieldName: "",
|
||||
directInput: false,
|
||||
inputFieldName: "Row Index",
|
||||
});
|
||||
dataSources.RunQuery();
|
||||
cy.get("@postExecute").then((interception: any) => {
|
||||
expect(interception.response.body.data.body.message).to.deep.equal(
|
||||
"Deleted row successfully!",
|
||||
);
|
||||
});
|
||||
agHelper.Sleep(500);
|
||||
});
|
||||
// Fetch many to verify all the data is deleted
|
||||
gsheetHelper.EnterBasicQueryValues(
|
||||
"Fetch Many",
|
||||
dataSourceName,
|
||||
spreadSheetName,
|
||||
false,
|
||||
);
|
||||
dataSources.RunQuery();
|
||||
cy.get("@postExecute").then((interception: any) => {
|
||||
expect(interception.response.body.data.body).to.deep.equal([]);
|
||||
});
|
||||
});
|
||||
|
||||
after("Delete app", function () {
|
||||
// Delete app
|
||||
homePage.NavigateToHome();
|
||||
homePage.DeleteApplication(appName);
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
/// <reference types="Cypress" />
|
||||
import { GSHEET_DATA } from "../../fixtures/test-data-gsheet";
|
||||
import {
|
||||
homePage,
|
||||
gsheetHelper,
|
||||
dataSources,
|
||||
agHelper,
|
||||
entityExplorer,
|
||||
propPane,
|
||||
table,
|
||||
draggableWidgets,
|
||||
} from "../../support/Objects/ObjectsCore";
|
||||
import { Widgets } from "../../support/Pages/DataSources";
|
||||
import oneClickBindingLocator from "../../locators/OneClickBindingLocator";
|
||||
|
||||
const workspaceName = "gsheet apps";
|
||||
const dataSourceName = "gsheet";
|
||||
let appName = "gsheet-app";
|
||||
let spreadSheetName = "test-sheet";
|
||||
describe("GSheet-widget binding", function () {
|
||||
before("Setup app and spreadsheet", function () {
|
||||
//Setting up the app name
|
||||
const uuid = Cypress._.random(0, 10000);
|
||||
spreadSheetName = spreadSheetName + "_" + uuid;
|
||||
appName = appName + "-" + uuid;
|
||||
|
||||
//Adding app
|
||||
homePage.NavigateToHome();
|
||||
homePage.CreateAppInWorkspace(workspaceName);
|
||||
homePage.RenameApplication(appName);
|
||||
gsheetHelper.AddNewSpreadsheetQuery(
|
||||
dataSourceName,
|
||||
spreadSheetName,
|
||||
JSON.stringify(GSHEET_DATA),
|
||||
);
|
||||
cy.get("@postExecute").then((interception: any) => {
|
||||
expect(
|
||||
interception.response.body.data.body.properties.title,
|
||||
).to.deep.equal(spreadSheetName);
|
||||
});
|
||||
});
|
||||
|
||||
it("1. Verify 'Add to widget [Widget Suggestion]' functionality - GSheet", () => {
|
||||
//Adding query
|
||||
gsheetHelper.EnterBasicQueryValues(
|
||||
"Fetch Many",
|
||||
dataSourceName,
|
||||
spreadSheetName,
|
||||
);
|
||||
dataSources.RunQueryNVerifyResponseViews(10);
|
||||
|
||||
// Adding suggested widgets and verify
|
||||
dataSources.AddSuggesstedWidget(Widgets.Table);
|
||||
table.ReadTableRowColumnData(0, 0, "v2").then((cellData) => {
|
||||
expect(cellData).to.eq("eac7efa5dbd3d667f26eb3d3ab504464");
|
||||
});
|
||||
agHelper.GetNClick(propPane._deleteWidget);
|
||||
});
|
||||
|
||||
it("2. One click binding to table widget functionality - GSheet", () => {
|
||||
//Adding table widget
|
||||
entityExplorer.DragDropWidgetNVerify(draggableWidgets.TABLE, 450, 200);
|
||||
agHelper.GetNClick(oneClickBindingLocator.datasourceDropdownSelector);
|
||||
agHelper.GetNClick(
|
||||
oneClickBindingLocator.datasourceQuerySelector("fetch_many_query"),
|
||||
);
|
||||
|
||||
// Assert table data
|
||||
table.ReadTableRowColumnData(0, 0, "v2").then((cellData) => {
|
||||
expect(cellData).to.eq("eac7efa5dbd3d667f26eb3d3ab504464");
|
||||
});
|
||||
agHelper.GetNClick(propPane._deleteWidget);
|
||||
});
|
||||
|
||||
after("Delete app", function () {
|
||||
// Delete spreadsheet and app
|
||||
entityExplorer.NavigateToSwitcher("Explorer");
|
||||
gsheetHelper.DeleteSpreadsheetQuery(dataSourceName, spreadSheetName);
|
||||
cy.get("@postExecute").then((interception: any) => {
|
||||
expect(interception.response.body.data.body.message).to.deep.equal(
|
||||
"Deleted spreadsheet successfully!",
|
||||
);
|
||||
});
|
||||
homePage.NavigateToHome();
|
||||
homePage.DeleteApplication(appName);
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
/// <reference types="Cypress" />
|
||||
import { GSHEET_DATA } from "../../fixtures/test-data-gsheet";
|
||||
import {
|
||||
homePage,
|
||||
gsheetHelper,
|
||||
dataSources,
|
||||
agHelper,
|
||||
entityExplorer,
|
||||
propPane,
|
||||
table,
|
||||
draggableWidgets,
|
||||
} from "../../support/Objects/ObjectsCore";
|
||||
import { Widgets } from "../../support/Pages/DataSources";
|
||||
import oneClickBindingLocator from "../../locators/OneClickBindingLocator";
|
||||
|
||||
const workspaceName = "gsheet apps";
|
||||
const dataSourceName = "gsheet-selected";
|
||||
let appName = "gsheet-app";
|
||||
let spreadSheetName = "test-sheet-automation-selected";
|
||||
describe("GSheet-widget binding for selected sheet access", function () {
|
||||
before("Setup app and spreadsheet", function () {
|
||||
//Setting up the app name
|
||||
const uuid = Cypress._.random(0, 10000);
|
||||
appName = appName + "-" + uuid;
|
||||
|
||||
//Adding app and data to the selected sheet
|
||||
homePage.NavigateToHome();
|
||||
homePage.CreateAppInWorkspace(workspaceName);
|
||||
homePage.RenameApplication(appName);
|
||||
gsheetHelper.AddInsertOrUpdateQuery(
|
||||
"Insert Many",
|
||||
dataSourceName,
|
||||
spreadSheetName,
|
||||
JSON.stringify(GSHEET_DATA),
|
||||
);
|
||||
cy.get("@postExecute").then((interception: any) => {
|
||||
expect(interception.response.body.data.body.message).to.deep.equal(
|
||||
"Inserted rows successfully!",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it("1. Verify 'Add to widget [Widget Suggestion]' functionality for selected sheet access - GSheet", () => {
|
||||
//Adding query
|
||||
gsheetHelper.EnterBasicQueryValues(
|
||||
"Fetch Many",
|
||||
dataSourceName,
|
||||
spreadSheetName,
|
||||
);
|
||||
dataSources.RunQueryNVerifyResponseViews(10);
|
||||
|
||||
// Adding suggested widgets and verify
|
||||
dataSources.AddSuggesstedWidget(Widgets.Table);
|
||||
table.ReadTableRowColumnData(0, 0, "v2").then((cellData) => {
|
||||
expect(cellData).to.eq("eac7efa5dbd3d667f26eb3d3ab504464");
|
||||
});
|
||||
agHelper.GetNClick(propPane._deleteWidget);
|
||||
});
|
||||
|
||||
it("2. One click binding to table widget functionality for selected sheet access - GSheet", () => {
|
||||
//Adding table widget
|
||||
entityExplorer.DragDropWidgetNVerify(draggableWidgets.TABLE, 450, 200);
|
||||
agHelper.GetNClick(oneClickBindingLocator.datasourceDropdownSelector);
|
||||
agHelper.GetNClick(
|
||||
oneClickBindingLocator.datasourceQuerySelector("fetch_many_query"),
|
||||
);
|
||||
|
||||
// Assert table data
|
||||
table.ReadTableRowColumnData(0, 0, "v2").then((cellData) => {
|
||||
expect(cellData).to.eq("eac7efa5dbd3d667f26eb3d3ab504464");
|
||||
});
|
||||
agHelper.GetNClick(propPane._deleteWidget);
|
||||
});
|
||||
|
||||
after("Delete app", function () {
|
||||
// Delete data in spreadsheet and app
|
||||
entityExplorer.NavigateToSwitcher("Explorer");
|
||||
gsheetHelper.EnterBasicQueryValues(
|
||||
"Delete One",
|
||||
dataSourceName,
|
||||
spreadSheetName,
|
||||
);
|
||||
GSHEET_DATA.reverse().forEach((d) => {
|
||||
agHelper.EnterValue(d.rowIndex, {
|
||||
propFieldName: "",
|
||||
directInput: false,
|
||||
inputFieldName: "Row Index",
|
||||
});
|
||||
dataSources.RunQuery();
|
||||
cy.get("@postExecute").then((interception: any) => {
|
||||
expect(interception.response.body.data.body.message).to.deep.equal(
|
||||
"Deleted row successfully!",
|
||||
);
|
||||
});
|
||||
agHelper.Sleep(500);
|
||||
});
|
||||
homePage.NavigateToHome();
|
||||
homePage.DeleteApplication(appName);
|
||||
});
|
||||
});
|
||||
|
|
@ -146,7 +146,7 @@ describe("AForce - Community Issues page validations", function () {
|
|||
|
||||
entityExplorer.SelectEntityByName("Table1", "Widgets");
|
||||
//propPane.EnterJSContext("Default search text", "Question", false);
|
||||
propPane.TypeTextIntoField("Default search text", "Quest");
|
||||
propPane.TypeTextIntoField("Default search text", "Quest", true, false);
|
||||
|
||||
deployMode.DeployApp();
|
||||
table.AssertSearchText("Quest", 2);
|
||||
|
|
|
|||
|
|
@ -6,14 +6,14 @@ import {
|
|||
gitSync,
|
||||
apiPage,
|
||||
dataSources,
|
||||
tedTestConfig,
|
||||
} from "../../../support/Objects/ObjectsCore";
|
||||
|
||||
describe("Content Management System App", function () {
|
||||
before(() => {
|
||||
homePage.NavigateToHome();
|
||||
agHelper.GenerateUUID();
|
||||
cy.get("@guid").then((uid) => {
|
||||
homePage.CreateNewWorkspace("EchoApiCMS" + uid);
|
||||
homePage.CreateNewWorkspace("EchoApiCMS" + uid, true);
|
||||
homePage.CreateAppInWorkspace("EchoApiCMS" + uid, "EchoApiCMSApp");
|
||||
agHelper.AddDsl("CMSdsl");
|
||||
});
|
||||
|
|
@ -21,55 +21,52 @@ describe("Content Management System App", function () {
|
|||
|
||||
let repoName;
|
||||
it("1.Create Get echo Api call", function () {
|
||||
cy.fixture("datasources").then((datasourceFormData) => {
|
||||
apiPage.CreateAndFillApi(datasourceFormData["echoApiUrl"], "get_data");
|
||||
// creating get request using echo
|
||||
apiPage.EnterHeader(
|
||||
"info",
|
||||
'[{"due":"2021-11-23","assignee":"Dan.Wyman@hotmail.com","title":"Recusan","description":"Ut quisquam eum beatae facere eos aliquam laborum ea.","id":"1"},{"due":"2021-11-23","assignee":"Dashawn_Maggio30@gmail.com","title":"Dignissimos eaque","description":"Consequatur corrupti et possimus en.","id":"2"},{"due":"2021-11-24","assignee":"Curt50@gmail.com","title":"Voluptas explicabo","description":"Quia ratione optio et maiores.","id":"3"},{"due":"2021-11-23","assignee":"Shanna63@hotmail.com","title":"Aut omnis.","description":"Neque rerum numquam veniam voluptatum id. Aut daut.","id":"4"}]',
|
||||
);
|
||||
// entering the data in header
|
||||
apiPage.RunAPI();
|
||||
apiPage.ResponseStatusCheck("200");
|
||||
});
|
||||
apiPage.CreateAndFillApi(
|
||||
tedTestConfig.dsValues[tedTestConfig.defaultEnviorment].echoApiUrl,
|
||||
"get_data",
|
||||
);
|
||||
// creating get request using echo
|
||||
apiPage.EnterHeader(
|
||||
"info",
|
||||
'[{"due":"2021-11-23","assignee":"Dan.Wyman@hotmail.com","title":"Recusan","description":"Ut quisquam eum beatae facere eos aliquam laborum ea.","id":"1"},{"due":"2021-11-23","assignee":"Dashawn_Maggio30@gmail.com","title":"Dignissimos eaque","description":"Consequatur corrupti et possimus en.","id":"2"},{"due":"2021-11-24","assignee":"Curt50@gmail.com","title":"Voluptas explicabo","description":"Quia ratione optio et maiores.","id":"3"},{"due":"2021-11-23","assignee":"Shanna63@hotmail.com","title":"Aut omnis.","description":"Neque rerum numquam veniam voluptatum id. Aut daut.","id":"4"}]',
|
||||
);
|
||||
// entering the data in header
|
||||
apiPage.RunAPI();
|
||||
apiPage.ResponseStatusCheck("200");
|
||||
});
|
||||
|
||||
it("2. Create Post echo Api call", function () {
|
||||
cy.fixture("datasources").then((datasourceFormData) => {
|
||||
apiPage.CreateAndFillApi(
|
||||
datasourceFormData["echoApiUrl"],
|
||||
"send_mail",
|
||||
10000,
|
||||
"POST",
|
||||
);
|
||||
apiPage.SelectPaneTab("Body");
|
||||
apiPage.SelectSubTab("JSON");
|
||||
// creating post request using echo
|
||||
dataSources.EnterQuery(
|
||||
'{"to":"{{to_input.text}}","subject":"{{subject.text}}","content":"{{content.text}}"}',
|
||||
);
|
||||
apiPage.RunAPI();
|
||||
apiPage.ResponseStatusCheck("200");
|
||||
});
|
||||
apiPage.CreateAndFillApi(
|
||||
tedTestConfig.dsValues[tedTestConfig.defaultEnviorment].echoApiUrl,
|
||||
"send_mail",
|
||||
10000,
|
||||
"POST",
|
||||
);
|
||||
apiPage.SelectPaneTab("Body");
|
||||
apiPage.SelectSubTab("JSON");
|
||||
// creating post request using echo
|
||||
dataSources.EnterQuery(
|
||||
'{"to":"{{to_input.text}}","subject":"{{subject.text}}","content":"{{content.text}}"}',
|
||||
);
|
||||
apiPage.RunAPI();
|
||||
apiPage.ResponseStatusCheck("200");
|
||||
});
|
||||
|
||||
it("3. Create Delete echo Api call", function () {
|
||||
cy.fixture("datasources").then((datasourceFormData) => {
|
||||
apiPage.CreateAndFillApi(
|
||||
datasourceFormData["echoApiUrl"],
|
||||
"delete_proposal",
|
||||
10000,
|
||||
"DELETE",
|
||||
);
|
||||
apiPage.SelectPaneTab("Body");
|
||||
apiPage.SelectSubTab("JSON");
|
||||
// creating post request using echo
|
||||
dataSources.EnterQuery(
|
||||
'{"title":"{{title.text}}","due":"{{due.text}}","assignee":"{{assignee.text}}"}',
|
||||
);
|
||||
apiPage.RunAPI();
|
||||
apiPage.ResponseStatusCheck("200");
|
||||
});
|
||||
apiPage.CreateAndFillApi(
|
||||
tedTestConfig.dsValues[tedTestConfig.defaultEnviorment].echoApiUrl,
|
||||
"delete_proposal",
|
||||
10000,
|
||||
"DELETE",
|
||||
);
|
||||
apiPage.SelectPaneTab("Body");
|
||||
apiPage.SelectSubTab("JSON");
|
||||
// creating post request using echo
|
||||
dataSources.EnterQuery(
|
||||
'{"title":"{{title.text}}","due":"{{due.text}}","assignee":"{{assignee.text}}"}',
|
||||
);
|
||||
apiPage.RunAPI();
|
||||
apiPage.ResponseStatusCheck("200");
|
||||
});
|
||||
|
||||
it("4. Send mail and verify post request body", function () {
|
||||
|
|
|
|||
|
|
@ -12,10 +12,9 @@ describe("Shopping cart App", function () {
|
|||
let datasourceName: string, repoName: any;
|
||||
|
||||
before(() => {
|
||||
homePage.NavigateToHome();
|
||||
agHelper.GenerateUUID();
|
||||
cy.get("@guid").then((uid) => {
|
||||
homePage.CreateNewWorkspace("MongoDBShop" + uid);
|
||||
homePage.CreateNewWorkspace("MongoDBShop" + uid, true);
|
||||
homePage.CreateAppInWorkspace("MongoDBShop" + uid, "MongoDBShopApp");
|
||||
agHelper.AddDsl("mongoAppdsl");
|
||||
});
|
||||
|
|
@ -28,7 +27,6 @@ describe("Shopping cart App", function () {
|
|||
it("1. Create MongoDB datasource and add Insert, Find, Update and Delete queries", function () {
|
||||
dataSources.CreateQueryAfterDSSaved("", "GetProduct");
|
||||
dataSources.EnterJSContext({
|
||||
fieldProperty: dataSources._mongoCollectionPath,
|
||||
fieldLabel: "Collection",
|
||||
fieldValue: "Productnames",
|
||||
});
|
||||
|
|
@ -42,7 +40,6 @@ describe("Shopping cart App", function () {
|
|||
"Update document(s)",
|
||||
);
|
||||
dataSources.EnterJSContext({
|
||||
fieldProperty: dataSources._mongoCollectionPath,
|
||||
fieldLabel: "Collection",
|
||||
fieldValue: "Productnames",
|
||||
});
|
||||
|
|
@ -73,7 +70,6 @@ describe("Shopping cart App", function () {
|
|||
"Insert document(s)",
|
||||
);
|
||||
dataSources.EnterJSContext({
|
||||
fieldProperty: dataSources._mongoCollectionPath,
|
||||
fieldLabel: "Collection",
|
||||
fieldValue: "Productnames",
|
||||
});
|
||||
|
|
@ -101,7 +97,6 @@ describe("Shopping cart App", function () {
|
|||
"Delete document(s)",
|
||||
);
|
||||
dataSources.EnterJSContext({
|
||||
fieldProperty: dataSources._mongoCollectionPath,
|
||||
fieldLabel: "Collection",
|
||||
fieldValue: "Productnames",
|
||||
});
|
||||
|
|
|
|||
|
|
@ -5,12 +5,14 @@ import {
|
|||
jsEditor,
|
||||
propPane,
|
||||
apiPage,
|
||||
} from "../../../../../support/Objects/ObjectsCore";
|
||||
draggableWidgets,
|
||||
} from "../../../../support/Objects/ObjectsCore";
|
||||
|
||||
describe("UI to Code", () => {
|
||||
before(() => {
|
||||
agHelper.AddDsl("buttondsl");
|
||||
apiPage.CreateApi("Api1", "GET");
|
||||
entityExplorer.DragDropWidgetNVerify(draggableWidgets.BUTTON);
|
||||
entityExplorer.NavigateToSwitcher("Explorer");
|
||||
apiPage.CreateApi();
|
||||
apiPage.CreateApi("Api2", "POST");
|
||||
});
|
||||
|
||||
|
|
@ -372,18 +374,18 @@ describe("UI to Code", () => {
|
|||
|
||||
// Edit the success callback of the nested Api2.run
|
||||
propPane.SelectActionByTitleAndValue("Execute a query", "Api2.run");
|
||||
cy.get(
|
||||
jsEditor._lineinPropertyPaneJsEditor(
|
||||
2,
|
||||
propPane._actionSelectorFieldContentByLabel("Params"),
|
||||
),
|
||||
).type("val: 1");
|
||||
agHelper.EnterActionValue(
|
||||
"Params",
|
||||
`{{{
|
||||
val: 1
|
||||
}}}`,
|
||||
);
|
||||
|
||||
agHelper.GetNClick(propPane._actionSelectorPopupClose);
|
||||
|
||||
propPane.ValidateJSFieldValue(
|
||||
"onClick",
|
||||
`{{Api1.run().then(() => { Api2.run({ val: 1 // "key": "value", }).then(() => { showAlert("Hello"); }).catch(() => { showAlert("World"); });});}}`,
|
||||
`{{Api1.run().then(() => { Api2.run({ val: 1 }).then(() => { showAlert("Hello"); }).catch(() => { showAlert("World"); });});}}`,
|
||||
);
|
||||
});
|
||||
|
||||
|
|
@ -414,13 +416,13 @@ describe("UI to Code", () => {
|
|||
|
||||
it("9. correctly configures a setInterval action", () => {
|
||||
propPane.SelectPlatformFunction("onClick", "Set interval");
|
||||
|
||||
cy.get(
|
||||
jsEditor._lineinPropertyPaneJsEditor(
|
||||
2,
|
||||
propPane._actionSelectorFieldContentByLabel("Callback function"),
|
||||
),
|
||||
).type("{enter}showAlert('Hello'){enter}//");
|
||||
agHelper.EnterActionValue(
|
||||
"Callback function",
|
||||
`{{() => {
|
||||
// add code here
|
||||
showAlert('Hello')
|
||||
}}}`,
|
||||
);
|
||||
|
||||
agHelper.TypeText(
|
||||
propPane._actionSelectorFieldByLabel("Id"),
|
||||
|
|
@ -430,7 +432,7 @@ describe("UI to Code", () => {
|
|||
|
||||
propPane.ValidateJSFieldValue(
|
||||
"onClick",
|
||||
`{{setInterval(() => { // add c showAlert(\'Hello\'); // ode here}, 5000, \'interval-id\');}}`,
|
||||
`{{setInterval(() => { // add code here showAlert('Hello');}, 5000, 'interval-id');}}`,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
@ -256,7 +256,8 @@ describe("Autocomplete tests", () => {
|
|||
});
|
||||
});
|
||||
|
||||
it("7. Autocompletion for bindings inside array and objects", () => {
|
||||
//To fix soon
|
||||
it.skip("7. Autocompletion for bindings inside array and objects", () => {
|
||||
dataSources.CreateDataSource("Mongo", true, false);
|
||||
dataSources.CreateQueryAfterDSSaved();
|
||||
|
||||
|
|
|
|||
|
|
@ -33,11 +33,11 @@ describe("Text-Chart Binding Functionality", function () {
|
|||
this.dataSet.Chartval[1],
|
||||
this.dataSet.Chartval[2],
|
||||
];
|
||||
[0, 1, 2].forEach((k) => {
|
||||
[0, 2].forEach((k) => {
|
||||
cy.get(viewWidgetsPage.rectangleChart)
|
||||
.eq(k)
|
||||
.first()
|
||||
.trigger("mousemove", { force: true });
|
||||
cy.get(viewWidgetsPage.Chartlabel).eq(k).should("have.text", labels[k]);
|
||||
cy.get(viewWidgetsPage.Chartlabel).contains(labels[k]);
|
||||
});
|
||||
deployMode.DeployApp();
|
||||
});
|
||||
|
|
@ -51,8 +51,8 @@ describe("Text-Chart Binding Functionality", function () {
|
|||
this.dataSet.Chartval[2],
|
||||
];
|
||||
[0, 1, 2].forEach((k) => {
|
||||
cy.get(publish.rectChart).eq(k).trigger("mousemove", { force: true });
|
||||
cy.get(publish.chartLab).eq(k).should("have.text", labels[k]);
|
||||
cy.get(publish.rectChart).first().trigger("mousemove", { force: true });
|
||||
cy.get(publish.chartLab).contains(labels[k]);
|
||||
});
|
||||
cy.get(commonlocators.TextInside).should(
|
||||
"have.text",
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ describe("Text-Table Binding Functionality", function () {
|
|||
cy.get(viewWidgetsPage.chartWidget)
|
||||
.find("svg")
|
||||
.find("text")
|
||||
.should("contain.text", "Product2");
|
||||
.should("contain.text", "Product1");
|
||||
|
||||
cy.get(viewWidgetsPage.chartWidget)
|
||||
.find("svg")
|
||||
|
|
|
|||
|
|
@ -1,21 +0,0 @@
|
|||
import * as _ from "../../../../support/Objects/ObjectsCore";
|
||||
|
||||
describe("Test Create Api and Bind to Table widget V2", function () {
|
||||
before(() => {
|
||||
_.agHelper.AddDsl("tableV2WidgetDsl");
|
||||
});
|
||||
|
||||
it("1. Test_Add users api, execute it and go to sniping mode.", function () {
|
||||
cy.createAndFillApi(this.dataSet.userApi, "/mock-api?records=10");
|
||||
cy.RunAPI();
|
||||
cy.get(".t--select-in-canvas").click();
|
||||
cy.get(".t--sniping-mode-banner").should("be.visible");
|
||||
//Click on table name controller to bind the data and exit sniping mode
|
||||
cy.get(".t--draggable-tablewidgetv2").trigger("mouseover");
|
||||
cy.get(".t--settings-sniping-control").click();
|
||||
cy.get(".t--property-control-tabledata .CodeMirror").contains(
|
||||
"{{Api1.data}}",
|
||||
);
|
||||
cy.get(".t--sniping-mode-banner").should("not.exist");
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
import {
|
||||
agHelper,
|
||||
apiPage,
|
||||
table,
|
||||
tedTestConfig,
|
||||
} from "../../../../support/Objects/ObjectsCore";
|
||||
|
||||
import OneClickBinding from "../../../../locators/OneClickBindingLocator";
|
||||
import FirstTimeUserOnboarding from "../../../../locators/FirstTimeUserOnboarding.json";
|
||||
|
||||
describe("Test Create Api and Bind to Table widget V2", function () {
|
||||
before(() => {
|
||||
agHelper.AddDsl("tableV2WidgetDsl");
|
||||
});
|
||||
|
||||
it("1. Test_Add users api, execute it and go to sniping mode.", function () {
|
||||
apiPage.CreateAndFillApi(
|
||||
tedTestConfig.dsValues[tedTestConfig.defaultEnviorment].mockApiUrl,
|
||||
);
|
||||
apiPage.RunAPI();
|
||||
agHelper.GetNClick(FirstTimeUserOnboarding.selectWidgetBtn);
|
||||
agHelper.AssertElementVisible(FirstTimeUserOnboarding.snipingBanner);
|
||||
//Click on table name controller to bind the data and exit sniping mode
|
||||
agHelper.GetNClick(table._tableV2Widget);
|
||||
agHelper.AssertContains(
|
||||
"Api1",
|
||||
"exist",
|
||||
OneClickBinding.datasourceDropdownSelector,
|
||||
);
|
||||
agHelper.AssertElementAbsence(FirstTimeUserOnboarding.snipingBanner);
|
||||
});
|
||||
});
|
||||
|
|
@ -1,19 +1,26 @@
|
|||
import { featureFlagIntercept } from "../../../../support/Objects/FeatureFlags";
|
||||
import { ObjectsRegistry } from "../../../../support/Objects/Registry";
|
||||
|
||||
const agHelper = ObjectsRegistry.AggregateHelper,
|
||||
dataSources = ObjectsRegistry.DataSources,
|
||||
ee = ObjectsRegistry.EntityExplorer;
|
||||
import {
|
||||
agHelper,
|
||||
entityItems,
|
||||
dataSources,
|
||||
entityExplorer,
|
||||
homePage,
|
||||
} from "../../../../support/Objects/ObjectsCore";
|
||||
|
||||
let guid;
|
||||
let dataSourceName: string;
|
||||
describe("Datasource form related tests", function () {
|
||||
before(() => {
|
||||
homePage.CreateNewWorkspace("FetchSchemaOnce", true);
|
||||
homePage.CreateAppInWorkspace("FetchSchemaOnce");
|
||||
});
|
||||
|
||||
it("1. Bug - 17238 Verify datasource structure refresh on save - invalid datasource", () => {
|
||||
agHelper.GenerateUUID();
|
||||
cy.get("@guid").then((uid) => {
|
||||
guid = uid;
|
||||
dataSourceName = "Postgres " + guid;
|
||||
ee.ExpandCollapseEntity("Datasources");
|
||||
entityExplorer.ExpandCollapseEntity("Datasources");
|
||||
dataSources.NavigateToDSCreateNew();
|
||||
dataSources.CreatePlugIn("PostgreSQL");
|
||||
agHelper.RenameWithInPane(dataSourceName, false);
|
||||
|
|
@ -36,14 +43,16 @@ describe("Datasource form related tests", function () {
|
|||
|
||||
it("2. Verify if schema was fetched once #18448", () => {
|
||||
agHelper.RefreshPage();
|
||||
ee.ExpandCollapseEntity("Datasources");
|
||||
ee.ExpandCollapseEntity(dataSourceName, false);
|
||||
cy.intercept("GET", dataSources._getStructureReq).as("getDSStructure");
|
||||
ee.ExpandCollapseEntity("Datasources");
|
||||
ee.ExpandCollapseEntity(dataSourceName);
|
||||
entityExplorer.ExpandCollapseEntity("Datasources");
|
||||
entityExplorer.ExpandCollapseEntity(dataSourceName, false);
|
||||
entityExplorer.ExpandCollapseEntity("Datasources");
|
||||
entityExplorer.ExpandCollapseEntity(dataSourceName);
|
||||
agHelper.Sleep(1500);
|
||||
agHelper.VerifyCallCount(`@getDatasourceStructure`, 1);
|
||||
dataSources.DeleteQuery("Query1");
|
||||
agHelper.ActionContextMenuWithInPane({
|
||||
action: "Delete",
|
||||
entityType: entityItems.Query,
|
||||
});
|
||||
dataSources.DeleteDatasouceFromWinthinDS(dataSourceName);
|
||||
});
|
||||
|
||||
|
|
@ -61,7 +70,7 @@ describe("Datasource form related tests", function () {
|
|||
dataSources.CreateMockDB("Users");
|
||||
dataSources.CreateQueryAfterDSSaved();
|
||||
dataSources.VerifyTableSchemaOnQueryEditor("public.users");
|
||||
ee.ExpandCollapseEntity("public.users");
|
||||
entityExplorer.ExpandCollapseEntity("public.users");
|
||||
dataSources.VerifyColumnSchemaOnQueryEditor("id");
|
||||
dataSources.FilterAndVerifyDatasourceSchemaBySearch(
|
||||
"gender",
|
||||
|
|
|
|||
|
|
@ -9,10 +9,9 @@ let tempBranch3: any;
|
|||
|
||||
describe("Git Bugs", function () {
|
||||
before(() => {
|
||||
_.homePage.NavigateToHome();
|
||||
_.agHelper.GenerateUUID();
|
||||
cy.get("@guid").then((uid) => {
|
||||
_.homePage.CreateNewWorkspace("GitBugs" + uid);
|
||||
_.homePage.CreateNewWorkspace("GitBugs" + uid, true);
|
||||
_.homePage.CreateAppInWorkspace("GitBugs" + uid);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,43 +1,51 @@
|
|||
import * as _ from "../../../../support/Objects/ObjectsCore";
|
||||
import {
|
||||
agHelper,
|
||||
locators,
|
||||
entityExplorer,
|
||||
propPane,
|
||||
deployMode,
|
||||
draggableWidgets,
|
||||
assertHelper,
|
||||
} from "../../../../support/Objects/ObjectsCore";
|
||||
|
||||
describe("Dynamic Height Width validation for text widget", function () {
|
||||
before(() => {
|
||||
_.entityExplorer.DragDropWidgetNVerify(_.draggableWidgets.TEXT);
|
||||
entityExplorer.DragDropWidgetNVerify(draggableWidgets.TEXT);
|
||||
});
|
||||
|
||||
it("1. Text widget validation of height with dynamic height feature", function () {
|
||||
const textMsg =
|
||||
"Dynamic height validation for text widget validation with respect to Auto height";
|
||||
//changing the Text and verifying
|
||||
_.propPane.AssertPropertiesDropDownCurrentValue("Height", "Auto Height");
|
||||
propPane.AssertPropertiesDropDownCurrentValue("Height", "Auto Height");
|
||||
|
||||
_.agHelper.GetHeight(_.locators._widgetInDeployed(_.draggableWidgets.TEXT));
|
||||
propPane.AssertPropertiesDropDownValues("Height", [
|
||||
"Auto Height",
|
||||
"Auto Height with limits",
|
||||
"Fixed",
|
||||
]);
|
||||
|
||||
agHelper.GetHeight(locators._widgetInDeployed(draggableWidgets.TEXT));
|
||||
cy.get("@eleHeight").then(($initalHeight) => {
|
||||
_.propPane.UpdatePropertyFieldValue("Text", textMsg);
|
||||
_.propPane.MoveToTab("Style");
|
||||
_.propPane.SelectPropertiesDropDown("Font size", "L");
|
||||
_.assertHelper.AssertNetworkStatus("@updateLayout", 200); //for textMsg update
|
||||
_.agHelper.GetHeight(
|
||||
_.locators._widgetInDeployed(_.draggableWidgets.TEXT),
|
||||
);
|
||||
propPane.UpdatePropertyFieldValue("Text", textMsg);
|
||||
propPane.MoveToTab("Style");
|
||||
propPane.SelectPropertiesDropDown("Font size", "L");
|
||||
assertHelper.AssertNetworkStatus("@updateLayout", 200); //for textMsg update
|
||||
agHelper.GetHeight(locators._widgetInDeployed(draggableWidgets.TEXT));
|
||||
cy.get("@eleHeight").then(($addedtextHeight) => {
|
||||
expect($addedtextHeight).to.not.equal($initalHeight);
|
||||
_.deployMode.DeployApp(_.locators._textWidgetInDeployed);
|
||||
_.agHelper
|
||||
.GetText(_.locators._textWidgetInDeployed)
|
||||
.then(($text: any) => {
|
||||
expect($text).to.eq(textMsg);
|
||||
});
|
||||
deployMode.DeployApp(locators._textWidgetInDeployed);
|
||||
agHelper.GetText(locators._textWidgetInDeployed).then(($text: any) => {
|
||||
expect($text).to.eq(textMsg);
|
||||
});
|
||||
|
||||
_.agHelper.AssertAttribute(
|
||||
_.locators._textWidgetStyleInDeployed,
|
||||
agHelper.AssertAttribute(
|
||||
locators._textWidgetStyleInDeployed,
|
||||
"font-size",
|
||||
"1.25rem", //for Font size 'L'
|
||||
);
|
||||
|
||||
_.agHelper.GetHeight(
|
||||
_.locators._widgetInDeployed(_.draggableWidgets.TEXT),
|
||||
);
|
||||
agHelper.GetHeight(locators._widgetInDeployed(draggableWidgets.TEXT));
|
||||
cy.get("@eleHeight").then(($deployedAutoHeight) => {
|
||||
expect($deployedAutoHeight).not.eq($initalHeight);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -11,8 +11,7 @@ let ee = ObjectsRegistry.EntityExplorer,
|
|||
|
||||
describe("Entity explorer API pane related testcases", function () {
|
||||
it("1. Empty Message validation for Widgets/API/Queries", function () {
|
||||
homePage.NavigateToHome();
|
||||
homePage.CreateNewWorkspace("EmptyMsgCheck");
|
||||
homePage.CreateNewWorkspace("EmptyMsgCheck", true);
|
||||
homePage.CreateAppInWorkspace("EmptyMsgCheck");
|
||||
ee.ExpandCollapseEntity("Widgets");
|
||||
agHelper.AssertElementVisible(
|
||||
|
|
|
|||
|
|
@ -32,11 +32,10 @@ describe("Fork application with multiple datasources", function () {
|
|||
it("1. Bug Id: 24708 - fork and test the forked application", function () {
|
||||
// Create a new workspace and fork application
|
||||
const appname: string = localStorage.getItem("AppName") || "randomApp";
|
||||
homePage.NavigateToHome();
|
||||
agHelper.GenerateUUID();
|
||||
cy.get("@guid").then((uid) => {
|
||||
workspaceId = "forkApp" + uid;
|
||||
homePage.CreateNewWorkspace(workspaceId);
|
||||
homePage.CreateNewWorkspace(workspaceId, true);
|
||||
agHelper.PressEscape();
|
||||
cy.log("------------------" + workspaceId);
|
||||
homePage.ForkApplication(appname, workspaceId);
|
||||
|
|
|
|||
|
|
@ -8,13 +8,12 @@ let currentWorkspace: string, currentAppName: string, forkWorkspaceName: string;
|
|||
|
||||
describe("Fork application across workspaces", function () {
|
||||
it("Bug 24702: Signed user should be able to fork a public forkable app & Check if the forked application has the same dsl as the original", function () {
|
||||
homePage.NavigateToHome();
|
||||
// Create new workspace to create App in
|
||||
agHelper.GenerateUUID();
|
||||
cy.get("@guid").then((uid) => {
|
||||
currentWorkspace = "CurrentWorkspace " + uid;
|
||||
currentAppName = "MongoQueryApp " + uid;
|
||||
homePage.CreateNewWorkspace(currentWorkspace);
|
||||
homePage.CreateNewWorkspace(currentWorkspace, true);
|
||||
homePage.CreateAppInWorkspace(currentWorkspace, currentAppName);
|
||||
|
||||
// Create datasource and query
|
||||
|
|
@ -23,12 +22,11 @@ describe("Fork application across workspaces", function () {
|
|||
|
||||
// eslint-disable-next-line cypress/no-unnecessary-waiting
|
||||
cy.wait(2000);
|
||||
homePage.NavigateToHome();
|
||||
|
||||
agHelper.GenerateUUID();
|
||||
cy.get("@guid").then((uid) => {
|
||||
forkWorkspaceName = "ForkApplication" + uid;
|
||||
homePage.CreateNewWorkspace(forkWorkspaceName);
|
||||
homePage.CreateNewWorkspace(forkWorkspaceName, true);
|
||||
homePage.FilterApplication(currentAppName);
|
||||
|
||||
agHelper.Sleep(500);
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ describe("Mongo Form to Native conversion works", () => {
|
|||
_.dataSources.CreateQueryAfterDSSaved();
|
||||
_.assertHelper.AssertNetworkStatus("@trigger");
|
||||
_.dataSources.EnterJSContext({
|
||||
fieldProperty: _.dataSources._mongoCollectionPath,
|
||||
fieldLabel: "Collection",
|
||||
fieldValue: "listingAndReviews",
|
||||
});
|
||||
|
|
|
|||
|
|
@ -19,11 +19,10 @@ describe("Import and validate older app (app created in older versions of Appsmi
|
|||
keyId: any,
|
||||
workspaceName: any;
|
||||
before(() => {
|
||||
homePage.NavigateToHome();
|
||||
agHelper.GenerateUUID();
|
||||
cy.get("@guid").then((uid) => {
|
||||
workspaceName = "GitImport_" + uid;
|
||||
homePage.CreateNewWorkspace(workspaceName);
|
||||
homePage.CreateNewWorkspace(workspaceName, true);
|
||||
});
|
||||
//Import App From Gitea
|
||||
gitSync.ImportAppFromGit(workspaceName, appRepoName, true);
|
||||
|
|
|
|||
|
|
@ -79,7 +79,6 @@ describe("MaintainContext&Focus", function () {
|
|||
|
||||
cy.wait(1000);
|
||||
_.dataSources.EnterJSContext({
|
||||
fieldProperty: _.dataSources._mongoCollectionPath,
|
||||
fieldLabel: "Collection",
|
||||
fieldValue: "TestCollection",
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import homePage from "../../../../locators/HomePage";
|
||||
import * as _ from "../../../../support/Objects/ObjectsCore";
|
||||
|
||||
describe.skip("Visual regression tests", () => {
|
||||
describe("Visual regression tests", () => {
|
||||
// for any changes in UI, update the screenshot in snapshot folder, to do so:
|
||||
// 1. Delete the required screenshot which you want to update.
|
||||
// 2. Run test in headless mode with any browser
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import * as _ from "../../../../support/Objects/ObjectsCore";
|
||||
|
||||
describe.skip("Visual tests for datasources", () => {
|
||||
describe("Visual tests for datasources", () => {
|
||||
// for any changes in UI, update the screenshot in snapshot folder, to do so:
|
||||
// 1. Delete the required screenshot which you want to update.
|
||||
// 2. Run test in headless mode with any browser
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { ObjectsRegistry } from "../../../../support/Objects/Registry";
|
|||
let jsEditor = ObjectsRegistry.JSEditor,
|
||||
agHelper = ObjectsRegistry.AggregateHelper;
|
||||
|
||||
describe.skip("JSEditor Comment - Visual tests", () => {
|
||||
describe("JSEditor Comment - Visual tests", () => {
|
||||
it("1. comments code on the editor", () => {
|
||||
jsEditor.CreateJSObject(
|
||||
`export default {
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import {
|
|||
jsEditor,
|
||||
} from "../../../../support/Objects/ObjectsCore";
|
||||
|
||||
describe.skip("JSEditor Indendation - Visual tests", () => {
|
||||
describe("JSEditor Indendation - Visual tests", () => {
|
||||
it("6. TC 1933 - jSEditor prettify verification on cloned application", () => {
|
||||
const appname = localStorage.getItem("AppName");
|
||||
jsEditor.CreateJSObject(
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import * as _ from "../../../../support/Objects/ObjectsCore";
|
||||
|
||||
describe.skip("JS Editor Save and Auto-indent: Visual tests", () => {
|
||||
describe("JS Editor Save and Auto-indent: Visual tests", () => {
|
||||
it("1. Auto indents and saves the code when Ctrl/Cmd+s is pressed", () => {
|
||||
_.jsEditor.CreateJSObject(
|
||||
`export default {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
describe.skip("Visual regression tests", () => {
|
||||
describe("Visual regression tests", () => {
|
||||
// for any changes in UI, update the screenshot in snapshot folder, to do so:
|
||||
// 1. Delete the required screenshot which you want to update
|
||||
// 2. Run test in headless mode with chrome (to maintain same resolution in CI)
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ import {
|
|||
entityExplorer,
|
||||
} from "../../../../../support/Objects/ObjectsCore";
|
||||
|
||||
const widgetLocators = require("../../../../../locators/Widgets.json");
|
||||
|
||||
let dataSet: any, dsl: any;
|
||||
|
||||
describe("Input widget test with default value from chart datapoint", () => {
|
||||
|
|
@ -38,7 +40,7 @@ describe("Input widget test with default value from chart datapoint", () => {
|
|||
);
|
||||
deployMode.DeployApp();
|
||||
agHelper.Sleep(1500); //waiting for chart to load!
|
||||
agHelper.GetNClick("//*[local-name()='rect']", 13);
|
||||
agHelper.GetNClick(widgetLocators.chartDataPoint);
|
||||
cy.get(locators._widgetInputSelector("inputwidgetv2"))
|
||||
.first()
|
||||
.invoke("val")
|
||||
|
|
|
|||
|
|
@ -0,0 +1,46 @@
|
|||
import {
|
||||
agHelper,
|
||||
locators,
|
||||
entityExplorer,
|
||||
draggableWidgets,
|
||||
} from "../../../../../support/Objects/ObjectsCore";
|
||||
|
||||
describe("Chart renders widget errors", () => {
|
||||
it("1. If there are syntax errors, the errors are displayed inside the chart widget", function () {
|
||||
entityExplorer.DragDropWidgetNVerify(draggableWidgets.CHART);
|
||||
|
||||
agHelper.AssertContains(
|
||||
"Sales Report",
|
||||
"exist",
|
||||
locators._widgetInDeployed(draggableWidgets.CHART),
|
||||
);
|
||||
agHelper.AssertContains(
|
||||
"Error in Chart Data/Configuration",
|
||||
"not.exist",
|
||||
locators._widgetInDeployed(draggableWidgets.CHART),
|
||||
);
|
||||
|
||||
agHelper.EnterActionValue("Series data", "{{Button1.text}}");
|
||||
|
||||
agHelper.AssertContains(
|
||||
"Error in Chart Data/Configuration",
|
||||
"exist",
|
||||
locators._widgetInDeployed(draggableWidgets.CHART),
|
||||
);
|
||||
agHelper.AssertContains(
|
||||
"Sales Report",
|
||||
"not.exist",
|
||||
locators._widgetInDeployed(draggableWidgets.CHART),
|
||||
);
|
||||
});
|
||||
|
||||
it("2. shows no chart data available is series data is missing", function () {
|
||||
agHelper.EnterActionValue("Series data", "");
|
||||
|
||||
agHelper.AssertContains(
|
||||
"No chart data to display",
|
||||
"exist",
|
||||
locators._widgetInDeployed(draggableWidgets.CHART),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
@ -1,283 +0,0 @@
|
|||
const viewWidgetsPage = require("../../../../../locators/ViewWidgets.json");
|
||||
const widgetsPage = require("../../../../../locators/Widgets.json");
|
||||
import * as _ from "../../../../../support/Objects/ObjectsCore";
|
||||
|
||||
describe("Chart Widget Functionality", function () {
|
||||
before(() => {
|
||||
_.agHelper.AddDsl("chartUpdatedDsl");
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
cy.openPropertyPane("chartwidget");
|
||||
});
|
||||
|
||||
it("1. Fill the Chart Widget Properties.", function () {
|
||||
//changing the Chart Name
|
||||
/**
|
||||
* @param{Text} Random Text
|
||||
* @param{ChartWidget}Mouseover
|
||||
* @param{ChartPre Css} Assertion
|
||||
*/
|
||||
cy.widgetText(
|
||||
"Test",
|
||||
viewWidgetsPage.chartWidget,
|
||||
widgetsPage.widgetNameSpan,
|
||||
);
|
||||
cy.EnableAllCodeEditors();
|
||||
//changing the Chart Title
|
||||
/**
|
||||
* @param{Text} Random Input Value
|
||||
*/
|
||||
cy.testJsontext("title", this.dataSet.chartIndata);
|
||||
cy.get(viewWidgetsPage.chartInnerText)
|
||||
.click()
|
||||
.contains("App Sign Up")
|
||||
.should("have.text", "App Sign Up");
|
||||
|
||||
//Entering the Chart data
|
||||
cy.testJsontext(
|
||||
"chart-series-data-control",
|
||||
JSON.stringify(this.dataSet.chartInput),
|
||||
);
|
||||
cy.get(".t--propertypane").click("right");
|
||||
|
||||
// Asserting Chart Height
|
||||
cy.get(viewWidgetsPage.chartWidget)
|
||||
.should("be.visible")
|
||||
.and((chart) => {
|
||||
expect(chart.height()).to.be.greaterThan(200);
|
||||
});
|
||||
|
||||
//Entring the label of x-axis
|
||||
cy.get(viewWidgetsPage.xlabel)
|
||||
.click({ force: true })
|
||||
.type(this.dataSet.command)
|
||||
.type(this.dataSet.plan);
|
||||
//Entring the label of y-axis
|
||||
cy.get(viewWidgetsPage.ylabel)
|
||||
.click({ force: true })
|
||||
.type(this.dataSet.command)
|
||||
.click({ force: true })
|
||||
.type(this.dataSet.ylabel);
|
||||
|
||||
_.deployMode.DeployApp();
|
||||
});
|
||||
|
||||
it("2. Pie Chart Widget Functionality", function () {
|
||||
//changing the Chart type
|
||||
cy.UpdateChartType("Pie chart");
|
||||
|
||||
//Verifying X-axis labels
|
||||
cy.get(viewWidgetsPage.chartWidget).should("have.css", "opacity", "1");
|
||||
const labels = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
|
||||
[0, 1, 2, 3, 4, 5, 6].forEach((k) => {
|
||||
cy.get(viewWidgetsPage.rectangleChart)
|
||||
.last()
|
||||
.trigger("mousemove", { force: true });
|
||||
cy.get(viewWidgetsPage.PieChartLabel)
|
||||
.eq(k)
|
||||
.should("have.text", labels[k]);
|
||||
});
|
||||
_.deployMode.DeployApp();
|
||||
});
|
||||
|
||||
it("3. Line Chart Widget Functionality", function () {
|
||||
//changing the Chart type
|
||||
cy.UpdateChartType("Line chart");
|
||||
|
||||
//Verifying X-axis labels
|
||||
cy.get(viewWidgetsPage.chartWidget).should("have.css", "opacity", "1");
|
||||
const labels = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
|
||||
[0, 1, 2, 3, 4, 5, 6].forEach((k) => {
|
||||
cy.get(viewWidgetsPage.rectangleChart)
|
||||
.last()
|
||||
.trigger("mousemove", { force: true });
|
||||
cy.get(viewWidgetsPage.Chartlabel).eq(k).should("have.text", labels[k]);
|
||||
});
|
||||
_.deployMode.DeployApp();
|
||||
});
|
||||
|
||||
it("4. Bar Chart Widget Functionality", function () {
|
||||
//changing the Chart type
|
||||
cy.UpdateChartType("Bar chart");
|
||||
|
||||
//Verifying X-axis labels
|
||||
cy.get(viewWidgetsPage.chartWidget).should("have.css", "opacity", "1");
|
||||
const labels = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
|
||||
[0, 1, 2, 3, 4, 5, 6].forEach((k) => {
|
||||
cy.get(viewWidgetsPage.rectangleChart)
|
||||
.eq(k)
|
||||
.trigger("mousemove", { force: true });
|
||||
cy.get(viewWidgetsPage.Chartlabel).eq(k).should("have.text", labels[k]);
|
||||
});
|
||||
_.deployMode.DeployApp();
|
||||
});
|
||||
|
||||
it("5. Area Chart Widget Functionality", function () {
|
||||
//changing the Chart type
|
||||
cy.UpdateChartType("Area chart");
|
||||
|
||||
//Verifying X-axis labels
|
||||
cy.get(viewWidgetsPage.chartWidget).should("have.css", "opacity", "1");
|
||||
const labels = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
|
||||
[0, 1, 2, 3, 4, 5, 6].forEach((k) => {
|
||||
cy.get(viewWidgetsPage.rectangleChart)
|
||||
.last()
|
||||
.trigger("mousemove", { force: true });
|
||||
cy.get(viewWidgetsPage.Chartlabel).eq(k).should("have.text", labels[k]);
|
||||
});
|
||||
_.deployMode.DeployApp();
|
||||
});
|
||||
|
||||
it("6. Column Chart Widget Functionality", function () {
|
||||
//changing the Chart type
|
||||
cy.UpdateChartType("Column chart");
|
||||
|
||||
//Verifying X-axis labels
|
||||
cy.get(viewWidgetsPage.chartWidget).should("have.css", "opacity", "1");
|
||||
const labels = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
|
||||
[0, 1, 2, 3, 4, 5, 6].forEach((k) => {
|
||||
cy.get(viewWidgetsPage.rectangleChart)
|
||||
.eq(k)
|
||||
.trigger("mousemove", { force: true });
|
||||
cy.get(viewWidgetsPage.Chartlabel).eq(k).should("have.text", labels[k]);
|
||||
});
|
||||
_.deployMode.DeployApp();
|
||||
});
|
||||
|
||||
it("7. Toggle JS - Pie Chart Widget Functionality", function () {
|
||||
//changing the Chart type
|
||||
cy.get(widgetsPage.toggleChartType).click({ force: true });
|
||||
cy.testJsontext("charttype", "PIE_CHART");
|
||||
|
||||
//Verifying X-axis labels
|
||||
cy.get(viewWidgetsPage.chartWidget).should("have.css", "opacity", "1");
|
||||
const labels = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
|
||||
[0, 1, 2, 3, 4, 5, 6].forEach((k) => {
|
||||
cy.get(viewWidgetsPage.rectangleChart)
|
||||
.last()
|
||||
.trigger("mousemove", { force: true });
|
||||
cy.get(viewWidgetsPage.PieChartLabel)
|
||||
.eq(k)
|
||||
.should("have.text", labels[k]);
|
||||
});
|
||||
_.deployMode.DeployApp();
|
||||
});
|
||||
|
||||
it("8. Toggle JS - Line Chart Widget Functionality", function () {
|
||||
//changing the Chart type
|
||||
cy.testJsontext("charttype", "LINE_CHART");
|
||||
|
||||
//Verifying X-axis labels
|
||||
cy.get(viewWidgetsPage.chartWidget).should("have.css", "opacity", "1");
|
||||
const labels = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
|
||||
[0, 1, 2, 3, 4, 5, 6].forEach((k) => {
|
||||
cy.get(viewWidgetsPage.rectangleChart)
|
||||
.last()
|
||||
.trigger("mousemove", { force: true });
|
||||
cy.get(viewWidgetsPage.Chartlabel).eq(k).should("have.text", labels[k]);
|
||||
});
|
||||
_.deployMode.DeployApp();
|
||||
});
|
||||
|
||||
it("9. Toggle JS - Bar Chart Widget Functionality", function () {
|
||||
//changing the Chart type
|
||||
cy.testJsontext("charttype", "BAR_CHART");
|
||||
|
||||
//Verifying X-axis labels
|
||||
cy.get(viewWidgetsPage.chartWidget).should("have.css", "opacity", "1");
|
||||
const labels = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
|
||||
[0, 1, 2, 3, 4, 5, 6].forEach((k) => {
|
||||
cy.get(viewWidgetsPage.rectangleChart)
|
||||
.eq(k)
|
||||
.trigger("mousemove", { force: true });
|
||||
cy.get(viewWidgetsPage.Chartlabel).eq(k).should("have.text", labels[k]);
|
||||
});
|
||||
_.deployMode.DeployApp();
|
||||
});
|
||||
|
||||
it("10. Toggle JS - Area Chart Widget Functionality", function () {
|
||||
//changing the Chart type
|
||||
cy.testJsontext("charttype", "AREA_CHART");
|
||||
|
||||
//Verifying X-axis labels
|
||||
cy.get(viewWidgetsPage.chartWidget).should("have.css", "opacity", "1");
|
||||
const labels = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
|
||||
[0, 1, 2, 3, 4, 5, 6].forEach((k) => {
|
||||
cy.get(viewWidgetsPage.rectangleChart)
|
||||
.last()
|
||||
.trigger("mousemove", { force: true });
|
||||
cy.get(viewWidgetsPage.Chartlabel).eq(k).should("have.text", labels[k]);
|
||||
});
|
||||
_.deployMode.DeployApp();
|
||||
});
|
||||
|
||||
it("11. Toggle JS - Column Chart Widget Functionality", function () {
|
||||
//changing the Chart type
|
||||
cy.testJsontext("charttype", "COLUMN_CHART");
|
||||
|
||||
//Verifying X-axis labels
|
||||
cy.get(viewWidgetsPage.chartWidget).should("have.css", "opacity", "1");
|
||||
const labels = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
|
||||
[0, 1, 2, 3, 4, 5, 6].forEach((k) => {
|
||||
cy.get(viewWidgetsPage.rectangleChart)
|
||||
.eq(k)
|
||||
.trigger("mousemove", { force: true });
|
||||
cy.get(viewWidgetsPage.Chartlabel).eq(k).should("have.text", labels[k]);
|
||||
});
|
||||
_.deployMode.DeployApp();
|
||||
});
|
||||
|
||||
it("12. Check Chart widget reskinning config", function () {
|
||||
cy.get(widgetsPage.toggleChartType).click({ force: true });
|
||||
cy.UpdateChartType("Column chart");
|
||||
|
||||
// Check plot fill color
|
||||
cy.get("g[class*='plot-group'] rect").should(
|
||||
"have.css",
|
||||
"fill",
|
||||
"rgb(85, 61, 233)",
|
||||
);
|
||||
|
||||
// Check axis name font size
|
||||
cy.get("g[class*='dataset-axis-name'] text").should(
|
||||
"have.css",
|
||||
"font-size",
|
||||
"14px",
|
||||
);
|
||||
|
||||
// Check axis value font size and fill color
|
||||
cy.get("g[class$='dataset-axis'] text")
|
||||
.should("have.css", "font-size", "12px")
|
||||
.should("have.css", "fill", "rgb(113, 110, 110)");
|
||||
|
||||
// Check axis caption's fontSize, and fill color
|
||||
cy.get("g[class$='caption'] text")
|
||||
.should("have.css", "font-size", "24px")
|
||||
.should("have.css", "fill", "rgb(35, 31, 32)");
|
||||
|
||||
// Check base font family
|
||||
cy.get(".fusioncharts-container").should(
|
||||
"have.css",
|
||||
"font-family",
|
||||
'"Nunito Sans", sans-serif',
|
||||
);
|
||||
|
||||
cy.UpdateChartType("Pie chart");
|
||||
cy.get("g[class$='item'] text").should(
|
||||
"have.css",
|
||||
"font-family",
|
||||
'"Nunito Sans"',
|
||||
);
|
||||
cy.get("g[class$='labels'] text").should(
|
||||
"have.css",
|
||||
"font-family",
|
||||
'"Nunito Sans"',
|
||||
);
|
||||
_.deployMode.DeployApp();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
_.deployMode.NavigateBacktoEditor();
|
||||
});
|
||||
});
|
||||
|
|
@ -1,124 +0,0 @@
|
|||
const commonlocators = require("../../../../../locators/commonlocators.json");
|
||||
const viewWidgetsPage = require("../../../../../locators/ViewWidgets.json");
|
||||
const publish = require("../../../../../locators/publishWidgetspage.json");
|
||||
const modalWidgetPage = require("../../../../../locators/ModalWidget.json");
|
||||
const widgetsPage = require("../../../../../locators/Widgets.json");
|
||||
import * as _ from "../../../../../support/Objects/ObjectsCore";
|
||||
|
||||
describe("Chart Widget Functionality", function () {
|
||||
before(() => {
|
||||
_.agHelper.AddDsl("chartUpdatedDsl");
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
cy.openPropertyPane("chartwidget");
|
||||
});
|
||||
|
||||
it("1. Fill the Chart Widget Properties.", function () {
|
||||
//changing the Chart Name
|
||||
/**
|
||||
* @param{Text} Random Text
|
||||
* @param{ChartWidget}Mouseover
|
||||
* @param{ChartPre Css} Assertion
|
||||
*/
|
||||
cy.widgetText(
|
||||
"Test",
|
||||
viewWidgetsPage.chartWidget,
|
||||
widgetsPage.widgetNameSpan,
|
||||
);
|
||||
cy.EnableAllCodeEditors();
|
||||
//changing the Chart Title
|
||||
/**
|
||||
* @param{Text} Random Input Value
|
||||
*/
|
||||
cy.testJsontext("title", this.dataSet.chartIndata);
|
||||
cy.get(viewWidgetsPage.chartInnerText)
|
||||
.click()
|
||||
.contains("App Sign Up")
|
||||
.should("have.text", "App Sign Up");
|
||||
|
||||
//Entering the Chart data
|
||||
cy.testJsontext(
|
||||
"chart-series-data-control",
|
||||
JSON.stringify(this.dataSet.chartInput),
|
||||
);
|
||||
cy.get(".t--propertypane").click("right");
|
||||
|
||||
// Asserting Chart Height
|
||||
cy.get(viewWidgetsPage.chartWidget)
|
||||
.should("be.visible")
|
||||
.and((chart) => {
|
||||
expect(chart.height()).to.be.greaterThan(200);
|
||||
});
|
||||
|
||||
//Entring the label of x-axis
|
||||
cy.get(viewWidgetsPage.xlabel)
|
||||
.click({ force: true })
|
||||
.type(this.dataSet.command)
|
||||
.type(this.dataSet.plan);
|
||||
//Entring the label of y-axis
|
||||
cy.get(viewWidgetsPage.ylabel)
|
||||
.click({ force: true })
|
||||
.type(this.dataSet.command)
|
||||
.click({ force: true })
|
||||
.type(this.dataSet.ylabel);
|
||||
|
||||
_.deployMode.DeployApp();
|
||||
});
|
||||
|
||||
it("2. Chart - Modal", function () {
|
||||
//creating the Modal and verify Modal name
|
||||
cy.createModal(this.dataSet.ModalName, "onDataPointClick");
|
||||
_.deployMode.DeployApp();
|
||||
cy.get(widgetsPage.chartPlotGroup).children().first().click();
|
||||
cy.get(modalWidgetPage.modelTextField).should(
|
||||
"have.text",
|
||||
this.dataSet.ModalName,
|
||||
);
|
||||
});
|
||||
|
||||
it("3. Chart-Unckeck Visible field Validation", function () {
|
||||
// Making the widget invisible
|
||||
cy.togglebarDisable(commonlocators.visibleCheckbox);
|
||||
_.deployMode.DeployApp();
|
||||
cy.get(publish.chartWidget).should("not.exist");
|
||||
});
|
||||
|
||||
it("4. Chart-Check Visible field Validation", function () {
|
||||
// Making the widget visible
|
||||
cy.togglebar(commonlocators.visibleCheckbox);
|
||||
_.deployMode.DeployApp();
|
||||
cy.get(publish.chartWidget).should("be.visible");
|
||||
});
|
||||
|
||||
it("5. Toggle JS - Chart-Unckeck Visible field Validation", function () {
|
||||
//Uncheck the disabled checkbox using JS and validate
|
||||
cy.get(widgetsPage.toggleVisible).click({ force: true });
|
||||
cy.testJsontext("visible", "false");
|
||||
_.deployMode.DeployApp();
|
||||
cy.get(publish.chartWidget).should("not.exist");
|
||||
});
|
||||
|
||||
it("6. Toggle JS - Chart-Check Visible field Validation", function () {
|
||||
//Check the disabled checkbox using JS and Validate
|
||||
cy.testJsontext("visible", "true");
|
||||
_.deployMode.DeployApp();
|
||||
cy.get(publish.chartWidget).should("be.visible");
|
||||
});
|
||||
|
||||
it("7. Chart Widget Functionality To Uncheck Horizontal Scroll Visible", function () {
|
||||
cy.togglebarDisable(commonlocators.allowScroll);
|
||||
_.deployMode.DeployApp();
|
||||
cy.get(publish.horizontalTab).should("not.exist");
|
||||
});
|
||||
|
||||
it("8. Chart Widget Functionality To Check Horizontal Scroll Visible", function () {
|
||||
cy.togglebar(commonlocators.allowScroll);
|
||||
_.deployMode.DeployApp();
|
||||
cy.get(publish.horizontalTab).eq(1).should("exist");
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
_.deployMode.NavigateBacktoEditor();
|
||||
});
|
||||
});
|
||||
|
|
@ -77,10 +77,12 @@ describe("Chart Widget Functionality around custom chart feature", function () {
|
|||
cy.get(viewWidgetsPage.chartWidget).should("have.css", "opacity", "1");
|
||||
const labels = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul"];
|
||||
[0, 1, 2, 3, 4, 5, 6].forEach((k) => {
|
||||
cy.get(viewWidgetsPage.rectangleChart)
|
||||
cy.get(viewWidgetsPage.fusionRectangleChart)
|
||||
.eq(k)
|
||||
.trigger("mousemove", { force: true });
|
||||
cy.get(viewWidgetsPage.Chartlabel).eq(k).should("have.text", labels[k]);
|
||||
cy.get(viewWidgetsPage.FusionChartlabel)
|
||||
.eq(k)
|
||||
.should("have.text", labels[k]);
|
||||
});
|
||||
_.deployMode.DeployApp();
|
||||
});
|
||||
|
|
@ -94,17 +96,19 @@ describe("Chart Widget Functionality around custom chart feature", function () {
|
|||
"response.body.responseMeta.status",
|
||||
200,
|
||||
);
|
||||
cy.get(viewWidgetsPage.Chartlabel + ":first-child", {
|
||||
cy.get(viewWidgetsPage.FusionChartlabel + ":first-child", {
|
||||
timeout: 10000,
|
||||
}).should("have.css", "opacity", "1");
|
||||
//Verifying X-axis labels
|
||||
cy.get(viewWidgetsPage.chartWidget).should("have.css", "opacity", "1");
|
||||
const labels = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul"];
|
||||
[0, 1, 2, 3, 4, 5, 6].forEach((k) => {
|
||||
cy.get(viewWidgetsPage.rectangleChart)
|
||||
cy.get(viewWidgetsPage.fusionRectangleChart)
|
||||
.eq(k)
|
||||
.trigger("mousemove", { force: true });
|
||||
cy.get(viewWidgetsPage.Chartlabel).eq(k).should("have.text", labels[k]);
|
||||
cy.get(viewWidgetsPage.FusionChartlabel)
|
||||
.eq(k)
|
||||
.should("have.text", labels[k]);
|
||||
});
|
||||
|
||||
//Close edit prop
|
||||
|
|
|
|||
|
|
@ -18,9 +18,10 @@ describe("Dropdown Widget", function () {
|
|||
it("1. Dropdown-Modal Validation", function () {
|
||||
entityExplorer.ExpandCollapseEntity("Container3", "Widgets");
|
||||
entityExplorer.SelectEntityByName("Dropdown1", "Widgets");
|
||||
|
||||
cy.EnableAllCodeEditors();
|
||||
cy.testJsontext("sourcedata", JSON.stringify(this.dataSet.input));
|
||||
propPane.UpdatePropertyFieldValue(
|
||||
"Source Data",
|
||||
JSON.stringify(this.dataSet.input),
|
||||
);
|
||||
//creating the Modal and verify Modal name //to fix below
|
||||
// cy.createModal("Modal1", false);
|
||||
// deployMode.DeployApp();
|
||||
|
|
|
|||
|
|
@ -57,13 +57,15 @@ describe(" File Picker Widget", function () {
|
|||
// Test for isValid === True
|
||||
cy.dragAndDropToWidget("textwidget", "listwidgetv2", {
|
||||
x: 550,
|
||||
y: 50,
|
||||
y: 100,
|
||||
});
|
||||
|
||||
cy.RenameWidgetFromPropertyPane("textwidget", "Text1", "FilePicker_Widget");
|
||||
propPane.RenameWidget("Text1", "FilePicker_Widget");
|
||||
|
||||
propPane.UpdatePropertyFieldValue(
|
||||
"Text",
|
||||
"{{currentView.FilePicker1.isDirty}}_{{currentView.FilePicker1.isValid}}_{{currentView.FilePicker1.files[0]?.name}}",
|
||||
false,
|
||||
);
|
||||
cy.get(
|
||||
`${widgetSelector("FilePicker_Widget")} ${commonlocators.bodyTextStyle}`,
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ describe("Input Widgets", function () {
|
|||
it("2. Input Widgets isValid", function () {
|
||||
// Test for isValid === True
|
||||
_.entityExplorer.DragDropWidgetNVerify(_.draggableWidgets.TEXT, 600, 300);
|
||||
cy.RenameWidgetFromPropertyPane("textwidget", "Text1", "Input_Widget");
|
||||
_.propPane.RenameWidget("Text1", "Input_Widget");
|
||||
cy.wait(1000);
|
||||
_.propPane.UpdatePropertyFieldValue(
|
||||
"Text",
|
||||
|
|
@ -87,8 +87,9 @@ describe("Input Widgets", function () {
|
|||
.first()
|
||||
.should("have.text", "true");
|
||||
|
||||
_.entityExplorer.DragDropWidgetNVerify(_.draggableWidgets.TEXT, 600, 100);
|
||||
cy.RenameWidgetFromPropertyPane("textwidget", "Text1", "Currency_Widget");
|
||||
_.entityExplorer.DragDropWidgetNVerify(_.draggableWidgets.TEXT, 700, 100);
|
||||
_.propPane.RenameWidget("Text1", "Currency_Widget");
|
||||
|
||||
cy.wait(1000);
|
||||
_.propPane.UpdatePropertyFieldValue(
|
||||
"Text",
|
||||
|
|
@ -100,9 +101,8 @@ describe("Input Widgets", function () {
|
|||
.first()
|
||||
.should("have.text", "true");
|
||||
|
||||
_.entityExplorer.DragDropWidgetNVerify(_.draggableWidgets.TEXT, 600, 200);
|
||||
|
||||
cy.RenameWidgetFromPropertyPane("textwidget", "Text1", "PhoneInput_Widget");
|
||||
_.entityExplorer.DragDropWidgetNVerify(_.draggableWidgets.TEXT, 500, 400);
|
||||
_.propPane.RenameWidget("Text1", "PhoneInput_Widget");
|
||||
cy.wait(1000);
|
||||
_.propPane.UpdatePropertyFieldValue(
|
||||
"Text",
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import {
|
|||
deployMode,
|
||||
entityExplorer,
|
||||
jsEditor,
|
||||
locators,
|
||||
} from "../../../../../support/Objects/ObjectsCore";
|
||||
const commonlocators = require("../../../../../locators/commonlocators.json");
|
||||
|
||||
|
|
@ -78,10 +79,9 @@ describe("List widget V2 Serverside Pagination", () => {
|
|||
cy.wrap(data).should("deep.equal", {});
|
||||
});
|
||||
|
||||
// Select First Row
|
||||
cy.get(`${widgetSelector("List1")} ${containerWidgetSelector}`)
|
||||
.eq(0)
|
||||
.click();
|
||||
// Select First Row in List
|
||||
agHelper.GetNClick(locators._imgWidgetInsideList, 0, true);
|
||||
|
||||
cy.wait(200);
|
||||
|
||||
cy.get(
|
||||
|
|
|
|||
|
|
@ -85,25 +85,12 @@ describe(" Nested List Widgets ", function () {
|
|||
y: 100,
|
||||
},
|
||||
);
|
||||
propPane.RemoveText("Text");
|
||||
propPane.TypeTextIntoField("Text", "{{level_1.currentView.");
|
||||
|
||||
cy.get(".t--property-control-text .CodeMirror textarea").type(
|
||||
"{{level_1.currentView.",
|
||||
{
|
||||
force: true,
|
||||
},
|
||||
);
|
||||
checkAutosuggestion("Text1", "Object");
|
||||
checkAutosuggestion("List1Copy", "Object");
|
||||
|
||||
propPane.RemoveText("Text", false);
|
||||
|
||||
cy.get(".t--property-control-text .CodeMirror textarea").type(
|
||||
"{{level_1.currentView.List1Copy.",
|
||||
{
|
||||
force: true,
|
||||
},
|
||||
);
|
||||
propPane.TypeTextIntoField("Text", "{{level_1.currentView.List1Copy.");
|
||||
checkAutosuggestion("backgroundColor", "String");
|
||||
checkAutosuggestion("itemSpacing", "Number");
|
||||
checkAutosuggestion("isVisible", "Boolean");
|
||||
|
|
@ -123,10 +110,7 @@ describe(" Nested List Widgets ", function () {
|
|||
cy.wrap($el).should("not.have.text", "triggeredItemView");
|
||||
});
|
||||
|
||||
cy.get(".CodeMirror-hints")
|
||||
.contains("pageNo")
|
||||
.first()
|
||||
.click({ force: true });
|
||||
agHelper.GetNClickByContains(".CodeMirror-hints", "pageNo", 0, true);
|
||||
|
||||
cy.get(`${widgetSelector("Text2")} .bp3-ui-text span`).should(
|
||||
"have.text",
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@ import {
|
|||
agHelper,
|
||||
draggableWidgets,
|
||||
entityExplorer,
|
||||
locators,
|
||||
propPane,
|
||||
} from "../../../../../support/Objects/ObjectsCore";
|
||||
const toggleJSButton = (name) => `.t--property-control-${name} .t--js-toggle`;
|
||||
const widgetSelector = (name) => `[data-widgetname-cy="${name}"]`;
|
||||
|
|
@ -69,10 +71,11 @@ describe("List widget v2 onItemClick", () => {
|
|||
});
|
||||
|
||||
it("2. List widget V2 with onItemClick should be triggered when child widget without event is clicked", () => {
|
||||
cy.get(widgetSelector("Image1")).first().click({ force: true });
|
||||
//Select first row Image within list
|
||||
agHelper.GetNClick(locators._imgWidgetInsideList, 0, true);
|
||||
agHelper.WaitUntilToastDisappear("ListWidget_Blue_0");
|
||||
|
||||
cy.get(widgetSelector("Text1")).first().click({ force: true });
|
||||
agHelper.GetNClickByContains(locators._textWidget, "Blue", 0, true);
|
||||
agHelper.WaitUntilToastDisappear("ListWidget_Blue_0");
|
||||
|
||||
deleteAllWidgetsInContainer();
|
||||
|
|
@ -84,10 +87,8 @@ describe("List widget v2 onItemClick", () => {
|
|||
draggableWidgets.CONTAINER,
|
||||
);
|
||||
|
||||
cy.get(`${widgetSelector("Input1")} input`)
|
||||
.first()
|
||||
.click({ force: true });
|
||||
validateToastDoestExist();
|
||||
agHelper.GetNClick(`${locators._widgetByName("Input1")} input`, 0, true);
|
||||
agHelper.AssertElementAbsence(locators._toastMsg);
|
||||
|
||||
deleteAllWidgetsInContainer();
|
||||
|
||||
|
|
@ -98,10 +99,9 @@ describe("List widget v2 onItemClick", () => {
|
|||
draggableWidgets.CONTAINER,
|
||||
);
|
||||
|
||||
cy.get(`${widgetSelector("Select1")} button`)
|
||||
.first()
|
||||
.click({ force: true });
|
||||
validateToastDoestExist();
|
||||
//This is clicking Select Widget
|
||||
agHelper.ClickButton("Green", 0);
|
||||
agHelper.AssertElementAbsence(locators._toastMsg);
|
||||
|
||||
deleteAllWidgetsInContainer();
|
||||
|
||||
|
|
@ -112,20 +112,13 @@ describe("List widget v2 onItemClick", () => {
|
|||
draggableWidgets.CONTAINER,
|
||||
);
|
||||
|
||||
cy.get(`${widgetSelector("Button1")} button`)
|
||||
.first()
|
||||
.click({ force: true });
|
||||
agHelper.ClickButton("Submit", 0);
|
||||
agHelper.WaitUntilToastDisappear("ListWidget_Blue_0");
|
||||
|
||||
cy.get(widgetsPage.toggleOnClick).click({ force: true });
|
||||
cy.get(".t--property-control-onclick").then(($el) => {
|
||||
cy.updateCodeInput($el, "{{clearStore()}}");
|
||||
});
|
||||
cy.wait(1000);
|
||||
propPane.EnterJSContext("onClick", "{{clearStore()}}");
|
||||
agHelper.Sleep(1000);
|
||||
|
||||
cy.get(`${widgetSelector("Button1")} button`)
|
||||
.first()
|
||||
.click({ force: true });
|
||||
validateToastDoestExist();
|
||||
agHelper.ClickButton("Submit", 0);
|
||||
agHelper.AssertElementAbsence(locators._toastMsg);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import {
|
|||
agHelper,
|
||||
entityExplorer,
|
||||
draggableWidgets,
|
||||
propPane,
|
||||
} from "../../../../../support/Objects/ObjectsCore";
|
||||
|
||||
describe("Video Widget Functionality", function () {
|
||||
|
|
@ -70,27 +71,32 @@ describe("Video Widget Functionality", function () {
|
|||
});
|
||||
|
||||
it("4. Checks if video widget is reset on button click", function () {
|
||||
cy.testCodeMirror(testdata.videoUrl2);
|
||||
propPane.UpdatePropertyFieldValue("URL", testdata.videoUrl2);
|
||||
entityExplorer.DragDropWidgetNVerify(draggableWidgets.BUTTON, 200, 200);
|
||||
|
||||
cy.selectResetWidget("onClick");
|
||||
cy.selectWidgetForReset("Video1");
|
||||
|
||||
entityExplorer.DragDropWidgetNVerify(draggableWidgets.TEXT, 300, 300);
|
||||
|
||||
cy.updateCodeInput(".t--property-control-text", `{{Video1.playState}}`);
|
||||
propPane.UpdatePropertyFieldValue("Text", "{{Video1.playState}}");
|
||||
agHelper.Sleep(1500); // Wait time added for the widget to load current video state
|
||||
|
||||
cy.openPropertyPane("videowidget");
|
||||
cy.get(widgetsPage.autoPlay).click({ force: true });
|
||||
// Wait time added, allowing a second to pass between playing and pausing the widget, before it is reset to zero
|
||||
cy.wait(1000);
|
||||
cy.get(widgetsPage.autoPlay).click({ force: true });
|
||||
cy.get(widgetsPage.widgetBtn).click({ force: true });
|
||||
propPane.TogglePropertyState("Autoplay", "On");
|
||||
agHelper.Sleep(1500); // Wait time added for the widget to load current video state
|
||||
cy.get(".t--widget-textwidget").should("contain", "ENDED");
|
||||
|
||||
propPane.TogglePropertyState("Autoplay", "Off");
|
||||
agHelper.Sleep(1500); // Wait time added, allowing a second to pass between playing and pausing the widget, before it is reset to zero
|
||||
cy.get(".t--widget-textwidget").should("contain", "PAUSED");
|
||||
|
||||
agHelper.ClickButton("Submit");
|
||||
cy.wait(1000);
|
||||
cy.get(`${widgetsPage.videoWidget} video`).then(($video) => {
|
||||
const video = $video.get(0);
|
||||
expect(video.currentTime).to.equal(0);
|
||||
});
|
||||
agHelper.Sleep(1500); // Wait time added for the widget to load current video state
|
||||
cy.get(".t--widget-textwidget").should("contain", "NOT_STARTED");
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -59,9 +59,15 @@ describe("Admin settings page", function () {
|
|||
cy.go(-1);
|
||||
}
|
||||
});
|
||||
|
||||
it("3. should test that Business features shows upgrade button and direct to pricing page", () => {
|
||||
cy.visit("/settings/general", { timeout: 60000 });
|
||||
if (CURRENT_REPO === REPO.CE) {
|
||||
cy.get(adminsSettings.accessControl).within(() => {
|
||||
cy.get(adminsSettings.businessTag)
|
||||
.should("exist")
|
||||
.should("contain", "Business");
|
||||
});
|
||||
cy.get(adminsSettings.accessControl).click();
|
||||
cy.url().should("contain", "/settings/access-control");
|
||||
stubPricingPage();
|
||||
|
|
@ -69,6 +75,11 @@ describe("Admin settings page", function () {
|
|||
cy.get("@pricingPage").should("be.called");
|
||||
cy.wait(2000);
|
||||
cy.go(-1);
|
||||
cy.get(adminsSettings.auditLogs).within(() => {
|
||||
cy.get(adminsSettings.businessTag)
|
||||
.should("exist")
|
||||
.should("contain", "Business");
|
||||
});
|
||||
cy.get(adminsSettings.auditLogs).click();
|
||||
cy.url().should("contain", "/settings/audit-logs");
|
||||
stubPricingPage();
|
||||
|
|
@ -76,6 +87,18 @@ describe("Admin settings page", function () {
|
|||
cy.get("@pricingPage").should("be.called");
|
||||
cy.wait(2000);
|
||||
cy.go(-1);
|
||||
cy.get(adminsSettings.provisioning).within(() => {
|
||||
cy.get(adminsSettings.businessTag)
|
||||
.should("exist")
|
||||
.should("contain", "Enterprise");
|
||||
});
|
||||
cy.get(adminsSettings.provisioning).click();
|
||||
cy.url().should("contain", "/settings/provisioning");
|
||||
stubPricingPage();
|
||||
cy.xpath(adminsSettings.upgrade).click();
|
||||
cy.get("@pricingPage").should("be.called");
|
||||
cy.wait(2000);
|
||||
cy.go(-1);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -0,0 +1,232 @@
|
|||
import {
|
||||
agHelper,
|
||||
entityExplorer,
|
||||
deployMode,
|
||||
appSettings,
|
||||
dataSources,
|
||||
table,
|
||||
locators,
|
||||
assertHelper,
|
||||
draggableWidgets,
|
||||
} from "../../../../support/Objects/ObjectsCore";
|
||||
import { Widgets } from "../../../../support/Pages/DataSources";
|
||||
|
||||
describe("Validate Mongo URI CRUD with JSON Form", () => {
|
||||
let dsName: any;
|
||||
|
||||
it("1. Create DS & Generate CRUD template", () => {
|
||||
dataSources.NavigateToDSCreateNew();
|
||||
agHelper.GenerateUUID();
|
||||
cy.get("@guid").then((uid) => {
|
||||
dataSources.CreatePlugIn("MongoDB");
|
||||
dsName = "Mongo" + uid;
|
||||
agHelper.RenameWithInPane(dsName, false);
|
||||
dataSources.FillMongoDatasourceFormWithURI();
|
||||
dataSources.TestSaveDatasource();
|
||||
entityExplorer.AddNewPage("Generate page with data");
|
||||
agHelper.GetNClick(dataSources._selectDatasourceDropdown);
|
||||
agHelper.GetNClickByContains(dataSources._dropdownOption, dsName);
|
||||
|
||||
assertHelper.AssertNetworkStatus("@getDatasourceStructure"); //Making sure table dropdown is populated
|
||||
agHelper.GetNClick(dataSources._selectTableDropdown, 0, true);
|
||||
agHelper.GetNClickByContains(dataSources._dropdownOption, "mongomart");
|
||||
GenerateCRUDNValidateDeployPage(
|
||||
"/img/products/mug.jpg",
|
||||
"Coffee Mug",
|
||||
`Kitchen`,
|
||||
4,
|
||||
);
|
||||
|
||||
deployMode.NavigateBacktoEditor();
|
||||
table.WaitUntilTableLoad();
|
||||
//Should not be able to delete ds until app is published again
|
||||
//coz if app is published & shared then deleting ds may cause issue, So!
|
||||
dataSources.DeleteDatasouceFromActiveTab(dsName as string, 409);
|
||||
});
|
||||
});
|
||||
|
||||
it("2. Verify Update data from Deploy page - on mongomart - existing record", () => {
|
||||
//Update documents query to handle the int _id data
|
||||
entityExplorer.NavigateToSwitcher("Explorer", 0, true);
|
||||
entityExplorer.SelectEntityByName("UpdateQuery");
|
||||
agHelper.EnterValue(`{ _id: {{data_table.selectedRow._id}}}`, {
|
||||
propFieldName: "",
|
||||
directInput: false,
|
||||
inputFieldName: "Query",
|
||||
});
|
||||
deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.TABLE_V1));
|
||||
agHelper.GetNAssertElementText(
|
||||
locators._textWidgetInDeployed,
|
||||
"mongomart Data",
|
||||
);
|
||||
//Validating loaded table
|
||||
table.SelectTableRow(2);
|
||||
agHelper.AssertElementExist(dataSources._selectedRow);
|
||||
table.ReadTableRowColumnData(2, 0, "v1", 200).then(($cellData) => {
|
||||
expect($cellData).to.be.empty;
|
||||
});
|
||||
table.ReadTableRowColumnData(2, 6, "v1", 2000).then(($cellData) => {
|
||||
expect($cellData).to.eq("WiredTiger T-shirt");
|
||||
});
|
||||
table.ReadTableRowColumnData(2, 7, "v1", 200).then(($cellData) => {
|
||||
expect($cellData).to.eq("Apparel");
|
||||
});
|
||||
|
||||
table.SelectTableRow(8);
|
||||
deployMode.ClearJSONFieldValue("Slogan");
|
||||
deployMode.ClearJSONFieldValue("Category");
|
||||
|
||||
agHelper.ClickButton("Update");
|
||||
agHelper.AssertElementAbsence(locators._toastMsg); //Validating fix for Bug 14063
|
||||
for (let i = 7; i <= 8; i++) {
|
||||
table.ReadTableRowColumnData(8, i, "v1").then(($cellData) => {
|
||||
expect($cellData).to.be.empty;
|
||||
});
|
||||
}
|
||||
deployMode.EnterJSONInputValue(
|
||||
"Slogan",
|
||||
"Write Your Story with Elegance: The Pen of Choice!",
|
||||
);
|
||||
agHelper.GetNClick(deployMode._jsonFormNumberFieldByName("Stars", "up")); //1
|
||||
agHelper.GetNClick(deployMode._jsonFormNumberFieldByName("Stars", "up")); //2
|
||||
agHelper.GetNClick(deployMode._jsonFormNumberFieldByName("Stars", "up")); //3
|
||||
|
||||
agHelper.ClickButton("Update");
|
||||
agHelper.AssertElementAbsence(locators._toastMsg); //Validating fix for Bug 14063
|
||||
table.ReadTableRowColumnData(8, 8, "v1", 200).then(($cellData) => {
|
||||
expect($cellData).to.eq(
|
||||
"Write Your Story with Elegance: The Pen of Choice!",
|
||||
);
|
||||
});
|
||||
table.ReadTableRowColumnData(8, 5, "v1", 200).then(($cellData) => {
|
||||
expect($cellData).to.eq("3");
|
||||
});
|
||||
});
|
||||
|
||||
it("3. Verify Add/Insert from Deploy page - on MongoMart - new record - few validations", () => {
|
||||
agHelper.GetNClick(dataSources._addIcon);
|
||||
agHelper.Sleep();
|
||||
//agHelper.AssertElementVisible(locators._jsonFormWidget, 1); //Insert Modal
|
||||
agHelper.AssertElementVisible(locators._visibleTextDiv("Insert Document"));
|
||||
|
||||
agHelper.AssertElementEnabledDisabled(
|
||||
locators._spanButton("Submit") + "/parent::div",
|
||||
0,
|
||||
false,
|
||||
);
|
||||
agHelper.ClickButton("Submit");
|
||||
for (let i = 0; i <= 1; i++) {
|
||||
table.ReadTableRowColumnData(i, 6, "v1").then(($cellData) => {
|
||||
expect($cellData).contains("Coffee Mug");
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
it("4. Verify Delete from Deploy page - on MongoMart - newly added record", () => {
|
||||
agHelper.ClickButton("Delete", 0);
|
||||
agHelper.AssertElementVisible(locators._modal);
|
||||
agHelper.AssertElementVisible(
|
||||
dataSources._visibleTextSpan(
|
||||
"Are you sure you want to delete this document?",
|
||||
),
|
||||
);
|
||||
agHelper.ClickButton("Confirm");
|
||||
assertHelper.AssertNetworkStatus("@postExecute", 200);
|
||||
assertHelper.AssertNetworkStatus("@postExecute", 200);
|
||||
table.ReadTableRowColumnData(0, 6, "v1", 200).then(($cellData) => {
|
||||
expect($cellData).to.eq("Coffee Mug");
|
||||
});
|
||||
table.ReadTableRowColumnData(1, 6, "v1", 200).then(($cellData) => {
|
||||
expect($cellData).to.eq("Track Jacket");
|
||||
});
|
||||
});
|
||||
|
||||
it("5 Verify Filter & Search & Download from Deploy page - on MongoMart - existing record", () => {
|
||||
table.SearchTable("Swag");
|
||||
agHelper.Sleep(2500); //for search to load
|
||||
for (let i = 0; i <= 1; i++) {
|
||||
table.ReadTableRowColumnData(i, 6, "v1").then(($cellData) => {
|
||||
expect($cellData).to.eq("Swag");
|
||||
});
|
||||
}
|
||||
table.ResetSearch();
|
||||
|
||||
table.OpenNFilterTable("title", "contains", "USB");
|
||||
for (let i = 0; i < 3; i++) {
|
||||
table.ReadTableRowColumnData(i, 5, "v1").then(($cellData) => {
|
||||
expect($cellData).contains("USB");
|
||||
});
|
||||
}
|
||||
table.CloseFilter();
|
||||
|
||||
table.DownloadFromTable("Download as CSV");
|
||||
table.ValidateDownloadNVerify("data_table.csv", "USB Stick (Green)");
|
||||
|
||||
table.DownloadFromTable("Download as Excel");
|
||||
table.ValidateDownloadNVerify("data_table.xlsx", "USB Stick (Leaf)");
|
||||
table.OpenFilter();
|
||||
table.RemoveFilter();
|
||||
agHelper
|
||||
.GetText(table._filtersCount)
|
||||
.then(($filters) => expect($filters).to.eq("Filters"));
|
||||
});
|
||||
|
||||
it("6. Suggested Widget - Table", () => {
|
||||
table.SelectTableRow(8);
|
||||
agHelper.GetNClick(deployMode._jsonFormNumberFieldByName("Stars", "down")); //2
|
||||
agHelper.GetNClick(deployMode._jsonFormNumberFieldByName("Stars", "down")); //1
|
||||
agHelper.GetNClick(deployMode._jsonFormNumberFieldByName("Stars", "down")); //0
|
||||
agHelper.ClickButton("Update");
|
||||
|
||||
deployMode.NavigateBacktoEditor();
|
||||
table.WaitUntilTableLoad();
|
||||
entityExplorer.AddNewPage();
|
||||
dataSources.NavigateFromActiveDS(dsName, true);
|
||||
dataSources.ValidateNSelectDropdown("Collection", "", "mongomart");
|
||||
dataSources.RunQuery({ toValidateResponse: false });
|
||||
dataSources.AddSuggesstedWidget(Widgets.Table);
|
||||
table.ReadTableRowColumnData(0, 3, "v2").then((cellData) => {
|
||||
expect(cellData).to.eq("1");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function GenerateCRUDNValidateDeployPage(
|
||||
col1Text: string,
|
||||
col6Text: string,
|
||||
col7Text: string,
|
||||
idIndex: number,
|
||||
) {
|
||||
agHelper.GetNClick(dataSources._generatePageBtn);
|
||||
assertHelper.AssertNetworkStatus("@replaceLayoutWithCRUDPage", 201);
|
||||
agHelper.AssertContains("Successfully generated a page"); // Commenting this since FindQuery failure appears sometimes
|
||||
assertHelper.AssertNetworkStatus("@getActions", 200);
|
||||
assertHelper.AssertNetworkStatus("@postExecute", 200);
|
||||
agHelper.GetNClick(dataSources._visibleTextSpan("Got it"));
|
||||
assertHelper.AssertNetworkStatus("@updateLayout", 200);
|
||||
appSettings.OpenPaneAndChangeTheme("Pacific");
|
||||
deployMode.DeployApp(locators._widgetInDeployed("tablewidget"));
|
||||
|
||||
//Validating loaded table
|
||||
agHelper.AssertElementExist(dataSources._selectedRow);
|
||||
table.ReadTableRowColumnData(0, 1, "v1", 2000).then(($cellData) => {
|
||||
expect($cellData).to.eq(col1Text);
|
||||
});
|
||||
table.ReadTableRowColumnData(0, 6, "v1", 200).then(($cellData) => {
|
||||
expect($cellData).to.eq(col6Text);
|
||||
});
|
||||
table.ReadTableRowColumnData(0, 7, "v1", 200).then(($cellData) => {
|
||||
expect($cellData).to.eq(col7Text);
|
||||
});
|
||||
|
||||
//Validating loaded JSON form
|
||||
cy.xpath(locators._spanButton("Update")).then((selector) => {
|
||||
cy.wrap(selector)
|
||||
.invoke("attr", "class")
|
||||
.then((classes) => {
|
||||
//cy.log("classes are:" + classes);
|
||||
expect(classes).not.contain("bp3-disabled");
|
||||
});
|
||||
});
|
||||
dataSources.AssertJSONFormHeader(0, idIndex, "Id", "", true);
|
||||
}
|
||||
|
|
@ -3,6 +3,8 @@ const datasourceEditor = require("../../../../locators/DatasourcesEditor.json");
|
|||
const commonlocators = require("../../../../locators/commonlocators.json");
|
||||
|
||||
import {
|
||||
agHelper,
|
||||
dataSources,
|
||||
entityExplorer,
|
||||
deployMode,
|
||||
homePage,
|
||||
|
|
@ -34,13 +36,8 @@ describe("Generate New CRUD Page Inside from entity explorer", function () {
|
|||
cy.wrap(datasourceName).as("dSName");
|
||||
});
|
||||
|
||||
//TestData source
|
||||
cy.get(".t--test-datasource").click();
|
||||
cy.wait("@testDatasource");
|
||||
|
||||
//Save source
|
||||
cy.get(".t--save-datasource").click();
|
||||
|
||||
//TestData & save datasource
|
||||
dataSources.TestSaveDatasource();
|
||||
// fetch bucket
|
||||
cy.wait("@getDatasourceStructure").should(
|
||||
"have.nested.property",
|
||||
|
|
@ -48,13 +45,13 @@ describe("Generate New CRUD Page Inside from entity explorer", function () {
|
|||
200,
|
||||
);
|
||||
|
||||
cy.get(generatePage.selectTableDropdown).click();
|
||||
cy.get(generatePage.dropdownOption)
|
||||
.contains("assets-test.appsmith.com")
|
||||
.scrollIntoView()
|
||||
.should("be.visible")
|
||||
.click();
|
||||
cy.get(generatePage.generatePageFormSubmitBtn).click();
|
||||
agHelper.AssertContains("Generate from data");
|
||||
agHelper.GetNClick(generatePage.selectTableDropdown);
|
||||
agHelper.GetNClickByContains(
|
||||
generatePage.dropdownOption,
|
||||
"assets-test.appsmith.com",
|
||||
);
|
||||
agHelper.GetNClick(generatePage.generatePageFormSubmitBtn);
|
||||
|
||||
cy.wait("@put_replaceLayoutCRUD").should(
|
||||
"have.nested.property",
|
||||
|
|
|
|||
|
|
@ -83,7 +83,6 @@ describe("Validate Mongo query commands", function () {
|
|||
);
|
||||
|
||||
dataSources.EnterJSContext({
|
||||
fieldProperty: dataSources._mongoCollectionPath,
|
||||
fieldLabel: "Collection",
|
||||
fieldValue: "listingAndReviews",
|
||||
});
|
||||
|
|
@ -153,7 +152,6 @@ describe("Validate Mongo query commands", function () {
|
|||
"Count",
|
||||
);
|
||||
dataSources.EnterJSContext({
|
||||
fieldProperty: dataSources._mongoCollectionPath,
|
||||
fieldLabel: "Collection",
|
||||
fieldValue: "listingAndReviews",
|
||||
});
|
||||
|
|
@ -182,7 +180,6 @@ describe("Validate Mongo query commands", function () {
|
|||
"Distinct",
|
||||
);
|
||||
dataSources.EnterJSContext({
|
||||
fieldProperty: dataSources._mongoCollectionPath,
|
||||
fieldLabel: "Collection",
|
||||
fieldValue: "listingAndReviews",
|
||||
});
|
||||
|
|
@ -215,7 +212,6 @@ describe("Validate Mongo query commands", function () {
|
|||
"Aggregate",
|
||||
);
|
||||
dataSources.EnterJSContext({
|
||||
fieldProperty: dataSources._mongoCollectionPath,
|
||||
fieldLabel: "Collection",
|
||||
fieldValue: "listingAndReviews",
|
||||
});
|
||||
|
|
@ -411,7 +407,6 @@ describe("Validate Mongo query commands", function () {
|
|||
{"_id":3, "Från" :"Olivia" , "Frõ" :"Active", "Leverantör":"De Bolster", "Frö":"Sallad - Oakleaf 'Red Salad Bowl'"}]`;
|
||||
|
||||
dataSources.EnterJSContext({
|
||||
fieldProperty: dataSources._mongoCollectionPath,
|
||||
fieldLabel: "Collection",
|
||||
fieldValue: "NonAsciiTest",
|
||||
});
|
||||
|
|
|
|||
|
|
@ -287,7 +287,6 @@ describe("Validate Mongo Query Pane Validations", () => {
|
|||
);
|
||||
|
||||
dataSources.EnterJSContext({
|
||||
fieldProperty: dataSources._mongoCollectionPath,
|
||||
fieldLabel: "Collection",
|
||||
fieldValue: "AuthorNAwards",
|
||||
});
|
||||
|
|
@ -777,7 +776,6 @@ describe("Validate Mongo Query Pane Validations", () => {
|
|||
|
||||
agHelper.RenameWithInPane("InsertBirthNDeath");
|
||||
dataSources.EnterJSContext({
|
||||
fieldProperty: dataSources._mongoCollectionPath,
|
||||
fieldLabel: "Collection",
|
||||
fieldValue: "BirthNDeath",
|
||||
});
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import {
|
|||
} from "../../../support/Objects/ObjectsCore";
|
||||
|
||||
let dsName: any, jsonSpecies: any, offset: any, insertedRecordId: any;
|
||||
describe.skip("excludeForAirgap", "Validate Airtable Ds", () => {
|
||||
describe("excludeForAirgap", "Validate Airtable Ds", () => {
|
||||
before("Create a new Airtable DS", () => {
|
||||
dataSources.CreateDataSource("Airtable", true, false);
|
||||
cy.get("@dsName").then(($dsName) => {
|
||||
|
|
@ -259,7 +259,8 @@ describe.skip("excludeForAirgap", "Validate Airtable Ds", () => {
|
|||
});
|
||||
});
|
||||
|
||||
it("2. Create/Retrieve/Update/Delete records", () => {
|
||||
//Skipping since Create records sometimes not giving results
|
||||
it.skip("2. Create/Retrieve/Update/Delete records", () => {
|
||||
let createReq = `[{"fields": {
|
||||
"Species_ID": "SF",
|
||||
"Genus": "Sigmodon",
|
||||
|
|
@ -379,6 +380,6 @@ describe.skip("excludeForAirgap", "Validate Airtable Ds", () => {
|
|||
action: "Delete",
|
||||
entityType: entityItems.Datasource,
|
||||
});
|
||||
assertHelper.AssertNetworkStatus("@deleteDatasource", 200);
|
||||
//assertHelper.AssertNetworkStatus("@deleteDatasource", 200); //to uncomment after 2nd case is fixed
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -41,7 +41,8 @@ describe("Authenticated API Datasource", function () {
|
|||
dataSources.DeleteDatasouceFromActiveTab(dsName);
|
||||
});
|
||||
|
||||
it("4. Bug: 18051 - Save and Authorise should return to datasource page in view mode and not new datasource page", () => {
|
||||
//skipping this test as it is failing in pipeline - "authorizationURL": "https://oauth.mocklab.io/oauth/authorize",
|
||||
it.skip("4. Bug: 18051 - Save and Authorise should return to datasource page in view mode and not new datasource page", () => {
|
||||
cy.NavigateToAPI_Panel();
|
||||
cy.get(apiwidget.createAuthApiDatasource).click();
|
||||
cy.generateUUID().then((uuid) => {
|
||||
|
|
|
|||
|
|
@ -241,12 +241,8 @@ describe("Validate MsSQL connection & basic querying with UI flows", () => {
|
|||
});
|
||||
|
||||
after("Verify Deletion of the datasource", () => {
|
||||
entityExplorer.SelectEntityByName(dsName, "Datasources");
|
||||
entityExplorer.ActionContextMenuByEntityName({
|
||||
entityNameinLeftSidebar: dsName,
|
||||
action: "Delete",
|
||||
entityType: entityItems.Datasource,
|
||||
});
|
||||
cy.intercept("DELETE", "/api/v1/datasources/*").as("deleteDatasource"); //Since intercept from before is not working
|
||||
dataSources.DeleteDatasouceFromWinthinDS(dsName);
|
||||
//dataSources.StopNDeleteContainer(containerName); //commenting to check if MsSQL specific container deletion is causing issues
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -12,10 +12,8 @@ describe("Datasource form OAuth2 client credentials related tests", function ()
|
|||
it("1. Create an API with app url and save as Datasource for Client Credentials test", function () {
|
||||
apiPage.CreateAndFillApi(testdata.appUrl, "TestOAuth");
|
||||
agHelper.GetNClick(apiPage._saveAsDS);
|
||||
// agHelper.ValidateToastMessage("datasource created"); //verifying there is no error toast, Bug 14566
|
||||
});
|
||||
|
||||
it("2. Add Oauth details to datasource and save", function () {
|
||||
// Add Oauth details to datasource and save
|
||||
cy.get(datasource.saveBtn).should("not.be.disabled");
|
||||
dataSources.AddOAuth2AuthorizationCodeDetails(
|
||||
testdata.accessTokenUrl,
|
||||
|
|
@ -27,7 +25,7 @@ describe("Datasource form OAuth2 client credentials related tests", function ()
|
|||
// since we are moving to different, it will show unsaved changes dialog
|
||||
// save datasource and then proceed
|
||||
dataSources.SaveDatasource();
|
||||
|
||||
agHelper.ValidateToastMessage("datasource created"); //verifying there is no error toast, Bug 14566
|
||||
entityExplorer.SelectEntityByName("TestOAuth", "Queries/JS");
|
||||
agHelper.ActionContextMenuWithInPane({
|
||||
action: "Delete",
|
||||
|
|
@ -35,13 +33,10 @@ describe("Datasource form OAuth2 client credentials related tests", function ()
|
|||
});
|
||||
});
|
||||
|
||||
it("3. Create an API with app url and save as Datasource for Authorization code details test", function () {
|
||||
it("2. Create an API with app url and save as Datasource for Authorization code details test", function () {
|
||||
apiPage.CreateAndFillApi(testdata.appUrl, "TestOAuth");
|
||||
agHelper.GetNClick(apiPage._saveAsDS);
|
||||
// agHelper.ValidateToastMessage("datasource created"); //verifying there is no error toast, Bug 14566
|
||||
});
|
||||
|
||||
it("4. Add Oauth details to datasource and save", function () {
|
||||
//Add Oauth details to datasource and save
|
||||
cy.get(datasource.saveBtn).should("not.be.disabled");
|
||||
dataSources.AddOAuth2AuthorizationCodeDetails(
|
||||
testdata.accessTokenUrl,
|
||||
|
|
@ -51,7 +46,8 @@ describe("Datasource form OAuth2 client credentials related tests", function ()
|
|||
);
|
||||
});
|
||||
|
||||
it("5. Validate save and Authorise", function () {
|
||||
//skipping this test as it is failing in pipeline - "authorizationURL": "https://oauth.mocklab.io/oauth/authorize",
|
||||
it.skip("3. Validate save and Authorise", function () {
|
||||
cy.get(datasource.saveAndAuthorize).click();
|
||||
cy.contains("#login-submit", "Login");
|
||||
cy.url().should("include", "oauth.mocklab.io/oauth/authorize");
|
||||
|
|
|
|||
192
app/client/cypress/fixtures/test-data-gsheet.ts
Normal file
192
app/client/cypress/fixtures/test-data-gsheet.ts
Normal file
|
|
@ -0,0 +1,192 @@
|
|||
export const GSHEET_DATA = [
|
||||
{
|
||||
rowIndex: "0",
|
||||
uniq_id: "eac7efa5dbd3d667f26eb3d3ab504464",
|
||||
japanese_name: "ホーンビィ 2014 カタログ",
|
||||
currencies: "₹, $, €, ¥, £",
|
||||
specialChars: "!@#$%^&*",
|
||||
product_name: "Hornby 2014 Catalogue",
|
||||
manufacturer: "Hornby",
|
||||
price: "3.42",
|
||||
number_available_in_stock: "5 new",
|
||||
number_of_reviews: "15",
|
||||
number_of_answered_questions: "1",
|
||||
average_review_rating: "4.9 out of 5 stars",
|
||||
amazon_category_and_sub_category:
|
||||
"Hobbies > Model Trains & Railway Sets > Rail Vehicles > Trains",
|
||||
customers_who_bought_this_item_also_bought:
|
||||
"http://www.amazon.co.uk/Hornby-R8150-Catalogue-2015/dp/B00S9SUUBE | http://www.amazon.co.uk/Hornby-Book-Model-Railways-Edition/dp/1844860957 | http://www.amazon.co.uk/Hornby-Book-Scenic-Railway-Modelling/dp/1844861120 | http://www.amazon.co.uk/Peco-60-Plans-Book/dp/B002QVL16I | http://www.amazon.co.uk/Hornby-Gloucester | http://www.amazon.co.uk/Airfix-5014429781902",
|
||||
},
|
||||
{
|
||||
rowIndex: "1",
|
||||
uniq_id: "b17540ef7e86e461d37f3ae58b7b72ac",
|
||||
japanese_name:
|
||||
"FunkyBuys® ラージ クリスマス ホリデー エクスプレス フェスティバル トレイン セット (SI-TY1017) おもちゃ ライト / サウンド / 電池式 & 煙",
|
||||
currencies: "₹, $, €, ¥, £",
|
||||
specialChars: "!@#$%^&*",
|
||||
product_name:
|
||||
"FunkyBuys® Large Christmas Holiday Express Festive Train Set (SI-TY1017) Toy Light / Sounds / Battery Operated & Smoke",
|
||||
manufacturer: "FunkyBuys",
|
||||
price: "16.99",
|
||||
number_available_in_stock: "null",
|
||||
number_of_reviews: "2",
|
||||
number_of_answered_questions: "1",
|
||||
average_review_rating: "4.5 out of 5 stars",
|
||||
amazon_category_and_sub_category:
|
||||
"Hobbies > Model Trains & Railway Sets > Rail Vehicles > Trains",
|
||||
customers_who_bought_this_item_also_bought:
|
||||
"http://www.amazon.co.uk/Christmas-Holiday-Express-Festive-Train-Set-Toy/dp/B009R8S8AA | http://www.amazon.co.uk/Goldlok-Holiday-Express-Operated-Multi-Colour/dp/B009R8PAO2 | http://www.amazon.co.uk/FunkyBuys%C2%AE-Christmas-SI-TY1017-Ornaments-Operated/dp/B01437QMHA | http://www.amazon.co.uk/Holiday-Express-Christmas-Ornament-Decoration | http://www.amazon.co.uk/Seasonal-Vision-Christmas-Tree-Train/dp/B0044ZC1W2 | http://www.amazon.co.uk/Coca-Cola-Santa-Express-Train-Set/dp/B004BYSNU0",
|
||||
},
|
||||
{
|
||||
rowIndex: "2",
|
||||
uniq_id: "348f344247b0c1a935b1223072ef9d8a",
|
||||
japanese_name:
|
||||
"クラシックなおもちゃの電車セット トラック車両 ライトエンジン 箱入り男の子 子供用バッテリー",
|
||||
currencies: "₹, $, €, ¥, £",
|
||||
specialChars: "!@#$%^&*",
|
||||
product_name:
|
||||
"CLASSIC TOY TRAIN SET TRACK CARRIAGES LIGHT ENGINE BOXED BOYS KIDS BATTERY",
|
||||
manufacturer: "ccf",
|
||||
price: "9.99",
|
||||
number_available_in_stock: "2 new",
|
||||
number_of_reviews: "17",
|
||||
number_of_answered_questions: "2",
|
||||
average_review_rating: "3.9 out of 5 stars",
|
||||
amazon_category_and_sub_category:
|
||||
"Hobbies > Model Trains & Railway Sets > Rail Vehicles > Trains",
|
||||
customers_who_bought_this_item_also_bought:
|
||||
"http://www.amazon.co.uk/Classic-Train-Lights-Battery-Operated/dp/B0041L9OHE | http://www.amazon.co.uk/Train-With-Tracks-Battery-Operated-x/dp/B009P540O8 | http://www.amazon.co.uk/13-Piece-Train-Set-Ideal/dp/B0173N6E4W | http://www.amazon.co.uk/Train-Flash-Electric-Sound-Europe/dp/B008D7CEH4 | http://www.amazon.co.uk/Train-Ultimate-Sticker-Book-Stickers/dp/1405314516 | http://www.amazon.co.uk/Train-Stickers-Dover-Little-Activity/dp/0486403106",
|
||||
},
|
||||
{
|
||||
rowIndex: "3",
|
||||
uniq_id: "e12b92dbb8eaee78b22965d2a9bbbd9f",
|
||||
japanese_name: "ホーンビー コーチ R4410A BR ホークスワース コリドー 3",
|
||||
currencies: "₹, $, €, ¥, £",
|
||||
specialChars: "!@#$%^&*",
|
||||
product_name: "HORNBY Coach R4410A BR Hawksworth Corridor 3rd",
|
||||
manufacturer: "Hornby",
|
||||
price: "39.99",
|
||||
number_available_in_stock: "null",
|
||||
number_of_reviews: "1",
|
||||
number_of_answered_questions: "2",
|
||||
average_review_rating: "5.0 out of 5 stars",
|
||||
amazon_category_and_sub_category:
|
||||
"Hobbies > Model Trains & Railway Sets > Rail Vehicles > Trains",
|
||||
customers_who_bought_this_item_also_bought: "null",
|
||||
},
|
||||
{
|
||||
rowIndex: "4",
|
||||
uniq_id: "e33a9adeed5f36840ccc227db4682a36",
|
||||
japanese_name:
|
||||
"ホーンビー 00 ゲージ 0-4-0 ギルデンロー塩社 蒸気機関車モデル",
|
||||
currencies: "₹, $, €, ¥, £",
|
||||
specialChars: "!@#$%^&*",
|
||||
product_name:
|
||||
"Hornby 00 Gauge 0-4-0 Gildenlow Salt Co. Steam Locomotive Model",
|
||||
manufacturer: "Hornby",
|
||||
price: "32.19",
|
||||
number_available_in_stock: "null",
|
||||
number_of_reviews: "3",
|
||||
number_of_answered_questions: "2",
|
||||
average_review_rating: "4.7 out of 5 stars",
|
||||
amazon_category_and_sub_category:
|
||||
"Hobbies > Model Trains & Railway Sets > Rail Vehicles > Trains",
|
||||
customers_who_bought_this_item_also_bought:
|
||||
"http://www.amazon.co.uk/Hornby-R6367-RailRoad-Gauge-Rolling/dp/B000WDWSD2 | http://www.amazon.co.uk/Hornby-R3064-RailRoad-Smokey-Locomotive | http://www.amazon.co.uk/Hornby-R8222-Gauge-Track-Extension/dp/B000RK3FZK | http://www.amazon.co.uk/Hornby-R6371-RailRoad-Petrol-Tanker/dp/B000WDS002 | http://www.amazon.co.uk/Hornby-R076-00-Gauge-Footbridge | http://www.amazon.co.uk/Hornby-R6368-RailRoad-Gauge-Brake/dp/B000WDWT22",
|
||||
},
|
||||
{
|
||||
rowIndex: "5",
|
||||
uniq_id: "cb34f0a84102c1ebc3ef6892d7444d36",
|
||||
japanese_name: "20 個モデルガーデンライトダブルヘッド街灯スケール 1:100",
|
||||
currencies: "₹, $, €, ¥, £",
|
||||
specialChars: "!@#$%^&*",
|
||||
product_name: "20pcs Model Garden Light Double Heads Lamppost Scale 1:100",
|
||||
manufacturer: "Generic",
|
||||
price: "6.99",
|
||||
number_available_in_stock: "null",
|
||||
number_of_reviews: "2",
|
||||
number_of_answered_questions: "1",
|
||||
average_review_rating: "5.0 out of 5 stars",
|
||||
amazon_category_and_sub_category:
|
||||
"Hobbies > Model Trains & Railway Sets > Lighting & Signal Engineering > Lamps & Lighting",
|
||||
customers_who_bought_this_item_also_bought:
|
||||
"http://www.amazon.co.uk/Single-Head-Garden-Lights-Lamppost-Layout/dp/B008XCSHCA | http://www.amazon.co.uk/douself-100Pcs-OO-Scale-Passenger/dp/B00GRUD8W4 | http://www.amazon.co.uk/Hornby-Digital-Electric-Point-Track/dp/B00105UJ14 | http://www.amazon.co.uk/20Pcs-Scenery-Landscape-Train-Flowers/dp/B00C1843MA | http://www.amazon.co.uk/Scenery-Landscape-100-Made-Plastic-Cement/dp/B007UYIJ48",
|
||||
},
|
||||
{
|
||||
rowIndex: "6",
|
||||
uniq_id: "f74b562470571dfb689324adf236f82c",
|
||||
japanese_name:
|
||||
"Hornby 00 ゲージ 230mm BR ボギー 旅客ブレーキ コーチ モデル (レッド)",
|
||||
currencies: "₹, $, €, ¥, £",
|
||||
specialChars: "!@#$%^&*",
|
||||
product_name:
|
||||
"Hornby 00 Gauge 230mm BR Bogie Passenger Brake Coach Model (Red)",
|
||||
manufacturer: "Hornby",
|
||||
price: "24.99",
|
||||
number_available_in_stock: "null",
|
||||
number_of_reviews: "2",
|
||||
number_of_answered_questions: "1",
|
||||
average_review_rating: "4.5 out of 5 stars",
|
||||
amazon_category_and_sub_category:
|
||||
"Hobbies > Model Trains & Railway Sets > Rail Vehicles > Trains",
|
||||
customers_who_bought_this_item_also_bought:
|
||||
"http://www.amazon.co.uk/Hornby-R4388-RailRoad-Composite-Gauge/dp/B00260GEXO | http://www.amazon.co.uk/Hornby-R1138-Passenger-Freight-Electric/dp/B006ZL6976",
|
||||
},
|
||||
{
|
||||
rowIndex: "7",
|
||||
uniq_id: "87bbb472ef9d90dcef140a551665c929",
|
||||
japanese_name: "ホーンビー サンタの特急列車セット",
|
||||
currencies: "₹, $, €, ¥, £",
|
||||
specialChars: "!@#$%^&*",
|
||||
product_name: "Hornby Santa's Express Train Set",
|
||||
manufacturer: "Hornby",
|
||||
price: "69.93",
|
||||
number_available_in_stock: "3 new",
|
||||
number_of_reviews: "36",
|
||||
number_of_answered_questions: "7",
|
||||
average_review_rating: "4.3 out of 5 stars",
|
||||
amazon_category_and_sub_category:
|
||||
"Hobbies > Model Trains & Railway Sets > Rail Vehicles > Trains",
|
||||
customers_who_bought_this_item_also_bought:
|
||||
"http://www.amazon.co.uk/Hornby-R8221-Gauge-Track-Extension/dp/B000PVFYZ0 | http://www.amazon.co.uk/Hornby-R8222-Gauge-Track-Extension/dp/B000RK3FZK | http://www.amazon.co.uk/Hornby-R6368-RailRoad-Gauge-Brake/dp/B000WDWT22 | http://www.amazon.co.uk/Hornby-R6370-RailRoad-Tredegar-Gauge/dp/B000WDZH58 | http://www.amazon.co.uk/Hornby-R044-Passing-Contact-Switch/dp/B000H5V0RK | http://www.amazon.co.uk/Hornby-Gauge-Logan-Plank-Wagon/dp/B00SWV6RAG",
|
||||
},
|
||||
{
|
||||
rowIndex: "8",
|
||||
uniq_id: "7e2aa2b4596a39ba852449718413d7cc",
|
||||
japanese_name:
|
||||
"ホーンビー ゲージ ウェスタン エクスプレス デジタル トレイン セット (eLink および TTS ロコ トレイン セット付き)",
|
||||
currencies: "₹, $, €, ¥, £",
|
||||
specialChars: "!@#$%^&*",
|
||||
product_name:
|
||||
"Hornby Gauge Western Express Digital Train Set with eLink and TTS Loco Train Set",
|
||||
manufacturer: "Hornby",
|
||||
price: "235.58",
|
||||
number_available_in_stock: "4 new",
|
||||
number_of_reviews: "1",
|
||||
number_of_answered_questions: "1",
|
||||
average_review_rating: "5.0 out of 5 stars",
|
||||
amazon_category_and_sub_category:
|
||||
"Hobbies > Model Trains & Railway Sets > Rail Vehicles > Trains",
|
||||
customers_who_bought_this_item_also_bought:
|
||||
"http://www.amazon.co.uk/Hornby-Western-Master-E-Link-Electric/dp/B00BUKPXS8 | http://www.amazon.co.uk/Hornby-Gloucester | http://www.amazon.co.uk/Hornby-Majestic-E-Link-Gauge-Electric/dp/B00BUKPXU6 | http://www.amazon.co.uk/Hornby-Gauge-Master-Glens/dp/B00TQNJIIW | http://www.amazon.co.uk/Hornby-Gauge-Eurostar-2014-Train/dp/B00TQNJIIC | http://www.amazon.co.uk/HORNBY-Digital-Train-Layout-Track/dp/B006BRH55Y",
|
||||
},
|
||||
{
|
||||
rowIndex: "9",
|
||||
uniq_id: "5afbaf65680c9f378af5b3a3ae22427e",
|
||||
japanese_name:
|
||||
"ラーニング カーブ チャギントン インタラクティブ チャッツワース",
|
||||
currencies: "₹, $, €, ¥, £",
|
||||
specialChars: "!@#$%^&*",
|
||||
product_name: "Learning Curve Chuggington Interactive Chatsworth",
|
||||
manufacturer: "Chuggington",
|
||||
price: "null",
|
||||
number_available_in_stock: "1 new",
|
||||
number_of_reviews: "8",
|
||||
number_of_answered_questions: "1",
|
||||
average_review_rating: "4.8 out of 5 stars",
|
||||
amazon_category_and_sub_category:
|
||||
"Hobbies > Model Trains & Railway Sets > Rail Vehicles > Trains",
|
||||
customers_who_bought_this_item_also_bought:
|
||||
"http://www.amazon.co.uk/Learning-Curve-Chuggington | http://www.amazon.co.uk/Chuggington | http://www.amazon.co.uk/Learning-Curve-Chuggington | http://www.amazon.co.uk/Learning-Chuggington",
|
||||
},
|
||||
];
|
||||
|
|
@ -29,5 +29,7 @@ export default {
|
|||
upgrade: "//button//span[text()='Upgrade']",
|
||||
accessControl: ".t--settings-category-access-control",
|
||||
auditLogs: ".t--settings-category-audit-logs",
|
||||
provisioning: ".t--settings-category-provisioning",
|
||||
upgrageLeftPane: "[data-testid='t--enterprise-settings-category-item-be']",
|
||||
businessTag: "[data-testid='t--business-tag']",
|
||||
};
|
||||
|
|
|
|||
|
|
@ -19,5 +19,6 @@
|
|||
"textWidgetName": ".t--widget-textwidget",
|
||||
"welcomeTourBtn": ".t--start-building",
|
||||
"editorWelcomeTourBtn": "[data-testid='editor-welcome-tour']",
|
||||
"checklistCompletionBanner": "[data-testid='checklist-completion-banner']"
|
||||
"checklistCompletionBanner": "[data-testid='checklist-completion-banner']",
|
||||
"selectWidgetBtn": ".t--select-in-canvas"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,8 @@
|
|||
"chartInnerText": ".t--property-control-title",
|
||||
"inputChartValue": ".t--property-control-chartseries .CodeMirror textarea",
|
||||
"chartButton": ".t--property-control-chartseries button",
|
||||
"rectangleChart": ".t--draggable-chartwidget g rect",
|
||||
"rectangleChart": ".t--draggable-chartwidget g",
|
||||
"fusionRectangleChart": ".t--draggable-chartwidget g rect",
|
||||
"xlabel": ".t--property-control-x-axislabel .CodeMirror-code",
|
||||
"ylabel": ".t--property-control-y-axislabel .CodeMirror-code",
|
||||
"mapInner": ".t--draggable-mapwidget span.t--widget-name",
|
||||
|
|
@ -30,8 +31,8 @@
|
|||
"zoomLevel": ".t--property-control-zoomlevel svg",
|
||||
"sourceImage": ".t--property-control-image .CodeMirror-code",
|
||||
"defaultImage": ".t--property-control-defaultimage .CodeMirror textarea",
|
||||
"Chartlabel": ".t--draggable-chartwidget g:nth-child(5) text",
|
||||
"PieChartLabel": ".t--draggable-chartwidget g g:nth-child(1) g text",
|
||||
"Chartlabel": ".t--draggable-chartwidget g text",
|
||||
"FusionChartlabel": ".t--draggable-chartwidget g:nth-child(5) text",
|
||||
"pickMyLocation": ".t--draggable-mapwidget div[title='Pick My Location']",
|
||||
"mapChartEntityLabels": ".t--draggable-mapchartwidget g[class*='-entityLabels'] text",
|
||||
"listWidget": ".t--draggable-listwidget"
|
||||
|
|
|
|||
|
|
@ -156,7 +156,7 @@
|
|||
"toggleBackground": ".t--property-control-background .t--js-toggle",
|
||||
"toggleItemBackground": ".t--property-control-itembackground .t--js-toggle",
|
||||
"toggleShowStepArrows": ".t--property-control-showsteparrows .t--js-toggle",
|
||||
"chartPlotGroup": "g.raphael-group-63-plot-group",
|
||||
"chartDataPoint": "g path[d^='M100 205.51']",
|
||||
"toggleEnableMultirowselection": ".t--property-control-enablemulti-rowselection input",
|
||||
"toggleEnableMultirowselection_tablev1": ".t--property-control-enablemultirowselection input",
|
||||
"formWidget": ".t--draggable-formwidget",
|
||||
|
|
|
|||
|
|
@ -21,16 +21,15 @@
|
|||
"tabWidget": ".t--widget-tabswidget",
|
||||
"jsonFormWidget": ".t--widget-jsonformwidget",
|
||||
"chartWidget": ".t--widget-chartwidget",
|
||||
"horizontalTab": ".t--widget-chartwidget g[class*='-scrollContainer'] rect",
|
||||
"tableWidget": ".t--widget-tablewidget",
|
||||
"chartCanvasVal": ".t--widget-chartwidget g[class*='-canvas'] rect ",
|
||||
"chartCanvasVal": ".t--widget-chartwidget svg rect",
|
||||
"mapWidget": ".t--widget-mapwidget",
|
||||
"tableLength": ".t--widget-tablewidget .tbody",
|
||||
"tableV2Length": ".t--widget-tablewidgetv2 .tbody",
|
||||
"mapSearch": ".t--widget-mapwidget input",
|
||||
"pickMyLocation": ".t--widget-mapwidget div[title='Pick My Location']",
|
||||
"rectChart": ".t--widget-chartwidget g rect",
|
||||
"chartLab": ".t--widget-chartwidget g:nth-child(5) text",
|
||||
"rectChart": ".t--widget-chartwidget svg rect",
|
||||
"chartLab": ".t--widget-chartwidget svg g text",
|
||||
"searchInput": ".t--search-input",
|
||||
"downloadBtn": ".t--table-download-btn",
|
||||
"filterBtn": ".t--table-filter-toggle-btn",
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@
|
|||
"@typescript-eslint/parser": "^5.25.0",
|
||||
"chalk": "^4.1.1",
|
||||
"cy-verify-downloads": "^0.0.5",
|
||||
"cypress": "^12.16.0",
|
||||
"cypress": "^12.17.0",
|
||||
"cypress-file-upload": "^4.1.1",
|
||||
"cypress-image-snapshot": "^4.0.1",
|
||||
"cypress-log-to-output": "^1.1.2",
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ const apiwidget = require("../locators/apiWidgetslocator.json");
|
|||
const explorer = require("../locators/explorerlocators.json");
|
||||
import { ObjectsRegistry } from "./Objects/Registry";
|
||||
|
||||
let agHelper = ObjectsRegistry.AggregateHelper;
|
||||
let dataSources = ObjectsRegistry.DataSources;
|
||||
let apiPage = ObjectsRegistry.ApiPage;
|
||||
|
||||
|
|
@ -109,6 +110,7 @@ Cypress.Commands.add(
|
|||
(apiName, baseurl, path, verb, error = false) => {
|
||||
cy.get(".ads-v2-tabs__list").contains("Logs").click();
|
||||
cy.get("[data-testid=t--debugger-search]").clear().type(apiName);
|
||||
agHelper.PressEnter();
|
||||
|
||||
if (!error) {
|
||||
cy.get(".object-key").last().contains("request").click();
|
||||
|
|
|
|||
|
|
@ -3,7 +3,8 @@ export class CommonLocators {
|
|||
_inputField = "input";
|
||||
_canvasViewport = "#canvas-viewport";
|
||||
_emptyPageTxt = ".bp3-heading";
|
||||
_chevronUp = ".bp3-icon-chevron-up";
|
||||
_chevronUp = "span[contains(@class, 'bp3-icon-chevron-up')]";
|
||||
_chevronDown = "span[contains(@class, 'bp3-icon-chevron-down')]";
|
||||
_loading = "#loading";
|
||||
_animationSpnner = ".bp3-spinner-animation";
|
||||
_btnSpinner = ".ads-v2-spinner";
|
||||
|
|
@ -263,6 +264,7 @@ export class CommonLocators {
|
|||
_adsV2CollapsibleHeader = ".ads-v2-collapsible__header";
|
||||
_adsV2Text = ".ads-v2-text";
|
||||
_svg = "svg";
|
||||
_imgWidgetInsideList = `//div[@data-testid='styledImage']//img`;
|
||||
|
||||
public ds_editor_env_filter = (envName: string) =>
|
||||
`[data-testid="t--ds-data-filter-${envName}"]`;
|
||||
|
|
|
|||
|
|
@ -32,3 +32,4 @@ export const fakerHelper = ObjectsRegistry.FakerHelper;
|
|||
export const tedTestConfig = ObjectsRegistry.TEDTestConfigs;
|
||||
export const entityItems = EntityItems;
|
||||
export const tabs = ObjectsRegistry.Tabs;
|
||||
export const gsheetHelper = ObjectsRegistry.GSheetHelper;
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import { TEDTestConfigs } from "./TestConfigs";
|
|||
import { AssertHelper } from "../Pages/AssertHelper";
|
||||
import { ReusableHelper } from "./ReusableHelper";
|
||||
import { Tabs } from "../Pages/Tabs";
|
||||
import { GsheetHelper } from "../Pages/GSheetHelper";
|
||||
|
||||
export class ObjectsRegistry {
|
||||
private static aggregateHelper__: AggregateHelper;
|
||||
|
|
@ -260,6 +261,14 @@ export class ObjectsRegistry {
|
|||
}
|
||||
return ObjectsRegistry.tedTestConfigs__;
|
||||
}
|
||||
|
||||
private static gsheetHelper__: GsheetHelper;
|
||||
static get GSheetHelper(): GsheetHelper {
|
||||
if (ObjectsRegistry.gsheetHelper__ === undefined) {
|
||||
ObjectsRegistry.gsheetHelper__ = new GsheetHelper();
|
||||
}
|
||||
return ObjectsRegistry.gsheetHelper__;
|
||||
}
|
||||
}
|
||||
|
||||
export const initLocalstorageRegistry = () => {
|
||||
|
|
|
|||
|
|
@ -77,6 +77,7 @@ export class TEDTestConfigs {
|
|||
mockHttpCodeUrl: "http://host.docker.internal:5001/v1/mock-http-codes/",
|
||||
AirtableBaseForME: "appubHrVbovcudwN6",
|
||||
AirtableTableForME: "tblsFCQSskVFf7xNd",
|
||||
ApiUrlME: "http://host.docker.internal:5001/v1/production",
|
||||
|
||||
firestore_database_url: "https://appsmith-22e8b.firebaseio.com",
|
||||
firestore_projectID: "appsmith-22e8b",
|
||||
|
|
@ -98,7 +99,7 @@ export class TEDTestConfigs {
|
|||
mongo_authenticationAuthtype: "SCRAM-SHA-1",
|
||||
mongo_host: "host.docker.internal",
|
||||
mongo_port: 28017,
|
||||
mongo_databaseName: "mongo_samples",
|
||||
mongo_databaseName: "mongo_samples2",
|
||||
|
||||
postgres_host: "host.docker.internal",
|
||||
postgres_port: 5432,
|
||||
|
|
@ -165,6 +166,7 @@ export class TEDTestConfigs {
|
|||
mockHttpCodeUrl: "http://host.docker.internal:5001/v1/mock-http-codes/",
|
||||
AirtableBaseForME: "appubHrVbovcudwN6",
|
||||
AirtableTableForME: "tblsFCQSskVFf7xNd",
|
||||
ApiUrlME: "http://host.docker.internal:5001/v1/staging",
|
||||
|
||||
firestore_database_url: "https://appsmith-22e8b.firebaseio.com",
|
||||
firestore_projectID: "appsmith-22e8b",
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ export class AdminSettings {
|
|||
public locator = ObjectsRegistry.CommonLocators;
|
||||
public homePage = ObjectsRegistry.HomePage;
|
||||
|
||||
private _adminSettingsBtn = '[data-testid="t--admin-settings-menu-option"]';
|
||||
public _adminSettingsBtn = '[data-testid="t--admin-settings-menu-option"]';
|
||||
private _settingsList = ".t--settings-category-list";
|
||||
public _usersTab = ".t--settings-category-users";
|
||||
public _roles = (user: string) =>
|
||||
|
|
|
|||
|
|
@ -674,11 +674,20 @@ export class AggregateHelper extends ReusableHelper {
|
|||
.wait(waitTimeInterval);
|
||||
}
|
||||
|
||||
public HoverElement(selector: string, index = 0, waitTimeInterval = 100) {
|
||||
return (
|
||||
this.ScrollIntoView(selector, index)
|
||||
public HoverElement(
|
||||
selector: string,
|
||||
index = 0,
|
||||
realTouch = true,
|
||||
waitTimeInterval = 100,
|
||||
) {
|
||||
let chain = this.ScrollIntoView(selector, index);
|
||||
if (realTouch) {
|
||||
chain = chain
|
||||
.realTouch({ position: "center" })
|
||||
.realHover({ pointer: "mouse" })
|
||||
.realHover({ pointer: "mouse" });
|
||||
}
|
||||
return (
|
||||
chain
|
||||
//.trigger("mousemove", { eventConstructor: "MouseEvent" })
|
||||
.wait(waitTimeInterval)
|
||||
);
|
||||
|
|
@ -1055,6 +1064,7 @@ export class AggregateHelper extends ReusableHelper {
|
|||
input.focus();
|
||||
this.Sleep(200);
|
||||
input.setValue(value);
|
||||
input.execCommand("goLineEnd");
|
||||
this.Sleep(200);
|
||||
});
|
||||
this.Sleep(500); //for value set to settle
|
||||
|
|
@ -1524,4 +1534,10 @@ export class AggregateHelper extends ReusableHelper {
|
|||
// }
|
||||
// return items;
|
||||
// }, { timeout: 5000 });
|
||||
|
||||
public AssertTooltip(tooltipText: string) {
|
||||
cy.get(".rc-tooltip-inner").should(($x) => {
|
||||
expect($x).contain(tooltipText);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -75,6 +75,7 @@ export class ApiPage {
|
|||
public _autoGeneratedHeaderInfoIcon = (key: string) =>
|
||||
`.t--auto-generated-${key}-info`;
|
||||
private _createQuery = ".t--create-query";
|
||||
public _editorDS = ".t--datasource-editor";
|
||||
|
||||
CreateApi(
|
||||
apiName = "",
|
||||
|
|
@ -115,7 +116,7 @@ export class ApiPage {
|
|||
) {
|
||||
this.CreateApi(apiName, apiVerb, aftDSSaved);
|
||||
this.EnterURL(url);
|
||||
//this.agHelper.Sleep(2000);// Added because api name edit takes some time to reflect in api sidebar after the call passes.
|
||||
this.agHelper.Sleep(2000); // Added because api name edit takes some time to reflect in api sidebar after the call passes.
|
||||
this.AssertRunButtonDisability();
|
||||
if (queryTimeout != 10000) this.SetAPITimeout(queryTimeout);
|
||||
}
|
||||
|
|
@ -130,8 +131,8 @@ export class ApiPage {
|
|||
directInput: true,
|
||||
inputFieldName: "",
|
||||
});
|
||||
this.agHelper.AssertAutoSave();
|
||||
|
||||
//this.agHelper.GetNClick(this._resourceUrl);
|
||||
this.agHelper.Sleep();
|
||||
if (evaluatedValue) {
|
||||
this.agHelper.VerifyEvaluatedValue(evaluatedValue);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ export class DataSources {
|
|||
}; //Container KeyValuePair
|
||||
|
||||
private _dsCreateNewTab = "[data-testid=t--tab-CREATE_NEW]";
|
||||
private _dsReviewSection = "[data-testid='t--ds-review-section']";
|
||||
private _addNewDataSource = ".t--entity-add-btn.datasources button";
|
||||
private _createNewPlgin = (pluginName: string) =>
|
||||
".t--plugin-name:contains('" + pluginName + "')";
|
||||
|
|
@ -91,6 +92,7 @@ export class DataSources {
|
|||
ddTitle +
|
||||
"']/following-sibling::span//button";
|
||||
_reconnectModal = "[data-testid='reconnect-datasource-modal']";
|
||||
_reconnect = ".t--reconnect-btn";
|
||||
_dropdown = (ddTitle: string) =>
|
||||
"//span[contains(@title, '" +
|
||||
ddTitle +
|
||||
|
|
@ -180,7 +182,6 @@ export class DataSources {
|
|||
_gsScopeOptions = ".ads-v2-select__dropdown .rc-select-item-option";
|
||||
private _queryTimeout =
|
||||
"//input[@name='actionConfiguration.timeoutInMillisecond']";
|
||||
_getStructureReq = "/api/v1/datasources/*/structure?ignoreCache=true";
|
||||
_editDatasourceFromActiveTab = (dsName: string) =>
|
||||
".t--datasource-name:contains('" + dsName + "')";
|
||||
private _suggestedWidget = (widgetType: string) =>
|
||||
|
|
@ -193,7 +194,7 @@ export class DataSources {
|
|||
dbName +
|
||||
"']/ancestor::div[contains(@class, 't--entity-item')]/following-sibling::div//p[text()='Schema not available']";
|
||||
// Authenticated API locators
|
||||
private _authApiDatasource = ".t--createAuthApiDatasource";
|
||||
public _authApiDatasource = ".t--createAuthApiDatasource";
|
||||
private _authType = "[data-testid=authType]";
|
||||
private _oauth2 = ".rc-select-item-option:contains('OAuth 2.0')";
|
||||
private _accessTokenUrl =
|
||||
|
|
@ -215,8 +216,10 @@ export class DataSources {
|
|||
public _cancelEditDatasourceButton = ".t--cancel-edit-datasource";
|
||||
public _urlInputControl = "input[name='url']";
|
||||
public _mongoCollectionPath = "t--actionConfiguration.formData.collection";
|
||||
private _getJSONswitchLocator = (fieldLocator: string) =>
|
||||
`[data-testid='${fieldLocator}.data-JS']`;
|
||||
_getJSONswitchLocator = (fieldName: string) =>
|
||||
"//p[contains(text(),'" +
|
||||
fieldName +
|
||||
"')]/ancestor::div[@class='form-config-top']//button";
|
||||
_nestedWhereClauseKey = (index: number) =>
|
||||
".t--actionConfiguration\\.formData\\.where\\.data\\.children\\[" +
|
||||
index +
|
||||
|
|
@ -231,12 +234,17 @@ export class DataSources {
|
|||
_bodyCodeMirror = "//div[contains(@class, 't--actionConfiguration.body')]";
|
||||
private _reconnectModalDSToolTip = ".t--ds-list .t--ds-list-title";
|
||||
private _reconnectModalDSToopTipIcon = ".t--ds-list .ads-v2-icon";
|
||||
_multiSelectDropdown = (ddName: string) =>
|
||||
"//p[contains(text(),'" +
|
||||
ddName +
|
||||
"')]/ancestor::div[@class='form-config-top']/following-sibling::div//div[contains(@class, 'rc-select-multiple')]";
|
||||
private _datasourceTableSchemaInQueryEditor =
|
||||
".datasourceStructure-query-editor";
|
||||
private _datasourceSchemaRefreshBtn = ".datasourceStructure-refresh";
|
||||
private _datasourceStructureHeader = ".datasourceStructure-header";
|
||||
private _datasourceColumnSchemaInQueryEditor = ".t--datasource-column";
|
||||
private _datasourceStructureSearchInput = ".datasourceStructure-search input";
|
||||
_jsModeSortingControl = ".t--actionConfiguration\\.formData\\.sortBy\\.data";
|
||||
public _queryEditorCollapsibleIcon = ".collapsible-icon";
|
||||
|
||||
public AssertDSEditViewMode(mode: "Edit" | "View") {
|
||||
|
|
@ -436,6 +444,20 @@ export class DataSources {
|
|||
this.ValidateNSelectDropdown("SSL mode", "Default");
|
||||
}
|
||||
|
||||
public ValidatePostgresDSForm(
|
||||
environment = this.tedTestConfig.defaultEnviorment,
|
||||
) {
|
||||
const databaseName =
|
||||
this.tedTestConfig.dsValues[environment].postgres_databaseName;
|
||||
this.agHelper.AssertContains(databaseName, "exist", this._dsReviewSection);
|
||||
}
|
||||
|
||||
public ValidateMongoForm(environment = this.tedTestConfig.defaultEnviorment) {
|
||||
const databaseName =
|
||||
this.tedTestConfig.dsValues[environment].mongo_databaseName;
|
||||
this.agHelper.AssertContains(this._dsReviewSection, databaseName);
|
||||
}
|
||||
|
||||
public FillOracleDSForm(
|
||||
environment = this.tedTestConfig.defaultEnviorment,
|
||||
shouldAddTrailingSpaces = false,
|
||||
|
|
@ -902,6 +924,18 @@ export class DataSources {
|
|||
}
|
||||
}
|
||||
|
||||
public CreateQueryForDS(datasourceName: string, query = "", queryName = "") {
|
||||
this.NavigateToActiveTab();
|
||||
cy.get(this._datasourceCard)
|
||||
.contains(datasourceName)
|
||||
.scrollIntoView()
|
||||
.should("be.visible")
|
||||
.click();
|
||||
this.agHelper.Sleep(); //for the Datasource page to open
|
||||
this.agHelper.GetNClick(this._cancelEditDatasourceButton, 0, true, 200);
|
||||
this.CreateQueryAfterDSSaved(query, queryName);
|
||||
}
|
||||
|
||||
DeleteQuery(queryName: string) {
|
||||
this.ee.ExpandCollapseEntity("Queries/JS");
|
||||
this.ee.ActionContextMenuByEntityName({
|
||||
|
|
@ -929,6 +963,17 @@ export class DataSources {
|
|||
}
|
||||
}
|
||||
|
||||
public ValidateReviewModeConfig(
|
||||
dsName: "PostgreSQL" | "MongoDB",
|
||||
environment = this.tedTestConfig.defaultEnviorment,
|
||||
) {
|
||||
if (dsName === "PostgreSQL") {
|
||||
this.ValidatePostgresDSForm(environment);
|
||||
} else if (dsName === "MongoDB") {
|
||||
this.ValidateMongoForm(environment);
|
||||
}
|
||||
}
|
||||
|
||||
public ReconnectSingleDSNAssert(
|
||||
dbName: string,
|
||||
dsName: "PostgreSQL" | "MySQL" | "MongoDB",
|
||||
|
|
@ -943,6 +988,18 @@ export class DataSources {
|
|||
this.assertHelper.AssertNetworkStatus("getWorkspace");
|
||||
}
|
||||
|
||||
public AssertReconnectDS(datasourceName: string) {
|
||||
cy.get(this._datasourceCard, { withinSubject: null })
|
||||
.find(this._activeDS)
|
||||
.contains(datasourceName)
|
||||
.scrollIntoView()
|
||||
.should("be.visible")
|
||||
.closest(this._datasourceCard)
|
||||
.scrollIntoView()
|
||||
.within(() => {
|
||||
this.agHelper.AssertElementVisible(this._reconnect, 0, 20000);
|
||||
});
|
||||
}
|
||||
public ReconnectModalValidation(
|
||||
dbName: string,
|
||||
dsName: "PostgreSQL" | "MySQL" | "MongoDB",
|
||||
|
|
@ -1265,7 +1322,6 @@ export class DataSources {
|
|||
schema: string,
|
||||
isUpdate = false,
|
||||
) {
|
||||
cy.intercept("GET", this._getStructureReq).as("getDSStructure");
|
||||
if (isUpdate) {
|
||||
this.UpdateDatasource();
|
||||
} else {
|
||||
|
|
@ -1275,7 +1331,7 @@ export class DataSources {
|
|||
entityNameinLeftSidebar: dataSourceName,
|
||||
action: "Refresh",
|
||||
});
|
||||
cy.wait("@getDSStructure").then(() => {
|
||||
cy.wait("@getDatasourceStructure").then(() => {
|
||||
cy.get(".bp3-collapse-body").contains(schema);
|
||||
});
|
||||
}
|
||||
|
|
@ -1572,21 +1628,19 @@ export class DataSources {
|
|||
|
||||
public EnterJSContext({
|
||||
fieldLabel,
|
||||
fieldProperty,
|
||||
fieldValue,
|
||||
}: {
|
||||
fieldProperty: string;
|
||||
fieldValue: string;
|
||||
fieldLabel: string;
|
||||
}) {
|
||||
this.agHelper.Sleep();
|
||||
this.agHelper
|
||||
.GetElement(this._getJSONswitchLocator(fieldProperty))
|
||||
.GetElement(this._getJSONswitchLocator(fieldLabel))
|
||||
.invoke("attr", "data-selected")
|
||||
.then(($state: any) => {
|
||||
if (!$state.includes("true"))
|
||||
this.agHelper.GetNClick(
|
||||
this._getJSONswitchLocator(fieldProperty),
|
||||
this._getJSONswitchLocator(fieldLabel),
|
||||
0,
|
||||
true,
|
||||
);
|
||||
|
|
@ -1658,4 +1712,40 @@ export class DataSources {
|
|||
});
|
||||
});
|
||||
}
|
||||
|
||||
public EnterSortByValues(sortBy: string, option: string, index = 0) {
|
||||
this.agHelper
|
||||
.GetElement(this._jsModeSortingControl)
|
||||
.eq(0)
|
||||
.children()
|
||||
.eq(index)
|
||||
.then((ele) => {
|
||||
cy.wrap(ele)
|
||||
.children()
|
||||
.eq(0)
|
||||
.find("textarea")
|
||||
.type(sortBy, { force: true });
|
||||
cy.wrap(ele).children().eq(1).find("input").click();
|
||||
});
|
||||
this.agHelper.GetNClickByContains(this._dropdownOption, option);
|
||||
}
|
||||
|
||||
public ClearSortByOption(index = 0) {
|
||||
this.agHelper.Sleep(500);
|
||||
this.agHelper
|
||||
.GetElement(this._jsModeSortingControl)
|
||||
.eq(0)
|
||||
.children()
|
||||
.eq(index)
|
||||
.find(`button[data-testid='t--sorting-delete-[${index}]']`)
|
||||
.click({ force: true });
|
||||
this.agHelper.Sleep(500);
|
||||
}
|
||||
|
||||
public AddNewSortByParameter() {
|
||||
this.agHelper
|
||||
.GetElement(this._jsModeSortingControl)
|
||||
.find("button[data-testid='t--sorting-add-field']")
|
||||
.click({ force: true });
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,13 @@ export class DeployMode {
|
|||
`//p[text()='${fieldName}']/ancestor::div[@direction='column']//div[@data-testid='radiogroup-container']//input`;
|
||||
_jsonFormDatepickerFieldByName = (fieldName: string) =>
|
||||
`//p[text()='${fieldName}']/ancestor::div[@direction='column']//div[@data-testid='datepicker-container']//input`;
|
||||
_jsonFormNumberFieldByName = (
|
||||
fieldName: string,
|
||||
direction: "up" | "down" = "up",
|
||||
) =>
|
||||
`//p[text()='${fieldName}']/ancestor::div[@direction='column']//div[@data-testid='input-container']// ${
|
||||
direction == "up" ? this.locator._chevronUp : this.locator._chevronDown
|
||||
}`;
|
||||
_jsonSelectDropdown = "button.select-button";
|
||||
private _jsonFormMultiSelectByName = (fieldName: string) =>
|
||||
`//p[text()='${fieldName}']/ancestor::div[@direction='column']//div[@data-testid='multiselect-container']//div[contains(@class, 'rc-select-show-arrow')]`;
|
||||
|
|
|
|||
|
|
@ -28,7 +28,8 @@ interface EntityActionParams {
|
|||
| "Copy to page"
|
||||
| "Move to page"
|
||||
| "Hide"
|
||||
| "Refresh";
|
||||
| "Refresh"
|
||||
| "Set as home page";
|
||||
subAction?: string;
|
||||
entityType?: EntityItems;
|
||||
toAssertAction?: boolean;
|
||||
|
|
@ -270,9 +271,7 @@ export class EntityExplorer {
|
|||
}
|
||||
|
||||
public ValidateDuplicateMessageToolTip(tooltipText: string) {
|
||||
cy.get(".rc-tooltip-inner").should(($x) => {
|
||||
expect($x).contain(tooltipText.concat(" is already being used."));
|
||||
});
|
||||
this.agHelper.AssertTooltip(tooltipText.concat(" is already being used."));
|
||||
}
|
||||
|
||||
public DeleteAllQueriesForDB(dsName: string) {
|
||||
|
|
@ -407,16 +406,20 @@ export class EntityExplorer {
|
|||
}
|
||||
|
||||
public PinUnpinEntityExplorer(pin = true) {
|
||||
this.agHelper
|
||||
.GetElement(this._entityExplorer)
|
||||
.invoke("attr", "class")
|
||||
.then(($classes) => {
|
||||
if (pin && !$classes?.includes("fixed"))
|
||||
this.agHelper.GetNClick(this._pinEntityExplorer, 0, false, 1000);
|
||||
else if (!pin && $classes?.includes("fixed"))
|
||||
this.agHelper.GetNClick(this._pinEntityExplorer, 0, false, 1000);
|
||||
else this.agHelper.Sleep(200); //do nothing
|
||||
});
|
||||
cy.get("body").then(($ele) => {
|
||||
if ($ele.find(this._pinEntityExplorer).length) {
|
||||
this.agHelper
|
||||
.GetElement(this._entityExplorer)
|
||||
.invoke("attr", "class")
|
||||
.then(($classes) => {
|
||||
if (pin && !$classes?.includes("fixed"))
|
||||
this.agHelper.GetNClick(this._pinEntityExplorer, 0, false, 1000);
|
||||
else if (!pin && $classes?.includes("fixed"))
|
||||
this.agHelper.GetNClick(this._pinEntityExplorer, 0, false, 1000);
|
||||
else this.agHelper.Sleep(200); //do nothing
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public RenameEntityFromExplorer(
|
||||
|
|
|
|||
138
app/client/cypress/support/Pages/GSheetHelper.ts
Normal file
138
app/client/cypress/support/Pages/GSheetHelper.ts
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
import { ObjectsRegistry } from "../Objects/Registry";
|
||||
|
||||
type operation =
|
||||
| "Insert One"
|
||||
| "Insert Many"
|
||||
| "Update One"
|
||||
| "Update Many"
|
||||
| "Fetch Details"
|
||||
| "Fetch Many"
|
||||
| "Delete One";
|
||||
|
||||
export class GsheetHelper {
|
||||
public agHelper = ObjectsRegistry.AggregateHelper;
|
||||
public locator = ObjectsRegistry.CommonLocators;
|
||||
private dataSources = ObjectsRegistry.DataSources;
|
||||
private entityExplorer = ObjectsRegistry.EntityExplorer;
|
||||
|
||||
public AddNewSpreadsheetQuery(
|
||||
dataSourceName: string,
|
||||
spreadsheet: string,
|
||||
rowData: string,
|
||||
) {
|
||||
this.entityExplorer.CreateNewDsQuery(dataSourceName);
|
||||
this.dataSources.ValidateNSelectDropdown(
|
||||
"Operation",
|
||||
"Fetch Many",
|
||||
"Insert One",
|
||||
);
|
||||
this.dataSources.ValidateNSelectDropdown(
|
||||
"Entity",
|
||||
"Sheet Row(s)",
|
||||
"Spreadsheet",
|
||||
);
|
||||
this.agHelper.EnterValue(spreadsheet, {
|
||||
propFieldName: "",
|
||||
directInput: false,
|
||||
inputFieldName: "Spreadsheet Name",
|
||||
});
|
||||
this.agHelper.RenameWithInPane("insert_spreadsheet");
|
||||
this.agHelper.EnterValue(rowData, {
|
||||
propFieldName: "",
|
||||
directInput: false,
|
||||
inputFieldName: "Row object(s)",
|
||||
});
|
||||
this.dataSources.RunQuery();
|
||||
}
|
||||
|
||||
public DeleteSpreadsheetQuery(dataSourceName: string, spreadsheet: string) {
|
||||
this.entityExplorer.CreateNewDsQuery(dataSourceName);
|
||||
this.dataSources.ValidateNSelectDropdown(
|
||||
"Operation",
|
||||
"Fetch Many",
|
||||
"Delete One",
|
||||
);
|
||||
this.dataSources.ValidateNSelectDropdown(
|
||||
"Entity",
|
||||
"Sheet Row(s)",
|
||||
"Spreadsheet",
|
||||
);
|
||||
this.dataSources.ValidateNSelectDropdown("Spreadsheet", "", spreadsheet);
|
||||
this.agHelper.RenameWithInPane("delete_spreadsheet");
|
||||
this.dataSources.RunQuery();
|
||||
}
|
||||
|
||||
public AddInsertOrUpdateQuery(
|
||||
operation: operation,
|
||||
dataSourceName: string,
|
||||
spreadSheet: string,
|
||||
rowData: string,
|
||||
executeQuery = true,
|
||||
sheetName = "Sheet1",
|
||||
headRowIndex = "1",
|
||||
) {
|
||||
this.EnterBasicQueryValues(
|
||||
operation,
|
||||
dataSourceName,
|
||||
spreadSheet,
|
||||
true,
|
||||
"Sheet Row(s)",
|
||||
sheetName,
|
||||
headRowIndex,
|
||||
);
|
||||
let inputField = "";
|
||||
if (operation.includes("Insert")) {
|
||||
inputField = operation == "Insert One" ? "Row object" : "Row object(s)";
|
||||
} else if (operation.includes("Update")) {
|
||||
inputField =
|
||||
operation == "Update One"
|
||||
? "Update row object"
|
||||
: "Update row object(s)";
|
||||
}
|
||||
|
||||
this.agHelper.EnterValue(rowData, {
|
||||
propFieldName: "",
|
||||
directInput: false,
|
||||
inputFieldName: inputField,
|
||||
});
|
||||
if (executeQuery) this.dataSources.RunQuery();
|
||||
}
|
||||
|
||||
public EnterBasicQueryValues(
|
||||
operation: operation,
|
||||
dataSourceName: string,
|
||||
spreadSheet: string,
|
||||
renameQuery = true,
|
||||
entity = "Sheet Row(s)",
|
||||
sheetName = "Sheet1",
|
||||
headRowIndex = "1",
|
||||
) {
|
||||
this.entityExplorer.CreateNewDsQuery(dataSourceName);
|
||||
this.dataSources.ValidateNSelectDropdown(
|
||||
"Operation",
|
||||
"Fetch Many",
|
||||
operation,
|
||||
);
|
||||
this.dataSources.ValidateNSelectDropdown("Entity", "Sheet Row(s)", entity);
|
||||
this.agHelper.Sleep(500);
|
||||
this.dataSources.ValidateNSelectDropdown("Spreadsheet", "", spreadSheet);
|
||||
if (!entity.includes("Spreadsheet")) {
|
||||
this.dataSources.ValidateNSelectDropdown("Sheet name", "", sheetName);
|
||||
this.agHelper.EnterValue(headRowIndex, {
|
||||
propFieldName: "",
|
||||
directInput: false,
|
||||
inputFieldName: "Table heading row index",
|
||||
});
|
||||
}
|
||||
if (renameQuery) {
|
||||
this.agHelper.RenameWithInPane(
|
||||
operation.toLowerCase().replace(" ", "_") + "_query",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public SelectMultiDropDownValue(ddName: string, option: string) {
|
||||
this.agHelper.GetNClick(this.dataSources._multiSelectDropdown(ddName));
|
||||
this.agHelper.GetNClickByContains(this.dataSources._dropdownOption, option);
|
||||
}
|
||||
}
|
||||
|
|
@ -124,7 +124,11 @@ export class HomePage {
|
|||
this.agHelper.GetNClick(this._homeTab);
|
||||
}
|
||||
|
||||
public CreateNewWorkspace(workspaceNewName: string) {
|
||||
public CreateNewWorkspace(
|
||||
workspaceNewName: string,
|
||||
toNavigateToHome = false,
|
||||
) {
|
||||
if (toNavigateToHome) this.NavigateToHome();
|
||||
let oldName = "";
|
||||
this.agHelper.GetNClick(this._newWorkSpaceLink);
|
||||
this.assertHelper.AssertNetworkStatus("createWorkspace", 201);
|
||||
|
|
@ -255,6 +259,7 @@ export class HomePage {
|
|||
//Maps to CreateAppForWorkspace in command.js
|
||||
public CreateAppInWorkspace(workspaceName: string, appname = "") {
|
||||
cy.xpath(this._existingWorkspaceCreateNewApp(workspaceName))
|
||||
.last()
|
||||
.scrollIntoView()
|
||||
.should("be.visible")
|
||||
.click({ force: true });
|
||||
|
|
|
|||
|
|
@ -88,8 +88,10 @@ export class PropertyPane {
|
|||
_selectorViewLabel = '[data-testId="selector-view-label"]';
|
||||
_textView = ".text-view";
|
||||
_selectorView = ".selector-view";
|
||||
_dropdownOptions =
|
||||
"//div[@class='rc-virtual-list']//div[contains(@class, 'rc-select-item-option')]";
|
||||
_dropDownValue = (dropdownOption: string) =>
|
||||
`//div[@class='rc-virtual-list']//div[contains(@class, 'rc-select-item-option')]//span[text()='${dropdownOption}']`;
|
||||
`${this._dropdownOptions}//span[text()='${dropdownOption}']`;
|
||||
_selectPropDropdown = (ddName: string) =>
|
||||
"//div[contains(@class, 't--property-control-" +
|
||||
ddName.replace(/ +/g, "").toLowerCase() +
|
||||
|
|
@ -259,6 +261,33 @@ export class PropertyPane {
|
|||
});
|
||||
}
|
||||
|
||||
public AssertPropertiesDropDownValues(
|
||||
endpoint: string,
|
||||
dropdownExpectedValues: string[],
|
||||
) {
|
||||
this.agHelper.GetNClick(this._selectPropDropdown(endpoint));
|
||||
this.agHelper
|
||||
.GetElement(this._dropdownOptions)
|
||||
.then(($ddVisibleTexts: any) => {
|
||||
let foundAll = true; // Flag to track if all expected selections are found
|
||||
const foundSelections: string[] = []; // Array to track found selections
|
||||
$ddVisibleTexts.each((index: any, element: any) => {
|
||||
const spanText = Cypress.$(element).text().trim();
|
||||
foundSelections.push(spanText);
|
||||
});
|
||||
// Check if all expected selections are found in the dropdown
|
||||
dropdownExpectedValues.forEach((expectedSelection) => {
|
||||
if (!foundSelections.includes(expectedSelection)) {
|
||||
foundAll = false;
|
||||
cy.log("Expected dropdown text not found: " + expectedSelection);
|
||||
}
|
||||
});
|
||||
expect(foundAll).to.be.true;
|
||||
cy.log("All dropdown values are present");
|
||||
});
|
||||
this.agHelper.GetNClick(this._selectPropDropdown(endpoint)); //Closing dropdown
|
||||
}
|
||||
|
||||
public SelectJSFunctionToExecuteInExistingActionBlock(
|
||||
jsName: string,
|
||||
funcName: string,
|
||||
|
|
@ -383,9 +412,14 @@ export class PropertyPane {
|
|||
toVerifySave && this.agHelper.AssertAutoSave();
|
||||
}
|
||||
|
||||
public TypeTextIntoField(endp: string, value: string, removeText = true) {
|
||||
public TypeTextIntoField(
|
||||
endp: string,
|
||||
value: string,
|
||||
removeText = true,
|
||||
toVerifySave = true,
|
||||
) {
|
||||
if (removeText) {
|
||||
this.RemoveText(endp);
|
||||
this.RemoveText(endp, toVerifySave);
|
||||
}
|
||||
this.agHelper
|
||||
.GetElement(this.locator._propertyInputField(endp))
|
||||
|
|
|
|||
|
|
@ -160,6 +160,7 @@ export class Table {
|
|||
_columnCheckbox = (columnName: string) =>
|
||||
"[data-rbd-draggable-id='" + columnName + "']" + " .t--card-checkbox input";
|
||||
_dateInputPopover = ".bp3-dateinput-popover";
|
||||
_tableV2Widget = ".t--draggable-tablewidgetv2";
|
||||
_tableV2Row = ".t--draggable-tablewidgetv2 .tbody";
|
||||
_weekdayRowDayPicker =
|
||||
".bp3-datepicker .DayPicker .DayPicker-Months .DayPicker-WeekdaysRow";
|
||||
|
|
|
|||
|
|
@ -864,7 +864,8 @@ Cypress.Commands.add(
|
|||
(forSuccess, forFailure, actionType, actionValue, idx = 0) => {
|
||||
propPane.SelectActionByTitleAndValue(actionType, actionValue);
|
||||
|
||||
cy.get(propPane._actionCallbacks).last().click();
|
||||
agHelper.Sleep();
|
||||
agHelper.GetNClick(propPane._actionCallbacks, 0, true);
|
||||
|
||||
// add a success callback
|
||||
cy.get(propPane._actionAddCallback("success")).click().wait(500);
|
||||
|
|
|
|||
|
|
@ -30,6 +30,9 @@ export default defineConfig({
|
|||
},
|
||||
specPattern: "cypress/e2e/**/*.{js,ts}",
|
||||
testIsolation: false,
|
||||
excludeSpecPattern: "cypress/e2e/**/spec_utility.ts",
|
||||
excludeSpecPattern: [
|
||||
"cypress/e2e/**/spec_utility.ts",
|
||||
"cypress/e2e/GSheet/**/**/*",
|
||||
],
|
||||
},
|
||||
});
|
||||
40
app/client/cypress_ci_hosted.config.ts
Normal file
40
app/client/cypress_ci_hosted.config.ts
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
import { defineConfig } from "cypress";
|
||||
|
||||
export default defineConfig({
|
||||
defaultCommandTimeout: 30000,
|
||||
requestTimeout: 60000,
|
||||
responseTimeout: 60000,
|
||||
pageLoadTimeout: 60000,
|
||||
videoUploadOnPasses: false,
|
||||
videoCompression: false,
|
||||
numTestsKeptInMemory: 5,
|
||||
experimentalMemoryManagement: true,
|
||||
reporterOptions: {
|
||||
reportDir: "results",
|
||||
overwrite: false,
|
||||
html: true,
|
||||
json: false,
|
||||
},
|
||||
chromeWebSecurity: false,
|
||||
viewportHeight: 1100,
|
||||
viewportWidth: 1400,
|
||||
scrollBehavior: "center",
|
||||
retries: {
|
||||
runMode: 1,
|
||||
openMode: 0,
|
||||
},
|
||||
e2e: {
|
||||
baseUrl: "https://regression.test.appsmith.com",
|
||||
setupNodeEvents(on, config) {
|
||||
return require("./cypress/plugins/index.js")(on, config);
|
||||
},
|
||||
specPattern: "cypress/e2e/**/*.{js,ts}",
|
||||
testIsolation: false,
|
||||
excludeSpecPattern: [
|
||||
"cypress/e2e/**/spec_utility.ts",
|
||||
"cypress/e2e/Regression/**/**/*",
|
||||
"cypress/e2e/Sanity/**/**/*",
|
||||
"cypress/e2e/Smoke/**/**/*",
|
||||
],
|
||||
},
|
||||
});
|
||||
|
|
@ -31,6 +31,9 @@ module.exports = {
|
|||
"design-system-old": "<rootDir>/node_modules/design-system-old/build",
|
||||
"@design-system/widgets-old":
|
||||
"<rootDir>/node_modules/@design-system/widgets-old",
|
||||
"@design-system/widgets": "<rootDir>/node_modules/@design-system/widgets",
|
||||
"@design-system/headless": "<rootDir>/node_modules/@design-system/headless",
|
||||
"@design-system/theming": "<rootDir>/node_modules/@design-system/theming",
|
||||
"design-system": "<rootDir>/node_modules/design-system/build",
|
||||
"^proxy-memoize$": "<rootDir>/node_modules/proxy-memoize/dist/wrapper.cjs",
|
||||
// @blueprintjs packages need to be resolved to the `esnext` directory. The default `esm` directory
|
||||
|
|
|
|||
|
|
@ -96,6 +96,7 @@
|
|||
"design-system": "npm:@appsmithorg/design-system@2.1.17",
|
||||
"design-system-old": "npm:@appsmithorg/design-system-old@1.1.11",
|
||||
"downloadjs": "^1.4.7",
|
||||
"echarts": "^5.4.2",
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
"fast-xml-parser": "^3.17.5",
|
||||
"fastdom": "^1.0.11",
|
||||
|
|
@ -278,7 +279,7 @@
|
|||
"compression-webpack-plugin": "^10.0.0",
|
||||
"cra-bundle-analyzer": "^0.1.0",
|
||||
"cy-verify-downloads": "^0.0.5",
|
||||
"cypress": "^12.16.0",
|
||||
"cypress": "^12.17.0",
|
||||
"cypress-file-upload": "^4.1.1",
|
||||
"cypress-image-snapshot": "^4.0.1",
|
||||
"cypress-mochawesome-reporter": "^3.5.1",
|
||||
|
|
@ -353,6 +354,7 @@
|
|||
"@blueprintjs/core@^3.43.0": "patch:@blueprintjs/core@npm%3A3.47.0#./.yarn/patches/@blueprintjs-core-npm-3.47.0-a5bc1ea927.patch",
|
||||
"@blueprintjs/core@^3.33.0": "patch:@blueprintjs/core@npm%3A3.47.0#./.yarn/patches/@blueprintjs-core-npm-3.47.0-a5bc1ea927.patch",
|
||||
"@blueprintjs/core@^3.47.0": "patch:@blueprintjs/core@npm%3A3.47.0#./.yarn/patches/@blueprintjs-core-npm-3.47.0-a5bc1ea927.patch",
|
||||
"@blueprintjs/icons": "3.22.0"
|
||||
"@blueprintjs/icons": "3.22.0",
|
||||
"@types/react": "^17.0.2"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user