Skip to content

Commit

Permalink
De-flake popupTabNavigation, hopefully for good
Browse files Browse the repository at this point in the history
  • Loading branch information
prushforth committed Mar 23, 2024
1 parent 9361864 commit 8d69508
Show file tree
Hide file tree
Showing 2 changed files with 105 additions and 154 deletions.
12 changes: 6 additions & 6 deletions test/e2e/core/popupTabNavigation.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@
</head>

<body>
<mapml-viewer style="width: 500px;height: 500px;" is="web-map" projection="CBMTILE" zoom="2" lat="45.5052040"
<mapml-viewer data-testid="viewer" style="width: 500px;height: 500px;" is="web-map" projection="CBMTILE" zoom="2" lat="45.5052040"
lon="-75.2202344" controls>
<layer- id="query" label="Fire" checked>
<layer- data-testid="query" id="query" label="Fire" checked>
<map-extent units="CBMTILE" checked hidden>
<map-input name="z" type="zoom" value="18" min="0" max="18" ></map-input>
<map-input name="txmin" type="location" units="tilematrix" position="top-left" axis="easting" min="-2.003750834E7"
Expand Down Expand Up @@ -46,10 +46,10 @@
<map-meta name="zoom" content="min=1,max=5,value=0"></map-meta>
<map-meta name="cs" content="gcrs"></map-meta>
<map-meta name="extent" content="zoom=0,top-left-column=0,top-left-row=0,bottom-right-column=5,bottom-right-row=5"></map-meta>
<map-feature zoom="2" class="refDiff">
<map-feature data-testid="big-square" zoom="2" class="refDiff">
<map-properties>
<h1>Test</h1>
<a href="www.example.com">test</a>
<a data-testid="anchor" href="www.example.com">test</a>
</map-properties>
<map-geometry cs="tilematrix">
<map-polygon>
Expand All @@ -69,7 +69,7 @@ <h1>Test</h1>
</map-geometry>
</map-feature>

<map-feature zoom="2" class="refDiff">
<map-feature data-testid="small-trapezoid" zoom="2" class="refDiff">
<map-properties>
<h1>Test</h1>
</map-properties>
Expand All @@ -80,7 +80,7 @@ <h1>Test</h1>
</map-geometry>
</map-feature>
</layer->
<layer- id="vector" label="vector states" src="data/us_pop_density.mapml"></layer->
<layer- data-testid="vector" id="vector" label="vector states" src="data/us_pop_density.mapml"></layer->
</mapml-viewer>
</body>

Expand Down
247 changes: 99 additions & 148 deletions test/e2e/core/popupTabNavigation.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,91 +17,74 @@ test.describe('Playwright Keyboard Navigation + Query Layer Tests', () => {

test.describe('Feature Popup Tab Navigation Tests', () => {
test('Inline features popup focus order', async () => {
await page.evaluateHandle(() =>
document.getElementById('vector').removeAttribute('checked')
);
await page.evaluateHandle(() =>
document.getElementById('query').removeAttribute('checked')
);
const body = page.locator('body');
await body.click();
const vectorLayer = page.getByTestId('vector');
await vectorLayer.evaluate((l) => {
l.removeAttribute('checked');
});
const queryLayer = page.getByTestId('query');
await queryLayer.evaluate((l) => {
l.removeAttribute('checked');
});
const viewer = page.locator('mapml-viewer');
await viewer.focus();
await page.keyboard.press('Tab'); // focus map

await page.keyboard.press('Tab'); // focus feature
await page.keyboard.press('Enter'); // display popup with link in it
const viewer = page.locator('mapml-viewer');
let f = await viewer.evaluate(
(viewer) => viewer.shadowRoot.activeElement.className
);
expect(f).toEqual('mapml-popup-content');

const popupContainer = page.locator('.leaflet-popup');
const popup = popupContainer.locator('.mapml-popup-content');
await expect(popup).toBeFocused();
await page.keyboard.press('Tab'); // focus link
let f2 = await viewer.evaluate(
(viewer) => viewer.shadowRoot.activeElement.tagName
);
expect(f2.toUpperCase()).toEqual('A');
// there are actually 2 copies of the testid, so we scope relative to the popup
const anchor = popupContainer.getByTestId('anchor');
await expect(anchor).toBeFocused();

await page.keyboard.press('Tab'); // focus on "zoom to here" link
let f3 = await viewer.evaluate(
(viewer) => viewer.shadowRoot.activeElement.tagName
);
expect(f3.toUpperCase()).toEqual('A');

const zoomToHereLink = popupContainer.getByText('Zoom to here');
await expect(zoomToHereLink).toBeFocused();

await page.keyboard.press('Tab'); // focus on |< affordance
let f4 = await viewer.evaluate(
(viewer) => viewer.shadowRoot.activeElement.title
);
expect(f4).toEqual('Focus Map');
const focusMapButton = popupContainer.getByRole('button', { name: 'Focus Map' });
await expect(focusMapButton).toBeFocused();

await page.keyboard.press('Tab'); // focus on < affordance
let f5 = await viewer.evaluate(
(viewer) => viewer.shadowRoot.activeElement.title
);
expect(f5).toEqual('Previous Feature');
const previousFeatureButton = popupContainer.getByRole('button', { name: 'Previous Feature' });
await expect(previousFeatureButton).toBeFocused();

await page.keyboard.press('Tab'); // focus on > affordance
let f6 = await viewer.evaluate(
(viewer) => viewer.shadowRoot.activeElement.title
);
expect(f6).toEqual('Next Feature');
const nextFeatureButton = popupContainer.getByRole('button', { name: 'Next Feature' });
await expect(nextFeatureButton).toBeFocused();

await page.keyboard.press('Tab'); // focus on >| affordance
let f7 = await viewer.evaluate(
(viewer) => viewer.shadowRoot.activeElement.title
);
expect(f7).toEqual('Focus Controls');
const focusControlsButton = popupContainer.getByRole('button', { name: 'Focus Controls' });
await expect(focusControlsButton).toBeFocused();

await page.keyboard.press('Tab'); // focus on X dismiss popup affordance
let f8 = await viewer.evaluate(
(viewer) => viewer.shadowRoot.activeElement.className
);
expect(f8).toEqual('leaflet-popup-close-button');
const dismissButton = popupContainer.getByRole('button', { name: 'Close popup' });
await expect(dismissButton).toBeFocused();
});

test('Tab to next feature after tabbing out of popup', async () => {
const viewer = page.getByTestId('viewer');
await page.keyboard.press('Escape'); // focus back on feature
const h = await page.evaluateHandle(() =>
document.querySelector('mapml-viewer')
);
const nh = await page.evaluateHandle((doc) => doc.shadowRoot, h);
const rh = await page.evaluateHandle(
(root) => root.activeElement.querySelector('.leaflet-interactive'),
nh
// according to https://github.com/microsoft/playwright/issues/15929
// tests should locate the element and then check that it is focused
const bigSquare = viewer.getByTestId('big-square');
const bigSquarePathData = await bigSquare.evaluate((f) => {
return f._groupEl.firstElementChild.getAttribute('d');
});
// no way to get a locator from another locator afaik, but this may work:
const bigSquareGroupEl = viewer.locator(
'g:has( > path[d="' + bigSquarePathData + '"])'
);
const f = await (
await page.evaluateHandle((elem) => elem.getAttribute('d'), rh)
).jsonValue();
expect(f).toEqual('M330 83L586 83L586 339L330 339z');
await page.waitForTimeout(500);
await expect(bigSquareGroupEl).toBeFocused();
// that we have to do this to get the tooltip back is a bug #681
await page.keyboard.press('Shift+Tab');
await page.keyboard.press('Tab');

let tooltipCount = await page.$eval(
'mapml-viewer .leaflet-tooltip-pane',
const toolTipPane = viewer.locator('.leaflet-tooltip-pane');
let tooltipCount = await toolTipPane.evaluate(
(div) => div.childElementCount
);

expect(tooltipCount).toEqual(1);
});

Expand All @@ -110,26 +93,20 @@ test.describe('Playwright Keyboard Navigation + Query Layer Tests', () => {
await page.waitForTimeout(500);
await page.keyboard.press('Shift+Tab');
await page.waitForTimeout(500);

const h = await page.evaluateHandle(() =>
document.querySelector('mapml-viewer')
);
const nh = await page.evaluateHandle((doc) => doc.shadowRoot, h);
const rh = await page.evaluateHandle(
(root) => root.activeElement.querySelector('.leaflet-interactive'),
nh
const viewer = page.getByTestId('viewer');
const bigSquare = viewer.getByTestId('big-square');
const bigSquarePathData = await bigSquare.evaluate((f) => {
return f._groupEl.firstElementChild.getAttribute('d');
});
const bigSquareGroupEl = viewer.locator(
'g:has( > path[d="' + bigSquarePathData + '"])'
);
const f = await (
await page.evaluateHandle((elem) => elem.getAttribute('d'), rh)
).jsonValue();

let tooltipCount = await page.$eval(
'mapml-viewer .leaflet-tooltip-pane',
await expect(bigSquareGroupEl).toBeFocused();
const toolTipPane = viewer.locator('.leaflet-tooltip-pane');
let tooltipCount = await toolTipPane.evaluate(
(div) => div.childElementCount
);

expect(tooltipCount).toEqual(1);
expect(f).toEqual('M330 83L586 83L586 339L330 339z');
});

test('Previous feature button focuses previous feature', async () => {
Expand All @@ -145,25 +122,20 @@ test.describe('Playwright Keyboard Navigation + Query Layer Tests', () => {
await page.waitForTimeout(500);
await page.keyboard.press('Enter'); // focus should fall on previous feature
await page.waitForTimeout(500);
const h = await page.evaluateHandle(() =>
document.querySelector('mapml-viewer')
);
const nh = await page.evaluateHandle((doc) => doc.shadowRoot, h);
const rh = await page.evaluateHandle(
(root) => root.activeElement.querySelector('.leaflet-interactive'),
nh
const viewer = page.getByTestId('viewer');
const bigSquare = viewer.getByTestId('big-square');
const bigSquarePathData = await bigSquare.evaluate((f) => {
return f._groupEl.firstElementChild.getAttribute('d');
});
const bigSquareGroupEl = viewer.locator(
'g:has( > path[d="' + bigSquarePathData + '"])'
);
const f = await (
await page.evaluateHandle((elem) => elem.getAttribute('d'), rh)
).jsonValue();

let tooltipCount = await page.$eval(
'mapml-viewer .leaflet-tooltip-pane',
await expect(bigSquareGroupEl).toBeFocused();
const toolTipPane = viewer.locator('.leaflet-tooltip-pane');
let tooltipCount = await toolTipPane.evaluate(
(div) => div.childElementCount
);

expect(tooltipCount).toEqual(1);
expect(f).toEqual('M330 83L586 83L586 339L330 339z');
});

test('Tooltip appears after pressing esc key', async () => {
Expand All @@ -172,25 +144,20 @@ test.describe('Playwright Keyboard Navigation + Query Layer Tests', () => {
await page.keyboard.down('Escape'); // focus back on feature
await page.keyboard.up('Escape');
await page.waitForTimeout(500);

const h = await page.evaluateHandle(() =>
document.querySelector('mapml-viewer')
const viewer = page.getByTestId('viewer');
const bigSquare = viewer.getByTestId('big-square');
const bigSquarePathData = await bigSquare.evaluate((f) => {
return f._groupEl.firstElementChild.getAttribute('d');
});
const bigSquareGroupEl = viewer.locator(
'g:has( > path[d="' + bigSquarePathData + '"])'
);
const nh = await page.evaluateHandle((doc) => doc.shadowRoot, h);
const rh = await page.evaluateHandle(
(root) => root.activeElement.querySelector('.leaflet-interactive'),
nh
);
const f = await (
await page.evaluateHandle((elem) => elem.getAttribute('d'), rh)
).jsonValue();

let tooltipCount = await page.$eval(
'mapml-viewer .leaflet-tooltip-pane',
await expect(bigSquareGroupEl).toBeFocused();
const toolTipPane = viewer.locator('.leaflet-tooltip-pane');
let tooltipCount = await toolTipPane.evaluate(
(div) => div.childElementCount
);
expect(tooltipCount).toEqual(1);
expect(f).toEqual('M330 83L586 83L586 339L330 339z');
});

test('Tooltip appears after pressing enter on close button', async () => {
Expand All @@ -205,25 +172,20 @@ test.describe('Playwright Keyboard Navigation + Query Layer Tests', () => {
await page.keyboard.down('Enter'); // press x button
await page.keyboard.up('Enter');
await page.waitForTimeout(500);

const h = await page.evaluateHandle(() =>
document.querySelector('mapml-viewer')
);
const nh = await page.evaluateHandle((doc) => doc.shadowRoot, h);
const rh = await page.evaluateHandle(
(root) => root.activeElement.querySelector('.leaflet-interactive'),
nh
const viewer = page.getByTestId('viewer');
const bigSquare = viewer.getByTestId('big-square');
const bigSquarePathData = await bigSquare.evaluate((f) => {
return f._groupEl.firstElementChild.getAttribute('d');
});
const bigSquareGroupEl = viewer.locator(
'g:has( > path[d="' + bigSquarePathData + '"])'
);
const f = await (
await page.evaluateHandle((elem) => elem.getAttribute('d'), rh)
).jsonValue();

let tooltipCount = await page.$eval(
'mapml-viewer .leaflet-tooltip-pane',
await expect(bigSquareGroupEl).toBeFocused();
const toolTipPane = viewer.locator('.leaflet-tooltip-pane');
let tooltipCount = await toolTipPane.evaluate(
(div) => div.childElementCount
);
expect(tooltipCount).toEqual(1);
expect(f).toEqual('M330 83L586 83L586 339L330 339z');
});

test('Next feature button focuses next feature', async () => {
Expand All @@ -240,25 +202,21 @@ test.describe('Playwright Keyboard Navigation + Query Layer Tests', () => {
await page.keyboard.press('Tab'); // focus > affordance (next feature)
await page.waitForTimeout(500);
await page.keyboard.press('Enter'); // focus falls on next feature
const h = await page.evaluateHandle(() =>
document.querySelector('mapml-viewer')
const viewer = page.getByTestId('viewer');
const smallTrapezoid = viewer.getByTestId('small-trapezoid');
const smallTrapezoidPathData = await smallTrapezoid.evaluate((f) => {
return f._groupEl.firstElementChild.getAttribute('d');
});
// no way to get a locator from another locator afaik, but this may work:
const smallTrapezoidGroupEl = viewer.locator(
'g:has( > path[d="' + smallTrapezoidPathData + '"])'
);
const nh = await page.evaluateHandle((doc) => doc.shadowRoot, h);
const rh = await page.evaluateHandle(
(root) => root.activeElement.querySelector('.leaflet-interactive'),
nh
);
const f = await (
await page.evaluateHandle((elem) => elem.getAttribute('d'), rh)
).jsonValue();

let tooltipCount = await page.$eval(
'mapml-viewer .leaflet-tooltip-pane',
await expect(smallTrapezoidGroupEl).toBeFocused();
const toolTipPane = viewer.locator('.leaflet-tooltip-pane');
let tooltipCount = await toolTipPane.evaluate(
(div) => div.childElementCount
);

expect(tooltipCount).toEqual(1);
expect(f).toEqual('M285 373L460 380L468 477L329 459z');
});

test('Focus Controls focuses the first <button> child in control div', async () => {
Expand All @@ -283,11 +241,8 @@ test.describe('Playwright Keyboard Navigation + Query Layer Tests', () => {
await page.keyboard.press('Enter');
for (let i = 0; i < 6; i++) await page.keyboard.press('Tab');
await page.keyboard.press('Enter');
let f = await page.$eval(
'body > mapml-viewer',
(viewer) => viewer.shadowRoot.activeElement.innerHTML
);
expect(f).toEqual('Maps for HTML Community Group');
const focusedElement = page.getByText('Maps for HTML Community Group');
await expect(focusedElement).toBeFocused();
});

test('Zoom link zooms to the zoom level = zoom attribute', async () => {
Expand All @@ -300,10 +255,8 @@ test.describe('Playwright Keyboard Navigation + Query Layer Tests', () => {
await page.keyboard.press('Tab'); // focus zoomto link
await page.keyboard.press('Enter');
await page.waitForTimeout(500);
const zoom = await page.$eval(
'body > mapml-viewer',
(map) => +map.getAttribute('zoom')
);
const viewer = page.getByTestId('viewer');
const zoom = await viewer.evaluate((map) => +map.getAttribute('zoom'));
expect(zoom).toEqual(2);
});

Expand All @@ -324,10 +277,8 @@ test.describe('Playwright Keyboard Navigation + Query Layer Tests', () => {
await page.keyboard.press('Tab'); // focus zoomto link
await page.keyboard.press('Enter');
await page.waitForTimeout(500);
const zoom = await page.$eval(
'body > mapml-viewer',
(map) => +map.getAttribute('zoom')
);
const viewer = page.getByTestId('viewer');
const zoom = await viewer.evaluate((map) => +map.getAttribute('zoom'));
expect(zoom).toEqual(2);
});
});
Expand Down

0 comments on commit 8d69508

Please sign in to comment.