EAS-202310715297/backend/test_absensi_integration.py
2026-05-10 21:40:06 +07:00

137 lines
5.3 KiB
Python

import pytest
import json
from unittest.mock import patch
import app as flask_app # Asumsi file utamamu bernama app.py
# ==========================================
# FIXTURE: Setup Lingkungan Testing
# ==========================================
@pytest.fixture
def setup_client():
# 1. Override nama database ke database khusus testing
flask_app.DB_CONFIG['database'] = 'db_absensi_test'
flask_app.init_database()
# 2. Buka koneksi dan Seed Data Dummy
conn = flask_app.get_db_connection()
cur = conn.cursor()
# Seed Mahasiswa
hashed_pw = flask_app.bcrypt.hashpw(b'Password123', flask_app.bcrypt.gensalt()).decode()
cur.execute("""
INSERT INTO mahasiswa (npm, password, nama, jenkel, fakultas, jurusan, semester, device_id)
VALUES ('202310715297', %s, 'Ariq', 'L', 'Fasilkom', 'Informatika', 6, 'device_sah_01')
""", (hashed_pw,))
# Seed Mata Kuliah
cur.execute("INSERT INTO mata_kuliah (kode_matkul, nama_matkul, sks, dosen) VALUES ('IF123', 'Integration Testing', 3, 'Tim QA')")
id_matkul = cur.lastrowid
# Seed Jadwal (Diset 00:00 - 23:59 hari ini agar [FIX 6] selalu lolos saat testing kapan pun)
hari_ini = flask_app.get_hari_indo()
cur.execute("""
INSERT INTO jadwal_kelas (id_matkul, hari, jam_mulai, jam_selesai, ruangan, jurusan, semester)
VALUES (%s, %s, '00:00:00', '23:59:59', 'Lab RPL', 'Informatika', 6)
""", (id_matkul, hari_ini))
id_jadwal = cur.lastrowid
conn.commit()
cur.close()
conn.close()
# 3. Jalankan Client Testing
with flask_app.app.test_client() as client:
yield client, id_jadwal
# 4. Teardown: Bersihkan/Drop database testing setelah selesai
conn = flask_app.get_db_connection()
cur = conn.cursor()
cur.execute("DROP DATABASE db_absensi_test")
cur.close()
conn.close()
# ==========================================
# SKENARIO INTEGRATION TESTING
# ==========================================
def test_it001_login_berhasil_dan_jwt_terbit(setup_client):
client, _ = setup_client
response = client.post('/api/auth/login', json={
"npm": "202310715297",
"password": "Password123",
"device_id": "device_sah_01"
})
data = json.loads(response.data)
assert response.status_code == 200
assert "token" in data['data']
assert data["message"] == "Login berhasil"
def test_it002_login_ditolak_device_berbeda(setup_client):
client, _ = setup_client
response = client.post('/api/auth/login', json={
"npm": "202310715297",
"password": "Password123",
"device_id": "device_ilegal_999" # [FIX 3] Memicu device binding error
})
assert response.status_code == 403
assert "terdaftar di perangkat lain" in json.loads(response.data)["error"]
def test_it003_request_location_token_berhasil(setup_client):
client, _ = setup_client
# Login ambil token
res_login = client.post('/api/auth/login', json={"npm": "202310715297", "password": "Password123", "device_id": "device_sah_01"})
jwt_token = json.loads(res_login.data)['data']['token']
# Koordinat di-offset sedikit dari KAMPUS_LATITUDE agar lolos [FIX 8] (Anomali Koordinat Identik)
# tetapi tetap masuk dalam radius 500m
lat_valid = flask_app.KAMPUS_LATITUDE + 0.0001
lon_valid = flask_app.KAMPUS_LONGITUDE + 0.0001
res_loc = client.post('/api/absensi/request-location-token',
json={"latitude": lat_valid, "longitude": lon_valid},
headers={'Authorization': f'Bearer {jwt_token}'}
)
data_loc = json.loads(res_loc.data)
assert res_loc.status_code == 200
assert "location_token" in data_loc
assert data_loc["expires_in_seconds"] == 120
@patch('app.requests.post') # Mock eksekusi jaringan eksternal (webhook) agar tidak hit API luar
@patch('app.validasi_foto') # Mock validasi foto agar tidak perlu kirim base64 5KB+ di script test
def test_it005_e2e_absensi_berhasil(mock_validasi_foto, mock_requests_post, setup_client):
client, id_jadwal = setup_client
mock_validasi_foto.return_value = (True, "OK")
# 1. Login
res_login = client.post('/api/auth/login', json={"npm": "202310715297", "password": "Password123", "device_id": "device_sah_01"})
jwt_token = json.loads(res_login.data)['data']['token']
# 2. Minta Location Token [FIX 7]
lat_valid = flask_app.KAMPUS_LATITUDE + 0.0001
lon_valid = flask_app.KAMPUS_LONGITUDE + 0.0001
res_loc = client.post('/api/absensi/request-location-token',
json={"latitude": lat_valid, "longitude": lon_valid},
headers={'Authorization': f'Bearer {jwt_token}'}
)
loc_token = json.loads(res_loc.data)['location_token']
# 3. Submit Absensi E2E
absensi_payload = {
"location_token": loc_token,
"id_jadwal": id_jadwal,
"foto_base64": "data:image/jpeg;base64,mocked_base64_string",
"status": "HADIR"
}
res_submit = client.post('/api/absensi/submit',
json=absensi_payload,
headers={'Authorization': f'Bearer {jwt_token}'}
)
assert res_submit.status_code == 201
assert json.loads(res_submit.data)['message'] == "Absensi berhasil disimpan"