This repository was archived by the owner on Nov 29, 2018. It is now read-only.
-
-
Notifications
You must be signed in to change notification settings - Fork 195
This repository was archived by the owner on Nov 29, 2018. It is now read-only.
SafariDriver cannot handle alerts #3862
Copy link
Copy link
Closed
Description
Originally reported on Google Code with ID 3862
Filing this bug to track the implementation of alert handling in the SafariDriver.
Here are the steps I've worked through so far:
--- Step 1
Since the SafariDriver is implemented in JS, in order to intercept calls to alert,
confirm, and prompt, we must override the functions in the context of the web page.
To achieve this, we should change the injected script to be injected as a "Start"
script instead of "End" script - which means the script is injected once the DOM has
been loaded, but before it has been parsed (as opposed to being injected after the
onload event):
http://developer.apple.com/library/safari/#documentation/Tools/Conceptual/SafariExtensionGuide/InjectingScripts/InjectingScripts.html#//apple_ref/doc/uid/TP40009977-CH6-SW5
---- Step 2
We must override the global alert functions in the context of the page under test,
_not_ the injected script. This is similar to the requirements of the executeScript
command. Therefore, the first thing our injected script should do is add a script
tag to DOM that sets up the alert overrides. This script tag should be added as the
first child of the documentElement to ensure it is executed before any others in the
page. This will ensure we set-up our alert handlers before anything in the page has
a chance to fire an alert.
---- Step 3
Once an alert fires, we must notify the extension that there was an alert, while simultaneously
blocking the current JS thread in the page. Normally, our page scripts communicate
with the injected script using window.postMessage. postMessage fires a MessageEvent
asynchronously. To maintain synchronicity, we can manually fire a MessageEvent:
// Use a MessageEvent instead of some other DOM event so we can include a
// JSON object describing the alert.
var event = document.createEvent('MessageEvent');
event.initMessageEvent('message', false, false, {
type: "alert", // confirm, or prompt
text: "hello"
}, window.location.origin, '0', window, null);
window.dispatchEvent(event);
---- Step 4
The injected script must listen for an respond to the page's alert message. To synchronously
send the alert to the extension for processing, we can (ab)use the Safari extension's
mechanism for blocking content from loading:
http://developer.apple.com/library/safari/#documentation/Tools/Conceptual/SafariExtensionGuide/MessagesandProxies/MessagesandProxies.html#//apple_ref/doc/uid/TP40009977-CH14-SW9
window.addEventListener('message', function(e) {
// Create a beforeload event, which is required by the canLoad method
var e = document.createEvent('Events');
e.initEvent('beforeload', false, false);
// canLoad sends and waits for a response synchronously. It is the only
// synchronous function in the Safari extension messaging API.
var response = safari.self.tab.canLoad(e, e.data);
// Send the response back to the page using another MessageEvent.
var responseEvent = document.createEvent('MessageEvent');
responseEvent.initMessageEvent('message', false, false, {
accepted: response.accepted,
response: response.value
}, window.location.origin, '0', window, null);
window.dispatchEvent(responseEvent);
}, true);
Note, the extension's alert response must be communicated back to the page using another
message since we are crossing context boundaries. The only other option is to store
the response on the DOM to be read on the other side.
---- Step 5
The final step, and this is the open-ended question, is how the extension should handle
the alert. Since we're maintaining the blocking behavior of alerts, it's not possible
to let anymore commands execute (even if they result in unhandled alert errors).
One possibility is to have the WebDriver client participate in the alert handling.
In addition to providing a WebSocket server, the WebDriver client will be expected
to also provide an XHR end-point. When an alert is detected, the server will send
a synchronous POST XHR to this end-point. The client should respond only once the
user has accepted or dismissed the alert (or an unhandled alert error was thrown from
another command). When the XHR response is received, the extension completes the chain
and sends the response back to the injected script.
---------------------------------
Yes, this is going to be ugly, but it should be doable. On the off chance anyone wants
to help get this worked out, I've attached a patch with my work on this front.
Reported by jmleyba
on 2012-05-07 16:44:15
- _Attachment: [alerts.diff](https://storage.googleapis.com/google-code-attachments/selenium/issue-3862/comment-0/alerts.diff)_