From a95fdb903b86a17af7b8b697fef845cc9db1cbb7 Mon Sep 17 00:00:00 2001 From: James Cole Date: Sat, 14 Jul 2018 11:16:12 +0200 Subject: [PATCH] Refactor account controller and some associated tests. --- .../Controllers/Account/CreateController.php | 125 +++++++++ .../Controllers/Account/DeleteController.php | 101 ++++++++ .../Controllers/Account/EditController.php | 153 +++++++++++ .../Account/ReconcileController.php | 3 + app/Http/Controllers/AccountController.php | 186 -------------- routes/web.php | 28 +- .../Account/CreateControllerTest.php | 128 +++++++++ .../Account/DeleteControllerTest.php | 86 +++++++ .../Account/EditControllerTest.php | 170 ++++++++++++ .../Controllers/AccountControllerTest.php | 242 ------------------ .../Routine/File/ImportableConverterTest.php | 11 +- 11 files changed, 792 insertions(+), 441 deletions(-) create mode 100644 app/Http/Controllers/Account/CreateController.php create mode 100644 app/Http/Controllers/Account/DeleteController.php create mode 100644 app/Http/Controllers/Account/EditController.php create mode 100644 tests/Feature/Controllers/Account/CreateControllerTest.php create mode 100644 tests/Feature/Controllers/Account/DeleteControllerTest.php create mode 100644 tests/Feature/Controllers/Account/EditControllerTest.php diff --git a/app/Http/Controllers/Account/CreateController.php b/app/Http/Controllers/Account/CreateController.php new file mode 100644 index 0000000000..5627fbe8e4 --- /dev/null +++ b/app/Http/Controllers/Account/CreateController.php @@ -0,0 +1,125 @@ +. + */ + +declare(strict_types=1); + +namespace FireflyIII\Http\Controllers\Account; + + +use FireflyIII\Http\Controllers\Controller; +use FireflyIII\Http\Requests\AccountFormRequest; +use FireflyIII\Models\AccountType; +use FireflyIII\Repositories\Account\AccountRepositoryInterface; +use Illuminate\Http\Request; +use Preferences; + +/** + * + * Class CreateController + */ +class CreateController extends Controller +{ + /** @var AccountRepositoryInterface */ + private $repository; + + /** + * + */ + public function __construct() + { + parent::__construct(); + + // translations: + $this->middleware( + function ($request, $next) { + app('view')->share('mainTitleIcon', 'fa-credit-card'); + app('view')->share('title', trans('firefly.accounts')); + + $this->repository = app(AccountRepositoryInterface::class); + + return $next($request); + } + ); + } + + /** + * @param Request $request + * @param string|null $what + * + * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View + */ + public function create(Request $request, string $what = null) + { + $what = $what ?? 'asset'; + $defaultCurrency = app('amount')->getDefaultCurrency(); + $subTitleIcon = config('firefly.subIconsByIdentifier.' . $what); + $subTitle = trans('firefly.make_new_' . $what . '_account'); + $roles = []; + foreach (config('firefly.accountRoles') as $role) { + $roles[$role] = (string)trans('firefly.account_role_' . $role); + } + + // pre fill some data + $request->session()->flash('preFilled', ['currency_id' => $defaultCurrency->id]); + + // put previous url in session if not redirect from store (not "create another"). + if (true !== session('accounts.create.fromStore')) { + $this->rememberPreviousUri('accounts.create.uri'); + } + $request->session()->forget('accounts.create.fromStore'); + + return view('accounts.create', compact('subTitleIcon', 'what', 'subTitle', 'roles')); + } + + + /** + * @param AccountFormRequest $request + * + * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector + */ + public function store(AccountFormRequest $request) + { + $data = $request->getAccountData(); + $account = $this->repository->store($data); + $request->session()->flash('success', (string)trans('firefly.stored_new_account', ['name' => $account->name])); + app('preferences')->mark(); + + // update preferences if necessary: + $frontPage = Preferences::get('frontPageAccounts', [])->data; + if (AccountType::ASSET === $account->accountType->type && \count($frontPage) > 0) { + // @codeCoverageIgnoreStart + $frontPage[] = $account->id; + Preferences::set('frontPageAccounts', $frontPage); + // @codeCoverageIgnoreEnd + } + // redirect to previous URL. + $redirect = redirect($this->getPreviousUri('accounts.create.uri')); + if (1 === (int)$request->get('create_another')) { + // set value so create routine will not overwrite URL: + $request->session()->put('accounts.create.fromStore', true); + + $redirect = redirect(route('accounts.create', [$request->input('what')]))->withInput(); + } + + return $redirect; + } + +} \ No newline at end of file diff --git a/app/Http/Controllers/Account/DeleteController.php b/app/Http/Controllers/Account/DeleteController.php new file mode 100644 index 0000000000..cdae3afeee --- /dev/null +++ b/app/Http/Controllers/Account/DeleteController.php @@ -0,0 +1,101 @@ +. + */ + +declare(strict_types=1); + +namespace FireflyIII\Http\Controllers\Account; + + +use ExpandedForm; +use FireflyIII\Http\Controllers\Controller; +use FireflyIII\Models\Account; +use FireflyIII\Repositories\Account\AccountRepositoryInterface; +use Illuminate\Http\Request; + +/** + * + * Class DeleteController + */ +class DeleteController extends Controller +{ + /** @var AccountRepositoryInterface */ + private $repository; + + /** + * + */ + public function __construct() + { + parent::__construct(); + + // translations: + $this->middleware( + function ($request, $next) { + app('view')->share('mainTitleIcon', 'fa-credit-card'); + app('view')->share('title', trans('firefly.accounts')); + + $this->repository = app(AccountRepositoryInterface::class); + + return $next($request); + } + ); + } + + /** + * @param Account $account + * + * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View + */ + public function delete(Account $account) + { + $typeName = config('firefly.shortNamesByFullName.' . $account->accountType->type); + $subTitle = trans('firefly.delete_' . $typeName . '_account', ['name' => $account->name]); + $accountList = ExpandedForm::makeSelectListWithEmpty($this->repository->getAccountsByType([$account->accountType->type])); + unset($accountList[$account->id]); + + // put previous url in session + $this->rememberPreviousUri('accounts.delete.uri'); + + return view('accounts.delete', compact('account', 'subTitle', 'accountList')); + } + + /** + * @param Request $request + * @param Account $account + * + * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector + */ + public function destroy(Request $request, Account $account) + { + $type = $account->accountType->type; + $typeName = config('firefly.shortNamesByFullName.' . $type); + $name = $account->name; + $moveTo = $this->repository->findNull((int)$request->get('move_account_before_delete')); + + $this->repository->destroy($account, $moveTo); + + $request->session()->flash('success', (string)trans('firefly.' . $typeName . '_deleted', ['name' => $name])); + app('preferences')->mark(); + + return redirect($this->getPreviousUri('accounts.delete.uri')); + } + +} \ No newline at end of file diff --git a/app/Http/Controllers/Account/EditController.php b/app/Http/Controllers/Account/EditController.php new file mode 100644 index 0000000000..5fad8ba628 --- /dev/null +++ b/app/Http/Controllers/Account/EditController.php @@ -0,0 +1,153 @@ +. + */ + +declare(strict_types=1); + +namespace FireflyIII\Http\Controllers\Account; + + +use FireflyIII\Http\Controllers\Controller; +use FireflyIII\Http\Requests\AccountFormRequest; +use FireflyIII\Models\Account; +use FireflyIII\Models\Note; +use FireflyIII\Repositories\Account\AccountRepositoryInterface; +use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface; +use Illuminate\Http\Request; + +/** + * + * Class EditController + */ +class EditController extends Controller +{ + /** @var CurrencyRepositoryInterface */ + private $currencyRepos; + /** @var AccountRepositoryInterface */ + private $repository; + + /** + * + */ + public function __construct() + { + parent::__construct(); + + // translations: + $this->middleware( + function ($request, $next) { + app('view')->share('mainTitleIcon', 'fa-credit-card'); + app('view')->share('title', trans('firefly.accounts')); + + $this->repository = app(AccountRepositoryInterface::class); + $this->currencyRepos = app(CurrencyRepositoryInterface::class); + + return $next($request); + } + ); + } + + /** + * @param Request $request + * @param Account $account + * @param AccountRepositoryInterface $repository + * + * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View + */ + public function edit(Request $request, Account $account, AccountRepositoryInterface $repository) + { + $what = config('firefly.shortNamesByFullName')[$account->accountType->type]; + $subTitle = trans('firefly.edit_' . $what . '_account', ['name' => $account->name]); + $subTitleIcon = config('firefly.subIconsByIdentifier.' . $what); + $roles = []; + foreach (config('firefly.accountRoles') as $role) { + $roles[$role] = (string)trans('firefly.account_role_' . $role); + } + + // put previous url in session if not redirect from store (not "return_to_edit"). + if (true !== session('accounts.edit.fromUpdate')) { + $this->rememberPreviousUri('accounts.edit.uri'); + } + $request->session()->forget('accounts.edit.fromUpdate'); + + // pre fill some useful values. + + // the opening balance is tricky: + $openingBalanceAmount = (string)$repository->getOpeningBalanceAmount($account); + $openingBalanceDate = $repository->getOpeningBalanceDate($account); + $default = app('amount')->getDefaultCurrency(); + $currency = $this->currencyRepos->findNull((int)$repository->getMetaValue($account, 'currency_id')); + if (null === $currency) { + $currency = $default; + } + + // code to handle active-checkboxes + $hasOldInput = null !== $request->old('_token'); + $preFilled = [ + 'accountNumber' => $repository->getMetaValue($account, 'accountNumber'), + 'accountRole' => $repository->getMetaValue($account, 'accountRole'), + 'ccType' => $repository->getMetaValue($account, 'ccType'), + 'ccMonthlyPaymentDate' => $repository->getMetaValue($account, 'ccMonthlyPaymentDate'), + 'BIC' => $repository->getMetaValue($account, 'BIC'), + 'openingBalanceDate' => $openingBalanceDate, + 'openingBalance' => $openingBalanceAmount, + 'virtualBalance' => $account->virtual_balance, + 'currency_id' => $currency->id, + 'notes' => '', + 'active' => $hasOldInput ? (bool)$request->old('active') : $account->active, + ]; + /** @var Note $note */ + $note = $this->repository->getNote($account); + if (null !== $note) { + $preFilled['notes'] = $note->text; + } + + $request->session()->flash('preFilled', $preFilled); + + return view('accounts.edit', compact('account', 'currency', 'subTitle', 'subTitleIcon', 'what', 'roles', 'preFilled')); + } + + + /** + * @param AccountFormRequest $request + * @param Account $account + * + * @return $this|\Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector + */ + public function update(AccountFormRequest $request, Account $account) + { + $data = $request->getAccountData(); + $this->repository->update($account, $data); + + $request->session()->flash('success', (string)trans('firefly.updated_account', ['name' => $account->name])); + app('preferences')->mark(); + + $redirect = redirect($this->getPreviousUri('accounts.edit.uri')); + if (1 === (int)$request->get('return_to_edit')) { + // set value so edit routine will not overwrite URL: + $request->session()->put('accounts.edit.fromUpdate', true); + + $redirect = redirect(route('accounts.edit', [$account->id]))->withInput(['return_to_edit' => 1]); + } + + return $redirect; + } + +} \ No newline at end of file diff --git a/app/Http/Controllers/Account/ReconcileController.php b/app/Http/Controllers/Account/ReconcileController.php index f1c96b4055..09f8101ba6 100644 --- a/app/Http/Controllers/Account/ReconcileController.php +++ b/app/Http/Controllers/Account/ReconcileController.php @@ -284,6 +284,9 @@ class ReconcileController extends Controller * @param TransactionJournal $journal * * @return $this|\Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector + * + * @SuppressWarnings(PHPMD.CyclomaticComplexity) + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) */ public function update(ReconciliationUpdateRequest $request, TransactionJournal $journal) { diff --git a/app/Http/Controllers/AccountController.php b/app/Http/Controllers/AccountController.php index 7859efca25..58ddb87578 100644 --- a/app/Http/Controllers/AccountController.php +++ b/app/Http/Controllers/AccountController.php @@ -30,7 +30,6 @@ use FireflyIII\Helpers\Collector\JournalCollectorInterface; use FireflyIII\Http\Requests\AccountFormRequest; use FireflyIII\Models\Account; use FireflyIII\Models\AccountType; -use FireflyIII\Models\Note; use FireflyIII\Models\Transaction; use FireflyIII\Models\TransactionType; use FireflyIII\Repositories\Account\AccountRepositoryInterface; @@ -74,134 +73,6 @@ class AccountController extends Controller ); } - /** - * @param Request $request - * @param string|null $what - * - * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View - */ - public function create(Request $request, string $what = null) - { - $what = $what ?? 'asset'; - $defaultCurrency = app('amount')->getDefaultCurrency(); - $subTitleIcon = config('firefly.subIconsByIdentifier.' . $what); - $subTitle = trans('firefly.make_new_' . $what . '_account'); - $roles = []; - foreach (config('firefly.accountRoles') as $role) { - $roles[$role] = (string)trans('firefly.account_role_' . $role); - } - - // pre fill some data - $request->session()->flash('preFilled', ['currency_id' => $defaultCurrency->id]); - - // put previous url in session if not redirect from store (not "create another"). - if (true !== session('accounts.create.fromStore')) { - $this->rememberPreviousUri('accounts.create.uri'); - } - $request->session()->forget('accounts.create.fromStore'); - - return view('accounts.create', compact('subTitleIcon', 'what', 'subTitle', 'roles')); - } - - /** - * @param Account $account - * - * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View - */ - public function delete(Account $account) - { - $typeName = config('firefly.shortNamesByFullName.' . $account->accountType->type); - $subTitle = trans('firefly.delete_' . $typeName . '_account', ['name' => $account->name]); - $accountList = ExpandedForm::makeSelectListWithEmpty($this->repository->getAccountsByType([$account->accountType->type])); - unset($accountList[$account->id]); - - // put previous url in session - $this->rememberPreviousUri('accounts.delete.uri'); - - return view('accounts.delete', compact('account', 'subTitle', 'accountList')); - } - - /** - * @param Request $request - * @param Account $account - * - * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector - */ - public function destroy(Request $request, Account $account) - { - $type = $account->accountType->type; - $typeName = config('firefly.shortNamesByFullName.' . $type); - $name = $account->name; - $moveTo = $this->repository->findNull((int)$request->get('move_account_before_delete')); - - $this->repository->destroy($account, $moveTo); - - $request->session()->flash('success', (string)trans('firefly.' . $typeName . '_deleted', ['name' => $name])); - app('preferences')->mark(); - - return redirect($this->getPreviousUri('accounts.delete.uri')); - } - - /** - * @param Request $request - * @param Account $account - * @param AccountRepositoryInterface $repository - * - * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View - */ - public function edit(Request $request, Account $account, AccountRepositoryInterface $repository) - { - $what = config('firefly.shortNamesByFullName')[$account->accountType->type]; - $subTitle = trans('firefly.edit_' . $what . '_account', ['name' => $account->name]); - $subTitleIcon = config('firefly.subIconsByIdentifier.' . $what); - $roles = []; - foreach (config('firefly.accountRoles') as $role) { - $roles[$role] = (string)trans('firefly.account_role_' . $role); - } - - // put previous url in session if not redirect from store (not "return_to_edit"). - if (true !== session('accounts.edit.fromUpdate')) { - $this->rememberPreviousUri('accounts.edit.uri'); - } - $request->session()->forget('accounts.edit.fromUpdate'); - - // pre fill some useful values. - - // the opening balance is tricky: - $openingBalanceAmount = (string)$repository->getOpeningBalanceAmount($account); - $openingBalanceDate = $repository->getOpeningBalanceDate($account); - $default = app('amount')->getDefaultCurrency(); - $currency = $this->currencyRepos->findNull((int)$repository->getMetaValue($account, 'currency_id')); - if (null === $currency) { - $currency = $default; - } - - // code to handle active-checkboxes - $hasOldInput = null !== $request->old('_token'); - $preFilled = [ - 'accountNumber' => $repository->getMetaValue($account, 'accountNumber'), - 'accountRole' => $repository->getMetaValue($account, 'accountRole'), - 'ccType' => $repository->getMetaValue($account, 'ccType'), - 'ccMonthlyPaymentDate' => $repository->getMetaValue($account, 'ccMonthlyPaymentDate'), - 'BIC' => $repository->getMetaValue($account, 'BIC'), - 'openingBalanceDate' => $openingBalanceDate, - 'openingBalance' => $openingBalanceAmount, - 'virtualBalance' => $account->virtual_balance, - 'currency_id' => $currency->id, - 'notes' => '', - 'active' => $hasOldInput ? (bool)$request->old('active') : $account->active, - ]; - /** @var Note $note */ - $note = $this->repository->getNote($account); - if (null !== $note) { - $preFilled['notes'] = $note->text; - } - - $request->session()->flash('preFilled', $preFilled); - - return view('accounts.edit', compact('account', 'currency', 'subTitle', 'subTitleIcon', 'what', 'roles', 'preFilled')); - } - /** * @param Request $request * @param string $what @@ -351,63 +222,6 @@ class AccountController extends Controller ); } - /** - * @param AccountFormRequest $request - * - * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector - */ - public function store(AccountFormRequest $request) - { - $data = $request->getAccountData(); - $account = $this->repository->store($data); - $request->session()->flash('success', (string)trans('firefly.stored_new_account', ['name' => $account->name])); - app('preferences')->mark(); - - // update preferences if necessary: - $frontPage = Preferences::get('frontPageAccounts', [])->data; - if (AccountType::ASSET === $account->accountType->type && \count($frontPage) > 0) { - // @codeCoverageIgnoreStart - $frontPage[] = $account->id; - Preferences::set('frontPageAccounts', $frontPage); - // @codeCoverageIgnoreEnd - } - // redirect to previous URL. - $redirect = redirect($this->getPreviousUri('accounts.create.uri')); - if (1 === (int)$request->get('create_another')) { - // set value so create routine will not overwrite URL: - $request->session()->put('accounts.create.fromStore', true); - - $redirect = redirect(route('accounts.create', [$request->input('what')]))->withInput(); - } - - return $redirect; - } - - /** - * @param AccountFormRequest $request - * @param Account $account - * - * @return $this|\Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector - */ - public function update(AccountFormRequest $request, Account $account) - { - $data = $request->getAccountData(); - $this->repository->update($account, $data); - - $request->session()->flash('success', (string)trans('firefly.updated_account', ['name' => $account->name])); - app('preferences')->mark(); - - $redirect = redirect($this->getPreviousUri('accounts.edit.uri')); - if (1 === (int)$request->get('return_to_edit')) { - // set value so edit routine will not overwrite URL: - $request->session()->put('accounts.edit.fromUpdate', true); - - $redirect = redirect(route('accounts.edit', [$account->id]))->withInput(['return_to_edit' => 1]); - } - - return $redirect; - } - /** * @param array $array * @param int $entryId diff --git a/routes/web.php b/routes/web.php index 3232892b16..9de923e8c3 100755 --- a/routes/web.php +++ b/routes/web.php @@ -109,30 +109,40 @@ Route::group( Route::group( ['middleware' => 'user-full-auth', 'namespace' => 'FireflyIII\Http\Controllers', 'prefix' => 'accounts', 'as' => 'accounts.'], function () { Route::get('{what}', ['uses' => 'AccountController@index', 'as' => 'index'])->where('what', 'revenue|asset|expense'); - Route::get('create/{what}', ['uses' => 'AccountController@create', 'as' => 'create'])->where('what', 'revenue|asset|expense'); - Route::get('edit/{account}', ['uses' => 'AccountController@edit', 'as' => 'edit']); - Route::get('delete/{account}', ['uses' => 'AccountController@delete', 'as' => 'delete']); + + + // create + Route::get('create/{what}', ['uses' => 'Account\CreateController@create', 'as' => 'create'])->where('what', 'revenue|asset|expense'); + Route::post('store', ['uses' => 'Account\CreateController@store', 'as' => 'store']); + + + // edit + Route::get('edit/{account}', ['uses' => 'Account\EditController@edit', 'as' => 'edit']); + Route::post('update/{account}', ['uses' => 'Account\EditController@update', 'as' => 'update']); + + // delete + Route::get('delete/{account}', ['uses' => 'Account\DeleteController@delete', 'as' => 'delete']); + Route::post('destroy/{account}', ['uses' => 'Account\DeleteController@destroy', 'as' => 'destroy']); + + // show Route::get('show/{account}/all', ['uses' => 'AccountController@showAll', 'as' => 'show.all']); Route::get('show/{account}/{start_date?}/{end_date?}', ['uses' => 'AccountController@show', 'as' => 'show']); // reconcile routes: Route::get('reconcile/{account}/index/{start_date?}/{end_date?}', ['uses' => 'Account\ReconcileController@reconcile', 'as' => 'reconcile']); - - Route::post('reconcile/{account}/submit/{start_date?}/{end_date?}', ['uses' => 'Account\ReconcileController@submit', 'as' => 'reconcile.submit']); // reconcile JSON routes Route::get('reconcile/{account}/overview/{start_date?}/{end_date?}', ['uses' => 'Json\ReconcileController@overview', 'as' => 'reconcile.overview']); - Route::get('reconcile/{account}/transactions/{start_date?}/{end_date?}', ['uses' => 'Json\ReconcileController@transactions', 'as' => 'reconcile.transactions']); + Route::get( + 'reconcile/{account}/transactions/{start_date?}/{end_date?}', ['uses' => 'Json\ReconcileController@transactions', 'as' => 'reconcile.transactions'] + ); // show reconciliation Route::get('reconcile/show/{tj}', ['uses' => 'Account\ReconcileController@show', 'as' => 'reconcile.show']); Route::get('reconcile/edit/{tj}', ['uses' => 'Account\ReconcileController@edit', 'as' => 'reconcile.edit']); Route::post('reconcile/update/{tj}', ['uses' => 'Account\ReconcileController@update', 'as' => 'reconcile.update']); - Route::post('store', ['uses' => 'AccountController@store', 'as' => 'store']); - Route::post('update/{account}', ['uses' => 'AccountController@update', 'as' => 'update']); - Route::post('destroy/{account}', ['uses' => 'AccountController@destroy', 'as' => 'destroy']); } ); diff --git a/tests/Feature/Controllers/Account/CreateControllerTest.php b/tests/Feature/Controllers/Account/CreateControllerTest.php new file mode 100644 index 0000000000..1df0d40739 --- /dev/null +++ b/tests/Feature/Controllers/Account/CreateControllerTest.php @@ -0,0 +1,128 @@ +. + */ + +declare(strict_types=1); + +namespace Tests\Feature\Controllers\Account; + + +use FireflyIII\Models\Account; +use FireflyIII\Models\TransactionJournal; +use FireflyIII\Repositories\Account\AccountRepositoryInterface; +use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface; +use FireflyIII\Repositories\Journal\JournalRepositoryInterface; +use Illuminate\Support\Collection; +use Log; +use Preferences; +use Tests\TestCase; + +/** + * + * Class CreateControllerTest + */ +class CreateControllerTest extends TestCase +{ + /** + * + */ + public function setUp(): void + { + parent::setUp(); + Log::debug(sprintf('Now in %s.', \get_class($this))); + } + + + /** + * @covers \FireflyIII\Http\Controllers\Account\CreateController + */ + public function testCreate(): void + { + // mock stuff + $journalRepos = $this->mock(JournalRepositoryInterface::class); + $accountRepos = $this->mock(AccountRepositoryInterface::class); + $repository = $this->mock(CurrencyRepositoryInterface::class); + $repository->shouldReceive('get')->andReturn(new Collection); + $journalRepos->shouldReceive('firstNull')->once()->andReturn(new TransactionJournal); + + $this->be($this->user()); + $response = $this->get(route('accounts.create', ['asset'])); + $response->assertStatus(200); + // has bread crumb + $response->assertSee('