Repository: elastic/synthetics (ts)

Issue:
listen to console events on browser context instead of page
+ We are not capturing some of the console logs from other pages/windows when the journey involves multiple pages. This can be fixed in our browser console plugin by listening to console events on the browser context, instead of the page. 

We need Playwright's next release which has the feature - https://github.com/microsoft/playwright/pull/22805

Pull request description:
feat: listen to console events in browser context
+ fix #721 
+ Playwright added this capability recently, where we can listen to all the browser console events for all pages that are created via the created browser context. We make use of that and create all the events that are of type `warning, error` and report them for failed tests. 

Check this commit for review - https://github.com/elastic/synthetics/pull/784/commits/33a9320a0358f54f76ee29a5602655a037262821


Patch:
diff --git a/src/plugins/browser-console.ts b/src/plugins/browser-console.ts
index bad449b..5f25e25 100644
--- a/src/plugins/browser-console.ts
+++ b/src/plugins/browser-console.ts
@@ -23,6 +23,7 @@
  *
  */
 
+import type { ConsoleMessage } from 'playwright-core';
 import { BrowserMessage, Driver } from '../common_types';
 import { log } from '../core/logger';
 import { Step } from '../dsl';
@@ -36,7 +37,7 @@ export class BrowserConsole {
 
   constructor(private driver: Driver) {}
 
-  private consoleEventListener = msg => {
+  private consoleEventListener = (msg: ConsoleMessage) => {
     if (!this._currentStep) {
       return;
     }
@@ -78,12 +79,12 @@ export class BrowserConsole {
 
   start() {
     log(`Plugins: started collecting console events`);
-    this.driver.page.on('console', this.consoleEventListener);
+    this.driver.context.on('console', this.consoleEventListener);
     this.driver.page.on('pageerror', this.pageErrorEventListener);
   }
 
   stop() {
-    this.driver.page.off('console', this.consoleEventListener);
+    this.driver.context.off('console', this.consoleEventListener);
     this.driver.page.off('pageerror', this.pageErrorEventListener);
     log(`Plugins: stopped collecting console events`);
     return this.messages;


Test patch:
diff --git a/__tests__/plugins/browser-console.test.ts b/__tests__/plugins/browser-console.test.ts
index 25d0046..607f8cf 100644
--- a/__tests__/plugins/browser-console.test.ts
+++ b/__tests__/plugins/browser-console.test.ts
@@ -41,20 +41,34 @@ describe('BrowserConsole', () => {
   it('should capture browser console logs', async () => {
     const driver = await Gatherer.setupDriver({ wsEndpoint });
     const browserConsole = new BrowserConsole(driver);
-    const { page } = driver;
     browserConsole.start();
-    await page.goto(server.TEST_PAGE);
     browserConsole._currentStep = currentStep;
-    await page.evaluate(() =>
-      console.warn('test-message', 1, { test: 'test' })
-    );
+    await driver.page.evaluate(() => {
+      console.warn('console.warn');
+      console.error('console.error');
+      console.info('console.info');
+    });
+    await Promise.all([
+      driver.page.evaluate(async () => {
+        const win = window.open();
+        (win as any).console.error('console.error popup');
+        (win as any).close();
+      }),
+      driver.page.context().waitForEvent('console'),
+      driver.page.waitForEvent('popup'),
+    ]);
+
     const messages = browserConsole.stop();
     await Gatherer.stop();
-    const testMessage = messages.find(m => m.text.indexOf('test-message') >= 0);
-    expect(testMessage?.text).toEqual(`test-message 1 {test: test}`);
-    expect(testMessage?.type).toEqual('warning');
-    expect(testMessage?.timestamp).toBeDefined();
-    expect(testMessage?.step).toEqual(currentStep);
+    const warnMessage = messages[0];
+    expect(warnMessage?.text).toEqual('console.warn');
+    expect(warnMessage?.type).toEqual('warning');
+    expect(warnMessage?.timestamp).toBeDefined();
+    expect(warnMessage?.step).toEqual(currentStep);
+    expect(messages.slice(1).map(m => m.text)).toEqual([
+      'console.error',
+      'console.error popup',
+    ]);
   });
 
   it('should capture browser page errors', async () => {