From 1405e17251b9ec2fd4f3436b5dcc511f4863e1d6 Mon Sep 17 00:00:00 2001 From: Marcus Moore Date: Tue, 8 Aug 2023 17:10:36 -0700 Subject: [PATCH 1/4] Add simple test around custom asset report response --- database/factories/UserFactory.php | 9 ++++++ tests/Feature/Reports/CustomReportTest.php | 33 ++++++++++++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 tests/Feature/Reports/CustomReportTest.php diff --git a/database/factories/UserFactory.php b/database/factories/UserFactory.php index 2445a351f3..db13224616 100644 --- a/database/factories/UserFactory.php +++ b/database/factories/UserFactory.php @@ -432,4 +432,13 @@ class UserFactory extends Factory ]; }); } + + public function canViewReports() + { + return $this->state(function () { + return [ + 'permissions' => '{"reports.view":"1"}', + ]; + }); + } } diff --git a/tests/Feature/Reports/CustomReportTest.php b/tests/Feature/Reports/CustomReportTest.php new file mode 100644 index 0000000000..b8d7009942 --- /dev/null +++ b/tests/Feature/Reports/CustomReportTest.php @@ -0,0 +1,33 @@ +create(['name' => 'Asset A']); + Asset::factory()->create(['name' => 'Asset B']); + + $response = $this->actingAs(User::factory()->canViewReports()->create()) + ->post('reports/custom', [ + 'asset_name' => '1', + 'asset_tag' => '1', + 'serial' => '1', + ])->assertOk() + ->assertHeader('content-type', 'text/csv; charset=UTF-8'); + + $reader = Reader::createFromString($response->streamedContent()); + + $this->assertTrue(collect($reader->getRecords())->pluck(0)->contains('Asset A')); + $this->assertTrue(collect($reader->getRecords())->pluck(0)->contains('Asset B')); + } +} From c752e1670cde2f067cfbd0b3f3fc73021592739d Mon Sep 17 00:00:00 2001 From: Marcus Moore Date: Tue, 8 Aug 2023 17:21:39 -0700 Subject: [PATCH 2/4] Add test around company scoping in custom report --- tests/Feature/Reports/CustomReportTest.php | 94 +++++++++++++++++++++- 1 file changed, 91 insertions(+), 3 deletions(-) diff --git a/tests/Feature/Reports/CustomReportTest.php b/tests/Feature/Reports/CustomReportTest.php index b8d7009942..8136330cf9 100644 --- a/tests/Feature/Reports/CustomReportTest.php +++ b/tests/Feature/Reports/CustomReportTest.php @@ -3,7 +3,9 @@ namespace Tests\Feature\Reports; use App\Models\Asset; +use App\Models\Company; use App\Models\User; +use Illuminate\Testing\TestResponse; use League\Csv\Reader; use Tests\Support\InteractsWithSettings; use Tests\TestCase; @@ -25,9 +27,95 @@ class CustomReportTest extends TestCase ])->assertOk() ->assertHeader('content-type', 'text/csv; charset=UTF-8'); - $reader = Reader::createFromString($response->streamedContent()); + $this->assertResponseContains($response, 'Asset A'); + $this->assertResponseContains($response, 'Asset B'); + } - $this->assertTrue(collect($reader->getRecords())->pluck(0)->contains('Asset A')); - $this->assertTrue(collect($reader->getRecords())->pluck(0)->contains('Asset B')); + public function testCustomAssetReportAdheresToCompanyScoping() + { + [$companyA, $companyB] = Company::factory()->count(2)->create(); + + Asset::factory()->for($companyA)->create(['name' => 'Asset A']); + Asset::factory()->for($companyB)->create(['name' => 'Asset B']); + + $superUser = $companyA->users()->save(User::factory()->superuser()->make()); + $userInCompanyA = $companyA->users()->save(User::factory()->canViewReports()->make()); + $userInCompanyB = $companyB->users()->save(User::factory()->canViewReports()->make()); + + $this->settings->disableMultipleFullCompanySupport(); + + $response = $this->actingAs($superUser) + ->post('reports/custom', [ + 'asset_name' => '1', + 'asset_tag' => '1', + 'serial' => '1', + ]); + $this->assertResponseContains($response, 'Asset A'); + $this->assertResponseContains($response, 'Asset B'); + + $response = $this->actingAs($userInCompanyA) + ->post('reports/custom', [ + 'asset_name' => '1', + 'asset_tag' => '1', + 'serial' => '1', + ]); + $this->assertResponseContains($response, 'Asset A'); + $this->assertResponseContains($response, 'Asset B'); + + $response = $this->actingAs($userInCompanyB) + ->post('reports/custom', [ + 'asset_name' => '1', + 'asset_tag' => '1', + 'serial' => '1', + ]); + $this->assertResponseContains($response, 'Asset A'); + $this->assertResponseContains($response, 'Asset B'); + + $this->settings->enableMultipleFullCompanySupport(); + + $response = $this->actingAs($superUser) + ->post('reports/custom', [ + 'asset_name' => '1', + 'asset_tag' => '1', + 'serial' => '1', + ]); + $this->assertResponseContains($response, 'Asset A'); + $this->assertResponseContains($response, 'Asset B'); + + $response = $this->actingAs($userInCompanyA) + ->post('reports/custom', [ + 'asset_name' => '1', + 'asset_tag' => '1', + 'serial' => '1', + ]); + $this->assertResponseContains($response, 'Asset A'); + $this->assertResponseDoesNotContain($response, 'Asset B'); + + $response = $this->actingAs($userInCompanyB) + ->post('reports/custom', [ + 'asset_name' => '1', + 'asset_tag' => '1', + 'serial' => '1', + ]); + $this->assertResponseDoesNotContain($response, 'Asset A'); + $this->assertResponseContains($response, 'Asset B'); + } + + private function assertResponseContains(TestResponse $response, string $needle) + { + $this->assertTrue( + collect(Reader::createFromString($response->streamedContent())->getRecords()) + ->pluck(0) + ->contains($needle) + ); + } + + private function assertResponseDoesNotContain(TestResponse $response, string $needle) + { + $this->assertFalse( + collect(Reader::createFromString($response->streamedContent())->getRecords()) + ->pluck(0) + ->contains($needle) + ); } } From c32f0990534baa8a5b70a2f3ca8f67b1e68b6d12 Mon Sep 17 00:00:00 2001 From: Marcus Moore Date: Tue, 8 Aug 2023 17:22:15 -0700 Subject: [PATCH 3/4] Remove unneeded call to Company::scopeCompanyables --- app/Http/Controllers/ReportsController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Http/Controllers/ReportsController.php b/app/Http/Controllers/ReportsController.php index 0f078326c9..c9a88ea0f1 100644 --- a/app/Http/Controllers/ReportsController.php +++ b/app/Http/Controllers/ReportsController.php @@ -590,7 +590,7 @@ class ReportsController extends Controller $executionTime = microtime(true) - $_SERVER['REQUEST_TIME_FLOAT']; \Log::debug('Added headers: '.$executionTime); - $assets = \App\Models\Company::scopeCompanyables(Asset::select('assets.*'))->with( + $assets = Asset::select('assets.*')->with( 'location', 'assetstatus', 'company', 'defaultLoc', 'assignedTo', 'model.category', 'model.manufacturer', 'supplier'); From 2e632a3d2d0d7d3d61b7b0372ebf877f4ac177da Mon Sep 17 00:00:00 2001 From: Marcus Moore Date: Tue, 8 Aug 2023 17:40:02 -0700 Subject: [PATCH 4/4] Improve test readability --- tests/Feature/Reports/CustomReportTest.php | 131 ++++++++++----------- 1 file changed, 60 insertions(+), 71 deletions(-) diff --git a/tests/Feature/Reports/CustomReportTest.php b/tests/Feature/Reports/CustomReportTest.php index 8136330cf9..b27ebc27ef 100644 --- a/tests/Feature/Reports/CustomReportTest.php +++ b/tests/Feature/Reports/CustomReportTest.php @@ -7,6 +7,7 @@ use App\Models\Company; use App\Models\User; use Illuminate\Testing\TestResponse; use League\Csv\Reader; +use PHPUnit\Framework\Assert; use Tests\Support\InteractsWithSettings; use Tests\TestCase; @@ -14,21 +15,51 @@ class CustomReportTest extends TestCase { use InteractsWithSettings; + protected function setUp(): void + { + parent::setUp(); + + TestResponse::macro( + 'assertSeeTextInStreamedResponse', + function (string $needle) { + Assert::assertTrue( + collect(Reader::createFromString($this->streamedContent())->getRecords()) + ->pluck(0) + ->contains($needle) + ); + + return $this; + } + ); + + TestResponse::macro( + 'assertDontSeeTextInStreamedResponse', + function (string $needle) { + Assert::assertFalse( + collect(Reader::createFromString($this->streamedContent())->getRecords()) + ->pluck(0) + ->contains($needle) + ); + + return $this; + } + ); + } + public function testCustomAssetReport() { Asset::factory()->create(['name' => 'Asset A']); Asset::factory()->create(['name' => 'Asset B']); - $response = $this->actingAs(User::factory()->canViewReports()->create()) + $this->actingAs(User::factory()->canViewReports()->create()) ->post('reports/custom', [ 'asset_name' => '1', 'asset_tag' => '1', 'serial' => '1', ])->assertOk() - ->assertHeader('content-type', 'text/csv; charset=UTF-8'); - - $this->assertResponseContains($response, 'Asset A'); - $this->assertResponseContains($response, 'Asset B'); + ->assertHeader('content-type', 'text/csv; charset=UTF-8') + ->assertSeeTextInStreamedResponse('Asset A') + ->assertSeeTextInStreamedResponse('Asset B'); } public function testCustomAssetReportAdheresToCompanyScoping() @@ -44,78 +75,36 @@ class CustomReportTest extends TestCase $this->settings->disableMultipleFullCompanySupport(); - $response = $this->actingAs($superUser) - ->post('reports/custom', [ - 'asset_name' => '1', - 'asset_tag' => '1', - 'serial' => '1', - ]); - $this->assertResponseContains($response, 'Asset A'); - $this->assertResponseContains($response, 'Asset B'); + $this->actingAs($superUser) + ->post('reports/custom', ['asset_name' => '1', 'asset_tag' => '1', 'serial' => '1']) + ->assertSeeTextInStreamedResponse('Asset A') + ->assertSeeTextInStreamedResponse('Asset B'); - $response = $this->actingAs($userInCompanyA) - ->post('reports/custom', [ - 'asset_name' => '1', - 'asset_tag' => '1', - 'serial' => '1', - ]); - $this->assertResponseContains($response, 'Asset A'); - $this->assertResponseContains($response, 'Asset B'); + $this->actingAs($userInCompanyA) + ->post('reports/custom', ['asset_name' => '1', 'asset_tag' => '1', 'serial' => '1']) + ->assertSeeTextInStreamedResponse('Asset A') + ->assertSeeTextInStreamedResponse('Asset B'); - $response = $this->actingAs($userInCompanyB) - ->post('reports/custom', [ - 'asset_name' => '1', - 'asset_tag' => '1', - 'serial' => '1', - ]); - $this->assertResponseContains($response, 'Asset A'); - $this->assertResponseContains($response, 'Asset B'); + $this->actingAs($userInCompanyB) + ->post('reports/custom', ['asset_name' => '1', 'asset_tag' => '1', 'serial' => '1']) + ->assertSeeTextInStreamedResponse('Asset A') + ->assertSeeTextInStreamedResponse('Asset B'); $this->settings->enableMultipleFullCompanySupport(); - $response = $this->actingAs($superUser) - ->post('reports/custom', [ - 'asset_name' => '1', - 'asset_tag' => '1', - 'serial' => '1', - ]); - $this->assertResponseContains($response, 'Asset A'); - $this->assertResponseContains($response, 'Asset B'); + $this->actingAs($superUser) + ->post('reports/custom', ['asset_name' => '1', 'asset_tag' => '1', 'serial' => '1']) + ->assertSeeTextInStreamedResponse('Asset A') + ->assertSeeTextInStreamedResponse('Asset B'); - $response = $this->actingAs($userInCompanyA) - ->post('reports/custom', [ - 'asset_name' => '1', - 'asset_tag' => '1', - 'serial' => '1', - ]); - $this->assertResponseContains($response, 'Asset A'); - $this->assertResponseDoesNotContain($response, 'Asset B'); + $this->actingAs($userInCompanyA) + ->post('reports/custom', ['asset_name' => '1', 'asset_tag' => '1', 'serial' => '1']) + ->assertSeeTextInStreamedResponse('Asset A') + ->assertDontSeeTextInStreamedResponse('Asset B'); - $response = $this->actingAs($userInCompanyB) - ->post('reports/custom', [ - 'asset_name' => '1', - 'asset_tag' => '1', - 'serial' => '1', - ]); - $this->assertResponseDoesNotContain($response, 'Asset A'); - $this->assertResponseContains($response, 'Asset B'); - } - - private function assertResponseContains(TestResponse $response, string $needle) - { - $this->assertTrue( - collect(Reader::createFromString($response->streamedContent())->getRecords()) - ->pluck(0) - ->contains($needle) - ); - } - - private function assertResponseDoesNotContain(TestResponse $response, string $needle) - { - $this->assertFalse( - collect(Reader::createFromString($response->streamedContent())->getRecords()) - ->pluck(0) - ->contains($needle) - ); + $this->actingAs($userInCompanyB) + ->post('reports/custom', ['asset_name' => '1', 'asset_tag' => '1', 'serial' => '1']) + ->assertDontSeeTextInStreamedResponse('Asset A') + ->assertSeeTextInStreamedResponse('Asset B'); } }