import os
import uuid
import sys
import subprocess
import ipykernel
import requests
from time import sleep
from pathlib import Path
from playwright.async_api import expect
from playwright.async_api import ViewportSize
from playwright.async_api import async_playwright
from jupyter_server import serverapp
from jupyter_server.services.contents.filemanager import FileContentsManager
from contextlib import contextmanager
from contextlib import asynccontextmanager
from nbformat import v4 as nbformatcontroller
Defines the interface between View & Model.
App
def App(
):
Initialize self. See help(type(self)) for accurate signature.
open_gui
def open_gui(
):
Start the interactive widgets interface for NeuralActivityCubic
GUI Tests Dependencies
def get_kernel_id() -> str | None:
try:
connection_file = ipykernel.get_connection_file()
return Path(connection_file).stem.split('-', 1).pop(-1)
except RuntimeError:
return None
def find_server_info_by_kernel_id(kernel_id: str):
servers = list(serverapp.list_running_servers())
for server in servers:
try:
response = requests.get(f"{server['url']}api/sessions", headers={'Authorization': f"token {server['token']}"})
for session in response.json():
if session['kernel']['id'] == kernel_id:
return server
except Exception as e:
continue
return None
def find_server_info_by_process_id(process_id: int):
servers = list(serverapp.list_running_servers())
for server in servers:
if server['pid'] == process_id:
return server
return None
@contextmanager
def run_jupyter_server_app(project_root: str):
jupyter_process = subprocess.Popen([sys.executable, '-m', 'jupyter', 'server', f'--ServerApp.root_dir={project_root}', '--ServerApp.open_browser=false'])
sleep(10) # Wait for the server to start
yield find_server_info_by_process_id(jupyter_process.pid)
jupyter_process.terminate()
@contextmanager
def get_jupyter_server():
kernel_id = get_kernel_id()
if kernel_id:
yield find_server_info_by_kernel_id(kernel_id)
else:
with run_jupyter_server_app(project_root=Path.cwd().parent) as server_info:
yield server_info@contextmanager
def create_temporary_notebook(cells: list[str], kernel_name: str = 'python3'):
fcm = FileContentsManager()
name = f"test-{uuid.uuid4()}.ipynb"
try:
notebook = nbformat.new_notebook()
notebook['metadata'] = {'kernelspec': {'name': kernel_name, 'display_name': kernel_name}}
for cell in cells:
notebook['cells'].append(nbformat.new_code_cell(source=cell))
fcm.save({'type': 'notebook', 'content': notebook}, name)
yield name
finally:
fcm.delete(name)
@asynccontextmanager
async def provide_playwright_page(headless: bool):
browser = 'chromium'
if headless:
browser = 'chromium-headless-shell'
subprocess.run([sys.executable, '-m', 'playwright', 'install', '--with-deps', browser])
async with async_playwright() as playwright:
browser_type = playwright.chromium
browser = await browser_type.launch(headless=headless)
page = await browser.new_page(viewport=ViewportSize(width=1280, height=1024))
yield page
await browser.close()
@asynccontextmanager
async def provide_na3_gui(visible: bool = True):
with get_jupyter_server() as server_info, create_temporary_notebook(cells=['import neuralactivitycubic as na3; na3.open_gui()']) as notebook_name:
token = server_info['token']
lab_url = server_info['url'] + 'lab/tree/nbs'
async with provide_playwright_page(headless=not visible) as page:
await page.goto(f'{lab_url}/{notebook_name}?token={token}')
await expect(page.get_by_role('main')).to_contain_text(notebook_name)
selected_tab_id = await page.get_by_role('main').get_by_role('tab', selected=True).first.get_attribute('data-id')
selected_tab = page.locator(f'#{selected_tab_id}').first
await expect(selected_tab).to_be_visible()
try:
await expect(page.locator('#filebrowser')).to_be_visible(timeout=1)
await page.locator('li[data-id="filebrowser"]').click()
except AssertionError:
pass
kernel_status = selected_tab.locator('.jp-Notebook-ExecutionIndicator')
await expect(kernel_status).to_have_attribute('data-status', 'idle')
await page.wait_for_timeout(timeout=1000)
run_menu = page.get_by_role('menuitem').filter(has=page.get_by_text('Run')).first
await run_menu.click()
run_all_cells_option = page.get_by_role('menuitem').filter(has=page.get_by_text('Run All Cells')).first
await expect(run_all_cells_option).to_be_visible()
await run_all_cells_option.click()
na3_gui = selected_tab.locator('.box-na3-gui')
await expect(na3_gui).to_be_visible()
yield na3_guivisible = os.environ.get('CI') != 'true'
async with provide_na3_gui(visible=visible) as gui:
general_settings = gui.locator('.box-general-settings')
assert not await general_settings.get_by_role("button", name="Select").is_disabled()
assert await general_settings.get_by_role("button", name="Load Data").is_disabled()
analysis_settings = gui.locator('.box-analysis-settings')
buttons = await analysis_settings.locator("button").all()
assert buttons
for button in buttons:
assert await button.is_disabled()
inputs = await analysis_settings.locator("input").all()
assert inputs
for input in inputs:
assert await input.is_disabled()