Laravel: How can I assertJson an array - laravel

I am creating a feature test for a Seminar. Everything is working great; I am trying to update my feature test to account for the seminar dates.
Each Seminar can have one or many dates, so I am saving these values as a json field:
// migration:
...
$table->json('dates');
...
Here is what my Seminar model looks like:
// Seminar.php
protected $casts = [
'dates' => 'array',
];
When saving the seminar, I am returning a json resource:
if ($seminar->save()) {
return response()->json(new SeminarResource($seminar), 200);
...
Using Postman, my Seminar looks a like this:
...
"capacity": 100,
"dates": [
"2020-10-15",
"2020-10-16"
],
...
So far so good!
In my test, I am testing that a seminar can be created.
$http->assertStatus(201)
->assertJson([
'type' => 'seminars',
'id' => (string)$response->id,
'attributes' => [
'dates' => $response->attributes->dates, // General error: 25 column index out of range
I've tried to convert the array to a string, or json_encode the value in the resource. I don't think that's the correct way since I am already casting the value as an array in the model.
How can I assert that my dates is returning an array?
+"dates": array:2 [
0 => "2020-10-15"
1 => "2020-10-16"
]
Thank you for your suggestions!
EDIT
When I dd($response->attributes->dates); this is what I'm getting (which is correct).
array:2 [
0 => "2020-10-15"
1 => "2020-10-16"
]
What I'm not sure is how to assert an array like that. Since I'm using faker to generate the date, I don't really know (or care) what the date is, just want to assert that it is in fact an array.
I've tried something like:
'dates' => ['*'],
However, that just adds another element to the array.
EDIT 2
If I make the array a string,
'dates' => json_encode($response->attributes->dates),
I'll get an error like this:
--- Expected
+++ Actual
## ##
- 'dates' => '["2020-10-15","2020-10-16"]',
+ 'dates' =>
+ array (
+ 0 => '2020-10-15',
+ 1 => '2020-10-16',
+ ),
In my database, the values are stored like this:
["2020-10-15","2020-10-16"]
My actual test looks like this:
$http->assertStatus(201)
->assertJsonStructure([
'type', 'id', 'attributes' => [
'name', 'venue', 'dates', 'description', 'created_at', 'updated_at',
],
])
->assertJson([
'type' => 'workshops',
'id' => (string)$response->id,
'attributes' => [
'name' => $response->attributes->name,
'venue' => $response->attributes->venue,
'dates' => $response->attributes->dates,
'description' => $response->attributes->description,
'created_at' => (string)$response->attributes->created_at,
'updated_at' => (string)$response->attributes->updated_at,
],
]);
$this->assertDatabaseHas('workshops', [
'id' => $response->id,
'name' => $response->attributes->name,
'venue' => $response->attributes->venue,
'dates' => $response->attributes->dates,
'description' => $response->attributes->description,
]);

Related

How to assert array value but not strict?

How can we assert some of the array's property values which contain the expected object values?
My code below is working okay, but it checks all array property values. I want to ask if there's a way we can check only some of it.
$dataToBeTested = [
'name' => 'Johnny',
'address' => 'Somewhere',
'age' => 21,
'card_no' => 13331577121,
'rep_no' => 441546661,
'status' => 'in-progress',
'created_at' => '2022-07-31T10:05:27.011000Z',
'updated_at' => '2022-07-31T10:05:27.011000Z',
];
$expectedPropValue = [
'name' => 'Johnny',
'address' => 'Somewhere',
'age' => 21,
];
as expected it will return fail, since expectedPropValue has some missing properties.
$this->assertEquals($dataToBeTested, $expectedPropValue);
Goal is something like this,
$this->assertSomeOfIt($dataToBeTested, $expectedPropValue); // return true
You are looking for assertArraySubset, Which it's been deprecated with the newer version of PHPUnit. As mentioned here https://github.com/sebastianbergmann/phpunit/issues/3494. But you can always introduce your approach and use it for your project. Or you can also try this package https://packagist.org/packages/dms/phpunit-arraysubset-asserts. which gives you what you need
self::assertArraySubset($expectedSubset, $content, true);

Laravel: custom array validation depends on previous selected value

Laravel version: 7.x
I have tested the code with hard-coded valid device_company_id (which is associated with the selected device) and it works fine.
Tables
device_companies
|- id
|- company_id
|- title
|- ...
devices
|- id
|- device_company_id
|- ...
Request data
Array
(
...
[devices] => Array
(
[0] => Array
(
[device_company_id] => 1
[device_id] => 2
[device_inventory_id] => null
[amount] =>
[refundable] =>
[description] =>
)
)
)
Rules:
...
$rules = array_merge($rules, [
'devices' => [
'required',
'array'
],
'devices.*.device_company_id' => [
'required',
'integer',
'exists:device_companies,id,company_id,' . auth()->user()->id
],
'devices.*.device_id' => [
'required',
'integer',
'exists:devices,id,device_company_id,devices.*.device_company_id'
],
]);
...
I need a custom validation rule for the exists validator to validate if device actually belongs the selected device_company or not. Because I don't want anyone opening the inspect tool, change the value and causing the application an error or anything like that.
Here is the link where I found the reference https://ericlbarnes.com/2015/04/04/laravel-array-validation/
My code:
...
$rules = [
...other rules
];
$newRules = [
'devices' => [
'required',
'array'
],
'devices.*.device_company_id' => [
'required',
'integer',
'exists:device_companies,id,company_id,' . auth()->user()->id
],
];
foreach($data['devices'] as $key => $array)
{
$newRules["devices.{$key}.device_id"] = [
'required',
'integer',
"exists:devices,id,device_company_id,{$array["device_company_id"]}",
];
}
$rules = array_merge($rules, $newRules);
...
Although, this code is working for me but I feel its not the proper way to do it. It feels kind of a way around instead of the proper solution. If anyone finds a better solution then please do post your answer.
Hope this can be helpful for someone. Thanks :)

Stripe webhook test returns empty table on execution, but works on stripe's webhook tester

We're having a problem with our test suite.
When we run this using the test suite we get a 'The table is empty...' response from PHPUnit.
We know it works as we've also tested using Stripe's 'Send a web hook' test function which works, and the response is stored as expected.
Our code is here:
public function test_webhook_received()
{
$this->expectsJobs([StoreStripeWebHookJob::class]);
$this->postJson('/stripeHook', [
'created' => 1326853478,
'livemode' => false,
'id' => 'evt_00000000000000',
'type' => 'account.external_account.created',
'object' => 'event',
'request' => NULL,
'pending_webhooks' => 1,
'api_version' => '2019-12-03',
'data' => [
'object' => [
'id' => 'ba_00000000000000',
'object' => 'bank_account',
'account' => 'acct_00000000000000',
'account_holder_name' => 'Jane Austin',
'account_holder_type' => 'individual',
'bank_name' => 'STRIPE TEST BANK',
'country' => 'US',
'currency' => 'gbp',
'fingerprint' => '8JXtPxqbdX5GnmYz',
'last4' => '6789',
'metadata' => [],
'routing_number' => '110000000',
'status' => 'new',
],
],
]);
$this->assertDatabaseHas('stripe_webhooks', [
'stripe_created_at' => 1326853478,
'type' => 'account.external_account.created',
]);
}
The response received is:
Failed asserting that a row in the table [stripe_webhooks] matches the
attributes {
"stripe_created_at": 1326853478,
"type": "account.external_account.created" }.
The table is empty..
If we remove the
$this->expectsJobs([StoreStripeWebHookJob::class]);
tests succeed. Obviously the expectsJob() call should be where it is though.
ExpectsJob also intercepts the job. Much like expectsException. Judging from your clean naming convention "StoreStripe..." - I'd say it's really not storing under these test circumstances.
You'll need to test separately that your endpoint/controller is queuing a job... and that the job is storing the data. 2 tests.

Concatenating two arrays and sum with keys via Laravel Collection

I'm having a set of array in something like this format:
[
{"GA_1":"1","GA_2":null,"GA_3":null,"GA_4":null},
{"SA_1":null,"SA_2":"2","SA_3":null,"SA_4":null},
{"RA_1":"1","RA_2":null,"RA_3":null,"RA_4":null}
]
I'm storing this in my mysql text column in json_decoded format. I want to call all the eloquent models and merge these arrays with sum of the each keys on object. For example
1st row contains:
[
{"GA_1":"1","GA_2":null,"GA_3":null,"GA_4":null},
{"SA_1":null,"SA_2":"2","SA_3":null,"SA_4":null},
{"RA_1":"1","RA_2":null,"RA_3":null,"RA_4":null}
]
2nd row contains:
[
{"GA_1":null,"GA_2":"1","GA_3":"2","GA_4":null},
{"SA_1":"1","SA_2":null,"SA_3":"3","SA_4":null},
{"RA_1":null,"RA_2":"2","RA_3":null,"RA_4":"5"}
]
3rd row contains:
[
{"GA_1":"1","GA_2":null,"GA_3":null,"GA_4":null},
{"SA_1":null,"SA_2":"2","SA_3":null,"SA_4":null},
{"RA_1":"1","RA_2":null,"RA_3":null,"RA_4":null}
]
so my final output should be:
[
{"GA_1":"2","GA_2":"1","GA_3":"2","GA_4":null},
{"SA_1":"1","SA_2":"4","SA_3":null,"SA_4":null},
{"RA_1":"1","RA_2":"2","RA_3":null,"RA_4":"5"}
]
I'm stuck in how can I achieve this:
$games = Game::get();
$grid = [];
foreach ($games as $game) {
$grid[] = collect($game->grid_values);
}
dd(collect('$grid')->flatten());
I'm getting this output:
Any suggestions are welcome. Thanks.
Well I tried something like this:
$games = Game::get();
$d = collect($games)->map(function($item) {
return json_decode($item->grid_values);
})->flatten();
$x = collect([
[
'GA_1' => $d->sum('GA_1'),
'GA_2' => $d->sum('GA_2'),
'GA_3' => $d->sum('GA_3'),
'GA_4' => $d->sum('GA_4'),
'GA_5' => $d->sum('GA_5'),
'GA_6' => $d->sum('GA_6'),
'GA_7' => $d->sum('GA_7'),
'GA_8' => $d->sum('GA_8'),
'GA_9' => $d->sum('GA_9'),
'GA_0' => $d->sum('GA_0'),
],
[
'SA_1' => $d->sum('SA_1'),
'SA_2' => $d->sum('SA_2'),
'SA_3' => $d->sum('SA_3'),
'SA_4' => $d->sum('SA_4'),
'SA_5' => $d->sum('SA_5'),
'SA_6' => $d->sum('SA_6'),
'SA_7' => $d->sum('SA_7'),
'SA_8' => $d->sum('SA_8'),
'SA_9' => $d->sum('SA_9'),
'SA_0' => $d->sum('SA_0'),
],
[
'RA_1' => $d->sum('RA_1'),
'RA_2' => $d->sum('RA_2'),
'RA_3' => $d->sum('RA_3'),
'RA_4' => $d->sum('RA_4'),
'RA_5' => $d->sum('RA_5'),
'RA_6' => $d->sum('RA_6'),
'RA_7' => $d->sum('RA_7'),
'RA_8' => $d->sum('RA_8'),
'RA_9' => $d->sum('RA_9'),
'RA_0' => $d->sum('RA_0'),
],
]);
return response()->json(['data' => $x], 200);
And I got expected result, any improvisation please suggest.

Override eloquent relationship result data

I use Laravel-Metable package in my project. This package return collection object using in key meta name and on value eloquent object.
Here you can see package data result screenshot.
How I can override result data and get this type of array data:
$meta = [
[
'id' => 1,
'key' => "Meta Name",
'value' => "Meta Value"
],
[
'id' => 2,
'key' => "Meta Name",
'value' => "Meta Value"
],
];
I will load my models meta with lazy loading:
use Metable;
protected $with = ['meta'];
You can use the collection map method for that so it should be something like this:
$result = $metaItems->map(function($meta) {
return [
'id' => $meta->id,
'key' => $meta->key,
'value' => $meta->value
];
})->values();
// then $result->toArray(); should give you the expected result

Resources