@pie-element/hotspot 11.1.2-next.5 → 11.1.3
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/CHANGELOG.json +997 -0
- package/CHANGELOG.md +2226 -0
- package/LICENSE.md +5 -0
- package/README.md +1 -0
- package/configure/CHANGELOG.json +682 -0
- package/configure/CHANGELOG.md +1963 -0
- package/configure/lib/DeleteWidget.js +64 -0
- package/configure/lib/DeleteWidget.js.map +1 -0
- package/configure/lib/button.js +42 -0
- package/configure/lib/button.js.map +1 -0
- package/configure/lib/buttons/circle.js +33 -0
- package/configure/lib/buttons/circle.js.map +1 -0
- package/configure/lib/buttons/polygon.js +39 -0
- package/configure/lib/buttons/polygon.js.map +1 -0
- package/configure/lib/buttons/rectangle.js +39 -0
- package/configure/lib/buttons/rectangle.js.map +1 -0
- package/configure/lib/defaults.js +155 -0
- package/configure/lib/defaults.js.map +1 -0
- package/configure/lib/hotspot-circle.js +192 -0
- package/configure/lib/hotspot-circle.js.map +1 -0
- package/configure/lib/hotspot-container.js +320 -0
- package/configure/lib/hotspot-container.js.map +1 -0
- package/configure/lib/hotspot-drawable.js +519 -0
- package/configure/lib/hotspot-drawable.js.map +1 -0
- package/configure/lib/hotspot-palette.js +107 -0
- package/configure/lib/hotspot-palette.js.map +1 -0
- package/configure/lib/hotspot-polygon.js +293 -0
- package/configure/lib/hotspot-polygon.js.map +1 -0
- package/configure/lib/hotspot-rectangle.js +190 -0
- package/configure/lib/hotspot-rectangle.js.map +1 -0
- package/configure/lib/icons.js +7 -0
- package/configure/lib/icons.js.map +1 -0
- package/configure/lib/image-konva.js +66 -0
- package/configure/lib/image-konva.js.map +1 -0
- package/configure/lib/index.js +194 -0
- package/configure/lib/index.js.map +1 -0
- package/configure/lib/root.js +330 -0
- package/configure/lib/root.js.map +1 -0
- package/configure/lib/shapes/circle.js +84 -0
- package/configure/lib/shapes/circle.js.map +1 -0
- package/configure/lib/shapes/index.js +50 -0
- package/configure/lib/shapes/index.js.map +1 -0
- package/configure/lib/shapes/polygon.js +82 -0
- package/configure/lib/shapes/polygon.js.map +1 -0
- package/configure/lib/shapes/rectagle.js +84 -0
- package/configure/lib/shapes/rectagle.js.map +1 -0
- package/configure/lib/shapes/utils.js +21 -0
- package/configure/lib/shapes/utils.js.map +1 -0
- package/configure/lib/upload-control.js +41 -0
- package/configure/lib/upload-control.js.map +1 -0
- package/configure/lib/utils.js +185 -0
- package/configure/lib/utils.js.map +1 -0
- package/configure/package.json +26 -0
- package/configure/src/DeleteWidget.jsx +51 -0
- package/configure/src/__tests__/DeleteWidget.test.jsx +366 -0
- package/configure/src/__tests__/button.test.jsx +198 -0
- package/configure/src/__tests__/hotspot-circle.test.jsx +259 -0
- package/configure/src/__tests__/hotspot-container.test.js +366 -0
- package/configure/src/__tests__/hotspot-drawable.test.js +271 -0
- package/configure/src/__tests__/hotspot-palette.test.jsx +71 -0
- package/configure/src/__tests__/image-konva.test.jsx +226 -0
- package/configure/src/__tests__/index.test.js +329 -0
- package/configure/src/__tests__/root.test.js +400 -0
- package/configure/src/__tests__/utils.test.js +241 -0
- package/configure/src/button.jsx +35 -0
- package/configure/src/buttons/circle.jsx +18 -0
- package/configure/src/buttons/polygon.jsx +29 -0
- package/configure/src/buttons/rectangle.jsx +29 -0
- package/configure/src/defaults.js +109 -0
- package/configure/src/hotspot-circle.jsx +183 -0
- package/configure/src/hotspot-container.jsx +330 -0
- package/configure/src/hotspot-drawable.jsx +527 -0
- package/configure/src/hotspot-palette.jsx +90 -0
- package/configure/src/hotspot-polygon.jsx +294 -0
- package/configure/src/hotspot-rectangle.jsx +169 -0
- package/configure/src/icons.js +5 -0
- package/configure/src/image-konva.jsx +63 -0
- package/configure/src/index.js +208 -0
- package/configure/src/root.jsx +346 -0
- package/configure/src/shapes/circle.js +81 -0
- package/configure/src/shapes/index.js +4 -0
- package/configure/src/shapes/polygon.js +81 -0
- package/configure/src/shapes/rectagle.js +82 -0
- package/configure/src/shapes/utils.js +16 -0
- package/configure/src/upload-control.jsx +33 -0
- package/configure/src/utils.js +210 -0
- package/controller/CHANGELOG.json +362 -0
- package/controller/CHANGELOG.md +1304 -0
- package/controller/lib/defaults.js +33 -0
- package/controller/lib/defaults.js.map +1 -0
- package/controller/lib/index.js +341 -0
- package/controller/lib/index.js.map +1 -0
- package/controller/lib/utils.js +32 -0
- package/controller/lib/utils.js.map +1 -0
- package/controller/package.json +18 -0
- package/controller/src/__tests__/index.test.js +419 -0
- package/controller/src/__tests__/utils.test.js +5 -0
- package/controller/src/defaults.js +19 -0
- package/controller/src/index.js +328 -0
- package/controller/src/utils.js +29 -0
- package/docs/config-schema.json +2023 -0
- package/docs/config-schema.json.md +1495 -0
- package/docs/demo/config.js +8 -0
- package/docs/demo/generate.js +118 -0
- package/docs/demo/index.html +1 -0
- package/docs/demo/session.js +11 -0
- package/docs/pie-schema.json +1204 -0
- package/docs/pie-schema.json.md +851 -0
- package/lib/hotspot/circle.js +156 -0
- package/lib/hotspot/circle.js.map +1 -0
- package/lib/hotspot/container.js +206 -0
- package/lib/hotspot/container.js.map +1 -0
- package/lib/hotspot/icons.js +8 -0
- package/lib/hotspot/icons.js.map +1 -0
- package/lib/hotspot/image-konva-tooltip.js +86 -0
- package/lib/hotspot/image-konva-tooltip.js.map +1 -0
- package/lib/hotspot/index.js +163 -0
- package/lib/hotspot/index.js.map +1 -0
- package/lib/hotspot/polygon.js +203 -0
- package/lib/hotspot/polygon.js.map +1 -0
- package/lib/hotspot/rectangle.js +175 -0
- package/lib/hotspot/rectangle.js.map +1 -0
- package/lib/index.js +213 -0
- package/lib/index.js.map +1 -0
- package/lib/session-updater.js +42 -0
- package/lib/session-updater.js.map +1 -0
- package/package.json +18 -83
- package/src/__tests__/container.test.jsx +58 -0
- package/src/__tests__/index.test.js +123 -0
- package/src/__tests__/session-updater.test.jsx +69 -0
- package/src/hotspot/__tests__/circle.test.jsx +464 -0
- package/src/hotspot/__tests__/container.test.jsx +546 -0
- package/src/hotspot/__tests__/image-konva-tooltip.test.jsx +510 -0
- package/src/hotspot/__tests__/polygon.test.jsx +502 -0
- package/src/hotspot/__tests__/rectangle.test.jsx +418 -0
- package/src/hotspot/circle.jsx +152 -0
- package/src/hotspot/container.jsx +217 -0
- package/src/hotspot/icons.js +7 -0
- package/src/hotspot/image-konva-tooltip.jsx +76 -0
- package/src/hotspot/index.jsx +165 -0
- package/src/hotspot/polygon.jsx +195 -0
- package/src/hotspot/rectangle.jsx +171 -0
- package/src/index.js +226 -0
- package/src/session-updater.js +29 -0
- package/configure.js +0 -2
- package/controller.js +0 -1
- package/dist/author/DeleteWidget.d.ts +0 -38
- package/dist/author/DeleteWidget.js +0 -46
- package/dist/author/button.d.ts +0 -31
- package/dist/author/button.js +0 -27
- package/dist/author/buttons/circle.d.ts +0 -18
- package/dist/author/buttons/circle.js +0 -25
- package/dist/author/buttons/polygon.d.ts +0 -18
- package/dist/author/buttons/polygon.js +0 -36
- package/dist/author/buttons/rectangle.d.ts +0 -18
- package/dist/author/buttons/rectangle.js +0 -36
- package/dist/author/defaults.d.ts +0 -157
- package/dist/author/defaults.js +0 -119
- package/dist/author/hotspot-circle.d.ts +0 -21
- package/dist/author/hotspot-circle.js +0 -124
- package/dist/author/hotspot-container.d.ts +0 -29
- package/dist/author/hotspot-container.js +0 -210
- package/dist/author/hotspot-drawable.d.ts +0 -31
- package/dist/author/hotspot-drawable.js +0 -312
- package/dist/author/hotspot-palette.d.ts +0 -14
- package/dist/author/hotspot-palette.js +0 -72
- package/dist/author/hotspot-polygon.d.ts +0 -38
- package/dist/author/hotspot-polygon.js +0 -200
- package/dist/author/hotspot-rectangle.d.ts +0 -20
- package/dist/author/hotspot-rectangle.js +0 -119
- package/dist/author/icons.d.ts +0 -9
- package/dist/author/icons.js +0 -4
- package/dist/author/image-konva.d.ts +0 -19
- package/dist/author/image-konva.js +0 -49
- package/dist/author/index.d.ts +0 -52
- package/dist/author/index.js +0 -143
- package/dist/author/root.d.ts +0 -15
- package/dist/author/root.js +0 -215
- package/dist/author/shapes/circle.d.ts +0 -18
- package/dist/author/shapes/circle.js +0 -47
- package/dist/author/shapes/index.d.ts +0 -12
- package/dist/author/shapes/polygon.d.ts +0 -19
- package/dist/author/shapes/polygon.js +0 -51
- package/dist/author/shapes/rectagle.d.ts +0 -18
- package/dist/author/shapes/rectagle.js +0 -57
- package/dist/author/shapes/utils.d.ts +0 -19
- package/dist/author/shapes/utils.js +0 -16
- package/dist/author/upload-control.d.ts +0 -29
- package/dist/author/upload-control.js +0 -28
- package/dist/author/utils.d.ts +0 -24
- package/dist/author/utils.js +0 -83
- package/dist/browser/ReactKonva-CFo7dxdy.js +0 -19336
- package/dist/browser/ReactKonva-CFo7dxdy.js.map +0 -1
- package/dist/browser/author/index.js +0 -47549
- package/dist/browser/author/index.js.map +0 -1
- package/dist/browser/browser-CfnAFove.js +0 -219
- package/dist/browser/browser-CfnAFove.js.map +0 -1
- package/dist/browser/controller/index.js +0 -198
- package/dist/browser/controller/index.js.map +0 -1
- package/dist/browser/delivery/index.js +0 -2460
- package/dist/browser/delivery/index.js.map +0 -1
- package/dist/browser/dist-CeB-1djc.js +0 -100
- package/dist/browser/dist-CeB-1djc.js.map +0 -1
- package/dist/browser/hotspot.css +0 -2
- package/dist/controller/defaults.d.ts +0 -35
- package/dist/controller/defaults.js +0 -29
- package/dist/controller/index.d.ts +0 -22
- package/dist/controller/index.js +0 -154
- package/dist/controller/utils.d.ts +0 -10
- package/dist/controller/utils.js +0 -12
- package/dist/delivery/hotspot/circle.d.ts +0 -19
- package/dist/delivery/hotspot/circle.js +0 -100
- package/dist/delivery/hotspot/container.d.ts +0 -16
- package/dist/delivery/hotspot/container.js +0 -150
- package/dist/delivery/hotspot/icons.d.ts +0 -10
- package/dist/delivery/hotspot/icons.js +0 -4
- package/dist/delivery/hotspot/image-konva-tooltip.d.ts +0 -19
- package/dist/delivery/hotspot/image-konva-tooltip.js +0 -66
- package/dist/delivery/hotspot/index.d.ts +0 -17
- package/dist/delivery/hotspot/index.js +0 -114
- package/dist/delivery/hotspot/polygon.d.ts +0 -21
- package/dist/delivery/hotspot/polygon.js +0 -108
- package/dist/delivery/hotspot/rectangle.d.ts +0 -19
- package/dist/delivery/hotspot/rectangle.js +0 -104
- package/dist/delivery/index.d.ts +0 -20
- package/dist/delivery/index.js +0 -107
- package/dist/delivery/session-updater.d.ts +0 -10
- package/dist/delivery/session-updater.js +0 -14
- package/dist/index.d.ts +0 -1
- package/dist/index.iife.d.ts +0 -8
- package/dist/index.iife.js +0 -169
- package/dist/index.js +0 -2
- package/dist/runtime-support.d.ts +0 -12
- package/dist/runtime-support.js +0 -12
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
import { render } from '@testing-library/react';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { Drawable } from '../hotspot-drawable';
|
|
4
|
+
|
|
5
|
+
jest.mock('react-konva', () => {
|
|
6
|
+
const React = require('react');
|
|
7
|
+
return {
|
|
8
|
+
Stage: ({ children, ...props }) => React.createElement('div', { 'data-testid': 'stage', ...props }, children),
|
|
9
|
+
Layer: ({ children, ...props }) => React.createElement('div', { 'data-testid': 'layer', ...props }, children),
|
|
10
|
+
Rect: (props) => React.createElement('div', { 'data-testid': 'rect', ...props }),
|
|
11
|
+
Circle: (props) => React.createElement('div', { 'data-testid': 'circle', ...props }),
|
|
12
|
+
Line: (props) => React.createElement('div', { 'data-testid': 'line', ...props }),
|
|
13
|
+
Group: ({ children, ...props }) => React.createElement('div', { 'data-testid': 'group', ...props }, children),
|
|
14
|
+
Image: (props) => React.createElement('div', { 'data-testid': 'image', ...props }),
|
|
15
|
+
};
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
const model = () => ({
|
|
19
|
+
imageUrl: 'https://cdn.fluence.net/image/0240eb1455ce4c4bb6180232347b6aef_W',
|
|
20
|
+
shapes: [
|
|
21
|
+
{
|
|
22
|
+
id: '0',
|
|
23
|
+
height: 140,
|
|
24
|
+
width: 130,
|
|
25
|
+
x: 1,
|
|
26
|
+
y: 1,
|
|
27
|
+
correct: true,
|
|
28
|
+
group: 'rectangles',
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
id: '1',
|
|
32
|
+
height: 140,
|
|
33
|
+
width: 130,
|
|
34
|
+
x: 140,
|
|
35
|
+
y: 1,
|
|
36
|
+
group: 'rectangles',
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
id: '2',
|
|
40
|
+
height: 140,
|
|
41
|
+
width: 130,
|
|
42
|
+
x: 280,
|
|
43
|
+
y: 1,
|
|
44
|
+
group: 'rectangles',
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
id: '3',
|
|
48
|
+
points: [
|
|
49
|
+
{ x: 1, y: 148 },
|
|
50
|
+
{ x: 1, y: 288 },
|
|
51
|
+
{ y: 288, x: 129 },
|
|
52
|
+
{ y: 148, x: 129 },
|
|
53
|
+
],
|
|
54
|
+
correct: true,
|
|
55
|
+
group: 'polygons',
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
id: '4',
|
|
59
|
+
points: [
|
|
60
|
+
{ y: 151, x: 141 },
|
|
61
|
+
{ y: 289, x: 141 },
|
|
62
|
+
{ y: 289, x: 269 },
|
|
63
|
+
{ x: 269, y: 151 },
|
|
64
|
+
],
|
|
65
|
+
correct: false,
|
|
66
|
+
group: 'polygons',
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
id: '5',
|
|
70
|
+
points: [
|
|
71
|
+
{ x: 279, y: 150 },
|
|
72
|
+
{ x: 279, y: 289 },
|
|
73
|
+
{ x: 407, y: 289 },
|
|
74
|
+
{ x: 407, y: 150 },
|
|
75
|
+
],
|
|
76
|
+
correct: false,
|
|
77
|
+
group: 'polygons',
|
|
78
|
+
},
|
|
79
|
+
],
|
|
80
|
+
dimensions: {
|
|
81
|
+
height: 291,
|
|
82
|
+
width: 410,
|
|
83
|
+
},
|
|
84
|
+
hotspotColor: 'rgba(137, 183, 244, 0.65)',
|
|
85
|
+
outlineColor: 'blue',
|
|
86
|
+
multipleCorrect: true,
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
describe('HotspotDrawable', () => {
|
|
90
|
+
let w,
|
|
91
|
+
handleDisableDrag = jest.fn(),
|
|
92
|
+
handleEnableDrag = jest.fn(),
|
|
93
|
+
onUpdateImageDimension = jest.fn(),
|
|
94
|
+
onUpdateShapes = jest.fn(),
|
|
95
|
+
initialModel = model();
|
|
96
|
+
beforeEach(() => {
|
|
97
|
+
w = (extras) => {
|
|
98
|
+
const props = {
|
|
99
|
+
classes: {},
|
|
100
|
+
dimensions: initialModel.dimensions,
|
|
101
|
+
disableDrag: handleDisableDrag,
|
|
102
|
+
enableDrag: handleEnableDrag,
|
|
103
|
+
imageUrl: initialModel.imageUrl,
|
|
104
|
+
hotspotColor: initialModel.hotspotColor,
|
|
105
|
+
multipleCorrect: initialModel.multipleCorrect,
|
|
106
|
+
onUpdateImageDimension: onUpdateImageDimension,
|
|
107
|
+
onUpdateShapes: onUpdateShapes,
|
|
108
|
+
outlineColor: initialModel.outlineColor,
|
|
109
|
+
shapes: initialModel.shapes,
|
|
110
|
+
strokeWidth: 5,
|
|
111
|
+
shapeType: 'rectangle',
|
|
112
|
+
handleFinishDrawing: jest.fn(),
|
|
113
|
+
onDeleteShape: jest.fn(),
|
|
114
|
+
...extras,
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
return render(<Drawable {...props} />);
|
|
118
|
+
};
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
describe('logic', () => {
|
|
122
|
+
const createInstance = () => {
|
|
123
|
+
const props = {
|
|
124
|
+
classes: {},
|
|
125
|
+
dimensions: initialModel.dimensions,
|
|
126
|
+
disableDrag: handleDisableDrag,
|
|
127
|
+
enableDrag: handleEnableDrag,
|
|
128
|
+
imageUrl: initialModel.imageUrl,
|
|
129
|
+
hotspotColor: initialModel.hotspotColor,
|
|
130
|
+
multipleCorrect: initialModel.multipleCorrect,
|
|
131
|
+
onUpdateImageDimension: onUpdateImageDimension,
|
|
132
|
+
onUpdateShapes: onUpdateShapes,
|
|
133
|
+
outlineColor: initialModel.outlineColor,
|
|
134
|
+
shapes: initialModel.shapes,
|
|
135
|
+
strokeWidth: 5,
|
|
136
|
+
shapeType: 'rectangle',
|
|
137
|
+
handleFinishDrawing: jest.fn(),
|
|
138
|
+
onDeleteShape: jest.fn(),
|
|
139
|
+
};
|
|
140
|
+
return new Drawable(props);
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
it('handleOnMouseDown target != Stage', () => {
|
|
144
|
+
const instance = createInstance();
|
|
145
|
+
instance.state.stateShapes = initialModel.shapes;
|
|
146
|
+
|
|
147
|
+
const event = {
|
|
148
|
+
target: 'Line',
|
|
149
|
+
currentTarget: 'Stage',
|
|
150
|
+
evt: {
|
|
151
|
+
layerX: 20,
|
|
152
|
+
layerY: 30,
|
|
153
|
+
},
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
instance.handleOnMouseDown(event);
|
|
157
|
+
|
|
158
|
+
expect(onUpdateShapes).not.toBeCalled();
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
it('handleOnMouseDown target = Stage', () => {
|
|
162
|
+
const instance = createInstance();
|
|
163
|
+
const event = {
|
|
164
|
+
target: 'Stage',
|
|
165
|
+
currentTarget: 'Stage',
|
|
166
|
+
evt: {
|
|
167
|
+
layerX: 20,
|
|
168
|
+
layerY: 30,
|
|
169
|
+
},
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
instance.handleOnMouseDown(event);
|
|
173
|
+
|
|
174
|
+
expect(onUpdateShapes).toHaveBeenCalledWith([
|
|
175
|
+
...initialModel.shapes,
|
|
176
|
+
{
|
|
177
|
+
id: '6',
|
|
178
|
+
height: 0,
|
|
179
|
+
width: 0,
|
|
180
|
+
x: 20,
|
|
181
|
+
y: 30,
|
|
182
|
+
group: 'rectangles',
|
|
183
|
+
index: 6,
|
|
184
|
+
},
|
|
185
|
+
]);
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
it('handleOnMouseUp isDrawing = true', () => {
|
|
189
|
+
const instance = createInstance();
|
|
190
|
+
instance.state.isDrawing = true;
|
|
191
|
+
instance.state.shapes = initialModel.shapes.slice(0, 2);
|
|
192
|
+
|
|
193
|
+
instance.handleOnMouseUp({
|
|
194
|
+
evt: {
|
|
195
|
+
layerX: 20,
|
|
196
|
+
layerY: 30,
|
|
197
|
+
},
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
expect(onUpdateShapes).toHaveBeenCalledWith([...initialModel.shapes.slice(0, 2)]);
|
|
201
|
+
|
|
202
|
+
// at this point, state.stateShapes is false, so we don't want to update shapes with false (onUpdateShapes)
|
|
203
|
+
expect(instance.state.stateShapes).toEqual(false);
|
|
204
|
+
|
|
205
|
+
instance.handleOnMouseUp({
|
|
206
|
+
evt: {
|
|
207
|
+
layerX: 20,
|
|
208
|
+
layerY: 30,
|
|
209
|
+
},
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
expect(onUpdateShapes).not.toBeCalledWith(false);
|
|
213
|
+
|
|
214
|
+
instance.handleOnMouseUp({});
|
|
215
|
+
|
|
216
|
+
expect(onUpdateShapes).toHaveBeenCalledWith(initialModel.shapes.slice(0, 2));
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
it('handleOnSetAsCorrect correct', () => {
|
|
220
|
+
const instance = createInstance();
|
|
221
|
+
instance.handleOnSetAsCorrect({
|
|
222
|
+
id: '1',
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
expect(onUpdateShapes).toHaveBeenCalledWith([
|
|
226
|
+
initialModel.shapes[0],
|
|
227
|
+
{
|
|
228
|
+
...initialModel.shapes[1],
|
|
229
|
+
correct: true,
|
|
230
|
+
},
|
|
231
|
+
...initialModel.shapes.slice(2),
|
|
232
|
+
]);
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
it('handleOnSetAsCorrect incorrect', () => {
|
|
236
|
+
const instance = createInstance();
|
|
237
|
+
instance.handleOnSetAsCorrect({
|
|
238
|
+
id: '0',
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
expect(onUpdateShapes).toHaveBeenCalledWith([
|
|
242
|
+
{
|
|
243
|
+
...initialModel.shapes[0],
|
|
244
|
+
correct: false,
|
|
245
|
+
},
|
|
246
|
+
...initialModel.shapes.slice(1),
|
|
247
|
+
]);
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
it('handleOnDragEnd', () => {
|
|
251
|
+
const instance = createInstance();
|
|
252
|
+
instance.handleOnDragEnd('0', { x: 1, y: 1 });
|
|
253
|
+
|
|
254
|
+
expect(onUpdateShapes).toHaveBeenCalledWith([
|
|
255
|
+
{
|
|
256
|
+
...initialModel.shapes[0],
|
|
257
|
+
x: 1,
|
|
258
|
+
y: 1,
|
|
259
|
+
},
|
|
260
|
+
...initialModel.shapes.slice(1),
|
|
261
|
+
]);
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
it('handleOnDragEnd unexistent id', () => {
|
|
265
|
+
const instance = createInstance();
|
|
266
|
+
instance.handleOnDragEnd('10', { x: 1, y: 1 });
|
|
267
|
+
|
|
268
|
+
expect(onUpdateShapes).toHaveBeenCalledWith(initialModel.shapes);
|
|
269
|
+
});
|
|
270
|
+
});
|
|
271
|
+
});
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { render, fireEvent } from '@testing-library/react';
|
|
3
|
+
import Palette from '../hotspot-palette';
|
|
4
|
+
|
|
5
|
+
describe('Palette', () => {
|
|
6
|
+
let defaultProps;
|
|
7
|
+
|
|
8
|
+
beforeEach(() => {
|
|
9
|
+
defaultProps = {
|
|
10
|
+
hotspotColor: '#FF0000',
|
|
11
|
+
outlineColor: '#0000FF',
|
|
12
|
+
hotspotList: ['#FF0000', '#00FF00', '#0000FF', '#FFFF00'],
|
|
13
|
+
outlineList: ['#000000', '#0000FF', '#FF0000', '#00FF00'],
|
|
14
|
+
onHotspotColorChange: jest.fn(),
|
|
15
|
+
onOutlineColorChange: jest.fn(),
|
|
16
|
+
};
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
describe('rendering', () => {
|
|
20
|
+
it('should render without crashing', () => {
|
|
21
|
+
const { container } = render(<Palette {...defaultProps} />);
|
|
22
|
+
expect(container).toBeTruthy();
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
describe('edge cases', () => {
|
|
27
|
+
it('should handle empty hotspot list gracefully', () => {
|
|
28
|
+
const { container } = render(<Palette {...defaultProps} hotspotList={[]} />);
|
|
29
|
+
expect(container).toBeTruthy();
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('should handle empty outline list gracefully', () => {
|
|
33
|
+
const { container } = render(<Palette {...defaultProps} outlineList={[]} />);
|
|
34
|
+
expect(container).toBeTruthy();
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
describe('onChange handler', () => {
|
|
39
|
+
it('should create onChange handler for hotspot', () => {
|
|
40
|
+
const component = new Palette(defaultProps);
|
|
41
|
+
const handler = component.onChange('hotspot');
|
|
42
|
+
expect(typeof handler).toBe('function');
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it('should create onChange handler for outline', () => {
|
|
46
|
+
const component = new Palette(defaultProps);
|
|
47
|
+
const handler = component.onChange('outline');
|
|
48
|
+
expect(typeof handler).toBe('function');
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('should call onHotspotColorChange when hotspot handler is invoked', () => {
|
|
52
|
+
const onHotspotColorChange = jest.fn();
|
|
53
|
+
const component = new Palette({ ...defaultProps, onHotspotColorChange });
|
|
54
|
+
const handler = component.onChange('hotspot');
|
|
55
|
+
|
|
56
|
+
handler({ target: { value: '#00FF00' } });
|
|
57
|
+
|
|
58
|
+
expect(onHotspotColorChange).toHaveBeenCalledWith('#00FF00');
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it('should call onOutlineColorChange when outline handler is invoked', () => {
|
|
62
|
+
const onOutlineColorChange = jest.fn();
|
|
63
|
+
const component = new Palette({ ...defaultProps, onOutlineColorChange });
|
|
64
|
+
const handler = component.onChange('outline');
|
|
65
|
+
|
|
66
|
+
handler({ target: { value: '#FF0000' } });
|
|
67
|
+
|
|
68
|
+
expect(onOutlineColorChange).toHaveBeenCalledWith('#FF0000');
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
});
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { render, waitFor } from '@testing-library/react';
|
|
3
|
+
import Konva from 'konva';
|
|
4
|
+
import ImageComponent from '../image-konva';
|
|
5
|
+
|
|
6
|
+
Konva.isBrowser = false;
|
|
7
|
+
|
|
8
|
+
jest.mock('react-konva', () => {
|
|
9
|
+
const React = require('react');
|
|
10
|
+
return {
|
|
11
|
+
Image: (props) => React.createElement('div', { 'data-testid': 'image', ...props }),
|
|
12
|
+
};
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
describe('ImageComponent', () => {
|
|
16
|
+
let defaultProps;
|
|
17
|
+
|
|
18
|
+
beforeEach(() => {
|
|
19
|
+
defaultProps = {
|
|
20
|
+
src: 'test-image.png',
|
|
21
|
+
x: 100,
|
|
22
|
+
y: 150,
|
|
23
|
+
};
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
describe('rendering', () => {
|
|
27
|
+
it('should render without crashing', () => {
|
|
28
|
+
const { container } = render(<ImageComponent {...defaultProps} />);
|
|
29
|
+
expect(container).toBeTruthy();
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('should render Image component', () => {
|
|
33
|
+
const { getByTestId } = render(<ImageComponent {...defaultProps} />);
|
|
34
|
+
expect(getByTestId('image')).toBeInTheDocument();
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('should render with correct position', () => {
|
|
38
|
+
const { getByTestId } = render(<ImageComponent {...defaultProps} x={200} y={250} />);
|
|
39
|
+
const image = getByTestId('image');
|
|
40
|
+
expect(image).toHaveAttribute('x', '200');
|
|
41
|
+
expect(image).toHaveAttribute('y', '250');
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('should render with fixed dimensions', () => {
|
|
45
|
+
const { getByTestId } = render(<ImageComponent {...defaultProps} />);
|
|
46
|
+
const image = getByTestId('image');
|
|
47
|
+
expect(image).toHaveAttribute('width', '20');
|
|
48
|
+
expect(image).toHaveAttribute('height', '20');
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('should render at origin (0, 0)', () => {
|
|
52
|
+
const { getByTestId } = render(<ImageComponent {...defaultProps} x={0} y={0} />);
|
|
53
|
+
const image = getByTestId('image');
|
|
54
|
+
expect(image).toHaveAttribute('x', '0');
|
|
55
|
+
expect(image).toHaveAttribute('y', '0');
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
describe('image loading', () => {
|
|
60
|
+
it('should load image on mount', async () => {
|
|
61
|
+
const { getByTestId } = render(<ImageComponent {...defaultProps} />);
|
|
62
|
+
|
|
63
|
+
const image = getByTestId('image');
|
|
64
|
+
expect(image).toBeInTheDocument();
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('should call loadImage on mount', () => {
|
|
68
|
+
const { container } = render(<ImageComponent {...defaultProps} src="custom-image.jpg" />);
|
|
69
|
+
|
|
70
|
+
expect(container).toBeTruthy();
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
describe('component lifecycle', () => {
|
|
75
|
+
it('should reload image when src changes', async () => {
|
|
76
|
+
const { rerender, container } = render(<ImageComponent {...defaultProps} src="image1.png" />);
|
|
77
|
+
|
|
78
|
+
expect(container).toBeTruthy();
|
|
79
|
+
|
|
80
|
+
rerender(<ImageComponent {...defaultProps} src="image2.png" />);
|
|
81
|
+
|
|
82
|
+
expect(container).toBeTruthy();
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it('should not reload image when src stays the same', async () => {
|
|
86
|
+
const { rerender, getByTestId } = render(<ImageComponent {...defaultProps} src="same-image.png" />);
|
|
87
|
+
|
|
88
|
+
const image = getByTestId('image');
|
|
89
|
+
expect(image).toBeInTheDocument();
|
|
90
|
+
|
|
91
|
+
rerender(<ImageComponent {...defaultProps} src="same-image.png" x={200} y={250} />);
|
|
92
|
+
|
|
93
|
+
const updatedImage = getByTestId('image');
|
|
94
|
+
expect(updatedImage).toHaveAttribute('x', '200');
|
|
95
|
+
expect(updatedImage).toHaveAttribute('y', '250');
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it('should clean up event listener on unmount', () => {
|
|
99
|
+
const { unmount } = render(<ImageComponent {...defaultProps} />);
|
|
100
|
+
|
|
101
|
+
expect(() => {
|
|
102
|
+
unmount();
|
|
103
|
+
}).not.toThrow();
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it('should handle multiple mount/unmount cycles', () => {
|
|
107
|
+
const { unmount } = render(<ImageComponent {...defaultProps} />);
|
|
108
|
+
unmount();
|
|
109
|
+
|
|
110
|
+
expect(() => {
|
|
111
|
+
render(<ImageComponent {...defaultProps} />);
|
|
112
|
+
}).not.toThrow();
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
describe('position updates', () => {
|
|
117
|
+
it('should update x position', () => {
|
|
118
|
+
const { getByTestId, rerender } = render(<ImageComponent {...defaultProps} x={100} />);
|
|
119
|
+
let image = getByTestId('image');
|
|
120
|
+
expect(image).toHaveAttribute('x', '100');
|
|
121
|
+
|
|
122
|
+
rerender(<ImageComponent {...defaultProps} x={200} />);
|
|
123
|
+
image = getByTestId('image');
|
|
124
|
+
expect(image).toHaveAttribute('x', '200');
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
it('should update y position', () => {
|
|
128
|
+
const { getByTestId, rerender } = render(<ImageComponent {...defaultProps} y={150} />);
|
|
129
|
+
let image = getByTestId('image');
|
|
130
|
+
expect(image).toHaveAttribute('y', '150');
|
|
131
|
+
|
|
132
|
+
rerender(<ImageComponent {...defaultProps} y={250} />);
|
|
133
|
+
image = getByTestId('image');
|
|
134
|
+
expect(image).toHaveAttribute('y', '250');
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
it('should update both x and y positions', () => {
|
|
138
|
+
const { getByTestId, rerender } = render(<ImageComponent {...defaultProps} x={100} y={150} />);
|
|
139
|
+
let image = getByTestId('image');
|
|
140
|
+
expect(image).toHaveAttribute('x', '100');
|
|
141
|
+
expect(image).toHaveAttribute('y', '150');
|
|
142
|
+
|
|
143
|
+
rerender(<ImageComponent {...defaultProps} x={300} y={400} />);
|
|
144
|
+
image = getByTestId('image');
|
|
145
|
+
expect(image).toHaveAttribute('x', '300');
|
|
146
|
+
expect(image).toHaveAttribute('y', '400');
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
describe('edge cases', () => {
|
|
151
|
+
it('should handle negative positions', () => {
|
|
152
|
+
const { getByTestId } = render(<ImageComponent {...defaultProps} x={-50} y={-75} />);
|
|
153
|
+
const image = getByTestId('image');
|
|
154
|
+
expect(image).toHaveAttribute('x', '-50');
|
|
155
|
+
expect(image).toHaveAttribute('y', '-75');
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
it('should handle very large positions', () => {
|
|
159
|
+
const { getByTestId } = render(<ImageComponent {...defaultProps} x={10000} y={20000} />);
|
|
160
|
+
const image = getByTestId('image');
|
|
161
|
+
expect(image).toHaveAttribute('x', '10000');
|
|
162
|
+
expect(image).toHaveAttribute('y', '20000');
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
it('should handle data URI as src', () => {
|
|
166
|
+
const dataUri = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==';
|
|
167
|
+
const { container } = render(<ImageComponent {...defaultProps} src={dataUri} />);
|
|
168
|
+
|
|
169
|
+
expect(container).toBeTruthy();
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
it('should handle SVG as src', () => {
|
|
173
|
+
const { container } = render(<ImageComponent {...defaultProps} src="icon.svg" />);
|
|
174
|
+
expect(container).toBeTruthy();
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
it('should handle empty src', () => {
|
|
178
|
+
const { container } = render(<ImageComponent {...defaultProps} src="" />);
|
|
179
|
+
expect(container).toBeTruthy();
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
it('should handle URL with query parameters', () => {
|
|
183
|
+
const srcWithParams = 'image.png?width=100&height=100';
|
|
184
|
+
const { container } = render(<ImageComponent {...defaultProps} src={srcWithParams} />);
|
|
185
|
+
|
|
186
|
+
expect(container).toBeTruthy();
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
it('should handle relative paths', () => {
|
|
190
|
+
const { container } = render(<ImageComponent {...defaultProps} src="./images/icon.png" />);
|
|
191
|
+
expect(container).toBeTruthy();
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
it('should handle absolute paths', () => {
|
|
195
|
+
const { container } = render(<ImageComponent {...defaultProps} src="/assets/icon.png" />);
|
|
196
|
+
expect(container).toBeTruthy();
|
|
197
|
+
});
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
describe('image state', () => {
|
|
201
|
+
it('should initially render without image loaded', () => {
|
|
202
|
+
const { getByTestId } = render(<ImageComponent {...defaultProps} />);
|
|
203
|
+
const image = getByTestId('image');
|
|
204
|
+
expect(image).toBeInTheDocument();
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
it('should render component regardless of image load state', () => {
|
|
208
|
+
const { getByTestId } = render(<ImageComponent {...defaultProps} />);
|
|
209
|
+
const image = getByTestId('image');
|
|
210
|
+
expect(image).toBeInTheDocument();
|
|
211
|
+
});
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
describe('error handling', () => {
|
|
215
|
+
it('should handle image load error gracefully', () => {
|
|
216
|
+
const { container } = render(<ImageComponent {...defaultProps} src="nonexistent.png" />);
|
|
217
|
+
|
|
218
|
+
const imgElements = document.querySelectorAll('img[src="nonexistent.png"]');
|
|
219
|
+
imgElements.forEach(img => {
|
|
220
|
+
img.dispatchEvent(new Event('error'));
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
expect(container).toBeTruthy();
|
|
224
|
+
});
|
|
225
|
+
});
|
|
226
|
+
});
|