0

I have a task do create e2e for a web app, but I don't know what is the correct way doing it.

For example: In app there is a possibility to add new employee, so the scenario is as described:

  1. Login to application(it can be implemented in TestNG @BeforeClass annotation)
  2. Switch to correct role that have posibility to add employee
  3. Forward to form & Filling form and submit
  4. Switch to employee tab, assert that employee exists @AfterClass teardown

In testing project I have to use Selenium with TestNG.

My question is what is the correct way to do this? There are three possible options:

Option 1:

public class CreateEmployeeTest {


    @BeforeClass
    public void loginToApplication() {

        driver.get("url");
        new LoginPage(driver).login("username", "password");
    }

    @Test
    public void addNewEmployee() {
        new DashboardPage(driver)
                .clickAddEmployeeButton();

        new AddEmployeeForm(driver)
                .fillFirstName("Name")
                .fillLastName("LastName")
                .fillEmail("email")
                .submitForm();

        new WebDriverWait(driver, 10)
                .until(ExpectedConditions.urlContains("/employees"));
        assertThat(new EmployeeDetails(driver).getEmployeeName(), equalTo(String.format("%s %s", "Name", "LastName")));
    }

    @Test(dependsOnMethods = "addNewEmployee")
    public void verifyThatEmployeeIsOnList() throws InterruptedException {
         new DashboardPage
                .switchToEmployesTab()
                .search(String.format("%s %s", "Name", "LastName"));

        Assert.assertTrue(DashboardPage.checkThatUserIsOnList(String.format("%s %s", "Name", "LastName")));
    }
}

Is it correct to create tests like this? I mean to create few @Test in one scenario with 'dependsOnMethod' option.

Option 2:

public class CreateEmployeeTest {


    @BeforeClass
    public void loginToApplication() {

        driver.get("url");
        new LoginPage(driver).login("username", "password");
    }

    @Test
    public void addNewEmployee() {
        new DashboardPage(driver)
                .clickAddEmployeeButton();

        new AddEmployeeForm(driver)
                .fillFirstName("Name")
                .fillLastName("LastName")
                .fillEmail("email")
                .submitForm();

        new WebDriverWait(driver, 10)
                .until(ExpectedConditions.urlContains("/employees"));
        assertThat(new EmployeeDetails(driver).getEmployeeName(), equalTo(String.format("%s %s", "Name", "LastName")));

        new DashboardPage
               .switchToEmployesTab()
               .search(String.format("%s %s", "Name", "LastName"));

        Assert.assertTrue(DashboardPage.checkThatUserIsOnList(String.format("%s %s", "Name", "LastName")));

   }
} 

Option 2 Create one @Test and write a full scenario in it. If option two is correct - what is the best way with dealing with very long tests?

Option 3: Maybe two of examples are incorrect - your idea?

  • If you want to validate employee creation, why are you mixing login and employee list displaying here? It seems you are violating the Single Responsibility Principle. – João Farias Feb 25 at 13:59
  • @JoãoFarias To add an employee I need to be logged. Also I need a employee list to verify that he was added. – jamal Feb 26 at 8:16
  • I meant you are mixing frontend (details) with business logic. Most probably you have components and layers between the frontend and the data storage - these three components (frontend, data storage, and everything between) are independent of each other, mixing all these concerns as you are doing will result and very low quality information (any failure will demand debugging on all three components) and very fragile check code (failures in any of the three components will cause an error to be raised). – João Farias Feb 26 at 9:43
  • So what is the correct way to write tests which need few page objects in one scenario? – jamal Feb 26 at 10:12
1

Your tests have a lot of page specific details in the test, the waiting, checking urls could be moved to the pageObjects. The action is adding an employee, not filling the form.

@Test
public void addNewEmployee() {
    // Arrange
    var dashboard = new LoginPage(driver).Login(user); // returns page with navigation
    var eManager = dashboard.navigateToEmployeeManagement(); // returns page employee formpage
    var employee = new Employee("Name", "LastName", "email"); // Simple data object

    // Act
    eManager.addEmployee(employee);

    // Assert
    Assert.True(eManager.employeeIsOnList(employee));
}

The test is easy to read, the complexity and abstractions are hidden in the pageObjects. As the addEmployee() method now contains your AddEmployeeForm and wait steps.

| improve this answer | |
  • To be sure: Is it correct that DashboardPage use the logic from other pageObject like AddEmployeeForm? So the DashboardPage can contains addEmployee method which includes: 1. Click on add employee button on dashboard page 2. calling a method from another object(AddEmployeeForm) to fill a employee form 3. Switch to employee tab using DashboardPage element – jamal Feb 26 at 9:05
  • Maybe I made it a bit to simple, personaly I like it if pageObject return page objects. See my updated answer. I do not have problems with pageObjects using other pageObjects in its class. Complex page navigation and forms are good examples of that. In the test I do not want to see the internal structure of the pages, just the actions it facilitates to the user. – Niels van Reijmersdal Feb 26 at 11:54
  • But what if there are many methods that using many different page objects? Lets say that adding a new employee is more complicated process. For example: 1. Filling initial form and submit (1st PO) 2. Filling detailed form and submit (2nd PO) 3. Go to page that upload mandatory file to employee account (3rd PO) 4. Signing the document(another one) 5. Finish process Where should I hide the whole logic? It's a good idea to make method called addEmployee in dashboard page object class that includes methods from many different PO and the body of method looks like a detailed scenario? – jamal May 24 at 16:20
0

You can start with few things that i consider part of best practices rules:

  1. driver should not be mentioned in a test class -> for this you can create a page object manager that creates the page objects you need
  2. you can use the Fluent / Chain of invocation pattern for writing the TDD way
  3. don't add too much details in the tests > keep them simple > all the logic should be in the page objects and the test should define the business flow

How your test could/should look:

private LoginPage loginPage;

@BeforeMethod
public void setLoginPage() {
    POM pom = new PageObjectManager(); /** gets pages with driver set */
    pom.getLoginPage();
}

@Test
public void test() {

    someObject = loginPage /** some object based on your app logic */
            .iLoginWith(methodThatGetCredentialsForSpecificUserLikeAdmin)
            .iAddEmployee(methodThatGeneratesDinamicEmployee); /** opens the form, fills and submits */

    Assert.assertTrue(someObject.theEmployeeIsOnList());
}
| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.