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);
Related
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,
]);
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.
I use a versioning system to save multiple versions of a 'minor' (a model in my application). It contains quite a few fields, like name, goals, requirements, subject and many more. When I save a new version, or 'version 2', using eloquent, it also changes the other version.
I have tried multiple ways of saving the minor, like requesting the first one and updating it like below, or changing each individual item one-by-one.
Minor::limit(1)
->where("id", $id)
->where('version', $_POST['version'])
->first()
->update([
'name' => $_POST['name'],
'ects' => floatval($_POST['ects']),
'contact_hours' => intval($_POST['contact_hours']),
'education_type' => $_POST['education_type'],
'language' => $_POST['language'],
'subject' => Input::get('subject'),
'goals' => Input::get('goals'),
'requirements' => Input::get('requirements'),
]);
It should only save the selected version, but instead, it overwrites all versions of the minor with the same ID and saves them to the database.
How can I prevent this, or does anyone have an idea on how to fix this?
You can try using updateOrCreate method:
Minor::updateOrCreate([
'id' => $id,
'version' => $_POST['version']
],[
'name' => $_POST['name'],
'ects' => floatval($_POST['ects']),
'contact_hours' => intval($_POST['contact_hours']),
'education_type' => $_POST['education_type'],
'language' => $_POST['language'],
'subject' => Input::get('subject'),
'goals' => Input::get('goals'),
'requirements' => Input::get('requirements'),
]);
I still don't know why this happened or how to fix it using the same method. I have however found a way around it. I now update and save the minor with the ->update([...]) method build into eloquent.
Minor::where([["id", "139858"], ["version", Input::get('version')]])
->update([
'name' => Input::get('name'),
'ects' => Input::get('ects'),
'contact_hours' => Input::get('contact_hours'),
'education_type' => Input::get('education_type'),
'language' => Input::get('language'),
'subject' => Input::get('subject'),
'requirements' => Input::get('requirements'),
'goals' => Input::get('goals')
]);
This doesn't seem to alter the other versions. This is the only way I found to make it work, you can't make a variable of the object, change values and then save it. That would overwrite the other versions.
I have a Model which contains many foreign keys. One of those foreign keys must be a unique value.
My validation rules are the following ones:
$data['rules'] = [
'address' => 'required|string',
'buyer_id' => 'required|exists:buyers,id',
'buyer_name' => 'required|string',
'date' => 'required|date',
'email' => 'required|email',
'identification_photo' => 'required|string',
'invoice' => 'string|required',
'middleman_id' => 'nullable|exists:middlemen,id',
'price' => 'required|numeric|between:1,99999999999999999999999999.9999',
'property_id' => 'required|exists:properties,id|unique:reservations,property_id',
'purchase_receipt' => 'required|string',
'rfc' => array(
'required',
'regex:/^([A-Z,Ñ,&]{3,4}([0-9]{2})(0[1-9]|1[0-2])(0[1-9]|1[0-9]|2[0-9]|3[0-1])[A-Z|\d]{3})$/'
),
'tier_id' => 'nullable|exists:tiers,id',
'user_id' => 'required|exists:users,id',
];
The one that I have trouble is property_id. This must be unique in the current table which is reservations.
In order to ignore that validation when I make an update, I'm adding this line of code before calling the Validator:
$book['rules']['property_id'] .= ",{$item->property_id}";
And when I do a Log::info of all my rules, I got the following line: 'property_id' => 'required|exists:properties,id|unique:reservations,property_id,4',
But I keep receiving the error. Am I doing something wrong?
The error is on this line:
$book['rules']['property_id'] .= ",{$item->property_id}";
Instead of passing the id of the foreign key you want to ignore, you have to give the current model ID in order to ignore that validation for a specific item.
$book['rules']['property_id'] .= ",{$item->id}";
With this you tell that for your Model with id = x, ignore that specific validation. To understand it in a better way, you are telling that for this validation, ignore the validation of the property only for the record with id equals to the $item->id.
I think the line of code you are looking for is
'property_id' => 'required|exists:properties,id|unique:reservations,property_id,'.$request->id',
This ignores the current row you are updating while also validating your property_id
In database seeder, I just want to insert some hard-coded data to the table.
$Pro1_id = DB::table('projects')->select('id')->where('projectName', '=', 'Project A')->get();
$data1_1 = array(
'id' => 1,
'projectID' => $Pro1_id,
'attributeID' => 1,
'levelID' => 2,
'percentage' => 20,
'risk_value' => 25186.86311,
'expectation_value' => 706455.9401,
);
$data1_2 = array(
'projectID' => $Pro1_id,
'attributeID' => 2,
'levelID' => 1,
'percentage' => 60,
'risk_value' => 530351.3397,
'expectation_value' => 392207.1248,
);
$data1 = [$data1_1, $data1_2];
DB::table('Mapping')->insert($data1);
However, I got the error:
[ErrorException] preg_replace(): Parameter mismatch, pattern is a
string while replacement is an array
It is so weird, because I did the same to another table, it worked.
DB::table('projects')->insert(array(
array(
'id' => Webpatser\Uuid\Uuid::generate(),
'projectName' => 'Project A',
'creator_id' => $pro1_creatorID,
'create_at' => \Carbon\Carbon::now()->toDateString(),
'lastEditor_id' => $pro1_creatorID,
'edit_at' => \Carbon\Carbon::now()->toDateString(),
'utility' => 1.597119661,
'exponential' => 4.94,
'projectValue' => 1225090.39
),
array(
'id' => Webpatser\Uuid\Uuid::generate(),
'projectName' => 'Project B',
'creator_id' => $pro2_creatorID,
'create_at' => \Carbon\Carbon::create(2014, 12, 12)->toDateString(),
'lastEditor_id' => $pro2_creatorID,
'edit_at' => \Carbon\Carbon::create(2014, 12, 12)->toDateString(),
'utility' => 1.754989409,
'exponential' => 5.78,
'projectValue' => 293760.36
),
array(
'id' => Webpatser\Uuid\Uuid::generate(),
'projectName' => 'Project C',
'creator_id' => $pro3_creatorID,
'create_at' => \Carbon\Carbon::create(2013, 10, 21)->toDateString(),
'lastEditor_id' => $pro3_creatorID,
'edit_at' => \Carbon\Carbon::create(2013, 10, 21)->toDateString(),
'utility' => 1.423114267,
'exponential' => 4.15,
'projectValue' => 1461924.67
)
)
);
I really don't understand why inserting into projects table works, but the one of the mapping table does NOT work.
They are exactly the same method.
I think your code is correct but when you insert the id in array, you are doing the wrong way.
$Pro1_id = DB::table('projects')->select('id')->where('projectName', '=', 'Project A')->get();
Here, $Pro1_id is Collection that contain value return from your query. Sometimes it might be one, but sometimes it might be 2 or 3.... So , your are doing the wrong way when you are inserting the id in the array. So , use foreach loop like this :
foreach($Pro1_id as $pro){
DB::table('Mapping')->insert(array(
'id' => 1,
'projectID' => $pro->id,
'attributeID' => 1,
'levelID' => 2,
'percentage' => 20,
'risk_value' => 25186.86311,
'expectation_value' => 706455.9401,
));
}
For simple , get returns Collection and is rather supposed to fetch multiple rows.
For more info . Check this