@pie-lib/plot 2.7.4-next.0 → 2.7.4-next.1618

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.
@@ -0,0 +1,326 @@
1
+ import { shallow } from 'enzyme';
2
+ import React from 'react';
3
+ import { gridDraggable } from '../grid-draggable';
4
+ import { getDelta } from '../utils';
5
+
6
+ import { clientPoint } from 'd3-selection';
7
+
8
+ jest.mock('d3-selection', () => ({
9
+ clientPoint: jest.fn().mockReturnValue([0, 0]),
10
+ }));
11
+
12
+ jest.mock('../draggable', () => ({
13
+ DraggableCore: jest.fn((type, props, children) => children),
14
+ }));
15
+
16
+ jest.mock('../utils', () => ({
17
+ getDelta: jest.fn(),
18
+ }));
19
+
20
+ const xyFn = () => {
21
+ const out = jest.fn((n) => n);
22
+ out.invert = jest.fn((n) => n);
23
+ return out;
24
+ };
25
+ const getGraphProps = () => ({
26
+ scale: {
27
+ x: xyFn(),
28
+ y: xyFn(),
29
+ },
30
+ snap: {
31
+ x: xyFn(),
32
+ y: xyFn(),
33
+ },
34
+ domain: {
35
+ min: 0,
36
+ max: 1,
37
+ step: 1,
38
+ },
39
+ range: {
40
+ min: 0,
41
+ max: 1,
42
+ step: 1,
43
+ },
44
+ size: {
45
+ width: 500,
46
+ height: 500,
47
+ },
48
+ getRootNode: () => ({}),
49
+ });
50
+
51
+ describe('gridDraggable', () => {
52
+ const wrapper = (opts, extras) => {
53
+ const defaults = {
54
+ graphProps: getGraphProps(),
55
+ };
56
+
57
+ defaults.graphProps.scale.x.invert = jest.fn((x) => x);
58
+ defaults.graphProps.scale.y.invert = jest.fn((x) => x);
59
+
60
+ const props = { ...defaults, ...extras };
61
+
62
+ opts = {
63
+ anchorPoint: jest.fn().mockReturnValue({ x: 0, y: 0 }),
64
+ bounds: jest.fn().mockReturnValue({ left: 0, top: 0, bottom: 0, right: 0 }),
65
+ fromDelta: jest.fn(),
66
+ ...opts,
67
+ };
68
+
69
+ const Comp = gridDraggable(opts)(() => <div />);
70
+ return shallow(<Comp {...props} />);
71
+ };
72
+
73
+ describe('snapshot', () => {
74
+ it('reqular', () => {
75
+ const w = wrapper();
76
+ expect(w).toMatchSnapshot();
77
+ });
78
+
79
+ it('render with decimals', () => {
80
+ const w = wrapper(
81
+ {},
82
+ {
83
+ domain: {
84
+ min: -1.5,
85
+ max: 1.6,
86
+ step: 0.3,
87
+ },
88
+ range: {
89
+ min: -2,
90
+ max: 3,
91
+ step: 0.2,
92
+ },
93
+ },
94
+ );
95
+ expect(w).toMatchSnapshot();
96
+ });
97
+ });
98
+
99
+ describe('logic', () => {
100
+ describe('grid', () => {
101
+ it('returns the grid', () => {
102
+ const w = wrapper();
103
+ const g = w.instance().grid();
104
+ expect(g).toEqual({ x: 1, y: 1 });
105
+ });
106
+ });
107
+
108
+ describe('onStart', () => {
109
+ it('sets the drag state', () => {
110
+ const w = wrapper();
111
+ w.instance().onStart({ clientX: 100, clientY: 100 });
112
+ expect(w.state().startX).toEqual(100);
113
+ expect(w.state().startY).toEqual(100);
114
+ });
115
+
116
+ it('calls the handler', () => {
117
+ const onDragStart = jest.fn();
118
+ const w = wrapper(
119
+ {},
120
+ {
121
+ onDragStart,
122
+ },
123
+ );
124
+ w.instance().onStart({ clientX: 100, clientY: 100 });
125
+ expect(onDragStart).toHaveBeenCalled();
126
+ });
127
+ });
128
+
129
+ describe('position', () => {
130
+ it('returns position object', () => {
131
+ const w = wrapper();
132
+ const pos = w.instance().position();
133
+
134
+ const anchorPoint = {
135
+ x: 0,
136
+ y: 0,
137
+ };
138
+ expect(pos).toEqual({
139
+ anchorPoint,
140
+ x: expect.any(Function),
141
+ y: expect.any(Function),
142
+ });
143
+ });
144
+ });
145
+
146
+ describe('tiny', () => {
147
+ it('returns true for 10 ', () => {
148
+ const w = wrapper();
149
+ w.setState({ startX: 0 });
150
+ const result = w.instance().tiny('x', { clientX: 10 });
151
+ expect(result).toBe(false);
152
+ });
153
+ it('returns true for 0.01', () => {
154
+ const w = wrapper();
155
+ w.setState({ startX: 0 });
156
+ const result = w.instance().tiny('x', { clientX: 0.01 });
157
+ expect(result).toBe(true);
158
+ });
159
+ });
160
+
161
+ describe('onDrag', () => {
162
+ let onDrag, w;
163
+
164
+ beforeEach(() => {
165
+ onDrag = jest.fn();
166
+ w = wrapper({}, { onDrag });
167
+ w.instance().applyDelta = jest.fn().mockReturnValue(0);
168
+ w.instance().props.graphProps.getRootNode = jest.fn().mockReturnValue({
169
+ ownerSVGElement: null,
170
+ getBoundingClientRect: jest.fn(() => ({
171
+ left: 0,
172
+ top: 0,
173
+ right: 100,
174
+ bottom: 100,
175
+ })),
176
+ });
177
+ w.instance().getClientPoint = jest.fn().mockReturnValue([50, 50]); // Mocking getClientPoint
178
+ w.instance().onDrag({}, { x: 1, y: 1 });
179
+ });
180
+
181
+ it('calls applyDelta', () => {
182
+ expect(w.instance().applyDelta).toHaveBeenCalled();
183
+ });
184
+
185
+ it('calls callback', () => {
186
+ expect(onDrag).toHaveBeenCalledWith(0);
187
+ });
188
+
189
+ const bounds = (left, right, top, bottom) => ({ left, right, top, bottom });
190
+ describe('bounds', () => {
191
+ const assertEarlyExit = (bounds, dd) => {
192
+ it(`${JSON.stringify(bounds)}, ${dd.deltaX}, ${dd.deltaY} `, () => {
193
+ w = wrapper({}, { onDrag });
194
+ w.instance().getScaledBounds = jest.fn().mockReturnValue(bounds);
195
+ w.instance().getClientPoint = jest.fn().mockReturnValue([50, 50]);
196
+ w.instance().onDrag({}, dd);
197
+ expect(w.instance().getClientPoint).not.toHaveBeenCalled();
198
+ });
199
+ };
200
+ assertEarlyExit(bounds(0, 0, 0, 0), { deltaX: -10 });
201
+ assertEarlyExit(bounds(0, 0, 0, 0), { deltaX: 10 });
202
+ assertEarlyExit(bounds(-100, 100, 0, 0), { deltaY: -10 });
203
+ assertEarlyExit(bounds(-100, 100, -100, 0), { deltaY: 10 });
204
+ it('calls client point if it doesnt exit early bounds', () => {
205
+ w = wrapper({}, { onDrag });
206
+ w.instance().getScaledBounds = jest.fn().mockReturnValue(bounds(100, 100, 100, 100));
207
+ w.instance().getClientPoint = jest.fn().mockReturnValue([50, 50]);
208
+ w.instance().onDrag({}, { deltaX: 10 });
209
+ expect(w.instance().getClientPoint).toHaveBeenCalled(); // Asserting that getClientPoint is called
210
+ });
211
+ });
212
+ });
213
+
214
+ describe('skipDragOutsideOfBounds', () => {
215
+ let w;
216
+ const assertSkipDrag = (dd, rawXFn, rawYFn, expected) => {
217
+ rawXFn = rawXFn || ((x) => x);
218
+ rawYFn = rawYFn || ((y) => y);
219
+
220
+ it(`${dd.deltaX}, ${dd.deltaY}, ${expected}`, () => {
221
+ w = wrapper({});
222
+ const gp = getGraphProps();
223
+
224
+ const mockGetBoundingClientRect = jest.fn(() => ({
225
+ left: 0,
226
+ top: 0,
227
+ right: 100,
228
+ bottom: 100,
229
+ }));
230
+
231
+ w.instance().getClientPoint = jest.fn(() => [
232
+ rawXFn(gp.domain.min, gp.domain.max),
233
+ rawYFn(gp.range.min, gp.range.max),
234
+ ]);
235
+
236
+ const rootNode = {
237
+ ownerSVGElement: null,
238
+ getBoundingClientRect: mockGetBoundingClientRect,
239
+ };
240
+
241
+ const result = w.instance().skipDragOutsideOfBounds(dd, {}, { ...gp, getRootNode: () => rootNode });
242
+ expect(result).toEqual(expected);
243
+ });
244
+ };
245
+ assertSkipDrag(
246
+ { deltaX: 1 },
247
+ (min, max) => min - 1,
248
+ (min, max) => min,
249
+ true,
250
+ );
251
+ assertSkipDrag(
252
+ { deltaX: -1 },
253
+ (min, max) => max + 1,
254
+ (min, max) => min,
255
+ true,
256
+ );
257
+ assertSkipDrag(
258
+ { deltaY: 1 },
259
+ (min, max) => max,
260
+ (min, max) => max + 1,
261
+ true,
262
+ );
263
+ assertSkipDrag(
264
+ { deltaY: -1 },
265
+ (min, max) => max,
266
+ (min, max) => min - 1,
267
+ true,
268
+ );
269
+ assertSkipDrag(
270
+ { deltaY: 1 },
271
+ (min, max) => max,
272
+ (min, max) => max,
273
+ false,
274
+ );
275
+ assertSkipDrag(
276
+ { deltaY: -1 },
277
+ (min, max) => max,
278
+ (min, max) => min,
279
+ false,
280
+ );
281
+ });
282
+
283
+ describe('getDelta', () => {
284
+ it('calls utils.getDelta', () => {
285
+ const w = wrapper();
286
+ w.instance().position = jest.fn().mockReturnValue({
287
+ anchorPoint: {
288
+ x: 0,
289
+ y: 0,
290
+ },
291
+ x: jest.fn((x) => x),
292
+ y: jest.fn((y) => y),
293
+ });
294
+ w.instance().getDelta({ x: 1, y: 1 });
295
+ expect(getDelta).toHaveBeenCalledWith({ x: 0, y: 0 }, { x: 1, y: 1 });
296
+ });
297
+ });
298
+ describe('applyDelta', () => {
299
+ it('calls fromDelta', () => {
300
+ const fromDelta = jest.fn();
301
+ const w = wrapper({ fromDelta });
302
+ w.instance().getDelta = jest.fn();
303
+ w.instance().applyDelta({ x: 1, y: 1 });
304
+ expect(fromDelta).toHaveBeenCalledWith(expect.anything(), undefined);
305
+ });
306
+ });
307
+ describe('onStop', () => {
308
+ it('calls onDragStop', () => {
309
+ const onDragStop = jest.fn();
310
+ const w = wrapper({}, { onDragStop });
311
+ w.setState({ startX: 0, startY: 0 });
312
+ w.instance().onStop({}, {});
313
+ expect(onDragStop).toHaveBeenCalled();
314
+ });
315
+
316
+ it('calls onClick if tiny', () => {
317
+ const onClick = jest.fn();
318
+ const w = wrapper({}, { onClick });
319
+ w.instance().tiny = jest.fn().mockReturnValue(true);
320
+ clientPoint.mockReturnValue([0, 0]);
321
+ w.instance().onStop({}, {});
322
+ expect(onClick).toHaveBeenCalledWith({ x: 0, y: 0 });
323
+ });
324
+ });
325
+ });
326
+ });
@@ -0,0 +1,118 @@
1
+ import { shallow } from 'enzyme';
2
+ import React from 'react';
3
+ import { Root } from '../root';
4
+ import { select, mouse } from 'd3-selection';
5
+
6
+ const scaleMock = () => {
7
+ const fn = jest.fn((n) => n);
8
+ fn.invert = jest.fn((n) => n);
9
+ return fn;
10
+ };
11
+
12
+ const graphProps = () => ({
13
+ scale: {
14
+ x: scaleMock(),
15
+ y: scaleMock(),
16
+ },
17
+ snap: {
18
+ x: jest.fn((n) => n),
19
+ y: jest.fn((n) => n),
20
+ },
21
+ domain: {
22
+ min: 0,
23
+ max: 1,
24
+ step: 1,
25
+ },
26
+ range: {
27
+ min: 0,
28
+ max: 1,
29
+ step: 1,
30
+ },
31
+ size: {
32
+ width: 400,
33
+ height: 400,
34
+ },
35
+ });
36
+
37
+ const wrapper = (props) => {
38
+ props = {
39
+ classes: {},
40
+ graphProps: graphProps(),
41
+ ...props,
42
+ };
43
+
44
+ return shallow(<Root {...props}>hi</Root>, { disableLifecycleMethods: true });
45
+ };
46
+
47
+ jest.mock('d3-selection', () => ({
48
+ select: jest.fn(),
49
+ mouse: jest.fn(),
50
+ }));
51
+
52
+ describe('root', () => {
53
+ describe('snapshot', () => {
54
+ it('matches', () => {
55
+ const w = wrapper();
56
+ expect(w).toMatchSnapshot();
57
+ });
58
+ });
59
+
60
+ describe('logic', () => {
61
+ describe('mousemove', () => {
62
+ describe('mount/unmount', () => {
63
+ it('adds mousemove listener on compenentDidMount', () => {
64
+ const w = wrapper();
65
+ const g = {
66
+ on: jest.fn(),
67
+ };
68
+ select.mockReturnValue(g);
69
+ w.instance().componentDidMount();
70
+ expect(g.on).toHaveBeenCalledWith('mousemove', expect.any(Function));
71
+ });
72
+ it('unsets mousemove listener on componentWillUnmount', () => {
73
+ const w = wrapper();
74
+ const g = {
75
+ on: jest.fn(),
76
+ };
77
+ select.mockReturnValue(g);
78
+ w.instance().componentWillUnmount();
79
+ expect(g.on).toHaveBeenCalledWith('mousemove', null);
80
+ });
81
+ });
82
+
83
+ describe('mouseMove function', () => {
84
+ let onMouseMove, w, gp;
85
+ beforeEach(() => {
86
+ onMouseMove = jest.fn();
87
+ gp = graphProps();
88
+ w = wrapper({
89
+ onMouseMove,
90
+ graphProps: gp,
91
+ });
92
+ mouse.mockReturnValue([0, 0]);
93
+ const g = { _groups: [[[0, 0]]] };
94
+ w.instance().mouseMove(g);
95
+ });
96
+ it('calls mouse', () => {
97
+ expect(mouse).toHaveBeenCalledWith([0, 0]);
98
+ });
99
+ it('calls, scale.x.invert', () => {
100
+ expect(gp.scale.x.invert).toHaveBeenCalledWith(0);
101
+ });
102
+ it('calls, scale.y.invert', () => {
103
+ expect(gp.scale.y.invert).toHaveBeenCalledWith(0);
104
+ });
105
+ it('calls, snap.x', () => {
106
+ expect(gp.snap.x).toHaveBeenCalledWith(0);
107
+ });
108
+ it('calls, snap.y', () => {
109
+ expect(gp.snap.y).toHaveBeenCalledWith(0);
110
+ });
111
+
112
+ it('calls handler', () => {
113
+ expect(onMouseMove).toHaveBeenCalledWith({ x: 0, y: 0 });
114
+ });
115
+ });
116
+ });
117
+ });
118
+ });
@@ -0,0 +1,174 @@
1
+ import {
2
+ angle,
3
+ edge,
4
+ edges,
5
+ maxEdge,
6
+ minEdge,
7
+ toRadians,
8
+ toDegrees,
9
+ acuteXAngle,
10
+ acuteYAngle,
11
+ diffEdge,
12
+ } from '../trig';
13
+ import { xy } from '../utils';
14
+ import debug from 'debug';
15
+ import { getOpposingSide } from '../trig';
16
+ const log = debug('pie-lib:plot:trig:test');
17
+
18
+ const vs = (v) => {
19
+ if (!v) {
20
+ return '';
21
+ }
22
+
23
+ if (Number.isFinite(v.x) && Number.isFinite(v.y)) {
24
+ return `[${v.x},${v.y}]`;
25
+ }
26
+ return JSON.stringify(v);
27
+ };
28
+ const p = (strings, ...values) => {
29
+ return strings.reduce((acc, s, index) => {
30
+ return `${acc}${s}${vs(values[index])}`;
31
+ }, '');
32
+ };
33
+ describe('trig', () => {
34
+ describe('angle', () => {
35
+ const assertAngle = (a, b, expected) => {
36
+ it(p`${a}, ${b} => ${toDegrees(expected)}`, () => {
37
+ const result = angle(a, b);
38
+ expect(result).toBeCloseTo(expected);
39
+ });
40
+ };
41
+
42
+ assertAngle(xy(0, 0), xy(1, 1), toRadians(45));
43
+ assertAngle(xy(0, 0), xy(0, 1), toRadians(90));
44
+ assertAngle(xy(0, 0), xy(-1, 1), toRadians(135));
45
+ assertAngle(xy(0, 0), xy(-1, 0), toRadians(180));
46
+ assertAngle(xy(0, 0), xy(-1, -1), toRadians(225));
47
+ assertAngle(xy(0, 0), xy(0, -1), toRadians(270));
48
+ assertAngle(xy(0, 0), xy(1, -1), toRadians(315));
49
+ assertAngle(xy(1, 1), xy(0, 0), toRadians(225));
50
+ assertAngle(xy(0, 0), xy(1, 1), toRadians(45));
51
+ assertAngle(xy(0, 0), xy(2, 1), toRadians(26.565));
52
+ assertAngle(xy(0, 0), xy(3, 1), toRadians(18.434));
53
+ assertAngle(xy(0, 0), xy(4, 1), toRadians(14.036));
54
+ assertAngle(xy(0, 0), xy(5, 1), toRadians(11.309));
55
+ });
56
+
57
+ describe('acuteXAngle', () => {
58
+ const assertAcute = (input, expected) => {
59
+ it(`${toDegrees(input)} => ${toDegrees(expected)}`, () => {
60
+ const result = acuteXAngle(input);
61
+ log(`result: ${toDegrees(result)}`);
62
+ expect(result).toBeCloseTo(expected);
63
+ });
64
+ };
65
+
66
+ assertAcute(toRadians(45), toRadians(45));
67
+ assertAcute(toRadians(100), toRadians(80));
68
+ assertAcute(toRadians(190), toRadians(10));
69
+ assertAcute(toRadians(350), toRadians(10));
70
+ });
71
+
72
+ describe('acuteYAngle', () => {
73
+ const assertAcute = (input, expected) => {
74
+ it(`${toDegrees(input)} => ${toDegrees(expected)}`, () => {
75
+ const result = acuteYAngle(input);
76
+ log(`result: ${toDegrees(result)}`);
77
+ expect(result).toBeCloseTo(expected);
78
+ });
79
+ };
80
+
81
+ assertAcute(toRadians(45), toRadians(45));
82
+ assertAcute(toRadians(100), toRadians(10));
83
+ assertAcute(toRadians(190), toRadians(80));
84
+ assertAcute(toRadians(350), toRadians(80));
85
+ });
86
+
87
+ describe('edges', () => {
88
+ const assertEdges = (domain, range) => (from, to, expected) => {
89
+ it(p`${domain}, ${range} + ${from} -> ${to} => ${expected[0]}${expected[1]}`, () => {
90
+ const result = edges(domain, range)(from, to);
91
+ expect(result[0].x).toBeCloseTo(expected[0].x);
92
+ expect(result[0].y).toBeCloseTo(expected[0].y);
93
+ expect(result[1].x).toBeCloseTo(expected[1].x);
94
+ expect(result[1].y).toBeCloseTo(expected[1].y);
95
+ });
96
+ };
97
+
98
+ const one = assertEdges({ min: -4, max: 4 }, { min: -4, max: 4 });
99
+ one(xy(0, 0), xy(1, 1), [xy(4, 4), xy(-4, -4)]);
100
+ one(xy(0, 0), xy(2, 1), [xy(4, 2), xy(-4, -2)]);
101
+ one(xy(1, 1), xy(2, 2), [xy(4, 4), xy(-4, -4)]);
102
+ one(xy(1, 0), xy(2, 0), [xy(4, 0), xy(-4, 0)]);
103
+ one(xy(1, 0), xy(-2, 0), [xy(-4, 0), xy(4, 0)]);
104
+
105
+ /**
106
+ * domain {min: -5, max: 5, padding: 0, step: 1, labelStep: 1}labelStep: 1max: 5min: -5padding: 0step: 1__proto__: Object range: {min: -5, max: 5, padding: 0, step: 1, labelStep: 1} a: {x: -5, y: 0} b: {x: -5, y: 2} edges: Point {x: -5, y: 5} Point {x: -5, y: 2}
107
+ */
108
+ const lineIssue = assertEdges({ min: -5, max: 5 }, { min: -5, max: 5 });
109
+ lineIssue(xy(-5, -0), xy(-5, 2), [xy(-5, 5), xy(-5, -5)]);
110
+ });
111
+
112
+ describe('diffEdge', () => {
113
+ const assertDiffEdge = (bounds, from, to, expected) => {
114
+ it(p`<${bounds}> ${from} -> ${to} => ${expected}`, () => {
115
+ const result = diffEdge(bounds, from, to);
116
+ expect(result.x).toBeCloseTo(expected.x);
117
+ expect(result.y).toBeCloseTo(expected.y);
118
+ });
119
+ };
120
+
121
+ const twoTwo = assertDiffEdge.bind(null, xy(2, 2));
122
+ twoTwo(xy(0, 0), xy(1, 1), xy(2, 2));
123
+ twoTwo(xy(0, 0), xy(1, 2), xy(1, 2));
124
+ twoTwo(xy(0, 0), xy(2, 2), xy(2, 2));
125
+ twoTwo(xy(0, 0), xy(2, 2), xy(2, 2));
126
+ twoTwo(xy(0, 0), xy(-1, 1), xy(-2, 2));
127
+ twoTwo(xy(0, 0), xy(-1, -1), xy(-2, -2));
128
+ const fourFour = assertDiffEdge.bind(null, xy(4, 4));
129
+
130
+ fourFour(xy(0, 0), xy(1, 1), xy(4, 4));
131
+ fourFour(xy(0, 0), xy(1, 2), xy(2, 4));
132
+ fourFour(xy(0, 0), xy(2, 1), xy(4, 2));
133
+ fourFour(xy(0, 0), xy(-1, 1), xy(-4, 4));
134
+ fourFour(xy(0, 0), xy(-1, 1), xy(-4, 4));
135
+
136
+ assertDiffEdge(xy(-4, -4), xy(0, 0), xy(-1, -1), xy(-4, -4));
137
+ assertDiffEdge(xy(4, 4), xy(1, 1), xy(2, 2), xy(4, 4));
138
+ assertDiffEdge(xy(4, 4), xy(2, 2), xy(3, 3), xy(4, 4));
139
+ assertDiffEdge(xy(-4, -4), xy(-1, -1), xy(-2, -2), xy(-4, -4));
140
+ assertDiffEdge(xy(-4, 4), xy(-1, -1), xy(-2, 0), xy(-4, 2));
141
+
142
+ const lineIssue = assertDiffEdge.bind(null, xy(-5, -5));
143
+
144
+ lineIssue(xy(-5, 2), xy(-5, 0), xy(-5, -5));
145
+ //Top Right
146
+ assertDiffEdge(xy(5, 5), xy(0, 5), xy(2, 5), xy(5, 5));
147
+ assertDiffEdge(xy(5, 5), xy(5, 0), xy(5, 1), xy(5, 5));
148
+
149
+ // //Bottom Right
150
+ assertDiffEdge(xy(5, -5), xy(5, 0), xy(5, -0.1), xy(5, -5));
151
+ assertDiffEdge(xy(5, -5), xy(0, -5), xy(1, -5), xy(5, -5));
152
+
153
+ //Top Left
154
+ assertDiffEdge(xy(-5, 5), xy(-5, 0), xy(-5, 0.1), xy(-5, 5));
155
+ assertDiffEdge(xy(-5, 5), xy(0, 5), xy(-1, 5), xy(-5, 5));
156
+
157
+ //Bottom Left
158
+ assertDiffEdge(xy(-5, -5), xy(-5, 0), xy(-5, -0.1), xy(-5, -5));
159
+ assertDiffEdge(xy(-5, -5), xy(0, -5), xy(-1, -5), xy(-5, -5));
160
+ });
161
+
162
+ describe('getOpposingSide', () => {
163
+ const assertOpposingSide = (hyp, angle, expected) => {
164
+ it(`${hyp}, ${angle} = ${expected}`, () => {
165
+ const radians = toRadians(angle);
166
+ const result = getOpposingSide(hyp, radians);
167
+ expect(result).toBeCloseTo(expected);
168
+ });
169
+ };
170
+
171
+ assertOpposingSide(1, 45, 0.707);
172
+ assertOpposingSide(1.25, 45, 0.88);
173
+ });
174
+ });