From 0ad4afe77d3e671b276486fac8c5059d94071aa3 Mon Sep 17 00:00:00 2001 From: Martin Pitt Date: Tue, 16 Jul 2024 14:20:55 +0200 Subject: [PATCH] webdriver-bidi demo --- bidi.js | 116 ++++++++++++++++++++++++++++++++++++++ chromium-headless-wrapper | 10 ++++ package.json | 3 +- 3 files changed, 128 insertions(+), 1 deletion(-) create mode 100644 bidi.js create mode 100755 chromium-headless-wrapper diff --git a/bidi.js b/bidi.js new file mode 100644 index 0000000..3b82d65 --- /dev/null +++ b/bidi.js @@ -0,0 +1,116 @@ +import WebDriver from "webdriver"; + +// copied from test-functions.js + +class PhWaitCondTimeout extends Error { + constructor(description) { + if (description && description.apply) + description = description.apply(); + if (description) + super(description); + else + super("condition did not become true"); + } +} +function wait_cond(cond, timeout, error_description) { + return new Promise((resolve, reject) => { + // poll every 100 ms for now; FIXME: poll less often and re-check on mutations using + // https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver + let stepTimer = null; + let last_err = null; + const tm = setTimeout(() => { + if (stepTimer) + clearTimeout(stepTimer); + reject(last_err || new PhWaitCondTimeout(error_description)); + }, timeout); + async function step() { + try { + if (await cond()) { + clearTimeout(tm); + resolve(); + return; + } + } catch (err) { + last_err = err; + } + stepTimer = setTimeout(step, 500); + } + step(); + }); +} + +// end copy + +// https://w3c.github.io/webdriver/#dfn-find-elements +const EL_ID = 'element-6066-11e4-a52e-4f735466cecf'; + +// async function get(selector: string): Promise { +async function get(selector) { + const elements = await b.findElements('css selector', selector); + if (elements.length === 0) + throw new Error(selector + ' not found'); + if (elements.length > 1) + throw new Error(selector + ' is ambiguous'); + return elements[0][EL_ID]; +} + +const wait = selector => wait_cond( + () => b.findElements('css selector', selector).then(r => r.length === 1), + 15000 +); + +const b = await WebDriver.newSession({ + capabilities: { + webSocketUrl: true, + browserName: process.env.TEST_BROWSER || 'chromium', + 'moz:firefoxOptions': { + args: ["-headless"], + }, + 'goog:chromeOptions': { + binary: './chromium-headless-wrapper', // only with --headless! + args: [ + "--headless", "--no-sandbox", "--disable-setuid-sandbox", + "--disable-namespace-sandbox", "--disable-seccomp-filter-sandbox", + "--disable-sandbox-denial-logging", "--disable-pushstate-throttle", + "--font-render-hinting=none", "--disable-popup-blocking"], + }, + } +}); + +try { + await b.sessionSubscribe({ events: ['log.entryAdded'] }); + + b.on('log.entryAdded', l => console.log('log.entryAdded:', l)); + + await b.executeScript('console.log("Hello Bidi")', []); + + await b.navigateTo("http://127.0.0.2:9091"); + + // const buttons = await b.findElements('css selector', 'button'); // length: 2 + + await b.elementClick(await get("#login-button")); + await b.elementSendKeys(await get("#login-user-input"), "admin"); + await b.elementSendKeys(await get("#login-password-input"), "foobar"); + await b.elementClick(await get("#login-button")); + + await wait("#super-user-indicator"); + const t = await b.getElementText(await get("#super-user-indicator")); + if (t !== "Limited access") + throw new Error(`Expected 'Limited access', got '${t}'`); + + // overview frame + const f_overview = await b.findElement('css selector', "iframe[name='cockpit1:localhost/system']"); + await b.switchToFrame(f_overview); // this gets the full object, not the ID + + const cct = await b.getElementText(await get(".system-configuration")); + if (!cct.includes("Join domain")) + throw new Error(`Expected 'Join domain' in '${cct}'`); + + // base64 encoded PNG, works fine + // const screenshot = await b.takeScreenshot(); + + console.log("\n\nFinished. Press Control-C to exit"); + await new Promise(resolve => setTimeout(resolve, 100000)); +} finally { + await b.deleteSession(); +} diff --git a/chromium-headless-wrapper b/chromium-headless-wrapper new file mode 100755 index 0000000..630e421 --- /dev/null +++ b/chromium-headless-wrapper @@ -0,0 +1,10 @@ +#!/bin/sh +# This is a hack around `headless_shell --version` not working +set -eu + +if [ "$1" = "--version" ]; then + echo "Chromium $(rpm -q --queryformat '%{VERSION}' chromium-headless) Fedora Project" + exit 0 +fi + +exec /usr/lib*/chromium-browser/headless_shell "$@" diff --git a/package.json b/package.json index 58e7428..76f69cb 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,8 @@ "stylelint-config-standard": "36.0.1", "stylelint-config-standard-scss": "13.1.0", "stylelint-formatter-pretty": "4.0.0", - "typescript": "5.5.3" + "typescript": "5.5.3", + "webdriver": "8.39.0" }, "dependencies": { "@patternfly/patternfly": "5.3.1",