Skip to content

Commit e744bd5

Browse files
committed
[Lens] [A11y] fix creating or removing layers in Lens looses focus
1 parent ff59d85 commit e744bd5

File tree

5 files changed

+38
-94
lines changed

5 files changed

+38
-94
lines changed

x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/config_panel.test.tsx

Lines changed: 0 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ import { generateId } from '../../../id_generator';
2727
import { mountWithProvider } from '../../../mocks';
2828
import { LayerTypes } from '@kbn/expression-xy-plugin/public';
2929
import { ReactWrapper } from 'enzyme';
30-
import { addLayer } from '../../../state_management';
3130
import { createIndexPatternServiceMock } from '../../../mocks/data_views_service_mock';
3231
import { AddLayerButton } from '../../../visualizations/xy/add_layer';
3332
import { LayerType } from '@kbn/visualizations-plugin/common';
@@ -190,96 +189,6 @@ describe('ConfigPanel', () => {
190189
);
191190
});
192191

193-
describe('focus behavior when adding or removing layers', () => {
194-
it('should focus the only layer when resetting the layer', async () => {
195-
const { instance } = await prepareAndMountComponent(getDefaultProps());
196-
const firstLayerFocusable = instance
197-
.find(LayerPanel)
198-
.first()
199-
.find('section')
200-
.first()
201-
.instance();
202-
act(() => {
203-
instance.find('[data-test-subj="lnsLayerRemove--0"]').first().simulate('click');
204-
});
205-
instance.update();
206-
207-
const focusedEl = document.activeElement;
208-
expect(focusedEl).toEqual(firstLayerFocusable);
209-
});
210-
211-
it('should focus the second layer when removing the first layer', async () => {
212-
const datasourceMap = mockDatasourceMap();
213-
const defaultProps = getDefaultProps({ datasourceMap });
214-
// overwriting datasourceLayers to test two layers
215-
frame.datasourceLayers = {
216-
first: datasourceMap.testDatasource.publicAPIMock,
217-
second: datasourceMap.testDatasource.publicAPIMock,
218-
};
219-
220-
const { instance } = await prepareAndMountComponent(defaultProps);
221-
const secondLayerFocusable = instance
222-
.find(LayerPanel)
223-
.at(1)
224-
.find('section')
225-
.first()
226-
.instance();
227-
act(() => {
228-
instance.find('[data-test-subj="lnsLayerRemove--0"]').first().simulate('click');
229-
});
230-
instance.update();
231-
232-
const focusedEl = document.activeElement;
233-
expect(focusedEl).toEqual(secondLayerFocusable);
234-
});
235-
236-
it('should focus the first layer when removing the second layer', async () => {
237-
const datasourceMap = mockDatasourceMap();
238-
const defaultProps = getDefaultProps({ datasourceMap });
239-
// overwriting datasourceLayers to test two layers
240-
frame.datasourceLayers = {
241-
first: datasourceMap.testDatasource.publicAPIMock,
242-
second: datasourceMap.testDatasource.publicAPIMock,
243-
};
244-
const { instance } = await prepareAndMountComponent(defaultProps);
245-
const firstLayerFocusable = instance
246-
.find(LayerPanel)
247-
.first()
248-
.find('section')
249-
.first()
250-
.instance();
251-
act(() => {
252-
instance.find('[data-test-subj="lnsLayerRemove--1"]').first().simulate('click');
253-
});
254-
instance.update();
255-
256-
const focusedEl = document.activeElement;
257-
expect(focusedEl).toEqual(firstLayerFocusable);
258-
});
259-
260-
it('should focus the added layer', async () => {
261-
const datasourceMap = mockDatasourceMap();
262-
frame.datasourceLayers = {
263-
first: datasourceMap.testDatasource.publicAPIMock,
264-
newId: datasourceMap.testDatasource.publicAPIMock,
265-
};
266-
267-
const defaultProps = getDefaultProps({ datasourceMap });
268-
269-
const { instance } = await prepareAndMountComponent(defaultProps, {
270-
dispatch: jest.fn((x) => {
271-
if (x.type === addLayer.type) {
272-
frame.datasourceLayers.newId = datasourceMap.testDatasource.publicAPIMock;
273-
}
274-
}),
275-
});
276-
277-
addNewLayer(instance);
278-
const focusedEl = document.activeElement;
279-
expect(focusedEl?.children[0].getAttribute('data-test-subj')).toEqual('lns-layerPanel-1');
280-
});
281-
});
282-
283192
describe('initial default value', () => {
284193
function clickToAddDimension(instance: ReactWrapper) {
285194
act(() => {

x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/layer_panel.test.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -950,6 +950,7 @@ describe('LayerPanel', () => {
950950
});
951951

952952
it('should reorder when dropping in the same group', async () => {
953+
jest.useFakeTimers();
953954
mockVisualization.getConfiguration.mockReturnValue({
954955
groups: [
955956
{
@@ -997,6 +998,7 @@ describe('LayerPanel', () => {
997998
.find('[data-test-subj="lnsDragDrop-keyboardHandler"]')
998999
.at(1)
9991000
.instance();
1001+
jest.runAllTimers();
10001002
const focusedEl = document.activeElement;
10011003
expect(focusedEl).toEqual(secondButton);
10021004
});

x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/layer_panel.tsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -363,8 +363,13 @@ export function LayerPanel(
363363

364364
return (
365365
<>
366-
<section tabIndex={-1} ref={registerLayerRef} className="lnsLayerPanel">
367-
<EuiPanel data-test-subj={`lns-layerPanel-${layerIndex}`} paddingSize="none">
366+
<section
367+
tabIndex={-1}
368+
ref={registerLayerRef}
369+
className="lnsLayerPanel"
370+
data-test-subj={`lns-layerPanel-${layerIndex}`}
371+
>
372+
<EuiPanel paddingSize="none">
368373
<header className="lnsLayerPanel__layerHeader">
369374
<EuiFlexGroup gutterSize="s" responsive={false} alignItems="center">
370375
<EuiFlexItem grow className="lnsLayerPanel__layerSettingsWrapper">

x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/use_focus_update.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ export function useFocusUpdate(ids: string[]) {
3030
const element = nextFocusedId && refsById.get(nextFocusedId);
3131
if (element) {
3232
const focusable = getFirstFocusable(element);
33-
focusable?.focus();
33+
setTimeout(() => focusable?.focus());
3434
setNextFocusedId(null);
3535
}
3636
}, [ids, refsById, nextFocusedId]);

x-pack/test/accessibility/apps/group2/lens.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
* 2.0.
66
*/
77

8+
import expect from '@kbn/expect';
89
import { FtrProviderContext } from '../../ftr_provider_context';
910

1011
export default function ({ getService, getPageObjects }: FtrProviderContext) {
@@ -14,6 +15,13 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
1415
const esArchiver = getService('esArchiver');
1516
const listingTable = getService('listingTable');
1617
const kibanaServer = getService('kibanaServer');
18+
const find = getService('find');
19+
20+
const hasFocus = async (testSubject: string) => {
21+
const targetElement = await testSubjects.find(testSubject);
22+
const activeElement = await find.activeElement();
23+
return (await targetElement._webElement.getId()) === (await activeElement._webElement.getId());
24+
};
1725

1826
describe('Lens Accessibility', () => {
1927
const lensChartName = 'MyLensChart';
@@ -175,5 +183,25 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
175183
await listingTable.clickDeleteSelected();
176184
await PageObjects.common.clickConfirmOnModal();
177185
});
186+
187+
describe('focus behavior when adding or removing layers', () => {
188+
it('should focus the added layer', async () => {
189+
await PageObjects.visualize.navigateToNewVisualization();
190+
await PageObjects.visualize.clickVisType('lens');
191+
await PageObjects.lens.createLayer();
192+
expect(await hasFocus('lns-layerPanel-1')).to.be(true);
193+
});
194+
it('should focus the remaining layer when the first is removed', async () => {
195+
await PageObjects.lens.removeLayer(0);
196+
expect(await hasFocus('lns-layerPanel-0')).to.be(true);
197+
await PageObjects.lens.createLayer();
198+
await PageObjects.lens.removeLayer(1);
199+
expect(await hasFocus('lns-layerPanel-0')).to.be(true);
200+
});
201+
it('should focus the only layer when resetting the layer', async () => {
202+
await PageObjects.lens.removeLayer();
203+
expect(await hasFocus('lns-layerPanel-0')).to.be(true);
204+
});
205+
});
178206
});
179207
}

0 commit comments

Comments
 (0)