@design-core/core 0.0.1 → 0.0.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/.eslintrc.json +14 -7
- package/.github/workflows/DesignCoreQA.yml +3 -1
- package/README.md +11 -4
- package/TODO.md +19 -0
- package/core/core/core.js +49 -42
- package/core/designCore.js +61 -2
- package/core/dimensions/alignedDimension.js +142 -0
- package/core/dimensions/angularDimension.js +550 -0
- package/core/dimensions/baseCircularDimension.js +244 -0
- package/core/dimensions/baseDimension.js +558 -0
- package/core/dimensions/baseLinearDimension.js +371 -0
- package/core/dimensions/diametricDimension.js +82 -0
- package/core/dimensions/dimension.js +298 -0
- package/core/dimensions/linearDimension.js +29 -0
- package/core/dimensions/radialDimension.js +78 -0
- package/core/dimensions/rotatedDimension.js +167 -0
- package/core/entities/arc.js +314 -60
- package/core/entities/arctext.js +642 -0
- package/core/entities/basePolyline.js +553 -94
- package/core/entities/circle.js +181 -54
- package/core/entities/entity.js +154 -74
- package/core/entities/hatch.js +807 -0
- package/core/entities/insert.js +200 -39
- package/core/entities/line.js +196 -134
- package/core/entities/lwpolyline.js +21 -44
- package/core/entities/point.js +194 -29
- package/core/entities/polyline.js +54 -7
- package/core/entities/rectangle.js +43 -13
- package/core/entities/solid.js +43 -6
- package/core/entities/text.js +324 -181
- package/core/lib/boundingBox.js +73 -13
- package/core/lib/canvas.js +256 -65
- package/core/lib/clipboard.js +198 -0
- package/core/lib/colour.js +144 -0
- package/core/lib/colours.js +367 -301
- package/core/lib/commandLine.js +16 -28
- package/core/lib/commandManager.js +115 -58
- package/core/lib/constants.js +23 -0
- package/core/lib/dxf/dxf.js +249 -34
- package/core/lib/dxf/dxfFile.js +23 -38
- package/core/lib/dxf/dxfIterator.js +17 -5
- package/core/lib/dxf/dxfRead.js +23 -7
- package/core/lib/dxf/dxfWrite.js +39 -129
- package/core/lib/dxf/handleManager.js +97 -0
- package/core/lib/dxf/sections/blocks.js +16 -2
- package/core/lib/dxf/sections/entities.js +17 -3
- package/core/lib/dxf/sections/header.js +10 -1
- package/core/lib/dxf/sections/objects.js +36 -0
- package/core/lib/dxf/sections/section.js +43 -5
- package/core/lib/dxf/sections/tables.js +17 -3
- package/core/lib/entityManager.js +178 -0
- package/core/lib/fileio.js +14 -4
- package/core/lib/headers.js +229 -0
- package/core/lib/input.js +46 -0
- package/core/lib/inputManager.js +199 -194
- package/core/lib/intersect.js +341 -468
- package/core/lib/logging.js +25 -1
- package/core/lib/matrix.js +6 -8
- package/core/lib/mouse.js +24 -79
- package/core/lib/patterns.js +690 -0
- package/core/lib/promptOptions.js +133 -0
- package/core/lib/scene.js +71 -174
- package/core/lib/selectionManager.js +74 -48
- package/core/lib/selectionWindow.js +24 -10
- package/core/lib/settings.js +18 -11
- package/core/lib/snapping.js +129 -21
- package/core/lib/stateManager.js +288 -0
- package/core/lib/strings.js +57 -5
- package/core/lib/utils.js +95 -11
- package/core/objects/dictionary.js +43 -0
- package/core/objects/dictionaryManager.js +80 -0
- package/core/properties/dimType.js +117 -0
- package/core/properties/flags.js +66 -0
- package/core/properties/property.js +26 -0
- package/core/properties/propertyManager.js +65 -19
- package/core/tables/appId.js +31 -0
- package/core/tables/appIdManager.js +44 -0
- package/core/tables/block.js +323 -0
- package/core/tables/blockManager.js +48 -0
- package/core/tables/blockRecord.js +29 -0
- package/core/tables/blockRecordManager.js +37 -0
- package/core/tables/dimStyle.js +627 -0
- package/core/tables/dimStyleManager.js +187 -0
- package/core/tables/endblk.js +28 -0
- package/core/tables/layer.js +219 -0
- package/core/tables/layerManager.js +47 -0
- package/core/tables/ltype.js +85 -0
- package/core/tables/ltypeManager.js +65 -0
- package/core/tables/style.js +145 -0
- package/core/tables/styleManager.js +55 -0
- package/core/tables/styleManagerBase.js +110 -0
- package/core/tables/tableManagerBase.js +354 -0
- package/core/tables/ucs.js +28 -0
- package/core/tables/ucsManager.js +44 -0
- package/core/tables/view.js +28 -0
- package/core/tables/viewManager.js +44 -0
- package/core/tables/vport.js +70 -0
- package/core/tables/vportManager.js +65 -0
- package/core/tools/chamfer.js +343 -0
- package/core/tools/chamferFilletBase.js +162 -0
- package/core/tools/copy.js +68 -40
- package/core/tools/copybase.js +65 -0
- package/core/tools/copyclip.js +59 -0
- package/core/tools/cornerEntity.js +138 -0
- package/core/tools/cutclip.js +72 -0
- package/core/tools/distance.js +37 -9
- package/core/tools/erase.js +43 -13
- package/core/tools/explode.js +117 -0
- package/core/tools/extend.js +71 -32
- package/core/tools/fillet.js +336 -0
- package/core/tools/identify.js +33 -6
- package/core/tools/matchProp.js +106 -0
- package/core/tools/mirror.js +141 -0
- package/core/tools/move.js +65 -32
- package/core/tools/offset.js +321 -0
- package/core/tools/pan.js +54 -0
- package/core/tools/pasteclip.js +93 -0
- package/core/tools/purge.js +90 -0
- package/core/tools/rotate.js +105 -70
- package/core/tools/scale.js +166 -0
- package/core/tools/tool.js +14 -4
- package/core/tools/trim.js +71 -32
- package/core/tools/zoom.js +152 -0
- package/package.json +3 -305
- package/test/dimensions/alignedDimension.test.js +211 -0
- package/test/dimensions/angularDimension.test.js +243 -0
- package/test/dimensions/baseDimension.test.js +239 -0
- package/test/dimensions/diametricDimension.test.js +203 -0
- package/test/dimensions/dimension.test.js +102 -0
- package/test/dimensions/radialDimension.test.js +203 -0
- package/test/dimensions/rotatedDimension.test.js +224 -0
- package/test/entities/arc.test.js +463 -41
- package/test/entities/arctext.test.js +329 -0
- package/test/entities/basePolyline.test.js +459 -10
- package/test/entities/circle.test.js +312 -7
- package/test/entities/entity.test.js +28 -9
- package/test/entities/hatch.test.js +606 -0
- package/test/entities/insert.test.js +90 -0
- package/test/entities/line.test.js +182 -6
- package/test/entities/point.test.js +375 -37
- package/test/entities/solid.test.js +156 -0
- package/test/entities/text.test.js +533 -7
- package/test/integration/exportIntegration.reference.dxf +1706 -0
- package/test/integration/exportIntegration.test.js +186 -0
- package/test/integration/importExportIntegration.test.js +126 -0
- package/test/integration/intersectionIntegration.test.js +880 -0
- package/test/integration/userInputIntegration.reference.dxf +1410 -0
- package/test/integration/userInputIntegration.test.js +269 -0
- package/test/lib/boundingBox.test.js +26 -2
- package/test/lib/canvas.test.js +613 -5
- package/test/lib/clipboard.test.js +70 -0
- package/test/lib/colour.test.js +114 -0
- package/test/lib/colours.test.js +63 -18
- package/test/lib/commandLine.test.js +159 -22
- package/test/lib/commandManager.test.js +4 -4
- package/test/lib/constants.test.js +9 -0
- package/test/lib/dxf/dxfFile.test.js +6 -2
- package/test/lib/dxf/dxfIterator.test.js +1 -1
- package/test/lib/dxf/dxfWrite.test.js +173 -0
- package/test/lib/dxf/handleManager.test.js +137 -0
- package/test/lib/dxf/sections/blocks.test.js +5 -5
- package/test/lib/dxf/sections/entities.test.js +4 -4
- package/test/lib/dxf/sections/header.test.js +18 -4
- package/test/lib/dxf/sections/objects.test.js +132 -0
- package/test/lib/dxf/sections/section.test.js +29 -29
- package/test/lib/dxf/sections/tables.test.js +3 -3
- package/test/lib/entityManager.test.js +163 -0
- package/test/lib/headers.test.js +233 -0
- package/test/lib/inputManager.test.js +1144 -5
- package/test/lib/intersect.test.js +454 -331
- package/test/lib/logging.test.js +1 -1
- package/test/lib/matrix.test.js +1 -1
- package/test/lib/mouse.test.js +327 -4
- package/test/lib/patterns.test.js +105 -0
- package/test/lib/promptOptions.test.js +179 -0
- package/test/lib/scene.test.js +16 -52
- package/test/lib/selectionManager.test.js +17 -5
- package/test/lib/settings.test.js +111 -5
- package/test/lib/snapping.test.js +142 -4
- package/test/lib/stateManager.test.js +155 -0
- package/test/lib/utils.test.js +81 -1
- package/test/objects/dictionary.test.js +81 -0
- package/test/objects/dictionaryManager.test.js +34 -0
- package/test/properties/dimType.test.js +62 -0
- package/test/properties/flags.test.js +164 -0
- package/test/properties/property.test.js +13 -0
- package/test/properties/propertyManager.test.js +10 -11
- package/test/tables/appId.test.js +46 -0
- package/test/tables/appIdManager.test.js +72 -0
- package/test/tables/block.test.js +157 -0
- package/test/tables/blockManager.test.js +52 -0
- package/test/tables/blockRecord.test.js +39 -0
- package/test/tables/blockRecordManager.test.js +60 -0
- package/test/tables/dimstyle.test.js +72 -0
- package/test/tables/endblk.test.js +30 -0
- package/test/tables/layer.test.js +95 -0
- package/test/tables/layerManager.test.js +172 -0
- package/test/{styles → tables}/ltype.test.js +7 -7
- package/test/{styles → tables}/ltypeManager.test.js +2 -2
- package/test/tables/style.test.js +44 -0
- package/test/tables/stylemanagerbase.test.js +220 -0
- package/test/tables/tableManagerBase.test.js +194 -0
- package/test/tables/ucs.test.js +37 -0
- package/test/tables/ucsManager.test.js +48 -0
- package/test/tables/view.test.js +37 -0
- package/test/tables/viewManager.test.js +48 -0
- package/test/tables/vport.test.js +117 -0
- package/test/tables/vportManager.test.js +54 -0
- package/test/test-helpers/test-helpers.js +66 -0
- package/test/tools/chamfer.test.js +970 -0
- package/test/tools/chamferFilletBase.test.js +446 -0
- package/test/tools/copy.test.js +22 -14
- package/test/tools/copybase.test.js +93 -0
- package/test/tools/copyclip.test.js +92 -0
- package/test/tools/cornerEntity.test.js +201 -0
- package/test/tools/cutclip.test.js +94 -0
- package/test/tools/distance.test.js +140 -18
- package/test/tools/erase.test.js +12 -12
- package/test/tools/explode.test.js +45 -0
- package/test/tools/extend.test.js +326 -44
- package/test/tools/fillet.test.js +831 -0
- package/test/tools/identify.test.js +115 -16
- package/test/tools/matchProp.test.js +84 -0
- package/test/tools/mirror.test.js +475 -0
- package/test/tools/move.test.js +75 -19
- package/test/tools/offset.test.js +748 -0
- package/test/tools/pan.test.js +72 -0
- package/test/tools/pasteclip.test.js +100 -0
- package/test/tools/purge.test.js +89 -0
- package/test/tools/rotate.test.js +89 -23
- package/test/tools/scale.test.js +529 -0
- package/test/tools/trim.test.js +419 -84
- package/test/tools/zoom.test.js +504 -0
- package/core/entities/alignedDimension.js +0 -279
- package/core/entities/angularDimension.js +0 -194
- package/core/entities/baseDimension.js +0 -227
- package/core/entities/block.js +0 -247
- package/core/entities/diametricDimension.js +0 -133
- package/core/entities/dimension.js +0 -202
- package/core/entities/radialDimension.js +0 -126
- package/core/styles/dimStyle.js +0 -719
- package/core/styles/dimStyleManager.js +0 -47
- package/core/styles/layer.js +0 -133
- package/core/styles/layerManager.js +0 -40
- package/core/styles/ltype.js +0 -86
- package/core/styles/ltypeManager.js +0 -50
- package/core/styles/style.js +0 -158
- package/core/styles/styleManager.js +0 -43
- package/core/styles/styleManagerBase.js +0 -299
- package/test/entities/block.test.js +0 -22
- package/test/styles/dimstyle.test.js +0 -19
- package/test/styles/layerManager.test.js +0 -150
- package/test/styles/style.test.js +0 -33
- package/test/styles/stylemanagerbase.test.js +0 -219
package/test/lib/logging.test.js
CHANGED
package/test/lib/matrix.test.js
CHANGED
package/test/lib/mouse.test.js
CHANGED
|
@@ -1,5 +1,328 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import { Core } from '../../core/core/core.js';
|
|
2
|
+
import { DesignCore } from '../../core/designCore.js';
|
|
3
|
+
import { Point } from '../../core/entities/point.js';
|
|
4
|
+
import { Matrix } from '../../core/lib/matrix.js';
|
|
5
|
+
import { expect, jest } from '@jest/globals';
|
|
4
6
|
|
|
5
|
-
|
|
7
|
+
const core = new Core();
|
|
8
|
+
const mouse = core.mouse;
|
|
9
|
+
|
|
10
|
+
test('Test Mouse constructor defaults', () => {
|
|
11
|
+
expect(mouse.x).toBe(0);
|
|
12
|
+
expect(mouse.y).toBe(0);
|
|
13
|
+
expect(mouse.buttonOneDown).toBe(false);
|
|
14
|
+
expect(mouse.buttonTwoDown).toBe(false);
|
|
15
|
+
expect(mouse.buttonThreeDown).toBe(false);
|
|
16
|
+
expect(mouse.mouseDownCanvasPoint).toBeDefined();
|
|
17
|
+
expect(mouse.lastClick).toBe(0);
|
|
18
|
+
expect(mouse.lastButton).toBe(0);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
test('Test Mouse.pointOnCanvas', () => {
|
|
22
|
+
mouse.x = 150;
|
|
23
|
+
mouse.y = 200;
|
|
24
|
+
const pt = mouse.pointOnCanvas();
|
|
25
|
+
expect(pt).toBeInstanceOf(Point);
|
|
26
|
+
expect(pt.x).toBe(150);
|
|
27
|
+
expect(pt.y).toBe(200);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
test('Test Mouse.pointOnScene returns Point', () => {
|
|
31
|
+
mouse.x = 100;
|
|
32
|
+
mouse.y = 50;
|
|
33
|
+
const pt = mouse.pointOnScene();
|
|
34
|
+
expect(pt).toBeInstanceOf(Point);
|
|
35
|
+
expect(typeof pt.x).toBe('number');
|
|
36
|
+
expect(typeof pt.y).toBe('number');
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
test('Test Mouse.transformToScene and transformToCanvas are inverse', () => {
|
|
40
|
+
core.canvas.matrix = new Matrix();
|
|
41
|
+
core.canvas.height = 600;
|
|
42
|
+
|
|
43
|
+
const scenePoint = new Point(250, 300);
|
|
44
|
+
const canvasPoint = mouse.transformToCanvas(scenePoint);
|
|
45
|
+
const roundTrip = mouse.transformToScene(canvasPoint);
|
|
46
|
+
|
|
47
|
+
expect(roundTrip.x).toBeCloseTo(scenePoint.x, 5);
|
|
48
|
+
expect(roundTrip.y).toBeCloseTo(scenePoint.y, 5);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
test('Test Mouse.positionString format', () => {
|
|
52
|
+
mouse.x = 0;
|
|
53
|
+
mouse.y = 0;
|
|
54
|
+
const str = mouse.positionString();
|
|
55
|
+
expect(typeof str).toBe('string');
|
|
56
|
+
expect(str).toMatch(/X: .+ Y: .+/);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
test('Test Mouse.positionString returns empty string when buttonOneDown', () => {
|
|
60
|
+
mouse.lastClick = 0;
|
|
61
|
+
mouse.mouseDown(0);
|
|
62
|
+
expect(mouse.positionString()).toBe('');
|
|
63
|
+
mouse.mouseUp(0);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
test('Test Mouse.positionString returns empty string when buttonTwoDown', () => {
|
|
67
|
+
mouse.lastClick = 0;
|
|
68
|
+
mouse.mouseDown(1);
|
|
69
|
+
expect(mouse.positionString()).toBe('');
|
|
70
|
+
mouse.mouseUp(1);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
test('Test Mouse.positionString returns empty string when buttonThreeDown', () => {
|
|
74
|
+
mouse.lastClick = 0;
|
|
75
|
+
mouse.mouseDown(2);
|
|
76
|
+
expect(mouse.positionString()).toBe('');
|
|
77
|
+
mouse.mouseUp(2);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
test('Test Mouse.positionString returns coordinate string when no buttons down', () => {
|
|
81
|
+
mouse.buttonOneDown = false;
|
|
82
|
+
mouse.buttonTwoDown = false;
|
|
83
|
+
mouse.buttonThreeDown = false;
|
|
84
|
+
expect(mouse.positionString()).toMatch(/X: .+ Y: .+/);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
test('Test Mouse.mouseDown sets button states', () => {
|
|
88
|
+
mouse.lastClick = 0;
|
|
89
|
+
|
|
90
|
+
mouse.mouseDown(0);
|
|
91
|
+
expect(mouse.buttonOneDown).toBe(true);
|
|
92
|
+
mouse.mouseUp(0);
|
|
93
|
+
|
|
94
|
+
mouse.mouseDown(1);
|
|
95
|
+
expect(mouse.buttonTwoDown).toBe(true);
|
|
96
|
+
mouse.mouseUp(1);
|
|
97
|
+
|
|
98
|
+
mouse.mouseDown(2);
|
|
99
|
+
expect(mouse.buttonThreeDown).toBe(true);
|
|
100
|
+
mouse.mouseUp(2);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
test('Test Mouse.mouseUp clears button states', () => {
|
|
104
|
+
mouse.lastClick = 0;
|
|
105
|
+
|
|
106
|
+
mouse.mouseDown(0);
|
|
107
|
+
mouse.mouseUp(0);
|
|
108
|
+
expect(mouse.buttonOneDown).toBe(false);
|
|
109
|
+
|
|
110
|
+
mouse.mouseDown(1);
|
|
111
|
+
mouse.mouseUp(1);
|
|
112
|
+
expect(mouse.buttonTwoDown).toBe(false);
|
|
113
|
+
|
|
114
|
+
mouse.mouseDown(2);
|
|
115
|
+
mouse.mouseUp(2);
|
|
116
|
+
expect(mouse.buttonThreeDown).toBe(false);
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
test('Test Mouse.mouseDown sets mouseDownCanvasPoint', () => {
|
|
120
|
+
mouse.x = 42;
|
|
121
|
+
mouse.y = 84;
|
|
122
|
+
mouse.lastClick = 0;
|
|
123
|
+
mouse.mouseDown(0);
|
|
124
|
+
expect(mouse.mouseDownCanvasPoint.x).toBe(42);
|
|
125
|
+
expect(mouse.mouseDownCanvasPoint.y).toBe(84);
|
|
126
|
+
mouse.mouseUp(0);
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
test('Test Mouse.mouseMoved updates position', () => {
|
|
130
|
+
core.canvas.height = 600;
|
|
131
|
+
mouse.mouseMoved(300, 400);
|
|
132
|
+
expect(mouse.x).toBe(300);
|
|
133
|
+
// y is inverted: -y + canvas.height = -400 + 600 = 200
|
|
134
|
+
expect(mouse.y).toBe(200);
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
test('Test Mouse.mouseMoved updates position when button is held down', () => {
|
|
138
|
+
core.canvas.height = 600;
|
|
139
|
+
mouse.lastClick = 0;
|
|
140
|
+
mouse.mouseDown(1); // buttonTwoDown (pan)
|
|
141
|
+
mouse.mouseMoved(100, 200);
|
|
142
|
+
expect(mouse.x).toBe(100);
|
|
143
|
+
expect(mouse.y).toBe(400); // -200 + 600
|
|
144
|
+
mouse.mouseUp(1);
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
test('Test Mouse.mouseMoved skips polar snap when a button is held down', () => {
|
|
148
|
+
core.canvas.height = 600;
|
|
149
|
+
const prevPolar = DesignCore.Settings.polar;
|
|
150
|
+
DesignCore.Settings.polar = true;
|
|
151
|
+
const polarSpy = jest.spyOn(core.scene.inputManager.snapping, 'polarSnap');
|
|
152
|
+
try {
|
|
153
|
+
mouse.lastClick = 0;
|
|
154
|
+
mouse.mouseDown(1);
|
|
155
|
+
mouse.mouseMoved(200, 300);
|
|
156
|
+
expect(polarSpy).not.toHaveBeenCalled();
|
|
157
|
+
mouse.mouseUp(1);
|
|
158
|
+
} finally {
|
|
159
|
+
DesignCore.Settings.polar = prevPolar;
|
|
160
|
+
polarSpy.mockRestore();
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
test('Test Mouse.mouseMoved skips ortho snap when a button is held down', () => {
|
|
165
|
+
core.canvas.height = 600;
|
|
166
|
+
const prevPolar = DesignCore.Settings.polar;
|
|
167
|
+
const prevOrtho = DesignCore.Settings.ortho;
|
|
168
|
+
DesignCore.Settings.polar = false;
|
|
169
|
+
DesignCore.Settings.ortho = true;
|
|
170
|
+
const orthoSpy = jest.spyOn(core.scene.inputManager.snapping, 'orthoSnap');
|
|
171
|
+
try {
|
|
172
|
+
mouse.lastClick = 0;
|
|
173
|
+
mouse.mouseDown(1);
|
|
174
|
+
mouse.mouseMoved(200, 300);
|
|
175
|
+
expect(orthoSpy).not.toHaveBeenCalled();
|
|
176
|
+
mouse.mouseUp(1);
|
|
177
|
+
} finally {
|
|
178
|
+
DesignCore.Settings.polar = prevPolar;
|
|
179
|
+
DesignCore.Settings.ortho = prevOrtho;
|
|
180
|
+
orthoSpy.mockRestore();
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
test('Test Mouse.setPosFromScenePoint', () => {
|
|
185
|
+
core.canvas.matrix = new Matrix();
|
|
186
|
+
core.canvas.height = 600;
|
|
187
|
+
|
|
188
|
+
const scenePoint = new Point(100, 200);
|
|
189
|
+
mouse.setPosFromScenePoint(scenePoint);
|
|
190
|
+
|
|
191
|
+
// Convert back to verify round-trip
|
|
192
|
+
const result = mouse.pointOnScene();
|
|
193
|
+
expect(result.x).toBeCloseTo(scenePoint.x, 5);
|
|
194
|
+
expect(result.y).toBeCloseTo(scenePoint.y, 5);
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
test('Test Mouse.isDoubleClick', () => {
|
|
198
|
+
// First click is never a double click
|
|
199
|
+
mouse.lastClick = 0;
|
|
200
|
+
expect(mouse.isDoubleClick(0)).toBe(false);
|
|
201
|
+
|
|
202
|
+
// Immediate second click should be a double click
|
|
203
|
+
expect(mouse.isDoubleClick(0)).toBe(true);
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
test('Test Mouse.isDoubleClick with different buttons', () => {
|
|
207
|
+
// Different buttons in quick succession should not be a double click
|
|
208
|
+
mouse.lastClick = 0;
|
|
209
|
+
mouse.isDoubleClick(0); // first click - left button
|
|
210
|
+
expect(mouse.isDoubleClick(1)).toBe(false); // second click - middle button
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
test('Test Mouse.wheel delegates to canvas', () => {
|
|
214
|
+
const scaleBefore = core.canvas.getScale();
|
|
215
|
+
mouse.wheel(1);
|
|
216
|
+
expect(core.canvas.getScale()).not.toBe(scaleBefore);
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
// ─── isDoubleClick ────────────────────────────────────────────────────────────
|
|
220
|
+
|
|
221
|
+
test('Test Mouse.isDoubleClick - slow second click is not a double click', () => {
|
|
222
|
+
const doubleClickThreshold = 250;
|
|
223
|
+
mouse.lastClick = 0;
|
|
224
|
+
mouse.isDoubleClick(0); // first click
|
|
225
|
+
// advance lastClick far enough back to exceed the threshold
|
|
226
|
+
mouse.lastClick = new Date().getTime() - doubleClickThreshold - 1;
|
|
227
|
+
expect(mouse.isDoubleClick(0)).toBe(false);
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
test('Test Mouse.isDoubleClick - updates lastButton', () => {
|
|
231
|
+
mouse.lastClick = 0;
|
|
232
|
+
mouse.lastButton = 0;
|
|
233
|
+
mouse.isDoubleClick(2);
|
|
234
|
+
expect(mouse.lastButton).toBe(2);
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
// ─── doubleClick ──────────────────────────────────────────────────────────────
|
|
238
|
+
|
|
239
|
+
test('Test Mouse.doubleClick delegates to Canvas.doubleClick', () => {
|
|
240
|
+
const spy = jest.spyOn(core.canvas, 'doubleClick').mockImplementation(() => {});
|
|
241
|
+
mouse.doubleClick(0);
|
|
242
|
+
expect(spy).toHaveBeenCalledWith(0);
|
|
243
|
+
spy.mockRestore();
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
test('Test Mouse.mouseDown triggers doubleClick on rapid second click', () => {
|
|
247
|
+
const spy = jest.spyOn(mouse, 'doubleClick').mockImplementation(() => {});
|
|
248
|
+
mouse.lastClick = 0;
|
|
249
|
+
mouse.mouseDown(0); // first click
|
|
250
|
+
mouse.mouseUp(0);
|
|
251
|
+
mouse.mouseDown(0); // immediate second click — should be double click
|
|
252
|
+
expect(spy).toHaveBeenCalledWith(0);
|
|
253
|
+
spy.mockRestore();
|
|
254
|
+
mouse.mouseUp(0);
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
// ─── mouseDown / mouseUp – unhandled button ───────────────────────────────────
|
|
258
|
+
|
|
259
|
+
test('Test Mouse.mouseDown with unhandled button does not change state', () => {
|
|
260
|
+
mouse.buttonOneDown = false;
|
|
261
|
+
mouse.buttonTwoDown = false;
|
|
262
|
+
mouse.buttonThreeDown = false;
|
|
263
|
+
mouse.lastClick = 0;
|
|
264
|
+
mouse.mouseDown(99);
|
|
265
|
+
expect(mouse.buttonOneDown).toBe(false);
|
|
266
|
+
expect(mouse.buttonTwoDown).toBe(false);
|
|
267
|
+
expect(mouse.buttonThreeDown).toBe(false);
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
test('Test Mouse.mouseUp with unhandled button does not change state', () => {
|
|
271
|
+
mouse.buttonOneDown = true;
|
|
272
|
+
mouse.buttonTwoDown = true;
|
|
273
|
+
mouse.buttonThreeDown = true;
|
|
274
|
+
mouse.mouseUp(99);
|
|
275
|
+
expect(mouse.buttonOneDown).toBe(true);
|
|
276
|
+
expect(mouse.buttonTwoDown).toBe(true);
|
|
277
|
+
expect(mouse.buttonThreeDown).toBe(true);
|
|
278
|
+
// restore
|
|
279
|
+
mouse.buttonOneDown = false;
|
|
280
|
+
mouse.buttonTwoDown = false;
|
|
281
|
+
mouse.buttonThreeDown = false;
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
// ─── mouseUp – delegates to Canvas ───────────────────────────────────────────
|
|
285
|
+
|
|
286
|
+
test('Test Mouse.mouseUp delegates to Canvas.mouseUp', () => {
|
|
287
|
+
mouse.lastClick = 0;
|
|
288
|
+
mouse.mouseDown(0);
|
|
289
|
+
const spy = jest.spyOn(core.canvas, 'mouseUp').mockImplementation(() => {});
|
|
290
|
+
mouse.mouseUp(0);
|
|
291
|
+
expect(spy).toHaveBeenCalledWith(0);
|
|
292
|
+
spy.mockRestore();
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
// ─── mouseMoved – delegates to Canvas ────────────────────────────────────────
|
|
296
|
+
|
|
297
|
+
test('Test Mouse.mouseMoved delegates to Canvas.mouseMoved', () => {
|
|
298
|
+
const spy = jest.spyOn(core.canvas, 'mouseMoved').mockImplementation(() => {});
|
|
299
|
+
mouse.mouseMoved(10, 20);
|
|
300
|
+
expect(spy).toHaveBeenCalled();
|
|
301
|
+
spy.mockRestore();
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
// ─── positionString – correct coordinate values ───────────────────────────────
|
|
305
|
+
|
|
306
|
+
test('Test Mouse.positionString reports current scene coordinates', () => {
|
|
307
|
+
mouse.buttonOneDown = false;
|
|
308
|
+
mouse.buttonTwoDown = false;
|
|
309
|
+
mouse.buttonThreeDown = false;
|
|
310
|
+
const scenePoint = mouse.pointOnScene();
|
|
311
|
+
const str = mouse.positionString();
|
|
312
|
+
expect(str).toContain(`X: ${scenePoint.x.toFixed(1)}`);
|
|
313
|
+
expect(str).toContain(`Y: ${scenePoint.y.toFixed(1)}`);
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
// ─── setPosFromScenePoint – x/y updated directly ─────────────────────────────
|
|
317
|
+
|
|
318
|
+
test('Test Mouse.setPosFromScenePoint sets x and y from scene coordinates', () => {
|
|
319
|
+
core.canvas.height = 600;
|
|
320
|
+
|
|
321
|
+
const scenePoint = new Point(123, 456);
|
|
322
|
+
mouse.setPosFromScenePoint(scenePoint);
|
|
323
|
+
|
|
324
|
+
// The canvas point is what transformToCanvas returns
|
|
325
|
+
const expected = mouse.transformToCanvas(scenePoint);
|
|
326
|
+
expect(mouse.x).toBeCloseTo(expected.x, 5);
|
|
327
|
+
expect(mouse.y).toBeCloseTo(expected.y, 5);
|
|
328
|
+
});
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { PatternLine, Patterns } from '../../core/lib/patterns.js';
|
|
2
|
+
|
|
3
|
+
test('Test Patterns.getPattern', () => {
|
|
4
|
+
const pattern = Patterns.getPattern('HONEY');
|
|
5
|
+
expect(pattern.length).toBe(3);
|
|
6
|
+
pattern.forEach((patternLine) => {
|
|
7
|
+
expect(patternLine instanceof PatternLine).toBe(true);
|
|
8
|
+
});
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
test('Test Patterns.getPattern returns cached result', () => {
|
|
12
|
+
const first = Patterns.getPattern('ANSI31');
|
|
13
|
+
const second = Patterns.getPattern('ANSI31');
|
|
14
|
+
expect(first).toBe(second);
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
test('Test Patterns.getPattern cache is case-insensitive', () => {
|
|
18
|
+
const upper = Patterns.getPattern('HONEY');
|
|
19
|
+
const lower = Patterns.getPattern('honey');
|
|
20
|
+
const mixed = Patterns.getPattern('Honey');
|
|
21
|
+
expect(upper).toBe(lower);
|
|
22
|
+
expect(upper).toBe(mixed);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
test('Test Patterns.getPattern returns frozen pattern array and objects', () => {
|
|
26
|
+
const pattern = Patterns.getPattern('ANSI31');
|
|
27
|
+
expect(Object.isFrozen(pattern)).toBe(true);
|
|
28
|
+
pattern.forEach((patternLine) => {
|
|
29
|
+
expect(Object.isFrozen(patternLine)).toBe(true);
|
|
30
|
+
expect(Object.isFrozen(patternLine.dashes)).toBe(true);
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
test('Test Patterns.getPattern frozen cache is not corrupted by caller mutation attempts', () => {
|
|
35
|
+
const pattern = Patterns.getPattern('ANSI31');
|
|
36
|
+
const originalAngle = pattern[0].angle;
|
|
37
|
+
const originalDashLength = pattern[0].dashes.length;
|
|
38
|
+
const originalLength = pattern.length;
|
|
39
|
+
|
|
40
|
+
// In strict mode (ESM), mutating frozen objects throws TypeError
|
|
41
|
+
expect(() => {
|
|
42
|
+
pattern[0].angle = 999;
|
|
43
|
+
}).toThrow(TypeError);
|
|
44
|
+
expect(() => {
|
|
45
|
+
pattern[0].dashes.push(999);
|
|
46
|
+
}).toThrow(TypeError);
|
|
47
|
+
expect(() => {
|
|
48
|
+
pattern.push(null);
|
|
49
|
+
}).toThrow(TypeError);
|
|
50
|
+
|
|
51
|
+
// Cache is unaffected
|
|
52
|
+
const patternAgain = Patterns.getPattern('ANSI31');
|
|
53
|
+
expect(patternAgain[0].angle).toBe(originalAngle);
|
|
54
|
+
expect(patternAgain[0].dashes.length).toBe(originalDashLength);
|
|
55
|
+
expect(patternAgain.length).toBe(originalLength);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
test('Test Patterns.getPatternLineCount', () => {
|
|
60
|
+
expect(Patterns.getPatternLineCount('HONEY')).toBe(3);
|
|
61
|
+
expect(Patterns.getPatternLineCount('hOnEy')).toBe(3);
|
|
62
|
+
expect(Patterns.getPatternLineCount('ansi34')).toBe(4);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
test('Test Patterns.patternExists', () => {
|
|
66
|
+
expect(Patterns.patternExists('HONEY')).toBe(true);
|
|
67
|
+
expect(Patterns.patternExists('hOnEy')).toBe(true);
|
|
68
|
+
expect(Patterns.patternExists('ansi34')).toBe(true);
|
|
69
|
+
|
|
70
|
+
expect(Patterns.patternExists('fakeName')).toBe(false);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
test('Test PatternLine.loadPatternLine', () => {
|
|
75
|
+
const patternLine = new PatternLine();
|
|
76
|
+
const patternString = `45, 0, 0, 0, 3.175`;
|
|
77
|
+
|
|
78
|
+
patternLine.loadPatternLine(patternString);
|
|
79
|
+
|
|
80
|
+
expect(patternLine.angle).toBe(45);
|
|
81
|
+
expect(patternLine.xOrigin).toBe(0);
|
|
82
|
+
expect(patternLine.yOrigin).toBe(0);
|
|
83
|
+
expect(patternLine.xDelta).toBe(0);
|
|
84
|
+
expect(patternLine.yDelta).toBe(3.175);
|
|
85
|
+
expect(patternLine.dashes.length).toBe(0);
|
|
86
|
+
|
|
87
|
+
const patternStringwithDashes = `120, 0, 0, 4.7625, 2.749630645, 3.175, -6.35 `;
|
|
88
|
+
|
|
89
|
+
patternLine.loadPatternLine(patternStringwithDashes);
|
|
90
|
+
|
|
91
|
+
expect(patternLine.angle).toBe(120);
|
|
92
|
+
expect(patternLine.xOrigin).toBe(0);
|
|
93
|
+
expect(patternLine.yOrigin).toBe(0);
|
|
94
|
+
expect(patternLine.xDelta).toBe(4.7625);
|
|
95
|
+
expect(patternLine.yDelta).toBe(2.749630645);
|
|
96
|
+
expect(patternLine.dashes.length).toBe(2);
|
|
97
|
+
expect(patternLine.dashes[0]).toBe(3.175);
|
|
98
|
+
expect(patternLine.dashes[1]).toBe(-6.35);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
test('Test PatternLine.getDashLength', () => {
|
|
102
|
+
const patternStringwithDashes = `120, 0, 0, 4.7625, 2.749630645, 3.175, -6.35 `;
|
|
103
|
+
const patternLine = new PatternLine(patternStringwithDashes);
|
|
104
|
+
expect(patternLine.getDashLength()).toBeCloseTo(9.5249);
|
|
105
|
+
});
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import { Core } from '../../core/core/core.js';
|
|
2
|
+
import { Point } from '../../core/entities/point.js';
|
|
3
|
+
import { Input, PromptOptions } from '../../core/lib/inputManager.js';
|
|
4
|
+
import { expect, jest } from '@jest/globals';
|
|
5
|
+
|
|
6
|
+
// Core must be initialised so that DesignCore.Core is available for
|
|
7
|
+
// PromptOptions.respond() to call Core.notify() on bad input.
|
|
8
|
+
const core = new Core();
|
|
9
|
+
|
|
10
|
+
// ─── Constructor ─────────────────────────────────────────────────────────────
|
|
11
|
+
|
|
12
|
+
test('constructor uses default values when no arguments are supplied', () => {
|
|
13
|
+
const po = new PromptOptions();
|
|
14
|
+
expect(po.promptMessage).toBe('error');
|
|
15
|
+
expect(po.types).toEqual([]);
|
|
16
|
+
expect(po.options).toEqual([]);
|
|
17
|
+
expect(po.defaultValue).toBeUndefined();
|
|
18
|
+
expect(po.resolve).toBeUndefined();
|
|
19
|
+
expect(po.reject).toBeUndefined();
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
test('constructor stores all supplied arguments', () => {
|
|
23
|
+
const types = [Input.Type.POINT, Input.Type.NUMBER];
|
|
24
|
+
const options = ['One', 'Two', 'Three'];
|
|
25
|
+
const po = new PromptOptions('Select a point', types, options, 42);
|
|
26
|
+
expect(po.promptMessage).toBe('Select a point');
|
|
27
|
+
expect(po.types).toBe(types);
|
|
28
|
+
expect(po.options).toBe(options);
|
|
29
|
+
expect(po.defaultValue).toBe(42);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
test('constructor defaultValue is undefined when not provided', () => {
|
|
33
|
+
const po = new PromptOptions('Enter value', [Input.Type.NUMBER]);
|
|
34
|
+
expect(po.defaultValue).toBeUndefined();
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
// ─── acceptsInput ─────────────────────────────────────────────────────────────
|
|
38
|
+
|
|
39
|
+
test('acceptsInput returns true for exact matching type', () => {
|
|
40
|
+
const po = new PromptOptions('', [Input.Type.POINT]);
|
|
41
|
+
expect(po.acceptsInput(new Point(1, 2))).toBe(true);
|
|
42
|
+
expect(po.acceptsInput('text')).toBe(false);
|
|
43
|
+
expect(po.acceptsInput(42)).toBe(false);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
test('acceptsInput returns true for DYNAMIC type with numeric input', () => {
|
|
47
|
+
const po = new PromptOptions('', [Input.Type.DYNAMIC]);
|
|
48
|
+
expect(po.acceptsInput(42)).toBe(true);
|
|
49
|
+
expect(po.acceptsInput(3.14)).toBe(true);
|
|
50
|
+
expect(po.acceptsInput('text')).toBe(false);
|
|
51
|
+
expect(po.acceptsInput(new Point())).toBe(false);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
test('acceptsInput returns true when any of multiple types matches', () => {
|
|
55
|
+
const po = new PromptOptions('', [Input.Type.POINT, Input.Type.NUMBER]);
|
|
56
|
+
expect(po.acceptsInput(new Point(1, 2))).toBe(true);
|
|
57
|
+
expect(po.acceptsInput(42)).toBe(true);
|
|
58
|
+
expect(po.acceptsInput('text')).toBe(false);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
// ─── createPromise ────────────────────────────────────────────────────────────
|
|
62
|
+
|
|
63
|
+
test('createPromise returns a Promise and sets resolve and reject', async () => {
|
|
64
|
+
const po = new PromptOptions('', [Input.Type.STRING]);
|
|
65
|
+
const p = po.createPromise();
|
|
66
|
+
expect(p).toBeInstanceOf(Promise);
|
|
67
|
+
expect(typeof po.resolve).toBe('function');
|
|
68
|
+
expect(typeof po.reject).toBe('function');
|
|
69
|
+
po.resolve('done');
|
|
70
|
+
await expect(p).resolves.toBe('done');
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
// ─── respond ─────────────────────────────────────────────────────────────────
|
|
74
|
+
|
|
75
|
+
test('respond returns true and resolves the promise when input matches accepted type', async () => {
|
|
76
|
+
const po = new PromptOptions('Enter text', [Input.Type.STRING]);
|
|
77
|
+
const p = po.createPromise();
|
|
78
|
+
const result = po.respond('hello');
|
|
79
|
+
expect(result).toBe(true);
|
|
80
|
+
await expect(p).resolves.toBe('hello');
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
test('respond returns true and resolves the promise when input matches an option', async () => {
|
|
84
|
+
const po = new PromptOptions('Choose', [Input.Type.POINT], ['Yes', 'No']);
|
|
85
|
+
const p = po.createPromise();
|
|
86
|
+
const result = po.respond('Y');
|
|
87
|
+
expect(result).toBe(true);
|
|
88
|
+
await expect(p).resolves.toBe('Yes');
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
test('respond returns false and calls Core.notify when input is invalid', () => {
|
|
92
|
+
const notifySpy = jest.spyOn(core, 'notify').mockImplementation(() => {});
|
|
93
|
+
const po = new PromptOptions('Enter point', [Input.Type.POINT]);
|
|
94
|
+
po.createPromise();
|
|
95
|
+
const result = po.respond('invalid string');
|
|
96
|
+
expect(result).toBe(false);
|
|
97
|
+
expect(notifySpy).toHaveBeenCalled();
|
|
98
|
+
notifySpy.mockRestore();
|
|
99
|
+
po.cancel();
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
// ─── parseInputToOption ───────────────────────────────────────────────────────
|
|
103
|
+
|
|
104
|
+
test('parseInputToOption returns undefined when no options are defined', () => {
|
|
105
|
+
const po = new PromptOptions('Enter value', [Input.Type.STRING]);
|
|
106
|
+
expect(po.parseInputToOption('A')).toBeUndefined();
|
|
107
|
+
expect(po.parseInputToOption('X')).toBeUndefined();
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
test('parseInputToOption returns undefined for non-string input', () => {
|
|
111
|
+
const po = new PromptOptions('Choose', [], ['Apple']);
|
|
112
|
+
expect(po.parseInputToOption(42)).toBeUndefined();
|
|
113
|
+
expect(po.parseInputToOption(new Point())).toBeUndefined();
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
test('parseInputToOption matches options by case-insensitive prefix', () => {
|
|
117
|
+
const po = new PromptOptions('Select option', [Input.Type.STRING], ['Apple', 'Banana', 'Cherry']);
|
|
118
|
+
expect(po.parseInputToOption('A')).toBe('Apple');
|
|
119
|
+
expect(po.parseInputToOption('B')).toBe('Banana');
|
|
120
|
+
expect(po.parseInputToOption('C')).toBe('Cherry');
|
|
121
|
+
expect(po.parseInputToOption('a')).toBe('Apple');
|
|
122
|
+
expect(po.parseInputToOption('Apple')).toBe('Apple');
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
test('parseInputToOption returns undefined when no option matches', () => {
|
|
126
|
+
const po = new PromptOptions('Choose', [], ['Apple', 'Banana']);
|
|
127
|
+
expect(po.parseInputToOption('X')).toBeUndefined();
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
// ─── cancel ──────────────────────────────────────────────────────────────────
|
|
131
|
+
|
|
132
|
+
test('cancel resolves the pending promise with undefined', async () => {
|
|
133
|
+
const po = new PromptOptions('Enter point', [Input.Type.POINT]);
|
|
134
|
+
const p = po.createPromise();
|
|
135
|
+
po.cancel();
|
|
136
|
+
await expect(p).resolves.toBeUndefined();
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
test('cancel is a no-op when no promise has been created', () => {
|
|
140
|
+
const po = new PromptOptions('', [Input.Type.STRING]);
|
|
141
|
+
expect(() => po.cancel()).not.toThrow();
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
// ─── getPrompt ────────────────────────────────────────────────────────────────
|
|
145
|
+
|
|
146
|
+
test('getPrompt returns bare message when no options or defaultValue are set', () => {
|
|
147
|
+
const po = new PromptOptions('Enter value', [Input.Type.NUMBER]);
|
|
148
|
+
expect(po.getPrompt()).toBe('Enter value');
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
test('getPrompt includes OR keyword and underscored shortcuts when options are set', () => {
|
|
152
|
+
const po = new PromptOptions('Select', [Input.Type.STRING], ['Apple', 'Banana']);
|
|
153
|
+
const prompt = po.getPrompt();
|
|
154
|
+
expect(prompt).toContain('Select');
|
|
155
|
+
expect(prompt).toContain('or');
|
|
156
|
+
expect(prompt).toContain('A\u0332pple');
|
|
157
|
+
expect(prompt).toContain('B\u0332anana');
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
test('getPrompt appends <defaultValue> when defaultValue is set', () => {
|
|
161
|
+
const po = new PromptOptions('Enter distance', [Input.Type.NUMBER], [], 10);
|
|
162
|
+
expect(po.getPrompt()).toBe('Enter distance <10>');
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
test('getPrompt appends <defaultValue> after the options bracket when both are set', () => {
|
|
166
|
+
const po = new PromptOptions('Select', [Input.Type.STRING], ['Apple', 'Banana'], 'Apple');
|
|
167
|
+
const prompt = po.getPrompt();
|
|
168
|
+
expect(prompt).toContain('A\u0332pple');
|
|
169
|
+
expect(prompt).toMatch(/<Apple>$/);
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
// ─── getOptionWithShortcut ────────────────────────────────────────────────────
|
|
173
|
+
|
|
174
|
+
test('getOptionWithShortcut underlines the first character of the option', () => {
|
|
175
|
+
const po = new PromptOptions();
|
|
176
|
+
expect(po.getOptionWithShortcut('input')).toBe('i\u0332nput');
|
|
177
|
+
expect(po.getOptionWithShortcut('Through')).toBe('T\u0332hrough');
|
|
178
|
+
expect(po.getOptionWithShortcut('A')).toBe('A\u0332');
|
|
179
|
+
});
|