From 45784f612e95129f7963471676e84b8deca87fa1 Mon Sep 17 00:00:00 2001 From: Damian Jansen Date: Wed, 21 Jan 2015 12:42:31 +1000 Subject: [PATCH 01/11] Wait for settings tab, be less wait-ish in waiting for it Remove superfluous waits Wait for the project version settings page to exist before moving to it Add logging as to exactly what the system is waiting for --- .../src/main/java/org/zanata/page/AbstractPage.java | 13 ++++++++----- .../zanata/page/projectversion/VersionBasePage.java | 1 + .../page/projectversion/VersionDocumentsPage.java | 2 +- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/functional-test/src/main/java/org/zanata/page/AbstractPage.java b/functional-test/src/main/java/org/zanata/page/AbstractPage.java index f6f2e8524e..d7b225f1a7 100644 --- a/functional-test/src/main/java/org/zanata/page/AbstractPage.java +++ b/functional-test/src/main/java/org/zanata/page/AbstractPage.java @@ -190,13 +190,14 @@ public boolean apply(WebDriver input) { * @return target WebElement */ public WebElement waitForWebElement(final By elementBy) { + log.info("Waiting for element ready {}", elementBy.toString()); waitForPageSilence(); return waitForAMoment().until(new Function() { @Override public WebElement apply(WebDriver input) { - WebElement targetElement = waitForElementExists(elementBy); + WebElement targetElement = getDriver().findElement(elementBy); if (!elementIsReady(targetElement)) { - throw new NoSuchElementException("Waiting for element"); + return null; } return targetElement; } @@ -211,14 +212,14 @@ public WebElement apply(WebDriver input) { */ public WebElement waitForWebElement(final WebElement parentElement, final By elementBy) { + log.info("Waiting for element ready {}", elementBy.toString()); waitForPageSilence(); return waitForAMoment().until(new Function() { @Override public WebElement apply(WebDriver input) { - WebElement targetElement = waitForElementExists(parentElement, - elementBy); + WebElement targetElement = parentElement.findElement(elementBy); if (!elementIsReady(targetElement)) { - throw new NoSuchElementException("Waiting for element"); + return null; } return targetElement; } @@ -233,6 +234,7 @@ public WebElement apply(WebDriver input) { * @return target WebElement */ public WebElement waitForElementExists(final By elementBy) { + log.info("Waiting for element exists {}", elementBy.toString()); waitForPageSilence(); return waitForAMoment().until(new Function() { @Override @@ -251,6 +253,7 @@ public WebElement apply(WebDriver input) { */ public WebElement waitForElementExists(final WebElement parentElement, final By elementBy) { + log.info("Waiting for element exists {}", elementBy.toString()); waitForPageSilence(); return waitForAMoment().until(new Function() { @Override diff --git a/functional-test/src/main/java/org/zanata/page/projectversion/VersionBasePage.java b/functional-test/src/main/java/org/zanata/page/projectversion/VersionBasePage.java index f8addd8514..9b8456e6e3 100644 --- a/functional-test/src/main/java/org/zanata/page/projectversion/VersionBasePage.java +++ b/functional-test/src/main/java/org/zanata/page/projectversion/VersionBasePage.java @@ -78,6 +78,7 @@ public VersionLanguagesPage gotoLanguageTab() { public VersionBasePage gotoSettingsTab() { log.info("Click Settings tab"); slightPause(); + waitForElementExists(By.id("settings")); clickWhenTabEnabled(waitForWebElement(By.id("settings_tab"))); waitForWebElement(By.id("settings")); return new VersionBasePage(getDriver()); diff --git a/functional-test/src/main/java/org/zanata/page/projectversion/VersionDocumentsPage.java b/functional-test/src/main/java/org/zanata/page/projectversion/VersionDocumentsPage.java index daaf57ec13..e79c925e81 100644 --- a/functional-test/src/main/java/org/zanata/page/projectversion/VersionDocumentsPage.java +++ b/functional-test/src/main/java/org/zanata/page/projectversion/VersionDocumentsPage.java @@ -65,7 +65,7 @@ public List getSourceDocumentNames() { public List apply(WebDriver input) { List fileNames = new ArrayList(); for (WebElement element : getDocumentsTabDocumentList()) { - fileNames.add(waitForWebElement(element, + fileNames.add(element.findElement( By.className("list__title")) .getText()); } From c1013ab796803b4d5a831b2ae0853b1f7398c1d0 Mon Sep 17 00:00:00 2001 From: Sean Flanigan Date: Wed, 21 Jan 2015 16:54:22 +1000 Subject: [PATCH 02/11] Initialise SMTP server as late as possible Otherwise it might be initialised in the Maven process rather than the test process. --- .../java/org/zanata/util/HasEmailRule.java | 35 +++++++++---------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/functional-test/src/test/java/org/zanata/util/HasEmailRule.java b/functional-test/src/test/java/org/zanata/util/HasEmailRule.java index c66394fe38..cb8528a497 100644 --- a/functional-test/src/test/java/org/zanata/util/HasEmailRule.java +++ b/functional-test/src/test/java/org/zanata/util/HasEmailRule.java @@ -27,6 +27,7 @@ import javax.mail.internet.MimeMultipart; +import org.junit.rules.ExternalResource; import org.junit.rules.TestRule; import org.junit.runner.Description; import org.junit.runners.model.Statement; @@ -41,29 +42,25 @@ * pahuang@redhat.com */ @Slf4j -public class HasEmailRule implements TestRule { - private static final Wiser wiser; +public class HasEmailRule extends ExternalResource { + private volatile static Wiser wiser; - static { - String port = PropertiesHolder.getProperty("smtp.port"); - wiser = new Wiser(Integer.parseInt(port)); - wiser.start(); - // NB we never call wiser.stop() because we want the email - // server to stay running for all tests + @Override + protected void before() throws Throwable { + super.before(); + if (HasEmailRule.wiser == null) { + String port = PropertiesHolder.getProperty("smtp.port"); + HasEmailRule.wiser = new Wiser(Integer.parseInt(port)); + HasEmailRule.wiser.start(); + // NB we never call wiser.stop() because we want the email + // server to stay running for all tests in this VM + } } @Override - public Statement apply(final Statement base, Description description) { - return new Statement() { - @Override - public void evaluate() throws Throwable { - try { - base.evaluate(); - } finally { - wiser.getMessages().clear(); - } - } - }; + protected void after() { + wiser.getMessages().clear(); + super.after(); } public List getMessages() { From fbdf66756b86fe75c991bc48c52d5d7aa43fce6a Mon Sep 17 00:00:00 2001 From: Sean Flanigan Date: Wed, 21 Jan 2015 17:21:41 +1000 Subject: [PATCH 03/11] Count all outstanding AJAX requests --- .../java/org/zanata/page/AbstractPage.java | 42 ++++++++++++------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/functional-test/src/main/java/org/zanata/page/AbstractPage.java b/functional-test/src/main/java/org/zanata/page/AbstractPage.java index f6f2e8524e..9d8a2d5e8e 100644 --- a/functional-test/src/main/java/org/zanata/page/AbstractPage.java +++ b/functional-test/src/main/java/org/zanata/page/AbstractPage.java @@ -46,7 +46,33 @@ public class AbstractPage { private final WebDriver driver; private final FluentWait ajaxWaitForSec; + static final String AJAX_COUNTER_SCRIPT = "(function(xhr) {\n" + + " if (xhr.active === undefined) {\n" + + " xhr.active = 0;\n" + + " var pt = xhr.prototype;\n" + + " pt._send = pt.send;\n" + + " pt.send = function() {\n" + + " XMLHttpRequest.active++;\n" + + " this._onreadystatechange = this.onreadystatechange;\n" + + " this.onreadystatechange = function(e) {\n" + + " if ( this.readyState == 4 ) {\n" + + " XMLHttpRequest.active--;\n" + + " }\n" + + " if ( this._onreadystatechange ) {\n" + + " var fn = this._onreadystatechange.handleEvent || this._onreadystatechange;\n" + + " fn.apply(this, arguments);\n" + + " }\n" + + " };\n" + + " this._send.apply(this, arguments);\n" + + " }\n" + + " }\n" + + "})(XMLHttpRequest);\n"; + public AbstractPage(final WebDriver driver) { + // FIXME avoid cast + JavascriptExecutor executor = (JavascriptExecutor) driver; + executor.executeScript(AJAX_COUNTER_SCRIPT); + PageFactory.initElements(new AjaxElementLocatorFactory(driver, 10), this); this.driver = driver; @@ -158,28 +184,16 @@ public void waitForPageSilence() { @Override public boolean apply(WebDriver input) { int ajaxCalls; - int jQueryCalls; - try { - jQueryCalls = Integer.parseInt( - ((JavascriptExecutor) getDriver()) - .executeScript("return jQuery.active") - .toString() - ); - } catch (WebDriverException jCall) { - jQueryCalls = 0; - } - try { ajaxCalls = Integer.parseInt( ((JavascriptExecutor) getDriver()) - .executeScript( - "return Ajax.activeRequestCount") + .executeScript("return XMLHttpRequest.active") .toString() ); } catch (WebDriverException jCall) { ajaxCalls = 0; } - return ajaxCalls + jQueryCalls == 0; + return ajaxCalls == 0; } }); } From 49b364dc6c6fda846b69d8302621c2d915380f8e Mon Sep 17 00:00:00 2001 From: Sean Flanigan Date: Thu, 22 Jan 2015 13:43:52 +1000 Subject: [PATCH 04/11] Include descriptions in some timeout exceptions --- .../java/org/zanata/page/AbstractPage.java | 99 ++++++++++++++----- .../main/java/org/zanata/page/BasePage.java | 58 ++++++----- .../main/java/org/zanata/page/CorePage.java | 39 ++++---- 3 files changed, 126 insertions(+), 70 deletions(-) diff --git a/functional-test/src/main/java/org/zanata/page/AbstractPage.java b/functional-test/src/main/java/org/zanata/page/AbstractPage.java index d73826319b..8a8e68fb7f 100644 --- a/functional-test/src/main/java/org/zanata/page/AbstractPage.java +++ b/functional-test/src/main/java/org/zanata/page/AbstractPage.java @@ -28,6 +28,7 @@ import org.hamcrest.Description; import org.hamcrest.Matcher; +import org.hamcrest.StringDescription; import org.openqa.selenium.*; import org.openqa.selenium.support.PageFactory; import org.openqa.selenium.support.pagefactory.AjaxElementLocatorFactory; @@ -103,6 +104,10 @@ public String getUrl() { return driver.getCurrentUrl(); } + protected void logWaiting(String msg) { + log.info("Waiting for {}", msg); + } + public FluentWait waitForAMoment() { return ajaxWaitForSec; } @@ -119,7 +124,7 @@ public void waitForPage(List elementBys) { } public Alert switchToAlert() { - return waitForAMoment().until(new Function() { + return waitForAMoment().withMessage("alert").until(new Function() { @Override public Alert apply(WebDriver driver) { try { @@ -131,16 +136,50 @@ public Alert apply(WebDriver driver) { }); } + /** + * @deprecated Use the overload which includes a message + */ + @Deprecated protected

P refreshPageUntil(P currentPage, Predicate predicate) { - waitForAMoment().until(predicate); + return refreshPageUntil(currentPage, predicate, null); + } + + /** + * @param currentPage + * @param predicate + * @param message description of predicate + * @param

+ * @return + */ + protected

P refreshPageUntil(P currentPage, + Predicate predicate, String message) { + waitForAMoment().withMessage(message).until(predicate); PageFactory.initElements(driver, currentPage); return currentPage; } + /** + * @deprecated Use the overload which includes a message + */ + @Deprecated protected

T refreshPageUntil(P currentPage, Function function) { - T done = waitForAMoment().until(function); + return refreshPageUntil(currentPage, function, null); + } + + /** + * + * @param currentPage + * @param function + * @param message description of function + * @param

+ * @param + * @return + */ + protected

T refreshPageUntil(P currentPage, + Function function, String message) { + T done = waitForAMoment().withMessage(message).until(function); PageFactory.initElements(driver, currentPage); return done; } @@ -156,22 +195,23 @@ protected

T refreshPageUntil(P currentPage, */ public void waitFor(final Callable callable, final Matcher matcher) { - waitForAMoment().until(new Predicate() { - @Override - public boolean apply(WebDriver input) { - try { - T result = callable.call(); - if (!matcher.matches(result)) { - matcher.describeMismatch(result, - new Description.NullDescription()); + waitForAMoment().withMessage(StringDescription.toString(matcher)).until( + new Predicate() { + @Override + public boolean apply(WebDriver input) { + try { + T result = callable.call(); + if (!matcher.matches(result)) { + matcher.describeMismatch(result, + new Description.NullDescription()); + } + return matcher.matches(result); + } catch (Exception e) { + log.warn("exception", e); + return false; + } } - return matcher.matches(result); - } catch (Exception e) { - log.warn("exception", e); - return false; - } - } - }); + }); } /** @@ -180,7 +220,7 @@ public boolean apply(WebDriver input) { */ public void waitForPageSilence() { // Wait for jQuery calls to be 0 - waitForAMoment().until(new Predicate() { + waitForAMoment().withMessage("page silence").until(new Predicate() { @Override public boolean apply(WebDriver input) { int ajaxCalls; @@ -204,9 +244,10 @@ public boolean apply(WebDriver input) { * @return target WebElement */ public WebElement waitForWebElement(final By elementBy) { - log.info("Waiting for element ready {}", elementBy.toString()); + String msg = "element ready " + elementBy; + logWaiting(msg); waitForPageSilence(); - return waitForAMoment().until(new Function() { + return waitForAMoment().withMessage(msg).until(new Function() { @Override public WebElement apply(WebDriver input) { WebElement targetElement = getDriver().findElement(elementBy); @@ -226,9 +267,10 @@ public WebElement apply(WebDriver input) { */ public WebElement waitForWebElement(final WebElement parentElement, final By elementBy) { - log.info("Waiting for element ready {}", elementBy.toString()); + String msg = "element ready " + elementBy; + logWaiting(msg); waitForPageSilence(); - return waitForAMoment().until(new Function() { + return waitForAMoment().withMessage(msg).until(new Function() { @Override public WebElement apply(WebDriver input) { WebElement targetElement = parentElement.findElement(elementBy); @@ -248,9 +290,11 @@ public WebElement apply(WebDriver input) { * @return target WebElement */ public WebElement waitForElementExists(final By elementBy) { - log.info("Waiting for element exists {}", elementBy.toString()); + String msg = "element exists " + elementBy; + logWaiting(msg); waitForPageSilence(); - return waitForAMoment().until(new Function() { + return waitForAMoment().withMessage(msg).until( + new Function() { @Override public WebElement apply(WebDriver input) { return getDriver().findElement(elementBy); @@ -267,9 +311,10 @@ public WebElement apply(WebDriver input) { */ public WebElement waitForElementExists(final WebElement parentElement, final By elementBy) { - log.info("Waiting for element exists {}", elementBy.toString()); + String msg = "element exists " + elementBy; + logWaiting(msg); waitForPageSilence(); - return waitForAMoment().until(new Function() { + return waitForAMoment().withMessage(msg).until(new Function() { @Override public WebElement apply(WebDriver input) { return parentElement.findElement(elementBy); diff --git a/functional-test/src/main/java/org/zanata/page/BasePage.java b/functional-test/src/main/java/org/zanata/page/BasePage.java index b896b431d4..0cc2833b0a 100644 --- a/functional-test/src/main/java/org/zanata/page/BasePage.java +++ b/functional-test/src/main/java/org/zanata/page/BasePage.java @@ -104,14 +104,16 @@ private void clickNavMenuItem(final WebElement menuItem) { getDriver().findElement(By.id("nav-main")) .findElement(By.tagName("a")).click(); } - waitForAMoment().until(new Predicate() { - @Override - public boolean apply(WebDriver input) { - return menuItem.isDisplayed(); - } - }); + waitForAMoment().withMessage("displayed: " + menuItem).until( + new Predicate() { + @Override + public boolean apply(WebDriver input) { + return menuItem.isDisplayed(); + } + }); // The notifications can sometimes get in the way - waitForAMoment().until(ExpectedConditions.elementToBeClickable(menuItem)); + waitForAMoment().withMessage("clickable: " + menuItem).until( + ExpectedConditions.elementToBeClickable(menuItem)); menuItem.click(); } @@ -263,8 +265,9 @@ public ProjectsPage submitSearch() { } public BasePage waitForSearchListContains(final String expected) { - log.info("Wait for Project search list contains {}", expected); - waitForAMoment().until(new Predicate() { + String msg = "Project search list contains " + expected; + logWaiting(msg); + waitForAMoment().withMessage(msg).until(new Predicate() { @Override public boolean apply(WebDriver input) { return getProjectSearchAutocompleteItems().contains(expected); @@ -281,29 +284,34 @@ public List getProjectSearchAutocompleteItems() { public ProjectVersionsPage clickSearchEntry(final String searchEntry) { log.info("Click Projects search result {}", searchEntry); + String msg = "search result " + searchEntry; WebElement searchItem = - waitForAMoment().until(new Function() { - @Override - public WebElement apply(WebDriver driver) { - List items = - WebElementUtil.getSearchAutocompleteResults( - driver, "general-search-form", - "projectAutocomplete"); - - for (WebElement item : items) { - if (item.getText().equals(searchEntry)) { - return item; + waitForAMoment().withMessage(msg).until( + new Function() { + @Override + public WebElement apply(WebDriver driver) { + List items = + WebElementUtil + .getSearchAutocompleteResults( + driver, + "general-search-form", + "projectAutocomplete"); + + for (WebElement item : items) { + if (item.getText().equals(searchEntry)) { + return item; + } + } + return null; } - } - return null; - } - }); + }); searchItem.click(); return new ProjectVersionsPage(getDriver()); } public void clickWhenTabEnabled(final WebElement tab) { - waitForAMoment().until(new Predicate() { + String msg = "Clickable tab: " + tab; + waitForAMoment().withMessage(msg).until(new Predicate() { @Override public boolean apply(WebDriver input) { waitForPageSilence(); diff --git a/functional-test/src/main/java/org/zanata/page/CorePage.java b/functional-test/src/main/java/org/zanata/page/CorePage.java index 3e8d2aab58..a5d287dd51 100644 --- a/functional-test/src/main/java/org/zanata/page/CorePage.java +++ b/functional-test/src/main/java/org/zanata/page/CorePage.java @@ -81,7 +81,7 @@ protected void clickAndExpectErrors(WebElement button) { public boolean apply(WebDriver input) { return getErrors().size() > 0; } - }); + }, "errors > 0"); } public List getErrors() { @@ -115,7 +115,7 @@ public List getErrors(final int expectedNumber) { public boolean apply(WebDriver input) { return getErrors().size() == expectedNumber; } - }); + }, "errors = " + expectedNumber); return getErrors(); } @@ -126,8 +126,9 @@ public boolean apply(WebDriver input) { * @return The full list of visible errors */ public List expectError(final String expected) { - log.info("Expect error {}", expected); - waitForAMoment().until(new Predicate() { + String msg = "expected error: " + expected; + logWaiting(msg); + waitForAMoment().withMessage(msg).until(new Predicate() { @Override public boolean apply(WebDriver input) { return getErrors().contains(expected); @@ -144,20 +145,22 @@ public String getNotificationMessage() { } public boolean expectNotification(final String notification) { - log.info("Wait for notification {}", notification); - return waitForAMoment().until(new Function() { - @Override - public Boolean apply(WebDriver driver) { - List messages = getDriver() - .findElement(By.id("messages")) - .findElements(By.tagName("li")); - List notifications = new ArrayList(); - for (WebElement message : messages) { - notifications.add(message.getText().trim()); - } - return notifications.contains(notification); - } - }); + String msg = "notification " + notification; + logWaiting(msg); + return waitForAMoment().withMessage(msg).until( + new Function() { + @Override + public Boolean apply(WebDriver driver) { + List messages = getDriver() + .findElement(By.id("messages")) + .findElements(By.tagName("li")); + List notifications = new ArrayList(); + for (WebElement message : messages) { + notifications.add(message.getText().trim()); + } + return notifications.contains(notification); + } + }); } public void assertNoCriticalErrors() { From 10969c060592cca3933ea982ae65dc5fa90b396f Mon Sep 17 00:00:00 2001 From: Damian Jansen Date: Fri, 23 Jan 2015 15:33:11 +1000 Subject: [PATCH 05/11] Stabilise some tab related test functions --- .../page/dashboard/DashboardBasePage.java | 8 +++++++ .../zanata/page/groups/VersionGroupPage.java | 14 +++++++---- .../zanata/page/projects/ProjectBasePage.java | 10 ++++++++ .../page/projectversion/VersionBasePage.java | 23 ++++++++++++------- .../projectversion/VersionLanguagesPage.java | 4 ++-- 5 files changed, 45 insertions(+), 14 deletions(-) diff --git a/functional-test/src/main/java/org/zanata/page/dashboard/DashboardBasePage.java b/functional-test/src/main/java/org/zanata/page/dashboard/DashboardBasePage.java index e2a89fb94c..9f3c672763 100644 --- a/functional-test/src/main/java/org/zanata/page/dashboard/DashboardBasePage.java +++ b/functional-test/src/main/java/org/zanata/page/dashboard/DashboardBasePage.java @@ -35,6 +35,11 @@ public class DashboardBasePage extends BasePage { private By activityTab = By.id("activity_tab"); private By projectsTab = By.id("projects_tab"); private By settingsTab = By.id("settings_tab"); + + private By activityTabBody = By.id("activity"); + private By projectsTabBody = By.id("projects"); + private By settingsTabBody = By.id("settings"); + private By settingsAccountTab = By.id("account_tab"); private By settingsProfileTab = By.id("profile_tab"); private By settingsClientTab = By.id("client_tab"); @@ -62,6 +67,7 @@ public String getUserFullName() { public DashboardActivityTab gotoActivityTab() { log.info("Click Activity tab"); + waitForElementExists(activityTabBody); clickWhenTabEnabled(waitForWebElement(activityTab)); return new DashboardActivityTab(getDriver()); } @@ -75,12 +81,14 @@ public boolean activityTabIsSelected() { public DashboardProjectsTab gotoProjectsTab() { log.info("Click Projects tab"); + waitForElementExists(projectsTabBody); clickWhenTabEnabled(waitForWebElement(projectsTab)); return new DashboardProjectsTab(getDriver()); } public DashboardBasePage goToSettingsTab() { log.info("Click Settings tab"); + waitForElementExists(settingsTabBody); clickWhenTabEnabled(waitForWebElement(settingsTab)); return new DashboardBasePage(getDriver()); } diff --git a/functional-test/src/main/java/org/zanata/page/groups/VersionGroupPage.java b/functional-test/src/main/java/org/zanata/page/groups/VersionGroupPage.java index 2473f3b491..015a3837a5 100644 --- a/functional-test/src/main/java/org/zanata/page/groups/VersionGroupPage.java +++ b/functional-test/src/main/java/org/zanata/page/groups/VersionGroupPage.java @@ -57,6 +57,12 @@ public class VersionGroupPage extends BasePage { private By projectsTab = By.id("projects_tab"); private By maintainersTab = By.id("maintainers_tab"); private By settingsTab = By.id("settings_tab"); + + private By languagesTabBody = By.id("languages"); + private By projectsTabBody = By.id("projects"); + private By maintainersTabBody = By.id("maintainers"); + private By settingsTabBody = By.id("settings"); + private By settingsLanguagesTab = By.id("settings-languages_tab"); public VersionGroupPage(final WebDriver driver) { @@ -146,10 +152,6 @@ public VersionLanguagesPage clickOnProjectVersionLinkOnRow(int row) { return new VersionLanguagesPage(getDriver()); } - public void clickOnTab(String tabId) { - waitForWebElement(By.id(tabId)).click(); - } - public VersionGroupPage clickAddProjectVersionsButton() { log.info("Click Add Project Version"); // parent @@ -160,24 +162,28 @@ public VersionGroupPage clickAddProjectVersionsButton() { public VersionGroupPage clickLanguagesTab() { log.info("Click Languages tab"); + waitForElementExists(languagesTabBody); clickWhenTabEnabled(waitForWebElement(languagesTab)); return new VersionGroupPage(getDriver()); } public VersionGroupPage clickProjectsTab() { log.info("Click Projects tab"); + waitForElementExists(projectsTabBody); clickWhenTabEnabled(waitForWebElement(projectsTab)); return new VersionGroupPage(getDriver()); } public VersionGroupPage clickMaintainersTab() { log.info("Click Maintainers tab"); + waitForElementExists(maintainersTabBody); clickWhenTabEnabled(waitForWebElement(maintainersTab)); return new VersionGroupPage(getDriver()); } public VersionGroupPage clickSettingsTab() { log.info("Click Settings tab"); + waitForElementExists(settingsTabBody); clickWhenTabEnabled(waitForWebElement(settingsTab)); return new VersionGroupPage(getDriver()); } diff --git a/functional-test/src/main/java/org/zanata/page/projects/ProjectBasePage.java b/functional-test/src/main/java/org/zanata/page/projects/ProjectBasePage.java index 7ad056b2e8..e8a8cd52e9 100644 --- a/functional-test/src/main/java/org/zanata/page/projects/ProjectBasePage.java +++ b/functional-test/src/main/java/org/zanata/page/projects/ProjectBasePage.java @@ -44,6 +44,12 @@ public class ProjectBasePage extends BasePage { private By maintainersTab = By.id("maintainers_tab"); private By aboutTab = By.id("about_tab"); private By settingsTab = By.id("settings_tab"); + + private By versionsTabBody = By.id("versions"); + private By maintainersTabBody = By.id("maintainers"); + private By aboutTabBody = By.id("about"); + private By settingsTabBody = By.id("settings"); + private By settingsGeneralTab = By.id("settings-general_tab"); private By settingsPermissionTab = By.id("settings-permissions_tab"); private By settingsTranslationTab = By.id("settings-translation_tab"); @@ -65,6 +71,7 @@ public String getProjectName() { public ProjectVersionsPage gotoVersionsTab() { log.info("Click Versions tab"); + waitForElementExists(versionsTabBody); clickWhenTabEnabled(waitForWebElement(versionsTab)); waitForWebElement(By.id("versions")); return new ProjectVersionsPage(getDriver()); @@ -72,6 +79,7 @@ public ProjectVersionsPage gotoVersionsTab() { public ProjectMaintainersPage gotoMaintainersTab() { log.info("Click Maintainers tab"); + waitForElementExists(maintainersTabBody); clickWhenTabEnabled(waitForWebElement(maintainersTab)); waitForWebElement(By.id("maintainers")); return new ProjectMaintainersPage(getDriver()); @@ -79,6 +87,7 @@ public ProjectMaintainersPage gotoMaintainersTab() { public ProjectAboutPage gotoAboutTab() { log.info("Click About tab"); + waitForElementExists(aboutTabBody); clickWhenTabEnabled(waitForWebElement(aboutTab)); waitForWebElement(By.id("about")); return new ProjectAboutPage(getDriver()); @@ -91,6 +100,7 @@ public boolean settingsTabIsDisplayed() { public ProjectBasePage gotoSettingsTab() { log.info("Click Settings tab"); + waitForElementExists(settingsTabBody); clickWhenTabEnabled(waitForWebElement(settingsTab)); waitForWebElement(settingsTab); return new ProjectBasePage(getDriver()); diff --git a/functional-test/src/main/java/org/zanata/page/projectversion/VersionBasePage.java b/functional-test/src/main/java/org/zanata/page/projectversion/VersionBasePage.java index 9b8456e6e3..102166ca6b 100644 --- a/functional-test/src/main/java/org/zanata/page/projectversion/VersionBasePage.java +++ b/functional-test/src/main/java/org/zanata/page/projectversion/VersionBasePage.java @@ -33,13 +33,18 @@ @Slf4j public class VersionBasePage extends BasePage { - private By settingsTab = By.id("settings_tab"); private By settingsGeneralTab = By.id("settings-general_tab"); private By settingsLanguagesTab = By.id("settings-languages_tab"); private By settingsDocumentsTab = By.id("settings-documents_tab"); private By settingsTranslationTab = By.id("settings-translation_tab"); - private By documentsTab = By.id("documents"); - private By languageTab = By.id("languages"); + private By documentsTab = By.id("documents_tab"); + private By languageTab = By.id("languages_tab"); + private By settingsTab = By.id("settings_tab"); + + private By documentsTabBody = By.id("documents"); + private By languageTabBody = By.id("languages"); + private By settingsTabBody = By.id("settings"); + private By versionInfo = By.id("version-info"); private By versionPage = By.id("version-page"); @@ -63,14 +68,16 @@ public ProjectVersionsPage clickProjectLink(String projectName) { public VersionDocumentsPage gotoDocumentTab() { log.info("Click Documents tab"); - clickWhenTabEnabled(waitForWebElement(By.id("documents_tab"))); + waitForElementExists(documentsTabBody); + clickWhenTabEnabled(waitForWebElement(documentsTab)); waitForWebElement(By.id("documents")); return new VersionDocumentsPage(getDriver()); } public VersionLanguagesPage gotoLanguageTab() { log.info("Click Languages tab"); - clickWhenTabEnabled(waitForWebElement(By.id("languages_tab"))); + waitForElementExists(languageTabBody); + clickWhenTabEnabled(waitForWebElement(languageTab)); waitForWebElement(By.id("languages")); return new VersionLanguagesPage(getDriver()); } @@ -78,9 +85,9 @@ public VersionLanguagesPage gotoLanguageTab() { public VersionBasePage gotoSettingsTab() { log.info("Click Settings tab"); slightPause(); - waitForElementExists(By.id("settings")); - clickWhenTabEnabled(waitForWebElement(By.id("settings_tab"))); - waitForWebElement(By.id("settings")); + waitForElementExists(settingsTabBody); + clickWhenTabEnabled(waitForWebElement(settingsTab)); + waitForWebElement(settingsTabBody); return new VersionBasePage(getDriver()); } diff --git a/functional-test/src/main/java/org/zanata/page/projectversion/VersionLanguagesPage.java b/functional-test/src/main/java/org/zanata/page/projectversion/VersionLanguagesPage.java index 1e357a71b7..c4326c978f 100644 --- a/functional-test/src/main/java/org/zanata/page/projectversion/VersionLanguagesPage.java +++ b/functional-test/src/main/java/org/zanata/page/projectversion/VersionLanguagesPage.java @@ -58,8 +58,8 @@ private List getLanguageTabLocaleList() { private List getLanguageTabDocumentList() { log.info("Query documents list"); - return waitForWebElement(languageDocumentList) - .findElement(By.className("list--stats")) + return waitForWebElement(waitForElementExists(languageDocumentList), + By.className("list--stats")) .findElements(documentListItem); } From b11149002adf4e092d71b5136fecb721f42dab4e Mon Sep 17 00:00:00 2001 From: Damian Jansen Date: Tue, 20 Jan 2015 14:20:59 +1000 Subject: [PATCH 06/11] Fix test element focus issues In some cases, element.blur works more reliably than a page click --- .../src/main/java/org/zanata/page/CorePage.java | 9 +++++++++ .../java/org/zanata/page/account/EditProfilePage.java | 4 ++-- .../java/org/zanata/page/account/RegisterPage.java | 2 +- .../projects/projectsettings/ProjectGeneralTab.java | 4 ++-- .../zanata/page/projectversion/CreateVersionPage.java | 2 +- .../java/org/zanata/feature/account/RegisterTest.java | 2 +- .../zanata/feature/account/UsernameValidationTest.java | 2 +- .../projectversion/CreateProjectVersionTest.java | 10 +++++----- 8 files changed, 22 insertions(+), 13 deletions(-) diff --git a/functional-test/src/main/java/org/zanata/page/CorePage.java b/functional-test/src/main/java/org/zanata/page/CorePage.java index a5d287dd51..a9e0dce373 100644 --- a/functional-test/src/main/java/org/zanata/page/CorePage.java +++ b/functional-test/src/main/java/org/zanata/page/CorePage.java @@ -196,6 +196,15 @@ public void defocus() { } } + /** + * Force the blur 'unfocus' process on a given element + */ + public void defocus(By elementBy) { + log.info("Force unfocus"); + WebElement element = getDriver().findElement(elementBy); + ((JavascriptExecutor) getDriver()).executeScript("arguments[0].blur()", element); + } + /* The system sometimes moves too fast for the Ajax pages, so provide a * pause */ diff --git a/functional-test/src/main/java/org/zanata/page/account/EditProfilePage.java b/functional-test/src/main/java/org/zanata/page/account/EditProfilePage.java index f55adc9acd..addb2d5246 100644 --- a/functional-test/src/main/java/org/zanata/page/account/EditProfilePage.java +++ b/functional-test/src/main/java/org/zanata/page/account/EditProfilePage.java @@ -47,7 +47,7 @@ public EditProfilePage enterName(String name) { log.info("Enter name {}", name); waitForWebElement(nameField).clear(); waitForWebElement(nameField).sendKeys(name); - defocus(); + defocus(nameField); return new EditProfilePage(getDriver()); } @@ -62,7 +62,7 @@ public EditProfilePage enterEmail(String email) { log.info("Enter email {}", email); waitForWebElement(emailField).clear(); waitForWebElement(emailField).sendKeys(email); - defocus(); + defocus(emailField); return new EditProfilePage(getDriver()); } diff --git a/functional-test/src/main/java/org/zanata/page/account/RegisterPage.java b/functional-test/src/main/java/org/zanata/page/account/RegisterPage.java index 110960e899..f78fbc8d66 100644 --- a/functional-test/src/main/java/org/zanata/page/account/RegisterPage.java +++ b/functional-test/src/main/java/org/zanata/page/account/RegisterPage.java @@ -53,7 +53,7 @@ public class RegisterPage extends CorePage { private By nameField = By.id("loginForm:name"); private By emailField = By.id("loginForm:emailField:email"); - private By usernameField = By.id("loginForm:usernameField:username"); + public By usernameField = By.id("loginForm:usernameField:username"); private By passwordField = By.id("loginForm:passwordField:password"); private By signUpButton = By.xpath("//input[@value='Sign Up']"); private By showHideToggleButton = By.className("js-form-password-toggle"); diff --git a/functional-test/src/main/java/org/zanata/page/projects/projectsettings/ProjectGeneralTab.java b/functional-test/src/main/java/org/zanata/page/projects/projectsettings/ProjectGeneralTab.java index f483080652..f5889d847f 100644 --- a/functional-test/src/main/java/org/zanata/page/projects/projectsettings/ProjectGeneralTab.java +++ b/functional-test/src/main/java/org/zanata/page/projects/projectsettings/ProjectGeneralTab.java @@ -73,7 +73,7 @@ public ProjectGeneralTab enterProjectName(final String projectName) { log.info("Enter project name {}", projectName); waitForWebElement(projectNameField).clear(); waitForWebElement(projectNameField).sendKeys(projectName); - defocus(); + defocus(projectNameField); return new ProjectGeneralTab(getDriver()); } @@ -86,7 +86,7 @@ public ProjectGeneralTab enterDescription(String projectDescription) { log.info("Enter project description {}", projectDescription); waitForWebElement(descriptionField).clear(); waitForWebElement(descriptionField).sendKeys(projectDescription); - defocus(); + defocus(descriptionField); return new ProjectGeneralTab(getDriver()); } diff --git a/functional-test/src/main/java/org/zanata/page/projectversion/CreateVersionPage.java b/functional-test/src/main/java/org/zanata/page/projectversion/CreateVersionPage.java index 77f521b454..0c5a880253 100644 --- a/functional-test/src/main/java/org/zanata/page/projectversion/CreateVersionPage.java +++ b/functional-test/src/main/java/org/zanata/page/projectversion/CreateVersionPage.java @@ -37,7 +37,7 @@ public class CreateVersionPage extends BasePage { "must start and end with letter or number, and contain only " + "letters, numbers, periods, underscores and hyphens."; - private By projectVersionID = By.id("create-version-form:slugField:slug"); + public By projectVersionID = By.id("create-version-form:slugField:slug"); private By projectTypeSelection = By.id("create-version-form:project-type"); private By saveButton = By.id("create-version-form:button-create"); private By copyFromPreviousVersionChk = By.id("create-version-form:copy-from-version"); diff --git a/functional-test/src/test/java/org/zanata/feature/account/RegisterTest.java b/functional-test/src/test/java/org/zanata/feature/account/RegisterTest.java index 22dcd0b2c5..a4eb239472 100644 --- a/functional-test/src/test/java/org/zanata/feature/account/RegisterTest.java +++ b/functional-test/src/test/java/org/zanata/feature/account/RegisterTest.java @@ -130,7 +130,7 @@ public void usernamePreExisting() throws Exception { RegisterPage registerPage = homePage .goToRegistration() .enterUserName("admin"); - registerPage.defocus(); + registerPage.defocus(registerPage.usernameField); assertThat(registerPage.expectError( RegisterPage.USERNAME_UNAVAILABLE_ERROR)) diff --git a/functional-test/src/test/java/org/zanata/feature/account/UsernameValidationTest.java b/functional-test/src/test/java/org/zanata/feature/account/UsernameValidationTest.java index 435fc1facd..cccf6daf24 100644 --- a/functional-test/src/test/java/org/zanata/feature/account/UsernameValidationTest.java +++ b/functional-test/src/test/java/org/zanata/feature/account/UsernameValidationTest.java @@ -48,7 +48,7 @@ public void usernameCharacterValidation() throws Exception { .goToHome() .goToRegistration() .enterUserName("user|name"); - registerPage.defocus(); + registerPage.defocus(registerPage.usernameField); assertThat(registerPage.expectError( RegisterPage.USERNAME_VALIDATION_ERROR)) diff --git a/functional-test/src/test/java/org/zanata/feature/projectversion/CreateProjectVersionTest.java b/functional-test/src/test/java/org/zanata/feature/projectversion/CreateProjectVersionTest.java index a6d3f7f2db..2022c74e18 100644 --- a/functional-test/src/test/java/org/zanata/feature/projectversion/CreateProjectVersionTest.java +++ b/functional-test/src/test/java/org/zanata/feature/projectversion/CreateProjectVersionTest.java @@ -85,7 +85,7 @@ public void idFieldMustNotBeEmpty() throws Exception { .goToProjectByName("about fedora") .clickCreateVersionLink() .inputVersionId(""); - createVersionPage.defocus(); + createVersionPage.defocus(createVersionPage.projectVersionID); assertThat(createVersionPage.getErrors()) .contains("value is required") @@ -101,7 +101,7 @@ public void idStartsAndEndsWithAlphanumeric() throws Exception { .goToProjectByName("about fedora") .clickCreateVersionLink() .inputVersionId("-A"); - createVersionPage.defocus(); + createVersionPage.defocus(createVersionPage.projectVersionID); assertThat(createVersionPage.expectError( CreateVersionPage.VALIDATION_ERROR)) @@ -109,7 +109,7 @@ public void idStartsAndEndsWithAlphanumeric() throws Exception { .as("The input is rejected"); createVersionPage = createVersionPage.inputVersionId("B-"); - createVersionPage.defocus(); + createVersionPage.defocus(createVersionPage.projectVersionID); assertThat(createVersionPage.expectError( CreateVersionPage.VALIDATION_ERROR)) @@ -117,7 +117,7 @@ public void idStartsAndEndsWithAlphanumeric() throws Exception { .as("The input is rejected"); createVersionPage = createVersionPage.inputVersionId("_C_"); - createVersionPage.defocus(); + createVersionPage.defocus(createVersionPage.projectVersionID); createVersionPage = createVersionPage.waitForNumErrors(1); assertThat(createVersionPage.expectError( @@ -126,7 +126,7 @@ public void idStartsAndEndsWithAlphanumeric() throws Exception { .as("The input is rejected"); createVersionPage = createVersionPage.inputVersionId("A-B_C"); - createVersionPage.defocus(); + createVersionPage.defocus(createVersionPage.projectVersionID); createVersionPage = createVersionPage.waitForNumErrors(0); assertThat(createVersionPage.getErrors()) From caee3adbe1e8e564743c97d7d2d44efa103f47b2 Mon Sep 17 00:00:00 2001 From: Sean Flanigan Date: Fri, 23 Jan 2015 18:06:37 +1000 Subject: [PATCH 07/11] Add TestLogger so that we can see in the log which tests have run or failed --- functional-test/pom.xml | 2 +- .../test/java/org/zanata/util/TestLogger.java | 61 +++++++++++++++++++ 2 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 functional-test/src/test/java/org/zanata/util/TestLogger.java diff --git a/functional-test/pom.xml b/functional-test/pom.xml index 3a1345b92c..60a78fb901 100644 --- a/functional-test/pom.xml +++ b/functional-test/pom.xml @@ -591,7 +591,7 @@ listener - org.zanata.util.ScreenshotEnabledTestRunListener,org.zanata.util.FeatureInventoryRecorder + org.zanata.util.ScreenshotEnabledTestRunListener,org.zanata.util.FeatureInventoryRecorder,org.zanata.util.TestLogger diff --git a/functional-test/src/test/java/org/zanata/util/TestLogger.java b/functional-test/src/test/java/org/zanata/util/TestLogger.java new file mode 100644 index 0000000000..317c055450 --- /dev/null +++ b/functional-test/src/test/java/org/zanata/util/TestLogger.java @@ -0,0 +1,61 @@ +/* + * Copyright 2014, Red Hat, Inc. and individual contributors as indicated by the + * @author tags. See the copyright.txt file in the distribution for a full + * listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 2.1 of the License, or (at your option) + * any later version. + * + * This software 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 Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this software; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA, or see the FSF + * site: http://www.fsf.org. + */ +package org.zanata.util; + +import lombok.extern.slf4j.Slf4j; + +import org.junit.runner.Description; +import org.junit.runner.notification.Failure; +import org.junit.runner.notification.RunListener; + +/** + * @author Sean Flanigan + * sflaniga@redhat.com + */ +@Slf4j +public class TestLogger extends RunListener { + @Override + public void testStarted(Description description) throws Exception { + log.info("Test {} starting", description); + } + + @Override + public void testFinished(Description description) throws Exception { + log.info("Test {} finished", description); + } + + @Override + public void testFailure(Failure failure) throws Exception { + log.error("FAILED test " + failure, failure.getException()); + } + + @Override + public void testAssumptionFailure(Failure failure) { + log.error("FAILED ASSUMPTION in test " + failure, + failure.getException()); + } + + @Override + public void testIgnored(Description description) throws Exception { + log.error("Test {} IGNORED", description); + } + +} From e81f45cb326ee4acde633edebba24a6285ecbb64 Mon Sep 17 00:00:00 2001 From: Sean Flanigan Date: Fri, 23 Jan 2015 12:22:21 +1000 Subject: [PATCH 08/11] Fix AJAX counter --- functional-test/pom.xml | 3 + .../java/org/zanata/page/AbstractPage.java | 69 ++++++++----------- .../org/zanata/page/webtrans/EditorPage.java | 10 +++ .../java/org/zanata/util/WebElementUtil.java | 1 + .../src/test/resources/conf/standalone.xml | 1 + .../resources/conf/standalone_wildfly.xml | 1 + .../org/zanata/action/AjaxCounterBean.java | 65 +++++++++++++++++ .../zanata/webtrans/public/Application.xhtml | 1 + .../webapp/WEB-INF/template/template.xhtml | 1 + .../webapp/WEB-INF/template/template_2x.xhtml | 1 + .../WEB-INF/template/template_nobanner.xhtml | 1 + zanata-war/src/main/webapp/app/index.html | 1 + 12 files changed, 116 insertions(+), 39 deletions(-) create mode 100644 zanata-war/src/main/java/org/zanata/action/AjaxCounterBean.java diff --git a/functional-test/pom.xml b/functional-test/pom.xml index 60a78fb901..5eae89d6d6 100644 --- a/functional-test/pom.xml +++ b/functional-test/pom.xml @@ -518,6 +518,9 @@ cargo-maven2-plugin + + true + ${cargo.installation} diff --git a/functional-test/src/main/java/org/zanata/page/AbstractPage.java b/functional-test/src/main/java/org/zanata/page/AbstractPage.java index 8a8e68fb7f..18a042ff0d 100644 --- a/functional-test/src/main/java/org/zanata/page/AbstractPage.java +++ b/functional-test/src/main/java/org/zanata/page/AbstractPage.java @@ -33,6 +33,7 @@ import org.openqa.selenium.support.PageFactory; import org.openqa.selenium.support.pagefactory.AjaxElementLocatorFactory; import org.openqa.selenium.support.ui.FluentWait; +import org.zanata.util.ShortString; import org.zanata.util.WebElementUtil; import com.google.common.base.Function; @@ -47,33 +48,7 @@ public class AbstractPage { private final WebDriver driver; private final FluentWait ajaxWaitForSec; - static final String AJAX_COUNTER_SCRIPT = "(function(xhr) {\n" + - " if (xhr.active === undefined) {\n" + - " xhr.active = 0;\n" + - " var pt = xhr.prototype;\n" + - " pt._send = pt.send;\n" + - " pt.send = function() {\n" + - " XMLHttpRequest.active++;\n" + - " this._onreadystatechange = this.onreadystatechange;\n" + - " this.onreadystatechange = function(e) {\n" + - " if ( this.readyState == 4 ) {\n" + - " XMLHttpRequest.active--;\n" + - " }\n" + - " if ( this._onreadystatechange ) {\n" + - " var fn = this._onreadystatechange.handleEvent || this._onreadystatechange;\n" + - " fn.apply(this, arguments);\n" + - " }\n" + - " };\n" + - " this._send.apply(this, arguments);\n" + - " }\n" + - " }\n" + - "})(XMLHttpRequest);\n"; - public AbstractPage(final WebDriver driver) { - // FIXME avoid cast - JavascriptExecutor executor = (JavascriptExecutor) driver; - executor.executeScript(AJAX_COUNTER_SCRIPT); - PageFactory.initElements(new AjaxElementLocatorFactory(driver, 10), this); this.driver = driver; @@ -215,25 +190,41 @@ public boolean apply(WebDriver input) { } /** - * Wait for jQuery and Ajax calls to be 0 - * If either are not defined, they can be assumed to be 0. + * Normally a page has no outstanding ajax requests when it has + * finished an operation, but some pages use long polling to + * "push" changes to the user, eg for the editor's event service. + * @return + */ + protected int getExpectedBackgroundRequests() { + return 0; + } + + /** + * Wait for any AJAX calls to return. */ public void waitForPageSilence() { - // Wait for jQuery calls to be 0 + // Wait for AJAX calls to be 0 waitForAMoment().withMessage("page silence").until(new Predicate() { @Override public boolean apply(WebDriver input) { - int ajaxCalls; - try { - ajaxCalls = Integer.parseInt( - ((JavascriptExecutor) getDriver()) - .executeScript("return XMLHttpRequest.active") - .toString() - ); - } catch (WebDriverException jCall) { - ajaxCalls = 0; + Long ajaxCalls = (Long) ((JavascriptExecutor) getDriver()) + .executeScript( + "return XMLHttpRequest.active"); + if (ajaxCalls == null) { + if (log.isWarnEnabled()) { + String url = getDriver().getCurrentUrl(); + String pageSource = ShortString.shorten(getDriver().getPageSource(), 2000); + log.warn("XMLHttpRequest.active is null. URL: {}\nPartial page source follows:\n{}", url, pageSource); + } + return true; + } + if (ajaxCalls < 0) { + throw new RuntimeException("XMLHttpRequest.active " + + "is negative. Please ensure that " + + "AjaxCounterBean's script is run before " + + "any AJAX requests."); } - return ajaxCalls == 0; + return ajaxCalls <= getExpectedBackgroundRequests(); } }); } diff --git a/functional-test/src/main/java/org/zanata/page/webtrans/EditorPage.java b/functional-test/src/main/java/org/zanata/page/webtrans/EditorPage.java index 7b42b7241f..5185878ecf 100644 --- a/functional-test/src/main/java/org/zanata/page/webtrans/EditorPage.java +++ b/functional-test/src/main/java/org/zanata/page/webtrans/EditorPage.java @@ -94,6 +94,16 @@ public boolean apply(WebDriver input) { return new EditorPage(getDriver()); } + /** + * There is usually a long poll waiting for GWTEventService events + * from the server. + * @return + */ + @Override + protected int getExpectedBackgroundRequests() { + return 1; + } + /** * First row is header: SourceTerm, TargetTerm, Action, Details. * diff --git a/functional-test/src/main/java/org/zanata/util/WebElementUtil.java b/functional-test/src/main/java/org/zanata/util/WebElementUtil.java index 85b67b13a9..fe45c9c23c 100644 --- a/functional-test/src/main/java/org/zanata/util/WebElementUtil.java +++ b/functional-test/src/main/java/org/zanata/util/WebElementUtil.java @@ -149,6 +149,7 @@ public static FluentWait waitForSeconds(WebDriver webDriver, .withTimeout(durationInSec, SECONDS) .pollingEvery(1, SECONDS) .ignoring(NoSuchElementException.class, + // TODO is ignoring this safe? StaleElementReferenceException.class); } diff --git a/functional-test/src/test/resources/conf/standalone.xml b/functional-test/src/test/resources/conf/standalone.xml index fcab1ca581..aaccd519ea 100644 --- a/functional-test/src/test/resources/conf/standalone.xml +++ b/functional-test/src/test/resources/conf/standalone.xml @@ -27,6 +27,7 @@ + diff --git a/functional-test/src/test/resources/conf/standalone_wildfly.xml b/functional-test/src/test/resources/conf/standalone_wildfly.xml index cb2bb3595b..8a732e530b 100644 --- a/functional-test/src/test/resources/conf/standalone_wildfly.xml +++ b/functional-test/src/test/resources/conf/standalone_wildfly.xml @@ -27,6 +27,7 @@ + diff --git a/zanata-war/src/main/java/org/zanata/action/AjaxCounterBean.java b/zanata-war/src/main/java/org/zanata/action/AjaxCounterBean.java new file mode 100644 index 0000000000..8cc8df0c4f --- /dev/null +++ b/zanata-war/src/main/java/org/zanata/action/AjaxCounterBean.java @@ -0,0 +1,65 @@ +/* + * Copyright 2014, Red Hat, Inc. and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.zanata.action; + +import lombok.extern.slf4j.Slf4j; +import org.jboss.seam.annotations.AutoCreate; +import org.jboss.seam.annotations.Name; + +/** + * @author Sean Flanigan sflaniga@redhat.com + */ +@AutoCreate +@Name("ajaxCounter") +@Slf4j +public class AjaxCounterBean { + // http://stackoverflow.com/questions/4410218/trying-to-keep-track-of-number-of-outstanding-ajax-requests-in-firefox + private static final String AJAX_COUNTER_SCRIPT = "\n"; + public String getAjaxCounterScript() { + String propName = "zanata.countAjax"; + if (Boolean.getBoolean(propName)) { + return AJAX_COUNTER_SCRIPT; + } + return ""; + } +} diff --git a/zanata-war/src/main/resources/org/zanata/webtrans/public/Application.xhtml b/zanata-war/src/main/resources/org/zanata/webtrans/public/Application.xhtml index 7ea3ae54ef..f445240599 100644 --- a/zanata-war/src/main/resources/org/zanata/webtrans/public/Application.xhtml +++ b/zanata-war/src/main/resources/org/zanata/webtrans/public/Application.xhtml @@ -11,6 +11,7 @@ xmlns:a4j="http://richfaces.org/a4j"> + #{msgs['jsf.PageTitle']} + diff --git a/zanata-war/src/main/webapp/WEB-INF/template/template_2x.xhtml b/zanata-war/src/main/webapp/WEB-INF/template/template_2x.xhtml index 4e02e20397..8b19df470a 100644 --- a/zanata-war/src/main/webapp/WEB-INF/template/template_2x.xhtml +++ b/zanata-war/src/main/webapp/WEB-INF/template/template_2x.xhtml @@ -8,6 +8,7 @@ + #{msgs['jsf.Zanata']}: <ui:insert name="page_title"/> + diff --git a/zanata-war/src/main/webapp/app/index.html b/zanata-war/src/main/webapp/app/index.html index b9f30d3dea..477cedabd7 100755 --- a/zanata-war/src/main/webapp/app/index.html +++ b/zanata-war/src/main/webapp/app/index.html @@ -2,6 +2,7 @@ + From 66636811a14783f7499cc31444369181169c8eaf Mon Sep 17 00:00:00 2001 From: Sean Flanigan Date: Mon, 2 Feb 2015 14:32:14 +1000 Subject: [PATCH 09/11] Fix and simplify config for Arquillian/functional tests Default to BasicAcceptanceTestSuite, but add -DallFuncTests option, also -DskipArqTests and -DskipFuncTests. Remove -Dfunctional-test. Make -Dappserver=wildfly8 or -Dappserver=jbosseap6 container installation logic consistent between zanata-war and functional-test modules. Warn if required container properties not set. Use same config (antrun) to install wildfly modules in both cases. Ensure that build fails if no integration tests are found. Generally reduce duplication of config where possible. --- functional-test/pom.xml | 174 +++++++++------ functional-test/src/etc/wildflyModules.groovy | 51 ----- pom.xml | 163 ++++++++++++++ zanata-war/pom.xml | 205 +++++++++--------- zanata-war/src/test/resources/arquillian.xml | 2 +- 5 files changed, 366 insertions(+), 229 deletions(-) delete mode 100644 functional-test/src/etc/wildflyModules.groovy diff --git a/functional-test/pom.xml b/functional-test/pom.xml index 5eae89d6d6..2bf339f20f 100644 --- a/functional-test/pom.xml +++ b/functional-test/pom.xml @@ -15,17 +15,14 @@ 2.39.0 - false localhost - jboss72x 0 + 8180 - http://downloads.sourceforge.net/project/zanata/server/zanata-server.zip ${project.build.directory}/cargo/installs ${project.build.directory}/jboss/container - ../../cargo/installs/zanata-server zanata @@ -61,7 +58,8 @@ -Xnoagent -Djava.compiler=NONE - **/AggregateTestSuite.java + **/BasicAcceptanceTestSuite.java + ${default.test.patterns} ${project.build.directory}/zanataindex ${project.build.directory}/zanatastats @@ -336,8 +334,6 @@ - wildfly8x - http://download.jboss.org/wildfly/${wildfly.version}/wildfly-${wildfly.version}.zip standalone_wildfly.xml org.wildfly wildfly-ejb-client-bom @@ -346,43 +342,22 @@ - maven-dependency-plugin - - - org.wildfly:wildfly-ejb-client-bom - - - - - org.codehaus.cargo - cargo-maven2-plugin - - + maven-antrun-plugin - cargo-install - prepare-package - - install - + install-wildfly-modules + package + - org.codehaus.gmaven - gmaven-plugin - - - unpack-wildfly-modules - package - - execute - - - ${pom.basedir}/src/etc/wildflyModules.groovy - - - + maven-dependency-plugin + + + org.wildfly:wildfly-ejb-client-bom + + @@ -403,11 +378,63 @@ + + + skipFuncTests + + + skipFuncTests + + + + true + + + + + allFuncTests + + + allFuncTests + true + + + + **/DetailedTestSuite.java + + + + + maven-antrun-plugin + + + check-tests-enabled + validate + + run + + + + + + + + + + + + + + + run-functional-test - functional-test + !skipFuncTests @@ -517,17 +544,6 @@ org.codehaus.cargo cargo-maven2-plugin - - - true - - - - ${cargo.installation} - ${user.home}/Downloads - ${cargo.extract.dir} - - ${cargo.servlet.port} @@ -547,6 +563,10 @@ + + cargo-install + prepare-package + cargo-start pre-integration-test @@ -566,21 +586,6 @@ maven-failsafe-plugin - 2.11 - - - integration-test - - integration-test - - - - verify - - verify - - - false true @@ -588,8 +593,6 @@ ${include.test.patterns} - - **/FeatureTest.java @@ -727,6 +730,10 @@ maven-antrun-plugin + + init-no-appserver + initialize + generate-resources @@ -735,26 +742,50 @@ ===== Properties that can be set for functional test ===== - -Dfunctional-test : to activate functional test run + -DskipFuncTests : to skip running functional tests, and/or: + -DskipArqTests : to skip Arquillian integration tests (if building zanata-war) + + Unless skipping tests, you must choose an appserver: + -Dappserver=jbosseap6 -Dcargo.installation=http://example.com/jbosseap632.zip -Dcargo.basename=jbosseap632 + or -Dappserver=wildfly8 + NB: cargo.basename needs to match the basename of the file given in cargo.installation. + For example, if cargo.installation is http://example.com/download/jboss-6.3.2.zip, cargo.basename should be jboss-6.3.2. + + -DallFuncTests to enable all functional tests (defaults to smoke tests) + + -Dcargo.debug.jvm.args : If not set by default will listen to port 8787. Need to set to empty on jenkins + -Dzanata.target.version=version of zanata to deploy. Default is: ${project.parent.version} -Dzanata.instance.url=http://${cargo.host}:${cargo.servlet.port}/${context.path} -Dzanata.apikey=b6d7044e9ee3b2447c28fb7c50d86d98 -Dzanata.sample.projects.basedir=${project.build.testOutputDirectory}/sample-projects - -Dcargo.debug.jvm.args : If not set by default will listen to port 8787. Need to set to empty on jenkins - -Dinclude.test.patterns=test filter pattern. Can be used to control what test to run. Default is **/*AggregateTestSuite.java. + -Dinclude.test.patterns=test filter pattern. Can be used to control what test to run. Default is ${default.test.patterns} -Dwebdriver.type=run tests in htmlUnit, chrome or firefox. For chrome, see also webdriver.chrome.* Default is chrome. -Dwebdriver.display=display to run test browser in, for Xnest or otherwise. Default is :0. -Dwebdriver.chrome.bin=full path to chrome binary. -Dwebdriver.chrome.driver=full path to chromedriver binary. -Dwebdriver.wait=global wait time in seconds for element searches. Default is 10. ========================================================== - to ask cargo to start up then wait so that tests can be run manually: mvn clean package cargo:run -Dfunctional-test -Dmysql.port=13306 + to ask cargo to start up then wait so that tests can be run manually: mvn clean package cargo:run -Dappserver=wildfly8 -Dmysql.port=13306 + + preIT-no-appserver + prepare-package + run + + + + + + + @@ -800,7 +831,6 @@ - ${cargo.container} installed ${project.build.directory}/container.log diff --git a/functional-test/src/etc/wildflyModules.groovy b/functional-test/src/etc/wildflyModules.groovy deleted file mode 100644 index 240212f518..0000000000 --- a/functional-test/src/etc/wildflyModules.groovy +++ /dev/null @@ -1,51 +0,0 @@ - -def download(String address, File destFile) { - def file = new FileOutputStream(destFile) - def out = new BufferedOutputStream(file) - out << new URL(address).openStream() - out.close() -} - -def mojarraUrl = "http://sourceforge.net/projects/zanata/files/wildfly/wildfly-8.1.0.Final-module-mojarra-2.1.28.zip/download" -def hibernateUrl = "http://sourceforge.net/projects/zanata/files/wildfly/wildfly-8.1.0.Final-module-hibernate-main-4.2.15.Final.zip/download" - -File mojarraZip = new File(project.build.directory, "mojarra.zip") -File hibernateZip = new File(project.build.directory, "hibernate.zip") - -download(mojarraUrl, mojarraZip) -download(hibernateUrl, hibernateZip) - - -def ant = new AntBuilder() - -def mojarraModuleDest = project.build.directory + "/mojarra" -ant.unzip(src: mojarraZip.absolutePath, dest: mojarraModuleDest, overwrite: "true" ) -def hibernateModuleDest = project.build.directory + "/hibernate" -ant.unzip(src: hibernateZip.absolutePath, dest: hibernateModuleDest, overwrite: "true" ) - -File wildFlyInstallRoot = new File(project.properties['cargo.extract.dir']) -def dirFilter = { - it.isDirectory(); -} as FileFilter - -def listSubDirs = { File it -> - it.listFiles(dirFilter) -} - -def subDirs = listSubDirs(wildFlyInstallRoot) -File wildFlyRoot; -while (subDirs.size() == 1) { - wildFlyRoot = subDirs[0] - subDirs = listSubDirs(wildFlyRoot) -} - -assert wildFlyRoot != null -println "Wild Fly root is at $wildFlyRoot" - -ant.copy(todir: wildFlyRoot, overwrite: true) { - fileset(dir: mojarraModuleDest) -} - -ant.copy(todir: wildFlyRoot, overwrite: true) { - fileset(dir: hibernateModuleDest) -} diff --git a/pom.xml b/pom.xml index e87ab9d684..b6455e9503 100644 --- a/pom.xml +++ b/pom.xml @@ -71,6 +71,11 @@ 5.1.26 compile + + ${project.build.directory}/cargo/installs + + + @@ -946,12 +951,94 @@ + + + maven-antrun-plugin + 1.8 + + + init-no-appserver + + none + run + + + + + + + + + + + + + + + org.codehaus.cargo + cargo-maven2-plugin + 1.4.5 + + + ${cargo.container} + + + ${cargo.installation} + ${user.home}/Downloads + ${cargo.extract.dir} + + + + + + + + + cargo-install + + none + + install + + + + maven-failsafe-plugin 2.12 + + true + + + + integration-test + + integration-test + + + + verify + + verify + + + org.apache.maven.plugins @@ -1080,17 +1167,93 @@ + + jbosseap6 + + + appserver + jbosseap6 + + + + jboss72x + + jboss-eap-6.3 + + ${cargo.extract.dir}/${cargo.basename}/${appserver.dir.name} + + + wildfly8 + true appserver wildfly8 + wildfly8x + 8.1.0.Final + + wildfly8 + http://download.jboss.org/wildfly/${wildfly.version}/wildfly-${wildfly.version}.zip + + wildfly-${wildfly.version} + + ${cargo.extract.dir}/${appserver.dir.name}/${appserver.dir.name} + + 8.1.0.Final + 2.1.28 + wildfly-${module.wildfly.version}-module-mojarra-${mojarra.module.version}.zip + 4.2.15.Final + wildfly-${module.wildfly.version}-module-hibernate-main-${hibernate.module.version}.zip + ${project.build.directory}/downloads + + + + + + maven-antrun-plugin + + + install-wildfly-modules + + none + + run + + + + + + + + + + + + + + + + + diff --git a/zanata-war/pom.xml b/zanata-war/pom.xml index db09a279d4..b63e3ce816 100644 --- a/zanata-war/pom.xml +++ b/zanata-war/pom.xml @@ -974,6 +974,81 @@ + + skipArqTests + + + skipArqTests + + + + true + + + + + run-arq-tests + + + !skipArqTests + + + + + + maven-antrun-plugin + + + init-no-appserver + initialize + + + preIT-no-appserver + prepare-package + run + + + + + + + + + + + org.codehaus.cargo + cargo-maven2-plugin + + + cargo-install + prepare-package + + + + + + maven-failsafe-plugin + + + **/*ITCase.java + + 1 + true + false + alphabetical + + org.jboss.logmanager.LogManager + ${appserver.home} + + none:none + + + + + + jbosseap6 @@ -987,19 +1062,18 @@ maven-antrun-plugin + prepare-arquillian-container - pre-integration-test + package run - - + + tofile="${appserver.home}/standalone/configuration/standalone-arquillian.xml" /> @@ -1019,31 +1093,14 @@ - maven-failsafe-plugin - - - - container-tests - - integration-test - verify - - - - **/*ITCase.java - - none:none - alphabetical - 1 - true - - jbossas-managed - - - - + + + + jbossas-managed + + @@ -1100,36 +1157,10 @@ wildfly8 - - ${project.build.directory}/wildfly/wildfly-${wildfly.version} - - maven-dependency-plugin - - - unpack - pre-integration-test - - unpack - - - - - org.wildfly - wildfly-dist - ${wildfly.version} - zip - false - ${project.build.directory}/wildfly - - - - - @@ -1143,78 +1174,42 @@ maven-antrun-plugin + + install-wildfly-modules + package + + + prepare-arquillian-container - pre-integration-test + package run - + - - - - - + tofile="${appserver.home}/standalone/configuration/standalone.xml" /> - maven-failsafe-plugin - - - - container-tests - - integration-test - verify - - - - **/*ITCase.java - - none:none - alphabetical - 1 - true - - wildfly81 - org.jboss.logmanager.LogManager - - ${wildfly.home} - - false - - - + + + + wildfly81 + + - - io.undertow - undertow-core - 1.0.15.Final - provided - org.wildfly wildfly-arquillian-container-managed diff --git a/zanata-war/src/test/resources/arquillian.xml b/zanata-war/src/test/resources/arquillian.xml index 4c62e2a092..5823647c7f 100644 --- a/zanata-war/src/test/resources/arquillian.xml +++ b/zanata-war/src/test/resources/arquillian.xml @@ -12,7 +12,7 @@ - ${arquillian.jboss.home} + ${jboss.home}