selenium server | Cell 1 | Cell 3 | Search

This code creates a REST API using Express for navigating and interacting with web pages in a Chrome browser instance, utilizing the Chrome Debugging Protocol. It provides functions for waiting for page loads and navigating to specific URLs, as well as API endpoints for retrieving and setting the current URL of the active tab.

Cell 2

var importer = require('../Core');
var express = require('express');
var router = express.Router();

function waitForComplete() {
    return promisifyChrome('debugger.sendCommand', {
        tabId: getTab()
    }, 'Runtime.evaluate', {
        expression: `new window.BackupPromise(resolve => {
resolve(document.readyState === "complete" || document.readyState === "interactive");
})`,
        awaitPromise: true
    })
    .then(b => b ? ({value: {}}) : waitForComplete())
}

function go(url) {
    return promisifyChrome('windows.getAll', {})
        .then(windows => importer.runAllPromises(windows
            .map(w => resolve =>
                promisifyChrome('tabs.getAllInWindow', w.id)
                    .then(tabs => resolve(tabs)))))
        .then(tabs => {
            for (const t of [].concat(...tabs)) {
                if (t.url.indexOf(url) > -1 || t.id === getTab()) {
                    return promisifyChrome(
                        'tabs.update', t.id, {active: true});
                }
            }
            return promisifyChrome('tabs.create', {
                active: true,
                url
            });
        })
        .then(t => {
            if(t.id !== getTab()) {
                setTab(t.id)
                return promisifyChrome('debugger.attach', {
                    tabId: getTab()
                }, '1.1')
            }
        })
        .then(() => promisifyChrome('debugger.sendCommand', {
            tabId: getTab()
        }, 'Page.navigate', {
            url: url
        }))
        .then(() => waitForComplete())
        .catch(e => console.log(e))
}
router.get('/session/:sessionId/url', (req, res) => {
    response(res, promisifyChrome('tabs.get', {
        tabId: getTab()
    }).then(r => ({value: r.url})));
})
router.post('/session/:sessionId/url', (req, res) => {
    response(res, go(req.body.url))
})

module.exports = {
    go,
    router
};

What the code could have been:

const { promisifyChrome } = require('../Core');
const express = require('express');
const router = express.Router();

/**
 * Wait for the page to be completely loaded.
 * @returns {Promise<{value: {}}> | null}
 */
async function waitForComplete() {
    try {
        const result = await promisifyChrome('debugger.sendCommand', {
            tabId: await getTab()
        }, 'Runtime.evaluate', {
            expression: `
                new window.BackupPromise(resolve => {
                    resolve(document.readyState === "complete" || document.readyState === "interactive");
                })
            `,
            awaitPromise: true
        });
        return result? ({ value: {} }) : null;
    } catch (error) {
        console.error('Error waiting for page to load:', error);
        return null;
    }
}

/**
 * Open or switch to the specified URL.
 * @param {string} url - The URL to open or switch to.
 * @returns {Promise<{ value: {} }>}
 */
async function go(url) {
    // Get all windows and their tabs
    const windows = await promisifyChrome('windows.getAll', {});
    const tabs = await Promise.all(windows.map(w => resolve =>
        promisifyChrome('tabs.getAllInWindow', w.id)
           .then(tabs => resolve(tabs))));

    // Find the first tab that matches the URL or is the current tab
    const tab = tabs.flat().find(t => t.url.includes(url) || t.id === await getTab());

    if (tab) {
        // Activate the tab
        await promisifyChrome('tabs.update', tab.id, { active: true });
    } else {
        // Create a new tab
        const newTab = await promisifyChrome('tabs.create', {
            active: true,
            url
        });
        // Set the new tab as the current tab
        await setTab(newTab.id);
        // Attach the debugger to the new tab
        await promisifyChrome('debugger.attach', {
            tabId: newTab.id
        }, '1.1');
    }

    // Navigate to the URL
    await promisifyChrome('debugger.sendCommand', {
        tabId: await getTab()
    }, 'Page.navigate', {
        url
    });

    // Wait for the page to load
    await waitForComplete();
}

/**
 * Get the URL of the current tab.
 * @returns {Promise<{value: {url: string}}>}
 */
router.get('/session/:sessionId/url', (req, res) => {
    response(res, promisifyChrome('tabs.get', {
        tabId: getTab()
    }).then(r => ({ value: r.url })));
});

/**
 * Open or switch to the specified URL.
 * @param {string} url - The URL to open or switch to.
 */
router.post('/session/:sessionId/url', (req, res) => {
    response(res, go(req.body.url));
});

module.exports = {
    go,
    router
};

Code Overview

The provided code defines a set of functions for interacting with a Chrome browser instance using the Chrome Debugging Protocol. It utilizes the express framework to create a REST API for navigating and interacting with web pages.

Functions

waitForComplete()

go(url)

API Endpoints

/session/:sessionId/url (GET)

/session/:sessionId/url (POST)

Module Exports