0

This may be similar to 5660956, but I am doing a GET first...

I think the key here is Selenium, hence the tags. Just in case it matters: I'm working in Java, using NinjaFramewor, FluentLenium and Firefox. It runs locally, but also on a headless CI box with Xvfb. I have some FluentLenium tests passing, so the whole thing isn't broken!

I have a web page, with a simple login form that performs a call to JavaScript which does an AJAX POST. The AJAX response is caught by JavaScript and causes some of the body of the page to update, with different results for login, register and fail. I can see this happening when I test by hand, and even when I run these tests locally.

The test looks like this:

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
}

And the LoginPage, which is where I'm having trouble looks like (with a super class containing constants folded back in):

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
}

The isErrorResult() method is never satisfied! The find h1 shows that the h1 text is still as it was when the page was first loaded. Clearing the session cookie is showing different behaviour on different machines (probably needs to wait for something). I've also tried testing the contents of welcomeDiv. I have a feeling I ought to be able to use the @AjaxElement to help here, but I haven't quite worked out how.

I don't want to inspect the JSON coming back. I've got tests which don't involve Selenium that get pretty close to this already.

What I want to do is automate checking that the user will see the right thing at the browser end after a POST. Even if there is a work-around for this code, other functionality will have large enough uploads that GET really isn't sensible; and testable AJAX seems like a reasonable want.

Any ideas, please?

Community
  • 1
  • 1
Dan
  • 358
  • 1
  • 11

1 Answers1

0

I have a working solution. As ever it a combination of changes got me to the place I want to be. In rough order of importance I think they are:

  • Only querying the state of a @Page once in any given test. The first test of Ajaxed content won. The subsequent ones found the wrong value.
  • Making the assert call to test that the ajax element is what it ought to be from the test object rather than within the page object. The broken version is commented out in the code below as this was unexpected.
  • Using @AjaxElement and then querying the content of those elements.
  • One web page had a missing id tag on the element I was looking for (wouldn't have accounted for all the problems).
  • Amongst other little changes along the way I am now testing heading h1 elements and list elements, rather than the div that contains them; and the different versions of the h1 have different id values. Haven't (yet) regression checked how significant this was.

The test code is now:

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"));
 }
}

And the page class:

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);
}
}
Dan
  • 358
  • 1
  • 11