Skip to content

Idea - Generic wait_until(predicate_func, timeout) & reaching max_time should fail the test & providing predicate functions like is_object_freed #585

@WebF0x

Description

@WebF0x

Context

Awaiting provides wait_seconds, wait_frames and wait_for_signal, which are great.

A pattern that often comes up in my tests is to wait for a particular condition to be true.
For example

  • repeatedly hit an enemy until it is dead
  • hit an enemy then wait until its HP regenerates to 100%
  • accelerate something until it has velocity X

In all cases, if a certain timeout is reached, I want the test to fail.

Ideas

Generic wait_until(predicate_func, timeout)

  • predicate_func: Callable returning a boolean. Returns true when the success condition is reached
  • max_wait: same as wait_for_signal. Timeout after which we stop blocking the test

Fail on max_time reached

I think wait_for_signal and wait_until should fail the test when the max_time is reached, just like a failed assertion.

is_object_freed predicate

GUT could provide a predicate function returning true when an object has been freed.

Other predicates

Many conditions used in assertions would be great as conditions to wait_until if they were converted into predicate functions (excuse the bad names hehe)

await wait_until(has(vegetables_array, 'potato'))
await wait_until(is_signal_connected(signaler, connector, 'the_signal'))
await wait_until(has_call_count(doubled, 'set_value', 1, [4]))

Usage

func test_when_sword_collides_with_wall_then_it_is_stopped() -> void:
  wall = add_child_autofree(WallScene.instantiate())
  wall.set_position(Vector2.RIGHT * 100)
  sword = add_child_autofree(SwordScene.instantiate())
  sword.set_linear_velocity(Vector2.RIGHT * 300)

  var is_immobile := func() -> bool: return sword.get_linear_velocity().is_zero_approx()
  await wait_until(is_immobile, 5)

Bonus idea: wait until freed

Here's a PR I made for wait_until_freed. Another way to wait until something is freed could be done with GUT just providing a predicate to check if something is freed.

func test_when_enemy_collides_with_sword_then_it_dies() -> void:
  enemy= add_child_autofree(EnemyScene.instantiate())
  enemy.set_position(Vector2.RIGHT * 100)
  sword.set_linear_velocity(Vector2.RIGHT * 300)
  sword = add_child_autofree(SwordScene.instantiate())

  var is_dead := func() -> bool: return is_object_freed(enemy) # is_object_freed being a new predicate provided by GUT
  await wait_until(is_dead , 5)

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementnext releaseThis has been implemented and will be in the next release.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions