|
| 1 | +--- |
| 2 | +title: Playwright |
| 3 | +parent: Testing |
| 4 | +layout: default |
| 5 | +published: true |
| 6 | +grand_parent: My Docs |
| 7 | +--- |
| 8 | + |
| 9 | +### How to extend the page object in the playwright. |
| 10 | +--- |
| 11 | + |
| 12 | +I googled a lot to find it but officially there are no docs for this. So after a lot of research I found a way to do it. |
| 13 | + |
| 14 | +This is the typescript version. |
| 15 | + |
| 16 | +```ts |
| 17 | +import { test as baseTest, Locator, Page } from '@playwright/test'; |
| 18 | +import { UserCredential } from '@firebase/auth'; |
| 19 | +import { FirebaseError } from 'firebase/app'; |
| 20 | +type MyPage = { |
| 21 | + navigateAsync: (testId: string) => Promise<void>, |
| 22 | + findTextInput: (testId: string) => { |
| 23 | + setCursorAt: (position: number) => Promise<void> |
| 24 | + selectText: (startPosition: number, endPosition: number) => Promise<void> |
| 25 | + } |
| 26 | +} |
| 27 | +type MyFixtures = { |
| 28 | + auth: { |
| 29 | + loginAsync: (user: any) => Promise<UserCredential | FirebaseError> |
| 30 | + logoutAsync: () => Promise<void> |
| 31 | + }, |
| 32 | + page: MyPage & Page, |
| 33 | +} |
| 34 | +export const test = baseTest.extend<MyFixtures>({ |
| 35 | + page: ({ page }: { page: MyPage & Page }, use) => { |
| 36 | + page.navigateAsync = async (testId: string) => await page.getByTestId(testId).click(); |
| 37 | + page.findTextInput = (testId: string) => { |
| 38 | + let textInput = page.getByTestId(testId) as Locator; |
| 39 | + return { |
| 40 | + selectText: async (startPosition: number, endPosition: number) => { |
| 41 | + await textInput.waitFor(); |
| 42 | + await textInput.evaluate((el, { startPosition, endPosition }) => { |
| 43 | + (el as HTMLInputElement).setSelectionRange(startPosition, endPosition) |
| 44 | + }, { startPosition, endPosition });; |
| 45 | + }, |
| 46 | + setCursorAt: async (position: number) => { |
| 47 | + await textInput.waitFor(); |
| 48 | + await textInput.evaluate((el, position) => { |
| 49 | + (el as HTMLInputElement).setSelectionRange(position, position) |
| 50 | + }, position); |
| 51 | + } |
| 52 | + } |
| 53 | + } |
| 54 | + use(page); |
| 55 | + }, |
| 56 | + auth: ({ page }, use) => { |
| 57 | + use({ |
| 58 | + loginAsync: async (user) => await page.evaluate(async (user: { email: string; displayName: string; }) => { |
| 59 | + return await (window as any).firebase.login(user.email, user.displayName); |
| 60 | + }, user), |
| 61 | + logoutAsync: async () => { |
| 62 | + await page |
| 63 | + .locator(`button[data-testid=menu-logout]`) |
| 64 | + .filter({ has: page.locator(':not([hidden]), :not([style*="display: none"])') }) |
| 65 | + .click(); |
| 66 | + }, |
| 67 | + }) |
| 68 | + }, |
| 69 | +}); |
| 70 | +export const expect = test.expect; |
| 71 | +``` |
| 72 | + |
| 73 | +Now instead of using test and expect from `import test, { expect } from '@playwright/test';`, import from the above custom test and expect. |
| 74 | + |
| 75 | +- Usage |
| 76 | + |
| 77 | +```ts |
| 78 | +import { expect, test } from './../baseFixtures'; |
| 79 | +test.describe('Suite 1', () => { |
| 80 | + test('Test 1', async ({ page, auth }) => { |
| 81 | + await page.goto('/'); |
| 82 | + await auth.loginAsync({ email: '', passowrd: '' }); |
| 83 | + await page.navigateAsync('menu-home'); |
| 84 | + // assert logic skipped. |
| 85 | + }); |
| 86 | +}); |
| 87 | +``` |
0 commit comments