Skip to content

Commit

Permalink
JasonLeyba: The SafariDriver should catch native dialogs from user de…
Browse files Browse the repository at this point in the history
…fined onbeforeunload handlers.

r18282
  • Loading branch information
jleyba committed Dec 7, 2012
1 parent ba741f0 commit fee17f6
Show file tree
Hide file tree
Showing 6 changed files with 284 additions and 69 deletions.
118 changes: 113 additions & 5 deletions java/client/test/org/openqa/selenium/safari/AlertTests.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.NoAlertPresentException;
import org.openqa.selenium.UnhandledAlertException;
import org.openqa.selenium.WebElement;

import org.junit.AfterClass;
import org.junit.Before;
Expand Down Expand Up @@ -110,7 +111,6 @@ public void throwsIfScriptTriggersAlertWhichTimesOut() {
fail("Expected UnhandledAlertException");
} catch (UnhandledAlertException expected) {
// Expected exception
expected.printStackTrace();
}
// Shouldn't throw
driver.getTitle();
Expand All @@ -136,9 +136,7 @@ public void testIncludesAlertInUnhandledAlertException() {
driver.findElement(By.id("alert")).click();
fail("Expected UnhandledAlertException");
} catch (UnhandledAlertException e) {
Alert alert = e.getAlert();
assertNotNull(alert);
assertEquals("cheese", alert.getText());
assertAlertText("cheese", e);
}
}

Expand All @@ -152,9 +150,119 @@ public void shouldCatchAlertsOpenedBetweenCommandsAndReportThemOnTheNextCommand(
try {
driver.getTitle();
} catch (UnhandledAlertException expected) {
assertEquals("hi", expected.getAlert().getText());
assertAlertText("hi", expected);
}
// Shouldn't throw
driver.getTitle();
}

@Test
public void onBeforeUnloadWithNoReturnValueShouldNotTriggerUnexpectedAlertErrors() {
driver.get(pages.alertsPage);

JavascriptExecutor executor = (JavascriptExecutor) driver;
assertEquals(0L,
executor.executeScript("localStorage.clear(); return localStorage.length"));

executor.executeScript(
"window.onbeforeunload = function() {\n" +
" localStorage.setItem('foo', 'bar');\n" +
"};");

driver.navigate().refresh();
assertEquals("onbeforeunload did not run!",
"bar", executor.executeScript("return localStorage.getItem('foo');"));
}

@Test
public void onBeforeUnloadWithNullReturnDoesNotTriggerAlertError() {
driver.get(pages.alertsPage);

JavascriptExecutor executor = (JavascriptExecutor) driver;
assertEquals(0L,
executor.executeScript("localStorage.clear(); return localStorage.length"));

executor.executeScript(
"window.onbeforeunload = function() {\n" +
" localStorage.setItem('foo', 'bar');\n" +
" return null;\n" +
"};");

driver.navigate().refresh();
assertEquals("onbeforeunload did not run!",
"bar", executor.executeScript("return localStorage.getItem('foo');"));
}

@Test
public void onBeforeUnloadFromPageLoadShouldTriggerUnexpectedAlertErrors() {
driver.get(pages.alertsPage);

setSimpleOnBeforeUnload("one two three");
try {
driver.get(pages.alertsPage);
fail("Expected UnhandledAlertException");
} catch (UnhandledAlertException e) {
assertAlertText("one two three", e);
}
}

@Test
public void onBeforeUnloadFromPageRefreshShouldTriggerUnexpectedAlertErrors() {
driver.get(pages.alertsPage);

setSimpleOnBeforeUnload("one two three");
try {
driver.navigate().refresh();
fail("Expected UnhandledAlertException");
} catch (UnhandledAlertException e) {
assertAlertText("one two three", e);
}
}

@Test
public void
onBeforeUnloadWithReturnValuesShouldTriggerUnexpectedAlertErrors_uiAction() {
driver.get(pages.alertsPage);

JavascriptExecutor executor = (JavascriptExecutor) driver;
WebElement body = (WebElement) executor.executeScript(
"window.onbeforeunload = function() { return 'one two three'; };" +
"document.body.onclick = function() { window.location.reload(); };" +
"return document.body;");

body.click();
try {
driver.getTitle();
fail("Expected UnhandledAlertException");
} catch (UnhandledAlertException e) {
assertAlertText("one two three", e);
}
}

@Test
public void
onBeforeUnloadWithReturnValuesShouldTriggerUnexpectedAlertErrors_asyncScript() {
driver.get(pages.alertsPage);

setSimpleOnBeforeUnload("one two three");
try {
((JavascriptExecutor) driver).executeAsyncScript(
"window.location = arguments[0]", pages.alertsPage);
fail("Expected UnhandledAlertException");
} catch (UnhandledAlertException e) {
assertAlertText("one two three", e);
}
}

private static void assertAlertText(String expectedText, UnhandledAlertException e) {
Alert alert = e.getAlert();
assertNotNull(alert);
assertEquals(expectedText, alert.getText());
}

private void setSimpleOnBeforeUnload(Object returnValue) {
((JavascriptExecutor) driver).executeScript(
"var retVal = arguments[0]; window.onbeforeunload = function() { return retVal; }",
returnValue);
}
}
127 changes: 83 additions & 44 deletions javascript/safari-driver/extension/commands.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ goog.require('goog.Uri');
goog.require('goog.array');
goog.require('goog.debug.Logger');
goog.require('goog.string');
goog.require('safaridriver.alert');
goog.require('safaridriver.extension.Tab');
goog.require('safaridriver.message.Alert');
goog.require('safaridriver.message.Load');
goog.require('webdriver.promise');

Expand Down Expand Up @@ -116,36 +118,8 @@ safaridriver.extension.commands.loadUrl = function(session, command) {
var tab = session.getCommandTab();
tab.whenReady(function() {
var expectLoad = tab.loadsNewPage(uri);
if (expectLoad) {
tab.once(safaridriver.message.Load.TYPE, onLoad);
}
safaridriver.extension.commands.sendCommand(session, command).
then(onSuccess, onFailure);

function onLoad() {
if (response.isPending()) {
safaridriver.extension.commands.LOG_.info(
'Page load finished; returning');
response.resolve();
}
}

function onSuccess() {
if (!expectLoad && response.isPending()) {
safaridriver.extension.commands.LOG_.info(
'Not expecting a new page load; returning');
response.resolve();
}
}

function onFailure(e) {
if (response.isPending()) {
safaridriver.extension.commands.LOG_.severe(
'Error while loading page; failing', e);
tab.removeListener(safaridriver.message.Load.TYPE, onLoad);
response.reject(e);
}
}
safaridriver.extension.commands.sendNavigationCommand_(session, command,
expectLoad).then(response.resolve, response.reject);
});

return response.promise;
Expand All @@ -161,25 +135,90 @@ safaridriver.extension.commands.loadUrl = function(session, command) {
*/
safaridriver.extension.commands.refresh = function(session, command) {
var response = new webdriver.promise.Deferred();
session.getCommandTab().whenReady(function() {
safaridriver.extension.commands.sendNavigationCommand_(session, command,
true).then(response.resolve, response.reject);
});
return response.promise;
};


/**
* Sends a navigation related command to the tab for execution.
* @param {!safaridriver.extension.Session} session The session object.
* @param {!safaridriver.Command} command The command object.
* @param {boolean} waitForLoad Whether to wait for a load message from the
* tab before considering the command completed.
* @return {!webdriver.promise.Promise} A promise that will be resolved when
* the operation has completed.
* @private
*/
safaridriver.extension.commands.sendNavigationCommand_ = function(session,
command, waitForLoad) {
var response = new webdriver.promise.Deferred();
var tab = session.getCommandTab();
tab.whenReady(function() {
if (waitForLoad) {
tab.once(safaridriver.message.Load.TYPE, onLoad);
}
safaridriver.extension.commands.sendCommand(session, command).
then(onSuccess, onFailure);
return response.promise;

safaridriver.extension.commands.sendCommand(session, command).
addErrback(function(e) {
if (response.isPending()) {
tab.removeListener(safaridriver.message.Load.TYPE, onLoad);
response.reject(e);
}
});
/** Load message handler that completes the command response. */
function onLoad() {
tab.removeListener(safaridriver.message.Alert.TYPE, onAlert);
if (response.isPending()) {
safaridriver.extension.commands.LOG_.info(
'Page load finished; returning');
tab.removeListener(safaridriver.message.Alert.TYPE, onAlert);
response.resolve();
}
}

function onLoad() {
if (response.isPending()) {
response.resolve();
}
/**
* Alert message handler that will fail the command if a UI blocking alert
* message is received.
* @param {!safaridriver.message.Alert} message The parsed message.
* @param {!SafariExtensionMessageEvent} e The message event.
*/
function onAlert(message, e) {
if (message.blocksUiThread() && response.isPending()) {
tab.removeListener(safaridriver.message.Alert.TYPE, onAlert);
tab.removeListener(safaridriver.message.Load.TYPE, onLoad);
// Stop propagation so the extension's global alert message handler
// does not fire.
e.stopPropagation();
response.resolve(
safaridriver.alert.createResponse(message.getMessage()));
}
});
return response.promise;
}

/**
* Handler for when the tab responds to navigation command. The receipt of
* this response does not indicate that the navigation has completed, so
* the command will be left pending.
*/
function onSuccess() {
if (!waitForLoad && response.isPending()) {
safaridriver.extension.commands.LOG_.info(
'Not expecting a new page load; returning');
response.resolve();
}
tab.on(safaridriver.message.Alert.TYPE, onAlert);
}

/**
* Handles command failures from the tab.
* @param {Error} e The failure reason.
*/
function onFailure(e) {
if (response.isPending()) {
safaridriver.extension.commands.LOG_.severe(
'Error while loading page; failing', e);
tab.removeListener(safaridriver.message.Load.TYPE, onLoad);
response.reject(e);
}
}
};


Expand Down
5 changes: 3 additions & 2 deletions javascript/safari-driver/extension/extension.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,9 @@ safaridriver.extension.numConnections_ = 0;


/**
* Responds to a message from an injected script.
* Responds to a message from an injected script. Note this event listener is
* attached to the {@code safari.application} object and will receive messages
* <em>after</em> any listeners attached directly to a tab or browser.
* @param {!SafariExtensionMessageEvent} e The event.
* @private
*/
Expand Down Expand Up @@ -138,7 +140,6 @@ safaridriver.extension.onMessage_ = function(e) {
// TODO: Fully support alerts. See
// http://code.google.com/p/selenium/issues/detail?id=3862
e.message = !!safaridriver.extension.numConnections_;
e.stopPropagation();
break;
}
};
Expand Down
Loading

0 comments on commit fee17f6

Please sign in to comment.