Тестирование эффекта AJAX/POST на странице с селеном - элемент не найден
Это может быть похоже на 5660956, но я делаю GET сначала...
Я думаю, что ключ здесь - Selenium, отсюда и теги. На всякий случай это важно: я работаю на Java, использую NinjaFramewor, FluentLenium и Firefox. Он работает локально, но также и на блоке CI без головы с Xvfb. У меня есть несколько тестов FluentLenium, так что все не сломано!
У меня есть веб-страница с простой формой входа в систему, которая выполняет вызов JavaScript, который выполняет AJAX POST. Ответ AJAX перехватывается JavaScript и вызывает обновление части тела страницы с различными результатами для входа в систему, регистрации и сбоя. Я вижу, что это происходит, когда я тестирую вручную, и даже когда я запускаю эти тесты локально.
Тест выглядит так:
import org.fluentlenium.adapter.util.SharedDriver;
import org.fluentlenium.core.annotation.Page;
import org.junit.Test;
@SharedDriver(deleteCookies=true)
public class UserControllerTest extends JSTest {
@Page
HomePage home;
@Page
LoginPage login;
@Test
public void test_cantLoginUntilReg() {
goTo(login);
login.fillOutReg("test_cantLoginUntilReg");
login.chooseLogin(); // script that POSTS and does AJAX update
login.isErrorResult(); // errors
goTo(login);
login.fillOutReg("test_cantLoginUntilReg");
login.chooseRegister(); // script that POSTS and does AJAX update
login.isWelcomeResult(); // errors
login.chooseHome(); // GET on home
home.isLoggedIn(); // this works
}
// more tests
}
И LoginPage, где у меня возникли проблемы (супер класс, содержащий константы, сложенные обратно):
public class LoginPage extends FluentPage {
protected static final String HOME_PAGE = "http://localhost:8080";
private static final String PAGE = HOME_PAGE + "/login";
@AjaxElement
FluentWebElement welcomeDiv;
@AjaxElement
FluentWebElement errorDiv;
@Override
public String getUrl() {
return PAGE;
}
@Override
public void isAt() {
assertTrue("url is " + url(), url().contains("login"));
assertTrue("h1 is " + find("h1").getText(), find("h1").getText().contains("Login"));
assertTrue("h1 is " + find("h1").getText(), find("h1").getText().contains("Register"));
}
public void isErrorResult() {
assertTrue("h1 is " + find("h1").getText(), find("h1").getText().contains("Failed"));
assertNull("cookie is " + getCookie(SESSION_COOKIE_NAME), getCookie(SESSION_COOKIE_NAME));
}
public void fillOutReg(String testName) {
fill("#email").with(testName + "@UserControllerJSTests.test.com"); // this passes the minimal validation in place so far
fill("#password").with("reallyBadPassword");
fill("#identName").with(testName);
}
public void chooseLogin() {
executeScript(LOGIN_SCRIPT); // I'd prefer click on the form, but that seemed to be a source of trouble as well
}
// and so on
}
Метод isErrorResult() никогда не выполняется! Поиск h1 показывает, что текст h1 остается таким же, каким он был при первой загрузке страницы. Очистка cookie сеанса показывает различное поведение на разных машинах (вероятно, нужно что-то ждать). Я также пытался протестировать содержимое welcomeDiv. У меня есть чувство, что я должен быть в состоянии использовать @AjaxElement, чтобы помочь здесь, но я не совсем понял, как.
Я не хочу проверять возвращение JSON. У меня есть тесты, в которых не участвует Selenium, которые уже достаточно близки к этому.
Что я хочу сделать, так это автоматизировать проверку того, что пользователь увидит правильную вещь в конце браузера после POST. Даже если есть обходной путь для этого кода, другие функции будут иметь достаточно большие загрузки, что GET действительно не имеет смысла; и тестируемый AJAX кажется разумным желанием.
Есть идеи, пожалуйста?
1 ответ
У меня есть рабочее решение. Как всегда, сочетание изменений привело меня в то место, где я хочу быть. В грубом порядке важности я думаю, что они:
- Запрашивать состояние @Page можно только один раз в любом тесте. Первый тест контента Ajaxed выиграл. Последующие нашли неправильное значение.
- Выполнение вызова assert для проверки того, что элемент ajax - это то, что должно быть из тестового объекта, а не внутри объекта страницы. Неработающая версия закомментирована в приведенном ниже коде, так как это было неожиданно.
- Использование @AjaxElement, а затем запрос содержимого этих элементов.
- На одной веб-странице отсутствовал тег id для элемента, который я искал (не учитывал бы все проблемы).
- Среди других небольших изменений по пути я сейчас тестирую заголовочные элементы h1 и элементы списка, а не div, который их содержит; и разные версии h1 имеют разные значения идентификатора. Не (пока) регрессия проверила, насколько это важно.
Тестовый код теперь:
import org.fluentlenium.adapter.util.SharedDriver;
import org.fluentlenium.core.annotation.Page;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
@SharedDriver(deleteCookies=true)
public class UserControllerTest extends JSTest {
@Page
HomePage home;
@Page
LoginPage login;
@Test
public void test_cantLoginBeforeReg() {
// try to login without being registered
goTo(login);
login.fillOutReg("test_cantLoginUntilReg");
login.chooseLogin();
isErrorResult();
goTo(home);
home.isNotLoggedIn();
}
@Test
public void test_registerLogout() {
goTo(login);
login.fillOutReg("test_registerLogout");
login.chooseRegister();
isWelcomeResult();
login.chooseLogout();
home.isAt();
home.isNotLoggedIn();
}
// tests etc
public void isWelcomeResult() {
assertTrue(login.getWelcomeText(), login.getWelcomeText().contains("Welcome"));
}
public void isErrorResult() {
assertTrue(login.getErrorText(), login.getErrorText().contains("Failed"));
}
}
И класс страницы:
import org.fluentlenium.core.annotation.AjaxElement;
import org.fluentlenium.core.domain.FluentWebElement;
import static org.junit.Assert.assertTrue;
public class LoginPage extends TripVisPage {
private static final String PAGE = HOME_PAGE + "/login";
@AjaxElement
FluentWebElement welcomeHeading;
@AjaxElement
FluentWebElement errorHeading;
@Override
public String getUrl() {
return PAGE;
}
public String getWelcomeText() {
return welcomeHeading.getText();
}
public String getErrorText() {
return errorHeading.getText();
}
@Override
public void isAt() {
assertTrue("url is " + url(), url().contains("login"));
assertTrue("h1 is " + find("h1").getText(), find("h1").getText().contains("Login"));
assertTrue("h1 is " + find("h1").getText(), find("h1").getText().contains("Register"));
}
/* calling these from the test is broken
public void isWelcomeResult() {
assertTrue(getWelcomeText(), getWelcomeText().contains("Welcome"));
}
public void isErrorResult() {
assertTrue(getErrorText(), getErrorText().contains("Failed"));
}
*/
public void fillOutReg(String testName) {
fill("#email").with(testName + "@UserControllerJSTests.tripvis.co.uk");
fill("#password").with("reallyBadPassword");
fill("#identName").with(testName);
}
public void chooseAbout() {
click(LINK_ABOUT_ID);
}
public void chooseLegal() {
click(LINK_LEGAL_ID);
}
public void chooseRegister() {
executeScript(REGISTER_SCRIPT);
}
public void chooseLogin() {
executeScript(LOGIN_SCRIPT);
}
public void chooseLogout() {
click(LINK_LOGOUT_ID);
}
}