diff --git a/app/client/cypress/scripts/cypress-local-setup.js b/app/client/cypress/scripts/cypress-local-setup.js new file mode 100644 index 0000000000..384b1bdc62 --- /dev/null +++ b/app/client/cypress/scripts/cypress-local-setup.js @@ -0,0 +1,189 @@ +const { execSync } = require("child_process"); +const { readFileSync, existsSync, writeFileSync } = require("fs"); +const path = require("path"); +const prompt = require("prompt-sync")(); + +// Function to check if a Docker container is running +function isContainerRunning(containerName) { + try { + const output = execSync( + `docker ps --format '{{.Names}}' | grep -w "${containerName}"`, + ); + return output.length > 0; + } catch (error) { + return false; + } +} + +function ensureTEDIsRunning() { + // Check if TED is running. If not, then ask user if they wish to pull and run the TED container + const isTedRunning = isContainerRunning("ted"); + + if (isTedRunning) { + console.log("INFO", "TED (TestEventDriver) is already running"); + } else { + try { + let user_input = prompt( + "TED (TestEventDriver) is not running. Do you want to pull & run the latest Docker container for TED (TestEventDriver)? (yes/no): ", + ); + user_input = user_input.trim().toLowerCase(); + switch (user_input) { + case "yes": + case "y": + console.log( + "INFO", + "Running the Docker container for TED (TestEventDriver)", + ); + try { + execSync( + "docker run --name ted --rm -d --pull always -p 2022:22 -p 5001:5001 -p 3306:3306 -p 28017:27017 -p 5432:5432 -p 25:25 -p 4200:4200 appsmith/test-event-driver", + { stdio: "inherit" }, + ); + console.log( + "INFO", + "Please check https://github.com/appsmithorg/TestEventDriver for more details and functionalities of TED", + ); + } catch (error) { + console.error("ERROR", `Error installing TED: ${error.message}`); + } + break; + case "no": + case "n": + console.log("INFO", "Proceeding without TED"); + break; + default: + console.log("ERROR", "Invalid input. Please enter yes or no."); + process.exit(1); + } + } catch (error) { + console.error("ERROR", `Error: ${error.message}`); + process.exit(1); + } + } +} + +async function checkIfAppsmithIsRunning(baseUrl) { + // Check if appsmith is running. If it's not running, check if we want the user to continue without it. + let isDevAppsmithAccessible; + try { + const response = await fetch(baseUrl); + isDevAppsmithAccessible = response.ok; + } catch (error) { + console.error( + "ERROR", + `Error checking availability of dev.appsmith.com: ${error.message}`, + ); + isDevAppsmithAccessible = false; + } + + if (!isDevAppsmithAccessible) { + let user_input = prompt( + `https://dev.appsmith.com is not accessible. Do you wish to continue without setting it up? (yes/no): `, + ); + user_input = user_input.trim().toLowerCase(); + switch (user_input) { + case "yes": + case "y": + console.log("INFO", "Continuing without setting up dev.appsmith.com"); + break; + case "no": + case "n": + process.exit(1); + default: + console.log("ERROR", "Invalid input. Please enter yes or no."); + process.exit(1); + } + } +} + +function getBaseUrl(repoRoot) { + try { + const cypressConfig = readFileSync(`${repoRoot}/cypress.config.ts`, "utf8"); + const baseUrlMatch = cypressConfig.match(/baseUrl\s*:\s*"([^"]+)"/); + if (baseUrlMatch) { + baseUrl = baseUrlMatch[1]; + console.log( + "INFO", + `Base url is ${baseUrl}. Please verify if it is correct. If not, please update it in cypress.config.ts file.`, + ); + return baseUrl; + } else { + console.error( + "ERROR", + "Base url not found in cypress.config.ts. Please configure `baseUrl` property in cypress.config.ts file.", + ); + process.exit(1); + } + } catch (err) { + if (err.code === "ENOENT") { + console.error("ERROR", "cypress.config.ts file not found"); + } else { + console.error("ERROR", "Error reading cypress.config.ts file:", err); + } + process.exit(1); + } +} + +function ensureCypressEnvFileExists(repoRoot) { + // Check if cypress.env.json file exists. If not, create it. + const filePath = `${repoRoot}/cypress.env.json`; + if (!existsSync(filePath)) { + const testEnvData = { + USERNAME: "testUser@test.com", + PASSWORD: "testPass", + TESTUSERNAME1: "viewerappsmith@test.com", + TESTPASSWORD1: "viewerPass", + TESTUSERNAME2: "developerappsmith@test.com", + TESTPASSWORD2: "developerPass", + }; + writeFileSync(filePath, JSON.stringify(testEnvData, null, 2)); + console.log("INFO", `${repoRoot}/cypress.env.json file created`); + } else { + console.log("INFO", `${repoRoot}/cypress.env.json file already exists`); + } +} + +async function setupCypress() { + // Get the baseUrl from cypress.config.ts file + let repoRoot = path.join(__dirname, "..", ".."); + let baseUrl = getBaseUrl(repoRoot); + + await checkIfAppsmithIsRunning(baseUrl); + + // Install Cypress using yarn install on the app/client repository + console.log("INFO", "Installing Cypress.."); + try { + execSync("yarn install", { cwd: `${repoRoot}` }); + } catch (error) { + console.error("ERROR", `Error installing Cypress: ${error.message}`); + } + + ensureCypressEnvFileExists(repoRoot); + + console.log( + "INFO", + "Please add APPSMITH_GIT_ROOT=./container-volumes/git-storage into server-side .env for running Git cases locally along with the server.", + ); + + ensureTEDIsRunning(); + + console.log( + "INFO", + "Please start cypress using the command: npx cypress open", + ); + console.log( + "INFO", + `In order to run single spec, please use the command: cd ${repoRoot} && npx cypress run --spec --browser chrome`, + ); + console.log( + "INFO", + "For more details check https://github.com/appsmithorg/appsmith/blob/master/contributions/ClientSetup.md#integration-tests", + ); +} + +async function main() { + await setupCypress(); + process.exit(0); +} + +main(); diff --git a/app/client/cypress/scripts/package.json b/app/client/cypress/scripts/package.json new file mode 100644 index 0000000000..91f6b3b1fe --- /dev/null +++ b/app/client/cypress/scripts/package.json @@ -0,0 +1,14 @@ +{ + "name": "scripts", + "version": "1.0.0", + "description": "", + "main": "cypress-local-setup.js", + "scripts": { + "setup": "node cypress-local-setup.js" + }, + "author": "", + "license": "ISC", + "dependencies": { + "prompt-sync": "^4.2.0" + } +} diff --git a/app/client/cypress/scripts/yarn.lock b/app/client/cypress/scripts/yarn.lock new file mode 100644 index 0000000000..68749661d2 --- /dev/null +++ b/app/client/cypress/scripts/yarn.lock @@ -0,0 +1,39 @@ +# This file is generated by running "yarn install" inside your project. +# Manual changes might be lost - proceed with caution! + +__metadata: + version: 6 + cacheKey: 8 + +"ansi-regex@npm:^4.1.0": + version: 4.1.1 + resolution: "ansi-regex@npm:4.1.1" + checksum: b1a6ee44cb6ecdabaa770b2ed500542714d4395d71c7e5c25baa631f680fb2ad322eb9ba697548d498a6fd366949fc8b5bfcf48d49a32803611f648005b01888 + languageName: node + linkType: hard + +"prompt-sync@npm:^4.2.0": + version: 4.2.0 + resolution: "prompt-sync@npm:4.2.0" + dependencies: + strip-ansi: ^5.0.0 + checksum: b14dfb7d2520f384324b49a64c033e92cf2889e34a148037d66b0b89e43f530a93344aebf57c4abe3ae4e351080e22388f7141ea0fbc56b1b9a7f152d5d4a423 + languageName: node + linkType: hard + +"scripts@workspace:.": + version: 0.0.0-use.local + resolution: "scripts@workspace:." + dependencies: + prompt-sync: ^4.2.0 + languageName: unknown + linkType: soft + +"strip-ansi@npm:^5.0.0": + version: 5.2.0 + resolution: "strip-ansi@npm:5.2.0" + dependencies: + ansi-regex: ^4.1.0 + checksum: bdb5f76ade97062bd88e7723aa019adbfacdcba42223b19ccb528ffb9fb0b89a5be442c663c4a3fb25268eaa3f6ea19c7c3fbae830bd1562d55adccae1fcec46 + languageName: node + linkType: hard diff --git a/contributions/ClientSetup.md b/contributions/ClientSetup.md index d5c8d9b134..480ea1fc23 100644 --- a/contributions/ClientSetup.md +++ b/contributions/ClientSetup.md @@ -10,62 +10,66 @@ On your development machine, please ensure that: 1. You have `docker` installed in your system. If not, please visit: [https://docs.docker.com/get-docker/](https://docs.docker.com/get-docker/) 1. You have `mkcert` installed. Please visit: [https://github.com/FiloSottile/mkcert#installation](https://github.com/FiloSottile/mkcert#installation) for details. - - For `mkcert` to work with Firefox, you may need to install the `nss` utility. Details are in the link above. - - On Linux, you can easily install `mkcert` using the following command - ``` - curl -s https://api.github.com/repos/FiloSottile/mkcert/releases/latest \ - | grep "browser_download_url.*linux-amd64" \ - | cut -d : -f 2,3 | tr -d \" \ - | wget -i - -O mkcert - chmod +x mkcert - sudo mv mkcert /usr/local/bin - ``` + - For `mkcert` to work with Firefox, you may need to install the `nss` utility. Details are in the link above. + - On Linux, you can easily install `mkcert` using the following command + + ``` + curl -s https://api.github.com/repos/FiloSottile/mkcert/releases/latest \ + | grep "browser_download_url.*linux-amd64" \ + | cut -d : -f 2,3 | tr -d \" \ + | wget -i - -O mkcert + chmod +x mkcert + sudo mv mkcert /usr/local/bin + ``` 1. You have `envsubst` installed. Use `brew install gettext` on MacOS. Linux machines usually have this installed. 1. You have cloned the repo in your local machine. 1. You have yarn installed as a global npm package, i.e. `npm install -g yarn`. 1. Create local HTTPS certificates - 1. Run the following command from the project root. - ```bash - cd app/client/docker && mkcert -install && mkcert "*.appsmith.com" && cd ../../.. + 1. Run the following command from the project root. + + ```bash + cd app/client/docker && mkcert -install && mkcert "*.appsmith.com" && cd ../../.. + ``` + + This command will create 2 files in the `docker/` directory: + + - `_wildcard.appsmith.com-key.pem` + - `_wildcard.appsmith.com.pem` + + 1. Add the domain `dev.appsmith.com` to `/etc/hosts`. + + ```bash + echo "127.0.0.1 dev.appsmith.com" | sudo tee -a /etc/hosts + ``` + + Note: + + - Please be careful when copying the above string as space between the IP and the string goes missing sometimes. + - Please check that the string is copied properly + ``` - - This command will create 2 files in the `docker/` directory: - - - `_wildcard.appsmith.com-key.pem` - - `_wildcard.appsmith.com.pem` - - 1. Add the domain `dev.appsmith.com` to `/etc/hosts`. - - ```bash - echo "127.0.0.1 dev.appsmith.com" | sudo tee -a /etc/hosts + cat /etc/hosts | grep appsmith ``` - Note: - - - Please be careful when copying the above string as space between the IP and the string goes missing sometimes. - - Please check that the string is copied properly - - ``` - cat /etc/hosts | grep appsmith - ``` - 1. Run cmd: `cp .env.example .env` 1. Run Backend server - - The backend server can be run in two ways - 1. Use Appsmith's staging server hosted at `https://release.app.appsmith.com` for development purposes. (Recommended) - 1. Run the backend server locally. To setup the backend server locally, refer [here](#running-backend-locally). - - Run the script `start-https.sh` to start the nginx container that will proxy the frontend requests to the backend server. - - Pass the server name as an argument to this command to use that server as backend. - ```bash - cd app/client - ./start-https.sh https://release.app.appsmith.com // uses Appsmith's staging backend server as backend for your local frontend code - ``` + - The backend server can be run in two ways + 1. Use Appsmith's staging server hosted at `https://release.app.appsmith.com` for development purposes. (Recommended) + 1. Run the backend server locally. To setup the backend server locally, refer [here](#running-backend-locally). + - Run the script `start-https.sh` to start the nginx container that will proxy the frontend requests to the backend server. - - If you want to use the backend server running on your local, you do not need to pass a parameter when running `start-https.sh`. + - Pass the server name as an argument to this command to use that server as backend. + + ```bash + cd app/client + ./start-https.sh https://release.app.appsmith.com // uses Appsmith's staging backend server as backend for your local frontend code + ``` + + - If you want to use the backend server running on your local, you do not need to pass a parameter when running `start-https.sh`. ### Steps to build & run the code: @@ -86,80 +90,93 @@ On your development machine, please ensure that: 1. If yarn start throws mismatch node version error - - This error occurs because the node version is not compatible with the app environment. In this case, Node version manager can be used, allowing multiple node versions in different projects. - - Check below for installation and usage details: + - This error occurs because the node version is not compatible with the app environment. In this case, Node version manager can be used, allowing multiple node versions in different projects. + - Check below for installation and usage details: - 1. Install a node version manager. For eg: check [nvm](https://github.com/nvm-sh/nvm) or [fnm](https://github.com/Schniz/fnm). - 1. In the project's root, run `nvm use 18.17.1` or `fnm use 18.17.1`. + 1. Install a node version manager. For eg: check [nvm](https://github.com/nvm-sh/nvm) or [fnm](https://github.com/Schniz/fnm). + 1. In the project's root, run `nvm use 18.17.1` or `fnm use 18.17.1`. ### Running Tests on Client #### Integration Tests -- To pass credentials for logging in your cypress tests, you can create a local file `app/client/cypress.env.json` to populate `USERNAME` and `PASSWORD` env variables or use one of the methods [from their docs](https://docs.cypress.io/guides/guides/environment-variables.html#Setting). - ```json - { - "USERNAME": "Enter username", - "PASSWORD": "Enter password" - } - ``` -- To run cypress application for running tests, use these commands below, - ```bash - cd app/client - yarn run cytest - ``` +##### Pre-flight checks -- In order to run cypress tests which use datasources/rest api, you will need to have TED (Test Event Driver) container running: (It bundles multiple services together along with fake data for testing) - ``` - docker pull appsmith/test-event-driver +- The base URL can be updated on a temporary basis in the `cypress.config.ts` file based on the configuration you used for running the codebase locally. By default, it’s `https://dev.appsmith.com` . +- If you wish to run Git test cases locally, please add `APPSMITH_GIT_ROOT=./container-volumes/git-storage` to the folder `app/server/.env` and run the server locally instead of via Docker container. - docker run --name appsmithted -d -p 2222:22 -p 5001:5001 -p 3306:3306 -p 28017:27017 -p 5432:5432 -p 25:25 -p 5000:5000 -p 3000:3000 -v `pwd`/git-server/keys:/git-server/keys -v `pwd`/git-server/repos:/git-server/repo appsmith/test-event-driver - ``` +##### Setup Cypress configurations -- You need to have client and server running locally to run TED +To setup the configurations for running integration tests via Cypress, use these commands below, + +```bash + cd app/client/cypress/scripts + yarn install + yarn run setup +``` + +##### Running Cypress tests locally + +To run a specific test file in headless fashion, use the following command: + +```bash + cd app/client/ + yarn install + npx cypress run --spec --browser chrome +``` + +To open Cypress in the browser and run the tests visually + +```bash + cd app/client/ + yarn install + npx cypress open +``` - Running appsmith backend server locally + - There are two configurations available for running the backend server locally. + 1. Running the server from source code. - Refer to [documentation](https://github.com/appsmithorg/appsmith/blob/release/contributions/ServerSetup.md) for setting up backend to do this. - 1. Running the server from a docker image. There are two ways to get a backend docker image + 1. Running the server from a docker image. There are two ways to get a backend docker image + 1. Pull latest release branch docker image from Appsmith's public docker hub account. - ``` - docker rm appsmith; + ``` + docker rm appsmith; - cd ~/appsmith; + cd ~/appsmith; - rm -rf stacks; + rm -rf stacks; - docker pull appsmith/appsmith-ce + docker pull appsmith/appsmith-ce - docker run -d --name appsmith -p 8000:80 appsmith/appsmith-ce:latest; + docker run -d --name appsmith -p 8000:80 appsmith/appsmith-ce:latest; - docker logs -f appsmith; + docker logs -f appsmith; - ./start-https.sh http://localhost:8000 // if nginx is installed locally - ./start-https.sh http://host.docker.internal:8000 // if nginx is running on docker - - ``` + ./start-https.sh http://localhost:8000 // if nginx is installed locally + ./start-https.sh http://host.docker.internal:8000 // if nginx is running on docker + ``` 1. Create docker image from local source code - ``` - cd ~/appsmith - ./scripts/local_testing.sh -l # This builds a fat docker image of local backend and frontend - # The docker image created above will show up in your docker desktop application + ``` + cd ~/appsmith + ./scripts/local_testing.sh -l # This builds a fat docker image of local backend and frontend + # The docker image created above will show up in your docker desktop application - docker run -d --name appsmith -p 8000:80 appsmith/appsmith-ce:local-testing; + docker run -d --name appsmith -p 8000:80 appsmith/appsmith-ce:local-testing; - ./start-https.sh http://localhost:8000 // if nginx is installed locally - ./start-https.sh http://host.docker.internal:8000 // if nginx is running on docker + ./start-https.sh http://localhost:8000 // if nginx is installed locally + ./start-https.sh http://host.docker.internal:8000 // if nginx is running on docker + + ``` - ``` - Please check out our [Testing Contribution](docs/TestAutomation.md) guide for more details on setting up & troubleshooting Cypress runs on your machine. - ### Running Unit Tests - To run the Jest unit tests, run: @@ -170,6 +187,7 @@ On your development machine, please ensure that: ``` - To run a single jest test, + ```bash cd app/client