test(radio-group): migrate tests to playwright (#25713)

This commit is contained in:
Sean Perkins
2022-08-04 15:55:37 -04:00
committed by GitHub
parent 3878bf7652
commit 7b565c57b5
17 changed files with 190 additions and 270 deletions

View File

@@ -22,161 +22,35 @@
</ion-toolbar>
</ion-header>
<ion-content class="outer-content">
<p class="ion-text-center">
<ion-button onClick="addRadio()">Add Radio</ion-button>
<ion-button onClick="addChecked()">Add Checked</ion-button>
<ion-button id="removeButton" onClick="removeRadio()">Remove Radio</ion-button>
</p>
<ion-content>
<ion-list>
<ion-radio-group id="dynamicDisabled" disabled name="tannen" id="group" value="biff">
<ion-radio-group name="items" id="group" value="1">
<ion-list-header>
<ion-label>Luckiest Man On Earth <span id="group-value"></span></ion-label>
<ion-label>Radio Group Header</ion-label>
</ion-list-header>
<ion-item>
<ion-label
>Biff
<span id="biff"></span>
</ion-label>
<ion-radio value="biff" slot="start"></ion-radio>
<ion-label>Item 1</ion-label>
<ion-radio value="1" slot="start"></ion-radio>
</ion-item>
<ion-item>
<ion-label
>Griff
<span id="griff"></span>
</ion-label>
<ion-radio value="griff" slot="start"></ion-radio>
<ion-label>Item 2</ion-label>
<ion-radio value="2" slot="start"></ion-radio>
</ion-item>
<ion-item>
<ion-label
>Buford
<span id="buford"></span>
</ion-label>
<ion-radio value="buford" slot="start"></ion-radio>
<ion-label>Item 3</ion-label>
<ion-radio value="3" slot="start"></ion-radio>
</ion-item>
<ion-item>
<ion-label>George</ion-label>
<ion-radio value="george" slot="start"></ion-radio>
</ion-item>
</ion-radio-group>
</ion-list>
<ion-list>
<ion-radio-group value="huey">
<ion-item>
<ion-label>Huey</ion-label>
<ion-radio slot="start" value="huey"></ion-radio>
</ion-item>
<ion-item>
<ion-label>Dewey</ion-label>
<ion-radio slot="start" value="dewey"></ion-radio>
</ion-item>
<ion-item>
<ion-label>Louie</ion-label>
<ion-radio slot="start" value="louie"></ion-radio>
</ion-item>
</ion-radio-group>
</ion-list>
<ion-list>
<ion-radio-group value="huey">
<ion-item-divider>
<ion-label> Maintenance Drone </ion-label>
</ion-item-divider>
<ion-item>
<ion-label>Huey</ion-label>
<ion-radio slot="start" value="huey"></ion-radio>
</ion-item>
<ion-item>
<ion-label>Dewey</ion-label>
<ion-radio slot="start" value="dewey"></ion-radio>
</ion-item>
<ion-item>
<ion-label>Louie</ion-label>
<ion-radio slot="start" value="louie"></ion-radio>
<ion-label>Item 4</ion-label>
<ion-radio value="4" slot="start"></ion-radio>
</ion-item>
</ion-radio-group>
</ion-list>
</ion-content>
<style>
.outer-content {
--background: #f2f2f2;
}
ion-list {
margin-bottom: 10px !important;
}
</style>
<script>
let count = 0;
const removeButton = document.querySelector('#removeButton');
const valueEl = document.querySelector('#group-value');
const group = document.querySelector('ion-radio-group');
group.addEventListener('ionChange', (ev) => {
valueEl.textContent = group.value;
});
customElements
.whenDefined('ion-radio-group')
.then(() => group.componentOnReady && group.componentOnReady())
.then(() => {
valueEl.textContent = group.value;
});
function addRadio() {
const item = document.createElement('ion-item');
item.innerHTML = `
<ion-label>Item ${count}</ion-label>
<ion-radio value="item-${count}" slot="start"></ion-radio>
`;
group.appendChild(item);
count++;
removeButton.disabled = false;
}
function addChecked() {
const item = document.createElement('ion-item');
item.innerHTML = `
<ion-label>Item ${count}</ion-label>
<ion-radio value="item-${count}" slot="start"></ion-radio>
`;
group.appendChild(item);
group.value = `item-${count}`;
count++;
removeButton.disabled = false;
}
function removeRadio() {
const removeEl = group.children[group.children.length - 1];
if (removeEl && removeEl.tagName === 'ION-ITEM') {
removeEl.remove();
// No more radios to remove, disable button
if (!group.querySelector('ion-item')) {
removeButton.disabled = true;
}
}
}
</script>
</ion-app>
</body>
</html>

View File

@@ -0,0 +1,110 @@
import { expect } from '@playwright/test';
import type { Locator } from '@playwright/test';
import { test } from '@utils/test/playwright';
import type { E2EPage } from '@utils/test/playwright';
test.describe('radio-group: basic', () => {
test('should not have visual regressions', async ({ page }) => {
await page.goto(`/src/components/radio-group/test/basic`);
const list = page.locator('ion-list');
expect(await list.screenshot()).toMatchSnapshot(`radio-group-diff-${page.getSnapshotSettings()}.png`);
});
});
test.describe('radio-group: interaction', () => {
let radioFixture: RadioFixture;
test.beforeEach(({ page }, testInfo) => {
test.skip(testInfo.project.metadata.rtl === true, 'This does not test LTR vs RTL logic.');
radioFixture = new RadioFixture(page);
});
test('spacebar should not deselect without allowEmptySelection', async ({ page }) => {
await page.setContent(`
<ion-radio-group value="one" allow-empty-selection="false">
<ion-item>
<ion-label>One</ion-label>
<ion-radio id="one" value="one"></ion-radio>
</ion-item>
</ion-radio-group>
`);
await radioFixture.checkRadio('keyboard');
await radioFixture.expectChecked(true);
});
test('spacebar should deselect with allowEmptySelection', async ({ page }) => {
await page.setContent(`
<ion-radio-group value="one" allow-empty-selection="true">
<ion-item>
<ion-label>One</ion-label>
<ion-radio id="one" value="one"></ion-radio>
</ion-item>
</ion-radio-group>
`);
await radioFixture.checkRadio('keyboard');
await radioFixture.expectChecked(false);
});
test('click should not deselect without allowEmptySelection', async ({ page }) => {
await page.setContent(`
<ion-radio-group value="one" allow-empty-selection="false">
<ion-item>
<ion-label>One</ion-label>
<ion-radio id="one" value="one"></ion-radio>
</ion-item>
</ion-radio-group>
`);
await radioFixture.checkRadio('mouse');
await radioFixture.expectChecked(true);
});
test('click should deselect with allowEmptySelection', async ({ page }) => {
await page.setContent(`
<ion-radio-group value="one" allow-empty-selection="true">
<ion-item>
<ion-label>One</ion-label>
<ion-radio id="one" value="one"></ion-radio>
</ion-item>
</ion-radio-group>
`);
await radioFixture.checkRadio('mouse');
await radioFixture.expectChecked(false);
});
});
class RadioFixture {
readonly page: E2EPage;
private radio!: Locator;
constructor(page: E2EPage) {
this.page = page;
}
async checkRadio(method: 'keyboard' | 'mouse', selector = 'ion-radio') {
const { page } = this;
const radio = (this.radio = page.locator(selector));
if (method === 'keyboard') {
await radio.focus();
await page.keyboard.press('Space');
} else {
await radio.click();
}
await page.waitForChanges();
return radio;
}
async expectChecked(state: boolean) {
const { radio } = this;
await expect(radio.locator('input')).toHaveJSProperty('checked', state);
}
}

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

View File

@@ -0,0 +1,34 @@
import { expect } from '@playwright/test';
import { test } from '@utils/test/playwright';
test.describe('radio-group: form', () => {
test.beforeEach(async ({ page }) => {
await page.goto('/src/components/radio-group/test/form');
});
test('selecting an option should update the value', async ({ page }) => {
const radioGroup = page.locator('ion-radio-group');
const ionChange = await page.spyOnEvent('ionChange');
const griffRadio = page.locator('ion-radio[value="griff"]');
await expect(radioGroup).toHaveAttribute('value', 'biff');
await griffRadio.click();
await page.waitForChanges();
await expect(ionChange).toHaveReceivedEventDetail({ value: 'griff' });
});
test('selecting a disabled option should not update the value', async ({ page }) => {
const value = page.locator('#value');
const disabledRadio = page.locator('ion-radio[value="george"]');
await expect(value).toHaveText('');
await expect(disabledRadio).toHaveAttribute('disabled', '');
await disabledRadio.click({ force: true });
await page.waitForChanges();
await expect(value).toHaveText('');
});
});

View File

@@ -1,133 +0,0 @@
import { expect } from '@playwright/test';
import type { Locator } from '@playwright/test';
import { test } from '@utils/test/playwright';
import type { E2EPage } from '@utils/test/playwright';
test.describe('radio-group', () => {
// eslint-disable-next-line no-empty-pattern
test.beforeEach(({}, testInfo) => {
test.skip(testInfo.project.metadata.rtl === true, 'This does not test LTR vs RTL logic.');
});
test.describe('radio-group: interaction', () => {
let radioFixture: RadioFixture;
test.beforeEach(({ page }) => {
radioFixture = new RadioFixture(page);
});
test('spacebar should not deselect without allowEmptySelection', async ({ page }) => {
await page.setContent(`
<ion-radio-group value="one" allow-empty-selection="false">
<ion-item>
<ion-label>One</ion-label>
<ion-radio id="one" value="one"></ion-radio>
</ion-item>
</ion-radio-group>
`);
await radioFixture.checkRadio('keyboard');
await radioFixture.expectChecked(true);
});
test('spacebar should deselect with allowEmptySelection', async ({ page }) => {
await page.setContent(`
<ion-radio-group value="one" allow-empty-selection="true">
<ion-item>
<ion-label>One</ion-label>
<ion-radio id="one" value="one"></ion-radio>
</ion-item>
</ion-radio-group>
`);
await radioFixture.checkRadio('keyboard');
await radioFixture.expectChecked(false);
});
test('click should not deselect without allowEmptySelection', async ({ page }) => {
await page.setContent(`
<ion-radio-group value="one" allow-empty-selection="false">
<ion-item>
<ion-label>One</ion-label>
<ion-radio id="one" value="one"></ion-radio>
</ion-item>
</ion-radio-group>
`);
await radioFixture.checkRadio('mouse');
await radioFixture.expectChecked(true);
});
test('click should deselect with allowEmptySelection', async ({ page }) => {
await page.setContent(`
<ion-radio-group value="one" allow-empty-selection="true">
<ion-item>
<ion-label>One</ion-label>
<ion-radio id="one" value="one"></ion-radio>
</ion-item>
</ion-radio-group>
`);
await radioFixture.checkRadio('mouse');
await radioFixture.expectChecked(false);
});
});
test.describe('radio-group: state', () => {
test('radio should remain checked after being removed/readded to the dom', async ({ page }) => {
await page.goto('/src/components/radio-group/test/search');
const radioGroup = page.locator('ion-radio-group');
const radio = page.locator('ion-radio[value=two]');
// select radio
await radio.click();
await expect(radio.locator('input')).toHaveJSProperty('checked', true);
// filter radio so it is not in DOM
await page.fill('ion-searchbar input', 'zero');
await page.waitForChanges();
expect(radio).toBeHidden();
// ensure radio group has the same value
expect(radioGroup).toHaveJSProperty('value', 'two');
// clear the search so the radio appears
await page.fill('ion-searchbar input', '');
await page.waitForChanges();
// ensure that the new radio instance is still checked
await expect(radio.locator('input')).toHaveJSProperty('checked', true);
});
});
});
class RadioFixture {
readonly page: E2EPage;
private radio!: Locator;
constructor(page: E2EPage) {
this.page = page;
}
async checkRadio(method: 'keyboard' | 'mouse', selector = 'ion-radio') {
const { page } = this;
const radio = (this.radio = page.locator(selector));
if (method === 'keyboard') {
await radio.focus();
await page.keyboard.press('Space');
} else {
await radio.click();
}
await page.waitForChanges();
return radio;
}
async expectChecked(state: boolean) {
const { radio } = this;
await expect(radio.locator('input')).toHaveJSProperty('checked', state);
}
}

View File

@@ -0,0 +1,35 @@
import { expect } from '@playwright/test';
import { test } from '@utils/test/playwright';
test.describe('radio-group', () => {
test.beforeEach(async ({ page }, testInfo) => {
test.skip(testInfo.project.metadata.rtl === true, 'This does not test LTR vs RTL logic.');
await page.goto('/src/components/radio-group/test/search');
});
test.describe('radio-group: state', () => {
test('radio should remain checked after being removed/readded to the dom', async ({ page }) => {
const radioGroup = page.locator('ion-radio-group');
const radio = page.locator('ion-radio[value=two]');
// select radio
await radio.click();
await expect(radio.locator('input')).toHaveJSProperty('checked', true);
// filter radio so it is not in DOM
await page.fill('ion-searchbar input', 'zero');
await page.waitForChanges();
expect(radio).toBeHidden();
// ensure radio group has the same value
expect(radioGroup).toHaveJSProperty('value', 'two');
// clear the search so the radio appears
await page.fill('ion-searchbar input', '');
await page.waitForChanges();
// ensure that the new radio instance is still checked
await expect(radio.locator('input')).toHaveJSProperty('checked', true);
});
});
});