Improve end-to-end test logging by rendering JSHandles (#7959)

Fixes https://github.com/vector-im/element-web/issues/13276

It's still not super pretty, but it works.
pull/21833/head
Travis Ralston 2022-03-03 07:59:29 -07:00 committed by GitHub
parent f9ad2a5151
commit 75abf03fed
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 53 additions and 3 deletions

View File

@ -19,7 +19,7 @@ import * as puppeteer from 'puppeteer';
import { Logger } from './logger';
import { LogBuffer } from './logbuffer';
import { delay } from './util';
import { delay, serializeLog } from './util';
const DEFAULT_TIMEOUT = 20000;
@ -35,7 +35,7 @@ export class ElementSession {
constructor(readonly browser: puppeteer.Browser, readonly page: puppeteer.Page, readonly username: string,
readonly elementServer: string, readonly hsUrl: string) {
this.consoleLog = new LogBuffer(page, "console",
async (msg: puppeteer.ConsoleMessage) => Promise.resolve(`${msg.text()}\n`));
async (msg: puppeteer.ConsoleMessage) => `${await serializeLog(msg)}\n`);
this.networkLog = new LogBuffer(page,
"requestfinished", async (req: puppeteer.HTTPRequest) => {
const type = req.resourceType();

View File

@ -15,6 +15,9 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import { ConsoleMessage } from "puppeteer";
import { padEnd } from "lodash";
import { ElementSession } from "./session";
export const range = function(start: number, amount: number, step = 1): Array<number> {
@ -51,3 +54,50 @@ export async function applyConfigChange(session: ElementSession, config: any): P
}
}, config);
}
export async function serializeLog(msg: ConsoleMessage): Promise<string> {
// 9 characters padding is somewhat arbitrary ("warning".length + some)
let s = `${padEnd(msg.type(), 9, ' ')}| ${msg.text()} `; // trailing space is intentional
const args = msg.args();
for (let i = 0; i < args.length; i++) {
const arg = args[i];
const val = await arg.jsonValue();
// We handle strings a bit differently because the `jsonValue` will be in a weird-looking
// shape ("JSHandle:words are here"). Weirdly, `msg.text()` also catches text nodes that
// we can't with our parsing, so we trust that it's correct whenever we can.
if (typeof val === 'string') {
if (i === 0) {
// if it's a string, just ignore it because it should have already been caught
// by the `msg.text()` in the initial `s` construction.
continue;
}
// evaluate the arg as a string by running it through the page context
s += `${await arg.evaluate(a => a.toString())} `; // trailing space is intentional
continue;
}
// Try and parse the value as an error object first (which will be an empty JSON
// object). Otherwise, parse the object to a string.
//
// Note: we have to run the checks against the object in the page context, so call
// evaluate instead of just doing it ourselves.
const stringyArg: string = await arg.evaluate((argInContext: any) => {
if (argInContext.stack || (argInContext instanceof Error)) {
// probably an error - toString it and append any properties which might not be
// caught. For example, on HTTP errors the JSON stringification will capture the
// status code.
//
// String format is a bit weird, but basically we're trying to get away from the
// stack trace so the context doesn't blend in but is otherwise indented correctly.
return `${argInContext.toString()}\n\n Error context: ${JSON.stringify(argInContext)}`;
}
// not an error, as far as we're concerned - return it as human-readable JSON
return JSON.stringify(argInContext, null, 4);
});
s += `${stringyArg} `; // trailing space is intentional
}
return s;
}

View File

@ -112,7 +112,7 @@ async function runTests() {
/**
* TODO: temporary only use one user session data
*/
performanceEntries = JSON.parse(measurements);
performanceEntries = JSON.parse(measurements ?? "[]");
return session.close();
}));
if (performanceEntries?.length > 0) {