CAPS04-FE-REFACTOR-2 / tests /Feature /MahasiswaDashboardTest.php
wepee's picture
add: integration admin dashboard
53a811b
Raw
History Blame Contribute Delete
17.9 kB
<?php
use Illuminate\Http\Client\Request as HttpRequest;
use Illuminate\Support\Facades\Http;
use Inertia\Testing\AssertableInertia as Assert;
function studentAuthUserCookie(): string
{
return json_encode([
'email' => 'student@example.com',
'id' => 11,
'identity_number' => '123456',
'name' => 'Alma',
'role' => 'student',
'status' => 'active',
], JSON_THROW_ON_ERROR);
}
test('mahasiswa routes redirect guests to login', function () {
$this->get(route('mahasiswa'))
->assertRedirect(route('login'));
});
test('mahasiswa dashboard page can be rendered through laravel proxy', function () {
config(['services.rag.base_url' => 'https://rag.test/api/v1']);
Http::fake([
'https://rag.test/api/v1/courses*' => Http::response([
'data' => [
[
'description' => 'Materi struktur data',
'id' => 101,
'title' => 'Struktur Data',
],
],
'limit' => 100,
'page' => 1,
'total' => 1,
]),
'https://rag.test/api/v1/chats/sessions*' => Http::response([
'data' => [
[
'course_id' => '101',
'created_at' => '2026-05-01T10:00:00Z',
'message_count' => 2,
'title' => 'Apa itu stack?',
'updated_at' => '2026-05-01T10:00:00Z',
'user_id' => 'student-1',
'uuid_id' => 'session-1',
],
],
'pagination' => [
'limit' => 20,
'page' => 1,
'total' => 1,
'total_pages' => 1,
],
]),
]);
$this->withCookie('sevima_raghub_auth_token', 'token')
->withCookie('sevima_raghub_auth_user', studentAuthUserCookie())
->get(route('mahasiswa'))
->assertOk()
->assertInertia(fn (Assert $page) => $page
->component('mahasiswa')
->where('backendMessage', null)
->has('courses', 1)
->where('courses.0.title', 'Struktur Data')
->has('chatSessions', 1)
->where('chatSessions.0.uuid_id', 'session-1')
->where('selectedCourseId', '101'));
Http::assertSent(fn (HttpRequest $request): bool => $request->method() === 'GET'
&& str_starts_with($request->url(), 'https://rag.test/api/v1/chats/sessions?')
&& str_contains($request->url(), 'page=1')
&& str_contains($request->url(), 'limit=20')
&& $request->hasHeader('Authorization', 'Bearer token'));
});
test('mahasiswa chat session can be created and initial message sent through laravel proxy', function () {
config([
'services.rag.base_url' => 'https://rag.test/api/v1',
'services.rag.chat_mode' => 'rest',
]);
Http::fake([
'https://rag.test/api/v1/chats/sessions/session-1/messages' => Http::response([
'content' => 'Stack adalah struktur data LIFO.',
'created_at' => '2026-05-01T10:01:00Z',
'role' => 'assistant',
'sources' => [],
'uuid_id' => 'message-1',
]),
'https://rag.test/api/v1/chats/sessions' => Http::response([
'course_id' => '101',
'created_at' => '2026-05-01T10:00:00Z',
'message_count' => 0,
'title' => 'Apa itu stack?',
'updated_at' => '2026-05-01T10:00:00Z',
'user_id' => 'student-1',
'uuid_id' => 'session-1',
], 201),
]);
$this->withCookie('sevima_raghub_auth_token', 'token')
->withCookie('sevima_raghub_auth_user', studentAuthUserCookie())
->from(route('mahasiswa'))
->post(route('mahasiswa.sessions.store'), [
'course_id' => '101',
'title' => 'Apa itu stack?',
])
->assertRedirect(route('mahasiswa.show', ['sessionId' => 'session-1']))
->assertSessionMissing('sevima_raghub_pending_initial_chat.session-1')
->assertSessionHasNoErrors();
Http::assertSent(fn (HttpRequest $request): bool => $request->method() === 'POST'
&& $request->url() === 'https://rag.test/api/v1/chats/sessions'
&& $request->hasHeader('Authorization', 'Bearer token')
&& $request['course_id'] === '101'
&& $request['title'] === 'Apa itu stack?');
Http::assertSent(fn (HttpRequest $request): bool => $request->method() === 'POST'
&& $request->url() === 'https://rag.test/api/v1/chats/sessions/session-1/messages'
&& $request->hasHeader('Authorization', 'Bearer token')
&& $request['content'] === 'Apa itu stack?');
});
test('mahasiswa chat detail page renders session and history from api', function () {
config([
'services.rag.base_url' => 'https://rag.test/api/v1',
'services.rag.chat_mode' => 'rest',
]);
Http::fake([
'https://rag.test/api/v1/courses*' => Http::response([
'data' => [
[
'id' => 101,
'title' => 'Struktur Data',
],
],
'limit' => 100,
'page' => 1,
'total' => 1,
]),
'https://rag.test/api/v1/chats/sessions/session-1/messages' => Http::response([
'data' => [
[
'content' => 'Apa itu stack?',
'created_at' => '2026-05-01T10:00:00Z',
'role' => 'user',
'sources' => [],
'uuid_id' => 'user-message-1',
],
[
'content' => 'Stack adalah struktur data LIFO.',
'created_at' => '2026-05-01T10:01:00Z',
'role' => 'assistant',
'sources' => [],
'uuid_id' => 'message-1',
],
],
]),
'https://rag.test/api/v1/chats/sessions/session-1' => Http::response([
'course_id' => '101',
'created_at' => '2026-05-01T10:00:00Z',
'message_count' => 2,
'title' => 'Apa itu stack?',
'updated_at' => '2026-05-01T10:01:00Z',
'user_id' => 'student-1',
'uuid_id' => 'session-1',
]),
'https://rag.test/api/v1/chats/sessions*' => Http::response([
'data' => [],
'pagination' => [
'limit' => 20,
'page' => 1,
'total' => 0,
'total_pages' => 0,
],
]),
]);
$this->withCookie('sevima_raghub_auth_token', 'token')
->withCookie('sevima_raghub_auth_user', studentAuthUserCookie())
->get(route('mahasiswa.show', ['sessionId' => 'session-1']))
->assertOk()
->assertInertia(fn (Assert $page) => $page
->component('mahasiswa-chat')
->where('sessionId', 'session-1')
->where('currentSession.uuid_id', 'session-1')
->has('messages', 2)
->where('messages.0.role', 'user')
->where('messages.1.role', 'assistant')
->where('selectedCourseId', '101'));
Http::assertSent(fn (HttpRequest $request): bool => $request->url() === 'https://rag.test/api/v1/chats/sessions/session-1');
Http::assertSent(fn (HttpRequest $request): bool => $request->url() === 'https://rag.test/api/v1/chats/sessions/session-1/messages');
});
test('mahasiswa chat detail page can be rendered with direct session messages', function () {
config([
'services.rag.base_url' => 'https://rag.test/api/v1',
'services.rag.chat_mode' => 'direct',
]);
Http::fake([
'https://rag.test/api/v1/courses*' => Http::response([
'data' => [
[
'id' => 101,
'title' => 'Struktur Data',
],
],
'limit' => 100,
'page' => 1,
'total' => 1,
]),
'https://rag.test/api/v1/chats/sessions/session-1/messages' => Http::response([
'data' => [],
]),
'https://rag.test/api/v1/chats/sessions/session-1' => Http::response([
'course_id' => '101',
'created_at' => '2026-05-01T10:00:00Z',
'message_count' => 0,
'title' => 'Apa itu stack?',
'updated_at' => '2026-05-01T10:00:00Z',
'user_id' => 'student-1',
'uuid_id' => 'session-1',
]),
'https://rag.test/api/v1/chats/sessions*' => Http::response([
'data' => [],
'pagination' => [
'limit' => 20,
'page' => 1,
'total' => 0,
'total_pages' => 0,
],
]),
]);
$this->withCookie('sevima_raghub_auth_token', 'token')
->withCookie('sevima_raghub_auth_user', studentAuthUserCookie())
->withSession([
'sevima_raghub_direct_messages.session-1' => [
[
'content' => 'Jawaban bot',
'created_at' => '2026-05-01T10:01:00Z',
'role' => 'assistant',
'sources' => [],
'uuid_id' => 'message-1',
],
],
])
->get(route('mahasiswa.show', ['sessionId' => 'session-1']))
->assertOk()
->assertInertia(fn (Assert $page) => $page
->component('mahasiswa-chat')
->where('backendMessage', null)
->where('sessionId', 'session-1')
->where('currentSession.uuid_id', 'session-1')
->has('messages', 1)
->where('messages.0.content', 'Jawaban bot')
->where('selectedCourseId', '101'));
});
test('mahasiswa direct chat message can be sent through laravel proxy', function () {
config([
'services.rag.base_url' => 'https://rag.test/api/v1',
'services.rag.chat_mode' => 'direct',
]);
Http::fake([
'https://rag.test/api/v1/ai/query' => Http::response([
'content' => 'Stack adalah struktur data LIFO.',
'created_at' => '2026-05-01T10:01:00Z',
'message_id' => 'message-1',
'role' => 'assistant',
'sources' => [],
]),
]);
$this->withCookie('sevima_raghub_auth_token', 'token')
->withCookie('sevima_raghub_auth_user', studentAuthUserCookie())
->from(route('mahasiswa.show', ['sessionId' => 'session-1']))
->post(route('mahasiswa.messages.store', ['sessionId' => 'session-1']), [
'content' => 'Apa itu stack?',
'course_id' => '101',
])
->assertRedirect(route('mahasiswa.show', ['sessionId' => 'session-1']))
->assertSessionHasNoErrors();
$directMessages = session('sevima_raghub_direct_messages.session-1');
expect($directMessages)->toHaveCount(2)
->and($directMessages[0]['content'])->toBe('Apa itu stack?')
->and($directMessages[1]['content'])->toBe('Stack adalah struktur data LIFO.');
Http::assertSent(fn (HttpRequest $request): bool => $request->method() === 'POST'
&& $request->url() === 'https://rag.test/api/v1/ai/query'
&& $request->hasHeader('Authorization', 'Bearer token')
&& $request['course_id'] === '101'
&& $request['prompt'] === 'Apa itu stack?');
});
test('mahasiswa rest chat message can be sent through laravel proxy', function () {
config([
'services.rag.base_url' => 'https://rag.test/api/v1',
'services.rag.chat_mode' => 'rest',
]);
Http::fake([
'https://rag.test/api/v1/chats/sessions/session-1/messages' => Http::response([
'content' => 'Stack adalah struktur data LIFO.',
'created_at' => '2026-05-01T10:01:00Z',
'role' => 'assistant',
'sources' => [],
'uuid_id' => 'message-1',
]),
]);
$this->withCookie('sevima_raghub_auth_token', 'token')
->withCookie('sevima_raghub_auth_user', studentAuthUserCookie())
->from(route('mahasiswa.show', ['sessionId' => 'session-1']))
->post(route('mahasiswa.messages.store', ['sessionId' => 'session-1']), [
'content' => 'Apa itu stack?',
'course_id' => '101',
])
->assertRedirect(route('mahasiswa.show', ['sessionId' => 'session-1']))
->assertSessionHasNoErrors();
Http::assertSent(fn (HttpRequest $request): bool => $request->method() === 'POST'
&& $request->url() === 'https://rag.test/api/v1/chats/sessions/session-1/messages'
&& $request->hasHeader('Authorization', 'Bearer token')
&& $request['content'] === 'Apa itu stack?');
});
test('mahasiswa stream mode json chat message uses rest endpoint', function () {
config([
'services.rag.base_url' => 'https://rag.test/api/v1',
'services.rag.chat_mode' => 'stream',
]);
Http::fake([
'https://rag.test/api/v1/chats/sessions/session-1/messages' => Http::response([
'content' => 'Stack adalah struktur data LIFO.',
'created_at' => '2026-05-01T10:01:00Z',
'role' => 'assistant',
'sources' => [],
'uuid_id' => 'message-1',
]),
]);
$this->withCookie('sevima_raghub_auth_token', 'token')
->withCookie('sevima_raghub_auth_user', studentAuthUserCookie())
->withHeaders(['Accept' => 'application/json'])
->postJson(route('mahasiswa.messages.store', ['sessionId' => 'session-1']), [
'content' => 'Apa itu stack?',
'course_id' => '101',
])
->assertSuccessful()
->assertJsonPath('assistantMessage.content', 'Stack adalah struktur data LIFO.');
Http::assertSent(fn (HttpRequest $request): bool => $request->method() === 'POST'
&& $request->url() === 'https://rag.test/api/v1/chats/sessions/session-1/messages'
&& $request->hasHeader('Authorization', 'Bearer token')
&& $request['content'] === 'Apa itu stack?');
});
test('mahasiswa stream chat message forwards backend server sent events', function () {
config([
'services.rag.base_url' => 'https://rag.test/api/v1',
'services.rag.chat_mode' => 'stream',
]);
$streamBody = "data: {\"content\":\"Stack adalah struktur data LIFO.\"}\n\n";
Http::fake([
'https://rag.test/api/v1/chats/sessions/session-1/stream' => Http::response(
$streamBody,
200,
['Content-Type' => 'text/event-stream'],
),
]);
$this->withCookie('sevima_raghub_auth_token', 'token')
->withCookie('sevima_raghub_auth_user', studentAuthUserCookie())
->withHeaders(['Accept' => 'text/event-stream'])
->post(route('mahasiswa.messages.store', ['sessionId' => 'session-1']), [
'content' => 'Apa itu stack?',
'course_id' => '101',
])
->assertSuccessful()
->assertStreamed()
->assertHeader('Content-Type', 'text/event-stream; charset=utf-8')
->assertStreamedContent($streamBody);
Http::assertSent(fn (HttpRequest $request): bool => $request->method() === 'POST'
&& $request->url() === 'https://rag.test/api/v1/chats/sessions/session-1/stream'
&& $request->hasHeader('Authorization', 'Bearer token')
&& $request->hasHeader('Accept', 'text/event-stream')
&& $request['content'] === 'Apa itu stack?');
});
test('mahasiswa chat message uses backend error message', function () {
config([
'services.rag.base_url' => 'https://rag.test/api/v1',
'services.rag.chat_mode' => 'direct',
]);
Http::fake([
'https://rag.test/api/v1/ai/query' => Http::response([
'message' => 'I do not know based on available materials.',
], 422),
]);
$this->withCookie('sevima_raghub_auth_token', 'token')
->withCookie('sevima_raghub_auth_user', studentAuthUserCookie())
->from(route('mahasiswa.show', ['sessionId' => 'session-1']))
->post(route('mahasiswa.messages.store', ['sessionId' => 'session-1']), [
'content' => 'Apa itu stack?',
'course_id' => '101',
])
->assertRedirect(route('mahasiswa.show', ['sessionId' => 'session-1']))
->assertSessionHasErrors(['message' => 'I do not know based on available materials.']);
});
test('mahasiswa chat session can be deleted through laravel proxy', function () {
config(['services.rag.base_url' => 'https://rag.test/api/v1']);
Http::fake([
'https://rag.test/api/v1/chats/sessions/session-1' => Http::response([]),
]);
$this->withCookie('sevima_raghub_auth_token', 'token')
->withCookie('sevima_raghub_auth_user', studentAuthUserCookie())
->withSession([
'sevima_raghub_direct_messages.session-1' => [
[
'content' => 'Jawaban bot',
'created_at' => '2026-05-01T10:01:00Z',
'role' => 'assistant',
'sources' => [],
'uuid_id' => 'message-1',
],
],
])
->from(route('mahasiswa.show', ['sessionId' => 'session-1']))
->delete(route('mahasiswa.destroy', ['sessionId' => 'session-1']), [
'active_session_id' => 'session-1',
])
->assertRedirect(route('mahasiswa'))
->assertSessionMissing('sevima_raghub_direct_messages.session-1')
->assertSessionHasNoErrors();
Http::assertSent(fn (HttpRequest $request): bool => $request->method() === 'DELETE'
&& $request->url() === 'https://rag.test/api/v1/chats/sessions/session-1'
&& $request->hasHeader('Authorization', 'Bearer token'));
});