diff --git a/CHANGELOG.md b/CHANGELOG.md index 61eb0c5..db5efe3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,16 @@ All notable changes to this project will be documented in this file. Dates are d Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). +### [6.3.2](https://github.com/eea/volto-columns-block/compare/6.3.1...6.3.2) - 24 July 2023 + +#### :nail_care: Enhancements + +- refactor: Fix more issues identified by Sonarqube Refs #254220 [dana-cfc4 - [`bc34507`](https://github.com/eea/volto-columns-block/commit/bc34507ef3722f64b0e170fd47d2e98cf76fab06)] +- refactor: Fix issues identified by Sonarqube Refs #254220 [dana-cfc4 - [`cb9a81f`](https://github.com/eea/volto-columns-block/commit/cb9a81fd0a794f9c26afe0c3d09dfe2b8fd9f896)] + +#### :hammer_and_wrench: Others + +- test: add unit tests for utils and e2e test for columns - refs #254313 [ana-oprea - [`92348b0`](https://github.com/eea/volto-columns-block/commit/92348b04d5053235be7b7366f1fa305af6918f28)] ### [6.3.1](https://github.com/eea/volto-columns-block/compare/6.3.0...6.3.1) - 12 June 2023 #### :house: Internal changes diff --git a/Makefile b/Makefile index 08175a5..62ced47 100644 --- a/Makefile +++ b/Makefile @@ -86,6 +86,7 @@ i18n: ## i18n .PHONY: cypress-run cypress-run: ## Run cypress integration tests + rm -rf .nyc_output NODE_ENV=development $(NODE_MODULES)/cypress/bin/cypress run .PHONY: cypress-open diff --git a/cypress/e2e/01-block-columns.cy.js b/cypress/e2e/01-block-columns.cy.js index 813baef..bd12acb 100644 --- a/cypress/e2e/01-block-columns.cy.js +++ b/cypress/e2e/01-block-columns.cy.js @@ -24,16 +24,23 @@ describe('Blocks Tests', () => { cy.get('.field-wrapper-title #field-title').last().type('Column test'); cy.get('.field-wrapper-data .columns-area button').last().click(); - cy.get('.columns-area .drag.handle.wrapper') - .first() - .trigger('mousedown', { which: 1 }, { force: true }) - .trigger('mousemove', 0, 60, { force: true }) - .trigger('mouseup'); - cy.get('.field-wrapper-gridCols #field-gridCols').click(); cy.get('.react-select__menu').contains('25').click(); + cy.get('.columns-block .columns-header') + .click() + .trigger('keydown', { keyCode: 38, which: 38 }); + + cy.get('.columns-block .columns-header') + .click() + .trigger('keydown', { keyCode: 40, which: 40 }); + + cy.get('.columns-block .columns-header') + .click() + .trigger('keydown', { keyCode: 13, which: 13 }); + cy.get('[contenteditable=true]').first().focus().click(); + cy.get('.columns-block [contenteditable=true]') .eq(0) .focus() @@ -48,16 +55,69 @@ describe('Blocks Tests', () => { .eq(2) .focus() .click() - .type('Third'); + .type('/description{enter}Third'); + cy.get('.block-toolbar button').eq(1).click(); cy.get( '.field-wrapper-grid_vertical_align #field-grid_vertical_align', ).click(); cy.get('.react-select__menu').contains('Middle').click(); + + cy.get('.field-wrapper-backgroundColor .ui.huge.button').click(); + cy.get('.github-picker.color-picker span').eq(3).click(); + cy.get('.field-wrapper-backgroundColor .ui.compact.button').click(); cy.get('.field-wrapper-backgroundColor .ui.huge.button').click(); cy.get('.github-picker.color-picker span').eq(3).click(); + cy.get( + '.inline.field.field-wrapper-padding-slider .slider-widget-wrapper .slider-knob.single', + ).dblclick(); + cy.get( + '.inline.field.field-wrapper-padding-slider .slider-widget-wrapper input', + ).type('3{enter}'); + cy.get( + '.inline.field.field-wrapper-padding-slider .slider-widget-wrapper .slider-knob.single', + ).trigger('mousedown', { which: 1 }); + cy.get( + '.inline.field.field-wrapper-padding-slider .slider-widget-wrapper .semantic_ui_range_inner', + ) + .trigger('mousemove', { clientX: 500 }) + .trigger('mouseup'); + + cy.get( + '.inline.field.field-wrapper-padding-lockSize .wrapper .checkbox label[for="field-padding-lockSize"]', + ).click(); + + cy.get('.slider-widget-wrapper .slider-knob.single').dblclick(); + + cy.get('#field-padding-unit .react-select__control').click(); + cy.get('.react-select__menu-list').contains('percentage').click(); + + cy.get('#field-padding-unit .react-select__control').click(); + cy.get('.react-select__menu-list').contains('em').click(); + + cy.get('#field-padding-unit .react-select__control').click(); + cy.get('.react-select__menu-list').contains('rem').click(); + + cy.get('#field-padding-unit .react-select__control').click(); + cy.get('.react-select__menu-list').contains('No value').click(); + + cy.get('.columns-block [contenteditable=true]').eq(0).focus().click(); + cy.get('.block-toolbar button').eq(1).click(); + + cy.get( + '.field-wrapper-grid_vertical_align #field-grid_vertical_align', + ).click(); + cy.get('.react-select__menu').contains('Middle').click(); + + cy.get('.field-wrapper-backgroundColor .ui.huge.button').click(); + cy.get('.github-picker.color-picker span').eq(3).click(); + + cy.get('.sidebar-container #sidebar-properties .ui.segment button') + .eq(1) + .click(); + // Save cy.get('#toolbar-save').click(); cy.url().should('eq', Cypress.config().baseUrl + '/cypress/my-page'); diff --git a/package.json b/package.json index bd5d725..4cf6934 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@eeacms/volto-columns-block", - "version": "6.3.1", + "version": "6.3.2", "description": "volto-columns-block: Volto add-on", "main": "src/index.js", "author": "European Environment Agency: IDM2 A-Team", diff --git a/src/ColumnsBlock/ColumnsBlockEdit.jsx b/src/ColumnsBlock/ColumnsBlockEdit.jsx index 5f2d37c..53141c7 100644 --- a/src/ColumnsBlock/ColumnsBlockEdit.jsx +++ b/src/ColumnsBlock/ColumnsBlockEdit.jsx @@ -1,18 +1,21 @@ import React from 'react'; import { defineMessages, FormattedMessage, injectIntl } from 'react-intl'; import { compose } from 'redux'; -import { Grid, Segment } from 'semantic-ui-react'; +import { Grid, Segment, Button } from 'semantic-ui-react'; import { isEmpty, without } from 'lodash'; -import { SidebarPortal, BlocksToolbar, Icon } from '@plone/volto/components'; // BlocksForm, Icon, -import { BlockDataForm } from '@plone/volto/components'; +import { + SidebarPortal, + BlocksToolbar, + Icon, + BlockDataForm, + BlocksForm, +} from '@plone/volto/components'; // BlocksForm, Icon, import { emptyBlocksForm, getBlocksLayoutFieldname, } from '@plone/volto/helpers'; import { setSidebarTab } from '@plone/volto/actions'; import { connect } from 'react-redux'; -import { BlocksForm } from '@plone/volto/components'; -import { Button } from 'semantic-ui-react'; import config from '@plone/volto/registry'; import cx from 'classnames'; diff --git a/src/ColumnsBlock/ColumnsBlockView.jsx b/src/ColumnsBlock/ColumnsBlockView.jsx index 71d20b3..398f051 100644 --- a/src/ColumnsBlock/ColumnsBlockView.jsx +++ b/src/ColumnsBlock/ColumnsBlockView.jsx @@ -10,7 +10,8 @@ import { getColumns } from './utils'; import { getStyle } from '@eeacms/volto-columns-block/Styles'; const getSide = (side, v) => { - return `${v?.[side] ? `${v[side]}${v.unit ? v.unit : 'px'}` : '0'}`; + const v_unit = v.unit ? v.unit : 'px'; + return `${v?.[side] ? `${v[side]}${v_unit}` : '0'}`; }; const getSides = (v) => { diff --git a/src/ColumnsBlock/ColumnsBlockView.test.js b/src/ColumnsBlock/ColumnsBlockView.test.js index 367e500..06f0dd6 100644 --- a/src/ColumnsBlock/ColumnsBlockView.test.js +++ b/src/ColumnsBlock/ColumnsBlockView.test.js @@ -1,5 +1,4 @@ import React from 'react'; -// import renderer from 'react-test-renderer'; import configureStore from 'redux-mock-store'; import { Provider } from 'react-intl-redux'; import config from '@plone/volto/registry'; diff --git a/src/ColumnsBlock/EditBlockWrapper.jsx b/src/ColumnsBlock/EditBlockWrapper.jsx index 0c00dc7..213a686 100644 --- a/src/ColumnsBlock/EditBlockWrapper.jsx +++ b/src/ColumnsBlock/EditBlockWrapper.jsx @@ -36,7 +36,6 @@ class EditBlockWrapper extends React.Component { } componentDidMount() { - // console.log('mount editblockwrapper', this.props.blockProps.block); document.addEventListener('mousedown', this.handleClickOutside, false); } diff --git a/src/ColumnsBlock/utils.test.js b/src/ColumnsBlock/utils.test.js new file mode 100644 index 0000000..02c5d44 --- /dev/null +++ b/src/ColumnsBlock/utils.test.js @@ -0,0 +1,109 @@ +import config from '@plone/volto/registry'; + +import { + getColumns, + hasColumns, + forEachColumn, + columnIsEmpty, + empty, + defaultNewColumn, +} from './utils'; + +describe('getColumns', () => { + it('should return an array of column IDs and their corresponding data', () => { + const data = { + blocks_layout: { + items: ['1', '2'], + }, + blocks: { + '1': { name: 'First' }, + '2': { name: 'Second' }, + }, + }; + expect(getColumns(data)).toEqual([ + ['1', { name: 'First' }], + ['2', { name: 'Second' }], + ]); + }); + + it('should return an array of column IDs and their corresponding data', () => { + const data = { + blocks_layout: { + items: undefined, + }, + blocks: { + '1': { name: 'First' }, + '2': { name: 'Second' }, + }, + }; + expect(getColumns(data)).toEqual([]); + }); +}); + +describe('hasColumns', () => { + it('should return true if data has columns', () => { + const data = { + blocks_layout: { + items: ['1', '2'], + }, + }; + expect(hasColumns(data)).toBe(true); + }); + + it('should return false if data does not have columns', () => { + const data = {}; + expect(hasColumns(data)).toBe(false); + }); +}); + +describe('forEachColumn', () => { + it('should call callback for each column', () => { + const data = { + blocks_layout: { + items: ['1', '2'], + }, + blocks: { + '1': { name: 'First' }, + '2': { name: 'Second' }, + }, + }; + const callback = jest.fn(); + forEachColumn(data, callback); + expect(callback).toHaveBeenCalledTimes(2); + }); +}); + +describe('columnIsEmpty', () => { + it('should return true if column is empty', () => { + const data = {}; + expect(columnIsEmpty(data)).toBe(true); + }); + + it('should return false if column is not empty', () => { + const data = { + blocks_layout: { + items: ['1'], + }, + }; + expect(columnIsEmpty(data)).toBe(false); + }); +}); + +describe('empty', () => { + it('should return data for specified number of empty columns', () => { + const result = empty(2); + expect(Object.keys(result.blocks)).toHaveLength(2); + expect(result.blocks_layout.items).toHaveLength(2); + }); +}); + +describe('defaultNewColumn', () => { + it('should return data for new column with default block type', () => { + const result = defaultNewColumn(); + const [id] = Object.keys(result.blocks); + expect(result.blocks[id]['@type']).toEqual( + config.settings.defaultBlockType, + ); + expect(result.blocks_layout.items).toEqual([id]); + }); +}); diff --git a/src/Widgets/ColumnsWidget.jsx b/src/Widgets/ColumnsWidget.jsx index 2e7d58e..74aa3ec 100644 --- a/src/Widgets/ColumnsWidget.jsx +++ b/src/Widgets/ColumnsWidget.jsx @@ -3,8 +3,7 @@ import { FormattedMessage } from 'react-intl'; import { v4 as uuid } from 'uuid'; import { omit, without } from 'lodash'; import move from 'lodash-move'; -import { Icon, FormFieldWrapper } from '@plone/volto/components'; -import { DragDropList } from '@plone/volto/components'; +import { Icon, FormFieldWrapper, DragDropList } from '@plone/volto/components'; import { emptyBlocksForm } from '@plone/volto/helpers'; import dragSVG from '@plone/volto/icons/drag.svg'; diff --git a/src/Widgets/Slider.jsx b/src/Widgets/Slider.jsx index c49b6d3..ad08c5b 100644 --- a/src/Widgets/Slider.jsx +++ b/src/Widgets/Slider.jsx @@ -348,10 +348,8 @@ export class Slider extends Component { }} style={{ ...styles.inner, - ...(this.props.style + ...(this.props.style && this.props.style.inner ? this.props.style.inner - ? this.props.style.inner - : {} : {}), }} > @@ -363,10 +361,8 @@ export class Slider extends Component { style={{ ...styles.track, ...(this.props.inverted ? styles.invertedTrack : {}), - ...(this.props.style + ...(this.props.style && this.props.style.track ? this.props.style.track - ? this.props.style.track - : {} : {}), }} /> @@ -383,16 +379,12 @@ export class Slider extends Component { ? 'inverted-' + this.props.color : this.props.color ], - ...(this.props.style + ...(this.props.style && this.props.style.trackFill ? this.props.style.trackFill - ? this.props.style.trackFill - : {} : {}), ...(this.props.disabled ? styles.disabledTrackFill : {}), - ...(this.props.style + ...(this.props.style && this.props.style.disabledTrackFill ? this.props.style.disabledTrackFill - ? this.props.style.disabledTrackFill - : {} : {}), ...{ width: this.state.position + this.state.offset + 'px' }, ...(this.props.multiple && this.state.position.length > 0 @@ -413,10 +405,8 @@ export class Slider extends Component { key={i} style={{ ...styles.knob, - ...(this.props.style + ...(this.props.style && this.props.style.knob ? this.props.style.knob - ? this.props.style.knob - : {} : {}), ...{ left: pos + 'px' }, }} @@ -431,10 +421,8 @@ export class Slider extends Component { onClick={this.handleKnobClick} style={{ ...styles.knob, - ...(this.props.style + ...(this.props.style && this.props.style.knob ? this.props.style.knob - ? this.props.style.knob - : {} : {}), ...{ left: this.state.position + 'px' }, }} @@ -487,7 +475,6 @@ const SliderWidget = (props) => { settings={{ ...settings, onChange: (value) => { - // console.log('onchange', value); onChange(id, value); }, }} diff --git a/src/index.js b/src/index.js index 8741e21..54dfe24 100644 --- a/src/index.js +++ b/src/index.js @@ -87,7 +87,6 @@ export default function install(config) { tocEntry: (block = {}, tocData) => { // integration with volto-block-toc const headlines = tocData.levels || ['h1', 'h2', 'h3', 'h4', 'h5', 'h6']; - // const column_blocks = block?.data?.blocks || {}; let entries = []; const sorted_column_blocks = getBlocks(block?.data || {}); sorted_column_blocks.forEach((column_block) => { diff --git a/src/utils.js b/src/utils.js index 9e03f27..19062c5 100644 --- a/src/utils.js +++ b/src/utils.js @@ -8,7 +8,6 @@ import config from '@plone/volto/registry'; const columnConfig = { cloneData(blockData) { - // console.log('column', blockData); return cloneFormData(blockData); }, }; diff --git a/src/utils.test.js b/src/utils.test.js index aa04f17..a090eae 100644 --- a/src/utils.test.js +++ b/src/utils.test.js @@ -23,7 +23,6 @@ describe('cloneColumnsBlockData', () => { }, }, }; - getBlocks.mockReturnValue([['block1', mockBlockData.data.blocks.block1]]); config.blocks.blocksConfig = { test: {},