Skip to content

Commit 102937e

Browse files
authored
FocalPointPicker: use KeyboardEvent.code, partially refactor tests to modern RTL and user-event (#43441)
* FocalPointPicker: use KeyboardEvent.code instead of KeyboardEvent.keyCode * FocalPointPicker: tidy up tests, use `user-event` where possible * Comments * CHANGELOG
1 parent 19dcf6c commit 102937e

File tree

3 files changed

+81
-42
lines changed

3 files changed

+81
-42
lines changed

packages/components/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
- `ColorPalette`: Refactor away from `_.uniq()` ([#43330](https://github.com/WordPress/gutenberg/pull/43330/)).
3939
- `Guide`: Refactor away from `_.times()` ([#43374](https://github.com/WordPress/gutenberg/pull/43374/)).
4040
- `Modal`: use `KeyboardEvent.code` instead of deprecated `KeyboardEvent.keyCode`. improve unit tests ([#43429](https://github.com/WordPress/gutenberg/pull/43429/)).
41+
- `FocalPointPicker`: use `KeyboardEvent.code`, partially refactor tests to modern RTL and `user-event` ([#43441](https://github.com/WordPress/gutenberg/pull/43441/)).
4142

4243
### Experimental
4344
- `FormTokenField`: add `__experimentalAutoSelectFirstMatch` prop to auto select the first matching suggestion on typing ([#42527](https://github.com/WordPress/gutenberg/pull/42527/)).

packages/components/src/focal-point-picker/index.js

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import classnames from 'classnames';
99
import { __ } from '@wordpress/i18n';
1010
import { Component, createRef } from '@wordpress/element';
1111
import { withInstanceId } from '@wordpress/compose';
12-
import { UP, DOWN, LEFT, RIGHT } from '@wordpress/keycodes';
1312

1413
/**
1514
* Internal dependencies
@@ -171,15 +170,21 @@ export class FocalPointPicker extends Component {
171170
this.props.onDragEnd?.( event );
172171
}
173172
onKeyDown( event ) {
174-
const { keyCode, shiftKey } = event;
175-
if ( ! [ UP, DOWN, LEFT, RIGHT ].includes( keyCode ) ) return;
173+
const { code, shiftKey } = event;
174+
if (
175+
! [ 'ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight' ].includes(
176+
code
177+
)
178+
)
179+
return;
176180

177181
event.preventDefault();
178182

179183
const next = { ...this.state.percentages };
180184
const step = shiftKey ? 0.1 : 0.01;
181-
const delta = keyCode === UP || keyCode === LEFT ? -1 * step : step;
182-
const axis = keyCode === UP || keyCode === DOWN ? 'y' : 'x';
185+
const delta =
186+
code === 'ArrowUp' || code === 'ArrowLeft' ? -1 * step : step;
187+
const axis = code === 'ArrowUp' || code === 'ArrowDown' ? 'y' : 'x';
183188
const value = parseFloat( next[ axis ] ) + delta;
184189

185190
next[ axis ] = roundClamp( value, 0, 1, step );

packages/components/src/focal-point-picker/test/index.js

Lines changed: 70 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
/**
22
* External dependencies
33
*/
4-
import { act, fireEvent, render, screen } from '@testing-library/react';
4+
import { fireEvent, render, screen } from '@testing-library/react';
5+
import userEvent from '@testing-library/user-event';
56

67
/**
78
* Internal dependencies
@@ -10,31 +11,49 @@ import Picker from '../index.js';
1011

1112
describe( 'FocalPointPicker', () => {
1213
describe( 'focus and blur', () => {
13-
let firedDragEnd;
14-
let firedDrag;
15-
const { unmount } = render(
16-
<Picker
17-
onChange={ () => {} }
18-
onDragEnd={ () => ( firedDragEnd = true ) }
19-
onDrag={ () => ( firedDrag = true ) }
20-
/>
21-
);
22-
const dragArea = screen.getByRole( 'button' );
23-
fireEvent.mouseDown( dragArea );
24-
const gainedFocus = dragArea.ownerDocument.activeElement === dragArea;
25-
26-
fireEvent.blur( dragArea );
27-
fireEvent.mouseMove( dragArea );
28-
29-
// cleans up as it's not automated for renders outside of test blocks
30-
unmount();
31-
32-
it( 'should focus the draggable area', () => {
33-
expect( gainedFocus ).toBe( true );
14+
it( 'clicking the draggable area should focus it', async () => {
15+
const user = userEvent.setup( {
16+
advanceTimers: jest.advanceTimersByTime,
17+
} );
18+
19+
const mockOnChange = jest.fn();
20+
21+
render( <Picker onChange={ mockOnChange } /> );
22+
23+
const draggableArea = screen.getByRole( 'button' );
24+
25+
await user.click( draggableArea );
26+
27+
expect( draggableArea ).toHaveFocus();
3428
} );
3529

3630
it( 'should stop a drag operation when focus is lost', () => {
37-
expect( firedDragEnd && ! firedDrag ).toBe( true );
31+
const mockOnDrag = jest.fn();
32+
const mockOnDragEnd = jest.fn();
33+
const mockOnChange = jest.fn();
34+
35+
render(
36+
<Picker
37+
onChange={ mockOnChange }
38+
onDrag={ mockOnDrag }
39+
onDragEnd={ mockOnDragEnd }
40+
/>
41+
);
42+
43+
const draggableArea = screen.getByRole( 'button' );
44+
45+
// `user-event` is not capable of testing drag interactions properly.
46+
// we could consider using playwright instead.
47+
fireEvent.mouseDown( draggableArea );
48+
49+
expect( mockOnDrag ).not.toHaveBeenCalled();
50+
expect( mockOnDragEnd ).not.toHaveBeenCalled();
51+
52+
fireEvent.blur( draggableArea );
53+
fireEvent.mouseMove( draggableArea );
54+
55+
expect( mockOnDrag ).not.toHaveBeenCalled();
56+
expect( mockOnDragEnd ).toHaveBeenCalledTimes( 1 );
3857
} );
3958
} );
4059

@@ -47,13 +66,17 @@ describe( 'FocalPointPicker', () => {
4766
events.forEach( ( name ) => {
4867
handlers[ name ] = ( ...all ) => eventLogger( name, all );
4968
} );
69+
5070
render( <Picker { ...handlers } /> );
71+
5172
const dragArea = screen.getByRole( 'button' );
52-
act( () => {
53-
fireEvent.mouseDown( dragArea );
54-
fireEvent.mouseMove( dragArea );
55-
fireEvent.mouseUp( dragArea );
56-
} );
73+
74+
// `user-event` is not capable of testing drag interactions properly.
75+
// we could consider using playwright instead.
76+
fireEvent.mouseDown( dragArea );
77+
fireEvent.mouseMove( dragArea );
78+
fireEvent.mouseUp( dragArea );
79+
5780
expect(
5881
events.reduce( ( last, eventName, index ) => {
5982
return last && logs[ index ].name === eventName;
@@ -64,8 +87,13 @@ describe( 'FocalPointPicker', () => {
6487

6588
describe( 'resolvePoint handling', () => {
6689
it( 'should allow value altering', async () => {
90+
const user = userEvent.setup( {
91+
advanceTimers: jest.advanceTimersByTime,
92+
} );
93+
6794
const spyChange = jest.fn();
6895
const spy = jest.fn();
96+
6997
render(
7098
<Picker
7199
value={ { x: 0.25, y: 0.25 } }
@@ -76,12 +104,13 @@ describe( 'FocalPointPicker', () => {
76104
} }
77105
/>
78106
);
107+
79108
// Click and press arrow up
80109
const dragArea = screen.getByRole( 'button' );
81-
act( () => {
82-
fireEvent.mouseDown( dragArea );
83-
fireEvent.keyDown( dragArea, { charCode: 0, keyCode: 38 } );
84-
} );
110+
111+
await user.click( dragArea );
112+
await user.keyboard( '[ArrowUp]' );
113+
85114
expect( spy ).toHaveBeenCalled();
86115
expect( spyChange ).toHaveBeenCalledWith( {
87116
x: '0.91',
@@ -100,19 +129,23 @@ describe( 'FocalPointPicker', () => {
100129
expect( xInput.value ).toBe( '93' );
101130
} );
102131
it( 'call onChange with the expected values', async () => {
132+
const user = userEvent.setup( {
133+
advanceTimers: jest.advanceTimersByTime,
134+
} );
135+
103136
const spyChange = jest.fn();
104137
render(
105138
<Picker value={ { x: 0.14, y: 0.62 } } onChange={ spyChange } />
106139
);
107140
// Click and press arrow up
108141
const dragArea = screen.getByRole( 'button' );
109-
act( () => {
110-
fireEvent.mouseDown( dragArea );
111-
fireEvent.keyDown( dragArea, { charCode: 0, keyCode: 38 } );
112-
} );
142+
143+
await user.click( dragArea );
144+
await user.keyboard( '[ArrowDown]' );
145+
113146
expect( spyChange ).toHaveBeenCalledWith( {
114147
x: '0.14',
115-
y: '0.61',
148+
y: '0.63',
116149
} );
117150
} );
118151
} );

0 commit comments

Comments
 (0)