Skip to content

Commit

Permalink
feat(testing): add getDiagnostics() and failOnConsole option
Browse files Browse the repository at this point in the history
  • Loading branch information
manucorporat committed Aug 30, 2019
1 parent ae74a27 commit 645b5f9
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 54 deletions.
2 changes: 1 addition & 1 deletion src/testing/jest/jest-serializer.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

import { MockNode, serializeNodeToHtml } from '@mock-doc';

const print = (val: HTMLElement | MockNode): string => {
const print = (val: HTMLElement | MockNode): string => {
return serializeNodeToHtml(val, {
serializeShadowRoot: true,
prettyHtml: true,
Expand Down
24 changes: 12 additions & 12 deletions src/testing/puppeteer/puppeteer-declarations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import * as puppeteer from 'puppeteer';
export interface NewE2EPageOptions extends puppeteer.NavigationOptions {
url?: string;
html?: string;
failOnConsoleError?: boolean;
failOnNetworkError?: boolean;
}


Expand All @@ -13,6 +15,11 @@ type PuppeteerPage = Omit<puppeteer.Page,
'bringToFront' | 'browser' | 'screenshot' | 'emulate' | 'emulateMedia' | 'frames' | 'goBack' | 'goForward' | 'isClosed' | 'mainFrame' | 'pdf' | 'reload' | 'target' | 'title' | 'viewport' | 'waitForNavigation' | 'screenshot' | 'workers' | 'addListener' | 'prependListener' | 'prependOnceListener' | 'removeListener' | 'removeAllListeners' | 'setMaxListeners' | 'getMaxListeners' | 'listeners' | 'rawListeners' | 'emit' | 'eventNames' | 'listenerCount' | '$x' | 'waitForXPath'
>;

export interface PageDiagnostic {
type: 'error' | 'pageerror' | 'requestfailed';
message?: string;
location?: string;
}

/**
* The E2EPage is a wrapper utility to Puppeteer in order to
Expand Down Expand Up @@ -118,13 +125,15 @@ export interface E2EPage extends PuppeteerPage {
* allows the listener to be set to `document` if needed.
*/
waitForEvent(eventName: string): Promise<any>;

getDiagnostics(): PageDiagnostic[];
}


export interface E2EPageInternal extends E2EPage {
isClosed(): boolean;
_e2eElements: E2EElementInternal[];
_e2eEvents: WaitForEvent[];
_e2eEvents: Map<number, WaitForEvent>;
_e2eEventIds: number;
_e2eGoto(url: string, options?: Partial<puppeteer.NavigationOptions>): Promise<puppeteer.Response | null>;
_e2eClose(options?: puppeteer.PageCloseOptions): Promise<void>;
Expand Down Expand Up @@ -425,21 +434,12 @@ export interface WaitForEventOptions {


export interface WaitForEvent {
id: number;
eventName: string;
resolve: (ev: any) => void;
cancelRejectId: any;
}


export interface BrowserContextEvent {
id: number;
event: any;
callback: (ev: any) => void;
}


export interface BrowserWindow extends Window {
stencilOnEvent(ev: BrowserContextEvent): void;
stencilOnEvent(id: number, event: any): void;
stencilSerializeEvent(ev: CustomEvent): any;
stencilSerializeEventTarget(target: any): any;
stencilAppLoaded: boolean;
Expand Down
43 changes: 16 additions & 27 deletions src/testing/puppeteer/puppeteer-events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,16 @@ import * as puppeteer from 'puppeteer';


export async function initPageEvents(page: pd.E2EPageInternal) {
page._e2eEvents = [];
page._e2eEvents = new Map();
page._e2eEventIds = 0;
page.spyOnEvent = pageSpyOnEvent.bind(page, page);

await page.exposeFunction('stencilOnEvent', (browserEvent: pd.BrowserContextEvent) => {
await page.exposeFunction('stencilOnEvent', (id: number, ev: any) => {
// NODE CONTEXT
nodeContextEvents(page._e2eEvents, browserEvent);
nodeContextEvents(page._e2eEvents, id, ev);
});

await page.evaluateOnNewDocument(browserContextEvents);

page.spyOnEvent = pageSpyOnEvent.bind(page, page);
}


Expand All @@ -27,7 +26,7 @@ async function pageSpyOnEvent(page: pd.E2EPageInternal, eventName: string, selec

const handle = await page.evaluateHandle(handler);

await addE2EListener(page, handle, eventName, (ev: any) => {
await addE2EListener(page, handle, eventName, (ev) => {
eventSpy.push(ev);
});

Expand Down Expand Up @@ -107,43 +106,33 @@ export class EventSpy implements d.EventSpy {
}


export async function addE2EListener(page: pd.E2EPageInternal, elmHandle: puppeteer.JSHandle, eventName: string, resolve: (ev: any) => void, cancelRejectId?: any) {
export async function addE2EListener(page: pd.E2EPageInternal, elmHandle: puppeteer.JSHandle, eventName: string, callback: (ev: any) => void) {
// NODE CONTEXT
const id = page._e2eEventIds++;

page._e2eEvents.push({
id: id,
eventName: eventName,
resolve: resolve,
cancelRejectId: cancelRejectId
page._e2eEvents.set(id, {
eventName,
callback,
});

const executionContext = elmHandle.executionContext();

// add element event listener
await executionContext.evaluate((elm: any, id: number, eventName: string) => {
elm.addEventListener(eventName, (ev: any) => {
(window as unknown as pd.BrowserWindow).stencilOnEvent({
id: id,
event: (window as unknown as pd.BrowserWindow).stencilSerializeEvent(ev)
});
(window as unknown as pd.BrowserWindow).stencilOnEvent(
id,
(window as unknown as pd.BrowserWindow).stencilSerializeEvent(ev)
);
});
}, elmHandle, id, eventName);
}


function nodeContextEvents(waitForEvents: pd.WaitForEvent[], browserEvent: pd.BrowserContextEvent) {
function nodeContextEvents(waitForEvents: Map<number, pd.WaitForEvent>, eventId: number, ev: any) {
// NODE CONTEXT
const waitForEventData = waitForEvents.find(waitData => {
return waitData.id === browserEvent.id;
});

const waitForEventData = waitForEvents.get(eventId);
if (waitForEventData) {
if (waitForEventData.cancelRejectId != null) {
clearTimeout(waitForEventData.cancelRejectId);
}

waitForEventData.resolve(browserEvent.event);
waitForEventData.callback(ev);
}
}

Expand Down
63 changes: 49 additions & 14 deletions src/testing/puppeteer/puppeteer-page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export async function newE2EPage(opts: pd.NewE2EPageOptions = {}): Promise<pd.E2
}

const page: pd.E2EPageInternal = await global.__NEW_TEST_PAGE__();

const diagnostics: pd.PageDiagnostic[] = [];
try {
page._e2eElements = [];

Expand Down Expand Up @@ -86,6 +86,10 @@ export async function newE2EPage(opts: pd.NewE2EPageOptions = {}): Promise<pd.E2
return waitForEvent(page, eventName, docHandle);
};

page.getDiagnostics = () => {
return diagnostics;
};

page.waitForChanges = waitForChanges.bind(null, page);

page.debugger = () => {
Expand All @@ -101,9 +105,43 @@ export async function newE2EPage(opts: pd.NewE2EPageOptions = {}): Promise<pd.E2
}) as any;
};

page.on('console', consoleMessage);
page.on('pageerror', pageError);
page.on('requestfailed', requestFailed);
const failOnConsoleError = opts.failOnConsoleError === true;
const failOnNetworkError = opts.failOnNetworkError === true;

page.on('console', (ev) => {
if (ev.type() === 'error') {
diagnostics.push({
type: 'error',
message: ev.text(),
location: ev.location().url
});
if (failOnConsoleError) {
fail(new Error(serializeConsoleMessage(ev)));
return;
}
}
consoleMessage(ev);
});
page.on('pageerror', (err: Error) => {
diagnostics.push({
type: 'pageerror',
message: err.message,
location: err.stack
});
fail(err);
});
page.on('requestfailed', (req) => {
diagnostics.push({
type: 'requestfailed',
message: req.failure().errorText,
location: req.url()
});
if (failOnNetworkError) {
fail(new Error(req.failure().errorText));
} else {
console.error('requestfailed', req.url());
}
});

if (typeof opts.html === 'string') {
await e2eSetContent(page, opts.html, { waitUntil: opts.waitUntil });
Expand Down Expand Up @@ -304,13 +342,18 @@ async function waitForChanges(page: pd.E2EPageInternal) {
function consoleMessage(c: puppeteer.ConsoleMessage) {
const type = c.type();
const normalizedType = type === 'warning' ? 'warn' : type;
const message = serializeConsoleMessage(c);
if (typeof (console as any)[normalizedType] === 'function') {
(console as any)[normalizedType](c.text(), serializeLocation(c.location()));
(console as any)[normalizedType](message);
} else {
console.log(type, c.text(), serializeLocation(c.location()));
console.log(type, message);
}
}

function serializeConsoleMessage(c: puppeteer.ConsoleMessage) {
return `${c.text()} ${serializeLocation(c.location())}`
}

function serializeLocation(loc: puppeteer.ConsoleMessageLocation) {
let locStr = '';
if (loc && loc.url) {
Expand All @@ -326,11 +369,3 @@ function serializeLocation(loc: puppeteer.ConsoleMessageLocation) {
}


function pageError(e: any) {
console.error('pageerror', e);
}


function requestFailed(req: puppeteer.Request) {
console.error('requestfailed', req.url());
}

0 comments on commit 645b5f9

Please sign in to comment.