diff --git a/core/playwright.config.ts b/core/playwright.config.ts index 9dbaf4bc14..8e5bb1374d 100644 --- a/core/playwright.config.ts +++ b/core/playwright.config.ts @@ -1,5 +1,9 @@ import type { PlaywrightTestConfig } from '@playwright/test'; -import { devices } from '@playwright/test'; +import { devices, expect } from '@playwright/test'; + +import { matchers } from './src/utils/test/playwright'; + +expect.extend(matchers); const projects = [ { diff --git a/core/src/components/picker-column-internal/test/basic/e2e.ts b/core/src/components/picker-column-internal/test/basic/e2e.ts deleted file mode 100644 index 7e82600e97..0000000000 --- a/core/src/components/picker-column-internal/test/basic/e2e.ts +++ /dev/null @@ -1,76 +0,0 @@ -import type { E2EPage } from '@stencil/core/testing'; -import { newE2EPage } from '@stencil/core/testing'; - -describe('picker-column-internal', () => { - let page: E2EPage; - - describe('default', () => { - beforeEach(async () => { - page = await newE2EPage({ - url: '/src/components/picker-column-internal/test/basic?ionic:_testing=true', - }); - }); - - it('should render a picker item for each item', async () => { - const columns = await page.findAll('ion-picker-column-internal >>> .picker-item:not(.picker-item-empty)'); - expect(columns.length).toEqual(24); - }); - - it('should render 6 empty picker items', async () => { - const columns = await page.findAll('ion-picker-column-internal >>> .picker-item-empty'); - expect(columns.length).toEqual(6); - }); - - it('should not have an active item when value is not set', async () => { - const activeColumn = await page.findAll('ion-picker-column-internal >>> .picker-item-active'); - expect(activeColumn.length).toEqual(0); - }); - - it('should have an active item when value is set', async () => { - await page.$eval('ion-picker-column-internal#default', (el: any) => { - el.value = '12'; - }); - await page.waitForChanges(); - - const activeColumn = await page.find('ion-picker-column-internal >>> .picker-item-active'); - - expect(activeColumn).not.toBeNull(); - }); - - it('scrolling should change the active item', async () => { - await page.$eval('ion-picker-column-internal#default', (el: any) => { - el.scrollTop = 801; - }); - - await page.waitForChanges(); - - const activeColumn = await page.find('ion-picker-column-internal >>> .picker-item-active'); - - expect(activeColumn.innerText).toEqual('23'); - }); - - it('should not emit ionChange when the value is modified externally', async () => { - const pickerColumn = await page.find('#default'); - const ionChangeSpy = await pickerColumn.spyOnEvent('ionChange'); - - await page.$eval('#default', (el: any) => { - el.value = '12'; - }); - - expect(ionChangeSpy).not.toHaveReceivedEvent(); - }); - - it('should emit ionChange when the picker is scrolled', async () => { - const pickerColumn = await page.find('#default'); - const ionChangeSpy = await pickerColumn.spyOnEvent('ionChange'); - - await page.$eval('#default', (el: any) => { - el.scrollTo(0, el.scrollHeight); - }); - - await ionChangeSpy.next(); - - expect(ionChangeSpy).toHaveReceivedEvent(); - }); - }); -}); diff --git a/core/src/components/picker-column-internal/test/basic/picker-column-internal.e2e.ts b/core/src/components/picker-column-internal/test/basic/picker-column-internal.e2e.ts new file mode 100644 index 0000000000..10d9296375 --- /dev/null +++ b/core/src/components/picker-column-internal/test/basic/picker-column-internal.e2e.ts @@ -0,0 +1,74 @@ +import { expect } from '@playwright/test'; +import { test } from '@utils/test/playwright'; + +test.describe('picker-column-internal', () => { + test.beforeEach(async ({ page }) => { + await page.goto('/src/components/picker-column-internal/test/basic'); + }); + + test('should render a picker item for each item', async ({ page }) => { + const columns = page.locator('ion-picker-column-internal .picker-item:not(.picker-item-empty)'); + expect(columns).toHaveCount(24); + }); + + test('should render 6 empty picker items', async ({ page }) => { + const columns = page.locator('ion-picker-column-internal .picker-item-empty'); + expect(columns).toHaveCount(6); + }); + + test('should not have an active item when value is not set', async ({ page }) => { + const activeColumn = page.locator('ion-picker-column-internal .picker-item-active'); + expect(activeColumn).toHaveCount(0); + }); + + test('should have an active item when value is set', async ({ page }) => { + await page.locator('#default').evaluate((el: HTMLIonPickerColumnInternalElement) => { + el.value = '12'; + }); + await page.waitForChanges(); + + const activeColumn = page.locator('ion-picker-column-internal .picker-item-active'); + + expect(activeColumn).not.toBeNull(); + }); + + test('scrolling should change the active item', async ({ page, browserName }) => { + test.skip(browserName === 'firefox', 'https://bugzilla.mozilla.org/show_bug.cgi?id=1766890'); + + await page.locator('#default').evaluate((el: HTMLIonPickerColumnInternalElement) => { + el.scrollTop = 801; + }); + await page.waitForChanges(); + + const activeColumn = page.locator('ion-picker-column-internal .picker-item-active'); + + expect(await activeColumn?.innerText()).toEqual('23'); + }); + + test('should not emit ionChange when the value is modified externally', async ({ page, browserName }) => { + test.skip(browserName === 'firefox', 'https://bugzilla.mozilla.org/show_bug.cgi?id=1766890'); + + const ionChangeSpy = await page.spyOnEvent('ionChange'); + + await page.locator('#default').evaluate((el: HTMLIonPickerColumnInternalElement) => { + el.value = '12'; + }); + + expect(ionChangeSpy).not.toHaveReceivedEvent(); + }); + + test('should emit ionChange when the picker is scrolled', async ({ page, browserName }) => { + test.skip(browserName === 'firefox', 'https://bugzilla.mozilla.org/show_bug.cgi?id=1766890'); + + const ionChangeSpy = await page.spyOnEvent('ionChange'); + + await page.locator('#default').evaluate((el: HTMLIonPickerColumnInternalElement) => { + el.scrollTo(0, el.scrollHeight); + }); + await page.waitForChanges(); + + await ionChangeSpy.next(); + + expect(ionChangeSpy).toHaveReceivedEvent(); + }); +}); diff --git a/core/src/utils/test/playwright/index.ts b/core/src/utils/test/playwright/index.ts index ef4f136f6c..25d11f86f4 100644 --- a/core/src/utils/test/playwright/index.ts +++ b/core/src/utils/test/playwright/index.ts @@ -2,3 +2,4 @@ export * from './playwright-page'; export * from './playwright-declarations'; export * from './page/event-spy'; export * from './drag-element'; +export * from './matchers'; diff --git a/core/src/utils/test/playwright/matchers/index.ts b/core/src/utils/test/playwright/matchers/index.ts new file mode 100644 index 0000000000..e8c2900067 --- /dev/null +++ b/core/src/utils/test/playwright/matchers/index.ts @@ -0,0 +1,5 @@ +import { toHaveReceivedEvent } from './toHaveReceivedEvent'; + +export const matchers = { + toHaveReceivedEvent, +}; diff --git a/core/src/utils/test/playwright/matchers/toHaveReceivedEvent.ts b/core/src/utils/test/playwright/matchers/toHaveReceivedEvent.ts new file mode 100644 index 0000000000..b07c37379f --- /dev/null +++ b/core/src/utils/test/playwright/matchers/toHaveReceivedEvent.ts @@ -0,0 +1,28 @@ +import type { EventSpy } from '../page/event-spy'; + +export function toHaveReceivedEvent(eventSpy: EventSpy) { + if (!eventSpy) { + return { + message: () => `expected spy to have received event, but it was not defined`, + pass: false, + }; + } + if (typeof (eventSpy as any).then === 'function') { + return { + message: () => + `expected spy to have received event, but it was not resolved (did you forget an await operator?).`, + pass: false, + }; + } + const pass = eventSpy.events.length > 0; + if (pass) { + return { + message: () => `expected to have called ${eventSpy.eventName} event`, + pass: true, + }; + } + return { + message: () => `expected to have not called ${eventSpy.eventName} event`, + pass: false, + }; +} diff --git a/core/src/utils/test/playwright/testExpect.d.ts b/core/src/utils/test/playwright/testExpect.d.ts new file mode 100644 index 0000000000..d64692a06a --- /dev/null +++ b/core/src/utils/test/playwright/testExpect.d.ts @@ -0,0 +1,11 @@ +interface CustomMatchers { + /** + * Will check if the event spy received the expected event. + */ + toHaveReceivedEvent(): R; +} + +declare namespace PlaywrightTest { + // eslint-disable-next-line @typescript-eslint/no-empty-interface + interface Matchers extends CustomMatchers {} +}