/**
* Candybean is a next generation automation and testing framework suite.
* It is a collection of components that foster test automation, execution
* configuration, data abstraction, results illustration, tag-based execution,
* top-down and bottom-up batches, mobile variants, test translation across
* languages, plain-language testing, and web service testing.
* Copyright (C) 2013 SugarCRM, Inc. <candybean@sugarcrm.com>
* <p>
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
* <p>
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
* <p>
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sugarcrm.candybean.automation.webdriver;
import com.sugarcrm.candybean.automation.AutomationInterface.Type;
import static org.junit.Assert.*;
import java.io.File;
import java.util.concurrent.TimeUnit;
import com.sugarcrm.candybean.automation.element.Hook;
import com.sugarcrm.candybean.configuration.Configuration;
import com.sugarcrm.candybean.testUtilities.TestConfiguration;
import org.junit.*;
import org.junit.rules.ExpectedException;
import com.sugarcrm.candybean.automation.AutomationInterfaceBuilder;
import com.sugarcrm.candybean.automation.Candybean;
import com.sugarcrm.candybean.automation.element.Hook.Strategy;
import com.sugarcrm.candybean.exceptions.CandybeanException;
/**
* Tests for WebDriverSystem.class
*
* Tests use the local web pages in resources/html/test/ to avoid needing an internet
* connection to test. The html page testPlayground.html contains a variety of elements
* each contained within a div.
*
* When selecting elements, the general rule of thumb is to include the id of the parent
* div if it is relevant. For example, if you wanted the span with id "writingSpan"
* because you wanted to test element visibility, you would search for it with
* $("#clickToHideDiv #writingSpan")
* However, if you only wanted it because you needed a span element to test against, you
* would not list the parent's div name because the ability to click to hide is irrelevant,
* search for it using:
* $("#writingSpan")
*
* There's no 100% answer when to use either, so use what you feel best portrays your intent
*/
public class WebDriverSystemTest {
private WebDriverInterface iface;
final String testPlaygroundPage = "file://" + System.getProperty("user.dir") + "/resources/html/test/testPlayground.html";
final String onOffScreenPage = "file://" + System.getProperty("user.dir") + "/resources/html/test/onOffScreen.html";
// Creating this function privately for now, a full implementation in WebDriverElement
// is detailed in CB-265
private WebDriverElement $(String cssPath) throws CandybeanException {
return iface.getWebDriverElement(Strategy.CSS, cssPath);
}
@Before
public void setUp() throws Exception {
Configuration config = TestConfiguration.getTestConfiguration("systemtest.webdriver.config");
Candybean candybean = Candybean.getInstance(config);
AutomationInterfaceBuilder builder = candybean.getAIB(WebDriverSystemTest.class);
builder.setType(Type.CHROME);
iface = builder.build();
iface.start();
}
@After
public void tearDown() throws CandybeanException {
iface.stop();
}
@Rule
public ExpectedException thrown = ExpectedException.none();
@Test
public void backwardForwardRefreshTest() throws Exception {
iface.go(testPlaygroundPage);
iface.go(onOffScreenPage);
iface.go(testPlaygroundPage);
assertEquals(testPlaygroundPage, iface.getURL());
iface.backward();
iface.pause(1000);
assertEquals(onOffScreenPage, iface.getURL());
iface.backward();
iface.pause(1000);
assertEquals(testPlaygroundPage, iface.getURL());
iface.forward();
iface.pause(1000);
assertEquals(onOffScreenPage, iface.getURL());
iface.forward();
iface.pause(1000);
assertEquals(testPlaygroundPage, iface.getURL());
iface.refresh(); // refreshing only at end; mid-refreshes crash in Chrome
iface.pause(2000);
assertEquals(testPlaygroundPage, iface.getURL());
}
@Test
public void screenshotTest() throws Exception {
File screenshotFile = new File(Candybean.ROOT_DIR + File.separator + "screenshot.png");
iface.go(testPlaygroundPage);
iface.screenshot(screenshotFile);
assertTrue(screenshotFile.exists());
screenshotFile.delete();
}
@Ignore("CB-259: Need support for chromedriver 2.20, as it does not block popups by default")
@Test
public void openCloseWindowTest() throws Exception {
iface.go(testPlaygroundPage);
assertEquals(testPlaygroundPage, iface.wd.getCurrentUrl());
iface.openWindow(onOffScreenPage);
assertEquals(onOffScreenPage, iface.wd.getCurrentUrl());
iface.focusWindow(0);
assertEquals(testPlaygroundPage, iface.wd.getCurrentUrl());
iface.focusWindow(1);
assertEquals(onOffScreenPage, iface.wd.getCurrentUrl());
iface.closeWindow();
assertEquals(testPlaygroundPage, iface.wd.getCurrentUrl());
}
@Test
public void presentAcceptDismissDialogTest() throws Exception {
iface.go(testPlaygroundPage);
// dialog not yet visible
assertFalse(iface.isDialogVisible());
// clicking; alert should be visible and window inactive
$("#newAlert").click();
iface.pause(1000);
assertTrue(iface.isDialogVisible());
// accepting alert dialog; should be gone
iface.acceptDialog();
assertFalse(iface.isDialogVisible());
// Dismiss not available in Chrome
if (!(iface instanceof ChromeInterface)) {
$("#newAlert").click();
assertTrue(iface.isDialogVisible());
iface.dismissDialog();
assertFalse(iface.isDialogVisible());
}
}
@Test
public void containsTest() throws Exception {
final boolean CASE_SENSITIVE = true;
final boolean CASE_INSENSITIVE = false;
iface.go(testPlaygroundPage);
Assert.assertTrue(iface.contains("Click button", CASE_SENSITIVE));
Assert.assertTrue(iface.contains("cLiCk BuTtOn", CASE_INSENSITIVE));
Assert.assertTrue(iface.contains("Click button", CASE_INSENSITIVE));
Assert.assertFalse(iface.contains("cLiCk BuTtOn", CASE_SENSITIVE));
Assert.assertFalse(iface.contains("Doesn't contain this", CASE_SENSITIVE));
Assert.assertFalse(iface.contains("Doesn't contain this", CASE_INSENSITIVE));
}
@Test
public void focusFrameTest() throws Exception {
String mainText = "Click button to hide me";
String iframeText = "This goes inside the iframe";
iface.go(testPlaygroundPage);
assertEquals(mainText, $("#writingSpan").getText());
// switch focus to frame by index
iface.focusFrame(0);
assertEquals(iframeText, $("#iframePara").getText());
// switch to default focus
iface.focusDefault();
assertEquals(mainText, $("#writingSpan").getText());
// switch focus to frame by name
iface.focusFrame("Test_iframe");
assertEquals(iframeText, $("#iframePara").getText());
// switch to default focus
iface.focusDefault();
assertEquals(mainText, $("#writingSpan").getText());
// switch to focus by control
iface.focusFrame(new WebDriverElement(Strategy.ID, "Test_iframe", iface.wd));
assertEquals(iframeText, $("#iframePara").getText());
// switch to default focus
iface.focusDefault();
assertEquals(mainText, $("#writingSpan").getText());
}
@Ignore("CB-263: Candybean does not properly model windows")
@Test
public void focusWindowTest() throws Exception {
String mainWindowTitle = "Candybean Test Page";
String altWindowTitle = "Candybean Test Page 2";
iface.go(testPlaygroundPage);
// Opens a window in a new tab
iface.getWebDriverElement(Strategy.PLINK, "Open in new window").click();
iface.getWebDriverElement(Strategy.PLINK, "Open in new window").click();
// Verify title without switching
assertEquals(mainWindowTitle, iface.wd.getTitle());
// Verify title with switching
iface.focusWindow(1);
Thread.sleep(1000);
assertEquals(altWindowTitle, iface.wd.getTitle());
// Close window which should auto-focus to previous window; verify title
iface.closeWindow();
assertEquals(mainWindowTitle, iface.wd.getTitle());
iface.getWebDriverElement(Strategy.PLINK, "Open in new window").click();
iface.focusWindow(altWindowTitle);
assertEquals(altWindowTitle, iface.wd.getTitle());
assertEquals(onOffScreenPage, iface.getURL());
// Verify URL with switching to window by URL
iface.focusWindow(testPlaygroundPage);
assertEquals(mainWindowTitle, iface.wd.getTitle());
// Close window and revert to previous window (1 index); verify URL
iface.closeWindow();
assertEquals(onOffScreenPage, iface.getURL());
// Verify errors by switching to erroneous window titles & indices
// We use try catch rather than expected errors so that we can assert multiple error message
try {
iface.focusWindow("garbage");
fail("The test should not have been able to focus the window titled \"garbage\"");
} catch (CandybeanException e) {
assertEquals("The given focus window string matched no title or URL: garbage",
e.getMessage());
}
try {
iface.focusWindow(-1);
fail("The test should not have been able to focus the window of index -1");
} catch (CandybeanException e) {
assertEquals("Given focus window index is out of bounds: -1; current size: 1",
e.getMessage());
}
try {
iface.focusWindow(0);
fail("The test should not have been able to focus the window of index 0, " +
"that window should no longer exist");
} catch (CandybeanException e) {
assertEquals("Given focus window index is out of bounds: 1; current size: 1",
e.getMessage());
}
}
@Test
public void delayFocusWindowTest() throws Exception {
iface.go(testPlaygroundPage);
// clicking; alert should be visible and window inactive
$("#openLinkInNewWindowDiv #linkInNewWindowDelay").click();
assertEquals(iface.getWindowCount(),1);
// Check that focusWindow properly waits for there to be enough windows before switching
iface.focusWindow(1);
assertEquals(iface.getWindowCount(),2);
}
@Test
public void executeJavaScriptTest() throws Exception {
// 0 arguments
String javascript = "alert('Alert!')";
iface.executeJavascript(javascript);
assertTrue(iface.wd.switchTo().alert().getText().contains("Alert!"));
iface.acceptDialog();
// 1 argument
javascript = "alert(arguments[0])";
String arg = "one";
iface.executeJavascript(javascript, arg);
assertTrue(iface.wd.switchTo().alert().getText().contains(arg));
iface.acceptDialog();
// multiple arguments
javascript = "alert(arguments[0] + ' and ' + arguments[1])";
String[] args = {"two", "three"};
iface.executeJavascript(javascript, args);
assertTrue(iface.wd.switchTo().alert().getText().contains(args[0]));
assertTrue(iface.wd.switchTo().alert().getText().contains(args[1]));
iface.acceptDialog();
Long toReturn = 12l;
javascript = "return " + toReturn + ";";
Long returnValue = (Long) (iface.executeJavascript(javascript));
assertEquals("Javascript return value incorrect. Expected: " + toReturn +
" Found: " + returnValue, toReturn, returnValue);
}
@Test
public void executeAsyncJavaScriptTest() throws Exception {
iface.wd.manage().timeouts().setScriptTimeout(1500, TimeUnit.MILLISECONDS);
// 0 arguments
long start = System.currentTimeMillis();
String javascript = "window.setTimeout(arguments[arguments.length - 1], 500);";
iface.executeAsyncJavascript(javascript);
// Assert that the test waited for at least 500ms
assertTrue(System.currentTimeMillis() >= start + 500);
// 1 argument
start = System.currentTimeMillis();
javascript = "window.setTimeout(arguments[arguments.length - 1], arguments[0]);";
iface.executeAsyncJavascript(javascript, 1000);
// Assert that the test waited for at least 1000ms
assertTrue(System.currentTimeMillis() >= start + 1000);
// multiple arguments
start = System.currentTimeMillis();
javascript = "window.setTimeout(arguments[arguments.length - 1], arguments[0]-arguments[1]);";
iface.executeAsyncJavascript(javascript, 1000, 400);
assertTrue(System.currentTimeMillis() >= start + 600);
String toReturn = "Hello World!";
javascript = "window.setTimeout(arguments[arguments.length-1] (\"Hello World!\"), 100);";
String returnValue = (String) (iface.executeAsyncJavascript(javascript));
assertEquals("Javascript return value incorrect. Expected: " + toReturn +
" Found: " + returnValue, toReturn, returnValue);
}
}