Workflow Test Pattern

A workflow pattern enables to turn customer journies of the application into reusable workflows. Once the workflows are defined, adding test cases is as simple as calling a workflow and asserting the outcomes.

Page Object Model

Page Object Model provides an abstraction for a page (a webpage or mobile screen). The workflow pattern could then be leveraged on top of POM to build workflows that represent a user journey

The workflow pattern components

  1. UseCase
  2. WorkFlowDefinition
  3. WorkFlowDoc

UseCase

UseCase has two purposes

  1. Acts as a data structure to store test data for the current test.
    a. Exposes a method to add test data addToUseCase(Object data)
    b. Exposes a method to retrieve test data <Q> Q getData(Class<Q> tClass)

  2. Stores the current state of the application.

Workflow Definition

A workflow definition defines a portion of the customer journey. A workflow definition offers following functions

  1. Get the page/screen object for the current work definition by means of create() method

  2. Define the criteria to go to the next workflow definition by means of fulfillCondition() - fulfillment criteria is to move to the next page/screen in the workflow / customer journey

  3. Proceed to the next workflow definition by means of next() method - next page/screen in the workflow / customer journey

WorkflowDoc

A workflow doc is the blueprint of your customer journey. It ties workflow definitions to construct end-to-end customer journies.

Sample app with workflow

A typical Buy a product worklow has below steps

  1. Login
  2. Add product to cart
  3. Navigate to cart to review products
  4. Checkout
  5. Order confirmation


Workflow test

A test with the workflow pattern looks like below code.

@Test(groups = "mobile")
public class PurchaseTests extends MobileTest {

  @Inject LocaleClient localeClient;
  @Inject private UseCaseGenerator useCaseGenerator;

  public void purchaseProductAndValidate() {
    UseCase happyPathCase = useCaseGenerator.happyPathCase();
    new BuyAProductDoc(happyPathCase)
        .confirmation()
        .create()
        .getConfirmationDetails()
        .orderConfirmed(localeClient.getLocale("confirmation_messages",
                ConfirmationDetails.class));
  }

}

WorkflowDoc

The workflow doc for the above workflow.

public class BuyAProductDoc extends WorkflowDoc {

  public BuyAProductDoc(UseCase useCase) {
    super(useCase);
  }

  // Entry workflow
  public LoginDefinition login() {
    return new LoginDefinition(useCase);
  }

  // Keep building on top of that
  public ProductsDefinition products() {
    return login().next();
  }

  public CartDefinition cart() {
    return products().cart();
  }

  public MenuDefinition menu() {
    return products().menu();
  }

  public CheckoutDefinition checkout() {
    return cart().next();
  }

  public ConfirmationDefinition confirmation() {
    return checkout().next();
  }
}

Workflow definition

A workflow definition for Login

public class LoginDefinition extends WorkflowDefinition {

  public LoginDefinition(UseCase useCase) {
    super(useCase);
  }

  protected FulfillCondition<LoginDefinition> loginCondition =
      () -> {
        create().login(useCase.getData(Credentials.class), LoginScreen.class);
        return this;
      };

  @Override
  public ProductsDefinition next() {
    return proceedToNext(loginCondition, new ProductsDefinition(useCase));
  }

  @Override
  public LoginScreen create() {
    return Screen(LoginScreen.class);
  }
}

Complete Code

The complete code is available here