@shopgate/pwa-common 7.32.0-beta.2 → 7.32.0-beta.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/actions/app/handleLink.js +6 -2
- package/components/Button/index.js +6 -0
- package/components/Image/Image.d.ts +78 -0
- package/components/Image/Image.d.ts.map +1 -0
- package/components/Image/Image.js +123 -91
- package/components/Image/ImageInner.d.ts +45 -0
- package/components/Image/ImageInner.d.ts.map +1 -0
- package/components/Image/ImageInner.js +23 -29
- package/components/Image/index.d.ts +3 -0
- package/components/Image/index.d.ts.map +1 -0
- package/components/Swiper/index.js +17 -2
- package/constants/Configuration.js +7 -0
- package/helpers/html/decodeHTML.js +5 -3
- package/helpers/html/htmlToText.js +15 -0
- package/helpers/mocks/mockRenderOptions.js +21 -0
- package/helpers/router/index.js +85 -0
- package/package.json +3 -3
- package/providers/toast/index.js +54 -40
- package/subscriptions/error.js +50 -27
- package/subscriptions/helpers/pipeline.js +68 -0
- package/subscriptions/router.js +22 -8
- package/action-creators/app/spec.js +0 -96
- package/action-creators/client/spec.js +0 -44
- package/action-creators/menu/spec.js +0 -37
- package/action-creators/modal/spec.js +0 -26
- package/action-creators/page/spec.js +0 -38
- package/action-creators/url/spec.js +0 -45
- package/action-creators/user/spec.js +0 -186
- package/components/Backdrop/spec.js +0 -24
- package/components/Button/spec.js +0 -42
- package/components/Checkbox/spec.js +0 -111
- package/components/CountdownTimer/spec.js +0 -141
- package/components/Drawer/spec.js +0 -79
- package/components/Ellipsis/spec.js +0 -15
- package/components/EmbeddedMedia/spec.js +0 -61
- package/components/Grid/components/Item/spec.js +0 -24
- package/components/Grid/spec.js +0 -24
- package/components/HtmlSanitizer/spec.js +0 -229
- package/components/I18n/components/FormatDate/spec.js +0 -54
- package/components/I18n/components/FormatNumber/spec.js +0 -51
- package/components/I18n/components/FormatPrice/spec.js +0 -54
- package/components/I18n/components/FormatTime/spec.js +0 -51
- package/components/I18n/components/I18nProvider/spec.js +0 -40
- package/components/I18n/components/Placeholder/spec.js +0 -37
- package/components/I18n/components/Translate/spec.js +0 -33
- package/components/InfiniteContainer/spec.js +0 -204
- package/components/Input/spec.js +0 -123
- package/components/Link/spec.js +0 -60
- package/components/List/spec.js +0 -26
- package/components/ModalContainer/spec.js +0 -115
- package/components/Select/spec.js +0 -122
- package/components/SelectBox/spec.js +0 -68
- package/components/Swiper/components/SwiperItem/spec.js +0 -26
- package/components/Widgets/components/Widget/spec.js +0 -75
- package/components/Widgets/components/WidgetGrid/spec.js +0 -53
- package/components/Widgets/spec.js +0 -234
- package/helpers/data/spec.js +0 -194
- package/helpers/date/spec.js +0 -92
- package/helpers/style/spec.js +0 -108
- package/helpers/validation/spec.js +0 -10
- package/styles/reset/form.js +0 -58
- package/styles/reset/index.js +0 -8
- package/styles/reset/media.js +0 -26
- package/styles/reset/root.js +0 -37
- package/styles/reset/table.js +0 -14
- package/styles/reset/typography.js +0 -30
- package/tsconfig.build.json +0 -16
- package/tsconfig.json +0 -3
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
/* eslint-disable no-unused-vars, jsx-a11y/control-has-associated-label */
|
|
2
|
-
import React from 'react';
|
|
3
|
-
import { mount } from 'enzyme';
|
|
4
|
-
import { Provider } from 'react-redux';
|
|
5
|
-
import { configureStore } from "../../store";
|
|
6
|
-
import modalReducer from "../../reducers/modal";
|
|
7
|
-
import showModal from "../../actions/modal/showModal";
|
|
8
|
-
import ModalContainer from "./index";
|
|
9
|
-
|
|
10
|
-
// const store = configureStore({ modal: modalReducer });
|
|
11
|
-
// Replacement for commented out configureStore()
|
|
12
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
13
|
-
const store = {};
|
|
14
|
-
jest.mock('redux-logger', () => ({
|
|
15
|
-
createLogger: () => () => next => action => next(action)
|
|
16
|
-
}));
|
|
17
|
-
global.requestAnimationFrame = fn => fn();
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Some mock modal component.
|
|
21
|
-
* @param {func} onConfirm Confirm callback
|
|
22
|
-
* @param {func} onDismiss Dismiss callback
|
|
23
|
-
* @constructor
|
|
24
|
-
*/
|
|
25
|
-
const MockModal = ({
|
|
26
|
-
onConfirm,
|
|
27
|
-
// eslint-disable-line react/prop-types
|
|
28
|
-
onDismiss // eslint-disable-line react/prop-types
|
|
29
|
-
}) => /*#__PURE__*/_jsxs("div", {
|
|
30
|
-
className: "modal",
|
|
31
|
-
children: [/*#__PURE__*/_jsx("button", {
|
|
32
|
-
className: "confirmBtn",
|
|
33
|
-
onClick: onConfirm,
|
|
34
|
-
type: "button"
|
|
35
|
-
}), /*#__PURE__*/_jsx("button", {
|
|
36
|
-
className: "dismissBtn",
|
|
37
|
-
onClick: onDismiss,
|
|
38
|
-
type: "button"
|
|
39
|
-
})]
|
|
40
|
-
});
|
|
41
|
-
describe.skip('<ModalContainer />', () => {
|
|
42
|
-
let renderedElement;
|
|
43
|
-
const {
|
|
44
|
-
dispatch,
|
|
45
|
-
getState
|
|
46
|
-
} = store;
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* The rendered component.
|
|
50
|
-
*/
|
|
51
|
-
const renderComponent = () => {
|
|
52
|
-
renderedElement = mount(/*#__PURE__*/_jsx(Provider, {
|
|
53
|
-
store: store,
|
|
54
|
-
children: /*#__PURE__*/_jsx("div", {
|
|
55
|
-
id: "container",
|
|
56
|
-
children: /*#__PURE__*/_jsx(ModalContainer, {
|
|
57
|
-
component: MockModal
|
|
58
|
-
})
|
|
59
|
-
})
|
|
60
|
-
}));
|
|
61
|
-
};
|
|
62
|
-
beforeEach(() => {
|
|
63
|
-
// Reset the modals state before each test.
|
|
64
|
-
getState().modal = [];
|
|
65
|
-
renderComponent();
|
|
66
|
-
});
|
|
67
|
-
describe('Given the component was mounted to the DOM', () => {
|
|
68
|
-
it('should match snapshot', () => {
|
|
69
|
-
expect(renderedElement).toMatchSnapshot();
|
|
70
|
-
});
|
|
71
|
-
it('should show no modal', () => {
|
|
72
|
-
expect(renderedElement.find('.modal').length).toBe(0);
|
|
73
|
-
});
|
|
74
|
-
describe('Given a modal gets dispatched', () => {
|
|
75
|
-
let modalPromise;
|
|
76
|
-
beforeEach(() => {
|
|
77
|
-
modalPromise = dispatch(showModal({
|
|
78
|
-
title: 'Title',
|
|
79
|
-
message: 'Message'
|
|
80
|
-
}));
|
|
81
|
-
renderedElement.update();
|
|
82
|
-
});
|
|
83
|
-
it('should contain a modal item in the state', () => {
|
|
84
|
-
expect(getState().modal.length).toBe(1);
|
|
85
|
-
});
|
|
86
|
-
it('should show the modal', () => {
|
|
87
|
-
expect(renderedElement.find('.modal').length).toBe(1);
|
|
88
|
-
});
|
|
89
|
-
describe('Given the modal gets confirmed', () => {
|
|
90
|
-
beforeEach(() => {
|
|
91
|
-
renderedElement.find('.confirmBtn').simulate('click');
|
|
92
|
-
});
|
|
93
|
-
it('should resolve the promise as confirmed', () => {
|
|
94
|
-
modalPromise.then(confirmed => expect(confirmed).toBe(true));
|
|
95
|
-
});
|
|
96
|
-
it('should contain no modal item in the state', () => {
|
|
97
|
-
expect(getState().modal.length).toBe(0);
|
|
98
|
-
});
|
|
99
|
-
it('should not show the modal anymore', () => {
|
|
100
|
-
expect(renderedElement.find('.modal').length).toBe(0);
|
|
101
|
-
});
|
|
102
|
-
});
|
|
103
|
-
describe('Given the modal gets dismissed', () => {
|
|
104
|
-
beforeEach(() => {
|
|
105
|
-
renderedElement.find('.dismissBtn').simulate('click');
|
|
106
|
-
});
|
|
107
|
-
it('should resolve the promise as dismissed', () => {
|
|
108
|
-
modalPromise.then(confirmed => expect(confirmed).toBe(false));
|
|
109
|
-
});
|
|
110
|
-
});
|
|
111
|
-
});
|
|
112
|
-
});
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
/* eslint-enable no-unused-vars, jsx-a11y/control-has-associated-label */
|
|
@@ -1,122 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { mount } from 'enzyme';
|
|
3
|
-
import { act } from 'react-dom/test-utils';
|
|
4
|
-
import Select from "./index";
|
|
5
|
-
import SelectItem from "./components/Item";
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Returns whether the given Enzyme wrapper contains at least one node
|
|
9
|
-
* with a class name that ends with the provided suffix.
|
|
10
|
-
*
|
|
11
|
-
* This checks individual class tokens, so it works with elements that
|
|
12
|
-
* have multiple classes.
|
|
13
|
-
*
|
|
14
|
-
* @param {Object} wrapper Enzyme wrapper (mount or shallow result).
|
|
15
|
-
* @param {string} suffix Class name suffix to match, e.g. "-innerShadow".
|
|
16
|
-
* @returns {boolean} True if a matching node exists.
|
|
17
|
-
*/
|
|
18
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
19
|
-
export function containsClassWithEnding(wrapper, suffix) {
|
|
20
|
-
if (!wrapper || typeof wrapper.findWhere !== 'function' || !suffix) {
|
|
21
|
-
return false;
|
|
22
|
-
}
|
|
23
|
-
return wrapper.findWhere(node => {
|
|
24
|
-
const className = node.prop('className');
|
|
25
|
-
if (typeof className !== 'string') {
|
|
26
|
-
return false;
|
|
27
|
-
}
|
|
28
|
-
return className.split(/\s+/).some(cls => cls.endsWith(suffix));
|
|
29
|
-
}).length > 0;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Helper to simulate toggling the open state by touching the handle area.
|
|
34
|
-
* @param {Object} wrapper Enzyme wrapper.
|
|
35
|
-
*/
|
|
36
|
-
const toggleOpen = wrapper => {
|
|
37
|
-
wrapper.find('[role="presentation"]').simulate('touchstart');
|
|
38
|
-
wrapper.update();
|
|
39
|
-
};
|
|
40
|
-
describe('<Select />', () => {
|
|
41
|
-
jest.useFakeTimers();
|
|
42
|
-
it('opens and closes the item list', () => {
|
|
43
|
-
const wrapper = mount(/*#__PURE__*/_jsx(Select, {}));
|
|
44
|
-
expect(wrapper.find(SelectItem).length).toBe(0);
|
|
45
|
-
toggleOpen(wrapper);
|
|
46
|
-
// opened – still 0 items because no items prop
|
|
47
|
-
expect(containsClassWithEnding(wrapper, '-items')).toBe(true);
|
|
48
|
-
toggleOpen(wrapper);
|
|
49
|
-
expect(containsClassWithEnding(wrapper, '-items')).toBe(false);
|
|
50
|
-
});
|
|
51
|
-
it('renders without items', () => {
|
|
52
|
-
const wrapper = mount(/*#__PURE__*/_jsx(Select, {}));
|
|
53
|
-
toggleOpen(wrapper);
|
|
54
|
-
expect(wrapper).toMatchSnapshot();
|
|
55
|
-
expect(wrapper.find(SelectItem).length).toBe(0);
|
|
56
|
-
});
|
|
57
|
-
it('renders with implicit items (closed)', () => {
|
|
58
|
-
const items = ['a', 'b', 'c', 'd', 'e', 'f'];
|
|
59
|
-
const wrapper = mount(/*#__PURE__*/_jsx(Select, {
|
|
60
|
-
items: items
|
|
61
|
-
}));
|
|
62
|
-
expect(wrapper).toMatchSnapshot();
|
|
63
|
-
expect(wrapper.find(SelectItem).length).toBe(0);
|
|
64
|
-
});
|
|
65
|
-
it('renders with implicit items (opened)', () => {
|
|
66
|
-
const items = ['a', 'b', 'c', 'd', 'e', 'f'];
|
|
67
|
-
const wrapper = mount(/*#__PURE__*/_jsx(Select, {
|
|
68
|
-
items: items
|
|
69
|
-
}));
|
|
70
|
-
toggleOpen(wrapper);
|
|
71
|
-
expect(wrapper).toMatchSnapshot();
|
|
72
|
-
expect(wrapper.find(SelectItem).length).toBe(items.length);
|
|
73
|
-
});
|
|
74
|
-
it('accepts implicit and explicit items', () => {
|
|
75
|
-
const items = ['a', 'b', {
|
|
76
|
-
value: 'c'
|
|
77
|
-
}, 'd', {
|
|
78
|
-
value: 'e',
|
|
79
|
-
label: 'E'
|
|
80
|
-
}, 'f'];
|
|
81
|
-
const wrapper = mount(/*#__PURE__*/_jsx(Select, {
|
|
82
|
-
items: items
|
|
83
|
-
}));
|
|
84
|
-
toggleOpen(wrapper);
|
|
85
|
-
expect(wrapper).toMatchSnapshot();
|
|
86
|
-
expect(wrapper.find(SelectItem).length).toBe(items.length);
|
|
87
|
-
let i = 0;
|
|
88
|
-
wrapper.find(SelectItem).forEach(item => {
|
|
89
|
-
let expectedLabel = items[i];
|
|
90
|
-
if (expectedLabel.label) {
|
|
91
|
-
expectedLabel = expectedLabel.label;
|
|
92
|
-
}
|
|
93
|
-
if (expectedLabel.value) {
|
|
94
|
-
expectedLabel = expectedLabel.value;
|
|
95
|
-
}
|
|
96
|
-
expect(item.prop('label')).toBe(expectedLabel);
|
|
97
|
-
i += 1;
|
|
98
|
-
});
|
|
99
|
-
});
|
|
100
|
-
it('triggers callback on change', () => {
|
|
101
|
-
const items = ['a', 'b', 'c', 'd', 'e', 'f'];
|
|
102
|
-
const selectionIndex = Math.floor(items.length / 2);
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
* Mocked callback for the onSelect event
|
|
106
|
-
* @param {string} value Mocked value
|
|
107
|
-
*/
|
|
108
|
-
const callback = value => {
|
|
109
|
-
expect(value).toBe(items[selectionIndex]);
|
|
110
|
-
};
|
|
111
|
-
const wrapper = mount(/*#__PURE__*/_jsx(Select, {
|
|
112
|
-
items: items,
|
|
113
|
-
onChange: callback
|
|
114
|
-
}));
|
|
115
|
-
toggleOpen(wrapper);
|
|
116
|
-
expect(wrapper).toMatchSnapshot();
|
|
117
|
-
const node = wrapper.find(SelectItem).at(selectionIndex);
|
|
118
|
-
act(() => {
|
|
119
|
-
node.prop('onSelect')(node.prop('value'), node.prop('label'));
|
|
120
|
-
});
|
|
121
|
-
});
|
|
122
|
-
});
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import PropTypes from 'prop-types';
|
|
3
|
-
import { mount } from 'enzyme';
|
|
4
|
-
import SelectBox from "./index";
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Mock Icon component.
|
|
8
|
-
* @returns {JSX}
|
|
9
|
-
*/
|
|
10
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
11
|
-
const MockIconComponent = () => /*#__PURE__*/_jsx("span", {
|
|
12
|
-
id: "icon"
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Mock Item component.
|
|
17
|
-
* @param {Object} props The components props.
|
|
18
|
-
* @param {JSX} props.children The components children.
|
|
19
|
-
* @returns {JSX}
|
|
20
|
-
*/
|
|
21
|
-
const MockItemComponent = ({
|
|
22
|
-
children
|
|
23
|
-
}) => /*#__PURE__*/_jsx("div", {
|
|
24
|
-
children: children
|
|
25
|
-
});
|
|
26
|
-
describe('<SelectBox>', () => {
|
|
27
|
-
const dummyItems = [{
|
|
28
|
-
label: 'My item #1',
|
|
29
|
-
value: 'item_1'
|
|
30
|
-
}, {
|
|
31
|
-
label: 'My item #2',
|
|
32
|
-
value: 'item_2'
|
|
33
|
-
}, {
|
|
34
|
-
label: 'My item #3',
|
|
35
|
-
value: 'item_3'
|
|
36
|
-
}];
|
|
37
|
-
it('should render the selectbox with given mock components', () => {
|
|
38
|
-
const wrapper = mount(/*#__PURE__*/_jsx(SelectBox, {
|
|
39
|
-
icon: MockIconComponent,
|
|
40
|
-
item: MockItemComponent,
|
|
41
|
-
items: dummyItems
|
|
42
|
-
}));
|
|
43
|
-
expect(wrapper).toMatchSnapshot();
|
|
44
|
-
expect(wrapper.find(MockIconComponent).length).toEqual(1);
|
|
45
|
-
expect(wrapper.find(MockItemComponent).length).toEqual(3);
|
|
46
|
-
});
|
|
47
|
-
it('should render with a default text', () => {
|
|
48
|
-
const wrapper = mount(/*#__PURE__*/_jsx(SelectBox, {
|
|
49
|
-
icon: MockIconComponent,
|
|
50
|
-
item: MockItemComponent,
|
|
51
|
-
items: dummyItems,
|
|
52
|
-
defaultText: "Foo"
|
|
53
|
-
}));
|
|
54
|
-
expect(wrapper).toMatchSnapshot();
|
|
55
|
-
expect(wrapper.find('span').at(0).text()).toEqual('Foo');
|
|
56
|
-
});
|
|
57
|
-
it('should render with a preselected selection', () => {
|
|
58
|
-
const wrapper = mount(/*#__PURE__*/_jsx(SelectBox, {
|
|
59
|
-
icon: MockIconComponent,
|
|
60
|
-
item: MockItemComponent,
|
|
61
|
-
items: dummyItems,
|
|
62
|
-
defaultText: "Foo",
|
|
63
|
-
initialValue: "item_2"
|
|
64
|
-
}));
|
|
65
|
-
expect(wrapper).toMatchSnapshot();
|
|
66
|
-
expect(wrapper.find('span').at(0).text()).toEqual('My item #2');
|
|
67
|
-
});
|
|
68
|
-
});
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { shallow } from 'enzyme';
|
|
3
|
-
import { CLASS_PREFIX } from '@shopgate/engage/styles/tss';
|
|
4
|
-
import SwiperItem from '.';
|
|
5
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
6
|
-
jest.mock('react', () => ({
|
|
7
|
-
...jest.requireActual('react'),
|
|
8
|
-
useLayoutEffect: jest.requireActual('react').useEffect
|
|
9
|
-
}));
|
|
10
|
-
describe('<SwiperItem />', () => {
|
|
11
|
-
it('should not render without children', () => {
|
|
12
|
-
const wrapper = shallow(/*#__PURE__*/_jsx(SwiperItem, {
|
|
13
|
-
children: /*#__PURE__*/_jsx("div", {})
|
|
14
|
-
}));
|
|
15
|
-
expect(wrapper).toMatchSnapshot();
|
|
16
|
-
expect(wrapper.html()).toMatch(new RegExp(`^<div class="swiper-slide ${CLASS_PREFIX}-[^"]+" data-test-id="Slider"><div></div></div>$`));
|
|
17
|
-
});
|
|
18
|
-
it('should add custom className', () => {
|
|
19
|
-
const wrapper = shallow(/*#__PURE__*/_jsx(SwiperItem, {
|
|
20
|
-
className: "test",
|
|
21
|
-
children: /*#__PURE__*/_jsx("div", {})
|
|
22
|
-
}));
|
|
23
|
-
expect(wrapper).toMatchSnapshot();
|
|
24
|
-
expect(wrapper.html()).toMatch(new RegExp(`^<div class="swiper-slide ${CLASS_PREFIX}-[^"]+ test" data-test-id="Slider"><div></div></div>$`));
|
|
25
|
-
});
|
|
26
|
-
});
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { mount } from 'enzyme';
|
|
3
|
-
import Grid from "../../../Grid";
|
|
4
|
-
import Widget from "./index";
|
|
5
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
6
|
-
jest.mock('react', () => {
|
|
7
|
-
const actual = jest.requireActual('react');
|
|
8
|
-
return {
|
|
9
|
-
...actual,
|
|
10
|
-
memo: c => c,
|
|
11
|
-
Suspense: function Suspense({
|
|
12
|
-
children
|
|
13
|
-
}) {
|
|
14
|
-
return children;
|
|
15
|
-
}
|
|
16
|
-
};
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* A dummy component.
|
|
21
|
-
* @returns {JSX}
|
|
22
|
-
*/
|
|
23
|
-
const MyComponent = () => /*#__PURE__*/_jsx("div", {});
|
|
24
|
-
const widgets = {
|
|
25
|
-
'@shopgate/commerce-widgets/image': MyComponent
|
|
26
|
-
};
|
|
27
|
-
describe('<Widget />', () => {
|
|
28
|
-
it('should render an image widget', () => {
|
|
29
|
-
const config = {
|
|
30
|
-
type: '@shopgate/commerce-widgets/image',
|
|
31
|
-
col: 1,
|
|
32
|
-
row: 1,
|
|
33
|
-
width: 12,
|
|
34
|
-
height: 6
|
|
35
|
-
};
|
|
36
|
-
const wrapper = mount(/*#__PURE__*/_jsx(Widget, {
|
|
37
|
-
config: config,
|
|
38
|
-
component: widgets[config.type]
|
|
39
|
-
}));
|
|
40
|
-
expect(wrapper).toMatchSnapshot();
|
|
41
|
-
expect(wrapper.find(Grid.Item).exists()).toBe(true);
|
|
42
|
-
});
|
|
43
|
-
it('should render an image widget with offset', () => {
|
|
44
|
-
const config = {
|
|
45
|
-
type: '@shopgate/commerce-widgets/image',
|
|
46
|
-
col: 1,
|
|
47
|
-
row: 1,
|
|
48
|
-
width: 6,
|
|
49
|
-
height: 6
|
|
50
|
-
};
|
|
51
|
-
const wrapper = mount(/*#__PURE__*/_jsx(Widget, {
|
|
52
|
-
config: config,
|
|
53
|
-
component: widgets[config.type],
|
|
54
|
-
cellSize: 100
|
|
55
|
-
}));
|
|
56
|
-
expect(wrapper).toMatchSnapshot();
|
|
57
|
-
expect(wrapper.find(Grid.Item).exists()).toBe(true);
|
|
58
|
-
});
|
|
59
|
-
it('should not render when the `type` prop is invalid', () => {
|
|
60
|
-
const config = {
|
|
61
|
-
type: 'some_widget',
|
|
62
|
-
// Invalid
|
|
63
|
-
col: 1,
|
|
64
|
-
row: 1,
|
|
65
|
-
width: 12,
|
|
66
|
-
height: 6
|
|
67
|
-
};
|
|
68
|
-
const wrapper = mount(/*#__PURE__*/_jsx(Widget, {
|
|
69
|
-
config: config,
|
|
70
|
-
component: widgets[config.type]
|
|
71
|
-
}));
|
|
72
|
-
expect(wrapper).toMatchSnapshot();
|
|
73
|
-
expect(wrapper.find(Grid.Item).exists()).toBe(false);
|
|
74
|
-
});
|
|
75
|
-
});
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { mount } from 'enzyme';
|
|
3
|
-
import WidgetGrid from "./index";
|
|
4
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
5
|
-
jest.mock('react', () => {
|
|
6
|
-
const actual = jest.requireActual('react');
|
|
7
|
-
return {
|
|
8
|
-
...actual,
|
|
9
|
-
memo: c => c,
|
|
10
|
-
Suspense: function Suspense({
|
|
11
|
-
children
|
|
12
|
-
}) {
|
|
13
|
-
return children;
|
|
14
|
-
}
|
|
15
|
-
};
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* A mock Image component.
|
|
20
|
-
* @returns {JSX}
|
|
21
|
-
*/
|
|
22
|
-
const Image = () => /*#__PURE__*/_jsx("div", {});
|
|
23
|
-
const components = {
|
|
24
|
-
'@shopgate/commerce-widgets/image': Image
|
|
25
|
-
};
|
|
26
|
-
describe('<WidgetGrid />', () => {
|
|
27
|
-
it('should render with a config', () => {
|
|
28
|
-
const config = [{
|
|
29
|
-
col: 0,
|
|
30
|
-
row: 0,
|
|
31
|
-
width: 12,
|
|
32
|
-
height: 3,
|
|
33
|
-
settings: {
|
|
34
|
-
id: 83535,
|
|
35
|
-
image: 'https://data.shopgate.com/shop_widget_images/23836/92204c0f264ac30d6836994c2fb64eb1.min.jpeg'
|
|
36
|
-
},
|
|
37
|
-
type: '@shopgate/commerce-widgets/image'
|
|
38
|
-
}];
|
|
39
|
-
const wrapper = mount(/*#__PURE__*/_jsx(WidgetGrid, {
|
|
40
|
-
config: config,
|
|
41
|
-
components: components
|
|
42
|
-
}));
|
|
43
|
-
expect(wrapper).toMatchSnapshot();
|
|
44
|
-
expect(wrapper.find(Image).length).toEqual(1);
|
|
45
|
-
});
|
|
46
|
-
it('should not render without a `config` prop', () => {
|
|
47
|
-
const wrapper = mount(/*#__PURE__*/_jsx(WidgetGrid, {
|
|
48
|
-
components: components
|
|
49
|
-
}));
|
|
50
|
-
expect(wrapper).toMatchSnapshot();
|
|
51
|
-
expect(wrapper.find(Image).length).toEqual(0);
|
|
52
|
-
});
|
|
53
|
-
});
|
|
@@ -1,234 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { mount } from 'enzyme';
|
|
3
|
-
import { ThemeResourcesProvider } from '@shopgate/engage/core/providers';
|
|
4
|
-
import Widgets from "./index";
|
|
5
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
6
|
-
jest.useFakeTimers();
|
|
7
|
-
jest.mock('@shopgate/pwa-common/context', () => ({
|
|
8
|
-
ThemeContext: {
|
|
9
|
-
Provider: ({
|
|
10
|
-
children
|
|
11
|
-
}) => children
|
|
12
|
-
}
|
|
13
|
-
}));
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* A mock Image component.
|
|
17
|
-
* @returns {JSX}
|
|
18
|
-
*/
|
|
19
|
-
const Image = () => /*#__PURE__*/_jsx("img", {
|
|
20
|
-
alt: ""
|
|
21
|
-
});
|
|
22
|
-
/* eslint-disable react/prop-types */
|
|
23
|
-
/**
|
|
24
|
-
* A mock WidgetGrid component.
|
|
25
|
-
* @param {Array} children Array of children.
|
|
26
|
-
* @returns {JSX}
|
|
27
|
-
*/
|
|
28
|
-
const WidgetGrid = ({
|
|
29
|
-
children
|
|
30
|
-
}) => /*#__PURE__*/_jsx("div", {
|
|
31
|
-
className: "widget-grid",
|
|
32
|
-
children: children
|
|
33
|
-
});
|
|
34
|
-
/* eslint-enable react/prop-types */
|
|
35
|
-
|
|
36
|
-
const components = {
|
|
37
|
-
v1: {
|
|
38
|
-
'@shopgate/commerce-widgets/image': Image,
|
|
39
|
-
'@shopgate/commerce-widgets/widget-grid': WidgetGrid
|
|
40
|
-
}
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* @param {Object[]} widgets Widgets to be rendered.
|
|
45
|
-
* @returns {JSX.Element}
|
|
46
|
-
*/
|
|
47
|
-
const createWrapper = widgets => mount(/*#__PURE__*/_jsx(ThemeResourcesProvider, {
|
|
48
|
-
widgets: components,
|
|
49
|
-
components: {},
|
|
50
|
-
children: /*#__PURE__*/_jsx(Widgets, {
|
|
51
|
-
widgets: widgets
|
|
52
|
-
})
|
|
53
|
-
}));
|
|
54
|
-
describe('<Widgets />', () => {
|
|
55
|
-
it('should render a grid if height is defined', () => {
|
|
56
|
-
const widgets = [{
|
|
57
|
-
col: 0,
|
|
58
|
-
row: 0,
|
|
59
|
-
width: 12,
|
|
60
|
-
height: 3,
|
|
61
|
-
settings: {
|
|
62
|
-
id: 83535,
|
|
63
|
-
image: 'https://data.shopgate.com/shop_widget_images/23836/92204c0f264ac30d6836994c2fb64eb1.min.jpeg'
|
|
64
|
-
},
|
|
65
|
-
type: '@shopgate/commerce-widgets/image'
|
|
66
|
-
}];
|
|
67
|
-
const wrapper = createWrapper(widgets);
|
|
68
|
-
expect(wrapper.find('WidgetGrid').exists()).toBe(true);
|
|
69
|
-
});
|
|
70
|
-
it('should not wrap a widget which is not a grid and has no height', () => {
|
|
71
|
-
const widgets = [{
|
|
72
|
-
col: 0,
|
|
73
|
-
row: 0,
|
|
74
|
-
width: 12,
|
|
75
|
-
settings: {
|
|
76
|
-
id: 83535,
|
|
77
|
-
image: 'https://data.shopgate.com/shop_widget_images/23836/92204c0f264ac30d6836994c2fb64eb1.min.jpeg'
|
|
78
|
-
},
|
|
79
|
-
type: '@shopgate/commerce-widgets/image'
|
|
80
|
-
}];
|
|
81
|
-
const wrapper = createWrapper(widgets);
|
|
82
|
-
expect(wrapper).toMatchSnapshot();
|
|
83
|
-
expect(wrapper.find('WidgetGrid').exists()).toBe(false);
|
|
84
|
-
});
|
|
85
|
-
it('should render a grid if the widget is of type grid', () => {
|
|
86
|
-
const widgets = [{
|
|
87
|
-
type: '@shopgate/commerce-widgets/widget-grid',
|
|
88
|
-
settings: {
|
|
89
|
-
widgets: [{
|
|
90
|
-
col: 0,
|
|
91
|
-
row: 0,
|
|
92
|
-
width: 12,
|
|
93
|
-
height: 5,
|
|
94
|
-
settings: {
|
|
95
|
-
id: '84961',
|
|
96
|
-
alt: '',
|
|
97
|
-
image: 'https://data.shopgate.com/shop_widget_images/23836/aedc545959f55e3f73851eca0ed40a75.min.jpeg',
|
|
98
|
-
link: '/category/'
|
|
99
|
-
},
|
|
100
|
-
type: '@shopgate/commerce-widgets/image'
|
|
101
|
-
}]
|
|
102
|
-
}
|
|
103
|
-
}];
|
|
104
|
-
const wrapper = createWrapper(widgets);
|
|
105
|
-
expect(wrapper).toMatchSnapshot();
|
|
106
|
-
expect(wrapper.find('WidgetGrid').exists()).toBe(true);
|
|
107
|
-
});
|
|
108
|
-
it('should render only one widget when the second one is not published and third one is invalid', () => {
|
|
109
|
-
const widgets = [{
|
|
110
|
-
col: 0,
|
|
111
|
-
row: 0,
|
|
112
|
-
width: 12,
|
|
113
|
-
settings: {
|
|
114
|
-
id: 835351,
|
|
115
|
-
image: 'https://data.shopgate.com/shop_widget_images/23836/92204c0f264ac30d6836994c2fb64eb1.min.jpeg'
|
|
116
|
-
},
|
|
117
|
-
type: '@shopgate/commerce-widgets/image'
|
|
118
|
-
}, {
|
|
119
|
-
col: 0,
|
|
120
|
-
row: 0,
|
|
121
|
-
width: 12,
|
|
122
|
-
settings: {
|
|
123
|
-
id: 835352,
|
|
124
|
-
image: 'https://data.shopgate.com/shop_widget_images/23836/92204c0f264ac30d6836994c2fb64eb1.min.jpeg'
|
|
125
|
-
},
|
|
126
|
-
type: '@shopgate/commerce-widgets/imagefoo'
|
|
127
|
-
}, {
|
|
128
|
-
col: 0,
|
|
129
|
-
row: 0,
|
|
130
|
-
width: 12,
|
|
131
|
-
settings: {
|
|
132
|
-
published: false,
|
|
133
|
-
id: 835353,
|
|
134
|
-
image: 'https://data.shopgate.com/shop_widget_images/23836/92204c0f264ac30d6836994c2fb64eb1.min.jpeg'
|
|
135
|
-
},
|
|
136
|
-
type: '@shopgate/commerce-widgets/image'
|
|
137
|
-
}];
|
|
138
|
-
const wrapper = createWrapper(widgets);
|
|
139
|
-
expect(wrapper).toMatchSnapshot();
|
|
140
|
-
expect(wrapper.find('img').length).toBe(1);
|
|
141
|
-
});
|
|
142
|
-
it('should schedule a re-render when widget is scheduled', () => {
|
|
143
|
-
// Use a fixed point in time so "next full hour" is deterministic.
|
|
144
|
-
// Pick a time that's not exactly on the hour.
|
|
145
|
-
const base = new Date('2023-01-01T10:37:00.000Z');
|
|
146
|
-
jest.setSystemTime(base);
|
|
147
|
-
const minutesToNextFullHour = 60 - base.getMinutes(); // 23
|
|
148
|
-
const msToNextFullHour = minutesToNextFullHour * 60000; // 23 * 60_000
|
|
149
|
-
|
|
150
|
-
const scheduledFromMs = Date.now() + msToNextFullHour - 1;
|
|
151
|
-
const scheduledToMs = Date.now() + minutesToNextFullHour + 1000;
|
|
152
|
-
const widgets = [{
|
|
153
|
-
col: 0,
|
|
154
|
-
row: 0,
|
|
155
|
-
width: 12,
|
|
156
|
-
settings: {
|
|
157
|
-
id: 835351,
|
|
158
|
-
image: 'https://data.shopgate.com/shop_widget_images/23836/92204c0f264ac30d6836994c2fb64eb1.min.jpeg',
|
|
159
|
-
published: true,
|
|
160
|
-
plan: true,
|
|
161
|
-
planDate: {
|
|
162
|
-
valid_from: new Date(scheduledFromMs).toISOString(),
|
|
163
|
-
valid_to: new Date(scheduledToMs).toISOString()
|
|
164
|
-
}
|
|
165
|
-
},
|
|
166
|
-
type: '@shopgate/commerce-widgets/image'
|
|
167
|
-
}];
|
|
168
|
-
const wrapper = createWrapper(widgets);
|
|
169
|
-
const instance = wrapper.find('Widgets').instance();
|
|
170
|
-
const clearSpy = jest.spyOn(global, 'clearTimeout');
|
|
171
|
-
instance.forceUpdate = jest.fn();
|
|
172
|
-
|
|
173
|
-
// Before the schedule hits, the image should not render yet.
|
|
174
|
-
expect(wrapper.find(Image).exists()).toBe(false);
|
|
175
|
-
|
|
176
|
-
// 1) Advance to the next full hour -> first forced update.
|
|
177
|
-
jest.advanceTimersByTime(msToNextFullHour);
|
|
178
|
-
expect(instance.forceUpdate).toHaveBeenCalledTimes(1);
|
|
179
|
-
|
|
180
|
-
// 2) The component should schedule the next tick for +60 min.
|
|
181
|
-
jest.advanceTimersByTime(60 * 60000);
|
|
182
|
-
expect(instance.forceUpdate).toHaveBeenCalledTimes(2);
|
|
183
|
-
|
|
184
|
-
// Unmount triggers cleanup of any pending timeouts.
|
|
185
|
-
wrapper.unmount();
|
|
186
|
-
expect(clearSpy).toHaveBeenCalled();
|
|
187
|
-
clearSpy.mockRestore();
|
|
188
|
-
});
|
|
189
|
-
it('should render only wrapper when widgets array is empty', () => {
|
|
190
|
-
const widgets = [];
|
|
191
|
-
const wrapper = createWrapper(widgets);
|
|
192
|
-
expect(wrapper.find('Image').exists()).toBe(false);
|
|
193
|
-
});
|
|
194
|
-
it('should render null when no widgets are passed', () => {
|
|
195
|
-
const wrapper = createWrapper(undefined);
|
|
196
|
-
expect(wrapper.find('Widgets').html()).toBe(null);
|
|
197
|
-
});
|
|
198
|
-
it('should check settings of child widgets inside widget-grid', () => {
|
|
199
|
-
const widgets = [{
|
|
200
|
-
height: 2,
|
|
201
|
-
id: 'index-5-@shopgate/commerce-widgets/widget-grid',
|
|
202
|
-
type: '@shopgate/commerce-widgets/widget-grid',
|
|
203
|
-
settings: {
|
|
204
|
-
widgets: [{
|
|
205
|
-
col: 0,
|
|
206
|
-
row: 0,
|
|
207
|
-
height: 2,
|
|
208
|
-
width: 2,
|
|
209
|
-
settings: {
|
|
210
|
-
id: 835351,
|
|
211
|
-
image: 'https://data.shopgate.com/shop_widget_images/23836/92204c0f264ac30d6836994c2fb64eb1.min.jpeg',
|
|
212
|
-
published: true,
|
|
213
|
-
plan: false
|
|
214
|
-
},
|
|
215
|
-
type: '@shopgate/commerce-widgets/image'
|
|
216
|
-
}, {
|
|
217
|
-
col: 2,
|
|
218
|
-
row: 0,
|
|
219
|
-
height: 2,
|
|
220
|
-
width: 2,
|
|
221
|
-
settings: {
|
|
222
|
-
id: 835352,
|
|
223
|
-
image: 'https://data.shopgate.com/shop_widget_images/23836/92204c0f264ac30d6836994c2fb64eb1.min.jpeg',
|
|
224
|
-
published: false,
|
|
225
|
-
plan: false
|
|
226
|
-
},
|
|
227
|
-
type: '@shopgate/commerce-widgets/image'
|
|
228
|
-
}]
|
|
229
|
-
}
|
|
230
|
-
}];
|
|
231
|
-
const wrapper = createWrapper(widgets);
|
|
232
|
-
expect(wrapper.find('img').length).toBe(1);
|
|
233
|
-
});
|
|
234
|
-
});
|