Adding Github Action workflow to the client code base (#66)
This PR adds the build, test & package workflow to the client code base as well. In order for us to run the Cypress tests, we also spin up a local server in a Docker container and run all our tests against that server. This ensures that our tests are faster to run as well. We also introduce the concept of stubbing network requests by stubbing the API that fetches the property pane configuration from the server. Results for the Cypress tests can be viewed at: https://dashboard.cypress.io/projects/eyxvp8/runs/
This commit is contained in:
parent
daeb39a8ce
commit
a9ed054cbb
151
.github/workflows/client.yml
vendored
151
.github/workflows/client.yml
vendored
|
|
@ -18,7 +18,10 @@ defaults:
|
|||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
defaults:
|
||||
run:
|
||||
working-directory: app/client
|
||||
|
||||
steps:
|
||||
# Checkout the code
|
||||
- uses: actions/checkout@v2
|
||||
|
|
@ -56,13 +59,149 @@ jobs:
|
|||
fi
|
||||
echo ::set-output name=REACT_APP_ENVIRONMENT::${REACT_APP_ENVIRONMENT}
|
||||
|
||||
- name: Build the code for automation
|
||||
run: |
|
||||
REACT_APP_ENVIRONMENT=${{steps.vars.outputs.REACT_APP_ENVIRONMENT}} GIT_SHA=${GITHUB_SHA} yarn build
|
||||
|
||||
- name: Run the jest tests
|
||||
run: REACT_APP_ENVIRONMENT=${{steps.vars.outputs.REACT_APP_ENVIRONMENT}} yarn run test:unit
|
||||
|
||||
|
||||
- name: Create the bundle
|
||||
run: REACT_APP_ENVIRONMENT=${{steps.vars.outputs.REACT_APP_ENVIRONMENT}} yarn build
|
||||
|
||||
# Upload the build artifact so that it can be used by the test & deploy job in the workflow
|
||||
- name: Upload react build bundle
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: build
|
||||
path: app/client/build/
|
||||
|
||||
ui-test:
|
||||
needs: build
|
||||
runs-on: ubuntu-latest
|
||||
# container: appsmith/cypress-nginx
|
||||
defaults:
|
||||
run:
|
||||
working-directory: app/client
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
job: [0, 1, 2, 3, 4, 5, 6]
|
||||
# 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:
|
||||
# Checkout the code
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Use Node.js 10.16.3
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: '10.16.3'
|
||||
|
||||
# Retrieve npm dependencies from cache. After a successful run, these dependencies are cached again
|
||||
- name: Cache npm dependencies
|
||||
uses: actions/cache@v2
|
||||
env:
|
||||
cache-name: cache-yarn-dependencies
|
||||
with:
|
||||
# maven dependencies are stored in `~/.m2` on Linux/macOS
|
||||
path: ~/.npm
|
||||
key: ${{ runner.OS }}-node-${{ hashFiles('**/yarn.lock') }}
|
||||
restore-keys: |
|
||||
${{ runner.OS }}-node-
|
||||
${{ runner.OS }}-
|
||||
|
||||
# Install all the dependencies
|
||||
- name: Install dependencies
|
||||
run: yarn install
|
||||
|
||||
- name: Download the react build artifact
|
||||
uses: actions/download-artifact@v2
|
||||
with:
|
||||
name: build
|
||||
path: app/client/build
|
||||
|
||||
- name: Pull server docker container and start it locally
|
||||
shell: bash
|
||||
run: |
|
||||
echo ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} | docker login -u ${{ secrets.DOCKER_HUB_USERNAME }} --password-stdin
|
||||
docker run -d --net=host --name appsmith-internal-server -p 8080:8080 \
|
||||
--env APPSMITH_MONGODB_URI=mongodb://localhost:27017/appsmith \
|
||||
--env APPSMITH_REDIS_URL=redis://localhost:6379 \
|
||||
--env APPSMITH_ENCRYPTION_PASSWORD=password \
|
||||
--env APPSMITH_ENCRYPTION_SALT=salt \
|
||||
appsmith/appsmith-server:latest
|
||||
|
||||
- name: Installing Yarn serve
|
||||
run: |
|
||||
yarn global add serve
|
||||
echo "::add-path::$(yarn global bin)"
|
||||
|
||||
- name: Setting up the cypress tests
|
||||
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 }}
|
||||
run: |
|
||||
./cypress/setup-test.sh
|
||||
|
||||
- name: Run the cypress test
|
||||
uses: cypress-io/github-action@v2
|
||||
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 }}
|
||||
with:
|
||||
browser: chrome
|
||||
headless: true
|
||||
record: true
|
||||
install: false
|
||||
parallel: true
|
||||
group: 'Electrons on Github Action'
|
||||
ci-build-id: '${{ github.sha }}-${{ github.workflow }}-${{ github.event_name }}'
|
||||
spec: 'cypress/integration/Smoke_TestSuite/*/*'
|
||||
working-directory: app/client
|
||||
|
||||
# Upload the screenshots as artifacts if there's a failure
|
||||
- uses: actions/upload-artifact@v1
|
||||
if: failure()
|
||||
with:
|
||||
name: cypress-screenshots-${{ matrix.job }}
|
||||
path: app/client/cypress/screenshots/
|
||||
|
||||
package:
|
||||
needs: ui-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: always() && (github.ref == 'refs/heads/release' || github.ref == 'refs/heads/release')
|
||||
|
||||
steps:
|
||||
|
||||
# Checkout the code
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Download the react build artifact
|
||||
uses: actions/download-artifact@v2
|
||||
with:
|
||||
name: build
|
||||
path: app/client/build
|
||||
|
||||
# Here, the GITHUB_REF is of type /refs/head/<branch_name>. We extract branch_name from this by removing the
|
||||
# first 11 characters. This can be used to build images for several branches
|
||||
- name: Get the version to tag the Docker image
|
||||
|
|
|
|||
|
|
@ -1,3 +1,8 @@
|
|||
FROM cypress/browsers:node10.16.3-chrome80-ff73
|
||||
# FROM cypress/browsers:node10.16.3-chrome80-ff73
|
||||
FROM nginx:1.17.9-alpine
|
||||
|
||||
RUN apt-get update -y && apt-get install -y nginx && apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* && yarn global add serve
|
||||
RUN apt update -y -q && \
|
||||
apt-get install -y -q nginx gettext-base && \
|
||||
apt-get clean && \
|
||||
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* && \
|
||||
yarn global add serve
|
||||
|
|
|
|||
|
|
@ -79,3 +79,5 @@ This section has moved here: https://facebook.github.io/create-react-app/docs/de
|
|||
### `npm run build` fails to minify
|
||||
|
||||
This section has moved here: https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -12,9 +12,5 @@
|
|||
"json": false
|
||||
},
|
||||
"viewportHeight": 900,
|
||||
"viewportWidth": 1400,
|
||||
"env": {
|
||||
"username": "",
|
||||
"password": ""
|
||||
}
|
||||
"viewportWidth": 1400
|
||||
}
|
||||
|
|
|
|||
33
app/client/cypress/cypress-docker-compose.yml
Normal file
33
app/client/cypress/cypress-docker-compose.yml
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
version: "3.7"
|
||||
|
||||
services:
|
||||
appsmith-server:
|
||||
image: appsmith/appsmith-server:latest
|
||||
environment:
|
||||
APPSMITH_MONGODB_URI: "mongodb://mongo:27017/appsmith"
|
||||
APPSMITH_REDIS_URL: "redis://redis:6379"
|
||||
APPSMITH_MAIL_ENABLED: "false"
|
||||
ports:
|
||||
- "8080:8080"
|
||||
links:
|
||||
- mongo
|
||||
depends_on:
|
||||
- mongo
|
||||
networks:
|
||||
- appsmith
|
||||
|
||||
mongo:
|
||||
image: mongo
|
||||
environment:
|
||||
- MONGO_INITDB_DATABASE=appsmith
|
||||
networks:
|
||||
- appsmith
|
||||
|
||||
redis:
|
||||
image: redis
|
||||
networks:
|
||||
- appsmith
|
||||
|
||||
networks:
|
||||
appsmith:
|
||||
driver: bridge
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
{
|
||||
"appname": "AutoDslCypress"
|
||||
|
||||
}
|
||||
1135
app/client/cypress/fixtures/propertyPaneResponse.json
Normal file
1135
app/client/cypress/fixtures/propertyPaneResponse.json
Normal file
File diff suppressed because it is too large
Load Diff
|
|
@ -1,6 +0,0 @@
|
|||
|
||||
{
|
||||
"username": "testowner@appsmith.com",
|
||||
"password": "own3rT3st1ng"
|
||||
|
||||
}
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
/// <reference types="Cypress" />
|
||||
|
||||
const dsl = require("../../../fixtures/commondsl.json");
|
||||
const pages = require("../../../locators/Pages.json");
|
||||
const dynamicInputLocators = require("../../../locators/DynamicInput.json");
|
||||
|
|
@ -8,6 +10,7 @@ describe("Dynamic input autocomplete", () => {
|
|||
cy.addDsl(dsl);
|
||||
});
|
||||
it("opens autocomplete for bindings", () => {
|
||||
cy.wait("@getPropertyPane");
|
||||
cy.get(pages.widgetsEditor).click();
|
||||
cy.openPropertyPane("buttonwidget");
|
||||
cy.get(dynamicInputLocators.input)
|
||||
|
|
@ -55,6 +58,7 @@ describe("Dynamic input autocomplete", () => {
|
|||
});
|
||||
it("opens current value popup", () => {
|
||||
// Test on widgets pane
|
||||
cy.wait("@getPropertyPane");
|
||||
cy.get(pages.widgetsEditor).click();
|
||||
cy.openPropertyPane("buttonwidget");
|
||||
cy.get(dynamicInputLocators.input)
|
||||
|
|
|
|||
|
|
@ -1,11 +1,10 @@
|
|||
const loginData = require("../../../fixtures/user.json");
|
||||
let pageid;
|
||||
let appId;
|
||||
|
||||
describe("Login from UI and check the functionality", function() {
|
||||
it("Login/create page/delete page/delete app from UI", function() {
|
||||
const appname = localStorage.getItem("AppName");
|
||||
cy.LogintoApp(loginData.username, loginData.password);
|
||||
cy.LogintoApp(Cypress.env("USERNAME"), Cypress.env("PASSWORD"));
|
||||
cy.SearchApp(appname);
|
||||
cy.get("#loading").should("not.exist");
|
||||
cy.wait("@getPropertyPane");
|
||||
|
|
|
|||
|
|
@ -26,4 +26,16 @@ module.exports = (on, config) => {
|
|||
|
||||
return launchOptions;
|
||||
});
|
||||
|
||||
/**
|
||||
* This task logs the message on the CLI terminal. Use with care because it can log sensitive details
|
||||
* Example usage: cy.task('log', 'This is the message printed to the terminal')
|
||||
*/
|
||||
|
||||
on("task", {
|
||||
log(message) {
|
||||
console.log(message);
|
||||
return null;
|
||||
},
|
||||
});
|
||||
};
|
||||
|
|
|
|||
46
app/client/cypress/setup-test.sh
Executable file
46
app/client/cypress/setup-test.sh
Executable file
|
|
@ -0,0 +1,46 @@
|
|||
#! /bin/sh
|
||||
|
||||
# This script is responsible for setting up the local Nginx server for running E2E Cypress tests
|
||||
# on our CI/CD system. Currently the script is geared towards Github Actions
|
||||
|
||||
# Serve the react bundle on a specific port. Nginx will proxy to this port
|
||||
echo "Starting the setup the test framework"
|
||||
sudo echo "127.0.0.1 dev.appsmith.com" | sudo tee -a /etc/hosts
|
||||
serve -s build -p 3000 &
|
||||
|
||||
# Substitute all the env variables in nginx
|
||||
vars_to_substitute=$(printf '\$%s,' $(env | grep -o "^APPSMITH_[A-Z0-9_]\+" | xargs))
|
||||
cat ./docker/templates/nginx-linux.conf.template | envsubst ${vars_to_substitute} | sed -e 's|\${\(APPSMITH_[A-Z0-9_]*\)}||g' > ./docker/nginx.conf
|
||||
|
||||
# Create the SSL files for Nginx. Required for service workers to work properly.
|
||||
touch ./docker/dev.appsmith.com.pem ./docker/dev.appsmith.com-key.pem
|
||||
echo "$APPSMITH_SSL_CERTIFICATE" > ./docker/dev.appsmith.com.pem
|
||||
echo "$APPSMITH_SSL_KEY" > ./docker/dev.appsmith.com-key.pem
|
||||
|
||||
echo "Going to run the nginx server"
|
||||
sudo docker pull nginx:latest
|
||||
|
||||
sudo docker run --network host --name wildcard-nginx -d -p 80:80 -p 443:443 \
|
||||
-v `pwd`/docker/nginx.conf:/etc/nginx/conf.d/app.conf \
|
||||
-v `pwd`/docker/dev.appsmith.com.pem:/etc/certificate/dev.appsmith.com.pem \
|
||||
-v `pwd`/docker/dev.appsmith.com-key.pem:/etc/certificate/dev.appsmith.com-key.pem \
|
||||
nginx:latest &
|
||||
|
||||
echo "Sleeping for 10 seconds to let the server start"
|
||||
sleep 10
|
||||
|
||||
# Create the test user
|
||||
curl -k --request POST -v 'https://dev.appsmith.com/api/v1/users' \
|
||||
--header 'Content-Type: application/json' \
|
||||
--data-raw '{
|
||||
"name" : "'"$CYPRESS_USERNAME"'",
|
||||
"email" : "'"$CYPRESS_USERNAME"'",
|
||||
"source" : "FORM",
|
||||
"state" : "ACTIVATED",
|
||||
"isEnabled" : "true",
|
||||
"password": "'"$CYPRESS_PASSWORD"'"
|
||||
}'
|
||||
|
||||
# DEBUG=cypress:* $(npm bin)/cypress version
|
||||
# sed -i -e "s|api_url:.*$|api_url: $CYPRESS_URL|g" /github/home/.cache/Cypress/4.1.0/Cypress/resources/app/packages/server/config/app.yml
|
||||
# cat /github/home/.cache/Cypress/4.1.0/Cypress/resources/app/packages/server/config/app.yml
|
||||
|
|
@ -14,6 +14,7 @@ const formWidgetsPage = require("../locators/FormWidgets.json");
|
|||
const ApiEditor = require("../locators/ApiEditor.json");
|
||||
const apiwidget = require("../locators/apiWidgetslocator.json");
|
||||
const dynamicInputLocators = require("../locators/DynamicInput.json");
|
||||
|
||||
let pageidcopy = " ";
|
||||
|
||||
Cypress.Commands.add("CreateApp", appname => {
|
||||
|
|
@ -1123,7 +1124,14 @@ Cypress.Commands.add("startServerAndRoutes", () => {
|
|||
cy.route("GET", "/api/v1/plugins").as("getPlugins");
|
||||
cy.route("POST", "/api/v1/logout").as("postLogout");
|
||||
|
||||
cy.route("GET", "/api/v1/configs/name/propertyPane").as("getPropertyPane");
|
||||
cy.route({
|
||||
method: "GET",
|
||||
url: "**/api/v1/configs/name/propertyPane",
|
||||
status: 200,
|
||||
response: "fixture:../fixtures/propertyPaneResponse.json",
|
||||
delay: 100,
|
||||
}).as("getPropertyPane");
|
||||
|
||||
cy.route("GET", "/api/v1/datasources").as("getDataSources");
|
||||
cy.route("GET", "/api/v1/pages/application/*").as("getPagesForApp");
|
||||
cy.route("GET", "/api/v1/pages/*").as("getPage");
|
||||
|
|
|
|||
|
|
@ -13,8 +13,6 @@
|
|||
// https://on.cypress.io/configuration
|
||||
// ***********************************************************
|
||||
require("cypress-xpath");
|
||||
const loginData = require("../fixtures/user.json");
|
||||
const inputData = require("../fixtures/inputdata.json");
|
||||
let pageid;
|
||||
let appId;
|
||||
|
||||
|
|
@ -28,10 +26,10 @@ Cypress.on("uncaught:exception", (err, runnable) => {
|
|||
});
|
||||
|
||||
before(function() {
|
||||
console.log("**** Got Cypress base URL as: ", process.env.CYPRESS_BASE_URL);
|
||||
cy.startServerAndRoutes();
|
||||
//cy.LogintoApp(loginData.username, loginData.password);
|
||||
cy.LoginFromAPI(Cypress.env("username"), Cypress.env("password"));
|
||||
const username = Cypress.env("USERNAME");
|
||||
const password = Cypress.env("PASSWORD");
|
||||
cy.LoginFromAPI(username, password);
|
||||
cy.visit("/applications");
|
||||
cy.wait("@applications").should(
|
||||
"have.nested.property",
|
||||
|
|
@ -45,14 +43,6 @@ before(function() {
|
|||
localStorage.setItem("AppName", appId);
|
||||
});
|
||||
|
||||
/*
|
||||
cy.generateUUID().then(uid => {
|
||||
pageid = uid;
|
||||
cy.Createpage(pageid);
|
||||
cy.NavigateToWidgets(pageid);
|
||||
localStorage.setItem("PageName", pageid);
|
||||
});
|
||||
*/
|
||||
cy.fixture("example").then(function(data) {
|
||||
this.data = data;
|
||||
});
|
||||
|
|
@ -64,9 +54,6 @@ beforeEach(function() {
|
|||
});
|
||||
|
||||
after(function() {
|
||||
// ---commenting Publish app and Delete page as of now--- //
|
||||
//cy.Deletepage(pageid);
|
||||
//cy.PublishtheApp();
|
||||
//-- Deleting the application by Api---//
|
||||
cy.DeleteAppByApi();
|
||||
//-- LogOut Application---//
|
||||
|
|
|
|||
|
|
@ -27,8 +27,8 @@ if [ "$target" == "ci" ]; then
|
|||
# On the CI server run the tests in parallel
|
||||
# This requires the projectId and the record_key to be configured in your environment variables. By default this is defined on the CI server
|
||||
echo "Got the Build ID: $BUILD_ID"
|
||||
CYPRESS_PROJECT_ID=appsmith-project $(npm bin)/cypress run --headless --browser chrome \
|
||||
--record --key "random-key" --ci-build-id $BUILD_ID \
|
||||
$(npm bin)/cypress run --headless --browser chrome \
|
||||
--record --key "$CYPRESS_RECORD_KEY" --ci-build-id $BUILD_ID \
|
||||
--parallel --group "Electrons on Gitlab CI" \
|
||||
--spec "cypress/integration/Smoke_TestSuite/*/*"
|
||||
else
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ server {
|
|||
proxy_set_header X-Forwarded-Host $host;
|
||||
proxy_set_header Accept-Encoding "";
|
||||
|
||||
|
||||
sub_filter_once off;
|
||||
location / {
|
||||
proxy_pass http://localhost:3000;
|
||||
|
|
@ -41,19 +40,19 @@ server {
|
|||
location /api {
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Host $host;
|
||||
proxy_pass https://release-api.appsmith.com;
|
||||
proxy_pass http://localhost:8080;
|
||||
}
|
||||
|
||||
location /oauth2 {
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Host $host;
|
||||
proxy_pass https://release-api.appsmith.com;
|
||||
proxy_pass http://localhost:8080;
|
||||
}
|
||||
|
||||
location /login {
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Host $host;
|
||||
proxy_pass https://release-api.appsmith.com;
|
||||
proxy_pass http://localhost:8080;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -103,19 +102,19 @@ server {
|
|||
location /api {
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Host $host;
|
||||
proxy_pass https://release-api.appsmith.com;
|
||||
proxy_pass http://localhost:8080;
|
||||
}
|
||||
|
||||
location /oauth2 {
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Host $host;
|
||||
proxy_pass https://release-api.appsmith.com;
|
||||
proxy_pass http://localhost:8080;
|
||||
}
|
||||
|
||||
location /login {
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Host $host;
|
||||
proxy_pass https://release-api.appsmith.com;
|
||||
proxy_pass http://localhost:8080;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user