Merge pull request #15533 from marcusmoore/testing/fmcs-accessories

Added tests for accessory api controller
This commit is contained in:
snipe 2024-10-11 11:29:34 +01:00 committed by GitHub
commit de62359c67
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 542 additions and 58 deletions

View file

@ -137,7 +137,6 @@ class AccessoriesController extends Controller
*/
public function store(StoreAccessoryRequest $request)
{
$this->authorize('create', Accessory::class);
$accessory = new Accessory;
$accessory->fill($request->all());
$accessory = $request->handleImages($accessory);
@ -197,9 +196,6 @@ class AccessoriesController extends Controller
$this->authorize('view', Accessory::class);
$accessory = Accessory::with('lastCheckout')->findOrFail($id);
if (! Company::isCurrentUserHasAccess($accessory)) {
return ['total' => 0, 'rows' => []];
}
$offset = request('offset', 0);
$limit = request('limit', 50);
@ -325,7 +321,7 @@ class AccessoriesController extends Controller
$accessory = Accessory::find($accessory_checkout->accessory_id);
$this->authorize('checkin', $accessory);
$logaction = $accessory->logCheckin(User::find($accessory_checkout->assigned_to), $request->input('note'));
$accessory->logCheckin(User::find($accessory_checkout->assigned_to), $request->input('note'));
// Was the accessory updated?
if ($accessory_checkout->delete()) {
@ -333,14 +329,6 @@ class AccessoriesController extends Controller
$user = User::find($accessory_checkout->assigned_to);
}
$data['log_id'] = $logaction->id;
$data['first_name'] = $user->first_name;
$data['last_name'] = $user->last_name;
$data['item_name'] = $accessory->name;
$data['checkin_date'] = $logaction->created_at;
$data['item_tag'] = '';
$data['note'] = $logaction->note;
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/accessories/message.checkin.success')));
}

View file

@ -117,7 +117,6 @@ trait Loggable
*/
public function logCheckin($target, $note, $action_date = null, $originalValues = [])
{
$settings = Setting::getSettings();
$log = new Actionlog;
if($target != null){
@ -171,39 +170,6 @@ trait Loggable
$log->logaction('checkin from');
// $params = [
// 'target' => $target,
// 'item' => $log->item,
// 'admin' => $log->user,
// 'note' => $note,
// 'target_type' => $log->target_type,
// 'settings' => $settings,
// ];
//
//
// $checkinClass = null;
//
// if (method_exists($target, 'notify')) {
// try {
// $target->notify(new static::$checkinClass($params));
// } catch (\Exception $e) {
// Log::debug($e);
// }
//
// }
//
// // Send to the admin, if settings dictate
// $recipient = new \App\Models\Recipients\AdminRecipient();
//
// if (($settings->admin_cc_email!='') && (static::$checkinClass!='')) {
// try {
// $recipient->notify(new static::$checkinClass($params));
// } catch (\Exception $e) {
// Log::debug($e);
// }
//
// }
return $log;
}

View file

@ -3,7 +3,6 @@
namespace Database\Factories;
use App\Models\Accessory;
use App\Models\AccessoryCheckout;
use App\Models\Category;
use App\Models\Location;
use App\Models\Manufacturer;
@ -156,4 +155,19 @@ class AccessoryFactory extends Factory
]);
});
}
public function checkedOutToUsers(array $users)
{
return $this->afterCreating(function (Accessory $accessory) use ($users) {
foreach ($users as $user) {
$accessory->checkouts()->create([
'accessory_id' => $accessory->id,
'created_at' => Carbon::now(),
'user_id' => 1,
'assigned_to' => $user->id,
'assigned_type' => User::class,
]);
}
});
}
}

View file

@ -0,0 +1,59 @@
<?php
namespace Tests\Feature\Accessories\Api;
use App\Models\Accessory;
use App\Models\Company;
use App\Models\User;
use Tests\Concerns\TestsFullMultipleCompaniesSupport;
use Tests\TestCase;
class AccessoriesForSelectListTest extends TestCase implements TestsFullMultipleCompaniesSupport
{
public function testAdheresToFullMultipleCompaniesSupportScoping()
{
[$companyA, $companyB] = Company::factory()->count(2)->create();
$accessoryA = Accessory::factory()->for($companyA)->create();
$accessoryB = Accessory::factory()->for($companyB)->create();
$superuser = User::factory()->superuser()->create();
$userInCompanyA = $companyA->users()->save(User::factory()->viewAccessories()->make());
$userInCompanyB = $companyB->users()->save(User::factory()->viewAccessories()->make());
$this->settings->enableMultipleFullCompanySupport();
$this->actingAsForApi($userInCompanyA)
->getJson(route('api.accessories.selectlist'))
->assertOk()
->assertJsonPath('total_count', 1)
->assertResponseContainsInResults($accessoryA)
->assertResponseDoesNotContainInResults($accessoryB);
$this->actingAsForApi($userInCompanyB)
->getJson(route('api.accessories.selectlist'))
->assertOk()
->assertJsonPath('total_count', 1)
->assertResponseDoesNotContainInResults($accessoryA)
->assertResponseContainsInResults($accessoryB);
$this->actingAsForApi($superuser)
->getJson(route('api.accessories.selectlist'))
->assertOk()
->assertJsonPath('total_count', 2)
->assertResponseContainsInResults($accessoryA)
->assertResponseContainsInResults($accessoryB);
}
public function testCanGetAccessoriesForSelectList()
{
[$accessoryA, $accessoryB] = Accessory::factory()->count(2)->create();
$this->actingAsForApi(User::factory()->viewAccessories()->create())
->getJson(route('api.accessories.selectlist'))
->assertOk()
->assertJsonPath('total_count', 2)
->assertResponseContainsInResults($accessoryA)
->assertResponseContainsInResults($accessoryB);
}
}

View file

@ -0,0 +1,84 @@
<?php
namespace Tests\Feature\Accessories\Api;
use App\Models\Accessory;
use App\Models\Company;
use App\Models\User;
use Tests\Concerns\TestsFullMultipleCompaniesSupport;
use Tests\Concerns\TestsPermissionsRequirement;
use Tests\TestCase;
class IndexAccessoryCheckoutsTest extends TestCase implements TestsFullMultipleCompaniesSupport, TestsPermissionsRequirement
{
public function testRequiresPermission()
{
$accessory = Accessory::factory()->create();
$this->actingAsForApi(User::factory()->create())
->getJson(route('api.accessories.checkedout', $accessory))
->assertForbidden();
}
public function testAdheresToFullMultipleCompaniesSupportScoping()
{
[$companyA, $companyB] = Company::factory()->count(2)->create();
$accessoryA = Accessory::factory()->for($companyA)->create();
$accessoryB = Accessory::factory()->for($companyB)->create();
$superuser = User::factory()->superuser()->create();
$userInCompanyA = $companyA->users()->save(User::factory()->viewAccessories()->make());
$userInCompanyB = $companyB->users()->save(User::factory()->viewAccessories()->make());
$this->settings->enableMultipleFullCompanySupport();
$this->actingAsForApi($userInCompanyA)
->getJson(route('api.accessories.checkedout', $accessoryB))
->assertStatusMessageIs('error');
$this->actingAsForApi($userInCompanyB)
->getJson(route('api.accessories.checkedout', $accessoryA))
->assertStatusMessageIs('error');
$this->actingAsForApi($superuser)
->getJson(route('api.accessories.checkedout', $accessoryA))
->assertOk();
}
public function testCanGetAccessoryCheckouts()
{
[$userA, $userB] = User::factory()->count(2)->create();
$accessory = Accessory::factory()->checkedOutToUsers([$userA, $userB])->create();
$this->assertEquals(2, $accessory->checkouts()->count());
$this->actingAsForApi(User::factory()->viewAccessories()->create())
->getJson(route('api.accessories.checkedout', $accessory))
->assertOk()
->assertJsonPath('total', 2)
->assertJsonPath('rows.0.assigned_to.id', $userA->id)
->assertJsonPath('rows.1.assigned_to.id', $userB->id);
}
public function testCanGetAccessoryCheckoutsWithOffsetAndLimitInQueryString()
{
[$userA, $userB, $userC] = User::factory()->count(3)->create();
$accessory = Accessory::factory()->checkedOutToUsers([$userA, $userB, $userC])->create();
$actor = $this->actingAsForApi(User::factory()->viewAccessories()->create());
$actor->getJson(route('api.accessories.checkedout', ['accessory' => $accessory->id, 'limit' => 1]))
->assertOk()
->assertJsonPath('total', 3)
->assertJsonPath('rows.0.assigned_to.id', $userA->id);
$actor->getJson(route('api.accessories.checkedout', ['accessory' => $accessory->id, 'limit' => 2, 'offset' => 1]))
->assertOk()
->assertJsonPath('total', 3)
->assertJsonPath('rows.0.assigned_to.id', $userB->id)
->assertJsonPath('rows.1.assigned_to.id', $userC->id);
}
}

View file

@ -2,15 +2,69 @@
namespace Tests\Feature\Accessories\Api;
use App\Models\Accessory;
use App\Models\Company;
use App\Models\User;
use Tests\Concerns\TestsFullMultipleCompaniesSupport;
use Tests\Concerns\TestsPermissionsRequirement;
use Tests\TestCase;
class IndexAccessoryTest extends TestCase
class IndexAccessoryTest extends TestCase implements TestsFullMultipleCompaniesSupport, TestsPermissionsRequirement
{
public function testPermissionRequiredToViewAccessoriesIndex()
public function testRequiresPermission()
{
$this->actingAsForApi(User::factory()->create())
->getJson(route('api.accessories.index'))
->assertForbidden();
}
public function testAdheresToFullMultipleCompaniesSupportScoping()
{
[$companyA, $companyB] = Company::factory()->count(2)->create();
$accessoryA = Accessory::factory()->for($companyA)->create(['name' => 'Accessory A']);
$accessoryB = Accessory::factory()->for($companyB)->create(['name' => 'Accessory B']);
$accessoryC = Accessory::factory()->for($companyB)->create(['name' => 'Accessory C']);
$superUser = $companyA->users()->save(User::factory()->superuser()->make());
$userInCompanyA = $companyA->users()->save(User::factory()->viewAccessories()->make());
$userInCompanyB = $companyB->users()->save(User::factory()->viewAccessories()->make());
$this->settings->enableMultipleFullCompanySupport();
$this->actingAsForApi($userInCompanyA)
->getJson(route('api.accessories.index'))
->assertOk()
->assertResponseContainsInRows($accessoryA)
->assertResponseDoesNotContainInRows($accessoryB)
->assertResponseDoesNotContainInRows($accessoryC);
$this->actingAsForApi($userInCompanyB)
->getJson(route('api.accessories.index'))
->assertOk()
->assertResponseDoesNotContainInRows($accessoryA)
->assertResponseContainsInRows($accessoryB)
->assertResponseContainsInRows($accessoryC);
$this->actingAsForApi($superUser)
->getJson(route('api.accessories.index'))
->assertOk()
->assertResponseContainsInRows($accessoryA)
->assertResponseContainsInRows($accessoryB)
->assertResponseContainsInRows($accessoryC);
}
public function testCanGetAccessories()
{
$user = User::factory()->viewAccessories()->create();
$accessoryA = Accessory::factory()->create(['name' => 'Accessory A']);
$accessoryB = Accessory::factory()->create(['name' => 'Accessory B']);
$this->actingAsForApi($user)
->getJson(route('api.accessories.index'))
->assertOk()
->assertResponseContainsInRows($accessoryA)
->assertResponseContainsInRows($accessoryB);
}
}

View file

@ -3,12 +3,15 @@
namespace Tests\Feature\Accessories\Api;
use App\Models\Accessory;
use App\Models\Company;
use App\Models\User;
use Tests\Concerns\TestsFullMultipleCompaniesSupport;
use Tests\Concerns\TestsPermissionsRequirement;
use Tests\TestCase;
class ShowAccessoryTest extends TestCase
class ShowAccessoryTest extends TestCase implements TestsFullMultipleCompaniesSupport, TestsPermissionsRequirement
{
public function testPermissionRequiredToShowAccessory()
public function testRequiresPermission()
{
$accessory = Accessory::factory()->create();
@ -16,4 +19,43 @@ class ShowAccessoryTest extends TestCase
->getJson(route('api.accessories.show', $accessory))
->assertForbidden();
}
public function testAdheresToFullMultipleCompaniesSupportScoping()
{
[$companyA, $companyB] = Company::factory()->count(2)->create();
$accessoryForCompanyA = Accessory::factory()->for($companyA)->create();
$superuser = User::factory()->superuser()->create();
$userForCompanyB = User::factory()->for($companyB)->viewAccessories()->create();
$this->settings->enableMultipleFullCompanySupport();
$this->actingAsForApi($userForCompanyB)
->getJson(route('api.accessories.show', $accessoryForCompanyA))
->assertOk()
->assertStatusMessageIs('error');
$this->actingAsForApi($superuser)
->getJson(route('api.accessories.show', $accessoryForCompanyA))
->assertOk()
->assertJsonFragment([
'id' => $accessoryForCompanyA->id,
]);
}
public function testCanGetSingleAccessory()
{
$accessory = Accessory::factory()->checkedOutToUser()->create(['name' => 'My Accessory']);
$this->actingAsForApi(User::factory()->viewAccessories()->create())
->getJson(route('api.accessories.show', $accessory))
->assertOk()
->assertJsonFragment([
'id' => $accessory->id,
'name' => 'My Accessory',
'checkouts_count' => 1,
]);
}
}

View file

@ -2,15 +2,97 @@
namespace Tests\Feature\Accessories\Api;
use App\Models\Category;
use App\Models\Company;
use App\Models\Location;
use App\Models\Manufacturer;
use App\Models\Supplier;
use App\Models\User;
use Tests\Concerns\TestsFullMultipleCompaniesSupport;
use Tests\Concerns\TestsPermissionsRequirement;
use Tests\TestCase;
class StoreAccessoryTest extends TestCase
class StoreAccessoryTest extends TestCase implements TestsFullMultipleCompaniesSupport, TestsPermissionsRequirement
{
public function testPermissionRequiredToStoreAccessory()
public function testRequiresPermission()
{
$this->actingAsForApi(User::factory()->create())
->postJson(route('api.accessories.store'))
->assertForbidden();
}
public function testAdheresToFullMultipleCompaniesSupportScoping()
{
$this->markTestSkipped('This behavior is not implemented');
[$companyA, $companyB] = Company::factory()->count(2)->create();
$userInCompanyA = User::factory()->for($companyA)->createAccessories()->create();
$this->settings->enableMultipleFullCompanySupport();
// attempt to store an accessory for company B
$this->actingAsForApi($userInCompanyA)
->postJson(route('api.accessories.store'), [
'category_id' => Category::factory()->forAccessories()->create()->id,
'name' => 'My Awesome Accessory',
'qty' => 1,
'company_id' => $companyB->id,
])->assertStatusMessageIs('error');
$this->assertDatabaseMissing('accessories', [
'name' => 'My Awesome Accessory',
]);
}
public function testValidation()
{
$this->actingAsForApi(User::factory()->createAccessories()->create())
->postJson(route('api.accessories.store'), [
//
])
->assertStatusMessageIs('error')
->assertMessagesContains([
'category_id',
'name',
'qty',
]);
}
public function testCanStoreAccessory()
{
$category = Category::factory()->forAccessories()->create();
$company = Company::factory()->create();
$location = Location::factory()->create();
$manufacturer = Manufacturer::factory()->create();
$supplier = Supplier::factory()->create();
$this->actingAsForApi(User::factory()->createAccessories()->create())
->postJson(route('api.accessories.store'), [
'name' => 'My Awesome Accessory',
'qty' => 2,
'order_number' => '12345',
'purchase_cost' => 100.00,
'purchase_date' => '2024-09-18',
'model_number' => '98765',
'category_id' => $category->id,
'company_id' => $company->id,
'location_id' => $location->id,
'manufacturer_id' => $manufacturer->id,
'supplier_id' => $supplier->id,
])->assertStatusMessageIs('success');
$this->assertDatabaseHas('accessories', [
'name' => 'My Awesome Accessory',
'qty' => 2,
'order_number' => '12345',
'purchase_cost' => 100.00,
'purchase_date' => '2024-09-18',
'model_number' => '98765',
'category_id' => $category->id,
'company_id' => $company->id,
'location_id' => $location->id,
'manufacturer_id' => $manufacturer->id,
'supplier_id' => $supplier->id,
]);
}
}

View file

@ -3,12 +3,19 @@
namespace Tests\Feature\Accessories\Api;
use App\Models\Accessory;
use App\Models\Category;
use App\Models\Company;
use App\Models\Location;
use App\Models\Manufacturer;
use App\Models\Supplier;
use App\Models\User;
use Tests\Concerns\TestsFullMultipleCompaniesSupport;
use Tests\Concerns\TestsPermissionsRequirement;
use Tests\TestCase;
class UpdateAccessoryTest extends TestCase
class UpdateAccessoryTest extends TestCase implements TestsFullMultipleCompaniesSupport, TestsPermissionsRequirement
{
public function testPermissionRequiredToUpdateAccessory()
public function testRequiresPermission()
{
$accessory = Accessory::factory()->create();
@ -16,4 +23,84 @@ class UpdateAccessoryTest extends TestCase
->patchJson(route('api.accessories.update', $accessory))
->assertForbidden();
}
public function testAdheresToFullMultipleCompaniesSupportScoping()
{
[$companyA, $companyB] = Company::factory()->count(2)->create();
$accessoryA = Accessory::factory()->for($companyA)->create(['name' => 'A Name to Change']);
$accessoryB = Accessory::factory()->for($companyB)->create(['name' => 'A Name to Change']);
$accessoryC = Accessory::factory()->for($companyB)->create(['name' => 'A Name to Change']);
$superuser = User::factory()->superuser()->create();
$userInCompanyA = $companyA->users()->save(User::factory()->editAccessories()->make());
$userInCompanyB = $companyB->users()->save(User::factory()->editAccessories()->make());
$this->settings->enableMultipleFullCompanySupport();
$this->actingAsForApi($userInCompanyA)
->patchJson(route('api.accessories.update', $accessoryB), ['name' => 'New Name'])
->assertStatusMessageIs('error');
$this->actingAsForApi($userInCompanyB)
->patchJson(route('api.accessories.update', $accessoryA), ['name' => 'New Name'])
->assertStatusMessageIs('error');
$this->actingAsForApi($superuser)
->patchJson(route('api.accessories.update', $accessoryC), ['name' => 'New Name'])
->assertOk();
$this->assertEquals('A Name to Change', $accessoryA->fresh()->name);
$this->assertEquals('A Name to Change', $accessoryB->fresh()->name);
$this->assertEquals('New Name', $accessoryC->fresh()->name);
}
public function testCanUpdateAccessoryViaPatch()
{
[$categoryA, $categoryB] = Category::factory()->count(2)->create();
[$companyA, $companyB] = Company::factory()->count(2)->create();
[$locationA, $locationB] = Location::factory()->count(2)->create();
[$manufacturerA, $manufacturerB] = Manufacturer::factory()->count(2)->create();
[$supplierA, $supplierB] = Supplier::factory()->count(2)->create();
$accessory = Accessory::factory()->create([
'name' => 'A Name to Change',
'qty' => 5,
'order_number' => 'A12345',
'purchase_cost' => 99.99,
'model_number' => 'ABC098',
'category_id' => $categoryA->id,
'company_id' => $companyA->id,
'location_id' => $locationA->id,
'manufacturer_id' => $manufacturerA->id,
'supplier_id' => $supplierA->id,
]);
$this->actingAsForApi(User::factory()->editAccessories()->create())
->patchJson(route('api.accessories.update', $accessory), [
'name' => 'A New Name',
'qty' => 10,
'order_number' => 'B54321',
'purchase_cost' => 199.99,
'model_number' => 'XYZ123',
'category_id' => $categoryB->id,
'company_id' => $companyB->id,
'location_id' => $locationB->id,
'manufacturer_id' => $manufacturerB->id,
'supplier_id' => $supplierB->id,
])
->assertOk();
$accessory = $accessory->fresh();
$this->assertEquals('A New Name', $accessory->name);
$this->assertEquals(10, $accessory->qty);
$this->assertEquals('B54321', $accessory->order_number);
$this->assertEquals(199.99, $accessory->purchase_cost);
$this->assertEquals('XYZ123', $accessory->model_number);
$this->assertEquals($categoryB->id, $accessory->category_id);
$this->assertEquals($companyB->id, $accessory->company_id);
$this->assertEquals($locationB->id, $accessory->location_id);
$this->assertEquals($manufacturerB->id, $accessory->manufacturer_id);
$this->assertEquals($supplierB->id, $accessory->supplier_id);
}
}

View file

@ -0,0 +1,86 @@
<?php
namespace Tests\Feature\Checkins\Api;
use App\Models\Accessory;
use App\Models\Company;
use App\Models\User;
use Tests\Concerns\TestsFullMultipleCompaniesSupport;
use Tests\Concerns\TestsPermissionsRequirement;
use Tests\TestCase;
class AccessoryCheckinTest extends TestCase implements TestsFullMultipleCompaniesSupport, TestsPermissionsRequirement
{
public function testRequiresPermission()
{
$accessory = Accessory::factory()->checkedOutToUser()->create();
$accessoryCheckout = $accessory->checkouts->first();
$this->actingAsForApi(User::factory()->create())
->postJson(route('api.accessories.checkin', $accessoryCheckout))
->assertForbidden();
}
public function testAdheresToFullMultipleCompaniesSupportScoping()
{
[$companyA, $companyB] = Company::factory()->count(2)->create();
$superUser = $companyA->users()->save(User::factory()->superuser()->make());
$userInCompanyA = User::factory()->for($companyA)->checkinAccessories()->create();
$accessoryForCompanyB = Accessory::factory()->for($companyB)->checkedOutToUser()->create();
$anotherAccessoryForCompanyB = Accessory::factory()->for($companyB)->checkedOutToUser()->create();
$this->assertEquals(1, $accessoryForCompanyB->checkouts->count());
$this->assertEquals(1, $anotherAccessoryForCompanyB->checkouts->count());
$this->settings->enableMultipleFullCompanySupport();
$this->actingAsForApi($userInCompanyA)
->postJson(route('api.accessories.checkin', $accessoryForCompanyB->checkouts->first()))
->assertForbidden();
$this->actingAsForApi($superUser)
->postJson(route('api.accessories.checkin', $anotherAccessoryForCompanyB->checkouts->first()))
->assertStatusMessageIs('success');
$this->assertEquals(1, $accessoryForCompanyB->fresh()->checkouts->count(), 'Accessory should not be checked in');
$this->assertEquals(0, $anotherAccessoryForCompanyB->fresh()->checkouts->count(), 'Accessory should be checked in');
}
public function testCanCheckinAccessory()
{
$accessory = Accessory::factory()->checkedOutToUser()->create();
$this->assertEquals(1, $accessory->checkouts->count());
$accessoryCheckout = $accessory->checkouts->first();
$this->actingAsForApi(User::factory()->checkinAccessories()->create())
->postJson(route('api.accessories.checkin', $accessoryCheckout))
->assertStatusMessageIs('success');
$this->assertEquals(0, $accessory->fresh()->checkouts->count(), 'Accessory should be checked in');
}
public function testCheckinIsLogged()
{
$user = User::factory()->create();
$actor = User::factory()->checkinAccessories()->create();
$accessory = Accessory::factory()->checkedOutToUser($user)->create();
$accessoryCheckout = $accessory->checkouts->first();
$this->actingAsForApi($actor)
->postJson(route('api.accessories.checkin', $accessoryCheckout))
->assertStatusMessageIs('success');
$this->assertDatabaseHas('action_logs', [
'created_by' => $actor->id,
'action_type' => 'checkin from',
'target_id' => $user->id,
'target_type' => User::class,
'item_id' => $accessory->id,
'item_type' => Accessory::class,
]);
}
}

View file

@ -7,11 +7,12 @@ use App\Models\Actionlog;
use App\Models\User;
use App\Notifications\CheckoutAccessoryNotification;
use Illuminate\Support\Facades\Notification;
use Tests\Concerns\TestsPermissionsRequirement;
use Tests\TestCase;
class AccessoryCheckoutTest extends TestCase
class AccessoryCheckoutTest extends TestCase implements TestsPermissionsRequirement
{
public function testCheckingOutAccessoryRequiresCorrectPermission()
public function testRequiresPermission()
{
$this->actingAsForApi(User::factory()->create())
->postJson(route('api.accessories.checkout', Accessory::factory()->create()))

View file

@ -100,5 +100,26 @@ trait CustomTestMacros
return $this;
}
);
TestResponse::macro(
'assertMessagesContains',
function (array|string $keys) {
Assert::assertArrayHasKey('messages', $this, 'Response did not contain any messages');
if (is_string($keys)) {
$keys = [$keys];
}
foreach ($keys as $key) {
Assert::assertArrayHasKey(
$key,
$this['messages'],
"Response messages did not contain the key: {$key}"
);
}
return $this;
}
);
}
}