From 87ccbb5a8bf610a2f58bada88c682d21f594c91a Mon Sep 17 00:00:00 2001 From: Vincent Amstoutz Date: Tue, 17 Jun 2025 10:44:20 +0200 Subject: [PATCH] [JsonPath] Add test documentation for the component --- components/json_path.rst | 122 ++++++++++++++++++++++++++++++++++----- 1 file changed, 107 insertions(+), 15 deletions(-) diff --git a/components/json_path.rst b/components/json_path.rst index ec5db0e8e74..294eed98917 100644 --- a/components/json_path.rst +++ b/components/json_path.rst @@ -30,9 +30,9 @@ You can install the component in your project using Composer: Usage ----- -To start querying a JSON document, first create a :class:`Symfony\\Component\\JsonPath\\JsonCrawler` -object from a JSON string. The following examples use this sample "bookstore" -JSON data:: +To start querying a JSON document, first create a +:class:`Symfony\\Component\\JsonPath\\JsonCrawler`object from a JSON string. The +following examples use this sample "bookstore" JSON data:: use Symfony\Component\JsonPath\JsonCrawler; @@ -77,8 +77,9 @@ JSON data:: $crawler = new JsonCrawler($json); -Once you have the crawler instance, use its :method:`Symfony\\Component\\JsonPath\\JsonCrawler::find` -method to start querying the data. This method returns an array of matching values. +Once you have the crawler instance, use its +:method:`Symfony\\Component\\JsonPath\\JsonCrawler::find` method to start +querying the data. This method returns an array of matching values. Querying with Expressions ------------------------- @@ -97,9 +98,9 @@ of the document is represented by ``$``:: // $titles is ['Sayings of the Century'] -Dot notation is the default, but JSONPath provides other syntaxes for cases where -it doesn't work. Use bracket notation (``['...']``) when a key contains spaces -or special characters:: +Dot notation is the default, but JSONPath provides other syntaxes for cases +where it doesn't work. Use bracket notation (``['...']``) when a key contains +spaces or special characters:: // this is equivalent to the previous example $titles = $crawler->find('$["store"]["book"][0]["title"]'); @@ -119,7 +120,12 @@ you to find values without specifying the full path:: // get all authors from anywhere in the document $authors = $crawler->find('$..author'); - // $authors is ['Nigel Rees', 'Evelyn Waugh', 'Herman Melville', 'John Ronald Reuel Tolkien'] + // $authors is equals to [ + 'Nigel Rees', + 'Evelyn Waugh', + 'Herman Melville', + 'John Ronald Reuel Tolkien' + ] Filtering Results ~~~~~~~~~~~~~~~~~ @@ -135,8 +141,9 @@ Building Queries Programmatically For more dynamic or complex query building, use the fluent API provided by the :class:`Symfony\\Component\\JsonPath\\JsonPath` class. This lets you -construct a query object step by step. The ``JsonPath`` object can then be passed -to the crawler's :method:`Symfony\\Component\\JsonPath\\JsonCrawler::find` method. +construct a query object step by step. The ``JsonPath`` object can then be +passed to the crawler's +:method:`Symfony\\Component\\JsonPath\\JsonCrawler::find` method. The main advantage of the programmatic builder is that it automatically handles escaping of keys and values, preventing syntax errors:: @@ -178,7 +185,8 @@ methods to build your query: * :method:`Symfony\\Component\\JsonPath\\JsonPath::index` Adds an array index selector. Index numbers start at ``0``. -* :method:`Symfony\\Component\\JsonPath\\JsonPath::first` / :method:`Symfony\\Component\\JsonPath\\JsonPath::last` +* :method:`Symfony\\Component\\JsonPath\\JsonPath::first` / + :method:`Symfony\\Component\\JsonPath\\JsonPath::last` Shortcuts for ``index(0)`` and ``index(-1)`` respectively:: // get the last book: '$["store"]["book"][-1]' @@ -213,17 +221,101 @@ filters, refer to the `Querying with Expressions`_ section above. All these features are supported and can be combined with the programmatic builder when appropriate (e.g., inside a ``filter()`` expression). +Testing with JSON Assertions +---------------------------- + +The component provides a set of PHPUnit assertions to make testing JSON data +more convenient. Use the +:class:`Symfony\\Component\\JsonPath\\Test\\JsonPathAssertionsTrait` +in your test class:: + + use PHPUnit\Framework\TestCase; + use Symfony\Component\JsonPath\Test\JsonPathAssertionsTrait; + + class MyTest extends TestCase + { + use JsonPathAssertionsTrait; + + public function testSomething(): void + { + $json = '{"books": [{"title": "A"}, {"title": "B"}]}'; + + self::assertJsonPathCount(2, '$.books[*]', $json); + } + } + +The trait provides the following assertion methods: + +* :method:`Symfony\\Component\\JsonPath\\Test\\JsonPathAssertionsTrait::assertJsonPathCount` + Asserts that the number of elements found by the JSONPath expression matches + an expected count:: + + $json = '{"a": [1, 2, 3]}'; + self::assertJsonPathCount(3, '$.a[*]', $json); + +* :method:`Symfony\\Component\\JsonPath\\Test\\JsonPathAssertionsTrait::assertJsonPathEquals` + Asserts that the result of a JSONPath expression is equal to an expected + value. The comparison uses ``==`` (type coercion) instead of ``===``:: + + $json = '{"a": [1, 2, 3]}'; + + // passes because "1" == 1 + self::assertJsonPathEquals(['1'], '$.a[0]', $json); + +* :method:`Symfony\\Component\\JsonPath\\Test\\JsonPathAssertionsTrait::assertJsonPathNotEquals` + Asserts that the result of a JSONPath expression is not equal to an expected + value. The comparison uses ``!=`` (type coercion) instead of ``!==``:: + + $json = '{"a": [1, 2, 3]}'; + self::assertJsonPathNotEquals([42], '$.a[0]', $json); + +* :method:`Symfony\\Component\\JsonPath\\Test\\JsonPathAssertionsTrait::assertJsonPathSame` + Asserts that the result of a JSONPath expression is identical (``===``) to an + expected value. This is a strict comparison and does not perform type + coercion:: + + $json = '{"a": [1, 2, 3]}'; + + // fails because "1" !== 1 + // self::assertJsonPathSame(['1'], '$.a[0]', $json); + + self::assertJsonPathSame([1], '$.a[0]', $json); + +* :method:`Symfony\\Component\\JsonPath\\Test\\JsonPathAssertionsTrait::assertJsonPathNotSame` + Asserts that the result of a JSONPath expression is not identical (``!==``) to + an expected value:: + + $json = '{"a": [1, 2, 3]}'; + self::assertJsonPathNotSame(['1'], '$.a[0]', $json); + +* :method:`Symfony\\Component\\JsonPath\\Test\\JsonPathAssertionsTrait::assertJsonPathContains` + Asserts that a given value is found within the array of results from the + JSONPath expression:: + + $json = '{"tags": ["php", "symfony", "json"]}'; + self::assertJsonPathContains('symfony', '$.tags[*]', $json); + +* :method:`Symfony\\Component\\JsonPath\\Test\\JsonPathAssertionsTrait::assertJsonPathNotContains` + Asserts that a given value is NOT found within the array of results from the + JSONPath expression:: + + $json = '{"tags": ["php", "symfony", "json"]}'; + self::assertJsonPathNotContains('java', '$.tags[*]', $json); + Error Handling -------------- The component throws specific exceptions for invalid input or queries: * :class:`Symfony\\Component\\JsonPath\\Exception\\InvalidArgumentException`: - Thrown if the input to the ``JsonCrawler`` constructor is not a valid JSON string; + Thrown if the input to the ``JsonCrawler`` constructor is not a valid JSON +string; * :class:`Symfony\\Component\\JsonPath\\Exception\\InvalidJsonStringInputException`: - Thrown during a ``find()`` call if the JSON string is malformed (e.g., syntax error); + Thrown during a ``find()`` call if the JSON string is malformed +(e.g., syntax error); * :class:`Symfony\\Component\\JsonPath\\Exception\\JsonCrawlerException`: - Thrown for errors within the JsonPath expression itself, such as using an unknown function + Thrown for errors within the JsonPath expression itself, such as using an + unknown function Example of handling errors::