From 02f30899cd2931e730d0fd4a6de3871d4445ed4e Mon Sep 17 00:00:00 2001 From: Holger Kohnen Date: Thu, 4 Jul 2019 00:40:10 +0200 Subject: [PATCH] add failing test for #14 --- .../DevtoolsClientTest.php | 84 +++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/test/ChromeDevtoolsProtocol/DevtoolsClientTest.php b/test/ChromeDevtoolsProtocol/DevtoolsClientTest.php index 1a36cca8..8a2d705f 100644 --- a/test/ChromeDevtoolsProtocol/DevtoolsClientTest.php +++ b/test/ChromeDevtoolsProtocol/DevtoolsClientTest.php @@ -1,15 +1,20 @@ getMockBuilder(Payload::class) + ->disableOriginalConstructor() + ->getMock(); + $payloadStub->method('getPayload')->willReturn($payload); + $responses[] = $payloadStub; + }; + + // create a stub websocket client, which returns predefined messages + $wsClient = $this->getMockBuilder(WebSocketClient::class) + ->disableOriginalConstructor() + ->getMock(); + $wsClient->method('receive')->willReturnCallback(function() use(&$responses) { + if (!empty($responses)) { + return [array_shift($responses)]; + } + return null; + }); + $wsClient->method('setDeadline')->willReturnCallback(function($deadline) { + $timeout = floatval($deadline->format("U.u")) - microtime(true); + if ($timeout < 0.0) { + throw new DeadlineException("Socket deadline reached."); + } + }); + + // create the failing scenario + $ctx = Context::withTimeout(Context::background(), 3); + + $client = new DevtoolsClient($wsClient); + register_shutdown_function(function () use ($client) { $client->close(); }); + + $addResponse('{"id":1,"result":{}}'); + $client->page()->enable($ctx); + + $addResponse('{"id":2,"result":{}}'); + $client->network()->enable($ctx, EnableRequest::make()); + + $client->network()->addLoadingFinishedListener(function (LoadingFinishedEvent $event) use($ctx, $client, $addResponse) { // <- 2 + + // The order of these responses matters, if the loadEventFired comes first, awaitLoadEventFired (1) would wait forever + $addResponse('{"method":"Page.loadEventFired","params":{"timestamp":6758.846787}}'); + $addResponse('{"id":4,"result":{"body":"..."}}'); + + $client->network()->getResponseBody($ctx, GetResponseBodyRequest::builder() // <- 3 + ->setRequestId($event->requestId) + ->build() + ); + }); + + $url = 'https://www.google.com'; + + $addResponse('{"id":3,"result":{"frameId":"1E56ACDD9B3B7F678F972C0EF0782649","loaderId":"AAF889CAE5B10663CA8D383A6125AC1B"}}'); + $client->page()->navigate($ctx, NavigateRequest::builder()->setUrl($url)->build()); + + $addResponse('{"method":"Network.loadingFinished","params":{"requestId":"AAF889CAE5B10663CA8D383A6125AC1B","timestamp":6758.623335,"encodedDataLength":67174,"shouldReportCorbBlocking":false}}'); + $client->page()->awaitLoadEventFired($ctx); // <- 1 + + $this->assertTrue((bool)'No conflict'); + + /* + + 1) we are waiting for the LoadEvent, but in the meanwhile the LoadingFinishedEvent arrives -> + 2) so the listener is called + 3) getResponseBody command is executed + - if the response is received before LoadEvent, everything is fine + - but if the LoadEvent is happening before the response is received, + the LoadEvent is dropped (not buffered) and awaitLoadEventFired could never return + + */ + } + + }