mirror of
				https://github.com/zulip/zulip.git
				synced 2025-11-04 14:03:30 +00:00 
			
		
		
		
	puppeteer_tests: Translate logged traces and errors with source maps.
Signed-off-by: Anders Kaseorg <anders@zulip.com>
This commit is contained in:
		
				
					committed by
					
						
						Tim Abbott
					
				
			
			
				
	
			
			
			
						parent
						
							da9783fd10
						
					
				
				
					commit
					e62b0d6b5f
				
			@@ -2,8 +2,12 @@ import {strict as assert} from "assert";
 | 
			
		||||
import "css.escape";
 | 
			
		||||
import path from "path";
 | 
			
		||||
 | 
			
		||||
import ErrorStackParser from "error-stack-parser";
 | 
			
		||||
import fetch from "node-fetch";
 | 
			
		||||
import type {Browser, ConsoleMessage, ConsoleMessageLocation, ElementHandle, Page} from "puppeteer";
 | 
			
		||||
import {launch} from "puppeteer";
 | 
			
		||||
import StackFrame from "stackframe";
 | 
			
		||||
import StackTraceGPS from "stacktrace-gps";
 | 
			
		||||
 | 
			
		||||
import {test_credentials} from "../../var/puppeteer/test_credentials";
 | 
			
		||||
 | 
			
		||||
@@ -17,6 +21,8 @@ class CommonUtils {
 | 
			
		||||
    screenshot_id = 0;
 | 
			
		||||
    is_firefox = process.env.PUPPETEER_PRODUCT === "firefox";
 | 
			
		||||
    realm_url = "http://zulip.zulipdev.com:9981/";
 | 
			
		||||
    gps = new StackTraceGPS({ajax: async (url) => (await fetch(url)).text()});
 | 
			
		||||
 | 
			
		||||
    pm_recipient = {
 | 
			
		||||
        async set(page: Page, recipient: string): Promise<void> {
 | 
			
		||||
            // Without using the delay option here there seems to be
 | 
			
		||||
@@ -493,51 +499,102 @@ class CommonUtils {
 | 
			
		||||
        const browser = await this.ensure_browser();
 | 
			
		||||
        const page = await this.get_page();
 | 
			
		||||
 | 
			
		||||
        // Used to keep console messages in order after async source mapping
 | 
			
		||||
        let console_ready = Promise.resolve();
 | 
			
		||||
 | 
			
		||||
        page.on("console", (message: ConsoleMessage) => {
 | 
			
		||||
            function context({url, lineNumber, columnNumber}: ConsoleMessageLocation): string {
 | 
			
		||||
            const context = async ({
 | 
			
		||||
                url,
 | 
			
		||||
                lineNumber,
 | 
			
		||||
                columnNumber,
 | 
			
		||||
            }: ConsoleMessageLocation): Promise<string> => {
 | 
			
		||||
                if (lineNumber === undefined || columnNumber === undefined) {
 | 
			
		||||
                    return `${url}`;
 | 
			
		||||
                }
 | 
			
		||||
                return `${url}:${lineNumber + 1}:${columnNumber + 1}`;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            console.log(`${context(message.location())}: ${message.type()}: ${message.text()}`);
 | 
			
		||||
            if (message.type() === "trace") {
 | 
			
		||||
                for (const frame of message.stackTrace()) {
 | 
			
		||||
                    console.log(`    at ${context(frame)}`);
 | 
			
		||||
                let frame = new StackFrame({
 | 
			
		||||
                    fileName: url,
 | 
			
		||||
                    lineNumber: lineNumber + 1,
 | 
			
		||||
                    columnNumber: columnNumber + 1,
 | 
			
		||||
                });
 | 
			
		||||
                try {
 | 
			
		||||
                    frame = await this.gps.getMappedLocation(frame);
 | 
			
		||||
                } catch {
 | 
			
		||||
                    // Ignore source mapping errors
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
                return `${frame.fileName}:${frame.lineNumber}:${frame.columnNumber}`;
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            const console_ready1 = console_ready;
 | 
			
		||||
            console_ready = (async () => {
 | 
			
		||||
                let output = `${await context(
 | 
			
		||||
                    message.location(),
 | 
			
		||||
                )}: ${message.type()}: ${message.text()}`;
 | 
			
		||||
                if (message.type() === "trace") {
 | 
			
		||||
                    for (const frame of message.stackTrace()) {
 | 
			
		||||
                        output += `\n    at ${await context(frame)}`;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                await console_ready1;
 | 
			
		||||
                console.log(output);
 | 
			
		||||
            })();
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        let page_errored = false;
 | 
			
		||||
        page.on("pageerror", async (error: Error) => {
 | 
			
		||||
            console.error("Page error:", error);
 | 
			
		||||
        page.on("pageerror", (error: Error) => {
 | 
			
		||||
            page_errored = true;
 | 
			
		||||
 | 
			
		||||
            try {
 | 
			
		||||
                // Take a screenshot, and increment the screenshot_id.
 | 
			
		||||
                await this.screenshot(page, `failure-${this.screenshot_id}`);
 | 
			
		||||
                this.screenshot_id += 1;
 | 
			
		||||
            } finally {
 | 
			
		||||
                console.log("Closing page to stop the test...");
 | 
			
		||||
                await page.close();
 | 
			
		||||
            }
 | 
			
		||||
            // Puppeteer gives us the stack as the message for some reason.
 | 
			
		||||
            const error1 = new Error("dummy");
 | 
			
		||||
            error1.stack = error.message;
 | 
			
		||||
 | 
			
		||||
            const console_ready1 = console_ready;
 | 
			
		||||
            console_ready = (async () => {
 | 
			
		||||
                const frames = await Promise.all(
 | 
			
		||||
                    ErrorStackParser.parse(error1).map(async (frame1) => {
 | 
			
		||||
                        let frame = (frame1 as unknown) as StackFrame;
 | 
			
		||||
                        try {
 | 
			
		||||
                            frame = await this.gps.getMappedLocation(frame);
 | 
			
		||||
                        } catch {
 | 
			
		||||
                            // Ignore source mapping errors
 | 
			
		||||
                        }
 | 
			
		||||
                        return `\n    at ${frame.functionName} (${frame.fileName}:${frame.lineNumber}:${frame.columnNumber})`;
 | 
			
		||||
                    }),
 | 
			
		||||
                );
 | 
			
		||||
                await console_ready1;
 | 
			
		||||
                console.error("Page error:", error.message.split("\n", 1)[0] + frames.join(""));
 | 
			
		||||
            })();
 | 
			
		||||
 | 
			
		||||
            const console_ready2 = console_ready;
 | 
			
		||||
            console_ready = (async () => {
 | 
			
		||||
                try {
 | 
			
		||||
                    // Take a screenshot, and increment the screenshot_id.
 | 
			
		||||
                    await this.screenshot(page, `failure-${this.screenshot_id}`);
 | 
			
		||||
                    this.screenshot_id += 1;
 | 
			
		||||
                } finally {
 | 
			
		||||
                    await console_ready2;
 | 
			
		||||
                    console.log("Closing page to stop the test...");
 | 
			
		||||
                    await page.close();
 | 
			
		||||
                }
 | 
			
		||||
            })();
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            await test_function(page);
 | 
			
		||||
        } catch (error: unknown) {
 | 
			
		||||
            console.log(error);
 | 
			
		||||
 | 
			
		||||
            if (page_errored) {
 | 
			
		||||
                throw new Error("Page threw an error");
 | 
			
		||||
            }
 | 
			
		||||
        } catch (error: unknown) {
 | 
			
		||||
            if (!page_errored) {
 | 
			
		||||
                // Take a screenshot, and increment the screenshot_id.
 | 
			
		||||
                await this.screenshot(page, `failure-${this.screenshot_id}`);
 | 
			
		||||
                this.screenshot_id += 1;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            await browser.close();
 | 
			
		||||
            process.exit(1);
 | 
			
		||||
            throw error;
 | 
			
		||||
        } finally {
 | 
			
		||||
            await console_ready;
 | 
			
		||||
            await browser.close();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -84,6 +84,7 @@
 | 
			
		||||
    "@types/jquery": "^3.3.31",
 | 
			
		||||
    "@types/mini-css-extract-plugin": "^1.0.0",
 | 
			
		||||
    "@types/node": "^14.0.11",
 | 
			
		||||
    "@types/node-fetch": "^2.5.8",
 | 
			
		||||
    "@types/optimize-css-assets-webpack-plugin": "^5.0.1",
 | 
			
		||||
    "@types/terser-webpack-plugin": "^4.1.0",
 | 
			
		||||
    "@types/webpack": "^4.4.32",
 | 
			
		||||
@@ -99,6 +100,7 @@
 | 
			
		||||
    "js-yaml": "^4.0.0",
 | 
			
		||||
    "jsdom": "^16.1.0",
 | 
			
		||||
    "mockdate": "^3.0.2",
 | 
			
		||||
    "node-fetch": "^2.6.1",
 | 
			
		||||
    "nyc": "^15.0.0",
 | 
			
		||||
    "openapi-examples-validator": "^4.0.0",
 | 
			
		||||
    "prettier": "^2.0.5",
 | 
			
		||||
 
 | 
			
		||||
@@ -45,4 +45,4 @@ API_FEATURE_LEVEL = 44
 | 
			
		||||
#   historical commits sharing the same major version, in which case a
 | 
			
		||||
#   minor version bump suffices.
 | 
			
		||||
 | 
			
		||||
PROVISION_VERSION = "134.0"
 | 
			
		||||
PROVISION_VERSION = "134.1"
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										19
									
								
								yarn.lock
									
									
									
									
									
								
							
							
						
						
									
										19
									
								
								yarn.lock
									
									
									
									
									
								
							@@ -1264,6 +1264,14 @@
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.1.tgz#283f669ff76d7b8260df8ab7a4262cc83d988256"
 | 
			
		||||
  integrity sha512-fZQQafSREFyuZcdWFAExYjBiCL7AUCdgsk80iO0q4yihYYdcIiH28CcuPTGFgLOCC8RlW49GSQxdHwZP+I7CNg==
 | 
			
		||||
 | 
			
		||||
"@types/node-fetch@^2.5.8":
 | 
			
		||||
  version "2.5.8"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.5.8.tgz#e199c835d234c7eb0846f6618012e558544ee2fb"
 | 
			
		||||
  integrity sha512-fbjI6ja0N5ZA8TV53RUqzsKNkl9fv8Oj3T7zxW7FGv1GSH7gwJaNF8dzCjrqKaxKeUpTz4yT1DaJFq/omNpGfw==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    "@types/node" "*"
 | 
			
		||||
    form-data "^3.0.0"
 | 
			
		||||
 | 
			
		||||
"@types/node@*", "@types/node@^14.0.11":
 | 
			
		||||
  version "14.14.31"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.31.tgz#72286bd33d137aa0d152d47ec7c1762563d34055"
 | 
			
		||||
@@ -3229,7 +3237,7 @@ colormap@^2.3.1:
 | 
			
		||||
  dependencies:
 | 
			
		||||
    lerp "^1.0.3"
 | 
			
		||||
 | 
			
		||||
combined-stream@^1.0.6, combined-stream@~1.0.6:
 | 
			
		||||
combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.6:
 | 
			
		||||
  version "1.0.8"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
 | 
			
		||||
  integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==
 | 
			
		||||
@@ -5347,6 +5355,15 @@ form-data@^2.3.2:
 | 
			
		||||
    combined-stream "^1.0.6"
 | 
			
		||||
    mime-types "^2.1.12"
 | 
			
		||||
 | 
			
		||||
form-data@^3.0.0:
 | 
			
		||||
  version "3.0.1"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.1.tgz#ebd53791b78356a99af9a300d4282c4d5eb9755f"
 | 
			
		||||
  integrity sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    asynckit "^0.4.0"
 | 
			
		||||
    combined-stream "^1.0.8"
 | 
			
		||||
    mime-types "^2.1.12"
 | 
			
		||||
 | 
			
		||||
form-data@~2.3.2:
 | 
			
		||||
  version "2.3.3"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6"
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user