diff --git a/.gitignore b/.gitignore
index 3cf7009..53b9801 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,19 +1,25 @@
.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
-coverage
+screenshots
+videos
.env.local
.env.development.local
.env.test.local
diff --git a/Jenkinsfile b/Jenkinsfile
index 1f7304c..405b31d 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 VOLTO="$VOLTO" -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 VOLTO="$VOLTO" -e NAMESPACE="$NAMESPACE" -e GIT_NAME=$GIT_NAME -e GIT_BRANCH="$BRANCH_NAME" -e GIT_CHANGE_ID="$CHANGE_ID" plone/volto-addon-ci:alpha eslint'''
}
},
"Style lint": {
node(label: 'docker') {
- sh '''docker run -i --rm --name="$BUILD_TAG-stylelint" -e VOLTO="$VOLTO" -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 VOLTO="$VOLTO" -e NAMESPACE="$NAMESPACE" -e GIT_NAME=$GIT_NAME -e GIT_BRANCH="$BRANCH_NAME" -e GIT_CHANGE_ID="$CHANGE_ID" plone/volto-addon-ci:alpha stylelint'''
}
},
"Prettier": {
node(label: 'docker') {
- sh '''docker run -i --rm --name="$BUILD_TAG-prettier" -e VOLTO="$VOLTO" -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 VOLTO="$VOLTO" -e NAMESPACE="$NAMESPACE" -e GIT_NAME=$GIT_NAME -e GIT_BRANCH="$BRANCH_NAME" -e GIT_CHANGE_ID="$CHANGE_ID" 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" 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 VOLTO="$VOLTO" -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 VOLTO="$VOLTO" -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/babel.config.js b/babel.config.js
new file mode 100644
index 0000000..2f4e1e8
--- /dev/null
+++ b/babel.config.js
@@ -0,0 +1,17 @@
+module.exports = function (api) {
+ api.cache(true);
+ const presets = ['razzle/babel'];
+ const plugins = [
+ [
+ 'react-intl', // React Intl extractor, required for the whole i18n infrastructure to work
+ {
+ messagesDir: './build/messages/',
+ },
+ ],
+ ];
+
+ return {
+ plugins,
+ presets,
+ };
+};
diff --git a/bootstrap b/bootstrap
index 8613750..743c3b9 100644
--- a/bootstrap
+++ b/bootstrap
@@ -5,37 +5,37 @@ const ejs = require('ejs');
const currentDir = path.basename(process.cwd());
const bootstrap = function (ofile) {
- fs.readFile(ofile, 'utf8', function (err, data) {
+ fs.readFile(ofile, 'utf8', function (err, data) {
+ if (err) {
+ return console.log(err);
+ }
+ const result = ejs.render(data, {
+ addonName: `@eeacms/${currentDir}`,
+ name: currentDir,
+ });
+ const output = ofile.replace('.tpl', '');
+ fs.writeFile(output, result, 'utf8', function (err) {
+ if (err) {
+ return console.log(err);
+ }
+ });
+ if (ofile.includes('.tpl')) {
+ fs.unlink(ofile, (err) => {
if (err) {
- return console.log(err);
- }
- const result = ejs.render(data, {
- addonName: `@eeacms/${currentDir}`,
- name: currentDir
- });
- const output = ofile.replace('.tpl', '');
- fs.writeFile(output, result, 'utf8', function (err) {
- if (err) {
- return console.log(err);
- }
- });
- if (ofile.includes('.tpl')) {
- fs.unlink(ofile, (err) => {
- if (err) {
- return console.error(err);
- }
- });
+ return console.error(err);
}
- });
-}
+ });
+ }
+ });
+};
-fs.readdir(".", { withFileTypes: true }, (err, dirents) => {
- const files = dirents
- .filter(dirent => dirent.isFile())
- .map(dirent => dirent.name);
- files.forEach(function (file) {
- if (file != 'bootstrap') {
- bootstrap(file);
- }
- });
+fs.readdir('.', { withFileTypes: true }, (err, dirents) => {
+ const files = dirents
+ .filter((dirent) => dirent.isFile())
+ .map((dirent) => dirent.name);
+ files.forEach(function (file) {
+ if (file != 'bootstrap') {
+ bootstrap(file);
+ }
+ });
});
diff --git a/cypress.config.js b/cypress.config.js
index 99117dc..30be8ac 100644
--- a/cypress.config.js
+++ b/cypress.config.js
@@ -17,7 +17,9 @@ module.exports = defineConfig({
},
e2e: {
setupNodeEvents(on, config) {
- return require('./cypress/plugins/index.js')(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/e2e/01-block-basics.cy.js b/cypress/e2e/01-block-basics.cy.js
index 568aadc..81e421c 100644
--- a/cypress/e2e/01-block-basics.cy.js
+++ b/cypress/e2e/01-block-basics.cy.js
@@ -1,13 +1,10 @@
-import { setupBeforeEach, tearDownAfterEach } from '../support/e2e';
+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
index 32395ab..f696418 100644
--- a/cypress/support/e2e.js
+++ b/cypress/support/e2e.js
@@ -15,16 +15,13 @@
// 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 = () => {
+export const slateBeforeEach = (contentType = 'Document') => {
cy.autologin();
cy.createContent({
contentType: 'Document',
@@ -32,7 +29,7 @@ export const setupBeforeEach = () => {
contentTitle: 'Cypress',
});
cy.createContent({
- contentType: 'Document',
+ contentType: contentType,
contentId: 'my-page',
contentTitle: 'My Page',
path: 'cypress',
@@ -44,10 +41,85 @@ export const setupBeforeEach = () => {
cy.waitForResourceToLoad('@types');
cy.waitForResourceToLoad('my-page');
cy.navigate('/cypress/my-page/edit');
- cy.get(`.block.title h1`);
};
-export const tearDownAfterEach = () => {
+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/jest-addon.config.js b/jest-addon.config.js
index b7ec257..6135d92 100644
--- a/jest-addon.config.js
+++ b/jest-addon.config.js
@@ -9,7 +9,6 @@ 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':
@@ -17,7 +16,6 @@ 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',
diff --git a/locales/volto.pot b/locales/volto.pot
new file mode 100644
index 0000000..e69de29