-
Notifications
You must be signed in to change notification settings - Fork 155
Migrate consent integration tests to playwright from webdriver.io - LIBRARIES-2546 #1279
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 4 commits
26fb722
e48f302
86ffd28
64136f7
5a31945
127f683
3528d93
f2b70d4
c82ee1d
9a5cfa9
eb27030
355a289
68fd11a
6cac5f9
0f52a33
cc45627
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| import type { PlaywrightTestConfig } from '@playwright/test' | ||
|
|
||
| const PORT = 4567 | ||
| const config: PlaywrightTestConfig = { | ||
| testDir: './src/tests', | ||
| timeout: 30000, | ||
| retries: 1, | ||
| webServer: { | ||
| command: 'yarn http-server public -p 4567', | ||
silesky marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| port: 4567, | ||
| reuseExistingServer: !process.env.CI, | ||
| }, | ||
| use: { | ||
| headless: true, | ||
| viewport: { width: 1280, height: 720 }, | ||
silesky marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| baseURL: `http://localhost:${PORT}`, | ||
| video: { | ||
| mode: 'off', | ||
| size: { width: 640, height: 480 }, | ||
| }, | ||
| }, | ||
| } | ||
|
|
||
| export default config | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,124 +1,116 @@ | ||
| import { CDNSettingsBuilder } from '@internal/test-helpers' | ||
| import type { SegmentEvent } from '@segment/analytics-next' | ||
| import assert from 'assert' | ||
| import type { Matches } from 'webdriverio' | ||
|
|
||
| const waitUntilReady = () => | ||
| browser.waitUntil( | ||
| () => browser.execute(() => document.readyState === 'complete'), | ||
| { | ||
| timeout: 10000, | ||
| } | ||
| ) | ||
| import { Page, Route, Request } from '@playwright/test' | ||
|
|
||
| export abstract class BasePage { | ||
| constructor(protected page: string) {} | ||
| protected page: Page | ||
| protected pageFile: string | ||
|
|
||
| segmentTrackingApiReqs: any[] = [] | ||
| fetchIntegrationReqs: any[] = [] | ||
|
|
||
| segmentTrackingApiReqs: Matches[] = [] | ||
| fetchIntegrationReqs: Matches[] = [] | ||
| constructor(page: Page, pageFile: string) { | ||
| this.page = page | ||
| this.pageFile = pageFile | ||
| } | ||
|
|
||
| async load(): Promise<void> { | ||
| const baseURL = browser.options.baseUrl | ||
| assert(baseURL) | ||
| await this.mockAPIs() | ||
| await browser.url(baseURL + '/public/' + this.page) | ||
| await waitUntilReady() | ||
| await this.page.goto(`/${this.pageFile}`) | ||
| await this.page.waitForLoadState('load') | ||
| } | ||
|
|
||
| async clearStorage() { | ||
| await browser.deleteAllCookies() | ||
| await browser.execute(() => window.localStorage.clear()) | ||
| await this.page.context().clearCookies() | ||
| await this.page.evaluate(() => { | ||
| window.localStorage.clear() | ||
| window.sessionStorage.clear() | ||
| }) | ||
| } | ||
|
|
||
| getAllTrackingEvents(): SegmentEvent[] { | ||
| const reqBodies = this.segmentTrackingApiReqs.map((el) => | ||
| JSON.parse(el.postData!) | ||
| ) | ||
| return reqBodies | ||
| async cleanup() { | ||
| this.segmentTrackingApiReqs = [] | ||
| this.fetchIntegrationReqs = [] | ||
| await this.clearStorage() | ||
| } | ||
|
|
||
| getAllTrackingEvents(): any[] { | ||
|
||
| return this.segmentTrackingApiReqs | ||
| } | ||
|
|
||
| getConsentChangedEvents(): SegmentEvent[] { | ||
| const reqBodies = this.getAllTrackingEvents() | ||
| const consentEvents = reqBodies.filter( | ||
| getConsentChangedEvents(): any[] { | ||
| return this.getAllTrackingEvents().filter( | ||
| (el) => el.event === 'Segment Consent Preference Updated' | ||
| ) | ||
| return consentEvents | ||
| } | ||
|
|
||
| async cleanup() { | ||
| this.segmentTrackingApiReqs = [] | ||
| this.fetchIntegrationReqs = [] | ||
| await this.clearStorage() | ||
| get fetchIntegrationReqsData(): any[] { | ||
| return this.fetchIntegrationReqs | ||
| } | ||
|
|
||
| async mockAPIs() { | ||
| private async mockAPIs() { | ||
| await this.mockSegmentTrackingAPI() | ||
| await this.mockCDNSettingsAPI() | ||
| await this.mockNextIntegrationsAPI() | ||
| } | ||
|
|
||
| private async mockSegmentTrackingAPI(): Promise<void> { | ||
| const mock = await browser.mock('https://api.segment.io/v1/t', { | ||
| method: 'post', | ||
| }) | ||
| mock.respond((mock) => { | ||
| this.segmentTrackingApiReqs.push(mock) | ||
| // response with status 200 | ||
| return Promise.resolve({ | ||
| statusCode: 200, | ||
| body: JSON.stringify({ success: true }), | ||
| }) | ||
| }) | ||
| private async mockSegmentTrackingAPI() { | ||
| await this.page.route( | ||
| 'https://api.segment.io/v1/t', | ||
| async (route: Route, request: Request) => { | ||
| const postData = await request.postData() | ||
| const parsed = JSON.parse(postData || '{}') | ||
| this.segmentTrackingApiReqs.push(parsed) // store the parsed event object directly | ||
|
|
||
| await route.fulfill({ | ||
| status: 200, | ||
| contentType: 'application/json', | ||
| body: JSON.stringify({ success: true }), | ||
| }) | ||
| } | ||
| ) | ||
| } | ||
|
|
||
| private async mockNextIntegrationsAPI(): Promise<void> { | ||
| const mock = await browser.mock('**/next-integrations/**') | ||
| mock.respond((mock) => { | ||
| this.fetchIntegrationReqs.push(mock) | ||
| return Promise.resolve({ | ||
| statusCode: 200, | ||
| body: 'console.log("mocking action and classic destinations")', | ||
| }) | ||
| }) | ||
| private async mockNextIntegrationsAPI() { | ||
| await this.page.route( | ||
| '**/next-integrations/**', | ||
| async (route: Route, request: Request) => { | ||
| this.fetchIntegrationReqs.push({ url: request.url() }) | ||
| await route.fulfill({ | ||
| status: 200, | ||
| body: 'console.log("mocking action and classic destinations")', | ||
| contentType: 'application/javascript', | ||
silesky marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| }) | ||
| } | ||
| ) | ||
| } | ||
|
|
||
| /** * Mock the CDN Settings endpoint so that this can run offline | ||
| */ | ||
| private async mockCDNSettingsAPI(): Promise<void> { | ||
| const settings = new CDNSettingsBuilder({ | ||
| writeKey: 'something', | ||
| }) | ||
| .addActionDestinationSettings( | ||
| { | ||
| private async mockCDNSettingsAPI() { | ||
|
||
| const settings = { | ||
| integrations: { | ||
| FullStory: { | ||
| url: 'https://cdn.segment.com/next-integrations/actions/fullstory-plugins/foo.js', | ||
| creationName: 'FullStory', | ||
| consentSettings: { | ||
| categories: ['FooCategory2'], | ||
| }, | ||
| }, | ||
| { | ||
| 'Actions Amplitude': { | ||
| url: 'https://cdn.segment.com/next-integrations/actions/amplitude-plugins/foo.js', | ||
| creationName: 'Actions Amplitude', | ||
| consentSettings: { | ||
| categories: ['FooCategory1'], | ||
| }, | ||
| } | ||
| ) | ||
| .build() | ||
|
|
||
| const mock = await browser.mock('**/settings') | ||
| mock.respond(settings, { | ||
| statusCode: 200, | ||
| headers: { | ||
| 'Content-Type': 'application/json', | ||
| }, | ||
| }, | ||
| } | ||
|
|
||
| await this.page.route('**/settings', async (route: Route) => { | ||
| await route.fulfill({ | ||
| status: 200, | ||
| contentType: 'application/json', | ||
| body: JSON.stringify(settings), | ||
| }) | ||
| }) | ||
| } | ||
|
|
||
| /** | ||
| * Hard reload the page | ||
| */ | ||
| reload() { | ||
| return browser.execute(() => window.location.reload()) | ||
| async reload() { | ||
| await this.page.reload() | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,24 +1,28 @@ | ||
| import { Page } from '@playwright/test' | ||
| import { BasePage } from './base-page' | ||
|
|
||
| export class ConsentToolsVanilla extends BasePage { | ||
| constructor(page: Page, file: string) { | ||
| super(page, file) | ||
| } | ||
|
|
||
| async clickGiveConsent() { | ||
| const button = await $('#give-consent') | ||
| return button.click() | ||
| await this.page.locator('#give-consent').click() | ||
| } | ||
|
|
||
| async clickDenyConsent() { | ||
| const button = await $('#give-consent') | ||
| return button.click() | ||
| await this.page.locator('#deny-consent').click() | ||
| } | ||
| } | ||
|
|
||
| export class ConsentToolsVanillaOptOut extends ConsentToolsVanilla { | ||
| constructor() { | ||
| super('consent-tools-vanilla-opt-out.html') | ||
| constructor(page: Page) { | ||
| super(page, 'consent-tools-vanilla-opt-out.html') | ||
| } | ||
| } | ||
|
|
||
| export class ConsentToolsVanillaOptIn extends ConsentToolsVanilla { | ||
| constructor() { | ||
| super('consent-tools-vanilla-opt-in.html') | ||
| constructor(page: Page) { | ||
| super(page, 'consent-tools-vanilla-opt-in.html') | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,18 +1,18 @@ | ||
| import { Page } from '@playwright/test' | ||
| import { BasePage } from './base-page' | ||
|
|
||
| class OneTrustPage extends BasePage { | ||
| constructor() { | ||
| super('onetrust.html') | ||
| export class OneTrustPage extends BasePage { | ||
| constructor(page: Page) { | ||
| super(page, 'onetrust.html') | ||
| } | ||
|
|
||
| get isOneTrustLoaded(): Promise<void> { | ||
| // @ts-ignore | ||
| return window.isOneTrustLoaded | ||
| // Check if OneTrust is loaded by evaluating a global variable on the page | ||
| async isOneTrustLoaded() { | ||
| // To Do | ||
| } | ||
|
|
||
| clickAcceptButtonAndClosePopup() { | ||
| return $('#onetrust-accept-btn-handler').click() | ||
| //Click the OneTrust accept button | ||
| async clickAcceptButtonAndClosePopup() { | ||
| // To Do | ||
| } | ||
| } | ||
|
|
||
| export default new OneTrustPage() |

Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CI is still failing after pushing yarn.lock. I will look into it separately once all the test cases have been migrated.