State

State is used to bundle up multiple ExpectedAttribute objects so that they can all be checked against a PageComponent with a single assert statement. The intent is to achieve the following:

  • Maintain the best practice of only using a single assert statement per test
    test function/method, while still allowing the test to check multiple things at once.
  • Speed up and simplify writing complex tests for a page’s components.
  • Make the code for tests more readable/writable and compact.
  • Provide concise, readable output containing all problems should the test fail.

How to Use

Assuming you have all the page objects and fixtures defined, writing a test can be as easy as this (assume this is a method inside a test class):

def test_some_component(self, page):
    assert page.some_component == State(
        IsDisplayed(),
        Text("My Text"),
        TagName("p"),
    )

If the element was found to be displayed, but had different text and wasn’t a <p> tag, you would see a failure that looks something like this:

Comparing SomeComponent State:
    Text: "Something else" != "My Text"
    TagName: "div" != "p"

The IsDisplayed, Text, and TagName classes you see all inherit from ExpectedAttribute. PyPCOM comes with several baked in (see Provided ExpectedAttribute Classes for a full list), but the system is designed to easily extended so you can add your own. For more detail on that, check out State or ExpectedAttribute.

How It Works

When you first make the State object, you pass it one or more ExpectedAttribute objects, which it holds onto. The ExpectedAttribute objects are responsible for knowing how to check the PageComponent for any problems, and storing them for later reference. The State object runs through all the ExpectedAttribute objects in it’s __eq__() method, and once all the ExpectedAttribute objects are checked against the PageComponent object, the State object checks their results. If it sees that any problems were found, the comparison will just evaluate to False.

For most testing frameworks, that’s as far as it will go. But if you’re using pytest_, then when it comes time for it to print out the failure report, the State object will be used to generate a more readable failure report message by having it compile the list of problems reported by each ExpectedAttribute object. It’s able to do this after the tests have long since been evaluated, because each of the ExpectedAttribute objects hold onto their findings, and the State object keeps a reference to each of them.