refactor: replace custom CRM with Monica fork
Some checks failed
Build & Push Monica Image to Gitea Registry / build-and-push (push) Failing after 9s

This commit is contained in:
Kroonk
2026-05-22 16:19:55 +02:00
parent 38cc4c09ca
commit a213a1dba0
2215 changed files with 242567 additions and 6015 deletions

View File

@@ -0,0 +1,183 @@
<?php
namespace Tests\Api\Account\Activity;
use Tests\ApiTestCase;
use App\Models\Account\ActivityTypeCategory;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class ApiActivityTypeCategoryControllerTest extends ApiTestCase
{
use DatabaseTransactions;
protected $jsonStructureActivityTypeCategory = [
'id',
'object',
'name',
'account' => [
'id',
],
'created_at',
'updated_at',
];
/** @test */
public function it_gets_a_list_of_activity_type_categories()
{
$user = $this->signin();
factory(ActivityTypeCategory::class, 10)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('GET', '/api/activitytypecategories');
$response->assertJsonStructure([
'data' => [
'*' => $this->jsonStructureActivityTypeCategory,
],
]);
}
/** @test */
public function it_applies_limit_parameter()
{
$user = $this->signin();
factory(ActivityTypeCategory::class, 10)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('GET', '/api/activitytypecategories?limit=1');
$response->assertJsonFragment([
'total' => 10,
'current_page' => 1,
'per_page' => 1,
'last_page' => 10,
]);
$response = $this->json('GET', '/api/activitytypecategories?limit=2');
$response->assertJsonFragment([
'total' => 10,
'current_page' => 1,
'per_page' => 2,
'last_page' => 5,
]);
}
/** @test */
public function it_stores_a_activity_type_category()
{
$user = $this->signin();
$response = $this->json('POST', '/api/activitytypecategories', [
'name' => 'Movies',
]);
$response->assertStatus(200);
$this->assertDatabaseHas('activity_type_categories', [
'name' => 'Movies',
]);
$response->assertJsonStructure([
'data' => $this->jsonStructureActivityTypeCategory,
]);
}
/** @test */
public function it_updates_a_activity_type_category()
{
$user = $this->signin();
$activityTypeCategory = factory(ActivityTypeCategory::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('PUT', '/api/activitytypecategories/'.$activityTypeCategory->id, [
'name' => 'Movies',
]);
$response->assertStatus(200);
$this->assertDatabaseHas('activity_type_categories', [
'name' => 'Movies',
]);
$response->assertJsonStructure([
'data' => $this->jsonStructureActivityTypeCategory,
]);
}
/** @test */
public function it_doesnt_update_if_custom_field_not_found()
{
$user = $this->signin();
$response = $this->json('PUT', '/api/activitytypecategories/2349273984279348', [
'name' => 'Movies',
]);
$response->assertStatus(422);
$this->expectDataError($response, [
'The selected activity type category id is invalid.',
]);
}
/** @test */
public function it_deletes_a_activity_type_category()
{
$user = $this->signin();
$activityTypeCategory = factory(ActivityTypeCategory::class)->create([
'account_id' => $user->account_id,
'name' => 'France',
]);
$response = $this->delete('/api/activitytypecategories/'.$activityTypeCategory->id);
$response->assertStatus(200);
$this->assertDatabaseMissing('activity_type_categories', [
'id' => $activityTypeCategory->id,
]);
$response->assertJsonFragment([
'deleted' => true,
'id' => $activityTypeCategory->id,
]);
}
/** @test */
public function it_doesnt_delete_the_custom_field_if_not_found()
{
$user = $this->signin();
$response = $this->delete('/api/activitytypecategories/2349273984279348');
$response->assertStatus(422);
$this->expectDataError($response, [
'The selected activity type category id is invalid.',
]);
}
/** @test */
public function it_gets_a_single_activity_type_category()
{
$user = $this->signin();
$activityTypeCategory = factory(ActivityTypeCategory::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('GET', '/api/activitytypecategories/'.$activityTypeCategory->id);
$response->assertJsonStructure([
'data' => $this->jsonStructureActivityTypeCategory,
]);
}
}

View File

@@ -0,0 +1,228 @@
<?php
namespace Tests\Api\Account\Activity;
use Tests\ApiTestCase;
use App\Models\Account\Activity;
use App\Models\Account\ActivityType;
use App\Models\Account\ActivityTypeCategory;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class ApiActivityTypeControllerTest extends ApiTestCase
{
use DatabaseTransactions;
protected $jsonStructureActivityType = [
'id',
'object',
'name',
'location_type',
'activity_type_category' => [
'id',
'object',
'name',
'account' => [
'id',
],
'created_at',
'updated_at',
],
'account' => [
'id',
],
'created_at',
'updated_at',
];
/** @test */
public function it_gets_a_list_of_activity_types()
{
$user = $this->signin();
factory(ActivityType::class, 10)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('GET', '/api/activitytypes');
$response->assertJsonStructure([
'data' => [
'*' => $this->jsonStructureActivityType,
],
]);
}
/** @test */
public function it_applies_limit_parameter()
{
$user = $this->signin();
$activityTypes = factory(ActivityType::class, 10)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('GET', '/api/activitytypes?limit=1');
$response->assertJsonFragment([
'total' => 10,
'current_page' => 1,
'per_page' => 1,
'last_page' => 10,
]);
$response = $this->json('GET', '/api/activitytypes?limit=2');
$response->assertJsonFragment([
'total' => 10,
'current_page' => 1,
'per_page' => 2,
'last_page' => 5,
]);
}
/** @test */
public function it_stores_an_activity_type()
{
$user = $this->signin();
$activityTypeCategory = factory(ActivityTypeCategory::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('POST', '/api/activitytypes', [
'name' => 'Movies',
'activity_type_category_id' => $activityTypeCategory->id,
]);
$response->assertStatus(200);
$this->assertDatabaseHas('activity_types', [
'name' => 'Movies',
'activity_type_category_id' => $activityTypeCategory->id,
]);
$response->assertJsonStructure([
'data' => $this->jsonStructureActivityType,
]);
}
/** @test */
public function it_doesnt_store_an_activity_type_if_query_not_valid()
{
$user = $this->signin();
$response = $this->json('POST', '/api/activitytypes');
$this->expectDataError($response, [
'The activity type category id field is required.',
]);
}
/** @test */
public function it_updates_an_activity_type()
{
$user = $this->signin();
$activityTypeCategory = factory(ActivityTypeCategory::class)->create([
'account_id' => $user->account_id,
]);
$activityType = factory(ActivityType::class)->create([
'account_id' => $user->account_id,
'activity_type_category_id' => $activityTypeCategory->id,
]);
$response = $this->json('PUT', '/api/activitytypes/'.$activityType->id, [
'name' => 'Movies',
'activity_type_category_id' => $activityTypeCategory->id,
]);
$response->assertStatus(200);
$this->assertDatabaseHas('activity_types', [
'name' => 'Movies',
]);
$response->assertJsonStructure([
'data' => $this->jsonStructureActivityType,
]);
}
/** @test */
public function it_doesnt_update_if_activity_type_not_found()
{
$user = $this->signin();
$response = $this->json('PUT', '/api/activitytypes/2349273984279348', [
'name' => 'Movies',
]);
$this->expectDataError($response, [
'The activity type category id field is required.',
]);
}
/** @test */
public function it_deletes_an_activity_type()
{
$user = $this->signin();
$activityType = factory(ActivityType::class)->create([
'account_id' => $user->account_id,
]);
$activities = factory(Activity::class, 10)->create([
'account_id' => $user->account_id,
'activity_type_id' => $activityType->id,
]);
$response = $this->delete('/api/activitytypes/'.$activityType->id);
$response->assertStatus(200);
$this->assertDatabaseMissing('activity_types', [
'id' => $activityType->id,
]);
$this->assertDatabaseMissing('activities', [
'activity_type_id' => $activityType->id,
]);
$response->assertJsonFragment([
'deleted' => true,
'id' => $activityType->id,
]);
}
/** @test */
public function it_doesnt_delete_the_activity_type_if_not_found()
{
$user = $this->signin();
$response = $this->delete('/api/activitytypes/2349273984279348');
$this->expectDataError($response, [
'The selected activity type id is invalid.',
]);
}
/** @test */
public function it_gets_a_single_activity_type()
{
$user = $this->signin();
$activityTypeCategory = factory(ActivityTypeCategory::class)->create([
'account_id' => $user->account_id,
]);
$activityType = factory(ActivityType::class)->create([
'account_id' => $user->account_id,
'activity_type_category_id' => $activityTypeCategory->id,
]);
$response = $this->json('GET', '/api/activitytypes/'.$activityType->id);
$response->assertJsonStructure([
'data' => $this->jsonStructureActivityType,
]);
}
}

View File

@@ -0,0 +1,216 @@
<?php
namespace Tests\Api\Account;
use Tests\ApiTestCase;
use App\Models\Account\Account;
use App\Models\Account\Company;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class ApiCompanyControllerTest extends ApiTestCase
{
use DatabaseTransactions;
protected $jsonCompany = [
'id',
'object',
'name',
'website',
'number_of_employees',
'account' => [
'id',
],
'created_at',
'updated_at',
];
/** @test */
public function it_gets_a_list_of_companies()
{
$user = $this->signin();
factory(Company::class, 3)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('GET', '/api/companies');
$response->assertStatus(200);
$response->assertJsonStructure([
'data' => ['*' => $this->jsonCompany],
]);
}
/** @test */
public function it_applies_the_limit_parameter_in_search()
{
$user = $this->signin();
factory(Company::class, 10)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('GET', '/api/companies?limit=1');
$response->assertJsonFragment([
'total' => 10,
'current_page' => 1,
'per_page' => 1,
'last_page' => 10,
]);
$response = $this->json('GET', '/api/companies?limit=2');
$response->assertJsonFragment([
'total' => 10,
'current_page' => 1,
'per_page' => 2,
'last_page' => 5,
]);
}
/** @test */
public function it_gets_one_company()
{
$user = $this->signin();
$company = factory(Company::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('get', '/api/companies/'.$company->id);
$response->assertStatus(200);
$response->assertJsonStructure([
'data' => $this->jsonCompany,
]);
$response->assertJsonFragment([
'object' => 'company',
'id' => $company->id,
]);
}
/** @test */
public function it_cant_get_a_call_with_unexistent_id()
{
$user = $this->signin();
$response = $this->json('get', '/api/companies/0');
$this->expectNotFound($response);
}
/** @test */
public function it_creates_a_company()
{
$user = $this->signin();
$response = $this->json('post', '/api/companies', [
'name' => 'Central Perk',
]);
$response->assertStatus(201);
$response->assertJsonStructure([
'data' => $this->jsonCompany,
]);
$companyId = $response->json('data.id');
$response->assertJsonFragment([
'object' => 'company',
'id' => $companyId,
]);
$this->assertDatabaseHas('companies', [
'account_id' => $user->account_id,
'id' => $companyId,
'name' => 'Central Perk',
'number_of_employees' => null,
]);
}
/** @test */
public function it_updates_a_company()
{
$user = $this->signin();
$company = factory(Company::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('put', '/api/companies/'.$company->id, [
'name' => 'Central Perk Central',
'number_of_employees' => 30,
]);
$response->assertStatus(200);
$response->assertJsonStructure([
'data' => $this->jsonCompany,
]);
$companyId = $response->json('data.id');
$this->assertEquals($company->id, $companyId);
$response->assertJsonFragment([
'object' => 'company',
'id' => $companyId,
]);
$this->assertDatabaseHas('companies', [
'account_id' => $user->account_id,
'id' => $companyId,
'name' => 'Central Perk Central',
'number_of_employees' => 30,
]);
}
/** @test */
public function it_cant_update_a_company_if_account_is_not_linked_to_company()
{
$user = $this->signin();
$account = factory(Account::class)->create([]);
$company = factory(Company::class)->create([
'account_id' => $account->id,
]);
$response = $this->json('put', '/api/companies/'.$company->id, [
'name' => 'Central Perk',
]);
$this->expectNotFound($response);
}
/** @test */
public function it_deletes_a_company()
{
$user = $this->signin();
$company = factory(Company::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('delete', '/api/companies/'.$company->id);
$response->assertStatus(200);
$this->assertdatabasemissing('companies', [
'account_id' => $user->account_id,
'id' => $company->id,
]);
}
/** @test */
public function it_cant_delete_a_company_if_company_doesnt_exist()
{
$user = $this->signin();
$response = $this->json('delete', '/api/companies/0');
$this->expectDataError($response, [
'The selected company id is invalid.',
]);
}
}

View File

@@ -0,0 +1,236 @@
<?php
namespace Tests\Api\Account;
use Tests\ApiTestCase;
use App\Models\Contact\Gender;
use App\Models\Account\Account;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class ApiGenderControllerTest extends ApiTestCase
{
use DatabaseTransactions;
protected $jsonGender = [
'id',
'object',
'name',
'type',
'account' => [
'id',
],
'created_at',
'updated_at',
];
/** @test */
public function it_gets_a_list_of_genders()
{
$user = $this->signin();
factory(Gender::class, 3)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('GET', '/api/genders');
$response->assertStatus(200);
$response->assertJsonStructure([
'data' => ['*' => $this->jsonGender],
]);
}
/** @test */
public function it_applies_the_limit_parameter_in_search()
{
$user = $this->signin();
factory(Gender::class, 10)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('GET', '/api/genders?limit=1');
$response->assertJsonFragment([
'total' => 10,
'current_page' => 1,
'per_page' => 1,
'last_page' => 10,
]);
$response = $this->json('GET', '/api/genders?limit=2');
$response->assertJsonFragment([
'total' => 10,
'current_page' => 1,
'per_page' => 2,
'last_page' => 5,
]);
}
/** @test */
public function it_gets_one_gender()
{
$user = $this->signin();
$gender = factory(Gender::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('get', '/api/genders/'.$gender->id);
$response->assertStatus(200);
$response->assertJsonStructure([
'data' => $this->jsonGender,
]);
$response->assertJsonFragment([
'object' => 'gender',
'id' => $gender->id,
]);
}
/** @test */
public function it_cant_get_a_gender_with_unexistent_id()
{
$user = $this->signin();
$response = $this->json('get', '/api/genders/0');
$this->expectNotFound($response);
}
/** @test */
public function it_creates_a_gender()
{
$user = $this->signin();
$response = $this->json('POST', '/api/genders', [
'name' => 'man',
'type' => 'M',
]);
$response->assertStatus(201);
$response->assertJsonStructure([
'data' => $this->jsonGender,
]);
$genderId = $response->json('data.id');
$response->assertJsonFragment([
'object' => 'gender',
'id' => $genderId,
]);
$this->assertDatabasehas('genders', [
'account_id' => $user->account_id,
'id' => $genderId,
'name' => 'man',
'type' => 'M',
]);
}
/** @test */
public function it_updates_a_gender()
{
$user = $this->signin();
$gender = factory(Gender::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('put', '/api/genders/'.$gender->id, [
'name' => 'man',
'type' => 'M',
]);
$response->assertStatus(200);
$response->assertJsonStructure([
'data' => $this->jsonGender,
]);
$genderId = $response->json('data.id');
$this->assertEquals($gender->id, $genderId);
$response->assertJsonFragment([
'object' => 'gender',
'id' => $genderId,
]);
$this->assertDatabaseHas('genders', [
'account_id' => $user->account_id,
'id' => $genderId,
'name' => 'man',
'type' => 'M',
]);
}
/** @test */
public function it_cant_update_a_gender_if_account_is_not_linked_to_gender()
{
$user = $this->signin();
$account = factory(Account::class)->create([]);
$gender = factory(Gender::class)->create([
'account_id' => $account->id,
]);
$response = $this->json('put', '/api/genders/'.$gender->id, [
'name' => 'man',
'type' => 'M',
]);
$this->expectNotFound($response);
}
/** @test */
public function it_cant_update_a_gender_if_account_is_not_linked_to_gender2()
{
$user = $this->signin();
$account = factory(Account::class)->create([]);
$gender = factory(Gender::class)->create([
'account_id' => $account->id,
]);
$response = $this->json('put', '/api/genders/'.$gender->id, [
'account_id' => $account->id,
'name' => 'man',
'type' => 'M',
]);
$this->expectNotFound($response);
}
/** @test */
public function it_deletes_a_gender()
{
$user = $this->signin();
$gender = factory(Gender::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('delete', '/api/genders/'.$gender->id);
$response->assertStatus(200);
$this->assertDatabaseMissing('genders', [
'account_id' => $user->account_id,
'id' => $gender->id,
]);
}
/** @test */
public function it_cant_delete_a_gender_if_gender_doesnt_exist()
{
$user = $this->signin();
$response = $this->json('delete', '/api/genders/0');
$this->expectDataError($response, [
'The selected gender id is invalid.',
]);
}
}

View File

@@ -0,0 +1,210 @@
<?php
namespace Tests\Api\Account;
use Tests\ApiTestCase;
use App\Models\Account\Place;
use App\Models\Account\Account;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class ApiPlaceControllerTest extends ApiTestCase
{
use DatabaseTransactions;
protected $jsonPlace = [
'id',
'object',
'street',
'city',
'province',
'postal_code',
'latitude',
'longitude',
'country',
'account' => [
'id',
],
'created_at',
'updated_at',
];
public function test_it_gets_a_list_of_places()
{
$user = $this->signin();
factory(Place::class, 3)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('GET', '/api/places');
$response->assertStatus(200);
$response->assertJsonStructure([
'data' => ['*' => $this->jsonPlace],
]);
}
public function test_it_applies_the_limit_parameter_in_search()
{
$user = $this->signin();
factory(Place::class, 10)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('GET', '/api/places?limit=1');
$response->assertJsonFragment([
'total' => 10,
'current_page' => 1,
'per_page' => 1,
'last_page' => 10,
]);
$response = $this->json('GET', '/api/places?limit=2');
$response->assertJsonFragment([
'total' => 10,
'current_page' => 1,
'per_page' => 2,
'last_page' => 5,
]);
}
public function test_it_gets_one_place()
{
$user = $this->signin();
$place = factory(Place::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('get', '/api/places/'.$place->id);
$response->assertStatus(200);
$response->assertJsonStructure([
'data' => $this->jsonPlace,
]);
$response->assertJsonFragment([
'object' => 'place',
'id' => $place->id,
]);
}
public function test_it_cant_get_a_call_with_unexistent_id()
{
$user = $this->signin();
$response = $this->json('get', '/api/places/0');
$this->expectNotFound($response);
}
public function test_it_create_a_place()
{
$user = $this->signin();
$response = $this->json('post', '/api/places', [
'city' => 'New York',
]);
$response->assertStatus(201);
$response->assertJsonStructure([
'data' => $this->jsonPlace,
]);
$placeId = $response->json('data.id');
$response->assertJsonFragment([
'object' => 'place',
'id' => $placeId,
]);
$this->assertDatabaseHas('places', [
'account_id' => $user->account_id,
'id' => $placeId,
'city' => 'New York',
'latitude' => null,
]);
}
public function test_it_updates_a_place()
{
$user = $this->signin();
$place = factory(Place::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('put', '/api/places/'.$place->id, [
'city' => 'New York',
]);
$response->assertStatus(200);
$response->assertJsonStructure([
'data' => $this->jsonPlace,
]);
$placeId = $response->json('data.id');
$this->assertEquals($place->id, $placeId);
$response->assertJsonFragment([
'object' => 'place',
'id' => $placeId,
]);
$this->assertDatabaseHas('places', [
'account_id' => $user->account_id,
'id' => $placeId,
'city' => 'New York',
'latitude' => null,
]);
}
public function test_it_cant_update_a_place_if_account_is_not_linked_to_place()
{
$user = $this->signin();
$account = factory(Account::class)->create([]);
$place = factory(Place::class)->create([
'account_id' => $account->id,
]);
$response = $this->json('put', '/api/places/'.$place->id, [
'city' => 'New York',
]);
$this->expectNotFound($response);
}
public function test_it_deletes_a_place()
{
$user = $this->signin();
$place = factory(Place::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('delete', '/api/places/'.$place->id);
$response->assertStatus(200);
$this->assertdatabasemissing('places', [
'account_id' => $user->account_id,
'id' => $place->id,
]);
}
public function test_it_cant_delete_a_place_if_place_doesnt_exist()
{
$user = $this->signin();
$response = $this->json('delete', '/api/places/0');
$this->expectDataError($response, [
'The selected place id is invalid.',
]);
}
}

View File

@@ -0,0 +1,157 @@
<?php
namespace Tests\Api\Account;
use Tests\ApiTestCase;
use App\Models\Settings\Term;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class ApiUserControllerTest extends ApiTestCase
{
use DatabaseTransactions;
protected $jsonStructureUser = [
'id',
'object',
'first_name',
'last_name',
'email',
'timezone',
'currency',
'locale',
'is_policy_compliant',
'account' => [
'id',
],
'created_at',
'updated_at',
];
/** @test */
public function it_gets_the_authenticated_user()
{
$user = $this->signIn();
$response = $this->get('/api/me');
$response->assertStatus(200);
$response->assertJsonStructure([
'data' => $this->jsonStructureUser,
]);
$response->assertJsonFragment([
'first_name' => $user->first_name,
'object' => 'user',
]);
}
/** @test */
public function it_tells_if_the_user_has_signed_a_given_policy()
{
$user = $this->signIn();
$term = factory(Term::class)->create([]);
$user->terms()->syncWithoutDetaching([$term->id => ['account_id' => $user->account_id]]);
$response = $this->get('/api/me/compliance/'.$term->id);
$response->assertJsonFragment([
'signed' => true,
'ip_address' => null,
]);
$response->assertJsonStructure([
'data' => [
'signed',
'signed_date',
'ip_address',
'user',
'term',
],
]);
}
/** @test */
public function it_returns_method_not_found_if_no_policy_is_found()
{
$user = $this->signIn();
$response = $this->get('/api/me/compliance/32455212');
$response->assertStatus(404);
$response->assertJsonFragment([
'message' => 'The resource has not been found',
'error_code' => 31,
]);
}
/** @test */
public function it_gets_all_the_compliances_signed_by_user()
{
$user = $this->signIn();
$term = factory(Term::class)->create([]);
$user->terms()->syncWithoutDetaching([$term->id => ['account_id' => $user->account_id]]);
$term2 = factory(Term::class)->create([]);
$user->terms()->syncWithoutDetaching([$term2->id => ['account_id' => $user->account_id]]);
$response = $this->get('/api/me/compliance');
$response->assertStatus(200);
$response->assertJsonCount(2, 'data');
}
/** @test */
public function it_gets_no_compliances_signed_by_user()
{
$user = $this->signIn();
$response = $this->get('/api/me/compliance');
$response->assertStatus(404);
}
/** @test */
public function it_tries_to_sign_lapolicy()
{
$user = $this->signIn();
$response = $this->post('/api/me/compliance');
$this->expectDataError($response, [
'The ip address field is required.',
]);
}
/** @test */
public function it_signs_lapolicy()
{
$user = $this->signIn();
$term = factory(Term::class)->create([]);
$user->terms()->syncWithoutDetaching([$term->id => ['account_id' => $user->account_id]]);
$term2 = factory(Term::class)->create([]);
$user->terms()->syncWithoutDetaching([$term2->id => ['account_id' => $user->account_id]]);
$params = [
'ip_address' => '128.3.1.2',
];
$response = $this->json('POST', '/api/me/compliance', $params);
$response->assertStatus(200);
$response->assertJsonStructure([
'data' => [
'signed',
'signed_date',
'ip_address',
'user',
'term',
],
]);
}
}

View File

@@ -0,0 +1,595 @@
<?php
namespace Tests\Api;
use Tests\ApiTestCase;
use App\Models\Contact\Contact;
use App\Models\Account\Activity;
use App\Models\Account\ActivityType;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class ApiActivitiesTest extends ApiTestCase
{
use DatabaseTransactions;
protected $jsonActivity = [
'id',
'object',
'summary',
'description',
'happened_at',
'activity_type' => [
'id',
'object',
'name',
'location_type',
'activity_type_category' => [
'id',
'object',
'name',
'account' => [
'id',
],
'created_at',
'updated_at',
],
'account'=> [
'id',
],
'created_at',
'updated_at',
],
'attendees' => [
'total',
'contacts' => [
'*' => [
'id',
'object',
'first_name',
'last_name',
'complete_name',
],
],
],
'emotions' => [
'*' => [
'id',
'object',
'name',
],
],
'account' => [
'id',
],
'created_at',
'updated_at',
];
protected $jsonActivityNoCategory = [
'id',
'object',
'summary',
'description',
'happened_at',
'attendees' => [
'total',
'contacts' => [
'*' => [
'id',
'object',
'first_name',
'last_name',
'complete_name',
],
],
],
'emotions' => [
'*' => [
'id',
'object',
'name',
],
],
'account' => [
'id',
],
'created_at',
'updated_at',
];
/** @test */
public function activities_get_all()
{
$user = $this->signin();
$activity1 = factory(Activity::class)->create([
'account_id' => $user->account_id,
]);
$activity2 = factory(Activity::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('GET', '/api/activities');
$response->assertStatus(200);
$response->assertJsonStructure([
'data' => ['*' => $this->jsonActivity],
]);
$response->assertJsonFragment([
'object' => 'activity',
'id' => $activity1->id,
]);
$response->assertJsonFragment([
'object' => 'activity',
'id' => $activity2->id,
]);
}
/** @test */
public function activities_get_contact_all()
{
$user = $this->signin();
$contact1 = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$activity1 = factory(Activity::class)->create([
'account_id' => $user->account_id,
]);
$activity1->contacts()->attach($contact1, ['account_id' => $user->account_id]);
$contact2 = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$activity2 = factory(Activity::class)->create([
'account_id' => $user->account_id,
]);
$activity2->contacts()->attach($contact2, ['account_id' => $user->account_id]);
$response = $this->json('GET', '/api/contacts/'.$contact1->id.'/activities');
$response->assertStatus(200);
$response->assertJsonStructure([
'data' => ['*' => $this->jsonActivity],
]);
$response->assertJsonFragment([
'object' => 'activity',
'id' => $activity1->id,
]);
$response->assertJsonMissingExact([
'object' => 'activity',
'id' => $activity2->id,
]);
}
/** @test */
public function activities_get_contact_all_error()
{
$this->signin();
$response = $this->json('GET', '/api/contacts/0/activities');
$this->expectNotFound($response);
}
/** @test */
public function activities_get_contact_all_error_wrong_account()
{
$this->signin();
$contact = factory(Contact::class)->create();
$response = $this->json('GET', '/api/contacts/'.$contact->id.'/activities');
$this->expectNotFound($response);
}
/** @test */
public function activities_get_one()
{
$user = $this->signin();
$activity1 = factory(Activity::class)->create([
'account_id' => $user->account_id,
]);
$activity2 = factory(Activity::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('GET', '/api/activities/'.$activity1->id);
$response->assertStatus(200);
$response->assertJsonStructure([
'data' => $this->jsonActivity,
]);
$response->assertJsonFragment([
'object' => 'activity',
'id' => $activity1->id,
]);
$response->assertJsonMissingExact([
'object' => 'activity',
'id' => $activity2->id,
]);
}
/** @test */
public function activities_get_one_error()
{
$this->signin();
$response = $this->json('GET', '/api/activities/0');
$this->expectNotFound($response);
}
/** @test */
public function activities_get_one_error_wrong_account()
{
$this->signin();
$activity = factory(Activity::class)->create();
$response = $this->json('GET', '/api/activities/'.$activity->id);
$this->expectNotFound($response);
}
/** @test */
public function activities_create()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$activityType = factory(ActivityType::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('POST', '/api/activities', [
'contacts' => [$contact->id],
'description' => 'the description',
'summary' => 'the activity',
'happened_at' => '2018-05-01',
'activity_type_id' => $activityType->id,
]);
$response->assertStatus(201);
$response->assertJsonStructure([
'data' => $this->jsonActivity,
]);
$activity_id = $response->json('data.id');
$response->assertJsonFragment([
'object' => 'activity',
'id' => $activity_id,
]);
$this->assertGreaterThan(0, $activity_id);
$this->assertDatabaseHas('activities', [
'account_id' => $user->account_id,
'id' => $activity_id,
'summary' => 'the activity',
'description' => 'the description',
'happened_at' => '2018-05-01',
]);
$this->assertDatabaseHas('activity_contact', [
'account_id' => $user->account_id,
'contact_id' => $contact->id,
'activity_id' => $activity_id,
]);
}
/** @test */
public function activities_create_error_wrong_parameter()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('POST', '/api/activities', [
'contact_id' => [$contact->id],
]);
$this->expectDataError($response, [
'The summary field is required.',
'The happened at field is required.',
]);
}
/** @test */
public function activities_create_error_bad_account()
{
$this->signin();
$contact = factory(Contact::class)->create();
$response = $this->json('POST', '/api/activities', [
'contacts' => [$contact->id],
'description' => 'the description',
'summary' => 'the activity',
'happened_at' => '2018-05-01',
]);
$this->expectNotFound($response);
}
/** @test */
public function activities_create_error_bad_account2()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$activityType = factory(ActivityType::class)->create();
$response = $this->json('POST', '/api/activities', [
'contacts' => [$contact->id],
'description' => 'the description',
'summary' => 'the activity',
'happened_at' => '2018-05-01',
'activity_type_id' => $activityType->id,
]);
$this->expectNotFound($response);
}
/** @test */
public function activities_update()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$activity = factory(Activity::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('PUT', '/api/activities/'.$activity->id, [
'contacts' => [$contact->id],
'description' => 'the description',
'summary' => 'the activity',
'happened_at' => '2018-05-01',
]);
$response->assertStatus(200);
$response->assertJsonStructure([
'data' => $this->jsonActivityNoCategory,
]);
$activity_id = $response->json('data.id');
$this->assertEquals($activity->id, $activity_id);
$response->assertJsonFragment([
'object' => 'activity',
'id' => $activity_id,
]);
$this->assertGreaterThan(0, $activity_id);
$this->assertDatabaseHas('activities', [
'account_id' => $user->account_id,
'id' => $activity_id,
'summary' => 'the activity',
'happened_at' => '2018-05-01',
]);
$this->assertDatabaseHas('activity_contact', [
'account_id' => $user->account_id,
'contact_id' => $contact->id,
'activity_id' => $activity_id,
]);
}
/** @test */
public function activities_update_category()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$activity = factory(Activity::class)->create([
'account_id' => $user->account_id,
]);
$activityType = factory(ActivityType::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('PUT', '/api/activities/'.$activity->id, [
'contacts' => [$contact->id],
'description' => 'the description',
'summary' => 'the activity',
'happened_at' => '2018-05-01',
'activity_type_id' => $activityType->id,
]);
$response->assertStatus(200);
$response->assertJsonStructure([
'data' => $this->jsonActivity,
]);
$activity_id = $response->json('data.id');
$this->assertEquals($activity->id, $activity_id);
$response->assertJsonFragment([
'object' => 'activity',
'id' => $activity_id,
]);
$activity_type_id = $response->json('data.activity_type.id');
$this->assertEquals($activityType->id, $activity_type_id);
$response->assertJsonFragment([
'object' => 'activityType',
'id' => $activity_type_id,
]);
$this->assertGreaterThan(0, $activity_id);
$this->assertDatabaseHas('activities', [
'account_id' => $user->account_id,
'id' => $activity_id,
'summary' => 'the activity',
'happened_at' => '2018-05-01',
'activity_type_id' => $activityType->id,
]);
$this->assertDatabaseHas('activity_contact', [
'account_id' => $user->account_id,
'contact_id' => $contact->id,
'activity_id' => $activity_id,
]);
}
/** @test */
public function activities_update_existing()
{
$user = $this->signin();
$activity = factory(Activity::class)->create([
'account_id' => $user->account_id,
]);
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$contact->activities()->attach($activity, [
'account_id' => $user->account_id,
]);
$contact2 = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$contact2->activities()->attach($activity, [
'account_id' => $user->account_id,
]);
$this->assertDatabaseHas('activity_contact', [
'account_id' => $user->account_id,
'contact_id' => $contact->id,
'activity_id' => $activity->id,
]);
$this->assertDatabaseHas('activity_contact', [
'account_id' => $user->account_id,
'contact_id' => $contact2->id,
'activity_id' => $activity->id,
]);
$response = $this->json('PUT', '/api/activities/'.$activity->id, [
'contacts' => [$contact->id],
'description' => 'the description',
'summary' => 'the activity',
'happened_at' => '2018-05-01',
]);
$response->assertStatus(200);
$response->assertJsonStructure([
'data' => $this->jsonActivityNoCategory,
]);
$activity_id = $response->json('data.id');
$this->assertEquals($activity->id, $activity_id);
$response->assertJsonFragment([
'object' => 'activity',
'id' => $activity_id,
]);
$this->assertGreaterThan(0, $activity_id);
$this->assertDatabaseHas('activities', [
'account_id' => $user->account_id,
'id' => $activity_id,
'summary' => 'the activity',
'happened_at' => '2018-05-01',
]);
$this->assertDatabaseHas('activity_contact', [
'account_id' => $user->account_id,
'contact_id' => $contact->id,
'activity_id' => $activity_id,
]);
$this->assertDatabaseMissing('activity_contact', [
'account_id' => $user->account_id,
'contact_id' => $contact2->id,
'activity_id' => $activity_id,
]);
}
/** @test */
public function activities_update_error_wrong_parameter()
{
$user = $this->signin();
$response = $this->json('PUT', '/api/activities/0', [
'description' => 'the description',
'summary' => 'the activity',
'happened_at' => '2018-05-01',
]);
$this->expectDataError($response, [
'The selected activity id is invalid.',
]);
}
/** @test */
public function activities_update_error_wrong_account_for_activity()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$activity = factory(Activity::class)->create();
$response = $this->json('PUT', '/api/activities/'.$activity->id, [
'contacts' => [$contact->id],
'description' => 'the description',
'summary' => 'the activity',
'happened_at' => '2018-05-01',
]);
$this->expectNotFound($response);
}
/** @test */
public function activities_update_error_wrong_account_for_contacts()
{
$user = $this->signin();
$contact = factory(Contact::class)->create();
$activity = factory(Activity::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('PUT', '/api/activities/'.$activity->id, [
'contacts' => [$contact->id],
'description' => 'the description',
'summary' => 'the activity',
'happened_at' => '2018-05-01',
]);
$this->expectNotFound($response);
}
/** @test */
public function activities_delete()
{
$user = $this->signin();
$activity = factory(Activity::class)->create([
'account_id' => $user->account_id,
]);
$this->assertDatabaseHas('activities', [
'account_id' => $user->account_id,
]);
$response = $this->json('DELETE', '/api/activities/'.$activity->id);
$response->assertStatus(200);
$this->assertDatabaseMissing('activities', [
'account_id' => $user->account_id,
'id' => $activity->id,
]);
}
/** @test */
public function activities_delete_error()
{
$this->signin();
$response = $this->json('DELETE', '/api/activities/0');
$this->expectDataError($response, [
'The selected activity id is invalid.',
]);
}
/** @test */
public function activities_delete_with_wrong_account()
{
$this->signin();
$activity = factory(Activity::class)->create();
$response = $this->json('DELETE', '/api/activities/'.$activity->id);
$this->expectNotFound($response);
}
}

View File

@@ -0,0 +1,203 @@
<?php
namespace Tests\Api;
use Tests\ApiTestCase;
use App\Http\Controllers\Api\ApiController;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class ApiControllerTest extends ApiTestCase
{
use DatabaseTransactions;
/** @test */
public function get_http_status_code_returns_the_status_code()
{
$apiController = new ApiController;
$this->assertEquals(
200,
$apiController->getHTTPStatusCode()
);
$apiController->setHTTPStatusCode(300);
$this->assertEquals(
300,
$apiController->getHTTPStatusCode()
);
}
/** @test */
public function get_error_code_returns_the_error_code()
{
$apiController = new ApiController;
$this->assertNull(
$apiController->getErrorCode()
);
$apiController->setErrorCode(30);
$this->assertEquals(
30,
$apiController->getErrorCode()
);
}
/** @test */
public function get_with_parameter_returns_the_parameter()
{
$apiController = new ApiController;
$this->assertNull(
$apiController->getWithParameter()
);
$apiController->setWithParameter('test');
$this->assertEquals(
'test',
$apiController->getWithParameter()
);
}
/** @test */
public function get_limit_per_page_code_returns_the_limit_per_page()
{
$apiController = new ApiController;
$this->assertEquals(
0,
$apiController->getLimitPerPage()
);
$apiController->setLimitPerPage(30);
$this->assertEquals(
30,
$apiController->getLimitPerPage()
);
}
/** @test */
public function it_gets_the_sort_criteria()
{
$apiController = new ApiController;
$this->assertEquals(
'created_at',
$apiController->getSortCriteria()
);
$apiController->setSortCriteria('created_at');
$this->assertEquals(
'created_at',
$apiController->getSortCriteria()
);
}
/** @test */
public function it_only_accepts_some_sorting_parameters()
{
$apiController = new ApiController;
$apiController->setSortCriteria('created_at');
$this->assertEquals(
'created_at',
$apiController->getSortCriteria()
);
$apiController->setSortCriteria('anything');
$this->assertEquals(
'',
$apiController->getSortCriteria()
);
}
/** @test */
public function calling_api_with_insane_limit_number_raises_an_error()
{
$user = $this->signin();
$insaneLimit = config('api.max_limit_per_page') * 100;
$response = $this->json('GET', "/api/contacts?limit={$insaneLimit}");
$response->assertStatus(400);
$response->assertJsonFragment([
'message' => 'The limit parameter is too big',
'error_code' => 30,
]);
}
/** @test */
public function calling_api_with_a_wrong_sort_parameter_raises_an_error()
{
$user = $this->signin();
$criteria = 'anything';
$response = $this->json('GET', "/api/contacts?sort={$criteria}");
$response->assertStatus(400);
$response->assertJsonFragment([
'message' => 'The sorting criteria is invalid',
'error_code' => 39,
]);
}
/** @test */
public function it_sets_the_order_by_parameters()
{
$apiController = new ApiController;
$apiController->setSortCriteria('created_at');
$this->assertEquals(
'created_at',
$apiController->getSortCriteria()
);
$this->assertEquals(
'asc',
$apiController->getSortDirection()
);
$apiController->setSortCriteria('-created_at');
$this->assertEquals(
'created_at',
$apiController->getSortCriteria()
);
$this->assertEquals(
'desc',
$apiController->getSortDirection()
);
}
/** @test */
public function root_api()
{
$user = $this->signin();
$response = $this->json('GET', '/api');
$response->assertStatus(200);
$response->assertJsonFragment([
'success' => [
'message' => 'Welcome to Monica',
],
]);
$response->assertJsonFragment([
'contacts_url' => route('api.contacts'),
]);
}
}

View File

@@ -0,0 +1,62 @@
<?php
namespace Tests\Api;
use Tests\ApiTestCase;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class ApiCountriesTest extends ApiTestCase
{
use DatabaseTransactions;
protected $jsonCountries = [
'id',
'iso',
'name',
'object',
];
/** @test */
public function it_gets_the_list_of_countries()
{
$user = $this->signin();
$response = $this->json('GET', '/api/countries');
$response->assertStatus(200);
$response->assertJsonStructure([
'data' => ['*' => $this->jsonCountries],
]);
$response->assertJsonFragment([
'de' => [
'id' => 'DE',
'iso' => 'DE',
'name' => 'Germany',
'object' => 'country',
],
]);
}
/** @test */
public function it_gets_a_specific_country_in_a_specific_locale()
{
$user = $this->signin();
$user->locale = 'fr';
$user->save();
$response = $this->json('GET', '/api/countries');
$response->assertStatus(200);
$response->assertJsonStructure([
'data' => ['*' => $this->jsonCountries],
]);
$response->assertJsonFragment([
'de' => [
'id' => 'DE',
'iso' => 'DE',
'name' => 'Allemagne',
'object' => 'country',
],
]);
}
}

377
tests/Api/ApiDebtsTest.php Normal file
View File

@@ -0,0 +1,377 @@
<?php
namespace Tests\Api;
use Tests\ApiTestCase;
use App\Models\Contact\Debt;
use App\Models\Account\Account;
use App\Models\Contact\Contact;
use App\Models\Settings\Currency;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class ApiDebtsTest extends ApiTestCase
{
use DatabaseTransactions;
protected $jsonDebt = [
'id',
'object',
'in_debt',
'status',
'amount',
'amount_with_currency',
'reason',
'account' => [
'id',
],
'contact' => [
'id',
],
'created_at',
'updated_at',
];
/** @test */
public function it_gets_all_the_debts()
{
$user = $this->signin();
$contact1 = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$debt1 = factory(Debt::class)->create([
'account_id' => $user->account_id,
'contact_id' => $contact1->id,
]);
$contact2 = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$debt2 = factory(Debt::class)->create([
'account_id' => $user->account_id,
'contact_id' => $contact2->id,
]);
$response = $this->json('GET', '/api/debts');
$response->assertStatus(200);
$response->assertJsonStructure([
'data' => ['*' => $this->jsonDebt],
]);
$response->assertJsonFragment([
'object' => 'debt',
'id' => $debt1->id,
]);
$response->assertJsonFragment([
'object' => 'debt',
'id' => $debt2->id,
]);
}
/** @test */
public function it_gets_all_the_debts_for_a_given_contact()
{
$user = $this->signin();
$contact1 = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$debt1 = factory(Debt::class)->create([
'account_id' => $user->account_id,
'contact_id' => $contact1->id,
]);
$contact2 = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$debt2 = factory(Debt::class)->create([
'account_id' => $user->account_id,
'contact_id' => $contact2->id,
]);
$response = $this->json('GET', '/api/contacts/'.$contact1->id.'/debts');
$response->assertStatus(200);
$response->assertJsonStructure([
'data' => ['*' => $this->jsonDebt],
]);
$response->assertJsonFragment([
'object' => 'debt',
'id' => $debt1->id,
]);
$response->assertJsonMissingExact([
'object' => 'debt',
'id' => $debt2->id,
]);
}
/** @test */
public function it_cant_get_debts_from_an_invalid_contact()
{
$user = $this->signin();
$response = $this->json('GET', '/api/contacts/0/debts');
$this->expectNotFound($response);
}
/** @test */
public function it_gets_one_debt()
{
$user = $this->signin();
$contact1 = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$debt1 = factory(Debt::class)->create([
'account_id' => $user->account_id,
'contact_id' => $contact1->id,
]);
$debt2 = factory(Debt::class)->create([
'account_id' => $user->account_id,
'contact_id' => $contact1->id,
]);
$response = $this->json('GET', '/api/debts/'.$debt1->id);
$response->assertStatus(200);
$response->assertJsonStructure([
'data' => $this->jsonDebt,
]);
$response->assertJsonFragment([
'object' => 'debt',
'id' => $debt1->id,
]);
$response->assertJsonMissingExact([
'object' => 'debt',
'id' => $debt2->id,
]);
}
/** @test */
public function it_cant_get_a_debt_with_an_invalid_id()
{
$user = $this->signin();
$response = $this->json('GET', '/api/debts/0');
$this->expectNotFound($response);
}
/** @test */
public function it_creates_a_debt()
{
$user = $this->signin();
$user->locale = 'fr';
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$currency = factory(Currency::class)->create([
'iso' => 'USD',
'symbol' => '$',
]);
$user->currency()->associate($currency);
$user->save();
$response = $this->json('POST', '/api/debts', [
'contact_id' => $contact->id,
'in_debt' => 'yes',
'status' => 'inprogress',
'amount' => 42,
'reason' => 'that\'s why',
]);
$response->assertStatus(201);
$response->assertJsonStructure([
'data' => $this->jsonDebt,
]);
$debt_id = $response->json('data.id');
$response->assertJsonFragment([
'object' => 'debt',
'id' => $debt_id,
'in_debt' => 'yes',
'status' => 'inprogress',
'amount' => '42.00',
'value' => '42,00',
'amount_with_currency' => '42,00'.chr(0xA0).'$US',
'reason' => 'that\'s why',
]);
$this->assertGreaterThan(0, $debt_id);
$this->assertDatabaseHas('debts', [
'account_id' => $user->account_id,
'contact_id' => $contact->id,
'id' => $debt_id,
'in_debt' => 'yes',
'status' => 'inprogress',
'amount' => 4200,
'reason' => 'that\'s why',
]);
}
/** @test */
public function it_cant_create_a_debt_if_fields_are_missing()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('POST', '/api/debts', [
'contact_id' => $contact->id,
]);
$this->expectDataError($response, [
'The in debt field is required.',
'The status field is required.',
'The amount field is required.',
]);
}
/** @test */
public function it_cant_create_a_debt_with_a_bad_account()
{
$user = $this->signin();
$account = factory(Account::class)->create();
$contact = factory(Contact::class)->create([
'account_id' => $account->id,
]);
$response = $this->json('POST', '/api/debts', [
'contact_id' => $contact->id,
'in_debt' => 'yes',
'status' => 'inprogress',
'amount' => 42,
'reason' => 'that\'s why',
]);
$this->expectNotFound($response);
}
/** @test */
public function it_updates_a_debt()
{
$user = $this->signin();
$user->locale = 'fr';
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$debt = factory(Debt::class)->create([
'account_id' => $user->account_id,
'contact_id' => $contact->id,
]);
$response = $this->json('PUT', '/api/debts/'.$debt->id, [
'contact_id' => $contact->id,
'in_debt' => 'yes',
'status' => 'completed',
'amount' => 142.01,
'reason' => 'voilà',
]);
$response->assertStatus(200);
$response->assertJsonStructure([
'data' => $this->jsonDebt,
]);
$debt_id = $response->json('data.id');
$this->assertEquals($debt->id, $debt_id);
$response->assertJsonFragment([
'object' => 'debt',
'id' => $debt_id,
'in_debt' => 'yes',
'status' => 'completed',
'amount' => '142.01',
'value' => '142,01',
'amount_with_currency' => '142,01'.chr(0xA0).'$US',
'reason' => 'voilà',
]);
$this->assertGreaterThan(0, $debt_id);
$this->assertDatabaseHas('debts', [
'account_id' => $user->account_id,
'contact_id' => $contact->id,
'id' => $debt_id,
'in_debt' => 'yes',
'status' => 'completed',
'amount' => 14201,
'reason' => 'voilà',
]);
}
/** @test */
public function it_cant_update_a_debt_with_missing_parameters()
{
$user = $this->signin();
$debt = factory(Debt::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('PUT', '/api/debts/'.$debt->id, [
'contact_id' => $debt->contact_id,
]);
$this->expectDataError($response, [
'The in debt field is required.',
'The status field is required.',
'The amount field is required.',
]);
}
/** @test */
public function it_cant_update_a_debt_with_a_wrong_account()
{
$user = $this->signin();
$account = factory(Account::class)->create();
$contact = factory(Contact::class)->create([
'account_id' => $account->id,
]);
$debt = factory(Debt::class)->create([
'account_id' => $user->account_id,
'contact_id' => $contact->id,
]);
$response = $this->json('PUT', '/api/debts/'.$debt->id, [
'contact_id' => $contact->id,
'in_debt' => 'yes',
'status' => 'completed',
'amount' => 142,
'reason' => 'voilà',
]);
$this->expectNotFound($response);
}
/** @test */
public function it_deletes_a_debt()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$debt = factory(Debt::class)->create([
'account_id' => $user->account_id,
'contact_id' => $contact->id,
]);
$this->assertDatabaseHas('debts', [
'account_id' => $user->account_id,
'contact_id' => $contact->id,
'id' => $debt->id,
]);
$response = $this->json('DELETE', '/api/debts/'.$debt->id);
$response->assertStatus(200);
$this->assertDatabaseMissing('debts', [
'account_id' => $user->account_id,
'contact_id' => $contact->id,
'id' => $debt->id,
]);
}
/** @test */
public function it_cant_delete_a_debt_with_an_invalid_id()
{
$user = $this->signin();
$response = $this->json('DELETE', '/api/debts/0');
$this->expectNotFound($response);
}
}

467
tests/Api/ApiGiftsTest.php Normal file
View File

@@ -0,0 +1,467 @@
<?php
namespace Tests\Api;
use Tests\ApiTestCase;
use App\Models\Contact\Gift;
use App\Models\Account\Account;
use App\Models\Contact\Contact;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class ApiGiftsTest extends ApiTestCase
{
use DatabaseTransactions;
protected $jsonGift = [
'id',
'object',
'status',
'comment',
'name',
'url',
'amount',
'amount_with_currency',
'status',
'account' => [
'id',
],
'contact' => [
'id',
],
'created_at',
'updated_at',
];
/** @test */
public function it_gets_all_the_gifts()
{
$user = $this->signin();
$contact1 = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$gift1 = factory(Gift::class)->create([
'account_id' => $user->account_id,
'contact_id' => $contact1->id,
]);
$contact2 = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$gift2 = factory(Gift::class)->create([
'account_id' => $user->account_id,
'contact_id' => $contact2->id,
]);
$response = $this->json('GET', '/api/gifts');
$response->assertStatus(200);
$response->assertJsonStructure([
'data' => ['*' => $this->jsonGift],
]);
$response->assertJsonFragment([
'object' => 'gift',
'id' => $gift1->id,
]);
$response->assertJsonFragment([
'object' => 'gift',
'id' => $gift2->id,
]);
}
/** @test */
public function it_gets_all_the_gifts_of_a_contact()
{
$user = $this->signin();
$contact1 = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$gift1 = factory(Gift::class)->create([
'account_id' => $user->account_id,
'contact_id' => $contact1->id,
]);
$contact2 = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$gift2 = factory(Gift::class)->create([
'account_id' => $user->account_id,
'contact_id' => $contact2->id,
]);
$response = $this->json('GET', '/api/contacts/'.$contact1->id.'/gifts');
$response->assertStatus(200);
$response->assertJsonStructure([
'data' => ['*' => $this->jsonGift],
]);
$response->assertJsonFragment([
'object' => 'gift',
'id' => $gift1->id,
]);
$response->assertJsonMissingExact([
'object' => 'gift',
'id' => $gift2->id,
]);
}
/** @test */
public function it_cant_get_all_the_gifts_of_an_invalid_contact()
{
$user = $this->signin();
$response = $this->json('GET', '/api/contacts/0/gifts');
$this->expectNotFound($response);
}
/** @test */
public function it_gets_one_gift()
{
$user = $this->signin();
$contact1 = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$gift1 = factory(Gift::class)->create([
'account_id' => $user->account_id,
'contact_id' => $contact1->id,
]);
$gift2 = factory(Gift::class)->create([
'account_id' => $user->account_id,
'contact_id' => $contact1->id,
]);
$response = $this->json('GET', '/api/gifts/'.$gift1->id);
$response->assertStatus(200);
$response->assertJsonStructure([
'data' => $this->jsonGift,
]);
$response->assertJsonFragment([
'object' => 'gift',
'id' => $gift1->id,
]);
$response->assertJsonMissingExact([
'object' => 'gift',
'id' => $gift2->id,
]);
}
/** @test */
public function it_cant_get_a_gift_with_an_invalid_id()
{
$user = $this->signin();
$response = $this->json('GET', '/api/gifts/0');
$this->expectNotFound($response);
}
/** @test */
public function it_create_a_gift()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('POST', '/api/gifts', [
'contact_id' => $contact->id,
'status' => 'idea',
'name' => 'the gift',
]);
$response->assertStatus(201);
$response->assertJsonStructure([
'data' => $this->jsonGift,
]);
$gift_id = $response->json('data.id');
$response->assertJsonFragment([
'object' => 'gift',
'id' => $gift_id,
]);
$this->assertGreaterThan(0, $gift_id);
$this->assertDatabaseHas('gifts', [
'account_id' => $user->account_id,
'contact_id' => $contact->id,
'id' => $gift_id,
'name' => 'the gift',
]);
}
/** @test */
public function gifts_create_is_for()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$contact2 = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('POST', '/api/gifts', [
'contact_id' => $contact->id,
'name' => 'the gift',
'status' => 'idea',
'recipient_id' => $contact2->id,
]);
$response->assertStatus(201);
$response->assertJsonStructure([
'data' => $this->jsonGift,
]);
$gift_id = $response->json('data.id');
$response->assertJsonFragment([
'object' => 'gift',
'id' => $gift_id,
]);
$this->assertGreaterThan(0, $gift_id);
$this->assertDatabaseHas('gifts', [
'account_id' => $user->account_id,
'contact_id' => $contact->id,
'id' => $gift_id,
'name' => 'the gift',
'is_for' => $contact2->id,
]);
}
/** @test */
public function gifts_create_is_for_bad_account()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$account = factory(Account::class)->create();
$contact2 = factory(Contact::class)->create([
'account_id' => $account->id,
]);
$response = $this->json('POST', '/api/gifts', [
'contact_id' => $contact->id,
'name' => 'the gift',
'status' => 'idea',
'recipient_id' => $contact2->id,
]);
$this->expectNotFound($response);
}
/** @test */
public function gifts_create_error()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('POST', '/api/gifts', [
'contact_id' => $contact->id,
'status' => 'idea',
]);
$this->expectDataError($response, [
'The name field is required.',
]);
}
/** @test */
public function gifts_create_error_bad_account()
{
$user = $this->signin();
$account = factory(Account::class)->create();
$contact = factory(Contact::class)->create([
'account_id' => $account->id,
]);
$response = $this->json('POST', '/api/gifts', [
'contact_id' => $contact->id,
'name' => 'the gift',
'status' => 'idea',
]);
$this->expectNotFound($response);
}
/** @test */
public function gifts_update()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$gift = factory(Gift::class)->create([
'account_id' => $user->account_id,
'contact_id' => $contact->id,
]);
$response = $this->json('PUT', '/api/gifts/'.$gift->id, [
'contact_id' => $contact->id,
'name' => 'the gift',
'status' => 'idea',
'comment' => 'one comment',
]);
$response->assertStatus(200);
$response->assertJsonStructure([
'data' => $this->jsonGift,
]);
$gift_id = $response->json('data.id');
$this->assertEquals($gift->id, $gift_id);
$response->assertJsonFragment([
'object' => 'gift',
'id' => $gift_id,
]);
$this->assertGreaterThan(0, $gift_id);
$this->assertDatabaseHas('gifts', [
'account_id' => $user->account_id,
'contact_id' => $contact->id,
'id' => $gift_id,
'name' => 'the gift',
'comment' => 'one comment',
]);
}
/** @test */
public function gifts_update_is_for()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$contact2 = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$gift = factory(Gift::class)->create([
'account_id' => $user->account_id,
'contact_id' => $contact->id,
]);
$response = $this->json('PUT', '/api/gifts/'.$gift->id, [
'contact_id' => $contact->id,
'name' => 'the gift',
'status' => 'idea',
'comment' => 'one comment',
'recipient_id' => $contact2->id,
]);
$response->assertStatus(200);
$response->assertJsonStructure([
'data' => $this->jsonGift,
]);
$gift_id = $response->json('data.id');
$this->assertEquals($gift->id, $gift_id);
$response->assertJsonFragment([
'object' => 'gift',
'id' => $gift_id,
]);
$this->assertGreaterThan(0, $gift_id);
$this->assertDatabaseHas('gifts', [
'account_id' => $user->account_id,
'contact_id' => $contact->id,
'id' => $gift_id,
'name' => 'the gift',
'comment' => 'one comment',
'is_for' => $contact2->id,
]);
}
/** @test */
public function gifts_update_error()
{
$user = $this->signin();
$gift = factory(Gift::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('PUT', '/api/gifts/'.$gift->id, [
'contact_id' => $gift->contact_id,
'status' => 'idea',
]);
$this->expectDataError($response, [
'The name field is required.',
]);
}
/** @test */
public function gifts_update_error_bad_account()
{
$user = $this->signin();
$account = factory(Account::class)->create();
$contact = factory(Contact::class)->create([
'account_id' => $account->id,
]);
$gift = factory(Gift::class)->create([
'account_id' => $user->account_id,
'contact_id' => $contact->id,
]);
$response = $this->json('PUT', '/api/gifts/'.$gift->id, [
'contact_id' => $contact->id,
'name' => 'the gift',
'status' => 'idea',
'comment' => 'one comment',
]);
$this->expectNotFound($response);
}
/** @test */
public function gifts_delete()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$gift = factory(Gift::class)->create([
'account_id' => $user->account_id,
'contact_id' => $contact->id,
]);
$this->assertDatabaseHas('gifts', [
'account_id' => $user->account_id,
'contact_id' => $contact->id,
'id' => $gift->id,
]);
$response = $this->json('DELETE', '/api/gifts/'.$gift->id);
$response->assertStatus(200);
$response->assertJson([
'deleted' => true,
'id' => $gift->id,
]);
$this->assertDatabaseMissing('gifts', [
'account_id' => $user->account_id,
'contact_id' => $contact->id,
'id' => $gift->id,
]);
}
/** @test */
public function gifts_delete_error()
{
$user = $this->signin();
$response = $this->json('DELETE', '/api/gifts/0');
$response->assertStatus(422);
}
/** @test */
public function gifts_delete_wrong_account()
{
$user = $this->signin();
$gift = factory(Gift::class)->create();
$response = $this->json('DELETE', '/api/gifts/'.$gift->id);
$this->expectNotFound($response);
}
}

View File

@@ -0,0 +1,215 @@
<?php
namespace Tests\Api;
use Tests\ApiTestCase;
use App\Models\Journal\Entry;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class ApiJournalTest extends ApiTestCase
{
use DatabaseTransactions;
protected $jsonJournal = [
'id',
'object',
'title',
'post',
'account' => [
'id',
],
'created_at',
'updated_at',
];
/** @test */
public function it_gets_all_the_journal_entries()
{
$user = $this->signin();
$firstEntry = factory(Entry::class)->create([
'account_id' => $user->account_id,
]);
$secondEntry = factory(Entry::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('GET', '/api/journal');
$response->assertStatus(200);
$response->assertJsonStructure([
'data' => ['*' => $this->jsonJournal],
]);
$response->assertJsonFragment([
'object' => 'entry',
'id' => $firstEntry->id,
]);
$response->assertJsonFragment([
'object' => 'entry',
'id' => $secondEntry->id,
]);
}
/** @test */
public function it_gets_one_journal_entry()
{
$user = $this->signin();
$firstEntry = factory(Entry::class)->create([
'account_id' => $user->account_id,
]);
$secondEntry = factory(Entry::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('GET', '/api/journal/'.$firstEntry->id);
$response->assertStatus(200);
$response->assertJsonStructure([
'data' => $this->jsonJournal,
]);
$response->assertJsonFragment([
'object' => 'entry',
'id' => $firstEntry->id,
]);
$response->assertJsonMissingExact([
'object' => 'entry',
'id' => $secondEntry->id,
]);
}
/** @test */
public function it_cant_get_a_journal_entry_with_an_invalid_id()
{
$user = $this->signin();
$response = $this->json('GET', '/api/journal/0');
$this->expectNotFound($response);
}
/** @test */
public function it_creates_a_journal_entry()
{
$user = $this->signin();
$response = $this->json('POST', '/api/journal', [
'title' => 'my title',
'post' => 'content post',
]);
$response->assertStatus(201);
$response->assertJsonStructure([
'data' => $this->jsonJournal,
]);
$entryId = $response->json('data.id');
$response->assertJsonFragment([
'object' => 'entry',
'id' => $entryId,
'title' => 'my title',
'post' => 'content post',
]);
$this->assertGreaterThan(0, $entryId);
$this->assertDatabaseHas('entries', [
'account_id' => $user->account_id,
'id' => $entryId,
'title' => 'my title',
'post' => 'content post',
]);
}
/** @test */
public function it_cant_create_a_journal_entry_with_missing_parameters()
{
$user = $this->signin();
$response = $this->json('POST', '/api/journal', []);
$this->expectDataError($response, [
'The title field is required.',
'The post field is required.',
]);
}
/** @test */
public function it_updates_a_journal_entry()
{
$user = $this->signin();
$entry = factory(Entry::class)->create([
'account_id' => $user->account_id,
'title' => 'xxx',
]);
$response = $this->json('PUT', '/api/journal/'.$entry->id, [
'title' => 'my title',
'post' => 'content post',
]);
$response->assertStatus(200);
$response->assertJsonStructure([
'data' => $this->jsonJournal,
]);
$entryId = $response->json('data.id');
$this->assertEquals($entry->id, $entryId);
$response->assertJsonFragment([
'object' => 'entry',
'id' => $entryId,
'title' => 'my title',
'post' => 'content post',
]);
$this->assertGreaterThan(0, $entryId);
$this->assertDatabaseHas('entries', [
'account_id' => $user->account_id,
'id' => $entryId,
'title' => 'my title',
'post' => 'content post',
]);
}
/** @test */
public function it_cant_update_a_journal_entry_with_missing_parameters()
{
$user = $this->signin();
$entry = factory(Entry::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('PUT', '/api/journal/'.$entry->id, []);
$this->expectDataError($response, [
'The title field is required.',
'The post field is required.',
]);
}
/** @test */
public function it_deletes_a_journal_entry()
{
$user = $this->signin();
$entry = factory(Entry::class)->create([
'account_id' => $user->account_id,
]);
$this->assertDatabaseHas('entries', [
'account_id' => $user->account_id,
'id' => $entry->id,
]);
$response = $this->json('DELETE', '/api/journal/'.$entry->id);
$response->assertStatus(200);
$this->assertDatabaseMissing('entries', [
'account_id' => $user->account_id,
'id' => $entry->id,
]);
}
/** @test */
public function it_cant_delete_a_journal_entry_with_an_invalid_id()
{
$user = $this->signin();
$response = $this->json('DELETE', '/api/journal/0');
$this->expectNotFound($response);
}
}

428
tests/Api/ApiNotesTest.php Normal file
View File

@@ -0,0 +1,428 @@
<?php
namespace Tests\Api;
use Carbon\Carbon;
use Tests\ApiTestCase;
use App\Models\Contact\Note;
use App\Models\Account\Account;
use App\Models\Contact\Contact;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class ApiNotesTest extends ApiTestCase
{
use DatabaseTransactions;
protected $jsonNote = [
'id',
'object',
'body',
'is_favorited',
'favorited_at',
'account' => [
'id',
],
'contact' => [
'id',
],
'created_at',
'updated_at',
];
/** @test */
public function it_gets_all_the_notes()
{
$user = $this->signin();
$contact1 = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$note1 = factory(Note::class)->create([
'account_id' => $user->account_id,
'contact_id' => $contact1->id,
]);
$contact2 = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$note2 = factory(Note::class)->create([
'account_id' => $user->account_id,
'contact_id' => $contact2->id,
]);
$response = $this->json('GET', '/api/notes');
$response->assertStatus(200);
$response->assertJsonStructure([
'data' => ['*' => $this->jsonNote],
]);
$response->assertJsonFragment([
'object' => 'note',
'id' => $note1->id,
]);
$response->assertJsonFragment([
'object' => 'note',
'id' => $note2->id,
]);
}
/** @test */
public function it_gets_all_the_notes_of_a_given_contact()
{
$user = $this->signin();
$contact1 = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$note1 = factory(Note::class)->create([
'account_id' => $user->account_id,
'contact_id' => $contact1->id,
]);
$contact2 = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$note2 = factory(Note::class)->create([
'account_id' => $user->account_id,
'contact_id' => $contact2->id,
]);
$response = $this->json('GET', '/api/contacts/'.$contact1->id.'/notes');
$response->assertStatus(200);
$response->assertJsonStructure([
'data' => ['*' => $this->jsonNote],
]);
$response->assertJsonFragment([
'object' => 'note',
'id' => $note1->id,
]);
$response->assertJsonMissingExact([
'object' => 'note',
'id' => $note2->id,
]);
}
/** @test */
public function it_cant_get_notes_from_a_contact_with_invalid_id()
{
$user = $this->signin();
$response = $this->json('GET', '/api/contacts/0/notes');
$this->expectNotFound($response);
}
/** @test */
public function it_gets_one_note()
{
$user = $this->signin();
$contact1 = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$note1 = factory(Note::class)->create([
'account_id' => $user->account_id,
'contact_id' => $contact1->id,
]);
$note2 = factory(Note::class)->create([
'account_id' => $user->account_id,
'contact_id' => $contact1->id,
]);
$response = $this->json('GET', '/api/notes/'.$note1->id);
$response->assertStatus(200);
$response->assertJsonStructure([
'data' => $this->jsonNote,
]);
$response->assertJsonFragment([
'object' => 'note',
'id' => $note1->id,
]);
$response->assertJsonMissingExact([
'object' => 'note',
'id' => $note2->id,
]);
}
/** @test */
public function it_gets_a_note_with_an_invalid_id()
{
$user = $this->signin();
$response = $this->json('GET', '/api/notes/0');
$this->expectNotFound($response);
}
/** @test */
public function it_creates_a_note()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('POST', '/api/notes', [
'contact_id' => $contact->id,
'body' => 'the body of the note',
'is_favorited' => false,
]);
$response->assertStatus(201);
$response->assertJsonStructure([
'data' => $this->jsonNote,
]);
$note_id = $response->json('data.id');
$response->assertJsonFragment([
'object' => 'note',
'id' => $note_id,
'body' => 'the body of the note',
'is_favorited' => false,
]);
$this->assertGreaterThan(0, $note_id);
$this->assertDatabaseHas('notes', [
'account_id' => $user->account_id,
'contact_id' => $contact->id,
'id' => $note_id,
'body' => 'the body of the note',
'is_favorited' => false,
]);
}
/** @test */
public function it_creates_a_note_and_marks_as_favorite()
{
Carbon::setTestNow(Carbon::create(2018, 1, 1, 7, 0, 0));
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('POST', '/api/notes', [
'contact_id' => $contact->id,
'body' => 'the body of the note',
'is_favorited' => true,
]);
$response->assertStatus(201);
$response->assertJsonStructure([
'data' => $this->jsonNote,
]);
$note_id = $response->json('data.id');
$response->assertJsonFragment([
'object' => 'note',
'id' => $note_id,
'body' => 'the body of the note',
'is_favorited' => true,
'favorited_at' => '2018-01-01T07:00:00Z',
]);
$this->assertGreaterThan(0, $note_id);
$this->assertDatabaseHas('notes', [
'account_id' => $user->account_id,
'contact_id' => $contact->id,
'id' => $note_id,
'body' => 'the body of the note',
'is_favorited' => true,
'favorited_at' => '2018-01-01',
]);
}
/** @test */
public function it_cant_create_a_note_with_missing_parameters()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('POST', '/api/notes', [
'contact_id' => $contact->id,
]);
$this->expectDataError($response, [
'The body field is required.',
]);
}
/** @test */
public function it_cant_create_a_note_with_an_invalid_account()
{
$user = $this->signin();
$account = factory(Account::class)->create();
$contact = factory(Contact::class)->create([
'account_id' => $account->id,
]);
$response = $this->json('POST', '/api/notes', [
'contact_id' => $contact->id,
'body' => 'the body of the note',
'is_favorited' => false,
]);
$this->expectNotFound($response);
}
/** @test */
public function it_updates_a_note()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$note = factory(Note::class)->create([
'account_id' => $user->account_id,
'contact_id' => $contact->id,
]);
$response = $this->json('PUT', '/api/notes/'.$note->id, [
'contact_id' => $contact->id,
'body' => 'the body of the note',
'is_favorited' => false,
]);
$response->assertStatus(200);
$response->assertJsonStructure([
'data' => $this->jsonNote,
]);
$note_id = $response->json('data.id');
$this->assertEquals($note->id, $note_id);
$response->assertJsonFragment([
'object' => 'note',
'id' => $note_id,
'body' => 'the body of the note',
'is_favorited' => false,
]);
$this->assertGreaterThan(0, $note_id);
$this->assertDatabaseHas('notes', [
'account_id' => $user->account_id,
'contact_id' => $contact->id,
'id' => $note_id,
'body' => 'the body of the note',
'is_favorited' => false,
]);
}
/** @test */
public function it_updates_a_note_and_marks_it_as_favorite()
{
Carbon::setTestNow(Carbon::create(2018, 1, 1, 7, 0, 0));
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$note = factory(Note::class)->create([
'account_id' => $user->account_id,
'contact_id' => $contact->id,
]);
$response = $this->json('PUT', '/api/notes/'.$note->id, [
'contact_id' => $contact->id,
'body' => 'the body of the note',
'is_favorited' => true,
]);
$response->assertStatus(200);
$response->assertJsonStructure([
'data' => $this->jsonNote,
]);
$note_id = $response->json('data.id');
$this->assertEquals($note->id, $note_id);
$response->assertJsonFragment([
'object' => 'note',
'id' => $note_id,
'body' => 'the body of the note',
'is_favorited' => true,
'favorited_at' => '2018-01-01T07:00:00Z',
]);
$this->assertGreaterThan(0, $note_id);
$this->assertDatabaseHas('notes', [
'account_id' => $user->account_id,
'contact_id' => $contact->id,
'id' => $note_id,
'body' => 'the body of the note',
'is_favorited' => true,
'favorited_at' => '2018-01-01',
]);
}
/** @test */
public function it_cant_update_a_note_with_missing_parameters()
{
$user = $this->signin();
$note = factory(Note::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('PUT', '/api/notes/'.$note->id, [
'contact_id' => $note->contact_id,
]);
$this->expectDataError($response, [
'The body field is required.',
]);
}
/** @test */
public function it_cant_update_a_note_with_an_invalid_account()
{
$user = $this->signin();
$account = factory(Account::class)->create();
$contact = factory(Contact::class)->create([
'account_id' => $account->id,
]);
$note = factory(Note::class)->create([
'account_id' => $user->account_id,
'contact_id' => $contact->id,
]);
$response = $this->json('PUT', '/api/notes/'.$note->id, [
'contact_id' => $contact->id,
'body' => 'the body of the note',
'is_favorited' => false,
]);
$this->expectNotFound($response);
}
/** @test */
public function it_deletes_a_note()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$note = factory(Note::class)->create([
'account_id' => $user->account_id,
'contact_id' => $contact->id,
]);
$this->assertDatabaseHas('notes', [
'account_id' => $user->account_id,
'contact_id' => $contact->id,
'id' => $note->id,
]);
$response = $this->json('DELETE', '/api/notes/'.$note->id);
$response->assertStatus(200);
$this->assertDatabaseMissing('notes', [
'account_id' => $user->account_id,
'contact_id' => $contact->id,
'id' => $note->id,
]);
}
/** @test */
public function it_cant_delete_a_note_with_an_invalid_id()
{
$user = $this->signin();
$response = $this->json('DELETE', '/api/notes/0');
$this->expectNotFound($response);
}
}

347
tests/Api/ApiPetsTest.php Normal file
View File

@@ -0,0 +1,347 @@
<?php
namespace Tests\Api;
use Tests\ApiTestCase;
use App\Models\Contact\Pet;
use App\Models\Account\Account;
use App\Models\Contact\Contact;
use App\Models\Contact\PetCategory;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class ApiPetsTest extends ApiTestCase
{
use DatabaseTransactions;
protected $jsonPet = [
'id',
'object',
'name',
'pet_category' => [
'id',
'object',
'name',
'is_common',
],
'account' => [
'id',
],
'contact' => [
'id',
],
'created_at',
'updated_at',
];
/** @test */
public function pets_get_all()
{
$user = $this->signin();
$contact1 = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$pet1 = factory(Pet::class)->create([
'account_id' => $user->account_id,
'contact_id' => $contact1->id,
]);
$contact2 = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$pet2 = factory(Pet::class)->create([
'account_id' => $user->account_id,
'contact_id' => $contact2->id,
]);
$response = $this->json('GET', '/api/pets');
$response->assertStatus(200);
$response->assertJsonStructure([
'data' => ['*' => $this->jsonPet],
]);
$response->assertJsonFragment([
'object' => 'pet',
'id' => $pet1->id,
]);
$response->assertJsonFragment([
'object' => 'pet',
'id' => $pet2->id,
]);
}
/** @test */
public function pets_get_contact_all()
{
$user = $this->signin();
$contact1 = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$pet1 = factory(Pet::class)->create([
'account_id' => $user->account_id,
'contact_id' => $contact1->id,
]);
$contact2 = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$pet2 = factory(Pet::class)->create([
'account_id' => $user->account_id,
'contact_id' => $contact2->id,
]);
$response = $this->json('GET', '/api/contacts/'.$contact1->id.'/pets');
$response->assertStatus(200);
$response->assertJsonStructure([
'data' => ['*' => $this->jsonPet],
]);
$response->assertJsonFragment([
'object' => 'pet',
'id' => $pet1->id,
]);
$response->assertJsonMissingExact([
'object' => 'pet',
'id' => $pet2->id,
]);
}
/** @test */
public function pets_get_contact_all_error()
{
$user = $this->signin();
$response = $this->json('GET', '/api/contacts/0/pets');
$this->expectNotFound($response);
}
/** @test */
public function pets_get_one()
{
$user = $this->signin();
$contact1 = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$pet1 = factory(Pet::class)->create([
'account_id' => $user->account_id,
'contact_id' => $contact1->id,
]);
$pet2 = factory(Pet::class)->create([
'account_id' => $user->account_id,
'contact_id' => $contact1->id,
]);
$response = $this->json('GET', '/api/pets/'.$pet1->id);
$response->assertStatus(200);
$response->assertJsonStructure([
'data' => $this->jsonPet,
]);
$response->assertJsonFragment([
'object' => 'pet',
'id' => $pet1->id,
]);
$response->assertJsonMissingExact([
'object' => 'pet',
'id' => $pet2->id,
]);
}
/** @test */
public function pets_get_one_error()
{
$user = $this->signin();
$response = $this->json('GET', '/api/pets/0');
$this->expectNotFound($response);
}
/** @test */
public function pets_create()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$pet_category = factory(PetCategory::class)->create();
$response = $this->json('POST', '/api/pets', [
'contact_id' => $contact->id,
'pet_category_id' => $pet_category->id,
'name' => 'the name',
]);
$response->assertStatus(201);
$response->assertJsonStructure([
'data' => $this->jsonPet,
]);
$pet_id = $response->json('data.id');
$response->assertJsonFragment([
'object' => 'pet',
'id' => $pet_id,
'name' => 'the name',
]);
$this->assertGreaterThan(0, $pet_id);
$this->assertDatabaseHas('pets', [
'account_id' => $user->account_id,
'contact_id' => $contact->id,
'pet_category_id' => $pet_category->id,
'id' => $pet_id,
'name' => 'the name',
]);
}
/** @test */
public function pets_create_error()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('POST', '/api/pets', [
'contact_id' => $contact->id,
]);
$this->expectDataError($response, [
'The pet category id field is required.',
]);
}
/** @test */
public function pets_create_error_bad_account()
{
$user = $this->signin();
$account = factory(Account::class)->create();
$contact = factory(Contact::class)->create([
'account_id' => $account->id,
]);
$pet_category = factory(PetCategory::class)->create();
$response = $this->json('POST', '/api/pets', [
'contact_id' => $contact->id,
'pet_category_id' => $pet_category->id,
]);
$this->expectNotFound($response);
}
/** @test */
public function pets_update()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$pet = factory(Pet::class)->create([
'account_id' => $user->account_id,
'contact_id' => $contact->id,
]);
$pet_category = factory(PetCategory::class)->create();
$response = $this->json('PUT', '/api/pets/'.$pet->id, [
'contact_id' => $contact->id,
'pet_category_id' => $pet_category->id,
'name' => 'the name',
]);
$response->assertStatus(200);
$response->assertJsonStructure([
'data' => $this->jsonPet,
]);
$pet_id = $response->json('data.id');
$this->assertEquals($pet->id, $pet_id);
$response->assertJsonFragment([
'object' => 'pet',
'id' => $pet_id,
'name' => 'the name',
]);
$this->assertGreaterThan(0, $pet_id);
$this->assertDatabaseHas('pets', [
'account_id' => $user->account_id,
'contact_id' => $contact->id,
'pet_category_id' => $pet_category->id,
'id' => $pet_id,
'name' => 'the name',
]);
}
/** @test */
public function pets_update_error()
{
$user = $this->signin();
$pet = factory(Pet::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('PUT', '/api/pets/'.$pet->id, [
'contact_id' => $pet->contact_id,
]);
$this->expectDataError($response, [
'The pet category id field is required.',
]);
}
/** @test */
public function pets_update_error_bad_account()
{
$user = $this->signin();
$account = factory(Account::class)->create();
$contact = factory(Contact::class)->create([
'account_id' => $account->id,
]);
$pet = factory(Pet::class)->create([
'account_id' => $user->account_id,
'contact_id' => $contact->id,
]);
$pet_category = factory(PetCategory::class)->create();
$response = $this->json('PUT', '/api/pets/'.$pet->id, [
'contact_id' => $contact->id,
'pet_category_id' => $pet_category->id,
]);
$this->expectNotFound($response);
}
/** @test */
public function pets_delete()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$pet = factory(Pet::class)->create([
'account_id' => $user->account_id,
'contact_id' => $contact->id,
]);
$this->assertDatabaseHas('pets', [
'account_id' => $user->account_id,
'contact_id' => $contact->id,
'id' => $pet->id,
]);
$response = $this->json('DELETE', '/api/pets/'.$pet->id);
$response->assertStatus(200);
$this->assertDatabaseMissing('pets', [
'account_id' => $user->account_id,
'contact_id' => $contact->id,
'id' => $pet->id,
]);
}
/** @test */
public function pets_delete_error()
{
$user = $this->signin();
$response = $this->json('DELETE', '/api/pets/0');
$this->expectNotFound($response);
}
}

View File

@@ -0,0 +1,389 @@
<?php
namespace Tests\Api;
use Tests\ApiTestCase;
use App\Models\Contact\Contact;
use App\Models\Relationship\Relationship;
use App\Models\Relationship\RelationshipType;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class ApiRelationshipControllerTest extends ApiTestCase
{
use DatabaseTransactions;
/** @test */
public function it_rejects_the_api_call_if_parameters_are_not_right()
{
$user = $this->signin();
$contactA = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$contactB = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$relationshipType = factory(RelationshipType::class)->create([
'account_id' => $user->account_id,
]);
// make sure contact_is is an integer
$response = $this->json('POST', '/api/relationships', [
'contact_is' => 'a',
'relationship_type_id' => $relationshipType->id,
'of_contact' => $contactB->id,
]);
$this->expectDataError($response, ['The contact is must be an integer.']);
// make sure relationship type id is an integer
$response = $this->json('POST', '/api/relationships', [
'contact_is' => $contactA->id,
'relationship_type_id' => 'a',
'of_contact' => $contactB->id,
]);
$this->expectDataError($response, ['The relationship type id must be an integer.']);
// make sure of_contact is an integer
$response = $this->json('POST', '/api/relationships', [
'contact_is' => $contactA->id,
'relationship_type_id' => $relationshipType->id,
'of_contact' => 'a',
]);
$this->expectDataError($response, ['The of contact must be an integer.']);
}
/** @test */
public function it_fails_if_relationship_type_id_is_invalid()
{
$user = $this->signin();
$contactA = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$contactB = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$relationshipType = factory(RelationshipType::class)->create();
$response = $this->json('POST', '/api/relationships', [
'contact_is' => $contactA->id,
'relationship_type_id' => $relationshipType->id,
'of_contact' => $contactB->id,
]);
$this->expectNotFound($response);
}
/** @test */
public function it_fails_if_contact_is_id_is_invalid()
{
$user = $this->signin();
$contactA = factory(Contact::class)->create();
$contactB = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$relationshipType = factory(RelationshipType::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('POST', '/api/relationships', [
'contact_is' => $contactA->id,
'relationship_type_id' => $relationshipType->id,
'of_contact' => $contactB->id,
]);
$this->expectNotFound($response);
}
/** @test */
public function it_fails_if_of_contact_id_is_invalid()
{
$user = $this->signin();
$contactA = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$contactB = factory(Contact::class)->create();
$relationshipType = factory(RelationshipType::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('POST', '/api/relationships', [
'contact_is' => $contactA->id,
'relationship_type_id' => $relationshipType->id,
'of_contact' => $contactB->id,
]);
$this->expectNotFound($response);
}
/** @test */
public function it_creates_a_new_resource()
{
$user = $this->signin();
$contactA = factory(Contact::class)->create(['account_id' => $user->account_id]);
$contactB = factory(Contact::class)->create(['account_id' => $user->account_id]);
$relationshipType = factory(RelationshipType::class)->create([
'account_id' => $user->account_id,
'name' => 'uncle',
'name_reverse_relationship' => 'nephew',
]);
$relationshipTypeB = factory(RelationshipType::class)->create([
'account_id' => $user->account_id,
'name' => 'nephew',
'name_reverse_relationship' => 'uncle',
]);
$response = $this->json('POST', '/api/relationships', [
'contact_is' => $contactA->id,
'relationship_type_id' => $relationshipType->id,
'of_contact' => $contactB->id,
]);
$response->assertStatus(201);
$this->assertDatabaseHas('relationships', [
'account_id' => auth()->user()->account_id,
'contact_is' => $contactA->id,
'of_contact' => $contactB->id,
'relationship_type_id' => $relationshipType->id,
]);
$this->assertDatabaseHas('relationships', [
'account_id' => auth()->user()->account_id,
'contact_is' => $contactB->id,
'of_contact' => $contactA->id,
'relationship_type_id' => auth()->user()->account->getRelationshipTypeByType($relationshipType->name_reverse_relationship)->id,
]);
}
/** @test */
public function it_displays_a_relationship()
{
$user = $this->signin();
$contactA = factory(Contact::class)->create(['account_id' => $user->account_id]);
$contactB = factory(Contact::class)->create(['account_id' => $user->account_id]);
$relationshipType = factory(RelationshipType::class)->create([
'account_id' => $user->account_id,
'name' => 'uncle',
'name_reverse_relationship' => 'nephew',
]);
$relationshipTypeB = factory(RelationshipType::class)->create([
'account_id' => $user->account_id,
'name' => 'nephew',
'name_reverse_relationship' => 'uncle',
]);
$relationship = factory(Relationship::class)->create([
'account_id' => $user->account_id,
'relationship_type_id' => $relationshipType->id,
'contact_is' => $contactA->id,
'of_contact' => $contactB->id,
]);
$response = $this->json('GET', '/api/relationships/'.$relationship->id);
$response->assertStatus(200)
->assertJsonFragment([
'id' => $relationship->id,
'object' => 'relationship',
]);
}
/** @test */
public function it_deletes_a_relationship()
{
$user = $this->signin();
$contactA = factory(Contact::class)->create(['account_id' => $user->account_id]);
$contactB = factory(Contact::class)->create(['account_id' => $user->account_id]);
$relationshipType = factory(RelationshipType::class)->create([
'account_id' => $user->account_id,
'name' => 'uncle',
'name_reverse_relationship' => 'nephew',
]);
$relationshipTypeB = factory(RelationshipType::class)->create([
'account_id' => $user->account_id,
'name' => 'nephew',
'name_reverse_relationship' => 'uncle',
]);
$relationship = factory(Relationship::class)->create([
'account_id' => $user->account_id,
'relationship_type_id' => $relationshipType->id,
'contact_is' => $contactA->id,
'of_contact' => $contactB->id,
]);
$relationshipB = factory(Relationship::class)->create([
'account_id' => $user->account_id,
'relationship_type_id' => $relationshipTypeB->id,
'contact_is' => $contactB->id,
'of_contact' => $contactA->id,
]);
$response = $this->json('DELETE', '/api/relationships/'.$relationship->id);
$response->assertStatus(200)
->assertJson([
'deleted' => true,
'id' => $relationship->id,
]);
$this->assertDatabaseMissing('relationships', [
'id' => $relationship->id,
]);
$this->assertDatabaseMissing('relationships', [
'id' => $relationshipB->id,
]);
}
/** @test */
public function it_rejects_the_delete_api_call_if_parameters_are_not_right()
{
$user = $this->signin();
// make sure relationship id is valid
$response = $this->json('DELETE', '/api/relationships/0');
$this->expectDataError($response, ['The selected relationship id is invalid.']);
// make sure relationship id is an integer
$response = $this->json('DELETE', '/api/relationships/x');
$this->expectDataError($response, ['The relationship id must be an integer.']);
// make sure relationship id is with the right account
$relationship = factory(Relationship::class)->create();
$response = $this->json('DELETE', '/api/relationships/'.$relationship->id);
$this->expectNotFound($response);
}
/** @test */
public function it_rejects_the_update_api_call_if_parameters_are_not_right()
{
$user = $this->signin();
$relationship = factory(Relationship::class)->create([
'account_id' => $user->account_id,
]);
$relationshipType = factory(RelationshipType::class)->create();
// make sure relationship type id is an integer
$response = $this->json('PUT', '/api/relationships/'.$relationship->id, [
'relationship_type_id' => $relationshipType->id,
]);
$this->expectNotFound($response);
}
/** @test */
public function it_rejects_the_update_api_call_if_parameters_are_not_right2()
{
$user = $this->signin();
$relationship = factory(Relationship::class)->create([
'account_id' => $user->account_id,
]);
// make sure relationship type id is an integer
$response = $this->json('PUT', '/api/relationships/'.$relationship->id, [
'relationship_type_id' => 'a',
]);
$this->expectDataError($response, ['The relationship type id must be an integer.']);
}
/** @test */
public function it_fails_the_update_if_relationship_type_id_is_invalid()
{
$user = $this->signin();
$relationship = factory(Relationship::class)->create([
'account_id' => $user->account_id,
]);
$relationshipType = factory(RelationshipType::class)->create();
$response = $this->json('PUT', '/api/relationships/'.$relationship->id, [
'relationship_type_id' => $relationshipType->id,
]);
$this->expectNotFound($response);
}
/** @test */
public function it_updates_a_relationship()
{
$user = $this->signin();
$contactA = factory(Contact::class)->create(['account_id' => $user->account_id]);
$contactB = factory(Contact::class)->create(['account_id' => $user->account_id]);
$relationshipType = factory(RelationshipType::class)->create([
'account_id' => $user->account_id,
'name' => 'uncle',
'name_reverse_relationship' => 'nephew',
]);
$relationshipTypeC = factory(RelationshipType::class)->create([
'account_id' => $user->account_id,
'name' => 'fuckfriend',
'name_reverse_relationship' => 'funnysituation',
]);
$relationship = factory(Relationship::class)->create([
'account_id' => $user->account_id,
'relationship_type_id' => $relationshipType->id,
'contact_is' => $contactA->id,
'of_contact' => $contactB->id,
]);
$response = $this->json('PUT', '/api/relationships/'.$relationship->id, [
'relationship_type_id' => $relationshipTypeC->id,
]);
$response->assertStatus(200)
->assertJsonFragment([
'id' => $relationshipTypeC->id,
'name' => 'fuckfriend',
]);
$this->assertDatabaseHas('relationships', [
'id' => $relationship->id,
'relationship_type_id' => $relationshipTypeC->id,
]);
}
/** @test */
public function it_displays_all_relationships_of_a_contact()
{
$user = $this->signin();
$contactA = factory(Contact::class)->create(['account_id' => $user->account_id]);
$contactB = factory(Contact::class)->create(['account_id' => $user->account_id]);
$relationshipType = factory(RelationshipType::class)->create([
'account_id' => $user->account_id,
'name' => 'uncle',
'name_reverse_relationship' => 'nephew',
]);
$relationshipTypeB = factory(RelationshipType::class)->create([
'account_id' => $user->account_id,
'name' => 'nephew',
'name_reverse_relationship' => 'uncle',
]);
$relationship = factory(Relationship::class, 3)->create([
'account_id' => $user->account_id,
'relationship_type_id' => $relationshipType->id,
'contact_is' => $contactA->id,
'of_contact' => $contactB->id,
]);
$response = $this->json('GET', '/api/contacts/'.$contactA->id.'/relationships');
$response->assertStatus(200);
$decodedJson = $response->decodeResponseJson();
$this->assertCount(
3,
$decodedJson['data']
);
}
}

View File

@@ -0,0 +1,100 @@
<?php
namespace Tests\Api;
use Tests\ApiTestCase;
use App\Models\Relationship\RelationshipType;
use App\Models\Relationship\RelationshipTypeGroup;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class ApiRelationshipTypeControllerTest extends ApiTestCase
{
use DatabaseTransactions;
/** @test */
public function it_gets_the_right_number_of_relationship_types()
{
$user = $this->signin();
factory(RelationshipType::class, 10)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('GET', '/api/relationshiptypes');
$response->assertStatus(200);
$decodedJson = $response->decodeResponseJson();
$this->assertCount(
10,
$decodedJson['data']
);
}
/** @test */
public function it_gets_the_list_of_relationship_types()
{
$user = $this->signin();
$relationshipTypeGroup = factory(RelationshipTypeGroup::class)->create([
'account_id' => $user->account_id,
]);
factory(RelationshipType::class)->create([
'account_id' => $user->account_id,
'name' => 'father',
'name_reverse_relationship' => 'son',
'relationship_type_group_id' => $relationshipTypeGroup->id,
'delible' => 0,
]);
$relationshipType2 = factory(RelationshipType::class)->create([
'account_id' => $user->account_id,
'name' => 'son',
'name_reverse_relationship' => 'father',
'relationship_type_group_id' => $relationshipTypeGroup->id,
'delible' => 0,
]);
$response = $this->json('GET', '/api/relationshiptypes');
$response->assertStatus(200);
$response->assertJsonFragment([
'id' => $relationshipType2->id,
'object' => 'relationshiptype',
'name' => 'son',
'delible' => false,
]);
}
/** @test */
public function it_gets_a_specific_relationship_type_group()
{
$user = $this->signin();
$relationshipTypeGroup = factory(RelationshipTypeGroup::class)->create([
'account_id' => $user->account_id,
]);
$relationshipType = factory(RelationshipType::class)->create([
'account_id' => $user->account_id,
'name' => 'father',
'name_reverse_relationship' => 'son',
'relationship_type_group_id' => $relationshipTypeGroup->id,
'delible' => 0,
]);
$response = $this->json('GET', '/api/relationshiptypes/'.$relationshipType->id);
$response->assertStatus(200);
$response->assertJsonFragment([
'id' => $relationshipType->id,
'object' => 'relationshiptype',
'name' => 'father',
'name_reverse_relationship' => 'son',
'relationship_type_group_id' => $relationshipTypeGroup->id,
'delible' => false,
]);
}
}

View File

@@ -0,0 +1,83 @@
<?php
namespace Tests\Api;
use Tests\ApiTestCase;
use App\Models\Relationship\RelationshipTypeGroup;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class ApiRelationshipTypeGroupControllerTest extends ApiTestCase
{
use DatabaseTransactions;
/** @test */
public function it_gets_the_right_number_of_relationship_type_groups()
{
$user = $this->signin();
factory(RelationshipTypeGroup::class, 10)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('GET', '/api/relationshiptypegroups');
$response->assertStatus(200);
$decodedJson = $response->decodeResponseJson();
$this->assertCount(
10,
$decodedJson['data']
);
}
/** @test */
public function it_gets_the_list_of_relationship_type_groups()
{
$user = $this->signin();
factory(RelationshipTypeGroup::class)->create([
'account_id' => $user->account_id,
'name' => 'love',
'delible' => 0,
]);
$relationshipTypeGroup2 = factory(RelationshipTypeGroup::class)->create([
'account_id' => $user->account_id,
'name' => 'hate',
'delible' => 0,
]);
$response = $this->json('GET', '/api/relationshiptypegroups');
$response->assertStatus(200);
$response->assertJsonFragment([
'id' => $relationshipTypeGroup2->id,
'object' => 'relationshiptypegroup',
'name' => 'hate',
'delible' => false,
]);
}
/** @test */
public function it_gets_a_specific_relationship_type_group()
{
$user = $this->signin();
$relationshipTypeGroup = factory(RelationshipTypeGroup::class)->create([
'account_id' => $user->account_id,
'name' => 'love',
'delible' => 0,
]);
$response = $this->json('GET', '/api/relationshiptypegroups/'.$relationshipTypeGroup->id);
$response->assertStatus(200);
$response->assertJsonFragment([
'id' => $relationshipTypeGroup->id,
'object' => 'relationshiptypegroup',
'name' => 'love',
'delible' => false,
]);
}
}

View File

@@ -0,0 +1,409 @@
<?php
namespace Tests\Api;
use Carbon\Carbon;
use Tests\ApiTestCase;
use App\Models\Account\Account;
use App\Models\Contact\Contact;
use App\Models\Contact\Reminder;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class ApiReminderControllerTest extends ApiTestCase
{
use DatabaseTransactions;
protected $jsonReminder = [
'id',
'object',
'initial_date',
'title',
'description',
'frequency_type',
'frequency_number',
'delible',
'account' => [
'id',
],
'contact' => [
'id',
],
'created_at',
'updated_at',
];
/** @test */
public function it_gets_all_reminders()
{
$user = $this->signin();
$contact1 = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$reminder1 = factory(Reminder::class)->create([
'account_id' => $user->account_id,
'contact_id' => $contact1->id,
]);
$contact2 = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$reminder2 = factory(Reminder::class)->create([
'account_id' => $user->account_id,
'contact_id' => $contact2->id,
'delible' => false,
]);
$response = $this->json('GET', '/api/reminders');
$response->assertStatus(200);
$response->assertJsonStructure([
'data' => ['*' => $this->jsonReminder],
]);
$response->assertJsonFragment([
'object' => 'reminder',
'id' => $reminder1->id,
'delible' => true,
]);
$response->assertJsonFragment([
'object' => 'reminder',
'id' => $reminder2->id,
'delible' => false,
]);
}
/** @test */
public function it_gets_all_the_reminders_of_a_contact()
{
$user = $this->signin();
$contact1 = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$reminder1 = factory(Reminder::class)->create([
'account_id' => $user->account_id,
'contact_id' => $contact1->id,
]);
$contact2 = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$reminder2 = factory(Reminder::class)->create([
'account_id' => $user->account_id,
'contact_id' => $contact2->id,
]);
$response = $this->json('GET', '/api/contacts/'.$contact1->id.'/reminders');
$response->assertStatus(200);
$response->assertJsonStructure([
'data' => ['*' => $this->jsonReminder],
]);
$response->assertJsonFragment([
'object' => 'reminder',
'id' => $reminder1->id,
]);
$response->assertJsonMissingExact([
'object' => 'reminder',
'id' => $reminder2->id,
]);
}
/** @test */
public function it_cant_get_a_reminder_of_a_contact_with_an_invalid_id()
{
$user = $this->signin();
$response = $this->json('GET', '/api/contacts/0/reminders');
$this->expectNotFound($response);
}
/** @test */
public function it_gets_one_reminder()
{
$user = $this->signin();
$contact1 = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$reminder1 = factory(Reminder::class)->create([
'account_id' => $user->account_id,
'contact_id' => $contact1->id,
]);
$reminder2 = factory(Reminder::class)->create([
'account_id' => $user->account_id,
'contact_id' => $contact1->id,
]);
$response = $this->json('GET', '/api/reminders/'.$reminder1->id);
$response->assertStatus(200);
$response->assertJsonStructure([
'data' => $this->jsonReminder,
]);
$response->assertJsonFragment([
'object' => 'reminder',
'id' => $reminder1->id,
]);
$response->assertJsonMissingExact([
'object' => 'reminder',
'id' => $reminder2->id,
]);
}
/** @test */
public function it_cant_get_a_reminder_with_an_invalid_id()
{
$user = $this->signin();
$response = $this->json('GET', '/api/reminders/0');
$this->expectNotFound($response);
}
/** @test */
public function it_creates_a_reminder()
{
Carbon::setTestNow(Carbon::create(2018, 1, 1, 7, 0, 0));
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('POST', '/api/reminders', [
'contact_id' => $contact->id,
'title' => 'the title',
'initial_date' => '2018-05-01',
'frequency_type' => 'one_time',
'frequency_number' => 1,
'description' => 'the description',
]);
$response->assertStatus(201);
$response->assertJsonStructure([
'data' => $this->jsonReminder,
]);
$reminderId = $response->json('data.id');
$response->assertJsonFragment([
'object' => 'reminder',
'id' => $reminderId,
]);
$this->assertGreaterThan(0, $reminderId);
$this->assertDatabaseHas('reminders', [
'account_id' => $user->account_id,
'contact_id' => $contact->id,
'id' => $reminderId,
'title' => 'the title',
'initial_date' => '2018-05-01',
'frequency_type' => 'one_time',
'description' => 'the description',
]);
}
/** @test */
public function create_reminders_gets_an_error_if_fields_are_missing()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('POST', '/api/reminders', [
'contact_id' => $contact->id,
]);
$this->expectDataError($response, [
'The initial date field is required.',
'The frequency type field is required.',
'The frequency number field is required.',
'The title field is required.',
]);
}
/** @test */
public function reminders_create_error_bad_account()
{
Carbon::setTestNow(Carbon::create(2018, 1, 1, 7, 0, 0));
$user = $this->signin();
$account = factory(Account::class)->create();
$contact = factory(Contact::class)->create([
'account_id' => $account->id,
]);
$response = $this->json('POST', '/api/reminders', [
'contact_id' => $contact->id,
'title' => 'the title',
'initial_date' => '2018-05-01',
'frequency_type' => 'one_time',
'frequency_number' => 1,
'description' => 'the description',
]);
$this->expectNotFound($response);
}
/** @test */
public function it_updates_a_reminder()
{
Carbon::setTestNow(Carbon::create(2018, 1, 1, 7, 0, 0));
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$reminder = factory(Reminder::class)->create([
'account_id' => $user->account_id,
'contact_id' => $contact->id,
]);
$response = $this->json('PUT', '/api/reminders/'.$reminder->id, [
'contact_id' => $contact->id,
'title' => 'the title',
'initial_date' => '2018-05-01',
'frequency_type' => 'one_time',
'description' => 'the description',
]);
$response->assertStatus(200);
$response->assertJsonStructure([
'data' => $this->jsonReminder,
]);
$reminder_id = $response->json('data.id');
$this->assertEquals($reminder->id, $reminder_id);
$response->assertJsonFragment([
'object' => 'reminder',
'id' => $reminder_id,
'title' => 'the title',
'initial_date' => '2018-05-01T00:00:00Z',
'frequency_type' => 'one_time',
'description' => 'the description',
]);
$this->assertGreaterThan(0, $reminder_id);
$this->assertDatabaseHas('reminders', [
'account_id' => $user->account_id,
'contact_id' => $contact->id,
'id' => $reminder_id,
'title' => 'the title',
'initial_date' => '2018-05-01 00:00:00',
'frequency_type' => 'one_time',
'description' => 'the description',
]);
}
/** @test */
public function updating_reminder_generates_an_error()
{
$user = $this->signin();
$reminder = factory(Reminder::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('PUT', '/api/reminders/'.$reminder->id, [
'contact_id' => $reminder->contact_id,
]);
$this->expectDataError($response, [
'The initial date field is required.',
'The frequency type field is required.',
'The title field is required.',
]);
}
/** @test */
public function reminders_update_error_bad_account()
{
Carbon::setTestNow(Carbon::create(2018, 1, 1, 7, 0, 0));
$user = $this->signin();
$contact = factory(Contact::class)->create([]);
$reminder = factory(Reminder::class)->create([
'account_id' => $contact->account_id,
'contact_id' => $contact->id,
]);
$response = $this->json('PUT', '/api/reminders/'.$reminder->id, [
'contact_id' => $contact->id,
'title' => 'the title',
'initial_date' => '2018-05-01',
'frequency_type' => 'one_time',
'description' => 'the description',
]);
$this->expectNotFound($response);
}
/** @test */
public function it_deletes_a_reminder()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$reminder = factory(Reminder::class)->create([
'account_id' => $user->account_id,
'contact_id' => $contact->id,
]);
$response = $this->json('DELETE', '/api/reminders/'.$reminder->id);
$response->assertStatus(200);
$this->assertDatabaseMissing('reminders', [
'account_id' => $user->account_id,
'contact_id' => $contact->id,
'id' => $reminder->id,
]);
}
/** @test */
public function reminders_delete_error()
{
$user = $this->signin();
$response = $this->json('DELETE', '/api/reminders/0');
$this->expectDataError($response, [
'The selected reminder id is invalid.',
]);
}
/** @test */
public function it_gets_all_upcoming_reminders()
{
$user = $this->signin();
Carbon::setTestNow(Carbon::create(2017, 1, 1));
// add 2 reminders for the month of March
$reminder1 = factory(Reminder::class)->create([
'account_id' => $user->account_id,
'initial_date' => '2017-03-03 00:00:00',
]);
$reminder1->schedule($user);
$reminder2 = factory(Reminder::class)->create([
'account_id' => $user->account_id,
'initial_date' => '2017-03-03 00:00:00',
'delible' => false,
]);
$reminder2->schedule($user);
$response = $this->json('GET', '/api/reminders/upcoming/2');
$response->assertStatus(200);
$response->assertJsonStructure([
'data' => ['*' => $this->jsonReminder],
]);
$response->assertJsonFragment([
'object' => 'reminder',
'reminder_id' => $reminder1->id,
'delible' => true,
]);
$response->assertJsonFragment([
'object' => 'reminder',
'reminder_id' => $reminder2->id,
'delible' => false,
]);
}
}

View File

@@ -0,0 +1,48 @@
<?php
namespace Tests\Api;
use Tests\ApiTestCase;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class ApiStatisticsControllerTest extends ApiTestCase
{
use DatabaseTransactions;
protected $jsonStructure = [
'instance_creation_date',
'number_of_contacts',
'number_of_users',
'number_of_activities',
'number_of_reminders',
'number_of_new_users_last_week',
];
/** @test */
public function it_gets_the_right_structure_of_the_public_statistics()
{
config(['monica.allow_statistics_through_public_api_access' => true]);
$user = $this->signin();
$response = $this->json('GET', '/api/statistics');
$response->assertStatus(200);
$response->assertJsonStructure([
$this->jsonStructure,
]);
}
/** @test */
public function it_returns_an_error_if_public_statistics_are_not_available()
{
config(['monica.allow_statistics_through_public_api_access' => false]);
$user = $this->signin();
$response = $this->json('GET', '/api/statistics');
$this->expectNotFound($response);
}
}

View File

@@ -0,0 +1,406 @@
<?php
namespace Tests\Api;
use Tests\ApiTestCase;
use App\Models\Contact\Tag;
use App\Models\Contact\Contact;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class ApiTagControllerTest extends ApiTestCase
{
use DatabaseTransactions;
protected $jsonTag = [
'id',
'object',
'name',
'name_slug',
'account' => [
'id',
],
'created_at',
'updated_at',
];
protected $jsonStructureContactWithContactFields = [
'id',
'object',
'hash_id',
'first_name',
'last_name',
'gender',
'gender_type',
'is_starred',
'is_partial',
'is_dead',
'last_called',
'last_activity_together',
'stay_in_touch_frequency',
'stay_in_touch_trigger_date',
'information' => [
'relationships' => [
'love' => [
'total',
'contacts',
],
'family' => [
'total',
'contacts',
],
'friend' => [
'total',
'contacts',
],
'work' => [
'total',
'contacts',
],
],
'dates' => [
'birthdate' => [
'is_age_based',
'is_year_unknown',
'date',
],
'deceased_date' => [
'is_age_based',
'is_year_unknown',
'date',
],
],
'career' => [
'job',
'company',
],
'avatar' => [
'url',
'source',
'default_avatar_color',
],
'food_preferences',
'how_you_met' => [
'general_information',
'first_met_date' => [
'is_age_based',
'is_year_unknown',
'date',
],
'first_met_through_contact',
],
],
'addresses' => [],
'tags' => [],
'statistics' => [
'number_of_calls',
'number_of_notes',
'number_of_activities',
'number_of_reminders',
'number_of_tasks',
'number_of_gifts',
'number_of_debts',
],
'contactFields' => [
'*' => [
'id',
'object',
'content',
'contact_field_type' => [
'id',
'object',
'name',
'fontawesome_icon',
'protocol',
'delible',
'type',
'account' => [
'id',
],
'created_at',
'updated_at',
],
'account' => [
'id',
],
'contact' => [],
'created_at',
'updated_at',
],
],
'notes' => [],
'account' => [
'id',
],
'created_at',
'updated_at',
];
/** @test */
public function it_get_all_tags()
{
$user = $this->signin();
$tag1 = factory(Tag::class)->create([
'account_id' => $user->account_id,
]);
$tag2 = factory(Tag::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('GET', '/api/tags');
$response->assertStatus(200);
$response->assertJsonStructure([
'data' => [
'*' => $this->jsonTag,
],
]);
$response->assertJsonFragment([
'object' => 'tag',
'id' => $tag1->id,
]);
$response->assertJsonFragment([
'object' => 'tag',
'id' => $tag2->id,
]);
}
/** @test */
public function it_gets_a_specific_tag()
{
$user = $this->signin();
$tag = factory(Tag::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('GET', '/api/tags/'.$tag->id);
$response->assertStatus(200);
$response->assertJsonStructure([
'data' => $this->jsonTag,
]);
$response->assertJsonFragment([
'object' => 'tag',
'id' => $tag->id,
]);
}
/** @test */
public function it_triggers_error_if_tag_unknown()
{
$user = $this->signin();
$response = $this->json('GET', '/api/tags/0');
$this->expectNotFound($response);
}
/** @test */
public function it_creates_a_tag()
{
$user = $this->signin();
$response = $this->json('POST', '/api/tags', [
'name' => 'the tag',
]);
$response->assertStatus(201);
$response->assertJsonStructure([
'data' => $this->jsonTag,
]);
$tag_id = $response->json('data.id');
$response->assertJsonFragment([
'object' => 'tag',
'id' => $tag_id,
'name' => 'the tag',
]);
$this->assertGreaterThan(0, $tag_id);
$this->assertDatabaseHas('tags', [
'account_id' => $user->account_id,
'id' => $tag_id,
'name' => 'the tag',
]);
}
/** @test */
public function it_updates_a_tag()
{
$user = $this->signin();
$tag = factory(Tag::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('PUT', '/api/tags/'.$tag->id, [
'name' => 'the tag',
]);
$response->assertStatus(200);
$response->assertJsonStructure([
'data' => $this->jsonTag,
]);
$tag_id = $response->json('data.id');
$this->assertEquals($tag->id, $tag_id);
$response->assertJsonFragment([
'object' => 'tag',
'id' => $tag_id,
'name' => 'the tag',
]);
$this->assertGreaterThan(0, $tag_id);
$this->assertDatabaseHas('tags', [
'account_id' => $user->account_id,
'id' => $tag_id,
'name' => 'the tag',
]);
}
/** @test */
public function it_deletes_a_tag()
{
$user = $this->signin();
$tag = factory(Tag::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('DELETE', '/api/tags/'.$tag->id);
$response->assertStatus(200);
$this->assertDatabaseMissing('contact_tag', [
'account_id' => $user->account_id,
'tag_id' => $tag->id,
]);
$this->assertDatabaseMissing('tags', [
'account_id' => $user->account_id,
'id' => $tag->id,
]);
}
/** @test */
public function it_deletes_a_tag_associated()
{
$user = $this->signin();
$tag = factory(Tag::class)->create([
'account_id' => $user->account_id,
]);
$contact1 = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$contact2 = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('POST', "/api/contacts/{$contact1->id}/setTags", ['tags' => [$tag->name]]);
$response = $this->json('POST', "/api/contacts/{$contact2->id}/setTags", ['tags' => [$tag->name]]);
$this->assertDatabaseHas('contact_tag', [
'account_id' => $user->account_id,
'contact_id' => $contact1->id,
'tag_id' => $tag->id,
]);
$this->assertDatabaseHas('contact_tag', [
'account_id' => $user->account_id,
'contact_id' => $contact2->id,
'tag_id' => $tag->id,
]);
$response = $this->json('DELETE', '/api/tags/'.$tag->id);
$response->assertStatus(200);
$this->assertDatabaseMissing('contact_tag', [
'account_id' => $user->account_id,
'contact_id' => $contact1->id,
'tag_id' => $tag->id,
]);
$this->assertDatabaseMissing('contact_tag', [
'account_id' => $user->account_id,
'contact_id' => $contact2->id,
'tag_id' => $tag->id,
]);
$this->assertDatabaseMissing('tags', [
'account_id' => $user->account_id,
'id' => $tag->id,
]);
}
/** @test */
public function it_gets_all_the_contacts_for_a_given_tag()
{
$user = $this->signin();
$tag = factory(Tag::class)->create([
'account_id' => $user->account_id,
]);
factory(Contact::class, 10)->create([
'account_id' => $user->account_id,
]);
for ($i = 0; $i < 3; $i++) {
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$contact->tags()->sync([
$tag->id => [
'account_id' => $user->account_id,
],
]);
}
$response = $this->json('GET', '/api/tags/'.$tag->id.'/contacts');
$response->assertStatus(200);
$response->assertJsonStructure([
'data' => ['*' => $this->jsonStructureContactWithContactFields],
]);
$this->assertCount(
3,
$response->decodeResponseJson()['data']
);
}
/** @test */
public function it_gets_all_the_contacts_for_a_given_tag_and_applies_pagination()
{
$user = $this->signin();
$tag = factory(Tag::class)->create([
'account_id' => $user->account_id,
]);
factory(Contact::class, 10)->create([
'account_id' => $user->account_id,
]);
for ($i = 0; $i < 3; $i++) {
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$contact->tags()->sync([
$tag->id => [
'account_id' => $user->account_id,
],
]);
}
$response = $this->json('GET', '/api/tags/'.$tag->id.'/contacts?limit=1');
$response->assertStatus(200);
$response->assertJsonStructure([
'data' => ['*' => $this->jsonStructureContactWithContactFields],
]);
$response->assertJsonFragment([
'total' => 3,
'current_page' => 1,
'per_page' => 1,
'last_page' => 3,
]);
}
}

View File

@@ -0,0 +1,369 @@
<?php
namespace Tests\Api;
use Tests\ApiTestCase;
use App\Models\Contact\Task;
use App\Models\Account\Account;
use App\Models\Contact\Contact;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class ApiTaskControllerTest extends ApiTestCase
{
use DatabaseTransactions;
protected $jsonTask = [
'id',
'object',
'title',
'description',
'completed',
'completed_at',
'account' => [
'id',
],
'contact' => [
'id',
],
'created_at',
'updated_at',
];
/** @test */
public function it_gets_all_the_tasks()
{
$user = $this->signin();
$contact1 = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$task1 = factory(Task::class)->create([
'account_id' => $user->account_id,
'contact_id' => $contact1->id,
]);
$contact2 = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$task2 = factory(Task::class)->create([
'account_id' => $user->account_id,
'contact_id' => $contact2->id,
]);
$response = $this->json('GET', '/api/tasks');
$response->assertStatus(200);
$response->assertJsonStructure([
'data' => ['*' => $this->jsonTask],
]);
$response->assertJsonFragment([
'object' => 'task',
'id' => $task1->id,
]);
$response->assertJsonFragment([
'object' => 'task',
'id' => $task2->id,
]);
}
/** @test */
public function it_gets_all_the_tasks_of_a_contact()
{
$user = $this->signin();
$contact1 = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$task1 = factory(Task::class)->create([
'account_id' => $user->account_id,
'contact_id' => $contact1->id,
]);
$contact2 = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$task2 = factory(Task::class)->create([
'account_id' => $user->account_id,
'contact_id' => $contact2->id,
]);
$response = $this->json('GET', '/api/contacts/'.$contact1->id.'/tasks');
$response->assertStatus(200);
$response->assertJsonStructure([
'data' => ['*' => $this->jsonTask],
]);
$response->assertJsonFragment([
'object' => 'task',
'id' => $task1->id,
]);
$response->assertJsonMissingExact([
'object' => 'task',
'id' => $task2->id,
]);
}
/** @test */
public function it_cant_get_the_tasks_of_a_contact_with_an_invalid_id()
{
$user = $this->signin();
$response = $this->json('GET', '/api/contacts/0/tasks');
$this->expectNotFound($response);
}
/** @test */
public function it_gets_a_specific_task()
{
$user = $this->signin();
$contact1 = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$task1 = factory(Task::class)->create([
'account_id' => $user->account_id,
'contact_id' => $contact1->id,
]);
$task2 = factory(Task::class)->create([
'account_id' => $user->account_id,
'contact_id' => $contact1->id,
]);
$response = $this->json('GET', '/api/tasks/'.$task1->id);
$response->assertStatus(200);
$response->assertJsonStructure([
'data' => $this->jsonTask,
]);
$response->assertJsonFragment([
'object' => 'task',
'id' => $task1->id,
]);
$response->assertJsonMissingExact([
'object' => 'task',
'id' => $task2->id,
]);
}
/** @test */
public function it_cant_get_a_task_with_an_invalid_id()
{
$user = $this->signin();
$response = $this->json('GET', '/api/tasks/0');
$this->expectNotFound($response);
}
/** @test */
public function it_create_a_task_associated_to_a_contact()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('POST', '/api/tasks', [
'contact_id' => $contact->id,
'title' => 'the task',
'description' => 'description',
'completed' => false,
]);
$response->assertStatus(200);
$response->assertJsonStructure([
'data' => $this->jsonTask,
]);
$taskId = $response->json('data.id');
$response->assertJsonFragment([
'object' => 'task',
'id' => $taskId,
]);
$this->assertGreaterThan(0, $taskId);
$this->assertDatabaseHas('tasks', [
'account_id' => $user->account_id,
'contact_id' => $contact->id,
'id' => $taskId,
'title' => 'the task',
'completed' => false,
]);
}
/** @test */
public function it_create_a_task_not_associated_to_a_contact()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('POST', '/api/tasks', [
'contact_id' => $contact->id,
'title' => 'the task',
'description' => 'description',
'completed' => false,
]);
$response->assertStatus(200);
$response->assertJsonStructure([
'data' => $this->jsonTask,
]);
$taskId = $response->json('data.id');
$response->assertJsonFragment([
'object' => 'task',
'id' => $taskId,
]);
$this->assertGreaterThan(0, $taskId);
$this->assertDatabaseHas('tasks', [
'account_id' => $user->account_id,
'contact_id' => $contact->id,
'id' => $taskId,
'title' => 'the task',
'completed' => false,
]);
}
/** @test */
public function creating_a_task_triggers_invalid_parameter_error()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('POST', '/api/tasks', [
'contact_id' => $contact->id,
]);
$this->expectDataError($response, [
'The title field is required.',
]);
}
/** @test */
public function creating_a_task_with_a_wrong_account_id_triggers_an_error()
{
$user = $this->signin();
$account = factory(Account::class)->create();
$contact = factory(Contact::class)->create([
'account_id' => $account->id,
]);
$response = $this->json('POST', '/api/tasks', [
'contact_id' => $contact->id,
'title' => 'the task',
'completed' => false,
]);
$this->expectNotFound($response);
}
/** @test */
public function it_updates_a_task()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$task = factory(Task::class)->create([
'account_id' => $user->account_id,
'contact_id' => $contact->id,
]);
$response = $this->json('PUT', '/api/tasks/'.$task->id, [
'contact_id' => $contact->id,
'title' => 'the task',
'completed' => false,
]);
$response->assertStatus(200);
$response->assertJsonStructure([
'data' => $this->jsonTask,
]);
$taskId = $response->json('data.id');
$this->assertEquals($task->id, $taskId);
$response->assertJsonFragment([
'object' => 'task',
'id' => $taskId,
]);
$this->assertGreaterThan(0, $taskId);
$this->assertDatabaseHas('tasks', [
'account_id' => $user->account_id,
'contact_id' => $contact->id,
'id' => $taskId,
'title' => 'the task',
'completed' => false,
]);
}
/** @test */
public function updating_a_task_with_missing_parameters_triggers_an_error()
{
$user = $this->signin();
$task = factory(Task::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('PUT', '/api/tasks/'.$task->id, [
'contact_id' => $task->contact_id,
]);
$this->expectDataError($response, [
'The title field is required.',
'The completed field is required.',
]);
}
/** @test */
public function updating_a_task_with_wrong_account_triggers_an_error()
{
$user = $this->signin();
$account = factory(Account::class)->create();
$contact = factory(Contact::class)->create([
'account_id' => $account->id,
]);
$task = factory(Task::class)->create([]);
$response = $this->json('PUT', '/api/tasks/'.$task->id, [
'contact_id' => $contact->id,
'title' => 'the task',
'completed' => false,
]);
$this->expectNotFound($response);
}
/** @test */
public function it_deletes_a_task()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$task = factory(Task::class)->create([
'account_id' => $user->account_id,
'contact_id' => $contact->id,
]);
$response = $this->json('DELETE', '/api/tasks/'.$task->id);
$response->assertStatus(200);
$this->assertDatabaseMissing('tasks', [
'account_id' => $user->account_id,
'contact_id' => $contact->id,
'id' => $task->id,
]);
}
/** @test */
public function it_cant_delete_a_task_if_wrong_task_id()
{
$user = $this->signin();
$response = $this->json('DELETE', '/api/tasks/0');
$this->expectNotFound($response);
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace Tests\Api\Authentication;
use Tests\ApiTestCase;
class ApiAuthenticateTest extends ApiTestCase
{
/** @test */
public function guest_is_rejected()
{
$response = $this->json('GET', '/api/contacts');
$response->assertStatus(401);
$response->assertJsonFragment([
'message' => 'Unauthenticated.',
]);
}
}

View File

@@ -0,0 +1,340 @@
<?php
namespace Tests\Api\Contact;
use Tests\ApiTestCase;
use App\Models\Account\Account;
use App\Models\Contact\Address;
use App\Models\Contact\Contact;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class ApiAdressesControllerTest extends ApiTestCase
{
use DatabaseTransactions;
protected $jsonAddress = [
'id',
'object',
'name',
'street',
'city',
'province',
'postal_code',
'latitude',
'longitude',
'country',
'account' => [
'id',
],
'contact' => [
'id',
],
'created_at',
'updated_at',
];
/** @test */
public function it_gets_a_list_of_addresses()
{
$user = $this->signin();
$contact = factory(Contact::class)->create(['account_id' => $user->account_id]);
$address = factory(Address::class)->create([
'account_id' => $user->account_id,
'contact_id' => $contact->id,
]);
$response = $this->json('GET', '/api/addresses');
$response->assertStatus(200);
$response->assertJsonStructure([
'data' => ['*' => $this->jsonAddress],
]);
$response->assertJsonFragment([
'object' => 'address',
'id' => $address->id,
]);
$response->assertJsonFragment([
'total' => 1,
'current_page' => 1,
]);
}
/** @test */
public function it_applies_the_limit_parameter_in_search()
{
$user = $this->signin();
$contact = factory(Contact::class)->create(['account_id' => $user->account_id]);
factory(Address::class, 20)->create([
'account_id' => $user->account_id,
'contact_id' => $contact->id,
]);
$response = $this->json('GET', '/api/addresses?limit=1');
$response->assertStatus(200);
$response->assertJsonFragment([
'total' => 20,
'current_page' => 1,
'per_page' => 1,
'last_page' => 20,
]);
$response = $this->json('GET', '/api/addresses?limit=2');
$response->assertStatus(200);
$response->assertJsonFragment([
'total' => 20,
'current_page' => 1,
'per_page' => 2,
'last_page' => 10,
]);
}
/** @test */
public function it_gets_addresses_for_a_specific_contact()
{
$user = $this->signin();
$contact = factory(Contact::class)->create(['account_id' => $user->account_id]);
$address = factory(Address::class)->create([
'account_id' => $user->account_id,
'contact_id' => $contact->id,
]);
$response = $this->json('GET', '/api/contacts/'.$contact->id.'/addresses');
$response->assertStatus(200);
$response->assertJsonFragment([
'object' => 'address',
'id' => $address->id,
'name' => $address->name,
]);
}
/** @test */
public function calling_addresses_gets_an_error_if_contact_doesnt_exist()
{
$user = $this->signin();
$response = $this->json('GET', '/api/contacts/0/addresses');
$this->expectNotFound($response);
}
/** @test */
public function it_gets_a_specific_address()
{
$user = $this->signin();
$contact = factory(Contact::class)->create(['account_id' => $user->account_id]);
$address = factory(Address::class)->create([
'account_id' => $user->account_id,
'contact_id' => $contact->id,
]);
$response = $this->json('GET', '/api/addresses/'.$address->id);
$response->assertStatus(200);
$response->assertJsonStructure([
'data' => $this->jsonAddress,
]);
$response->assertJsonFragment([
'object' => 'address',
'id' => $address->id,
'name' => $address->name,
'street' => $address->place->street,
]);
}
/** @test */
public function it_creates_an_address()
{
$user = $this->signin();
$contact = factory(Contact::class)->create(['account_id' => $user->account_id]);
$response = $this->json('POST', '/api/addresses', [
'contact_id' => $contact->id,
'name' => 'address name',
'street' => 'street',
'postal_code' => '12345',
'country' => 'FR',
]);
$response->assertStatus(201);
$this->assertDatabaseHas('addresses', [
'account_id' => $user->account_id,
'contact_id' => $contact->id,
'name' => 'address name',
]);
$response->assertJsonFragment([
'object' => 'address',
'name' => 'address name',
'country' => [
'object' => 'country',
'id' => 'FR',
'name' => 'France',
'iso' => 'FR',
],
'street' => 'street',
'postal_code' => '12345',
]);
$addressId = $response->json('data.id');
$this->assertGreaterThan(0, $addressId);
}
/** @test */
public function create_addresses_gets_an_error_if_fields_are_missing()
{
$user = $this->signin();
$contact = factory(Contact::class)->create(['account_id' => $user->account_id]);
$response = $this->json('POST', '/api/addresses', [
]);
$this->expectDataError($response, [
'The contact id field is required.',
]);
}
/** @test */
public function create_addresses_gets_an_error_if_contact_is_not_linked_to_user()
{
$user = $this->signin();
$account = factory(Account::class)->create();
$contact = factory(Contact::class)->create([
'account_id' => $account->id,
]);
$response = $this->json('POST', '/api/addresses', [
'contact_id' => $contact->id,
'name' => 'address name',
'street' => 'street',
'postal_code' => '12345',
'country' => 'FR',
]);
$this->expectNotFound($response);
}
/** @test */
public function it_updates_an_address()
{
$user = $this->signin();
$contact = factory(Contact::class)->create(['account_id' => $user->account_id]);
$address = factory(Address::class)->create([
'account_id' => $user->account_id,
'contact_id' => $contact->id,
'name' => 'address name',
]);
$response = $this->json('PUT', '/api/addresses/'.$address->id, [
'contact_id' => $contact->id,
'name' => 'address name up',
'country' => 'US',
]);
$response->assertStatus(200);
$response->assertJsonFragment([
'object' => 'address',
'id' => $address->id,
'name' => 'address name up',
'country' => [
'object' => 'country',
'id' => 'US',
'name' => 'United States',
'iso' => 'US',
],
'postal_code' => $address->place->postal_code,
]);
$this->assertDatabaseHas('addresses', [
'account_id' => $user->account_id,
'contact_id' => $contact->id,
'place_id' => $address->place->id,
'id' => $address->id,
'name' => 'address name up',
]);
}
/** @test */
public function updating_address_generates_an_error()
{
$user = $this->signin();
$address = factory(Address::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('PUT', '/api/addresses/'.$address->id, []);
$this->expectDataError($response, [
'The contact id field is required.',
]);
}
/** @test */
public function it_cant_update_an_address_if_account_is_not_linked_to_address()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([]);
$address = factory(Address::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('PUT', '/api/addresses/'.$address->id, [
'contact_id' => $contact->id,
]);
$this->expectNotFound($response);
}
/** @test */
public function it_deletes_an_address()
{
$user = $this->signin();
$contact = factory(Contact::class)->create(['account_id' => $user->account_id]);
$address = factory(Address::class)->create([
'account_id' => $user->account_id,
'contact_id' => $contact->id,
]);
$response = $this->json('DELETE', '/api/addresses/'.$address->id);
$response->assertStatus(200);
$response->assertJsonFragment([
'id' => $address->id,
'deleted' => true,
]);
$this->assertDatabaseMissing('addresses', [
'account_id' => $user->account_id,
'contact_id' => $contact->id,
'id' => $address->id,
]);
}
/** @test */
public function address_delete_error()
{
$user = $this->signin();
$response = $this->json('DELETE', '/api/addresses/0');
$this->expectDataError($response, [
'The selected address id is invalid.',
]);
}
}

View File

@@ -0,0 +1,59 @@
<?php
namespace Tests\Api\Contact;
use Tests\ApiTestCase;
use App\Models\Contact\Contact;
use App\Models\Instance\AuditLog;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class ApiAuditLogControllerTest extends ApiTestCase
{
use DatabaseTransactions;
protected $jsonStructureAuditLog = [
'id',
'object',
'author' => [
'name',
],
'action',
'objects',
'audited_at',
'created_at',
'updated_at',
];
/** @test */
public function it_gets_a_list_of_audit_logs()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
'first_name' => 'roger',
]);
factory(AuditLog::class, 10)->create([
'account_id' => $user->account_id,
'about_contact_id' => $contact->id,
]);
$response = $this->json('GET', '/api/contacts/'.$contact->id.'/logs');
$response->assertStatus(200);
$response->assertJsonStructure([
'data' => ['*' => $this->jsonStructureAuditLog],
]);
$this->assertCount(
10,
$response->decodeResponseJson()['data']
);
$response->assertJsonFragment([
'total' => 10,
'current_page' => 1,
]);
}
}

View File

@@ -0,0 +1,180 @@
<?php
namespace Tests\Api\Contact;
use Tests\ApiTestCase;
use App\Models\Contact\Contact;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Storage;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class ApiAvatarControllerTest extends ApiTestCase
{
use DatabaseTransactions;
protected $jsonDatas = [
'id',
'object',
'account' => [
'id',
],
'information' => [
'avatar' => [
'url',
'source',
'default_avatar_color',
],
],
'created_at',
'updated_at',
];
/** @test */
public function it_updates_the_photo_avatar()
{
Storage::fake();
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('POST', '/api/photos', [
'contact_id' => $contact->id,
'photo' => UploadedFile::fake()->image('test.jpg'),
]);
$response->assertStatus(201);
$this->assertDatabaseHas('photos', [
'account_id' => $user->account_id,
'original_filename' => 'test.jpg',
]);
$photo = $contact->photos->first();
Storage::disk('public')->assertExists($photo->new_filename);
$response = $this->json('PUT', '/api/contacts/'.$contact->id.'/avatar', [
'photo' => UploadedFile::fake()->image('test.jpg'),
'source' => 'photo',
'photo_id' => $photo->id,
]);
$response->assertStatus(200);
$response->assertJsonStructure([
'*' => $this->jsonDatas,
]);
$this->assertDatabaseHas('contacts', [
'id' => $contact->id,
'avatar_source' => 'photo',
'avatar_photo_id' => $photo->id,
]);
}
/** @test */
public function it_updates_the_gravatar_avatar()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
'avatar_gravatar_url' => 'a gravatar url',
]);
$response = $this->json('PUT', '/api/contacts/'.$contact->id.'/avatar', [
'source' => 'gravatar',
]);
$response->assertStatus(200);
$response->assertJsonStructure([
'*' => $this->jsonDatas,
]);
$this->assertDatabaseHas('contacts', [
'id' => $contact->id,
'avatar_source' => 'gravatar',
]);
}
/** @test */
public function it_updates_the_adorable_avatar()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('PUT', '/api/contacts/'.$contact->id.'/avatar', [
'source' => 'adorable',
]);
$response->assertStatus(200);
$response->assertJsonStructure([
'*' => $this->jsonDatas,
]);
$this->assertDatabaseHas('contacts', [
'id' => $contact->id,
'avatar_source' => 'adorable',
]);
}
/** @test */
public function it_updates_the_default_avatar()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('PUT', '/api/contacts/'.$contact->id.'/avatar', [
'source' => 'default',
]);
$response->assertStatus(200);
$response->assertJsonStructure([
'*' => $this->jsonDatas,
]);
$this->assertDatabaseHas('contacts', [
'id' => $contact->id,
'avatar_source' => 'default',
]);
}
/** @test */
public function avatar_update_gets_an_error_if_fields_are_missing()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('PUT', '/api/contacts/'.$contact->id.'/avatar', [
'source' => 'blabla',
]);
$this->expectDataError($response, [
'The selected source is invalid.',
]);
}
/** @test */
public function avatar_update_gets_an_error_if_contact_is_not_linked_to_user()
{
$user = $this->signin();
$contact = factory(Contact::class)->create();
$response = $this->json('PUT', '/api/contacts/'.$contact->id.'/avatar', [
'source' => 'default',
]);
$this->expectNotFound($response);
}
}

View File

@@ -0,0 +1,352 @@
<?php
namespace Tests\Api\Contact;
use Tests\ApiTestCase;
use App\Models\Contact\Call;
use App\Models\Account\Account;
use App\Models\Contact\Contact;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class ApiCallControllerTest extends ApiTestCase
{
use DatabaseTransactions;
protected $jsonCall = [
'id',
'object',
'called_at',
'content',
'account' => [
'id',
],
'contact' => [
'id',
],
'created_at',
'updated_at',
];
/** @test */
public function it_gets_a_list_of_calls()
{
$user = $this->signin();
$contact1 = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$call1 = factory(Call::class)->create([
'account_id' => $user->account_id,
'contact_id' => $contact1->id,
]);
$contact2 = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$call2 = factory(Call::class)->create([
'account_id' => $user->account_id,
'contact_id' => $contact2->id,
]);
$response = $this->json('GET', '/api/calls');
$response->assertStatus(200);
$response->assertJsonStructure([
'data' => ['*' => $this->jsonCall],
]);
$response->assertJsonFragment([
'object' => 'call',
'id' => $call1->id,
]);
$response->assertJsonFragment([
'object' => 'call',
'id' => $call2->id,
]);
}
/** @test */
public function it_gets_the_calls_of_a_contact()
{
$user = $this->signin();
$contact1 = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$call1 = factory(Call::class)->create([
'account_id' => $user->account_id,
'contact_id' => $contact1->id,
]);
$contact2 = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$call2 = factory(Call::class)->create([
'account_id' => $user->account_id,
'contact_id' => $contact2->id,
]);
$response = $this->json('GET', '/api/contacts/'.$contact1->id.'/calls');
$response->assertStatus(200);
$response->assertJsonStructure([
'data' => ['*' => $this->jsonCall],
]);
$response->assertJsonFragment([
'object' => 'call',
'id' => $call1->id,
]);
$response->assertJsonMissingExact([
'object' => 'call',
'id' => $call2->id,
]);
}
/** @test */
public function calling_calls_get_error()
{
$user = $this->signin();
$response = $this->json('GET', '/api/contacts/0/calls');
$this->expectNotFound($response);
}
/** @test */
public function it_gets_one_call()
{
$user = $this->signin();
$contact1 = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$call1 = factory(Call::class)->create([
'account_id' => $user->account_id,
'contact_id' => $contact1->id,
]);
$call2 = factory(Call::class)->create([
'account_id' => $user->account_id,
'contact_id' => $contact1->id,
]);
$response = $this->json('GET', '/api/calls/'.$call1->id);
$response->assertStatus(200);
$response->assertJsonStructure([
'data' => $this->jsonCall,
]);
$response->assertJsonFragment([
'object' => 'call',
'id' => $call1->id,
]);
$response->assertJsonMissingExact([
'object' => 'call',
'id' => $call2->id,
]);
}
/** @test */
public function calling_one_call_gets_an_error()
{
$user = $this->signin();
$response = $this->json('GET', '/api/calls/0');
$this->expectNotFound($response);
}
/** @test */
public function it_creates_a_call()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('POST', '/api/calls', [
'contact_id' => $contact->id,
'content' => 'the call',
'called_at' => '2018-05-01',
]);
$response->assertStatus(201);
$response->assertJsonStructure([
'data' => $this->jsonCall,
]);
$callId = $response->json('data.id');
$response->assertJsonFragment([
'object' => 'call',
'id' => $callId,
]);
$this->assertGreaterThan(0, $callId);
$this->assertDatabaseHas('calls', [
'account_id' => $user->account_id,
'contact_id' => $contact->id,
'id' => $callId,
'content' => 'the call',
'called_at' => '2018-05-01',
]);
}
/** @test */
public function create_calls_gets_an_error_if_fields_are_missing()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('POST', '/api/calls', [
'contact_id' => $contact->id,
]);
$this->expectDataError($response, [
'The called at field is required.',
]);
}
/** @test */
public function it_cant_create_a_call_if_account_is_wrong()
{
$user = $this->signin();
$account = factory(Account::class)->create();
$contact = factory(Contact::class)->create([
'account_id' => $account->id,
]);
$response = $this->json('POST', '/api/calls', [
'contact_id' => $contact->id,
'content' => 'the call',
'called_at' => '2018-05-01',
]);
$this->expectNotFound($response);
}
/** @test */
public function it_updates_a_call()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$call = factory(Call::class)->create([
'account_id' => $user->account_id,
'contact_id' => $contact->id,
]);
$response = $this->json('PUT', '/api/calls/'.$call->id, [
'contact_id' => $contact->id,
'content' => 'the call',
'called_at' => '2018-05-01',
]);
$response->assertStatus(200);
$response->assertJsonStructure([
'data' => $this->jsonCall,
]);
$callId = $response->json('data.id');
$this->assertEquals($call->id, $callId);
$response->assertJsonFragment([
'object' => 'call',
'id' => $callId,
]);
$this->assertGreaterThan(0, $callId);
$this->assertDatabaseHas('calls', [
'account_id' => $user->account_id,
'contact_id' => $contact->id,
'id' => $callId,
'content' => 'the call',
'called_at' => '2018-05-01',
]);
}
/** @test */
public function updating_call_generates_an_error()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$call = factory(Call::class)->create([
'account_id' => $user->account_id,
'contact_id' => $contact->id,
]);
$response = $this->json('PUT', '/api/calls/'.$call->id, [
'contact_id' => $call->contact_id,
]);
$this->expectDataError($response, [
'The called at field is required.',
]);
}
/** @test */
public function it_cant_update_a_call_if_account_is_not_linked_to_call()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([]);
$call = factory(Call::class)->create([
'account_id' => $contact->account_id,
'contact_id' => $contact->id,
]);
$response = $this->json('PUT', '/api/calls/'.$call->id, [
'content' => 'the call',
'called_at' => '2018-05-01',
]);
$this->expectNotFound($response);
}
/** @test */
public function it_deletes_a_call()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$call = factory(Call::class)->create([
'account_id' => $user->account_id,
'contact_id' => $contact->id,
]);
$this->assertDatabaseHas('calls', [
'account_id' => $user->account_id,
'contact_id' => $contact->id,
'id' => $call->id,
]);
$response = $this->json('DELETE', '/api/calls/'.$call->id);
$response->assertStatus(200);
$this->assertDatabaseMissing('calls', [
'account_id' => $user->account_id,
'contact_id' => $contact->id,
'id' => $call->id,
]);
}
/** @test */
public function it_cant_delete_a_call_if_call_doesnt_exist()
{
$user = $this->signin();
$response = $this->json('DELETE', '/api/calls/0');
$this->expectNotFound($response);
}
/** @test */
public function it_cant_delete_a_call_if_account_is_not_linked()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([]);
$call = factory(Call::class)->create([
'account_id' => $contact->account_id,
'contact_id' => $contact->id,
]);
$response = $this->json('DELETE', '/api/calls/'.$call->id);
$this->expectNotFound($response);
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,289 @@
<?php
namespace Tests\Api\Contact;
use Tests\ApiTestCase;
use App\Models\Contact\Tag;
use App\Models\Contact\Contact;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class ApiContactTagControllerTest extends ApiTestCase
{
use DatabaseTransactions;
/** @test */
public function tags_are_required_to_associate_tags_to_a_contact()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('POST', "/api/contacts/{$contact->id}/setTags");
$this->expectDataError($response, ['The tags field is required.']);
}
/** @test */
public function it_associates_tags_to_a_contact()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('POST', "/api/contacts/{$contact->id}/setTags", [
'tags' => ['very-specific-tag-name', 'very-specific-tag-name-2'],
]);
$response->assertStatus(200);
$tagId1 = $response->json('data.tags.0.id');
$tagId2 = $response->json('data.tags.1.id');
$response->assertJsonFragment([
'object' => 'tag',
'id' => $tagId1,
'name' => 'very-specific-tag-name',
]);
$response->assertJsonFragment([
'object' => 'tag',
'id' => $tagId2,
'name' => 'very-specific-tag-name-2',
]);
$this->assertDatabaseHas('contact_tag', [
'account_id' => $user->account_id,
'contact_id' => $contact->id,
'tag_id' => $tagId1,
]);
$this->assertDatabaseHas('contact_tag', [
'account_id' => $user->account_id,
'contact_id' => $contact->id,
'tag_id' => $tagId2,
]);
}
/** @test */
public function tags_ignore_empty_tags()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('POST', "/api/contacts/{$contact->id}/setTags", [
'tags' => [
'very-specific-tag-name',
null,
'very-specific-tag-name-2',
],
]);
$response->assertStatus(200);
$tagId1 = $response->json('data.tags.0.id');
$tagId2 = $response->json('data.tags.1.id');
$response->assertJsonFragment([
'object' => 'tag',
'id' => $tagId1,
'name' => 'very-specific-tag-name',
]);
$response->assertJsonFragment([
'object' => 'tag',
'id' => $tagId2,
'name' => 'very-specific-tag-name-2',
]);
$this->assertDatabaseHas('contact_tag', [
'account_id' => $user->account_id,
'contact_id' => $contact->id,
'tag_id' => $tagId1,
]);
$this->assertDatabaseHas('contact_tag', [
'account_id' => $user->account_id,
'contact_id' => $contact->id,
'tag_id' => $tagId2,
]);
}
/** @test */
public function a_list_of_tags_are_required_to_remove_a_tag_from_a_contact()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('POST', "/api/contacts/{$contact->id}/unsetTag");
$this->expectDataError($response, ['The tags field is required.']);
}
/** @test */
public function it_removes_one_tag_from_a_contact()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$tag = factory(Tag::class)->create([
'account_id' => $user->account_id,
'name' => 'friend',
]);
$tag2 = factory(Tag::class)->create([
'account_id' => $user->account_id,
'name' => 'family',
]);
$contact->tags()->syncWithoutDetaching([
$tag->id => [
'account_id' => $contact->account_id,
],
$tag2->id => [
'account_id' => $contact->account_id,
],
]);
$response = $this->json('POST', "/api/contacts/{$contact->id}/unsetTag", [
'tags' => [$tag->id],
]);
$response->assertStatus(200);
$response->assertJsonFragment([
'id' => $contact->id,
'name' => $tag2->name,
]);
$response->assertJsonMissing([
'name' => $tag->name,
]);
$this->assertDatabaseHas('contact_tag', [
'contact_id' => $contact->id,
'tag_id' => $tag2->id,
'account_id' => $user->account_id,
]);
$this->assertDatabaseMissing('contact_tag', [
'contact_id' => $contact->id,
'tag_id' => $tag->id,
'account_id' => $user->account_id,
]);
}
/** @test */
public function it_removes_multiple_tags_from_a_contact()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$tag = factory(Tag::class)->create([
'account_id' => $user->account_id,
'name' => 'friend',
]);
$tag2 = factory(Tag::class)->create([
'account_id' => $user->account_id,
'name' => 'family',
]);
$tag3 = factory(Tag::class)->create([
'account_id' => $user->account_id,
'name' => 'work',
]);
$contact->tags()->syncWithoutDetaching([
$tag->id => [
'account_id' => $contact->account_id,
],
$tag2->id => [
'account_id' => $contact->account_id,
],
$tag3->id => [
'account_id' => $contact->account_id,
],
]);
$response = $this->json('POST', "/api/contacts/{$contact->id}/unsetTag", [
'tags' => [$tag->id, $tag2->id],
]);
$response->assertStatus(200);
$response->assertJsonFragment([
'id' => $contact->id,
'name' => $tag3->name,
]);
$response->assertJsonMissing([
'name' => $tag2->name,
]);
$this->assertDatabaseMissing('contact_tag', [
'contact_id' => $contact->id,
'account_id' => $user->account_id,
'tag_id' => $tag->id,
]);
$this->assertDatabaseMissing('contact_tag', [
'contact_id' => $contact->id,
'account_id' => $user->account_id,
'tag_id' => $tag2->id,
]);
$this->assertDatabaseHas('contact_tag', [
'contact_id' => $contact->id,
'account_id' => $user->account_id,
'tag_id' => $tag3->id,
]);
}
/** @test */
public function it_removes_all_tags_from_a_contact()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$tag = factory(Tag::class)->create([
'account_id' => $user->account_id,
'name' => 'friend',
]);
$tag2 = factory(Tag::class)->create([
'account_id' => $user->account_id,
'name' => 'family',
]);
$contact->tags()->syncWithoutDetaching([
$tag->id => [
'account_id' => $contact->account_id,
],
$tag2->id => [
'account_id' => $contact->account_id,
],
]);
$response = $this->json('POST', "/api/contacts/{$contact->id}/unsetTags");
$response->assertStatus(200);
$response->assertJsonMissing([
'name' => $tag2->name,
]);
$this->assertDatabaseMissing('contact_tag', [
'contact_id' => $contact->id,
'account_id' => $user->account_id,
]);
}
}

View File

@@ -0,0 +1,208 @@
<?php
namespace Tests\Api\Contact;
use Tests\ApiTestCase;
use App\Models\User\User;
use App\Models\Contact\Contact;
use App\Models\Contact\Conversation;
use App\Models\Contact\ContactFieldType;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class ApiConversationControllerTest extends ApiTestCase
{
use DatabaseTransactions;
protected $jsonConversations = [
'id',
'object',
'happened_at',
'messages',
'contact_field_type' => [
'id',
],
'account' => [
'id',
],
'contact' => [
'id',
],
'created_at',
'updated_at',
];
private function createConversation(User $user): Conversation
{
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$contactFieldType = factory(ContactFieldType::class)->create([
'account_id' => $user->account_id,
]);
$conversation = factory(Conversation::class)->create([
'account_id' => $user->account_id,
'contact_id' => $contact->id,
'contact_field_type_id' => $contactFieldType->id,
'happened_at' => now(),
]);
return $conversation;
}
/** @test */
public function it_gets_a_list_of_conversations()
{
$user = $this->signin();
for ($i = 0; $i < 10; $i++) {
$this->createConversation($user);
}
$response = $this->json('GET', '/api/conversations');
$response->assertStatus(200);
$this->assertCount(
10,
$response->decodeResponseJson()['data']
);
$response->assertJsonFragment([
'total' => 10,
'current_page' => 1,
]);
$response->assertJsonStructure([
'data' => [
'*' => $this->jsonConversations,
],
]);
}
/** @test */
public function it_applies_the_limit_parameter_in_search()
{
$user = $this->signin();
for ($i = 0; $i < 10; $i++) {
$this->createConversation($user);
}
$response = $this->json('GET', '/api/conversations?limit=1');
$response->assertJsonFragment([
'total' => 10,
'current_page' => 1,
'per_page' => 1,
'last_page' => 10,
]);
$response = $this->json('GET', '/api/conversations?limit=2');
$response->assertJsonFragment([
'total' => 10,
'current_page' => 1,
'per_page' => 2,
'last_page' => 5,
]);
}
/** @test */
public function it_gets_a_conversation()
{
$user = $this->signin();
$conversation = $this->createConversation($user);
$response = $this->json('GET', '/api/conversations/'.$conversation->id);
$response->assertStatus(200);
$response->assertJsonStructure([
'*' => $this->jsonConversations,
]);
}
/** @test */
public function it_gets_a_conversation_for_a_specific_contact()
{
$user = $this->signin();
$conversation = $this->createConversation($user);
$response = $this->json('GET', '/api/contacts/'.$conversation['contact_id'].'/conversations');
$response->assertStatus(200);
$response->assertJsonStructure([
'data' => [
'*' => $this->jsonConversations,
],
]);
}
/** @test */
public function it_creates_a_conversation()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$contactFieldType = factory(ContactFieldType::class)->create([
'account_id' => $contact->account_id,
]);
$response = $this->json('POST', '/api/conversations', [
'contact_id' => $contact->id,
'happened_at' => '1989-02-02',
'contact_field_type_id' => $contactFieldType->id,
]);
$response->assertStatus(201);
$response->assertJsonStructure([
'data' => $this->jsonConversations,
]);
}
/** @test */
public function it_updates_a_conversation()
{
$user = $this->signin();
$conversation = $this->createConversation($user);
$contactFieldType = factory(ContactFieldType::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('PUT', '/api/conversations/'.$conversation->id, [
'happened_at' => '1989-02-02',
'contact_field_type_id' => $contactFieldType->id,
]);
$response->assertStatus(200);
$response->assertJsonStructure([
'data' => $this->jsonConversations,
]);
}
/** @test */
public function it_destroys_a_conversation()
{
$user = $this->signin();
$conversation = $this->createConversation($user);
$response = $this->delete('/api/conversations/'.$conversation->id);
$response->assertStatus(200);
$response->assertJsonFragment([
'deleted' => true,
'id' => $conversation->id,
]);
}
}

View File

@@ -0,0 +1,256 @@
<?php
namespace Tests\Api\Contact;
use Tests\ApiTestCase;
use App\Models\User\User;
use App\Models\Contact\Contact;
use App\Models\Contact\Document;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Storage;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class ApiDocumentControllerTest extends ApiTestCase
{
use DatabaseTransactions;
protected $jsonDocuments = [
'id',
'object',
'original_filename',
'new_filename',
'filesize',
'type',
'mime_type',
'number_of_downloads',
'link',
'account' => [
'id',
],
'contact' => [
'id',
],
'created_at',
'updated_at',
];
private function createDocument(User $user): Document
{
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$document = factory(Document::class)->create([
'account_id' => $user->account_id,
'contact_id' => $contact->id,
]);
return $document;
}
/** @test */
public function it_gets_a_list_of_documents()
{
$user = $this->signin();
for ($i = 0; $i < 10; $i++) {
$this->createDocument($user);
}
$response = $this->json('GET', '/api/documents');
$response->assertStatus(200);
$this->assertCount(
10,
$response->decodeResponseJson()['data']
);
$response->assertJsonFragment([
'total' => 10,
'current_page' => 1,
]);
$response->assertJsonStructure([
'data' => [
'*' => $this->jsonDocuments,
],
]);
}
/** @test */
public function it_applies_the_limit_parameter_in_search()
{
$user = $this->signin();
for ($i = 0; $i < 10; $i++) {
$this->createDocument($user);
}
$response = $this->json('GET', '/api/documents?limit=1');
$response->assertJsonFragment([
'total' => 10,
'current_page' => 1,
'per_page' => 1,
'last_page' => 10,
]);
$response = $this->json('GET', '/api/documents?limit=2');
$response->assertJsonFragment([
'total' => 10,
'current_page' => 1,
'per_page' => 2,
'last_page' => 5,
]);
}
/** @test */
public function it_gets_a_document()
{
$user = $this->signin();
$document = $this->createDocument($user);
$response = $this->json('GET', '/api/documents/'.$document->id);
$response->assertStatus(200);
$response->assertJsonStructure([
'*' => $this->jsonDocuments,
]);
}
/** @test */
public function document_show_gets_an_error_if_document_is_not_linked_to_account()
{
$user = $this->signin();
$contact = factory(Contact::class)->create();
$document = factory(Document::class)->create([
'account_id' => $contact->account_id,
'contact_id' => $contact->id,
]);
$response = $this->json('GET', '/api/documents/'.$document->id);
$this->expectNotFound($response);
}
/** @test */
public function it_gets_a_document_for_a_specific_contact()
{
$user = $this->signin();
$document = $this->createDocument($user);
$response = $this->json('GET', '/api/contacts/'.$document['contact_id'].'/documents');
$response->assertStatus(200);
$response->assertJsonStructure([
'data' => [
'*' => $this->jsonDocuments,
],
]);
$response->assertJsonFragment([
'total' => 1,
'current_page' => 1,
'per_page' => 15,
'last_page' => 1,
]);
}
/** @test */
public function it_store_a_document_for_a_specific_contact()
{
Storage::fake();
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('POST', '/api/documents', [
'contact_id' => $contact->id,
'document' => UploadedFile::fake()->image('test.pdf'),
]);
$response->assertStatus(201);
$response->assertJsonStructure([
'data' => $this->jsonDocuments,
]);
$this->assertDatabaseHas('documents', [
'account_id' => $user->account_id,
'contact_id' => $contact->id,
'original_filename' => 'test.pdf',
]);
Storage::disk('public')->assertExists($response->json('data.new_filename'));
}
/** @test */
public function document_store_gets_an_error_if_fields_are_missing()
{
$user = $this->signin();
$response = $this->json('POST', '/api/documents', [
]);
$this->expectDataError($response, [
'The contact id field is required.',
]);
}
/** @test */
public function document_store_gets_an_error_if_contact_is_not_linked_to_user()
{
$user = $this->signin();
$contact = factory(Contact::class)->create();
$response = $this->json('POST', '/api/documents', [
'contact_id' => $contact->id,
'document' => UploadedFile::fake()->image('test.pdf'),
]);
$this->expectNotFound($response);
}
/** @test */
public function it_destroy_a_document()
{
$user = $this->signin();
$document = $this->createDocument($user);
$response = $this->json('DELETE', '/api/documents/'.$document->id);
$response->assertStatus(200);
$response->assertJsonFragment([
'deleted' => true,
'id' => $document->id,
]);
}
/** @test */
public function document_destroy_gets_an_error_if_document_is_not_linked_to_user()
{
$user = $this->signin();
$contact = factory(Contact::class)->create();
$document = factory(Document::class)->create([
'account_id' => $contact->account_id,
'contact_id' => $contact->id,
]);
$response = $this->json('DELETE', '/api/documents/'.$document->id);
$this->expectNotFound($response);
}
}

View File

@@ -0,0 +1,340 @@
<?php
namespace Tests\Api\Contact;
use Tests\ApiTestCase;
use App\Models\User\User;
use App\Models\Contact\Contact;
use App\Models\Contact\LifeEvent;
use App\Models\Contact\LifeEventType;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class ApiLifeEventControllerTest extends ApiTestCase
{
use DatabaseTransactions;
protected $jsonLifeEvents = [
'id',
'object',
'name',
'note',
'happened_at',
'life_event_type' => [
'id',
],
'account' => [
'id',
],
'contact' => [
'id',
],
'created_at',
'updated_at',
];
private function createLifeEvent(User $user): LifeEvent
{
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$lifeEventType = factory(LifeEventType::class)->create([
'account_id' => $user->account_id,
]);
$lifeEvent = factory(LifeEvent::class)->create([
'account_id' => $user->account_id,
'contact_id' => $contact->id,
'life_event_type_id' => $lifeEventType->id,
'happened_at' => now(),
'name' => 'This is a text',
'note' => 'This is a text',
]);
return $lifeEvent;
}
/** @test */
public function it_gets_a_list_of_life_events()
{
$user = $this->signin();
for ($i = 0; $i < 10; $i++) {
$this->createLifeEvent($user);
}
$response = $this->json('GET', '/api/lifeevents');
$response->assertStatus(200);
$this->assertCount(
10,
$response->decodeResponseJson()['data']
);
$response->assertJsonFragment([
'total' => 10,
'current_page' => 1,
]);
$response->assertJsonStructure([
'data' => [
'*' => $this->jsonLifeEvents,
],
]);
}
/** @test */
public function it_applies_the_limit_parameter_in_search()
{
$user = $this->signin();
for ($i = 0; $i < 10; $i++) {
$this->createLifeEvent($user);
}
$response = $this->json('GET', '/api/lifeevents?limit=1');
$response->assertJsonFragment([
'total' => 10,
'current_page' => 1,
'per_page' => 1,
'last_page' => 10,
]);
$response = $this->json('GET', '/api/lifeevents?limit=2');
$response->assertJsonFragment([
'total' => 10,
'current_page' => 1,
'per_page' => 2,
'last_page' => 5,
]);
}
/** @test */
public function it_gets_a_life_event()
{
$user = $this->signin();
$lifeEvent = $this->createLifeEvent($user);
$response = $this->json('GET', '/api/lifeevents/'.$lifeEvent->id);
$response->assertStatus(200);
$response->assertJsonStructure([
'*' => $this->jsonLifeEvents,
]);
}
/** @test */
public function getting_a_life_event_doesnt_work_if_life_event_doesnt_exist()
{
$user = $this->signin();
$response = $this->json('GET', '/api/lifeevents/329029093809');
$this->expectNotFound($response);
}
/** @test */
public function it_creates_a_life_event()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$lifeEventType = factory(LifeEventType::class)->create([
'account_id' => $contact->account_id,
]);
$response = $this->json('POST', '/api/lifeevents', [
'contact_id' => $contact->id,
'life_event_type_id' => $lifeEventType->id,
'happened_at' => '1989-02-02',
'name' => 'This is a text',
'note' => 'This is a text',
'has_reminder' => false,
'happened_at_month_unknown' => false,
'happened_at_day_unknown' => false,
]);
$response->assertStatus(200);
$response->assertJsonStructure([
'data' => $this->jsonLifeEvents,
]);
}
/** @test */
public function creating_a_life_event_doesnt_work_if_ids_are_not_found()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('POST', '/api/lifeevents', [
'contact_id' => $contact->id,
'life_event_type_id' => 0,
'happened_at' => '1989-02-02',
'name' => 'This is a text',
'note' => 'This is a text',
'has_reminder' => false,
'happened_at_month_unknown' => false,
'happened_at_day_unknown' => false,
]);
$this->expectNotFound($response);
$lifeEventType = factory(LifeEventType::class)->create([
'account_id' => $contact->account_id,
]);
$response = $this->json('POST', '/api/lifeevents', [
'contact_id' => 0,
'life_event_type_id' => $lifeEventType->id,
'happened_at' => '1989-02-02',
'name' => 'This is a text',
'note' => 'This is a text',
'has_reminder' => false,
'happened_at_month_unknown' => false,
'happened_at_day_unknown' => false,
]);
$this->expectNotFound($response);
}
/** @test */
public function creating_a_life_event_doesnt_work_if_parameters_are_not_right()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$lifeEventType = factory(LifeEventType::class)->create([
'account_id' => $contact->account_id,
]);
$response = $this->json('POST', '/api/lifeevents', [
'contact_id' => $contact->id,
'life_event_type_id' => $lifeEventType->id,
'name' => 'This is a text',
'note' => 'This is a text',
]);
$this->expectDataError($response, [
'The happened at field is required.',
'The has reminder field is required.',
'The happened at month unknown field is required.',
'The happened at day unknown field is required.',
]);
}
/** @test */
public function it_updates_a_life_event()
{
$user = $this->signin();
$lifeEvent = $this->createLifeEvent($user);
$lifeEventType = factory(LifeEventType::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('PUT', '/api/lifeevents/'.$lifeEvent->id, [
'happened_at' => '1989-02-02',
'life_event_type_id' => $lifeEventType->id,
'name' => 'This is a text',
'note' => 'This is a text',
]);
$response->assertStatus(200);
$response->assertJsonStructure([
'data' => $this->jsonLifeEvents,
]);
}
/** @test */
public function updating_a_life_event_doesnt_work_if_ids_are_not_found()
{
$user = $this->signin();
$lifeEvent = $this->createLifeEvent($user);
$lifeEventType = factory(LifeEventType::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('PUT', '/api/lifeevents/23929390', [
'happened_at' => '1989-02-02',
'life_event_type_id' => $lifeEventType->id,
'name' => 'This is a text',
'note' => 'This is a text',
]);
$this->expectNotFound($response);
$response = $this->json('PUT', '/api/lifeevents/'.$lifeEvent->id, [
'happened_at' => '1989-02-02',
'life_event_type_id' => 3283028,
'name' => 'This is a text',
'note' => 'This is a text',
]);
$this->expectNotFound($response);
}
/** @test */
public function updating_a_life_event_doesnt_work_if_parameters_are_not_right()
{
$user = $this->signin();
$lifeEvent = $this->createLifeEvent($user);
$lifeEventType = factory(LifeEventType::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('PUT', '/api/lifeevents/'.$lifeEvent->id, [
'life_event_type_id' => $lifeEventType->id,
'name' => 'This is a text',
'note' => 'This is a text',
]);
$this->expectDataError($response, [
'The happened at field is required.',
]);
}
/** @test */
public function it_destroys_a_life_event()
{
$user = $this->signin();
$lifeEvent = $this->createLifeEvent($user);
$response = $this->delete('/api/lifeevents/'.$lifeEvent->id);
$response->assertStatus(200);
$response->assertJsonFragment([
'deleted' => true,
'id' => $lifeEvent->id,
]);
}
/** @test */
public function deleting_a_life_event_doesnt_work_if_ids_are_not_found()
{
$user = $this->signin();
$lifeEvent = $this->createLifeEvent($user);
$response = $this->delete('/api/lifeevents/39230990');
$this->expectNotFound($response);
}
}

View File

@@ -0,0 +1,73 @@
<?php
namespace Tests\Api\Contact;
use Tests\ApiTestCase;
use App\Models\Contact\Contact;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class ApiMeControllerTest extends ApiTestCase
{
use DatabaseTransactions;
/** @test */
public function it_sets_me_contact()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('POST', '/api/me/contact', ['contact_id' => $contact->id]);
$response->assertStatus(200);
$this->assertDatabaseHas('users', [
'account_id' => $user->account_id,
'me_contact_id' => $contact->id,
]);
}
/** @test */
public function it_throws_an_error_if_wrong_account_on_sets_me_contact()
{
$this->signin();
$contact = factory(Contact::class)->create();
$response = $this->json('POST', '/api/me/contact', ['contact_id' => $contact->id]);
$this->expectNotFound($response);
}
/** @test */
public function it_throws_an_error_if_account_not_exists_on_sets_me_contact()
{
$this->signin();
$response = $this->json('POST', '/api/me/contact', ['contact_id' => 0]);
$this->expectDataError($response, [
'The selected contact id is invalid.',
]);
}
/** @test */
public function it_removes_me_contact()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$user->me_contact_id = $contact->id;
$user->save();
$response = $this->json('DELETE', '/api/me/contact');
$response->assertStatus(200);
$this->assertDatabaseHas('users', [
'account_id' => $user->account_id,
'me_contact_id' => null,
]);
}
}

View File

@@ -0,0 +1,127 @@
<?php
namespace Tests\Api\Contact;
use Tests\ApiTestCase;
use App\Models\User\User;
use App\Models\Contact\Contact;
use App\Models\Contact\Message;
use App\Models\Contact\Conversation;
use App\Models\Contact\ContactFieldType;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class ApiMessageControllerTest extends ApiTestCase
{
use DatabaseTransactions;
protected $jsonConversations = [
'id',
'object',
'happened_at',
'messages' => [
[
'id',
],
],
'contact_field_type' => [
'id',
],
'account' => [
'id',
],
'contact' => [
'id',
],
'created_at',
'updated_at',
];
private function createConversation(User $user): Conversation
{
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$contactFieldType = factory(ContactFieldType::class)->create([
'account_id' => $user->account_id,
]);
$conversation = factory(Conversation::class)->create([
'account_id' => $user->account_id,
'contact_id' => $contact->id,
'contact_field_type_id' => $contactFieldType->id,
'happened_at' => now(),
]);
return $conversation;
}
private function addMessage(Conversation $conversation): Message
{
$message = factory(Message::class)->create([
'account_id' => $conversation->account_id,
'contact_id' => $conversation->contact_id,
'conversation_id' => $conversation->id,
]);
return $message;
}
/** @test */
public function it_adds_a_message_to_a_conversation()
{
$user = $this->signin();
$conversation = $this->createConversation($user);
$response = $this->json('POST', '/api/conversations/'.$conversation->id.'/messages', [
'written_at' => '1998-02-02',
'written_by_me' => true,
'content' => 'lorem ipsum',
]);
$response->assertStatus(200);
$response->assertJsonStructure([
'data' => $this->jsonConversations,
]);
}
/** @test */
public function it_updates_a_message()
{
$user = $this->signin();
$conversation = $this->createConversation($user);
$message = $this->addMessage($conversation);
$response = $this->json('PUT', '/api/conversations/'.$conversation->id.'/messages/'.$message->id, [
'written_at' => '1989-02-02',
'written_by_me' => true,
'content' => 'lorem ipsum',
]);
$response->assertStatus(200);
$response->assertJsonStructure([
'data' => $this->jsonConversations,
]);
}
/** @test */
public function it_destroys_a_message()
{
$user = $this->signin();
$conversation = $this->createConversation($user);
$message = $this->addMessage($conversation);
$response = $this->delete('/api/conversations/'.$conversation->id.'/messages/'.$message->id);
$response->assertStatus(200);
$response->assertJsonFragment([
'deleted' => true,
'id' => $message->id,
]);
}
}

View File

@@ -0,0 +1,228 @@
<?php
namespace Tests\Api\Contact;
use Tests\ApiTestCase;
use App\Models\Account\Account;
use App\Models\Account\Company;
use App\Models\Contact\Contact;
use App\Models\Contact\Occupation;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class ApiOccupationControllerTest extends ApiTestCase
{
use DatabaseTransactions;
protected $jsonOccupation = [
'id',
'object',
'title',
'description',
'salary',
'salary_unit',
'currently_works_here',
'start_date',
'end_date',
'company' => [
'id',
],
'account' => [
'id',
],
'created_at',
'updated_at',
];
public function test_it_gets_a_list_of_occupations()
{
$user = $this->signin();
factory(Occupation::class, 3)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('GET', '/api/occupations');
$response->assertStatus(200);
$response->assertJsonStructure([
'data' => ['*' => $this->jsonOccupation],
]);
}
public function test_it_applies_the_limit_parameter_in_search()
{
$user = $this->signin();
factory(Occupation::class, 10)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('GET', '/api/occupations?limit=1');
$response->assertJsonFragment([
'total' => 10,
'current_page' => 1,
'per_page' => 1,
'last_page' => 10,
]);
$response = $this->json('GET', '/api/occupations?limit=2');
$response->assertJsonFragment([
'total' => 10,
'current_page' => 1,
'per_page' => 2,
'last_page' => 5,
]);
}
public function test_it_gets_one_occupation()
{
$user = $this->signin();
$occupation = factory(Occupation::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('get', '/api/occupations/'.$occupation->id);
$response->assertStatus(200);
$response->assertJsonStructure([
'data' => $this->jsonOccupation,
]);
$response->assertJsonFragment([
'object' => 'occupation',
'id' => $occupation->id,
]);
}
public function test_it_cant_get_a_occupation_with_unexistent_id()
{
$user = $this->signin();
$response = $this->json('get', '/api/occupations/0');
$this->expectNotFound($response);
}
public function test_it_creates_a_occupation()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$company = factory(Company::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('post', '/api/occupations', [
'contact_id' => $contact->id,
'company_id' => $company->id,
'title' => 'Waiter',
]);
$response->assertStatus(201);
$response->assertJsonStructure([
'data' => $this->jsonOccupation,
]);
$occupationId = $response->json('data.id');
$response->assertJsonFragment([
'object' => 'occupation',
'id' => $occupationId,
]);
$this->assertDatabaseHas('occupations', [
'account_id' => $user->account_id,
'id' => $occupationId,
'title' => 'Waiter',
]);
}
public function test_it_updates_a_occupation()
{
$user = $this->signin();
$occupation = factory(Occupation::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('put', '/api/occupations/'.$occupation->id, [
'contact_id' => $occupation->contact_id,
'company_id' => $occupation->company_id,
'title' => 'Commissaire',
'salary' => null,
]);
$response->assertStatus(200);
$response->assertJsonStructure([
'data' => $this->jsonOccupation,
]);
$occupationId = $response->json('data.id');
$this->assertEquals($occupation->id, $occupationId);
$response->assertJsonFragment([
'object' => 'occupation',
'id' => $occupationId,
]);
$this->assertDatabaseHas('occupations', [
'account_id' => $user->account_id,
'id' => $occupationId,
'title' => 'Commissaire',
'salary' => null,
]);
}
public function test_it_cant_update_a_occupation_if_account_is_not_linked_to_occupation()
{
$user = $this->signin();
$account = factory(Account::class)->create([]);
$occupation = factory(Occupation::class)->create([
'account_id' => $account->id,
]);
$response = $this->json('put', '/api/occupations/'.$occupation->id, [
'contact_id' => $occupation->contact_id,
'company_id' => $occupation->company_id,
'title' => 'Commissaire',
'salary' => null,
]);
$this->expectNotFound($response);
}
public function test_it_deletes_a_occupation()
{
$user = $this->signin();
$occupation = factory(Occupation::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('delete', '/api/occupations/'.$occupation->id);
$response->assertStatus(200);
$this->assertdatabasemissing('occupations', [
'account_id' => $user->account_id,
'id' => $occupation->id,
]);
}
public function test_it_cant_delete_a_occupation_if_occupation_doesnt_exist()
{
$user = $this->signin();
$response = $this->json('delete', '/api/occupations/0');
$this->expectDataError($response, [
'The selected occupation id is invalid.',
]);
}
}

View File

@@ -0,0 +1,294 @@
<?php
namespace Tests\Api\Contact;
use Tests\ApiTestCase;
use App\Models\User\User;
use App\Models\Account\Photo;
use App\Models\Contact\Contact;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Storage;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class ApiPhotoControllerTest extends ApiTestCase
{
use DatabaseTransactions;
protected $jsonDatas = [
'id',
'object',
'original_filename',
'new_filename',
'filesize',
'mime_type',
'link',
'account' => [
'id',
],
'contact' => [
'id',
],
'created_at',
'updated_at',
];
private function createPhoto(User $user): Photo
{
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$photo = factory(Photo::class)->create([
'account_id' => $user->account_id,
]);
UploadedFile::fake()->image('file.jpg')->storeAs('', 'file.jpg');
$contact->photos()->syncWithoutDetaching([$photo->id]);
return $photo;
}
/** @test */
public function it_gets_a_list_of_photos()
{
$user = $this->signin();
for ($i = 0; $i < 10; $i++) {
$this->createPhoto($user);
}
$response = $this->json('GET', '/api/photos');
$response->assertStatus(200);
$this->assertCount(
10,
$response->decodeResponseJson()['data']
);
$response->assertJsonFragment([
'total' => 10,
'current_page' => 1,
]);
$response->assertJsonStructure([
'data' => [
'*' => $this->jsonDatas,
],
]);
}
/** @test */
public function it_applies_the_limit_parameter_in_search()
{
$user = $this->signin();
for ($i = 0; $i < 10; $i++) {
$this->createPhoto($user);
}
$response = $this->json('GET', '/api/photos?limit=1');
$response->assertJsonFragment([
'total' => 10,
'current_page' => 1,
'per_page' => 1,
'last_page' => 10,
]);
$response = $this->json('GET', '/api/photos?limit=2');
$response->assertJsonFragment([
'total' => 10,
'current_page' => 1,
'per_page' => 2,
'last_page' => 5,
]);
}
/** @test */
public function it_gets_a_photo()
{
$user = $this->signin();
$photo = $this->createPhoto($user);
$response = $this->json('GET', '/api/photos/'.$photo->id);
$response->assertStatus(200);
$response->assertJsonStructure([
'*' => $this->jsonDatas,
]);
}
/** @test */
public function photo_show_gets_an_error_if_photo_is_not_linked_to_account()
{
$user = $this->signin();
$contact = factory(Contact::class)->create();
$photo = factory(Photo::class)->create([
'account_id' => $contact->account_id,
]);
$contact->photos()->syncWithoutDetaching([$photo->id]);
$response = $this->json('GET', '/api/photos/'.$photo->id);
$this->expectNotFound($response);
}
/** @test */
public function it_gets_a_photo_for_a_specific_contact()
{
$user = $this->signin();
$photo = $this->createPhoto($user);
$response = $this->json('GET', '/api/contacts/'.$photo->contact()->id.'/photos');
$response->assertStatus(200);
$response->assertJsonStructure([
'data' => [
'*' => $this->jsonDatas,
],
]);
$response->assertJsonFragment([
'total' => 1,
'current_page' => 1,
'per_page' => 15,
'last_page' => 1,
]);
}
/** @test */
public function it_store_a_photo_for_a_specific_contact()
{
Storage::fake();
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('POST', '/api/photos', [
'contact_id' => $contact->id,
'photo' => UploadedFile::fake()->image('test.jpg'),
]);
$response->assertStatus(201);
$response->assertJsonStructure([
'data' => $this->jsonDatas,
]);
$this->assertDatabaseHas('photos', [
'account_id' => $user->account_id,
'original_filename' => 'test.jpg',
]);
Storage::disk('public')->assertExists($response->json('data.new_filename'));
}
/** @test */
public function photo_store_gets_an_error_if_fields_are_missing()
{
$user = $this->signin();
$response = $this->json('POST', '/api/photos', [
]);
$this->expectDataError($response, [
'The contact id field is required.',
]);
}
/** @test */
public function photo_store_gets_an_error_if_contact_is_not_linked_to_user()
{
$user = $this->signin();
$contact = factory(Contact::class)->create();
$response = $this->json('POST', '/api/photos', [
'account_id' => $contact->account_id,
'contact_id' => $contact->id,
'photo' => UploadedFile::fake()->image('test.jpg'),
]);
$this->expectNotFound($response);
}
/** @test */
public function it_destroy_a_photo()
{
$user = $this->signin();
$photo = $this->createPhoto($user);
$response = $this->json('DELETE', '/api/photos/'.$photo->id);
$response->assertStatus(200);
$response->assertJsonFragment([
'deleted' => true,
'id' => $photo->id,
]);
$this->assertDatabaseMissing('photos', [
'id' => $photo->id,
'account_id' => $user->account_id,
]);
}
/** @test */
public function photo_destroy_gets_an_error_if_photo_is_not_linked_to_account()
{
$user = $this->signin();
$contact = factory(Contact::class)->create();
$photo = factory(Photo::class)->create([
'account_id' => $contact->account_id,
]);
$contact->photos()->syncWithoutDetaching([$photo->id]);
$response = $this->json('DELETE', '/api/photos/'.$photo->id);
$this->expectNotFound($response);
}
/** @test */
public function it_store_and_destroy_a_photo()
{
Storage::fake();
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('POST', '/api/photos/', [
'contact_id' => $contact->id,
'photo' => UploadedFile::fake()->image('test.jpg'),
]);
$photo = $contact->photos->first();
Storage::disk('public')->assertExists($photo->new_filename);
$response = $this->json('DELETE', '/api/photos/'.$photo->id);
$response->assertStatus(200);
$response->assertJsonFragment([
'deleted' => true,
'id' => $photo->id,
]);
Storage::disk('public')->assertMissing($photo->new_filename);
}
}

View File

@@ -0,0 +1,311 @@
<?php
namespace Tests\Api\ContactField;
use Tests\ApiTestCase;
use App\Models\Account\Account;
use App\Models\Contact\Contact;
use App\Models\Contact\ContactField;
use App\Models\Contact\ContactFieldType;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class ApiContactFieldControllerTest extends ApiTestCase
{
use DatabaseTransactions;
protected $jsonContactField = [
'id',
'object',
'content',
'contact_field_type',
'account' => [
'id',
],
'contact',
'created_at',
'updated_at',
];
/** @test */
public function contact_fields_get_contact_all()
{
$user = $this->signin();
$contact1 = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$contactField1 = factory(ContactField::class)->create([
'account_id' => $user->account_id,
'contact_id' => $contact1->id,
]);
$contact2 = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$contactField2 = factory(ContactField::class)->create([
'account_id' => $user->account_id,
'contact_id' => $contact2->id,
]);
$response = $this->json('GET', '/api/contacts/'.$contact1->id.'/contactfields');
$response->assertStatus(200);
$response->assertJsonStructure([
'data' => ['*' => $this->jsonContactField],
]);
$response->assertJsonFragment([
'object' => 'contactfield',
'id' => $contactField1->id,
]);
$response->assertJsonMissingExact([
'object' => 'contactfield',
'id' => $contactField2->id,
]);
}
/** @test */
public function contact_fields_get_contact_all_error()
{
$user = $this->signin();
$response = $this->json('GET', '/api/contacts/0/contactfields');
$this->expectNotFound($response);
}
/** @test */
public function contact_fields_get_one()
{
$user = $this->signin();
$contact1 = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$contactField1 = factory(ContactField::class)->create([
'account_id' => $user->account_id,
'contact_id' => $contact1->id,
]);
$contactField2 = factory(ContactField::class)->create([
'account_id' => $user->account_id,
'contact_id' => $contact1->id,
]);
$response = $this->json('GET', '/api/contactfields/'.$contactField1->id);
$response->assertStatus(200);
$response->assertJsonStructure([
'data' => $this->jsonContactField,
]);
$response->assertJsonFragment([
'object' => 'contactfield',
'id' => $contactField1->id,
]);
$response->assertJsonMissingExact([
'object' => 'contactfield',
'id' => $contactField2->id,
]);
}
/** @test */
public function contact_fields_get_one_error()
{
$user = $this->signin();
$response = $this->json('GET', '/api/contactfields/0');
$this->expectNotFound($response);
}
/** @test */
public function contact_fields_create()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$field = factory(ContactFieldType::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('POST', '/api/contactfields', [
'contact_id' => $contact->id,
'contact_field_type_id' => $field->id,
'data' => 'ok',
]);
$response->assertStatus(201);
$response->assertJsonStructure([
'data' => $this->jsonContactField,
]);
$contactField_id = $response->json('data.id');
$response->assertJsonFragment([
'object' => 'contactfield',
'id' => $contactField_id,
]);
$this->assertGreaterThan(0, $contactField_id);
$this->assertDatabaseHas('contact_fields', [
'account_id' => $user->account_id,
'contact_id' => $contact->id,
'id' => $contactField_id,
'contact_field_type_id' => $field->id,
'data' => 'ok',
]);
}
/** @test */
public function contact_fields_create_error()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('POST', '/api/contactfields', [
'contact_id' => $contact->id,
]);
$this->expectDataError($response, [
'The contact field type id field is required.',
'The data field is required.',
]);
}
/** @test */
public function contact_fields_create_error_bad_account()
{
$user = $this->signin();
$account = factory(Account::class)->create();
$contact = factory(Contact::class)->create([
'account_id' => $account->id,
]);
$field = factory(ContactFieldType::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('POST', '/api/contactfields', [
'contact_id' => $contact->id,
'contact_field_type_id' => $field->id,
'data' => 'ok',
]);
$this->expectNotFound($response);
}
/** @test */
public function contact_fields_update()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$contactField = factory(ContactField::class)->create([
'account_id' => $user->account_id,
'contact_id' => $contact->id,
]);
$response = $this->json('PUT', '/api/contactfields/'.$contactField->id, [
'contact_id' => $contact->id,
'contact_field_type_id' => $contactField->contact_field_type_id,
'data' => 'ok',
]);
$response->assertStatus(200);
$response->assertJsonStructure([
'data' => $this->jsonContactField,
]);
$contactField_id = $response->json('data.id');
$this->assertEquals($contactField->id, $contactField_id);
$response->assertJsonFragment([
'object' => 'contactfield',
'id' => $contactField_id,
]);
$this->assertGreaterThan(0, $contactField_id);
$this->assertDatabaseHas('contact_fields', [
'account_id' => $user->account_id,
'contact_id' => $contact->id,
'id' => $contactField_id,
'contact_field_type_id' => $contactField->contact_field_type_id,
'data' => 'ok',
]);
}
/** @test */
public function contact_fields_update_error()
{
$user = $this->signin();
$contactField = factory(ContactField::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('PUT', '/api/contactfields/'.$contactField->id, [
'contact_id' => $contactField->contact_id,
]);
$this->expectDataError($response, [
'The contact field type id field is required.',
'The data field is required.',
]);
}
/** @test */
public function contact_fields_update_error_bad_account()
{
$user = $this->signin();
$account = factory(Account::class)->create();
$contact = factory(Contact::class)->create([
'account_id' => $account->id,
]);
$contactField = factory(ContactField::class)->create([
'account_id' => $user->account_id,
'contact_id' => $contact->id,
]);
$response = $this->json('PUT', '/api/contactfields/'.$contactField->id, [
'contact_id' => $contact->id,
'contact_field_type_id' => $contactField->contact_field_type_id,
'data' => 'ok',
]);
$this->expectNotFound($response);
}
/** @test */
public function contact_fields_delete()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$contactField = factory(ContactField::class)->create([
'account_id' => $user->account_id,
'contact_id' => $contact->id,
]);
$this->assertDatabaseHas('contact_fields', [
'account_id' => $user->account_id,
'contact_id' => $contact->id,
'id' => $contactField->id,
]);
$response = $this->json('DELETE', '/api/contactfields/'.$contactField->id);
$response->assertStatus(200);
$this->assertDatabaseMissing('contact_fields', [
'account_id' => $user->account_id,
'contact_id' => $contact->id,
'id' => $contactField->id,
]);
}
/** @test */
public function contact_fields_delete_error()
{
$user = $this->signin();
$response = $this->json('DELETE', '/api/contactfields/0');
$this->expectDataError($response, [
'The selected contact field id is invalid.',
]);
}
}

View File

@@ -0,0 +1,223 @@
<?php
namespace Tests\Api\ContactField;
use Tests\ApiTestCase;
use App\Models\Account\Account;
use App\Models\Contact\ContactFieldType;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class ApiContactFieldTypeControllerTest extends ApiTestCase
{
use DatabaseTransactions;
protected $jsonContactFieldType = [
'id',
'object',
'name',
'protocol',
'delible',
'type',
'account' => [
'id',
],
'created_at',
'updated_at',
];
/** @test */
public function contact_field_type_get_one()
{
$user = $this->signin();
$contactFieldType1 = factory(ContactFieldType::class)->create([
'account_id' => $user->account_id,
]);
$contactFieldType2 = factory(ContactFieldType::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('GET', '/api/contactfieldtypes/'.$contactFieldType1->id);
$response->assertStatus(200);
$response->assertJsonStructure([
'data' => $this->jsonContactFieldType,
]);
$response->assertJsonFragment([
'object' => 'contactfieldtype',
'id' => $contactFieldType1->id,
]);
$response->assertJsonMissingExact([
'object' => 'contactfieldtype',
'id' => $contactFieldType2->id,
]);
}
/** @test */
public function contact_field_type_get_one_error()
{
$user = $this->signin();
$response = $this->json('GET', '/api/contactfieldtypes/0');
$this->expectNotFound($response);
}
/** @test */
public function contact_field_type_create()
{
$user = $this->signin();
$response = $this->json('POST', '/api/contactfieldtypes', [
'name' => 'Email',
'protocol' => 'mailto:',
'type' => 'email',
]);
$response->assertStatus(201);
$response->assertJsonStructure([
'data' => $this->jsonContactFieldType,
]);
$contactFieldTypeId = $response->json('data.id');
$response->assertJsonFragment([
'object' => 'contactfieldtype',
'id' => $contactFieldTypeId,
]);
$this->assertGreaterThan(0, $contactFieldTypeId);
$this->assertDatabaseHas('contact_field_types', [
'account_id' => $user->account_id,
'id' => $contactFieldTypeId,
'name' => 'Email',
'protocol' => 'mailto:',
'type' => 'email',
]);
}
/** @test */
public function contact_field_type_create_error()
{
$user = $this->signin();
$response = $this->json('POST', '/api/contactfieldtypes', [
]);
$this->expectDataError($response, [
'The name field is required.',
]);
}
/** @test */
public function contact_field_type_update()
{
$user = $this->signin();
$contactFieldType = factory(ContactFieldType::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('PUT', '/api/contactfieldtypes/'.$contactFieldType->id, [
'name' => 'Email2',
'protocol' => 'mailto:',
'type' => 'email',
]);
$response->assertStatus(200);
$response->assertJsonStructure([
'data' => $this->jsonContactFieldType,
]);
$contactFieldTypeId = $response->json('data.id');
$this->assertEquals($contactFieldType->id, $contactFieldTypeId);
$response->assertJsonFragment([
'object' => 'contactfieldtype',
'id' => $contactFieldTypeId,
]);
$this->assertGreaterThan(0, $contactFieldTypeId);
$this->assertDatabaseHas('contact_field_types', [
'account_id' => $user->account_id,
'id' => $contactFieldType->id,
'name' => 'Email2',
'protocol' => 'mailto:',
'type' => 'email',
]);
}
/** @test */
public function contact_field_type_update_error()
{
$user = $this->signin();
$contactFieldType = factory(ContactFieldType::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('PUT', '/api/contactfieldtypes/'.$contactFieldType->id, []);
$this->expectDataError($response, [
'The name field is required.',
]);
}
/** @test */
public function contact_field_type_update_error_bad_account()
{
$user = $this->signin();
$account = factory(Account::class)->create();
$contactFieldType = factory(ContactFieldType::class)->create([
'account_id' => $account->id,
]);
$response = $this->json('PUT', '/api/contactfieldtypes/'.$contactFieldType->id, [
'name' => 'Email2',
'protocol' => 'mailto:',
'type' => 'email',
]);
$this->expectNotFound($response);
}
/** @test */
public function contact_field_type_delete()
{
$user = $this->signin();
$contactFieldType = factory(ContactFieldType::class)->create([
'account_id' => $user->account_id,
]);
$this->assertDatabaseHas('contact_field_types', [
'account_id' => $user->account_id,
'id' => $contactFieldType->id,
]);
$response = $this->json('DELETE', '/api/contactfieldtypes/'.$contactFieldType->id);
$response->assertStatus(200);
$this->assertDatabaseMissing('contact_field_types', [
'account_id' => $user->account_id,
'id' => $contactFieldType->id,
]);
}
/** @test */
public function contact_field_type_delete_error()
{
$user = $this->signin();
$response = $this->json('DELETE', '/api/contactfieldtypes/0');
$this->expectNotFound($response);
}
/** @test */
public function contact_field_type_delete_bad_account()
{
$user = $this->signin();
$account = factory(Account::class)->create();
$contactFieldType = factory(ContactFieldType::class)->create([
'account_id' => $account->id,
]);
$response = $this->json('DELETE', '/api/contactfieldtypes/'.$contactFieldType->id);
$this->expectNotFound($response);
}
}

View File

@@ -0,0 +1,294 @@
<?php
namespace Tests\Api\DAV;
use Carbon\Carbon;
use Tests\ApiTestCase;
use Illuminate\Support\Str;
use App\Models\User\SyncToken;
use App\Models\Contact\Contact;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class CalDAVBirthdaysTest extends ApiTestCase
{
use DatabaseTransactions, CardEtag;
/**
* @group dav
*/
public function test_caldav_birthdays_propfind()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$specialDate = $contact->setSpecialDate('birthdate', 1983, 03, 04);
$response = $this->call('PROPFIND', "/dav/calendars/{$user->email}/birthdays");
$response->assertStatus(207);
$response->assertHeader('X-Sabre-Version');
$response->assertSee("<d:response><d:href>/dav/calendars/{$user->email}/birthdays/</d:href>", false);
$specialDate->refresh();
$response->assertSee("<d:response><d:href>/dav/calendars/{$user->email}/birthdays/{$specialDate->uuid}.ics</d:href>", false);
}
public function test_caldav_birthdays_propfind_with_props()
{
$user = $this->signin();
$response = $this->call('PROPFIND', "/dav/calendars/{$user->email}/birthdays/", [], [], [],
[
'HTTP_DEPTH' => 0,
],
'<d:propfind xmlns:d="DAV:">
<d:prop>
<d:displayname />
</d:prop>
</d:propfind>'
);
$response->assertStatus(207);
$response->assertHeader('X-Sabre-Version');
$response->assertSee('<d:multistatus xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns" xmlns:card="urn:ietf:params:xml:ns:carddav" xmlns:cal="urn:ietf:params:xml:ns:caldav" xmlns:cs="http://calendarserver.org/ns/">'.
'<d:response>'.
"<d:href>/dav/calendars/{$user->email}/birthdays/</d:href>".
'<d:propstat>'.
'<d:prop>'.
'<d:displayname>Birthdays</d:displayname>'.
'</d:prop>'.
'<d:status>HTTP/1.1 200 OK</d:status>'.
'</d:propstat>'.
'</d:response>'.
'</d:multistatus', false);
}
/**
* @group dav
*/
public function test_caldav_birthdays_propfind_one_birthday()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$specialDate = $contact->setSpecialDate('birthdate', 1983, 03, 04);
$specialDate->uuid = Str::uuid();
$specialDate->save();
$response = $this->call('PROPFIND', "/dav/calendars/{$user->email}/birthdays/{$specialDate->uuid}.ics");
$response->assertStatus(207);
$response->assertHeader('X-Sabre-Version');
$response->assertSee("<d:response><d:href>/dav/calendars/{$user->email}/birthdays/{$specialDate->uuid}.ics</d:href>", false);
}
public function test_caldav_birthdays_getctag()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$specialDate = $contact->setSpecialDate('birthdate', 1983, 03, 04);
$specialDate->uuid = Str::uuid();
$specialDate->save();
$response = $this->call('PROPFIND', "/dav/calendars/{$user->email}/", [], [], [],
[
'HTTP_DEPTH' => '1',
'content-type' => 'application/xml; charset=utf-8',
],
"<propfind xmlns='DAV:' xmlns:cs='http://calendarserver.org/ns/' xmlns:s='http://sabredav.org/ns'>
<prop>
<cs:getctag />
<sync-token />
<s:sync-token />
</prop>
</propfind>"
);
$response->assertStatus(207);
$response->assertHeader('X-Sabre-Version');
$tokens = SyncToken::where([
'account_id' => $user->account_id,
'user_id' => $user->id,
'name' => 'birthdays',
])->orderBy('created_at')->get();
$this->assertGreaterThan(0, $tokens->count());
$token = $tokens->last();
$response->assertSee('<d:multistatus xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns" xmlns:card="urn:ietf:params:xml:ns:carddav" xmlns:cal="urn:ietf:params:xml:ns:caldav" xmlns:cs="http://calendarserver.org/ns/">', false);
$response->assertSee('<d:response>'.
"<d:href>/dav/calendars/{$user->email}/birthdays/</d:href>".
'<d:propstat>'.
'<d:prop>'.
"<cs:getctag>http://sabre.io/ns/sync/{$token->id}</cs:getctag>".
"<d:sync-token>http://sabre.io/ns/sync/{$token->id}</d:sync-token>".
"<s:sync-token>http://sabre.io/ns/sync/{$token->id}</s:sync-token>".
'</d:prop>'.
'<d:status>HTTP/1.1 200 OK</d:status>'.
'</d:propstat>'.
'</d:response>', false);
}
public function test_caldav_birthdays_getctag_birthday()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$specialDate = $contact->setSpecialDate('birthdate', 1983, 03, 04);
$specialDate->uuid = Str::uuid();
$specialDate->save();
$response = $this->call('PROPFIND', "/dav/calendars/{$user->email}/birthdays/", [], [], [],
[
'HTTP_DEPTH' => '0',
'content-type' => 'application/xml; charset=utf-8',
],
"<propfind xmlns='DAV:' xmlns:cs='http://calendarserver.org/ns/' xmlns:s='http://sabredav.org/ns'>
<prop>
<cs:getctag />
<sync-token />
<s:sync-token />
</prop>
</propfind>"
);
$response->assertStatus(207);
$response->assertHeader('X-Sabre-Version');
$tokens = SyncToken::where([
'account_id' => $user->account_id,
'user_id' => $user->id,
'name' => 'birthdays',
])->orderBy('created_at')->get();
$this->assertGreaterThan(0, $tokens->count());
$token = $tokens->last();
$response->assertSee('<d:multistatus xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns" xmlns:card="urn:ietf:params:xml:ns:carddav" xmlns:cal="urn:ietf:params:xml:ns:caldav" xmlns:cs="http://calendarserver.org/ns/">', false);
$response->assertSee('<d:response>'.
"<d:href>/dav/calendars/{$user->email}/birthdays/</d:href>".
'<d:propstat>'.
'<d:prop>'.
"<cs:getctag>http://sabre.io/ns/sync/{$token->id}</cs:getctag>".
"<d:sync-token>http://sabre.io/ns/sync/{$token->id}</d:sync-token>".
"<s:sync-token>http://sabre.io/ns/sync/{$token->id}</s:sync-token>".
'</d:prop>'.
'<d:status>HTTP/1.1 200 OK</d:status>'.
'</d:propstat>'.
'</d:response>', false);
}
public function test_caldav_birthdays_sync_collection_with_token()
{
Carbon::setTestNow(Carbon::create(2019, 1, 1, 9, 0, 0));
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$specialDate = $contact->setSpecialDate('birthdate', 1983, 03, 04);
$specialDate->uuid = Str::uuid();
$specialDate->save();
Carbon::setTestNow(Carbon::create(2019, 1, 1, 8, 0, 0));
$token = factory(SyncToken::class)->create([
'account_id' => $user->account_id,
'user_id' => $user->id,
'name' => 'birthdays',
'timestamp' => now(),
]);
$response = $this->call('REPORT', "/dav/calendars/{$user->email}/birthdays/", [], [], [],
[
'content-type' => 'application/xml; charset=utf-8',
],
"<sync-collection xmlns='DAV:'>
<sync-token>http://sabre.io/ns/sync/{$token->id}</sync-token>
<sync-level>1</sync-level>
<prop>
<getetag />
</prop>
</sync-collection>"
);
$response->assertStatus(207);
$token = SyncToken::where([
'account_id' => $user->account_id,
'user_id' => $user->id,
'name' => 'birthdays',
])
->orderBy('created_at')
->get()
->last();
$response->assertSee("<d:multistatus xmlns:d=\"DAV:\" xmlns:s=\"http://sabredav.org/ns\" xmlns:card=\"urn:ietf:params:xml:ns:carddav\" xmlns:cal=\"urn:ietf:params:xml:ns:caldav\" xmlns:cs=\"http://calendarserver.org/ns/\">
<d:response>
<d:href>/dav/calendars/{$user->email}/birthdays/{$specialDate->uuid}.ics</d:href>
<d:propstat>
<d:prop>
<d:getetag>&quot;{$this->getEtag($specialDate)}&quot;</d:getetag>
</d:prop>
<d:status>HTTP/1.1 200 OK</d:status>
</d:propstat>
</d:response>
<d:sync-token>http://sabre.io/ns/sync/{$token->id}</d:sync-token>
</d:multistatus>", false);
}
public function test_caldav_birthdays_sync_collection_init()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$specialDate = $contact->setSpecialDate('birthdate', 1983, 03, 04);
$specialDate->uuid = Str::uuid();
$specialDate->save();
$response = $this->call('REPORT', "/dav/calendars/{$user->email}/birthdays/", [], [], [],
[
'content-type' => 'application/xml; charset=utf-8',
],
"<sync-collection xmlns='DAV:'>
<sync-token />
<sync-level>1</sync-level>
<prop>
<getetag />
</prop>
</sync-collection>"
);
$response->assertStatus(207);
$response->assertHeader('X-Sabre-Version');
$tokens = SyncToken::where([
'account_id' => $user->account_id,
'user_id' => $user->id,
'name' => 'birthdays',
])->orderBy('created_at')->get();
$this->assertGreaterThan(0, $tokens->count());
$token = $tokens->last();
$response->assertSee("<d:multistatus xmlns:d=\"DAV:\" xmlns:s=\"http://sabredav.org/ns\" xmlns:card=\"urn:ietf:params:xml:ns:carddav\" xmlns:cal=\"urn:ietf:params:xml:ns:caldav\" xmlns:cs=\"http://calendarserver.org/ns/\">
<d:response>
<d:href>/dav/calendars/{$user->email}/birthdays/{$specialDate->uuid}.ics</d:href>
<d:propstat>
<d:prop>
<d:getetag>&quot;{$this->getEtag($specialDate)}&quot;</d:getetag>
</d:prop>
<d:status>HTTP/1.1 200 OK</d:status>
</d:propstat>
</d:response>
<d:sync-token>http://sabre.io/ns/sync/{$token->id}</d:sync-token>
</d:multistatus>", false);
}
}

View File

@@ -0,0 +1,303 @@
<?php
namespace Tests\Api\DAV;
use Carbon\Carbon;
use Tests\ApiTestCase;
use App\Models\Contact\Task;
use App\Models\User\SyncToken;
use App\Models\Contact\Contact;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class CalDAVTasksTest extends ApiTestCase
{
use DatabaseTransactions, CardEtag;
/**
* @group dav
*/
public function test_caldav_tasks_propfind()
{
$user = $this->signin();
$task = factory(Task::class)->create([
'account_id' => $user->account_id,
'contact_id' => null,
'created_at' => now(),
'updated_at' => now(),
]);
$response = $this->call('PROPFIND', "/dav/calendars/{$user->email}/tasks");
$response->assertStatus(207);
$response->assertHeader('X-Sabre-Version');
$response->assertSee("<d:response><d:href>/dav/calendars/{$user->email}/tasks/</d:href>", false);
$response->assertSee("<d:response><d:href>/dav/calendars/{$user->email}/tasks/{$task->uuid}.ics</d:href>", false);
}
public function test_caldav_tasks_propfind_with_props()
{
$user = $this->signin();
$response = $this->call('PROPFIND', "/dav/calendars/{$user->email}/tasks/", [], [], [],
[
'HTTP_DEPTH' => 0,
],
'<d:propfind xmlns:d="DAV:">
<d:prop>
<d:displayname />
</d:prop>
</d:propfind>'
);
$response->assertStatus(207);
$response->assertHeader('X-Sabre-Version');
$response->assertSee('<d:multistatus xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns" xmlns:card="urn:ietf:params:xml:ns:carddav" xmlns:cal="urn:ietf:params:xml:ns:caldav" xmlns:cs="http://calendarserver.org/ns/">'.
'<d:response>'.
"<d:href>/dav/calendars/{$user->email}/tasks/</d:href>".
'<d:propstat>'.
'<d:prop>'.
'<d:displayname>Tasks</d:displayname>'.
'</d:prop>'.
'<d:status>HTTP/1.1 200 OK</d:status>'.
'</d:propstat>'.
'</d:response>'.
'</d:multistatus', false);
}
/**
* @group dav
*/
public function test_caldav_tasks_propfind_one_task()
{
$user = $this->signin();
$task = factory(Task::class)->create([
'account_id' => $user->account_id,
'created_at' => now(),
'updated_at' => now(),
]);
$response = $this->call('PROPFIND', "/dav/calendars/{$user->email}/tasks/{$task->uuid}.ics");
$response->assertStatus(207);
$response->assertHeader('X-Sabre-Version');
$response->assertSee("<d:response><d:href>/dav/calendars/{$user->email}/tasks/{$task->uuid}.ics</d:href>", false);
}
public function test_caldav_tasks_getctag()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$task = factory(Task::class)->create([
'account_id' => $user->account_id,
'contact_id' => $contact->id,
]);
$response = $this->call('PROPFIND', "/dav/calendars/{$user->email}/", [], [], [],
[
'HTTP_DEPTH' => '1',
'content-type' => 'application/xml; charset=utf-8',
],
"<propfind xmlns='DAV:' xmlns:cs='http://calendarserver.org/ns/' xmlns:s='http://sabredav.org/ns'>
<prop>
<cs:getctag />
<sync-token />
<s:sync-token />
</prop>
</propfind>"
);
$response->assertStatus(207);
$response->assertHeader('X-Sabre-Version');
$tokens = SyncToken::where([
'account_id' => $user->account_id,
'user_id' => $user->id,
'name' => 'tasks',
])->orderBy('created_at')->get();
$this->assertGreaterThan(0, $tokens->count());
$token = $tokens->last();
$response->assertSee('<d:multistatus xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns" xmlns:card="urn:ietf:params:xml:ns:carddav" xmlns:cal="urn:ietf:params:xml:ns:caldav" xmlns:cs="http://calendarserver.org/ns/">', false);
$response->assertSee('<d:response>'.
"<d:href>/dav/calendars/{$user->email}/tasks/</d:href>".
'<d:propstat>'.
'<d:prop>'.
"<cs:getctag>http://sabre.io/ns/sync/{$token->id}</cs:getctag>".
"<d:sync-token>http://sabre.io/ns/sync/{$token->id}</d:sync-token>".
"<s:sync-token>http://sabre.io/ns/sync/{$token->id}</s:sync-token>".
'</d:prop>'.
'<d:status>HTTP/1.1 200 OK</d:status>'.
'</d:propstat>'.
'</d:response>', false);
}
public function test_caldav_tasks_getctag_task()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$task = factory(Task::class)->create([
'account_id' => $user->account_id,
'contact_id' => $contact->id,
'created_at' => now(),
'updated_at' => now(),
]);
$response = $this->call('PROPFIND', "/dav/calendars/{$user->email}/tasks/", [], [], [],
[
'HTTP_DEPTH' => '0',
'content-type' => 'application/xml; charset=utf-8',
],
"<propfind xmlns='DAV:' xmlns:cs='http://calendarserver.org/ns/' xmlns:s='http://sabredav.org/ns'>
<prop>
<cs:getctag />
<sync-token />
<s:sync-token />
</prop>
</propfind>"
);
$response->assertStatus(207);
$response->assertHeader('X-Sabre-Version');
$tokens = SyncToken::where([
'account_id' => $user->account_id,
'user_id' => $user->id,
'name' => 'tasks',
])->orderBy('created_at')->get();
$this->assertGreaterThan(0, $tokens->count());
$token = $tokens->last();
$response->assertSee('<d:multistatus xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns" xmlns:card="urn:ietf:params:xml:ns:carddav" xmlns:cal="urn:ietf:params:xml:ns:caldav" xmlns:cs="http://calendarserver.org/ns/">', false);
$response->assertSee('<d:response>'.
"<d:href>/dav/calendars/{$user->email}/tasks/</d:href>".
'<d:propstat>'.
'<d:prop>'.
"<cs:getctag>http://sabre.io/ns/sync/{$token->id}</cs:getctag>".
"<d:sync-token>http://sabre.io/ns/sync/{$token->id}</d:sync-token>".
"<s:sync-token>http://sabre.io/ns/sync/{$token->id}</s:sync-token>".
'</d:prop>'.
'<d:status>HTTP/1.1 200 OK</d:status>'.
'</d:propstat>'.
'</d:response>', false);
}
public function test_caldav_tasks_sync_collection_with_token()
{
Carbon::setTestNow(Carbon::create(2019, 1, 1, 9, 0, 0));
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$task = factory(Task::class)->create([
'account_id' => $user->account_id,
'contact_id' => $contact->id,
'created_at' => now(),
'updated_at' => now(),
]);
Carbon::setTestNow(Carbon::create(2019, 1, 1, 8, 0, 0));
$token = factory(SyncToken::class)->create([
'account_id' => $user->account_id,
'user_id' => $user->id,
'name' => 'tasks',
'timestamp' => now(),
]);
$response = $this->call('REPORT', "/dav/calendars/{$user->email}/tasks/", [], [], [],
[
'content-type' => 'application/xml; charset=utf-8',
],
"<sync-collection xmlns='DAV:'>
<sync-token>http://sabre.io/ns/sync/{$token->id}</sync-token>
<sync-level>1</sync-level>
<prop>
<getetag />
</prop>
</sync-collection>"
);
$response->assertStatus(207);
$token = SyncToken::where([
'account_id' => $user->account_id,
'user_id' => $user->id,
'name' => 'tasks',
])
->orderBy('created_at')
->get()
->last();
$response->assertSee("<d:multistatus xmlns:d=\"DAV:\" xmlns:s=\"http://sabredav.org/ns\" xmlns:card=\"urn:ietf:params:xml:ns:carddav\" xmlns:cal=\"urn:ietf:params:xml:ns:caldav\" xmlns:cs=\"http://calendarserver.org/ns/\">
<d:response>
<d:href>/dav/calendars/{$user->email}/tasks/{$task->uuid}.ics</d:href>
<d:propstat>
<d:prop>
<d:getetag>&quot;{$this->getEtag($task)}&quot;</d:getetag>
</d:prop>
<d:status>HTTP/1.1 200 OK</d:status>
</d:propstat>
</d:response>
<d:sync-token>http://sabre.io/ns/sync/{$token->id}</d:sync-token>
</d:multistatus>", false);
}
public function test_caldav_tasks_sync_collection_init()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$task = factory(Task::class)->create([
'account_id' => $user->account_id,
'contact_id' => $contact->id,
'created_at' => now(),
'updated_at' => now(),
]);
$response = $this->call('REPORT', "/dav/calendars/{$user->email}/tasks/", [], [], [],
[
'content-type' => 'application/xml; charset=utf-8',
],
"<sync-collection xmlns='DAV:'>
<sync-token />
<sync-level>1</sync-level>
<prop>
<getetag />
</prop>
</sync-collection>"
);
$response->assertStatus(207);
$response->assertHeader('X-Sabre-Version');
$tokens = SyncToken::where([
'account_id' => $user->account_id,
'user_id' => $user->id,
'name' => 'tasks',
])->orderBy('created_at')->get();
$this->assertGreaterThan(0, $tokens->count());
$token = $tokens->last();
$response->assertSee("<d:multistatus xmlns:d=\"DAV:\" xmlns:s=\"http://sabredav.org/ns\" xmlns:card=\"urn:ietf:params:xml:ns:carddav\" xmlns:cal=\"urn:ietf:params:xml:ns:caldav\" xmlns:cs=\"http://calendarserver.org/ns/\">
<d:response>
<d:href>/dav/calendars/{$user->email}/tasks/{$task->uuid}.ics</d:href>
<d:propstat>
<d:prop>
<d:getetag>&quot;{$this->getEtag($task)}&quot;</d:getetag>
</d:prop>
<d:status>HTTP/1.1 200 OK</d:status>
</d:propstat>
</d:response>
<d:sync-token>http://sabre.io/ns/sync/{$token->id}</d:sync-token>
</d:multistatus>", false);
}
}

View File

@@ -0,0 +1,451 @@
<?php
namespace Tests\Api\DAV;
use Carbon\Carbon;
use Tests\ApiTestCase;
use App\Models\User\SyncToken;
use App\Models\Contact\Contact;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class CardDAVTest extends ApiTestCase
{
use DatabaseTransactions, CardEtag;
/**
* @group dav
*/
public function test_carddav_propfind_addressbooks()
{
$user = $this->signin();
$response = $this->call('PROPFIND', '/dav/addressbooks');
$response->assertStatus(207);
$response->assertHeader('X-Sabre-Version');
$response->assertSee('<d:response><d:href>/dav/addressbooks/</d:href>', false);
$response->assertSee("<d:response><d:href>/dav/addressbooks/{$user->email}/</d:href>", false);
}
/**
* @group dav
*/
public function test_carddav_propfind_addressbooks_user()
{
$user = $this->signin();
$response = $this->call('PROPFIND', "/dav/addressbooks/{$user->email}");
$response->assertStatus(207);
$response->assertHeader('X-Sabre-Version');
$response->assertSee("<d:response><d:href>/dav/addressbooks/{$user->email}/</d:href>", false);
$response->assertSee("<d:response><d:href>/dav/addressbooks/{$user->email}/contacts/</d:href>", false);
}
/**
* @group dav
*/
public function test_carddav_propfind_contacts()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->call('PROPFIND', "/dav/addressbooks/{$user->email}/contacts");
$response->assertStatus(207);
$response->assertHeader('X-Sabre-Version');
$response->assertSee("<d:response><d:href>/dav/addressbooks/{$user->email}/contacts/</d:href>", false);
$contactId = urlencode($contact->uuid);
$response->assertSee("<d:response><d:href>/dav/addressbooks/{$user->email}/contacts/{$contactId}.vcf</d:href>", false);
}
public function test_carddav_propfind_contacts_with_props()
{
$user = $this->signin();
$response = $this->call('PROPFIND', "/dav/addressbooks/{$user->email}/contacts/", [], [], [],
[
'HTTP_DEPTH' => 0,
],
'<d:propfind xmlns:d="DAV:">
<d:prop>
<d:displayname />
</d:prop>
</d:propfind>'
);
$response->assertStatus(207);
$response->assertHeader('X-Sabre-Version');
$response->assertSee('<d:multistatus xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns" xmlns:card="urn:ietf:params:xml:ns:carddav" xmlns:cal="urn:ietf:params:xml:ns:caldav" xmlns:cs="http://calendarserver.org/ns/">'.
'<d:response>'.
"<d:href>/dav/addressbooks/{$user->email}/contacts/</d:href>".
'<d:propstat>'.
'<d:prop>'.
'<d:displayname>Contacts</d:displayname>'.
'</d:prop>'.
'<d:status>HTTP/1.1 200 OK</d:status>'.
'</d:propstat>'.
'</d:response>'.
'</d:multistatus', false);
}
/**
* @group dav
*/
public function test_carddav_propfind_one_contact()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->call('PROPFIND', "/dav/addressbooks/{$user->email}/contacts/{$contact->uuid}.vcf");
$response->assertStatus(207);
$response->assertHeader('X-Sabre-Version');
$response->assertSee("<d:response><d:href>/dav/addressbooks/{$user->email}/contacts/{$contact->uuid}.vcf</d:href>", false);
}
/**
* @group dav
*/
public function test_carddav_propfind_one_contact_without_extension()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->call('PROPFIND', "/dav/addressbooks/{$user->email}/contacts/{$contact->uuid}");
$response->assertStatus(207);
$response->assertHeader('X-Sabre-Version');
$response->assertSee("<d:response><d:href>/dav/addressbooks/{$user->email}/contacts/{$contact->uuid}</d:href>", false);
}
public function test_carddav_getctag()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->call('PROPFIND', "/dav/addressbooks/{$user->email}/", [], [], [],
[
'HTTP_DEPTH' => '1',
'content-type' => 'application/xml; charset=utf-8',
],
"<propfind xmlns='DAV:' xmlns:cs='http://calendarserver.org/ns/'>
<prop>
<cs:getctag />
<sync-token />
</prop>
</propfind>"
);
$response->assertStatus(207);
$response->assertHeader('X-Sabre-Version');
$tokens = SyncToken::where([
'account_id' => $user->account_id,
'user_id' => $user->id,
'name' => 'contacts',
])->orderBy('created_at')->get();
$this->assertGreaterThan(0, $tokens->count());
$token = $tokens->last();
$response->assertSee('<d:multistatus xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns" xmlns:card="urn:ietf:params:xml:ns:carddav" xmlns:cal="urn:ietf:params:xml:ns:caldav" xmlns:cs="http://calendarserver.org/ns/">', false);
$response->assertSee('<d:response>'.
"<d:href>/dav/addressbooks/{$user->email}/contacts/</d:href>".
'<d:propstat>'.
'<d:prop>'.
"<cs:getctag>http://sabre.io/ns/sync/{$token->id}</cs:getctag>".
"<d:sync-token>http://sabre.io/ns/sync/{$token->id}</d:sync-token>".
'</d:prop>'.
'<d:status>HTTP/1.1 200 OK</d:status>'.
'</d:propstat>'.
'</d:response>', false);
}
public function test_carddav_get_me_card()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$user->me_contact_id = $contact->id;
$user->save();
$response = $this->call('PROPFIND', "/dav/addressbooks/{$user->email}", [], [], [],
[
'HTTP_DEPTH' => '1',
'content-type' => 'application/xml; charset=utf-8',
],
"<propfind xmlns='DAV:' xmlns:cs='http://calendarserver.org/ns/'>
<prop>
<cs:me-card />
</prop>
</propfind>"
);
$response->assertStatus(207);
$response->assertHeader('X-Sabre-Version');
$response->assertSee('<d:response>'.
"<d:href>/dav/addressbooks/{$user->email}/contacts/</d:href>".
'<d:propstat>'.
'<d:prop>'.
"<cs:me-card>/dav/addressbooks/{$user->email}/contacts/{$contact->uuid}.vcf</cs:me-card>".
'</d:prop>'.
'<d:status>HTTP/1.1 200 OK</d:status>'.
'</d:propstat>'.
'</d:response>', false);
}
public function test_carddav_set_me_card()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->call('PROPPATCH', "/dav/addressbooks/{$user->email}/contacts", [], [], [],
[
'content-type' => 'application/xml; charset=utf-8',
],
"<propertyupdate xmlns='DAV:' xmlns:cs='http://calendarserver.org/ns/'>
<set>
<prop>
<cs:me-card>
<href>/dav/addressbooks/{$user->email}/contacts/{$contact->uuid}.vcf</href>
</cs:me-card>
</prop>
</set>
</propertyupdate>"
);
$response->assertSee('<d:multistatus xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns" xmlns:card="urn:ietf:params:xml:ns:carddav" xmlns:cal="urn:ietf:params:xml:ns:caldav" xmlns:cs="http://calendarserver.org/ns/">', false);
$response->assertSee('<d:response>'.
"<d:href>/dav/addressbooks/{$user->email}/contacts</d:href>".
'<d:propstat>'.
'<d:prop>'.
'<cs:me-card/>'.
'</d:prop>'.
'<d:status>HTTP/1.1 200 OK</d:status>'.
'</d:propstat>'.
'</d:response>', false);
$this->assertDatabaseHas('users', [
'id' => $user->id,
'me_contact_id' => $contact->id,
]);
}
public function test_carddav_getctag_contacts()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->call('PROPFIND', "/dav/addressbooks/{$user->email}/contacts/", [], [], [],
[
'HTTP_DEPTH' => '0',
'content-type' => 'application/xml; charset=utf-8',
],
"<propfind xmlns='DAV:' xmlns:cs='http://calendarserver.org/ns/'>
<prop>
<cs:getctag />
<sync-token />
</prop>
</propfind>"
);
$response->assertStatus(207);
$response->assertHeader('X-Sabre-Version');
$tokens = SyncToken::where([
'account_id' => $user->account_id,
'user_id' => $user->id,
'name' => 'contacts',
])->orderBy('created_at')->get();
$this->assertGreaterThan(0, $tokens->count());
$token = $tokens->last();
$response->assertSee('<d:multistatus xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns" xmlns:card="urn:ietf:params:xml:ns:carddav" xmlns:cal="urn:ietf:params:xml:ns:caldav" xmlns:cs="http://calendarserver.org/ns/">', false);
$response->assertSee('<d:response>'.
"<d:href>/dav/addressbooks/{$user->email}/contacts/</d:href>".
'<d:propstat>'.
'<d:prop>'.
"<cs:getctag>http://sabre.io/ns/sync/{$token->id}</cs:getctag>".
"<d:sync-token>http://sabre.io/ns/sync/{$token->id}</d:sync-token>".
'</d:prop>'.
'<d:status>HTTP/1.1 200 OK</d:status>'.
'</d:propstat>'.
'</d:response>', false);
}
public function test_carddav_sync_collection_with_token()
{
Carbon::setTestNow(Carbon::create(2019, 1, 1, 9, 0, 0));
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
Carbon::setTestNow(Carbon::create(2018, 1, 1, 8, 0, 0));
$token = factory(SyncToken::class)->create([
'account_id' => $user->account_id,
'user_id' => $user->id,
'name' => 'contacts',
'timestamp' => now(),
]);
$response = $this->call('REPORT', "/dav/addressbooks/{$user->email}/contacts/", [], [], [],
[
'content-type' => 'application/xml; charset=utf-8',
],
"<sync-collection xmlns='DAV:'>
<sync-token>http://sabre.io/ns/sync/{$token->id}</sync-token>
<sync-level>1</sync-level>
<prop>
<getetag />
</prop>
</sync-collection>"
);
$response->assertStatus(207);
$token = SyncToken::where([
'account_id' => $user->account_id,
'user_id' => $user->id,
'name' => 'contacts',
])
->orderBy('created_at')
->get()
->last();
$response->assertSee("<d:multistatus xmlns:d=\"DAV:\" xmlns:s=\"http://sabredav.org/ns\" xmlns:card=\"urn:ietf:params:xml:ns:carddav\" xmlns:cal=\"urn:ietf:params:xml:ns:caldav\" xmlns:cs=\"http://calendarserver.org/ns/\">
<d:response>
<d:href>/dav/addressbooks/{$user->email}/contacts/{$contact->uuid}.vcf</d:href>
<d:propstat>
<d:prop>
<d:getetag>&quot;{$this->getEtag($contact)}&quot;</d:getetag>
</d:prop>
<d:status>HTTP/1.1 200 OK</d:status>
</d:propstat>
</d:response>
<d:sync-token>http://sabre.io/ns/sync/{$token->id}</d:sync-token>
</d:multistatus>", false);
}
public function test_carddav_sync_collection_init()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->call('REPORT', "/dav/addressbooks/{$user->email}/contacts/", [], [], [],
[
'content-type' => 'application/xml; charset=utf-8',
],
"<sync-collection xmlns='DAV:'>
<sync-token />
<sync-level>1</sync-level>
<prop>
<getetag />
</prop>
</sync-collection>"
);
$response->assertStatus(207);
$response->assertHeader('X-Sabre-Version');
$tokens = SyncToken::where([
'account_id' => $user->account_id,
'user_id' => $user->id,
'name' => 'contacts',
])->orderBy('created_at')->get();
$this->assertGreaterThan(0, $tokens->count());
$token = $tokens->last();
$response->assertSee("<d:multistatus xmlns:d=\"DAV:\" xmlns:s=\"http://sabredav.org/ns\" xmlns:card=\"urn:ietf:params:xml:ns:carddav\" xmlns:cal=\"urn:ietf:params:xml:ns:caldav\" xmlns:cs=\"http://calendarserver.org/ns/\">
<d:response>
<d:href>/dav/addressbooks/{$user->email}/contacts/{$contact->uuid}.vcf</d:href>
<d:propstat>
<d:prop>
<d:getetag>&quot;{$this->getEtag($contact)}&quot;</d:getetag>
</d:prop>
<d:status>HTTP/1.1 200 OK</d:status>
</d:propstat>
</d:response>
<d:sync-token>http://sabre.io/ns/sync/{$token->id}</d:sync-token>
</d:multistatus>", false);
}
public function test_carddav_sync_collection_deleted_contact()
{
Carbon::setTestNow(Carbon::create(2019, 1, 1, 9, 0, 0));
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
'deleted_at' => Carbon::create(2019, 3, 1, 9, 0, 0),
]);
Carbon::setTestNow(Carbon::create(2019, 2, 1, 9, 0, 0));
$token = factory(SyncToken::class)->create([
'account_id' => $user->account_id,
'user_id' => $user->id,
'name' => 'contacts',
'timestamp' => now(),
]);
Carbon::setTestNow(Carbon::create(2019, 4, 1, 9, 0, 0));
$response = $this->call('REPORT', "/dav/addressbooks/{$user->email}/contacts/", [], [], [],
[
'content-type' => 'application/xml; charset=utf-8',
],
"<sync-collection xmlns='DAV:'>
<sync-token>http://sabre.io/ns/sync/{$token->id}</sync-token>
<sync-level>1</sync-level>
<prop>
<getetag />
</prop>
</sync-collection>"
);
$response->assertStatus(207);
$token = SyncToken::where([
'account_id' => $user->account_id,
'user_id' => $user->id,
'name' => 'contacts',
])
->orderBy('created_at')
->get()
->last();
$response->assertSee("<d:multistatus xmlns:d=\"DAV:\" xmlns:s=\"http://sabredav.org/ns\" xmlns:card=\"urn:ietf:params:xml:ns:carddav\" xmlns:cal=\"urn:ietf:params:xml:ns:caldav\" xmlns:cs=\"http://calendarserver.org/ns/\">
<d:response>
<d:href>/dav/addressbooks/{$user->email}/contacts/{$contact->uuid}.vcf</d:href>
<d:status>HTTP/1.1 404 Not Found</d:status>
</d:response>
<d:sync-token>http://sabre.io/ns/sync/{$token->id}</d:sync-token>
</d:multistatus>", false);
}
}

176
tests/Api/DAV/CardEtag.php Normal file
View File

@@ -0,0 +1,176 @@
<?php
namespace Tests\Api\DAV;
use App\Models\Contact\Task;
use App\Models\Contact\Contact;
use App\Models\Instance\SpecialDate;
use App\Models\Contact\ContactFieldType;
trait CardEtag
{
protected function getEtag($obj, bool $quotes = false)
{
$data = '';
if ($obj instanceof Contact) {
$data = $this->getCard($obj, true);
} elseif ($obj instanceof SpecialDate) {
$data = $this->getCal($obj, true);
} elseif ($obj instanceof Task) {
$data = $this->getVTodo($obj, true);
}
$etag = sha1($data);
if ($quotes) {
$etag = '"'.$etag.'"';
}
return $etag;
}
protected function getCard(Contact $contact, bool $realFormat = false): string
{
$contact = $contact->refresh();
$url = route('people.show', $contact);
$sabreversion = \Sabre\VObject\Version::VERSION;
$timestamp = $contact->updated_at->format('Ymd\THis\Z');
$data = "BEGIN:VCARD
VERSION:4.0
PRODID:-//Sabre//Sabre VObject {$sabreversion}//EN
UID:{$contact->uuid}
SOURCE:{$url}
FN:{$contact->name}
N:{$contact->last_name};{$contact->first_name};{$contact->middle_name};;
";
if ($contact->gender) {
$data .= "GENDER:{$contact->gender->type}";
$data .= "\n";
}
$picture = $contact->getAvatarURL();
if (! empty($picture)) {
$data .= "PHOTO;VALUE=URI:{$picture}\n";
}
foreach ($contact->addresses as $address) {
$data .= 'ADR:;;';
$data .= $address->place->street.';';
$data .= $address->place->city.';';
$data .= $address->place->province.';';
$data .= $address->place->postal_code.';';
$data .= $address->place->country;
$data .= "\n";
}
foreach ($contact->contactFields as $contactField) {
$type = '';
if ($contactField->labels->count() > 0) {
$type = ';TYPE='.$contactField->labels->map(function ($label) {
return $label->label_i18n ?: $label->label;
})->join(',');
}
switch ($contactField->contactFieldType->type) {
case ContactFieldType::PHONE:
$data .= "TEL$type:{$contactField->data}\n";
break;
case ContactFieldType::EMAIL:
$data .= "EMAIL$type:{$contactField->data}\n";
break;
default:
break;
}
}
$data .= "REV:{$timestamp}\n";
$tags = $contact->getTagsAsString();
if (! empty($tags)) {
$data .= "CATEGORIES:{$tags}\n";
}
$data .= "END:VCARD\n";
if ($realFormat) {
$data = mb_ereg_replace("\n", "\r\n", $data);
}
return $data;
}
protected function getCal(SpecialDate $specialDate, bool $realFormat = false): string
{
$contact = $specialDate->contact;
$url = route('people.show', $contact);
$description = "See {$contact->name}s profile: {$url}";
$description1 = mb_substr($description, 0, 61);
$description2 = mb_substr($description, 61);
$sabreversion = \Sabre\VObject\Version::VERSION;
$timestamp = $specialDate->created_at->format('Ymd\THis\Z');
$start = $specialDate->date->format('Ymd');
$end = $specialDate->date->addDays(1)->format('Ymd');
$data = "BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Sabre//Sabre VObject {$sabreversion}//EN
CALSCALE:GREGORIAN
BEGIN:VTIMEZONE
TZID:UTC
END:VTIMEZONE
BEGIN:VEVENT
UID:{$specialDate->uuid}
DTSTART;VALUE=DATE:{$start}
DTEND;VALUE=DATE:{$end}
RRULE:FREQ=YEARLY
DTSTAMP:{$timestamp}
CREATED:{$timestamp}
SUMMARY:Birthday of {$contact->name}
ATTACH:{$url}
DESCRIPTION:{$description1}
{$description2}
END:VEVENT
END:VCALENDAR
";
if ($realFormat) {
$data = mb_ereg_replace("\n", "\r\n", $data);
}
return $data;
}
protected function getVTodo(Task $task, bool $realFormat = false): string
{
$sabreversion = \Sabre\VObject\Version::VERSION;
$timestamp = $task->created_at->format('Ymd\THis\Z');
$contact = $task->contact;
$data = "BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Sabre//Sabre VObject {$sabreversion}//EN
CALSCALE:GREGORIAN
BEGIN:VTIMEZONE
TZID:UTC
END:VTIMEZONE
BEGIN:VTODO
UID:{$task->uuid}
SUMMARY:{$task->title}
DTSTAMP:{$timestamp}
CREATED:{$timestamp}
DESCRIPTION:{$task->description}
";
if ($contact) {
$url = route('people.show', $contact);
$data .= "ATTACH:{$url}
";
}
$data .= 'END:VTODO
END:VCALENDAR
';
if ($realFormat) {
$data = mb_ereg_replace("\n", "\r\n", $data);
}
return $data;
}
}

View File

@@ -0,0 +1,218 @@
<?php
namespace Tests\Api\DAV;
use Tests\ApiTestCase;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class DAVServerTest extends ApiTestCase
{
use DatabaseTransactions;
/**
* @group dav
*/
public function test_dav_propfind_base()
{
$user = $this->signin();
$response = $this->call('PROPFIND', '/dav');
$response->assertStatus(207);
$response->assertHeader('X-Sabre-Version');
$response->assertSee('<d:response><d:href>/dav/</d:href>', false);
$response->assertSee('<d:response><d:href>/dav/principals/</d:href>', false);
$response->assertSee('<d:response><d:href>/dav/addressbooks/</d:href>', false);
$response->assertSee('<d:response><d:href>/dav/calendars/</d:href>', false);
}
/**
* @group dav
*/
public function test_dav_propfind_principals()
{
$user = $this->signin();
$response = $this->call('PROPFIND', '/dav/principals');
$response->assertStatus(207);
$response->assertHeader('X-Sabre-Version');
$response->assertSee('<d:response><d:href>/dav/principals/</d:href>', false);
$response->assertSee("<d:response><d:href>/dav/principals/{$user->email}/</d:href>", false);
}
/**
* @group dav
*/
public function test_dav_propfind_principals_user()
{
$user = $this->signin();
$response = $this->call('PROPFIND', "/dav/principals/{$user->email}");
$response->assertStatus(207);
$response->assertHeader('X-Sabre-Version');
$response->assertSee("<d:response><d:href>/dav/principals/{$user->email}/</d:href>", false);
}
/**
* @group dav
*/
public function test_dav_ensure_browser_plugin_not_enabled()
{
$user = $this->signin();
$response = $this->call('GET', '/dav');
$response->assertStatus(302);
$response->assertHeader('X-Sabre-Version');
$response->assertHeader('Location', route('settings.dav'));
}
/**
* @group dav
*/
public function test_carddav_propfind_groupmemberset()
{
$user = $this->signin();
$response = $this->call('PROPFIND', "/dav/principals/{$user->email}/", [], [], [],
[
'content-type' => 'application/xml; charset=utf-8',
],
'<propfind xmlns="DAV:"
xmlns:CAL="urn:ietf:params:xml:ns:caldav"
xmlns:CARD="urn:ietf:params:xml:ns:carddav">
<prop>
<CARD:addressbook-home-set />
<group-member-set />
</prop>
</propfind>'
);
$response->assertStatus(207);
$response->assertHeader('X-Sabre-Version');
$response->assertSee('<d:multistatus xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns" xmlns:card="urn:ietf:params:xml:ns:carddav" xmlns:cal="urn:ietf:params:xml:ns:caldav" xmlns:cs="http://calendarserver.org/ns/">'.
'<d:response>'.
"<d:href>/dav/principals/{$user->email}/</d:href>".
'<d:propstat>'.
'<d:prop>'.
'<card:addressbook-home-set>'.
"<d:href>/dav/addressbooks/{$user->email}/</d:href>".
'</card:addressbook-home-set>'.
'<d:group-member-set>'.
"<d:href>/dav/principals/{$user->email}/</d:href>".
'</d:group-member-set>'.
'</d:prop>'.
'<d:status>HTTP/1.1 200 OK</d:status>'.
'</d:propstat>'.
'</d:response>'.
'</d:multistatus>', false);
}
/**
* @group dav
*/
public function test_carddav_report_propertysearch()
{
$user = $this->signin();
$response = $this->call('REPORT', '/dav/principals/', [], [], [],
[
'HTTP_DEPTH' => '0',
'content-type' => 'application/xml; charset=utf-8',
],
"<principal-property-search xmlns=\"DAV:\">
<property-search>
<match>{$user->name}</match>
<prop>
<displayname/>
</prop>
</property-search>
<prop>
<displayname/>
</prop>
</principal-property-search>"
);
$response->assertStatus(207);
$response->assertHeader('X-Sabre-Version');
$response->assertSee('<d:multistatus xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns" xmlns:card="urn:ietf:params:xml:ns:carddav" xmlns:cal="urn:ietf:params:xml:ns:caldav" xmlns:cs="http://calendarserver.org/ns/">'.
'<d:response>'.
"<d:href>/dav/principals/{$user->email}/</d:href>".
'<d:propstat>'.
'<d:prop>'.
"<d:displayname>{$user->name}</d:displayname>".
'</d:prop>'.
'<d:status>HTTP/1.1 200 OK</d:status>'.
'</d:propstat>'.
'</d:response>'.
'</d:multistatus>', false);
}
/**
* @group dav
*/
public function test_caldav_propfind()
{
$user = $this->signin();
$response = $this->call('PROPFIND', '/dav/calendars');
$response->assertStatus(207);
$response->assertHeader('X-Sabre-Version');
$response->assertSee('<d:response><d:href>/dav/calendars/</d:href>', false);
$response->assertSee("<d:response><d:href>/dav/calendars/{$user->email}/</d:href>", false);
}
/**
* @group dav
*/
public function test_caldav_propfind_calendars_user()
{
$user = $this->signin();
$response = $this->call('PROPFIND', "/dav/calendars/{$user->email}");
$response->assertStatus(207);
$response->assertHeader('X-Sabre-Version');
$response->assertSee("<d:response><d:href>/dav/calendars/{$user->email}/</d:href>", false);
$response->assertSee("<d:response><d:href>/dav/calendars/{$user->email}/birthdays/</d:href>", false);
$response->assertSee("<d:response><d:href>/dav/calendars/{$user->email}/tasks/</d:href>", false);
}
/**
* @group dav
*/
public function test_dav_limit_users_unauthorized()
{
$user = $this->signin();
config(['laravelsabre.users' => 'unauthorized']);
$response = $this->call('PROPFIND', '/dav');
$response->assertStatus(403);
}
/**
* @group dav
*/
public function test_dav_limit_users_authorized()
{
$user = $this->signin();
config(['laravelsabre.users' => $user->email]);
$response = $this->call('PROPFIND', '/dav');
$response->assertStatus(207);
}
}

View File

@@ -0,0 +1,494 @@
<?php
namespace Tests\Api\DAV;
use Tests\ApiTestCase;
use Illuminate\Support\Str;
use App\Models\Account\Photo;
use App\Models\Contact\Contact;
use Illuminate\Http\UploadedFile;
use Sabre\VObject\PHPUnitAssertions;
use Intervention\Image\Facades\Image;
use Illuminate\Support\Facades\Storage;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class VCardContactTest extends ApiTestCase
{
use DatabaseTransactions, CardEtag, PHPUnitAssertions;
/**
* @group dav
*/
public function test_carddav_get_one_contact()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->get("/dav/addressbooks/{$user->email}/contacts/{$contact->uuid}.vcf", [
'HTTP_ACCEPT' => 'text/vcard; version=4.0',
]);
$response->assertStatus(200);
$response->assertHeader('X-Sabre-Version');
$this->assertVObjectEqualsVObject($this->getCard($contact, true), $response->getContent());
}
/**
* @group dav
*/
public function test_carddav_put_one_contact()
{
$user = $this->signin();
$response = $this->call('PUT', "/dav/addressbooks/{$user->email}/contacts/single_vcard_stub.vcf", [], [], [],
['content-type' => 'application/xml; charset=utf-8'],
"BEGIN:VCARD\nVERSION:4.0\nFN:John Doe\nN:Doe;John;;;\nEND:VCARD"
);
$response->assertStatus(201);
$response->assertHeader('X-Sabre-Version');
$response->assertHeaderMissing('ETag');
$this->assertDatabaseHas('contacts', [
'account_id' => $user->account_id,
'first_name' => 'John',
'last_name' => 'Doe',
]);
}
/**
* @group dav
*/
public function test_carddav_put_one_contact_with_photo()
{
Storage::fake();
$user = $this->signin();
$image = Image::canvas(1, 1, '#fff')->encode('data-url');
$response = $this->call('PUT', "/dav/addressbooks/{$user->email}/contacts/single_vcard_stub.vcf", [], [], [],
['content-type' => 'application/xml; charset=utf-8'],
"BEGIN:VCARD\nVERSION:4.0\nFN:John Doe\nN:Doe;John;;;\nPHOTO:$image\nEND:VCARD"
);
$response->assertStatus(201);
$response->assertHeader('X-Sabre-Version');
$response->assertHeaderMissing('ETag');
$this->assertDatabaseHas('contacts', [
'account_id' => $user->account_id,
'first_name' => 'John',
'last_name' => 'Doe',
]);
$this->assertDatabaseHas('photos', [
'account_id' => $user->account_id,
]);
$photo = Photo::where(['account_id' => $user->account_id])->first();
Storage::disk('public')->assertExists($photo->new_filename);
}
/**
* @group dav
*/
public function test_carddav_put_one_contact_with_photo_already_set()
{
$user = $this->signin();
$photo = factory(Photo::class)->create([
'account_id' => $user->account_id,
]);
UploadedFile::fake()->image('file.jpg')->storeAs('', 'file.jpg');
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
'avatar_source' => 'photo',
'avatar_photo_id' => $photo->id,
'uuid' => Str::uuid()->toString(),
]);
$image = Image::canvas(1, 1, '#fff')->encode('data-url');
$response = $this->call('PUT', "/dav/addressbooks/{$user->email}/contacts/{$contact->uuid}.vcf", [], [], [],
['content-type' => 'application/xml; charset=utf-8'],
"BEGIN:VCARD\nVERSION:4.0\nFN:John Doe\nN:Doe;John;;;\nPHOTO:$image\nEND:VCARD"
);
$response->assertStatus(204);
$response->assertHeader('X-Sabre-Version');
$response->assertHeaderMissing('ETag');
$this->assertDatabaseHas('contacts', [
'account_id' => $user->account_id,
'first_name' => 'John',
'last_name' => 'Doe',
'avatar_photo_id' => $photo->id,
]);
}
/**
* @group dav
*/
public function test_carddav_put_one_contact_with_photo_and_attributes()
{
Storage::fake();
$user = $this->signin();
$image = base64_encode(Image::canvas(1, 1, '#fff')->encode('jpg'));
$response = $this->call('PUT', "/dav/addressbooks/{$user->email}/contacts/single_vcard_stub.vcf", [], [], [],
['content-type' => 'application/xml; charset=utf-8'],
"BEGIN:VCARD\nVERSION:3.0\nFN:John Doe\nN:Doe;John;;;\nPHOTO;ENCODING=B;TYPE=JPEG:$image\nEND:VCARD"
);
$response->assertStatus(201);
$response->assertHeader('X-Sabre-Version');
$response->assertHeaderMissing('ETag');
$this->assertDatabaseHas('contacts', [
'account_id' => $user->account_id,
'first_name' => 'John',
'last_name' => 'Doe',
]);
$this->assertDatabaseHas('photos', [
'account_id' => $user->account_id,
]);
$photo = Photo::where(['account_id' => $user->account_id])->first();
Storage::disk('public')->assertExists($photo->new_filename);
}
/**
* @group dav
*/
public function test_carddav_update_existing_contact()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->call('PUT', "/dav/addressbooks/{$user->email}/contacts/{$contact->uuid}.vcf", [], [], [],
['content-type' => 'application/xml; charset=utf-8'],
"BEGIN:VCARD\nVERSION:4.0\nFN:John Doex\nN:Doex;John;;;\nEND:VCARD"
);
$response->assertStatus(204);
$response->assertHeader('X-Sabre-Version');
$response->assertHeaderMissing('ETag');
$this->assertDatabaseHas('contacts', [
'account_id' => $user->account_id,
'first_name' => 'John',
'last_name' => 'Doex',
]);
}
/**
* @group dav
*/
public function test_carddav_update_existing_contact_if_modified()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$filename = urlencode($contact->uuid.'.vcf');
$response = $this->call('PUT', "/dav/addressbooks/{$user->email}/contacts/{$filename}", [], [], [],
[
'HTTP_If-Modified-Since' => $contact->updated_at->addDays(-1)->toRfc7231String(),
'content-type' => 'application/xml; charset=utf-8',
],
"BEGIN:VCARD\nVERSION:4.0\nFN:John Doex\nN:Doex;John;;;\nEND:VCARD"
);
$response->assertStatus(204);
$response->assertHeader('X-Sabre-Version');
$response->assertHeaderMissing('ETag');
$this->assertDatabaseHas('contacts', [
'account_id' => $user->account_id,
'first_name' => 'John',
'last_name' => 'Doex',
]);
}
/**
* @group dav
*/
public function test_carddav_update_existing_contact_if_modified_not_modified()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$filename = urlencode($contact->uuid.'.vcf');
$response = $this->call('PUT', "/dav/addressbooks/{$user->email}/contacts/{$filename}", [], [], [],
[
'HTTP_If-Modified-Since' => $contact->updated_at->addDays(1)->toRfc7231String(),
'content-type' => 'application/xml; charset=utf-8',
],
"BEGIN:VCARD\nVERSION:4.0\nFN:John Doex\nN:Doex;John;;;\nEND:VCARD"
);
// Not modified
$response->assertStatus(304);
$response->assertHeader('X-Sabre-Version');
// see http://tools.ietf.org/html/rfc2616#section-10.3.5
$response->assertHeaderMissing('Last-Modified');
$response->assertHeaderMissing('ETag');
}
/**
* @group dav
*/
public function test_carddav_update_existing_contact_if_unmodified()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$filename = urlencode($contact->uuid.'.vcf');
$response = $this->call('PUT', "/dav/addressbooks/{$user->email}/contacts/{$filename}", [], [], [],
[
'HTTP_If-Unmodified-Since' => $contact->updated_at->addDays(1)->toRfc7231String(),
'content-type' => 'application/xml; charset=utf-8',
],
"BEGIN:VCARD\nVERSION:4.0\nFN:John Doex\nN:Doex;John;;;\nEND:VCARD"
);
$response->assertStatus(204);
$response->assertHeader('X-Sabre-Version');
$response->assertHeaderMissing('ETag');
$this->assertDatabaseHas('contacts', [
'account_id' => $user->account_id,
'first_name' => 'John',
'last_name' => 'Doex',
]);
}
/**
* @group dav
*/
public function test_carddav_update_existing_contact_if_unmodified_error()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$filename = urlencode($contact->uuid.'.vcf');
$response = $this->call('PUT', "/dav/addressbooks/{$user->email}/contacts/{$filename}", [], [], [],
[
'HTTP_If-Unmodified-Since' => $contact->updated_at->addDays(-1)->toRfc7231String(),
'content-type' => 'application/xml; charset=utf-8',
],
"BEGIN:VCARD\nVERSION:4.0\nFN:John Doex\nN:Doex;John;;;\nEND:VCARD"
);
// PRECONDITION FAILED
$response->assertStatus(412);
$response->assertHeader('X-Sabre-Version');
$sabreversion = \Sabre\DAV\Version::VERSION;
$response->assertSee("<d:error xmlns:d=\"DAV:\" xmlns:s=\"http://sabredav.org/ns\">
<s:sabredav-version>{$sabreversion}</s:sabredav-version>
<s:exception>Sabre\DAV\Exception\PreconditionFailed</s:exception>
<s:message>An If-Unmodified-Since header was specified, but the entity has been changed since the specified date.</s:message>", false);
}
/**
* @group dav
*/
public function test_carddav_update_existing_contact_no_modify()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$filename = urlencode($contact->uuid.'.vcf');
$response = $this->get("/dav/addressbooks/{$user->email}/contacts/{$filename}");
$data = $response->getContent();
$response = $this->call('PUT', "/dav/addressbooks/{$user->email}/contacts/{$filename}", [], [], [],
['content-type' => 'application/xml; charset=utf-8'],
$data
);
$response->assertStatus(204);
$response->assertHeader('X-Sabre-Version');
//$response->assertHeader('ETag'); // etag no more sent
}
public function test_carddav_contacts_report_version4()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->call('REPORT', "/dav/addressbooks/{$user->email}/contacts/", [], [], [],
[
'HTTP_DEPTH' => '1',
'content-type' => 'application/xml; charset=utf-8',
],
'<card:addressbook-query xmlns:d="DAV:" xmlns:card="urn:ietf:params:xml:ns:carddav">
<d:prop>
<d:getetag />
<card:address-data content-type="text/vcard" version="4.0" />
</d:prop>
</card:addressbook-query>'
);
$response->assertStatus(207);
$response->assertHeader('X-Sabre-Version');
$vcard = mb_ereg_replace("\n", "&#13;\n", $this->getCard($contact));
$response->assertSee('<d:multistatus xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns" xmlns:card="urn:ietf:params:xml:ns:carddav" xmlns:cal="urn:ietf:params:xml:ns:caldav" xmlns:cs="http://calendarserver.org/ns/">'.
'<d:response>'.
"<d:href>/dav/addressbooks/{$user->email}/contacts/{$contact->uuid}.vcf</d:href>".
'<d:propstat>'.
'<d:prop>'.
"<d:getetag>&quot;{$this->getEtag($contact)}&quot;</d:getetag>".
"<card:address-data>{$vcard}</card:address-data>".
'</d:prop>'.
'<d:status>HTTP/1.1 200 OK</d:status>'.
'</d:propstat>'.
'</d:response>'.
'</d:multistatus>', false);
}
public function test_carddav_contacts_report_version3()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->call('REPORT', "/dav/addressbooks/{$user->email}/contacts/", [], [], [],
[
'HTTP_DEPTH' => '1',
'content-type' => 'application/xml; charset=utf-8',
],
'<card:addressbook-query xmlns:d="DAV:" xmlns:card="urn:ietf:params:xml:ns:carddav">
<d:prop>
<d:getetag />
<card:address-data content-type="text/vcard" version="3.0" />
</d:prop>
</card:addressbook-query>'
);
$response->assertStatus(207);
$response->assertHeader('X-Sabre-Version');
$vcard = mb_ereg_replace('VERSION:4.0', 'VERSION:3.0', $this->getCard($contact));
$vcard = mb_ereg_replace("\n", "&#13;\n", $vcard);
$response->assertSee('<d:multistatus xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns" xmlns:card="urn:ietf:params:xml:ns:carddav" xmlns:cal="urn:ietf:params:xml:ns:caldav" xmlns:cs="http://calendarserver.org/ns/">'.
'<d:response>'.
"<d:href>/dav/addressbooks/{$user->email}/contacts/{$contact->uuid}.vcf</d:href>".
'<d:propstat>'.
'<d:prop>'.
"<d:getetag>&quot;{$this->getEtag($contact)}&quot;</d:getetag>".
"<card:address-data>{$vcard}</card:address-data>".
'</d:prop>'.
'<d:status>HTTP/1.1 200 OK</d:status>'.
'</d:propstat>'.
'</d:response>'.
'</d:multistatus>', false);
}
public function test_carddav_contacts_report_multiget()
{
$user = $this->signin();
$contact1 = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$contact2 = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->call('REPORT', "/dav/addressbooks/{$user->email}/contacts/", [], [], [],
[
'HTTP_DEPTH' => '1',
],
"<card:addressbook-multiget xmlns:d=\"DAV:\" xmlns:card=\"urn:ietf:params:xml:ns:carddav\">
<d:prop>
<d:getetag />
<card:address-data content-type=\"text/vcard\" version=\"4.0\" />
</d:prop>
<d:href>/dav/addressbooks/{$user->email}/contacts/{$contact1->uuid}.vcf</d:href>
<d:href>/dav/addressbooks/{$user->email}/contacts/{$contact2->uuid}.vcf</d:href>
</card:addressbook-multiget>"
);
$response->assertStatus(207);
$response->assertHeader('X-Sabre-Version');
$vcard1 = mb_ereg_replace("\n", "&#13;\n", $this->getCard($contact1));
$vcard2 = mb_ereg_replace("\n", "&#13;\n", $this->getCard($contact2));
$response->assertSee('<d:multistatus xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns" xmlns:card="urn:ietf:params:xml:ns:carddav" xmlns:cal="urn:ietf:params:xml:ns:caldav" xmlns:cs="http://calendarserver.org/ns/">'.
'<d:response>'.
"<d:href>/dav/addressbooks/{$user->email}/contacts/{$contact1->uuid}.vcf</d:href>".
'<d:propstat>'.
'<d:prop>'.
"<d:getetag>&quot;{$this->getEtag($contact1)}&quot;</d:getetag>".
"<card:address-data>{$vcard1}</card:address-data>".
'</d:prop>'.
'<d:status>HTTP/1.1 200 OK</d:status>'.
'</d:propstat>'.
'</d:response>', false);
$response->assertSee(
'<d:response>'.
"<d:href>/dav/addressbooks/{$user->email}/contacts/{$contact2->uuid}.vcf</d:href>".
'<d:propstat>'.
'<d:prop>'.
"<d:getetag>&quot;{$this->getEtag($contact2)}&quot;</d:getetag>".
"<card:address-data>{$vcard2}</card:address-data>".
'</d:prop>'.
'<d:status>HTTP/1.1 200 OK</d:status>'.
'</d:propstat>'.
'</d:response>'.
'</d:multistatus>', false);
}
/**
* @group dav
* @test
*/
public function carddav_delete_one_contact()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$response = $this->call('DELETE', "/dav/addressbooks/{$user->email}/contacts/{$contact->uuid}.vcf");
$response->assertStatus(204);
$response->assertHeader('X-Sabre-Version');
$response->assertHeaderMissing('ETag');
$this->assertDatabaseMissing('contacts', [
'account_id' => $user->account_id,
'id' => $contact->id,
'deleted_at' => null,
]);
}
}

View File

@@ -0,0 +1,138 @@
<?php
namespace Tests\Api\DAV;
use Tests\ApiTestCase;
use Illuminate\Support\Str;
use App\Models\Contact\Contact;
use Sabre\VObject\PHPUnitAssertions;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class VEventBirthdayTest extends ApiTestCase
{
use DatabaseTransactions, CardEtag, PHPUnitAssertions;
/**
* @group dav
*/
public function test_caldav_get_one_birthday()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$specialDate = $contact->setSpecialDate('birthdate', 1983, 03, 04);
$specialDate->uuid = Str::uuid();
$specialDate->save();
$response = $this->get("/dav/calendars/{$user->email}/birthdays/{$specialDate->uuid}.ics");
$response->assertStatus(200);
$response->assertHeader('X-Sabre-Version');
$this->assertVObjectEqualsVObject($this->getCal($specialDate, true), $response->getContent() ?: $response->streamedContent());
}
public function test_caldav_birthdays_report()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$specialDate = $contact->setSpecialDate('birthdate', 1983, 03, 04);
$specialDate->uuid = Str::uuid();
$specialDate->save();
$response = $this->call('REPORT', "/dav/calendars/{$user->email}/birthdays/", [], [], [],
[
'HTTP_DEPTH' => '1',
'content-type' => 'application/xml; charset=utf-8',
],
'<cal:calendar-query xmlns:d="DAV:" xmlns:cal="urn:ietf:params:xml:ns:caldav">
<d:prop>
<d:getetag />
<cal:calendar-data content-type="text/calendar" version="2.0" />
</d:prop>
<cal:filter>
<cal:comp-filter name="VCALENDAR" />
</cal:filter>
</cal:calendar-query>'
);
$response->assertStatus(207);
$response->assertHeader('X-Sabre-Version');
$response->assertSee('<d:multistatus xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns" xmlns:card="urn:ietf:params:xml:ns:carddav" xmlns:cal="urn:ietf:params:xml:ns:caldav" xmlns:cs="http://calendarserver.org/ns/">'.
'<d:response>'.
"<d:href>/dav/calendars/{$user->email}/birthdays/{$specialDate->uuid}.ics</d:href>".
'<d:propstat>'.
'<d:prop>'.
"<d:getetag>&quot;{$this->getEtag($specialDate)}&quot;</d:getetag>".
"<cal:calendar-data>{$this->getCal($specialDate)}</cal:calendar-data>".
'</d:prop>'.
'<d:status>HTTP/1.1 200 OK</d:status>'.
'</d:propstat>'.
'</d:response>'.
'</d:multistatus>', false);
}
public function test_caldav_birthdays_report_multiget()
{
$user = $this->signin();
$contact1 = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$specialDate1 = $contact1->setSpecialDate('birthdate', 1983, 03, 04);
$specialDate1->uuid = Str::uuid();
$specialDate1->save();
$contact2 = factory(Contact::class)->create([
'account_id' => $user->account_id,
'firstname' => 'Jane',
]);
$specialDate2 = $contact2->setSpecialDate('birthdate', 1980, 05, 01);
$specialDate2->uuid = Str::uuid();
$specialDate2->save();
$response = $this->call('REPORT', "/dav/calendars/{$user->email}/birthdays/", [], [], [],
[
'HTTP_DEPTH' => '1',
],
"<cal:calendar-multiget xmlns:d=\"DAV:\" xmlns:cal=\"urn:ietf:params:xml:ns:caldav\">
<d:prop>
<d:getetag />
<cal:calendar-data content-type=\"text/calendar\" version=\"2.0\" />
</d:prop>
<d:href>/dav/calendars/{$user->email}/birthdays/{$specialDate1->uuid}.ics</d:href>
<d:href>/dav/calendars/{$user->email}/birthdays/{$specialDate2->uuid}.ics</d:href>
</cal:calendar-multiget>"
);
$response->assertStatus(207);
$response->assertHeader('X-Sabre-Version');
$response->assertSee('<d:multistatus xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns" xmlns:card="urn:ietf:params:xml:ns:carddav" xmlns:cal="urn:ietf:params:xml:ns:caldav" xmlns:cs="http://calendarserver.org/ns/">'.
'<d:response>'.
"<d:href>/dav/calendars/{$user->email}/birthdays/{$specialDate1->uuid}.ics</d:href>".
'<d:propstat>'.
'<d:prop>'.
"<d:getetag>&quot;{$this->getEtag($specialDate1)}&quot;</d:getetag>".
"<cal:calendar-data>{$this->getCal($specialDate1)}</cal:calendar-data>".
'</d:prop>'.
'<d:status>HTTP/1.1 200 OK</d:status>'.
'</d:propstat>'.
'</d:response>', false);
$response->assertSee(
'<d:response>'.
"<d:href>/dav/calendars/{$user->email}/birthdays/{$specialDate2->uuid}.ics</d:href>".
'<d:propstat>'.
'<d:prop>'.
"<d:getetag>&quot;{$this->getEtag($specialDate2)}&quot;</d:getetag>".
"<cal:calendar-data>{$this->getCal($specialDate2)}</cal:calendar-data>".
'</d:prop>'.
'<d:status>HTTP/1.1 200 OK</d:status>'.
'</d:propstat>'.
'</d:response>'.
'</d:multistatus>', false);
}
}

View File

@@ -0,0 +1,244 @@
<?php
namespace Tests\Api\DAV;
use Carbon\Carbon;
use Tests\ApiTestCase;
use Illuminate\Support\Str;
use App\Models\Contact\Task;
use App\Models\Contact\Contact;
use Sabre\VObject\PHPUnitAssertions;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class VTodoTaskTest extends ApiTestCase
{
use DatabaseTransactions, CardEtag, PHPUnitAssertions;
/**
* @group dav
*/
public function test_caldav_get_one_task()
{
$user = $this->signin();
$task = factory(Task::class)->create([
'account_id' => $user->account_id,
'contact_id' => null,
'created_at' => now(),
'updated_at' => now(),
]);
$response = $this->get("/dav/calendars/{$user->email}/tasks/{$task->uuid}.ics");
$response->assertStatus(200);
$response->assertHeader('X-Sabre-Version');
$this->assertVObjectEqualsVObject($this->getVTodo($task, true), $response->getContent() ?: $response->streamedContent());
}
/**
* @group dav
*/
public function test_caldav_put_one_task()
{
$user = $this->signin();
$uuid = Str::uuid();
$response = $this->call('PUT', "/dav/calendars/{$user->email}/tasks/{$uuid->toString()}.ics", [], [], [],
['content-type' => 'application/xml; charset=utf-8'],
"BEGIN:VCALENDAR
BEGIN:VTODO
UID:{$uuid->toString()}
SUMMARY:title
DESCRIPTION:description
END:VTODO
END:VCALENDAR
"
);
$response->assertStatus(201);
$response->assertHeader('X-Sabre-Version');
$response->assertHeaderMissing('ETag');
$this->assertDatabaseHas('tasks', [
'account_id' => $user->account_id,
'contact_id' => null,
'uuid' => $uuid,
'title' => 'title',
'description' => 'description',
]);
}
/**
* @group dav
*/
public function test_caldav_update_existing_task()
{
$user = $this->signin();
$task = factory(Task::class)->create([
'account_id' => $user->account_id,
'contact_id' => null,
]);
$response = $this->call('PUT', "/dav/calendars/{$user->email}/tasks/{$task->uuid}.ics", [], [], [],
['content-type' => 'application/xml; charset=utf-8'],
"BEGIN:VCALENDAR
BEGIN:VTODO
UID:{$task->uuid}
SUMMARY:new title
DESCRIPTION:new description
END:VTODO
END:VCALENDAR
"
);
$response->assertStatus(204);
$response->assertHeader('X-Sabre-Version');
$response->assertHeaderMissing('ETag');
$this->assertDatabaseHas('tasks', [
'account_id' => $user->account_id,
'uuid' => $task->uuid,
'title' => 'new title',
'description' => 'new description',
]);
}
/**
* @group dav
*/
public function test_caldav_update_task_complete()
{
$user = $this->signin();
$task = factory(Task::class)->create([
'account_id' => $user->account_id,
'contact_id' => null,
]);
$response = $this->call('PUT', "/dav/calendars/{$user->email}/tasks/{$task->uuid}.ics", [], [], [],
['content-type' => 'application/xml; charset=utf-8'],
"BEGIN:VCALENDAR
BEGIN:VTODO
UID:{$task->uuid}
SUMMARY:{$task->title}
DESCRIPTION:{$task->description}
STATUS:COMPLETED
COMPLETED:20190121T182800Z
END:VTODO
END:VCALENDAR
"
);
$response->assertStatus(204);
$response->assertHeader('X-Sabre-Version');
$response->assertHeaderMissing('ETag');
$this->assertDatabaseHas('tasks', [
'account_id' => $user->account_id,
'uuid' => $task->uuid,
'completed' => true,
'completed_at' => Carbon::create(2019, 01, 21, 18, 28, 00),
]);
}
public function test_caldav_tasks_report()
{
$user = $this->signin();
$contact = factory(Contact::class)->create([
'account_id' => $user->account_id,
]);
$task = factory(Task::class)->create([
'account_id' => $user->account_id,
'created_at' => now(),
]);
$response = $this->call('REPORT', "/dav/calendars/{$user->email}/tasks/", [], [], [],
[
'HTTP_DEPTH' => '1',
'content-type' => 'application/xml; charset=utf-8',
],
'<cal:calendar-query xmlns:d="DAV:" xmlns:cal="urn:ietf:params:xml:ns:caldav">
<d:prop>
<d:getetag />
<cal:calendar-data content-type="text/calendar" version="2.0" />
</d:prop>
<cal:filter>
<cal:comp-filter name="VCALENDAR" />
</cal:filter>
</cal:calendar-query>'
);
$response->assertStatus(207);
$response->assertHeader('X-Sabre-Version');
$peopleurl = route('people.show', $contact);
$sabreversion = \Sabre\VObject\Version::VERSION;
$response->assertSee('<d:multistatus xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns" xmlns:card="urn:ietf:params:xml:ns:carddav" xmlns:cal="urn:ietf:params:xml:ns:caldav" xmlns:cs="http://calendarserver.org/ns/">'.
'<d:response>'.
"<d:href>/dav/calendars/{$user->email}/tasks/{$task->uuid}.ics</d:href>".
'<d:propstat>'.
'<d:prop>'.
"<d:getetag>&quot;{$this->getEtag($task)}&quot;</d:getetag>".
"<cal:calendar-data>{$this->getVTodo($task)}</cal:calendar-data>".
'</d:prop>'.
'<d:status>HTTP/1.1 200 OK</d:status>'.
'</d:propstat>'.
'</d:response>'.
'</d:multistatus>', false);
}
public function test_caldav_tasks_report_multiget()
{
$user = $this->signin();
$task1 = factory(Task::class)->create([
'account_id' => $user->account_id,
'created_at' => now(),
]);
$task2 = factory(Task::class)->create([
'account_id' => $user->account_id,
'created_at' => now(),
]);
$response = $this->call('REPORT', "/dav/calendars/{$user->email}/tasks/", [], [], [],
[
'HTTP_DEPTH' => '1',
],
"<cal:calendar-multiget xmlns:d=\"DAV:\" xmlns:cal=\"urn:ietf:params:xml:ns:caldav\">
<d:prop>
<d:getetag />
<cal:calendar-data content-type=\"text/calendar\" version=\"2.0\" />
</d:prop>
<d:href>/dav/calendars/{$user->email}/tasks/{$task1->uuid}.ics</d:href>
<d:href>/dav/calendars/{$user->email}/tasks/{$task2->uuid}.ics</d:href>
</cal:calendar-multiget>"
);
$response->assertStatus(207);
$response->assertHeader('X-Sabre-Version');
$response->assertSee('<d:multistatus xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns" xmlns:card="urn:ietf:params:xml:ns:carddav" xmlns:cal="urn:ietf:params:xml:ns:caldav" xmlns:cs="http://calendarserver.org/ns/">'.
'<d:response>'.
"<d:href>/dav/calendars/{$user->email}/tasks/{$task1->uuid}.ics</d:href>".
'<d:propstat>'.
'<d:prop>'.
"<d:getetag>&quot;{$this->getEtag($task1)}&quot;</d:getetag>".
"<cal:calendar-data>{$this->getVTodo($task1)}</cal:calendar-data>".
'</d:prop>'.
'<d:status>HTTP/1.1 200 OK</d:status>'.
'</d:propstat>'.
'</d:response>', false);
$response->assertSee(
'<d:response>'.
"<d:href>/dav/calendars/{$user->email}/tasks/{$task2->uuid}.ics</d:href>".
'<d:propstat>'.
'<d:prop>'.
"<d:getetag>&quot;{$this->getEtag($task2)}&quot;</d:getetag>".
"<cal:calendar-data>{$this->getVTodo($task2)}</cal:calendar-data>".
'</d:prop>'.
'<d:status>HTTP/1.1 200 OK</d:status>'.
'</d:propstat>'.
'</d:response>'.
'</d:multistatus>', false);
}
}

View File

@@ -0,0 +1,75 @@
<?php
namespace Tests\Api\Settings;
use Tests\ApiTestCase;
use App\Models\Instance\AuditLog;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class ApiAuditLogControllerTest extends ApiTestCase
{
use DatabaseTransactions;
protected $jsonStructureAuditLog = [
'id',
'object',
'author' => [
'name',
],
'action',
'objects',
'audited_at',
'created_at',
'updated_at',
];
/** @test */
public function it_gets_a_list_of_audit_logs()
{
$user = $this->signin();
factory(AuditLog::class, 10)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('GET', '/api/logs');
$response->assertStatus(200);
$response->assertJsonStructure([
'data' => ['*' => $this->jsonStructureAuditLog],
]);
$this->assertCount(
10,
$response->decodeResponseJson()['data']
);
$response->assertJsonFragment([
'total' => 10,
'current_page' => 1,
]);
}
/** @test */
public function it_is_possible_to_get_audit_logs_and_limit_query_and_paginate()
{
$user = $this->signin();
factory(AuditLog::class, 10)->create([
'account_id' => $user->account_id,
]);
$response = $this->json('GET', '/api/logs?limit=1&page=2');
$response->assertStatus(200);
$response->assertJsonStructure([
'data' => ['*' => $this->jsonStructureAuditLog],
]);
$response->assertJsonFragment([
'total' => 10,
'per_page' => 1,
'current_page' => 2,
]);
}
}

View File

@@ -0,0 +1,91 @@
<?php
namespace Tests\Api\Settings;
use Tests\ApiTestCase;
use App\Models\Settings\Term;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class ApiComplianceControllerTest extends ApiTestCase
{
use DatabaseTransactions;
protected $jsonStructureCompliance = [
'id',
'object',
'term_version',
'term_content',
'privacy_version',
'privacy_content',
'created_at',
'updated_at',
];
/** @test */
public function it_gets_a_list_of_terms()
{
$term = factory(Term::class, 10)->create([
'term_version' => rand(1, 100),
'term_content' => 'dummy data',
'privacy_version' => rand(1, 100),
'privacy_content' => 'dummy data',
]);
$response = $this->json('GET', '/api/compliance/');
$response->assertStatus(200);
$this->assertCount(
Term::get()->count(),
$response->decodeResponseJson()['data']
);
$response->assertJsonFragment([
'total' => Term::get()->count(),
'current_page' => 1,
]);
$response->assertJsonStructure([
'data' => [
'*' => $this->jsonStructureCompliance,
],
]);
}
/** @test */
public function it_gets_a_single_term()
{
$term = factory(Term::class)->create([
'term_version' => rand(1, 100),
'term_content' => 'dummy data',
'privacy_version' => rand(1, 100),
'privacy_content' => 'dummy data',
]);
$response = $this->json('GET', '/api/compliance/'.$term->id);
$response->assertStatus(200);
$response->assertJsonFragment([
'id' => $term->id,
'object' => 'term',
]);
$response->assertJsonStructure([
'data' => $this->jsonStructureCompliance,
]);
}
/** @test */
public function it_doesnt_get_a_single_term()
{
$response = $this->json('GET', '/api/compliance/3');
$response->assertStatus(404);
$response->assertJsonFragment([
'message' => 'The resource has not been found',
'error_code' => 31,
]);
}
}

View File

@@ -0,0 +1,70 @@
<?php
namespace Tests\Api\Settings;
use Tests\ApiTestCase;
use App\Models\Settings\Currency;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class ApiCurrencyControllerTest extends ApiTestCase
{
use DatabaseTransactions;
protected $jsonStructureCurrency = [
'id',
'object',
'iso',
'name',
'symbol',
];
/** @test */
public function it_gets_all_the_currencies()
{
// in theory the currencies table is seeded by the initial script
$response = $this->json('GET', '/api/currencies/');
$response->assertStatus(200);
$this->assertCount(
15,
$response->decodeResponseJson()['data']
);
$response->assertJsonFragment([
'total' => 153,
'current_page' => 1,
]);
$response->assertJsonStructure([
'data' => ['*' => $this->jsonStructureCurrency],
]);
}
/** @test */
public function it_gets_one_currency()
{
$currency = factory(Currency::class)->create([]);
$response = $this->json('GET', '/api/currencies/'.$currency->id);
$response->assertStatus(200);
$response->assertJsonFragment([
'id' => $currency->id,
'object' => 'currency',
]);
$response->assertJsonStructure([
'data' => $this->jsonStructureCurrency,
]);
}
/** @test */
public function it_gets_a_currency_that_is_invalid()
{
$response = $this->json('GET', '/api/currencies/0');
$this->expectNotFound($response);
}
}