diff --git a/.github/workflows/fix-style.yml b/.github/workflows/fix-style.yml index 7907c3e..c72e0f7 100644 --- a/.github/workflows/fix-style.yml +++ b/.github/workflows/fix-style.yml @@ -13,8 +13,6 @@ jobs: - name: Checkout code uses: actions/checkout@v4 - with: - ref: ${{ github.head_ref }} - name: Setup PHP uses: shivammathur/setup-php@v2 diff --git a/src/Http/Response.php b/src/Http/Response.php index ab4012a..27f25f6 100644 --- a/src/Http/Response.php +++ b/src/Http/Response.php @@ -25,21 +25,28 @@ */ final class Response implements DroppableInterface { - use HasMetaData; use Droppable; + use HasMetaData; - private Crawler $crawler; + private ?Crawler $crawler = null; public function __construct( private ResponseInterface $response, private Request $request, ) { - $this->crawler = new Crawler((string) $response->getBody(), $request->getUri()); } + /** + * @param array $args + */ public function __call(string $method, array $args): mixed { - return $this->crawler->{$method}(...$args); + return $this->getCrawler()->{$method}(...$args); + } + + public function getCrawler(): Crawler + { + return $this->crawler ??= new Crawler((string) $this->response->getBody(), (string) $this->request->getUri()); } public function getRequest(): Request @@ -60,7 +67,7 @@ public function getBody(): string public function withBody(string $body): self { $this->response = $this->response->withBody(Utils::streamFor($body)); - $this->crawler = new Crawler($body, $this->request->getUri()); + $this->crawler = null; return $this; } diff --git a/tests/Http/ResponseTest.php b/tests/Http/ResponseTest.php index 14e3503..06946dc 100644 --- a/tests/Http/ResponseTest.php +++ b/tests/Http/ResponseTest.php @@ -14,11 +14,13 @@ namespace RoachPHP\Tests\Http; use GuzzleHttp\Psr7\Stream; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; use RoachPHP\Http\Response; use RoachPHP\Support\DroppableInterface; use RoachPHP\Testing\Concerns\InteractsWithRequestsAndResponses; use RoachPHP\Tests\Support\DroppableTestCase; +use Symfony\Component\DomCrawler\Crawler; /** * @internal @@ -37,6 +39,7 @@ public function testCanAccessDomCrawlerDirectlyFromResponse(): void self::assertCount(1, $links); } + #[DataProvider('responseCodeProvider')] /** * @dataProvider responseCodeProvider */ @@ -60,6 +63,7 @@ public static function responseCodeProvider(): iterable ]; } + #[DataProvider('responseBodyProvider')] /** * @dataProvider responseBodyProvider */ @@ -81,6 +85,7 @@ public static function responseBodyProvider(): iterable 'stream' => [static function (string $body) { $stream = \fopen('php://memory', 'r+b'); + self::assertIsResource($stream); \fwrite($stream, $body); \rewind($stream); @@ -89,6 +94,7 @@ public static function responseBodyProvider(): iterable 'StreamInterface' => [static function (string $body) { $stream = \fopen('php://memory', 'r+b'); + self::assertIsResource($stream); \fwrite($stream, $body); \rewind($stream); @@ -125,6 +131,18 @@ public function testUpdatingResponseBodyUpdatesCrawler(): void self::assertSame('New', $response->filter('p')->text('')); } + public function testDomCrawlerIsLazyLoadedOnDemand(): void + { + $response = $this->makeResponse(body: ''); + + $crawlerProperty = new \ReflectionProperty(Response::class, 'crawler'); + + self::assertNull($crawlerProperty->getValue($response)); + + self::assertSame(0, $response->filter('p')->count()); + self::assertInstanceOf(Crawler::class, $crawlerProperty->getValue($response)); + } + protected function createDroppable(): DroppableInterface { return $this->makeResponse(