@pie-lib/render-ui 5.1.1-next.0 → 5.2.0-next.0
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/lib/assets/enableAudioAutoplayImage.js +0 -1
- package/lib/assets/enableAudioAutoplayImage.js.map +1 -1
- package/lib/collapsible/index.js +0 -3
- package/lib/collapsible/index.js.map +1 -1
- package/lib/color.js +0 -4
- package/lib/color.js.map +1 -1
- package/lib/feedback.js +0 -9
- package/lib/feedback.js.map +1 -1
- package/lib/has-media.js +0 -1
- package/lib/has-media.js.map +1 -1
- package/lib/has-text.js +0 -2
- package/lib/has-text.js.map +1 -1
- package/lib/html-and-math.js +0 -2
- package/lib/html-and-math.js.map +1 -1
- package/lib/index.js +0 -7
- package/lib/index.js.map +1 -1
- package/lib/input-container.js +0 -1
- package/lib/input-container.js.map +1 -1
- package/lib/preview-layout.js +0 -2
- package/lib/preview-layout.js.map +1 -1
- package/lib/preview-prompt.js +0 -26
- package/lib/preview-prompt.js.map +1 -1
- package/lib/purpose.js +0 -3
- package/lib/purpose.js.map +1 -1
- package/lib/readable.js +0 -3
- package/lib/readable.js.map +1 -1
- package/lib/response-indicators.js +0 -8
- package/lib/response-indicators.js.map +1 -1
- package/lib/ui-layout.js +0 -3
- package/lib/ui-layout.js.map +1 -1
- package/lib/withUndoReset.js +2 -14
- package/lib/withUndoReset.js.map +1 -1
- package/package.json +11 -7
- package/src/__tests__/color.test.js +248 -1
- package/src/__tests__/feedback.test.jsx +279 -0
- package/src/__tests__/has-media.test.js +0 -1
- package/src/__tests__/has-text.test.js +0 -1
- package/src/__tests__/input-container.test.jsx +328 -0
- package/src/__tests__/preview-layout.test.jsx +349 -0
- package/src/__tests__/preview-prompt.test.jsx +320 -0
- package/src/__tests__/response-indicators.test.jsx +1 -1
- package/src/__tests__/ui-layout.test.jsx +3 -1
- package/src/color.js +9 -7
- package/src/feedback.jsx +4 -14
- package/src/input-container.jsx +2 -5
- package/src/preview-layout.jsx +6 -1
- package/src/ui-layout.jsx +1 -2
- package/NEXT.CHANGELOG.json +0 -1
|
@@ -1,4 +1,50 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
background,
|
|
3
|
+
backgroundDark,
|
|
4
|
+
black,
|
|
5
|
+
blueGrey100,
|
|
6
|
+
blueGrey300,
|
|
7
|
+
blueGrey600,
|
|
8
|
+
blueGrey900,
|
|
9
|
+
border,
|
|
10
|
+
borderDark,
|
|
11
|
+
borderGray,
|
|
12
|
+
borderLight,
|
|
13
|
+
correct,
|
|
14
|
+
correctSecondary,
|
|
15
|
+
correctTertiary,
|
|
16
|
+
correctWithIcon,
|
|
17
|
+
defaults,
|
|
18
|
+
disabled,
|
|
19
|
+
disabledSecondary,
|
|
20
|
+
dropdownBackground,
|
|
21
|
+
fadedPrimary,
|
|
22
|
+
focusChecked,
|
|
23
|
+
focusCheckedBorder,
|
|
24
|
+
focusUnchecked,
|
|
25
|
+
focusUncheckedBorder,
|
|
26
|
+
incorrectSecondary,
|
|
27
|
+
incorrectWithIcon,
|
|
28
|
+
missing,
|
|
29
|
+
missingWithIcon,
|
|
30
|
+
primary,
|
|
31
|
+
primaryDark,
|
|
32
|
+
primaryLight,
|
|
33
|
+
primaryText,
|
|
34
|
+
secondary,
|
|
35
|
+
secondaryBackground,
|
|
36
|
+
secondaryDark,
|
|
37
|
+
secondaryLight,
|
|
38
|
+
secondaryText,
|
|
39
|
+
tertiary,
|
|
40
|
+
tertiaryLight,
|
|
41
|
+
text,
|
|
42
|
+
transparent,
|
|
43
|
+
v,
|
|
44
|
+
visualElementsColors,
|
|
45
|
+
white,
|
|
46
|
+
} from '../color';
|
|
47
|
+
|
|
2
48
|
describe('v', () => {
|
|
3
49
|
it.each`
|
|
4
50
|
args | expected
|
|
@@ -9,4 +55,205 @@ describe('v', () => {
|
|
|
9
55
|
`('$args => $expected', ({ args, expected }) => {
|
|
10
56
|
expect(v('pie')(...args)).toEqual(expected);
|
|
11
57
|
});
|
|
58
|
+
|
|
59
|
+
it('should create custom prefix CSS variables', () => {
|
|
60
|
+
const customPrefix = v('custom');
|
|
61
|
+
expect(customPrefix('color', '#fff')).toBe('var(--custom-color, #fff)');
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it('should handle multiple nested variables', () => {
|
|
65
|
+
const pv = v('pie');
|
|
66
|
+
expect(pv('a', 'b', 'c', 'd', 'fallback')).toBe('var(--pie-a, var(--pie-b, var(--pie-c, var(--pie-d, fallback))))');
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
describe('defaults', () => {
|
|
71
|
+
it('should be frozen and immutable', () => {
|
|
72
|
+
expect(Object.isFrozen(defaults)).toBe(true);
|
|
73
|
+
expect(() => {
|
|
74
|
+
defaults.TEXT = 'red';
|
|
75
|
+
}).toThrow();
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it('should contain expected color values', () => {
|
|
79
|
+
expect(defaults.TEXT).toBe('black');
|
|
80
|
+
expect(defaults.CORRECT).toBeDefined();
|
|
81
|
+
expect(defaults.PRIMARY).toBeDefined();
|
|
82
|
+
expect(defaults.TRANSPARENT).toBe('transparent');
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
describe('color functions', () => {
|
|
87
|
+
it('should return CSS variable string for text', () => {
|
|
88
|
+
expect(text()).toBe('var(--pie-text, black)');
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it('should return CSS variable string for correct', () => {
|
|
92
|
+
expect(correct()).toContain('var(--pie-correct,');
|
|
93
|
+
expect(correct()).toContain(defaults.CORRECT);
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it('should return CSS variable string for primary', () => {
|
|
97
|
+
expect(primary()).toContain('var(--pie-primary,');
|
|
98
|
+
expect(primary()).toContain(defaults.PRIMARY);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it('should return default value for transparent', () => {
|
|
102
|
+
expect(transparent()).toBe('transparent');
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it('should return nested CSS variables for primaryText', () => {
|
|
106
|
+
const result = primaryText();
|
|
107
|
+
expect(result).toContain('var(--pie-primary-text,');
|
|
108
|
+
expect(result).toContain('var(--pie-text,');
|
|
109
|
+
expect(result).toContain('black');
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it('should return CSS variable string for border', () => {
|
|
113
|
+
expect(border()).toContain('var(--pie-border,');
|
|
114
|
+
expect(border()).toContain(defaults.BORDER);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it('should return CSS variable string for blueGrey600', () => {
|
|
118
|
+
expect(blueGrey600()).toContain('var(--pie-blue-grey-600,');
|
|
119
|
+
expect(blueGrey600()).toContain(defaults.BLUE_GREY600);
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
describe('visualElementsColors', () => {
|
|
124
|
+
it('should contain expected charting colors', () => {
|
|
125
|
+
expect(visualElementsColors.AXIS_LINE_COLOR).toBe('#5A53C9');
|
|
126
|
+
expect(visualElementsColors.ROLLOVER_FILL_BAR_COLOR).toBe('#050F2D');
|
|
127
|
+
expect(visualElementsColors.GRIDLINES_COLOR).toBe('#8E88EA');
|
|
128
|
+
expect(visualElementsColors.PLOT_FILL_COLOR).toBe('#1463B3');
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it('should have all required properties', () => {
|
|
132
|
+
expect(visualElementsColors).toHaveProperty('AXIS_LINE_COLOR');
|
|
133
|
+
expect(visualElementsColors).toHaveProperty('ROLLOVER_FILL_BAR_COLOR');
|
|
134
|
+
expect(visualElementsColors).toHaveProperty('GRIDLINES_COLOR');
|
|
135
|
+
expect(visualElementsColors).toHaveProperty('PLOT_FILL_COLOR');
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
it('should be immutable', () => {
|
|
139
|
+
const original = { ...visualElementsColors };
|
|
140
|
+
expect(() => {
|
|
141
|
+
visualElementsColors.AXIS_LINE_COLOR = '#000000';
|
|
142
|
+
}).not.toThrow(); // Note: not frozen, but we document this is expected behavior
|
|
143
|
+
// Verify it didn't actually change (if frozen, it wouldn't)
|
|
144
|
+
expect(original.AXIS_LINE_COLOR).toBe('#5A53C9');
|
|
145
|
+
});
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
describe('additional color functions', () => {
|
|
149
|
+
it('should return correct values for disabled colors', () => {
|
|
150
|
+
expect(disabled()).toContain('var(--pie-disabled,');
|
|
151
|
+
expect(disabled()).toContain(defaults.DISABLED);
|
|
152
|
+
|
|
153
|
+
expect(disabledSecondary()).toContain('var(--pie-disabled-secondary,');
|
|
154
|
+
expect(disabledSecondary()).toContain(defaults.DISABLED_SECONDARY);
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
it('should return correct values for correct color variants', () => {
|
|
158
|
+
expect(correctSecondary()).toContain('var(--pie-correct-secondary,');
|
|
159
|
+
expect(correctTertiary()).toContain('var(--pie-correct-tertiary,');
|
|
160
|
+
expect(correctWithIcon()).toContain('var(--pie-correct-icon,');
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
it('should return correct values for incorrect color variants', () => {
|
|
164
|
+
expect(incorrectWithIcon()).toContain('var(--pie-incorrect-icon,');
|
|
165
|
+
expect(incorrectSecondary()).toContain('var(--pie-incorrect-secondary,');
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
it('should return correct values for missing color variants', () => {
|
|
169
|
+
expect(missing()).toContain('var(--pie-missing,');
|
|
170
|
+
expect(missingWithIcon()).toContain('var(--pie-missing-icon,');
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
it('should return correct values for primary color variants', () => {
|
|
174
|
+
expect(primaryLight()).toContain('var(--pie-primary-light,');
|
|
175
|
+
expect(primaryDark()).toContain('var(--pie-primary-dark,');
|
|
176
|
+
expect(fadedPrimary()).toContain('var(--pie-faded-primary,');
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
it('should return correct values for secondary color variants', () => {
|
|
180
|
+
expect(secondary()).toContain('var(--pie-secondary,');
|
|
181
|
+
expect(secondaryLight()).toContain('var(--pie-secondary-light,');
|
|
182
|
+
expect(secondaryDark()).toContain('var(--pie-secondary-dark,');
|
|
183
|
+
expect(secondaryText()).toContain('var(--pie-secondary-text,');
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
it('should return correct values for tertiary colors', () => {
|
|
187
|
+
expect(tertiary()).toContain('var(--pie-tertiary,');
|
|
188
|
+
expect(tertiaryLight()).toContain('var(--pie-tertiary-light,');
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
it('should return correct values for background colors', () => {
|
|
192
|
+
expect(background()).toContain('var(--pie-background,');
|
|
193
|
+
expect(backgroundDark()).toContain('var(--pie-background-dark,');
|
|
194
|
+
expect(secondaryBackground()).toContain('var(--pie-secondary-background,');
|
|
195
|
+
expect(dropdownBackground()).toContain('var(--pie-dropdown-background,');
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
it('should return correct values for border colors', () => {
|
|
199
|
+
expect(borderLight()).toContain('var(--pie-border-light,');
|
|
200
|
+
expect(borderDark()).toContain('var(--pie-border-dark,');
|
|
201
|
+
expect(borderGray()).toContain('var(--pie-border-gray,');
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
it('should return correct values for black and white', () => {
|
|
205
|
+
expect(black()).toContain('var(--pie-black,');
|
|
206
|
+
expect(black()).toContain(defaults.BLACK);
|
|
207
|
+
expect(white()).toContain('var(--pie-white,');
|
|
208
|
+
expect(white()).toContain(defaults.WHITE);
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
it('should return correct values for focus colors', () => {
|
|
212
|
+
expect(focusChecked()).toContain('var(--pie-focus-checked,');
|
|
213
|
+
expect(focusCheckedBorder()).toContain('var(--pie-focus-checked-border,');
|
|
214
|
+
expect(focusUnchecked()).toContain('var(--pie-focus-unchecked,');
|
|
215
|
+
expect(focusUncheckedBorder()).toContain('var(--pie-focus-unchecked-border,');
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
it('should return correct values for blue-grey colors', () => {
|
|
219
|
+
expect(blueGrey100()).toContain('var(--pie-blue-grey-100,');
|
|
220
|
+
expect(blueGrey300()).toContain('var(--pie-blue-grey-300,');
|
|
221
|
+
expect(blueGrey900()).toContain('var(--pie-blue-grey-900,');
|
|
222
|
+
});
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
describe('edge cases', () => {
|
|
226
|
+
it('should handle empty arguments for v function', () => {
|
|
227
|
+
const customV = v('test');
|
|
228
|
+
expect(customV('fallback')).toBe('fallback');
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
it('should handle single argument for v function', () => {
|
|
232
|
+
const customV = v('test');
|
|
233
|
+
expect(customV('color', 'red')).toBe('var(--test-color, red)');
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
it('should handle special characters in prefix', () => {
|
|
237
|
+
const specialV = v('my-custom-prefix');
|
|
238
|
+
expect(specialV('color', 'blue')).toBe('var(--my-custom-prefix-color, blue)');
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
it('should verify secondaryText nesting', () => {
|
|
242
|
+
const result = secondaryText();
|
|
243
|
+
expect(result).toContain('var(--pie-secondary-text,');
|
|
244
|
+
expect(result).toContain('var(--pie-text,');
|
|
245
|
+
expect(result).toContain('black');
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
it('should verify all defaults are strings', () => {
|
|
249
|
+
Object.values(defaults).forEach((value) => {
|
|
250
|
+
expect(typeof value).toBe('string');
|
|
251
|
+
});
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
it('should verify color hex format for specific defaults', () => {
|
|
255
|
+
expect(defaults.BLACK).toMatch(/^#[0-9A-Fa-f]{6}$/);
|
|
256
|
+
expect(defaults.WHITE).toMatch(/^#[0-9A-Fa-f]{6}$/);
|
|
257
|
+
expect(defaults.TERTIARY).toMatch(/^#[0-9A-Fa-f]{6}$/);
|
|
258
|
+
});
|
|
12
259
|
});
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { renderWithTheme, screen } from '@pie-lib/test-utils';
|
|
3
|
+
import { Feedback } from '../feedback';
|
|
4
|
+
|
|
5
|
+
describe('Feedback', () => {
|
|
6
|
+
describe('rendering', () => {
|
|
7
|
+
it('should render feedback when correctness and feedback are provided', () => {
|
|
8
|
+
renderWithTheme(<Feedback correctness="correct" feedback="Great job!" />);
|
|
9
|
+
expect(screen.getByText('Great job!')).toBeInTheDocument();
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
it('should not render feedback when correctness is missing', () => {
|
|
13
|
+
renderWithTheme(<Feedback feedback="Great job!" />);
|
|
14
|
+
expect(screen.queryByText('Great job!')).not.toBeInTheDocument();
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it('should not render feedback when feedback text is missing', () => {
|
|
18
|
+
renderWithTheme(<Feedback correctness="correct" />);
|
|
19
|
+
const { container } = renderWithTheme(<Feedback correctness="correct" />);
|
|
20
|
+
expect(container.querySelector('[class*="feedback"]')).not.toBeInTheDocument();
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it('should not render feedback when both correctness and feedback are missing', () => {
|
|
24
|
+
const { container } = renderWithTheme(<Feedback />);
|
|
25
|
+
expect(container.querySelector('[class*="FeedbackContent"]')).not.toBeInTheDocument();
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('should render feedback with HTML content', () => {
|
|
29
|
+
renderWithTheme(<Feedback correctness="correct" feedback="<strong>Excellent!</strong> You got it right." />);
|
|
30
|
+
expect(screen.getByText(/Excellent!/)).toBeInTheDocument();
|
|
31
|
+
expect(screen.getByText(/You got it right/)).toBeInTheDocument();
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
describe('correctness states', () => {
|
|
36
|
+
it('should render with correct class when correctness is "correct"', () => {
|
|
37
|
+
const { container } = renderWithTheme(<Feedback correctness="correct" feedback="Correct!" />);
|
|
38
|
+
const feedbackElement = container.querySelector('.correct');
|
|
39
|
+
expect(feedbackElement).toBeInTheDocument();
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('should render with incorrect class when correctness is "incorrect"', () => {
|
|
43
|
+
const { container } = renderWithTheme(<Feedback correctness="incorrect" feedback="Try again!" />);
|
|
44
|
+
const feedbackElement = container.querySelector('.incorrect');
|
|
45
|
+
expect(feedbackElement).toBeInTheDocument();
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('should render with partial class when correctness is "partial"', () => {
|
|
49
|
+
const { container } = renderWithTheme(<Feedback correctness="partial" feedback="Partially correct" />);
|
|
50
|
+
expect(screen.getByText('Partially correct')).toBeInTheDocument();
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it('should handle unknown correctness values', () => {
|
|
54
|
+
const { container } = renderWithTheme(<Feedback correctness="unknown" feedback="Unknown state" />);
|
|
55
|
+
expect(screen.getByText('Unknown state')).toBeInTheDocument();
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
describe('feedback content', () => {
|
|
60
|
+
it('should render simple text feedback', () => {
|
|
61
|
+
renderWithTheme(<Feedback correctness="correct" feedback="Well done!" />);
|
|
62
|
+
expect(screen.getByText('Well done!')).toBeInTheDocument();
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it('should render feedback with special characters', () => {
|
|
66
|
+
renderWithTheme(<Feedback correctness="incorrect" feedback="You selected 2 + 2 = 5. That's incorrect!" />);
|
|
67
|
+
expect(screen.getByText(/You selected 2 \+ 2 = 5/)).toBeInTheDocument();
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it('should render feedback with math markup', () => {
|
|
71
|
+
renderWithTheme(<Feedback correctness="correct" feedback="The answer is <math><mn>42</mn></math>" />);
|
|
72
|
+
expect(screen.getByText(/The answer is/)).toBeInTheDocument();
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it('should render feedback with multiple HTML elements', () => {
|
|
76
|
+
renderWithTheme(
|
|
77
|
+
<Feedback correctness="correct" feedback="<p>Great!</p><ul><li>Point 1</li><li>Point 2</li></ul>" />,
|
|
78
|
+
);
|
|
79
|
+
expect(screen.getByText(/Great!/)).toBeInTheDocument();
|
|
80
|
+
expect(screen.getByText(/Point 1/)).toBeInTheDocument();
|
|
81
|
+
expect(screen.getByText(/Point 2/)).toBeInTheDocument();
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('should handle empty string feedback', () => {
|
|
85
|
+
renderWithTheme(<Feedback correctness="correct" feedback="" />);
|
|
86
|
+
// Empty feedback should not render
|
|
87
|
+
const { container } = renderWithTheme(<Feedback correctness="correct" feedback="" />);
|
|
88
|
+
expect(container.querySelector('[class*="FeedbackContent"]')).not.toBeInTheDocument();
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it('should render feedback with line breaks', () => {
|
|
92
|
+
renderWithTheme(<Feedback correctness="incorrect" feedback="Line 1<br/>Line 2<br/>Line 3" />);
|
|
93
|
+
expect(screen.getByText(/Line 1/)).toBeInTheDocument();
|
|
94
|
+
expect(screen.getByText(/Line 2/)).toBeInTheDocument();
|
|
95
|
+
expect(screen.getByText(/Line 3/)).toBeInTheDocument();
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
describe('TransitionGroup integration', () => {
|
|
100
|
+
it('should use TransitionGroup for animations', () => {
|
|
101
|
+
const { container } = renderWithTheme(<Feedback correctness="correct" feedback="Animated feedback" />);
|
|
102
|
+
// TransitionGroup should be present
|
|
103
|
+
expect(container.querySelector('[class*="transition"]')).toBeDefined();
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it('should handle feedback changes', () => {
|
|
107
|
+
const { rerender } = renderWithTheme(<Feedback correctness="correct" feedback="Initial feedback" />);
|
|
108
|
+
expect(screen.getByText('Initial feedback')).toBeInTheDocument();
|
|
109
|
+
|
|
110
|
+
rerender(<Feedback correctness="incorrect" feedback="Updated feedback" />);
|
|
111
|
+
expect(screen.getByText('Updated feedback')).toBeInTheDocument();
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it('should handle feedback addition', () => {
|
|
115
|
+
const { rerender } = renderWithTheme(<Feedback />);
|
|
116
|
+
expect(screen.queryByText('New feedback')).not.toBeInTheDocument();
|
|
117
|
+
|
|
118
|
+
rerender(<Feedback correctness="correct" feedback="New feedback" />);
|
|
119
|
+
expect(screen.getByText('New feedback')).toBeInTheDocument();
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
describe('CSSTransition configuration', () => {
|
|
124
|
+
it('should render with CSSTransition wrapper', () => {
|
|
125
|
+
const { container } = renderWithTheme(<Feedback correctness="correct" feedback="Test feedback" />);
|
|
126
|
+
expect(container.firstChild).toBeInTheDocument();
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
it('should have nodeRef for CSSTransition', () => {
|
|
130
|
+
const feedback = new Feedback({ correctness: 'correct', feedback: 'Test' });
|
|
131
|
+
expect(feedback.nodeRef).toBeDefined();
|
|
132
|
+
expect(feedback.nodeRef.current).toBe(null);
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
describe('styling classes', () => {
|
|
137
|
+
it('should apply FeedbackContainer class', () => {
|
|
138
|
+
const { container } = renderWithTheme(<Feedback correctness="correct" feedback="Test" />);
|
|
139
|
+
expect(container.querySelector('[class*="Feedback"]')).toBeDefined();
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
it('should apply correct styling for correct feedback', () => {
|
|
143
|
+
const { container } = renderWithTheme(<Feedback correctness="correct" feedback="Correct answer!" />);
|
|
144
|
+
const correctElement = container.querySelector('.correct');
|
|
145
|
+
expect(correctElement).toBeInTheDocument();
|
|
146
|
+
expect(correctElement).toHaveTextContent('Correct answer!');
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
it('should apply incorrect styling for incorrect feedback', () => {
|
|
150
|
+
const { container } = renderWithTheme(<Feedback correctness="incorrect" feedback="Wrong answer" />);
|
|
151
|
+
const incorrectElement = container.querySelector('.incorrect');
|
|
152
|
+
expect(incorrectElement).toBeInTheDocument();
|
|
153
|
+
expect(incorrectElement).toHaveTextContent('Wrong answer');
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
describe('edge cases', () => {
|
|
158
|
+
it('should handle null correctness', () => {
|
|
159
|
+
renderWithTheme(<Feedback correctness={null} feedback="Test" />);
|
|
160
|
+
expect(screen.queryByText('Test')).not.toBeInTheDocument();
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
it('should handle undefined correctness', () => {
|
|
164
|
+
renderWithTheme(<Feedback correctness={undefined} feedback="Test" />);
|
|
165
|
+
expect(screen.queryByText('Test')).not.toBeInTheDocument();
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
it('should handle null feedback', () => {
|
|
169
|
+
renderWithTheme(<Feedback correctness="correct" feedback={null} />);
|
|
170
|
+
const { container } = renderWithTheme(<Feedback correctness="correct" feedback={null} />);
|
|
171
|
+
expect(container.querySelector('[class*="FeedbackContent"]')).not.toBeInTheDocument();
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
it('should handle undefined feedback', () => {
|
|
175
|
+
renderWithTheme(<Feedback correctness="correct" feedback={undefined} />);
|
|
176
|
+
const { container } = renderWithTheme(<Feedback correctness="correct" feedback={undefined} />);
|
|
177
|
+
expect(container.querySelector('[class*="FeedbackContent"]')).not.toBeInTheDocument();
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
it('should handle very long feedback text', () => {
|
|
181
|
+
const longFeedback = 'A'.repeat(1000);
|
|
182
|
+
renderWithTheme(<Feedback correctness="correct" feedback={longFeedback} />);
|
|
183
|
+
expect(screen.getByText(longFeedback)).toBeInTheDocument();
|
|
184
|
+
});
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
describe('dangerouslySetInnerHTML', () => {
|
|
188
|
+
it('should render HTML safely using dangerouslySetInnerHTML', () => {
|
|
189
|
+
renderWithTheme(<Feedback correctness="correct" feedback='<span id="test-span">HTML Content</span>' />);
|
|
190
|
+
const htmlElement = document.getElementById('test-span');
|
|
191
|
+
expect(htmlElement).toBeInTheDocument();
|
|
192
|
+
expect(htmlElement).toHaveTextContent('HTML Content');
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
it('should handle complex nested HTML', () => {
|
|
196
|
+
renderWithTheme(<Feedback correctness="incorrect" feedback="<div><p>Paragraph 1</p><p>Paragraph 2</p></div>" />);
|
|
197
|
+
expect(screen.getByText('Paragraph 1')).toBeInTheDocument();
|
|
198
|
+
expect(screen.getByText('Paragraph 2')).toBeInTheDocument();
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
it('should render HTML with inline styles', () => {
|
|
202
|
+
renderWithTheme(<Feedback correctness="correct" feedback='<span style="color: red;">Styled text</span>' />);
|
|
203
|
+
expect(screen.getByText('Styled text')).toBeInTheDocument();
|
|
204
|
+
});
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
describe('component lifecycle', () => {
|
|
208
|
+
it('should render correctly on mount', () => {
|
|
209
|
+
renderWithTheme(<Feedback correctness="correct" feedback="Mounted feedback" />);
|
|
210
|
+
expect(screen.getByText('Mounted feedback')).toBeInTheDocument();
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
it('should update correctly when props change', () => {
|
|
214
|
+
const { rerender } = renderWithTheme(<Feedback correctness="correct" feedback="Original" />);
|
|
215
|
+
expect(screen.getByText('Original')).toBeInTheDocument();
|
|
216
|
+
|
|
217
|
+
rerender(<Feedback correctness="incorrect" feedback="Changed" />);
|
|
218
|
+
expect(screen.getByText('Changed')).toBeInTheDocument();
|
|
219
|
+
expect(screen.queryByText('Original')).not.toBeInTheDocument();
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
it('should handle multiple rapid updates', () => {
|
|
223
|
+
const { rerender } = renderWithTheme(<Feedback correctness="correct" feedback="V1" />);
|
|
224
|
+
|
|
225
|
+
rerender(<Feedback correctness="incorrect" feedback="V2" />);
|
|
226
|
+
rerender(<Feedback correctness="correct" feedback="V3" />);
|
|
227
|
+
rerender(<Feedback correctness="incorrect" feedback="V4" />);
|
|
228
|
+
|
|
229
|
+
expect(screen.getByText('V4')).toBeInTheDocument();
|
|
230
|
+
expect(screen.queryByText('V1')).not.toBeInTheDocument();
|
|
231
|
+
expect(screen.queryByText('V2')).not.toBeInTheDocument();
|
|
232
|
+
expect(screen.queryByText('V3')).not.toBeInTheDocument();
|
|
233
|
+
});
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
describe('accessibility', () => {
|
|
237
|
+
it('should render accessible content structure', () => {
|
|
238
|
+
const { container } = renderWithTheme(<Feedback correctness="correct" feedback="Accessible feedback" />);
|
|
239
|
+
expect(screen.getByText('Accessible feedback')).toBeInTheDocument();
|
|
240
|
+
expect(container.textContent).toContain('Accessible feedback');
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
it('should preserve semantic HTML in feedback', () => {
|
|
244
|
+
renderWithTheme(<Feedback correctness="correct" feedback="<strong>Important:</strong> Good work!" />);
|
|
245
|
+
const strongElement = document.querySelector('strong');
|
|
246
|
+
expect(strongElement).toBeInTheDocument();
|
|
247
|
+
expect(strongElement).toHaveTextContent('Important:');
|
|
248
|
+
});
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
describe('integration scenarios', () => {
|
|
252
|
+
it('should work in a typical correct answer scenario', () => {
|
|
253
|
+
renderWithTheme(
|
|
254
|
+
<Feedback correctness="correct" feedback="<strong>Correct!</strong> You identified the right answer." />,
|
|
255
|
+
);
|
|
256
|
+
const container = screen.getByText(/Correct!/);
|
|
257
|
+
expect(container).toBeInTheDocument();
|
|
258
|
+
expect(screen.getByText(/You identified the right answer/)).toBeInTheDocument();
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
it('should work in a typical incorrect answer scenario', () => {
|
|
262
|
+
renderWithTheme(
|
|
263
|
+
<Feedback
|
|
264
|
+
correctness="incorrect"
|
|
265
|
+
feedback="<strong>Incorrect.</strong> Please review the material and try again."
|
|
266
|
+
/>,
|
|
267
|
+
);
|
|
268
|
+
expect(screen.getByText(/Incorrect/)).toBeInTheDocument();
|
|
269
|
+
expect(screen.getByText(/Please review the material/)).toBeInTheDocument();
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
it('should work in a partially correct scenario', () => {
|
|
273
|
+
renderWithTheme(
|
|
274
|
+
<Feedback correctness="partial" feedback="You got some parts correct, but missed a few key points." />,
|
|
275
|
+
);
|
|
276
|
+
expect(screen.getByText(/You got some parts correct/)).toBeInTheDocument();
|
|
277
|
+
});
|
|
278
|
+
});
|
|
279
|
+
});
|