diff --git a/src/Codeception/Module/REST.php b/src/Codeception/Module/REST.php index 4c31898..87110ab 100644 --- a/src/Codeception/Module/REST.php +++ b/src/Codeception/Module/REST.php @@ -1100,6 +1100,67 @@ public function seeResponseJsonMatchesXpath(string $xPath): void ); } + /** + * Checks if applying xpath to json structure in response matches the expected result. + * JSON is not supposed to be checked against XPath, yet it can be converted to xml and used with XPath. + * This assertion allows you to check the structure of response json. + * * + * ```json + * { "store": { + * "book": [ + * { "category": "reference", + * "author": "Nigel Rees", + * "title": "Sayings of the Century", + * "price": 8.95 + * }, + * { "category": "fiction", + * "author": "Evelyn Waugh", + * "title": "Sword of Honour", + * "price": 12.99 + * } + * ], + * "bicycle": { + * "color": "red", + * "price": 19.95 + * } + * } + * } + * ``` + * + * ```php + * seeResponseJsonXpathEvaluatesTo('count(//store/book/author) > 0', true); + * // count the number of books written by given author is 5 + * $I->seeResponseJsonMatchesXpath("//author[text() = 'Nigel Rees']", 1.0); + * ``` + * @part json + */ + public function seeResponseJsonXpathEvaluatesTo(string $xPath, $expected): void + { + $response = $this->connectionModule->_getResponseContent(); + $this->assertEquals( + $expected, + (new JsonArray($response))->evaluateXPath($xPath), + "Received JSON did not evualated XPath `{$xPath}` as expected.\nJson Response: \n" . $response + ); + } + + /** + * Opposite to seeResponseJsonXpathEvaluatesTo + * + * @part json + */ + public function dontSeeResponseJsonXpathEvaluatesTo(string $xPath, $expected): void + { + $response = $this->connectionModule->_getResponseContent(); + $this->assertNotEquals( + $expected, + (new JsonArray($response))->evaluateXPath($xPath), + "Received JSON did not evualated XPath `{$xPath}` as expected.\nJson Response: \n" . $response + ); + } + /** * Opposite to seeResponseJsonMatchesXpath * diff --git a/src/Codeception/Util/JsonArray.php b/src/Codeception/Util/JsonArray.php index a1cae64..d0592c0 100644 --- a/src/Codeception/Util/JsonArray.php +++ b/src/Codeception/Util/JsonArray.php @@ -75,6 +75,12 @@ public function filterByXPath(string $xPath): DOMNodeList|false $path = new DOMXPath($this->toXml()); return $path->query($xPath); } + + public function evaluateXPath(string $xPath): mixed + { + $path = new DOMXPath($this->toXml()); + return $path->evaluate($xPath); + } public function filterByJsonPath(string $jsonPath): array { diff --git a/tests/unit/Codeception/Module/RestTest.php b/tests/unit/Codeception/Module/RestTest.php index acafe1c..1efbf33 100644 --- a/tests/unit/Codeception/Module/RestTest.php +++ b/tests/unit/Codeception/Module/RestTest.php @@ -566,6 +566,31 @@ public function testSeeResponseJsonMatchesXpathCanHandleResponseWithOneSubArray( $this->module->seeResponseJsonMatchesXpath('//array/success'); } + + public function testSeeResponseJsonXpathEvaluatesToBoolean() + { + $this->setStubResponse('{"success": 1}'); + $this->module->seeResponseJsonXpathEvaluatesTo('count(//success) > 0', true); + } + + public function testSeeResponseJsonXpathEvaluatesToNumber() + { + $this->setStubResponse('{"success": 1}'); + $this->module->seeResponseJsonXpathEvaluatesTo('count(//success)', 1.0); + } + + public function testDontSeeResponseJsonXpathEvaluatesToBoolean() + { + $this->setStubResponse('{"success": 1}'); + $this->module->dontSeeResponseJsonXpathEvaluatesTo('count(//success) > 0', false); + } + + public function testDontSeeResponseJsonXpathEvaluatesToNumber() + { + $this->setStubResponse('{"success": 1}'); + $this->module->dontSeeResponseJsonXpathEvaluatesTo('count(//success)', 0.0); + } + public function testSeeBinaryResponseEquals() { $data = base64_decode('/9j/2wBDAAMCAgICAgMCAgIDAwMDBAYEBAQEBAgGBgUGCQgKCgkICQkKDA8MCgsOCwkJDRENDg8QEBEQCgwSExIQEw8QEBD/yQALCAABAAEBAREA/8wABgAQEAX/2gAIAQEAAD8A0s8g/9k='); diff --git a/tests/unit/Codeception/Util/JsonArrayTest.php b/tests/unit/Codeception/Util/JsonArrayTest.php index 8f5daaa..19c0023 100644 --- a/tests/unit/Codeception/Util/JsonArrayTest.php +++ b/tests/unit/Codeception/Util/JsonArrayTest.php @@ -36,6 +36,13 @@ public function testXmlArrayConversion2() $this->assertSame(2, $jsonArray->filterByXPath('//user')->length); } + public function testXPathEvaluation() + { + $this->assertSame(true, $this->jsonArray->evaluateXPath('count(//ticket/title)>0')); + $this->assertEquals(1.0 , $this->jsonArray->evaluateXPath('count(//ticket/user/name)')); + $this->assertSame(true, $this->jsonArray->evaluateXPath("count(//user/name[text() = 'Davert']) > 0")); + } + public function testXPathLocation() { $this->assertGreaterThan(0, $this->jsonArray->filterByXPath('//ticket/title')->length);