@pie-lib/render-ui 4.15.10-next.1 → 4.16.0-beta.1

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.
Files changed (54) hide show
  1. package/CHANGELOG.md +20 -52
  2. package/NEXT.CHANGELOG.json +1 -0
  3. package/lib/append-css-rules.js +88 -0
  4. package/lib/append-css-rules.js.map +1 -0
  5. package/lib/assets/enableAudioAutoplayImage.js +9 -0
  6. package/lib/assets/enableAudioAutoplayImage.js.map +1 -0
  7. package/lib/collapsible/index.js +2 -1
  8. package/lib/collapsible/index.js.map +1 -1
  9. package/lib/color.js +123 -2
  10. package/lib/color.js.map +1 -1
  11. package/lib/feedback.js +0 -1
  12. package/lib/feedback.js.map +1 -1
  13. package/lib/has-media.js +27 -0
  14. package/lib/has-media.js.map +1 -0
  15. package/lib/has-text.js +5 -1
  16. package/lib/has-text.js.map +1 -1
  17. package/lib/index.js +32 -0
  18. package/lib/index.js.map +1 -1
  19. package/lib/preview-layout.js +16 -4
  20. package/lib/preview-layout.js.map +1 -1
  21. package/lib/preview-prompt.js +156 -41
  22. package/lib/preview-prompt.js.map +1 -1
  23. package/lib/ui-layout.js +122 -0
  24. package/lib/ui-layout.js.map +1 -0
  25. package/package.json +6 -4
  26. package/src/__tests__/__snapshots__/html-and-math.test.js.snap +11 -0
  27. package/src/__tests__/__snapshots__/preview-prompt.test.jsx.snap +37 -0
  28. package/src/__tests__/__snapshots__/purpose.test.jsx.snap +42 -0
  29. package/src/__tests__/__snapshots__/readable.test.jsx.snap +64 -0
  30. package/src/__tests__/__snapshots__/response-indicators.test.jsx.snap +95 -0
  31. package/src/__tests__/color.test.js +12 -0
  32. package/src/__tests__/has-media.test.js +20 -0
  33. package/src/__tests__/has-text.test.js +21 -0
  34. package/src/__tests__/html-and-math.test.js +46 -0
  35. package/src/__tests__/preview-prompt.test.jsx +56 -0
  36. package/src/__tests__/purpose.test.jsx +47 -0
  37. package/src/__tests__/readable.test.jsx +64 -0
  38. package/src/__tests__/response-indicators.test.jsx +16 -0
  39. package/src/__tests__/ui-layout.test.jsx +34 -0
  40. package/src/__tests__/withUndoReset.test.jsx +254 -0
  41. package/src/append-css-rules.js +51 -0
  42. package/src/assets/enableAudioAutoplayImage.js +1 -0
  43. package/src/collapsible/__tests__/__snapshots__/index.test.jsx.snap +18 -0
  44. package/src/collapsible/__tests__/index.test.jsx +13 -0
  45. package/src/collapsible/index.jsx +1 -0
  46. package/src/color.js +40 -0
  47. package/src/feedback.jsx +0 -1
  48. package/src/has-media.js +16 -0
  49. package/src/has-text.js +5 -1
  50. package/src/index.js +8 -0
  51. package/src/preview-layout.jsx +14 -3
  52. package/src/preview-prompt.jsx +150 -26
  53. package/src/ui-layout.jsx +66 -0
  54. package/README.md +0 -33
@@ -0,0 +1,95 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`response-indicators snapshot - no feedback 1`] = `
4
+ <div>
5
+ <span
6
+ onClick={[Function]}
7
+ >
8
+ <div
9
+ style={
10
+ Object {
11
+ "display": "inline-block",
12
+ "height": "30px",
13
+ "position": "relative",
14
+ "width": "30px",
15
+ }
16
+ }
17
+ >
18
+ <svg
19
+ preserveAspectRatio="xMinYMin meet"
20
+ style={
21
+ Object {
22
+ "enableBackground": "new 0 0 44 40",
23
+ }
24
+ }
25
+ version="1.1"
26
+ viewBox="0 0 44 40"
27
+ x="0px"
28
+ y="0px"
29
+ >
30
+
31
+ <circle
32
+ className="IconBase-bg-5"
33
+ cx="23"
34
+ cy="20.4"
35
+ r="16"
36
+ transform="translate(-3, 0)"
37
+ />
38
+ <polygon
39
+ className="IconBase-fg-6"
40
+ points="19.1,28.6 11.8,22.3 14.4,19.2 17.9,22.1 23.9,11.4 27.5,13.4"
41
+ transform="translate(0, 0)"
42
+ />
43
+ </svg>
44
+ </div>
45
+ </span>
46
+ </div>
47
+ `;
48
+
49
+ exports[`response-indicators snapshot - with feedback 1`] = `
50
+ <div
51
+ className="RawIndicator-responseIndicator-1"
52
+ >
53
+ <span
54
+ onClick={[Function]}
55
+ >
56
+ <div
57
+ style={
58
+ Object {
59
+ "display": "inline-block",
60
+ "height": "30px",
61
+ "position": "relative",
62
+ "width": "30px",
63
+ }
64
+ }
65
+ >
66
+ <svg
67
+ preserveAspectRatio="xMinYMin meet"
68
+ style={
69
+ Object {
70
+ "enableBackground": "new 0 0 44 40",
71
+ }
72
+ }
73
+ version="1.1"
74
+ viewBox="0 0 44 40"
75
+ x="0px"
76
+ y="0px"
77
+ >
78
+
79
+ <circle
80
+ className="IconBase-bg-5"
81
+ cx="23"
82
+ cy="20.4"
83
+ r="16"
84
+ transform="translate(-3, 0)"
85
+ />
86
+ <polygon
87
+ className="IconBase-fg-6"
88
+ points="19.1,28.6 11.8,22.3 14.4,19.2 17.9,22.1 23.9,11.4 27.5,13.4"
89
+ transform="translate(0, 0)"
90
+ />
91
+ </svg>
92
+ </div>
93
+ </span>
94
+ </div>
95
+ `;
@@ -0,0 +1,12 @@
1
+ import { v } from '../color';
2
+ describe('v', () => {
3
+ it.each`
4
+ args | expected
5
+ ${['text', 'black']} | ${'var(--pie-text, black)'}
6
+ ${['primary-text', 'text', 'black']} | ${'var(--pie-primary-text, var(--pie-text, black))'}
7
+ ${['black']} | ${'black'}
8
+ ${['#00ff00']} | ${'#00ff00'}
9
+ `('$args => $expected', ({ args, expected }) => {
10
+ expect(v('pie')(...args)).toEqual(expected);
11
+ });
12
+ });
@@ -0,0 +1,20 @@
1
+ import * as React from 'react';
2
+ import { hasMedia } from '../has-media'; // Assuming you have a hasMedia function
3
+
4
+ describe('hasMedia', () => {
5
+ it.each`
6
+ input | expected
7
+ ${'<img src="image.jpg" />'} | ${true}
8
+ ${'<audio src="audio.mp3" />'} | ${true}
9
+ ${'<div><img src="image.jpg" /></div>'} | ${true}
10
+ ${'<div><audio src="audio.mp3" /></div>'} | ${true}
11
+ ${'<div>No media here</div>'} | ${false}
12
+ ${'<div></div>'} | ${false}
13
+ ${' '} | ${false}
14
+ ${null} | ${false}
15
+ `('$input -> $expected', ({ input, expected }) => {
16
+ const output = hasMedia(input);
17
+
18
+ expect(output).toEqual(expected);
19
+ });
20
+ });
@@ -0,0 +1,21 @@
1
+ import * as React from 'react';
2
+ import { hasText } from '../has-text';
3
+
4
+ describe('has-text', () => {
5
+ it.each`
6
+ input | expected
7
+ ${'<div>Rationale</div>'} | ${true}
8
+ ${'Rationale'} | ${true}
9
+ ${'<div>hi</div>'} | ${true}
10
+ ${'<div>hi'} | ${true}
11
+ ${'<div></div>'} | ${false}
12
+ ${'<div> </div>'} | ${false}
13
+ ${'<div><br /> </div>'} | ${false}
14
+ ${' '} | ${false}
15
+ ${null} | ${false}
16
+ `('$input -> $expected', ({ input, expected }) => {
17
+ const output = hasText(input);
18
+
19
+ expect(output).toEqual(expected);
20
+ });
21
+ });
@@ -0,0 +1,46 @@
1
+ import HtmlAndMath from '../html-and-math';
2
+ import { shallow } from 'enzyme';
3
+ import React from 'react';
4
+ import { renderMath } from '@pie-lib/math-rendering';
5
+
6
+ jest.mock('@pie-lib/math-rendering', () => ({ renderMath: jest.fn() }));
7
+
8
+ describe('html-and-math', () => {
9
+ const mkWrapper = (extras) => {
10
+ const props = {
11
+ html: '<p>hi</p>',
12
+ ...extras,
13
+ };
14
+
15
+ return shallow(<HtmlAndMath {...props} />, {
16
+ disableLifecycleMethods: true,
17
+ });
18
+ };
19
+
20
+ describe('render', () => {
21
+ it('renders', () => {
22
+ const w = mkWrapper();
23
+
24
+ expect(w).toMatchSnapshot();
25
+ });
26
+ });
27
+
28
+ describe('componentDidMount', () => {
29
+ it('calls renderMath', () => {
30
+ const w = mkWrapper();
31
+ //mock the ref
32
+ w.instance().node = { node: true };
33
+ w.instance().componentDidMount();
34
+ expect(renderMath).toHaveBeenCalled();
35
+ });
36
+ });
37
+ describe('componentDidUpdate', () => {
38
+ it('calls renderMath', () => {
39
+ const w = mkWrapper();
40
+ //mock the ref
41
+ w.instance().node = { node: true };
42
+ w.instance().componentDidUpdate();
43
+ expect(renderMath).toHaveBeenCalled();
44
+ });
45
+ });
46
+ });
@@ -0,0 +1,56 @@
1
+ import React from 'react';
2
+ import { shallow } from 'enzyme';
3
+ import PreviewPrompt from '../preview-prompt';
4
+
5
+ describe('Prompt without Custom tag ', () => {
6
+ let wrapper;
7
+ let mkWrapper = (opts) => {
8
+ opts = {
9
+ classes: {},
10
+ prompt:
11
+ 'Which of these northern European countries are EU members? <math><mstack><msrow><mn>111</mn></msrow><msline/></mstack></math>',
12
+ tagName: '',
13
+ className: '',
14
+ ...opts,
15
+ };
16
+
17
+ return shallow(<PreviewPrompt {...opts} />);
18
+ };
19
+
20
+ beforeEach(() => {
21
+ wrapper = mkWrapper();
22
+ });
23
+
24
+ describe('default class with markup', () => {
25
+ it('renders', () => {
26
+ expect(wrapper.hasClass('prompt')).toEqual(false);
27
+ expect(wrapper).toMatchSnapshot();
28
+ });
29
+ });
30
+ });
31
+
32
+ describe('Prompt with Custom tag ', () => {
33
+ let wrapper;
34
+ let mkWrapper = (opts) => {
35
+ opts = {
36
+ classes: {},
37
+ prompt:
38
+ 'Which of these northern European countries are EU members? <math><mstack><msrow><mn>111</mn></msrow><msline/></mstack></math>',
39
+ tagName: '',
40
+ className: '',
41
+ ...opts,
42
+ };
43
+ return shallow(<PreviewPrompt {...opts} />);
44
+ };
45
+
46
+ beforeEach(() => {
47
+ wrapper = mkWrapper({ tagName: 'span', className: 'prompt' });
48
+ });
49
+
50
+ describe('renders with custom tag "span" correctly', () => {
51
+ it('renders', () => {
52
+ expect(wrapper.hasClass('prompt')).toEqual(true);
53
+ expect(wrapper).toMatchSnapshot();
54
+ });
55
+ });
56
+ });
@@ -0,0 +1,47 @@
1
+ import React from 'react';
2
+ import { mount } from 'enzyme';
3
+ import Purpose from '../purpose';
4
+
5
+ describe('Purpose', () => {
6
+ let wrapper;
7
+
8
+ describe('renders fine', () => {
9
+ it('renders child unaltered without purpose prop', () => {
10
+ wrapper = mount(
11
+ <Purpose>
12
+ <div>text</div>
13
+ </Purpose>,
14
+ );
15
+ expect(wrapper.find('div')).toHaveLength(1);
16
+ expect(wrapper.html().includes('data-pie-purpose=""')).toEqual(false);
17
+ expect(wrapper.html().includes('text')).toEqual(true);
18
+ expect(wrapper).toMatchSnapshot();
19
+ });
20
+ it('renders child unaltered', () => {
21
+ wrapper = mount(
22
+ <Purpose purpose="passage">
23
+ <div>text</div>
24
+ </Purpose>,
25
+ );
26
+ expect(wrapper.find('div')).toHaveLength(1);
27
+ expect(wrapper.html().includes('data-pie-purpose="passage"')).toEqual(true);
28
+ expect(wrapper.html().includes('text')).toEqual(true);
29
+ expect(wrapper).toMatchSnapshot();
30
+ });
31
+ it('renders children unaltered', () => {
32
+ wrapper = mount(
33
+ <Purpose purpose="something">
34
+ <div>
35
+ <div>text1</div>
36
+ <div>text2</div>
37
+ </div>
38
+ </Purpose>,
39
+ );
40
+ expect(wrapper.find('div')).toHaveLength(3);
41
+ expect(wrapper.html().includes('data-pie-purpose="something"')).toEqual(true);
42
+ expect(wrapper.html().includes('text1')).toEqual(true);
43
+ expect(wrapper.html().includes('text3')).toEqual(false);
44
+ expect(wrapper).toMatchSnapshot();
45
+ });
46
+ });
47
+ });
@@ -0,0 +1,64 @@
1
+ import React from 'react';
2
+ import { mount } from 'enzyme';
3
+ import Readable from '../readable';
4
+
5
+ describe('Readable', () => {
6
+ let wrapper;
7
+
8
+ describe('renders fine', () => {
9
+ it('renders child unaltered', () => {
10
+ wrapper = mount(
11
+ <Readable>
12
+ <div>text</div>
13
+ </Readable>,
14
+ );
15
+ expect(wrapper.find('div')).toHaveLength(1);
16
+ expect(wrapper.html().includes('data-pie-readable="true"')).toEqual(true);
17
+ expect(wrapper.html().includes('text')).toEqual(true);
18
+ expect(wrapper).toMatchSnapshot();
19
+ });
20
+ it('renders children unaltered', () => {
21
+ wrapper = mount(
22
+ <Readable>
23
+ <div>
24
+ <div>text1</div>
25
+ <div>text2</div>
26
+ </div>
27
+ </Readable>,
28
+ );
29
+ expect(wrapper.find('div')).toHaveLength(3);
30
+ expect(wrapper.html().includes('data-pie-readable="true"')).toEqual(true);
31
+ expect(wrapper.html().includes('text1')).toEqual(true);
32
+ expect(wrapper.html().includes('text3')).toEqual(false);
33
+ expect(wrapper).toMatchSnapshot();
34
+ });
35
+ it('renders with false tag', () => {
36
+ wrapper = mount(
37
+ <Readable false>
38
+ <div>
39
+ <div>text1</div>
40
+ <div>text2</div>
41
+ </div>
42
+ </Readable>,
43
+ );
44
+ expect(wrapper.find('div')).toHaveLength(3);
45
+ expect(wrapper.html().includes('data-pie-readable="false"')).toEqual(true);
46
+ expect(wrapper.html().includes('text1')).toEqual(true);
47
+ expect(wrapper.html().includes('text3')).toEqual(false);
48
+ expect(wrapper).toMatchSnapshot();
49
+ });
50
+ it('renders even with specific true tag', () => {
51
+ wrapper = mount(
52
+ <Readable false={true}>
53
+ <div>
54
+ <div>text1</div>
55
+ <div>text2</div>
56
+ </div>
57
+ </Readable>,
58
+ );
59
+ expect(wrapper.find('div')).toHaveLength(3);
60
+ expect(wrapper.html().includes('data-pie-readable="false"')).toEqual(true);
61
+ expect(wrapper).toMatchSnapshot();
62
+ });
63
+ });
64
+ });
@@ -0,0 +1,16 @@
1
+ import React from 'react';
2
+ import debug from 'debug';
3
+ import renderer from 'react-test-renderer';
4
+ import { Correct } from '../response-indicators';
5
+
6
+ describe('response-indicators', () => {
7
+ it('snapshot - no feedback ', () => {
8
+ const tree = renderer.create(<Correct />).toJSON();
9
+ expect(tree).toMatchSnapshot();
10
+ });
11
+
12
+ it('snapshot - with feedback ', () => {
13
+ const tree = renderer.create(<Correct feedback="hi" />).toJSON();
14
+ expect(tree).toMatchSnapshot();
15
+ });
16
+ });
@@ -0,0 +1,34 @@
1
+ import React from 'react';
2
+ import { mount, shallow } from 'enzyme';
3
+ import { UiLayout } from '../index';
4
+
5
+ describe('UiLayout', () => {
6
+ let wrapper;
7
+ const mockClasses = { extraCSSRules: 'extra-class' };
8
+ const fontSizeFactor = 1.5;
9
+
10
+ // Mock `getComputedStyle` to return a specific root font size.
11
+ jest.spyOn(window, 'getComputedStyle').mockImplementation(() => ({
12
+ fontSize: '16px', // Default font size for root
13
+ }));
14
+
15
+ wrapper = mount(<UiLayout classes={mockClasses} fontSizeFactor={fontSizeFactor} />);
16
+
17
+ it('renders correctly', () => {
18
+ expect(wrapper.exists()).toBe(true);
19
+ });
20
+
21
+ it('applies the correct classes', () => {
22
+ const div = wrapper.find('.extra-class');
23
+ expect(div.exists()).toBe(true);
24
+ });
25
+
26
+ it('computes style correctly based on fontSizeFactor', () => {
27
+ const div = wrapper.find('.extra-class');
28
+
29
+ // Get the style property of the rendered div
30
+ const computedStyle = div.getDOMNode().style;
31
+ // Assert the computed font size
32
+ expect(computedStyle.fontSize).toBe('24px');
33
+ });
34
+ });
@@ -0,0 +1,254 @@
1
+ import * as React from 'react';
2
+ import withUndoReset from '../withUndoReset';
3
+ import { mount, shallow } from 'enzyme';
4
+ import { shallowChild } from '@pie-lib/test-utils';
5
+
6
+ describe('withUndoReset', () => {
7
+ let wrapper;
8
+ let defaultProps;
9
+ const WrappedClass = class WrappedComponent extends React.Component {
10
+ onSessionChange = (session) => {
11
+ this.props.onSessionChange(session);
12
+ };
13
+
14
+ onAddItem = (item) => {
15
+ this.onSessionChange({
16
+ ...this.props.session,
17
+ items: this.props.session.items.concat(item),
18
+ });
19
+ };
20
+
21
+ onRemoveLastItem = () => {
22
+ const newItems = [...this.props.session.items];
23
+
24
+ newItems.pop();
25
+
26
+ this.onSessionChange({
27
+ ...this.props.session,
28
+ items: newItems,
29
+ });
30
+ };
31
+
32
+ render() {
33
+ const { session } = this.props;
34
+ const items = session.items || {};
35
+
36
+ return (
37
+ <div>
38
+ {items.map((item) => (
39
+ <span key={item.id}>{item.id}</span>
40
+ ))}
41
+ </div>
42
+ );
43
+ }
44
+ };
45
+
46
+ const Component = withUndoReset(WrappedClass);
47
+
48
+ describe('retains internal component functionality', () => {
49
+ beforeEach(() => {
50
+ defaultProps = {
51
+ session: {
52
+ items: [],
53
+ },
54
+ onSessionChange: jest.fn(),
55
+ };
56
+ });
57
+
58
+ it('moves past HoC and returns the rendered component using enzyme', () => {
59
+ wrapper = mount(<Component {...defaultProps} />);
60
+ expect(wrapper.find(WrappedClass).length).toEqual(1);
61
+ expect(wrapper.find(WrappedClass).props()).toEqual(
62
+ expect.objectContaining({
63
+ session: { items: [] },
64
+ }),
65
+ );
66
+ });
67
+
68
+ it('contains the reset logic container', () => {
69
+ wrapper = mount(<Component {...defaultProps} />);
70
+ expect(wrapper.html().includes('Start Over')).toEqual(true);
71
+ expect(wrapper.html().includes('Undo')).toEqual(true);
72
+ });
73
+
74
+ it('can interact with session', () => {
75
+ wrapper = mount(<Component {...defaultProps} />);
76
+
77
+ expect(wrapper.find('span').length).toEqual(2);
78
+
79
+ wrapper
80
+ .find(WrappedClass)
81
+ .instance()
82
+ .onAddItem({ id: 1 });
83
+
84
+ expect(
85
+ wrapper
86
+ .find(WrappedClass)
87
+ .html()
88
+ .includes('span'),
89
+ ).toEqual(true);
90
+
91
+ wrapper
92
+ .find(WrappedClass)
93
+ .instance()
94
+ .onRemoveLastItem();
95
+
96
+ expect(
97
+ wrapper
98
+ .find(WrappedClass)
99
+ .html()
100
+ .includes('span'),
101
+ ).toEqual(false);
102
+ });
103
+
104
+ it('can undo changes in the session', () => {
105
+ wrapper = shallowChild(Component, defaultProps, 1)();
106
+ const instance = wrapper.instance();
107
+
108
+ instance.onSessionChange({
109
+ items: [
110
+ {
111
+ id: 2,
112
+ },
113
+ ],
114
+ });
115
+
116
+ instance.onSessionChange({
117
+ items: [
118
+ {
119
+ id: 2,
120
+ },
121
+ {
122
+ id: 3,
123
+ },
124
+ ],
125
+ });
126
+
127
+ expect(wrapper.state().changes).toEqual([
128
+ {
129
+ items: [
130
+ {
131
+ id: 2,
132
+ },
133
+ ],
134
+ },
135
+ {
136
+ items: [
137
+ {
138
+ id: 2,
139
+ },
140
+ {
141
+ id: 3,
142
+ },
143
+ ],
144
+ },
145
+ ]);
146
+
147
+ expect(wrapper.state().session).toEqual({
148
+ items: [
149
+ {
150
+ id: 2,
151
+ },
152
+ {
153
+ id: 3,
154
+ },
155
+ ],
156
+ });
157
+
158
+ instance.onUndo();
159
+
160
+ expect(wrapper.state().changes).toEqual([
161
+ {
162
+ items: [
163
+ {
164
+ id: 2,
165
+ },
166
+ ],
167
+ },
168
+ ]);
169
+
170
+ expect(wrapper.state().session).toEqual({
171
+ items: [
172
+ {
173
+ id: 2,
174
+ },
175
+ ],
176
+ });
177
+
178
+ instance.onUndo();
179
+
180
+ expect(wrapper.state().changes).toEqual([]);
181
+
182
+ expect(wrapper.state().session).toEqual({
183
+ items: [],
184
+ });
185
+
186
+ expect(wrapper.find(WrappedClass).html()).toEqual('<div></div>');
187
+ });
188
+
189
+ it('can reset changes in the session', () => {
190
+ wrapper = shallowChild(Component, defaultProps, 1)();
191
+ const instance = wrapper.instance();
192
+
193
+ instance.onSessionChange({
194
+ items: [
195
+ {
196
+ id: 2,
197
+ },
198
+ ],
199
+ });
200
+
201
+ instance.onSessionChange({
202
+ items: [
203
+ {
204
+ id: 2,
205
+ },
206
+ {
207
+ id: 3,
208
+ },
209
+ ],
210
+ });
211
+
212
+ expect(wrapper.state().changes).toEqual([
213
+ {
214
+ items: [
215
+ {
216
+ id: 2,
217
+ },
218
+ ],
219
+ },
220
+ {
221
+ items: [
222
+ {
223
+ id: 2,
224
+ },
225
+ {
226
+ id: 3,
227
+ },
228
+ ],
229
+ },
230
+ ]);
231
+
232
+ expect(wrapper.state().session).toEqual({
233
+ items: [
234
+ {
235
+ id: 2,
236
+ },
237
+ {
238
+ id: 3,
239
+ },
240
+ ],
241
+ });
242
+
243
+ instance.onReset();
244
+
245
+ expect(wrapper.state().changes).toEqual([]);
246
+
247
+ expect(wrapper.state().session).toEqual({
248
+ items: [],
249
+ });
250
+
251
+ expect(wrapper.find(WrappedClass).html()).toEqual('<div></div>');
252
+ });
253
+ });
254
+ });