-
Notifications
You must be signed in to change notification settings - Fork 11.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[8.x] Add Fluent JSON Assertions #36454
Conversation
Can you explain the |
Sure! Since the Explaining the interaction checkSo, given the following JSON payload: {
"user": {
"id": 5,
"name": "Claudio Dekker",
"email": "claudio@example.com",
"created_at": "2020-01-01 00:00:00",
"updated_at": "2020-01-01 00:00:00",
"posts": [
{
"id": 12,
"user_id": 5,
"title": "This is a post title",
"summary": "Once upon a time..",
"created_at": "2020-01-01 01:00:00",
"updated_at": "2020-01-01 00:00:00",
}
]
}
} When you create a $response->assertJson(fn (Assert $json) => $json
// Start a new 'has' scope.
->has('user', fn (Assert $json) => $json
->where('id', 5)
->where('name', "Claudio Dekker")
)
); Because we haven't interacted with the other properties in the scope ( The reason this logic exists is pretty straight forward: If we didn't have this, and we were to somehow accidentally expose the So by automatically handling this internally instead, the user always gets this benefit and peace-of-mind of knowing they haven't missed anything without any additional effort. Explaining the
|
@claudiodekker
Here it is asserting just the first |
This PR implements Inertia's Laravel Testing helpers as generic JSON helpers for Laravel.
While I initially wrote this code for Inertia specifically, one of the first things @reinink mentioned was that these would be amazing to have as first-party tooling to test JSON API's in Laravel, as (and we both share this opinion) the current JSON testing helpers can be difficult to use sometimes. It goes without saying that all Inertia-specific code has been stripped out.
Example
Here's an example of how this can be used, do note that while this shares the
assertJson
method, it is entirely backwards compatible:Basics
There's two ways to start using this, both of which rely on the 'Fluent Assert' class that this PR adds.
In the more-common scenario (testing a JSON API response), you would use it as already demonstrated above:
Alternatively, you may instantiate the object manually, even on non-JSON arrays if you wish:
Furthermore, while the scoping syntax above is by far the nicest to use with PHP 8's arrow functions, there's nothing preventing you from using standard functions.
Available Assertions
has
where
etc
missing
Reducing verbosity (multiple assertions):
hasAll
whereAll
missingAll
Helpers:
dump
&dd
)Finally, the entire thing is Macroable and Tappable as well, so if someone really wants they can make use of those functionalities as well!
has
Basic Usage
To assert that your JSON response has a property, you may use the
has
method.You can think of
has
similar to PHP'sisset
:Count / Size / Length
To assert that your JSON response has a certain amount of items, you may provide the expected size as the second argument:
The above will first assert that the property exists, as well as that is the expected size.
This means that there is no need to manually ensure that the property exists using a separate
has
call.Scoping
The deeper your assertions go, the more complex and verbose they can become:
Fortunately, using scopes, we can remove this problem altogether through the
has
method:While this is already a significant improvement, that's not all: As you can see in the example above, you'll often run
into situations where you'll want to check that a property has a certain length, and then tap into one of the entries
to make sure that all the props there are as expected:
To simplify this, you can simply combine the two calls, providing the scope as the third argument:
where
To assert that an property has an expected value, you may use the
where
assertion:Under the hood, this first calls the
has
method to ensure that the property exists, and then uses an assertion tomake sure that the values match. This means that there is no need to manually call
has
andwhere
on the same exact prop.Automatic Eloquent
Model
/Arrayable
castingFor convenience, the
where
method doesn't just assert using basic JSON values, but also has the ability totest directly against Eloquent Models and other classes that implement the
Arrayable
interface.For example:
Using a Closure
Finally, it's also possible to assert against a callback / closure. To do so, simply provide a callback as the value,
and make sure that the response is
true
in order to make the assertion pass, or anything else to fail the assertion:Because working with arrays directly isn't always a great experience, we'll automatically cast arrays to
Collections:
etc
This library will automatically fail your test when you haven't interacted with at least one of the props in a scope.
While this is generally useful, you might run into situations where you're working with unreliable data
(such as from a feed), or with data that you really don't want interact with, in order to keep your test simple.
For those situations, the
etc
method exists:missing
Because
missing
isn't necessary by default, it provides a great solution when usingetc
.In short, it does the exact opposite of the
has
method, ensuring that the property does not exist:Reducing verbosity
To reduce the amount of
where
,has
ormissing
calls, there are a couple of convenience methods that allow you tomake these same assertions in a slightly less-verbose looking way. Do note that these methods do not make your assertions
any faster, and really only exist to help you reduce your test's visual complexity.
has
Instead of making multiple
has
calls, you may use thehasAll
assertion instead. Depending on how you providearguments, this method will perform a series of slightly different but predictable assertion:
Basic
has
usageCount / Size / Length
where
To reduce the amount of
where
calls, thewhereAll
method exists.Since this method checks properties against values by design, there isn't a lot of flexibility like with some of these
other methods, meaning that only the array-syntax exists for it right now:
missing
Instead of making multiple
missing
call, you may usemissingAll
instead.Similar to basic
hasAll
usage, this assertion accepts both a single array or a list of arguments, at which point itwill assert that the given props do not exist:
Debugging
While writing your tests, you might find yourself wanting to inspect some of the page's props using Laravel's
dump
ordd
helpers. Luckily, this is really easy to do, and would work more or less how you'd expect it to: