Skip to content

Commit 2dd5fd8

Browse files
committed
Fail test if returned promise or coroutine does not resolve
1 parent 1986104 commit 2dd5fd8

File tree

2 files changed

+40
-11
lines changed

2 files changed

+40
-11
lines changed

src/AsyncTestCase.php

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -49,27 +49,32 @@ final public function runAsyncTest(...$args)
4949
));
5050
}
5151

52+
$invoked = false;
5253
$returnValue = null;
5354

5455
$start = \microtime(true);
5556

56-
Loop::run(function () use (&$returnValue, &$exception, $args) {
57-
try {
58-
$returnValue = yield call([$this, $this->realTestName], ...$args);
59-
} catch (\Throwable $exception) {
60-
// Also catches exception from potential nested loop.
61-
// Exception is rethrown after Loop::run().
62-
} finally {
63-
if (isset($this->timeoutId)) {
64-
Loop::cancel($this->timeoutId);
65-
}
66-
}
57+
Loop::run(function () use (&$returnValue, &$exception, &$invoked, $args) {
58+
$promise = call([$this, $this->realTestName], ...$args);
59+
$promise->onResolve(function ($error, $value) use (&$invoked, &$exception, &$returnValue) {
60+
$invoked = true;
61+
$exception = $error;
62+
$returnValue = $value;
63+
});
6764
});
6865

66+
if (isset($this->timeoutId)) {
67+
Loop::cancel($this->timeoutId);
68+
}
69+
6970
if (isset($exception)) {
7071
throw $exception;
7172
}
7273

74+
if (!$invoked) {
75+
$this->fail('Loop stopped without resolving promise or coroutine returned from test method');
76+
}
77+
7378
if ($this->minimumRuntime > 0) {
7479
$actualRuntime = (int) (\round(\microtime(true) - $start, self::RUNTIME_PRECISION) * 1000);
7580
$msg = 'Expected test to take at least %dms but instead took %dms';

test/AsyncTestCaseTest.php

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,12 @@ public function testArgumentSupport(string $foo, int $bar, bool $baz)
9898
}
9999

100100
public function testSetTimeout(): \Generator
101+
{
102+
$this->setTimeout(100);
103+
$this->assertNull(yield new Delayed(50));
104+
}
105+
106+
public function testSetTimeoutWithCoroutine(): \Generator
101107
{
102108
$this->setTimeout(100);
103109

@@ -107,6 +113,16 @@ public function testSetTimeout(): \Generator
107113
yield new Delayed(200);
108114
}
109115

116+
public function testSetTimeoutWithWatcher()
117+
{
118+
$this->setTimeout(100);
119+
120+
$this->expectException(AssertionFailedError::class);
121+
$this->expectExceptionMessage('Expected test to complete before 100ms time limit');
122+
123+
Loop::delay(200, function () {});
124+
}
125+
110126
public function testSetMinimumRunTime(): \Generator
111127
{
112128
$this->setMinimumRuntime(100);
@@ -126,6 +142,14 @@ public function testSetMinimumRunTimeWithWatchersOnly()
126142
Loop::delay(100, $this->createCallback(1));
127143
}
128144

145+
public function testUnresolvedPromise(): Promise
146+
{
147+
$this->expectException(AssertionFailedError::class);
148+
$this->expectExceptionMessage('Loop stopped without resolving promise or coroutine returned from test method');
149+
150+
return (new Deferred)->promise();
151+
}
152+
129153
public function testCreateCallback()
130154
{
131155
$mock = $this->createCallback(1, function (int $value): int {

0 commit comments

Comments
 (0)