from fastcore.test import test_eqSolveitCDP API
Channel connects to Solveit’s /wsx relay for ongoing JSON messaging. Set SOLVEIT_URL to the Solveit server’s URL, or pass a full WebSocket url to Channel.connect. The default server is http://localhost:5001.
Channel
def Channel(
chan, url:NoneType=None
):Duplex JSON messaging with the other peers on a named /wsx relay channel
Connect each peer to the same channel name on Solveit’s /wsx relay. The relay forwards each frame unchanged to every other peer on that channel. solvecdp uses Channel to communicate with the solveit-chrome extension.
Channel sends JSON dictionaries. Pass the fields as keyword arguments to send. Incoming frames become AttrDict objects. If a frame’s id matches a pending request, it completes that request. Other frames go into the events queue.
Here we connect two peers and send a greeting. The second peer reads it from events.
ch1,ch2 = await Channel.connect('test'),await Channel.connect('test')
await ch1.send(hello='world')
test_eq((await ch2.events.get()).hello, 'world')request adds a unique id and waits for a reply with that id. Requests can run concurrently. The peer answering a request must include its id in the reply. This example replies with twice the supplied number.
async def _responder():
msg = await ch2.events.get()
await ch2.send(id=msg.id, result=msg.x*2)
task = asyncio.create_task(_responder())
test_eq((await ch1.request(x=21)).result, 42)Check is_open before and after closing the connections.
assert ch1.is_open
await ch1.close()
await ch2.close()
assert not ch1.is_openJsCDP
def JsCDP(
wsconn:str=None, # WebSocket URL, populated by connection helpers
debug:bool=False, # Log protocol events
command_timeout:float=10, # Seconds before an unanswered command raises TimeoutError
):CDP over the solveit-chrome extension: frames relayed via solveit’s /wsx channel
Everything else comes from fastcdp.ext’s ExtCDP: the sessionId↔︎tabId mapping, the lifecycle actions, and new_page/attach_page/pages. JsCDP just supplies the channel, meeting the extension at this solveit’s /wsx relay instead of listening on a local port (a solveit kernel usually runs in a container that the user’s browser can’t reach, so both sides dial out to the relay).
Connect, open a tab, and drive it. goto, eval, and friends are all inherited from fastcdp through the Page proxy:
cdp = await JsCDP.connect()
page = await cdp.new_page()
await page.goto('https://httpbingo.org/forms/post')
await page.eval('document.title')assert 'httpbingo.org' in await page.eval('document.title')
assert first(await cdp.pages, lambda t: 'httpbingo' in t.get('url',''))The accessibility tree and form helpers also come straight from fastcdp: find elements with ax_tree/find_id, then fill_text, click, select_option, and click_and_wait.
root = await page.ax_tree()
await page.fill_text(root.find_id('textbox', 'Customer name'), 'Jeremy Howard')
await page.click(root.find_id('radio', 'Large'))
await page.click(root.find_id('checkbox', 'Extra Cheese'))await page.click_and_wait(root.find_id('button', 'Submit order'))
assert 'Jeremy Howard' in await page.eval('document.body.innerText')The debugging buffers work too, since every chrome.debugger event is streamed over the channel and dispatched by the inherited machinery:
await page.start_console()
await page.eval(r'console.warn("watch out")')
test_eq(await page.console(r'watch'), ['warning: watch out'])await page.close()
await cdp.close()