Skip to content

Commit

Permalink
Add (dont)seeResponseJsonXpathEvaluatesTo methods
Browse files Browse the repository at this point in the history
* compare result of evaluated xpath expression to value

* replace same instead equal

* bug fix tests

* bug fix docu

* Change assertions to stricter

* Revert test change, because evalueXpath returns float

* expect float

* revert to assertEquals

* Use assertEquals in new methods

because float can be returned when integer is expected

* Remoce unnecessary space

Co-authored-by: Gintautas Miselis <gintautas@miselis.lt>
  • Loading branch information
pamoller and Naktibalda committed Aug 13, 2022
1 parent 2b21087 commit 2535889
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 0 deletions.
61 changes: 61 additions & 0 deletions src/Codeception/Module/REST.php
Expand Up @@ -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
* <?php
* // at least one book in store has author
* $I->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
*
Expand Down
6 changes: 6 additions & 0 deletions src/Codeception/Util/JsonArray.php
Expand Up @@ -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
{
Expand Down
25 changes: 25 additions & 0 deletions tests/unit/Codeception/Module/RestTest.php
Expand Up @@ -567,6 +567,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=');
Expand Down
7 changes: 7 additions & 0 deletions tests/unit/Codeception/Util/JsonArrayTest.php
Expand Up @@ -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);
Expand Down

1 comment on commit 2535889

@pamoller
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fine, thanks. It was dropped out off my mind: XPath numbers are always floats.

Please sign in to comment.