Add tests for creating course

This commit is contained in:
philipp lang 2022-02-19 15:18:24 +01:00
parent 50cf61e944
commit a30d2659ad
15 changed files with 134 additions and 175 deletions

View File

@ -8,14 +8,15 @@ use App\Course\Requests\StoreRequest;
use App\Course\Requests\UpdateRequest;
use App\Http\Controllers\Controller;
use App\Member\Member;
use App\Setting\NamiSettings;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
class CourseController extends Controller
{
public function store(Member $member, StoreRequest $request): RedirectResponse
public function store(Member $member, StoreRequest $request, NamiSettings $settings): RedirectResponse
{
$request->persist($member);
$request->persist($member, $settings);
return redirect()->back()->success('Ausbildung erstellt');
}

View File

@ -4,13 +4,16 @@ namespace App\Course\Requests;
use App\Course\Models\Course;
use App\Member\Member;
use App\Setting\NamiSettings;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Arr;
use Illuminate\Validation\ValidationException;
use Zoomyboy\LaravelNami\Nami;
use Zoomyboy\LaravelNami\NamiException;
class StoreRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
@ -36,20 +39,21 @@ class StoreRequest extends FormRequest
];
}
public function persist(Member $member): void
public function persist(Member $member, NamiSettings $settings): void
{
$course = Course::where('id', $this->input('course_id'))->firstOrFail();
$payload = array_merge(
$this->only(['event_name', 'completed_at', 'organizer']),
['course_id' => $course->nami_id],
);
$payload = collect($this->input())->only(['event_name', 'completed_at', 'organizer'])->merge([
'course_id' => $course->nami_id,
])->toArray();
try {
$namiId = auth()->user()->api()->createCourse($member->nami_id, $payload);
$namiId = Nami::login($settings->mglnr, $settings->password)->createCourse($member->nami_id, $payload);
} catch(NamiException $e) {
throw ValidationException::withMessages(['id' => 'Unbekannter Fehler']);
}
$member->courses()->create($this->safe()->collect()->put('nami_id', $namiId)->toArray());
}
}

View File

@ -3,7 +3,9 @@
namespace App\Exceptions;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Illuminate\Validation\ValidationException;
use Throwable;
use Zoomyboy\LaravelNami\LoginException;
use Zoomyboy\LaravelNami\NamiException;
class Handler extends ExceptionHandler
@ -58,6 +60,10 @@ class Handler extends ExceptionHandler
*/
public function render($request, Throwable $exception)
{
if ($exception instanceof LoginException) {
throw ValidationException::withMessages(['nami' => 'NaMi Login fehlgeschlagen.']);
}
return parent::render($request, $exception);
}
}

View File

@ -8,7 +8,6 @@ use Illuminate\Http\Resources\Json\JsonResource;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\ServiceProvider;
use Laravel\Telescope\Telescope;
use Zoomyboy\LaravelNami\Authentication\NamiGuard;
class AppServiceProvider extends ServiceProvider
{
@ -38,10 +37,6 @@ class AppServiceProvider extends ServiceProvider
*/
public function boot()
{
NamiGuard::beforeLogin(function(array $credentials) {
return in_array($credentials['mglnr'], app(GeneralSettings::class)->allowed_nami_accounts)
? null
: false;
});
//
}
}

View File

@ -0,0 +1,19 @@
<?php
namespace App\Setting;
use Spatie\LaravelSettings\Settings;
class NamiSettings extends Settings
{
public int $mglnr;
public string $password;
public static function group(): string
{
return 'nami';
}
}

View File

@ -39,8 +39,8 @@ return [
'guards' => [
'web' => [
'driver' => 'nami',
'other_providers' => ['database'],
'driver' => 'session',
'provider' => 'database',
],
'api' => [

View File

@ -4,6 +4,7 @@ namespace Database\Factories;
use App\User;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Facades\Hash;
/**
* @extends Factory<User>
@ -21,7 +22,9 @@ class UserFactory extends Factory
public function definition()
{
return [
//
'email' => $this->faker->safeEmail,
'password' => Hash::make('password'),
'name' => $this->faker->firstName,
];
}
}

View File

@ -16,6 +16,7 @@ class CreateUsersTable extends Migration
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('email');
$table->string('name');
$table->string('password');
$table->timestamps();
});

View File

@ -0,0 +1,13 @@
<?php
use Spatie\LaravelSettings\Migrations\SettingsMigration;
class CreateNamiSettings extends SettingsMigration
{
public function up(): void
{
$this->migrator->add('nami.mglnr', -1);
$this->migrator->add('nami.password', '');
}
}

@ -1 +1 @@
Subproject commit 829dd01358858c887dddaeadd6e4ddebd8f9fb0b
Subproject commit b8d2a04d43dd7634ac6e653b26b07b317c5566db

View File

@ -55,9 +55,9 @@ class StoreTest extends TestCase
*/
public function testItValidatesInput(array $payload, array $errors): void
{
$this->login()->init();
$member = Member::factory()->defaults()->inNami(123)->createOne();
$course = Course::factory()->inNami(456)->createOne();
$this->login();
$member = Member::factory()->defaults()->createOne();
$course = Course::factory()->createOne();
$response = $this->post("/member/{$member->id}/course", array_merge([
'course_id' => $course->id,
@ -71,8 +71,7 @@ class StoreTest extends TestCase
public function testItCreatesACourse(): void
{
$this->withoutExceptionHandling();
$this->login()->init();
$this->withoutExceptionHandling()->login()->loginNami();
$member = Member::factory()->defaults()->inNami(123)->createOne();
$course = Course::factory()->inNami(456)->createOne();
app(CourseFake::class)->createsSuccessful(123, 999);
@ -100,9 +99,29 @@ class StoreTest extends TestCase
]);
}
public function testItThrowsErrorWhenLoginIsWrong(): void
{
$this->login()->failedNami();
$member = Member::factory()->defaults()->inNami(123)->createOne();
$course = Course::factory()->inNami(456)->createOne();
$response = $this->post("/member/{$member->id}/course", [
'course_id' => $course->id,
'completed_at' => '2021-01-02',
'event_name' => '::event::',
'organizer' => '::org::',
]);
$this->assertErrors(['nami' => 'NaMi Login fehlgeschlagen.'], $response);
$this->assertDatabaseMissing('course_members', [
'member_id' => $member->id,
]);
}
public function testItReceivesUnknownErrors(): void
{
$this->login()->init();
$this->login()->loginNami();
$member = Member::factory()->defaults()->inNami(123)->createOne();
$course = Course::factory()->inNami(456)->createOne();
app(CourseFake::class)->doesntCreateWithError(123);

View File

@ -56,7 +56,7 @@ class UpdateTest extends TestCase
*/
public function testItValidatesInput(array $payload, array $errors): void
{
$this->login()->init();
$this->login();
$member = Member::factory()->defaults()->inNami(123)->has(CourseMember::factory()->for(Course::factory()), 'courses')->createOne();
$newCourse = Course::factory()->inNami(789)->create();

View File

@ -1,140 +0,0 @@
<?php
namespace Tests\Feature;
use App\Setting\GeneralSettings;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Foundation\Testing\WithFaker;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Http;
use Tests\TestCase;
use Zoomyboy\LaravelNami\Authentication\NamiGuard;
use Zoomyboy\LaravelNami\Backend\FakeBackend;
class NamiLoginTest extends TestCase
{
use DatabaseTransactions;
public function setUp(): void
{
parent::setUp();
}
public function testItCanLoginWithANamiAccount(): void
{
$this->withoutExceptionHandling();
$this->setLoginId(123);
app(FakeBackend::class)
->fakeLogin('123')
->addSearch(123, ['entries_vorname' => '::firstname::', 'entries_nachname' => '::lastname::', 'entries_gruppierungId' => 1000]);
$this->post('/login', [
'mglnr' => 123,
'provider' => 'nami',
'password' => 'secret'
]);
$key = session()->get('auth_key');
$cache = Cache::get("namiauth-{$key}");
$this->assertEquals('secret', data_get($cache, 'credentials.password'));
$this->assertEquals('::firstname::', data_get($cache, 'firstname'));
$this->assertEquals('::lastname::', data_get($cache, 'lastname'));
$this->assertEquals(1000, data_get($cache, 'group_id'));
$this->assertEquals(123, data_get($cache, 'credentials.mglnr'));
$this->assertTrue(auth()->check());
}
public function testItDoesntLoginTwoTimes(): void
{
$this->withoutExceptionHandling();
$this->setLoginId(123);
app(FakeBackend::class)
->fakeLogin('123')
->addSearch(123, ['entries_vorname' => '::firstname::', 'entries_nachname' => '::lastname::', 'entries_gruppierungId' => 1000]);
$this->post('/login', [
'mglnr' => 123,
'provider' => 'nami',
'password' => 'secret'
]);
auth()->logout();
$this->post('/login', [
'mglnr' => 123,
'provider' => 'nami',
'password' => 'secret'
]);
$this->assertTrue(auth()->check());
Http::assertSentCount(4);
}
public function testItResolvesTheLoginFromTheCache(): void
{
$this->withoutExceptionHandling();
$this->setLoginId(123);
app(FakeBackend::class)
->fakeLogin('123')
->addSearch(123, ['entries_vorname' => '::firstname::', 'entries_nachname' => '::lastname::', 'entries_gruppierungId' => 1000]);
$this->post('/login', [
'mglnr' => 123,
'provider' => 'nami',
'password' => 'secret'
]);
app(NamiGuard::class)->setUser(null);
$this->post('/login', [
'mglnr' => 123,
'provider' => 'nami',
'password' => 'secret'
]);
$this->assertTrue(auth()->check());
Http::assertSentCount(3);
}
public function testItThrowsExceptionWhenLoginFailed(): void
{
$this->setLoginId(123);
app(FakeBackend::class)->fakeFailedLogin();
$this->post('/login', [
'mglnr' => 123,
'provider' => 'nami',
'password' => 'secret'
])->assertRedirect('/');
$this->assertFalse(auth()->check());
Http::assertSentCount(2);
}
public function testItCannotLoginWithAWrongNamiId(): void
{
app(FakeBackend::class)
->fakeLogin('123')
->addSearch(123, ['entries_vorname' => '::firstname::', 'entries_nachname' => '::lastname::', 'entries_gruppierungId' => 1000]);
$this->post('/login', [
'mglnr' => 123,
'provider' => 'nami',
'password' => 'secret'
])->assertRedirect('/');
$this->assertTrue(auth()->guest());
Http::assertSentCount(0);
}
private function setLoginId(int $mglNr): self
{
GeneralSettings::fake([
'allowed_nami_accounts' => [$mglNr]
]);
return $this;
}
}

View File

@ -10,7 +10,6 @@ use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Http;
use Tests\TestCase;
use Zoomyboy\LaravelNami\Authentication\NamiGuard;
use Zoomyboy\LaravelNami\Backend\FakeBackend;
class UserLoginTest extends TestCase

View File

@ -4,9 +4,13 @@ namespace Tests;
use App\Member\Member;
use App\Setting\GeneralSettings;
use App\Setting\NamiSettings;
use App\User;
use Illuminate\Foundation\Testing\TestCase as BaseTestCase;
use Illuminate\Http\RedirectResponse;
use Illuminate\Testing\TestResponse;
use Tests\Lib\TestsInertia;
use Zoomyboy\LaravelNami\Authentication\Auth;
use Zoomyboy\LaravelNami\Backend\FakeBackend;
use Zoomyboy\LaravelNami\Nami;
use Zoomyboy\LaravelNami\NamiUser;
@ -16,20 +20,40 @@ abstract class TestCase extends BaseTestCase
use CreatesApplication;
use TestsInertia;
public function fakeAuthUser(): void
protected User $me;
public function setUp(): void
{
app(FakeBackend::class)
->fakeLogin('123')
->addSearch(123, ['entries_vorname' => '::firstname::', 'entries_nachname' => '::lastname::', 'entries_gruppierungId' => 1000]);
parent::setUp();
Auth::fake();
}
public function loginNami(int $mglnr = 12345, string $password = 'password'): self
{
Auth::success($mglnr, $password);
NamiSettings::fake([
'mglnr' => $mglnr,
'password' => $password,
]);
return $this;
}
public function failedNami(int $mglnr = 12345, string $password = 'password'): self
{
Auth::failed($mglnr, $password);
NamiSettings::fake([
'mglnr' => $mglnr,
'password' => $password,
]);
return $this;
}
public function login(): self
{
$this->fakeAuthUser();
auth()->loginNami([
'mglnr' => 123,
'password' => 'secret',
]);
$this->be($user = User::factory()->create());
$this->me = $user;
return $this;
}
@ -40,5 +64,20 @@ abstract class TestCase extends BaseTestCase
return $this;
}
public function assertErrors(array $errors, TestResponse $response) {
$response->assertSessionHas('errors');
$this->assertInstanceOf(RedirectResponse::class, $response->baseResponse);
/** @var RedirectResponse */
$response = $response;
$sessionErrors = $response->getSession()->get('errors')->getBag('default');
foreach ($errors as $key => $value) {
$this->assertTrue($sessionErrors->has($key), "Cannot find key {$key} in errors '".print_r($sessionErrors, true));
$this->assertEquals($value, $sessionErrors->get($key)[0], "Failed to validate value for session error key {$key}. Actual value: ".print_r($sessionErrors, true));
}
return $this;
}
}