Skip to content

Commit

Permalink
test(e2e): Improve compatibility with Docker/CI
Browse files Browse the repository at this point in the history
  • Loading branch information
JalilArfaoui committed Jun 9, 2021
1 parent dfeea8f commit 704004f
Show file tree
Hide file tree
Showing 14 changed files with 153 additions and 42 deletions.
5 changes: 1 addition & 4 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,4 @@ WORKDIR /app

# make sure we can run without a UI
ENV DISPLAY :99
CMD yarn install --frozen-lockfile &&\
Xvfb :99 -screen 0 1024x768x16 & yarn concurrently -r --kill-others -n profiles,cucumber \
'yarn start:profiles:no-progress' \
'yarn wait-on ./build/development/chromium/ && yarn wait-on http://localhost:8080 && yarn cucumber-js'
CMD ./ci/run-e2e.sh
5 changes: 5 additions & 0 deletions ci/run-e2e.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
yarn install --frozen-lockfile

Xvfb :99 -screen 0 1280x800x16 & yarn concurrently -r --kill-others -s first -n profiles,cucumber \
'yarn start:profiles:no-progress' \
'yarn wait-on ./build/development/chromium/ && yarn wait-on http://localhost:8080 && yarn cucumber-js'
2 changes: 1 addition & 1 deletion features/MatchingContext.feature
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@ Feature: Matching context
Scenario: yarnpkg.com while following Maarten
Given I am following "Maarten"
When I open the url "https://classic.yarnpkg.com/en/docs/pnp/"
Then I see the notification within 30 seconds
Then I see the notification within 10 seconds
And The first notice has text "Les développeurs de Malt expliquent pourquoi et comment"
2 changes: 2 additions & 0 deletions manifest/development/chromium.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ const base = require('../base');

module.exports = {
...base,
key:
'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuw5vP+Lrux5C7/2xOAb13OLhdVjoUrybRyq7BoLuaRPBOc3YOSP1XNVdzTfwwPNxKpPHAERYs6avmgKomfOPmuaxUpgj2hBGiJM9DJ9pbM6kkfn/ATRu9G+uug46UN8A+HbJWHsJJi/pWrGA95MBfILHmJoNN3GExnQWJZTMx7hdpgWRZmhBexEqfyI3xEzPpRTI/miU57qNwsyHw5/9riMGTpkjOqXG+sJqfax7Z630XrvmvOLN2tyG3jKbUdFx1krj1yHQDDRnkigp11BYqU1s08i1d2dY5Mnva0gT+lPuX8n/IeuMbyqkAkZTaCoeEycAdr3LGMvi2Q0uetwdJQIDAQAB',
name: `${base.name} - development`,
content_security_policy: csp({
directives: {
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@
"test:e2e:ci": "yarn build:dev && docker build -t dismoi-extension-e2e . && docker run -it --rm -v $(pwd):/app dismoi-extension-e2e",
"test:e2e": "yarn cucumber-js",
"test:e2e:extensive": "yarn concurrently -r --kill-others -n extension,profiles,cucumber 'yarn start' 'yarn start:profiles:no-progress' 'yarn wait-on ./build/development/chromium/ && yarn wait-on http://localhost:8080 && yarn test:e2e:run' ",
"test": "yarn test:unit && yarn test:e2e:run",
"test:ci": "yarn test:unit && yarn test:e2e:extensive",
"test": "yarn test:unit",
"test:ci": "yarn test:unit && yarn test:e2e:ci",
"typecheck": "tsc --noEmit",
"lint": "yarn lint:ts",
"lint-fixme-stylelint-has-to-be-fixed": "yarn lint:ts && yarn lint:css",
Expand Down
2 changes: 2 additions & 0 deletions src/Lowercase.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// puppeteer types needs this, but it’s only available in TypeScript 4+
declare type Lowercase<T> = string;
2 changes: 1 addition & 1 deletion src/components/atoms/Contributor/ContributorCard.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import styled from 'styled-components';
import { Contributor } from 'app/lmem/contributor';
import { Contributor } from 'libs/domain/contributor';

interface ContributorCardProps {
contributor: Contributor;
Expand Down
2 changes: 2 additions & 0 deletions test/e2e/pageObjects/background.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,7 @@ export default {
await background.goto(getBackgroundUrl(extensionID), {
waitUntil: 'networkidle0'
});

return background;
}
};
24 changes: 24 additions & 0 deletions test/e2e/pageObjects/iframe/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { Page, Frame } from 'puppeteer';
import expect from 'expect';
import { findIframe } from 'test/e2e/support/iframe';
import { iFrameId } from 'app/content/constants/iframe';

export const getIframe = async (page: Page): Promise<Frame> => {
await page.waitForSelector(`iframe[id="${iFrameId}"]`);
const frame = findIframe(page);
expect(frame).toBeDefined();
return frame as Frame;
};

export default {
async waitForNotification(page: Page, delayInSeconds: number) {
const frame = await getIframe(page);
if (frame) {
await frame.waitForSelector(
`section[data-test-id="notification-container"]`,
{ timeout: delayInSeconds * 1000 }
);
}
return frame;
}
};
5 changes: 4 additions & 1 deletion test/e2e/pageObjects/iframe/notices.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { Frame } from 'puppeteer';

const noticeTitle = "[data-test-type='noticeTitle']";

export default {
async getNoticesTitle(frame: Frame) {
return (frame as Frame).$$("[data-test-type='noticeTitle']");
await frame.waitForSelector(noticeTitle);
return frame.$$(noticeTitle);
}
};
35 changes: 25 additions & 10 deletions test/e2e/pageObjects/profiles/contributorsList.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Browser, Page } from 'puppeteer';
import { ConsoleMessage, Page } from 'puppeteer';
import { InitializedDisMoiWorld } from 'test/e2e/support/setup';

const profilesHost = 'http://localhost:8080';
const profilesUrl = `${profilesHost}/eclaireurs`;
Expand All @@ -11,19 +12,30 @@ const contributorCardTitleLink = (contributorName?: string) =>
`${contributorCard(
contributorName
)} [data-test-type="contributor-name-link"]`;
const contributorButton = (contributorName?: string) =>
`${contributorCard(contributorName)} [data-test-type="contributor-button"]`;

const getProfilesPage = async (browser: Browser) => {
const pages = await browser.pages();
const getProfilesPage = async (world: InitializedDisMoiWorld) => {
const pages = await world.browser.pages();
const existing = pages.find(page => page.url().includes(profilesHost));
if (existing) return existing;
const page = await browser.newPage();
if (existing) {
existing.on('console', (consoleMessage: ConsoleMessage) => {
world.consoleMessages.push(['profiles', consoleMessage.text()]);
});

return existing;
}
const page = await world.browser.newPage();
await page.goto(profilesUrl);
page.on('console', (consoleMessage: ConsoleMessage) => {
console.warn('profiles', consoleMessage.text());
});
return page;
};

export default {
async getContributorsList(browser: Browser) {
const page = await getProfilesPage(browser);
async getContributorsList(world: InitializedDisMoiWorld) {
const page = await getProfilesPage(world);
await page.goto(profilesUrl);
await page.waitForSelector(contributorCard());
return page;
Expand All @@ -34,10 +46,13 @@ export default {
);
},
async clickContributorButton(page: Page, contributorName: string) {
await page.click(
`${contributorCard(
await page.click(contributorButton(contributorName));
},
async expectContributorIsFollowed(page: Page, contributorName: string) {
await page.waitForFunction(
`document.querySelector('${contributorButton(
contributorName
)} [data-test-type="contributor-button"]`
)}').innerText !== 'Suivre'`
);
}
};
4 changes: 2 additions & 2 deletions test/e2e/step_definitions/following.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Given(/^I am following "(.+)"$/, async function(
this: InitializedDisMoiWorld,
contributorName: string
) {
this.page = await Profiles.getContributorsList(this.browser);
this.page = await Profiles.getContributorsList(this);
await Profiles.clickContributorButton(this.page, contributorName);
await this.page.waitForTimeout(1000);
await Profiles.expectContributorIsFollowed(this.page, contributorName);
});
2 changes: 1 addition & 1 deletion test/e2e/support/iframe.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Page } from 'puppeteer';
import { iFrameId } from 'app/constants/iframe';
import { iFrameId } from 'app/content/constants/iframe';

export const findIframe = (page: Page) =>
page
Expand Down
101 changes: 81 additions & 20 deletions test/e2e/support/setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ import {
Status,
World
} from '@cucumber/cucumber';
import puppeteer, { Browser, Page } from 'puppeteer';
import puppeteer, { Browser, ConsoleMessage, Page } from 'puppeteer';
import path from 'path';
import expect from 'expect';
import * as fs from 'fs';

setDefaultTimeout(60 * 1000);

Expand All @@ -26,43 +28,102 @@ const delay = (ms: number) =>
setTimeout(resolve, ms);
});

type ConsoleType = 'profiles' | 'background' | 'contentScript';

export interface DisMoiWorld extends World {
browser?: Browser;
page?: Page;
extensionId?: string;
consoleMessages?: [ConsoleType, string][];
}

export interface InitializedDisMoiWorld extends DisMoiWorld {
browser: Browser;
page: Page;
extensionId: string;
consoleMessages: [ConsoleType, string][];
}

export const getExtensionId = async (browser: Browser) => {
const targets = await browser.targets();
const startChromium = async () => {
try {
return await puppeteer.launch({
headless: false,
args: [
'--no-sandbox',
// '--disable-dev-shm-usage',
`--load-extension=${CRX_PATH}`,
`--disable-extensions-except=${CRX_PATH}`,
'--enable-automation'
],
ignoreHTTPSErrors: true,
ignoreDefaultArgs: ['--disable-extensions']
});
} catch (e) {
console.error('Could not start Chromium');
return null;
}
};

const getExtensionId = async (world: DisMoiWorld) => {
try {
const targets = await world.browser?.targets();

if (!targets) return;

const extensionTarget = targets.find(target => {
return target.type() === 'background_page';
}) as puppeteer.Target;
const extensionTarget = targets.find(target => {
return target.type() === 'background_page';
}) as puppeteer.Target;

return extensionTarget.url().split('/')[2];
const p = (await extensionTarget.page()) as Page;

p.on('console', (consoleMessage: ConsoleMessage) => {
if (world.consoleMessages) {
world.consoleMessages.push(['background', consoleMessage.text()]);
}
});

const id = extensionTarget.url().split('/')[2];

console.log(`Extension ID: ${id}`);

return id;
} catch (e) {
console.error('Could not get extension ID', e, e.stack);
}
};

const waitForOnboarding = async (browser: Browser) => {
await browser.waitForTarget(target => target.url().includes('localhost'));
};

const closeEmptyTab = async (browser: Browser) => {
const targets = await browser.targets();
const blank = targets.find(target => target.url() === 'about:blank');
if (blank) {
await (await blank.page())?.close();
}
};

Before(async function(this: DisMoiWorld) {
this.browser = await puppeteer.launch({
headless: false,
args: [
'--no-sandbox',
'--disable-dev-shm-usage',
`--load-extension=${CRX_PATH}`,
`--disable-extensions-except=${CRX_PATH}`
],
ignoreHTTPSErrors: true
});
if (fs.existsSync(config.screenshotPath)) {
fs.rmdirSync(config.screenshotPath, { recursive: true });
}
fs.mkdirSync(config.screenshotPath, { recursive: true });

this.consoleMessages = [];

const browser = await startChromium();

expect(browser).toBeDefined();
this.browser = browser as Browser;

const extensionId = await getExtensionId(this);

await delay(3000);
expect(extensionId).toBeDefined();
this.browser = browser as Browser;

this.extensionId = await getExtensionId(this.browser);
await waitForOnboarding(browser as Browser);
await closeEmptyTab(browser as Browser);
});

After(async function(this: DisMoiWorld, scenario) {
Expand All @@ -74,7 +135,7 @@ After(async function(this: DisMoiWorld, scenario) {
) {
const screenShotName = scenario.pickle.name.replace(/[\W_]+/g, '-');
await this.page.screenshot({
path: `${config.screenshotPath}/error/${screenShotName}.png`
path: `${config.screenshotPath}/${screenShotName}.png`
});
}
});

0 comments on commit 704004f

Please sign in to comment.