diff --git a/src/PropertiesPanel.js b/src/PropertiesPanel.js index 377db72d..f2472f8f 100644 --- a/src/PropertiesPanel.js +++ b/src/PropertiesPanel.js @@ -119,13 +119,6 @@ export default function PropertiesPanel(props) { // set-up layout context const [ layout, setLayout ] = useState(createLayout(layoutConfig)); - // react to external changes in the layout config - useEffect(() => { - const newLayout = createLayout(layoutConfig); - - setLayout(newLayout); - }, [ layoutConfig ]); - useEffect(() => { if (typeof layoutChanged === 'function') { layoutChanged(layout); @@ -236,9 +229,9 @@ export default function PropertiesPanel(props) { // helpers ////////////////// -function createLayout(overrides, defaults = DEFAULT_LAYOUT) { +function createLayout(overrides) { return { - ...defaults, + ...DEFAULT_LAYOUT, ...overrides }; } diff --git a/src/hooks/useLayoutState.js b/src/hooks/useLayoutState.js index 427526b7..07981efe 100644 --- a/src/hooks/useLayoutState.js +++ b/src/hooks/useLayoutState.js @@ -1,6 +1,6 @@ import { - useCallback, - useContext + useContext, + useState } from 'preact/hooks'; import { @@ -29,11 +29,16 @@ export function useLayoutState(path, defaultValue) { } = useContext(LayoutContext); const layoutForKey = getLayoutForKey(path, defaultValue); + const [ value, set ] = useState(layoutForKey); - const setState = useCallback ((newValue) => { - setLayoutForKey(path, newValue); - }, [ setLayoutForKey ]); + const setState = (newValue) => { + + // (1) set component state + set(newValue); + // (2) set context + setLayoutForKey(path, newValue); + }; - return [ layoutForKey, setState ]; + return [ value, setState ]; } diff --git a/test/spec/PropertiesPanel.spec.js b/test/spec/PropertiesPanel.spec.js index db23fc68..413b1fcb 100644 --- a/test/spec/PropertiesPanel.spec.js +++ b/test/spec/PropertiesPanel.spec.js @@ -1,7 +1,6 @@ import { act, - render, - cleanup + render } from '@testing-library/preact/pure'; import TestContainer from 'mocha-test-container-support'; @@ -53,8 +52,6 @@ describe('', function() { }); - afterEach(cleanup); - it('should render (no element)', function() { // given @@ -317,41 +314,6 @@ describe('', function() { }); }); - - it('should notify on external layout change', async function() { - - // given - const initialLayoutConfig = { - open: true, - foo: 'bar' - }; - - const layoutChangedSpy = sinon.spy(); - - const options = { - container, - element: noopElement, - layoutConfig: initialLayoutConfig, - layoutChanged: layoutChangedSpy, - }; - - const { rerender } = createPropertiesPanel(options); - - // when - const updatedLayoutConfig = { - open: false, - foo: 'baz' - }; - - createPropertiesPanel({ - ...options, - layoutConfig: updatedLayoutConfig - }, rerender); - - // then - expect(layoutChangedSpy).to.have.been.calledWith(updatedLayoutConfig); - }); - }); @@ -402,7 +364,7 @@ describe('', function() { // helpers ////////// -function createPropertiesPanel(options = {}, renderFn = render) { +function createPropertiesPanel(options = {}) { const { container, @@ -410,13 +372,13 @@ function createPropertiesPanel(options = {}, renderFn = render) { headerProvider = HeaderProvider, placeholderProvider = PlaceholderProvider, groups = [], - layoutConfig = {}, + layoutConfig, layoutChanged = noop, - descriptionConfig = {}, + descriptionConfig, descriptionLoaded = noop } = options; - return renderFn( + return render( ', function() { expect(domClasses(entries).has('open')).to.be.false; // when - await act(() => { - header.click(); - }); + await header.click(); // then expect(domClasses(entries).has('open')).to.be.true; diff --git a/test/spec/components/Feel.spec.js b/test/spec/components/Feel.spec.js index 45590bc4..cc14d01a 100644 --- a/test/spec/components/Feel.spec.js +++ b/test/spec/components/Feel.spec.js @@ -417,7 +417,7 @@ describe('', function() { describe('toggle', function() { - it('should toggle feel active', async function() { + it('should toggle feel active', function() { // given const updateSpy = sinon.spy(); @@ -434,9 +434,7 @@ describe('', function() { field.container); // when - await act(() => { - icon.click(); - }); + icon.click(); // then return waitFor(() => { @@ -876,7 +874,7 @@ describe('', function() { describe('toggle', function() { - it('should toggle feel active', async function() { + it('should toggle feel active', function() { // given const updateSpy = sinon.spy(); @@ -893,9 +891,7 @@ describe('', function() { field.container); // when - await act(() => { - icon.click(); - }); + icon.click(); // then return waitFor(() => { @@ -1090,7 +1086,7 @@ describe('', function() { }); - it('should be edited after update', async function() { + it('should be edited after update', function() { // given const result = createFeelField({ container, feel: 'required' }); @@ -1102,9 +1098,7 @@ describe('', function() { expect(isEdited(input)).to.be.false; // when - await act(() => { - contentEditable.textContent = 'foo'; - }); + contentEditable.textContent = 'foo'; // then return waitFor(() => { @@ -1153,7 +1147,7 @@ describe('', function() { }); - it('should show syntax error', async function() { + it('should show syntax error', function() { // given const clock = sinon.useFakeTimers(); @@ -1161,17 +1155,17 @@ describe('', function() { // when // trigger debounced validation - await act(() => { clock.tick(1000); }); - await act(() => { clock.restore(); }); + clock.tick(1000); + clock.restore(); // then - await waitFor(() => { + return waitFor(() => { expect(domQuery('.bio-properties-panel-error', result.container)).to.exist; }); }); - it('should show local error over global error', async function() { + it('should show local error over global error', function() { // given const clock = sinon.useFakeTimers(); @@ -1194,9 +1188,8 @@ describe('', function() { // when // trigger debounced validation - await act(() => { clock.tick(1000); }); - await act(() => { clock.restore(); }); - + clock.tick(1000); + clock.restore(); // then return waitFor(() => { @@ -1236,7 +1229,7 @@ describe('', function() { }); - it('should set invalid', async function() { + it('should set invalid', function() { // given const validate = (v) => { @@ -1251,10 +1244,7 @@ describe('', function() { const input = domQuery('[role="textbox"]', entry); // when - await act(() => { - input.textContent = 'bar'; - }); - + input.textContent = 'bar'; // then return waitFor(() => { @@ -1287,7 +1277,7 @@ describe('', function() { }); - it('should show error message', async function() { + it('should show error message', function() { // given const validate = (v) => { @@ -1302,10 +1292,7 @@ describe('', function() { const input = domQuery('[role="textbox"]', entry); // when - await act(() => { - input.textContent = 'bar'; - }); - + input.textContent = 'bar'; // then return waitFor(() => { @@ -1468,7 +1455,7 @@ describe('', function() { describe('toggle', function() { - it('should toggle feel inactive', async function() { + it('should toggle feel inactive', function() { // given const updateSpy = sinon.spy(); @@ -1485,16 +1472,14 @@ describe('', function() { field.container); // when - await act(() => { - icon.click(); - }); + icon.click(); // then expect(updateSpy).to.have.been.calledWith('foo'); }); - it('should NOT toggle if FEEL is required', async function() { + it('should NOT toggle if FEEL is required', function() { // given const updateSpy = sinon.spy(); @@ -1511,9 +1496,7 @@ describe('', function() { field.container); // when - await act(() => { - icon.click(); - }); + icon.click(); // then expect(updateSpy).not.to.have.been.called; diff --git a/test/spec/components/Group.spec.js b/test/spec/components/Group.spec.js index e91d1893..5a75b5ca 100644 --- a/test/spec/components/Group.spec.js +++ b/test/spec/components/Group.spec.js @@ -1,4 +1,4 @@ -import { useContext, useEffect, useState } from 'preact/hooks'; +import { useContext } from 'preact/hooks'; import { render @@ -25,7 +25,6 @@ import Group from 'src/components/Group'; import { PropertiesPanelContext } from 'src/context'; import { fireEvent } from '@testing-library/preact'; -import { act } from 'preact/test-utils'; insertCoreStyles(); @@ -84,37 +83,6 @@ describe('', function() { expect(domClasses(entries).has('open')).to.be.true; }); - - it('should use global layout', async function() { - - // given - let setLayoutForKey; - const Entry = () => { - setLayoutForKey = useContext(LayoutContext).setLayoutForKey; - }; - - const result = createGroup({ - container, - id: 'groupId', - entries: createEntries({ - component: Entry - }), - label: 'Group' - }); - - const entries = domQuery('.bio-properties-panel-group-entries', result.container); - - // assume - expect(domClasses(entries).has('open')).to.be.false; - - // when - await act(() => setLayoutForKey([ 'groups', 'groupId', 'open' ], true)); - - // then - expect(domClasses(entries).has('open')).to.be.true; - - }); - }); @@ -124,7 +92,7 @@ describe('', function() { const Entry = () => { const { onShow } = useContext(PropertiesPanelContext); - useEffect(onShow, []); + onShow(); }; const result = createGroup({ @@ -308,10 +276,11 @@ function createGroup(options = {}) { container } = options; + var MockLayout = createLayout(); return render( - + , { container @@ -330,18 +299,12 @@ function TestEntry(props = {}) { ; } -function MockLayout({ children }) { - const [ layout, setLayout ] = useState({}); - - const getLayoutForKey = (key, defaultValue) => { - return layout[key] || defaultValue; - }; - - const setLayoutForKey = (key, value) => { - setLayout({ - [key]: value - }); - }; +function createLayout(props = {}) { + const { + layout = {}, + getLayoutForKey = (key, defaultValue) => defaultValue, + setLayoutForKey = noop + } = props; const context = { layout, @@ -349,5 +312,5 @@ function MockLayout({ children }) { setLayoutForKey }; - return {children}; + return ({ children }) => {children}; } diff --git a/test/spec/components/ListGroup.spec.js b/test/spec/components/ListGroup.spec.js index 9adcecc1..8c198fae 100644 --- a/test/spec/components/ListGroup.spec.js +++ b/test/spec/components/ListGroup.spec.js @@ -1,4 +1,4 @@ -import { useContext, useEffect, useState } from 'preact/hooks'; +import { useContext } from 'preact/hooks'; import { act, @@ -22,7 +22,7 @@ import { import ListGroup from 'src/components/ListGroup'; -import { PropertiesPanelContext, LayoutContext } from 'src/context'; +import { PropertiesPanelContext } from 'src/context'; insertCoreStyles(); @@ -134,7 +134,7 @@ describe('', function() { const Entry = () => { const { onShow } = useContext(PropertiesPanelContext); - useEffect(onShow, []); + onShow(); }; const items = [ @@ -1122,7 +1122,7 @@ describe('', function() { function createListGroup(options = {}, renderFn = render) { const { element = noopElement, - id = 'sampleId', + id, label = 'List', items = [], add, @@ -1132,16 +1132,14 @@ function createListGroup(options = {}, renderFn = render) { } = options; return renderFn( - - - , + , { container } @@ -1161,25 +1159,3 @@ function getListOrdering(list) { return ordering; } - -function MockLayout({ children }) { - const [ layout, setLayout ] = useState({}); - - const getLayoutForKey = (key, defaultValue) => { - return layout[key] || defaultValue; - }; - - const setLayoutForKey = (key, value) => { - setLayout({ - [key]: value - }); - }; - - const context = { - layout, - getLayoutForKey, - setLayoutForKey - }; - - return {children}; -} \ No newline at end of file diff --git a/test/spec/hooks/useLayoutState.spec.js b/test/spec/hooks/useLayoutState.spec.js index f393ef61..958a4ac1 100644 --- a/test/spec/hooks/useLayoutState.spec.js +++ b/test/spec/hooks/useLayoutState.spec.js @@ -4,7 +4,6 @@ import { } from '@testing-library/preact-hooks'; import { - assign, get, set } from 'min-dash'; @@ -16,7 +15,8 @@ import { import { LayoutContext } from 'src/context'; -import { useContext, useState } from 'preact/hooks'; + +const noop = () => {}; describe('hooks/useLayoutState', function() { @@ -72,7 +72,7 @@ describe('hooks/useLayoutState', function() { }); - it('should set to layout context', async function() { + it('should set to layout context', function() { // given const layout = { @@ -81,20 +81,18 @@ describe('hooks/useLayoutState', function() { } }; + const setLayoutForKey = (path, value) => set(layout, path, value); + const path = [ 'a', 'b' ]; const wrapper = createLayout({ + setLayoutForKey, layout }); - const { result } = renderHook(() => { - return { - state: useLayoutState(path), - context: useContext(LayoutContext) - }; - }, { wrapper }); + const { result } = renderHook(() => useLayoutState(path), { wrapper }); - const [ , setState ] = result.current.state; + const [ , setState ] = result.current; const newValue = 'newValue'; @@ -103,13 +101,11 @@ describe('hooks/useLayoutState', function() { setState(newValue); }); - const [ value ] = result.current.state; - const newLayout = result.current.context.layout; - + const [ value ] = result.current; // then expect(value).to.eql(newValue); - expect(newLayout).to.eql({ + expect(layout).to.eql({ a: { b: newValue } @@ -122,30 +118,17 @@ describe('hooks/useLayoutState', function() { // helper //////////////////// function createLayout(props = {}) { - - return ({ children }) => { - const { - layout = {}, - } = props; - - const [ _layout, setLayout ] = useState(layout); - - const getLayoutForKey = props.getLayoutForKey || function(path, defaultValue) { - return get(_layout, path) || defaultValue; - }; - - const setLayoutForKey = props.setLayoutForKey || function(path, value) { - const newLayout = assign({}, layout); - set(newLayout, path, value); - setLayout(newLayout); - }; - - const context = { - layout: _layout, - getLayoutForKey, - setLayoutForKey - }; - - return {children}; + const { + layout = {}, + getLayoutForKey = noop, + setLayoutForKey = noop + } = props; + + const context = { + layout, + getLayoutForKey, + setLayoutForKey }; + + return ({ children }) => {children}; }