/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.zeppelin; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import java.io.File; import java.util.LinkedList; import java.util.List; import java.util.concurrent.TimeUnit; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.openqa.selenium.By; import org.openqa.selenium.ElementNotVisibleException; import org.openqa.selenium.Keys; import org.openqa.selenium.NoSuchElementException; import org.openqa.selenium.OutputType; import org.openqa.selenium.TakesScreenshot; import org.openqa.selenium.TimeoutException; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.chrome.ChromeDriver; import org.openqa.selenium.firefox.FirefoxBinary; import org.openqa.selenium.firefox.FirefoxDriver; import org.openqa.selenium.firefox.FirefoxProfile; import org.openqa.selenium.safari.SafariDriver; import org.openqa.selenium.support.ui.ExpectedConditions; import org.openqa.selenium.support.ui.FluentWait; import org.openqa.selenium.support.ui.Wait; import org.openqa.selenium.support.ui.WebDriverWait; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.base.Function; /** * Test Zeppelin with web browser. * * To test, ZeppelinServer should be running on port 8080 * On OSX, you'll need firefox 42.0 installed, then you can run with * * PATH=~/Applications/Firefox.app/Contents/MacOS/:$PATH CI="" \ * mvn -Dtest=org.apache.zeppelin.ZeppelinIT -Denforcer.skip=true \ * test -pl zeppelin-server * */ public class ZeppelinIT { private static final Logger LOG = LoggerFactory.getLogger(ZeppelinIT.class); private static final long MAX_BROWSER_TIMEOUT_SEC = 30; private static final long MAX_PARAGRAPH_TIMEOUT_SEC = 60; private WebDriver driver; @Before public void startUp() { if (!endToEndTestEnabled()) { return; } driver = WebDriverManager.getWebDriver(); } @After public void tearDown() { if (!endToEndTestEnabled()) { return; } driver.quit(); } String getParagraphXPath(int paragraphNo) { return "//div[@ng-controller=\"ParagraphCtrl\"][" + paragraphNo +"]"; } boolean waitForParagraph(final int paragraphNo, final String state) { By locator = By.xpath(getParagraphXPath(paragraphNo) + "//div[contains(@class, 'control')]//span[1][contains(.,'" + state + "')]"); WebElement element = pollingWait(locator, MAX_PARAGRAPH_TIMEOUT_SEC); return element.isDisplayed(); } boolean waitForText(final String txt, final By locator) { try { WebElement element = pollingWait(locator, MAX_BROWSER_TIMEOUT_SEC); return txt.equals(element.getText()); } catch (TimeoutException e) { return false; } } public WebElement pollingWait(final By locator, final long timeWait) { Wait<WebDriver> wait = new FluentWait<WebDriver>(driver) .withTimeout(timeWait, TimeUnit.SECONDS) .pollingEvery(1, TimeUnit.SECONDS) .ignoring(NoSuchElementException.class); return wait.until(new Function<WebDriver, WebElement>() { public WebElement apply(WebDriver driver) { return driver.findElement(locator); } }); }; boolean endToEndTestEnabled() { return null != System.getenv("CI"); } @Test public void testAngularDisplay() throws InterruptedException{ if (!endToEndTestEnabled()) { return; } try { createNewNote(); // wait for first paragraph's " READY " status text waitForParagraph(1, "READY"); /* * print angular template * %angular <div id='angularTestButton' ng-click='myVar=myVar+1'>BindingTest_{{myVar}}_</div> */ WebElement paragraph1Editor = driver.findElement(By.xpath(getParagraphXPath(1) + "//textarea")); paragraph1Editor.sendKeys("println" + Keys.chord(Keys.SHIFT, "9") + "\"" + Keys.chord(Keys.SHIFT, "5") + "angular <div id='angularTestButton' " + "ng" + Keys.chord(Keys.SUBTRACT) + "click='myVar=myVar+1'>" + "BindingTest_{{myVar}}_</div>\")"); paragraph1Editor.sendKeys(Keys.chord(Keys.SHIFT, Keys.ENTER)); waitForParagraph(1, "FINISHED"); // check expected text waitForText("BindingTest__", By.xpath( getParagraphXPath(1) + "//div[@id=\"angularTestButton\"]")); /* * Bind variable * z.angularBind("myVar", 1) */ assertEquals(1, driver.findElements(By.xpath(getParagraphXPath(2) + "//textarea")).size()); WebElement paragraph2Editor = driver.findElement(By.xpath(getParagraphXPath(2) + "//textarea")); paragraph2Editor.sendKeys("z.angularBind" + Keys.chord(Keys.SHIFT, "9") + "\"myVar\", 1)"); paragraph2Editor.sendKeys(Keys.chord(Keys.SHIFT, Keys.ENTER)); waitForParagraph(2, "FINISHED"); // check expected text waitForText("BindingTest_1_", By.xpath( getParagraphXPath(1) + "//div[@id=\"angularTestButton\"]")); /* * print variable * print("myVar="+z.angular("myVar")) */ WebElement paragraph3Editor = driver.findElement(By.xpath(getParagraphXPath(3) + "//textarea")); paragraph3Editor.sendKeys( "print" + Keys.chord(Keys.SHIFT, "9") + "\"myVar=\"" + Keys.chord(Keys.ADD) + "z.angular" + Keys.chord(Keys.SHIFT, "9") + "\"myVar\"))"); paragraph3Editor.sendKeys(Keys.chord(Keys.SHIFT, Keys.ENTER)); waitForParagraph(3, "FINISHED"); // check expected text waitForText("myVar=1", By.xpath( getParagraphXPath(3) + "//div[@ng-bind=\"paragraph.result.msg\"]")); /* * Click element */ driver.findElement(By.xpath( getParagraphXPath(1) + "//div[@id=\"angularTestButton\"]")).click(); // check expected text waitForText("BindingTest_2_", By.xpath( getParagraphXPath(1) + "//div[@id=\"angularTestButton\"]")); /* * Register watcher * z.angularWatch("myVar", (before:Object, after:Object, context:org.apache.zeppelin.interpreter.InterpreterContext) => { * z.run(2, context) * } */ WebElement paragraph4Editor = driver.findElement(By.xpath(getParagraphXPath(4) + "//textarea")); paragraph4Editor.sendKeys( "z.angularWatch" + Keys.chord(Keys.SHIFT, "9") + "\"myVar\", " + Keys.chord(Keys.SHIFT, "9") + "before:Object, after:Object, context:org.apache.zeppelin.interpreter.InterpreterContext)" + Keys.EQUALS + ">{ z.run" +Keys.chord(Keys.SHIFT, "9") + "2, context)}"); paragraph4Editor.sendKeys(Keys.chord(Keys.SHIFT, Keys.ENTER)); waitForParagraph(4, "FINISHED"); /* * Click element, again and see watcher works */ driver.findElement(By.xpath( getParagraphXPath(1) + "//div[@id=\"angularTestButton\"]")).click(); // check expected text waitForText("BindingTest_3_", By.xpath( getParagraphXPath(1) + "//div[@id=\"angularTestButton\"]")); waitForParagraph(3, "FINISHED"); // check expected text by watcher waitForText("myVar=3", By.xpath( getParagraphXPath(3) + "//div[@ng-bind=\"paragraph.result.msg\"]")); /* * Unbind * z.angularUnbind("myVar") */ WebElement paragraph5Editor = driver.findElement(By.xpath(getParagraphXPath(5) + "//textarea")); paragraph5Editor.sendKeys( "z.angularUnbind" + Keys.chord(Keys.SHIFT, "9") + "\"myVar\")"); paragraph5Editor.sendKeys(Keys.chord(Keys.SHIFT, Keys.ENTER)); waitForParagraph(5, "FINISHED"); // check expected text waitForText("BindingTest__", By.xpath(getParagraphXPath(1) + "//div[@id=\"angularTestButton\"]")); /* * Bind again and see rebind works. */ paragraph2Editor = driver.findElement(By.xpath(getParagraphXPath(2) + "//textarea")); paragraph2Editor.sendKeys(Keys.chord(Keys.SHIFT, Keys.ENTER)); waitForParagraph(2, "FINISHED"); // check expected text waitForText("BindingTest_1_", By.xpath(getParagraphXPath(1) + "//div[@id=\"angularTestButton\"]")); driver.findElement(By.xpath("//*[@id='main']/div//h3/span[1]/button[@tooltip='Remove the notebook']")) .sendKeys(Keys.ENTER); ZeppelinITUtils.sleep(1000, true); driver.findElement(By.xpath("//div[@class='modal-dialog'][contains(.,'delete this notebook')]" + "//div[@class='modal-footer']//button[contains(.,'OK')]")).click(); ZeppelinITUtils.sleep(100, true); System.out.println("testCreateNotebook Test executed"); } catch (ElementNotVisibleException e) { File scrFile = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE); } } private void createNewNote() { List<WebElement> notebookLinks = driver.findElements(By .xpath("//div[contains(@class, \"col-md-4\")]/div/ul/li")); List<String> notebookTitles = new LinkedList<String>(); for (WebElement el : notebookLinks) { notebookTitles.add(el.getText()); } WebElement createNoteLink = driver.findElement(By.xpath("//div[contains(@class, \"col-md-4\")]/div/h5/a[contains(.,'Create new note')]")); createNoteLink.click(); WebDriverWait block = new WebDriverWait(driver, MAX_BROWSER_TIMEOUT_SEC); WebElement modal = block.until(ExpectedConditions.visibilityOfElementLocated(By.id("noteNameModal"))); WebElement createNoteButton = modal.findElement(By.id("createNoteButton")); createNoteButton.click(); try { Thread.sleep(500); // wait for notebook list updated } catch (InterruptedException e) { } } }