@@ -200,6 +200,14 @@ const cookiesCallbacks = new Map<string, CookiesCallback>();
200
200
const localStorageCallbacks = new Map < string, LocalStorageCallback > ( ) ;
201
201
const sessionStorageCallbacks = new Map < string, SessionStorageCallback > ( ) ;
202
202
203
+ // Add new state for tracking selector requests
204
+ interface SelectorCallback {
205
+ resolve : ( value : string [ ] ) => void ;
206
+ reject : ( reason : Error ) = > void ;
207
+ }
208
+
209
+ const selectorCallbacks = new Map < string , SelectorCallback > ( ) ;
210
+
203
211
// Function to get available port starting with the given port
204
212
async function getAvailablePort (
205
213
startPort : number ,
@@ -651,6 +659,18 @@ export class BrowserConnector {
651
659
}
652
660
) ;
653
661
662
+ // Register the inspect-elements-by-selector endpoint
663
+ this . app . post (
664
+ "/inspect-elements-by-selector" ,
665
+ async ( req : express . Request , res : express . Response ) => {
666
+ console . log (
667
+ "Browser Connector: Received request to /inspect-elements-by-selector endpoint"
668
+ ) ;
669
+ console . log ( "Browser Connector: Request body:" , req . body ) ;
670
+ await this . inspectElementsBySelector ( req , res ) ;
671
+ }
672
+ ) ;
673
+
654
674
// Set up accessibility audit endpoint
655
675
this . setupAccessibilityAudit ( ) ;
656
676
@@ -887,7 +907,28 @@ export class BrowserConnector {
887
907
} else {
888
908
console . log ( "No callbacks found for sessionStorage" ) ;
889
909
}
890
- } else {
910
+ }
911
+ // Handle selector response
912
+ if ( data . type === "html-by-selector" && data . requestId ) {
913
+ console . log ( "Received HTML by selector response" ) ;
914
+ const callback = selectorCallbacks . get ( data . requestId ) ;
915
+ if ( callback ) {
916
+ callback . resolve ( data . html || [ ] ) ;
917
+ selectorCallbacks . delete ( data . requestId ) ;
918
+ } else {
919
+ console . log ( "No callback found for selector request:" , data . requestId ) ;
920
+ }
921
+ }
922
+ // Handle selector error
923
+ else if ( data . type === "selector-error" && data . requestId ) {
924
+ console . log ( "Received selector error:" , data . error ) ;
925
+ const callback = selectorCallbacks . get ( data . requestId ) ;
926
+ if ( callback ) {
927
+ callback . reject ( new Error ( data . error || "Failed to get HTML by selector" ) ) ;
928
+ selectorCallbacks . delete ( data . requestId ) ;
929
+ }
930
+ }
931
+ else {
891
932
console . log ( "Unhandled message type:" , data . type ) ;
892
933
}
893
934
} catch ( error ) {
@@ -1548,6 +1589,113 @@ export class BrowserConnector {
1548
1589
});
1549
1590
}
1550
1591
1592
+ // Add method to handle elements with styles requests
1593
+ private async inspectElementsBySelector(req: express.Request, res: express.Response) {
1594
+ if (!this.activeConnection) {
1595
+ return res.status(503).json({ error: "Chrome extension not connected" });
1596
+ }
1597
+
1598
+ const { selector, resultLimit = 1, includeComputedStyles = [] } = req.body;
1599
+ if (!selector) {
1600
+ return res.status(400).json({ error: "No selector provided" });
1601
+ }
1602
+
1603
+ try {
1604
+ const requestId = Date.now().toString();
1605
+ console.log("Browser Connector: Generated requestId for elements with styles request:", requestId);
1606
+
1607
+ // Create promise that will resolve when we get the elements and styles data
1608
+ const elementsBySelectorPromise = new Promise<any>((resolve, reject) => {
1609
+ console.log(
1610
+ ` Browser Connector : Setting up elements with styles callback for requestId : ${requestId } `
1611
+ );
1612
+
1613
+ // Store callback in a map
1614
+ const elementsBySelectorCallbacks = new Map<string, {
1615
+ resolve: (value: any) => void;
1616
+ reject: (reason: Error) => void;
1617
+ }>();
1618
+
1619
+ // Store callback in map
1620
+ elementsBySelectorCallbacks.set(requestId, { resolve, reject });
1621
+
1622
+ // Add a message listener for inspect-elements-by-selector response
1623
+ const messageHandler = (event: WebSocket.MessageEvent) => {
1624
+ try {
1625
+ const response = JSON.parse(event.data as string);
1626
+
1627
+ if (response.type === "inspect-elements-response" && response.requestId === requestId) {
1628
+ console.log("Browser Connector: Received inspect-elements-by-selector response");
1629
+ const callback = elementsBySelectorCallbacks.get(requestId);
1630
+ if (callback) {
1631
+ callback.resolve(response.data);
1632
+ elementsBySelectorCallbacks.delete(requestId);
1633
+ this.activeConnection?.removeEventListener("message", messageHandler);
1634
+ }
1635
+ }
1636
+ else if (response.type === "inspect-elements-error" && response.requestId === requestId) {
1637
+ console.error("Browser Connector: inspect-elements-by-selector error:", response.error);
1638
+ const callback = elementsBySelectorCallbacks.get(requestId);
1639
+ if (callback) {
1640
+ callback.reject(new Error(response.error || "Failed to get inspect-elements-by-selector"));
1641
+ elementsBySelectorCallbacks.delete(requestId);
1642
+ this.activeConnection?.removeEventListener("message", messageHandler);
1643
+ }
1644
+ }
1645
+ } catch (error) {
1646
+ console.error("Error processing inspect-elements-by-selector response:", error);
1647
+ }
1648
+ };
1649
+
1650
+ // Add the message listener
1651
+ this.activeConnection?.addEventListener("message", messageHandler);
1652
+
1653
+ // Set timeout to clean up if we don't get a response
1654
+ setTimeout(() => {
1655
+ if (elementsBySelectorCallbacks.has(requestId)) {
1656
+ console.log(
1657
+ ` Browser Connector : inspect - elements - by - selector request timed out for requestId : ${requestId } `
1658
+ );
1659
+ elementsBySelectorCallbacks.delete(requestId);
1660
+ this.activeConnection?.removeEventListener("message", messageHandler);
1661
+ reject(new Error("inspect-elements-by-selector request timed out - no response from Chrome extension"));
1662
+ }
1663
+ }, 10000); // 10 second timeout
1664
+ });
1665
+
1666
+ // Send request to extension
1667
+ const message = JSON.stringify({
1668
+ type: "inspect-elements-by-selector",
1669
+ selector,
1670
+ resultLimit,
1671
+ includeComputedStyles,
1672
+ requestId,
1673
+ });
1674
+ console.log(
1675
+ ` Browser Connector : Sending WebSocket message to extension :`,
1676
+ message
1677
+ );
1678
+ this.activeConnection.send(message);
1679
+
1680
+ // Wait for inspect-elements-by-selector data
1681
+ console.log("Browser Connector: Waiting for inspect-elements-by-selector response...");
1682
+ const elementsBySelector = await elementsBySelectorPromise;
1683
+ console.log(` Browser Connector : Received inspect - elements - by - selector data with ${elementsBySelector . elements . length } elements `);
1684
+
1685
+ res.json({ data: elementsBySelector });
1686
+ } catch (error: unknown) {
1687
+ const errorMessage = error instanceof Error ? error.message : String(error);
1688
+ console.error("Browser Connector: Error inspecting elements by selector:", errorMessage);
1689
+ if (errorMessage.includes("Invalid selector")) {
1690
+ return res.status(400).json({ error: errorMessage });
1691
+ } else if (errorMessage.includes("timed out")) {
1692
+ return res.status(504).json({ error: errorMessage });
1693
+ } else {
1694
+ return res.status(500).json({ error: errorMessage });
1695
+ }
1696
+ }
1697
+ }
1698
+
1551
1699
// Add method to get cookies
1552
1700
async getCookies(req: express.Request, res: express.Response) {
1553
1701
if (!this.activeConnection) {
0 commit comments