diff --git a/.github/helper/install.sh b/.github/helper/install.sh
new file mode 100644
index 00000000..8b8de45a
--- /dev/null
+++ b/.github/helper/install.sh
@@ -0,0 +1,48 @@
+#!/bin/bash
+set -e
+cd ~ || exit
+
+echo "Setting Up Bench..."
+
+pip install frappe-bench
+bench -v init frappe-bench --skip-assets --python "$(which python)"
+cd ./frappe-bench || exit
+
+bench -v setup requirements
+
+echo "Setting Up Builder App..."
+bench get-app builder "${GITHUB_WORKSPACE}"
+
+echo "Setting Up Sites & Database..."
+
+mkdir ~/frappe-bench/sites/builder.test
+cp "${GITHUB_WORKSPACE}/.github/helper/site_config.json" ~/frappe-bench/sites/builder.test/site_config.json
+
+mariadb --host 127.0.0.1 --port 3306 -u root -p123 -e "SET GLOBAL character_set_server = 'utf8mb4'";
+mariadb --host 127.0.0.1 --port 3306 -u root -p123 -e "SET GLOBAL collation_server = 'utf8mb4_unicode_ci'";
+
+mariadb --host 127.0.0.1 --port 3306 -u root -p123 -e "CREATE DATABASE test_builder";
+mariadb --host 127.0.0.1 --port 3306 -u root -p123 -e "CREATE USER 'test_builder'@'localhost' IDENTIFIED BY 'test_builder'";
+mariadb --host 127.0.0.1 --port 3306 -u root -p123 -e "GRANT ALL PRIVILEGES ON \`test_builder\`.* TO 'test_builder'@'localhost'";
+
+mariadb --host 127.0.0.1 --port 3306 -u root -p123 -e "FLUSH PRIVILEGES";
+
+
+echo "Setting Up Procfile..."
+
+sed -i 's/^watch:/# watch:/g' Procfile
+sed -i 's/^schedule:/# schedule:/g' Procfile
+
+
+echo "Starting Bench..."
+
+bench start &> bench_start.log &
+
+CI=Yes bench build &
+build_pid=$!
+
+bench --site builder.test reinstall --yes
+bench --site builder.test install-app website_builder
+
+# wait till assets are built succesfully
+wait $build_pid
diff --git a/.github/helper/install_dependencies.sh b/.github/helper/install_dependencies.sh
new file mode 100644
index 00000000..fdcd920e
--- /dev/null
+++ b/.github/helper/install_dependencies.sh
@@ -0,0 +1,17 @@
+#!/bin/bash
+set -e
+
+echo "Setting Up System Dependencies..."
+
+# redis repository
+curl -fsSL https://packages.redis.io/gpg | sudo gpg --dearmor -o /usr/share/keyrings/redis-archive-keyring.gpg
+echo "deb [signed-by=/usr/share/keyrings/redis-archive-keyring.gpg] https://packages.redis.io/deb $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/redis.list
+
+sudo apt update
+sudo apt install libcups2-dev redis mariadb-client-10.6
+
+install_wkhtmltopdf() {
+ wget -q https://github.com/wkhtmltopdf/packaging/releases/download/0.12.6-1/wkhtmltox_0.12.6-1.focal_amd64.deb
+ sudo apt install ./wkhtmltox_0.12.6-1.focal_amd64.deb
+}
+install_wkhtmltopdf &
diff --git a/.github/helper/site_config.json b/.github/helper/site_config.json
new file mode 100644
index 00000000..134aab8d
--- /dev/null
+++ b/.github/helper/site_config.json
@@ -0,0 +1,20 @@
+{
+ "db_host": "127.0.0.1",
+ "db_port": 3306,
+ "db_name": "test_builder",
+ "db_password": "test_builder",
+ "allow_tests": true,
+ "enable_ui_tests": true,
+ "db_type": "mariadb",
+ "auto_email_id": "test@example.com",
+ "mail_server": "smtp.example.com",
+ "mail_login": "test@example.com",
+ "mail_password": "test",
+ "admin_password": "admin",
+ "root_login": "root",
+ "root_password": "123",
+ "host_name": "http://builder.test:8000",
+ "monitor": 1,
+ "server_script_enabled": true,
+ "mute_emails": true
+}
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index e30c9a05..519b50d4 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -4,11 +4,11 @@ name: CI
on:
push:
branches:
- - develop
+ - main
pull_request:
concurrency:
- group: develop-website_builder-${{ github.event.number }}
+ group: main-website_builder-${{ github.event.number }}
cancel-in-progress: true
jobs:
diff --git a/.github/workflows/ui-test.yml b/.github/workflows/ui-test.yml
new file mode 100644
index 00000000..057e7225
--- /dev/null
+++ b/.github/workflows/ui-test.yml
@@ -0,0 +1,100 @@
+name: UI Test
+
+on:
+ pull_request:
+ push:
+ branches: [ main ]
+
+permissions:
+ contents: read
+
+jobs:
+ test:
+ runs-on: ubuntu-latest
+ if: ${{ github.repository_owner == 'frappe' }}
+ timeout-minutes: 60
+
+ strategy:
+ fail-fast: false
+
+ name: UI Tests (Cypress)
+
+ services:
+ mariadb:
+ image: mariadb:10.6
+ env:
+ MARIADB_ROOT_PASSWORD: 123
+ ports:
+ - 3306:3306
+ options: --health-cmd="mysqladmin ping" --health-interval=5s --health-timeout=2s --health-retries=3
+
+ steps:
+ - name: Clone
+ uses: actions/checkout@v3
+
+ - name: Setup Python
+ uses: actions/setup-python@v4
+ with:
+ python-version: '3.10'
+
+ - uses: actions/setup-node@v3
+ with:
+ node-version: 18
+ check-latest: true
+
+ - name: Add to Hosts
+ run: |
+ echo "127.0.0.1 builder.test" | sudo tee -a /etc/hosts
+
+ - name: Cache pip
+ uses: actions/cache@v3
+ with:
+ path: ~/.cache/pip
+ key: ${{ runner.os }}-pip-${{ hashFiles('**/*requirements.txt', '**/pyproject.toml', '**/setup.py') }}
+ restore-keys: |
+ ${{ runner.os }}-pip-
+ ${{ runner.os }}-
+
+ - name: Get yarn cache directory path
+ id: yarn-cache-dir-path
+ run: echo "::set-output name=dir::$(yarn cache dir)"
+
+ - uses: actions/cache@v3
+ id: yarn-cache
+ with:
+ path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
+ key: ${{ runner.os }}-yarn-ui-${{ hashFiles('**/yarn.lock') }}
+ restore-keys: |
+ ${{ runner.os }}-yarn-ui-
+
+ - name: Cache cypress binary
+ uses: actions/cache@v3
+ with:
+ path: ~/.cache/Cypress
+ key: ${{ runner.os }}-cypress
+
+ - name: Install Dependencies
+ run: |
+ bash ${GITHUB_WORKSPACE}/.github/helper/install_dependencies.sh
+ bash ${GITHUB_WORKSPACE}/.github/helper/install.sh
+ env:
+ BEFORE: ${{ env.GITHUB_EVENT_PATH.before }}
+ AFTER: ${{ env.GITHUB_EVENT_PATH.after }}
+
+ - name: Site Setup
+ run: |
+ cd ~/frappe-bench/
+ bench --site builder.test execute frappe.utils.install.complete_setup_wizard
+ bench --site builder.test execute frappe.tests.ui_test_helpers.create_test_user
+
+ - name: UI Tests
+ run: cd ~/frappe-bench/apps/gameplan/frontend && yarn test
+
+ - name: Stop server
+ run: |
+ ps -ef | grep "[f]rappe serve" | awk '{print $2}' | xargs kill -s SIGINT
+ sleep 5
+
+ - name: Show bench output
+ if: ${{ always() }}
+ run: cat ~/frappe-bench/bench_start.log || true
diff --git a/frontend/cypress.config.ts b/frontend/cypress.config.ts
new file mode 100644
index 00000000..98e70ca4
--- /dev/null
+++ b/frontend/cypress.config.ts
@@ -0,0 +1,13 @@
+import { defineConfig } from "cypress";
+
+module.exports = defineConfig({
+ projectId: "jvejd7",
+ e2e: {
+ baseUrl: "http://builder.test:8000",
+ adminPassword: "admin",
+ },
+ retries: {
+ runMode: 2,
+ openMode: 0,
+ },
+});
diff --git a/frontend/cypress/e2e/landing.cy.ts b/frontend/cypress/e2e/landing.cy.ts
new file mode 100644
index 00000000..dc7fd2d9
--- /dev/null
+++ b/frontend/cypress/e2e/landing.cy.ts
@@ -0,0 +1,8 @@
+describe("Builder Landing", () => {
+ before(() => {
+ cy.login();
+ });
+ it("Open builder page", () => {
+ cy.visit("builder/home");
+ });
+});
diff --git a/frontend/cypress/support/commands.ts b/frontend/cypress/support/commands.ts
new file mode 100644
index 00000000..eb2286dd
--- /dev/null
+++ b/frontend/cypress/support/commands.ts
@@ -0,0 +1,51 @@
+///
+// ***********************************************
+// This example commands.ts shows you how to
+// create various custom commands and overwrite
+// existing commands.
+//
+// For more comprehensive examples of custom
+// commands please read more here:
+// https://on.cypress.io/custom-commands
+// ***********************************************
+//
+//
+// -- This is a parent command --
+// Cypress.Commands.add('login', (email, password) => { ... })
+//
+//
+// -- This is a child command --
+// Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... })
+//
+//
+// -- This is a dual command --
+// Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... })
+//
+//
+// -- This will overwrite an existing command --
+// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... })
+//
+// declare global {
+// namespace Cypress {
+// interface Chainable {
+// login(email: string, password: string): Chainable
+// drag(subject: string, options?: Partial): Chainable
+// dismiss(subject: string, options?: Partial): Chainable
+// visit(originalFn: CommandOriginalFn, url: string, options: Partial): Chainable
+// }
+// }
+// }
+
+Cypress.Commands.add("login", (email, password) => {
+ if (!email) {
+ email = Cypress.config("testUser") || "Administrator";
+ }
+ if (!password) {
+ password = Cypress.config("adminPassword");
+ }
+ cy.request({
+ url: "/api/method/login",
+ method: "POST",
+ body: { usr: email, pwd: password },
+ });
+});
diff --git a/frontend/cypress/support/e2e.ts b/frontend/cypress/support/e2e.ts
new file mode 100644
index 00000000..f80f74f8
--- /dev/null
+++ b/frontend/cypress/support/e2e.ts
@@ -0,0 +1,20 @@
+// ***********************************************************
+// This example support/e2e.ts is processed and
+// loaded automatically before your test files.
+//
+// This is a great place to put global configuration and
+// behavior that modifies Cypress.
+//
+// You can change the location of this file or turn off
+// automatically serving support files with the
+// 'supportFile' configuration option.
+//
+// You can read more here:
+// https://on.cypress.io/configuration
+// ***********************************************************
+
+// Import commands.js using ES2015 syntax:
+import './commands'
+
+// Alternatively you can use CommonJS syntax:
+// require('./commands')
\ No newline at end of file
diff --git a/frontend/cypress/tsconfig.json b/frontend/cypress/tsconfig.json
new file mode 100644
index 00000000..c3693385
--- /dev/null
+++ b/frontend/cypress/tsconfig.json
@@ -0,0 +1,11 @@
+{
+ "extends": "../tsconfig.json",
+ "include": [
+ "../node_modules/cypress",
+ "*/*.ts"
+ ],
+ "compilerOptions": {
+ "noEmit": false,
+ "sourceMap": false
+ }
+}
\ No newline at end of file
diff --git a/frontend/package.json b/frontend/package.json
index f443984a..a7e26f90 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -7,7 +7,9 @@
"dev": "vite",
"build": "vite build --base=/assets/website_builder/frontend/ && yarn copy-html-entry",
"copy-html-entry": "cp ../website_builder/public/frontend/index.html ../website_builder/www/builder.html",
- "preview": "vite preview"
+ "preview": "vite preview",
+ "test-local": "cypress open --e2e --browser chrome",
+ "test": "npx cypress run --record --key fa50a4df-569e-41bc-8600-850331fd1630"
},
"dependencies": {
"@tiptap/extension-color": "^2.0.4",
@@ -31,6 +33,7 @@
"devDependencies": {
"@vitejs/plugin-vue": "3",
"autoprefixer": "^10.4.2",
+ "cypress": "^13.3.1",
"eslint": "^8.38.0",
"eslint-plugin-import": "^2.27.5",
"eslint-plugin-vue": "^9.11.0",
diff --git a/frontend/tsconfig.json b/frontend/tsconfig.json
index d76ed781..530ce5a7 100644
--- a/frontend/tsconfig.json
+++ b/frontend/tsconfig.json
@@ -21,7 +21,7 @@
"@/*": [
"src/*"
],
- "tslib" : ["/node_modules/tslib/tslib.d.ts"]
+ "tslib" : ["/node_modules/tslib/"]
},
"lib": [
"esnext",
diff --git a/website_builder/www/builder.html b/website_builder/www/builder.html
index c4f8c2a9..62f50792 100644
--- a/website_builder/www/builder.html
+++ b/website_builder/www/builder.html
@@ -7,8 +7,8 @@
Frappe Builder
-
-
+
+
@@ -18,6 +18,5 @@
-