package com.tyndalehouse.step.test;
import org.apache.commons.lang3.StringUtils;
import org.junit.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.ExpectedCondition;
import org.openqa.selenium.support.ui.WebDriverWait;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Pattern;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
/**
* Created by cjburrell on 04/06/2015.
*/
public class AutoCompleteTest extends AbstractSTEPTest {
public AutoCompleteTest(String os, String version, String browser) {
super(os, version, browser);
}
/**
* Checks that for various prefixes, we get various references out
*/
@Test
public void testSimpleReferenceEnglish() {
Object[][] tests = new Object[][] {
{ "Mar does not yield first three chapters and book in Mark", "Mar", new String[] {"[Bible]Mark", "[Reference]Mark 1", "[Reference]Mark 2", "[Reference]Mark 3"}, new String[] {"Mark 4", "Exodus"}},
{ "Psa does not yield first three chapters and book in Mark", "Psa", new String[] {"[Bible]Psalms", "[Reference]Psalms 1", "[Reference]Psalms 2", "[Reference]Psalms 3"}, new String[] {"[Reference]Psalms 4", "[Bible]Exodus"}},
{ "Ma should yield list of books", "Ma", new String[] {"[Bible]Matthew", "[Bible]Malachi", "[Bible]Mark", "[Reference]Matthew 1"}, new String[] {"[Reference]Matthew 2", "[Reference]Matthew 3"}},
{ "Jn should yield list of John references", "Jn", new String[] {"[Bible]John", "[Reference]John 1", "[Reference]John 2", "[Reference]John 3"}, new String[] {}},
{ "Jon should yield list of Jonah references", "Jon", new String[] {"[Bible]Jonah", "[Reference]Jonah 1", "[Reference]Jonah 2", "[Reference]Jonah 3"}, new String[] {}},
{ "Ob should yield single book", "Ob", new String[] {"[Bible]Ob"}, new String[] {"Ob 1"}}
};
for(Object[] test : tests) {
testingReferencesPresentInSearchCommand((String) test[0], (String) test[1], (String[]) test[2], (String[]) test[3]);
}
}
/**
* Checks that references are Bible / Reference / Book depending on how they are. Also ensures that drill down
* works correctly
*/
@Test
public void testNameOfReferenceBibleText() {
openHomePage();
//check we have Romans, Romans 1, 2,3
testingReferencesPresentInSearchCommand("Correct Romans references are missing", "Rom", new String[]{"[Bible]Romans", "[Reference]Romans 1"}, new String[]{"[Whole book]Romans"});
//now click on sub link
clickSearchCommandOption("Bible", "Romans");
waitForSearchCommandInteraction();
List<String> romansChapters = new ArrayList<>();
for(int ii = 1; ii <= 16; ii++) {
romansChapters.add("[Reference]Romans " + ii);
}
romansChapters.add("[Whole book]Romans");
assertSearchCommandContents("Drilled-down Romans does not contain all chapters.", romansChapters.toArray(new String[]{}), new String[]{});
}
@Test
public void testSimpleReferenceInternational() {
Object[][] tests = new Object[][] {
{ "Jean does not yield first three chapters and book in John", "Jean", },
};
openHomePage("fr");
sendKeysToSearchCommand("Jean");
assertSearchCommandContents("Failed international references", new String[] {"[Bible]Jean", "[Référence]Jean 1", "[Référence]Jean 2", "[Référence]Jean 3"}, new String[] {"Jean 4", "Marc", "Mark", "John"});
}
public void testingReferencesPresentInSearchCommand(String message, String keysToType, String[] present, String[] absent) {
openHomePage();
sendKeysToSearchCommand(keysToType);
assertSearchCommandContents(message, present, absent);
}
private void clickSearchCommandOption(String sourceType, String text) {
final List<WebElement> elements = getDriver().findElements(By.xpath(
String.format("//span[@class='source' and text() = '[%s]']/ancestor::*[contains(@class, 'select2-result-selectable')]", sourceType)));
final Pattern matchingItem = Pattern.compile(String.format("%s.*[\r\n]*.*%s$", sourceType, text));
for(WebElement e : elements) {
if(matchingItem.matcher(e.getText()).find()) {
e.click();
return;
}
}
fail(String.format("Unable to find source type %s with text %s", sourceType, text));
}
public void assertSearchCommandContents(String message, String[] present, String[] absent) {
//find results
final List<WebElement> elements = getDriver().findElements(By.cssSelector(".select2-result-label"));
Set<String> references = new HashSet<>();
for (WebElement e : elements) {
references.add(e.getText().replaceAll("[\r\n]", ""));
}
assertContains("Some references are missing. " + message, references, present);
assertNotContains("Some references are showing when they shouldn't be. " + message, references, absent);
}
public void sendKeysToSearchCommand(String keysToType) {
getDriver().findElement(By.cssSelector(".select2-search-field .select2-input")).sendKeys(keysToType);
waitForSearchCommandInteraction();
assertTrue("Results aren't showing", getDriver().findElement(By.cssSelector(".select2-results")).isDisplayed());
waitForJQuery(getDriver());
}
public void waitForSearchCommandInteraction() {
JavascriptExecutor js = (JavascriptExecutor) getDriver();
final Number keyPause = (Number) js.executeScript("return KEY_PAUSE");
try {
Thread.sleep(keyPause.longValue() + 1);
} catch (InterruptedException e) {
fail("Failed to wait for keys to be sent to server");
}
}
public void waitForJQuery(WebDriver driver) {
(new WebDriverWait(driver, 5)).until(new ExpectedCondition<Boolean>() {
public Boolean apply(WebDriver d) {
JavascriptExecutor js = (JavascriptExecutor) d;
return (Boolean) js.executeScript("return jQuery.active == 0");
}
});
}
private void assertContains(String message, Set<String> set, String... items) {
Set<String> missing = new HashSet<>();
for (String i : items) {
boolean found = false;
for (String s : set) {
if (s.contains(i)) {
found = true;
break;
}
}
if (!found) {
missing.add(i);
}
}
if (missing.size() > 0) {
fail(message + ": " + StringUtils.join(missing, ','));
}
}
private void assertNotContains(String message, Set<String> set, String... items) {
Set<String> foundByMistake = new HashSet<>();
for (String i : items) {
boolean found = false;
for (String s : set) {
if (s.contains(i)) {
found = true;
break;
}
}
if (found) {
foundByMistake.add(i);
}
}
if (foundByMistake.size() > 0) {
fail(message + ": " + StringUtils.join(foundByMistake, ','));
}
}
}