From 6cda9f290096c47dd2ecef92c6d20fd2a11c53f7 Mon Sep 17 00:00:00 2001 From: James Cole Date: Sat, 17 Feb 2018 19:56:45 +0100 Subject: [PATCH] Expand tests for account API. --- app/Api/V1/Controllers/AccountController.php | 10 +- .../V1/Controllers/AccountControllerTest.php | 352 ++++++++++++++++++ 2 files changed, 357 insertions(+), 5 deletions(-) diff --git a/app/Api/V1/Controllers/AccountController.php b/app/Api/V1/Controllers/AccountController.php index 40ed973b92..d1f76c53c8 100644 --- a/app/Api/V1/Controllers/AccountController.php +++ b/app/Api/V1/Controllers/AccountController.php @@ -154,8 +154,8 @@ class AccountController extends Controller $data = $request->getAll(); // if currency ID is 0, find the currency by the code: if ($data['currency_id'] === 0) { - $currency = $this->currencyRepository->findByCode($data['currency_code']); - $data['currency_id'] = $currency->id; + $currency = $this->currencyRepository->findByCodeNull($data['currency_code']); + $data['currency_id'] = is_null($currency) ? 0 : $currency->id; } $account = $this->repository->store($data); $manager = new Manager(); @@ -179,8 +179,8 @@ class AccountController extends Controller $data = $request->getAll(); // if currency ID is 0, find the currency by the code: if ($data['currency_id'] === 0) { - $currency = $this->currencyRepository->findByCode($data['currency_code']); - $data['currency_id'] = $currency->id; + $currency = $this->currencyRepository->findByCodeNull($data['currency_code']); + $data['currency_id'] = is_null($currency) ? 0 : $currency->id; } // set correct type: $data['type'] = config('firefly.shortNamesByFullName.' . $account->accountType->type); @@ -256,6 +256,6 @@ class AccountController extends Controller return $types[$type]; } - return $types['all']; + return $types['all']; // @codeCoverageIgnore } } \ No newline at end of file diff --git a/tests/Api/V1/Controllers/AccountControllerTest.php b/tests/Api/V1/Controllers/AccountControllerTest.php index 1dfb8489c8..1e194fab59 100644 --- a/tests/Api/V1/Controllers/AccountControllerTest.php +++ b/tests/Api/V1/Controllers/AccountControllerTest.php @@ -23,7 +23,9 @@ declare(strict_types=1); namespace Tests\Api\V1\Controllers; +use FireflyIII\Api\V1\Requests\AccountRequest; use FireflyIII\Models\Account; +use FireflyIII\Models\TransactionCurrency; use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface; use Laravel\Passport\Passport; @@ -70,6 +72,7 @@ class AccountControllerTest extends TestCase /** * @covers \FireflyIII\Api\V1\Controllers\AccountController::__construct * @covers \FireflyIII\Api\V1\Controllers\AccountController::index + * @covers \FireflyIII\Api\V1\Controllers\AccountController::mapTypes */ public function testIndex() { @@ -97,5 +100,354 @@ class AccountControllerTest extends TestCase $response->assertHeader('Content-Type', 'application/vnd.api+json'); } + /** + * Opening balance without date. + * + * @covers \FireflyIII\Api\V1\Controllers\AccountController::store + * @covers \FireflyIII\Api\V1\Requests\AccountRequest::authorize + * @covers \FireflyIII\Api\V1\Requests\AccountRequest::rules + * @covers \FireflyIII\Api\V1\Requests\AccountRequest::getAll + */ + public function testInvalidBalance() + { + // mock repositories + $repository = $this->mock(AccountRepositoryInterface::class); + $currencyRepos = $this->mock(CurrencyRepositoryInterface::class); + + // mock calls: + $repository->shouldReceive('setUser')->once(); + $currencyRepos->shouldReceive('setUser')->once(); + + // data to submit + $data = [ + 'name' => 'Some new asset account #' . rand(1, 10000), + 'currency_id' => 1, + 'type' => 'asset', + 'active' => 1, + 'account_role' => 'defaultAsset', + 'opening_balance' => '123.45', + ]; + + // test API + $response = $this->post('/api/v1/accounts', $data, ['Accept' => 'application/json']); + $response->assertStatus(422); + $response->assertExactJson( + [ + 'message' => 'The given data was invalid.', + 'errors' => [ + 'opening_balance_date' => ['The opening balance date field is required when opening balance is present.'], + ], + ] + ); + $response->assertHeader('Content-Type', 'application/json'); + } + + /** + * CC type present when account is a credit card. + * + * @covers \FireflyIII\Api\V1\Controllers\AccountController::store + * @covers \FireflyIII\Api\V1\Requests\AccountRequest::authorize + * @covers \FireflyIII\Api\V1\Requests\AccountRequest::rules + * @covers \FireflyIII\Api\V1\Requests\AccountRequest::getAll + */ + public function testNoCreditCardData() + { + // mock repositories + $repository = $this->mock(AccountRepositoryInterface::class); + $currencyRepos = $this->mock(CurrencyRepositoryInterface::class); + + // mock calls: + $repository->shouldReceive('setUser')->once(); + $currencyRepos->shouldReceive('setUser')->once(); + + // data to submit + $data = [ + 'name' => 'Some new asset account #' . rand(1, 10000), + 'type' => 'asset', + 'active' => 1, + 'account_role' => 'ccAsset', + 'currency_id' => 1, + ]; + + // test API + $response = $this->post('/api/v1/accounts', $data, ['Accept' => 'application/json']); + $response->assertStatus(422); + $response->assertExactJson( + [ + 'message' => 'The given data was invalid.', + 'errors' => [ + 'cc_monthly_payment_date' => ['The cc monthly payment date field is required when account role is ccAsset.'], + 'cc_type' => ['The cc type field is required when account role is ccAsset.'], + ], + ] + ); + $response->assertHeader('Content-Type', 'application/json'); + } + + /** + * No currency information + * + * @covers \FireflyIII\Api\V1\Controllers\AccountController::store + * @covers \FireflyIII\Api\V1\Requests\AccountRequest::authorize + * @covers \FireflyIII\Api\V1\Requests\AccountRequest::rules + * @covers \FireflyIII\Api\V1\Requests\AccountRequest::getAll + */ + public function testNoCurrencyInfo() + { + // mock repositories + $repository = $this->mock(AccountRepositoryInterface::class); + $currencyRepos = $this->mock(CurrencyRepositoryInterface::class); + + // mock calls: + $repository->shouldReceive('setUser')->once(); + $currencyRepos->shouldReceive('setUser')->once(); + + // data to submit + $data = [ + 'name' => 'Some new asset account #' . rand(1, 10000), + 'type' => 'asset', + 'active' => 1, + 'account_role' => 'defaultAsset', + ]; + + // test API + $response = $this->post('/api/v1/accounts', $data, ['Accept' => 'application/json']); + $response->assertStatus(422); + $response->assertExactJson( + [ + 'message' => 'The given data was invalid.', + 'errors' => [ + 'currency_code' => ['The currency code field is required when currency id is not present.'], + 'currency_id' => ['The currency id field is required when currency code is not present.'], + ], + ] + ); + $response->assertHeader('Content-Type', 'application/json'); + } + + /** + * @covers \FireflyIII\Api\V1\Controllers\AccountController::show + */ + + public function testShow() + { + // create stuff + $account = $this->user()->accounts()->first(); + + // mock stuff: + $repository = $this->mock(AccountRepositoryInterface::class); + $currencyRepos = $this->mock(CurrencyRepositoryInterface::class); + + // mock calls: + $repository->shouldReceive('setUser'); + $currencyRepos->shouldReceive('setUser')->once(); + $repository->shouldReceive('getOpeningBalanceAmount')->andReturn('10')->once(); + $repository->shouldReceive('getOpeningBalanceDate')->andReturn('2018-01-01')->once(); + + // test API + $response = $this->get('/api/v1/accounts/' . $account->id); + $response->assertStatus(200); + $response->assertJson(['data' => ['type' => 'accounts', 'links' => true],]); + $response->assertSee('2018-01-01'); // opening balance date + $response->assertHeader('Content-Type', 'application/vnd.api+json'); + } + + /** + * Name already in use. + * + * @covers \FireflyIII\Api\V1\Controllers\AccountController::store + * @covers \FireflyIII\Api\V1\Requests\AccountRequest::authorize + * @covers \FireflyIII\Api\V1\Requests\AccountRequest::rules + * @covers \FireflyIII\Api\V1\Requests\AccountRequest::getAll + */ + public function testStoreNotUnique() + { + // mock repositories + $repository = $this->mock(AccountRepositoryInterface::class); + $currencyRepos = $this->mock(CurrencyRepositoryInterface::class); + + // mock calls: + $repository->shouldReceive('setUser')->once(); + $currencyRepos->shouldReceive('setUser')->once(); + + $account = $this->user()->accounts()->where('account_type_id', 3)->first(); + // data to submit + $data = [ + 'name' => $account->name, + 'currency_id' => 1, + 'type' => 'asset', + 'active' => 1, + 'account_role' => 'defaultAsset', + ]; + + // test API + $response = $this->post('/api/v1/accounts', $data, ['Accept' => 'application/json']); + $response->assertStatus(422); + $response->assertExactJson( + [ + 'message' => 'The given data was invalid.', + 'errors' => [ + 'name' => ['This account name is already in use'], + ], + ] + ); + $response->assertHeader('Content-Type', 'application/json'); + } + + /** + * Send correct data. Should call account repository store method. + * + * @covers \FireflyIII\Api\V1\Controllers\AccountController::store + * @covers \FireflyIII\Api\V1\Requests\AccountRequest::authorize + * @covers \FireflyIII\Api\V1\Requests\AccountRequest::rules + * @covers \FireflyIII\Api\V1\Requests\AccountRequest::getAll + */ + public function testStoreValid() + { + // mock repositories + $repository = $this->mock(AccountRepositoryInterface::class); + $currencyRepos = $this->mock(CurrencyRepositoryInterface::class); + $account = $this->user()->accounts()->first(); + // mock calls: + $repository->shouldReceive('setUser'); + $repository->shouldReceive('store')->once()->andReturn($account); + $repository->shouldReceive('getOpeningBalanceAmount')->andReturn('10'); + $repository->shouldReceive('getOpeningBalanceDate')->andReturn('2018-01-01'); + $currencyRepos->shouldReceive('setUser')->once(); + + // data to submit + $data = [ + 'name' => 'Some new asset account #' . rand(1, 10000), + 'currency_id' => 1, + 'type' => 'asset', + 'active' => 1, + 'account_role' => 'defaultAsset', + ]; + + // test API + $response = $this->post('/api/v1/accounts', $data, ['Accept' => 'application/json']); + $response->assertStatus(200); + $response->assertJson(['data' => ['type' => 'accounts', 'links' => true],]); + $response->assertHeader('Content-Type', 'application/vnd.api+json'); + $response->assertSee($account->name); + } + + /** + * Send correct data. Should call account repository store method. + * + * @covers \FireflyIII\Api\V1\Controllers\AccountController::store + * @covers \FireflyIII\Api\V1\Requests\AccountRequest::authorize + * @covers \FireflyIII\Api\V1\Requests\AccountRequest::rules + * @covers \FireflyIII\Api\V1\Requests\AccountRequest::getAll + */ + public function testStoreWithCurrencyCode() + { + // mock repositories + $repository = $this->mock(AccountRepositoryInterface::class); + $currencyRepos = $this->mock(CurrencyRepositoryInterface::class); + $account = $this->user()->accounts()->first(); + + // mock calls: + $repository->shouldReceive('setUser'); + $currencyRepos->shouldReceive('setUser')->once(); + $repository->shouldReceive('store')->once()->andReturn($account); + $repository->shouldReceive('getOpeningBalanceAmount')->andReturn('10'); + $repository->shouldReceive('getOpeningBalanceDate')->andReturn('2018-01-01'); + $currencyRepos->shouldReceive('findByCodeNull')->andReturn(TransactionCurrency::find(1)); + + // functions to expect: + + // data to submit + $data = [ + 'name' => 'Some new asset account #' . rand(1, 10000), + 'currency_code' => 'EUR', + 'type' => 'asset', + 'active' => 1, + 'account_role' => 'defaultAsset', + ]; + + // test API + $response = $this->post('/api/v1/accounts', $data, ['Accept' => 'application/json']); + $response->assertStatus(200); + $response->assertJson(['data' => ['type' => 'accounts', 'links' => true],]); + $response->assertHeader('Content-Type', 'application/vnd.api+json'); + $response->assertSee($account->name); + } + + /** + * Update first asset account we find. Name can be the same as it was. + * + * @covers \FireflyIII\Api\V1\Controllers\AccountController::update + * @covers \FireflyIII\Api\V1\Requests\AccountRequest::rules + */ + public function testUpdate() + { + // mock repositories + $repository = $this->mock(AccountRepositoryInterface::class); + $currencyRepos = $this->mock(CurrencyRepositoryInterface::class); + + // mock calls: + $repository->shouldReceive('setUser'); + $repository->shouldReceive('update')->once(); + $currencyRepos->shouldReceive('setUser')->once(); + $repository->shouldReceive('getOpeningBalanceAmount')->andReturn('10'); + $repository->shouldReceive('getOpeningBalanceDate')->andReturn('2018-01-01'); + + $account = $this->user()->accounts()->first(); + // data to submit + $data = [ + 'name' => $account->name, + 'currency_id' => 1, + 'type' => 'asset', + 'active' => 1, + 'account_role' => 'defaultAsset', + ]; + + // test API + $response = $this->put('/api/v1/accounts/' . $account->id, $data, ['Accept' => 'application/json']); + $response->assertStatus(200); + $response->assertJson(['data' => ['type' => 'accounts', 'links' => true],]); + $response->assertHeader('Content-Type', 'application/vnd.api+json'); + $response->assertSee($account->name); + } + + /** + * Update first asset account we find. Name can be the same as it was. + * + * @covers \FireflyIII\Api\V1\Controllers\AccountController::update + * @covers \FireflyIII\Api\V1\Requests\AccountRequest::rules + */ + public function testUpdateCurrencyCode() + { + // mock repositories + $repository = $this->mock(AccountRepositoryInterface::class); + $currencyRepos = $this->mock(CurrencyRepositoryInterface::class); + + // mock calls: + $repository->shouldReceive('setUser'); + $repository->shouldReceive('update')->once(); + $currencyRepos->shouldReceive('setUser')->once(); + $repository->shouldReceive('getOpeningBalanceAmount')->andReturn('10'); + $repository->shouldReceive('getOpeningBalanceDate')->andReturn('2018-01-01'); + $currencyRepos->shouldReceive('findByCodeNull')->andReturn(TransactionCurrency::find(1)); + + $account = $this->user()->accounts()->first(); + // data to submit + $data = [ + 'name' => $account->name, + 'currency_code' => 'EUR', + 'type' => 'asset', + 'active' => 1, + 'account_role' => 'defaultAsset', + ]; + + // test API + $response = $this->put('/api/v1/accounts/' . $account->id, $data, ['Accept' => 'application/json']); + $response->assertStatus(200); + $response->assertJson(['data' => ['type' => 'accounts', 'links' => true],]); + $response->assertHeader('Content-Type', 'application/vnd.api+json'); + $response->assertSee($account->name); + } + } \ No newline at end of file