Skip to content

Commit 8719ca8

Browse files
committed
Add Python which automatically runs smallpt.ipynb in chosen browser
1 parent feab77a commit 8719ca8

File tree

1 file changed

+192
-0
lines changed

1 file changed

+192
-0
lines changed
Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
import argparse
2+
from selenium import webdriver
3+
from selenium.webdriver.support.ui import WebDriverWait
4+
from selenium.webdriver.support import expected_conditions as EC
5+
from selenium.webdriver.common.action_chains import ActionChains
6+
from selenium.webdriver.common.by import By
7+
from selenium.webdriver.common.keys import Keys
8+
import time
9+
10+
11+
def main():
12+
parser = argparse.ArgumentParser(description="Run Selenium with a chosen driver")
13+
parser.add_argument(
14+
"--driver",
15+
type=str,
16+
default="chrome",
17+
choices=["chrome", "firefox", "safari"],
18+
help="Choose which WebDriver to use",
19+
)
20+
21+
args = parser.parse_args()
22+
URL = "http://127.0.0.1:8000/lab/index.html?path=smallpt.ipynb"
23+
24+
# This will start the right driver depending on what
25+
# driver option is chosen
26+
if args.driver == "chrome":
27+
driver = webdriver.Chrome()
28+
29+
elif args.driver == "firefox":
30+
driver = webdriver.Firefox()
31+
32+
elif args.driver == "safari":
33+
driver = webdriver.Safari()
34+
35+
wait = WebDriverWait(driver, 30)
36+
actions = ActionChains(driver)
37+
38+
# Open Jupyter Lite with the notebook requested
39+
driver.get(URL)
40+
41+
# Waiting for Jupyter Lite URL to finish loading
42+
notebook_area = wait.until(
43+
EC.presence_of_element_located((By.CSS_SELECTOR, ".jp-Notebook"))
44+
)
45+
46+
time.sleep(1)
47+
48+
notebook_area.click()
49+
time.sleep(0.5)
50+
51+
# This will run all the cells of the chosen notebook
52+
if args.driver == "chrome":
53+
print("Opening Run Menu")
54+
run_menu = wait.until(
55+
EC.element_to_be_clickable((By.XPATH, "//li[normalize-space()='Run']"))
56+
)
57+
actions.move_to_element(run_menu).pause(0.1).click().perform()
58+
time.sleep(0.5)
59+
print("Click on Run All Cells")
60+
run_all_menu = wait.until(
61+
EC.visibility_of_element_located(
62+
(By.XPATH, "//li[normalize-space()='Run All Cells']")
63+
)
64+
)
65+
actions.move_to_element(run_all_menu).click().perform()
66+
time.sleep(100)
67+
68+
elif args.driver == "firefox":
69+
print("Opening Run Menu")
70+
run_menu = wait.until(
71+
EC.element_to_be_clickable((By.XPATH, "//li[normalize-space()='Run']"))
72+
)
73+
actions.move_to_element(run_menu).pause(0.1).click().perform()
74+
time.sleep(0.5)
75+
print("Click on Run All Cells")
76+
run_all_menu = wait.until(
77+
EC.element_to_be_clickable(
78+
(By.XPATH, "//li[normalize-space()='Run All Cells']")
79+
)
80+
)
81+
actions.move_to_element(run_all_menu).click().perform()
82+
time.sleep(100)
83+
84+
elif args.driver == "safari":
85+
print("Running all cells using Shift+Enter...")
86+
while True:
87+
# Focused cell
88+
focused_cell = driver.find_element(
89+
By.CSS_SELECTOR, ".jp-Notebook-cell.jp-mod-selected"
90+
)
91+
92+
# Get the cell content text reliably in Safari
93+
editor_divs = focused_cell.find_elements(
94+
By.CSS_SELECTOR, ".jp-InputArea-editor div"
95+
)
96+
cell_content = "".join([div.text for div in editor_divs]).strip()
97+
98+
if not cell_content:
99+
break
100+
101+
# Press Shift+Enter to run the cell
102+
notebook_area.send_keys(Keys.SHIFT, Keys.ENTER)
103+
time.sleep(0.5)
104+
105+
time.sleep(145)
106+
107+
if args.driver == "chrome" or args.driver == "firefox":
108+
print("Saving notebook")
109+
file_menu = wait.until(
110+
EC.element_to_be_clickable((By.XPATH, "//li[normalize-space()='File']"))
111+
)
112+
actions.move_to_element(file_menu).click().perform()
113+
save_item = wait.until(
114+
EC.visibility_of_element_located(
115+
(By.XPATH, "//li[contains(normalize-space(), 'Save')]")
116+
)
117+
)
118+
119+
actions.move_to_element(save_item).click().perform()
120+
time.sleep(0.5)
121+
122+
elif args.driver == "safari":
123+
print("Saving notebook using command + s + enter.")
124+
notebook_area.send_keys(Keys.COMMAND, "s")
125+
time.sleep(0.5)
126+
127+
notebook_area.send_keys(Keys.ENTER)
128+
time.sleep(0.5)
129+
130+
# This downloads the notebook, so it can be compared
131+
# to a reference notebook
132+
print("Downloading notebook by clicking download button")
133+
search_script = """
134+
function deepQuerySelector(root, selector) {
135+
const walker = document.createTreeWalker(
136+
root,
137+
NodeFilter.SHOW_ELEMENT,
138+
{
139+
acceptNode: node => NodeFilter.FILTER_ACCEPT
140+
},
141+
false
142+
);
143+
144+
while (walker.nextNode()) {
145+
let node = walker.currentNode;
146+
147+
// Check if this node matches
148+
if (node.matches && node.matches(selector)) {
149+
return node;
150+
}
151+
152+
// If this element has a shadow root, search inside it
153+
if (node.shadowRoot) {
154+
const found = deepQuerySelector(node.shadowRoot, selector);
155+
if (found) return found;
156+
}
157+
}
158+
return null;
159+
}
160+
161+
return deepQuerySelector(document, "jp-button[data-command='docmanager:download']");
162+
"""
163+
164+
download_button = driver.execute_script(search_script)
165+
166+
driver.execute_script(
167+
"""
168+
const el = arguments[0];
169+
170+
// Force element to be visible and focused
171+
el.scrollIntoView({block: 'center', inline: 'center'});
172+
173+
// Dispatch real mouse events since Safari WebDriver ignores .click() on Web Components
174+
['pointerdown', 'mousedown', 'mouseup', 'click'].forEach(type => {
175+
el.dispatchEvent(new MouseEvent(type, {
176+
bubbles: true,
177+
cancelable: true,
178+
composed: true, // IMPORTANT for shadow DOM
179+
view: window
180+
}));
181+
});
182+
""",
183+
download_button,
184+
)
185+
time.sleep(2)
186+
187+
# Close browser
188+
driver.quit()
189+
190+
191+
if __name__ == "__main__":
192+
main()

0 commit comments

Comments
 (0)