Initial commit
This commit is contained in:
commit
701fd59bb4
|
|
@ -0,0 +1,17 @@
|
|||
# Virtual Environment
|
||||
venv/
|
||||
|
||||
# Python
|
||||
__pycache__/
|
||||
*.pyc
|
||||
|
||||
# Pytest
|
||||
.pytest_cache/
|
||||
|
||||
# Selenium
|
||||
chromedriver*
|
||||
screenshots/
|
||||
|
||||
# OS
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
# Selenium Automated Testing Project
|
||||
|
||||
Project ini digunakan untuk pengujian otomatis website
|
||||
Adaptive Metacognitive Hypermedia Learning Environment (AMetative HLE)
|
||||
menggunakan Selenium WebDriver dan framework pytest.
|
||||
|
||||
## Tools & Tech Stack
|
||||
- Python 3.x
|
||||
- Selenium WebDriver
|
||||
- Pytest
|
||||
- WebDriver Manager
|
||||
|
||||
## Cara Menjalankan Test
|
||||
1. Clone repository
|
||||
2. Install dependencies
|
||||
pip install -r requirements.txt
|
||||
3. Jalankan test
|
||||
pytest -v
|
||||
|
||||
## Jenis Pengujian
|
||||
- Functional Testing
|
||||
- Integration Testing
|
||||
- Automated Regression Test
|
||||
|
||||
## Author
|
||||
Rurin Haliza
|
||||
|
||||
|
|
@ -0,0 +1,224 @@
|
|||
import os
|
||||
import pytest
|
||||
from datetime import datetime
|
||||
from selenium import webdriver
|
||||
from selenium.webdriver.chrome.service import Service
|
||||
from selenium.webdriver.chrome.options import Options
|
||||
|
||||
from pages.register_page import RegisterPage
|
||||
from utils.data_generator import generate_valid_register_data
|
||||
from pages.login_page import LoginPage
|
||||
from pages.dashboard_page import DashboardPage
|
||||
|
||||
|
||||
# ===============================
|
||||
# FIXTURE DRIVER
|
||||
# ===============================
|
||||
@pytest.fixture(scope="function")
|
||||
def driver():
|
||||
options = Options()
|
||||
options.add_argument("--start-maximized")
|
||||
|
||||
service = Service()
|
||||
driver = webdriver.Chrome(service=service, options=options)
|
||||
|
||||
yield driver
|
||||
driver.quit()
|
||||
|
||||
# ===============================
|
||||
# FIXTURE REGISTER PAGE
|
||||
# ===============================
|
||||
@pytest.fixture
|
||||
def register_page(driver):
|
||||
page = RegisterPage(driver)
|
||||
page.open()
|
||||
return page
|
||||
|
||||
# ===============================
|
||||
# DATA REGISTER VALID (FINAL)
|
||||
# ===============================
|
||||
@pytest.fixture
|
||||
def valid_register_data():
|
||||
"""
|
||||
- Data selalu VALID
|
||||
- Data SELALU BARU setiap test
|
||||
- Field boleh dioverride di test
|
||||
"""
|
||||
data = generate_valid_register_data()
|
||||
|
||||
# pastikan field WAJIB selalu ada
|
||||
data.setdefault("nama_lengkap", data["nama"])
|
||||
data.setdefault("konfirmasi_password", data["password"])
|
||||
|
||||
return data
|
||||
|
||||
# ===============================
|
||||
# SCREENSHOT SAAT FAIL
|
||||
# ===============================
|
||||
@pytest.hookimpl(hookwrapper=True)
|
||||
def pytest_runtest_makereport(item, call):
|
||||
"""
|
||||
Ambil screenshot otomatis jika test FAIL
|
||||
"""
|
||||
outcome = yield
|
||||
rep = outcome.get_result()
|
||||
|
||||
if rep.when == "call" and rep.failed:
|
||||
driver = item.funcargs.get("driver")
|
||||
if driver:
|
||||
screenshots_dir = "screenshots"
|
||||
os.makedirs(screenshots_dir, exist_ok=True)
|
||||
|
||||
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
||||
file_path = os.path.join(
|
||||
screenshots_dir,
|
||||
f"{item.name}_{timestamp}.png"
|
||||
)
|
||||
|
||||
driver.save_screenshot(file_path)
|
||||
print(f"\n📸 Screenshot saved: {file_path}")
|
||||
|
||||
# ===============================
|
||||
# FIXTURE LOGIN PAGE
|
||||
# ===============================
|
||||
@pytest.fixture
|
||||
def login_page(driver):
|
||||
page = LoginPage(driver)
|
||||
page.open()
|
||||
return page
|
||||
|
||||
# =========================
|
||||
# LOGIN FIXTURES FOR TEST
|
||||
# =========================
|
||||
|
||||
@pytest.fixture
|
||||
def login_as_user_belum_kuesioner(driver):
|
||||
"""
|
||||
User valid, BELUM pernah mengisi kuesioner
|
||||
Digunakan untuk:
|
||||
- popup dashboard
|
||||
- status KM / RM kosong
|
||||
"""
|
||||
|
||||
login_page = LoginPage(driver)
|
||||
login_page.open()
|
||||
|
||||
login_page.fill_email("e41222052@student.polije.ac.id")
|
||||
login_page.fill_password("e41222052@student.polije.ac.id")
|
||||
login_page.submit()
|
||||
|
||||
dashboard = DashboardPage(driver)
|
||||
dashboard.open()
|
||||
|
||||
return driver
|
||||
|
||||
@pytest.fixture
|
||||
def login_as_user_sudah_kuesioner(driver):
|
||||
"""
|
||||
User valid, SUDAH pernah mengisi kuesioner
|
||||
Digunakan untuk:
|
||||
- status KM / RM tersedia
|
||||
- tidak ada popup
|
||||
"""
|
||||
|
||||
login_page = LoginPage(driver)
|
||||
login_page.open()
|
||||
|
||||
# Akun yang SUDAH isi kuesioner
|
||||
login_page.fill_email("tester@polije.ac.id")
|
||||
login_page.fill_password("tester@polije.ac.id")
|
||||
login_page.submit()
|
||||
|
||||
dashboard = DashboardPage(driver)
|
||||
dashboard.open()
|
||||
|
||||
return driver
|
||||
|
||||
@pytest.fixture
|
||||
def login_as_user_belum_kuesioner2(driver):
|
||||
"""
|
||||
User valid, SUDAH pernah mengisi kuesioner
|
||||
Digunakan untuk:
|
||||
- status KM / RM tersedia
|
||||
- tidak ada popup
|
||||
"""
|
||||
|
||||
login_page = LoginPage(driver)
|
||||
login_page.open()
|
||||
|
||||
# Akun yang SUDAH isi kuesioner
|
||||
login_page.fill_email("akuntesting2@polije.ac.id")
|
||||
login_page.fill_password("akuntesting2@polije.ac.id")
|
||||
login_page.submit()
|
||||
|
||||
dashboard = DashboardPage(driver)
|
||||
dashboard.open()
|
||||
|
||||
return driver
|
||||
|
||||
#Account For Regression
|
||||
@pytest.fixture
|
||||
def login_as_user_belum_kuesionerNew(driver):
|
||||
"""
|
||||
User valid, SUDAH pernah mengisi kuesioner
|
||||
Digunakan untuk:
|
||||
- status KM / RM tersedia
|
||||
- tidak ada popup
|
||||
"""
|
||||
|
||||
login_page = LoginPage(driver)
|
||||
login_page.open()
|
||||
|
||||
# Akun yang SUDAH isi kuesioner
|
||||
login_page.fill_email("tester2@polije.ac.id")
|
||||
login_page.fill_password("tester2@polije.ac.id")
|
||||
login_page.submit()
|
||||
|
||||
dashboard = DashboardPage(driver)
|
||||
dashboard.open()
|
||||
|
||||
return driver
|
||||
|
||||
@pytest.fixture
|
||||
def login_as_user_belum_kuesionerNew2(driver):
|
||||
"""
|
||||
User valid, SUDAH pernah mengisi kuesioner
|
||||
Digunakan untuk:
|
||||
- status KM / RM tersedia
|
||||
- tidak ada popup
|
||||
"""
|
||||
|
||||
login_page = LoginPage(driver)
|
||||
login_page.open()
|
||||
|
||||
# Akun yang SUDAH isi kuesioner
|
||||
login_page.fill_email("iniemail@polije.ac.id")
|
||||
login_page.fill_password("inipassword")
|
||||
login_page.submit()
|
||||
|
||||
dashboard = DashboardPage(driver)
|
||||
dashboard.open()
|
||||
|
||||
return driver
|
||||
|
||||
@pytest.fixture
|
||||
def login_as_user_sudah_kuesioner3(driver):
|
||||
"""
|
||||
User valid, SUDAH pernah mengisi kuesioner
|
||||
Digunakan untuk:
|
||||
- status KM / RM tersedia
|
||||
- tidak ada popup
|
||||
"""
|
||||
|
||||
login_page = LoginPage(driver)
|
||||
login_page.open()
|
||||
|
||||
# Akun yang SUDAH isi kuesioner
|
||||
login_page.fill_email("sudah@polije.ac.id")
|
||||
login_page.fill_password("sudah@polije.ac.id")
|
||||
login_page.submit()
|
||||
|
||||
dashboard = DashboardPage(driver)
|
||||
dashboard.open()
|
||||
|
||||
return driver
|
||||
|
|
@ -0,0 +1,206 @@
|
|||
from selenium.webdriver.common.by import By
|
||||
from selenium.webdriver.support.ui import WebDriverWait
|
||||
from selenium.webdriver.support import expected_conditions as EC
|
||||
import re
|
||||
|
||||
|
||||
class DashboardPage:
|
||||
URL = "https://hypermedialearning.project2025.id/public/dashboard"
|
||||
|
||||
# ===== POPUP (MODAL) =====
|
||||
POPUP_MODAL = (By.ID, "kuesionerModal")
|
||||
|
||||
BTN_ISI_KUESIONER_POPUP = (
|
||||
By.XPATH, "//div[@id='kuesionerModal']//a[contains(text(),'Isi Kuesioner')]"
|
||||
)
|
||||
|
||||
BTN_TUTUP_POPUP = (
|
||||
By.XPATH, "//div[@id='kuesionerModal']//button[contains(text(),'Tutup')]"
|
||||
)
|
||||
|
||||
BTN_CLOSE_X = (
|
||||
By.XPATH, "//div[@id='kuesionerModal']//button[@aria-label='Close']"
|
||||
)
|
||||
|
||||
MODAL_KUESIONER = (By.ID, "kuesionerModal")
|
||||
|
||||
BTN_TUTUP_MODAL = (
|
||||
By.XPATH,
|
||||
"//button[contains(text(),'Nanti') or contains(text(),'Tutup')]"
|
||||
)
|
||||
|
||||
KM_VALUE = (
|
||||
By.XPATH,
|
||||
"//span[normalize-space()='Knowledge of Metakognitif (KM)']"
|
||||
"/ancestor::div[contains(@class,'card')]"
|
||||
"//span[normalize-space()='Nilai']/following-sibling::span"
|
||||
)
|
||||
|
||||
RM_VALUE = (
|
||||
By.XPATH,
|
||||
"//span[normalize-space()='Regulation of Metakognitif (RM)']"
|
||||
"/ancestor::div[contains(@class,'card')]"
|
||||
"//span[normalize-space()='Nilai']/following-sibling::span"
|
||||
)
|
||||
|
||||
LEARNING_STYLE_VALUE = (
|
||||
By.XPATH,
|
||||
"//span[normalize-space()='Learning Style']"
|
||||
"/ancestor::div[contains(@class,'card')]"
|
||||
"//span[normalize-space()='Gaya Belajar']/following-sibling::span"
|
||||
)
|
||||
|
||||
PENGISIAN_KUESIONER_SECTION = (
|
||||
By.XPATH,
|
||||
"//h6[normalize-space()='Pengisian Kuesioner']/ancestor::div[contains(@class,'card')]"
|
||||
)
|
||||
|
||||
KUESIONER_VARK_MAI_TEXT = (
|
||||
By.XPATH,
|
||||
"//td[normalize-space()='Kuesioner VARK dan MAI']"
|
||||
)
|
||||
|
||||
ISI_KUESIONER_BUTTON = (
|
||||
By.XPATH,
|
||||
"//a[@href='https://hypermedialearning.sanggadewa.my.id/kuesioner-panduan']"
|
||||
)
|
||||
|
||||
|
||||
|
||||
def __init__(self, driver):
|
||||
self.driver = driver
|
||||
self.wait = WebDriverWait(driver, 15)
|
||||
|
||||
def open(self):
|
||||
self.driver.get(self.URL)
|
||||
|
||||
# POM for test dashboard PopUp
|
||||
|
||||
def is_popup_visible(self):
|
||||
try:
|
||||
self.wait.until(
|
||||
EC.visibility_of_element_located(self.POPUP_MODAL)
|
||||
)
|
||||
return True
|
||||
except:
|
||||
return False
|
||||
|
||||
def click_isi_kuesioner_pop_up(self):
|
||||
self.wait.until(
|
||||
EC.element_to_be_clickable(self.BTN_ISI_KUESIONER_POPUP)
|
||||
).click()
|
||||
|
||||
def close_popup_with_x(self):
|
||||
btn = self.wait.until(
|
||||
EC.visibility_of_element_located(self.BTN_CLOSE_X)
|
||||
)
|
||||
btn.click()
|
||||
self.wait_popup_disappear()
|
||||
|
||||
def is_redirected_to_kuesioner(self):
|
||||
self.wait.until(lambda d: "kuesioner" in d.current_url)
|
||||
return True
|
||||
|
||||
def wait_popup_disappear(self):
|
||||
self.wait.until(
|
||||
EC.invisibility_of_element_located(self.POPUP_MODAL)
|
||||
)
|
||||
|
||||
#POM for Test Dashboard KMRM
|
||||
|
||||
def close_kuesioner_popup_if_present(self):
|
||||
btn = self.wait.until(
|
||||
EC.visibility_of_element_located(self.BTN_CLOSE_X)
|
||||
)
|
||||
btn.click()
|
||||
self.wait_popup_disappear()
|
||||
|
||||
def get_km_status_text(self):
|
||||
return self.wait.until(
|
||||
EC.visibility_of_element_located(self.KM_VALUE)
|
||||
).text.strip()
|
||||
|
||||
def get_rm_status_text(self):
|
||||
return self.wait.until(
|
||||
EC.visibility_of_element_located(self.RM_VALUE)
|
||||
).text.strip()
|
||||
|
||||
def is_km_not_filled(self):
|
||||
return self.get_km_status_text() == "()"
|
||||
|
||||
def is_rm_not_filled(self):
|
||||
return self.get_rm_status_text() == "()"
|
||||
|
||||
def is_km_filled(self):
|
||||
el = self.wait.until(
|
||||
EC.visibility_of_element_located(self.KM_VALUE)
|
||||
)
|
||||
return el.text.strip()
|
||||
|
||||
def is_rm_filled(self):
|
||||
el = self.wait.until(
|
||||
EC.visibility_of_element_located(self.RM_VALUE)
|
||||
)
|
||||
return el.text.strip()
|
||||
|
||||
#POM for Learning Style
|
||||
|
||||
def get_learning_style_text(self) -> str:
|
||||
el = self.wait.until(
|
||||
EC.visibility_of_element_located(self.LEARNING_STYLE_VALUE)
|
||||
)
|
||||
return el.text.strip()
|
||||
|
||||
def is_learning_style_not_filled(self) -> bool:
|
||||
return self.get_learning_style_text() == "(Tidak diketahui)"
|
||||
|
||||
def is_learning_style_filled(self) -> bool:
|
||||
text = self.get_learning_style_text()
|
||||
return text != "" and text != "(Tidak diketahui)"
|
||||
|
||||
#POM for Pengisian Kuesioner
|
||||
def is_pengisian_kuesioner_section_visible(self) -> bool:
|
||||
try:
|
||||
self.wait.until(
|
||||
EC.visibility_of_element_located(
|
||||
self.PENGISIAN_KUESIONER_SECTION
|
||||
)
|
||||
)
|
||||
return True
|
||||
except:
|
||||
return False
|
||||
|
||||
def is_kuesioner_vark_mai_visible(self) -> bool:
|
||||
try:
|
||||
self.wait.until(
|
||||
EC.visibility_of_element_located(
|
||||
self.KUESIONER_VARK_MAI_TEXT
|
||||
)
|
||||
)
|
||||
return True
|
||||
except:
|
||||
return False
|
||||
|
||||
def click_isi_kuesioner(self):
|
||||
self.wait.until(
|
||||
EC.element_to_be_clickable(
|
||||
self.ISI_KUESIONER_BUTTON
|
||||
)
|
||||
).click()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,186 @@
|
|||
from selenium.webdriver.common.by import By
|
||||
from selenium.webdriver.support.ui import WebDriverWait
|
||||
from selenium.webdriver.support import expected_conditions as EC
|
||||
|
||||
|
||||
class HistoryKuesionerPage:
|
||||
|
||||
URL = "https://hypermedialearning.sanggadewa.my.id/history_quis"
|
||||
|
||||
# ===== SIDEBAR =====
|
||||
SIDEBAR_HISTORY = (
|
||||
By.XPATH,
|
||||
"//li[contains(@class,'menu-item') and .//div[normalize-space()='History Kuisioner']]"
|
||||
)
|
||||
|
||||
# ===== SKOR GAYA BELAJAR =====
|
||||
SCORE_CONTAINER = (By.CSS_SELECTOR, "div.card")
|
||||
SCORE_LABELS = (By.CSS_SELECTOR, "div.score-label")
|
||||
SCORE_VALUES = (By.CSS_SELECTOR, "div.score-value")
|
||||
|
||||
LEARNING_STYLE_CARD = (
|
||||
By.XPATH,
|
||||
"//div[contains(@class,'card') and .//div[text()='Visual']]"
|
||||
)
|
||||
|
||||
LEARNING_STYLE_LABELS = (
|
||||
By.XPATH,
|
||||
"//div[contains(@class,'card') and .//div[text()='Visual']]//div[@class='score-label']"
|
||||
)
|
||||
|
||||
LEARNING_STYLE_VALUES = (
|
||||
By.XPATH,
|
||||
"//div[contains(@class,'card') and .//div[text()='Visual']]//div[@class='score-value']"
|
||||
)
|
||||
|
||||
LEARNING_STYLE_ITEMS = (
|
||||
By.CSS_SELECTOR,
|
||||
"div.card.shadow.border-0.p-4 > div.row.text-center > div.col-6.col-md-3"
|
||||
)
|
||||
|
||||
# ===== PROGRESS =====
|
||||
PROGRESS_BAR = (By.CSS_SELECTOR, "div.progress-bar")
|
||||
PROGRESS_TEXT = (
|
||||
By.XPATH,
|
||||
"//small[contains(text(),'pertanyaan dijawab')]"
|
||||
)
|
||||
|
||||
# ===== GAYA BELAJAR DOMINAN =====
|
||||
DOMINANT_STYLE_TEXT = (
|
||||
By.XPATH,
|
||||
"//h2[contains(@class,'fw-bold')]"
|
||||
)
|
||||
|
||||
BTN_MULAI_BELAJAR = (
|
||||
By.XPATH,
|
||||
"//a[contains(@href,'/materi') and contains(.,'Mulai')]"
|
||||
)
|
||||
|
||||
# ===== KM & RM =====
|
||||
KM_VALUE = (
|
||||
By.XPATH,
|
||||
"//div[normalize-space()='KM']/following-sibling::div[contains(@class,'score-value')]"
|
||||
)
|
||||
|
||||
RM_VALUE = (
|
||||
By.XPATH,
|
||||
"//div[normalize-space()='RM']/following-sibling::div[contains(@class,'score-value')]"
|
||||
)
|
||||
|
||||
# ===== RIWAYAT =====
|
||||
TABLE_ROWS = (By.CSS_SELECTOR, "table.table tbody tr")
|
||||
|
||||
# ===== AKSI =====
|
||||
BTN_MULAI_BELAJAR = (
|
||||
By.XPATH,
|
||||
"//a[contains(@href,'/materi')]"
|
||||
)
|
||||
|
||||
BTN_UBAH = (
|
||||
By.XPATH,
|
||||
"//a[contains(@href,'kuesioner')]"
|
||||
)
|
||||
|
||||
BTN_UNDUH = (
|
||||
By.XPATH,
|
||||
"//a[contains(@href,'user-result')]"
|
||||
)
|
||||
|
||||
def __init__(self, driver):
|
||||
self.driver = driver
|
||||
self.wait = WebDriverWait(driver, 10)
|
||||
|
||||
def open(self):
|
||||
self.driver.get(self.URL)
|
||||
|
||||
def is_page_loaded(self):
|
||||
self.wait.until(EC.presence_of_element_located(self.SIDEBAR_HISTORY))
|
||||
return True
|
||||
|
||||
def get_scores(self):
|
||||
"""
|
||||
Return skor gaya belajar saja.
|
||||
PASSED = benar-benar 4 gaya belajar.
|
||||
"""
|
||||
items = self.wait.until(
|
||||
lambda d: d.find_elements(*self.LEARNING_STYLE_ITEMS)
|
||||
)
|
||||
|
||||
assert len(items) == 4, f"Expected 4 learning styles, found {len(items)}"
|
||||
|
||||
scores = {}
|
||||
for item in items:
|
||||
label = item.find_element(By.CSS_SELECTOR, ".score-label").text.strip()
|
||||
value = item.find_element(By.CSS_SELECTOR, ".score-value").text.strip()
|
||||
scores[label] = value
|
||||
|
||||
return scores
|
||||
|
||||
def get_score_labels(self):
|
||||
# tunggu card halaman muncul dulu
|
||||
self.wait.until(
|
||||
EC.presence_of_element_located(self.SCORE_CONTAINER)
|
||||
)
|
||||
|
||||
# baru ambil labels
|
||||
self.wait.until(
|
||||
lambda d: len(d.find_elements(*self.SCORE_LABELS)) >= 4
|
||||
)
|
||||
|
||||
return [
|
||||
e.text.strip()
|
||||
for e in self.driver.find_elements(*self.SCORE_LABELS)
|
||||
if e.text.strip() != ""
|
||||
]
|
||||
|
||||
def get_score_values(self):
|
||||
self.wait.until(
|
||||
lambda d: all(
|
||||
e.text.strip().isdigit()
|
||||
for e in d.find_elements(*self.LEARNING_STYLE_VALUES)
|
||||
)
|
||||
)
|
||||
return [e.text.strip() for e in self.driver.find_elements(*self.LEARNING_STYLE_VALUES)]
|
||||
|
||||
def get_progress_value(self):
|
||||
bar = self.wait.until(EC.presence_of_element_located(self.PROGRESS_BAR))
|
||||
return bar.get_attribute("aria-valuenow")
|
||||
|
||||
def get_progress_text(self):
|
||||
return self.driver.find_element(*self.PROGRESS_TEXT).text
|
||||
|
||||
def get_dominant_style(self):
|
||||
return self.wait.until(
|
||||
EC.presence_of_element_located(self.DOMINANT_STYLE_TEXT)
|
||||
).text.strip()
|
||||
|
||||
def click_mulai(self):
|
||||
button = self.wait.until(
|
||||
EC.presence_of_element_located(self.BTN_MULAI_BELAJAR)
|
||||
)
|
||||
|
||||
# Scroll ke elemen (cukup)
|
||||
self.driver.execute_script(
|
||||
"arguments[0].scrollIntoView({block: 'center'});", button
|
||||
)
|
||||
|
||||
# Klik pakai JS (paling stabil untuk <a>)
|
||||
self.driver.execute_script("arguments[0].click();", button)
|
||||
|
||||
def get_km_value(self):
|
||||
return self.driver.find_element(*self.KM_VALUE).text.lower()
|
||||
|
||||
def get_rm_value(self):
|
||||
return self.driver.find_element(*self.RM_VALUE).text.lower()
|
||||
|
||||
def get_history_rows(self):
|
||||
return self.driver.find_elements(*self.TABLE_ROWS)
|
||||
|
||||
def click_ubah(self):
|
||||
self.wait.until(EC.element_to_be_clickable(self.BTN_UBAH)).click()
|
||||
|
||||
def click_unduh(self):
|
||||
button = self.wait.until(EC.element_to_be_clickable(self.BTN_UNDUH))
|
||||
self.driver.execute_script("arguments[0].scrollIntoView(true);", button)
|
||||
self.driver.execute_script("arguments[0].click();", button)
|
||||
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
from selenium.webdriver.common.by import By
|
||||
from selenium.webdriver.support.ui import WebDriverWait
|
||||
from selenium.webdriver.support import expected_conditions as EC
|
||||
|
||||
class KuesionerLSPage:
|
||||
|
||||
DASHBOARD_MENU = (
|
||||
By.XPATH,
|
||||
"//a[contains(@href,'dashboard') or .//div[normalize-space()='Dashboard']]"
|
||||
)
|
||||
|
||||
SUBMIT_BUTTON = (
|
||||
By.XPATH, "//button[normalize-space()='Simpan Jawaban']"
|
||||
)
|
||||
|
||||
KUESIONER_MENU = (
|
||||
By.XPATH,
|
||||
"//a[contains(@href,'kuesioner-panduan') and .//div[normalize-space()='Kuesioner']]"
|
||||
)
|
||||
|
||||
MULAI_KUESIONER_BUTTON = (
|
||||
By.XPATH,
|
||||
"//a[contains(@href,'/kuesioner-ls') and normalize-space()='Mulai Kuesioner']"
|
||||
)
|
||||
|
||||
def __init__(self, driver):
|
||||
self.driver = driver
|
||||
self.wait = WebDriverWait(driver, 10)
|
||||
|
||||
def open_from_sidebar(self):
|
||||
self.wait.until(
|
||||
EC.element_to_be_clickable(self.KUESIONER_MENU)
|
||||
).click()
|
||||
|
||||
def click_mulai_kuesioner(self):
|
||||
self.wait.until(
|
||||
EC.element_to_be_clickable(self.MULAI_KUESIONER_BUTTON)
|
||||
).click()
|
||||
|
||||
def answer_question(self, question_number, option_index=0):
|
||||
"""
|
||||
option_index: 0-3 (LS punya 4 opsi)
|
||||
"""
|
||||
options = self.wait.until(
|
||||
EC.presence_of_all_elements_located(
|
||||
(By.NAME, f"soal{question_number}")
|
||||
)
|
||||
)
|
||||
|
||||
option = options[option_index]
|
||||
|
||||
# WAJIB scroll dulu
|
||||
self.driver.execute_script(
|
||||
"arguments[0].scrollIntoView({block: 'center'});", option
|
||||
)
|
||||
|
||||
self.wait.until(EC.element_to_be_clickable(option)).click()
|
||||
|
||||
|
||||
def answer_all_questions(self, total_questions=16):
|
||||
for i in range(1, total_questions + 1):
|
||||
self.answer_question(i)
|
||||
|
||||
def submit(self):
|
||||
button = self.wait.until(
|
||||
EC.presence_of_element_located(self.SUBMIT_BUTTON)
|
||||
)
|
||||
|
||||
self.driver.execute_script(
|
||||
"arguments[0].scrollIntoView({block: 'center'});", button
|
||||
)
|
||||
|
||||
self.wait.until(EC.element_to_be_clickable(self.SUBMIT_BUTTON)).click()
|
||||
|
||||
def force_navigate_to_dashboard(self):
|
||||
menu = self.wait.until(
|
||||
EC.presence_of_element_located(self.DASHBOARD_MENU)
|
||||
)
|
||||
|
||||
self.driver.execute_script(
|
||||
"arguments[0].scrollIntoView({block: 'center'});", menu
|
||||
)
|
||||
|
||||
self.wait.until(EC.element_to_be_clickable(self.DASHBOARD_MENU)).click()
|
||||
|
||||
|
|
@ -0,0 +1,101 @@
|
|||
from selenium.webdriver.common.by import By
|
||||
from selenium.webdriver.support.ui import WebDriverWait
|
||||
from selenium.webdriver.support import expected_conditions as EC
|
||||
|
||||
class KuesionerMAIPage:
|
||||
|
||||
TITLE = (
|
||||
By.XPATH,
|
||||
"//h3[contains(text(),'Kuesioner Metakognitif')]"
|
||||
)
|
||||
|
||||
SUBMIT_BUTTON = (
|
||||
By.XPATH,
|
||||
"//button[normalize-space()='Simpan Jawaban']"
|
||||
)
|
||||
|
||||
KUESIONER_MENU = (
|
||||
By.XPATH,
|
||||
"//a[contains(@href,'kuesioner-panduan') and .//div[normalize-space()='Kuesioner']]"
|
||||
)
|
||||
|
||||
MULAI_KUESIONER_BUTTON = (
|
||||
By.XPATH,
|
||||
"//a[contains(@href,'/kuesioner-ls') and normalize-space()='Mulai Kuesioner']"
|
||||
)
|
||||
|
||||
def __init__(self, driver):
|
||||
self.driver = driver
|
||||
self.wait = WebDriverWait(driver, 15)
|
||||
|
||||
def wait_until_loaded(self):
|
||||
self.wait.until(
|
||||
EC.presence_of_element_located(self.TITLE)
|
||||
)
|
||||
|
||||
def answer_question_mai(self, question_number, option_index=0):
|
||||
"""
|
||||
option_index: 0–4 (nilai 0–4)
|
||||
"""
|
||||
radios = self.driver.find_elements(
|
||||
By.NAME, f"soal{question_number}"
|
||||
)
|
||||
|
||||
target = radios[option_index]
|
||||
|
||||
# WAJIB scroll agar tidak intercepted
|
||||
self.driver.execute_script(
|
||||
"arguments[0].scrollIntoView({block:'center'});",
|
||||
target
|
||||
)
|
||||
|
||||
self.wait.until(EC.element_to_be_clickable(target)).click()
|
||||
|
||||
def answer_question_ls(self, question_number, option_index=0):
|
||||
"""
|
||||
option_index: 0-3 (LS punya 4 opsi)
|
||||
"""
|
||||
options = self.wait.until(
|
||||
EC.presence_of_all_elements_located(
|
||||
(By.NAME, f"soal{question_number}")
|
||||
)
|
||||
)
|
||||
|
||||
option = options[option_index]
|
||||
|
||||
# WAJIB scroll dulu
|
||||
self.driver.execute_script(
|
||||
"arguments[0].scrollIntoView({block: 'center'});", option
|
||||
)
|
||||
|
||||
self.wait.until(EC.element_to_be_clickable(option)).click()
|
||||
|
||||
def answer_all_questions_ls(self, total_questions=16):
|
||||
for i in range(1, total_questions + 1):
|
||||
self.answer_question_ls(i)
|
||||
|
||||
def answer_all_questions_mai(self, total_questions=52):
|
||||
for i in range(1, total_questions + 1):
|
||||
self.answer_question_mai(i)
|
||||
|
||||
def submit(self):
|
||||
btn = self.wait.until(
|
||||
EC.element_to_be_clickable(self.SUBMIT_BUTTON)
|
||||
)
|
||||
|
||||
self.driver.execute_script(
|
||||
"arguments[0].scrollIntoView({block:'center'});",
|
||||
btn
|
||||
)
|
||||
|
||||
btn.click()
|
||||
|
||||
def open_from_sidebar(self):
|
||||
self.wait.until(
|
||||
EC.element_to_be_clickable(self.KUESIONER_MENU)
|
||||
).click()
|
||||
|
||||
def click_mulai_kuesioner(self):
|
||||
self.wait.until(
|
||||
EC.element_to_be_clickable(self.MULAI_KUESIONER_BUTTON)
|
||||
).click()
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
from selenium.webdriver.common.by import By
|
||||
from selenium.webdriver.support.ui import WebDriverWait
|
||||
from selenium.webdriver.support import expected_conditions as EC
|
||||
|
||||
|
||||
class KuesionerPanduanPage:
|
||||
|
||||
URL = "https://hypermedialearning.sanggadewa.my.id/kuesioner-panduan"
|
||||
|
||||
# ===== LOCATORS =====
|
||||
KUESIONER_MENU = (
|
||||
By.XPATH,
|
||||
"//a[contains(@href,'kuesioner-panduan') and .//div[normalize-space()='Kuesioner']]"
|
||||
)
|
||||
|
||||
MULAI_KUESIONER_BUTTON = (
|
||||
By.XPATH,
|
||||
"//a[contains(@href,'/kuesioner-ls') and normalize-space()='Mulai Kuesioner']"
|
||||
)
|
||||
|
||||
BANTUAN_BUTTON = (
|
||||
By.XPATH,
|
||||
"//a[contains(@href,'wa.me') and contains(normalize-space(),'Bantuan')]"
|
||||
)
|
||||
|
||||
# ===== INIT =====
|
||||
def __init__(self, driver):
|
||||
self.driver = driver
|
||||
self.wait = WebDriverWait(driver, 15)
|
||||
|
||||
# ===== ACTIONS =====
|
||||
def open_from_sidebar(self):
|
||||
self.wait.until(
|
||||
EC.element_to_be_clickable(self.KUESIONER_MENU)
|
||||
).click()
|
||||
|
||||
def click_mulai_kuesioner(self):
|
||||
self.wait.until(
|
||||
EC.element_to_be_clickable(self.MULAI_KUESIONER_BUTTON)
|
||||
).click()
|
||||
|
||||
def click_bantuan(self):
|
||||
self.wait.until(
|
||||
EC.element_to_be_clickable(self.BANTUAN_BUTTON)
|
||||
).click()
|
||||
|
||||
# ===== ASSERTIONS =====
|
||||
def is_on_panduan_page(self) -> bool:
|
||||
return "kuesioner-panduan" in self.driver.current_url
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,151 @@
|
|||
from selenium.webdriver.common.by import By
|
||||
from selenium.webdriver.common.action_chains import ActionChains
|
||||
from selenium.webdriver.common.keys import Keys
|
||||
from selenium.webdriver.support.ui import WebDriverWait
|
||||
from selenium.webdriver.support import expected_conditions as EC
|
||||
from selenium.common.exceptions import NoAlertPresentException
|
||||
|
||||
|
||||
class LiveCodingPage:
|
||||
|
||||
# ===== LOCATORS =====
|
||||
PAGE_TITLE = (By.XPATH, "//h4[contains(text(),'Live Coding')]")
|
||||
EXPECTED_OUTPUT = (By.XPATH, "//strong[contains(text(),'Hasil Output')]")
|
||||
CODE_EDITOR = (By.ID, "editor")
|
||||
SUBMIT_BUTTON = (By.ID, "submit-code")
|
||||
ERROR_404_TEXT = "404"
|
||||
|
||||
#alert / result
|
||||
RESULT_MESSAGE = (By.ID, "result")
|
||||
MODAL = (By.CLASS_NAME, "modal-dialog")
|
||||
CLOSE_BUTTON = (By.XPATH, "//button[normalize-space()='Tutup']")
|
||||
PREVIOUS_BUTTON = (By.XPATH, "//a[contains(text(),'Sebelumnya')]")
|
||||
NEXT_BUTTON = (By.XPATH, "//a[contains(text(),'Selanjutnya')]")
|
||||
OTHER_MENU = (By.XPATH, "//a[contains(@href,'/materi/visual/')]")
|
||||
CONFIRM_MODAL = (By.CLASS_NAME, "modal")
|
||||
CONFIRM_TEXT = (By.CLASS_NAME, "modal-body")
|
||||
|
||||
def __init__(self, driver):
|
||||
self.driver = driver
|
||||
self.wait = WebDriverWait(driver, 10)
|
||||
|
||||
# ===== PAGE ACTIONS =====
|
||||
def is_page_loaded(self):
|
||||
self.wait.until(EC.visibility_of_element_located(self.PAGE_TITLE))
|
||||
return True
|
||||
|
||||
def get_expected_output_text(self):
|
||||
return self.driver.find_element(*self.EXPECTED_OUTPUT).text
|
||||
|
||||
def editor_is_visible(self):
|
||||
return self.driver.find_element(*self.CODE_EDITOR).is_displayed()
|
||||
|
||||
def append_code(self, code):
|
||||
"""
|
||||
Menambahkan kode ke editor (tanpa menghapus kode bawaan)
|
||||
"""
|
||||
editor = self.driver.find_element(*self.CODE_EDITOR)
|
||||
editor.click()
|
||||
|
||||
actions = ActionChains(self.driver)
|
||||
actions.key_down(Keys.CONTROL).send_keys(Keys.END).key_up(Keys.CONTROL)
|
||||
actions.send_keys(Keys.ENTER)
|
||||
actions.send_keys(code)
|
||||
actions.perform()
|
||||
|
||||
def append_code2(self, code):
|
||||
|
||||
current_code = self.driver.execute_script("""
|
||||
return monaco.editor.getModels()[0].getValue();
|
||||
""")
|
||||
|
||||
updated_code = current_code
|
||||
updated_code = updated_code.replace("...............", " Mahasiswa")
|
||||
updated_code = updated_code.replace(".........", ".println")
|
||||
|
||||
self.driver.execute_script("""
|
||||
monaco.editor.getModels()[0].setValue(arguments[0]);
|
||||
""", updated_code)
|
||||
|
||||
def submit_code(self):
|
||||
btn = WebDriverWait(self.driver, 15).until(
|
||||
EC.element_to_be_clickable(self.SUBMIT_BUTTON)
|
||||
)
|
||||
self.driver.execute_script(
|
||||
"arguments[0].scrollIntoView({block:'center'});", btn
|
||||
)
|
||||
self.driver.execute_script("arguments[0].click();", btn)
|
||||
|
||||
def get_result_message(self):
|
||||
wait = WebDriverWait(self.driver, 20)
|
||||
|
||||
def result_has_text(driver):
|
||||
el = driver.find_element(By.ID, "result")
|
||||
return el if el.text.strip() != "" else False
|
||||
|
||||
result_el = wait.until(result_has_text)
|
||||
return result_el.text
|
||||
|
||||
def close_result_modal(self):
|
||||
WebDriverWait(self.driver, 10).until(
|
||||
EC.element_to_be_clickable(self.CLOSE_BUTTON)
|
||||
).click()
|
||||
|
||||
def get_editor_value(self):
|
||||
"""
|
||||
Ambil isi editor Monaco via JavaScript
|
||||
"""
|
||||
return self.driver.execute_script(
|
||||
"return monaco.editor.getModels()[0].getValue();"
|
||||
)
|
||||
|
||||
def wait_popup_visible(self):
|
||||
self.wait.until(EC.visibility_of_element_located(self.RESULT_MESSAGE))
|
||||
|
||||
def is_popup_visible(self):
|
||||
try:
|
||||
return self.driver.find_element(*self.RESULT_MESSAGE).is_displayed()
|
||||
except:
|
||||
return False
|
||||
|
||||
def click_previous(self):
|
||||
element = self.driver.find_element(*self.PREVIOUS_BUTTON)
|
||||
self.driver.execute_script("arguments[0].scrollIntoView(true);", element)
|
||||
element.click()
|
||||
|
||||
def click_next(self):
|
||||
element = self.driver.find_element(*self.NEXT_BUTTON)
|
||||
self.driver.execute_script("arguments[0].scrollIntoView(true);", element)
|
||||
element.click()
|
||||
|
||||
def wait_popup_invisible(self):
|
||||
WebDriverWait(self.driver, 10).until(
|
||||
EC.invisibility_of_element_located((By.ID, "resultModal"))
|
||||
)
|
||||
|
||||
# ===== INFO =====
|
||||
def get_current_url(self):
|
||||
return self.driver.current_url
|
||||
|
||||
def is_404_page(self):
|
||||
return self.ERROR_404_TEXT in self.driver.page_source
|
||||
|
||||
def click_other_menu(self):
|
||||
self.driver.find_element(*self.OTHER_MENU).click()
|
||||
|
||||
# ===== ALERT HANDLER =====
|
||||
def is_confirm_alert_present(self):
|
||||
try:
|
||||
alert = self.driver.switch_to.alert
|
||||
return alert.text
|
||||
except NoAlertPresentException:
|
||||
return None
|
||||
|
||||
# ===== MODAL HANDLER =====
|
||||
def is_confirm_modal_visible(self):
|
||||
try:
|
||||
return self.driver.find_element(*self.CONFIRM_MODAL).is_displayed()
|
||||
except:
|
||||
return False
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,169 @@
|
|||
from selenium.webdriver.common.by import By
|
||||
from selenium.webdriver.support.ui import WebDriverWait
|
||||
from selenium.webdriver.support import expected_conditions as EC
|
||||
|
||||
|
||||
class LoginPage:
|
||||
#URL = "https://hypermedialearning.sanggadewa.my.id/login"
|
||||
URL = "https://hypermedialearning.project2025.id/public/login"
|
||||
DASHBOARD_URL_PART = "/dashboard"
|
||||
|
||||
# ===============================
|
||||
# LOCATORS
|
||||
# ===============================
|
||||
EMAIL = (By.ID, "email")
|
||||
PASSWORD = (By.ID, "password")
|
||||
REMEMBER_ME = (By.NAME, "remember")
|
||||
BUTTON_LOGIN = (By.XPATH, "//button[@type='submit']")
|
||||
|
||||
ERROR_MESSAGE = (By.CLASS_NAME, "invalid-feedback")
|
||||
GLOBAL_ERROR = (
|
||||
By.XPATH,
|
||||
"//*[contains(text(),'These credentials do not match our records')]"
|
||||
)
|
||||
|
||||
SSO_GOOGLE_BUTTON = (By.XPATH, "//a[contains(@href,'/auth/google')]")
|
||||
|
||||
# ===============================
|
||||
# INIT
|
||||
# ===============================
|
||||
def __init__(self, driver):
|
||||
self.driver = driver
|
||||
self.wait = WebDriverWait(driver, 10)
|
||||
|
||||
# ===============================
|
||||
# PAGE ACTIONS
|
||||
# ===============================
|
||||
def open(self):
|
||||
self.driver.get(self.URL)
|
||||
|
||||
def fill_email(self, value: str):
|
||||
field = self.wait.until(
|
||||
EC.visibility_of_element_located(self.EMAIL)
|
||||
)
|
||||
field.clear()
|
||||
field.send_keys(value)
|
||||
|
||||
def fill_password(self, value: str):
|
||||
field = self.wait.until(
|
||||
EC.visibility_of_element_located(self.PASSWORD)
|
||||
)
|
||||
field.clear()
|
||||
field.send_keys(value)
|
||||
|
||||
def click_login(self):
|
||||
self.wait.until(
|
||||
EC.element_to_be_clickable(self.BUTTON_LOGIN)
|
||||
).click()
|
||||
|
||||
def click_remember_me(self):
|
||||
checkbox = self.wait.until(
|
||||
EC.element_to_be_clickable(self.REMEMBER_ME)
|
||||
)
|
||||
if not checkbox.is_selected():
|
||||
checkbox.click()
|
||||
|
||||
def click_google_sso(self):
|
||||
self.wait.until(
|
||||
EC.element_to_be_clickable(self.GOOGLE_SSO_BUTTON)
|
||||
).click()
|
||||
|
||||
# ===============================
|
||||
# BUSINESS / HELPER METHODS
|
||||
# ===============================
|
||||
def login(self, email: str, password: str):
|
||||
self.fill_email(email)
|
||||
self.fill_password(password)
|
||||
self.click_login()
|
||||
|
||||
def is_login_success(self) -> bool:
|
||||
try:
|
||||
self.wait.until(
|
||||
lambda d: self.DASHBOARD_URL_PART in d.current_url
|
||||
)
|
||||
return True
|
||||
except:
|
||||
return False
|
||||
|
||||
def is_login_failed(self) -> bool:
|
||||
return self.has_error_message()
|
||||
|
||||
def has_error_message(self) -> bool:
|
||||
return any(
|
||||
el.text.strip()
|
||||
for el in self.driver.find_elements(*self.ERROR_MESSAGE)
|
||||
)
|
||||
|
||||
def has_global_error(self) -> bool:
|
||||
try:
|
||||
return self.driver.find_element(
|
||||
*self.GLOBAL_ERROR
|
||||
).is_displayed()
|
||||
except:
|
||||
return False
|
||||
|
||||
def is_field_required(self, field_name: str) -> bool:
|
||||
fields = {
|
||||
"email": self.EMAIL,
|
||||
"password": self.PASSWORD
|
||||
}
|
||||
|
||||
locator = fields.get(field_name)
|
||||
if not locator:
|
||||
raise ValueError(f"Field '{field_name}' tidak dikenali")
|
||||
|
||||
element = self.driver.find_element(*locator)
|
||||
return element.get_attribute("required") is not None
|
||||
|
||||
def get_email_validation_message(self):
|
||||
email = self.driver.find_element(By.ID, "email")
|
||||
return self.driver.execute_script(
|
||||
"return arguments[0].validationMessage;",
|
||||
email
|
||||
)
|
||||
|
||||
def submit(self):
|
||||
self.click_login()
|
||||
|
||||
def has_html5_validation(self, field_name: str) -> bool:
|
||||
field = self.get_field(field_name)
|
||||
return field.get_attribute("validationMessage") != ""
|
||||
|
||||
def get_field(self, field_name: str):
|
||||
fields = {
|
||||
"email": self.EMAIL,
|
||||
"password": self.PASSWORD,
|
||||
}
|
||||
|
||||
locator = fields.get(field_name)
|
||||
if not locator:
|
||||
raise ValueError(f"Field '{field_name}' tidak dikenali di LoginPage")
|
||||
|
||||
return self.driver.find_element(*locator)
|
||||
|
||||
def click_remember_me(self):
|
||||
checkbox = self.wait.until(
|
||||
EC.element_to_be_clickable(self.REMEMBER_ME)
|
||||
)
|
||||
if not checkbox.is_selected():
|
||||
checkbox.click()
|
||||
|
||||
def is_remember_me_checked(self) -> bool:
|
||||
checkbox = self.driver.find_element(*self.REMEMBER_ME)
|
||||
return checkbox.is_selected()
|
||||
|
||||
def click_sso_google(self):
|
||||
self.wait.until(
|
||||
EC.element_to_be_clickable(self.SSO_GOOGLE_BUTTON)
|
||||
).click()
|
||||
|
||||
def is_redirected_to_google(self) -> bool:
|
||||
self.wait.until(
|
||||
lambda d: "accounts.google.com" in d.current_url
|
||||
)
|
||||
return "accounts.google.com" in self.driver.current_url
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
from selenium.webdriver.common.by import By
|
||||
from selenium.webdriver.support.ui import WebDriverWait
|
||||
from selenium.webdriver.support import expected_conditions as EC
|
||||
|
||||
|
||||
class LogoutPage:
|
||||
|
||||
URL = "https://hypermedialearning.sanggadewa.my.id/dashboard"
|
||||
|
||||
# --- USER ICON (pojok kanan atas) ---
|
||||
USER_ICON = (
|
||||
By.XPATH,
|
||||
"//li[contains(@class,'dropdown')]//a[contains(@class,'dropdown-toggle')]"
|
||||
)
|
||||
|
||||
# --- MENU DROPDOWN ---
|
||||
LOGOUT_MENU = (By.XPATH,"//a[@data-bs-target='#confirmlogout']")
|
||||
|
||||
# --- MODAL ---
|
||||
LOGOUT_MODAL = (By.ID, "confirmlogout")
|
||||
MODAL_TITLE = (By.ID, "confirmlogoutLabel")
|
||||
|
||||
# --- BUTTON DI MODAL ---
|
||||
BUTTON_TIDAK = (
|
||||
By.XPATH,
|
||||
"//div[@id='confirmlogout']//button[contains(text(),'Tidak')]"
|
||||
)
|
||||
|
||||
BUTTON_YA = (
|
||||
By.XPATH,
|
||||
"//div[@id='confirmlogout']//button[contains(text(),'Ya')]"
|
||||
)
|
||||
|
||||
def __init__(self, driver):
|
||||
self.driver = driver
|
||||
self.wait = WebDriverWait(driver, 15)
|
||||
|
||||
def open(self):
|
||||
self.driver.get(self.URL)
|
||||
|
||||
# =============================
|
||||
# ACTIONS
|
||||
# =============================
|
||||
|
||||
|
||||
def open_user_dropdown(self):
|
||||
dropdown = self.wait.until(
|
||||
EC.element_to_be_clickable(self.USER_ICON)
|
||||
)
|
||||
dropdown.click()
|
||||
|
||||
# Tunggu logout menu muncul
|
||||
self.wait.until(
|
||||
EC.visibility_of_element_located(self.LOGOUT_MENU)
|
||||
)
|
||||
|
||||
def click_logout_menu(self):
|
||||
self.wait.until(
|
||||
EC.element_to_be_clickable(self.LOGOUT_MENU)
|
||||
).click()
|
||||
|
||||
def is_logout_modal_visible(self):
|
||||
return self.wait.until(
|
||||
EC.visibility_of_element_located(self.MODAL_TITLE)
|
||||
)
|
||||
|
||||
|
||||
def click_tidak(self):
|
||||
self.wait.until(
|
||||
EC.element_to_be_clickable(self.BUTTON_TIDAK)
|
||||
).click()
|
||||
|
||||
def click_ya_logout(self):
|
||||
self.wait.until(
|
||||
EC.element_to_be_clickable(self.BUTTON_YA)
|
||||
).click()
|
||||
|
||||
def wait_until_redirect_to_home(self):
|
||||
self.wait.until(
|
||||
EC.url_to_be("https://hypermedialearning.sanggadewa.my.id/")
|
||||
)
|
||||
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
from selenium.webdriver.common.by import By
|
||||
from selenium.webdriver.support.ui import WebDriverWait
|
||||
from selenium.webdriver.support import expected_conditions as EC
|
||||
|
||||
|
||||
class MateriPage:
|
||||
|
||||
# ===== SIDEBAR =====
|
||||
SIDEBAR = (By.ID, "learningStyleSidebar")
|
||||
|
||||
BTN_VISUAL = (
|
||||
By.XPATH,
|
||||
"//div[@id='learningStyleSidebar']//h6[normalize-space()='Visual']/following-sibling::a"
|
||||
)
|
||||
|
||||
BTN_AUDITORY = (
|
||||
By.XPATH,
|
||||
"//div[@id='learningStyleSidebar']//h6[normalize-space()='Auditory']/following-sibling::a"
|
||||
)
|
||||
|
||||
# ===== JUDUL HALAMAN =====
|
||||
TITLE_VISUAL = (By.XPATH, "//h4[normalize-space()='Materi Visual']")
|
||||
TITLE_AUDITORY = (By.XPATH, "//h4[normalize-space()='Materi Auditory']")
|
||||
|
||||
# ===== MEDIA =====
|
||||
VISUAL_IMAGE = (By.XPATH, "//img[@alt='Gambar Materi']")
|
||||
AUDIO_PLAYER = (By.XPATH, "//audio")
|
||||
|
||||
def __init__(self, driver):
|
||||
self.driver = driver
|
||||
self.wait = WebDriverWait(driver, 10)
|
||||
|
||||
# ===== SIDEBAR =====
|
||||
def sidebar_visible(self):
|
||||
self.wait.until(EC.visibility_of_element_located(self.SIDEBAR))
|
||||
|
||||
def go_to_visual(self):
|
||||
self.wait.until(EC.element_to_be_clickable(self.BTN_VISUAL)).click()
|
||||
|
||||
def go_to_auditory(self):
|
||||
self.wait.until(EC.element_to_be_clickable(self.BTN_AUDITORY)).click()
|
||||
|
||||
# ===== ASSERTION =====
|
||||
def visual_page_loaded(self):
|
||||
self.wait.until(EC.visibility_of_element_located(self.TITLE_VISUAL))
|
||||
self.wait.until(EC.visibility_of_element_located(self.VISUAL_IMAGE))
|
||||
|
||||
def auditory_page_loaded(self):
|
||||
self.wait.until(EC.visibility_of_element_located(self.TITLE_AUDITORY))
|
||||
self.wait.until(EC.visibility_of_element_located(self.AUDIO_PLAYER))
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
from selenium.webdriver.common.by import By
|
||||
from selenium.webdriver.support.ui import WebDriverWait
|
||||
from selenium.webdriver.support import expected_conditions as EC
|
||||
|
||||
|
||||
class MateriPembelajaranPage:
|
||||
|
||||
# ===== SIDEBAR =====
|
||||
MENU_MATERI_PEMBELAJARAN = (
|
||||
By.XPATH,
|
||||
"//div[normalize-space()='Materi Pembelajaran']/ancestor::a"
|
||||
)
|
||||
|
||||
SUBMENU_ENKAPSULASI = (
|
||||
By.XPATH,
|
||||
"//a[@href='/materi']//div[normalize-space()='Enkapsulasi']"
|
||||
)
|
||||
|
||||
# ===== LEARNING STYLE UTAMA =====
|
||||
LEARNING_STYLE_TITLE = (
|
||||
By.XPATH,
|
||||
"//h5[normalize-space()='Learning Style Kamu 🎉']"
|
||||
)
|
||||
|
||||
LEARNING_STYLE_VALUE = (
|
||||
By.XPATH,
|
||||
"//h5[normalize-space()='Learning Style Kamu 🎉']/following-sibling::p"
|
||||
)
|
||||
|
||||
BUTTON_MULAI_BELAJAR_UTAMA = (
|
||||
By.XPATH,
|
||||
"//h5[normalize-space()='Learning Style Kamu 🎉']/following::a[normalize-space()='Mulai Belajar']"
|
||||
)
|
||||
|
||||
# ===== PESAN ALTERNATIF =====
|
||||
PESAN_ALTERNATIF = (
|
||||
By.XPATH,
|
||||
"//h5[contains(text(),'Materi Sesuai Learning Style Kamu Sulit Dipahami')]"
|
||||
)
|
||||
|
||||
# ===== CARD ALTERNATIF =====
|
||||
CARD_VISUAL = (
|
||||
By.XPATH,
|
||||
"//h5[normalize-space()='Visual']/following::a[normalize-space()='Mulai Belajar'][1]"
|
||||
)
|
||||
|
||||
CARD_AUDITORY = (
|
||||
By.XPATH,
|
||||
"//h5[normalize-space()='Auditory']/following::a[normalize-space()='Mulai Belajar'][1]"
|
||||
)
|
||||
|
||||
CARD_READ_WRITE = (
|
||||
By.XPATH,
|
||||
"//h5[normalize-space()='Read/ Write']/following::a[normalize-space()='Mulai Belajar'][1]"
|
||||
)
|
||||
|
||||
# ===== JUDUL HALAMAN MATERI =====
|
||||
JUDUL_HALAMAN_MATERI = (
|
||||
By.XPATH,
|
||||
"//h4[@class='fw-bold mb-4']"
|
||||
)
|
||||
|
||||
def __init__(self, driver):
|
||||
self.driver = driver
|
||||
self.wait = WebDriverWait(driver, 10)
|
||||
|
||||
# ===== ACTIONS =====
|
||||
def open_from_sidebar(self):
|
||||
self.wait.until(
|
||||
EC.element_to_be_clickable(self.MENU_MATERI_PEMBELAJARAN)
|
||||
).click()
|
||||
|
||||
self.wait.until(
|
||||
EC.element_to_be_clickable(self.SUBMENU_ENKAPSULASI)
|
||||
).click()
|
||||
|
||||
def click_mulai_belajar_utama(self):
|
||||
self.wait.until(
|
||||
EC.element_to_be_clickable(self.BUTTON_MULAI_BELAJAR_UTAMA)
|
||||
).click()
|
||||
|
||||
def click_visual(self):
|
||||
self.wait.until(
|
||||
EC.element_to_be_clickable(self.CARD_VISUAL)
|
||||
).click()
|
||||
|
||||
def click_auditory(self):
|
||||
self.wait.until(
|
||||
EC.element_to_be_clickable(self.CARD_AUDITORY)
|
||||
).click()
|
||||
|
||||
def click_read_write(self):
|
||||
self.wait.until(
|
||||
EC.element_to_be_clickable(self.CARD_READ_WRITE)
|
||||
).click()
|
||||
|
||||
def get_learning_style_user(self):
|
||||
return self.wait.until(
|
||||
EC.visibility_of_element_located(self.LEARNING_STYLE_VALUE)
|
||||
).text
|
||||
|
||||
def get_judul_materi(self):
|
||||
return self.wait.until(
|
||||
EC.visibility_of_element_located(self.JUDUL_HALAMAN_MATERI)
|
||||
).text
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
from selenium.webdriver.common.by import By
|
||||
from selenium.webdriver.support.ui import WebDriverWait
|
||||
from selenium.webdriver.support import expected_conditions as EC
|
||||
|
||||
class MateriReadWritePage:
|
||||
|
||||
# ===== Locator =====
|
||||
PAGE_TITLE = (By.XPATH, "//h4[normalize-space()='Materi Read / Write']")
|
||||
TEXT_MATERI = (By.XPATH, "//strong[text()='Teks:']/following-sibling::pre")
|
||||
|
||||
RANGKUMAN_TEXTAREA = (By.ID, "rangkuman")
|
||||
SUBMIT_BUTTON = (By.XPATH, "//button[normalize-space()='Kirim Rangkuman']")
|
||||
|
||||
SUCCESS_ALERT = (By.XPATH, "//div[contains(@class,'alert-success')]")
|
||||
TUGAS_RANGKUMAN_LABEL = (By.XPATH,"//label[@for='rangkuman']//strong[normalize-space()='Tugas Rangkuman:']")
|
||||
|
||||
|
||||
# Sidebar navigasi materi lain
|
||||
SIDEBAR_VISUAL = (
|
||||
By.XPATH,
|
||||
"//div[@id='learningStyleSidebar']//h6[normalize-space()='Visual']/following-sibling::a"
|
||||
)
|
||||
SIDEBAR_AUDITORY = (
|
||||
By.XPATH,
|
||||
"//div[@id='learningStyleSidebar']//h6[normalize-space()='Auditory']/following-sibling::a"
|
||||
)
|
||||
SIDEBAR_KINESTHETIC = (
|
||||
By.XPATH,
|
||||
"//div[@id='learningStyleSidebar']//h6[normalize-space()='Kinesthetic']/following-sibling::a"
|
||||
)
|
||||
ERROR_ALERT = (By.XPATH, "//div[contains(@class,'alert-danger')]")
|
||||
|
||||
def __init__(self, driver):
|
||||
self.driver = driver
|
||||
self.wait = WebDriverWait(driver, 10)
|
||||
|
||||
# ===== Actions =====
|
||||
def page_loaded(self):
|
||||
self.wait.until(EC.visibility_of_element_located(self.PAGE_TITLE))
|
||||
|
||||
def get_text_materi(self):
|
||||
return self.wait.until(
|
||||
EC.visibility_of_element_located(self.TEXT_MATERI)
|
||||
).text
|
||||
|
||||
def input_rangkuman(self, text):
|
||||
textarea = self.wait.until(
|
||||
EC.visibility_of_element_located(self.RANGKUMAN_TEXTAREA)
|
||||
)
|
||||
textarea.clear()
|
||||
textarea.send_keys(text)
|
||||
|
||||
def submit_rangkuman(self):
|
||||
self.wait.until(
|
||||
EC.element_to_be_clickable(self.SUBMIT_BUTTON)
|
||||
).click()
|
||||
|
||||
def success_message_displayed(self):
|
||||
return self.wait.until(
|
||||
EC.visibility_of_element_located(self.SUCCESS_ALERT)
|
||||
)
|
||||
|
||||
# ===== Sidebar navigation =====
|
||||
def go_to_visual(self):
|
||||
self.wait.until(EC.element_to_be_clickable(self.SIDEBAR_VISUAL)).click()
|
||||
|
||||
def go_to_auditory(self):
|
||||
self.wait.until(EC.element_to_be_clickable(self.SIDEBAR_AUDITORY)).click()
|
||||
|
||||
def go_to_kinesthetic(self):
|
||||
self.wait.until(EC.element_to_be_clickable(self.SIDEBAR_KINESTHETIC)).click()
|
||||
|
||||
def error_message_displayed(self):
|
||||
return self.wait.until(
|
||||
EC.visibility_of_element_located(self.ERROR_ALERT)
|
||||
)
|
||||
|
|
@ -0,0 +1,193 @@
|
|||
from selenium.webdriver.common.by import By
|
||||
from selenium.webdriver.support.ui import Select
|
||||
from selenium.webdriver.support.ui import WebDriverWait
|
||||
from selenium.webdriver.support import expected_conditions as EC
|
||||
|
||||
|
||||
class ProfilePage:
|
||||
|
||||
# ===============================
|
||||
# LOCATORS
|
||||
# ===============================
|
||||
|
||||
# --- Profile Display ---
|
||||
EMAIL_FIELD = (By.ID, "email")
|
||||
NAMA_LENGKAP_FIELD = (By.ID, "nama_lengkap")
|
||||
NIM_FIELD = (By.ID, "nim")
|
||||
SEMESTER_DROPDOWN = (By.ID, "semester")
|
||||
ANGKATAN_DROPDOWN = (By.ID, "angkatan")
|
||||
|
||||
# --- Upload Foto ---
|
||||
FILE_INPUT = (By.ID, "profile_image")
|
||||
PROFILE_IMAGE = (By.ID, "uploadedAvatar")
|
||||
RESET_BUTTON = (By.XPATH, "//a[.//span[text()='Reset']]")
|
||||
|
||||
# --- Buttons ---
|
||||
SAVE_BUTTON = (By.XPATH, "//button[contains(text(),'Simpan Perubahan')]")
|
||||
CANCEL_BUTTON = (By.XPATH, "//button[contains(text(),'Batal')]")
|
||||
|
||||
# --- Error Messages ---
|
||||
ERROR_NAMA = (By.ID, "nama_lengkap-error")
|
||||
ERROR_NIM = (By.ID, "nim-error")
|
||||
ERROR_SEMESTER = (By.ID, "semester-error")
|
||||
ERROR_ANGKATAN = (By.ID, "angkatan-error")
|
||||
|
||||
# --- Success Message ---
|
||||
SUCCESS_ALERT = (By.CLASS_NAME, "alert-success")
|
||||
|
||||
|
||||
# ===============================
|
||||
# PROFILE DISPLAY METHODS
|
||||
# ===============================
|
||||
|
||||
def __init__(self, driver):
|
||||
self.driver = driver
|
||||
self.wait = WebDriverWait(driver, 10)
|
||||
|
||||
def get_email(self):
|
||||
return self.driver.find_element(*self.EMAIL_FIELD).get_attribute("value")
|
||||
|
||||
def is_email_readonly(self):
|
||||
return self.driver.find_element(*self.EMAIL_FIELD).get_attribute("readonly") is not None
|
||||
|
||||
def get_nama_lengkap(self):
|
||||
return self.driver.find_element(*self.NAMA_LENGKAP_FIELD).get_attribute("value")
|
||||
|
||||
def get_nim(self):
|
||||
return self.driver.find_element(*self.NIM_FIELD).get_attribute("value")
|
||||
|
||||
def get_selected_semester(self):
|
||||
select = Select(self.driver.find_element(*self.SEMESTER_DROPDOWN))
|
||||
return select.first_selected_option.text
|
||||
|
||||
def get_selected_angkatan(self):
|
||||
select = Select(self.driver.find_element(*self.ANGKATAN_DROPDOWN))
|
||||
return select.first_selected_option.text
|
||||
|
||||
def get_all_semester_options(self):
|
||||
"""
|
||||
Mengambil seluruh opsi semester dari dropdown
|
||||
Return: list of string (contoh: ["1","2","3","4","5","6","7","8"])
|
||||
"""
|
||||
select_element = Select(self.driver.find_element(*self.SEMESTER_DROPDOWN))
|
||||
options = select_element.options
|
||||
|
||||
return [option.text.strip() for option in options]
|
||||
|
||||
def get_all_angkatan_options(self):
|
||||
"""
|
||||
Mengambil seluruh opsi angkatan dari dropdown
|
||||
Return: list of string (contoh: ["2020","2021","3","4","5","6","7","8"])
|
||||
"""
|
||||
select_element = Select(self.driver.find_element(*self.ANGKATAN_DROPDOWN))
|
||||
options = select_element.options
|
||||
|
||||
return [option.text.strip() for option in options]
|
||||
|
||||
|
||||
# ===============================
|
||||
# EDIT METHODS
|
||||
# ===============================
|
||||
|
||||
def set_nama_lengkap(self, name):
|
||||
field = self.driver.find_element(*self.NAMA_LENGKAP_FIELD)
|
||||
field.clear()
|
||||
field.send_keys(name)
|
||||
|
||||
def set_nim(self, nim):
|
||||
field = self.driver.find_element(*self.NIM_FIELD)
|
||||
field.clear()
|
||||
field.send_keys(nim)
|
||||
|
||||
def select_semester(self, value):
|
||||
Select(self.driver.find_element(*self.SEMESTER_DROPDOWN)).select_by_value(value)
|
||||
|
||||
def select_angkatan(self, value):
|
||||
Select(self.driver.find_element(*self.ANGKATAN_DROPDOWN)).select_by_value(value)
|
||||
|
||||
# ===============================
|
||||
# UPLOAD METHODS
|
||||
# ===============================
|
||||
|
||||
def upload_photo(self, file_path):
|
||||
self.driver.find_element(*self.FILE_INPUT).send_keys(file_path)
|
||||
|
||||
def get_profile_image_src(self):
|
||||
return self.driver.find_element(*self.PROFILE_IMAGE).get_attribute("src")
|
||||
|
||||
def click_reset_photo(self):
|
||||
wait = WebDriverWait(self.driver, 10)
|
||||
|
||||
reset_btn = wait.until(
|
||||
EC.element_to_be_clickable(self.RESET_BUTTON)
|
||||
)
|
||||
|
||||
self.driver.execute_script("arguments[0].scrollIntoView(true);", reset_btn)
|
||||
self.driver.execute_script("arguments[0].click();", reset_btn)
|
||||
|
||||
|
||||
# ===============================
|
||||
# BUTTON ACTIONS
|
||||
# ===============================
|
||||
|
||||
def click_save(self):
|
||||
wait = WebDriverWait(self.driver, 10)
|
||||
|
||||
save_btn = wait.until(
|
||||
EC.element_to_be_clickable(self.SAVE_BUTTON)
|
||||
)
|
||||
|
||||
# scroll dulu supaya tidak ketutup elemen
|
||||
self.driver.execute_script("arguments[0].scrollIntoView({block: 'center'});", save_btn)
|
||||
|
||||
wait.until(EC.element_to_be_clickable(self.SAVE_BUTTON))
|
||||
save_btn.click()
|
||||
|
||||
def click_cancel(self):
|
||||
cancel_btn = WebDriverWait(self.driver, 10).until(
|
||||
EC.element_to_be_clickable(self.CANCEL_BUTTON)
|
||||
)
|
||||
self.driver.execute_script("arguments[0].scrollIntoView(true);", cancel_btn)
|
||||
cancel_btn.click()
|
||||
|
||||
|
||||
# ===============================
|
||||
# UTILITIES
|
||||
# ===============================
|
||||
|
||||
def refresh_page(self):
|
||||
self.driver.refresh()
|
||||
|
||||
def wait_until_page_loaded(self):
|
||||
self.wait.until(
|
||||
EC.presence_of_element_located(self.EMAIL_FIELD)
|
||||
)
|
||||
|
||||
# ===============================
|
||||
# VALIDATION MESSAGE METHODS
|
||||
# ===============================
|
||||
|
||||
def get_error_nama(self):
|
||||
return self.wait.until(
|
||||
EC.visibility_of_element_located(self.ERROR_NAMA)
|
||||
).text
|
||||
|
||||
def get_error_nim(self):
|
||||
return self.wait.until(
|
||||
EC.visibility_of_element_located(self.ERROR_NIM)
|
||||
).text
|
||||
|
||||
def get_error_semester(self):
|
||||
return self.wait.until(
|
||||
EC.visibility_of_element_located(self.ERROR_SEMESTER)
|
||||
).text
|
||||
|
||||
def get_error_angkatan(self):
|
||||
return self.wait.until(
|
||||
EC.visibility_of_element_located(self.ERROR_ANGKATAN)
|
||||
).text
|
||||
|
||||
def wait_until_reload_after_save(self):
|
||||
self.wait.until(
|
||||
EC.presence_of_element_located(self.EMAIL_FIELD)
|
||||
)
|
||||
|
|
@ -0,0 +1,202 @@
|
|||
from selenium.webdriver.common.by import By
|
||||
from selenium.webdriver.support.ui import WebDriverWait
|
||||
from selenium.webdriver.support import expected_conditions as EC
|
||||
|
||||
|
||||
class RegisterPage:
|
||||
#URL = "https://hypermedialearning.sanggadewa.my.id/register"
|
||||
URL = "https://hypermedialearning.project2025.id/public/register"
|
||||
# ===============================
|
||||
# LOCATORS
|
||||
# ===============================
|
||||
NAMA_LENGKAP = (By.ID, "nama_lengkap")
|
||||
NIM = (By.ID, "nim")
|
||||
SEMESTER = (By.ID, "semester")
|
||||
ANGKATAN = (By.ID, "angkatan")
|
||||
EMAIL = (By.ID, "email")
|
||||
PASSWORD = (By.NAME, "password")
|
||||
KONFIRMASI_PASSWORD = (By.NAME, "password_confirmation")
|
||||
BUTTON_DAFTAR = (By.XPATH, "//button[@type='submit']")
|
||||
|
||||
ERROR_MESSAGE = (By.CLASS_NAME, "invalid-feedback")
|
||||
EMAIL_ERROR_MESSAGE = (
|
||||
By.XPATH,
|
||||
"//*[contains(text(),'Email harus menggunakan domain')]"
|
||||
)
|
||||
|
||||
# ===============================
|
||||
# INIT
|
||||
# ===============================
|
||||
def __init__(self, driver):
|
||||
self.driver = driver
|
||||
self.wait = WebDriverWait(driver, 10)
|
||||
|
||||
# ===============================
|
||||
# PAGE ACTIONS
|
||||
# ===============================
|
||||
def open(self):
|
||||
self.driver.get(self.URL)
|
||||
|
||||
def fill_nama_lengkap(self, value: str):
|
||||
field = self.wait.until(
|
||||
EC.visibility_of_element_located(self.NAMA_LENGKAP)
|
||||
)
|
||||
field.clear()
|
||||
field.send_keys(value)
|
||||
|
||||
def fill_nim(self, value: str):
|
||||
field = self.wait.until(
|
||||
EC.visibility_of_element_located(self.NIM)
|
||||
)
|
||||
field.clear()
|
||||
field.send_keys(value)
|
||||
|
||||
def fill_semester(self, value: str):
|
||||
field = self.wait.until(
|
||||
EC.visibility_of_element_located(self.SEMESTER)
|
||||
)
|
||||
field.clear()
|
||||
field.send_keys(value)
|
||||
|
||||
def fill_angkatan(self, value: str):
|
||||
field = self.wait.until(
|
||||
EC.visibility_of_element_located(self.ANGKATAN)
|
||||
)
|
||||
field.clear()
|
||||
field.send_keys(value)
|
||||
|
||||
def fill_email(self, value: str):
|
||||
field = self.wait.until(
|
||||
EC.visibility_of_element_located(self.EMAIL)
|
||||
)
|
||||
field.clear()
|
||||
field.send_keys(value)
|
||||
|
||||
def fill_password(self, value: str):
|
||||
field = self.wait.until(
|
||||
EC.visibility_of_element_located(self.PASSWORD)
|
||||
)
|
||||
field.clear()
|
||||
field.send_keys(value)
|
||||
|
||||
def fill_confirm_password(self, value: str):
|
||||
field = self.wait.until(
|
||||
EC.visibility_of_element_located(self.KONFIRMASI_PASSWORD)
|
||||
)
|
||||
field.clear()
|
||||
field.send_keys(value)
|
||||
|
||||
def click_daftar(self):
|
||||
self.wait.until(
|
||||
EC.element_to_be_clickable(self.BUTTON_DAFTAR)
|
||||
).click()
|
||||
|
||||
# ===============================
|
||||
# HELPER / BUSINESS METHODS
|
||||
# ===============================
|
||||
def fill_form(self, data: dict):
|
||||
self.fill_nama_lengkap(data["nama_lengkap"])
|
||||
self.fill_nim(data["nim"])
|
||||
self.fill_semester(data["semester"])
|
||||
self.fill_angkatan(data["angkatan"])
|
||||
self.fill_email(data["email"])
|
||||
self.fill_password(data["password"])
|
||||
|
||||
if "konfirmasi_password" in data:
|
||||
self.fill_confirm_password(data["konfirmasi_password"])
|
||||
|
||||
pwd = self.driver.find_element(*self.PASSWORD).get_attribute("value")
|
||||
cpwd = self.driver.find_element(*self.KONFIRMASI_PASSWORD).get_attribute("value")
|
||||
|
||||
print("PASSWORD FIELD :", repr(pwd))
|
||||
print("CONFIRM FIELD :", repr(cpwd))
|
||||
|
||||
|
||||
|
||||
def submit(self):
|
||||
"""Alias agar test lebih readable"""
|
||||
self.click_daftar()
|
||||
|
||||
def get_error_messages(self):
|
||||
elements = self.driver.find_elements(*self.ERROR_MESSAGE)
|
||||
return [el.text for el in elements if el.text.strip()]
|
||||
|
||||
def has_error(self, field_name: str) -> bool:
|
||||
"""
|
||||
Mengecek apakah error message terkait field tertentu muncul
|
||||
"""
|
||||
return any(
|
||||
field_name.lower() in err.lower()
|
||||
for err in self.get_error_messages()
|
||||
)
|
||||
|
||||
def is_email_domain_error_displayed(self) -> bool:
|
||||
try:
|
||||
return self.driver.find_element(
|
||||
*self.EMAIL_ERROR_MESSAGE
|
||||
).is_displayed()
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
def is_register_success(self) -> bool:
|
||||
"""
|
||||
Register dianggap sukses jika terjadi redirect dari halaman register.
|
||||
"""
|
||||
self.wait.until(
|
||||
lambda d: d.current_url != self.URL
|
||||
)
|
||||
return True
|
||||
|
||||
def is_field_required(self, label_text: str) -> bool:
|
||||
"""
|
||||
Mengecek apakah field dengan label tertentu memiliki atribut required
|
||||
(HTML5 native validation)
|
||||
"""
|
||||
fields = {
|
||||
"nama_lengkap": self.NAMA_LENGKAP,
|
||||
"NIM": self.NIM,
|
||||
"nim": self.NIM,
|
||||
"semester": self.SEMESTER,
|
||||
"angkatan": self.ANGKATAN,
|
||||
"email": self.EMAIL,
|
||||
"password": self.PASSWORD,
|
||||
"konfirmasi_password":self.KONFIRMASI_PASSWORD,
|
||||
}
|
||||
|
||||
locator = fields.get(label_text)
|
||||
if not locator:
|
||||
raise ValueError(f"Field '{label_text}' tidak dikenali")
|
||||
|
||||
element = self.driver.find_element(*locator)
|
||||
return element.get_attribute("required") is not None
|
||||
|
||||
def get_value(self, field_name: str) -> str:
|
||||
field = self.get_field(field_name)
|
||||
return field.get_attribute("value")
|
||||
|
||||
def get_field(self, field_name: str):
|
||||
fields = {
|
||||
"nama_lengkap": self.NAMA_LENGKAP,
|
||||
"NIM": self.NIM,
|
||||
"nim": self.NIM,
|
||||
"semester": self.SEMESTER,
|
||||
"Semester": self.SEMESTER,
|
||||
"angkatan": self.ANGKATAN,
|
||||
"Angkatan": self.ANGKATAN,
|
||||
"email": self.EMAIL,
|
||||
"password": self.PASSWORD,
|
||||
"konfirmasi_password":self.KONFIRMASI_PASSWORD,
|
||||
}
|
||||
|
||||
locator = fields.get(field_name)
|
||||
if not locator:
|
||||
raise ValueError(f"Field '{field_name}' tidak dikenali")
|
||||
|
||||
return self.driver.find_element(*locator)
|
||||
|
||||
def has_html5_validation(self, field_name: str) -> bool:
|
||||
field = self.get_field(field_name)
|
||||
return field.get_attribute("validationMessage") != ""
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
from selenium.webdriver.common.by import By
|
||||
from selenium.webdriver.support.ui import WebDriverWait
|
||||
from selenium.webdriver.support import expected_conditions as EC
|
||||
from selenium.common.exceptions import TimeoutException
|
||||
|
||||
class ResumePembelajaranPage:
|
||||
|
||||
# ===== Locator =====
|
||||
PAGE_TITLE = (By.XPATH, "//h4[normalize-space()='Resume Pembelajaran']")
|
||||
|
||||
EMPTY_MESSAGE = (
|
||||
By.CSS_SELECTOR,
|
||||
"div.text-center.text-muted"
|
||||
)
|
||||
|
||||
RESUME_CARD = (By.CSS_SELECTOR, "div.card")
|
||||
RESUME_CONTENT = (By.CSS_SELECTOR, "div.card-body pre")
|
||||
|
||||
def __init__(self, driver):
|
||||
self.driver = driver
|
||||
self.wait = WebDriverWait(driver, 10)
|
||||
|
||||
# ===== Assertions / Getters =====
|
||||
def page_loaded(self):
|
||||
self.wait.until(EC.visibility_of_element_located(self.PAGE_TITLE))
|
||||
|
||||
|
||||
def is_empty_message_displayed(self):
|
||||
try:
|
||||
self.wait.until(
|
||||
EC.presence_of_element_located(self.EMPTY_MESSAGE)
|
||||
)
|
||||
return True
|
||||
except TimeoutException:
|
||||
return False
|
||||
|
||||
def is_resume_displayed(self):
|
||||
return self.wait.until(
|
||||
EC.visibility_of_element_located(self.RESUME_CARD)
|
||||
)
|
||||
|
||||
def get_resume_text(self):
|
||||
return self.wait.until(
|
||||
EC.visibility_of_element_located(self.RESUME_CONTENT)
|
||||
).text
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
[pytest]
|
||||
addopts = -v -s
|
||||
testpaths = tests
|
||||
markers = dashboard: test untuk fitur dashboard
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
selenium
|
||||
pytest
|
||||
webdriver-manager
|
||||
.\venv\Scripts\Activate.ps1 (perintah aktifkan venv)
|
||||
|
||||
def fill_email(self, email):
|
||||
email_field = self.driver.find_element(*self.EMAIL)
|
||||
email_field.clear()
|
||||
email_field.send_keys(email)
|
||||
|
||||
|
||||
|
||||
def fill_required_fields_except_email(self):
|
||||
self.fill_nama("Mahasiswa Polije")
|
||||
self.fill_password("Password123!")
|
||||
self.fill_konfirmasi_password("Password123!")
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
import pytest
|
||||
from pages.dashboard_page import DashboardPage
|
||||
|
||||
@pytest.mark.dashboard
|
||||
class TestDashboardPengisianKuesioner:
|
||||
|
||||
def test_section_pengisian_kuesioner_tampil(self, driver, login_as_user_sudah_kuesioner):
|
||||
dashboard = DashboardPage(driver)
|
||||
dashboard.open()
|
||||
|
||||
assert dashboard.is_pengisian_kuesioner_section_visible()
|
||||
|
||||
def test_kuesioner_vark_mai_tampil(self, driver, login_as_user_sudah_kuesioner):
|
||||
dashboard = DashboardPage(driver)
|
||||
dashboard.open()
|
||||
|
||||
assert dashboard.is_kuesioner_vark_mai_visible()
|
||||
|
||||
def test_click_isi_kuesioner_redirect(self, driver, login_as_user_sudah_kuesioner):
|
||||
dashboard = DashboardPage(driver)
|
||||
dashboard.open()
|
||||
|
||||
dashboard.click_isi_kuesioner()
|
||||
|
||||
assert "kuesioner" in driver.current_url
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
import pytest
|
||||
from pages.dashboard_page import DashboardPage
|
||||
|
||||
|
||||
@pytest.mark.dashboard
|
||||
class TestDashboardPopup:
|
||||
|
||||
def test_popup_muncul_jika_belum_isi_kuesioner(self, driver, login_as_user_belum_kuesioner2):
|
||||
dashboard = DashboardPage(driver)
|
||||
dashboard.open()
|
||||
|
||||
assert dashboard.is_popup_visible()
|
||||
|
||||
def test_button_isi_kuesioner_redirect(self,
|
||||
driver, login_as_user_belum_kuesionerNew2):
|
||||
dashboard = DashboardPage(driver)
|
||||
dashboard.open()
|
||||
|
||||
dashboard.click_isi_kuesioner_pop_up()
|
||||
|
||||
assert dashboard.is_redirected_to_kuesioner()
|
||||
|
||||
def test_button_close_x_menutup_popup(self, driver, login_as_user_belum_kuesioner2):
|
||||
dashboard = DashboardPage(driver)
|
||||
dashboard.open()
|
||||
|
||||
dashboard.close_popup_with_x()
|
||||
dashboard.wait_popup_disappear()
|
||||
|
||||
assert not dashboard.is_popup_visible()
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
import pytest
|
||||
from pages.dashboard_page import DashboardPage
|
||||
|
||||
|
||||
@pytest.mark.dashboard
|
||||
class TestDashboardStatusKMRM:
|
||||
|
||||
def test_status_km_belum_diisi(self, driver, login_as_user_belum_kuesioner2):
|
||||
dashboard = DashboardPage(driver)
|
||||
dashboard.open()
|
||||
dashboard.close_kuesioner_popup_if_present()
|
||||
print("KM TEXT =", dashboard.get_km_status_text())
|
||||
assert dashboard.is_km_not_filled()
|
||||
|
||||
def test_status_rm_belum_diisi(self, driver, login_as_user_belum_kuesioner2):
|
||||
dashboard = DashboardPage(driver)
|
||||
dashboard.open()
|
||||
dashboard.close_kuesioner_popup_if_present()
|
||||
print("RM TEXT =", dashboard.get_rm_status_text())
|
||||
assert dashboard.is_rm_not_filled()
|
||||
|
||||
def test_status_km_sudah_isi_kuesioner(self, driver, login_as_user_sudah_kuesioner):
|
||||
dashboard = DashboardPage(driver)
|
||||
assert dashboard.is_km_filled()
|
||||
print("KM TEXT =", dashboard.get_km_status_text())
|
||||
|
||||
def test_status_rm_sudah_isi_kuesioner(self, driver, login_as_user_sudah_kuesioner):
|
||||
dashboard = DashboardPage(driver)
|
||||
assert dashboard.is_rm_filled()
|
||||
print("RM TEXT =", dashboard.get_rm_status_text())
|
||||
|
||||
def test_learning_style_belum_diisi(self, driver, login_as_user_belum_kuesioner2):
|
||||
dashboard = DashboardPage(driver)
|
||||
dashboard.open()
|
||||
dashboard.close_kuesioner_popup_if_present()
|
||||
assert dashboard.is_learning_style_not_filled()
|
||||
print("LEARNING STYLE =", dashboard.get_learning_style_text())
|
||||
|
||||
def test_learning_style_sudah_diisi(self,
|
||||
driver, login_as_user_sudah_kuesioner3):
|
||||
dashboard = DashboardPage(driver)
|
||||
dashboard.open()
|
||||
assert dashboard.is_learning_style_filled()
|
||||
print("LEARNING STYLE =", dashboard.get_learning_style_text())
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,107 @@
|
|||
import re
|
||||
import pytest
|
||||
from pages.history_kuesioner_page import HistoryKuesionerPage
|
||||
from selenium.webdriver.support.ui import WebDriverWait
|
||||
from selenium.webdriver.support import expected_conditions as EC
|
||||
|
||||
@pytest.mark.usefixtures("login_as_user_belum_kuesioner")
|
||||
class TestHistoryKuesioner:
|
||||
|
||||
def test_history_page_loaded(self, driver):
|
||||
page = HistoryKuesionerPage(driver)
|
||||
page.open()
|
||||
assert page.is_page_loaded()
|
||||
|
||||
def test_km_dan_rm_value(self, driver):
|
||||
page = HistoryKuesionerPage(driver)
|
||||
page.open()
|
||||
|
||||
assert page.get_km_value() in ["low", "medium", "high"]
|
||||
assert page.get_rm_value() in ["low", "medium", "high"]
|
||||
|
||||
def test_ringkasan_skor_gaya_belajar(self, driver):
|
||||
"""
|
||||
PASSED berarti:
|
||||
- 4 gaya belajar muncul
|
||||
- Label sesuai requirement
|
||||
- Nilai skor valid (angka)
|
||||
"""
|
||||
page = HistoryKuesionerPage(driver)
|
||||
page.open()
|
||||
scores = page.get_scores()
|
||||
|
||||
expected_labels = {"Visual", "Auditory", "Read/Write", "Kinesthetic"}
|
||||
|
||||
assert set(scores.keys()) == expected_labels, (
|
||||
f"Label tidak sesuai: {scores.keys()}"
|
||||
)
|
||||
|
||||
for label, value in scores.items():
|
||||
assert value.isdigit(), f"Skor {label} bukan angka: {value}"
|
||||
|
||||
def test_progress_pengisian_100_persen(self, driver):
|
||||
page = HistoryKuesionerPage(driver)
|
||||
page.open()
|
||||
|
||||
progress = page.get_progress_value()
|
||||
assert progress == "100", f"Progress seharusnya 100%, tetapi {progress}%"
|
||||
|
||||
def test_gaya_belajar_dominan_valid(self, driver):
|
||||
page = HistoryKuesionerPage(driver)
|
||||
page.open()
|
||||
|
||||
dominant = page.get_dominant_style()
|
||||
assert dominant in ["Visual", "Auditory", "Read/Write", "Kinesthetic"], (
|
||||
f"Gaya dominan tidak valid: {dominant}"
|
||||
)
|
||||
|
||||
def test_button_mulai_belajar_redirect(self, driver):
|
||||
page = HistoryKuesionerPage(driver)
|
||||
page.open()
|
||||
|
||||
page.click_mulai()
|
||||
|
||||
WebDriverWait(driver, 10).until(
|
||||
lambda d: "materi" in d.current_url
|
||||
)
|
||||
|
||||
assert "materi" in driver.current_url
|
||||
|
||||
|
||||
def test_tabel_riwayat_memuat_data(self, driver):
|
||||
page = HistoryKuesionerPage(driver)
|
||||
page.open()
|
||||
|
||||
rows = page.get_history_rows()
|
||||
assert len(rows) > 0, "Tabel riwayat kosong"
|
||||
|
||||
def test_format_tanggal_valid(self, driver):
|
||||
page = HistoryKuesionerPage(driver)
|
||||
page.open()
|
||||
|
||||
row_text = page.get_history_rows()[0].text
|
||||
assert re.search(r"\d{2}\s[A-Za-z]{3}\s\d{4}", row_text), (
|
||||
f"Format tanggal tidak valid: {row_text}"
|
||||
)
|
||||
|
||||
def test_button_ubah_redirect(self, driver):
|
||||
page = HistoryKuesionerPage(driver)
|
||||
page.open()
|
||||
|
||||
page.click_ubah()
|
||||
WebDriverWait(driver, 5).until(EC.url_contains("kuesioner"))
|
||||
assert "kuesioner" in driver.current_url
|
||||
|
||||
def test_button_unduh_redirect(self, driver):
|
||||
"""
|
||||
PASSED berarti:
|
||||
- Tombol bisa diklik
|
||||
- Redirect ke halaman user-result berhasil
|
||||
"""
|
||||
page = HistoryKuesionerPage(driver)
|
||||
page.open()
|
||||
|
||||
page.click_unduh()
|
||||
|
||||
WebDriverWait(driver, 5).until(EC.url_contains("user-result"))
|
||||
assert "user-result" in driver.current_url
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
import pytest
|
||||
from pages.kuesioner_ls_page import KuesionerLSPage
|
||||
|
||||
class TestKuesionerLS:
|
||||
|
||||
def test_open_kuesioner_ls(self, driver, login_as_user_belum_kuesioner):
|
||||
page = KuesionerLSPage(driver)
|
||||
page.open_from_sidebar()
|
||||
page.click_mulai_kuesioner()
|
||||
|
||||
assert "kuesioner-ls" in driver.current_url
|
||||
|
||||
def test_submit_without_answer_should_fail(self, driver, login_as_user_belum_kuesioner):
|
||||
page = KuesionerLSPage(driver)
|
||||
page.open_from_sidebar()
|
||||
page.click_mulai_kuesioner()
|
||||
|
||||
# jawab hanya 15 dari 16
|
||||
for i in range(1, 16):
|
||||
page.answer_question(i)
|
||||
|
||||
page.submit()
|
||||
|
||||
assert "kuesioner-ls" in driver.current_url
|
||||
|
||||
def test_submit_success_redirect_to_mai(self, driver, login_as_user_belum_kuesioner):
|
||||
page = KuesionerLSPage(driver)
|
||||
page.open_from_sidebar()
|
||||
page.click_mulai_kuesioner()
|
||||
|
||||
page.answer_all_questions()
|
||||
page.submit()
|
||||
|
||||
assert "kuesioner-mai" in driver.current_url
|
||||
|
||||
def test_force_navigation_before_submit_allowed_known_issue(
|
||||
self, driver, login_as_user_belum_kuesioner
|
||||
):
|
||||
page = KuesionerLSPage(driver)
|
||||
page.open_from_sidebar()
|
||||
page.click_mulai_kuesioner()
|
||||
|
||||
# jawab sebagian (belum selesai)
|
||||
page.answer_question(1)
|
||||
page.answer_question(2)
|
||||
|
||||
# user paksa pindah halaman
|
||||
page.force_navigate_to_dashboard()
|
||||
|
||||
assert "kuesioner" in driver.current_url
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
import pytest
|
||||
from pages.kuesioner_mai_page import KuesionerMAIPage
|
||||
|
||||
class TestKuesionerMAI:
|
||||
|
||||
def test_open_kuesioner_mai(self, driver, login_as_user_belum_kuesioner):
|
||||
page = KuesionerMAIPage(driver)
|
||||
page.open_from_sidebar()
|
||||
page.click_mulai_kuesioner()
|
||||
page.answer_all_questions_ls()
|
||||
page.submit()
|
||||
|
||||
assert "kuesioner-mai" in driver.current_url
|
||||
|
||||
def test_submit_mai_without_answer_should_fail(self, driver, login_as_user_belum_kuesioner):
|
||||
page = KuesionerMAIPage(driver)
|
||||
page.open_from_sidebar()
|
||||
page.click_mulai_kuesioner()
|
||||
page.answer_all_questions_ls()
|
||||
page.submit()
|
||||
|
||||
# jawab hanya 50 dari 52
|
||||
for i in range(2, 52):
|
||||
page.answer_question_mai(i)
|
||||
|
||||
page.submit()
|
||||
|
||||
# tetap di halaman MAI
|
||||
assert "kuesioner-mai" in driver.current_url
|
||||
|
||||
def test_submit_mai_success_redirect_to_history(self, driver, login_as_user_belum_kuesioner):
|
||||
page = KuesionerMAIPage(driver)
|
||||
page.open_from_sidebar()
|
||||
page.click_mulai_kuesioner()
|
||||
page.answer_all_questions_ls()
|
||||
page.submit()
|
||||
page.answer_all_questions_mai()
|
||||
page.submit()
|
||||
|
||||
assert "history_quis" in driver.current_url
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
import pytest
|
||||
from pages.kuesioner_panduan_page import KuesionerPanduanPage
|
||||
|
||||
|
||||
class TestKuesionerPanduan:
|
||||
|
||||
def test_open_panduan_from_sidebar(self,
|
||||
driver, login_as_user_sudah_kuesioner):
|
||||
panduan = KuesionerPanduanPage(driver)
|
||||
panduan.open_from_sidebar()
|
||||
|
||||
assert panduan.is_on_panduan_page()
|
||||
|
||||
def test_click_mulai_kuesioner_redirect(self, driver, login_as_user_sudah_kuesioner):
|
||||
panduan = KuesionerPanduanPage(driver)
|
||||
panduan.open_from_sidebar()
|
||||
panduan.click_mulai_kuesioner()
|
||||
|
||||
assert "kuesioner-ls" in driver.current_url
|
||||
|
||||
def test_click_bantuan_redirect_whatsapp(self, driver, login_as_user_sudah_kuesioner):
|
||||
panduan = KuesionerPanduanPage(driver)
|
||||
panduan.open_from_sidebar()
|
||||
panduan.click_bantuan()
|
||||
|
||||
current_url = driver.current_url
|
||||
|
||||
assert "whatsapp.com" in current_url
|
||||
assert "6285290543351" in current_url
|
||||
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
import pytest
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("driver")
|
||||
class TestLoginEmail:
|
||||
"""
|
||||
TEST LOGIN - EMAIL FIELD
|
||||
"""
|
||||
|
||||
VALID_EMAIL = "e41222052@student.polije.ac.id"
|
||||
VALID_PASSWORD = "e41222052@student.polije.ac.id"
|
||||
|
||||
# =========================
|
||||
# POSITIVE TEST
|
||||
# =========================
|
||||
|
||||
def test_login_email_valid(self, login_page):
|
||||
login_page.open()
|
||||
login_page.login(
|
||||
self.VALID_EMAIL,
|
||||
self.VALID_PASSWORD
|
||||
)
|
||||
|
||||
assert login_page.is_login_success()
|
||||
|
||||
# =========================
|
||||
# NEGATIVE TESTS
|
||||
# =========================
|
||||
|
||||
def test_login_email_salah_password_benar(self, login_page):
|
||||
login_page.open()
|
||||
login_page.login(
|
||||
"salah@student.polije.ac.id",
|
||||
self.VALID_PASSWORD
|
||||
)
|
||||
|
||||
assert login_page.has_global_error()
|
||||
|
||||
def test_login_email_kosong(self, login_page):
|
||||
login_page.open()
|
||||
login_page.fill_email("")
|
||||
login_page.fill_password(self.VALID_PASSWORD)
|
||||
login_page.click_login()
|
||||
|
||||
assert login_page.is_field_required("email")
|
||||
|
||||
def test_login_email_tanpa_at(self, login_page):
|
||||
login_page.open()
|
||||
login_page.login(
|
||||
"e41222052student.polije.ac.id",
|
||||
self.VALID_PASSWORD
|
||||
)
|
||||
|
||||
assert login_page.get_email_validation_message()
|
||||
|
||||
def test_login_email_hanya_spasi(self, login_page):
|
||||
login_page.open()
|
||||
login_page.login(
|
||||
" ",
|
||||
self.VALID_PASSWORD
|
||||
)
|
||||
|
||||
assert login_page.get_email_validation_message()
|
||||
|
||||
def test_login_email_tidak_terdaftar(self, login_page):
|
||||
login_page.open()
|
||||
login_page.login(
|
||||
"tidakterdaftar@student.polije.ac.id",
|
||||
self.VALID_PASSWORD
|
||||
)
|
||||
|
||||
assert login_page.has_global_error()
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
import pytest
|
||||
|
||||
|
||||
class TestLoginPassword:
|
||||
|
||||
VALID_EMAIL = "e41222052@student.polije.ac.id"
|
||||
VALID_PASSWORD = "e41222052@student.polije.ac.id"
|
||||
|
||||
# ==========================
|
||||
# PASSWORD NEGATIVE CASES
|
||||
# ==========================
|
||||
|
||||
def test_password_kosong(self, login_page):
|
||||
login_page.fill_email(self.VALID_EMAIL)
|
||||
login_page.fill_password("")
|
||||
login_page.submit()
|
||||
|
||||
assert login_page.has_html5_validation("password")
|
||||
|
||||
def test_password_salah(self, login_page):
|
||||
login_page.fill_email(self.VALID_EMAIL)
|
||||
login_page.fill_password("PasswordSalah123!")
|
||||
login_page.submit()
|
||||
|
||||
assert login_page.is_login_failed()
|
||||
|
||||
def test_password_hanya_spasi(self, login_page):
|
||||
login_page.fill_email(self.VALID_EMAIL)
|
||||
login_page.fill_password(" ")
|
||||
login_page.submit()
|
||||
|
||||
assert login_page.is_login_failed()
|
||||
|
||||
def test_password_kurang_dari_8_karakter(self, login_page):
|
||||
login_page.fill_email(self.VALID_EMAIL)
|
||||
login_page.fill_password("Abc1!")
|
||||
login_page.submit()
|
||||
|
||||
assert login_page.is_login_failed()
|
||||
|
||||
# ==========================
|
||||
# PASSWORD POSITIVE CASE
|
||||
# ==========================
|
||||
|
||||
def test_password_valid(self, login_page):
|
||||
login_page.fill_email(self.VALID_EMAIL)
|
||||
login_page.fill_password(self.VALID_PASSWORD)
|
||||
login_page.submit()
|
||||
|
||||
assert login_page.is_login_success()
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
import pytest
|
||||
|
||||
@pytest.mark.usefixtures("driver")
|
||||
class TestLoginRememberMe:
|
||||
|
||||
VALID_EMAIL = "e41222052@student.polije.ac.id"
|
||||
VALID_PASSWORD = "e41222052@student.polije.ac.id"
|
||||
|
||||
def test_remember_me_checkbox_dapat_dicentang(self, login_page):
|
||||
login_page.fill_email(self.VALID_EMAIL)
|
||||
login_page.fill_password(self.VALID_PASSWORD)
|
||||
login_page.click_remember_me()
|
||||
|
||||
assert login_page.is_remember_me_checked()
|
||||
|
||||
def test_login_dengan_remember_me_dan_refresh(self, login_page, driver):
|
||||
login_page.fill_email(self.VALID_EMAIL)
|
||||
login_page.fill_password(self.VALID_PASSWORD)
|
||||
login_page.click_remember_me()
|
||||
login_page.submit()
|
||||
|
||||
assert login_page.is_login_success()
|
||||
|
||||
# refresh halaman
|
||||
driver.refresh()
|
||||
|
||||
# masih di dashboard
|
||||
assert login_page.is_login_success()
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
import pytest
|
||||
|
||||
class TestLoginSSOGoogle:
|
||||
|
||||
def test_button_sso_google_tersedia(self, login_page):
|
||||
assert login_page.driver.find_element(
|
||||
*login_page.SSO_GOOGLE_BUTTON
|
||||
)
|
||||
|
||||
def test_redirect_ke_google_oauth(self, login_page):
|
||||
login_page.click_sso_google()
|
||||
|
||||
assert login_page.is_redirected_to_google()
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
import pytest
|
||||
from pages.logout_page import LogoutPage
|
||||
|
||||
|
||||
class TestLogout:
|
||||
|
||||
# ===============================
|
||||
# 1️⃣ Test: Modal Muncul
|
||||
# ===============================
|
||||
def test_logout_modal_muncul(self, driver, login_as_user_sudah_kuesioner):
|
||||
logout = LogoutPage(driver)
|
||||
|
||||
logout.open_user_dropdown()
|
||||
logout.click_logout_menu()
|
||||
|
||||
assert logout.is_logout_modal_visible()
|
||||
|
||||
|
||||
# ===============================
|
||||
# 2️⃣ Test: Klik Tidak → Tetap di halaman
|
||||
# ===============================
|
||||
def test_logout_tidak_tetap_di_dashboard(self, driver, login_as_user_sudah_kuesioner):
|
||||
logout = LogoutPage(driver)
|
||||
|
||||
current_url = driver.current_url
|
||||
|
||||
logout.open_user_dropdown()
|
||||
logout.click_logout_menu()
|
||||
logout.click_tidak()
|
||||
|
||||
assert driver.current_url == current_url
|
||||
|
||||
|
||||
# ===============================
|
||||
# 3️⃣ Test: Klik Ya → Redirect ke Home
|
||||
# ===============================
|
||||
def test_logout_ya_redirect_ke_home(self, driver, login_as_user_sudah_kuesioner):
|
||||
logout = LogoutPage(driver)
|
||||
|
||||
logout.open_user_dropdown()
|
||||
logout.click_logout_menu()
|
||||
logout.click_ya_logout()
|
||||
|
||||
logout.wait_until_redirect_to_home()
|
||||
|
||||
assert "dashboard" not in driver.current_url.lower()
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
from pages.materi_page import MateriPage
|
||||
|
||||
|
||||
class TestMateriAuditory:
|
||||
|
||||
def test_open_auditory_material(self, driver, login_as_user_sudah_kuesioner):
|
||||
driver.get("https://hypermedialearning.sanggadewa.my.id/materi/auditory/1")
|
||||
|
||||
page = MateriPage(driver)
|
||||
page.auditory_page_loaded()
|
||||
page.sidebar_visible()
|
||||
|
||||
assert "materi/auditory" in driver.current_url
|
||||
|
||||
def test_auditory_has_audio_player(self, driver, login_as_user_sudah_kuesioner):
|
||||
driver.get("https://hypermedialearning.sanggadewa.my.id/materi/auditory/1")
|
||||
|
||||
page = MateriPage(driver)
|
||||
page.auditory_page_loaded()
|
||||
|
||||
audio = page.driver.find_element(*page.AUDIO_PLAYER)
|
||||
assert audio.is_displayed()
|
||||
assert audio.get_attribute("controls") is not None
|
||||
|
||||
def test_navigate_auditory_to_visual(self, driver, login_as_user_sudah_kuesioner):
|
||||
driver.get("https://hypermedialearning.sanggadewa.my.id/materi/auditory/1")
|
||||
|
||||
page = MateriPage(driver)
|
||||
page.go_to_visual()
|
||||
page.visual_page_loaded()
|
||||
|
||||
assert "materi/visual" in driver.current_url
|
||||
|
||||
def test_navigation_requires_confirmation_from_auditory(
|
||||
self, driver, login_as_user_sudah_kuesioner
|
||||
):
|
||||
driver.get("https://hypermedialearning.sanggadewa.my.id/materi/auditory/1")
|
||||
|
||||
page = MateriPage(driver)
|
||||
|
||||
# User mencoba pindah sebelum selesai belajar
|
||||
page.go_to_visual()
|
||||
|
||||
# Expected behavior (ideal requirement):
|
||||
assert "materi/auditory" in driver.current_url, \
|
||||
"User seharusnya tidak bisa meninggalkan halaman sebelum selesai belajar"
|
||||
|
|
@ -0,0 +1,141 @@
|
|||
import pytest
|
||||
from pages.live_coding_page import LiveCodingPage
|
||||
|
||||
class TestKinesthetic:
|
||||
|
||||
def test_live_coding_page_loaded(self,driver,login_as_user_belum_kuesioner):
|
||||
driver.get("https://hypermedialearning.sanggadewa.my.id/materi/kinesthetic/1")
|
||||
page = LiveCodingPage(driver)
|
||||
|
||||
assert page.is_page_loaded()
|
||||
assert page.editor_is_visible()
|
||||
assert "Hasil Output" in page.get_expected_output_text()
|
||||
|
||||
def test_submit_without_completing_code(self,driver,login_as_user_belum_kuesioner):
|
||||
driver.get("https://hypermedialearning.sanggadewa.my.id/materi/kinesthetic/1")
|
||||
page = LiveCodingPage(driver)
|
||||
|
||||
page.submit_code()
|
||||
result = page.get_result_message()
|
||||
assert "Kompilasi Gagal" in result
|
||||
|
||||
"""assert "Jawaban Salah" in result
|
||||
assert "Seharusnya" in result"""
|
||||
|
||||
def test_submit_with_wrong_code(self,driver,login_as_user_belum_kuesioner):
|
||||
driver.get("https://hypermedialearning.sanggadewa.my.id/materi/kinesthetic/1")
|
||||
page = LiveCodingPage(driver)
|
||||
|
||||
page.append_code("System.out.println(\"SALAH\");")
|
||||
page.submit_code()
|
||||
|
||||
result = page.get_result_message()
|
||||
assert "Kompilasi Gagal" in result
|
||||
|
||||
"""assert "Jawaban Salah" in result
|
||||
assert "Seharusnya" in result"""
|
||||
|
||||
def test_submit_with_correct_code(self,driver,login_as_user_belum_kuesioner):
|
||||
driver.get("https://hypermedialearning.sanggadewa.my.id/materi/kinesthetic/1")
|
||||
page = LiveCodingPage(driver)
|
||||
|
||||
page.append_code(
|
||||
"System.out.println(m1.getNama() + \" | IPK: \" + m1.getIpk() + \"\\n\" + m2.getNama() + \" | IPK: \" + m2.getIpk());")
|
||||
page.submit_code()
|
||||
|
||||
result = page.get_result_message()
|
||||
assert "Jawaban Benar" in result
|
||||
|
||||
def test_default_code_is_displayed(self,driver,login_as_user_belum_kuesioner):
|
||||
driver.get("https://hypermedialearning.sanggadewa.my.id/materi/kinesthetic/1")
|
||||
page = LiveCodingPage(driver)
|
||||
code = page.get_editor_value()
|
||||
|
||||
assert code.strip() != "", \
|
||||
"FAIL: Kode bawaan materi tidak tampil pada editor"
|
||||
|
||||
def test_popup_can_be_closed(self,driver,login_as_user_belum_kuesioner):
|
||||
driver.get("https://hypermedialearning.sanggadewa.my.id/materi/kinesthetic/1")
|
||||
page = LiveCodingPage(driver)
|
||||
page.append_code("\nprint('test')")
|
||||
page.submit_code()
|
||||
|
||||
page.wait_popup_visible()
|
||||
assert page.is_popup_visible()
|
||||
|
||||
page.close_result_modal()
|
||||
page.wait_popup_invisible()
|
||||
|
||||
assert not page.is_popup_visible(), \
|
||||
"FAIL: Popup evaluasi tidak tertutup"
|
||||
|
||||
def test_previous_button_on_first_page(self,driver,login_as_user_belum_kuesioner):
|
||||
driver.get("https://hypermedialearning.sanggadewa.my.id/materi/kinesthetic/1")
|
||||
page = LiveCodingPage(driver)
|
||||
initial_url = page.get_current_url()
|
||||
|
||||
page.click_previous()
|
||||
|
||||
current_url = page.get_current_url()
|
||||
|
||||
assert current_url == initial_url, (
|
||||
"FAIL: Tombol Sebelumnya pada halaman pertama "
|
||||
"seharusnya tidak berpindah halaman"
|
||||
)
|
||||
|
||||
assert not page.is_404_page(), (
|
||||
"FAIL: Tombol Sebelumnya menyebabkan halaman 404"
|
||||
)
|
||||
|
||||
def test_next_button_on_first_page(self,driver,login_as_user_belum_kuesioner):
|
||||
driver.get("https://hypermedialearning.sanggadewa.my.id/materi/kinesthetic/1")
|
||||
page = LiveCodingPage(driver)
|
||||
initial_url = page.get_current_url()
|
||||
|
||||
page.click_next()
|
||||
|
||||
current_url = page.get_current_url()
|
||||
|
||||
assert current_url != initial_url, (
|
||||
"FAIL: Tombol Selanjutnya tidak berpindah ke halaman berikutnya"
|
||||
)
|
||||
|
||||
assert not page.is_404_page(), (
|
||||
"FAIL: Tombol Selanjutnya menyebabkan halaman 404"
|
||||
)
|
||||
|
||||
def test_navigation_without_submit_shows_validation(self,driver,login_as_user_belum_kuesioner):
|
||||
driver.get("https://hypermedialearning.sanggadewa.my.id/materi/kinesthetic/1")
|
||||
page = LiveCodingPage(driver)
|
||||
"""
|
||||
User berpindah halaman sebelum submit kode
|
||||
Expected: muncul notifikasi validasi
|
||||
"""
|
||||
|
||||
initial_url = page.get_current_url()
|
||||
page.append_code("\nSystem.out.println('Belum submit');")
|
||||
page.click_other_menu()
|
||||
|
||||
# ===== CASE 1: JS ALERT =====
|
||||
alert_text = page.is_confirm_alert_present()
|
||||
if alert_text:
|
||||
assert (
|
||||
"yakin" in alert_text.lower()
|
||||
or "belum" in alert_text.lower()
|
||||
), "FAIL: Teks alert tidak sesuai validasi"
|
||||
return
|
||||
|
||||
# ===== CASE 2: HTML MODAL =====
|
||||
assert page.is_confirm_modal_visible(), (
|
||||
"FAIL: Tidak ada alert atau modal validasi saat berpindah halaman"
|
||||
)
|
||||
|
||||
# Pastikan belum pindah halaman
|
||||
assert page.get_current_url() == initial_url, (
|
||||
"FAIL: Sistem berpindah halaman tanpa konfirmasi"
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
import pytest
|
||||
from pages.materi_pembelajaran_page import MateriPembelajaranPage
|
||||
|
||||
|
||||
class TestMateriPembelajaranEnkapsulasi:
|
||||
|
||||
def test_open_halaman_enkapsulasi(self, driver, login_as_user_sudah_kuesioner):
|
||||
page = MateriPembelajaranPage(driver)
|
||||
page.open_from_sidebar()
|
||||
|
||||
assert "/materi" in driver.current_url
|
||||
|
||||
def test_tampilkan_learning_style_user(self, driver, login_as_user_sudah_kuesioner):
|
||||
page = MateriPembelajaranPage(driver)
|
||||
page.open_from_sidebar()
|
||||
|
||||
style = page.get_learning_style_user()
|
||||
assert style in ["Visual", "Auditory", "Read/Write", "Kinesthetic"]
|
||||
|
||||
def test_mulai_belajar_learning_style_utama(self, driver, login_as_user_sudah_kuesioner):
|
||||
page = MateriPembelajaranPage(driver)
|
||||
page.open_from_sidebar()
|
||||
page.click_mulai_belajar_utama()
|
||||
|
||||
judul = page.get_judul_materi()
|
||||
assert judul != ""
|
||||
|
||||
def test_pesan_materi_alternatif_muncul(self, driver, login_as_user_sudah_kuesioner):
|
||||
page = MateriPembelajaranPage(driver)
|
||||
page.open_from_sidebar()
|
||||
|
||||
assert page.wait.until(
|
||||
lambda d: d.find_element(*page.PESAN_ALTERNATIF)
|
||||
)
|
||||
|
||||
def test_mulai_belajar_visual(self, driver, login_as_user_sudah_kuesioner):
|
||||
page = MateriPembelajaranPage(driver)
|
||||
page.open_from_sidebar()
|
||||
page.click_visual()
|
||||
|
||||
assert page.get_judul_materi() == "Materi Visual"
|
||||
|
||||
def test_mulai_belajar_auditory(self, driver, login_as_user_sudah_kuesioner):
|
||||
page = MateriPembelajaranPage(driver)
|
||||
page.open_from_sidebar()
|
||||
page.click_auditory()
|
||||
|
||||
assert page.get_judul_materi() == "Materi Auditory"
|
||||
|
||||
def test_mulai_belajar_read_write(self, driver, login_as_user_sudah_kuesioner):
|
||||
page = MateriPembelajaranPage(driver)
|
||||
page.open_from_sidebar()
|
||||
page.click_read_write()
|
||||
|
||||
assert page.get_judul_materi() == "Materi Read / Write"
|
||||
|
|
@ -0,0 +1,114 @@
|
|||
import pytest
|
||||
from pages.materi_readwrite_page import MateriReadWritePage
|
||||
from selenium.webdriver.support import expected_conditions as EC
|
||||
|
||||
class TestMateriReadWrite:
|
||||
|
||||
def test_readwrite_page_display_text_materi(self, driver, login_as_user_sudah_kuesioner):
|
||||
driver.get("https://hypermedialearning.sanggadewa.my.id/materi/readwrite/1")
|
||||
page = MateriReadWritePage(driver)
|
||||
page.page_loaded()
|
||||
|
||||
text = page.get_text_materi()
|
||||
assert len(text) > 0
|
||||
|
||||
def test_submit_rangkuman_success(self, driver, login_as_user_sudah_kuesioner):
|
||||
driver.get("https://hypermedialearning.sanggadewa.my.id/materi/readwrite/1")
|
||||
page = MateriReadWritePage(driver)
|
||||
page.page_loaded()
|
||||
|
||||
rangkuman_valid = (
|
||||
"Enkapsulasi adalah konsep dalam pemrograman berorientasi objek "
|
||||
"yang digunakan untuk membungkus data dan method dalam satu kelas. "
|
||||
"Tujuannya adalah melindungi data agar tidak diakses langsung dari luar."
|
||||
)
|
||||
page.input_rangkuman(rangkuman_valid)
|
||||
page.submit_rangkuman()
|
||||
|
||||
alert = page.success_message_displayed()
|
||||
assert "berhasil" in alert.text.lower()
|
||||
|
||||
def test_submit_rangkuman_empty_should_fail(self, driver, login_as_user_sudah_kuesioner):
|
||||
driver.get("https://hypermedialearning.sanggadewa.my.id/materi/readwrite/1")
|
||||
page = MateriReadWritePage(driver)
|
||||
page.page_loaded()
|
||||
|
||||
page.input_rangkuman("")
|
||||
page.submit_rangkuman()
|
||||
|
||||
# tetap di halaman yang sama (validasi HTML required)
|
||||
assert "readwrite" in driver.current_url
|
||||
|
||||
def test_tugas_rangkuman_section_label_displayed(self, driver, login_as_user_sudah_kuesioner):
|
||||
driver.get("https://hypermedialearning.sanggadewa.my.id/materi/readwrite/1")
|
||||
page = MateriReadWritePage(driver)
|
||||
page.page_loaded()
|
||||
|
||||
label = page.wait.until(
|
||||
EC.visibility_of_element_located(page.TUGAS_RANGKUMAN_LABEL)
|
||||
)
|
||||
|
||||
assert label.is_displayed()
|
||||
assert "TUGAS RANGKUMAN" in label.text
|
||||
|
||||
def test_input_rangkuman_textarea_displayed(self, driver, login_as_user_sudah_kuesioner):
|
||||
driver.get("https://hypermedialearning.sanggadewa.my.id/materi/readwrite/1")
|
||||
page = MateriReadWritePage(driver)
|
||||
page.page_loaded()
|
||||
|
||||
textarea = page.wait.until(
|
||||
EC.visibility_of_element_located(page.RANGKUMAN_TEXTAREA)
|
||||
)
|
||||
|
||||
assert textarea.is_displayed()
|
||||
assert textarea.is_enabled()
|
||||
|
||||
def test_submit_rangkuman_less_than_50_words_should_be_rejected(self, driver, login_as_user_sudah_kuesioner):
|
||||
driver.get("https://hypermedialearning.sanggadewa.my.id/materi/readwrite/1")
|
||||
page = MateriReadWritePage(driver)
|
||||
page.page_loaded()
|
||||
|
||||
short_text = "Enkapsulasi adalah konsep OOP untuk melindungi data."
|
||||
page.input_rangkuman(short_text)
|
||||
page.submit_rangkuman()
|
||||
|
||||
assert page.error_message_displayed()
|
||||
|
||||
def test_submit_rangkuman_more_than_75_words_should_be_rejected(self, driver, login_as_user_sudah_kuesioner):
|
||||
driver.get("https://hypermedialearning.sanggadewa.my.id/materi/readwrite/1")
|
||||
page = MateriReadWritePage(driver)
|
||||
page.page_loaded()
|
||||
|
||||
long_text = " ".join(["enkapsulasi"] * 80)
|
||||
page.input_rangkuman(long_text)
|
||||
page.submit_rangkuman()
|
||||
|
||||
assert page.error_message_displayed()
|
||||
|
||||
def test_cannot_leave_page_without_submit_rangkuman(self, driver, login_as_user_sudah_kuesioner):
|
||||
driver.get("https://hypermedialearning.sanggadewa.my.id/materi/readwrite/1")
|
||||
page = MateriReadWritePage(driver)
|
||||
page.page_loaded()
|
||||
|
||||
page.input_rangkuman("Rangkuman belum dikirim")
|
||||
page.go_to_visual()
|
||||
|
||||
# Sistem HARUS menahan user di halaman ini
|
||||
assert "readwrite" in driver.current_url
|
||||
|
||||
def test_textarea_cleared_after_submit(self, driver, login_as_user_sudah_kuesioner):
|
||||
driver.get("https://hypermedialearning.sanggadewa.my.id/materi/readwrite/1")
|
||||
page = MateriReadWritePage(driver)
|
||||
page.page_loaded()
|
||||
|
||||
text = " ".join(["enkapsulasi"] * 50)
|
||||
page.input_rangkuman(text)
|
||||
page.submit_rangkuman()
|
||||
|
||||
textarea = driver.find_element(*page.RANGKUMAN_TEXTAREA)
|
||||
assert textarea.get_attribute("value") == ""
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
import pytest
|
||||
from pages.materi_page import MateriPage
|
||||
|
||||
|
||||
class TestMateriVisual:
|
||||
|
||||
def test_open_visual_material(self, driver, login_as_user_sudah_kuesioner):
|
||||
driver.get("https://hypermedialearning.sanggadewa.my.id/materi/visual/1")
|
||||
|
||||
page = MateriPage(driver)
|
||||
page.visual_page_loaded()
|
||||
page.sidebar_visible()
|
||||
|
||||
assert "materi/visual" in driver.current_url
|
||||
|
||||
def test_visual_has_image(self, driver, login_as_user_sudah_kuesioner):
|
||||
driver.get("https://hypermedialearning.sanggadewa.my.id/materi/visual/1")
|
||||
|
||||
page = MateriPage(driver)
|
||||
page.visual_page_loaded()
|
||||
|
||||
assert page.driver.find_element(*page.VISUAL_IMAGE).is_displayed()
|
||||
|
||||
def test_navigate_visual_to_auditory(self, driver, login_as_user_sudah_kuesioner):
|
||||
driver.get("https://hypermedialearning.sanggadewa.my.id/materi/visual/1")
|
||||
|
||||
page = MateriPage(driver)
|
||||
page.go_to_auditory()
|
||||
page.auditory_page_loaded()
|
||||
|
||||
assert "materi/auditory" in driver.current_url
|
||||
|
||||
#@pytest.mark.xfail(reason="Belum ada validasi sebelum meninggalkan halaman materi")
|
||||
def test_navigation_requires_confirmation(self, driver, login_as_user_sudah_kuesioner):
|
||||
driver.get("https://hypermedialearning.sanggadewa.my.id/materi/visual/1")
|
||||
|
||||
page = MateriPage(driver)
|
||||
page.go_to_auditory()
|
||||
|
||||
# Expected behavior (yang benar secara requirement)
|
||||
assert "materi/visual" in driver.current_url
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
import pytest
|
||||
from datetime import datetime
|
||||
from pages.profile_page import ProfilePage
|
||||
|
||||
|
||||
# ======================================================
|
||||
# ANGKATAN VALIDATION
|
||||
# ======================================================
|
||||
|
||||
class TestProfileAngkatanValidation:
|
||||
|
||||
def test_angkatan_dropdown_options(self,driver,login_as_user_belum_kuesioner):
|
||||
driver.get("https://hypermedialearning.sanggadewa.my.id/profile")
|
||||
page = ProfilePage(driver)
|
||||
|
||||
current_year = datetime.now().year
|
||||
|
||||
expected_years = [
|
||||
str(current_year - i) for i in reversed(range(7))
|
||||
]
|
||||
|
||||
actual_years = page.get_all_angkatan_options()
|
||||
|
||||
assert actual_years == expected_years
|
||||
|
||||
def test_angkatan_valid(self,driver,login_as_user_belum_kuesioner):
|
||||
driver.get("https://hypermedialearning.sanggadewa.my.id/profile")
|
||||
page = ProfilePage(driver)
|
||||
|
||||
page.select_angkatan("2022")
|
||||
page.click_save()
|
||||
page.wait_until_reload_after_save()
|
||||
|
||||
assert page.get_selected_angkatan() == "2022"
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
import pytest
|
||||
from pages.profile_page import ProfilePage
|
||||
|
||||
class TestProfileButton:
|
||||
|
||||
def test_button_simpan_update_data(self,driver,login_as_user_belum_kuesioner):
|
||||
driver.get("https://hypermedialearning.sanggadewa.my.id/profile")
|
||||
page = ProfilePage(driver)
|
||||
new_name = "Ini Testing"
|
||||
page.set_nama_lengkap(new_name)
|
||||
page.click_save()
|
||||
page.wait_until_reload_after_save()
|
||||
assert page.get_nama_lengkap() == new_name
|
||||
|
||||
|
||||
def test_button_simpan_validasi_gagal_revert(self,driver,login_as_user_belum_kuesioner):
|
||||
driver.get("https://hypermedialearning.sanggadewa.my.id/profile")
|
||||
page = ProfilePage(driver)
|
||||
default_name = page.get_nama_lengkap()
|
||||
page.set_nama_lengkap("")
|
||||
page.click_save()
|
||||
assert page.get_nama_lengkap() == default_name
|
||||
|
||||
|
||||
def test_button_batal_kembali_ke_default(self,driver,login_as_user_belum_kuesioner):
|
||||
driver.get("https://hypermedialearning.sanggadewa.my.id/profile")
|
||||
page = ProfilePage(driver)
|
||||
default_name = page.get_nama_lengkap()
|
||||
page.set_nama_lengkap("Nama Tidak Disimpan")
|
||||
page.click_cancel()
|
||||
assert page.get_nama_lengkap() == default_name
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
import pytest
|
||||
from pages.profile_page import ProfilePage
|
||||
|
||||
class TestProfileDisplay:
|
||||
|
||||
def test_email_tampil_sesuai_akun(self,driver,login_as_user_belum_kuesioner):
|
||||
driver.get("https://hypermedialearning.sanggadewa.my.id/profile")
|
||||
page = ProfilePage(driver)
|
||||
"""
|
||||
Verifikasi email tampil sesuai akun dan tidak kosong
|
||||
"""
|
||||
page.wait_until_page_loaded()
|
||||
|
||||
email = page.get_email()
|
||||
|
||||
assert email is not None
|
||||
#assert email != ""
|
||||
assert "@" in email
|
||||
assert email.endswith(".ac.id")
|
||||
#or email.endswith(".com")
|
||||
|
||||
|
||||
def test_email_tidak_bisa_diedit(self,driver,login_as_user_belum_kuesioner):
|
||||
driver.get("https://hypermedialearning.sanggadewa.my.id/profile")
|
||||
page = ProfilePage(driver)
|
||||
"""
|
||||
Verifikasi email memiliki attribute readonly
|
||||
"""
|
||||
assert page.is_email_readonly() is True
|
||||
|
||||
|
||||
def test_nim_tampil_sesuai_akun(self,driver,login_as_user_belum_kuesioner):
|
||||
driver.get("https://hypermedialearning.sanggadewa.my.id/profile")
|
||||
page = ProfilePage(driver)
|
||||
"""
|
||||
Verifikasi NIM tampil dan tidak kosong
|
||||
"""
|
||||
nim = page.get_nim()
|
||||
|
||||
assert nim is not None
|
||||
assert nim != ""
|
||||
assert len(nim) >= 9
|
||||
assert len(nim) <= 10
|
||||
|
||||
|
||||
def test_semester_tampil_sesuai_akun(self,driver,login_as_user_belum_kuesioner):
|
||||
driver.get("https://hypermedialearning.sanggadewa.my.id/profile")
|
||||
page = ProfilePage(driver)
|
||||
"""
|
||||
Verifikasi semester memiliki selected value
|
||||
"""
|
||||
semester = page.get_selected_semester()
|
||||
|
||||
assert semester is not None
|
||||
assert semester.isdigit()
|
||||
assert int(semester) >= 1
|
||||
assert int(semester) <= 8
|
||||
|
||||
|
||||
def test_angkatan_tampil_sesuai_akun(self,driver,login_as_user_belum_kuesioner):
|
||||
driver.get("https://hypermedialearning.sanggadewa.my.id/profile")
|
||||
page = ProfilePage(driver)
|
||||
"""
|
||||
Verifikasi angkatan memiliki selected value
|
||||
"""
|
||||
angkatan = page.get_selected_angkatan()
|
||||
|
||||
assert angkatan is not None
|
||||
assert angkatan.isdigit()
|
||||
assert len(angkatan) == 4
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
import pytest
|
||||
from datetime import datetime
|
||||
from pages.profile_page import ProfilePage
|
||||
|
||||
|
||||
class TestProfileNamaValidation:
|
||||
|
||||
# ======================================================
|
||||
# NAMA VALIDATION
|
||||
# ======================================================
|
||||
|
||||
def test_nama_kosong(self,driver,login_as_user_belum_kuesioner):
|
||||
driver.get("https://hypermedialearning.sanggadewa.my.id/profile")
|
||||
page = ProfilePage(driver)
|
||||
default_name = page.get_nama_lengkap()
|
||||
page.set_nama_lengkap("")
|
||||
page.click_save()
|
||||
assert page.get_nama_lengkap() == default_name
|
||||
|
||||
def test_nama_valid(self,driver,login_as_user_belum_kuesioner):
|
||||
driver.get("https://hypermedialearning.sanggadewa.my.id/profile")
|
||||
page = ProfilePage(driver)
|
||||
|
||||
page.set_nama_lengkap("Rurin Nurliza")
|
||||
page.click_save()
|
||||
page.wait_until_reload_after_save()
|
||||
|
||||
assert page.get_nama_lengkap() == "Rurin Nurliza"
|
||||
|
||||
def test_nama_kurang_5_karakter(self,driver,login_as_user_belum_kuesioner):
|
||||
driver.get("https://hypermedialearning.sanggadewa.my.id/profile")
|
||||
page = ProfilePage(driver)
|
||||
default_name = page.get_nama_lengkap()
|
||||
page.set_nama_lengkap("Rin")
|
||||
page.click_save()
|
||||
assert page.get_nama_lengkap() == default_name, ("FAIL, Sistem tidak mengembalikan nama ke default")
|
||||
|
||||
def test_nama_lebih_30_karakter(self,driver,login_as_user_belum_kuesioner):
|
||||
driver.get("https://hypermedialearning.sanggadewa.my.id/profile")
|
||||
page = ProfilePage(driver)
|
||||
default_name = page.get_nama_lengkap()
|
||||
page.set_nama_lengkap("IniNamaYangSangatPanjangSekaliSeharusnyaTidakBoleh")
|
||||
page.click_save()
|
||||
assert page.get_nama_lengkap() == default_name, ("FAIL, Sistem tidak mengembalikan nama ke default")
|
||||
|
||||
def test_nama_angka_semua(self,driver,login_as_user_belum_kuesioner):
|
||||
driver.get("https://hypermedialearning.sanggadewa.my.id/profile")
|
||||
page = ProfilePage(driver)
|
||||
default_name = page.get_nama_lengkap()
|
||||
page.set_nama_lengkap("12345678")
|
||||
page.click_save()
|
||||
assert page.get_nama_lengkap() == default_name, ("FAIL, Sistem tidak mengembalikan nama ke default dan tidak memberika validasi error")
|
||||
|
||||
def test_nama_simbol_semua(self,driver,login_as_user_belum_kuesioner):
|
||||
driver.get("https://hypermedialearning.sanggadewa.my.id/profile")
|
||||
page = ProfilePage(driver)
|
||||
default_name = page.get_nama_lengkap()
|
||||
page.set_nama_lengkap("@@@@@@@")
|
||||
page.click_save()
|
||||
assert page.get_nama_lengkap() == default_name, ("FAIL, Sistem tidak mengembalikan nama ke default dan tidak memberika validasi error")
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
import pytest
|
||||
from datetime import datetime
|
||||
from pages.profile_page import ProfilePage
|
||||
|
||||
|
||||
class TestProfileNimValidation:
|
||||
|
||||
# ======================================================
|
||||
# NIM VALIDATION
|
||||
# ======================================================
|
||||
|
||||
def test_nim_kosong(self,driver,login_as_user_belum_kuesioner):
|
||||
driver.get("https://hypermedialearning.sanggadewa.my.id/profile")
|
||||
page = ProfilePage(driver)
|
||||
default_nim = page.get_nim()
|
||||
page.set_nim("")
|
||||
page.click_save()
|
||||
assert page.get_nim() == default_nim
|
||||
|
||||
def test_nim_valid(self,driver,login_as_user_belum_kuesioner):
|
||||
driver.get("https://hypermedialearning.sanggadewa.my.id/profile")
|
||||
page = ProfilePage(driver)
|
||||
|
||||
page.set_nim("2022012345")
|
||||
page.click_save()
|
||||
page.wait_until_reload_after_save()
|
||||
|
||||
assert page.get_nim() == "2022012345"
|
||||
|
||||
def test_nim_bukan_angka(self,driver,login_as_user_belum_kuesioner):
|
||||
driver.get("https://hypermedialearning.sanggadewa.my.id/profile")
|
||||
page = ProfilePage(driver)
|
||||
default_nim = page.get_nim
|
||||
page.set_nim("ABC12345")
|
||||
page.click_save()
|
||||
assert page.get_nim() == default_nim
|
||||
|
||||
def test_nim_kurang_minimal(self,driver,login_as_user_belum_kuesioner):
|
||||
driver.get("https://hypermedialearning.sanggadewa.my.id/profile")
|
||||
page = ProfilePage(driver)
|
||||
default_nim = page.get_nim
|
||||
page.set_nim("1234567")
|
||||
page.click_save()
|
||||
assert page.get_nim() == default_nim
|
||||
|
||||
def test_nim_lebih_maksimal(self,driver,login_as_user_belum_kuesioner):
|
||||
driver.get("https://hypermedialearning.sanggadewa.my.id/profile")
|
||||
page = ProfilePage(driver)
|
||||
default_nim = page.get_nim
|
||||
page.set_nim("1234567890123456")
|
||||
page.click_save()
|
||||
assert page.get_nim() == default_nim
|
||||
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
import pytest
|
||||
from datetime import datetime
|
||||
from pages.profile_page import ProfilePage
|
||||
|
||||
|
||||
class TestProfileSemesterValidation:
|
||||
|
||||
# ======================================================
|
||||
# SEMESTER VALIDATION
|
||||
# ======================================================
|
||||
|
||||
def test_semester_valid(self,driver,login_as_user_belum_kuesioner):
|
||||
driver.get("https://hypermedialearning.sanggadewa.my.id/profile")
|
||||
page = ProfilePage(driver)
|
||||
page.select_semester("5")
|
||||
page.click_save()
|
||||
page.wait_until_reload_after_save()
|
||||
|
||||
assert page.get_selected_semester() == "5"
|
||||
|
||||
def test_semester_dropdown_options(self,driver,login_as_user_belum_kuesioner):
|
||||
driver.get("https://hypermedialearning.sanggadewa.my.id/profile")
|
||||
page = ProfilePage(driver)
|
||||
|
||||
options = page.get_all_semester_options()
|
||||
|
||||
assert options == ["1", "2", "3", "4", "5", "6", "7", "8"]
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,114 @@
|
|||
import os
|
||||
import pytest
|
||||
from pages.profile_page import ProfilePage
|
||||
|
||||
|
||||
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
|
||||
TEST_DATA_DIR = os.path.join(BASE_DIR, "test_data")
|
||||
|
||||
class TestProfileUpload:
|
||||
|
||||
def test_upload_jpg_berhasil(self,driver,login_as_user_belum_kuesioner):
|
||||
driver.get("https://hypermedialearning.sanggadewa.my.id/profile")
|
||||
page = ProfilePage(driver)
|
||||
"""
|
||||
Upload file JPG berhasil dan preview berubah
|
||||
"""
|
||||
page.wait_until_page_loaded()
|
||||
|
||||
old_src = page.get_profile_image_src()
|
||||
|
||||
file_path = os.path.join(TEST_DATA_DIR, "Kucink_Jpg.jpg")
|
||||
page.upload_photo(file_path)
|
||||
page.click_save()
|
||||
page.refresh_page()
|
||||
|
||||
new_src = page.get_profile_image_src()
|
||||
|
||||
assert old_src != new_src
|
||||
|
||||
|
||||
def test_upload_png_berhasil(self,driver,login_as_user_belum_kuesioner):
|
||||
driver.get("https://hypermedialearning.sanggadewa.my.id/profile")
|
||||
page = ProfilePage(driver)
|
||||
"""
|
||||
Upload file PNG berhasil
|
||||
"""
|
||||
old_src = page.get_profile_image_src()
|
||||
|
||||
file_path = os.path.join(TEST_DATA_DIR, "Kucink_PNG.png")
|
||||
page.upload_photo(file_path)
|
||||
page.click_save()
|
||||
page.refresh_page()
|
||||
|
||||
new_src = page.get_profile_image_src()
|
||||
|
||||
assert old_src != new_src
|
||||
|
||||
|
||||
def test_upload_file_selain_gambar_ditolak(self,driver,login_as_user_belum_kuesioner):
|
||||
driver.get("https://hypermedialearning.sanggadewa.my.id/profile")
|
||||
page = ProfilePage(driver)
|
||||
"""
|
||||
Upload file selain JPG/PNG harus ditolak
|
||||
"""
|
||||
old_src = page.get_profile_image_src()
|
||||
|
||||
file_path = os.path.join(TEST_DATA_DIR, "invalid_file.pdf")
|
||||
page.upload_photo(file_path)
|
||||
page.click_save()
|
||||
page.refresh_page()
|
||||
|
||||
new_src = page.get_profile_image_src()
|
||||
|
||||
assert old_src == new_src
|
||||
|
||||
|
||||
def test_upload_file_lebih_800kb_ditolak(self,driver,login_as_user_belum_kuesioner):
|
||||
driver.get("https://hypermedialearning.sanggadewa.my.id/profile")
|
||||
page = ProfilePage(driver)
|
||||
"""
|
||||
Upload file > 800KB harus gagal
|
||||
"""
|
||||
old_src = page.get_profile_image_src()
|
||||
|
||||
file_path = os.path.join(TEST_DATA_DIR, "large_image.jpg")
|
||||
page.upload_photo(file_path)
|
||||
page.click_save()
|
||||
page.refresh_page()
|
||||
|
||||
new_src = page.get_profile_image_src()
|
||||
|
||||
assert old_src == new_src
|
||||
|
||||
|
||||
def test_preview_muncul_setelah_upload(self,driver,login_as_user_belum_kuesioner):
|
||||
driver.get("https://hypermedialearning.sanggadewa.my.id/profile")
|
||||
page = ProfilePage(driver)
|
||||
"""
|
||||
Preview image harus berubah sebelum save
|
||||
"""
|
||||
old_src = page.get_profile_image_src()
|
||||
|
||||
file_path = os.path.join(TEST_DATA_DIR, "Kucink_Jpg.jpg")
|
||||
page.upload_photo(file_path)
|
||||
|
||||
new_src = page.get_profile_image_src()
|
||||
|
||||
assert old_src != new_src
|
||||
|
||||
|
||||
def test_reset_mengembalikan_foto_default(self,driver,login_as_user_belum_kuesioner):
|
||||
driver.get("https://hypermedialearning.sanggadewa.my.id/profile")
|
||||
page = ProfilePage(driver)
|
||||
"""
|
||||
Reset harus mengembalikan foto ke default
|
||||
"""
|
||||
page.wait_until_page_loaded()
|
||||
|
||||
page.click_reset_photo()
|
||||
page.refresh_page()
|
||||
|
||||
src = page.get_profile_image_src()
|
||||
|
||||
assert "defaultProfile" in src
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
import pytest
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("driver")
|
||||
class TestRegisterAngkatan:
|
||||
"""
|
||||
RULE ANGKATAN:
|
||||
- Wajib diisi (HTML5)
|
||||
- Hanya angka
|
||||
- Minimal 2021
|
||||
- Maksimal tahun sekarang + 1
|
||||
"""
|
||||
|
||||
# =========================
|
||||
# NEGATIVE TEST CASES
|
||||
# =========================
|
||||
|
||||
def test_angkatan_kosong(self, register_page, valid_register_data):
|
||||
valid_register_data["angkatan"] = ""
|
||||
register_page.fill_form(valid_register_data)
|
||||
assert register_page.is_field_required("angkatan")
|
||||
|
||||
def test_angkatan_hanya_spasi(self, register_page, valid_register_data):
|
||||
valid_register_data["angkatan"] = " "
|
||||
register_page.fill_form(valid_register_data)
|
||||
assert register_page.is_field_required("angkatan")
|
||||
|
||||
def test_angkatan_huruf(self, register_page, valid_register_data):
|
||||
valid_register_data["angkatan"] = "abcd"
|
||||
register_page.fill_form(valid_register_data)
|
||||
value = register_page.get_value("angkatan")
|
||||
assert value == ""
|
||||
|
||||
def test_angkatan_simbol(self, register_page, valid_register_data):
|
||||
valid_register_data["angkatan"] = "&&&&"
|
||||
register_page.fill_form(valid_register_data)
|
||||
value = register_page.get_value("angkatan")
|
||||
assert value == ""
|
||||
|
||||
def test_angkatan_kurang_dari_minimum(self, register_page, valid_register_data):
|
||||
valid_register_data["angkatan"] = "2019"
|
||||
register_page.fill_form(valid_register_data)
|
||||
register_page.submit()
|
||||
assert register_page.has_html5_validation("angkatan")
|
||||
|
||||
def test_angkatan_terlalu_besar(self, register_page, valid_register_data):
|
||||
valid_register_data["angkatan"] = "9999"
|
||||
register_page.fill_form(valid_register_data)
|
||||
register_page.submit()
|
||||
assert register_page.has_html5_validation("angkatan")
|
||||
|
||||
|
||||
# =========================
|
||||
# POSITIVE TEST CASES
|
||||
# =========================
|
||||
|
||||
def test_angkatan_valid_minimum(self, register_page, valid_register_data):
|
||||
valid_register_data["angkatan"] = "2022"
|
||||
register_page.fill_form(valid_register_data)
|
||||
register_page.submit()
|
||||
assert register_page.is_register_success()
|
||||
|
||||
def test_angkatan_valid_tahun_sekarang(self, register_page, valid_register_data):
|
||||
tahun_sekarang = str(datetime.now().year)
|
||||
valid_register_data["angkatan"] = tahun_sekarang
|
||||
register_page.fill_form(valid_register_data)
|
||||
register_page.submit()
|
||||
assert register_page.is_register_success()
|
||||
|
||||
def test_angkatan_valid_random(self, register_page, valid_register_data):
|
||||
valid_register_data["angkatan"] = valid_register_data["angkatan"]
|
||||
register_page.fill_form(valid_register_data)
|
||||
register_page.submit()
|
||||
assert register_page.is_register_success()
|
||||
|
|
@ -0,0 +1,147 @@
|
|||
import pytest
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("driver")
|
||||
class TestRegisterEmail:
|
||||
"""
|
||||
RULE EMAIL:
|
||||
- Wajib diisi (HTML5)
|
||||
- Harus format email valid (HTML5)
|
||||
- Tidak boleh mengandung spasi
|
||||
- Domain wajib:
|
||||
@polije.ac.id
|
||||
@student.polije.ac.id
|
||||
- Validasi domain & email aktif menggunakan backend / JS
|
||||
"""
|
||||
|
||||
# =========================
|
||||
# NEGATIVE TEST CASES
|
||||
# =========================
|
||||
|
||||
def test_email_kosong(self, register_page, valid_register_data):
|
||||
valid_register_data["email"] = ""
|
||||
register_page.fill_form(valid_register_data)
|
||||
register_page.submit()
|
||||
assert register_page.is_field_required("email")
|
||||
|
||||
def test_email_hanya_spasi(self, register_page, valid_register_data):
|
||||
valid_register_data["email"] = " "
|
||||
register_page.fill_form(valid_register_data)
|
||||
register_page.submit()
|
||||
assert register_page.is_field_required("email")
|
||||
|
||||
def test_email_tanpa_at(self, register_page, valid_register_data):
|
||||
valid_register_data["email"] = "userpolije.ac.id"
|
||||
register_page.fill_form(valid_register_data)
|
||||
register_page.submit()
|
||||
assert register_page.has_html5_validation("email")
|
||||
|
||||
def test_email_angka_semua(self, register_page, valid_register_data):
|
||||
valid_register_data["email"] = "123456789"
|
||||
register_page.fill_form(valid_register_data)
|
||||
register_page.submit()
|
||||
assert register_page.has_html5_validation("email")
|
||||
|
||||
def test_nama_email_angka_semua(self, register_page, valid_register_data):
|
||||
valid_register_data["email"] = "12345678@student.polije.ac.id"
|
||||
register_page.fill_form(valid_register_data)
|
||||
register_page.submit()
|
||||
assert register_page.has_error("Email")
|
||||
|
||||
def test_email_simbol_semua(self, register_page, valid_register_data):
|
||||
valid_register_data["email"] = "&&&&"
|
||||
register_page.fill_form(valid_register_data)
|
||||
register_page.submit()
|
||||
assert register_page.has_html5_validation("email")
|
||||
|
||||
def test_email_mengandung_spasi(self, register_page, valid_register_data):
|
||||
valid_register_data["email"] = "user @polije.ac.id"
|
||||
register_page.fill_form(valid_register_data)
|
||||
register_page.submit()
|
||||
assert register_page.has_html5_validation("email")
|
||||
|
||||
def test_email_domain_bukan_polije(self, register_page, valid_register_data):
|
||||
valid_register_data["email"] = "user@gmail.com"
|
||||
register_page.fill_form(valid_register_data)
|
||||
register_page.submit()
|
||||
assert register_page.has_error("Email")
|
||||
|
||||
def test_email_domain_salah(self, register_page, valid_register_data):
|
||||
valid_register_data["email"] = "user@student.polije.co.id"
|
||||
register_page.fill_form(valid_register_data)
|
||||
register_page.submit()
|
||||
assert register_page.has_error("Email")
|
||||
|
||||
def test_email_terdaftar_typo(self, register_page, valid_register_data):
|
||||
valid_register_data["email"] = "e41222052@polije.acid"
|
||||
register_page.fill_form(valid_register_data)
|
||||
register_page.submit()
|
||||
assert register_page.has_error("Email")
|
||||
|
||||
def test_email_tidak_aktif(self, register_page, valid_register_data):
|
||||
valid_register_data["email"] = "email.tidak.aktif@student.polije.ac.id"
|
||||
register_page.fill_form(valid_register_data)
|
||||
register_page.submit()
|
||||
assert register_page.has_error("Email")
|
||||
|
||||
def test_email_mengandung_dash(self, register_page, valid_register_data):
|
||||
valid_register_data["email"] = "user-test@student.polije.ac.id"
|
||||
register_page.fill_form(valid_register_data)
|
||||
register_page.submit()
|
||||
assert register_page.has_error("Email")
|
||||
|
||||
def test_email_mengandung_plus(self, register_page, valid_register_data):
|
||||
valid_register_data["email"] = "user+test@student.polije.ac.id"
|
||||
register_page.fill_form(valid_register_data)
|
||||
register_page.submit()
|
||||
assert register_page.has_error("Email")
|
||||
|
||||
|
||||
def test_register_dua_kali_email_sama(self, register_page, valid_register_data):
|
||||
email = valid_register_data["email"]
|
||||
|
||||
# Register pertama
|
||||
register_page.fill_form(valid_register_data)
|
||||
register_page.submit()
|
||||
assert register_page.is_register_success()
|
||||
|
||||
# Register kedua → email sama, nama & NIM beda
|
||||
register_page.open()
|
||||
|
||||
data_kedua = valid_register_data.copy()
|
||||
data_kedua["email"] = email
|
||||
data_kedua["nama_lengkap"] = "User Kedua Unik"
|
||||
data_kedua["nim"] = "E41229999"
|
||||
|
||||
register_page.fill_form(data_kedua)
|
||||
register_page.submit()
|
||||
|
||||
assert register_page.has_error("Email")
|
||||
|
||||
|
||||
# =========================
|
||||
# POSITIVE TEST CASES
|
||||
# =========================
|
||||
|
||||
def test_email_mengandung_underscore(self, register_page, valid_register_data):
|
||||
valid_register_data["email"] = "user_test@student.polije.ac.id"
|
||||
register_page.fill_form(valid_register_data)
|
||||
register_page.submit()
|
||||
assert register_page.is_register_success()
|
||||
|
||||
def test_email_valid_polije(self, register_page, valid_register_data):
|
||||
valid_register_data["email"] = "dosen@polije.ac.id"
|
||||
register_page.fill_form(valid_register_data)
|
||||
register_page.submit()
|
||||
assert register_page.is_register_success()
|
||||
|
||||
def test_email_valid_student_polije(self, register_page, valid_register_data):
|
||||
valid_register_data["email"] = "E41222050@student.polije.ac.id"
|
||||
register_page.fill_form(valid_register_data)
|
||||
register_page.submit()
|
||||
assert register_page.is_register_success()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
import pytest
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("driver")
|
||||
class TestRegisterKonfirmasiPassword:
|
||||
"""
|
||||
RULE KONFIRMASI PASSWORD:
|
||||
- Wajib diisi
|
||||
- Harus sama dengan password
|
||||
- Validasi muncul setelah klik submit
|
||||
"""
|
||||
|
||||
# =========================
|
||||
# NEGATIVE TEST CASES
|
||||
# =========================
|
||||
|
||||
def test_konfirmasi_password_kosong(self, register_page, valid_register_data):
|
||||
"""
|
||||
Konfirmasi password kosong → HTML5 required
|
||||
"""
|
||||
valid_register_data["password"] = "Abcdef1@"
|
||||
valid_register_data["konfirmasi_password"] = ""
|
||||
|
||||
register_page.fill_form(valid_register_data)
|
||||
|
||||
assert register_page.is_field_required("konfirmasi_password")
|
||||
|
||||
def test_konfirmasi_password_hanya_spasi(self, register_page, valid_register_data):
|
||||
valid_register_data["password"] = "Abcdef1@"
|
||||
valid_register_data["konfirmasi_password"] = " "
|
||||
|
||||
register_page.fill_form(valid_register_data)
|
||||
register_page.submit()
|
||||
|
||||
assert register_page.has_error("Password")
|
||||
|
||||
def test_konfirmasi_password_tidak_sama(self, register_page, valid_register_data):
|
||||
valid_register_data["password"] = "Abcdef1@"
|
||||
valid_register_data["konfirmasi_password"] = "Abcdef2@"
|
||||
|
||||
register_page.fill_form(valid_register_data)
|
||||
register_page.submit()
|
||||
|
||||
assert register_page.has_error("Password")
|
||||
|
||||
def test_konfirmasi_password_lebih_pendek(self, register_page, valid_register_data):
|
||||
valid_register_data["password"] = "Abcdef1@"
|
||||
valid_register_data["konfirmasi_password"] = "Abcdef1"
|
||||
|
||||
register_page.fill_form(valid_register_data)
|
||||
register_page.submit()
|
||||
|
||||
assert register_page.has_error("Password")
|
||||
|
||||
def test_konfirmasi_password_lebih_panjang(self, register_page, valid_register_data):
|
||||
valid_register_data["password"] = "Abcdef1@"
|
||||
valid_register_data["konfirmasi_password"] = "Abcdef1@xxx"
|
||||
|
||||
register_page.fill_form(valid_register_data)
|
||||
register_page.submit()
|
||||
|
||||
assert register_page.has_error("Password")
|
||||
|
||||
# =========================
|
||||
# POSITIVE TEST CASES
|
||||
# =========================
|
||||
|
||||
def test_konfirmasi_password_sama(self, register_page, valid_register_data):
|
||||
valid_register_data["password"] = "Abcdef1@"
|
||||
valid_register_data["konfirmasi_password"] = "Abcdef1@"
|
||||
|
||||
register_page.fill_form(valid_register_data)
|
||||
register_page.submit()
|
||||
|
||||
assert register_page.is_register_success()
|
||||
|
||||
def test_konfirmasi_password_valid_dengan_spasi(self, register_page, valid_register_data):
|
||||
"""
|
||||
Jika password mengandung spasi dan konfirmasi sama → valid
|
||||
"""
|
||||
valid_register_data["password"] = "Abc def1@"
|
||||
valid_register_data["konfirmasi_password"] = "Abc def1@"
|
||||
|
||||
register_page.fill_form(valid_register_data)
|
||||
register_page.submit()
|
||||
|
||||
assert register_page.is_register_success()
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
import pytest
|
||||
from pages.register_page import RegisterPage
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("driver")
|
||||
class TestRegisterNamaLengkap:
|
||||
"""
|
||||
RULE FINAL NAMA LENGKAP:
|
||||
- Minimal 5 karakter
|
||||
- Maksimal 30 karakter
|
||||
- HANYA boleh huruf dan spasi
|
||||
- Huruf kapital/kecil bebas
|
||||
- TIDAK BOLEH angka atau simbol
|
||||
"""
|
||||
|
||||
# =========================
|
||||
# NEGATIVE TEST CASES
|
||||
# =========================
|
||||
|
||||
def test_nama_kosong(self, register_page, valid_register_data):
|
||||
valid_register_data["nama_lengkap"] = ""
|
||||
register_page.fill_form(valid_register_data)
|
||||
register_page.submit()
|
||||
assert register_page.is_field_required("nama_lengkap")
|
||||
|
||||
def test_nama_hanya_spasi(self, register_page, valid_register_data):
|
||||
valid_register_data["nama_lengkap"] = " "
|
||||
register_page.fill_form(valid_register_data)
|
||||
register_page.submit()
|
||||
assert register_page.has_error("Nama Lengkap")
|
||||
|
||||
def test_nama_kurang_dari_5_karakter(self, register_page, valid_register_data):
|
||||
valid_register_data["nama_lengkap"] = "Aa"
|
||||
register_page.fill_form(valid_register_data)
|
||||
register_page.submit()
|
||||
assert register_page.has_error("Nama Lengkap")
|
||||
|
||||
def test_nama_lebih_dari_30_karakter(self, register_page, valid_register_data):
|
||||
valid_register_data["nama_lengkap"] = "B" * 31
|
||||
register_page.fill_form(valid_register_data)
|
||||
register_page.submit()
|
||||
assert register_page.has_error("Nama Lengkap")
|
||||
|
||||
def test_nama_angka_semua(self, register_page, valid_register_data):
|
||||
valid_register_data["nama_lengkap"] = "98076545"
|
||||
register_page.fill_form(valid_register_data)
|
||||
register_page.submit()
|
||||
assert register_page.has_error("Nama Lengkap")
|
||||
|
||||
def test_nama_simbol_semua(self, register_page, valid_register_data):
|
||||
valid_register_data["nama_lengkap"] = "######"
|
||||
register_page.fill_form(valid_register_data)
|
||||
register_page.submit()
|
||||
assert register_page.has_error("Nama Lengkap")
|
||||
|
||||
def test_nama_huruf_dan_angka(self, register_page, valid_register_data):
|
||||
valid_register_data["nama_lengkap"] = "Bagus123"
|
||||
register_page.fill_form(valid_register_data)
|
||||
register_page.submit()
|
||||
assert register_page.has_error("Nama Lengkap")
|
||||
|
||||
def test_nama_huruf_dan_simbol(self, register_page, valid_register_data):
|
||||
valid_register_data["nama_lengkap"] = "Gilang@Putra"
|
||||
register_page.fill_form(valid_register_data)
|
||||
register_page.submit()
|
||||
assert register_page.has_error("Nama Lengkap")
|
||||
|
||||
# =========================
|
||||
# POSITIVE TEST CASES
|
||||
# =========================
|
||||
|
||||
def test_nama_valid_huruf_kecil(self, register_page, valid_register_data):
|
||||
valid_register_data["nama_lengkap"] = "gilang bagus"
|
||||
register_page.fill_form(valid_register_data)
|
||||
register_page.submit()
|
||||
assert register_page.is_register_success()
|
||||
|
||||
def test_nama_valid_huruf_kapital(self, register_page, valid_register_data):
|
||||
valid_register_data["nama_lengkap"] = "GILANG RAMADAN"
|
||||
register_page.fill_form(valid_register_data)
|
||||
register_page.submit()
|
||||
assert register_page.is_register_success()
|
||||
|
||||
def test_nama_valid_huruf_dan_spasi(self, register_page, valid_register_data):
|
||||
valid_register_data["nama_lengkap"] = "Gilang Rama"
|
||||
register_page.fill_form(valid_register_data)
|
||||
register_page.submit()
|
||||
assert register_page.is_register_success()
|
||||
|
||||
def test_nama_valid_minimal_karakter(self, register_page, valid_register_data):
|
||||
valid_register_data["nama_lengkap"] = "Rurin Nur"
|
||||
register_page.fill_form(valid_register_data)
|
||||
register_page.submit()
|
||||
assert register_page.is_register_success()
|
||||
|
||||
def test_nama_valid_maksimal_karakter(self, register_page, valid_register_data):
|
||||
valid_register_data["nama_lengkap"] = "C" * 30
|
||||
register_page.fill_form(valid_register_data)
|
||||
register_page.submit()
|
||||
assert register_page.is_register_success()
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
import pytest
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("driver")
|
||||
class TestRegisterNIM:
|
||||
"""
|
||||
RULE FINAL NIM:
|
||||
- Tidak boleh kosong (HTML5 required)
|
||||
- Tidak boleh spasi
|
||||
- Harus kombinasi huruf + angka
|
||||
- Tidak boleh karakter khusus
|
||||
- Minimal 9 karakter
|
||||
- Maksimal 10 karakter
|
||||
"""
|
||||
|
||||
# =========================
|
||||
# REQUIRED (HTML5)
|
||||
# =========================
|
||||
|
||||
def test_nim_kosong(self, register_page, valid_register_data):
|
||||
valid_register_data["nim"] = ""
|
||||
register_page.fill_form(valid_register_data)
|
||||
|
||||
# ❌ JANGAN submit
|
||||
assert register_page.is_field_required("NIM")
|
||||
|
||||
# =========================
|
||||
# NEGATIVE (SERVER / JS)
|
||||
# =========================
|
||||
|
||||
def test_nim_spasi_saja(self, register_page, valid_register_data):
|
||||
valid_register_data["nim"] = " "
|
||||
register_page.fill_form(valid_register_data)
|
||||
register_page.submit()
|
||||
|
||||
assert register_page.has_error("NIM")
|
||||
|
||||
def test_nim_mengandung_spasi(self, register_page, valid_register_data):
|
||||
valid_register_data["nim"] = "E 4122987"
|
||||
register_page.fill_form(valid_register_data)
|
||||
register_page.submit()
|
||||
|
||||
assert register_page.has_error("NIM")
|
||||
|
||||
def test_nim_hanya_angka(self, register_page, valid_register_data):
|
||||
valid_register_data["nim"] = "412227890"
|
||||
register_page.fill_form(valid_register_data)
|
||||
register_page.submit()
|
||||
|
||||
assert register_page.has_error("NIM")
|
||||
|
||||
def test_nim_hanya_huruf(self, register_page, valid_register_data):
|
||||
valid_register_data["nim"] = "ABCDEFGHI"
|
||||
register_page.fill_form(valid_register_data)
|
||||
register_page.submit()
|
||||
|
||||
assert register_page.has_error("NIM")
|
||||
|
||||
def test_nim_karakter_khusus(self, register_page, valid_register_data):
|
||||
valid_register_data["nim"] = "E41222@89"
|
||||
register_page.fill_form(valid_register_data)
|
||||
register_page.submit()
|
||||
|
||||
assert register_page.has_error("NIM")
|
||||
|
||||
def test_nim_kurang_dari_9_karakter(self, register_page, valid_register_data):
|
||||
valid_register_data["nim"] = "E41222"
|
||||
register_page.fill_form(valid_register_data)
|
||||
register_page.submit()
|
||||
|
||||
assert register_page.has_error("NIM")
|
||||
|
||||
def test_nim_lebih_dari_10_karakter(self, register_page, valid_register_data):
|
||||
valid_register_data["nim"] = "E41222789099"
|
||||
register_page.fill_form(valid_register_data)
|
||||
register_page.submit()
|
||||
|
||||
assert register_page.has_error("NIM")
|
||||
|
||||
# =========================
|
||||
# POSITIVE
|
||||
# =========================
|
||||
|
||||
def test_nim_valid_9_karakter(self, register_page, valid_register_data):
|
||||
valid_register_data["nim"] = "E41222050"
|
||||
register_page.fill_form(valid_register_data)
|
||||
register_page.submit()
|
||||
|
||||
assert register_page.is_register_success()
|
||||
|
||||
def test_nim_valid_10_karakter(self, register_page, valid_register_data):
|
||||
valid_register_data["nim"] = "E412227890"
|
||||
register_page.fill_form(valid_register_data)
|
||||
register_page.submit()
|
||||
|
||||
assert register_page.is_register_success()
|
||||
|
|
@ -0,0 +1,160 @@
|
|||
import pytest
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("driver")
|
||||
class TestRegisterPassword:
|
||||
"""
|
||||
RULE PASSWORD:
|
||||
- Wajib diisi (HTML5)
|
||||
- Minimal 8 karakter
|
||||
- Maksimal 12 karakter
|
||||
- Boleh mengandung spasi
|
||||
- Wajib mengandung:
|
||||
- Huruf besar
|
||||
- Huruf kecil
|
||||
- Angka atau karakter khusus
|
||||
- Validasi muncul setelah klik submit
|
||||
"""
|
||||
|
||||
# =========================
|
||||
# HTML5 VALIDATION
|
||||
# =========================
|
||||
|
||||
def test_password_kosong(self, register_page, valid_register_data):
|
||||
"""
|
||||
Password kosong → HTML5 required
|
||||
"""
|
||||
valid_register_data["password"] = ""
|
||||
valid_register_data["konfirmasi_password"] = ""
|
||||
|
||||
register_page.fill_form(valid_register_data)
|
||||
|
||||
# TIDAK perlu submit, HTML5 sudah aktif
|
||||
assert register_page.is_field_required("password")
|
||||
|
||||
# =========================
|
||||
# NEGATIVE TEST CASES (CUSTOM VALIDATION)
|
||||
# =========================
|
||||
|
||||
def test_password_kurang_dari_minimum(self, register_page, valid_register_data):
|
||||
valid_register_data["password"] = "Ab1@"
|
||||
valid_register_data["konfirmasi_password"] = "Ab1@"
|
||||
|
||||
register_page.fill_form(valid_register_data)
|
||||
register_page.submit()
|
||||
|
||||
assert register_page.has_error("Password")
|
||||
|
||||
def test_password_lebih_dari_maksimum(self, register_page, valid_register_data):
|
||||
valid_register_data["password"] = "Abcdef1@xxxx"
|
||||
valid_register_data["konfirmasi_password"] = "Abcdef1@xxxx"
|
||||
|
||||
register_page.fill_form(valid_register_data)
|
||||
register_page.submit()
|
||||
|
||||
assert register_page.has_error("Password")
|
||||
|
||||
def test_password_tanpa_huruf_kapital(self, register_page, valid_register_data):
|
||||
valid_register_data["password"] = "abcdef1@"
|
||||
valid_register_data["konfirmasi_password"] = "abcdef1@"
|
||||
|
||||
register_page.fill_form(valid_register_data)
|
||||
register_page.submit()
|
||||
|
||||
assert register_page.has_error("Password")
|
||||
|
||||
def test_password_tanpa_huruf_kecil(self, register_page, valid_register_data):
|
||||
valid_register_data["password"] = "ABCDEF1@"
|
||||
valid_register_data["konfirmasi_password"] = "ABCDEF1@"
|
||||
|
||||
register_page.fill_form(valid_register_data)
|
||||
register_page.submit()
|
||||
|
||||
assert register_page.has_error("Password")
|
||||
|
||||
def test_password_tanpa_angka(self, register_page, valid_register_data):
|
||||
valid_register_data["password"] = "Abcdef@@"
|
||||
valid_register_data["konfirmasi_password"] = "Abcdef@@"
|
||||
|
||||
register_page.fill_form(valid_register_data)
|
||||
register_page.submit()
|
||||
|
||||
assert register_page.has_error("Password")
|
||||
|
||||
def test_password_tanpa_karakter_khusus(self, register_page, valid_register_data):
|
||||
valid_register_data["password"] = "Abcdef12"
|
||||
valid_register_data["konfirmasi_password"] = "Abcdef12"
|
||||
|
||||
register_page.fill_form(valid_register_data)
|
||||
register_page.submit()
|
||||
|
||||
assert register_page.has_error("Password")
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"password",
|
||||
[
|
||||
"12345678", # angka semua
|
||||
"abcdefgh", # huruf kecil semua
|
||||
"ABCDEFGH", # huruf besar semua
|
||||
"&&&&&&&&", # simbol semua
|
||||
]
|
||||
)
|
||||
def test_password_komposisi_tidak_valid(
|
||||
self, register_page, valid_register_data, password
|
||||
):
|
||||
valid_register_data["password"] = password
|
||||
valid_register_data["konfirmasi_password"] = password
|
||||
|
||||
register_page.fill_form(valid_register_data)
|
||||
register_page.submit()
|
||||
|
||||
assert register_page.has_error("Password")
|
||||
|
||||
def test_password_mengandung_spasi(self, register_page, valid_register_data):
|
||||
"""
|
||||
Spasi BOLEH, selama rule lain terpenuhi
|
||||
"""
|
||||
valid_register_data["password"] = "Abc def1@"
|
||||
valid_register_data["konfirmasi_password"] = "Abc def1@"
|
||||
|
||||
register_page.fill_form(valid_register_data)
|
||||
register_page.submit()
|
||||
|
||||
assert register_page.is_register_success()
|
||||
|
||||
def test_password_tepat_minimum(self, register_page, valid_register_data):
|
||||
valid_register_data["password"] = "Abcd1@xy"
|
||||
valid_register_data["konfirmasi_password"] = "Abcd1@xy"
|
||||
register_page.fill_form(valid_register_data)
|
||||
register_page.submit()
|
||||
|
||||
assert register_page.is_register_success()
|
||||
|
||||
def test_password_tepat_maksimum(self, register_page, valid_register_data):
|
||||
"""
|
||||
Boundary value: tepat 12 karakter
|
||||
"""
|
||||
valid_register_data["password"] = "Abcd12@xyzQ"
|
||||
valid_register_data["konfirmasi_password"] = "Abcd12@xyzQ"
|
||||
|
||||
register_page.fill_form(valid_register_data)
|
||||
register_page.submit()
|
||||
|
||||
assert register_page.is_register_success()
|
||||
|
||||
def test_password_valid_kriteria(self, register_page, valid_register_data):
|
||||
"""
|
||||
Boundary value: tepat 8 karakter
|
||||
"""
|
||||
valid_register_data["password"] = "#Qwerty123"
|
||||
valid_register_data["konfirmasi_password"] = "#Qwerty123"
|
||||
|
||||
register_page.fill_form(valid_register_data)
|
||||
register_page.submit()
|
||||
|
||||
assert register_page.is_register_success()
|
||||
# =========================
|
||||
# POSITIVE TEST CASE
|
||||
# =========================
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
import pytest
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("driver")
|
||||
class TestRegisterSemester:
|
||||
"""
|
||||
RULE SEMESTER:
|
||||
- Wajib diisi (HTML5)
|
||||
- Hanya angka
|
||||
- Range 1 - 14
|
||||
"""
|
||||
|
||||
# =========================
|
||||
# NEGATIVE TEST CASES
|
||||
# =========================
|
||||
|
||||
def test_semester_kosong(self, register_page, valid_register_data):
|
||||
valid_register_data["semester"] = ""
|
||||
register_page.fill_form(valid_register_data)
|
||||
register_page.submit()
|
||||
assert register_page.is_field_required("semester")
|
||||
|
||||
def test_semester_hanya_spasi(self, register_page, valid_register_data):
|
||||
valid_register_data["semester"] = " "
|
||||
register_page.fill_form(valid_register_data)
|
||||
register_page.submit()
|
||||
assert register_page.is_field_required("semester")
|
||||
|
||||
def test_semester_huruf(self, register_page, valid_register_data):
|
||||
valid_register_data["semester"] = "abc"
|
||||
register_page.fill_form(valid_register_data)
|
||||
register_page.submit()
|
||||
assert register_page.has_error("semester")
|
||||
|
||||
def test_semester_simbol(self, register_page, valid_register_data):
|
||||
valid_register_data["semester"] = "&&"
|
||||
register_page.fill_form(valid_register_data)
|
||||
register_page.submit()
|
||||
assert register_page.has_error("semester")
|
||||
|
||||
def test_semester_kurang_dari_minimum(self, register_page, valid_register_data):
|
||||
valid_register_data["semester"] = "0"
|
||||
register_page.fill_form(valid_register_data)
|
||||
register_page.submit()
|
||||
assert register_page.has_error("semester")
|
||||
|
||||
def test_semester_lebih_dari_maksimum(self, register_page, valid_register_data):
|
||||
valid_register_data["semester"] = "15"
|
||||
register_page.fill_form(valid_register_data)
|
||||
register_page.submit()
|
||||
assert register_page.has_error("semester")
|
||||
|
||||
# =========================
|
||||
# POSITIVE TEST CASES
|
||||
# =========================
|
||||
|
||||
def test_semester_valid_minimum(self, register_page, valid_register_data):
|
||||
valid_register_data["semester"] = "1"
|
||||
register_page.fill_form(valid_register_data)
|
||||
register_page.submit()
|
||||
assert register_page.is_register_success()
|
||||
|
||||
def test_semester_valid_tengah(self, register_page, valid_register_data):
|
||||
valid_register_data["semester"] = "8"
|
||||
register_page.fill_form(valid_register_data)
|
||||
register_page.submit()
|
||||
assert register_page.is_register_success()
|
||||
|
||||
def test_semester_valid_maksimum(self, register_page, valid_register_data):
|
||||
valid_register_data["semester"] = "14"
|
||||
register_page.fill_form(valid_register_data)
|
||||
register_page.submit()
|
||||
assert register_page.is_register_success()
|
||||
|
|
@ -0,0 +1,163 @@
|
|||
import pytest
|
||||
import os
|
||||
from pages.register_page import RegisterPage
|
||||
from pages.live_coding_page import LiveCodingPage
|
||||
from pages.profile_page import ProfilePage
|
||||
|
||||
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
|
||||
TEST_DATA_DIR = os.path.join(BASE_DIR, "test_data")
|
||||
|
||||
@pytest.mark.usefixtures("driver")
|
||||
class TestRegression:
|
||||
|
||||
#Regression Daftar Akun
|
||||
def test_nama_valid_huruf_kecil(self, register_page, valid_register_data):
|
||||
valid_register_data["nama_lengkap"] = "rurinhaliza"
|
||||
register_page.fill_form(valid_register_data)
|
||||
register_page.submit()
|
||||
assert register_page.is_register_success()
|
||||
|
||||
def test_nim_valid_9_karakter(self, register_page, valid_register_data):
|
||||
valid_register_data["nim"] = "E41222555"
|
||||
register_page.fill_form(valid_register_data)
|
||||
register_page.submit()
|
||||
assert register_page.is_register_success()
|
||||
|
||||
def test_semester_valid_tengah(self, register_page, valid_register_data):
|
||||
valid_register_data["semester"] = "4"
|
||||
register_page.fill_form(valid_register_data)
|
||||
register_page.submit()
|
||||
assert register_page.is_register_success()
|
||||
|
||||
def test_angkatan_valid_random(self, register_page, valid_register_data):
|
||||
valid_register_data["angkatan"] = valid_register_data["angkatan"]
|
||||
register_page.fill_form(valid_register_data)
|
||||
register_page.submit()
|
||||
assert register_page.is_register_success()
|
||||
|
||||
def test_email_valid_student_polije(self, register_page, valid_register_data):
|
||||
valid_register_data["email"] = "siswa@student.polije.ac.id"
|
||||
register_page.fill_form(valid_register_data)
|
||||
register_page.submit()
|
||||
assert register_page.is_register_success()
|
||||
|
||||
def test_password_valid(self, register_page, valid_register_data):
|
||||
"""
|
||||
Password valid (huruf besar, kecil, angka, simbol)
|
||||
"""
|
||||
valid_register_data["password"] = "Qwerty098"
|
||||
valid_register_data["konfirmasi_password"] = "Qwerty098"
|
||||
register_page.fill_form(valid_register_data)
|
||||
register_page.submit()
|
||||
assert register_page.is_register_success()
|
||||
|
||||
def test_konfirmasi_password_sama(self, register_page, valid_register_data):
|
||||
valid_register_data["password"] = "Zxcvbn123"
|
||||
valid_register_data["konfirmasi_password"] = "Zxcvbn123"
|
||||
register_page.fill_form(valid_register_data)
|
||||
register_page.submit()
|
||||
assert register_page.is_register_success()
|
||||
|
||||
# Regression materi kinesthetic
|
||||
def test_submit_with_correct_code(self,driver,login_as_user_belum_kuesionerNew):
|
||||
driver.get("https://hypermedialearning.project2025.id/public/materi/kinesthetic/1")
|
||||
page = LiveCodingPage(driver)
|
||||
|
||||
page.append_code2("""
|
||||
Mahasiswa
|
||||
println
|
||||
""")
|
||||
page.submit_code()
|
||||
|
||||
result = page.get_result_message()
|
||||
assert "Jawaban Benar" in result
|
||||
print(result)
|
||||
|
||||
def test_next_button_on_first_page(self,driver,login_as_user_belum_kuesionerNew):
|
||||
driver.get("https://hypermedialearning.project2025.id/public/materi/kinesthetic/1")
|
||||
page = LiveCodingPage(driver)
|
||||
initial_url = page.get_current_url()
|
||||
|
||||
page.click_next()
|
||||
|
||||
current_url = page.get_current_url()
|
||||
|
||||
assert "/kinesthetic/2" in current_url
|
||||
|
||||
#Regression Pofile
|
||||
def test_email_tampil_sesuai_akun(self,driver,login_as_user_belum_kuesionerNew):
|
||||
driver.get("https://hypermedialearning.project2025.id/public/profile")
|
||||
page = ProfilePage(driver)
|
||||
"""
|
||||
Verifikasi email tampil sesuai akun dan tidak kosong
|
||||
"""
|
||||
page.wait_until_page_loaded()
|
||||
|
||||
email = page.get_email()
|
||||
|
||||
assert email is not None
|
||||
#assert email != ""
|
||||
assert "@" in email
|
||||
assert email.endswith(".ac.id")
|
||||
#or email.endswith(".com")
|
||||
|
||||
def test_upload_file_selain_gambar_ditolak(self,driver,login_as_user_belum_kuesionerNew):
|
||||
driver.get("https://hypermedialearning.project2025.id/public/profile")
|
||||
page = ProfilePage(driver)
|
||||
"""
|
||||
Upload file selain JPG/PNG harus ditolak
|
||||
"""
|
||||
old_src = page.get_profile_image_src()
|
||||
|
||||
file_path = os.path.join(TEST_DATA_DIR, "invalid_file.pdf")
|
||||
page.upload_photo(file_path)
|
||||
page.click_save()
|
||||
page.refresh_page()
|
||||
|
||||
new_src = page.get_profile_image_src()
|
||||
|
||||
assert old_src == new_src
|
||||
|
||||
def test_nama_kosong(self,driver,login_as_user_belum_kuesionerNew):
|
||||
driver.get("https://hypermedialearning.project2025.id/public/profile")
|
||||
page = ProfilePage(driver)
|
||||
default_name = page.get_nama_lengkap()
|
||||
page.set_nama_lengkap("")
|
||||
page.click_save()
|
||||
assert page.get_nama_lengkap() == default_name
|
||||
|
||||
def test_nim_kosong(self,driver,login_as_user_belum_kuesionerNew):
|
||||
driver.get("https://hypermedialearning.project2025.id/public/profile")
|
||||
page = ProfilePage(driver)
|
||||
default_nim = page.get_nim()
|
||||
page.set_nim("")
|
||||
page.click_save()
|
||||
assert page.get_nim() == default_nim
|
||||
|
||||
def test_semester_valid(self,driver,login_as_user_belum_kuesionerNew):
|
||||
driver.get("https://hypermedialearning.project2025.id/public/profile")
|
||||
page = ProfilePage(driver)
|
||||
page.select_semester("1")
|
||||
page.click_save()
|
||||
page.wait_until_reload_after_save()
|
||||
|
||||
assert page.get_selected_semester() == "1"
|
||||
|
||||
def test_angkatan_valid(self,driver,login_as_user_belum_kuesionerNew):
|
||||
driver.get("https://hypermedialearning.project2025.id/public/profile")
|
||||
page = ProfilePage(driver)
|
||||
|
||||
page.select_angkatan("2025")
|
||||
page.click_save()
|
||||
page.wait_until_reload_after_save()
|
||||
|
||||
assert page.get_selected_angkatan() == "2025"
|
||||
|
||||
def test_button_simpan_update_data(self,driver,login_as_user_belum_kuesionerNew):
|
||||
driver.get("https://hypermedialearning.project2025.id/public/profile")
|
||||
page = ProfilePage(driver)
|
||||
new_name = "ItsTesting"
|
||||
page.set_nama_lengkap(new_name)
|
||||
page.click_save()
|
||||
page.wait_until_reload_after_save()
|
||||
assert page.get_nama_lengkap() == new_name
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
import pytest
|
||||
from pages.resume_pembelajaran_page import ResumePembelajaranPage
|
||||
from pages.materi_readwrite_page import MateriReadWritePage
|
||||
|
||||
class TestResumePembelajaran:
|
||||
|
||||
def test_resume_empty_state_displayed(self,driver,login_as_user_belum_kuesioner):
|
||||
driver.get("https://hypermedialearning.sanggadewa.my.id/resume-pembelajaran")
|
||||
page = ResumePembelajaranPage(driver)
|
||||
page.page_loaded()
|
||||
|
||||
assert page.is_empty_message_displayed() is True
|
||||
|
||||
def test_resume_created_after_submit_rangkuman(self,driver, login_as_user_sudah_kuesioner):
|
||||
# 1. Kirim rangkuman dari Materi Read/Write
|
||||
driver.get("https://hypermedialearning.sanggadewa.my.id/materi/readwrite/1")
|
||||
materi_page = MateriReadWritePage(driver)
|
||||
materi_page.page_loaded()
|
||||
|
||||
rangkuman_text = " ".join(["test resume"] * 50)
|
||||
materi_page.input_rangkuman(rangkuman_text)
|
||||
materi_page.submit_rangkuman()
|
||||
|
||||
# 2. Buka Resume Pembelajaran
|
||||
driver.get(
|
||||
"https://hypermedialearning.sanggadewa.my.id/resume-pembelajaran"
|
||||
)
|
||||
|
||||
resume_page = ResumePembelajaranPage(driver)
|
||||
resume_page.page_loaded()
|
||||
|
||||
resume_content = resume_page.get_resume_text()
|
||||
assert rangkuman_text in resume_content
|
||||
|
||||
def test_resume_persist_after_page_reload(self,driver, login_as_user_sudah_kuesioner):
|
||||
driver.get("https://hypermedialearning.sanggadewa.my.id/resume-pembelajaran")
|
||||
page = ResumePembelajaranPage(driver)
|
||||
page.page_loaded()
|
||||
|
||||
first_load_text = page.get_resume_text()
|
||||
|
||||
driver.refresh()
|
||||
page.page_loaded()
|
||||
|
||||
second_load_text = page.get_resume_text()
|
||||
assert first_load_text == second_load_text
|
||||
|
||||
|
||||
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 137 KiB |
|
|
@ -0,0 +1,4 @@
|
|||
INI FILE
|
||||
UNTUK
|
||||
TESTING
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 253 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 976 KiB |
|
|
@ -0,0 +1,146 @@
|
|||
from pages.register_page import RegisterPage
|
||||
from selenium.webdriver.support.ui import WebDriverWait
|
||||
from selenium.webdriver.support import expected_conditions as EC
|
||||
import time
|
||||
|
||||
|
||||
def test_register_valid_data(driver):
|
||||
"""
|
||||
Test Scenario:
|
||||
Periksa sistem jika user mengisi seluruh form pendaftaran dengan data valid
|
||||
|
||||
Technical Requirement:
|
||||
T1–T6, T7–T12, T13–T20, T21–T28, T29–T41
|
||||
|
||||
Expected Result:
|
||||
Sistem menerima pendaftaran akun
|
||||
"""
|
||||
|
||||
register = RegisterPage(driver)
|
||||
register.open()
|
||||
|
||||
# === DATA UNIK ===
|
||||
timestamp = int(time.time())
|
||||
email_unik = f"dummy_{timestamp}@polije.ac.id"
|
||||
nim_unik = f"E41{timestamp % 100000}"
|
||||
|
||||
register.input_nama_lengkap("Budi Santoso")
|
||||
register.input_nim("E41234567")
|
||||
register.input_semester("6")
|
||||
register.input_angkatan("2022")
|
||||
register.input_email("dummy_test@polije.ac.id")
|
||||
register.input_password("Password1!")
|
||||
register.input_konfirmasi_password("Password1!")
|
||||
|
||||
register.submit()
|
||||
|
||||
# === WAIT PROSES SUBMIT ===
|
||||
WebDriverWait(driver, 10).until(
|
||||
lambda d: d.current_url != RegisterPage.URL
|
||||
or len(register.get_error_message()) > 0
|
||||
)
|
||||
|
||||
# === ASSERTION ===
|
||||
assert "register" not in driver.current_url, \
|
||||
"Registrasi gagal, user masih berada di halaman register"
|
||||
|
||||
def test_register_nama_lengkap_kosong(driver):
|
||||
"""
|
||||
Test Scenario:
|
||||
Nama Lengkap tidak diisi
|
||||
|
||||
Technical Requirement:
|
||||
T1 – Nama Lengkap tidak boleh kosong
|
||||
|
||||
Expected Result:
|
||||
Sistem menolak pendaftaran dan menampilkan validasi wajib isi
|
||||
"""
|
||||
|
||||
register = RegisterPage(driver)
|
||||
register.open()
|
||||
|
||||
# Nama kosong
|
||||
register.input_nim("E41234567")
|
||||
register.input_semester("6")
|
||||
register.input_angkatan("2022")
|
||||
register.input_email("test@polije.ac.id")
|
||||
register.input_password("Password1!")
|
||||
register.input_konfirmasi_password("Password1!")
|
||||
|
||||
register.submit()
|
||||
|
||||
assert register.is_field_invalid(RegisterPage.NAMA_LENGKAP)
|
||||
assert "fill out" in register.get_validation_message(RegisterPage.NAMA_LENGKAP).lower()
|
||||
|
||||
def test_register_email_tidak_valid(driver):
|
||||
register = RegisterPage(driver)
|
||||
register.open()
|
||||
|
||||
register.input_nama_lengkap("Budi Santoso")
|
||||
register.input_nim("E41234568")
|
||||
register.input_semester("6")
|
||||
register.input_angkatan("2022")
|
||||
register.input_email("email-salah-format")
|
||||
register.input_password("Password1!")
|
||||
register.input_konfirmasi_password("Password1!")
|
||||
|
||||
register.submit()
|
||||
|
||||
assert register.is_field_invalid(RegisterPage.EMAIL)
|
||||
|
||||
def test_register_password_tidak_sama(driver):
|
||||
register = RegisterPage(driver)
|
||||
register.open()
|
||||
|
||||
register.input_nama_lengkap("Budi Santoso")
|
||||
register.input_nim("E41234569")
|
||||
register.input_semester("6")
|
||||
register.input_angkatan("2022")
|
||||
register.input_email("passwordbeda@polije.ac.id")
|
||||
register.input_password("Password1!")
|
||||
register.input_konfirmasi_password("Password2!")
|
||||
|
||||
register.submit()
|
||||
|
||||
errors = register.get_error_message()
|
||||
assert len(errors) > 0
|
||||
|
||||
def test_register_nim_kosong(driver):
|
||||
register = RegisterPage(driver)
|
||||
register.open()
|
||||
|
||||
register.input_nama_lengkap("Budi Santoso")
|
||||
register.input_semester("6")
|
||||
register.input_angkatan("2022")
|
||||
register.input_email("nimkosong@polije.ac.id")
|
||||
register.input_password("Password1!")
|
||||
register.input_konfirmasi_password("Password1!")
|
||||
|
||||
register.submit()
|
||||
|
||||
assert register.is_field_invalid(RegisterPage.NIM)
|
||||
|
||||
def test_register_semester_bukan_angka(driver):
|
||||
register = RegisterPage(driver)
|
||||
register.open()
|
||||
|
||||
register.input_nama_lengkap("Budi Santoso")
|
||||
register.input_nim("E41234570")
|
||||
register.input_semester("enam")
|
||||
register.input_angkatan("2022")
|
||||
register.input_email("semester@polije.ac.id")
|
||||
register.input_password("Password1!")
|
||||
register.input_konfirmasi_password("Password1!")
|
||||
|
||||
register.submit()
|
||||
|
||||
assert register.is_field_invalid(RegisterPage.SEMESTER)
|
||||
|
||||
def test_register_semua_field_kosong(driver):
|
||||
register = RegisterPage(driver)
|
||||
register.open()
|
||||
|
||||
# ASSERTION TANPA CLICK
|
||||
assert register.is_field_invalid(RegisterPage.NAMA_LENGKAP)
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
import random
|
||||
import string
|
||||
import time
|
||||
|
||||
|
||||
def random_string(length=6):
|
||||
return ''.join(random.choices(string.ascii_letters, k=length))
|
||||
|
||||
|
||||
def random_number(length=10):
|
||||
return ''.join(random.choices(string.digits, k=length))
|
||||
|
||||
|
||||
def valid_nama_lengkap():
|
||||
return f"User {random_string(5)}"
|
||||
|
||||
|
||||
def valid_nim():
|
||||
return random_number(9)
|
||||
|
||||
|
||||
def valid_semester():
|
||||
return str(random.randint(1, 8))
|
||||
|
||||
|
||||
def valid_angkatan():
|
||||
return str(random.randint(2022, 2025))
|
||||
|
||||
|
||||
def valid_email():
|
||||
timestamp = int(time.time() * 1000)
|
||||
return f"user{timestamp}@student.polije.ac.id"
|
||||
|
||||
|
||||
def valid_password():
|
||||
return "Test@1234"
|
||||
|
||||
|
||||
def generate_valid_register_data():
|
||||
"""
|
||||
Data VALID & lengkap untuk form register
|
||||
"""
|
||||
return {
|
||||
"nama": valid_nama_lengkap(),
|
||||
"nim": valid_nim(),
|
||||
"semester": valid_semester(),
|
||||
"angkatan": valid_angkatan(),
|
||||
"email": valid_email(),
|
||||
"password": valid_password(),
|
||||
}
|
||||
|
||||
def generate_valid_nim():
|
||||
"""
|
||||
NIM valid:
|
||||
- huruf + angka
|
||||
- panjang 9–10
|
||||
Contoh: E41222789
|
||||
"""
|
||||
prefix = random.choice(string.ascii_uppercase)
|
||||
digits = ''.join(random.choices(string.digits, k=random.randint(8, 9)))
|
||||
return prefix + digits
|
||||
Loading…
Reference in New Issue