22 Sep 2014.

Stb-tester’s wait_for_match function works well enough, but what if you want to wait for a UI element to disappear? Or when you want to check that 2 different UI elements are present in the same frame? Or when you just want to know if the element is present or not, without raising an exception? An addition to stb-tester’s Python API, due in stb-tester 0.21, will make this much easier.

All posts in this series:

Stb-tester.com Ltd is currently working with a global TV manufacturer to provide testing services for their latest development project. To support this work we have developed a lot of exciting new features in stb-tester. We’ve been far too busy to release these features officially, but over the next months you should see them making their way to an stb-tester release.

Introducing stbt.match

wait_for_match really does 3 things:

  1. It searches for a template image
  2. …over and over, pulling new frames from the system under test, until it finds the template image
  3. …or raises an exception if it doesn’t find a match within a certain time.

Sometimes you want all three behaviours, but sometimes you only want the first one. The new stbt.match does just that – it searches for an image in a single frame:

if stbt.match("template.png"):
    do_something()
else:
    do_something_else()

Other times you want the first and second behaviours (matching repeatedly until finding a match or timing out, but without raising an exception):

if wait_until(lambda: stbt.match("template.png")):
    do_something()
else:
    do_something_else()

(See below for an implementation of wait_until.)

And yet other times you want the first and third behaviours:

assert stbt.match("template.png")

If you want all three behaviours, you don’t even need wait_for_match anymore:

assert wait_until(lambda: stbt.match("template.png"))

More complex examples

Check that a UI element has disappeared after you dispelled it (just negate the result of stbt.match):

assert wait_until(lambda: not stbt.match("template.png"))

Check that 2 different templates are present at the same time in the same frame:

f = stbt.get_frame()
assert (stbt.match("template1.png", frame=f)
        and stbt.match("template2.png", frame=f))

You can get as complex as you like while keeping quite good readability. Here’s an example from our own HbbTV test suite:

def find_selection():
    # ...image processing details elided...

stbt.press(Key.MENU)
selection = wait_until(find_selection)
assert selection
print stbt.ocr(selection.region)

API details

  • stbt.match

  • stbt.MatchResult

  • wait_until is a helper function that can be implemented without using any stb-tester APIs. It takes a timeout in seconds and a function f; it calls f until f returns something truthy or until the timeout is reached.

      def wait_until(f, timeout_secs=10):
          expiry_time = time.time() + timeout_secs
          while True:
              val = f()
              if val:
                  return val  # truthy
              if time.time() > expiry_time:
                  return val  # falsy
    

    (We place the above code snippet in the public domain.)

Update 2015-03-31: wait_until is now provided by the stbt Python API, as of stb-tester v22. See the Python API reference documentation for details.

But… but…

Won’t using assert throw away too much information? The stb-tester results will say “AssertionError” instead of the MatchTimeout information that the existing wait_for_match logs (including, most usefully, the name of the template image that failed to match).

You could write your test script like this:

assert stbt.match("menu.png"), "Failed to match menu.png"

…but we’re not going to ask you to stoop to that level of boilerplate and repetition! We’re working on a new, smarter test runner that solves this problem. But that will have to wait until the next blog post.

Comments? Join the discussion on the project mailing list.