44 * SPDX-License-Identifier: Apache-2.0
55 */
66
7+ import type * as CdpProtocol from '../node_modules/chrome-devtools-frontend/front_end/generated/protocol-proxy-api.js' ;
8+ import { IssuesManager , Issue } from '../node_modules/chrome-devtools-frontend/mcp/mcp.js' ;
9+
710import {
811 type Browser ,
912 type Frame ,
1013 type Handler ,
1114 type HTTPRequest ,
1215 type Page ,
13- type PageEvents ,
16+ type PageEvents as PuppeteerPageEvents ,
1417} from './third_party/index.js' ;
1518
19+ interface PageEvents extends PuppeteerPageEvents {
20+ issue : Issue . Issue ;
21+ }
22+
1623export type ListenerMap < EventMap extends PageEvents = PageEvents > = {
1724 [ K in keyof EventMap ] ?: ( event : EventMap [ K ] ) => void ;
1825} ;
@@ -58,15 +65,15 @@ export class PageCollector<T> {
5865 async init ( ) {
5966 const pages = await this . #browser. pages ( ) ;
6067 for ( const page of pages ) {
61- this . #initializePage ( page ) ;
68+ await this . addPage ( page ) ;
6269 }
6370
6471 this . #browser. on ( 'targetcreated' , async target => {
6572 const page = await target . page ( ) ;
6673 if ( ! page ) {
6774 return ;
6875 }
69- this . #initializePage ( page ) ;
76+ await this . addPage ( page ) ;
7077 } ) ;
7178 this . #browser. on ( 'targetdestroyed' , async target => {
7279 const page = await target . page ( ) ;
@@ -77,15 +84,15 @@ export class PageCollector<T> {
7784 } ) ;
7885 }
7986
80- public addPage ( page : Page ) {
81- this . #initializePage( page ) ;
82- }
83-
84- #initializePage( page : Page ) {
87+ public async addPage ( page : Page ) {
8588 if ( this . storage . has ( page ) ) {
8689 return ;
8790 }
91+ await this . #initializePage( page ) ;
92+ }
8893
94+ async #initializePage( page : Page ) {
95+ await this . subscribeForIssues ( page ) ;
8996 const idGenerator = createIdGenerator ( ) ;
9097 const storedLists : Array < Array < WithSymbolId < T > > > = [ [ ] ] ;
9198 this . storage . set ( page , storedLists ) ;
@@ -113,6 +120,19 @@ export class PageCollector<T> {
113120 this . #listeners. set ( page , listeners ) ;
114121 }
115122
123+ protected async subscribeForIssues ( page : Page ) {
124+ const session = await page . createCDPSession ( ) ;
125+ session . on ( 'Audits.issueAdded' , ( data ) => { // TODO unsubscribe
126+ // @ts -expect-error Types of protocol from Puppeteer and CDP are incopatible for Issues
127+ const issue = IssuesManager . createIssuesFromProtocolIssue ( null , data . issue ) [ 0 ] ; // returns issue wrapped in array, need to get first element
128+ if ( ! issue ) {
129+ return ;
130+ }
131+ page . emit ( 'issue' , issue ) ;
132+ } ) ;
133+ await session . send ( 'Audits.enable' ) ;
134+ }
135+
116136 protected splitAfterNavigation ( page : Page ) {
117137 const navigations = this . storage . get ( page ) ;
118138 if ( ! navigations ) {
0 commit comments