merge: 1.9.45 front-end

This commit is contained in:
zhaisifeng 2024-01-03 18:25:02 +08:00
commit 0eacfa2267
3038 changed files with 143450 additions and 44627 deletions

13
.editorconfig Normal file
View File

@ -0,0 +1,13 @@
# https://EditorConfig.org
root = true
[*]
charset = utf-8
end_of_line = lf
indent_style = space
indent_size = 2
insert_final_newline = true
trim_trailing_whitespace = true
[{*.java,pom.xml,*.py}]
indent_size = 4

2268
.github/config.json vendored

File diff suppressed because one or more lines are too long

View File

@ -11,12 +11,12 @@
> Add a TL;DR when description is extra long (helps content team)
Fixes # (issue)
> if no issue exists, please create an issue and ask the maintainers about this first
Media
> A video or a GIF is preferred. when using Loom, dont embed because it looks like its a GIF. instead, just link to the video
> A video or a GIF is preferred. when using Loom, dont embed because it looks like its a GIF. instead, just link to the video
## Type of change
@ -27,26 +27,35 @@ Media
- Breaking change (fix or feature that would cause existing functionality to not work as expected)
- Chore (housekeeping or task changes that don't impact user perception)
- This change requires a documentation update
>
## Testing
## How Has This Been Tested?
> Please describe the tests that you ran to verify your changes. Provide instructions, so we can reproduce.
> Please also list any relevant details for your test configuration.
> Delete anything that is not important
>
- Manual
- Jest
- Cypress
#### How Has This Been Tested?
> Please describe the tests that you ran to verify your changes. Also list any relevant details for your test configuration.
> Delete anything that is not relevant
- [ ] Manual
- [ ] JUnit
- [ ] Jest
- [ ] Cypress
>
#### Test Plan
### Test Plan
> Add Testsmith test cases links that relate to this PR
### Issues raised during DP testing
> Link issues raised during DP testing for better visiblity and tracking (copy link from comments dropped on this PR)
## Checklist:
### Dev activity
- [ ] My code follows the style guidelines of this project
- [ ] I have performed a self-review of my own code
- [ ] I have commented my code, particularly in hard-to-understand areas
@ -56,8 +65,8 @@ Media
- [ ] New and existing unit tests pass locally with my changes
- [ ] PR is being merged under a feature flag
#### QA activity:
- [ ] [Speedbreak features](https://github.com/appsmithorg/TestSmith/wiki/Guidelines-for-test-plans#speedbreakers-) have been covered
- [ ] Test plan covers all impacted features and [areas of interest](https://github.com/appsmithorg/TestSmith/wiki/Guidelines-for-test-plans#areas-of-interest-)
- [ ] Test plan has been peer reviewed by project stakeholders and other QA members

View File

@ -31,7 +31,7 @@ jobs:
"status": "IN_PROGRESS",
"githubWorkflowId": "${{ github.run_id }}"
}'
server-build:
name: server-build
uses: ./.github/workflows/server-build.yml
@ -104,6 +104,12 @@ jobs:
echo "Cleaning up the tar files"
rm app/client/packages/rts/dist/rts-dist.tar
- name: Generate info.json
run: |
if [[ -f scripts/generate_info_json.sh ]]; then
scripts/generate_info_json.sh
fi
- name: Login to DockerHub
uses: docker/login-action@v1
with:
@ -121,6 +127,7 @@ jobs:
${{ vars.DOCKER_HUB_ORGANIZATION }}/appsmith-dp:${{ github.event.inputs.sub-domain-name }}
build-args: |
APPSMITH_CLOUD_SERVICES_BASE_URL=https://release-cs.appsmith.com
BASE=${{ vars.DOCKER_HUB_ORGANIZATION }}/base-${{ vars.EDITION }}:release
outputs:
imageHash: ${{ github.event.inputs.sub-domain-name }}
@ -190,4 +197,4 @@ jobs:
"status": "FAILED"
}'

View File

@ -14,12 +14,12 @@ on:
pull_request:
branches: [release, master]
paths:
- "deploy/docker/utils/**"
- "deploy/docker/fs/opt/appsmith/utils/**"
# Change the working directory for all the jobs in this workflow
defaults:
run:
working-directory: deploy/docker/utils/
working-directory: deploy/docker/fs/opt/appsmith/utils/
jobs:
build:
@ -97,7 +97,7 @@ jobs:
echo "appsmithctl_run_result=failed" >> $GITHUB_OUTPUT > ~/appsmithctl_run_result
exit 1;
# Set status = success
- name: Save the status of the run
run: echo "appsmithctl_run_result=success" >> $GITHUB_OUTPUT > ~/appsmithctl_run_result

View File

@ -186,45 +186,63 @@ jobs:
run:
shell: bash
steps:
# Deleting the existing dir's if any
- name: Delete existing directories
- name: Setup node
if: needs.ci-test-limited.result != 'success'
run: |
rm -f ~/failed_spec_ci
rm -f ~/combined_failed_spec_ci
# Force store previous cypress dashboard url from cache
- name: Store the previous cypress dashboard url
if: success()
uses: actions/cache@v3
uses: actions/setup-node@v3
with:
path: |
~/cypress_url
key: ${{ github.run_id }}-dashboard-url-${{ github.run_attempt }}
restore-keys: |
${{ github.run_id }}-dashboard-url
node-version: 18
- name: Print cypress dashboard url
id: dashboard_url
run: |
cypress_url=$(cat ~/cypress_url)
echo "dashboard_url=$cypress_url" >> $GITHUB_OUTPUT
# Download failed_spec list for all jobs
- uses: actions/download-artifact@v3
- name: install pg
if: needs.ci-test-limited.result != 'success'
id: download_ci
run: npm install pg
- name: Fetch the failed specs
if: needs.ci-test-limited.result != 'success'
id: failed_specs
env:
DB_HOST: ${{ secrets.CYPRESS_DB_HOST }}
DB_NAME: ${{ secrets.CYPRESS_DB_NAME }}
DB_USER: ${{ secrets.CYPRESS_DB_USER }}
DB_PWD: ${{ secrets.CYPRESS_DB_PWD }}
RUN_ID: ${{ github.run_id }}
ATTEMPT_NUMBER: ${{ github.run_attempt }}
uses: actions/github-script@v6
with:
name: failed-spec-ci-${{github.run_attempt}}
path: ~/failed_spec_ci
script: |
const { Pool } = require("pg");
const { DB_HOST, DB_NAME, DB_USER, DB_PWD, RUN_ID, ATTEMPT_NUMBER } = process.env
const client = await new Pool({
user: DB_USER,
host: DB_HOST,
database: DB_NAME,
password: DB_PWD,
port: 5432,
connectionTimeoutMillis: 60000,
}).connect();
const result = await client.query(
`SELECT DISTINCT name FROM public."specs"
WHERE "matrixId" IN
(SELECT id FROM public."matrix"
WHERE "attemptId" = (
SELECT id FROM public."attempt" WHERE "workflowId" = $1 and "attempt" = $2
)
) AND status = 'fail'`,
[RUN_ID, ATTEMPT_NUMBER],
);
client.release();
return result.rows.map((spec) => spec.name);
# 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-limited.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
failed_specs=$(echo ${{steps.failed_specs.outputs.result}} | sed 's/\[\|\]//g' | tr -d ' ' | tr ',' '\n')
while read -r line; do
echo "$line" >> ~/combined_failed_spec_ci
done <<< "$failed_specs"
# Upload combined failed CI spec list to a file
# This is done for debugging.
@ -258,9 +276,9 @@ jobs:
issue-number: ${{fromJson(needs.file-check.outputs.pr)}}
body: |
Workflow run: <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}>.
Cypress dashboard: <a href="${{ steps.dashboard_url.outputs.dashboard_url }}" target="_blank"> Click here!</a>
Cypress dashboard: <a href="https://internal.appsmith.com/app/cypressdashboard/rundetails-64ec3df0c632e24c00764938?branch=master&workflowId=${{ github.run_id }}&attempt=${{ github.run_attempt }}&selectiontype=test&testsstatus=failed&specsstatus=fail" target="_blank"> Click here!</a>
The following are new failures, please fix them before merging the PR: ${{env.new_failed_spec_env}}
To know the list of identified flaky tests - <a href="https://app.appsmith.com/applications/613868bedd7786286ddd4a6a/pages/63ec710e8e503f763651791a" target="_blank">Refer here</a>
To know the list of identified flaky tests - <a href="https://internal.appsmith.com/app/cypressdashboard/identified-flaky-tests-6541e22b0c243558fe2288ca?branch=master" target="_blank">Refer here</a>
- name: Add a comment on the PR when ci-test-limited is success
if: needs.ci-test-limited.result == 'success' && needs.file-check.outputs.pr != '0'
@ -269,7 +287,7 @@ jobs:
issue-number: ${{fromJson(needs.file-check.outputs.pr)}}
body: |
Workflow run: <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}>.
Cypress dashboard url: <a href="${{ steps.dashboard_url.outputs.dashboard_url }}" target="_blank">Click here!</a>
Cypress dashboard url: <a href="https://internal.appsmith.com/app/cypressdashboard/rundetails-64ec3df0c632e24c00764938?branch=master&workflowId=${{ github.run_id }}&attempt=${{ github.run_attempt }}" target="_blank">Click here!</a>
All cypress tests have passed 🎉🎉🎉
- name: Check ci-test-limited set status
@ -285,45 +303,63 @@ jobs:
run:
shell: bash
steps:
# Deleting the existing dir's if any
- name: Delete existing directories
- name: Setup node
if: needs.ci-test-limited-existing-docker-image.result != 'success'
run: |
rm -f ~/failed_spec_ci
rm -f ~/combined_failed_spec_ci
# Force store previous cypress dashboard url from cache
- name: Store the previous cypress dashboard url
if: success()
uses: actions/cache@v3
uses: actions/setup-node@v3
with:
path: |
~/cypress_url
key: ${{ github.run_id }}-dashboard-url-${{ github.run_attempt }}
restore-keys: |
${{ github.run_id }}-dashboard-url
node-version: 18
- name: Print cypress dashboard url
id: dashboard_url
run: |
cypress_url=$(cat ~/cypress_url)
echo "dashboard_url=$cypress_url" >> $GITHUB_OUTPUT
# Download failed_spec list for all jobs
- uses: actions/download-artifact@v3
- name: install pg
if: needs.ci-test-limited-existing-docker-image.result != 'success'
id: download_ci
run: npm install pg
- name: Fetch the failed specs
if: needs.ci-test-limited-existing-docker-image.result != 'success'
id: failed_specs
env:
DB_HOST: ${{ secrets.CYPRESS_DB_HOST }}
DB_NAME: ${{ secrets.CYPRESS_DB_NAME }}
DB_USER: ${{ secrets.CYPRESS_DB_USER }}
DB_PWD: ${{ secrets.CYPRESS_DB_PWD }}
RUN_ID: ${{ github.run_id }}
ATTEMPT_NUMBER: ${{ github.run_attempt }}
uses: actions/github-script@v6
with:
name: failed-spec-ci-${{github.run_attempt}}
path: ~/failed_spec_ci
script: |
const { Pool } = require("pg");
const { DB_HOST, DB_NAME, DB_USER, DB_PWD, RUN_ID, ATTEMPT_NUMBER } = process.env
const client = await new Pool({
user: DB_USER,
host: DB_HOST,
database: DB_NAME,
password: DB_PWD,
port: 5432,
connectionTimeoutMillis: 60000,
}).connect();
const result = await client.query(
`SELECT DISTINCT name FROM public."specs"
WHERE "matrixId" IN
(SELECT id FROM public."matrix"
WHERE "attemptId" = (
SELECT id FROM public."attempt" WHERE "workflowId" = $1 and "attempt" = $2
)
) AND status = 'fail'`,
[RUN_ID, ATTEMPT_NUMBER],
);
client.release();
return result.rows.map((spec) => spec.name);
# 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-limited-existing-docker-image.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
failed_specs=$(echo ${{steps.failed_specs.outputs.result}} | sed 's/\[\|\]//g' | tr -d ' ' | tr ',' '\n')
while read -r line; do
echo "$line" >> ~/combined_failed_spec_ci
done <<< "$failed_specs"
# Upload combined failed CI spec list to a file
# This is done for debugging.
@ -357,9 +393,9 @@ jobs:
issue-number: ${{fromJson(needs.file-check.outputs.pr)}}
body: |
Workflow run: <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}>.
Cypress dashboard: <a href="${{ steps.dashboard_url.outputs.dashboard_url }}" target="_blank"> Click here!</a>
Cypress dashboard: <a href="https://internal.appsmith.com/app/cypressdashboard/rundetails-64ec3df0c632e24c00764938?branch=master&workflowId=${{ github.run_id }}&attempt=${{ github.run_attempt }}&selectiontype=test&testsstatus=failed&specsstatus=fail" target="_blank"> Click here!</a>
The following are new failures, please fix them before merging the PR: ${{env.new_failed_spec_env}}
To know the list of identified flaky tests - <a href="https://app.appsmith.com/applications/613868bedd7786286ddd4a6a/pages/63ec710e8e503f763651791a" target="_blank">Refer here</a>
To know the list of identified flaky tests - <a href="https://internal.appsmith.com/app/cypressdashboard/identified-flaky-tests-6541e22b0c243558fe2288ca?branch=master" target="_blank">Refer here</a>
- name: Add a comment on the PR when ci-test-limited-existing-docker-image is success
if: needs.ci-test-limited-existing-docker-image.result == 'success' && needs.file-check.outputs.pr != '0'
@ -368,7 +404,7 @@ jobs:
issue-number: ${{fromJson(needs.file-check.outputs.pr)}}
body: |
Workflow run: <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}>.
Cypress dashboard url: <a href="${{ steps.dashboard_url.outputs.dashboard_url }}" target="_blank">Click here!</a>
Cypress dashboard url: <a href="https://internal.appsmith.com/app/cypressdashboard/rundetails-64ec3df0c632e24c00764938?branch=master&workflowId=${{ github.run_id }}&attempt=${{ github.run_attempt }}" target="_blank">Click here!</a>
All cypress tests have passed 🎉🎉🎉
- name: Check ci-test-limited-existing-docker-image set status

View File

@ -79,19 +79,27 @@ jobs:
echo "Cleaning up the tar files"
rm app/client/packages/rts/dist/rts-dist.tar
- name: Generate info.json
run: |
if [[ -f scripts/generate_info_json.sh ]]; then
scripts/generate_info_json.sh
fi
# We don't use Depot Docker builds because it's faster for local Docker images to be built locally.
# It's slower and more expensive to build these Docker images on Depot and download it back to the CI node.
- name: Build docker image
if: steps.run_result.outputs.run_result != 'success'
working-directory: "."
run: |
set -o xtrace
declare -a args
if [[ "${{ inputs.pr }}" != 0 ]]; then
args+=(--cache-from "${{ vars.DOCKER_HUB_ORGANIZATION }}/appsmith-${{ vars.EDITION }}:release")
fi
if [[ "${{ inputs.pr }}" != 0 || "${{ github.ref_name }}" != master ]]; then
args+=(--build-arg "APPSMITH_CLOUD_SERVICES_BASE_URL=https://release-cs.appsmith.com")
base_tag=release
else
base_tag=nightly
fi
args+=(--build-arg "BASE=${{ vars.DOCKER_HUB_ORGANIZATION }}/base-${{ vars.EDITION }}:$base_tag")
docker build -t cicontainer "${args[@]}" .
# Saving the docker image to tar file

View File

@ -92,7 +92,7 @@ jobs:
key: ${{ github.run_id }}-failed_spec_ci_sanity-${{ github.job }}
restore-keys: |
${{ github.run_id }}-failed_spec_ci_sanity-${{ github.job }}
# 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
@ -151,15 +151,15 @@ jobs:
cicontainer
- name: Setup MSSQL & Arango docker containers
working-directory : app/client/cypress
run : |
working-directory: app/client/cypress
run: |
docker run --name=mssqldb -e "ACCEPT_EULA=Y" -e "SA_PASSWORD=Root@123" -p 1433:1433 -d mcr.microsoft.com/azure-sql-edge
docker run --name arangodb -e ARANGO_USERNAME=root -e ARANGO_ROOT_PASSWORD=Arango -p 8529:8529 -d arangodb
# docker exec -i mssqldb /bin/bash -c "echo -e '[mysqld]\ntcpport=1433\ntcpnodelay=1' >> /var/opt/mssql/mssql.conf"
# docker restart mssqldb
# sudo ufw allow 1433/tcp
# docker cp init-mssql-dump-for-test.sql mssqldb:var/init-mssql-dump-for-test.sql
# docker exec -i mssqldb /opt/mssql-tools/bin/sqlcmd -S localhost -U SA -P Root@123 -i /var/init-mssql-dump-for-test.sql
# docker exec -i mssqldb /bin/bash -c "echo -e '[mysqld]\ntcpport=1433\ntcpnodelay=1' >> /var/opt/mssql/mssql.conf"
# docker restart mssqldb
# sudo ufw allow 1433/tcp
# docker cp init-mssql-dump-for-test.sql mssqldb:var/init-mssql-dump-for-test.sql
# docker exec -i mssqldb /opt/mssql-tools/bin/sqlcmd -S localhost -U SA -P Root@123 -i /var/init-mssql-dump-for-test.sql
- name: Use Node.js
if: steps.run_result.outputs.run_result != 'success'
@ -179,48 +179,6 @@ jobs:
- 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_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
run: |
cd app/client
chmod a+x ./cypress/setup-test-ci.sh
@ -253,6 +211,10 @@ jobs:
CYPRESS_S3_SECRET_KEY: ${{ secrets.CYPRESS_S3_SECRET_KEY }}
CYPRESS_GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
CYPRESS_AIRTABLE_BEARER: ${{ secrets.AIRTABLE_BEARER }}
CYPRESS_ORACLE_HOST: ${{ secrets.ORACLE_HOST }}
CYPRESS_ORACLE_SERVICE: ${{ secrets.ORACLE_SERVICE }}
CYPRESS_ORACLE_USERNAME: ${{ secrets.ORACLE_USERNAME }}
CYPRESS_ORACLE_PASSWORD: ${{ secrets.ORACLE_PASSWORD }}
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 }}
@ -272,6 +234,8 @@ jobs:
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_APPSMITH_OAUTH2_OIDC_OKTA_PASSWORD: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_OKTA_PASSWORD }}
CYPRESS_APPSMITH_OAUTH2_OIDC_DIRECT_URL: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_DIRECT_URL }}
CYPRESS_EXCLUDE_TAGS: "airgap"
CYPRESS_AIRGAPPED: false
APPSMITH_DISABLE_TELEMETRY: true
@ -313,6 +277,10 @@ jobs:
CYPRESS_S3_SECRET_KEY: ${{ secrets.CYPRESS_S3_SECRET_KEY }}
CYPRESS_GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
CYPRESS_AIRTABLE_BEARER: ${{ secrets.AIRTABLE_BEARER }}
CYPRESS_ORACLE_HOST: ${{ secrets.ORACLE_HOST }}
CYPRESS_ORACLE_SERVICE: ${{ secrets.ORACLE_SERVICE }}
CYPRESS_ORACLE_USERNAME: ${{ secrets.ORACLE_USERNAME }}
CYPRESS_ORACLE_PASSWORD: ${{ secrets.ORACLE_PASSWORD }}
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 }}
@ -332,6 +300,8 @@ jobs:
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_APPSMITH_OAUTH2_OIDC_OKTA_PASSWORD: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_OKTA_PASSWORD }}
CYPRESS_APPSMITH_OAUTH2_OIDC_DIRECT_URL: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_DIRECT_URL }}
CYPRESS_EXCLUDE_TAGS: "airgap"
CYPRESS_AIRGAPPED: false
APPSMITH_DISABLE_TELEMETRY: true

View File

@ -92,7 +92,7 @@ jobs:
key: ${{ github.run_id }}-failed_spec_ci_smoke-${{ github.job }}
restore-keys: |
${{ github.run_id }}-failed_spec_ci_smoke-${{ github.job }}
# 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
@ -151,15 +151,15 @@ jobs:
cicontainer
- name: Setup MSSQL & Arango docker containers
working-directory : app/client/cypress
run : |
working-directory: app/client/cypress
run: |
docker run --name=mssqldb -e "ACCEPT_EULA=Y" -e "SA_PASSWORD=Root@123" -p 1433:1433 -d mcr.microsoft.com/azure-sql-edge
docker run --name arangodb -e ARANGO_USERNAME=root -e ARANGO_ROOT_PASSWORD=Arango -p 8529:8529 -d arangodb
# docker exec -i mssqldb /bin/bash -c "echo -e '[mysqld]\ntcpport=1433\ntcpnodelay=1' >> /var/opt/mssql/mssql.conf"
# docker restart mssqldb
# sudo ufw allow 1433/tcp
# docker cp init-mssql-dump-for-test.sql mssqldb:var/init-mssql-dump-for-test.sql
# docker exec -i mssqldb /opt/mssql-tools/bin/sqlcmd -S localhost -U SA -P Root@123 -i /var/init-mssql-dump-for-test.sql
# docker exec -i mssqldb /bin/bash -c "echo -e '[mysqld]\ntcpport=1433\ntcpnodelay=1' >> /var/opt/mssql/mssql.conf"
# docker restart mssqldb
# sudo ufw allow 1433/tcp
# docker cp init-mssql-dump-for-test.sql mssqldb:var/init-mssql-dump-for-test.sql
# docker exec -i mssqldb /opt/mssql-tools/bin/sqlcmd -S localhost -U SA -P Root@123 -i /var/init-mssql-dump-for-test.sql
- name: Use Node.js
if: steps.run_result.outputs.run_result != 'success'
@ -179,48 +179,6 @@ jobs:
- 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_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
run: |
cd app/client
chmod a+x ./cypress/setup-test-ci.sh
@ -253,6 +211,10 @@ jobs:
CYPRESS_S3_SECRET_KEY: ${{ secrets.CYPRESS_S3_SECRET_KEY }}
CYPRESS_GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
CYPRESS_AIRTABLE_BEARER: ${{ secrets.AIRTABLE_BEARER }}
CYPRESS_ORACLE_HOST: ${{ secrets.ORACLE_HOST }}
CYPRESS_ORACLE_SERVICE: ${{ secrets.ORACLE_SERVICE }}
CYPRESS_ORACLE_USERNAME: ${{ secrets.ORACLE_USERNAME }}
CYPRESS_ORACLE_PASSWORD: ${{ secrets.ORACLE_PASSWORD }}
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 }}
@ -272,6 +234,8 @@ jobs:
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_APPSMITH_OAUTH2_OIDC_OKTA_PASSWORD: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_OKTA_PASSWORD }}
CYPRESS_APPSMITH_OAUTH2_OIDC_DIRECT_URL: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_DIRECT_URL }}
CYPRESS_EXCLUDE_TAGS: "airgap"
CYPRESS_AIRGAPPED: false
APPSMITH_DISABLE_TELEMETRY: true
@ -313,6 +277,10 @@ jobs:
CYPRESS_S3_SECRET_KEY: ${{ secrets.CYPRESS_S3_SECRET_KEY }}
CYPRESS_GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
CYPRESS_AIRTABLE_BEARER: ${{ secrets.AIRTABLE_BEARER }}
CYPRESS_ORACLE_HOST: ${{ secrets.ORACLE_HOST }}
CYPRESS_ORACLE_SERVICE: ${{ secrets.ORACLE_SERVICE }}
CYPRESS_ORACLE_USERNAME: ${{ secrets.ORACLE_USERNAME }}
CYPRESS_ORACLE_PASSWORD: ${{ secrets.ORACLE_PASSWORD }}
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 }}
@ -332,6 +300,8 @@ jobs:
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_APPSMITH_OAUTH2_OIDC_OKTA_PASSWORD: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_OKTA_PASSWORD }}
CYPRESS_APPSMITH_OAUTH2_OIDC_DIRECT_URL: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_DIRECT_URL }}
CYPRESS_EXCLUDE_TAGS: "airgap"
CYPRESS_AIRGAPPED: false
APPSMITH_DISABLE_TELEMETRY: true

View File

@ -24,7 +24,69 @@ jobs:
strategy:
fail-fast: false
matrix:
job: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59]
job:
[
0,
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25,
26,
27,
28,
29,
30,
31,
32,
33,
34,
35,
36,
37,
38,
39,
40,
41,
42,
43,
44,
45,
46,
47,
48,
49,
50,
51,
52,
53,
54,
55,
56,
57,
58,
59,
]
# Service containers to run with this job. Required for running tests
services:
@ -44,6 +106,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
@ -80,39 +148,17 @@ jobs:
run: |
run_result_env=$(cat ~/run_result)
echo "run_result=$run_result_env" >> $GITHUB_OUTPUT
if [[ "$run_result_env" == "failedtest" ]]; then
echo "rerun=true" >> $GITHUB_OUTPUT
else
echo "rerun=false" >> $GITHUB_OUTPUT
fi
- name: Dump steps context
env:
STEPS_CONTEXT: ${{ toJson(steps) }}
run: echo "$STEPS_CONTEXT"
# In case this is second attempt try restoring failed tests
- if : steps.run_result.outputs.run_result == 'failedtest'
run: echo "failed_spec_artifact=failed-spec-ci-$((${{github.run_attempt}}-1))" >> $GITHUB_ENV
- name: Restore the previous failed combine result
if: steps.run_result.outputs.run_result == 'failedtest'
uses: actions/download-artifact@v3
with:
name: ${{ env.failed_spec_artifact }}
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: |
failed_spec_env=""
while IFS= read -r line
do
spec_name=$(echo $line | awk -F'/' '{print $NF}')
failed_spec=$(find . -name $spec_name | sed 's|./||')
failed_spec_env="$failed_spec_env,$failed_spec"
done < ~/failed_spec_ci/failed_spec_ci-${{ matrix.job }}
failed_spec_env=${failed_spec_env#,}
echo "failed_spec_env=$failed_spec_env" >> $GITHUB_ENV
- if: steps.run_result.outputs.run_result != 'success' && steps.run_result.outputs.run_result != 'failedtest'
run: echo "Starting full run" && exit 0
@ -148,12 +194,43 @@ jobs:
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 \
-e FLAGSMITH_URL=http://host.docker.internal:5001/flagsmith \
-e FLAGSMITH_SERVER_KEY=dummykey \
-e FLAGSMITH_SERVER_KEY_BUSINESS_FEATURES=dummykeybusinessfeatures \
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
@ -185,49 +262,6 @@ jobs:
- 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_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
@ -239,69 +273,50 @@ jobs:
- run: |
echo "BROWSER_PATH=$(which chrome)" >> $GITHUB_ENV
- 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_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
TOTAL_RUNNERS: ${{ strategy.job-total }}
THIS_RUNNER: ${{ strategy.job-index }}
CYPRESS_SPEC_PATTERN: "cypress/e2e/**/**/*"
CYPRESS_ENV: "NODE_ENV=development"
CYPRESS_CONFIG_FILE: cypress_ci_custom.config.ts
CYPRESS_HEADLESS: "true"
CYPRESS_BROWSER: ${{ env.BROWSER_PATH }}
with:
install: false
working-directory: app/client
command: yarn ts-node --require esm cypress/cypress-split.ts
- 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
# 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
- 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: |
eventCommit=$(echo ${{env.EVENT_COMMITS}} | sed "s/'//g")
if [[ ${{ inputs.pr }} -ne 0 ]]; then
echo "COMMIT_INFO_MESSAGE=${{ env.COMMIT_INFO_MESSAGE }}" >> $GITHUB_ENV
else
if [[ '$eventCommit' == 'null' ]]; then
echo "COMMIT_INFO_MESSAGE=$(echo ${{ github.event_name }} | perl -pe 's/(^|_)./uc($&)/ge;s/_//g')" >> $GITHUB_ENV
echo "COMMIT_INFO_MESSAGE=${{ env.COMMIT_INFO_MESSAGE}} by ${{ env.COMMIT_INFO_AUTHOR }}" >> $GITHUB_ENV
else
echo "COMMIT_INFO_MESSAGE=$(echo "$eventCommit" | awk -F '\\\\n' '{print $1}' | sed 's/^"//;s/"$//')" >> $GITHUB_ENV
fi
fi
- name: Run the cypress test
uses: cypress-io/github-action@v6
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CYPRESS_USERNAME: ${{ secrets.CYPRESS_USERNAME }}
@ -318,6 +333,10 @@ jobs:
CYPRESS_S3_SECRET_KEY: ${{ secrets.CYPRESS_S3_SECRET_KEY }}
CYPRESS_GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
CYPRESS_AIRTABLE_BEARER: ${{ secrets.AIRTABLE_BEARER }}
CYPRESS_ORACLE_HOST: ${{ secrets.ORACLE_HOST }}
CYPRESS_ORACLE_SERVICE: ${{ secrets.ORACLE_SERVICE }}
CYPRESS_ORACLE_USERNAME: ${{ secrets.ORACLE_USERNAME }}
CYPRESS_ORACLE_PASSWORD: ${{ secrets.ORACLE_PASSWORD }}
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 }}
@ -338,19 +357,47 @@ jobs:
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_APPSMITH_OAUTH2_OIDC_OKTA_PASSWORD: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_OKTA_PASSWORD }}
CYPRESS_APPSMITH_OAUTH2_OIDC_DIRECT_URL: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_DIRECT_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
COMMIT_INFO_MESSAGE: ${{ env.COMMIT_INFO_MESSAGE }}
CYPRESS_ENV: "NODE_ENV=development"
CYPRESS_CONFIG_FILE: cypress_ci.config.ts
CYPRESS_HEADLESS: "true"
CYPRESS_BROWSER: ${{ env.BROWSER_PATH }}
THIS_RUNNER: ${{ strategy.job-index }}
RUNID: ${{ github.run_id }}
ATTEMPT_NUMBER: ${{ github.run_attempt }}
REPOSITORY: ${{ github.repository }}
COMMITTER: ${{ env.COMMIT_INFO_AUTHOR }}
TAG: ${{ github.event_name }}
BRANCH: ${{ env.COMMIT_INFO_BRANCH }}
CYPRESS_RERUN: ${{steps.run_result.outputs.rerun}}
CYPRESS_DB_USER: ${{ secrets.CYPRESS_DB_USER }}
CYPRESS_DB_HOST: ${{ secrets.CYPRESS_DB_HOST }}
CYPRESS_DB_NAME: ${{ secrets.CYPRESS_DB_NAME }}
CYPRESS_DB_PWD: ${{ secrets.CYPRESS_DB_PWD }}
CYPRESS_S3_ACCESS: ${{ secrets.CYPRESS_S3_ACCESS }}
CYPRESS_S3_SECRET: ${{ secrets.CYPRESS_S3_SECRET }}
with:
browser: ${{ env.BROWSER_PATH }}
install: false
config-file: cypress_ci_custom.config.ts
working-directory: app/client
command: yarn cypress run --browser ${{ env.BROWSER_PATH }} --config-file cypress_ci_custom.config.ts --spec ${{ env.failed_spec_env }}
env: "NODE_ENV=development"
- name: Trim number of cypress log files
if: failure()
run: |
find ${{ github.workspace }}/app/client/cypress/cypress-logs -name '*.json' -type f | tail -n +11 | xargs -I {} rm -- {}
- name: Upload failed test cypress logs artifact
if: failure()
uses: actions/upload-artifact@v3
with:
name: cypress-console-logs
path: ${{ github.workspace }}/app/client/cypress/cypress-logs
- name: Collect CI container logs
if: failure()
@ -368,13 +415,13 @@ jobs:
path: ~/dockerlogs
- name: Rename reports
if: always()
if: failure()
run: |
mkdir -p ~/results
mv ${{ github.workspace }}/app/client/results ~/results/${{ matrix.job }}
- name: Upload cypress report
if: always()
if: failure()
uses: actions/upload-artifact@v3
with:
name: results-${{github.run_attempt}}
@ -387,28 +434,6 @@ jobs:
echo "run_result=failedtest" >> $GITHUB_OUTPUT
echo "failedtest" > ~/run_result
# Create a directory ~/failed_spec_ci and add a dummy file
# This will ensure upload and download steps are successful
- name: Create directory for failed tests
if: always()
run: |
mkdir -p ~/failed_spec_ci-${{github.run_attempt}}
# 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-${{github.run_attempt}}/failed_spec_ci-${{ matrix.job }}
# Upload failed test list using common path for all matrix job
- name: Upload failed test list artifact
if: failure()
uses: actions/upload-artifact@v3
with:
name: failed-spec-ci-${{github.run_attempt}}
path: ~/failed_spec_ci-${{github.run_attempt}}
# Force store previous run result to cache
- name: Store the previous run result
if: failure()
@ -418,16 +443,6 @@ jobs:
~/run_result
key: ${{ github.run_id }}-${{ github.job }}-${{ matrix.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 "" >> ~/cypress_url
elif [[ "${{steps.run_result.outputs.run_result }}" == "failedtest" ]]; then
echo "" >> ~/cypress_url
fi
# Force store previous run result to cache
- name: Store the previous run result
if: success()

View File

@ -86,36 +86,17 @@ jobs:
run: |
run_result_env=$(cat ~/run_result)
echo "run_result=$run_result_env" >> $GITHUB_OUTPUT
if [[ "$run_result_env" == "failedtest" ]]; then
echo "rerun=true" >> $GITHUB_OUTPUT
else
echo "rerun=false" >> $GITHUB_OUTPUT
fi
- 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
@ -153,50 +134,6 @@ jobs:
- 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
@ -208,12 +145,6 @@ jobs:
- 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
@ -245,19 +176,15 @@ jobs:
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
echo "COMMIT_INFO_MESSAGE=Scheduled run for Hosted tests" >> $GITHUB_ENV
else
echo "COMMIT_INFO_MESSAGE=Manual workflow run for gsheet tests" >> $GITHUB_ENV
echo "COMMIT_INFO_MESSAGE=Manual workflow run for Hosted tests" >> $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
uses: cypress-io/github-action@v6
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 }}
@ -272,6 +199,10 @@ jobs:
CYPRESS_S3_SECRET_KEY: ${{ secrets.CYPRESS_S3_SECRET_KEY }}
CYPRESS_GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
CYPRESS_AIRTABLE_BEARER: ${{ secrets.AIRTABLE_BEARER }}
CYPRESS_ORACLE_HOST: ${{ secrets.ORACLE_HOST }}
CYPRESS_ORACLE_SERVICE: ${{ secrets.ORACLE_SERVICE }}
CYPRESS_ORACLE_USERNAME: ${{ secrets.ORACLE_USERNAME }}
CYPRESS_ORACLE_PASSWORD: ${{ secrets.ORACLE_PASSWORD }}
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 }}
@ -292,87 +223,54 @@ jobs:
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_APPSMITH_OAUTH2_OIDC_OKTA_PASSWORD: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_OKTA_PASSWORD }}
CYPRESS_APPSMITH_OAUTH2_OIDC_DIRECT_URL: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_DIRECT_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
RUNID: ${{ github.run_id }}
ATTEMPT_NUMBER: ${{ github.run_attempt }}
REPOSITORY: ${{ github.repository }}
COMMITTER: ${{ env.COMMIT_INFO_AUTHOR }}
TAG: ${{ github.event_name }}
BRANCH: ${{ env.COMMIT_INFO_BRANCH }}
THIS_RUNNER: ${{ strategy.job-index }}
TOTAL_RUNNERS: ${{ strategy.job-total }}
CYPRESS_RERUN: ${{steps.run_result.outputs.rerun}}
CYPRESS_DB_USER: ${{ secrets.CYPRESS_DB_USER }}
CYPRESS_DB_HOST: ${{ secrets.CYPRESS_DB_HOST }}
CYPRESS_DB_NAME: ${{ secrets.CYPRESS_DB_NAME }}
CYPRESS_DB_PWD: ${{ secrets.CYPRESS_DB_PWD }}
CYPRESS_S3_ACCESS: ${{ secrets.CYPRESS_S3_ACCESS }}
CYPRESS_S3_SECRET: ${{ secrets.CYPRESS_S3_SECRET }}
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/Sanity/Datasources/Airtable_Basic_Spec.ts
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 }}
- name: Rename reports
if: failure()
run: |
mkdir -p ~/results
mv ${{ github.workspace }}/app/client/results ~/results/${{ matrix.job }}
- name: Upload cypress report
if: failure()
uses: actions/upload-artifact@v3
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: results-${{github.run_attempt}}
path: ~/results
- name: Upload cypress snapshots
if: failure()
uses: actions/upload-artifact@v3
with:
name: snapshots
path: ${{ github.workspace }}/app/client/cypress/snapshots
# Set status = failedtest
- name: Set fail if there are test failures
@ -382,27 +280,6 @@ jobs:
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()
@ -411,16 +288,6 @@ jobs:
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 "url=${{ steps.cypress_test.outputs.resultsUrl }}" >> $GITHUB_OUTPUT
elif [[ "${{steps.run_result.outputs.run_result }}" == "failedtest" ]]; then
echo "url=${{ steps.cypress_test_failedtest.outputs.resultsUrl }}" >> $GITHUB_OUTPUT
fi
- name: Generate slack message
continue-on-error: true
@ -428,11 +295,13 @@ jobs:
id: slack_notification
run: |
if [[ "${{ steps.test_status.outputs.run_result }}" == "failedtest" ]]; then
echo "slack_message=There are test failures in the run. Please check the <${{ steps.dashboard_url.outputs.url }}|Cypress dashboard> for more details." >> $GITHUB_OUTPUT
echo "slack_message=There are test failures in the run. Cypress Dashboard: <https://internal.appsmith.com/app/cypressdashboard/rundetails-64ec3df0c632e24c00764938?branch=master&workflowId=${{ github.run_id }}&attempt=${{ github.run_attempt }}&selectiontype=test&testsstatus=failed&specsstatus=fail|Click here!>" >> $GITHUB_OUTPUT
echo "slack_color=#FF0000" >> $GITHUB_OUTPUT
echo "slack_icon=:parachute:" >> $GITHUB_OUTPUT
else
echo "slack_message=All tests passed successfully :tada: . Cypress Dashboard: <${{ steps.dashboard_url.outputs.url }}|Click here!>" >> $GITHUB_OUTPUT
echo "slack_message=All tests passed successfully :tada: . Cypress Dashboard: <https://internal.appsmith.com/app/cypressdashboard/rundetails-64ec3df0c632e24c00764938?branch=master&workflowId=${{ github.run_id }}&attempt=${{ github.run_attempt }}|Click here!>" >> $GITHUB_OUTPUT
echo "slack_color=#00FF00" >> $GITHUB_OUTPUT
echo "slack_icon=:eight_spoked_asterisk:" >> $GITHUB_OUTPUT
fi
- name: Slack Notification
@ -442,21 +311,13 @@ jobs:
env:
SLACK_CHANNEL: cypresspushworkflow
SLACK_COLOR: ${{steps.slack_notification.outputs.slack_color}}
SLACK_ICON_EMOJI: ':bell:'
SLACK_ICON_EMOJI: ${{steps.slack_notification.outputs.slack_icon}}
SLACK_MESSAGE: ${{steps.slack_notification.outputs.slack_message}}
SLACK_TITLE: 'Result:'
SLACK_USERNAME: Cloud-Hosted Tests
SLACK_TITLE: "Result:"
SLACK_USERNAME: Cloud Hosted Run
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_HOSTED }}
MSG_MINIMAL: Ref,Event,Commit
SLACK_FOOTER: 'Appsmith CI runs'
# 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
SLACK_FOOTER: "Hosted run"
# Set status = success
- name: Save the status of the run

View File

@ -3,6 +3,22 @@ name: Appsmith CI run limited Tests Workflow
on:
# This line enables manual triggering of this workflow.
workflow_dispatch:
inputs:
pr:
description: "PR number"
required: false
type: number
default: 0
previous-workflow-run-id:
description: "Workflow ID (To Download cicontainer)"
required: false
type: number
default: 0
matrix:
description: "Matrix jobs"
required: false
type: string
default: "[0, 1, 2]"
workflow_call:
inputs:
pr:
@ -55,6 +71,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
@ -89,46 +111,28 @@ jobs:
id: run_result
run: |
run_result_env=$(cat ~/run_result)
echo "::set-output name=run_result::$run_result_env"
# 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: combined_failed_spec_ci
path: ~/combined_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 < ~/combined_failed_spec_ci/combined_failed_spec_ci
echo "EOF" >> $GITHUB_ENV
echo "run_result=$run_result_env" >> $GITHUB_OUTPUT
if [[ "$run_result_env" == "failedtest" ]]; then
echo "rerun=true" >> $GITHUB_OUTPUT
else
echo "rerun=false" >> $GITHUB_OUTPUT
fi
# Get specs to run
- name: Get specs to run
if: steps.run_result.outputs.run_result != 'success'
if: steps.run_result.outputs.run_result != 'success' && steps.run_result.outputs.run_result != 'failedtest'
run: |
echo "specs_to_run<<EOF" >> $GITHUB_ENV
specs_to_run=""
while IFS= read -r line
do
if [[ $line =~ ^#|^\/\/ ]]; then
continue
else
echo "$line" >> $GITHUB_ENV
specs_to_run="$specs_to_run,$line"
fi
done < app/client/cypress/limited-tests.txt
echo "EOF" >> $GITHUB_ENV
specs_to_run=${specs_to_run#,}
echo "specs_to_run=$specs_to_run" >> $GITHUB_ENV
# In case of run-id provided download the artifact from the previous run
- name: Download Docker image artifact
@ -166,6 +170,36 @@ jobs:
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 \
-e FLAGSMITH_URL=http://host.docker.internal:5001/flagsmith \
-e FLAGSMITH_SERVER_KEY=dummykey \
-e FLAGSMITH_SERVER_KEY_BUSINESS_FEATURES=dummykeybusinessfeatures \
appsmith/cloud-services:release
cd cicontainerlocal
docker run -d --name appsmith -p 80:80 -p 9001:9001 \
-v "$PWD/stacks:/appsmith-stacks" \
@ -201,50 +235,6 @@ jobs:
- 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
@ -256,12 +246,6 @@ jobs:
- run: |
echo "BROWSER_PATH=$(which chrome)" >> $GITHUB_ENV
# - name: Set Pull Request Title
# env:
# EVENT_COMMITS: ${{ toJson(github.event.commits[0].message) }}
# run: |
# echo "test: Cypress (#24586)\n\n## Description\r\n- This PR adds the No Error toast to NavigateBacktoEditor() which\r\nsometimes results in Edit page not being load in CI runs" | awk -F '\\\\n' '{sub(/.*#/, "#", $1); sub(/).*/, "", $1); print $1}'
- name: Save Git values
# pass env variables from this step to other steps
# using GitHub Actions environment file
@ -296,17 +280,17 @@ jobs:
elif [[ ${{ inputs.pr }} -ne 0 && ${{github.event_name}} == 'workflow_dispatch' ]]; then
echo "COMMIT_INFO_MESSAGE=Workflow run on PR# ${{ inputs.pr }}" >> $GITHUB_ENV
else
echo "COMMIT_INFO_MESSAGE=$(echo \"${{ env.EVENT_COMMITS }}\" | awk -F '\\\\n' '{print $1}' | sed 's/^\"//')" >> $GITHUB_ENV
if [[ '${{env.EVENT_COMMITS}}' == 'null' ]]; then
echo "COMMIT_INFO_MESSAGE=${{ github.event_name }} by ${{ env.COMMIT_INFO_AUTHOR }}" >> $GITHUB_ENV
else
echo "COMMIT_INFO_MESSAGE=$(echo \"${{ env.EVENT_COMMITS }}\" | awk -F '\\\\n' '{print $1}' | sed 's/^\"//')" >> $GITHUB_ENV
fi
fi
- name: Run the cypress test
id: cypress_test
if: steps.run_result.outputs.run_result != 'success' && steps.run_result.outputs.run_result != 'failedtest'
uses: cypress-io/github-action@v5
uses: cypress-io/github-action@v6
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 }}
@ -321,6 +305,10 @@ jobs:
CYPRESS_S3_SECRET_KEY: ${{ secrets.CYPRESS_S3_SECRET_KEY }}
CYPRESS_GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
CYPRESS_AIRTABLE_BEARER: ${{ secrets.AIRTABLE_BEARER }}
CYPRESS_ORACLE_HOST: ${{ secrets.ORACLE_HOST }}
CYPRESS_ORACLE_SERVICE: ${{ secrets.ORACLE_SERVICE }}
CYPRESS_ORACLE_USERNAME: ${{ secrets.ORACLE_USERNAME }}
CYPRESS_ORACLE_PASSWORD: ${{ secrets.ORACLE_PASSWORD }}
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 }}
@ -341,86 +329,56 @@ jobs:
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_APPSMITH_OAUTH2_OIDC_OKTA_PASSWORD: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_OKTA_PASSWORD }}
CYPRESS_APPSMITH_OAUTH2_OIDC_DIRECT_URL: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_DIRECT_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 }}
POSTGRES_PASSWORD: postgres
CYPRESS_VERIFY_TIMEOUT: 100000
COMMIT_INFO_MESSAGE: ${{ env.COMMIT_INFO_MESSAGE }}
RUNID: ${{ github.run_id }}
ATTEMPT_NUMBER: ${{ github.run_attempt }}
REPOSITORY: ${{ github.repository }}
COMMITTER: ${{ env.COMMIT_INFO_AUTHOR }}
TAG: ${{ github.event_name }}
BRANCH: ${{ env.COMMIT_INFO_BRANCH }}
THIS_RUNNER: ${{ strategy.job-index }}
CYPRESS_SPECS: ${{ env.specs_to_run }}
CYPRESS_RERUN: ${{steps.run_result.outputs.rerun}}
CYPRESS_DB_USER: ${{ secrets.CYPRESS_DB_USER }}
CYPRESS_DB_HOST: ${{ secrets.CYPRESS_DB_HOST }}
CYPRESS_DB_NAME: ${{ secrets.CYPRESS_DB_NAME }}
CYPRESS_DB_PWD: ${{ secrets.CYPRESS_DB_PWD }}
CYPRESS_S3_ACCESS: ${{ secrets.CYPRESS_S3_ACCESS }}
CYPRESS_S3_SECRET: ${{ secrets.CYPRESS_S3_SECRET }}
with:
browser: ${{ env.BROWSER_PATH }}
record: true
install: false
parallel: true
config-file: cypress_ci.config.ts
group: "Chrome-Fat Container tests"
config-file: cypress_ci_custom.config.ts
spec: ${{ env.specs_to_run }}
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
id: cypress_test_failedtest
if: steps.run_result.outputs.run_result == '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 }}
CYPRESS_VERIFY_TIMEOUT: 100000
- name: Trim number of cypress log files
if: failure()
run: |
find ${{ github.workspace }}/app/client/cypress/cypress-logs -name '*.json' -type f | tail -n +11 | xargs -I {} rm -- {}
- name: Upload failed test cypress logs artifact
if: failure()
uses: actions/upload-artifact@v3
with:
browser: ${{ env.BROWSER_PATH }}
record: true
install: false
parallel: true
config-file: cypress_ci.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: cypress-console-logs
path: ${{ github.workspace }}/app/client/cypress/cypress-logs
- name: Upload cypress snapshots
if: always()
uses: actions/upload-artifact@v3
with:
name: snapshots
path: ${{ github.workspace }}/app/client/cypress/snapshots
- name: Collect CI container logs
if: failure()
@ -437,35 +395,25 @@ jobs:
name: dockerlogs
path: ~/dockerlogs
- name: Rename reports
if: failure()
run: |
mkdir -p ~/results
mv ${{ github.workspace }}/app/client/results ~/results/${{ matrix.job }}
- name: Upload cypress report
if: failure()
uses: actions/upload-artifact@v3
with:
name: results-${{github.run_attempt}}
path: ~/results
# Set status = failedtest
- name: Set fail if there are test failures
if: failure()
run: |
echo "::set-output name=run_result::failedtest"
echo "failedtest" > ~/run_result
# Create a directory ~/failed_spec_ci and add a dummy file
# This will ensure upload and download steps are successful
- name: Create directory for failed tests
if: always()
run: |
mkdir -p ~/failed_spec_ci-${{github.run_attempt}}
# 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-${{github.run_attempt}}/failed_spec_ci-${{ matrix.job }}
# Upload failed test list using common path for all matrix job
- name: Upload failed test list artifact
if: failure()
uses: actions/upload-artifact@v3
with:
name: failed-spec-ci-${{github.run_attempt}}
path: ~/failed_spec_ci-${{github.run_attempt}}
# Force store previous run result to cache
- name: Store the previous run result
if: failure()
@ -485,25 +433,6 @@ jobs:
name: server-logs-${{ matrix.job }}
path: app/server/server-logs.log
- 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
# Force store previous run result to cache
- name: Store the previous run result
if: success()
uses: actions/cache/save@v3
with:
path: |
~/cypress_url
key: ${{ github.run_id }}-dashboard-url-${{ github.run_attempt }}
# Set status = success
- name: Save the status of the run
run: |

View File

@ -0,0 +1,627 @@
name: Appsmith CI Test (with DocumentDB) Workflow
on:
# This line enables manual triggering of this workflow.
workflow_dispatch:
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'
defaults:
run:
shell: bash
strategy:
fail-fast: false
matrix:
job:
[
0,
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25,
26,
27,
28,
29,
30,
31,
32,
33,
34,
35,
36,
37,
38,
39,
40,
41,
42,
43,
44,
45,
46,
47,
48,
49,
50,
51,
52,
53,
54,
55,
56,
57,
58,
59,
]
# 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
- 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
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
# 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 }}-${{ matrix.job }}
restore-keys: |
${{ github.run_id }}-${{ github.job }}-${{ matrix.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
- if: steps.run_result.outputs.run_result == 'failedtest'
run: echo "failed_spec_artifact=failed-spec-ci-$((${{github.run_attempt}}-1))" >> $GITHUB_ENV
- name: Restore the previous failed combine result
if: steps.run_result.outputs.run_result == 'failedtest'
uses: actions/download-artifact@v3
with:
name: ${{ env.failed_spec_artifact }}
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: |
failed_spec_env=""
while IFS= read -r line || [ -n "$line" ]; do
file_path=$(echo "$line" | awk -F'/' '{print $(NF-1)"/"$NF}')
spec_name=$(echo "$file_path" | awk -F'/' '{print $NF}')
failed_spec=$(find . -name "$spec_name" | sed 's|./||')
if [ "$(echo "$failed_spec" | wc -l)" -eq 1 ]; then
failed_spec_env="$failed_spec_env,$failed_spec"
else
for file in $failed_spec; do
new_file_path=$(echo "$file" | awk -F'/' '{print $(NF-1)"/"$NF}')
if [ "$new_file_path" == "$file_path" ]; then
failed_spec_env="$failed_spec_env,$file"
fi
done
fi
done < ~/failed_spec_ci/failed_spec_ci-${{ matrix.job }}
failed_spec_env=${failed_spec_env#,}
echo "failed_spec_env=$failed_spec_env" >> $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: Setup mongodb-tools
run: |
wget https://fastdl.mongodb.org/tools/db/mongodb-database-tools-ubuntu2204-x86_64-100.6.1.deb
sudo apt install ./mongodb-database-tools-*-100.6.1.deb
- name: Download mongodb archive
run: |
curl -o data.gz https://appsmithctl-backup-restore-test.s3.ap-south-1.amazonaws.com/docdb-data.gz
- name: Download Docker image artifact
uses: actions/download-artifact@v3
with:
name: cicontainer
- name: Load Docker image from tar file
run: |
gunzip cicontainer.tar.gz
docker load -i cicontainer.tar
- name: Create folder
if: steps.run_result.outputs.run_result != 'success'
working-directory: "."
run: |
mkdir -p cicontainerlocal/stacks/configuration/
- name: Set up SSH key for tunnel
env:
SSH_PRIVATE_KEY: ${{ secrets.APPSMITH_CI_TUNNEL_PRIVATE_KEY }}
run: |
echo "$SSH_PRIVATE_KEY" > ssh_key.pem
chmod 400 ssh_key.pem
- name: Setup SSH tunnel to AWS DocumentDB instance
run: |
chmod 400 ssh_key.pem
ssh -4 -o StrictHostKeyChecking=no -o ServerAliveInterval=180 -o ServerAliveCountMax=5 -i "ssh_key.pem" -L 0.0.0.0:27010:docdb-ansible-test-cluster.cluster-cz8diybf9wdj.ap-south-1.docdb.amazonaws.com:27017 ubuntu@65.1.106.35 -N -f
- name: Run Appsmith, CS & TED docker image
if: steps.run_result.outputs.run_result != 'success'
working-directory: "."
env:
APPSMITH_MONGODB_URI: ${{ secrets.INTERNAL_CI_DOC_DB_URI }}
run: |
timestamp=$(date +%Y%m%d%H%M%S)
hash=$(hostname)
random=$(shuf -i 1000-9999 -n 1)
DB_NAME="${timestamp}-${hash}-${random}"
echo "DB_NAME: ${DB_NAME}"
MONGO_CREDS=$(echo $APPSMITH_MONGODB_URI | sed 's/@.*//')
URI="${MONGO_CREDS}@localhost:27010/${DB_NAME}?retryWrites=false&replicaSet=rs0&directConnection=true"
mongorestore --uri="${URI}" --archive=data.gz --gzip --drop --nsInclude "doc-db-base.*" --nsFrom "doc-db-base.*" --nsTo "${DB_NAME}.*"
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 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_MONGODB_URI="${APPSMITH_MONGODB_URI}${DB_NAME}?retryWrites=false&replicaSet=rs0&directConnection=true" \
--add-host=host.docker.internal:host-gateway --add-host=api.segment.io:host-gateway --add-host=t.appsmith.com:host-gateway \
cicontainer
- name: Use Node.js
if: steps.run_result.outputs.run_result != 'success'
uses: actions/setup-node@v3
with:
node-version-file: app/client/package.json
# actions/setup-node@v3 doesnt 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: Wait until appsmith server is healthy
run: |
bash scripts/health_check.sh
- name: Setting up the cypress tests
if: steps.run_result.outputs.run_result != 'success'
shell: bash
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: 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 [[ ${{ inputs.pr }} -ne 0 ]]; then
echo "COMMIT_INFO_MESSAGE=${{ env.COMMIT_INFO_MESSAGE }}" >> $GITHUB_ENV
else
if [[ '${{env.EVENT_COMMITS}}' == 'null' ]]; then
echo "COMMIT_INFO_MESSAGE=${{ github.event_name }} by ${{ env.COMMIT_INFO_AUTHOR }}" >> $GITHUB_ENV
else
echo "COMMIT_INFO_MESSAGE=$(echo \"${{ env.EVENT_COMMITS }}\" | awk -F '\\\\n' '{print $1}' | sed 's/^\"//')" >> $GITHUB_ENV
fi
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_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_ORACLE_HOST: ${{ secrets.ORACLE_HOST }}
CYPRESS_ORACLE_SERVICE: ${{ secrets.ORACLE_SERVICE }}
CYPRESS_ORACLE_USERNAME: ${{ secrets.ORACLE_USERNAME }}
CYPRESS_ORACLE_PASSWORD: ${{ secrets.ORACLE_PASSWORD }}
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_APPSMITH_OAUTH2_OIDC_OKTA_PASSWORD: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_OKTA_PASSWORD }}
CYPRESS_APPSMITH_OAUTH2_OIDC_DIRECT_URL: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_DIRECT_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
TOTAL_RUNNERS: ${{ strategy.job-total }}
THIS_RUNNER: ${{ strategy.job-index }}
CYPRESS_SPEC_PATTERN: "cypress/e2e/**/**/*"
CYPRESS_ENV: "NODE_ENV=development"
CYPRESS_CONFIG_FILE: cypress_ci_custom.config.ts
CYPRESS_HEADLESS: "true"
CYPRESS_BROWSER: ${{ env.BROWSER_PATH }}
RUNID: ${{ github.run_id }}
ATTEMPT_NUMBER: ${{ github.run_attempt }}
REPOSITORY: ${{ github.repository }}
COMMITTER: ${{ env.COMMIT_INFO_AUTHOR }}
TAG: ${{ github.event_name }}
BRANCH: ${{ env.COMMIT_INFO_BRANCH }}
CYPRESS_DB_USER: ${{ secrets.CYPRESS_DB_USER }}
CYPRESS_DB_HOST: ${{ secrets.CYPRESS_DB_HOST }}
CYPRESS_DB_NAME: ${{ secrets.CYPRESS_DB_NAME }}
CYPRESS_DB_PWD: ${{ secrets.CYPRESS_DB_PWD }}
CYPRESS_S3_ACCESS: ${{ secrets.CYPRESS_S3_ACCESS }}
CYPRESS_S3_SECRET: ${{ secrets.CYPRESS_S3_SECRET }}
with:
install: false
working-directory: app/client
command: yarn ts-node --require esm cypress/cypress-split.ts
# 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_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_ORACLE_HOST: ${{ secrets.ORACLE_HOST }}
CYPRESS_ORACLE_SERVICE: ${{ secrets.ORACLE_SERVICE }}
CYPRESS_ORACLE_USERNAME: ${{ secrets.ORACLE_USERNAME }}
CYPRESS_ORACLE_PASSWORD: ${{ secrets.ORACLE_PASSWORD }}
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_APPSMITH_OAUTH2_OIDC_OKTA_PASSWORD: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_OKTA_PASSWORD }}
CYPRESS_APPSMITH_OAUTH2_OIDC_DIRECT_URL: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_DIRECT_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_ENV: "NODE_ENV=development"
CYPRESS_CONFIG_FILE: cypress_ci.config.ts
CYPRESS_HEADLESS: "true"
CYPRESS_BROWSER: ${{ env.BROWSER_PATH }}
RUNID: ${{ github.run_id }}
ATTEMPT_NUMBER: ${{ github.run_attempt }}
REPOSITORY: ${{ github.repository }}
COMMITTER: ${{ env.COMMIT_INFO_AUTHOR }}
TAG: ${{ github.event_name }}
BRANCH: ${{ env.COMMIT_INFO_BRANCH }}
THIS_RUNNER: ${{ strategy.job-index }}
CYPRESS_DB_USER: ${{ secrets.CYPRESS_DB_USER }}
CYPRESS_DB_HOST: ${{ secrets.CYPRESS_DB_HOST }}
CYPRESS_DB_NAME: ${{ secrets.CYPRESS_DB_NAME }}
CYPRESS_DB_PWD: ${{ secrets.CYPRESS_DB_PWD }}
CYPRESS_S3_ACCESS: ${{ secrets.CYPRESS_S3_ACCESS }}
CYPRESS_S3_SECRET: ${{ secrets.CYPRESS_S3_SECRET }}
with:
install: false
working-directory: app/client
command: yarn cypress run --browser ${{ env.BROWSER_PATH }} --config-file cypress_ci_custom.config.ts --spec ${{ env.failed_spec_env }}
- name: Collect CI container logs
if: failure()
working-directory: "."
run: |
mkdir -p ~/dockerlogs
docker logs appsmith 2>&1 > ~/dockerlogs/dockerlogs-${{ matrix.job }}.txt
# Upload docker logs
- name: Upload failed test list artifact
if: failure()
uses: actions/upload-artifact@v3
with:
name: dockerlogs
path: ~/dockerlogs
- name: Rename reports
if: always()
run: |
mkdir -p ~/results
mv ${{ github.workspace }}/app/client/results ~/results/${{ matrix.job }}
- name: Upload cypress report
if: always()
uses: actions/upload-artifact@v3
with:
name: results-${{github.run_attempt}}
path: ~/results
# Set status = failedtest
- name: Set fail if there are test failures
if: failure()
run: |
echo "run_result=failedtest" >> $GITHUB_OUTPUT
echo "failedtest" > ~/run_result
# Create a directory ~/failed_spec_ci and add a dummy file
# This will ensure upload and download steps are successful
- name: Create directory for failed tests
if: always()
run: |
mkdir -p ~/failed_spec_ci-${{github.run_attempt}}
# 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-${{github.run_attempt}}/failed_spec_ci-${{ matrix.job }}
# Upload failed test list using common path for all matrix job
- name: Upload failed test list artifact
if: failure()
uses: actions/upload-artifact@v3
with:
name: failed-spec-ci-${{github.run_attempt}}
path: ~/failed_spec_ci-${{github.run_attempt}}
# 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 }}-${{ matrix.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 "" >> ~/cypress_url
# elif [[ "${{steps.run_result.outputs.run_result }}" == "failedtest" ]]; then
# echo "" >> ~/cypress_url
# fi
# Force store previous run result to cache
- name: Store the previous run result
if: success()
uses: actions/cache/save@v3
with:
path: |
~/cypress_url
key: ${{ github.run_id }}-dashboard-url-${{ github.run_number }}
# 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

View File

@ -24,7 +24,7 @@ jobs:
strategy:
fail-fast: false
matrix:
job: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59]
job: [0]
# Service containers to run with this job. Required for running tests
services:
@ -178,6 +178,9 @@ jobs:
-e ENTERPRISE_USER_PASSWORD=ent_user_password \
-e ENTERPRISE_ADMIN_NAME=ent-admin@appsmith.com \
-e ENTERPRISE_ADMIN_PASSWORD=ent_admin_password \
-e FLAGSMITH_URL=http://host.docker.internal:5001/flagsmith \
-e FLAGSMITH_SERVER_KEY=dummykey \
-e FLAGSMITH_SERVER_KEY_BUSINESS_FEATURES=dummykeybusinessfeatures \
appsmith/cloud-services:release
cd cicontainerlocal
docker run -d --name appsmith -p 80:80 -p 9001:9001 \
@ -217,50 +220,6 @@ jobs:
- 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
@ -311,7 +270,11 @@ jobs:
if [[ ${{ inputs.pr }} -ne 0 ]]; then
echo "COMMIT_INFO_MESSAGE=${{ env.COMMIT_INFO_MESSAGE }}" >> $GITHUB_ENV
else
echo "COMMIT_INFO_MESSAGE=$(echo \"${{ env.EVENT_COMMITS }}\" | awk -F '\\\\n' '{print $1}' | sed 's/^\"//')" >> $GITHUB_ENV
if [[ '${{env.EVENT_COMMITS}}' == 'null' ]]; then
echo "COMMIT_INFO_MESSAGE=${{ github.event_name }} by ${{ env.COMMIT_INFO_AUTHOR }}" >> $GITHUB_ENV
else
echo "COMMIT_INFO_MESSAGE=$(echo \"${{ env.EVENT_COMMITS }}\" | awk -F '\\\\n' '{print $1}' | sed 's/^\"//')" >> $GITHUB_ENV
fi
fi
- name: Run the cypress test
@ -362,6 +325,19 @@ jobs:
APPSMITH_GOOGLE_MAPS_API_KEY: ${{ secrets.APPSMITH_GOOGLE_MAPS_API_KEY }}
COMMIT_INFO_MESSAGE: ${{ env.COMMIT_INFO_MESSAGE }}
CYPRESS_VERIFY_TIMEOUT: 100000
RUNID: ${{ github.run_id }}
ATTEMPT_NUMBER: ${{ github.run_attempt }}
REPOSITORY: ${{ github.repository }}
COMMITTER: ${{ env.COMMIT_INFO_AUTHOR }}
TAG: ${{ github.event_name }}
BRANCH: ${{ env.COMMIT_INFO_BRANCH }}
THIS_RUNNER: ${{ strategy.job-index }}
CYPRESS_DB_USER: ${{ secrets.CYPRESS_DB_USER }}
CYPRESS_DB_HOST: ${{ secrets.CYPRESS_DB_HOST }}
CYPRESS_DB_NAME: ${{ secrets.CYPRESS_DB_NAME }}
CYPRESS_DB_PWD: ${{ secrets.CYPRESS_DB_PWD }}
CYPRESS_S3_ACCESS: ${{ secrets.CYPRESS_S3_ACCESS }}
CYPRESS_S3_SECRET: ${{ secrets.CYPRESS_S3_SECRET }}
with:
browser: ${{ env.BROWSER_PATH }}
record: true
@ -441,6 +417,19 @@ jobs:
APPSMITH_DISABLE_TELEMETRY: true
APPSMITH_GOOGLE_MAPS_API_KEY: ${{ secrets.APPSMITH_GOOGLE_MAPS_API_KEY }}
COMMIT_INFO_MESSAGE: ${{ env.COMMIT_INFO_MESSAGE }}
RUNID: ${{ github.run_id }}
ATTEMPT_NUMBER: ${{ github.run_attempt }}
REPOSITORY: ${{ github.repository }}
COMMITTER: ${{ env.COMMIT_INFO_AUTHOR }}
TAG: ${{ github.event_name }}
BRANCH: ${{ env.COMMIT_INFO_BRANCH }}
THIS_RUNNER: ${{ strategy.job-index }}
CYPRESS_DB_USER: ${{ secrets.CYPRESS_DB_USER }}
CYPRESS_DB_HOST: ${{ secrets.CYPRESS_DB_HOST }}
CYPRESS_DB_NAME: ${{ secrets.CYPRESS_DB_NAME }}
CYPRESS_DB_PWD: ${{ secrets.CYPRESS_DB_PWD }}
CYPRESS_S3_ACCESS: ${{ secrets.CYPRESS_S3_ACCESS }}
CYPRESS_S3_SECRET: ${{ secrets.CYPRESS_S3_SECRET }}
with:
browser: ${{ env.BROWSER_PATH }}
record: true
@ -507,15 +496,15 @@ jobs:
~/run_result
key: ${{ github.run_id }}-${{ github.job }}-${{ matrix.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
# - 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
# Force store previous run result to cache
- name: Store the previous run result

View File

@ -1,6 +1,7 @@
name: Cleanup Deploy Previews
on:
workflow_dispatch:
schedule:
- cron: 0 0 * * *

View File

@ -21,7 +21,11 @@ on:
description: "This is the branch to be used for the build."
required: false
type: string
ads-compliant-check:
description: "This is a boolean value in case the workflow is being called in build deploy-preview"
required: false
type: string
default: "true"
# Change the working directory for all the jobs in this workflow
defaults:
@ -76,7 +80,7 @@ jobs:
uses: umani/changed-files@v4.0.0
with:
repo-token: ${{ secrets.APPSMITH_CI_TEST_PAT }}
pattern: 'app/client/cypress/e2e/.*'
pattern: "app/client/cypress/e2e/.*"
pr-number: ${{ inputs.pr }}
# Check all the newly added files are in ts
@ -107,6 +111,46 @@ jobs:
- if: steps.check_files.outputs.non_ts_files_count != 0 && inputs.check-test-files == 'true' && inputs.pr != 0
run: exit 1
- name: Get all the added or changed files in client/src folder
if: inputs.ads-compliant-check == 'true' && inputs.pr != 0 && github.pull_request.base.ref == 'release'
id: client_files
uses: umani/changed-files@v4.0.0
with:
repo-token: ${{ secrets.APPSMITH_CI_TEST_PAT }}
pattern: "app/client/src/.*"
pr-number: ${{ inputs.pr }}
# Check all the newly added files are in ts
- name: ADS compliant check
if: inputs.ads-compliant-check == 'true' && inputs.pr != 0 && github.pull_request.base.ref == 'release'
id: ads_check
run: |
comment_files=""
files=(${{steps.client_files.outputs.files_created}}${{steps.client_files.outputs.files_updated}})
for file in "${files[@]}"; do
while IFS= read -r line; do
if echo "$line" | grep -q -E '(color|Color).*#|border.*#|(color|Color).*"'; then
comment_files+=("$file")
break
fi
done < ${file#app/client/}
done
unique_files=$(echo "${comment_files[@]}" | sort -u | sed '/^[[:space:]]*$/d' | sed 's/ / <li>/g')
echo "ads_non_compliant_files=$unique_files" >> $GITHUB_OUTPUT
echo "ads_non_compliant_count=${#unique_files[@]}" >> $GITHUB_OUTPUT
# Comment in PR if test files are not written in ts and fail the workflow
- name: Comment in PR if test files are not written in ts
if: steps.ads_check.outputs.ads_non_compliant_count != 0 && inputs.ads-compliant-check == 'true' && inputs.pr != 0 && github.pull_request.base.ref == 'release'
uses: peter-evans/create-or-update-comment@v1
with:
issue-number: ${{ inputs.pr }}
body: |
<b> 🔴 Below files are not compliant with ADS. Please fix and re-trigger ok-to-test </b>
<ol>${{steps.ads_check.outputs.ads_non_compliant_files}}</ol>
- if: steps.ads_check.outputs.ads_non_compliant_count != 0 && inputs.ads-compliant-check == 'true' && inputs.pr != 0 && github.pull_request.base.ref == 'release'
run: exit 1
# Create a run record exactly at the time of merge to release to
# ensure we compare run details with code at this point
- name: Create Perf Meta

57
.github/workflows/docker-base-image.yml vendored Normal file
View File

@ -0,0 +1,57 @@
name: Docker Base Image
on:
workflow_dispatch:
schedule:
- cron: "0 5 * * MON"
push:
branches:
- release
- master
paths:
- "deploy/docker/base.dockerfile"
jobs:
build-docker:
runs-on: ubuntu-latest
defaults:
run:
shell: bash
steps:
- name: Checkout the head commit of the branch
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Login to DockerHub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Get tag
id: tag
run: |
tag="${GITHUB_REF_NAME//\//-}"
if [[ "$tag" == master ]]; then
tag=nightly
fi
echo "tag=$tag" >> "$GITHUB_OUTPUT"
- name: Build and push base image
uses: docker/build-push-action@v5
with:
context: .
file: deploy/docker/base.dockerfile
push: true
platforms: linux/arm64,linux/amd64
tags: |
${{ vars.DOCKER_HUB_ORGANIZATION }}/base-${{ vars.EDITION }}:${{ steps.tag.outputs.tag }}

View File

@ -269,6 +269,12 @@ jobs:
echo "Cleaning up the tar files"
rm app/client/packages/rts/dist/rts-dist.tar
- name: Generate info.json
run: |
if [[ -f scripts/generate_info_json.sh ]]; then
scripts/generate_info_json.sh
fi
- name: Login to DockerHub
uses: docker/login-action@v1
with:
@ -283,6 +289,7 @@ jobs:
platforms: linux/arm64,linux/amd64
build-args: |
APPSMITH_SEGMENT_CE_KEY=${{ secrets.APPSMITH_SEGMENT_CE_KEY }}
BASE=${{ vars.DOCKER_HUB_ORGANIZATION }}/base-${{ vars.EDITION }}:nightly
tags: |
${{ vars.DOCKER_HUB_ORGANIZATION }}/appsmith-${{ vars.EDITION }}:${{needs.prelude.outputs.tag}}
@ -296,5 +303,6 @@ jobs:
platforms: linux/arm64,linux/amd64
build-args: |
APPSMITH_SEGMENT_CE_KEY=${{ secrets.APPSMITH_SEGMENT_CE_KEY }}
BASE=${{ vars.DOCKER_HUB_ORGANIZATION }}/base-${{ vars.EDITION }}:nightly
tags: |
${{ vars.DOCKER_HUB_ORGANIZATION }}/appsmith-${{ vars.EDITION }}:latest

View File

@ -3,7 +3,7 @@ name: Appsmith External Integration Test Workflow
on:
# This workflow is only triggered by the ok to test command dispatch
repository_dispatch:
types: [ ok-to-test-command ]
types: [ok-to-test-command]
jobs:
notify:
@ -19,8 +19,7 @@ jobs:
Workflow: `${{ github.workflow }}`.
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}}>
server-build:
name: server-build
uses: ./.github/workflows/server-build.yml
@ -52,7 +51,7 @@ jobs:
pr: ${{ github.event.client_payload.pull_request.number }}
build-docker-image:
needs: [ client-build, server-build, rts-build ]
needs: [client-build, server-build, rts-build]
# Only run if the build step is successful
if: success()
name: build-docker-image
@ -62,27 +61,17 @@ jobs:
pr: ${{ github.event.client_payload.pull_request.number }}
ci-test:
needs: [ build-docker-image ]
needs: [build-docker-image]
# Only run if the build step is successful
if: success()
name: ci-test
uses: ./.github/workflows/ci-test.yml
secrets: inherit
with:
pr: ${{ github.event.client_payload.pull_request.number }}
perf-test:
needs: [ build-docker-image ]
# Only run if the build step is successful
if: success()
name: perf-test
uses: ./.github/workflows/perf-test.yml
uses: ./.github/workflows/ci-test-custom-script.yml
secrets: inherit
with:
pr: ${{ github.event.client_payload.pull_request.number }}
ci-test-result:
needs: [ci-test, perf-test ]
needs: [ci-test]
# Only run if the ci-test with matrices step is successful
if: always()
runs-on: ubuntu-latest
@ -95,54 +84,69 @@ jobs:
PAYLOAD_CONTEXT: ${{ toJson(github.event.client_payload) }}
run: echo "$PAYLOAD_CONTEXT"
# Deleting the existing dir's if any
- name: Delete existing directories
- name: Setup node
if: needs.ci-test.result != 'success'
run: |
rm -f ~/failed_spec_ci
rm -f ~/combined_failed_spec_ci
# Force store previous cypress dashboard url from cache
- name: Store the previous cypress dashboard url
continue-on-error: true
if: success()
uses: actions/cache@v3
uses: actions/setup-node@v3
with:
path: |
~/cypress_url
key: ${{ github.run_id }}-dashboard-url-${{ github.run_attempt }}
restore-keys: |
${{ github.run_id }}-dashboard-url
node-version: 18
- name: Print cypress dashboard url
continue-on-error: true
id: dashboard_url
run: |
cypress_url=$(cat ~/cypress_url)
echo "dashboard_url=$cypress_url" >> $GITHUB_OUTPUT
# Download failed_spec list for all jobs
- uses: actions/download-artifact@v3
- name: install pg
if: needs.ci-test.result != 'success'
id: download_ci
run: npm install pg
- name: Fetch the failed specs
if: needs.ci-test.result != 'success'
id: failed_specs
env:
DB_HOST: ${{ secrets.CYPRESS_DB_HOST }}
DB_NAME: ${{ secrets.CYPRESS_DB_NAME }}
DB_USER: ${{ secrets.CYPRESS_DB_USER }}
DB_PWD: ${{ secrets.CYPRESS_DB_PWD }}
RUN_ID: ${{ github.run_id }}
ATTEMPT_NUMBER: ${{ github.run_attempt }}
uses: actions/github-script@v6
with:
name: failed-spec-ci-${{github.run_attempt}}
path: ~/failed_spec_ci
script: |
const { Pool } = require("pg");
const { DB_HOST, DB_NAME, DB_USER, DB_PWD, RUN_ID, ATTEMPT_NUMBER } = process.env
const client = await new Pool({
user: DB_USER,
host: DB_HOST,
database: DB_NAME,
password: DB_PWD,
port: 5432,
connectionTimeoutMillis: 60000,
}).connect();
const result = await client.query(
`SELECT DISTINCT name FROM public."specs"
WHERE "matrixId" IN
(SELECT id FROM public."matrix"
WHERE "attemptId" = (
SELECT id FROM public."attempt" WHERE "workflowId" = $1 and "attempt" = $2
)
) AND status = 'fail'`,
[RUN_ID, ATTEMPT_NUMBER],
);
client.release();
return result.rows.map((spec) => spec.name);
# In case for any ci job failure, create combined failed spec
- 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
failed_specs=$(echo ${{steps.failed_specs.outputs.result}} | sed 's/\[\|\]//g' | tr -d ' ' | tr ',' '\n')
while read -r line; do
echo "$line" >> ~/combined_failed_spec_ci
done <<< "$failed_specs"
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.
- name: upload combined failed spec
@ -157,7 +161,7 @@ jobs:
run: |
curl --request POST --url https://yatin-s-workspace-jk8ru5.us-east-1.xata.sh/db/CypressKnownFailures:main/tables/CypressKnownFailuires/query --header 'Authorization: Bearer ${{ secrets.XATA_TOKEN }}' --header 'Content-Type: application/json'|jq -r |grep Spec|cut -d ':' -f 2 2> /dev/null|sed 's/"//g'|sed 's/,//g' > ~/knownfailures
# Verify CI test failures against known failures
# Verify CI test failures against known failures
- name: Verify CI test failures against known failures
if: needs.ci-test.result != 'success'
shell: bash
@ -176,19 +180,30 @@ jobs:
body: |
Workflow run: <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}>.
Commit: `${{ github.event.client_payload.slash_command.args.named.sha }}`.
Cypress dashboard: <a href="${{ steps.dashboard_url.outputs.dashboard_url }}" target="_blank"> Click here!</a>
Cypress dashboard: <a href="https://internal.appsmith.com/app/cypressdashboard/rundetails-64ec3df0c632e24c00764938?branch=master&workflowId=${{ github.run_id }}&attempt=${{ github.run_attempt }}&selectiontype=test&testsstatus=failed&specsstatus=fail" target="_blank"> Click here!</a>
The following are new failures, please fix them before merging the PR: ${{env.new_failed_spec_env}}
To know the list of identified flaky tests - <a href="https://app.appsmith.com/applications/613868bedd7786286ddd4a6a/pages/63ec710e8e503f763651791a" target="_blank">Refer here</a>
To know the list of identified flaky tests - <a href="https://internal.appsmith.com/app/cypressdashboard/identified-flaky-tests-6541e22b0c243558fe2288ca?branch=master" target="_blank">Refer here</a>
- name: Add a comment on the PR when ci-test is success
if: needs.ci-test.result == 'success' || steps.combine_ci.outputs.specs_failed == '0'
- name: Add a comment on the PR when ci-test is failed but no specs found
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 }}
body: |
Workflow run: <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}>.
Commit: `${{ github.event.client_payload.slash_command.args.named.sha }}`.
Cypress dashboard url: <a href="${{ steps.dashboard_url.outputs.dashboard_url }}" target="_blank">Click here!</a>
Cypress dashboard url: <a href="https://internal.appsmith.com/app/cypressdashboard/rundetails-64ec3df0c632e24c00764938?branch=master&workflowId=${{ github.run_id }}&attempt=${{ github.run_attempt }}" target="_blank">Click here!</a>
It seems like there are some failures 😔. We are not able to recognize it, please check this manually <a href="${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" target="_blank">here.</a>
- name: Add a comment on the PR when ci-test is 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 }}
body: |
Workflow run: <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}>.
Commit: `${{ github.event.client_payload.slash_command.args.named.sha }}`.
Cypress dashboard url: <a href="https://internal.appsmith.com/app/cypressdashboard/rundetails-64ec3df0c632e24c00764938?branch=master&workflowId=${{ github.run_id }}&attempt=${{ github.run_attempt }}" target="_blank">Click here!</a>
All cypress tests have passed 🎉🎉🎉
# Update check run called "ci-test-result"
@ -261,11 +276,11 @@ jobs:
run: echo "$PAYLOAD_CONTEXT"
- name: Check ci-test set status
if: needs.ci-test.result != 'success' || needs.perf-test.result != 'success'
if: needs.ci-test.result != 'success'
run: exit 1
package:
needs: [ ci-test ]
needs: [ci-test]
runs-on: ubuntu-latest
defaults:
run:

View File

@ -0,0 +1,323 @@
name: Appsmith External Integration Test (with DocumentDB ) Workflow
on:
# This workflow is only triggered by the ok to test command dispatch
repository_dispatch:
types: [ok-to-test-with-documentdb-command]
jobs:
notify:
runs-on: ubuntu-latest
steps:
# This step creates a comment on the PR with a link to this workflow run.
- name: Add a comment on the PR with link to workflow run
uses: peter-evans/create-or-update-comment@v2
with:
issue-number: ${{ github.event.client_payload.pull_request.number }}
body: |
Tests running at: <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}>.
Workflow: `${{ github.workflow }}`.
Commit: `${{ github.event.client_payload.slash_command.args.named.sha }}`.
PR: ${{ github.event.client_payload.pull_request.number }}.
server-build:
name: server-build
uses: ./.github/workflows/server-build.yml
secrets: inherit
with:
pr: ${{ github.event.client_payload.pull_request.number }}
skip-tests: true
client-build:
name: client-build
uses: ./.github/workflows/client-build.yml
secrets: inherit
with:
pr: ${{ github.event.client_payload.pull_request.number }}
check-test-files: "true"
rts-build:
name: rts-build
uses: ./.github/workflows/rts-build.yml
secrets: inherit
with:
pr: ${{ github.event.client_payload.pull_request.number }}
test-appsmithctl:
name: appsmithctl
uses: ./.github/workflows/appsmithctl.yml
secrets: inherit
with:
pr: ${{ github.event.client_payload.pull_request.number }}
build-docker-image:
needs: [client-build, server-build, rts-build]
# Only run if the build step is successful
if: success()
name: build-docker-image
uses: ./.github/workflows/build-docker-image.yml
secrets: inherit
with:
pr: ${{ github.event.client_payload.pull_request.number }}
ci-test:
needs: [build-docker-image]
# Only run if the build step is successful
if: success()
name: ci-test-with-documentDB
uses: ./.github/workflows/ci-test-with-documentdb.yml
secrets: inherit
with:
pr: ${{ github.event.client_payload.pull_request.number }}
ci-test-result:
needs: [ci-test]
# Only run if the ci-test with matrices step is successful
if: always()
runs-on: ubuntu-latest
defaults:
run:
shell: bash
steps:
- name: Dump the client payload context
env:
PAYLOAD_CONTEXT: ${{ toJson(github.event.client_payload) }}
run: echo "$PAYLOAD_CONTEXT"
# Deleting the existing dir's if any
- name: Delete existing directories
if: needs.ci-test.result != 'success'
run: |
rm -f ~/failed_spec_ci
rm -f ~/combined_failed_spec_ci
# Force store previous cypress dashboard url from cache
- name: Store the previous cypress dashboard url
continue-on-error: true
if: success()
uses: actions/cache@v3
with:
path: |
~/cypress_url
key: ${{ github.run_id }}-dashboard-url-${{ github.run_attempt }}
restore-keys: |
${{ github.run_id }}-dashboard-url
- name: Print cypress dashboard url
continue-on-error: true
id: dashboard_url
run: |
cypress_url="https://internal.appsmith.com/app/cypressdashboard/rundetails-64ec3df0c632e24c00764938?branch=master&workflowId=${{ github.run_id }}&attempt=${{ github.run_attempt }}"
echo "dashboard_url=$cypress_url" >> $GITHUB_OUTPUT
# Download failed_spec list for all jobs
- uses: actions/download-artifact@v3
if: needs.ci-test.result != 'success'
id: download_ci
with:
name: failed-spec-ci-${{github.run_attempt}}
path: ~/failed_spec_ci
# In case for any ci job failure, create combined failed spec
- 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.
- name: upload combined failed spec
if: needs.ci-test.result != 'success'
uses: actions/upload-artifact@v3
with:
name: combined_failed_spec_ci
path: ~/combined_failed_spec_ci
- name: Get Latest flaky Tests
shell: bash
run: |
curl --request POST --url https://yatin-s-workspace-jk8ru5.us-east-1.xata.sh/db/CypressKnownFailures:main/tables/CypressKnownFailuires/query --header 'Authorization: Bearer ${{ secrets.XATA_TOKEN }}' --header 'Content-Type: application/json'|jq -r |grep Spec|cut -d ':' -f 2 2> /dev/null|sed 's/"//g'|sed 's/,//g' > ~/knownfailures
# Verify CI test failures against known failures
- name: Verify CI test failures against known failures
if: needs.ci-test.result != 'success'
shell: bash
run: |
new_failed_spec_env="<ol>$(comm -1 -3 <(sort ~/knownfailures) <(sort -u ~/combined_failed_spec_ci) | sed 's/|cypress|cypress/\n/g' | sed 's/^/<li>/')</ol>"
echo "$new_failed_spec_env"
echo "new_failed_spec_env<<EOF" >> $GITHUB_ENV
echo "$new_failed_spec_env" >> $GITHUB_ENV
echo "EOF" >> $GITHUB_ENV
- name: Add a comment on the PR with new CI failures
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 }}
body: |
Workflow run: <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}>.
Commit: `${{ github.event.client_payload.slash_command.args.named.sha }}`.
Cypress dashboard: <a href="https://internal.appsmith.com/app/cypressdashboard/rundetails-64ec3df0c632e24c00764938?branch=master&workflowId=${{ github.run_id }}&attempt=${{ github.run_attempt }}&selectiontype=test&testsstatus=failed&specsstatus=fail" target="_blank"> Click here!</a>
The following are new failures, please fix them before merging the PR: ${{env.new_failed_spec_env}}
To know the list of identified flaky tests - <a href="https://internal.appsmith.com/app/cypressdashboard/identified-flaky-tests-6541e22b0c243558fe2288ca?branch=master" target="_blank">Refer here</a>
- name: Add a comment on the PR when ci-test is 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 }}
body: |
Workflow run: <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}>.
Commit: `${{ github.event.client_payload.slash_command.args.named.sha }}`.
Cypress dashboard: <a href="https://internal.appsmith.com/app/cypressdashboard/rundetails-64ec3df0c632e24c00764938?branch=master&workflowId=${{ github.run_id }}&attempt=${{ github.run_attempt }}" target="_blank">Click here!</a>
All cypress tests have passed 🎉🎉🎉
# Update check run called "ci-test-result"
- name: Mark ci-test-result job as complete
uses: actions/github-script@v6
id: update-check-run
if: ${{ always() }}
env:
run_id: ${{ github.run_id }}
repository: ${{ github.repository }}
number: ${{ github.event.client_payload.pull_request.number }}
job: ${{ github.job }}
# Conveniently, job.status maps to https://developer.github.com/v3/checks/runs/#update-a-check-run
conclusion: ${{ job.status }}
matrix_result: ${{ toJson(needs.ci-test) }}
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const { data: pull } = await github.rest.pulls.get({
...context.repo,
pull_number: process.env.number
});
const ref = pull.head.sha;
const { data: checks } = await github.rest.checks.listForRef({
...context.repo,
ref
});
const check = checks.check_runs.filter(c => c.name === process.env.job);
if(check.length == 0) {
const head_sha = pull.head.sha;
const { data: completed_at } = await github.rest.checks.create({
owner: context.repo.owner,
repo: context.repo.repo,
head_sha: head_sha,
name: process.env.job,
status: 'completed',
conclusion: JSON.parse(process.env.matrix_result).result,
output: {
title: "Integration tests result for ok to test",
summary: "https://github.com/" + process.env.repository + "/actions/runs/" + process.env.run_id
}
});
return completed_at;
} else {
try {
const { data: result } = await github.rest.checks.update({
...context.repo,
check_run_id: check[0].id,
status: 'completed',
conclusion: JSON.parse(process.env.matrix_result).result,
output: {
title: "Integration tests result for ok to test",
summary: "https://github.com/" + process.env.repository + "/actions/runs/" + process.env.run_id
}
});
console.log({ result });
return result;
} catch(e) {
console.error({ error: e.message });
}
}
- name: Dump the client payload context
env:
PAYLOAD_CONTEXT: ${{ toJson(github.event.client_payload) }}
run: echo "$PAYLOAD_CONTEXT"
- name: Check ci-test set status
if: needs.ci-test.result != 'success'
run: exit 1
package:
needs: [ci-test]
runs-on: ubuntu-latest
defaults:
run:
working-directory: app/client
# Run this job only if all the previous steps are a success and the reference if the release or master branch
if: success() && (github.ref == 'refs/heads/release' || github.ref == 'refs/heads/master')
steps:
# Update check run called "package"
- name: Mark package job as complete
uses: actions/github-script@v6
id: update-check-run
if: ${{ always() }}
env:
run_id: ${{ github.run_id }}
repository: ${{ github.repository }}
number: ${{ github.event.client_payload.pull_request.number }}
job: ${{ github.job }}
# Conveniently, job.status maps to https://developer.github.com/v3/checks/runs/#update-a-check-run
conclusion: ${{ job.status }}
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const { data: pull } = await github.rest.pulls.get({
...context.repo,
pull_number: process.env.number
});
const ref = pull.head.sha;
const { data: checks } = await github.rest.checks.listForRef({
...context.repo,
ref
});
const check = checks.check_runs.filter(c => c.name === process.env.job);
if(check.length == 0) {
const head_sha = pull.head.sha;
const { data: completed_at } = await github.rest.checks.create({
owner: context.repo.owner,
repo: context.repo.repo,
head_sha: head_sha,
name: process.env.job,
status: 'completed',
conclusion: process.env.conclusion,
output: {
title: "Package result for ok to test",
summary: "https://github.com/" + process.env.repository + "/actions/runs/" + process.env.run_id
}
});
return completed_at;
} else {
const { data: result } = await github.rest.checks.update({
...context.repo,
check_run_id: check[0].id,
status: 'completed',
conclusion: process.env.conclusion,
output: {
title: "Package result for ok to test",
summary: "https://github.com/" + process.env.repository + "/actions/runs/" + process.env.run_id
}
});
return result;
}

View File

@ -0,0 +1,33 @@
# If someone with write access comments "/ok-to-test" on a pull request, emit a repository_dispatch event
name: Ok To Test with DocumentDB
on:
issue_comment:
types: [created]
jobs:
ok-to-test:
runs-on: ubuntu-latest
# Only run for PRs, not issue comments
if: |
github.event.issue.pull_request
steps:
- name: Generate token
id: generate_token
uses: tibdex/github-app-token@v1
with:
app_id: ${{ secrets.APPSMITH_INTEGRATION_TESTING_ID }}
private_key: ${{ secrets.APPSMITH_INTEGRATION_TESTING_KEY }}
- if: contains(github.event.comment.body, '/ok-to-test-with-documentdb')
name: Slash Command Dispatch
uses: peter-evans/slash-command-dispatch@v3
env:
TOKEN: ${{ steps.generate_token.outputs.token }}
with:
token: ${{ env.TOKEN }} # GitHub App installation access token
reaction-token: ${{ secrets.GITHUB_TOKEN }}
issue-type: pull-request
commands: |
ok-to-test-with-documentdb
permission: write

View File

@ -187,6 +187,7 @@ jobs:
${{ vars.DOCKER_HUB_ORGANIZATION }}/appsmith-dp:${{ vars.EDITION }}-${{ github.event.client_payload.pull_request.number }}
build-args: |
APPSMITH_CLOUD_SERVICES_BASE_URL=https://release-cs.appsmith.com
BASE=${{ vars.DOCKER_HUB_ORGANIZATION }}/base-${{ vars.EDITION }}:release
outputs:
imageHash: ${{ vars.EDITION }}-${{ github.event.client_payload.pull_request.number }}
@ -207,23 +208,31 @@ jobs:
ref: "refs/pull/${{ github.event.client_payload.pull_request.number }}/merge"
fetch-depth: 0
- name: Print versions of tools
run: |
set -o errexit
set -o xtrace
aws --version || true
kubectl version || true
helm version || true
- name: Install mongosh
run: |
curl -fsSL https://pgp.mongodb.com/server-6.0.asc \
| sudo gpg -o /usr/share/keyrings/mongodb-server-6.0.gpg --dearmor
echo "deb [ arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-6.0.gpg ] https://repo.mongodb.org/apt/ubuntu jammy/mongodb-org/6.0 multiverse" \
| sudo tee /etc/apt/sources.list.d/mongodb-org-6.0.list
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
sudo apt-get install --yes mongodb-mongosh
echo "MongoSH version: $(mongosh --version)"
- 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
set -o errexit
# We still need Kubectl v1.23. Once we up the cluster version, we can get rid of this step.
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
kubectl version || true
- name: Deploy Helm chart
env:
@ -241,7 +250,7 @@ jobs:
DB_PASSWORD: ${{ secrets.DB_PASSWORD }}
DB_URL: ${{ secrets.DB_URL }}
DP_EFS_ID: ${{ secrets.APPSMITH_DP_EFS_ID }}
REDIS_URL: ${{ secrets.APPSMITH_DP_REDIS_URL }}
REDIS_URL: ${{ secrets.APPSMITH_DP_REDIS_URL }}
run: |
echo "environment variables set to deploy the image" $IMAGE_HASH
/bin/bash ./scripts/deploy_preview.sh

View File

@ -0,0 +1,259 @@
name: Appsmith Performance Test (on DocumentDB) Workflow
on:
# This line enables manual triggering of this workflow.
workflow_dispatch:
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
# Change the working directory for all the jobs in this workflow
defaults:
run:
working-directory: app/client
shell: bash
jobs:
perf-test:
runs-on: ubuntu-latest-4-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
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
steps:
- 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
- name: Figure out the PR number
run: echo ${{ inputs.pr }}
- name: Print the Github event
run: echo ${{ github.event_name }}
# Timestamp will be used to create cache key
- id: timestamp
run: echo "timestamp=$(date +'%Y-%m-%dT%H:%M:%S')" >> $GITHUB_OUTPUT
# 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
with:
path: |
~/run_result
key: ${{ github.run_id }}-${{ github.job }}-${{ steps.timestamp.outputs.timestamp }}
restore-keys: |
${{ github.run_id }}-${{ github.job }}-
# Fetch prior run result
- name: Get the previous run result
id: run_result
run: cat ~/run_result 2>/dev/null || echo 'default'
# In case of prior failure run the job
- if: steps.run_result.outputs.run_result != 'success'
run: echo "I'm alive!" && exit 0
# Set status = success
- name: Save the status of the run
run: echo "run_result=success" >> $GITHUB_OUTPUT > ~/run_result
# Set up Node.js cache yarn dependencies.
# actions/setup-node@v3 now support caching of dependencies using actions/cache under the hood
# https://github.com/actions/setup-node#caching-global-packages-data
- name: Set up Node.js
if: steps.run_result.outputs.run_result != 'success'
uses: actions/setup-node@v3
with:
node-version-file: app/client/package.json
- name: Download Docker image artifact
uses: actions/download-artifact@v3
with:
name: cicontainer
- name: Load Docker image from tar file
working-directory: "."
run: |
gunzip cicontainer.tar.gz
docker load -i cicontainer.tar
- name: Create folder
if: steps.run_result.outputs.run_result != 'success'
env:
APPSMITH_LICENSE_KEY: ${{ secrets.APPSMITH_LICENSE_KEY }}
working-directory: "."
run: |
mkdir -p cicontainerlocal/stacks/configuration/
- name: Set up SSH key for tunnel
env:
SSH_PRIVATE_KEY: ${{ secrets.APPSMITH_CI_TUNNEL_PRIVATE_KEY }}
run: |
echo "$SSH_PRIVATE_KEY" > ssh_key.pem \
chmod 600 ssh_key.pem
- name: Setup SSH tunnel to AWS DocumentDB instance
run: |
ssh -4 -o StrictHostKeyChecking=no -o ServerAliveInterval=180 -o ServerAliveCountMax=5 -i "ssh_key.pem" -L 0.0.0.0:27010:docdb-ansible-test-cluster.cluster-cz8diybf9wdj.ap-south-1.docdb.amazonaws.com:27017 ubuntu@65.1.106.35 -N -f
- name: Run docker image
if: steps.run_result.outputs.run_result != 'success'
env:
APPSMITH_LICENSE_KEY: ${{ secrets.APPSMITH_LICENSE_KEY }}
APPSMITH_MONGODB_URI: ${{ secrets.INTERNAL_CI_DOC_DB_URI }}
working-directory: "."
run: |
timestamp=$(date +%s)
hash=$(echo -n "$timestamp" | sha1sum | awk '{print $1}')
current_date=$(date -d "@$timestamp" +"%d-%m")
DB_NAME="ci${hash:1:3}-${current_date}"
mkdir -p ~/git-server/keys
mkdir -p ~/git-server/repos
docker run --name test-event-driver -d -p 2222:22 -p 5001:5001 -p 3306:3306 \
-p 5432:5432 -p 28017:27017 -p 25:25 -p 5000:5000 -p 3000:3000 --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
cd cicontainerlocal
docker run -d --name appsmith -p 80:80 -p 9001:9001 \
-v "$PWD/stacks:/appsmith-stacks" -e APPSMITH_LICENSE_KEY=$APPSMITH_LICENSE_KEY \
-e APPSMITH_DISABLE_TELEMETRY=true \
-e APPSMITH_CLOUD_SERVICES_BASE_URL=http://host.docker.internal:5001 \
-e APPSMITH_MONGODB_URI="${APPSMITH_MONGODB_URI}${DB_NAME}?retryWrites=false&replicaSet=rs0&directConnection=true" \
--add-host=host.docker.internal:host-gateway \
cicontainer
# Start rts
- name: Start RTS Server
if: steps.run_result.outputs.run_result != 'success'
working-directory: ./app/client/packages/rts
run: |
cp .env.example .env
./start-server.sh &
- name: Setting up the perf 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_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 }}
APPSMITH_DISABLE_TELEMETRY: true
APPSMITH_GOOGLE_MAPS_API_KEY: ${{ secrets.APPSMITH_GOOGLE_MAPS_API_KEY }}
POSTGRES_PASSWORD: postgres
run: |
chmod a+x ./perf/setup-perf-test.sh
./perf/setup-perf-test.sh
- name: Get the performance-infra branch/ref
id: perf_infra_ref
run: |
ref=${{ github.event.client_payload.slash_command.args.named.ref }}
if [[ -z "$ref" ]]; then ref="main"; fi
echo ref=$ref >> $GITHUB_OUTPUT
- name: Checkout Performance Infra code
uses: actions/checkout@v3
with:
repository: appsmithorg/performance-infra
token: ${{ secrets.APPSMITH_PERF_INFRA_REPO_PAT }}
ref: ${{ steps.perf_infra_ref.outputs.ref }}
path: perf
- name: Installing performance tests dependencies
if: steps.run_result.outputs.run_result != 'success'
working-directory: perf
shell: bash
run: yarn install --frozen-lockfile
- name: Change test script permissions
if: steps.run_result.outputs.run_result != 'success'
working-directory: perf
run: chmod +x ./start-test.sh
- name: Run performance tests
if: steps.run_result.outputs.run_result != 'success'
working-directory: perf
shell: bash
env:
APPSMITH_SSL_CERTIFICATE: ${{ secrets.APPSMITH_SSL_CERTIFICATE }}
APPSMITH_SSL_KEY: ${{ secrets.APPSMITH_SSL_KEY }}
CYPRESS_TESTUSERNAME1: ${{ secrets.CYPRESS_TESTUSERNAME9 }}
CYPRESS_TESTPASSWORD1: ${{ secrets.CYPRESS_TESTPASSWORD9 }}
APPSMITH_PERFORMANCE_DB_CONFIG: ${{ secrets.APPSMITH_PERFORMANCE_DB_CONFIG }}
APPSMITH_PERFORMANCE_S3_KEY: ${{secrets.APPSMITH_PERFORMANCE_S3_KEY}}
APPSMITH_PERFORMANCE_S3_SECRET: ${{secrets.APPSMITH_PERFORMANCE_S3_SECRET}}
APPSMITH_PERFORMANCE_DB_PASSWORD: ${{secrets.APPSMITH_PERFORMANCE_DB_PASSWORD}}
APPSMITH_PERFORMANCE_DB_HOST: ${{secrets.APPSMITH_PERFORMANCE_DB_HOST}}
APPSMITH_PERFORMANCE_DB_V2_CONFIG: ${{ secrets.APPSMITH_PERFORMANCE_DB_V2_CONFIG }}
PERF_GITHUB_PAT: ${{ secrets.APPSMITH_PERF_INFRA_REPO_PAT }}
APPSMITH_DISABLE_TELEMETRY: true
POSTGRES_PASSWORD: postgres
NODE_TLS_REJECT_UNAUTHORIZED: "0"
MACHINE: ubuntu-latest-4-cores
run: ./start-test.sh
# Restore the previous built bundle if present. If not push the newly built into the cache
- name: Restore the previous bundle
uses: actions/cache@v3
with:
path: |
perf/traces
key: ${{ github.run_id }}-${{ github.job }}-${{ steps.timestamp.outputs.timestamp }}
restore-keys: |
${{ github.run_id }}-${{ github.job }}
- uses: actions/upload-artifact@v3
with:
name: performance-test-logs
path: perf/traces/reports
# Set status = success
- name: Save the status of the run
run: echo "run_result=success" >> $GITHUB_OUTPUT > ~/run_result

View File

@ -29,6 +29,11 @@ jobs:
run:
working-directory: app/client
shell: bash
strategy:
fail-fast: false
matrix:
job: [0, 1]
# Service containers to run with this job. Required for running tests
services:
@ -222,6 +227,7 @@ jobs:
POSTGRES_PASSWORD: postgres
NODE_TLS_REJECT_UNAUTHORIZED: "0"
MACHINE: ubuntu-latest-4-cores
JOB: ${{ matrix.job }}
run: ./start-test.sh

View File

@ -60,3 +60,13 @@ jobs:
secrets: inherit
with:
pr: ${{ github.event.client_payload.pull_request.number }}
perf-test-v2:
needs: [ build-docker-image ]
# Only run if the build step is successful
if: success()
name: perf-test-v2
uses: ./.github/workflows/perf-test-v2.yml
secrets: inherit
with:
pr: ${{ github.event.client_payload.pull_request.number }}

View File

@ -69,9 +69,6 @@ jobs:
- name: Print the Github event
run: echo ${{ github.event_name }}
- name: Set up Depot CLI
uses: depot/setup-action@v1
# 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

View File

@ -131,6 +131,7 @@ jobs:
ACTIVE_PROFILE: test
APPSMITH_MONGODB_URI: "mongodb://localhost:27017/mobtools"
APPSMITH_CLOUD_SERVICES_BASE_URL: "https://release-cs.appsmith.com"
APPSMITH_CLOUD_SERVICES_TEMPLATE_UPLOAD_AUTH: ${{ secrets.APPSMITH_CLOUD_SERVICES_TEMPLATE_UPLOAD_AUTH }}
APPSMITH_REDIS_URL: "redis://127.0.0.1:6379"
APPSMITH_ENCRYPTION_PASSWORD: "password"
APPSMITH_ENCRYPTION_SALT: "salt"

View File

@ -45,16 +45,6 @@ jobs:
with:
pr: 0
perf-test:
needs: [build-docker-image]
# Only run if the build step is successful
if: success()
name: perf-test
uses: ./.github/workflows/perf-test.yml
secrets: inherit
with:
pr: 0
ci-test:
needs: [build-docker-image]
# Only run if the build step is successful
@ -106,7 +96,7 @@ jobs:
if: needs.ci-test.result != 'success'
shell: bash
run: |
new_failed_spec_env="<ol>$(sort -u ~/combined_failed_spec_ci | sed 's/|cypress|cypress/\n/g' | sed 's/^/<li>/')</ol>"
new_failed_spec_env="<ol>$(sort -u ~/combined_failed_spec_ci | sed 's/|cypress|cypress/<\/li>\n<li>/g' | sed -e 's/^<li>//' -e 's/<\/li>$//' -e 's/<\/li>/<\/li>\n/')</ol>"
echo "$new_failed_spec_env"
echo "new_failed_spec_env<<EOF" >> $GITHUB_ENV
echo "$new_failed_spec_env" >> $GITHUB_ENV
@ -116,13 +106,23 @@ jobs:
continue-on-error: true
if: always()
id: slack_notification
env:
EVENT_COMMITS: ${{ toJson(github.event.commits[0].message) }}
run: |
if [[ "${{ needs.ci-test.result }}" != "success" ]]; then
echo "slack_message=There are test failures in the run.<br>${{env.new_failed_spec_env}}<br>Please check the <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|Github Actions> for more details." >> $GITHUB_OUTPUT
eventCommit=$(echo ${{env.EVENT_COMMITS}} | sed "s/'//g")
echo "slack_username=$(echo "$eventCommit" | awk -F '\\\\n' '{print $1}' | sed 's/^"//;s/"$//')" >> $GITHUB_OUTPUT
if [[ ${{ needs.ci-test.result }} == 'failure' ]]; then
echo "slack_message=There are test failures in the run. Cypress Dashboard: <https://internal.appsmith.com/app/cypressdashboard/rundetails-64ec3df0c632e24c00764938?branch=master&workflowId=${{ github.run_id }}&attempt=${{ github.run_attempt }}&selectiontype=test&testsstatus=failed&specsstatus=fail|Click here!>" >> $GITHUB_OUTPUT
echo "slack_color=#FF0000" >> $GITHUB_OUTPUT
else
echo "slack_message=All tests passed successfully :tada: . Github Action: <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|Click here!>" >> $GITHUB_OUTPUT
echo "slack_icon=:no_entry:" >> $GITHUB_OUTPUT
elif [[ ${{ needs.ci-test.result }} == 'success' ]]; then
echo "slack_message=All tests passed successfully :tada: Cypress Dashboard: <https://internal.appsmith.com/app/cypressdashboard/rundetails-64ec3df0c632e24c00764938?branch=master&workflowId=${{ github.run_id }}&attempt=${{ github.run_attempt }}|Click here!>" >> $GITHUB_OUTPUT
echo "slack_color=#00FF00" >> $GITHUB_OUTPUT
echo "slack_icon=:white_check_mark:" >> $GITHUB_OUTPUT
else
echo "slack_message=There are build failures. To analyze run go <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|here>" >> $GITHUB_OUTPUT
echo "slack_color=#FF0000" >> $GITHUB_OUTPUT
echo "slack_icon=:warning:" >> $GITHUB_OUTPUT
fi
- name: Slack Notification
@ -132,12 +132,13 @@ jobs:
env:
SLACK_CHANNEL: cypresspushworkflow
SLACK_COLOR: ${{steps.slack_notification.outputs.slack_color}}
SLACK_ICON_EMOJI: ${{steps.slack_notification.outputs.slack_icon}}
SLACK_ICON: https://app.slack.com/services/B05D17E4QVB
SLACK_TITLE: 'Result:'
SLACK_USERNAME: Cypress Push Workflows
SLACK_TITLE: "Result:"
SLACK_USERNAME: ${{steps.slack_notification.outputs.slack_username}}
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_HOSTED }}
MSG_MINIMAL: Ref,Event,Commit
SLACK_FOOTER: 'Appsmith Push Workflows'
SLACK_FOOTER: "Push Workflow"
SLACK_MESSAGE: ${{steps.slack_notification.outputs.slack_message}}
# Force save the CI failed spec list into a cache
@ -173,7 +174,6 @@ jobs:
exit 1;
fi
package-release:
needs: build-docker-image
runs-on: ubuntu-latest
@ -220,6 +220,12 @@ jobs:
echo "Cleaning up the tar files"
rm app/client/packages/rts/dist/rts-dist.tar
- name: Generate info.json
run: |
if [[ -f scripts/generate_info_json.sh ]]; then
scripts/generate_info_json.sh
fi
- name: Set up Depot CLI
uses: depot/setup-action@v1
@ -239,6 +245,7 @@ jobs:
build-args: |
APPSMITH_SEGMENT_CE_KEY=${{ secrets.APPSMITH_SEGMENT_CE_KEY_RELEASE }}
APPSMITH_CLOUD_SERVICES_BASE_URL=https://release-cs.appsmith.com
BASE=${{ vars.DOCKER_HUB_ORGANIZATION }}/base-${{ vars.EDITION }}:release
tags: |
${{ vars.DOCKER_HUB_ORGANIZATION }}/appsmith-${{ vars.EDITION }}:release
@ -288,6 +295,12 @@ jobs:
echo "Cleaning up the tar files"
rm app/client/packages/rts/dist/rts-dist.tar
- name: Generate info.json
run: |
if [[ -f scripts/generate_info_json.sh ]]; then
scripts/generate_info_json.sh
fi
- name: Set up Depot CLI
uses: depot/setup-action@v1
@ -306,6 +319,44 @@ jobs:
platforms: linux/arm64,linux/amd64
build-args: |
APPSMITH_SEGMENT_CE_KEY=${{ secrets.APPSMITH_SEGMENT_CE_KEY }}
BASE=${{ vars.DOCKER_HUB_ORGANIZATION }}/base-${{ vars.EDITION }}:nightly
tags: |
${{ vars.DOCKER_HUB_ORGANIZATION }}/appsmith-${{ vars.EDITION }}:${{ github.sha }}
${{ vars.DOCKER_HUB_ORGANIZATION }}/appsmith-${{ vars.EDITION }}:nightly
notify-slack-for-promotion:
needs: ci-test
runs-on: ubuntu-latest
if: ( failure() && github.ref == 'refs/heads/master' )
steps:
- name: Notify failure on workflow run and on Slack
run: |
set -o errexit
set -o nounset
set -o xtrace
run_url='${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}/attempts/${{ github.run_attempt }}'
common_parent_sha='${{ steps.merge.outputs.common_parent_sha }}'
common_parent_sha_short="$(echo "$common_parent_sha" | grep -o '^.\{8\}' || true)"
merged_upto_sha='${{ steps.merge.outputs.merged_upto_sha }}'
merged_upto_sha_short="$(echo "$merged_upto_sha" | grep -o '^.\{8\}' || true)"
details="🚨 TBP workflow failed in <$run_url|${{ github.run_id }}/attempts/${{ github.run_attempt }}>.
# This unweildy horror of a sed command, converts standard Markdown links to Slack's unweildy link syntax.
slack_message="$(echo "$details" | sed -E 's/\[([^]]+)\]\(([^)]+)\)/<\2|\1>/g')"
# This is the ChannelId of the tech channel.
body="$(jq -nc \
--arg channel CGBPVEJ5C \
--arg text "$slack_message" \
'$ARGS.named'
)"
curl -v https://slack.com/api/chat.postMessage \
--fail-with-body \
--header 'Authorization: Bearer ${{ secrets.SLACK_APPSMITH_ALERTS_TOKEN }}' \
--header 'Content-Type: application/json; charset=utf-8' \
--data-raw "$body"

View File

@ -121,4 +121,4 @@ jobs:
- name: Check ci-test set status
if: needs.ci-test.result != 'success'
run: exit 1
run: exit 1

2
.gitignore vendored
View File

@ -5,7 +5,7 @@
app/client/cypress.env.json
dist
stacks
/info.json
/deploy/docker/fs/opt/appsmith/info.json
# to ignore the node_modeules folder
node_modules

View File

@ -23,12 +23,12 @@ app/client/tsconfig.json @KelvinOm
app/client/tsconfig.path.json @KelvinOm
# App viewers pod
app/client/src/widgets/* @appsmithorg/app-viewers @rajatagrawal
app/client/src/widgets/* @appsmithorg/app-viewers
app/client/cypress/e2e/Regression/ClientSide/Widgets/* @rajatagrawal
app/client/src/components/propertyControls/* @appsmithorg/app-viewers
app/client/src/sagas/OneClickBindingSaga.ts @sbalaji1192 @berzerkeer
app/client/src/WidgetQueryGenerators/* @sbalaji1192 @berzerkeer
app/client/src/components/editorComponents/WidgetQueryGeneratorForm/* @sbalaji1192 @berzerkeer
app/client/src/sagas/OneClickBindingSaga.ts @sbalaji1192
app/client/src/WidgetQueryGenerators/* @sbalaji1192
app/client/src/components/editorComponents/WidgetQueryGeneratorForm/* @sbalaji1192
app/client/src/pages/AppViewer/* @appsmithorg/app-viewers
app/client/src/pages/Editor/AppSettingsPane/AppSettings/NavigationSettings/* @dhruvikn
app/client/src/ce/pages/AppViewer/NavigationLogo.tsx @dhruvikn
@ -63,26 +63,16 @@ app/client/src/actions/autoLayoutActions.ts @appsmithorg/ui-builders
app/client/src/actions/canvasSelectionActions.ts @appsmithorg/ui-builders
app/client/src/actions/reflowActions.ts @appsmithorg/ui-builders
app/client/src/actions/widgetSelectionActions.ts @appsmithorg/ui-builders
app/client/src/components/autoHeight/* @appsmithorg/ui-builders
app/client/src/components/autoHeightOverlay/* @appsmithorg/ui-builders
app/client/src/components/designSystems/appsmith/PositionedContainer.tsx @appsmithorg/ui-builders
app/client/src/components/editorComponents/DraggableComponent.tsx @appsmithorg/ui-builders
app/client/src/components/editorComponents/ResizableComponent.tsx @appsmithorg/ui-builders
app/client/src/components/editorComponents/ResizableUtils.ts @appsmithorg/ui-builders
app/client/src/components/editorComponents/ResizeStyledComponents.tsx @appsmithorg/ui-builders
app/client/src/components/editorComponents/WidgetNameComponent/* @appsmithorg/ui-builders
app/client/src/components/propertyControls/* @appsmithorg/ui-builders
app/client/src/layoutSystems/* @appsmithorg/ui-builders
app/client/src/normalizers/CanvasWidgetsNormalizer.tsx @appsmithorg/ui-builders
app/client/src/pages/Editor/Canvas.tsx @appsmithorg/ui-builders
app/client/src/pages/Editor/CanvasLayoutConversion/* @appsmithorg/ui-builders
app/client/src/pages/Editor/PropertyPane/* @appsmithorg/ui-builders
app/client/src/pages/Editor/WidgetsMultiSelectBox.tsx @appsmithorg/ui-builders
app/client/src/pages/common/CanvasArenas/* @appsmithorg/ui-builders
app/client/src/reducers/entityReducers/autoHeightReducers/* @appsmithorg/ui-builders
app/client/src/reducers/entityReducers/canvasWidgetsReducer.ts @appsmithorg/ui-builders
app/client/src/reducers/entityReducers/widgetConfigReducer.ts @appsmithorg/ui-builders
app/client/src/reflow/* @appsmithorg/ui-builders
app/client/src/resizable/* @appsmithorg/ui-builders
app/client/src/sagas/AutoLayoutUpdateSagas.tsx @appsmithorg/ui-builders
app/client/src/sagas/CanvasSagas/* @appsmithorg/ui-builders
app/client/src/sagas/ReplaySaga.ts @appsmithorg/ui-builders
@ -102,7 +92,6 @@ app/client/src/selectors/canvasSelectors.ts @appsmithorg/ui-builders
app/client/src/selectors/widgetSelectors.ts @appsmithorg/ui-builders
app/client/src/utils/DSLConversions/* @appsmithorg/ui-builders
app/client/src/utils/autoHeight/* @appsmithorg/ui-builders
app/client/src/utils/autoLayout/* @appsmithorg/ui-builders
app/client/src/utils/hooks/autoHeightUIHooks.ts @appsmithorg/ui-builders
app/client/src/utils/hooks/useAllowEditorDragToSelect.ts @appsmithorg/ui-builders
app/client/src/utils/hooks/useClickToSelectWidget.tsx @appsmithorg/ui-builders
@ -111,7 +100,7 @@ app/client/src/utils/hooks/usePositionedContainerZIndex.ts @appsmithorg/ui-build
app/client/src/utils/hooks/useReflow.ts @appsmithorg/ui-builders
app/client/src/utils/hooks/useWidgetSelection.ts @appsmithorg/ui-builders
app/client/src/widgets/BaseWidget.tsx @appsmithorg/ui-builders
app/client/src/widgets/CanvasResizer.tsx @appsmithorg/ui-builders
app/client/src/widgets/BaseWidgetHOC/* @appsmithorg/ui-builders
app/client/src/widgets/CanvasWidget.tsx @appsmithorg/ui-builders
app/client/src/widgets/ContainerWidget/* @appsmithorg/ui-builders
app/client/src/widgets/MetaHOC.tsx @appsmithorg/ui-builders
@ -132,82 +121,115 @@ app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/GitUtils.ja
# Data Platform
app/client/src/actions/datasourceActions.ts @ayushpahwa @ChandanBalajiBP
app/client/src/api/ActionAPI.tsx @ayushpahwa @ChandanBalajiBP
app/client/src/ce/components/DSDataFilter/index.tsx @ayushpahwa @ChandanBalajiBP
app/client/src/ce/constants/ReduxActionConstants.tsx @ayushpahwa @ChandanBalajiBP
app/client/src/ce/sagas/ApplicationSagas.tsx @ayushpahwa @ChandanBalajiBP
app/client/src/ce/selectors/environmentSelectors.tsx @ayushpahwa @ChandanBalajiBP
app/client/src/ce/utils/Environments/index.tsx @ayushpahwa @ChandanBalajiBP
app/client/src/components/BottomBar/index.tsx @ayushpahwa @ChandanBalajiBP
app/client/src/components/editorComponents/form/fields/EmbeddedDatasourcePathField.tsx @ayushpahwa @ChandanBalajiBP
app/client/src/components/formControls/utils.test.ts @ayushpahwa @ChandanBalajiBP
app/client/src/components/formControls/utils.ts @ayushpahwa @ChandanBalajiBP
app/client/src/entities/Datasource/index.ts @ayushpahwa @ChandanBalajiBP
app/client/src/entities/FeatureFlags.ts @ayushpahwa @ChandanBalajiBP
app/client/src/navigation/FocusEntity.ts @ayushpahwa @ChandanBalajiBP
app/client/src/pages/Editor/APIEditor/* @ayushpahwa @ChandanBalajiBP
app/client/src/pages/Editor/DataSourceEditor/* @ayushpahwa @ChandanBalajiBP
app/client/src/pages/Editor/IntegrationEditor/DatasourceCard.tsx @ayushpahwa @ChandanBalajiBP
app/client/src/pages/Editor/IntegrationEditor/IntegrationsHomeScreen.tsx @ayushpahwa @ChandanBalajiBP
app/client/src/pages/Editor/IntegrationEditor/NewApi.tsx @ayushpahwa @ChandanBalajiBP
app/client/src/pages/Editor/QueryEditor/EditorJSONtoForm.tsx @ayushpahwa @ChandanBalajiBP
app/client/src/pages/Editor/SaaSEditor/DatasourceCard.tsx @ayushpahwa @ChandanBalajiBP
app/client/src/pages/Editor/SaaSEditor/DatasourceForm.tsx @ayushpahwa @ChandanBalajiBP
app/client/src/pages/Editor/gitSync/ReconnectDatasourceModal.tsx @ayushpahwa @ChandanBalajiBP
app/client/src/pages/common/datasourceAuth/index.tsx @ayushpahwa @ChandanBalajiBP
app/client/src/reducers/entityReducers/datasourceReducer.ts @ayushpahwa @ChandanBalajiBP
app/client/src/sagas/ActionExecution/PluginActionSaga.ts @ayushpahwa @ChandanBalajiBP
app/client/src/sagas/DatasourcesSagas.ts @ayushpahwa @ChandanBalajiBP
app/client/src/sagas/QueryPaneSagas.ts @ayushpahwa @ChandanBalajiBP
app/client/src/transformers/RestAPIDatasourceFormTransformer.ts @ayushpahwa @ChandanBalajiBP
app/client/src/actions/datasourceActions.ts @ayushpahwa
app/client/src/api/ActionAPI.tsx @ayushpahwa
app/client/src/ce/components/DSDataFilter/index.tsx @ayushpahwa
app/client/src/ce/constants/ReduxActionConstants.tsx @ayushpahwa
app/client/src/ce/sagas/ApplicationSagas.tsx @ayushpahwa
app/client/src/ce/selectors/environmentSelectors.tsx @ayushpahwa
app/client/src/ce/utils/Environments/index.tsx @ayushpahwa
app/client/src/components/BottomBar/index.tsx @ayushpahwa
app/client/src/components/editorComponents/form/fields/EmbeddedDatasourcePathField.tsx @ayushpahwa
app/client/src/components/formControls/utils.test.ts @ayushpahwa
app/client/src/components/formControls/utils.ts @ayushpahwa
app/client/src/entities/Datasource/index.ts @ayushpahwa
app/client/src/entities/FeatureFlags.ts @ayushpahwa
app/client/src/navigation/FocusEntity.ts @ayushpahwa
app/client/src/pages/Editor/APIEditor/* @ayushpahwa
app/client/src/pages/Editor/DataSourceEditor/* @ayushpahwa
app/client/src/pages/Editor/IntegrationEditor/DatasourceCard.tsx @ayushpahwa
app/client/src/pages/Editor/IntegrationEditor/IntegrationsHomeScreen.tsx @ayushpahwa
app/client/src/pages/Editor/IntegrationEditor/NewApi.tsx @ayushpahwa
app/client/src/pages/Editor/QueryEditor/EditorJSONtoForm.tsx @ayushpahwa
app/client/src/pages/Editor/SaaSEditor/DatasourceCard.tsx @ayushpahwa
app/client/src/pages/Editor/SaaSEditor/DatasourceForm.tsx @ayushpahwa
app/client/src/pages/Editor/gitSync/ReconnectDatasourceModal.tsx @ayushpahwa
app/client/src/pages/common/datasourceAuth/index.tsx @ayushpahwa
app/client/src/reducers/entityReducers/datasourceReducer.ts @ayushpahwa
app/client/src/sagas/ActionExecution/PluginActionSaga.ts @ayushpahwa
app/client/src/sagas/DatasourcesSagas.ts @ayushpahwa
app/client/src/sagas/QueryPaneSagas.ts @ayushpahwa
app/client/src/transformers/RestAPIDatasourceFormTransformer.ts @ayushpahwa
# Followed Globstar paths in combination with wildcard paths. Reference https://docs.gitlab.com/ee/user/project/codeowners/reference.html#globstar-paths
# Data Platform server - Interfaces
app/server/appsmith-interfaces/src/main/java/com/appsmith/external/**/Action* @nidhi-nair @sondermanish @tkappsmith
app/server/appsmith-interfaces/src/main/java/com/appsmith/external/**/Datasource* @nidhi-nair @sondermanish @tkappsmith
app/server/appsmith-interfaces/src/main/java/com/appsmith/external/**/OAuth2* @nidhi-nair @sondermanish @tkappsmith
app/server/appsmith-interfaces/src/main/java/com/appsmith/external/**/Action* @nidhi-nair @sondermanish
app/server/appsmith-interfaces/src/main/java/com/appsmith/external/**/Datasource* @nidhi-nair @sondermanish
app/server/appsmith-interfaces/src/main/java/com/appsmith/external/**/OAuth2* @nidhi-nair @sondermanish
# Data Platform server - Controllers
app/server/appsmith-server/src/main/java/com/appsmith/server/controllers/**/Action* @nidhi-nair @sondermanish @tkappsmith
app/server/appsmith-server/src/main/java/com/appsmith/server/controllers/**/Datasource* @nidhi-nair @sondermanish @tkappsmith
app/server/appsmith-server/src/main/java/com/appsmith/server/controllers/**/Action* @nidhi-nair @sondermanish
app/server/appsmith-server/src/main/java/com/appsmith/server/controllers/**/Datasource* @nidhi-nair @sondermanish
# Data Platform server - Domains
app/server/appsmith-server/src/main/java/com/appsmith/server/domains/**/Action* @nidhi-nair @sondermanish @tkappsmith
app/server/appsmith-server/src/main/java/com/appsmith/server/domains/**/Datasource* @nidhi-nair @sondermanish @tkappsmith
app/server/appsmith-server/src/main/java/com/appsmith/server/domains/**/Action* @nidhi-nair @sondermanish
app/server/appsmith-server/src/main/java/com/appsmith/server/domains/**/Datasource* @nidhi-nair @sondermanish
# Data Platform server - DTOs
app/server/appsmith-server/src/main/java/com/appsmith/server/dtos/**/Action* @nidhi-nair @sondermanish @tkappsmith
app/server/appsmith-server/src/main/java/com/appsmith/server/dtos/**/Datasource* @nidhi-nair @sondermanish @tkappsmith
app/server/appsmith-server/src/main/java/com/appsmith/server/dtos/**/Action* @nidhi-nair @sondermanish
app/server/appsmith-server/src/main/java/com/appsmith/server/dtos/**/Datasource* @nidhi-nair @sondermanish
# Data Platform server - Repositories
app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/**/*Action* @nidhi-nair @sondermanish @tkappsmith
app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/**/*Datasource* @nidhi-nair @sondermanish @tkappsmith
app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/**/*Action* @nidhi-nair @sondermanish
app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/**/*Datasource* @nidhi-nair @sondermanish
# Data Platform server - Services
app/server/appsmith-server/src/main/java/com/appsmith/server/services/**/*Action* @nidhi-nair @sondermanish @tkappsmith
app/server/appsmith-server/src/main/java/com/appsmith/server/services/**/*Datasource* @nidhi-nair @sondermanish @tkappsmith
app/server/appsmith-server/src/main/java/com/appsmith/server/services/**/*Authentication* @nidhi-nair @sondermanish @tkappsmith
app/server/appsmith-server/src/main/java/com/appsmith/server/services/**/*Action* @nidhi-nair @sondermanish
app/server/appsmith-server/src/main/java/com/appsmith/server/services/**/*Datasource* @nidhi-nair @sondermanish
app/server/appsmith-server/src/main/java/com/appsmith/server/services/**/*Authentication* @nidhi-nair @sondermanish
# Data Platform server - Solutions
app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/**/*Action* @nidhi-nair @sondermanish @tkappsmith
app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/**/*Datasource* @nidhi-nair @sondermanish @tkappsmith
app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/**/*Authentication* @nidhi-nair @sondermanish @tkappsmith
app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/**/*Environment* @nidhi-nair @sondermanish @tkappsmith
app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/**/*Action* @nidhi-nair @sondermanish
app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/**/*Datasource* @nidhi-nair @sondermanish
app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/**/*Authentication* @nidhi-nair @sondermanish
app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/**/*Environment* @nidhi-nair @sondermanish
# Data Platform server - Misc
app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/**/Datasource* @nidhi-nair @sondermanish @tkappsmith
app/server/appsmith-server/src/main/java/com/appsmith/server/exceptions/AppsmithError* @nidhi-nair @sondermanish @tkappsmith
app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/**/Datasource* @nidhi-nair @sondermanish
app/server/appsmith-server/src/main/java/com/appsmith/server/exceptions/AppsmithError* @nidhi-nair @sondermanish
# Team Managers pod
app/client/src/ce/* @ankitakinger
app/client/src/ee/* @ankitakinger
app/client/src/pages/Settings/* @ankitakinger
app/client/cypress/e2e/Regression/Enterprise/* @ankitakinger
app/client/cypress/e2e/Regression/EE/Enterprise/* @ankitakinger
app/client/cypress/e2e/Regression/ClientSide/AdminSettings/* @ankitakinger
app/client/cypress/e2e/Regression/ClientSide/Google/* @ankitakinger
app/client/cypress/e2e/Regression/ClientSide/Github/* @ankitakinger
app/client/cypress/e2e/Regression/ClientSide/FormLogin/* @ankitakinger
app/client/cypress/e2e/Regression/ClientSide/Auditlogs/* @ankitakinger
app/client/src/pages/Settings/**/* @ankitakinger
app/client/src/pages/workspace/settings.tsx @ankitakinger
app/client/src/pages/workspace/AppInviteUsersForm.tsx @ankitakinger
app/client/src/pages/workspace/WorkspaceInviteUsersForm.tsx @ankitakinger
app/client/src/components/editorComponents/form/FormDialogComponent.tsx @ankitakinger
app/client/src/ce/pages/AdminSettings/**/* @ankitakinger
app/client/src/ee/pages/AdminSettings/**/* @ankitakinger
app/client/src/ce/pages/Applications/EmbedSnippetTab.tsx @ankitakinger
app/client/src/ee/pages/Applications/EmbedSnippetTab.tsx @ankitakinger
app/client/src/ce/pages/Applications/PrivateEmbedSettings.tsx @ankitakinger
app/client/src/ee/pages/Applications/PrivateEmbedSettings.tsx @ankitakinger
app/client/src/ce/pages/workspace/Members.tsx @ankitakinger
app/client/src/ee/pages/workspace/Members.tsx @ankitakinger
app/client/src/ce/pages/workspace/InviteUsersForm.tsx @ankitakinger
app/client/src/ee/pages/workspace/InviteUsersForm.tsx @ankitakinger
app/client/src/ce/pages/Upgrade/**/* @ankitakinger
app/client/src/ee/pages/Auditlogs/**/* @ankitakinger
app/client/cypress/e2e/Regression/Enterprise/**/* @ankitakinger
app/client/cypress/e2e/Regression/EE/Enterprise/**/* @ankitakinger
app/client/cypress/e2e/Regression/ClientSide/AdminSettings/**/* @ankitakinger
app/client/cypress/e2e/Regression/ClientSide/Google/**/* @ankitakinger
app/client/cypress/e2e/Regression/ClientSide/Github/**/* @ankitakinger
app/client/cypress/e2e/Regression/ClientSide/FormLogin/**/* @ankitakinger
app/client/cypress/e2e/Regression/ClientSide/Auditlogs/**/* @ankitakinger
#FE pod
app/client/src/actions/evaluationActions.ts @ApekshaBhosale
app/client/src/ce/entities/DataTree/**/* @ApekshaBhosale
app/client/src/ce/entities/DependencyMap/**/* @ApekshaBhosale
app/client/src/ce/entities/workers/**/* @ApekshaBhosale
app/client/src/ee/entities/DataTree* @ApekshaBhosale
app/client/src/ee/entities/workers/**/* @ApekshaBhosale
app/client/src/sagas/EvaluationsSaga.ts @ApekshaBhosale
app/client/src/sagas/EvalWorkerActionSagas.ts @ApekshaBhosale
app/client/src/sagas/LintingSagas.ts @ApekshaBhosale
app/client/src/sagas/PostEvaluationSags.ts @ApekshaBhosale
app/client/src/sagas/PostLintingSagas.ts @ApekshaBhosale
app/client/src/workers/**/* @ApekshaBhosale
app/client/src/sagas/JSLibrarySaga.ts @ApekshaBhosale
app/client/src/ce/ActionExecution/ActionExecutionSagas.ts @ApekshaBhosale
app/client/src/ee/ActionExecution/ActionExecutionSagas.ts @ApekshaBhosale
app/client/src/ce/JSFunctionExecutionSaga.ts @ApekshaBhosale
app/client/src/ee/JSFunctionExecutionSaga.ts @ApekshaBhosale

View File

@ -14,7 +14,9 @@ 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
RUN mkdir -p ./backend ./editor ./rts ./backend/plugins ./templates ./utils
RUN mkdir -p ./editor ./rts ./backend/plugins
COPY deploy/docker/fs /
#Add the jar to the container
COPY ${JAR_FILE} backend/server.jar
@ -24,45 +26,19 @@ COPY ${PLUGIN_JARS} backend/plugins/
COPY ./app/client/build editor/
# Add RTS - Application Layer
COPY ./app/client/packages/rts/package.json ./app/client/packages/rts/dist rts/
COPY ./app/client/packages/rts/dist rts/
# Nginx, MongoDB and PostgreSQL data config template - Configuration layer
COPY ./deploy/docker/templates/nginx/* \
./deploy/docker/templates/docker.env.sh \
./deploy/docker/templates/mockdb_postgres.sql \
./deploy/docker/templates/users_postgres.sql \
./deploy/docker/templates/appsmith_starting.html \
./deploy/docker/templates/appsmith_initializing.html \
templates/
ENV PATH /opt/appsmith/utils/node_modules/.bin:/opt/java/bin:/opt/node/bin:$PATH
# Add bootstrapfile
COPY ./deploy/docker/entrypoint.sh ./deploy/docker/scripts/* info.*json ./
RUN cd ./utils && npm install --only=prod && npm install --only=prod -g . && cd - \
&& chmod 0644 /etc/cron.d/* \
&& chmod +x *.sh templates/nginx-app.conf.sh /watchtower-hooks/*.sh \
# Disable setuid/setgid bits for the files inside container.
&& find / \( -path /proc -prune \) -o \( \( -perm -2000 -o -perm -4000 \) -print -exec chmod -s '{}' + \) || true \
&& node prepare-image.mjs
# Add util tools
COPY ./deploy/docker/utils ./utils
RUN cd ./utils && npm install --only=prod && npm install --only=prod -g .
# Add process config to be run by supervisord
COPY ./deploy/docker/templates/supervisord.conf /etc/supervisor/supervisord.conf
COPY ./deploy/docker/templates/supervisord/ templates/supervisord/
# Add defined cron job
COPY ./deploy/docker/templates/cron.d /etc/cron.d/
RUN chmod 0644 /etc/cron.d/*
RUN chmod +x entrypoint.sh renew-certificate.sh healthcheck.sh
# Disable setuid/setgid bits for the files inside container.
RUN find / \( -path /proc -prune \) -o \( \( -perm -2000 -o -perm -4000 \) -print -exec chmod -s '{}' + \) || true
# Update path to load appsmith utils tool as default
ENV PATH /opt/appsmith/utils/node_modules/.bin:$PATH
LABEL com.centurylinklabs.watchtower.lifecycle.pre-check=/watchtower-hooks/pre-check.sh
LABEL com.centurylinklabs.watchtower.lifecycle.pre-update=/watchtower-hooks/pre-update.sh
COPY ./deploy/docker/watchtower-hooks /watchtower-hooks
RUN chmod +x /watchtower-hooks/pre-check.sh
RUN chmod +x /watchtower-hooks/pre-update.sh
EXPOSE 80
EXPOSE 443

View File

@ -31,7 +31,7 @@
"value": ""
},
"APPSMITH_DISABLE_TELEMETRY": {
"description" : "We want to be transparent and request that you share anonymous usage data with us. This data is purely statistical in nature and helps us understand your needs & provide better support to your self-hosted instance. You can read more about what information is collected in our documentation https://docs.appsmith.com/v/v1.2.1/setup/telemetry",
"description" : "We want to be transparent and request that you share anonymous usage data with us. This data is purely statistical in nature and helps us understand your needs & provide better support to your self-hosted instance. You can read more about what information is collected in our documentation https://docs.appsmith.com/product/telemetry",
"value": "false"
},
"APPSMITH_SUPERVISOR_PASSWORD": {

View File

@ -2,6 +2,12 @@
"$schema": "http://json.schemastore.org/eslintrc",
"root": true,
"parser": "@typescript-eslint/parser",
"ignorePatterns": [
"jest.config.js",
"jest.setup.ts",
"rollup.config.js",
".eslintrc.js"
],
"plugins": [
"react",
"@typescript-eslint",
@ -22,9 +28,14 @@
"sourceType": "module",
"ecmaFeatures": {
"jsx": true
}
},
"project": "./tsconfig.json"
},
"rules": {
"@typescript-eslint/consistent-type-definitions": "error",
"@typescript-eslint/prefer-nullish-coalescing": "error",
"@typescript-eslint/promise-function-async": "error",
"@typescript-eslint/strict-boolean-expressions": "error",
"@typescript-eslint/no-explicit-any": "error",
"@typescript-eslint/no-unused-vars": "warn",
"jest/no-focused-tests": "error",

View File

@ -13,6 +13,8 @@ const baseNoRestrictedImports =
const eslintConfig = {
extends: [".eslintrc.base.json"],
rules: {
"@typescript-eslint/prefer-nullish-coalescing": "off",
"@typescript-eslint/strict-boolean-expressions": "off",
"@typescript-eslint/no-explicit-any": "off",
"react/display-name": "off",
"react/prop-types": "off",
@ -86,6 +88,9 @@ const eslintConfig = {
},
],
},
parserOptions: {
tsconfigRootDir: __dirname,
},
};
eslintConfig.overrides = [

View File

@ -38,6 +38,7 @@ cypress/videos
cypress/screenshots
cypress/limited-tests.txt
cypress.env.json
cypress/cypress-logs
results/

View File

@ -3,8 +3,13 @@
is_server_change=$(git diff --cached --name-only | grep -c "app/server")
is_client_change=$(git diff --cached --name-only | grep -c "app/client")
if [ "$is_server_change" -ge 1 ]; then
echo "Running Spotless check ..."
is_merge_commit=$(git rev-parse -q --verify MERGE_HEAD)
if [ "$is_merge_commit" ]; then
echo "Skipping server and client checks for merge commit"
else
if [ "$is_server_change" -ge 1 ]; then
echo "Running Spotless check ..."
pushd app/server > /dev/null
if (mvn spotless:check 1> /dev/null && popd > /dev/null) then
popd
@ -12,13 +17,14 @@ if [ "$is_server_change" -ge 1 ]; then
echo "Spotless check failed, please run mvn spotless:apply"
exit 1
fi
else
echo "Skipping server side check..."
fi
else
echo "Skipping server side check..."
fi
if [ "$is_client_change" -ge 1 ]; then
echo "Running client check ..."
npx lint-staged --cwd app/client && git-secrets --scan --untracked && git-secrets --scan -r
else
echo "Skipping client side check..."
if [ "$is_client_change" -ge 1 ]; then
echo "Running client check ..."
npx lint-staged --cwd app/client
else
echo "Skipping client side check..."
fi
fi

View File

@ -1,8 +0,0 @@
{
"src/**/*.{js,ts,tsx}": ["npx eslint --fix"],
"src/**/*.{js,ts,tsx,css,md,json}": ["npx prettier --write"],
"cypress/**/*.{js,ts}": ["npx eslint --fix"],
"cypress/**/*.{js,ts,json}": ["npx prettier --write"],
"packages/**/*.{js,ts,tsx}": ["npx eslint --fix"],
"packages/**/*.{js,ts,tsx,css,mdx,json}": ["npx prettier --write"]
}

View File

@ -0,0 +1,11 @@
{
"src/**/*.{js,ts,tsx}": ["eslint --fix --cache"],
"src/**/*.{css,md,json}": ["prettier --write --cache"],
"cypress/**/*.{js,ts}": [
"cd ./cypress && eslint -c .eslintrc.json --fix --cache"
],
"cypress/**/*.json": ["prettier --write --cache"],
"packages/**/*.{js,ts,tsx}": ["eslint --fix --cache"],
"packages/**/*.{css,mdx,json}": ["prettier --write --cache"],
"*": ["git-secrets --scan --cached"]
}

View File

@ -1,13 +1,8 @@
/* eslint-disable @typescript-eslint/no-var-requires */
const CracoAlias = require("craco-alias");
const CracoLessPlugin = require("craco-less");
const {
DefinePlugin,
EnvironmentPlugin
} = require("webpack");
const {
merge
} = require("webpack-merge");
const { DefinePlugin, EnvironmentPlugin } = require("webpack");
const { merge } = require("webpack-merge");
const CracoBabelLoader = require("craco-babel-loader");
const path = require("path");
const webpack = require("webpack");
@ -44,25 +39,78 @@ module.exports = {
},
},
module: {
rules: [{
test: /\.m?js/,
resolve: {
fullySpecified: false,
rules: [
{
test: /\.m?js/,
resolve: {
fullySpecified: false,
},
},
}, ],
{
test: /\.module\.css$/,
use: [
{
loader: "postcss-loader",
options: {
postcssOptions: {
plugins: [
"postcss-nesting",
"postcss-import",
"postcss-at-rules-variables",
"postcss-each",
"postcss-url",
"postcss-modules-values",
[
"cssnano",
{
preset: ["default"],
},
],
],
},
},
},
],
},
],
},
optimization: {
splitChunks: {
cacheGroups: {
icons: {
// This determines which modules are considered icons
test: (module) => {},
test: (module) => {
const modulePath = module.resource;
if (!modulePath) return false;
return (
modulePath.match(
/node_modules[\\\/]remixicon-react[\\\/]/,
) ||
modulePath.endsWith(".svg.js") ||
modulePath.endsWith(".svg")
);
},
// This determines which chunk to put the icon into.
//
// Why have three separate cache groups for three different kinds of
// icons? Purely as an optimization: not every page needs all icons,
// so we can avoid loading unused icons sometimes.
name: (module) => {},
name: (module) => {
if (
module.resource?.match(
/node_modules[\\\/]remixicon-react[\\\/]/,
)
) {
return "remix-icons";
}
if (module.resource?.includes("blueprint")) {
return "blueprint-icons";
}
return "svg-icons";
},
// This specifies that only icons from import()ed chunks should be moved
chunks: "async",
// This makes webpack ignore the minimum chunk size requirement
@ -93,10 +141,8 @@ module.exports = {
],
};
const scopePluginIndex = webpackConfig.resolve.plugins.findIndex(
({
constructor
}) =>
constructor && constructor.name === "ModuleScopePlugin",
({ constructor }) =>
constructor && constructor.name === "ModuleScopePlugin",
);
webpackConfig.resolve.plugins.splice(scopePluginIndex, 1);
return merge(webpackConfig, config);
@ -131,10 +177,10 @@ module.exports = {
],
},
},
},
},
plugins: [{
plugins: [
{
plugin: CracoAlias,
options: {
source: "tsconfig",
@ -175,9 +221,7 @@ module.exports = {
// This matters for cases where `src/<dirname>` and `node_modules/<dirname>` both exist
// e.g., when `<dirname>` is `entities`: https://github.com/appsmithorg/appsmith/pull/20964#discussion_r1124782356
plugin: {
overrideWebpackConfig: ({
webpackConfig
}) => {
overrideWebpackConfig: ({ webpackConfig }) => {
webpackConfig.resolve.modules = [
path.resolve(__dirname, "src"),
...webpackConfig.resolve.modules,

View File

@ -6,8 +6,7 @@ export default defineConfig({
requestTimeout: 60000,
responseTimeout: 60000,
pageLoadTimeout: 60000,
videoUploadOnPasses: false,
videoCompression: false,
video: true,
numTestsKeptInMemory: 5,
experimentalMemoryManagement: true,
reporterOptions: {

View File

@ -1,9 +1,12 @@
{
"extends": ["../.eslintrc.base.json"],
"ignorePatterns": ["locators", "fixtures"],
"env": {
"cypress/globals": true
},
"rules": {
"@typescript-eslint/prefer-nullish-coalescing": "off",
"@typescript-eslint/strict-boolean-expressions": "off",
"@typescript-eslint/no-array-constructor": "off",
"@typescript-eslint/no-namespace": "off",
"@typescript-eslint/no-unused-vars": "off",

View File

@ -1,187 +0,0 @@
/* eslint-disable no-console */
import globby from "globby";
import minimatch from "minimatch";
import { exec } from "child_process";
const fs = require("fs/promises");
type GetEnvOptions = {
required?: boolean;
};
// some default properties
const ignoreTestFiles = [
"cypress/e2e/**/spec_utility.ts",
"cypress/e2e/GSheet/**/*",
];
// used to roughly determine how many tests are in a file
const testPattern = /(^|\s)(it)\(/g;
// This function will get all the spec paths using the pattern
async function getSpecFilePaths(specPattern: any): Promise<string[]> {
const files = globby.sync(specPattern, {
ignore: ignoreTestFiles,
});
// ignore the files that doesn't match
const ignorePatterns = [...(ignoreTestFiles || [])];
// a function which returns true if the file does NOT match
const doesNotMatchAllIgnoredPatterns = (file: string) => {
// using {dot: true} here so that folders with a '.' in them are matched
const MINIMATCH_OPTIONS = { dot: true, matchBase: true };
return ignorePatterns.every((pattern) => {
return !minimatch(file, pattern, MINIMATCH_OPTIONS);
});
};
const filtered = files.filter(doesNotMatchAllIgnoredPatterns);
return filtered;
}
// This function will determine the test counts in each file to sort it further
async function getTestCount(filePath: string): Promise<number> {
const content = await fs.readFile(filePath, "utf8");
return content.match(testPattern)?.length || 0;
}
// Sorting the spec files as per the test count in it
async function sortSpecFilesByTestCount(
specPathsOriginal: string[],
): Promise<string[]> {
const specPaths = [...specPathsOriginal];
const testPerSpec: Record<string, number> = {};
for (const specPath of specPaths) {
testPerSpec[specPath] = await getTestCount(specPath);
}
return (
Object.entries(testPerSpec)
// Sort by the number of tests per spec file. And this will create a consistent file list/ordering so that file division proper.
.sort((a, b) => b[1] - a[1])
.map((x) => x[0])
);
}
// This function will split the specs between the runners by calculating the modulus between spec index and the totalRunners
function splitSpecs(
specs: string[],
totalRunnersCount: number,
currentRunner: number,
): string[] {
let specs_to_run = specs.filter((_, index) => {
return index % totalRunnersCount === currentRunner;
});
return specs_to_run;
}
// This function will finally get the specs as a comma separated string to pass the specs to the command
async function getSpecsToRun(
totalRunnersCount = 0,
currentRunner = 0,
specPattern = "cypress/e2e/**/**/*.{js,ts}",
): Promise<string> {
{
try {
const specFilePaths = await sortSpecFilesByTestCount(
await getSpecFilePaths(specPattern),
);
if (!specFilePaths.length) {
throw Error("No spec files found.");
}
const specsToRun = splitSpecs(
specFilePaths,
totalRunnersCount,
currentRunner,
);
return specsToRun.join(",");
} catch (err) {
console.error(err);
process.exit(1);
}
}
}
// This function will help to get and convert the env variables
function getEnvNumber(
varName: string,
{ required = false }: GetEnvOptions = {},
): number {
if (required && process.env[varName] === undefined) {
throw Error(`${varName} is not set.`);
}
const value = Number(process.env[varName]);
if (isNaN(value)) {
throw Error(`${varName} is not a number.`);
}
return value;
}
// This function will helps to check and get env variables
function getEnvValue(
varName: string,
{ required = false }: GetEnvOptions = {},
) {
if (required && process.env[varName] === undefined) {
throw Error(`${varName} is not set.`);
}
const value = process.env[varName] === undefined ? "" : process.env[varName];
return value;
}
// This is to fetch the env variables from CI
function getArgs() {
return {
totalRunners: getEnvNumber("TOTAL_RUNNERS", { required: true }),
thisRunner: getEnvNumber("THIS_RUNNER", { required: true }),
specsPattern: getEnvValue("CYPRESS_SPEC_PATTERN", { required: true }),
env: getEnvValue("CYPRESS_ENV", { required: false }),
configFile: getEnvValue("CYPRESS_CONFIG_FILE", { required: false }),
headless: getEnvValue("CYPRESS_HEADLESS", { required: false }),
browser: getEnvValue("CYPRESS_BROWSER", { required: false }),
};
}
// This will finally segregate the specs and run the command to execute cypress
(async () => {
try {
const {
browser,
configFile,
env,
headless,
specsPattern,
thisRunner,
totalRunners,
} = getArgs();
let command = "yarn cypress run ";
command += browser != "" ? `--browser ${browser} ` : "";
command += configFile != "" ? `--config-file ${configFile} ` : "";
command += env != "" ? `--env ${env} ` : "";
command += headless == "false" ? `--headed ` : "";
const specs = await getSpecsToRun(totalRunners, thisRunner, specsPattern);
const final_command = `${command} --spec "${specs}"`;
const commandProcess = exec(final_command);
// pipe output because we want to see the results of the run
if (commandProcess.stdout) {
commandProcess.stdout.pipe(process.stdout);
}
if (commandProcess.stderr) {
commandProcess.stderr.pipe(process.stderr);
}
commandProcess.on("exit", (code) => {
process.exit(code || 0);
});
} catch (err) {
console.error(err);
process.exit(1);
}
})();

View File

@ -6,6 +6,9 @@ import {
dataSources,
agHelper,
entityExplorer,
table,
assertHelper,
appSettings,
} from "../../support/Objects/ObjectsCore";
const workspaceName = "gsheet apps";
@ -22,8 +25,7 @@ describe("GSheet-Functional Tests With All Access", function () {
//Adding query to insert a new spreadsheet
homePage.NavigateToHome();
homePage.CreateAppInWorkspace(workspaceName);
homePage.RenameApplication(appName);
homePage.CreateAppInWorkspace(workspaceName, appName);
gsheetHelper.AddNewSpreadsheetQuery(
dataSourceName,
spreadSheetName,
@ -173,21 +175,20 @@ describe("GSheet-Functional Tests With All Access", function () {
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");
dataSources.ValidateNSelectDropdown(
"Filter Format",
"Where Clause",
"Cell range",
);
agHelper.EnterValue("A2:A5", {
propFieldName: "",
directInput: false,
inputFieldName: "Cell range",
});
dataSources.RunQuery();
dataSources.RunQueryNVerifyResponseViews(4);
dataSources.AssertQueryTableResponse(0, "eac7efa5dbd3d667f26eb3d3ab504464");
});
it("5. Update a record which is not present and verify the error", () => {
@ -286,8 +287,44 @@ describe("GSheet-Functional Tests With All Access", function () {
});
});
it("8. Import an app with all access sheet", function () {
homePage.NavigateToHome();
homePage.ImportApp("ImportAppAllAccess.json", workspaceName);
assertHelper.WaitForNetworkCall("importNewApplication").then(() => {
agHelper.Sleep();
//Validate table is not empty!
table.WaitUntilTableLoad(0, 0, "v2");
});
// Assert table data
table.ReadTableRowColumnData(0, 0, "v2").then((cellData) => {
expect(cellData).to.eq("eac7efa5dbd3d667f26eb3d3ab504464");
});
homePage.NavigateToHome();
homePage.DeleteApplication("ImportAppAllAccess");
});
it("9. App level import of app with all access gsheet", function () {
homePage.CreateAppInWorkspace(workspaceName, "AppLevelImport");
appSettings.OpenAppSettings();
appSettings.GoToImport();
agHelper.ClickButton("Import");
homePage.ImportApp("ImportAppAllAccess.json", "", true);
cy.wait("@importNewApplication").then(() => {
agHelper.Sleep();
agHelper.RefreshPage();
table.WaitUntilTableLoad(0, 0, "v2");
});
// Assert table data
table.ReadTableRowColumnData(0, 0, "v2").then((cellData) => {
expect(cellData).to.eq("eac7efa5dbd3d667f26eb3d3ab504464");
});
homePage.NavigateToHome();
homePage.DeleteApplication("AppLevelImport");
});
after("Delete spreadsheet and app", function () {
// Delete spreadsheet and app
homePage.SearchAndOpenApp(appName);
gsheetHelper.DeleteSpreadsheetQuery(dataSourceName, spreadSheetName);
cy.get("@postExecute").then((interception: any) => {
expect(interception.response.body.data.body.message).to.deep.equal(

View File

@ -11,6 +11,7 @@ import {
deployMode,
locators,
draggableWidgets,
appSettings,
} from "../../support/Objects/ObjectsCore";
const workspaceName = "gsheet apps";
@ -45,6 +46,7 @@ describe("GSheet Miscellaneous Tests", function () {
JSON.stringify(GSHEET_DATA),
);
cy.get("@postExecute").then((interception: any) => {
agHelper.Sleep();
expect(
interception.response.body.data.body.properties.title,
).to.deep.equal(spreadSheetName);
@ -119,7 +121,7 @@ describe("GSheet Miscellaneous Tests", function () {
assertHelper.AssertNetworkStatus("@getActions", 200);
assertHelper.AssertNetworkStatus("@postExecute", 200);
assertHelper.AssertNetworkStatus("@updateLayout", 200);
agHelper.GetNClick(dataSources._visibleTextSpan("Got it"));
agHelper.ClickButton("Got it");
assertHelper.AssertNetworkStatus("@updateLayout", 200);
//deploy the app and verify the table data
@ -176,7 +178,7 @@ describe("GSheet Miscellaneous Tests", function () {
assertHelper.AssertNetworkStatus("@getActions", 200);
assertHelper.AssertNetworkStatus("@postExecute", 200);
assertHelper.AssertNetworkStatus("@updateLayout", 200);
agHelper.GetNClick(dataSources._visibleTextSpan("Got it"));
agHelper.ClickButton("Got it");
assertHelper.AssertNetworkStatus("@updateLayout", 200);
//deploy the app and verify the table data
@ -212,8 +214,62 @@ describe("GSheet Miscellaneous Tests", function () {
table.WaitUntilTableLoad();
});
it("6. Bug: 16391 - Verify placeholder texts for insert one/many queries", function () {
// Verify place holder text for Insert one query
let placeholderText =
'{\n "name": {{nameInput.text}},\n "dob": {{dobPicker.formattedDate}},\n "gender": {{genderSelect.selectedOptionValue}} \n}';
gsheetHelper.EnterBasicQueryValues(
"Insert One",
dataSourceName,
spreadSheetName,
false,
);
agHelper.AssertText(
dataSources._gSheetQueryPlaceholder,
"text",
placeholderText,
);
// Verify place holder text for Insert many query
placeholderText =
'[{\n "name": {{nameInput.text}},\n "dob": {{dobPicker.formattedDate}},\n "gender": {{genderSelect.selectedOptionValue}} \n}]';
gsheetHelper.EnterBasicQueryValues(
"Insert Many",
dataSourceName,
spreadSheetName,
false,
);
agHelper.AssertText(
dataSources._gSheetQueryPlaceholder,
"text",
placeholderText,
);
});
// This test is commented since we can't use Cypress to go to the Google authorization screen. We will uncomment it whenever we figure out how to do it.
// it("7. Bug#26024 App level import of gsheet app", function () {
// homePage.NavigateToHome();
// homePage.CreateNewWorkspace("AppLevelImport");
// homePage.CreateAppInWorkspace("AppLevelImport", "AppLevelImportCheck");
// appSettings.OpenAppSettings();
// appSettings.GoToImport();
// agHelper.ClickButton("Import");
// homePage.ImportApp("ImportAppAllAccess.json", "", true);
// cy.wait("@importNewApplication").then(() => {
// agHelper.Sleep();
// agHelper.ClickButton("Save & Authorize");
// });
// cy.url().should("contain", "accounts.google.com");
// homePage.NavigateToHome();
// homePage.DeleteApplication("AppLevelImportCheck");
// homePage.DeleteWorkspace("AppLevelImport");
// });
after("Delete spreadsheet and app", function () {
// Delete spreadsheet and app
homePage.NavigateToHome();
homePage.SearchAndOpenApp(appName);
gsheetHelper.DeleteSpreadsheetQuery(dataSourceName, spreadSheetName);
cy.get("@postExecute").then((interception: any) => {
expect(interception.response.body.data.body.message).to.deep.equal(

View File

@ -6,6 +6,9 @@ import {
dataSources,
agHelper,
entityExplorer,
assertHelper,
table,
appSettings,
} from "../../support/Objects/ObjectsCore";
describe("GSheet-Functional Tests With Read/Write Access", function () {
@ -26,8 +29,7 @@ describe("GSheet-Functional Tests With Read/Write Access", function () {
//Adding query to insert a new spreadsheet
homePage.NavigateToHome();
homePage.CreateAppInWorkspace(workspaceName);
homePage.RenameApplication(appName);
homePage.CreateAppInWorkspace(workspaceName, appName);
gsheetHelper.AddNewSpreadsheetQuery(
dataSourceName.readNWrite,
spreadSheetName,
@ -170,21 +172,20 @@ describe("GSheet-Functional Tests With Read/Write Access", function () {
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");
dataSources.ValidateNSelectDropdown(
"Filter Format",
"Where Clause",
"Cell range",
);
agHelper.EnterValue("A2:A5", {
propFieldName: "",
directInput: false,
inputFieldName: "Cell range",
});
dataSources.RunQuery();
dataSources.RunQueryNVerifyResponseViews(4);
dataSources.AssertQueryTableResponse(0, "eac7efa5dbd3d667f26eb3d3ab504464");
});
it("5. Update a record which is not present and verify the error", () => {
@ -297,8 +298,44 @@ describe("GSheet-Functional Tests With Read/Write Access", function () {
});
});
it("9. Import an app with read write access sheet", function () {
homePage.NavigateToHome();
homePage.ImportApp("ImportAppReadWriteAccess.json", workspaceName);
assertHelper.WaitForNetworkCall("importNewApplication").then(() => {
agHelper.Sleep();
//Validate table is not empty!
table.WaitUntilTableLoad(0, 0, "v2");
});
// Assert table data
table.ReadTableRowColumnData(0, 0, "v2").then((cellData) => {
expect(cellData).to.eq("eac7efa5dbd3d667f26eb3d3ab504464");
});
homePage.NavigateToHome();
homePage.DeleteApplication("ImportAppReadWriteAccess");
});
it("10. App level import of app with read and write access gsheet", function () {
homePage.CreateAppInWorkspace(workspaceName, "AppLevelImportReadNWrite");
appSettings.OpenAppSettings();
appSettings.GoToImport();
agHelper.ClickButton("Import");
homePage.ImportApp("ImportAppReadWriteAccess.json", "", true);
cy.wait("@importNewApplication").then(() => {
agHelper.Sleep();
agHelper.RefreshPage();
table.WaitUntilTableLoad(0, 0, "v2");
});
// Assert table data
table.ReadTableRowColumnData(0, 0, "v2").then((cellData) => {
expect(cellData).to.eq("eac7efa5dbd3d667f26eb3d3ab504464");
});
homePage.NavigateToHome();
homePage.DeleteApplication("AppLevelImportReadNWrite");
});
after("Delete spreadsheet and app", function () {
// Delete spreadsheet and app
homePage.SearchAndOpenApp(appName);
gsheetHelper.DeleteSpreadsheetQuery(
dataSourceName.allAccess,
spreadSheetName,

View File

@ -6,6 +6,9 @@ import {
dataSources,
agHelper,
entityExplorer,
assertHelper,
table,
appSettings,
} from "../../support/Objects/ObjectsCore";
describe("GSheet-Functional Tests With Read Access", function () {
@ -26,8 +29,7 @@ describe("GSheet-Functional Tests With Read Access", function () {
//Adding query to insert a new spreadsheet
homePage.NavigateToHome();
homePage.CreateAppInWorkspace(workspaceName);
homePage.RenameApplication(appName);
homePage.CreateAppInWorkspace(workspaceName, appName);
gsheetHelper.AddNewSpreadsheetQuery(
dataSourceName.allAccess,
spreadSheetName,
@ -178,21 +180,20 @@ describe("GSheet-Functional Tests With Read Access", function () {
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");
dataSources.ValidateNSelectDropdown(
"Filter Format",
"Where Clause",
"Cell range",
);
agHelper.EnterValue("A2:A5", {
propFieldName: "",
directInput: false,
inputFieldName: "Cell range",
});
dataSources.RunQuery();
dataSources.RunQueryNVerifyResponseViews(4);
dataSources.AssertQueryTableResponse(0, "eac7efa5dbd3d667f26eb3d3ab504464");
});
it("5. Convert field to JS and verify", () => {
@ -279,8 +280,47 @@ describe("GSheet-Functional Tests With Read Access", function () {
});
});
it("8. Import an app with read only access sheet", function () {
homePage.NavigateToHome();
homePage.ImportApp("ImportAppReadAccess.json", workspaceName);
assertHelper.WaitForNetworkCall("importNewApplication").then(() => {
agHelper.Sleep();
//Validate table is not empty!
table.WaitUntilTableLoad(0, 0, "v2");
});
// Assert table data
table.ReadTableRowColumnData(0, 0, "v2").then((cellData) => {
expect(cellData).to.eq("eac7efa5dbd3d667f26eb3d3ab504464");
});
homePage.NavigateToHome();
homePage.DeleteApplication("ImportAppReadAccess");
});
it("9. App level import of app with read only access gsheet", function () {
homePage.CreateAppInWorkspace(
workspaceName,
"AppLevelImportReadOnlyAccess",
);
appSettings.OpenAppSettings();
appSettings.GoToImport();
agHelper.ClickButton("Import");
homePage.ImportApp("ImportAppReadAccess.json", "", true);
cy.wait("@importNewApplication").then(() => {
agHelper.Sleep();
agHelper.RefreshPage();
table.WaitUntilTableLoad(0, 0, "v2");
});
// Assert table data
table.ReadTableRowColumnData(0, 0, "v2").then((cellData) => {
expect(cellData).to.eq("eac7efa5dbd3d667f26eb3d3ab504464");
});
homePage.NavigateToHome();
homePage.DeleteApplication("AppLevelImportReadOnlyAccess");
});
after("Delete spreadsheet and app", function () {
// Delete spreadsheet and app
homePage.SearchAndOpenApp(appName);
gsheetHelper.DeleteSpreadsheetQuery(
dataSourceName.allAccess,
spreadSheetName,

View File

@ -6,6 +6,9 @@ import {
dataSources,
agHelper,
entityExplorer,
assertHelper,
table,
appSettings,
} from "../../support/Objects/ObjectsCore";
const workspaceName = "gsheet apps";
@ -20,8 +23,7 @@ describe("GSheet-Functional Tests With Selected Access", function () {
//Adding app
homePage.NavigateToHome();
homePage.CreateAppInWorkspace(workspaceName);
homePage.RenameApplication(appName);
homePage.CreateAppInWorkspace(workspaceName, appName);
});
it("1. Add and verify fetch details query", () => {
@ -161,21 +163,20 @@ describe("GSheet-Functional Tests With Selected Access", function () {
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");
dataSources.ValidateNSelectDropdown(
"Filter Format",
"Where Clause",
"Cell range",
);
agHelper.EnterValue("A2:A5", {
propFieldName: "",
directInput: false,
inputFieldName: "Cell range",
});
dataSources.RunQuery();
dataSources.RunQueryNVerifyResponseViews(4);
dataSources.AssertQueryTableResponse(0, "eac7efa5dbd3d667f26eb3d3ab504464");
});
it("5. Update a record which is not present and verify the error", () => {
@ -291,9 +292,46 @@ describe("GSheet-Functional Tests With Selected Access", function () {
});
});
it("8. Import an app with selected access sheet", function () {
homePage.NavigateToHome();
homePage.ImportApp("ImportAppSelectedAccess.json", workspaceName);
assertHelper.WaitForNetworkCall("importNewApplication").then(() => {
agHelper.Sleep();
//Validate table is not empty!
table.WaitUntilTableLoad(0, 0, "v2");
});
// Assert table data
table.ReadTableRowColumnData(0, 0, "v2").then((cellData) => {
expect(cellData).to.eq("eac7efa5dbd3d667f26eb3d3ab504464");
});
homePage.NavigateToHome();
homePage.DeleteApplication("ImportAppSelectedAccess");
});
it("9. App level import of app with Selected sheet access gsheet", function () {
homePage.CreateAppInWorkspace(
workspaceName,
"AppLevelImportSelectedAccess",
);
appSettings.OpenAppSettings();
appSettings.GoToImport();
agHelper.ClickButton("Import");
homePage.ImportApp("ImportAppSelectedAccess.json", "", true);
cy.wait("@importNewApplication").then(() => {
agHelper.Sleep();
agHelper.RefreshPage();
table.WaitUntilTableLoad(0, 0, "v2");
});
// Assert table data
table.ReadTableRowColumnData(0, 0, "v2").then((cellData) => {
expect(cellData).to.eq("eac7efa5dbd3d667f26eb3d3ab504464");
});
homePage.NavigateToHome();
homePage.DeleteApplication("AppLevelImportSelectedAccess");
});
after("Delete app", function () {
// Delete app
homePage.NavigateToHome();
homePage.DeleteApplication(appName);
});
});

View File

@ -51,6 +51,7 @@ describe("GSheet-widget binding", function () {
// Adding suggested widgets and verify
dataSources.AddSuggestedWidget(Widgets.Table);
agHelper.RefreshPage();
table.ReadTableRowColumnData(0, 0, "v2").then((cellData) => {
expect(cellData).to.eq("eac7efa5dbd3d667f26eb3d3ab504464");
});

View File

@ -51,6 +51,7 @@ describe("GSheet-widget binding for selected sheet access", function () {
// Adding suggested widgets and verify
dataSources.AddSuggestedWidget(Widgets.Table);
agHelper.RefreshPage();
table.ReadTableRowColumnData(0, 0, "v2").then((cellData) => {
expect(cellData).to.eq("eac7efa5dbd3d667f26eb3d3ab504464");
});

View File

@ -9,6 +9,7 @@ import {
entityExplorer,
locators,
assertHelper,
draggableWidgets,
} from "../../../support/Objects/ObjectsCore";
describe("AForce - Community Issues page validations", function () {
@ -30,12 +31,15 @@ describe("AForce - Community Issues page validations", function () {
homePage.ImportApp("CommunityIssuesExport.json");
assertHelper
.WaitForNetworkCall("importNewApplication")
.then((interception: any) => {
.then((response: any) => {
agHelper.Sleep();
const { isPartialImport } = interception.response.body.data;
const { isPartialImport } = response.body.data;
if (isPartialImport) {
// should reconnect modal
dataSources.ReconnectSingleDSNAssert("AForceDB", "PostgreSQL");
dataSources.ReconnectSingleDSNAssert(
String.raw`AForceDB`,
"PostgreSQL",
);
homePage.AssertNCloseImport();
} else {
homePage.AssertImportToast();
@ -66,7 +70,7 @@ describe("AForce - Community Issues page validations", function () {
it("2. Validate table navigation with Server Side pagination enabled with Default selected row", () => {
entityExplorer.SelectEntityByName("Table1", "Widgets");
agHelper.AssertExistingToggleState("serversidepagination", "true");
agHelper.AssertExistingToggleState("Server side pagination", "true");
propPane
.ValidatePropertyFieldValue("Default selected row", "0")
@ -139,7 +143,7 @@ describe("AForce - Community Issues page validations", function () {
//propPane.EnterJSContext("Default search text", "Bug", false);
propPane.TypeTextIntoField("Default search text", "Bug");
deployMode.DeployApp();
table.AssertSearchText("Bug", 2);
table.AssertSearchText("Bug");
table.WaitUntilTableLoad(0, 0, "v2");
table.WaitUntilTableLoad(0, 0, "v2");
deployMode.NavigateBacktoEditor();
@ -149,7 +153,7 @@ describe("AForce - Community Issues page validations", function () {
propPane.TypeTextIntoField("Default search text", "Quest", true, false);
deployMode.DeployApp();
table.AssertSearchText("Quest", 2);
table.AssertSearchText("Quest");
table.WaitUntilTableLoad(0, 0, "v2");
deployMode.NavigateBacktoEditor();
table.WaitUntilTableLoad();
@ -168,42 +172,75 @@ describe("AForce - Community Issues page validations", function () {
table.WaitUntilTableLoad(0, 0, "v2");
});
it.skip("6. Validate Search table with Client Side Search enabled & disabled", () => {
it("6. Validate Search table with Client Side Search enabled & disabled & onSearchTextChanged is set", () => {
entityExplorer.SelectEntityByName("Table1", "Widgets");
agHelper.AssertExistingToggleState("clientsidesearch", "true");
agHelper.AssertExistingToggleState("Client side search", "true");
deployMode.DeployApp();
table.WaitUntilTableLoad();
deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.TABLE));
table.WaitUntilTableLoad(0, 1, "v2");
table.SearchTable("Bug", 2);
table.WaitUntilTableLoad(0, 0, "v2");
cy.xpath(table._searchBoxCross).click();
table.SearchTable("Best");
table.WaitUntilTableLoad(0, 1, "v2");
table.ResetSearch();
table.SearchTable("Quest");
table.WaitUntilTableLoad(0, 0, "v2");
cy.xpath(table._searchBoxCross).click();
table.WaitUntilTableLoad(0, 1, "v2");
table.ResetSearch();
deployMode.NavigateBacktoEditor();
table.WaitUntilTableLoad();
table.WaitUntilTableLoad(0, 1, "v2");
entityExplorer.SelectEntityByName("Table1", "Widgets");
propPane.TogglePropertyState("Client side search", "Off");
deployMode.DeployApp();
table.WaitUntilTableLoad();
deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.TABLE));
table.WaitUntilTableLoad(0, 1, "v2");
table.SearchTable("Bug", 2);
table.WaitForTableEmpty("v2");
cy.xpath(table._searchBoxCross).click();
table.SearchTable("Bug");
table.WaitUntilTableLoad(0, 1, "v2"); //Since onSearchTextChanged is set , Search is queried for Search text with Client side search On or Off
table.ResetSearch();
table.SearchTable("Quest");
table.WaitForTableEmpty("v2");
cy.xpath(table._searchBoxCross).click();
table.WaitUntilTableLoad(0, 1, "v2");
table.ResetSearch();
//Remove onSearchTextChanged & test
deployMode.NavigateBacktoEditor();
table.WaitUntilTableLoad(0, 0, "v2");
table.WaitUntilTableLoad(0, 1, "v2");
entityExplorer.SelectEntityByName("Table1", "Widgets");
propPane.TogglePropertyState("Client side search", "On");
propPane.EnterJSContext("onSearchTextChanged", "");
propPane.ToggleJSMode("onSearchTextChanged", false);
deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.TABLE));
table.WaitUntilTableLoad(0, 1, "v2");
table.SearchTable("Xano");
table.WaitForTableEmpty("v2"); //Since Xano is present in 2nd page & Client side search is On
table.ResetSearch();
table.SearchTable("SSL");
table.WaitUntilTableLoad(0, 1, "v2"); //as 1st page has SSL entries
table.ResetSearch();
//if the client side search is off, and there is no text in onSearchTextChanged, we still go ahead with client side search. this is a known limitation deployMode.NavigateBacktoEditor();
deployMode.NavigateBacktoEditor();
table.WaitUntilTableLoad(0, 1, "v2");
entityExplorer.SelectEntityByName("Table1", "Widgets");
propPane.TogglePropertyState("Client side search", "Off");
deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.TABLE));
table.WaitUntilTableLoad(0, 1, "v2");
table.SearchTable("Xano");
table.WaitForTableEmpty("v2"); //Since Xano is present in 2nd page & Client side search is Off
table.ResetSearch();
table.SearchTable("SSL");
table.WaitUntilTableLoad(0, 1, "v2"); //as 1st page has SSL entries
table.ResetSearch();
deployMode.NavigateBacktoEditor();
});
it("7. Validate Filter table", () => {
@ -293,8 +330,8 @@ describe("AForce - Community Issues page validations", function () {
agHelper.ClickButton("Confirm");
agHelper.AssertElementAbsence(locators._toastMsg); //Making sure internal api doesnt throw error
agHelper.Sleep(3000);
table.SearchTable("Suggestion", 2);
table.WaitUntilTableLoad();
table.SearchTable("Suggestion");
table.WaitUntilTableLoad(0, 0, "v2");
table.ReadTableRowColumnData(0, 0, "v1", 4000).then((cellData) => {
expect(cellData).to.be.equal("Suggestion");
@ -311,6 +348,7 @@ describe("AForce - Community Issues page validations", function () {
agHelper.Sleep(2000);
table.SelectTableRow(0, 1, true, "v2");
agHelper.AssertElementVisibility(locators._widgetInDeployed("tabswidget"));
agHelper.Sleep(2000);
agHelper
.GetNClick(locators._inputWidgetv1InDeployed, 0, true, 0)
.type("-updating title");

View File

@ -117,26 +117,23 @@ describe("Content Management System App", function () {
gitSync.CreateNConnectToGit(repoName);
cy.get("@gitRepoName").then((repName) => {
repoName = repName;
});
cy.latestDeployPreview();
cy.wait(2000);
cy.xpath("//span[text()='Curt50@gmail.com']")
.should("be.visible")
.click({ force: true });
cy.get(appPage.mailButton).closest("div").click();
cy.xpath(appPage.sendMailText).should("be.visible");
cy.xpath(appPage.subjectField).type("Test");
cy.get(appPage.contentField)
.last()
.find("textarea")
.type("Task completed", { force: true });
cy.get(appPage.confirmButton).closest("div").click({ force: true });
cy.get(appPage.closeButton).closest("div").click({ force: true });
deployMode.NavigateBacktoEditor();
});
after(() => {
//clean up
gitSync.DeleteTestGithubRepo(repoName);
cy.latestDeployPreview();
cy.wait(2000);
cy.xpath("//span[text()='Curt50@gmail.com']")
.should("be.visible")
.click({ force: true });
cy.get(appPage.mailButton).closest("div").click();
cy.xpath(appPage.sendMailText).should("be.visible");
cy.xpath(appPage.subjectField).type("Test");
cy.get(appPage.contentField)
.last()
.find("textarea")
.type("Task completed", { force: true });
cy.get(appPage.confirmButton).closest("div").click({ force: true });
cy.get(appPage.closeButton).closest("div").click({ force: true });
deployMode.NavigateBacktoEditor();
gitSync.DeleteTestGithubRepo(repoName);
});
});
});

View File

@ -4,6 +4,7 @@ import {
jsEditor,
apiPage,
dataManager,
assertHelper,
} from "../../../support/Objects/ObjectsCore";
const commonlocators = require("../../../locators/commonlocators.json");
@ -84,46 +85,38 @@ describe("JSEditor tests", function () {
);
});
// move to page 2 on table widget
cy.get(commonlocators.tableNextPage).click();
agHelper.GetNClick(commonlocators.tableNextPage);
cy.get(".t--table-widget-page-input").within(() => {
cy.get("input.bp3-input").should("have.value", "2");
});
cy.wait(3000);
cy.wait(1000);
// hit audio play button and trigger actions
/* cy.openPropertyPane("audiowidget");
cy.get(widgetsPage.autoPlay).click({ force: true });
cy.wait("@postExecute").should(
"have.nested.property",
"response.body.responseMeta.status",
200,
entityExplorer.SelectEntityByName("Audio1", "Widgets");
agHelper.GetElement("audio").then(($audio) => {
$audio[0].play();
});
assertHelper.AssertNetworkStatus("@postExecute");
// verify text is visible
agHelper.AssertContains(
"Step 4: Value is Green and will default to GREEN",
"be.visible",
".t--draggable-textwidget span",
);
cy.wait(1000)
// verify text is visible
cy.get(".t--draggable-textwidget span")
.eq(2)
.invoke("text")
.then((text) => {
expect(text).to.equal("Step 4: Value is Green and will default to Green");
});
cy.get(commonlocators.tableNextPage).click()
cy.get('.t--table-widget-page-input').within(()=>{
cy.get('input.bp3-input').should('have.value', '1')
})
cy.get(homePageLocators.toastMessage).should(
"contain",
"Success running API query",
"GREEN",
); */
agHelper.GetNClick(commonlocators.tableNextPage);
agHelper.ValidateToastMessage("Success running API query");
agHelper.ValidateToastMessage("GREEN");
agHelper.GetElement(".t--table-widget-page-input").within(() => {
agHelper.ValidateFieldInputValue("input.bp3-input", "2");
});
});
//Skipping reason? to add
it.skip("2. Testing dynamic widgets display using consecutive storeValue calls", () => {
it("2. Testing dynamic widgets display using consecutive storeValue calls", () => {
entityExplorer.SelectEntityByName("JSObject1", "Queries/JS");
jsEditor.SelectFunctionDropdown("clearStore");
jsEditor.RunJSObj();
cy.wait("@postExecute")
.its("response.body.responseMeta.status")
.should("eq", 200);
entityExplorer.SelectEntityByName("Page1", "Pages");
cy.xpath("//span[text()='Clear store']").click({ force: true });
cy.get(".t--draggable-textwidget span")
.eq(5)

View File

@ -1,19 +1,16 @@
import {
agHelper,
draggableWidgets,
entityExplorer,
locators,
propPane,
} from "../../../../support/Objects/ObjectsCore";
describe("JS to non-JS mode in Action Selector", () => {
before(() => {
agHelper.AddDsl("promisesBtnDsl", locators._buttonByText("Submit"));
entityExplorer.DragDropWidgetNVerify(draggableWidgets.BUTTON);
});
it("1. shows fields for navigate to from js to non-js mode", () => {
entityExplorer.SelectEntityByName("Page1", "Pages");
entityExplorer.SelectEntityByName("Button1", "Widgets");
propPane.EnterJSContext("onClick", "{{navigateTo()}}", true, false);
propPane.ToggleJSMode("onClick", false);
@ -508,7 +505,7 @@ describe("JS to non-JS mode in Action Selector", () => {
propPane.ToggleJSMode("onClick");
propPane.ValidatePropertyFieldValue(
"onClick",
`{{copyToClipboard('line1\\nline2\\nline3a');}}`,
`{{copyToClipboard('aline1\\nline2\\nline3');}}`,
);
});

View File

@ -251,16 +251,16 @@ describe("JS to non-JS mode in Action Selector", () => {
0,
);
agHelper.GetNAssertElementText(
propPane._actionPopupTextLabel,
"Target iframe",
propPane._windowTargetDropdown,
"Window",
"have.text",
1,
0,
);
agHelper.GetNAssertElementText(
propPane._actionPopupTextLabel,
"Allowed origins",
"have.text",
2,
1,
);
propPane.EnterJSContext(

View File

@ -15,7 +15,8 @@ describe("Post window message", () => {
entityExplorer.SelectEntityByName("Button1", "Widgets");
propPane.SelectPlatformFunction("onClick", "Post message");
agHelper.EnterActionValue("Message", "After postMessage");
agHelper.EnterActionValue("Target iframe", "Iframe1");
agHelper.GetNClick(propPane._windowTargetDropdown);
agHelper.GetNClick(locators._dropDownValue("Iframe1"), 0, true);
entityExplorer.SelectEntityByName("Iframe1", "Widgets");
propPane.UpdatePropertyFieldValue(

View File

@ -4,6 +4,7 @@ import {
jsEditor,
propPane,
deployMode,
debuggerHelper,
} from "../../../../support/Objects/ObjectsCore";
describe("storeValue Action test", () => {
@ -198,4 +199,40 @@ describe("storeValue Action test", () => {
agHelper.ValidateToastMessage(JSON.stringify(TEST_OBJECT), 0);
deployMode.NavigateBacktoEditor();
});
it("4. Bug 24882. StoreValue, removeValue and clearStore should emit platform generated logs", function () {
const jsObjectBody = `export default {
storeFns: () => {
storeValue("xyz", 123);
removeValue("xyz");
clearStore();
}
}`;
jsEditor.CreateJSObject(jsObjectBody, {
paste: true,
completeReplace: true,
toRun: true,
shouldCreateNewJSObj: true,
});
entityExplorer.DragDropWidgetNVerify("buttonwidget", 400, 400);
entityExplorer.SelectEntityByName("Button3", "Widgets");
propPane.UpdatePropertyFieldValue("Label", "Test store logs");
cy.get("@jsObjName").then((jsObj: any) => {
propPane.SelectJSFunctionToExecute(
"onClick",
jsObj as string,
"storeFns",
);
});
agHelper.ClickButton("Test store logs");
debuggerHelper.ClickDebuggerIcon();
debuggerHelper.ClickLogsTab();
debuggerHelper.changeLogsGroup("System logs");
debuggerHelper.DoesConsoleLogExist("storeValue('xyz', '123', true)");
debuggerHelper.DoesConsoleLogExist("removeValue('xyz')");
debuggerHelper.DoesConsoleLogExist("clearStore()");
});
});

View File

@ -36,7 +36,7 @@ describe("Admin settings page", function () {
cy.visit("/settings/general", { timeout: 60000 });
// non super users are redirected to home page
cy.url().should("contain", "/applications");
cy.LogOut();
cy.LogOut(false);
});
it("3. Should test that settings page is redirected to default tab", () => {
@ -62,8 +62,8 @@ describe("Admin settings page", function () {
cy.url().should("contain", "/settings/authentication");
cy.get(adminsSettings.emailTab).click();
cy.url().should("contain", "/settings/email");
cy.get(adminsSettings.googleMapsTab).click();
cy.url().should("contain", "/settings/google-maps");
cy.get(adminsSettings.developerSettingsTab).click();
cy.url().should("contain", "/settings/developer-settings");
cy.get(adminsSettings.versionTab).click();
cy.url().should("contain", "/settings/version");
},
@ -71,7 +71,7 @@ describe("Admin settings page", function () {
it(
"airgap",
"4. Should test that settings page tab redirects and google maps doesn't exist - airgap",
"4. Should test that settings page tab redirects and developer settings doesn't exist - airgap",
() => {
cy.visit("/applications", { timeout: 60000 });
if (!Cypress.env("AIRGAPPED")) {
@ -90,7 +90,7 @@ describe("Admin settings page", function () {
cy.url().should("contain", "/settings/authentication");
cy.get(adminsSettings.emailTab).click();
cy.url().should("contain", "/settings/email");
cy.get(adminsSettings.googleMapsTab).should("not.exist");
cy.get(adminsSettings.developerSettingsTab).should("not.exist");
cy.get(adminsSettings.versionTab).click();
cy.url().should("contain", "/settings/version");
},

View File

@ -3,9 +3,11 @@ import {
adminSettings,
} from "../../../../support/Objects/ObjectsCore";
import { CURRENT_REPO, REPO } from "../../../../fixtures/REPO";
import { featureFlagIntercept } from "../../../../support/Objects/FeatureFlags";
describe("Admin Settings Page - General page validations", () => {
it("1. TC# 2439 Verify 'Page title' changes upon changing Instance name", () => {
featureFlagIntercept({ license_branding_enabled: true });
adminSettings.NavigateToAdminSettings();
agHelper.ClearNType(adminSettings._instanceName, "Testing Instance name");
agHelper.ClickButton("Save");
@ -15,4 +17,12 @@ describe("Admin Settings Page - General page validations", () => {
else if (CURRENT_REPO === REPO.EE)
cy.title().should("eq", "Testing Instance name"); //verifying that Instance name is not changed in EE
});
it("2. TC# 2439 Verify 'Page title' does not change upon changing Instance name in free plan", () => {
featureFlagIntercept({ license_branding_enabled: false });
adminSettings.NavigateToAdminSettings();
agHelper.ClearNType(adminSettings._instanceName, "Testing Instance name 2");
agHelper.ClickButton("Save");
agHelper.ValidateToastMessage("Successfully saved");
cy.title().should("eq", "Appsmith");
});
});

View File

@ -48,9 +48,9 @@ describe("General checks for app navigation", function () {
homePage.ImportApp("appNavigationTestingApp.json");
assertHelper
.WaitForNetworkCall("@importNewApplication")
.then((interception) => {
.then((response) => {
agHelper.Sleep();
const { isPartialImport } = interception.response.body.data;
const { isPartialImport } = response.body.data;
if (isPartialImport) {
homePage.AssertNCloseImport();
} else {

View File

@ -14,9 +14,9 @@ describe("Test Sidebar navigation style", function () {
homePage.ImportApp("appNavigationTestingAppWithLongPageNamesAndTitle.json");
assertHelper
.WaitForNetworkCall("@importNewApplication")
.then((interception) => {
.then((response) => {
agHelper.Sleep();
const { isPartialImport } = interception.response.body.data;
const { isPartialImport } = response.body.data;
if (isPartialImport) {
homePage.AssertNCloseImport();
} else {

View File

@ -15,11 +15,9 @@ describe("Test Top + Inline navigation style", function () {
assertHelper
.WaitForNetworkCall("@importNewApplication")
.then((interception) => {
.then((response) => {
agHelper.Sleep();
const { isPartialImport } = interception.response.body.data;
const { isPartialImport } = response.body.data;
if (isPartialImport) {
homePage.AssertNCloseImport();
} else {

View File

@ -14,9 +14,9 @@ describe("Test Top + Stacked navigation style", function () {
homePage.ImportApp("appNavigationTestingAppWithLongPageNamesAndTitle.json");
assertHelper
.WaitForNetworkCall("importNewApplication")
.then((interception: any) => {
.then((response: any) => {
agHelper.Sleep();
const { isPartialImport } = interception.response.body.data;
const { isPartialImport } = response.body.data;
if (isPartialImport) {
homePage.AssertNCloseImport();
} else {

View File

@ -0,0 +1,150 @@
import {
agHelper,
locators,
entityExplorer,
jsEditor,
propPane,
apiPage,
dataManager,
} from "../../../../support/Objects/ObjectsCore";
describe("Assistive Binding", function () {
before(() => {
// Button1
entityExplorer.DragDropWidgetNVerify("buttonwidget", 200, 200);
// Create JSObject1
jsEditor.CreateJSObject(
`export default {
myFun1: ()=>{
f;
return "yes"
}
}`,
{
paste: true,
completeReplace: true,
toRun: false,
shouldCreateNewJSObj: true,
prettify: false,
},
);
// Create JSObject2
jsEditor.CreateJSObject(
`export default {
myFun1: ()=>{
f;
return "yes"
}
}`,
{
paste: true,
completeReplace: true,
toRun: false,
shouldCreateNewJSObj: true,
prettify: false,
},
);
// Create Api1
apiPage.CreateAndFillApi(
dataManager.dsValues[dataManager.defaultEnviorment].echoApiUrl,
);
// Create Api2
apiPage.CreateAndFillApi(
dataManager.dsValues[dataManager.defaultEnviorment].echoApiUrl,
);
});
it("1. Shows hints without curly braces when user types in data fields", () => {
entityExplorer.SelectEntityByName("Button1", "Widgets");
propPane.TypeTextIntoField("Label", "JS");
// Assert that no hint shows up when length of text is less than 3
agHelper.AssertElementAbsence(locators._hints);
propPane.TypeTextIntoField("Label", "JSo");
// Assert that hints show up when length of text is equal to or greater than 3
agHelper.AssertElementExist(locators._hints);
propPane.TypeTextIntoField("Label", "unknownVar");
// Assert that no hint shows up text doesn't match any entity name within the app
agHelper.AssertElementAbsence(locators._hints);
propPane.TypeTextIntoField("Label", "API");
// Assert that hints show up without considering capitalization
agHelper.AssertElementExist(locators._hints);
propPane.TypeTextIntoField("Label", "{");
// Assert that hints show up when 1 curly brace is entered
agHelper.AssertElementExist(locators._hints);
});
it("2. Selects correct value when hint is selected", () => {
entityExplorer.SelectEntityByName("Button1", "Widgets");
propPane.TypeTextIntoField("Label", "JSo");
agHelper.GetNClickByContains(locators._hints, "JSObject1.myFun1");
// After selecting "JSObject1.myFun1", expect "{{JSObject1.myFun1.data}}" in binding
propPane.ValidatePropertyFieldValue("Label", "{{JSObject1.myFun1.data}}");
propPane.TypeTextIntoField("Label", "Api");
agHelper.GetNClickByContains(locators._hints, "Api1");
// After selecting "Api1", expect "{{Api1.data}}" in binding
propPane.ValidatePropertyFieldValue("Label", "{{Api1.data}}");
});
it("3. Shows hints after every white space", () => {
entityExplorer.SelectEntityByName("Button1", "Widgets");
propPane.TypeTextIntoField("Label", "JSo JSo");
// Assert that hints show up when length of text after any previous blank space is equal to or greater than 3
agHelper.AssertElementExist(locators._hints);
entityExplorer.SelectEntityByName("Button1", "Widgets");
propPane.TypeTextIntoField("Label", "JSo tab\tJSo");
// Assert that hints show up when length of text after any previous tab is equal to or greater than 3
agHelper.AssertElementExist(locators._hints);
propPane.TypeTextIntoField("Label", "JSo \nJSo");
// Assert that hints show up when length of text after any previous new line is equal to or greater than 3
agHelper.AssertElementExist(locators._hints);
});
it("4. Selects correct value and inserts in right place when hint is selected after whitespace ", () => {
entityExplorer.SelectEntityByName("Button1", "Widgets");
propPane.TypeTextIntoField("Label", "JSo JSo");
agHelper.GetNClickByContains(locators._hints, "JSObject1.myFun1");
// After selecting "JSObject1.myFun1", expect "JSo {{JSObject1.myFun1.data}}" in binding
propPane.ValidatePropertyFieldValue(
"Label",
"JSo {{JSObject1.myFun1.data}}",
);
entityExplorer.SelectEntityByName("Button1", "Widgets");
propPane.TypeTextIntoField("Label", "JSo tab\tJSo");
agHelper.GetNClickByContains(locators._hints, "JSObject1.myFun1");
// After selecting "JSObject1.myFun1", expect "JSo tab {{JSObject1.myFun1.data}}" in binding
propPane.ValidatePropertyFieldValue(
"Label",
"JSo tab {{JSObject1.myFun1.data}}",
);
entityExplorer.SelectEntityByName("Button1", "Widgets");
propPane.TypeTextIntoField("Label", `JSo \nJSo`);
agHelper.GetNClickByContains(locators._hints, "JSObject1.myFun1");
// After selecting "JSObject1.myFun1", expect `JSo \n{{JSObject1.myFun1.data}}` in binding
propPane.ValidatePropertyFieldValue(
"Label",
`JSo {{JSObject1.myFun1.data}}`,
);
});
it("5. Partial binding {} syntax is replaced with correct values ", () => {
entityExplorer.SelectEntityByName("Button1", "Widgets");
propPane.TypeTextIntoField("Label", "{");
agHelper.GetNClickByContains(locators._hints, "JSObject1.myFun1");
// After selecting "JSObject1.myFun1", expect "{{JSObject1.myFun1.data}}" in binding
propPane.ValidatePropertyFieldValue("Label", "{{JSObject1.myFun1.data}}");
entityExplorer.SelectEntityByName("Button1", "Widgets");
propPane.TypeTextIntoField("Label", "{");
agHelper.GetNClickByContains(locators._hints, "Add a binding");
// After selecting "Add a binding", expect "{{}}" in binding
propPane.ValidatePropertyFieldValue("Label", "{{}}");
});
it("6. Works correctly when user toggles JS", () => {
entityExplorer.SelectEntityByName("Button1", "Widgets");
propPane.ToggleJSMode("onClick");
propPane.ValidatePropertyFieldValue("onClick", "{{}}");
propPane.TypeTextIntoField("onClick", "hello", false);
// This asserts that cursor was originally between the curly braces after the user switched to js mode
propPane.ValidatePropertyFieldValue("onClick", "{{hello}}");
});
});

View File

@ -40,22 +40,22 @@ describe("Autocomplete tests for setters", () => {
agHelper.GetElementsNAssertTextPresence(
locators._hints,
"Button1.setColor()",
"Button1.setColor",
);
agHelper.GetElementsNAssertTextPresence(
locators._hints,
"Button1.setDisabled()",
"Button1.setDisabled",
);
agHelper.GetElementsNAssertTextPresence(
locators._hints,
"Button1.setVisibility()",
"Button1.setVisibility",
);
agHelper.RemoveCharsNType(locators._codeMirrorTextArea, 7, "Input1.set");
agHelper.GetElementsNAssertTextPresence(locators._hints, "setValue()");
agHelper.GetElementsNAssertTextPresence(locators._hints, "setDisabled()");
agHelper.GetElementsNAssertTextPresence(locators._hints, "setVisibility()");
agHelper.GetElementsNAssertTextPresence(locators._hints, "setValue");
agHelper.GetElementsNAssertTextPresence(locators._hints, "setDisabled");
agHelper.GetElementsNAssertTextPresence(locators._hints, "setVisibility");
agHelper.RemoveCharsNType(
locators._codeMirrorTextArea,
@ -63,14 +63,14 @@ describe("Autocomplete tests for setters", () => {
"Checkbox1.set",
);
agHelper.GetElementsNAssertTextPresence(locators._hints, "setValue()");
agHelper.GetElementsNAssertTextPresence(locators._hints, "setDisabled()");
agHelper.GetElementsNAssertTextPresence(locators._hints, "setVisibility()");
agHelper.GetElementsNAssertTextPresence(locators._hints, "setValue");
agHelper.GetElementsNAssertTextPresence(locators._hints, "setDisabled");
agHelper.GetElementsNAssertTextPresence(locators._hints, "setVisibility");
agHelper.RemoveCharsNType(locators._codeMirrorTextArea, 13, "Switch1.set");
agHelper.GetElementsNAssertTextPresence(locators._hints, "setDisabled()");
agHelper.GetElementsNAssertTextPresence(locators._hints, "setRequired()");
agHelper.GetElementsNAssertTextPresence(locators._hints, "setDisabled");
agHelper.GetElementsNAssertTextPresence(locators._hints, "setRequired");
agHelper.Sleep(); //a bit for time for CI
});
@ -78,6 +78,6 @@ describe("Autocomplete tests for setters", () => {
entityExplorer.DragDropWidgetNVerify(draggableWidgets.INPUT_V2, 500, 500);
entityExplorer.SelectEntityByName("Button1");
propPane.EnterJSContext("onClick", "{{Input1.set", true, false);
agHelper.GetElementsNAssertTextPresence(locators._hints, "setDisabled()");
agHelper.GetElementsNAssertTextPresence(locators._hints, "setDisabled");
});
});

View File

@ -130,22 +130,22 @@ describe("Autocomplete tests", () => {
// eval function verification
{
type: "eval",
expected: "eval()",
expected: "eval",
haveOrNotHave: false,
},
{
type: "Blob",
expected: "Blob()",
expected: "Blob",
haveOrNotHave: true,
},
{
type: "FormData",
expected: "FormData()",
expected: "FormData",
haveOrNotHave: true,
},
{
type: "FileReader",
expected: "FileReader()",
expected: "FileReader",
haveOrNotHave: true,
},
];
@ -167,7 +167,7 @@ describe("Autocomplete tests", () => {
agHelper.GetNClick(jsEditor._lineinJsEditor(5));
agHelper.TypeText(locators._codeMirrorTextArea, "this.");
["myFun2()", "myVar1", "myVar2"].forEach((element, index) => {
["myFun2", "myVar1", "myVar2"].forEach((element, index) => {
agHelper.AssertContains(element);
});
});

View File

@ -49,7 +49,7 @@ describe("Autocomplete tests", () => {
0,
);
agHelper.GetNAssertElementText(locators._hints, "myFun1()", "have.text", 4);
agHelper.GetNAssertElementText(locators._hints, "myFun1", "have.text", 4);
// Same check in JSObject1
entityExplorer.SelectEntityByName("JSObject1", "Queries/JS");
@ -65,7 +65,7 @@ describe("Autocomplete tests", () => {
0,
);
agHelper.GetNAssertElementText(locators._hints, "myFun1()", "have.text", 4);
agHelper.GetNAssertElementText(locators._hints, "myFun1", "have.text", 4);
entityExplorer.ActionContextMenuByEntityName({
entityNameinLeftSidebar: "JSObject1",
action: "Delete",

View File

@ -16,8 +16,8 @@ describe("Property Pane Suggestions", () => {
entityExplorer.SelectEntityByName("Button1", "Widgets");
propPane.TypeTextIntoField("Label", "/");
agHelper.Sleep(500);
agHelper.GetElementsNAssertTextPresence(locators._hints, "New binding");
agHelper.GetNClickByContains(locators._hints, "New binding");
agHelper.GetElementsNAssertTextPresence(locators._hints, "Add a binding");
agHelper.GetNClickByContains(locators._hints, "Add a binding");
propPane.ValidatePropertyFieldValue("Label", "{{}}");
//typing {{}}
@ -46,6 +46,6 @@ describe("Property Pane Suggestions", () => {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
cy.get("body").tab();
propPane.ValidatePropertyFieldValue("Label", "{{appsmith}}");
propPane.ValidatePropertyFieldValue("Label", "{{JSObject1}}");
});
});

View File

@ -72,7 +72,7 @@ describe("Dynamic input autocomplete", () => {
cy.wait(1000);
cy.evaluateErrorMessage(
"Found a reference to {{actionName}} during evaluation. Data fields cannot execute framework actions. Please remove any direct/indirect references to {{actionName}} and try again.".replaceAll(
"Please remove any direct/indirect references to {{actionName}} and try again. Data fields cannot execute framework actions.".replaceAll(
"{{actionName}}",
"storeValue()",
),

View File

@ -70,7 +70,6 @@ describe("Test Create Api and Bind to List widget", function () {
it("3. Test_Validate the list widget ", function () {
deployMode.NavigateBacktoEditor();
cy.wait("@postExecute");
cy.wait("@postExecute").then((interception) => {
valueToTest = JSON.stringify(
interception.response.body.data.body[0].name,

View File

@ -27,7 +27,7 @@ describe("Binding the button Widgets and validating NavigateTo Page functionalit
deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.BUTTON));
cy.wait(2000);
agHelper.ClickButton("Submit");
cy.wait(2000); //for page to load
cy.wait(4000); //for page to load
agHelper.AssertElementAbsence(
locators._widgetInDeployed(draggableWidgets.BUTTON),
);

View File

@ -15,54 +15,18 @@ describe(
.GetText(_.locators._widgetInCanvas("textwidget") + " span")
.should("be.empty");
_.entityExplorer.SelectEntityByName("Button1");
_.agHelper.SelectDropdownList("Google reCAPTCHA version", "reCAPTCHA v2");
_.propPane.SelectPropertiesDropDown(
"Google reCAPTCHA version",
"reCAPTCHA v2",
);
_.agHelper.ClickButton("Submit");
_.agHelper
.GetText(_.locators._widgetInCanvas("textwidget") + " span")
.should("be.empty");
_.agHelper.SelectDropdownList("Google reCAPTCHA version", "reCAPTCHA v3");
});
//This test to be enabled once the product bug is fixed
it.skip("Validate the Button binding with Text Widget with Recaptcha Token with invalid key before using valid key", function () {
cy.get("button")
.contains("Submit")
.should("be.visible")
.click({ force: true });
cy.testCodeMirrorLast(testdata.invalidKey);
_.entityExplorer.SelectEntityByName("Text1");
cy.get(".t--draggable-textwidget span")
.last()
.invoke("text")
.then((x) => {
cy.log(x);
expect(x).to.be.empty;
});
_.entityExplorer.SelectEntityByName("Button1");
cy.get(".t--property-control-googlerecaptchaversion .bp3-popover-target")
.last()
.should("be.visible")
.click({ force: true });
cy.get(".t--dropdown-option:contains('reCAPTCHA v2')").click({
force: true,
});
cy.get("button")
.contains("Submit")
.should("be.visible")
.click({ force: true });
cy.get(".t--toast-action span").should("have.text", testdata.errorMsg);
_.entityExplorer.SelectEntityByName("Text1");
cy.wait(3000);
cy.get(".t--draggable-textwidget span")
.last()
.invoke("text")
.then((x) => {
cy.log(x);
expect(x).to.be.empty;
});
_.propPane.SelectPropertiesDropDown(
"Google reCAPTCHA version",
"reCAPTCHA v3",
);
});
it("2. Validate the Button binding with Text Widget with Recaptcha Token with v2Key & upward compatibilty doesnt work", function () {
@ -77,13 +41,19 @@ describe(
.GetText(_.locators._widgetInCanvas("textwidget") + " span")
.should("be.empty");
_.entityExplorer.SelectEntityByName("Button1");
_.agHelper.SelectDropdownList("Google reCAPTCHA version", "reCAPTCHA v2");
_.propPane.SelectPropertiesDropDown(
"Google reCAPTCHA version",
"reCAPTCHA v2",
);
_.agHelper.ClickButton("Submit");
_.agHelper.Sleep();
_.agHelper
.GetText(_.locators._widgetInCanvas("textwidget") + " span")
.should("not.be.empty");
_.agHelper.SelectDropdownList("Google reCAPTCHA version", "reCAPTCHA v3");
_.propPane.SelectPropertiesDropDown(
"Google reCAPTCHA version",
"reCAPTCHA v3",
);
_.agHelper.ClickButton("Submit");
_.agHelper.Sleep();
});
@ -94,20 +64,24 @@ describe(
"Google reCAPTCHA key",
testdata.v3Key,
);
_.agHelper.SelectDropdownList("Google reCAPTCHA version", "reCAPTCHA v3");
_.propPane.SelectPropertiesDropDown(
"Google reCAPTCHA version",
"reCAPTCHA v3",
);
_.agHelper.ClickButton("Submit");
_.agHelper.Sleep();
cy.get("body").then(($ele) => {
if (
$ele.find(
_.locators._specificToast(
"Google Re-Captcha token generation failed!",
"Google reCAPTCHA token generation failed!",
),
).length ||
$ele
.find(_.locators._widgetInCanvas("textwidget") + " span")
.text() == ""
) {
_.agHelper.WaitUntilAllToastsDisappear();
_.agHelper.ClickButton("Submit");
}
});
@ -115,50 +89,30 @@ describe(
.GetText(_.locators._widgetInCanvas("textwidget") + " span")
.should("not.be.empty");
_.entityExplorer.SelectEntityByName("Button1");
_.agHelper.SelectDropdownList("Google reCAPTCHA version", "reCAPTCHA v2");
_.propPane.SelectPropertiesDropDown(
"Google reCAPTCHA version",
"reCAPTCHA v2",
);
_.agHelper.ClickButton("Submit");
_.agHelper.AssertContains("Google Re-Captcha token generation failed!"); //toast doesnt come when run in CI!
_.agHelper.AssertContains("Google reCAPTCHA token generation failed!");
});
//This test to be enabled once the product bug is fixed
it.skip("Validate the Button binding with Text Widget with Recaptcha Token with invalid key", function () {
cy.get("button")
.contains("Submit")
.should("be.visible")
.click({ force: true });
cy.testCodeMirrorLast(testdata.invalidKey);
_.entityExplorer.SelectEntityByName("Text1");
cy.get(".t--draggable-textwidget span")
.last()
.invoke("text")
.then((x) => {
cy.log(x);
expect(x).not.to.be.empty;
});
it("4. Validate the Button binding with Text Widget with Recaptcha Token with invalid key (after using valid key)", function () {
_.propPane.DeleteWidgetFromPropertyPane("Text1");
_.entityExplorer.SelectEntityByName("Button1");
cy.get(".t--property-control-googlerecaptchaversion .bp3-popover-target")
.last()
.should("be.visible")
.click({ force: true });
cy.get(".t--dropdown-option:contains('reCAPTCHA v2')").click({
force: true,
});
cy.get("button")
.contains("Submit")
.should("be.visible")
.click({ force: true });
_.entityExplorer.SelectEntityByName("Text1");
cy.wait(3000);
cy.get(".t--draggable-textwidget span")
.last()
.invoke("text")
.then((x) => {
cy.log(x);
expect(x).not.to.be.empty;
});
_.propPane.UpdatePropertyFieldValue(
"Google reCAPTCHA key",
testdata.invalidKey,
);
_.agHelper.ClickButton("Submit"); //for version 3
_.agHelper.WaitUntilToastDisappear(testdata.errorMsg);
_.entityExplorer.SelectEntityByName("Button1");
_.propPane.SelectPropertiesDropDown(
"Google reCAPTCHA version",
"reCAPTCHA v2",
);
_.agHelper.ClickButton("Submit");
_.agHelper.WaitUntilToastDisappear(testdata.errorMsg);
});
},
);

View File

@ -41,11 +41,7 @@ describe("Bind a button and Api usecase", function () {
it("2. Button-Name updation & API datasource binding with button name validation", function () {
_.entityExplorer.SelectEntityByName("Button1");
//changing the Button Name
cy.widgetText(
testdata.buttonName,
widgetsPage.buttonWidget,
widgetsPage.widgetNameSpan,
);
_.propPane.RenameWidget("Button1", testdata.buttonName);
//API datasource binding with button name validation
_.entityExplorer.SelectEntityByName("Api1", "Queries/JS");

View File

@ -2,6 +2,7 @@ const queryLocators = require("../../../../locators/QueryEditor.json");
const queryEditor = require("../../../../locators/QueryEditor.json");
import homePage from "../../../../locators/HomePage";
import * as _ from "../../../../support/Objects/ObjectsCore";
import { Widgets } from "../../../../support/Pages/DataSources";
import * as _ from "../../../../support/Objects/ObjectsCore";
@ -30,7 +31,7 @@ describe("Addwidget from Query and bind with other widgets", function () {
fixture: "addWidgetTable-mock",
});
cy.onlyQueryRun();
cy.get(queryEditor.suggestedTableWidget).click();
_.dataSources.AddSuggestedWidget(Widgets.Table);
_.jsEditor.CreateJSObject("return Query1.data;");
cy.CheckAndUnfoldEntityItem("Widgets");
cy.get(".t--entity-name").contains("Table1").click({ force: true });

View File

@ -59,7 +59,7 @@ Object.entries(widgetsToTest).forEach(([widgetSelector, testConfig]) => {
cy.updateCodeInput(PROPERTY_SELECTOR.text, testConfig.textBindingValue);
cy.closePropertyPane();
cy.get(".rc-select-selector").click({ force: true });
agHelper.GetNClick(".rc-select-selector", 0, true);
cy.wait(1000);
cy.get('.rc-select-item-option:contains("Blue")').click({ force: true });
cy.wait(1000);

View File

@ -236,6 +236,7 @@ showAlert("Wonderful! all apis executed", "success")).catch(() => showAlert("Ple
deployMode.DeployApp();
agHelper.ClickButton("Submit");
//agHelper.AssertElementLength(locator._toastMsg, 3); //Below incases of some api's failure
agHelper.WaitUntilEleAppear(locator._toastMsg);
agHelper
.GetElementLength(locator._toastMsg)
.then(($len) => expect($len).to.be.at.least(2));

View File

@ -43,34 +43,34 @@ describe("Validate basic binding of Input widget to Input widget", () => {
});
});
//Till bug fixed
it.skip("2. Validation of default displayed in Select widget based on row selected + Bug 12531", function () {
table.SelectTableRow(1);
agHelper.ReadSelectedDropDownValue().then(($selectedValue) => {
expect($selectedValue).to.eq("#2");
});
// //Till bug fixed
// it.skip("2. Validation of default displayed in Select widget based on row selected + Bug 12531", function () {
// table.SelectTableRow(1);
// agHelper.ReadSelectedDropDownValue().then(($selectedValue) => {
// expect($selectedValue).to.eq("#2");
// });
table.SelectTableRow(0);
agHelper.ReadSelectedDropDownValue().then(($selectedValue) => {
expect($selectedValue).to.eq("#1");
});
// table.SelectTableRow(0);
// agHelper.ReadSelectedDropDownValue().then(($selectedValue) => {
// expect($selectedValue).to.eq("#1");
// });
table.SelectTableRow(2);
agHelper.ReadSelectedDropDownValue().then(($selectedValue) => {
expect($selectedValue).to.eq("Select option");
});
// table.SelectTableRow(2);
// agHelper.ReadSelectedDropDownValue().then(($selectedValue) => {
// expect($selectedValue).to.eq("Select option");
// });
//Change select value now - failing here!
agHelper.SelectDropDown("#1");
agHelper.ReadSelectedDropDownValue().then(($selectedValue) => {
expect($selectedValue).to.eq("#1");
});
// //Change select value now - failing here!
// agHelper.SelectDropDown("#1");
// agHelper.ReadSelectedDropDownValue().then(($selectedValue) => {
// expect($selectedValue).to.eq("#1");
// });
table.SelectTableRow(2, 0, false); //Deselecting here!
agHelper.ReadSelectedDropDownValue().then(($selectedValue) => {
expect($selectedValue).to.eq("Select option");
});
});
// table.SelectTableRow(2, 0, false); //Deselecting here!
// agHelper.ReadSelectedDropDownValue().then(($selectedValue) => {
// expect($selectedValue).to.eq("Select option");
// });
// });
it("3. Verify Selecting the already selected row deselects it", () => {
table.SelectTableRow(0); //select here

View File

@ -136,24 +136,15 @@ describe("Test Create Api and Bind to Table widget", function () {
cy.executeDbQuery("Api2", "onPageChange");
});
it.skip("5. Table-Text, Validate Server Side Pagination of Paginate with response URL", function () {
it("5. Table-Text, Validate Server Side Pagination of Paginate with response URL", function () {
/**Validate Response data with Table data in Text Widget */
entityExplorer.SelectEntityByName("Table1", "Widgets");
cy.ValidatePaginateResponseUrlData(
apiLocators.apiPaginationPrevTest,
false,
);
cy.ValidatePaginateResponseUrlData(apiLocators.apiPaginationPrevTest);
cy.get("@postExecute.all");
deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.TABLE_V1));
table.WaitUntilTableLoad(0, 0);
agHelper.Sleep(3000);
cy.wait("@postExecute").then((interception) => {
let valueToTest = JSON.stringify(
interception.response.body.data.body[0].name,
);
cy.ValidatePaginationInputData(valueToTest);
});
deployMode.NavigateBacktoEditor();
cy.wait(3000);
entityExplorer.SelectEntityByName("Table1", "Widgets");

View File

@ -135,7 +135,7 @@ describe("Test Create Api and Bind to Table widget", function () {
cy.executeDbQuery("Api2", "onPageChange");
});
it.skip("5. Table-Text, Validate Server Side Pagination of Paginate with Response URL", function () {
it("5. Table-Text, Validate Server Side Pagination of Paginate with Response URL", function () {
/**Validate Response data with Table data in Text Widget */
cy.get("body").then(($ele) => {
if ($ele.find(locators._backToEditor).length) {
@ -144,20 +144,11 @@ describe("Test Create Api and Bind to Table widget", function () {
});
entityExplorer.SelectEntityByName("Table1", "Widgets");
cy.ValidatePaginateResponseUrlDataV2(
apiPageLocators.apiPaginationPrevTest,
false,
);
cy.ValidatePaginateResponseUrlDataV2(apiPageLocators.apiPaginationPrevTest);
cy.get("@postExecute.all");
deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.TABLE));
table.WaitUntilTableLoad(0, 0, "v2");
agHelper.Sleep(3000);
cy.wait("@postExecute").then((interception) => {
let valueToTest = JSON.stringify(
interception.response.body.data.body[0].name,
);
cy.ValidatePaginationInputDataV2(valueToTest);
});
deployMode.NavigateBacktoEditor();
entityExplorer.SelectEntityByName("Table1", "Widgets");
cy.ValidatePaginateResponseUrlDataV2(

View File

@ -1,32 +0,0 @@
import {
agHelper,
apiPage,
table,
dataManager,
} 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(
dataManager.dsValues[dataManager.defaultEnviorment].mockApiUrl,
);
apiPage.RunAPI();
agHelper.GetNClick(FirstTimeUserOnboarding.selectWidgetBtn);
agHelper.AssertElementVisibility(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);
});
});

View File

@ -92,7 +92,6 @@ describe("Table Widget V2 property pane feature validation", function () {
// eslint-disable-next-line cypress/no-unnecessary-waiting
cy.wait(1000);
propPane.EnterJSContext("Text color", testdata.bindingTextColor);
cy.wait("@updateLayout");
cy.readTableV2dataValidateCSS("0", "0", "color", "rgb(0, 128, 0)");
cy.readTableV2dataValidateCSS("1", "0", "color", "rgb(255, 0, 0)");
});
@ -104,7 +103,6 @@ describe("Table Widget V2 property pane feature validation", function () {
cy.moveToStyleTab();
cy.wait(1000);
propPane.EnterJSContext("Cell Background", testdata.bindingTextColor);
cy.wait("@updateLayout");
cy.readTableV2dataValidateCSS(
"0",
"0",

View File

@ -15,7 +15,6 @@ describe("Table Widget V2 property pane feature validation", function () {
cy.moveToStyleTab();
_.agHelper.Sleep();
_.propPane.EnterJSContext("Text align", testdata.bindingAlign);
cy.wait("@updateLayout");
cy.readTableV2dataValidateCSS("0", "0", "justify-content", "flex-start");
cy.readTableV2dataValidateCSS("1", "0", "justify-content", "flex-end");
});
@ -36,7 +35,6 @@ describe("Table Widget V2 property pane feature validation", function () {
"Vertical alignment",
testdata.bindingVerticalAlig,
);
cy.wait("@updateLayout");
cy.readTableV2dataValidateCSS("0", "0", "align-items", "flex-start");
cy.readTableV2dataValidateCSS("1", "0", "align-items", "flex-end");
});
@ -45,7 +43,6 @@ describe("Table Widget V2 property pane feature validation", function () {
//cy.movetoStyleTab();
_.agHelper.Sleep();
_.propPane.EnterJSContext("Text size", testdata.bindingNewSize);
cy.wait("@updateLayout");
cy.readTableV2dataValidateCSS("0", "0", "font-size", "14px");
cy.readTableV2dataValidateCSS("1", "0", "font-size", "24px");
});
@ -53,7 +50,6 @@ describe("Table Widget V2 property pane feature validation", function () {
it("5. Table widget V2 toggle test for style Alignment", function () {
_.agHelper.Sleep();
_.propPane.EnterJSContext("Emphasis", testdata.bindingStyle);
cy.wait("@updateLayout");
cy.readTableV2dataValidateCSS("0", "0", "font-style", "normal");
cy.readTableV2dataValidateCSS("1", "0", "font-style", "italic");
});
@ -62,7 +58,6 @@ describe("Table Widget V2 property pane feature validation", function () {
cy.moveToStyleTab();
_.agHelper.Sleep();
_.propPane.EnterJSContext("Text color", testdata.bindingTextColor);
cy.wait("@updateLayout");
cy.readTableV2dataValidateCSS("0", "0", "color", "rgb(0, 128, 0)");
cy.readTableV2dataValidateCSS("1", "0", "color", "rgb(255, 0, 0)");
});
@ -71,7 +66,6 @@ describe("Table Widget V2 property pane feature validation", function () {
cy.moveToStyleTab();
_.agHelper.Sleep();
_.propPane.EnterJSContext("Cell Background", testdata.bindingTextColor);
cy.wait("@updateLayout");
cy.readTableV2dataValidateCSS(
"0",
"0",

View File

@ -1,21 +0,0 @@
import * as _ from "../../../../support/Objects/ObjectsCore";
describe("Test Create Api and Bind to Table widget", function () {
before(() => {
_.agHelper.AddDsl("tableWidgetDsl");
});
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-tablewidget").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");
});
});

View File

@ -15,7 +15,6 @@ describe("Table Widget property pane feature validation", function () {
//cy.movetoStyleTab();
_.agHelper.Sleep();
_.propPane.EnterJSContext("Text align", testdata.bindingAlign);
cy.wait("@updateLayout");
cy.readTabledataValidateCSS("0", "0", "justify-content", "flex-start");
cy.readTabledataValidateCSS("1", "0", "justify-content", "flex-end");
});
@ -36,7 +35,6 @@ describe("Table Widget property pane feature validation", function () {
"Vertical alignment",
testdata.bindingVerticalAlig,
);
cy.wait("@updateLayout");
cy.readTabledataValidateCSS("0", "0", "align-items", "flex-start");
cy.readTabledataValidateCSS("1", "0", "align-items", "flex-end");
});
@ -46,7 +44,6 @@ describe("Table Widget property pane feature validation", function () {
_.agHelper.Sleep();
_.propPane.EnterJSContext("Text size", testdata.bindingSize);
cy.wait(2000);
cy.wait("@updateLayout");
cy.readTabledataValidateCSS("0", "0", "font-size", "14px");
cy.readTabledataValidateCSS("1", "0", "font-size", "24px");
});
@ -55,7 +52,6 @@ describe("Table Widget property pane feature validation", function () {
//cy.movetoStyleTab();
_.agHelper.Sleep();
_.propPane.EnterJSContext("Font Style", testdata.bindingStyle);
cy.wait("@updateLayout");
cy.readTabledataValidateCSS("0", "0", "font-style", "normal");
cy.readTabledataValidateCSS("1", "0", "font-style", "italic");
});
@ -64,7 +60,6 @@ describe("Table Widget property pane feature validation", function () {
//cy.movetoStyleTab();
_.agHelper.Sleep();
_.propPane.EnterJSContext("Text color", testdata.bindingTextColor);
cy.wait("@updateLayout");
cy.readTabledataValidateCSS("0", "0", "color", "rgb(0, 128, 0)");
cy.readTabledataValidateCSS("1", "0", "color", "rgb(255, 0, 0)");
});
@ -73,7 +68,6 @@ describe("Table Widget property pane feature validation", function () {
//cy.movetoStyleTab();
_.agHelper.Sleep();
_.propPane.EnterJSContext("Cell Background", testdata.bindingTextColor);
cy.wait("@updateLayout");
cy.readTabledataValidateCSS(
"0",
"0",

View File

@ -3,9 +3,21 @@ import * as _ from "../../../../support/Objects/ObjectsCore";
describe("xml2json text", function () {
before(() => {
_.agHelper.AddDsl("xmlParser");
_.homePage.NavigateToHome();
_.homePage.ImportApp("xmlParser.json");
_.homePage.AssertImportToast();
});
it("1. Publish widget and validate the data displayed in text widget from xmlParser function", function () {
it("1. Check if XMLparser v3 autocomplete works", function () {
_.entityExplorer.SelectEntityByName("Text2", "Widgets");
_.propPane.TypeTextIntoField("Text", "{{xmlParser.j", true);
_.agHelper.GetNAssertElementText(_.locators._hints, "j2xParser");
_.propPane.TypeTextIntoField("Text", "{{new xmlParser.j2xParser().p", true);
_.agHelper.GetNAssertElementText(_.locators._hints, "parse");
});
it("2. Publish widget and validate the data displayed in text widget from xmlParser function", function () {
_.deployMode.DeployApp();
cy.get(publish.textWidget)
.first()

View File

@ -10,7 +10,8 @@ import {
createMessage,
} from "../../../../support/Objects/CommonErrorMessages";
const largeResponseApiUrl = "https://api.publicapis.org/entries";
const largeResponseApiUrl = "https://api.github.com/emojis";
//"https://api.publicapis.org/entries";
//"https://jsonplaceholder.typicode.com/photos";//Commenting since this is faster sometimes & case is failing
describe("Abort Action Execution", function () {
@ -49,7 +50,7 @@ describe("Abort Action Execution", function () {
action: "Delete",
entityType: entityItems.Query,
});
dataSources.DeleteDatasouceFromWinthinDS($dsName as unknown as string);
dataSources.DeleteDatasourceFromWithinDS($dsName as unknown as string);
});
});
});

View File

@ -280,8 +280,7 @@ function multiTreeSelectAndReset() {
}
function radiogroupAndReset() {
cy.get("input").last().click({ force: true });
cy.wait(1000);
_.agHelper.GetNClick("input", 1, true, 1000);
_.agHelper.GetNAssertElementText(
_.locators._textWidgetInDeployed,
"N",
@ -350,8 +349,7 @@ function checkboxGroupAndReset() {
}
function checkboxAndReset() {
cy.get("input").last().click({ force: true });
cy.wait(1000);
_.agHelper.GetNClick("input", 0, true, 1000);
_.agHelper.GetNAssertElementText(
_.locators._textWidgetInDeployed,
"false",

View File

@ -8,6 +8,8 @@ import {
dataManager,
propPane,
table,
draggableWidgets,
entityExplorer,
} from "../../../../support/Objects/ObjectsCore";
import { Widgets } from "../../../../support/Pages/DataSources";
@ -15,16 +17,9 @@ import {
ERROR_ACTION_EXECUTE_FAIL,
createMessage,
} from "../../../../support/Objects/CommonErrorMessages";
import { featureFlagIntercept } from "../../../../support/Objects/FeatureFlags";
describe("API Bugs", function () {
before(() => {
featureFlagIntercept(
{
ab_ds_binding_enabled: false,
},
false,
);
agHelper.RefreshPage();
});
@ -93,4 +88,42 @@ describe("API Bugs", function () {
value: "4{{Math.random() > 0.5 ? '&param1=5' : '&param2=6'}}",
});
});
it("5. Bug 26897, Invalid binding of table data when used existing suggested widgets for an action returning object & array", function () {
entityExplorer.DragDropWidgetNVerify(draggableWidgets.TABLE);
entityExplorer.NavigateToSwitcher("Explorer");
// Case where api returns array response
apiPage.CreateAndFillApi(
dataManager.dsValues[dataManager.defaultEnviorment].mockApiUrl,
"ARRAY_RESPONSE",
);
apiPage.RunAPI();
dataSources.AddSuggestedWidget(
Widgets.Table,
dataSources._addSuggestedExisting,
);
debuggerHelper.AssertErrorCount(0);
table.WaitUntilTableLoad(0, 0, "v2");
propPane.AssertPropertiesDropDownCurrentValue(
"Table data",
"ARRAY_RESPONSE",
);
// Create API so that it returns object response
apiPage.CreateAndFillApi(
dataManager.dsValues[dataManager.defaultEnviorment].mockApiObjectUrl,
"OBJECT_RESPONSE",
);
apiPage.RunAPI();
dataSources.AddSuggestedWidget(
Widgets.Table,
dataSources._addSuggestedExisting,
);
table.WaitUntilTableLoad(0, 0, "v2");
propPane.ValidatePropertyFieldValue(
"Table data",
"{{OBJECT_RESPONSE.data.users}}",
);
});
});

View File

@ -12,7 +12,7 @@ describe(
dataSources.CreatePlugIn("Google Sheets");
agHelper.GoBack();
agHelper.AssertContains(
"Save and authorize",
"Save & Authorize",
"exist",
dataSources._datasourceModalSave,
);

View File

@ -1,33 +0,0 @@
import { agHelper, dataSources } from "../../../../support/Objects/ObjectsCore";
let dsName: string;
const testString = "test";
describe("Bug 19933: Authenticated API DS in case of OAuth2, should have save and authorise button enabled all the times", function () {
it("1. Create Auth API DS, save i, now edit again and check the save and authorise button state", function () {
dataSources.NavigateToDSCreateNew();
agHelper.GenerateUUID();
cy.get("@guid").then((uid) => {
dsName = "AuthAPI " + uid;
dataSources.CreatePlugIn("Authenticated API");
agHelper.RenameWithInPane(dsName, false);
dataSources.FillAuthAPIUrl();
dataSources.AddOAuth2AuthorizationCodeDetails(
testString,
testString,
testString,
testString,
);
dataSources.SaveDatasource();
});
dataSources.EditDatasource();
agHelper.AssertElementEnabledDisabled(
dataSources._saveAndAuthorizeDS,
0,
false,
);
dataSources.DeleteDSDirectly();
});
});

View File

@ -1,10 +1,10 @@
import * as _ from "../../../../support/Objects/ObjectsCore";
let guid;
let guid: any;
let ws1Name;
let ws2Name;
let app1Name;
let repoName;
let app1Name: any;
let repoName: any;
let branchName;
describe("Issue 24486 - Issue with Export Application", () => {
@ -19,7 +19,7 @@ describe("Issue 24486 - Issue with Export Application", () => {
});
});
it("Should export the current branch", () => {
it("1. Should export the current branch", () => {
_.entityExplorer.DragDropWidgetNVerify(_.draggableWidgets.BUTTON, 200, 200);
_.gitSync.CreateNConnectToGit();
cy.get("@gitRepoName").then((repName) => {
@ -60,7 +60,7 @@ describe("Issue 24486 - Issue with Export Application", () => {
});
});
it("Should import the exported branch", () => {
it("2. Should import the exported branch", () => {
ws2Name = "Bug24486-w2" + guid;
_.homePage.CreateNewWorkspace(ws2Name, true);
_.homePage.ImportApp("app-b24486.json", ws2Name);
@ -73,7 +73,7 @@ describe("Issue 24486 - Issue with Export Application", () => {
_.propPane.ValidatePropertyFieldValue("Label", "Submit");
});
// after(() => {
// _.gitSync.DeleteTestGithubRepo(repoName);
// });
after(() => {
_.gitSync.DeleteTestGithubRepo(repoName);
});
});

View File

@ -1,24 +1,38 @@
import * as _ from "../../../../support/Objects/ObjectsCore";
const { entityExplorer, propPane } = _;
import {
entityExplorer,
propPane,
draggableWidgets,
agHelper,
} from "../../../../support/Objects/ObjectsCore";
describe("Bug 25894 - Moustache brackets should be highlighted", () => {
it("1. should show {{ }} in bold", () => {
entityExplorer.DragDropWidgetNVerify(_.draggableWidgets.BUTTON, 200, 200);
entityExplorer.DragDropWidgetNVerify(draggableWidgets.BUTTON);
entityExplorer.SelectEntityByName("Button1", "Widgets");
propPane.EnterJSContext(
"onClick",
`{{Api1.run({
`{{ Api1.run({
"key": Button1.text
}).then(() => {
storeValue('my-secret-key', Button3.text);
Query1.run();
}).catch(() => {});const a = { a: "key"} }}`,
);
agHelper
.GetElement("span")
.filter((index, element) => {
const text = Cypress.$(element).text();
return text.includes("{{") || text.includes("{");
})
.should("have.class", "cm-binding-brackets");
cy.get("span").contains("{{").should("have.class", "cm-binding-brackets");
cy.get("span").contains("}}").should("have.class", "cm-binding-brackets");
agHelper
.GetElement("span")
.filter((index, element) => {
const text = Cypress.$(element).text();
return text.includes("}}") || text.includes("}");
})
.should("have.class", "cm-binding-brackets"); // Check the class of filtered elements
});
});

View File

@ -0,0 +1,26 @@
import {
dataSources,
entityExplorer,
} from "../../../../support/Objects/ObjectsCore";
describe("Bug 26126: Fix DS button disability", function () {
it("ensures save button is correctly updated when DS required fields change", function () {
dataSources.NavigateToDSCreateNew();
dataSources.CreatePlugIn("S3");
dataSources.FillS3DSForm();
dataSources.AssertSaveDSButtonDisability(false);
dataSources.ValidateNSelectDropdown(
"S3 service provider",
"Amazon S3",
"Upcloud",
);
dataSources.AssertSaveDSButtonDisability(true);
dataSources.ValidateNSelectDropdown(
"S3 service provider",
"Upcloud",
"Amazon S3",
);
dataSources.AssertSaveDSButtonDisability(false);
});
});

View File

@ -0,0 +1,72 @@
import {
agHelper,
dataSources,
entityExplorer,
} from "../../../../support/Objects/ObjectsCore";
let dsName: any, userMock: string, movieMock: string;
describe(
"excludeForAirgap",
"Bug 26716: Datasource selected from entity explorer should be correctly highlighted",
function () {
it("1. Create users and movies mock datasources and switch between them through entity explorer, check the active state", function () {
dataSources.CreateMockDB("Users").then((mockDBName) => {
userMock = mockDBName;
cy.log("Mock DB Name: " + userMock);
dataSources.CreateQueryAfterDSSaved(); //create dummy query for DS to be visible in entity explorer
dataSources.CreateMockDB("Movies").then((mockDBName) => {
movieMock = mockDBName;
cy.log("Mock DB Name: " + mockDBName);
dataSources.CreateQueryAfterDSSaved(); //create dummy query for DS to be visible in entity explorer
dataSources.CreateDataSource("Postgres");
dataSources.CreateQueryAfterDSSaved(); //create dummy query for DS to be visible in entity explorer
cy.get("@dsName").then(($dsName) => {
dsName = $dsName;
// Select Users
entityExplorer.SelectEntityByName(userMock, "Datasources");
agHelper.Sleep(200);
agHelper.AssertClassExists(
dataSources._entityExplorerID(userMock),
"active",
);
// Switch to Movies
entityExplorer.SelectEntityByName(movieMock, "Datasources");
agHelper.Sleep(200);
agHelper.AssertClassExists(
dataSources._entityExplorerID(movieMock),
"active",
);
// Switch to custom DS
entityExplorer.SelectEntityByName(dsName, "Datasources");
entityExplorer.ExpandCollapseEntity(dsName, false);
agHelper.Sleep(200);
agHelper.AssertClassExists(
dataSources._entityExplorerID(dsName),
"active",
);
// Delete all datasources
entityExplorer.ActionContextMenuByEntityName({
entityNameinLeftSidebar: "Query1",
action: "Delete",
});
entityExplorer.ActionContextMenuByEntityName({
entityNameinLeftSidebar: "Query2",
action: "Delete",
});
entityExplorer.ActionContextMenuByEntityName({
entityNameinLeftSidebar: "Query3",
action: "Delete",
});
dataSources.DeleteDatasouceFromActiveTab(userMock);
dataSources.DeleteDatasouceFromActiveTab(movieMock);
dataSources.DeleteDatasouceFromActiveTab(dsName);
});
});
});
});
},
);

View File

@ -0,0 +1,45 @@
import {
agHelper,
apiPage,
dataManager,
debuggerHelper,
} from "../../../../support/Objects/ObjectsCore";
describe("Inconsistent Api error after the invalid chars are removed from header key", function () {
it("1. Checking whether the appropriate error is displayed even after the removal of invalid chars in header key.", function () {
const randomApi = `${
dataManager.dsValues[dataManager.defaultEnviorment].mockApiUrl
}123`;
apiPage.CreateAndFillApi(randomApi);
apiPage.RunAPI(false, 20, {
expectedPath: "response.body.data.body.data.isExecutionSuccess",
expectedRes: false,
});
agHelper.AssertElementAbsence(
debuggerHelper.locators._debuggerDownStreamErrMsg,
);
apiPage.EnterHeader(">", "");
apiPage.RunAPI(false, 20, {
expectedPath: "response.body.data.body.data.isExecutionSuccess",
expectedRes: false,
});
cy.get("@postExecute").then((interception: any) => {
debuggerHelper.AssertDownStreamLogError(
interception.response.body.data.pluginErrorDetails
.downstreamErrorMessage,
);
});
apiPage.EnterHeader("", "");
apiPage.RunAPI(false, 20, {
expectedPath: "response.body.data.body.data.isExecutionSuccess",
expectedRes: false,
});
agHelper.AssertElementAbsence(
debuggerHelper.locators._debuggerDownStreamErrMsg,
);
});
});

View File

@ -0,0 +1,25 @@
import {
agHelper,
assertHelper,
dataSources,
} from "../../../../support/Objects/ObjectsCore";
import { featureFlagIntercept } from "../../../../support/Objects/FeatureFlags";
describe("Datasource structure schema preview data", () => {
before(() => {
featureFlagIntercept({ ab_gsheet_schema_enabled: true });
dataSources.CreateDataSource("Postgres");
});
it("1. Table selection should be enabled and add template button absent", () => {
dataSources.selectTabOnDatasourcePage("View data");
agHelper.TypeText(dataSources._datasourceStructureSearchInput, "users");
agHelper.GetNClick(
dataSources._dsPageTabContainerTableName("public.users"),
);
assertHelper.AssertNetworkExecutionSuccess("@schemaPreview");
agHelper.AssertElementAbsence(
dataSources._dsPageTableTriggermenuTarget("public.users"),
);
});
});

View File

@ -0,0 +1,44 @@
import {
dataSources,
agHelper,
entityExplorer,
propPane,
debuggerHelper,
draggableWidgets,
} from "../../../../support/Objects/ObjectsCore";
let dsName: any;
let queryName: string;
describe("Bug 28287: Binding query to widget, check query response in query editor on page load", function () {
before("Drag drop a text widget", () => {
entityExplorer.DragDropWidgetNVerify(draggableWidgets.TEXT);
});
it("1. Check query response in query editor on page load", () => {
agHelper.GenerateUUID();
cy.get("@guid").then((uuid) => {
dataSources.CreateDataSource("Postgres");
cy.get("@dsName").then(($dsName) => {
dsName = $dsName;
});
queryName = `Query_${uuid}`;
dataSources.CreateQueryAfterDSSaved(
"SELECT * FROM users LIMIT 10",
queryName,
);
dataSources.ToggleUsePreparedStatement(false);
entityExplorer.SelectEntityByName("Text1");
propPane.TypeTextIntoField("Text", `{{${queryName}.data}}`);
agHelper.RefreshPage();
agHelper.Sleep(1000);
entityExplorer.SelectEntityByName(queryName, "Queries/JS");
agHelper.AssertElementVisibility(dataSources._queryResponse("TABLE"));
});
});
});

View File

@ -34,7 +34,7 @@ describe("Bug 9334: The Select widget value is sent as null when user switches b
agHelper.AssertContains("Successfully generated a page");
//assertHelper.AssertNetworkStatus("@getActions", 200);//Since failing sometimes
assertHelper.AssertNetworkStatus("@postExecute", 200);
agHelper.GetNClick(dataSources._visibleTextSpan("Got it"));
agHelper.ClickButton("Got it");
assertHelper.AssertNetworkStatus("@updateLayout", 200);
table.WaitUntilTableLoad();
@ -52,10 +52,11 @@ describe("Bug 9334: The Select widget value is sent as null when user switches b
agHelper.AssertContains("Successfully generated a page");
//assertHelper.AssertNetworkStatus("@getActions", 200);//Since failing sometimes
assertHelper.AssertNetworkStatus("@postExecute", 200);
agHelper.GetNClick(dataSources._visibleTextSpan("Got it"));
agHelper.ClickButton("Got it");
assertHelper.AssertNetworkStatus("@updateLayout", 200);
table.WaitUntilTableLoad();
});
it("2. Navigate & Assert toast", () => {
//Navigating between CRUD (Page3) & EmptyPage (Page2):
entityExplorer.SelectEntityByName("Page1");

View File

@ -0,0 +1,30 @@
import {
dataSources,
entityExplorer,
} from "../../../../support/Objects/ObjectsCore";
describe("Fix UQI query switching", function () {
it(
"excludeForAirgap",
"1. The command of the Mongo query must be preserved and should not default to initial value after changed.",
function () {
dataSources.NavigateToDSCreateNew();
dataSources.CreateDataSource("Mongo", false, false);
dataSources.CreateQueryAfterDSSaved("", "MongoQuery");
dataSources.ValidateNSelectDropdown(
"Commands",
"Find document(s)",
"Insert document(s)",
);
dataSources.NavigateToDSCreateNew();
dataSources.CreateDataSource("Twilio", false, false);
dataSources.CreateQueryAfterDSSaved("", "TwilioQuery");
dataSources.ValidateNSelectDropdown("Commands", "", "Schedule message");
entityExplorer.SelectEntityByName("MongoQuery", "Queries/JS");
dataSources.ValidateNSelectDropdown("Commands", "Insert document(s)");
entityExplorer.SelectEntityByName("TwilioQuery", "Queries/JS");
dataSources.ValidateNSelectDropdown("Commands", "Schedule message");
},
);
});

View File

@ -44,25 +44,6 @@ describe("datasource unsaved changes popup shows even without changes", function
_.dataSources.EditDatasource();
_.agHelper.GoBack();
_.agHelper.AssertElementVisibility(_.dataSources._activeDS);
// Edit DS from active tab and add oauth2 details
_.dataSources.EditDSFromActiveTab(dsName);
_.dataSources.AddOAuth2AuthorizationCodeDetails(
testString,
testString,
testString,
testString,
);
_.dataSources.UpdateDatasource();
_.agHelper.Sleep();
// Now edit DS, and ensure that discard popup is not shown on back button click
// Even if custom authentication params are being initialized, we shouldnt see the popup
// as those are not initialized by user
_.dataSources.EditDatasource();
_.agHelper.GoBack();
_.agHelper.AssertElementVisibility(_.dataSources._activeDS);
_.dataSources.DeleteDatasouceFromActiveTab(dsName);
});
});
@ -154,7 +135,7 @@ describe("datasource unsaved changes popup shows even without changes", function
// Edit datasource, change connection string uri param and click on back button
_.dataSources.EditDatasource();
_.agHelper.UpdateInputValue(_.dataSources._host, "jargons");
_.agHelper.UpdateInputValue(_.dataSources._host(), "jargons");
// Assert that popup is visible
_.dataSources.cancelDSEditAndAssertModalPopUp(true, false);
@ -164,7 +145,7 @@ describe("datasource unsaved changes popup shows even without changes", function
// validate the input field value still remains as the saved value
_.agHelper.ValidateFieldInputValue(
_.dataSources._host,
_.dataSources._host(),
_.dataManager.dsValues.Staging.mongo_host,
);

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