Skip to content

Commit

Permalink
Merge pull request laravel#57 from eurides-eu/feature/add-organizatio…
Browse files Browse the repository at this point in the history
…n-endpoints-tests

Add organization & organization role endpoints tests
  • Loading branch information
dieterve authored May 28, 2018
2 parents 608f42b + cc4cddf commit c32fddc
Show file tree
Hide file tree
Showing 16 changed files with 580 additions and 21 deletions.
1 change: 1 addition & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ jobs:
# Prepare application for tests
- run: touch database/database.sqlite
- run: php artisan migrate --seed -vvv
- run: php artisan passport:keys

# Run tests
- run: composer lint -- --dry-run --verbose
Expand Down
1 change: 1 addition & 0 deletions .php_cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ $finder = Finder::create()->in([
'app',
'config',
'database',
'tests',
]);

return Config::create()
Expand Down
2 changes: 1 addition & 1 deletion app/Http/Controllers/OrganizationRolesController.php
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ public function update(OrganizationRoleRequest $request, $organizationId, $roleI
*/
public function delete($organizationId, $roleId, Organization $organization)
{
$role = $this->rolesReadRepository->findForOrganization($roleId);
$role = $this->rolesReadRepository->findForOrganization($roleId, $organizationId);

$this->dispatch(new DeleteOrganizationRole($organization, $role));

Expand Down
3 changes: 1 addition & 2 deletions app/Http/Requests/Organizations/OrganizationRoleRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,10 @@ public function authorize()
public function rules()
{
$organizationId = $this->route('organizationId');
$services = (array) $this->input('services');

return [
'name' => 'string|required',
'services' => ['required', 'array', new ValidOrganizationService($organizationId, $services)],
'services' => ['required', 'array', new ValidOrganizationService($organizationId)],
];
}
}
13 changes: 3 additions & 10 deletions app/Organizations/Rules/ValidOrganizationService.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,12 @@ class ValidOrganizationService implements Rule
*/
protected $organizationId;

/**
* @var array
*/
protected $services;

/**
* @param string $organizationId
* @param array $services
*/
public function __construct(string $organizationId, array $services)
public function __construct(string $organizationId)
{
$this->organizationId = $organizationId;
$this->services = $services;
}

/**
Expand All @@ -38,10 +31,10 @@ public function __construct(string $organizationId, array $services)
public function passes($attribute, $value)
{
$count = OrganizationService::where('organization_id', $this->organizationId)
->whereIn('service', $this->services)
->whereIn('service', $value)
->count();

return $count === count($this->services);
return $count === count($value);
}

/**
Expand Down
5 changes: 4 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,10 @@
"Illuminate\\Foundation\\ComposerScripts::postAutoloadDump",
"@php artisan package:discover"
],
"lint" : "php-cs-fixer fix -vvv"
"lint" : "php-cs-fixer fix -vvv",
"test": [
"phpunit"
]
},
"config": {
"preferred-install": "dist",
Expand Down
27 changes: 27 additions & 0 deletions database/factories/OrganizationBudgetFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

use App\Models\Organization;
use App\Models\OrganizationBudget;
use Faker\Generator as Faker;

/*
|--------------------------------------------------------------------------
| Model Factories
|--------------------------------------------------------------------------
|
| This directory should contain each of the model factory definitions for
| your application. Factories provide a convenient way to generate new
| model instances for testing / seeding your application's database.
|
*/

$factory->define(OrganizationBudget::class, function (Faker $faker) {
return [
'name' => 'Default Budget',
'reference' => str_random(10),
'max_amount' => $faker->randomFloat(2, 0, 12000),
'organization_id' => function () {
return factory(Organization::class)->create()->id;
},
];
});
22 changes: 22 additions & 0 deletions database/factories/OrganizationFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

use App\Models\Organization;
use Faker\Generator as Faker;

/*
|--------------------------------------------------------------------------
| Model Factories
|--------------------------------------------------------------------------
|
| This directory should contain each of the model factory definitions for
| your application. Factories provide a convenient way to generate new
| model instances for testing / seeding your application's database.
|
*/

$factory->define(Organization::class, function (Faker $faker) {
return [
'name' => $faker->company,
'reference_code' => str_random(10),
];
});
20 changes: 20 additions & 0 deletions database/factories/RoleFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

use Faker\Generator as Faker;

/*
|--------------------------------------------------------------------------
| Model Factories
|--------------------------------------------------------------------------
|
| This directory should contain each of the model factory definitions for
| your application. Factories provide a convenient way to generate new
| model instances for testing / seeding your application's database.
|
*/

$factory->define(App\Models\OrganizationRole::class, function (Faker $faker) {
return [
'name' => $faker->jobTitle,
];
});
27 changes: 27 additions & 0 deletions database/factories/oAuthClientFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

use Faker\Generator as Faker;
use Laravel\Passport\Client;

/*
|--------------------------------------------------------------------------
| Model Factories
|--------------------------------------------------------------------------
|
| This directory should contain each of the model factory definitions for
| your application. Factories provide a convenient way to generate new
| model instances for testing / seeding your application's database.
|
*/

$factory->define(Client::class, function (Faker $faker) {
return [
'name' => 'Eurides Password Grant Client',
'secret' => str_random(40),
'role' => 'operator',
'password_client' => 1,
'personal_access_client' => 0,
'revoked' => 0,
'redirect' => url('callback'),
];
});
2 changes: 1 addition & 1 deletion tests/CreatesApplication.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

namespace Tests;

use Illuminate\Support\Facades\Hash;
use Illuminate\Contracts\Console\Kernel;
use Illuminate\Support\Facades\Hash;

trait CreatesApplication
{
Expand Down
3 changes: 0 additions & 3 deletions tests/Feature/ExampleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,11 @@
namespace Tests\Feature;

use Tests\TestCase;
use Illuminate\Foundation\Testing\RefreshDatabase;

class ExampleTest extends TestCase
{
/**
* A basic test example.
*
* @return void
*/
public function testBasicTest()
{
Expand Down
182 changes: 182 additions & 0 deletions tests/Feature/OrganizationsTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
<?php

namespace Tests\Feature;

use App\Models\Organization;
use App\Models\OrganizationBudget;
use Faker\Factory as Faker;
use Tests\TestCase;

class OrganizationsTest extends TestCase
{
/**
* @var array
*/
protected $organizationJsonStructure = [
'data' => [
'id',
'name',
'reference',
'services',
'defaultBudget' => [
'id',
'name',
'reference',
'maxAmount',
'approverEmail',
'autoApproveAmountLimit',
'autoApproveMonthlyLimit',
'autoApproveAfter',
],
],
];

public function testOrganizationsAreCreatedCorrectly()
{
$this->setupOperatorAccessToken();

$faker = Faker::create();

$data = [
'name' => $faker->company,
'reference' => (string) $faker->randomNumber(5),
'services' => config('eurides.services'),
];

$response = $this->post('api/organizations', $data, $this->headers);

$content = json_decode($response->getContent());

$response->assertStatus(201)
->assertJsonStructure($this->organizationJsonStructure);

$this->assertEquals($data['name'], $content->data->name);
$this->assertEquals($data['reference'], $content->data->reference);
$this->assertEquals(config('eurides.services'), $content->data->services);
}

public function testCreateRequiresName()
{
$this->setupOperatorAccessToken();

$response = $this->post('api/organizations', [], $this->headers);

$response->assertStatus(422)
->assertJson([
'errors' => [
[
'name' => [
[
'code' => 'errors.required',
'message' => trans('validation.required', ['attribute' => 'name']),
],
],
],
],
]);
}

public function testNotFound()
{
$this->setupOperatorAccessToken();

$response = $this->get('api/organizations/whatever', $this->headers);

$response->assertStatus(404);
}

public function testOrganizationIsListedCorrectly()
{
$this->setupOperatorAccessToken();

$organization = factory(Organization::class)->make();

$createResponse = $this->post('api/organizations', $organization->toArray(), $this->headers);

$createResponseContent = json_decode($createResponse->getContent());

$response = $this->get("api/organizations/{$createResponseContent->data->id}", $this->headers);

$response->assertStatus(200)
->assertJsonStructure($this->organizationJsonStructure);
}

public function testOrganizationsAreUpdatedCorrectly()
{
$this->setupOperatorAccessToken();

$organizationBudget = factory(OrganizationBudget::class)->create();

$payload = [
'name' => 'Company B',
'reference' => 'BCD234',
'services' => config('eurides.services'),
'defaultBudgetId' => $organizationBudget->id,
];

$response = $this->put("api/organizations/$organizationBudget->organization_id", $payload, $this->headers);

$content = json_decode($response->getContent(), true);

$response->assertSuccessful()
->assertJsonStructure($this->organizationJsonStructure);

$this->assertEquals($payload['name'], $content['data']['name']);
$this->assertEquals($payload['reference'], $content['data']['reference']);
$this->assertEquals($payload['services'], $content['data']['services']);
$this->assertEquals($payload['defaultBudgetId'], $content['data']['defaultBudget']['id']);
}

public function testUpdateRequiresNameAndDefaultBudgetId()
{
$this->setupOperatorAccessToken();

$organizationBudget = factory(OrganizationBudget::class)->create();

$response = $this->put("api/organizations/$organizationBudget->organization_id", [], $this->headers);

$response->assertStatus(422)
->assertJson([
'errors' => [
[
'name' => [
[
'code' => 'errors.required',
'message' => trans('validation.required', ['attribute' => 'name']),
],
],
],
[
'defaultBudgetId' => [
[
'code' => 'errors.required',
'message' => trans('validation.required', ['attribute' => 'default budget id']),
],
],
],
],
]);
}

public function testOrganizationsAreDeletedCorrectly()
{
$this->setupOperatorAccessToken();

$organization = factory(Organization::class)->create();

$response = $this->delete("api/organizations/$organization->id", [], $this->headers);

$response->assertSuccessful();

$this->assertSoftDeleted((new Organization())->getTable(), ['id' => $organization->id]);
}

public function testDeleteNotFound()
{
$this->setupOperatorAccessToken();

$response = $this->delete('api/organizations/notfound', [], $this->headers);

$response->assertStatus(404);
}
}
Loading

0 comments on commit c32fddc

Please sign in to comment.