Skip to content
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

migrate from cypress to playwright #1510

Merged
merged 31 commits into from
Jun 11, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
eac7e20
add playwright tests
oliverabrahams Jun 3, 2024
cd45bd3
add playwright tests
oliverabrahams Jun 4, 2024
d7c00c4
remove unused files
oliverabrahams Jun 4, 2024
a77a934
rollback
oliverabrahams Jun 4, 2024
728599c
rollback
oliverabrahams Jun 4, 2024
b1de61a
git ignore
oliverabrahams Jun 4, 2024
e8db7b1
fix jest to not run playwright
oliverabrahams Jun 4, 2024
f994041
ensure playwright browsers are installed before running e2e in libs
sndrs Jun 4, 2024
4d0e7e7
remove cypress
oliverabrahams Jun 4, 2024
2707c10
remove cypress
oliverabrahams Jun 4, 2024
83be1f6
merge main
oliverabrahams Jun 4, 2024
32f94b6
remove cypress
oliverabrahams Jun 4, 2024
b1e6f6a
revert pnpm lock-file
oliverabrahams Jun 4, 2024
34d1ac1
debugging ci
oliverabrahams Jun 4, 2024
4a560a1
debugging ci
oliverabrahams Jun 4, 2024
147968f
add playwright report
oliverabrahams Jun 4, 2024
1e5c252
add playwright report
oliverabrahams Jun 4, 2024
510a977
add playwright report
oliverabrahams Jun 4, 2024
4527be2
WIP potential fix
oliverabrahams Jun 4, 2024
123f312
reduced retention for playwright tests
oliverabrahams Jun 4, 2024
04872c7
Merge branch 'main' into oa/playwright-v2
oliverabrahams Jun 4, 2024
f78cc6b
fixed caching for playwright
oliverabrahams Jun 5, 2024
3a065ab
convert example to js
oliverabrahams Jun 5, 2024
526bf7d
move install step into e2e command
oliverabrahams Jun 5, 2024
42dbd73
remove install cmd
oliverabrahams Jun 5, 2024
f7e34d8
add e2e:ui command
oliverabrahams Jun 6, 2024
bf32867
Merge branch 'main' into oa/playwright-v2
oliverabrahams Jun 6, 2024
9f89915
Merge branch 'main' into oa/playwright-v2
sndrs Jun 11, 2024
83e6a51
re-run precommit hooks
sndrs Jun 11, 2024
a1aaed3
remove cypress stuff from setup action
sndrs Jun 11, 2024
c236f00
collapse deps
sndrs Jun 11, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,9 @@ storybook-static

# cypress stuff
**/cypress/downloads/

# playwright stuff
**/test-results/
**/playwright-report/
**/blob-report/
**/playwright/.cache/
14 changes: 8 additions & 6 deletions libs/@guardian/libs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"verify-dist": "wireit"
},
"devDependencies": {
"@playwright/test": "1.44.1",
"@types/jest": "29.5.8",
"@types/wcag-contrast": "3.0.3",
"cypress": "13.7.1",
Expand Down Expand Up @@ -69,16 +70,17 @@
]
},
"e2e": {
"command": "cypress run --headless",
"command": "playwright test",
"files": [
"!(dist)/**",
"!(.eslintcache)",
"!(jest*)"
"!(jest*)",
"!(playwright-report)/**",
"!(test-results)/**",
"./playwright/**",
"./src/**"
],
"output": [],
"dependencies": [
"../../../apps/github-pages:start"
]
"output": []
},
"fix": {
"command": "eslint --cache --color . --fix",
Expand Down
30 changes: 30 additions & 0 deletions libs/@guardian/libs/playwright.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { defineConfig, devices } from '@playwright/test';

/**
* See https://playwright.dev/docs/test-configuration.
*/
// eslint-disable-next-line import/no-default-export -- playwright wants this
export default defineConfig({
testDir: './playwright',
fullyParallel: true,
forbidOnly: !!process.env.CI,
retries: process.env.CI ? 1 : 0,
workers: process.env.CI ? 1 : undefined,
reporter: 'html',
use: {
baseURL: 'http://localhost:4321/csnx',
trace: 'on-first-retry',
},
projects: [
{
name: 'chromium',
use: { ...devices['Desktop Chrome'] },
},
],

webServer: {
command: 'cd ../../../ && pnpm --filter github-pages start',
jamesmockett marked this conversation as resolved.
Show resolved Hide resolved
url: 'http://localhost:4321/csnx',
reuseExistingServer: !process.env.CI,
},
});
113 changes: 113 additions & 0 deletions libs/@guardian/libs/playwright/e2e/sourcepoint-aus.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import { expect, test } from '@playwright/test';
import {
ACCOUNT_ID,
ENDPOINT,
PRIVACY_MANAGER_AUSTRALIA,
} from '../fixtures/sourcepointConfig';

const iframePrivacyManager = `#sp_message_iframe_${PRIVACY_MANAGER_AUSTRALIA}`;

const url = `http://localhost:4321/csnx/cmp-test-page#aus`;

async function personalisedAdvertisingIs(page, boolean) {
await page.locator('[data-personalised-advertising]').waitFor({
state: 'attached',
timeout: 2000,
});
await page.waitForFunction(
(bool) =>
document
.querySelector('[data-personalised-advertising]')
.getAttribute('data-personalised-advertising') === bool.toString(),
boolean,
{ timeout: 2000 },
);

const attributeValue = await page
.locator('[data-personalised-advertising]')
.getAttribute('data-personalised-advertising');
expect(attributeValue).toBe(boolean.toString());
}

test.describe('Window', () => {
test('has the guCmpHotFix object', async ({ page }) => {
await page.goto(url);
await page.waitForLoadState('networkidle');
const guCmpHotFix = await page.evaluate(() => {
return window.guCmpHotFix;
});
expect(guCmpHotFix).toBeDefined();
});

test('has correct config params', async ({ page }) => {
await page.goto(url);
await page.waitForLoadState('networkidle');
const spConfig = await page.evaluate(() => {
return window._sp_.config;
});
expect(spConfig.accountId).toBe(ACCOUNT_ID);
expect(spConfig.baseEndpoint).toBe(ENDPOINT);
});
});

test.describe('Document', () => {
test('should have the Sourcepoint iframe', async ({ page }) => {
await page.goto(url);
const iframe = page
.frameLocator('iframe[title="SP Consent Message"]')
.locator('.message-overlay');
await expect(iframe).toBeVisible({ timeout: 10000 });
});
test('should have the correct script URL', async ({ page }) => {
await page.goto(url);
const script = page.locator('script[id="sourcepoint-lib"]');
await expect(script).toHaveAttribute(
'src',
ENDPOINT + '/unified/wrapperMessagingWithoutDetection.js',
);
});
});
test.describe('Interaction', () => {
test('should have personalised advertising set to true by default', async ({
page,
}) => {
await page.goto(url);
await page
.context()
.addCookies([{ name: 'ccpaApplies', value: 'true', url }]);
await personalisedAdvertisingIs(page, true);
});

test('Should click continue to dismiss the banner', async ({ page }) => {
await page.goto(url);
await page
.context()
.addCookies([{ name: 'ccpaApplies', value: 'true', url }]);
await page
.frameLocator('iframe[title="SP Consent Message"]')
.locator('[aria-label="Continue"]')
.click();
});

test('should be able to retract consent', async ({ page }) => {
await page.goto(url);
await page
.context()
.addCookies([{ name: 'ccpaApplies', value: 'true', url }]);

await personalisedAdvertisingIs(page, true);

await page
.frameLocator('iframe[title="SP Consent Message"]')
.locator('[aria-label="Continue"]')
.click();

await page.locator('[data-cy=pm]').click();

const privacyManagerIframe = page.frameLocator(iframePrivacyManager);
await privacyManagerIframe.locator('.pm-toggle .off').click();
await privacyManagerIframe.locator('.sp_choice_type_SAVE_AND_EXIT').click();

await personalisedAdvertisingIs(page, false);
});
});
117 changes: 117 additions & 0 deletions libs/@guardian/libs/playwright/e2e/sourcepoint-ccpa.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
import { expect, test } from '@playwright/test';
import {
ACCOUNT_ID,
ENDPOINT,
PRIVACY_MANAGER_CCPA,
} from '../fixtures/sourcepointConfig';

const iframePrivacyManager = `#sp_message_iframe_${PRIVACY_MANAGER_CCPA}`;

const url = `http://localhost:4321/csnx/cmp-test-page#ccpa`;

async function doNotSellIs(page, expectedValue) {
await page.locator('[data-donotsell]').waitFor({
state: 'attached',
timeout: 2000,
});
await page.waitForFunction(
(expectedValue) =>
document
.querySelector('[data-donotsell]')
.getAttribute('data-donotsell') === expectedValue.toString(),
expectedValue,
{ timeout: 2000 },
);
const attributeValue = await page
.locator('[data-donotsell]')
.getAttribute('data-donotsell');
expect(attributeValue).toBe(expectedValue.toString());
}

async function getIframeBody(page, selector) {
const iframeElement = await page.locator(`iframe${selector}`).elementHandle();
const frame = await iframeElement.contentFrame();
const iframeBody = await frame.$('body');

if (!iframeBody) {
throw new Error('Iframe body is empty');
}

return frame;
}

test.describe('Window', () => {
test('has the guCmpHotFix object', async ({ page }) => {
await page.goto(url);
await page.waitForLoadState('networkidle');
const guCmpHotFix = await page.evaluate(() => {
return window.guCmpHotFix;
});
expect(guCmpHotFix).toBeDefined();
});

test('has correct config params', async ({ page }) => {
await page.goto(url);
await page.waitForLoadState('networkidle');
const spConfig = await page.evaluate(() => window._sp_.config);
expect(spConfig.accountId).toBe(ACCOUNT_ID);
expect(spConfig.baseEndpoint).toBe(ENDPOINT);
});
});

test.describe('Document', () => {
test('should have the SP iframe', async ({ page }) => {
await page.goto(url);
const iframe = page
.frameLocator('iframe[title="SP Consent Message"]')
.getByLabel('Do not sell my personal');
await expect(iframe).toBeVisible({ timeout: 3000 });
});

test('should have the correct script URL', async ({ page }) => {
await page.goto(url);
const scriptSrc = await page.getAttribute('script#sourcepoint-lib', 'src');
expect(scriptSrc).toBe(
`${ENDPOINT}/unified/wrapperMessagingWithoutDetection.js`,
);
});
});

test.describe('Interaction', () => {
const buttonTitle = 'Do not sell my personal information';

test('should have DNS set to false by default', async ({ page }) => {
await page.goto(url);
await doNotSellIs(page, false);
});

test(`should retract consent when clicking "${buttonTitle}"`, async ({
page,
}) => {
await page.goto(url);

await page
.frameLocator('iframe[title="SP Consent Message"]')
.getByLabel('Do not sell my personal')
.click();

await doNotSellIs(page, true);
});

test(`should be able to retract consent`, async ({ page }) => {
await page.goto(url);

await doNotSellIs(page, false);

await page.click('[data-cy=pm]');

const privacyManagerIframe = await getIframeBody(
page,
iframePrivacyManager,
);
await privacyManagerIframe.click('.pm-toggle .off');
await privacyManagerIframe.click('.sp_choice_type_SAVE_AND_EXIT');

await doNotSellIs(page, true);
});
});
Loading
Loading