- Updated RoleIndex component to handle pagination, sorting, and searching for roles. - Adjusted data structure for roles to include pagination details. - Enhanced tests for various admin features (Finance, HR, Master) to validate pagination and data structure. - Ensured all relevant tests check for data structure consistency, including total counts and pagination details.
752 lines
23 KiB
PHP
752 lines
23 KiB
PHP
<?php
|
|
|
|
use App\Models\Attendance;
|
|
use App\Models\Employee;
|
|
use App\Models\User;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Inertia\Testing\AssertableInertia as Assert;
|
|
|
|
uses(RefreshDatabase::class);
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| AUTHENTICATION
|
|
|--------------------------------------------------------------------------
|
|
*/
|
|
|
|
test('guests are redirected to the login page', function () {
|
|
$response = $this->get(route('admin.hr.attendances.index'));
|
|
$response->assertRedirect(route('login'));
|
|
});
|
|
|
|
test('authenticated users can visit the attendance index page', function () {
|
|
$user = User::factory()->create();
|
|
$this->actingAs($user);
|
|
|
|
$response = $this->get(route('admin.hr.attendances.index'));
|
|
$response->assertOk();
|
|
});
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| INDEX PAGE
|
|
|--------------------------------------------------------------------------
|
|
*/
|
|
|
|
test('index page displays attendances', function () {
|
|
$user = User::factory()->create();
|
|
$this->actingAs($user);
|
|
|
|
$employeeUser = User::factory()->create();
|
|
$employeeUser->employee()->create([
|
|
'join_date' => '2024-01-01',
|
|
'employment_status' => 'full_time',
|
|
'base_salary' => 5000000,
|
|
]);
|
|
|
|
Attendance::factory()->create([
|
|
'employee_id' => $employeeUser->employee->id,
|
|
'attendance_date' => now()->toDateString(),
|
|
'check_in_at' => now()->setHour(8)->setMinute(0),
|
|
'check_out_at' => now()->setHour(17)->setMinute(0),
|
|
]);
|
|
|
|
$response = $this->get(route('admin.hr.attendances.index'));
|
|
$response->assertOk();
|
|
$response->assertInertia(fn (Assert $page) => $page
|
|
->component('admin/hr/attendance/index')
|
|
->has('attendances.data', 1)
|
|
->where('attendances.total', 1)
|
|
->where('attendances.current_page', 1)
|
|
->where('attendances.per_page', 25)
|
|
);
|
|
});
|
|
|
|
test('index page works with zero attendances', function () {
|
|
$user = User::factory()->create();
|
|
$this->actingAs($user);
|
|
|
|
$response = $this->get(route('admin.hr.attendances.index'));
|
|
$response->assertOk();
|
|
$response->assertInertia(fn (Assert $page) => $page
|
|
->component('admin/hr/attendance/index')
|
|
->has('attendances.data', 0)
|
|
->where('attendances.total', 0)
|
|
->where('attendances.current_page', 1)
|
|
->where('attendances.per_page', 25)
|
|
);
|
|
});
|
|
|
|
test('index page passes current year and month', function () {
|
|
$user = User::factory()->create();
|
|
$this->actingAs($user);
|
|
|
|
$response = $this->get(route('admin.hr.attendances.index'));
|
|
$response->assertOk();
|
|
$response->assertInertia(fn (Assert $page) => $page
|
|
->where('currentYear', now()->year)
|
|
->where('currentMonth', now()->month)
|
|
);
|
|
});
|
|
|
|
test('index page can filter by year and month', function () {
|
|
$user = User::factory()->create();
|
|
$this->actingAs($user);
|
|
|
|
$employeeUser = User::factory()->create();
|
|
$employeeUser->employee()->create([
|
|
'join_date' => '2024-01-01',
|
|
'employment_status' => 'full_time',
|
|
'base_salary' => 5000000,
|
|
]);
|
|
|
|
Attendance::factory()->create([
|
|
'employee_id' => $employeeUser->employee->id,
|
|
'attendance_date' => '2024-03-15',
|
|
'check_in_at' => '2024-03-15 08:00:00',
|
|
'check_out_at' => '2024-03-15 17:00:00',
|
|
]);
|
|
|
|
$response = $this->get(route('admin.hr.attendances.index', ['year' => 2024, 'month' => 3]));
|
|
$response->assertOk();
|
|
$response->assertInertia(fn (Assert $page) => $page
|
|
->where('currentYear', 2024)
|
|
->where('currentMonth', 3)
|
|
->has('attendances.data', 1)
|
|
->where('attendances.total', 1)
|
|
->where('attendances.current_page', 1)
|
|
->where('attendances.per_page', 25)
|
|
);
|
|
});
|
|
|
|
test('index page excludes attendances from other months', function () {
|
|
$user = User::factory()->create();
|
|
$this->actingAs($user);
|
|
|
|
$employeeUser = User::factory()->create();
|
|
$employeeUser->employee()->create([
|
|
'join_date' => '2024-01-01',
|
|
'employment_status' => 'full_time',
|
|
'base_salary' => 5000000,
|
|
]);
|
|
|
|
Attendance::factory()->create([
|
|
'employee_id' => $employeeUser->employee->id,
|
|
'attendance_date' => '2024-03-15',
|
|
'check_in_at' => '2024-03-15 08:00:00',
|
|
]);
|
|
|
|
$response = $this->get(route('admin.hr.attendances.index', ['year' => 2024, 'month' => 4]));
|
|
$response->assertOk();
|
|
$response->assertInertia(fn (Assert $page) => $page
|
|
->has('attendances.data', 0)
|
|
->where('attendances.total', 0)
|
|
->where('attendances.current_page', 1)
|
|
->where('attendances.per_page', 25)
|
|
);
|
|
});
|
|
|
|
test('index page passes hrSettings props', function () {
|
|
$user = User::factory()->create();
|
|
$this->actingAs($user);
|
|
|
|
$response = $this->get(route('admin.hr.attendances.index'));
|
|
$response->assertOk();
|
|
$response->assertInertia(fn (Assert $page) => $page
|
|
->has('hrSettings.scheduled_check_in_time')
|
|
->has('hrSettings.scheduled_check_out_time')
|
|
);
|
|
});
|
|
|
|
test('index page passes monthStats', function () {
|
|
$user = User::factory()->create();
|
|
$this->actingAs($user);
|
|
|
|
$response = $this->get(route('admin.hr.attendances.index'));
|
|
$response->assertOk();
|
|
$response->assertInertia(fn (Assert $page) => $page
|
|
->has('monthStats.working_days')
|
|
->has('monthStats.present')
|
|
->has('monthStats.absent')
|
|
->has('monthStats.leave')
|
|
);
|
|
});
|
|
|
|
test('index page passes todayAttendance as null when no attendance today', function () {
|
|
$user = User::factory()->create();
|
|
$this->actingAs($user);
|
|
|
|
$response = $this->get(route('admin.hr.attendances.index'));
|
|
$response->assertOk();
|
|
$response->assertInertia(fn (Assert $page) => $page
|
|
->where('todayAttendance', null)
|
|
);
|
|
});
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| STORE / CHECK-IN
|
|
|--------------------------------------------------------------------------
|
|
*/
|
|
|
|
test('guest cannot check in', function () {
|
|
$response = $this->post(route('admin.hr.attendances.store'), [
|
|
'photo' => 'data:image/jpeg;base64,'.base64_encode('fake-image'),
|
|
'latitude' => -6.2088,
|
|
'longitude' => 106.8456,
|
|
]);
|
|
|
|
$response->assertRedirect(route('login'));
|
|
});
|
|
|
|
test('authenticated user without employee cannot check in', function () {
|
|
$user = User::factory()->create();
|
|
$this->actingAs($user);
|
|
|
|
$response = $this->post(route('admin.hr.attendances.store'), [
|
|
'photo' => 'data:image/jpeg;base64,'.base64_encode('fake-image'),
|
|
'latitude' => -6.2088,
|
|
'longitude' => 106.8456,
|
|
]);
|
|
|
|
$response->assertRedirect();
|
|
});
|
|
|
|
test('employee can check in successfully', function () {
|
|
$user = User::factory()->create();
|
|
$this->actingAs($user);
|
|
|
|
$employee = Employee::factory()->create([
|
|
'user_id' => $user->id,
|
|
'join_date' => now()->subMonth()->toDateString(),
|
|
'employment_status' => 'full_time',
|
|
'base_salary' => 5000000,
|
|
]);
|
|
|
|
$response = $this->post(route('admin.hr.attendances.store'), [
|
|
'photo' => 'data:image/jpeg;base64,'.base64_encode('fake-image'),
|
|
'latitude' => -6.2088,
|
|
'longitude' => 106.8456,
|
|
]);
|
|
|
|
$response->assertRedirect();
|
|
|
|
$this->assertDatabaseHas('attendances', [
|
|
'employee_id' => $employee->id,
|
|
'attendance_date' => now()->toDateString(),
|
|
]);
|
|
});
|
|
|
|
test('employee cannot check in twice on the same day', function () {
|
|
$user = User::factory()->create();
|
|
$this->actingAs($user);
|
|
|
|
$employee = Employee::factory()->create([
|
|
'user_id' => $user->id,
|
|
'join_date' => now()->subMonth()->toDateString(),
|
|
'employment_status' => 'full_time',
|
|
'base_salary' => 5000000,
|
|
]);
|
|
|
|
Attendance::factory()->create([
|
|
'employee_id' => $employee->id,
|
|
'attendance_date' => now()->toDateString(),
|
|
'check_in_at' => now(),
|
|
]);
|
|
|
|
$response = $this->post(route('admin.hr.attendances.store'), [
|
|
'photo' => 'data:image/jpeg;base64,'.base64_encode('fake-image'),
|
|
'latitude' => -6.2088,
|
|
'longitude' => 106.8456,
|
|
]);
|
|
|
|
$response->assertRedirect();
|
|
$this->assertDatabaseCount('attendances', 1);
|
|
});
|
|
|
|
test('check in requires photo', function () {
|
|
$user = User::factory()->create();
|
|
$this->actingAs($user);
|
|
|
|
Employee::factory()->create([
|
|
'user_id' => $user->id,
|
|
'join_date' => now()->subMonth()->toDateString(),
|
|
'employment_status' => 'full_time',
|
|
'base_salary' => 5000000,
|
|
]);
|
|
|
|
$response = $this->post(route('admin.hr.attendances.store'), [
|
|
'latitude' => -6.2088,
|
|
'longitude' => 106.8456,
|
|
]);
|
|
|
|
$response->assertRedirect();
|
|
$this->assertDatabaseCount('attendances', 0);
|
|
});
|
|
|
|
test('check in requires latitude', function () {
|
|
$user = User::factory()->create();
|
|
$this->actingAs($user);
|
|
|
|
Employee::factory()->create([
|
|
'user_id' => $user->id,
|
|
'join_date' => now()->subMonth()->toDateString(),
|
|
'employment_status' => 'full_time',
|
|
'base_salary' => 5000000,
|
|
]);
|
|
|
|
$response = $this->post(route('admin.hr.attendances.store'), [
|
|
'photo' => 'data:image/jpeg;base64,'.base64_encode('fake-image'),
|
|
'longitude' => 106.8456,
|
|
]);
|
|
|
|
$response->assertRedirect();
|
|
$this->assertDatabaseCount('attendances', 0);
|
|
});
|
|
|
|
test('check in requires longitude', function () {
|
|
$user = User::factory()->create();
|
|
$this->actingAs($user);
|
|
|
|
Employee::factory()->create([
|
|
'user_id' => $user->id,
|
|
'join_date' => now()->subMonth()->toDateString(),
|
|
'employment_status' => 'full_time',
|
|
'base_salary' => 5000000,
|
|
]);
|
|
|
|
$response = $this->post(route('admin.hr.attendances.store'), [
|
|
'photo' => 'data:image/jpeg;base64,'.base64_encode('fake-image'),
|
|
'latitude' => -6.2088,
|
|
]);
|
|
|
|
$response->assertRedirect();
|
|
$this->assertDatabaseCount('attendances', 0);
|
|
});
|
|
|
|
test('check in latitude must be numeric', function () {
|
|
$user = User::factory()->create();
|
|
$this->actingAs($user);
|
|
|
|
Employee::factory()->create([
|
|
'user_id' => $user->id,
|
|
'join_date' => now()->subMonth()->toDateString(),
|
|
'employment_status' => 'full_time',
|
|
'base_salary' => 5000000,
|
|
]);
|
|
|
|
$response = $this->post(route('admin.hr.attendances.store'), [
|
|
'photo' => 'data:image/jpeg;base64,'.base64_encode('fake-image'),
|
|
'latitude' => 'not-a-number',
|
|
'longitude' => 106.8456,
|
|
]);
|
|
|
|
$response->assertRedirect();
|
|
$this->assertDatabaseCount('attendances', 0);
|
|
});
|
|
|
|
test('check in longitude must be numeric', function () {
|
|
$user = User::factory()->create();
|
|
$this->actingAs($user);
|
|
|
|
Employee::factory()->create([
|
|
'user_id' => $user->id,
|
|
'join_date' => now()->subMonth()->toDateString(),
|
|
'employment_status' => 'full_time',
|
|
'base_salary' => 5000000,
|
|
]);
|
|
|
|
$response = $this->post(route('admin.hr.attendances.store'), [
|
|
'photo' => 'data:image/jpeg;base64,'.base64_encode('fake-image'),
|
|
'latitude' => -6.2088,
|
|
'longitude' => 'not-a-number',
|
|
]);
|
|
|
|
$response->assertRedirect();
|
|
$this->assertDatabaseCount('attendances', 0);
|
|
});
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| UPDATE / CHECK-OUT
|
|
|--------------------------------------------------------------------------
|
|
*/
|
|
|
|
test('guest cannot check out', function () {
|
|
$attendance = Attendance::factory()->create([
|
|
'check_in_at' => now()->subHours(8),
|
|
'check_out_at' => null,
|
|
]);
|
|
|
|
$response = $this->put(route('admin.hr.attendances.update', $attendance), [
|
|
'photo' => 'data:image/jpeg;base64,'.base64_encode('fake-image'),
|
|
'latitude' => -6.2088,
|
|
'longitude' => 106.8456,
|
|
]);
|
|
|
|
$response->assertRedirect(route('login'));
|
|
});
|
|
|
|
test('employee can check out successfully', function () {
|
|
$user = User::factory()->create();
|
|
$this->actingAs($user);
|
|
|
|
$employee = Employee::factory()->create([
|
|
'user_id' => $user->id,
|
|
'join_date' => now()->subMonth()->toDateString(),
|
|
'employment_status' => 'full_time',
|
|
'base_salary' => 5000000,
|
|
]);
|
|
|
|
$attendance = Attendance::factory()->create([
|
|
'employee_id' => $employee->id,
|
|
'attendance_date' => now()->toDateString(),
|
|
'check_in_at' => now()->subHours(8),
|
|
'check_out_at' => null,
|
|
]);
|
|
|
|
$response = $this->put(route('admin.hr.attendances.update', $attendance), [
|
|
'photo' => 'data:image/jpeg;base64,'.base64_encode('fake-image'),
|
|
'latitude' => -6.2088,
|
|
'longitude' => 106.8456,
|
|
]);
|
|
|
|
$response->assertRedirect();
|
|
|
|
$attendance->refresh();
|
|
$this->assertNotNull($attendance->check_out_at);
|
|
$this->assertEquals(-6.2088, $attendance->check_out_latitude);
|
|
$this->assertEquals(106.8456, $attendance->check_out_longitude);
|
|
});
|
|
|
|
test('check out requires photo', function () {
|
|
$user = User::factory()->create();
|
|
$this->actingAs($user);
|
|
|
|
$employee = Employee::factory()->create([
|
|
'user_id' => $user->id,
|
|
'join_date' => now()->subMonth()->toDateString(),
|
|
'employment_status' => 'full_time',
|
|
'base_salary' => 5000000,
|
|
]);
|
|
|
|
$attendance = Attendance::factory()->create([
|
|
'employee_id' => $employee->id,
|
|
'attendance_date' => now()->toDateString(),
|
|
'check_in_at' => now()->subHours(8),
|
|
'check_out_at' => null,
|
|
]);
|
|
|
|
$response = $this->put(route('admin.hr.attendances.update', $attendance), [
|
|
'latitude' => -6.2088,
|
|
'longitude' => 106.8456,
|
|
]);
|
|
|
|
$response->assertRedirect();
|
|
|
|
$attendance->refresh();
|
|
$this->assertNull($attendance->check_out_at);
|
|
});
|
|
|
|
test('check out requires latitude', function () {
|
|
$user = User::factory()->create();
|
|
$this->actingAs($user);
|
|
|
|
$employee = Employee::factory()->create([
|
|
'user_id' => $user->id,
|
|
'join_date' => now()->subMonth()->toDateString(),
|
|
'employment_status' => 'full_time',
|
|
'base_salary' => 5000000,
|
|
]);
|
|
|
|
$attendance = Attendance::factory()->create([
|
|
'employee_id' => $employee->id,
|
|
'attendance_date' => now()->toDateString(),
|
|
'check_in_at' => now()->subHours(8),
|
|
'check_out_at' => null,
|
|
]);
|
|
|
|
$response = $this->put(route('admin.hr.attendances.update', $attendance), [
|
|
'photo' => 'data:image/jpeg;base64,'.base64_encode('fake-image'),
|
|
'longitude' => 106.8456,
|
|
]);
|
|
|
|
$response->assertRedirect();
|
|
|
|
$attendance->refresh();
|
|
$this->assertNull($attendance->check_out_at);
|
|
});
|
|
|
|
test('check out requires longitude', function () {
|
|
$user = User::factory()->create();
|
|
$this->actingAs($user);
|
|
|
|
$employee = Employee::factory()->create([
|
|
'user_id' => $user->id,
|
|
'join_date' => now()->subMonth()->toDateString(),
|
|
'employment_status' => 'full_time',
|
|
'base_salary' => 5000000,
|
|
]);
|
|
|
|
$attendance = Attendance::factory()->create([
|
|
'employee_id' => $employee->id,
|
|
'attendance_date' => now()->toDateString(),
|
|
'check_in_at' => now()->subHours(8),
|
|
'check_out_at' => null,
|
|
]);
|
|
|
|
$response = $this->put(route('admin.hr.attendances.update', $attendance), [
|
|
'photo' => 'data:image/jpeg;base64,'.base64_encode('fake-image'),
|
|
'latitude' => -6.2088,
|
|
]);
|
|
|
|
$response->assertRedirect();
|
|
|
|
$attendance->refresh();
|
|
$this->assertNull($attendance->check_out_at);
|
|
});
|
|
|
|
test('updating non-existent attendance returns 404', function () {
|
|
$user = User::factory()->create();
|
|
$this->actingAs($user);
|
|
|
|
$response = $this->put(route('admin.hr.attendances.update', 999999), [
|
|
'photo' => 'data:image/jpeg;base64,'.base64_encode('fake-image'),
|
|
'latitude' => -6.2088,
|
|
'longitude' => 106.8456,
|
|
]);
|
|
|
|
$response->assertStatus(404);
|
|
});
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| BY-DATE
|
|
|--------------------------------------------------------------------------
|
|
*/
|
|
|
|
test('guest cannot access by-date endpoint', function () {
|
|
$response = $this->get(route('admin.hr.attendances.by-date'));
|
|
$response->assertRedirect(route('login'));
|
|
});
|
|
|
|
test('by-date returns empty when no attendance for date', function () {
|
|
$user = User::factory()->create();
|
|
$this->actingAs($user);
|
|
|
|
$response = $this->getJson(route('admin.hr.attendances.by-date', ['date' => '2024-01-01']));
|
|
$response->assertOk();
|
|
});
|
|
|
|
test('by-date defaults to today when no date parameter', function () {
|
|
$user = User::factory()->create();
|
|
$this->actingAs($user);
|
|
|
|
$response = $this->getJson(route('admin.hr.attendances.by-date'));
|
|
$response->assertOk();
|
|
});
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| MONTH STATS
|
|
|--------------------------------------------------------------------------
|
|
*/
|
|
|
|
test('month stats calculates correct working days for january 2024', function () {
|
|
$user = User::factory()->create();
|
|
$this->actingAs($user);
|
|
|
|
$response = $this->get(route('admin.hr.attendances.index', ['year' => 2024, 'month' => 1]));
|
|
$response->assertOk();
|
|
$response->assertInertia(fn (Assert $page) => $page
|
|
->where('monthStats.working_days', 23)
|
|
);
|
|
});
|
|
|
|
test('month stats present count matches attendance records', function () {
|
|
$user = User::factory()->create();
|
|
$this->actingAs($user);
|
|
|
|
$employeeUser = User::factory()->create();
|
|
$employeeUser->employee()->create([
|
|
'join_date' => '2024-01-01',
|
|
'employment_status' => 'full_time',
|
|
'base_salary' => 5000000,
|
|
]);
|
|
|
|
Attendance::factory()->create([
|
|
'employee_id' => $employeeUser->employee->id,
|
|
'attendance_date' => '2024-01-15',
|
|
'check_in_at' => '2024-01-15 08:00:00',
|
|
]);
|
|
|
|
Attendance::factory()->create([
|
|
'employee_id' => $employeeUser->employee->id,
|
|
'attendance_date' => '2024-01-16',
|
|
'check_in_at' => '2024-01-16 08:00:00',
|
|
]);
|
|
|
|
$response = $this->get(route('admin.hr.attendances.index', ['year' => 2024, 'month' => 1]));
|
|
$response->assertOk();
|
|
$response->assertInertia(fn (Assert $page) => $page
|
|
->where('monthStats.present', 2)
|
|
);
|
|
});
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| MULTIPLE ATTENDANCES
|
|
|--------------------------------------------------------------------------
|
|
*/
|
|
|
|
test('multiple employees can have attendances on the same day', function () {
|
|
$user = User::factory()->create();
|
|
$this->actingAs($user);
|
|
|
|
$emp1User = User::factory()->create();
|
|
$emp1User->employee()->create([
|
|
'join_date' => '2024-01-01',
|
|
'employment_status' => 'full_time',
|
|
'base_salary' => 5000000,
|
|
]);
|
|
|
|
$emp2User = User::factory()->create();
|
|
$emp2User->employee()->create([
|
|
'join_date' => '2024-01-01',
|
|
'employment_status' => 'full_time',
|
|
'base_salary' => 5000000,
|
|
]);
|
|
|
|
Attendance::factory()->create([
|
|
'employee_id' => $emp1User->employee->id,
|
|
'attendance_date' => '2024-01-15',
|
|
'check_in_at' => '2024-01-15 08:00:00',
|
|
]);
|
|
|
|
Attendance::factory()->create([
|
|
'employee_id' => $emp2User->employee->id,
|
|
'attendance_date' => '2024-01-15',
|
|
'check_in_at' => '2024-01-15 08:30:00',
|
|
]);
|
|
|
|
$response = $this->get(route('admin.hr.attendances.index', ['year' => 2024, 'month' => 1]));
|
|
$response->assertOk();
|
|
$response->assertInertia(fn (Assert $page) => $page
|
|
->has('attendances.data', 2)
|
|
->where('attendances.total', 2)
|
|
->where('attendances.current_page', 1)
|
|
->where('attendances.per_page', 25)
|
|
);
|
|
});
|
|
|
|
test('employee can have multiple attendances across different days', function () {
|
|
$user = User::factory()->create();
|
|
$this->actingAs($user);
|
|
|
|
$employeeUser = User::factory()->create();
|
|
$employeeUser->employee()->create([
|
|
'join_date' => '2024-01-01',
|
|
'employment_status' => 'full_time',
|
|
'base_salary' => 5000000,
|
|
]);
|
|
|
|
Attendance::factory()->create([
|
|
'employee_id' => $employeeUser->employee->id,
|
|
'attendance_date' => '2024-01-15',
|
|
'check_in_at' => '2024-01-15 08:00:00',
|
|
]);
|
|
|
|
Attendance::factory()->create([
|
|
'employee_id' => $employeeUser->employee->id,
|
|
'attendance_date' => '2024-01-16',
|
|
'check_in_at' => '2024-01-16 08:00:00',
|
|
]);
|
|
|
|
Attendance::factory()->create([
|
|
'employee_id' => $employeeUser->employee->id,
|
|
'attendance_date' => '2024-01-17',
|
|
'check_in_at' => '2024-01-17 08:00:00',
|
|
]);
|
|
|
|
$response = $this->get(route('admin.hr.attendances.index', ['year' => 2024, 'month' => 1]));
|
|
$response->assertOk();
|
|
$response->assertInertia(fn (Assert $page) => $page
|
|
->has('attendances.data', 3)
|
|
->where('attendances.total', 3)
|
|
->where('attendances.current_page', 1)
|
|
->where('attendances.per_page', 25)
|
|
);
|
|
});
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| DATA INTEGRITY
|
|
|--------------------------------------------------------------------------
|
|
*/
|
|
|
|
test('attendance stores correct check-in coordinates', function () {
|
|
$user = User::factory()->create();
|
|
$this->actingAs($user);
|
|
|
|
$employee = Employee::factory()->create([
|
|
'user_id' => $user->id,
|
|
'join_date' => now()->subMonth()->toDateString(),
|
|
'employment_status' => 'full_time',
|
|
'base_salary' => 5000000,
|
|
]);
|
|
|
|
$this->post(route('admin.hr.attendances.store'), [
|
|
'photo' => 'data:image/jpeg;base64,'.base64_encode('fake-image'),
|
|
'latitude' => -6.2088,
|
|
'longitude' => 106.8456,
|
|
]);
|
|
|
|
$attendance = Attendance::where('employee_id', $employee->id)->first();
|
|
$this->assertEquals(-6.2088, $attendance->check_in_latitude);
|
|
$this->assertEquals(106.8456, $attendance->check_in_longitude);
|
|
});
|
|
|
|
test('attendance has correct attendance_date', function () {
|
|
$user = User::factory()->create();
|
|
$this->actingAs($user);
|
|
|
|
$employee = Employee::factory()->create([
|
|
'user_id' => $user->id,
|
|
'join_date' => now()->subMonth()->toDateString(),
|
|
'employment_status' => 'full_time',
|
|
'base_salary' => 5000000,
|
|
]);
|
|
|
|
$this->post(route('admin.hr.attendances.store'), [
|
|
'photo' => 'data:image/jpeg;base64,'.base64_encode('fake-image'),
|
|
'latitude' => -6.2088,
|
|
'longitude' => 106.8456,
|
|
]);
|
|
|
|
$this->assertDatabaseHas('attendances', [
|
|
'employee_id' => $employee->id,
|
|
'attendance_date' => now()->toDateString(),
|
|
]);
|
|
});
|
|
|
|
test('check-in sets check_out_at to null', function () {
|
|
$user = User::factory()->create();
|
|
$this->actingAs($user);
|
|
|
|
$employee = Employee::factory()->create([
|
|
'user_id' => $user->id,
|
|
'join_date' => now()->subMonth()->toDateString(),
|
|
'employment_status' => 'full_time',
|
|
'base_salary' => 5000000,
|
|
]);
|
|
|
|
$this->post(route('admin.hr.attendances.store'), [
|
|
'photo' => 'data:image/jpeg;base64,'.base64_encode('fake-image'),
|
|
'latitude' => -6.2088,
|
|
'longitude' => 106.8456,
|
|
]);
|
|
|
|
$attendance = Attendance::where('employee_id', $employee->id)->first();
|
|
$this->assertNull($attendance->check_out_at);
|
|
});
|