From 4e9a8a24b8258db553f57adf0a344b1aa66d73fe Mon Sep 17 00:00:00 2001 From: philipp lang Date: Tue, 22 Feb 2022 23:37:32 +0100 Subject: [PATCH] Add tests for courses --- src/Api.php | 31 +++++++-- src/Fakes/CourseFake.php | 123 ++++++++++++++++++++++++--------- src/Fakes/Fake.php | 11 ++- src/Fakes/MembershipFake.php | 2 +- tests/Unit/CourseTest.php | 129 ++++++++++++++++++++++++++++------- 5 files changed, 233 insertions(+), 63 deletions(-) diff --git a/src/Api.php b/src/Api.php index 2eeec1a..5a78d62 100644 --- a/src/Api.php +++ b/src/Api.php @@ -209,16 +209,16 @@ class Api { "/ica/rest/nami/mitglied-ausbildung/filtered-for-navigation/mitglied/mitglied/{$memberId}/flist", 'Courses fetch failed' )->map(function ($course) use ($memberId) { - $single = $this->http()->get($this->url."/ica/rest/nami/mitglied-ausbildung/filtered-for-navigation/mitglied/mitglied/{$memberId}/{$course['id']}")['data']; + $single = $this->fetchData("/ica/rest/nami/mitglied-ausbildung/filtered-for-navigation/mitglied/mitglied/{$memberId}/{$course['id']}", "Error fetching single course"); - return (object) [ + return $single ? (object) [ 'id' => $single['id'], 'organizer' => $single['veranstalter'], 'course_id' => $single['bausteinId'], 'event_name' => $single['vstgName'], 'completed_at' => $single['vstgTag'], - ]; - }); + ] : null; + })->filter(fn ($course) => $course !== null); } /** @@ -453,5 +453,28 @@ class Api { return collect($response['data']); } + private function fetchData(string $url, string $error): ?array + { + $response = $this->http()->get($this->url.$url); + + if ($response->json() === null) { + return null; + } + + if (data_get($response, 'message') && Str::contains($response['message'], 'no right')) { + return null; + } + + if (data_get($response, 'message') && Str::contains($response['message'], 'Sicherheitsverletzung')) { + return null; + } + + if ($response['success'] === false) { + $this->exception($error, $url, $response->json()); + } + + return $response['data']; + } + } diff --git a/src/Fakes/CourseFake.php b/src/Fakes/CourseFake.php index 1e4b210..4077c73 100644 --- a/src/Fakes/CourseFake.php +++ b/src/Fakes/CourseFake.php @@ -7,42 +7,90 @@ use Illuminate\Support\Facades\Http; class CourseFake extends Fake { - public function forMember(int $memberId, array $data): void - { - Http::fake(function($request) use ($memberId, $data) { - if ($request->url() === "https://nami.dpsg.de/ica/rest/nami/mitglied-ausbildung/filtered-for-navigation/mitglied/mitglied/{$memberId}/flist") { - return Http::response(json_encode([ - 'success' => true, - 'totalEntries' => collect($data)->count(), - 'data' => collect($data)->map(fn ($course) => ['id' => $course['id']]), - ]) ?: '{}', 200); - } + private array $defaults = [ + 'bausteinId' => 506, + 'veranstalter' => 'KJA', + 'vstgName' => 'eventname', + 'vstgTag' => '2021-11-12 00:00:00' + ]; - foreach ($data as $course) { - if ($request->url() === "https://nami.dpsg.de/ica/rest/nami/mitglied-ausbildung/filtered-for-navigation/mitglied/mitglied/{$memberId}/{$course['id']}") { - return Http::response(json_encode([ - 'success' => true, - 'data' => $course, - ]) ?: '{}', 200); - } + /** + * @param int $memberId + * @param array $ids + * + * @return self + */ + public function fetches(int $memberId, array $ids): self + { + Http::fake(function($request) use ($memberId, $ids) { + if ($request->url() === "https://nami.dpsg.de/ica/rest/nami/mitglied-ausbildung/filtered-for-navigation/mitglied/mitglied/{$memberId}/flist") { + return $this->collection(collect($ids)->map(fn ($id) => ['id' => $id])); } }); + + return $this; } - public function createsSuccessful(int $memberId, int $courseId): void + public function fetchesWithHtml(int $memberId): self + { + Http::fake(function($request) use ($memberId) { + if ($request->url() === "https://nami.dpsg.de/ica/rest/nami/mitglied-ausbildung/filtered-for-navigation/mitglied/mitglied/{$memberId}/flist") { + return $this->htmlResponse(); + } + }); + + return $this; + } + + /** + * @param int $memberId + * @param array $data + * + * @return self + */ + public function fetchesSingle(int $memberId, array $data): self + { + Http::fake(function($request) use ($memberId, $data) { + if ($request->url() === "https://nami.dpsg.de/ica/rest/nami/mitglied-ausbildung/filtered-for-navigation/mitglied/mitglied/{$memberId}/{$data['id']}") { + return $this->dataResponse(array_merge($this->defaults, $data)); + } + }); + + return $this; + } + + public function failsFetchingSingle(int $memberId, int $courseId, string $error = 'Error'): self + { + Http::fake(function($request) use ($memberId, $courseId, $error) { + if ($request->url() === "https://nami.dpsg.de/ica/rest/nami/mitglied-ausbildung/filtered-for-navigation/mitglied/mitglied/{$memberId}/{$courseId}") { + return $this->errorResponse($error); + } + }); + + return $this; + } + + public function fetchesSingleWithHtml(int $memberId, int $courseId): self + { + Http::fake(function($request) use ($memberId, $courseId) { + if ($request->url() === "https://nami.dpsg.de/ica/rest/nami/mitglied-ausbildung/filtered-for-navigation/mitglied/mitglied/{$memberId}/{$courseId}") { + return $this->htmlResponse(); + } + }); + + return $this; + } + + public function createsSuccessfully(int $memberId, int $courseId): void { Http::fake(function($request) use ($memberId, $courseId) { if ($request->url() === "https://nami.dpsg.de/ica/rest/nami/mitglied-ausbildung/filtered-for-navigation/mitglied/mitglied/{$memberId}" && $request->method() === 'POST') { - return Http::response([ - 'data' => $courseId, - 'responseType' => 'OK', - 'success' => true, - ], 200); + return $this->idResponse($courseId); } }); } - public function updatesSuccessful(int $memberId, int $courseId): void + public function updatesSuccessfully(int $memberId, int $courseId): void { Http::fake(function($request) use ($memberId, $courseId) { if ($request->url() === "https://nami.dpsg.de/ica/rest/nami/mitglied-ausbildung/filtered-for-navigation/mitglied/mitglied/{$memberId}/{$courseId}" && $request->method() === 'PUT') { @@ -81,10 +129,7 @@ class CourseFake extends Fake { }); } - /** - * @todo migrate this to parent errorResponse - */ - public function createFailed(int $memberId): void + public function createFails(int $memberId): void { Http::fake(function($request) use ($memberId) { if ($request->url() === "https://nami.dpsg.de/ica/rest/nami/mitglied-ausbildung/filtered-for-navigation/mitglied/mitglied/{$memberId}") { @@ -93,11 +138,11 @@ class CourseFake extends Fake { }); } - public function doesntUpdateWithError(int $memberId, int $courseId): void + public function doesntUpdateWithError(int $memberId, int $courseId, string $error = "Error"): void { - Http::fake(function($request) use ($memberId, $courseId) { + Http::fake(function($request) use ($memberId, $courseId, $error) { if ($request->url() === "https://nami.dpsg.de/ica/rest/nami/mitglied-ausbildung/filtered-for-navigation/mitglied/mitglied/{$memberId}/{$courseId}" && $request->method() === 'PUT') { - return Http::response('{"success":false,"data":null,"responseType":"EXCEPTION","message":"Unexpected Error javax.ejb.EJBException","title":null}', 200); + return $this->errorResponse($error); } }); } @@ -143,4 +188,20 @@ class CourseFake extends Fake { }); } + public function assertFetched(int $memberId): void + { + Http::assertSent(function($request) use ($memberId) { + return $request->url() === "https://nami.dpsg.de/ica/rest/nami/mitglied-ausbildung/filtered-for-navigation/mitglied/mitglied/{$memberId}/flist" + && $request->method() === 'GET'; + }); + } + + public function assertFetchedSingle(int $memberId, int $courseId): void + { + Http::assertSent(function($request) use ($memberId, $courseId) { + return $request->url() === "https://nami.dpsg.de/ica/rest/nami/mitglied-ausbildung/filtered-for-navigation/mitglied/mitglied/{$memberId}/{$courseId}" + && $request->method() === 'GET'; + }); + } + } diff --git a/src/Fakes/Fake.php b/src/Fakes/Fake.php index 229a48a..524e4f1 100644 --- a/src/Fakes/Fake.php +++ b/src/Fakes/Fake.php @@ -20,11 +20,12 @@ abstract class Fake { { return Http::response(json_encode([ 'success' => true, + 'totalEntries' => $collection->count(), 'data' => $collection->toArray(), ])); } - public function data(array $data): PromiseInterface + public function dataResponse(array $data): PromiseInterface { return Http::response(json_encode([ 'success' => true, @@ -32,6 +33,14 @@ abstract class Fake { ])); } + public function idResponse(int $id): PromiseInterface + { + return Http::response(json_encode([ + 'success' => true, + 'data' => $id, + ])); + } + public function htmlResponse(): PromiseInterface { return Http::response(''); diff --git a/src/Fakes/MembershipFake.php b/src/Fakes/MembershipFake.php index fa5c45d..ad92377 100644 --- a/src/Fakes/MembershipFake.php +++ b/src/Fakes/MembershipFake.php @@ -36,7 +36,7 @@ class MembershipFake extends Fake { Http::fake(function($request) use ($memberId, $data) { $url = 'https://nami.dpsg.de/ica/rest/nami/zugeordnete-taetigkeiten/filtered-for-navigation/gruppierung-mitglied/mitglied/'.$memberId.'/'.$data['id']; if ($request->url() === $url && $request->method() === 'GET') { - return $this->data(array_merge([ + return $this->dataResponse(array_merge([ "id" => 68, "gruppierung" => "Diözesanleitung Köln 100000", "gruppierungId" => 103, diff --git a/tests/Unit/CourseTest.php b/tests/Unit/CourseTest.php index 37562e3..c524dd4 100644 --- a/tests/Unit/CourseTest.php +++ b/tests/Unit/CourseTest.php @@ -24,25 +24,62 @@ class CourseTest extends TestCase public function test_get_courses_of_member(): void { Auth::success(12345, 'secret'); - app(CourseFake::class)->forMember(11111, [ - ['bausteinId' => 506, 'id' => 788, 'veranstalter' => 'KJA', 'vstgName' => 'eventname', 'vstgTag' => '2021-11-12 00:00:00'] - ]); + app(CourseFake::class) + ->fetches(11111, [788]) + ->fetchesSingle(11111, [ + 'bausteinId' => 506, + 'id' => 788, + 'veranstalter' => 'KJA', + 'vstgName' => 'eventname', + 'vstgTag' => '2021-11-12 00:00:00' + ]); + + $course = Nami::login(12345, 'secret')->coursesFor(11111)->first(); + + $this->assertEquals(788, $course->id); + $this->assertEquals('KJA', $course->organizer); + $this->assertEquals(506, $course->course_id); + $this->assertEquals('eventname', $course->event_name); + $this->assertEquals('2021-11-12 00:00:00', $course->completed_at); + + app(CourseFake::class)->assertFetched(11111); + app(CourseFake::class)->assertFetchedSingle(11111, 788); + } + + public function test_it_gets_multiple_courses_of_member(): void + { + Auth::success(12345, 'secret'); + app(CourseFake::class) + ->fetches(11111, [788, 789]) + ->fetchesSingle(11111, ['id' => 788]) + ->fetchesSingle(11111, ['id' => 789]); $courses = Nami::login(12345, 'secret')->coursesFor(11111); - $this->assertEquals(788, $courses->first()->id); - $this->assertEquals('KJA', $courses->first()->organizer); - $this->assertEquals(506, $courses->first()->course_id); - $this->assertEquals('eventname', $courses->first()->event_name); - $this->assertEquals('2021-11-12 00:00:00', $courses->first()->completed_at); + $this->assertCount(2, $courses); + } - Http::assertSent(function($request) { - return $request->url() == 'https://nami.dpsg.de/ica/rest/nami/mitglied-ausbildung/filtered-for-navigation/mitglied/mitglied/11111/flist'; - }); - Http::assertSent(function($request) { - return $request->url() == 'https://nami.dpsg.de/ica/rest/nami/mitglied-ausbildung/filtered-for-navigation/mitglied/mitglied/11111/788'; - }); - Http::assertSentCount(2); + public function test_return_nothing_when_course_returns_html(): void + { + Auth::success(12345, 'secret'); + app(CourseFake::class) + ->fetches(11111, [788, 789]) + ->fetchesSingleWithHtml(11111, 788) + ->fetchesSingle(11111, ['id' => 789]); + + $courses = Nami::login(12345, 'secret')->coursesFor(11111); + + $this->assertCount(1, $courses); + } + + public function test_return_empty_when_course_index_returns_html(): void + { + Auth::success(12345, 'secret'); + app(CourseFake::class)->fetchesWithHtml(11111); + + $courses = Nami::login(12345, 'secret')->coursesFor(11111); + + $this->assertCount(0, $courses); } public function test_it_needs_login_to_get_courses(): void @@ -55,10 +92,8 @@ class CourseTest extends TestCase public function test_store_a_course(): void { Auth::success(12345, 'secret'); - app(CourseFake::class)->createsSuccessful(123, 999); - Nami::login(12345, 'secret'); - - Nami::createCourse(123, [ + app(CourseFake::class)->createsSuccessfully(123, 999); + Nami::login(12345, 'secret')->createCourse(123, [ 'event_name' => '::event::', 'completed_at' => '2021-01-02 00:00:00', 'organizer' => '::org::', @@ -66,10 +101,10 @@ class CourseTest extends TestCase ]); app(CourseFake::class)->assertCreated(123, [ - 'bausteinId' => 456, - 'veranstalter' => '::org::', 'vstgName' => '::event::', 'vstgTag' => '2021-01-02T00:00:00', + 'veranstalter' => '::org::', + 'bausteinId' => 456, ]); } @@ -84,14 +119,56 @@ class CourseTest extends TestCase ]); } - public function test_needs_login(): void + public function test_update_a_course(): void { - $this->expectException(NotAuthenticatedException::class); + Auth::success(12345, 'secret'); + app(CourseFake::class)->updatesSuccessfully(123, 999); - Nami::coursesFor(11111); + Nami::login(12345, 'secret')->updateCourse(123, 999, [ + 'event_name' => '::event::', + 'completed_at' => '2021-01-02 00:00:00', + 'organizer' => '::org::', + 'course_id' => 456, + 'id' => 999, + ]); + + app(CourseFake::class)->assertUpdated(123, 999, [ + 'vstgName' => '::event::', + 'vstgTag' => '2021-01-02T00:00:00', + 'veranstalter' => '::org::', + 'bausteinId' => 456, + 'id' => 999, + ]); } - public function test_parses_failed_login(): void + public function test_throw_exception_when_course_update_failed(): void + { + $this->expectException(NamiException::class); + Auth::success(12345, 'secret'); + app(CourseFake::class)->doesntUpdateWithError(123, 999); + + Nami::login(12345, 'secret')->updateCourse(123, 999, [ + 'event_name' => '::event::', + 'completed_at' => '2021-01-02 00:00:00', + 'organizer' => '::org::', + 'course_id' => 456, + 'id' => 999, + ]); + } + + public function test_it_needs_valid_credentials_to_store_a_course(): void + { + Auth::failed(12345, 'secret'); + $this->expectException(NotAuthenticatedException::class); + Nami::createCourse(123, [ + 'event_name' => '::event::', + 'completed_at' => '2021-01-02 00:00:00', + 'organizer' => '::org::', + 'course_id' => 456 + ]); + } + + public function test_it_throws_login_exception_when_fetching_with_wrong_credentials(): void { Auth::failed(12345, 'secret'); $this->expectException(LoginException::class); @@ -103,7 +180,7 @@ class CourseTest extends TestCase { $this->expectException(NamiException::class); Auth::success(12345, 'secret'); - app(CourseFake::class)->createFailed(123); + app(CourseFake::class)->createFails(123); Nami::login(12345, 'secret'); Nami::createCourse(123, [