From 165ef4a017833e757a69da734985acd18155228e Mon Sep 17 00:00:00 2001 From: Miu Razvan Date: Tue, 25 Oct 2022 15:52:50 +0300 Subject: [PATCH] Use latest cypress --- .coverage.babel.config.js | 2 +- .gitignore | 10 +- .i18n.babel.config.js | 1 + .npmignore | 96 ++++++++++ .project.eslintrc.js | 46 +++++ Jenkinsfile | 12 +- Makefile | 98 ++++++++++ README.md | 74 +------- RELEASE.md | 74 ++++++++ babel.config.js | 17 ++ cypress.config.js | 26 +++ cypress.json | 17 -- .../01-block-basics.cy.js} | 9 +- cypress/plugins/index.js | 26 --- cypress/support/commands.js | 172 +++++++++++++++++- cypress/support/e2e.js | 125 +++++++++++++ cypress/support/index.js | 53 ------ jest-addon.config.js | 5 +- locales/volto.pot | 0 package.json | 5 +- 20 files changed, 679 insertions(+), 189 deletions(-) create mode 100644 .i18n.babel.config.js create mode 100644 .npmignore create mode 100644 .project.eslintrc.js create mode 100644 Makefile create mode 100644 RELEASE.md create mode 100644 babel.config.js create mode 100644 cypress.config.js delete mode 100644 cypress.json rename cypress/{integration/block-basics.js => e2e/01-block-basics.cy.js} (79%) delete mode 100644 cypress/plugins/index.js create mode 100644 cypress/support/e2e.js delete mode 100644 cypress/support/index.js create mode 100644 locales/volto.pot diff --git a/.coverage.babel.config.js b/.coverage.babel.config.js index e8b54d3..37219fd 100644 --- a/.coverage.babel.config.js +++ b/.coverage.babel.config.js @@ -2,7 +2,7 @@ const defaultBabel = require('@plone/volto/babel'); function applyDefault(api) { const voltoBabel = defaultBabel(api); - voltoBabel.plugins.push('@babel/plugin-transform-modules-commonjs', 'transform-class-properties', 'istanbul'); + voltoBabel.plugins.push('istanbul'); return voltoBabel; } diff --git a/.gitignore b/.gitignore index 28b40bb..53b9801 100644 --- a/.gitignore +++ b/.gitignore @@ -1,19 +1,27 @@ .vscode/ .history +.eslintrc.js +.nyc_output +project +coverage logs *.log npm-debug.log* .DS_Store *.swp yarn-error.log +yarn.lock +package-lock.json node_modules build dist -screenshots cypress/videos cypress/reports +screenshots +videos .env.local .env.development.local .env.test.local .env.production.local +*~ diff --git a/.i18n.babel.config.js b/.i18n.babel.config.js new file mode 100644 index 0000000..a900a75 --- /dev/null +++ b/.i18n.babel.config.js @@ -0,0 +1 @@ +module.exports = require('@plone/volto/babel'); diff --git a/.npmignore b/.npmignore new file mode 100644 index 0000000..080322a --- /dev/null +++ b/.npmignore @@ -0,0 +1,96 @@ +# https://docs.npmjs.com/using-npm/developers.html#keeping-files-out-of-your-package + +# Directories +api/ +bin/ +build/ +lib/ +g-api/ +tests/ + +# Docs +docs/ + +# Cypress +cypress/ + +# Tests +__tests__/ +*.snap + +# Files +.travis.yml +requirements-docs.txt +requirements-tests.txt +yarn.lock +.dockerignore +.gitattributes +.yarnrc +.nvmrc +changelogupdater.js +pip-selfcheck.json +Dockerfile +CNAME +entrypoint.sh +Jenkinsfile +Makefile + +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage + +# nyc test coverage +.nyc_output + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# TypeScript v1 declaration files +typings/ + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env + +# next.js build output +.next + +styleguide.config +.vscode +packages diff --git a/.project.eslintrc.js b/.project.eslintrc.js new file mode 100644 index 0000000..cfefd89 --- /dev/null +++ b/.project.eslintrc.js @@ -0,0 +1,46 @@ +const fs = require('fs'); +const path = require('path'); + +const projectRootPath = fs.realpathSync('./project'); // __dirname +const packageJson = require(path.join(projectRootPath, 'package.json')); +const jsConfig = require(path.join(projectRootPath, 'jsconfig.json')).compilerOptions; + +const pathsConfig = jsConfig.paths; + +let voltoPath = path.join(projectRootPath, 'node_modules/@plone/volto'); + +Object.keys(pathsConfig).forEach(pkg => { + if (pkg === '@plone/volto') { + voltoPath = `./${jsConfig.baseUrl}/${pathsConfig[pkg][0]}`; + } +}); +const AddonConfigurationRegistry = require(`${voltoPath}/addon-registry.js`); +const reg = new AddonConfigurationRegistry(projectRootPath); + +// Extends ESlint configuration for adding the aliases to `src` directories in Volto addons +const addonAliases = Object.keys(reg.packages).map(o => [ + o, + reg.packages[o].modulePath, +]); + + +module.exports = { + extends: `${projectRootPath}/node_modules/@plone/volto/.eslintrc`, + settings: { + 'import/resolver': { + alias: { + map: [ + ['@plone/volto', '@plone/volto/src'], + ...addonAliases, + ['@package', `${__dirname}/src`], + ['~', `${__dirname}/src`], + ], + extensions: ['.js', '.jsx', '.json'], + }, + 'babel-plugin-root-import': { + rootPathSuffix: 'src', + }, + }, + }, +}; + diff --git a/Jenkinsfile b/Jenkinsfile index 721f306..bb3481e 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -41,19 +41,19 @@ pipeline { "ES lint": { node(label: 'docker') { - sh '''docker run -i --rm --name="$BUILD_TAG-eslint" -e NAMESPACE="$NAMESPACE" -e GIT_NAME=$GIT_NAME -e GIT_BRANCH="$BRANCH_NAME" -e GIT_CHANGE_ID="$CHANGE_ID" plone/volto-addon-ci eslint''' + sh '''docker run -i --rm --name="$BUILD_TAG-eslint" -e NAMESPACE="$NAMESPACE" -e GIT_NAME=$GIT_NAME -e GIT_BRANCH="$BRANCH_NAME" -e GIT_CHANGE_ID="$CHANGE_ID" -e VOLTO=$VOLTO plone/volto-addon-ci:alpha eslint''' } }, "Style lint": { node(label: 'docker') { - sh '''docker run -i --rm --name="$BUILD_TAG-stylelint" -e NAMESPACE="$NAMESPACE" -e GIT_NAME=$GIT_NAME -e GIT_BRANCH="$BRANCH_NAME" -e GIT_CHANGE_ID="$CHANGE_ID" plone/volto-addon-ci stylelint''' + sh '''docker run -i --rm --name="$BUILD_TAG-stylelint" -e NAMESPACE="$NAMESPACE" -e GIT_NAME=$GIT_NAME -e GIT_BRANCH="$BRANCH_NAME" -e GIT_CHANGE_ID="$CHANGE_ID" -e VOLTO=$VOLTO plone/volto-addon-ci:alpha stylelint''' } }, "Prettier": { node(label: 'docker') { - sh '''docker run -i --rm --name="$BUILD_TAG-prettier" -e NAMESPACE="$NAMESPACE" -e GIT_NAME=$GIT_NAME -e GIT_BRANCH="$BRANCH_NAME" -e GIT_CHANGE_ID="$CHANGE_ID" plone/volto-addon-ci prettier''' + sh '''docker run -i --rm --name="$BUILD_TAG-prettier" -e NAMESPACE="$NAMESPACE" -e GIT_NAME=$GIT_NAME -e GIT_BRANCH="$BRANCH_NAME" -e GIT_CHANGE_ID="$CHANGE_ID" -e VOLTO=$VOLTO plone/volto-addon-ci:alpha prettier''' } } ) @@ -77,8 +77,8 @@ pipeline { node(label: 'docker') { script { try { - sh '''docker pull plone/volto-addon-ci''' - sh '''docker run -i --name="$BUILD_TAG-volto" -e NAMESPACE="$NAMESPACE" -e GIT_NAME=$GIT_NAME -e GIT_BRANCH="$BRANCH_NAME" -e GIT_CHANGE_ID="$CHANGE_ID" plone/volto-addon-ci''' + sh '''docker pull plone/volto-addon-ci:alpha''' + sh '''docker run -i --name="$BUILD_TAG-volto" -e NAMESPACE="$NAMESPACE" -e GIT_NAME=$GIT_NAME -e GIT_BRANCH="$BRANCH_NAME" -e GIT_CHANGE_ID="$CHANGE_ID" -e VOLTO=$VOLTO plone/volto-addon-ci:alpha''' sh '''rm -rf xunit-reports''' sh '''mkdir -p xunit-reports''' sh '''docker cp $BUILD_TAG-volto:/opt/frontend/my-volto-project/coverage xunit-reports/''' @@ -126,7 +126,7 @@ pipeline { script { try { sh '''docker pull eeacms/plone-backend; docker run --rm -d --name="$BUILD_TAG-plone" -e SITE="Plone" -e PROFILES="eea.kitkat:testing" eeacms/plone-backend''' - sh '''docker pull plone/volto-addon-ci; docker run -i --name="$BUILD_TAG-cypress" --link $BUILD_TAG-plone:plone -e NAMESPACE="$NAMESPACE" -e GIT_NAME=$GIT_NAME -e GIT_BRANCH="$BRANCH_NAME" -e GIT_CHANGE_ID="$CHANGE_ID" -e DEPENDENCIES="$DEPENDENCIES" -e NODE_ENV=development -e VOLTO="$VOLTO" plone/volto-addon-ci cypress''' + sh '''docker pull plone/volto-addon-ci:alpha; docker run -i --name="$BUILD_TAG-cypress" --link $BUILD_TAG-plone:plone -e NAMESPACE="$NAMESPACE" -e GIT_NAME=$GIT_NAME -e GIT_BRANCH="$BRANCH_NAME" -e GIT_CHANGE_ID="$CHANGE_ID" -e DEPENDENCIES="$DEPENDENCIES" -e NODE_ENV=development -e VOLTO=$VOLTO plone/volto-addon-ci:alpha cypress''' } finally { try { sh '''rm -rf cypress-reports cypress-results cypress-coverage''' diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..b873d77 --- /dev/null +++ b/Makefile @@ -0,0 +1,98 @@ +SHELL=/bin/bash + +DIR=$(shell basename $$(pwd)) +ADDON ?= "@eeacms/volto-addon-template" + +# We like colors +# From: https://coderwall.com/p/izxssa/colored-makefile-for-golang-projects +RED=`tput setaf 1` +GREEN=`tput setaf 2` +RESET=`tput sgr0` +YELLOW=`tput setaf 3` + +project: + npm install -g yo + npm install -g @plone/generator-volto + npm install -g mrs-developer + yo @plone/volto project --addon ${ADDON} --workspace "src/addons/${DIR}" --no-interactive + ln -sf $$(pwd) project/src/addons/ + cp .project.eslintrc.js .eslintrc.js + cd project && yarn + @echo "-------------------" + @echo "$(GREEN)Volto project is ready!$(RESET)" + @echo "$(RED)Now run: cd project && yarn start$(RESET)" + +all: project + +.PHONY: start-test-backend +start-test-backend: ## Start Test Plone Backend + @echo "$(GREEN)==> Start Test Plone Backend$(RESET)" + docker run -i --rm -e ZSERVER_HOST=0.0.0.0 -e ZSERVER_PORT=55001 -p 55001:55001 -e SITE=plone -e APPLY_PROFILES=plone.app.contenttypes:plone-content,plone.restapi:default,kitconcept.volto:default-homepage -e CONFIGURE_PACKAGES=plone.app.contenttypes,plone.restapi,kitconcept.volto,kitconcept.volto.cors -e ADDONS='plone.app.robotframework plone.app.contenttypes plone.restapi kitconcept.volto' plone ./bin/robot-server plone.app.robotframework.testing.PLONE_ROBOT_TESTING + +.PHONY: start-backend-docker +start-backend-docker: ## Starts a Docker-based backend + @echo "$(GREEN)==> Start Docker-based Plone Backend$(RESET)" + docker run -it --rm --name=plone -p 8080:8080 -e SITE=Plone -e ADDONS="kitconcept.volto" -e ZCML="kitconcept.volto.cors" plone + +.PHONY: test +test: + docker pull plone/volto-addon-ci:alpha + docker run -it --rm -e NAMESPACE="@eeacms" -e GIT_NAME="${DIR}" -e RAZZLE_JEST_CONFIG=jest-addon.config.js -v "$$(pwd):/opt/frontend/my-volto-project/src/addons/${DIR}" -e CI="true" plone/volto-addon-ci:alpha + +.PHONY: test-update +test-update: + docker pull plone/volto-addon-ci:alpha + docker run -it --rm -e NAMESPACE="@eeacms" -e GIT_NAME="${DIR}" -e RAZZLE_JEST_CONFIG=jest-addon.config.js -v "$$(pwd):/opt/frontend/my-volto-project/src/addons/${DIR}" -e CI="true" plone/volto-addon-ci:alpha yarn test src/addons/${DIR}/src --watchAll=false -u + +.PHONY: help +help: ## Show this help. + @echo -e "$$(grep -hE '^\S+:.*##' $(MAKEFILE_LIST) | sed -e 's/:.*##\s*/:/' -e 's/^\(.\+\):\(.*\)/\\x1b[36m\1\\x1b[m:\2/' | column -c2 -t -s :)" + + +ifeq ($(wildcard ./project),) + NODE_MODULES = "../../../node_modules" +else + NODE_MODULES = "./project/node_modules" +endif + +.PHONY: stylelint +stylelint: + $(NODE_MODULES)/stylelint/bin/stylelint.js --allow-empty-input 'src/**/*.{css,less}' + +.PHONY: stylelint-overrides +stylelint-overrides: + $(NODE_MODULES)/.bin/stylelint --syntax less --allow-empty-input 'theme/**/*.overrides' 'src/**/*.overrides' + +.PHONY: stylelint-fix +stylelint-fix: + $(NODE_MODULES)/stylelint/bin/stylelint.js --allow-empty-input 'src/**/*.{css,less}' --fix + $(NODE_MODULES)/.bin/stylelint --syntax less --allow-empty-input 'theme/**/*.overrides' 'src/**/*.overrides' --fix + +.PHONY: prettier +prettier: + $(NODE_MODULES)/.bin/prettier --single-quote --check 'src/**/*.{js,jsx,json,css,less,md}' + +.PHONY: prettier-fix +prettier-fix: + $(NODE_MODULES)/.bin/prettier --single-quote --write 'src/**/*.{js,jsx,json,css,less,md}' + +.PHONY: lint +lint: + $(NODE_MODULES)/eslint/bin/eslint.js --max-warnings=0 'src/**/*.{js,jsx}' + +.PHONY: lint-fix +lint-fix: + $(NODE_MODULES)/eslint/bin/eslint.js --fix 'src/**/*.{js,jsx}' + +.PHONY: i18n +i18n: + rm -rf build/messages + NODE_ENV=development $(NODE_MODULES)/.bin/i18n --addon + +.PHONY: cypress-run +cypress-run: + NODE_ENV=development $(NODE_MODULES)/cypress/bin/cypress run + +.PHONY: cypress-open +cypress-open: + NODE_ENV=development $(NODE_MODULES)/cypress/bin/cypress open diff --git a/README.md b/README.md index 5a2b41a..b060756 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,6 @@ [![Bugs](https://sonarqube.eea.europa.eu/api/project_badges/measure?project=volto-widget-toggle-develop&metric=bugs)](https://sonarqube.eea.europa.eu/dashboard?id=volto-widget-toggle-develop) [![Duplicated Lines (%)](https://sonarqube.eea.europa.eu/api/project_badges/measure?project=volto-widget-toggle-develop&metric=duplicated_lines_density)](https://sonarqube.eea.europa.eu/dashboard?id=volto-widget-toggle-develop) - [Volto](https://github.com/plone/volto) add-on: Replace any checkbox with a nice toggle button within edit forms ## Features @@ -58,78 +57,7 @@ ## Release -### Automatic release using Jenkins - -* The automatic release is started by creating a [Pull Request](../../compare/master...develop) from `develop` to `master`. The pull request status checks correlated to the branch and PR Jenkins jobs need to be processed successfully. 1 review from a github user with rights is mandatory. -* It runs on every commit on `master` branch, which is protected from direct commits, only allowing pull request merge commits. -* The automatic release is done by [Jenkins](https://ci.eionet.europa.eu). The status of the release job can be seen both in the Readme.md badges and the green check/red cross/yellow circle near the last commit information. If you click on the icon, you will have the list of checks that were run. The `continuous-integration/jenkins/branch` link goes to the Jenkins job execution webpage. -* Automated release scripts are located in the `eeacms/gitflow` docker image, specifically [js-release.sh](https://github.com/eea/eea.docker.gitflow/blob/master/src/js-release.sh) script. It uses the `release-it` tool. -* As long as a PR request is open from develop to master, the PR Jenkins job will automatically re-create the CHANGELOG.md and package.json files to be production-ready. -* The version format must be MAJOR.MINOR.PATCH. By default, next release is set to next minor version (with patch 0). -* You can manually change the version in `package.json`. The new version must not be already present in the tags/releases of the repository, otherwise it will be automatically increased by the script. Any changes to the version will trigger a `CHANGELOG.md` re-generation. -* Automated commits and commits with [JENKINS] or [YARN] in the commit log are excluded from `CHANGELOG.md` file. - -### Manual release from the develop branch ( beta release ) - -#### Installation and configuration of release-it - -You need to first install the [release-it](https://github.com/release-it/release-it) client. - - ``` - npm install -g release-it - ``` - -Release-it uses the configuration written in the [`.release-it.json`](./.release-it.json) file located in the root of the repository. - -Release-it is a tool that automates 4 important steps in the release process: - -1. Version increase in `package.json` ( increased from the current version in `package.json`) -2. `CHANGELOG.md` automatic generation from commit messages ( grouped by releases ) -3. GitHub release on the commit with the changelog and package.json modification on the develop branch -4. NPM release ( by default it's disabled, but can be enabled in the configuration file ) - -To configure the authentification, you need to export GITHUB_TOKEN for [GitHub](https://github.com/settings/tokens) - - ``` - export GITHUB_TOKEN=XXX-XXXXXXXXXXXXXXXXXXXXXX - ``` - - To configure npm, you can use the `npm login` command or use a configuration file with a TOKEN : - - ``` - echo "//registry.npmjs.org/:_authToken=YYYYYYYYYYYYYYYYYYYYYYYYYYYYYY" > .npmrc - ``` - -#### Using release-it tool - -There are 3 yarn scripts that can be run to do the release - -##### yarn release-beta - -Automatically calculates and presents 3 beta versions - patch, minor and major for you to choose ( or Other for manual input). - -``` -? Select increment (next version): -❯ prepatch (0.1.1-beta.0) - preminor (0.2.0-beta.0) - premajor (1.0.0-beta.0) - Other, please specify... -``` - -##### yarn release-major-beta - -Same as `yarn release-beta`, but with premajor version pre-selected. - -##### yarn release - -Generic command, does not automatically add the `beta` to version, but you can still manually write it if you choose Other. - -#### Important notes - -> Do not use release-it tool on master branch, the commit on CHANGELOG.md file and the version increase in the package.json file can't be done without a PULL REQUEST. - -> Do not keep Pull Requests from develop to master branches open when you are doing beta releases from the develop branch. As long as a PR to master is open, an automatic script will run on every commit and will update both the version and the changelog to a production-ready state - ( MAJOR.MINOR.PATCH mandatory format for version). - +See [RELEASE.md](https://github.com/eea/volto-addon-template/blob/master/RELEASE.md). ## How to contribute diff --git a/RELEASE.md b/RELEASE.md new file mode 100644 index 0000000..24f98ee --- /dev/null +++ b/RELEASE.md @@ -0,0 +1,74 @@ +## Release + +### Automatic release using Jenkins + +* The automatic release is started by creating a [Pull Request](../../compare/master...develop) from `develop` to `master`. The pull request status checks correlated to the branch and PR Jenkins jobs need to be processed successfully. 1 review from a github user with rights is mandatory. +* It runs on every commit on `master` branch, which is protected from direct commits, only allowing pull request merge commits. +* The automatic release is done by [Jenkins](https://ci.eionet.europa.eu). The status of the release job can be seen both in the Readme.md badges and the green check/red cross/yellow circle near the last commit information. If you click on the icon, you will have the list of checks that were run. The `continuous-integration/jenkins/branch` link goes to the Jenkins job execution webpage. +* Automated release scripts are located in the `eeacms/gitflow` docker image, specifically [js-release.sh](https://github.com/eea/eea.docker.gitflow/blob/master/src/js-release.sh) script. It uses the `release-it` tool. +* As long as a PR request is open from develop to master, the PR Jenkins job will automatically re-create the CHANGELOG.md and package.json files to be production-ready. +* The version format must be MAJOR.MINOR.PATCH. By default, next release is set to next minor version (with patch 0). +* You can manually change the version in `package.json`. The new version must not be already present in the tags/releases of the repository, otherwise it will be automatically increased by the script. Any changes to the version will trigger a `CHANGELOG.md` re-generation. +* Automated commits and commits with [JENKINS] or [YARN] in the commit log are excluded from `CHANGELOG.md` file. + +### Manual release from the develop branch ( beta release ) + +#### Installation and configuration of release-it + +You need to first install the [release-it](https://github.com/release-it/release-it) client. + + ``` + npm install -g release-it + ``` + +Release-it uses the configuration written in the [`.release-it.json`](./.release-it.json) file located in the root of the repository. + +Release-it is a tool that automates 4 important steps in the release process: + +1. Version increase in `package.json` ( increased from the current version in `package.json`) +2. `CHANGELOG.md` automatic generation from commit messages ( grouped by releases ) +3. GitHub release on the commit with the changelog and package.json modification on the develop branch +4. NPM release ( by default it's disabled, but can be enabled in the configuration file ) + +To configure the authentification, you need to export GITHUB_TOKEN for [GitHub](https://github.com/settings/tokens) + + ``` + export GITHUB_TOKEN=XXX-XXXXXXXXXXXXXXXXXXXXXX + ``` + + To configure npm, you can use the `npm login` command or use a configuration file with a TOKEN : + + ``` + echo "//registry.npmjs.org/:_authToken=YYYYYYYYYYYYYYYYYYYYYYYYYYYYYY" > .npmrc + ``` + +#### Using release-it tool + +There are 3 yarn scripts that can be run to do the release + +##### yarn release-beta + +Automatically calculates and presents 3 beta versions - patch, minor and major for you to choose ( or Other for manual input). + +``` +? Select increment (next version): +❯ prepatch (0.1.1-beta.0) + preminor (0.2.0-beta.0) + premajor (1.0.0-beta.0) + Other, please specify... +``` + +##### yarn release-major-beta + +Same as `yarn release-beta`, but with premajor version pre-selected. + +##### yarn release + +Generic command, does not automatically add the `beta` to version, but you can still manually write it if you choose Other. + +#### Important notes + +> Do not use release-it tool on master branch, the commit on CHANGELOG.md file and the version increase in the package.json file can't be done without a PULL REQUEST. + +> Do not keep Pull Requests from develop to master branches open when you are doing beta releases from the develop branch. As long as a PR to master is open, an automatic script will run on every commit and will update both the version and the changelog to a production-ready state - ( MAJOR.MINOR.PATCH mandatory format for version). + diff --git a/babel.config.js b/babel.config.js new file mode 100644 index 0000000..51bd52b --- /dev/null +++ b/babel.config.js @@ -0,0 +1,17 @@ +module.exports = function (api) { + api.cache(true); + const presets = ['razzle']; + const plugins = [ + [ + 'react-intl', // React Intl extractor, required for the whole i18n infrastructure to work + { + messagesDir: './build/messages/', + }, + ], + ]; + + return { + plugins, + presets, + }; +}; diff --git a/cypress.config.js b/cypress.config.js new file mode 100644 index 0000000..30be8ac --- /dev/null +++ b/cypress.config.js @@ -0,0 +1,26 @@ +const { defineConfig } = require('cypress'); + +module.exports = defineConfig({ + viewportWidth: 1280, + defaultCommandTimeout: 8888, + chromeWebSecurity: false, + reporter: 'junit', + video: true, + retries: { + runMode: 8, + openMode: 0, + }, + reporterOptions: { + mochaFile: 'cypress/reports/cypress-[hash].xml', + jenkinsMode: true, + toConsole: true, + }, + e2e: { + setupNodeEvents(on, config) { + // e2e testing node events setup code + require('@cypress/code-coverage/task')(on, config); + return config; + }, + baseUrl: 'http://localhost:3000', + }, +}); diff --git a/cypress.json b/cypress.json deleted file mode 100644 index 736dedd..0000000 --- a/cypress.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "baseUrl": "http://localhost:3000", - "viewportWidth": 1280, - "defaultCommandTimeout": 8888, - "chromeWebSecurity": false, - "reporter": "junit", - "video": true, - "retries": { - "runMode": 8, - "openMode": 0 - }, - "reporterOptions": { - "mochaFile": "cypress/reports/cypress-[hash].xml", - "jenkinsMode": true, - "toConsole": true - } -} diff --git a/cypress/integration/block-basics.js b/cypress/e2e/01-block-basics.cy.js similarity index 79% rename from cypress/integration/block-basics.js rename to cypress/e2e/01-block-basics.cy.js index 4daed6d..81e421c 100644 --- a/cypress/integration/block-basics.js +++ b/cypress/e2e/01-block-basics.cy.js @@ -1,13 +1,10 @@ -import { setupBeforeEach, tearDownAfterEach } from '../support'; +import { slateBeforeEach, slateAfterEach } from '../support/e2e'; describe('Blocks Tests', () => { - beforeEach(setupBeforeEach); - afterEach(tearDownAfterEach); + beforeEach(slateBeforeEach); + afterEach(slateAfterEach); it('Add Block: Empty', () => { - // without this the clear command below does nothing sometimes - cy.wait(500); - // Change page title cy.get('[contenteditable=true]').first().clear(); diff --git a/cypress/plugins/index.js b/cypress/plugins/index.js deleted file mode 100644 index 27a31a5..0000000 --- a/cypress/plugins/index.js +++ /dev/null @@ -1,26 +0,0 @@ -/// -// *********************************************************** -// This example plugins/index.js can be used to load plugins -// -// You can change the location of this file or turn off loading -// the plugins file with the 'pluginsFile' configuration option. -// -// You can read more here: -// https://on.cypress.io/plugins-guide -// *********************************************************** - -// This function is called when a project is opened or re-opened (e.g. due to -// the project's config changing) - -/** - * @type {Cypress.PluginConfig} - */ -module.exports = (on, config) => { - // `on` is used to hook into various events Cypress emits - // `config` is the resolved Cypress config - /* coverage-start - require('@cypress/code-coverage/task')(on, config) - on('file:preprocessor', require('@cypress/code-coverage/use-babelrc')) - return config - coverage-end */ -}; diff --git a/cypress/support/commands.js b/cypress/support/commands.js index ac48461..0a63558 100644 --- a/cypress/support/commands.js +++ b/cypress/support/commands.js @@ -92,7 +92,7 @@ Cypress.Commands.add( title: contentTitle, blocks: { 'd3f1c443-583f-4e8e-a682-3bf25752a300': { '@type': 'title' }, - '7624cf59-05d0-4055-8f55-5fd6597d84b0': { '@type': 'text' }, + '7624cf59-05d0-4055-8f55-5fd6597d84b0': { '@type': 'slate' }, }, blocks_layout: { items: [ @@ -125,6 +125,100 @@ Cypress.Commands.add( }, ); +// --- Add DX Content-Type ---------------------------------------------------------- +Cypress.Commands.add('addContentType', (name) => { + let api_url, auth; + api_url = Cypress.env('API_PATH') || 'http://localhost:8080/Plone'; + auth = { + user: 'admin', + pass: 'admin', + }; + return cy + .request({ + method: 'POST', + url: `${api_url}/@controlpanels/dexterity-types/${name}`, + headers: { + Accept: 'application/json', + }, + auth: auth, + body: { + title: name, + }, + }) + .then(() => console.log(`${name} content-type added.`)); +}); + +// --- Remove DX behavior ---------------------------------------------------------- +Cypress.Commands.add('removeContentType', (name) => { + let api_url, auth; + api_url = Cypress.env('API_PATH') || 'http://localhost:8080/Plone'; + auth = { + user: 'admin', + pass: 'admin', + }; + return cy + .request({ + method: 'DELETE', + url: `${api_url}/@controlpanels/dexterity-types/${name}`, + headers: { + Accept: 'application/json', + }, + auth: auth, + body: {}, + }) + .then(() => console.log(`${name} content-type removed.`)); +}); + +// --- Add DX field ---------------------------------------------------------- +Cypress.Commands.add('addSlateJSONField', (type, name) => { + let api_url, auth; + api_url = Cypress.env('API_PATH') || 'http://localhost:8080/Plone'; + auth = { + user: 'admin', + pass: 'admin', + }; + return cy + .request({ + method: 'POST', + url: `${api_url}/@types/${type}`, + headers: { + Accept: 'application/json', + }, + auth: auth, + body: { + id: name, + title: name, + description: 'Slate JSON Field', + factory: 'SlateJSONField', + required: false, + }, + }) + .then(() => console.log(`${name} SlateJSONField field added to ${type}`)); +}); + +// --- Remove DX field ---------------------------------------------------------- +Cypress.Commands.add('removeSlateJSONField', (type, name) => { + let api_url, auth; + api_url = Cypress.env('API_PATH') || 'http://localhost:8080/Plone'; + auth = { + user: 'admin', + pass: 'admin', + }; + return cy + .request({ + method: 'DELETE', + url: `${api_url}/@types/${type}/${name}`, + headers: { + Accept: 'application/json', + }, + auth: auth, + body: {}, + }) + .then(() => + console.log(`${name} SlateJSONField field removed from ${type}`), + ); +}); + // --- REMOVE CONTENT -------------------------------------------------------- Cypress.Commands.add('removeContent', (path) => { let api_url, auth; @@ -146,6 +240,41 @@ Cypress.Commands.add('removeContent', (path) => { .then(() => console.log(`${path} removed`)); }); +Cypress.Commands.add('typeInSlate', { prevSubject: true }, (subject, text) => { + return ( + cy + .wrap(subject) + .then((subject) => { + subject[0].dispatchEvent( + new InputEvent('beforeinput', { + inputType: 'insertText', + data: text, + }), + ); + return subject; + }) + // TODO: do this only for Electron-based browser which does not understand instantaneously + // that the user inserted some text in the block + .wait(1000) + ); +}); + +Cypress.Commands.add('lineBreakInSlate', { prevSubject: true }, (subject) => { + return ( + cy + .wrap(subject) + .then((subject) => { + subject[0].dispatchEvent( + new InputEvent('beforeinput', { inputType: 'insertLineBreak' }), + ); + return subject; + }) + // TODO: do this only for Electron-based browser which does not understand instantaneously + // that the block was split + .wait(1000) + ); +}); + // --- SET WORKFLOW ---------------------------------------------------------- Cypress.Commands.add( 'setWorkflow', @@ -247,6 +376,47 @@ Cypress.Commands.add( }, ); +Cypress.Commands.add('getSlateEditorAndType', (type) => { + cy.get('.content-area .slate-editor [contenteditable=true]') + .focus() + .click() + .wait(1000) + .type(type); +}); + +Cypress.Commands.add('setSlateSelection', (subject, query, endQuery) => { + cy.get('.slate-editor.selected [contenteditable=true]') + .focus() + .click() + .setSelection(subject, query, endQuery) + .wait(1000); +}); + +Cypress.Commands.add('setSlateCursor', (subject, query, endQuery) => { + cy.get('.slate-editor.selected [contenteditable=true]') + .focus() + .click() + .setCursor(subject, query, endQuery) + .wait(1000); +}); + +Cypress.Commands.add('clickSlateButton', (button) => { + cy.get(`.slate-inline-toolbar .button-wrapper a[title="${button}"]`).click(); +}); + +Cypress.Commands.add('toolbarSave', () => { + cy.wait(1000); + + // Save + cy.get('#toolbar-save').click(); + cy.waitForResourceToLoad('@navigation'); + cy.waitForResourceToLoad('@breadcrumbs'); + cy.waitForResourceToLoad('@actions'); + cy.waitForResourceToLoad('@types'); + cy.waitForResourceToLoad('my-page'); + cy.url().should('eq', Cypress.config().baseUrl + '/cypress/my-page'); +}); + // Low level command reused by `setCursorBefore` and `setCursorAfter`, equal to `setCursorAfter` Cypress.Commands.add( 'setCursor', diff --git a/cypress/support/e2e.js b/cypress/support/e2e.js new file mode 100644 index 0000000..f696418 --- /dev/null +++ b/cypress/support/e2e.js @@ -0,0 +1,125 @@ +// *********************************************************** +// This example support/index.js 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') + +//Generate code-coverage +import '@cypress/code-coverage/support'; + +export const slateBeforeEach = (contentType = 'Document') => { + cy.autologin(); + cy.createContent({ + contentType: 'Document', + contentId: 'cypress', + contentTitle: 'Cypress', + }); + cy.createContent({ + contentType: contentType, + contentId: 'my-page', + contentTitle: 'My Page', + path: 'cypress', + }); + cy.visit('/cypress/my-page'); + cy.waitForResourceToLoad('@navigation'); + cy.waitForResourceToLoad('@breadcrumbs'); + cy.waitForResourceToLoad('@actions'); + cy.waitForResourceToLoad('@types'); + cy.waitForResourceToLoad('my-page'); + cy.navigate('/cypress/my-page/edit'); +}; + +export const slateAfterEach = () => { + cy.autologin(); + cy.removeContent('cypress'); +}; + +export const slateJsonBeforeEach = (contentType = 'slate') => { + cy.autologin(); + cy.addContentType(contentType); + cy.addSlateJSONField(contentType, 'slate'); + slateBeforeEach(contentType); +}; + +export const slateJsonAfterEach = (contentType = 'slate') => { + cy.autologin(); + cy.removeContentType(contentType); + slateAfterEach(); +}; + +export const getSelectedSlateEditor = () => { + return cy.get('.slate-editor.selected [contenteditable=true]').click(); +}; + +export const createSlateBlock = () => { + cy.get('.ui.basic.icon.button.block-add-button').first().click(); + cy.get('.blocks-chooser .title').contains('Text').click(); + cy.get('.ui.basic.icon.button.slate').contains('Text').click(); + return getSelectedSlateEditor(); +}; + +export const getSlateBlockValue = (sb) => { + return sb.invoke('attr', 'data-slate-value').then((str) => { + return typeof str === 'undefined' ? [] : JSON.parse(str); + }); +}; + +export const createSlateBlockWithList = ({ + numbered, + firstItemText, + secondItemText, +}) => { + let s1 = createSlateBlock(); + + s1.typeInSlate(firstItemText + secondItemText); + + // select all contents of slate block + // - this opens hovering toolbar + cy.contains(firstItemText + secondItemText).then((el) => { + selectSlateNodeOfWord(el); + }); + + // TODO: do not hardcode these selectors: + if (numbered) { + // this is the numbered list option in the hovering toolbar + cy.get('.slate-inline-toolbar > :nth-child(9)').click(); + } else { + // this is the bulleted list option in the hovering toolbar + cy.get('.slate-inline-toolbar > :nth-child(10)').click(); + } + + // move the text cursor + const sse = getSelectedSlateEditor(); + sse.type('{leftarrow}'); + for (let i = 0; i < firstItemText.length; ++i) { + sse.type('{rightarrow}'); + } + + // simulate pressing Enter + getSelectedSlateEditor().lineBreakInSlate(); + + return s1; +}; + +export const selectSlateNodeOfWord = (el) => { + return cy.window().then((win) => { + var event = new CustomEvent('Test_SelectWord', { + detail: el[0], + }); + win.document.dispatchEvent(event); + }); +}; diff --git a/cypress/support/index.js b/cypress/support/index.js deleted file mode 100644 index 32395ab..0000000 --- a/cypress/support/index.js +++ /dev/null @@ -1,53 +0,0 @@ -// *********************************************************** -// This example support/index.js 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') - -/* coverage-start -//Generate code-coverage -import '@cypress/code-coverage/support'; -coverage-end */ - -export const setupBeforeEach = () => { - cy.autologin(); - cy.createContent({ - contentType: 'Document', - contentId: 'cypress', - contentTitle: 'Cypress', - }); - cy.createContent({ - contentType: 'Document', - contentId: 'my-page', - contentTitle: 'My Page', - path: 'cypress', - }); - cy.visit('/cypress/my-page'); - cy.waitForResourceToLoad('@navigation'); - cy.waitForResourceToLoad('@breadcrumbs'); - cy.waitForResourceToLoad('@actions'); - cy.waitForResourceToLoad('@types'); - cy.waitForResourceToLoad('my-page'); - cy.navigate('/cypress/my-page/edit'); - cy.get(`.block.title h1`); -}; - -export const tearDownAfterEach = () => { - cy.autologin(); - cy.removeContent('cypress'); -}; diff --git a/jest-addon.config.js b/jest-addon.config.js index 6135d92..da38318 100644 --- a/jest-addon.config.js +++ b/jest-addon.config.js @@ -9,6 +9,7 @@ module.exports = { '@plone/volto/babel': '/node_modules/@plone/volto/babel', '@plone/volto/(.*)$': '/node_modules/@plone/volto/src/$1', '@package/(.*)$': '/src/$1', + '@root/(.*)$': '/src/$1', '@plone/volto-quanta/(.*)$': '/src/addons/volto-quanta/src/$1', '@eeacms/(.*?)/(.*)$': '/src/addons/$1/src/$2', '@plone/volto-slate': @@ -16,12 +17,10 @@ module.exports = { '~/(.*)$': '/src/$1', 'load-volto-addons': '/node_modules/@plone/volto/jest-addons-loader.js', + '\\.(css|less|scss|sass)$': 'identity-obj-proxy', }, transform: { '^.+\\.js(x)?$': 'babel-jest', - '^.+\\.css$': 'jest-css-modules', - '^.+\\.less$': 'jest-css-modules', - '^.+\\.scss$': 'jest-css-modules', '^.+\\.(png)$': 'jest-file', '^.+\\.(jpg)$': 'jest-file', '^.+\\.(svg)$': './node_modules/@plone/volto/jest-svgsystem-transform.js', diff --git a/locales/volto.pot b/locales/volto.pot new file mode 100644 index 0000000..e69de29 diff --git a/package.json b/package.json index 0f09b69..917cf0c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@eeacms/volto-widget-toggle", - "version": "2.2.7", + "version": "3.0.0", "description": "volto-widget-toggle: Volto add-on to replace checkboxes with toggle buttons", "main": "src/index.js", "author": "European Environment Agency: IDM2 A-Team", @@ -20,7 +20,8 @@ }, "dependencies": {}, "devDependencies": { - "@cypress/code-coverage": "^3.9.5", + "@plone/scripts": "*", + "@cypress/code-coverage": "^3.10.0", "babel-plugin-transform-class-properties": "^6.24.1", "md5": "^2.3.0" },