diff --git a/CHANGELOG.md b/CHANGELOG.md index f8364d9..c9c5073 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,8 @@ Updates should follow the [Keep a CHANGELOG](http://keepachangelog.com/) princip ## Unreleased -- Nothing +### Added +- Add an option to ignore certain query parameters. See readme for more info. ## [2.3.2] - 2021-08-30 diff --git a/README.md b/README.md index d77ca4e..96935a4 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![PHP from Packagist](https://img.shields.io/packagist/php-v/swisnl/php-http-fixture-client.svg)](https://packagist.org/packages/swisnl/php-http-fixture-client) [![Latest Version on Packagist](https://img.shields.io/packagist/v/swisnl/php-http-fixture-client.svg)](https://packagist.org/packages/swisnl/php-http-fixture-client) -[![Software License](https://img.shields.io/packagist/l/swisnl/php-http-fixture-client.svg)](https://github.com/swisnl/php-http-fixture-client/blob/master/LICENSE) +[![Software License](https://img.shields.io/packagist/l/swisnl/php-http-fixture-client.svg)](https://github.com/swisnl/php-http-fixture-client/blob/master/LICENSE) [![Buy us a tree](https://img.shields.io/badge/Treeware-%F0%9F%8C%B3-lightgreen.svg)](https://plant.treeware.earth/swisnl/php-http-fixture-client) [![Build Status](https://travis-ci.org/swisnl/php-http-fixture-client.svg?branch=master)](https://travis-ci.org/swisnl/php-http-fixture-client) [![Scrutinizer Coverage](https://img.shields.io/scrutinizer/coverage/g/swisnl/php-http-fixture-client.svg)](https://scrutinizer-ci.com/g/swisnl/php-http-fixture-client/?branch=master) @@ -57,6 +57,13 @@ Please see the following table for some examples. | | | /path/to/fixtures/example.com/api/comments.get.mock | | | | /path/to/fixtures/example.com/api/comments.mock | +### Ignored query parameters +The `ReponseBuilder` can be instructed to ignore certain query parameters using `setIgnoredQueryParameters([...])`. +When configured, the provided parameters will be ignored when transforming requests to file paths. +You should only provide the parameter name, not the value. +This allows you to ignore 'dynamic' parameters that change in each test execution. +Parameters are matched strictly, so 'foo' will match 'foo=bar', but not 'foo[]=bar'. + ### Strict mode The `ReponseBuilder` can be set to strict mode using `setStrictMode(true)`. When in strict mode, only the first possible fixture path will be used. @@ -68,7 +75,7 @@ This means that both the method and query params must be present in the fixture ### Body The body of a request is loaded directly from a fixture with the file extension _.mock_. -The contents of this file can be anything that is a valid HTTP response, e.g. HTML, JSON or even images. +The contents of this file can be anything that is a valid HTTP response, e.g. HTML, JSON or even images. If a fixture can not be found, a `MockNotFoundException` will be thrown. This exception has a convenience method `getPossiblePaths()` which lists all file paths that were checked, in order of specificity. @@ -120,4 +127,4 @@ This package is [Treeware](https://treeware.earth). If you use it in production, ## SWIS :heart: Open Source -[SWIS](https://www.swis.nl) is a web agency from Leiden, the Netherlands. We love working with open source software. +[SWIS](https://www.swis.nl) is a web agency from Leiden, the Netherlands. We love working with open source software. diff --git a/src/ResponseBuilder.php b/src/ResponseBuilder.php index f11ed14..583d7d8 100644 --- a/src/ResponseBuilder.php +++ b/src/ResponseBuilder.php @@ -45,6 +45,11 @@ class ResponseBuilder implements ResponseBuilderInterface */ private $strictMode = false; + /** + * @var array + */ + private $ignoredQueryParameters = []; + /** * @param string $fixturesPath * @param array $domainAliases @@ -77,6 +82,26 @@ public function setStrictMode(bool $strictMode): self return $this; } + /** + * @return array + */ + public function getIgnoredQueryParameters(): array + { + return $this->ignoredQueryParameters; + } + + /** + * @param array $ignoredQueryParameters + * + * @return self + */ + public function setIgnoredQueryParameters(array $ignoredQueryParameters): self + { + $this->ignoredQueryParameters = $ignoredQueryParameters; + + return $this; + } + /** * @param \Psr\Http\Message\RequestInterface $request * @@ -256,7 +281,12 @@ protected function getMethodFromRequest(RequestInterface $request): string protected function getQueryFromRequest(RequestInterface $request, string $replacement = '-'): string { $query = urldecode($request->getUri()->getQuery()); - $parts = explode('&', $query); + $parts = array_filter( + explode('&', $query), + function (string $part) { + return !$this->isQueryPartIgnored($part); + } + ); sort($parts); $query = implode('&', $parts); @@ -267,6 +297,22 @@ protected function getQueryFromRequest(RequestInterface $request, string $replac ->removeRight($replacement); } + /** + * @param string $part + * + * @return bool + */ + protected function isQueryPartIgnored(string $part): bool + { + foreach ($this->getIgnoredQueryParameters() as $parameter) { + if ($part === $parameter || strncmp($part, $parameter.'=', strlen($parameter) + 1) === 0) { + return true; + } + } + + return false; + } + /** * @return string */ diff --git a/tests/ResponseBuilderTest.php b/tests/ResponseBuilderTest.php index cef4f84..5a54f4e 100644 --- a/tests/ResponseBuilderTest.php +++ b/tests/ResponseBuilderTest.php @@ -126,6 +126,25 @@ public function itCanBuildAResponseUsingDomainAliases() $this->assertEquals($expectedResponse->getBody()->__toString(), $actualResponse->getBody()->__toString()); } + /** + * @test + */ + public function itCanBuildAResponseWithIgnoredParameters(): void + { + // arrange + $messageFactory = MessageFactoryDiscovery::find(); + $builder = $this->getBuilder()->setIgnoredQueryParameters(['ignore-me', 'ignore-me-too']); + + $expectedResponse = $messageFactory->createResponse() + ->withBody(Utils::streamFor(file_get_contents($this->getFixturesPath().'/example.com/api/articles.mock'))); + + // act + $actualResponse = $builder->build($messageFactory->createRequest('GET', 'https://example.com/api/articles?ignore-me=true&ignore-me-too')); + + // assert + $this->assertEquals($expectedResponse->getBody()->__toString(), $actualResponse->getBody()->__toString()); + } + /** * @test */