This commit is contained in:
whilb 2025-08-16 17:54:12 -07:00
commit 97f9a95415
21 changed files with 2963 additions and 0 deletions

404
tests/test_calculators.py Normal file
View file

@ -0,0 +1,404 @@
import pytest
from selenium import webdriver
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.webdriver.chrome.options import Options
import time
from selenium.webdriver.common.keys import Keys
@pytest.fixture(scope="function")
def driver():
"""Create a new browser instance for each test"""
chrome_options = Options()
chrome_options.add_argument("--headless")
chrome_options.add_argument("--no-sandbox")
chrome_options.add_argument("--disable-dev-shm-usage")
chrome_options.add_argument("--disable-gpu")
driver = webdriver.Chrome(options=chrome_options)
driver.implicitly_wait(10)
yield driver
driver.quit()
# calculator_page fixture is now defined in conftest.py
class TestCalculatorNavigation:
"""Test calculator navigation and basic functionality"""
def test_debug_page_content(self, driver):
"""Debug test to see what's actually on the page"""
driver.get("http://localhost:8008")
# Wait for basic page structure
WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.CLASS_NAME, "sidenav"))
)
# Print page title and basic info
print(f"\nPage title: {driver.title}")
print(f"Current URL: {driver.current_url}")
# Check if sidenav has any content
sidenav = driver.find_element(By.CLASS_NAME, "sidenav")
print(f"Sidenav HTML: {sidenav.get_attribute('innerHTML')}")
# Check for JavaScript errors in console
logs = driver.get_log('browser')
if logs:
print(f"\nBrowser console logs:")
for log in logs:
print(f" {log['level']}: {log['message']}")
# Check if app.js loaded
try:
app_js = driver.find_element(By.XPATH, "//script[@src='/js/app.js']")
print(f"App.js script tag found: {app_js.get_attribute('outerHTML')}")
except:
print("App.js script tag NOT found!")
# Wait a bit longer and check again
time.sleep(3)
sidenav_after_wait = driver.find_element(By.CLASS_NAME, "sidenav")
print(f"Sidenav HTML after 3s wait: {sidenav_after_wait.get_attribute('innerHTML')}")
# This test should always pass for debugging
assert True
def test_page_loads(self, calculator_page):
"""Test that the calculator page loads correctly"""
assert "calculator.127local.net" in calculator_page.title
assert calculator_page.find_element(By.CLASS_NAME, "sidenav")
assert calculator_page.find_element(By.CLASS_NAME, "content")
def test_calculator_list(self, calculator_page):
"""Test that all calculators are listed in navigation"""
nav_items = calculator_page.find_elements(By.CSS_SELECTOR, ".sidenav a")
calculator_names = [item.text for item in nav_items]
expected_calculators = [
"Interest (Simple & Compound)",
"Bandwidth",
"NMEA",
"RAID",
"Currency Converter"
]
for expected in expected_calculators:
assert expected in calculator_names, f"Calculator {expected} not found in navigation"
class TestInterestCalculator:
"""Test the Interest calculator functionality"""
def test_interest_calculator_loads(self, calculator_page):
"""Test that interest calculator loads and displays correctly"""
# Click on interest calculator
interest_btn = calculator_page.find_element(By.XPATH, "//a[contains(text(), 'Interest')]")
interest_btn.click()
# Wait for calculator to load
WebDriverWait(calculator_page, 10).until(
EC.presence_of_element_located((By.NAME, "principal"))
)
# Check that all inputs are present
assert calculator_page.find_element(By.NAME, "principal")
assert calculator_page.find_element(By.NAME, "rate")
assert calculator_page.find_element(By.NAME, "compound")
assert calculator_page.find_element(By.NAME, "years")
assert calculator_page.find_element(By.NAME, "contrib")
assert calculator_page.find_element(By.NAME, "contribFreq")
def test_simple_interest_calculation(self, calculator_page):
"""Test simple interest calculation"""
# Load interest calculator
interest_btn = calculator_page.find_element(By.XPATH, "//a[contains(text(), 'Interest')]")
interest_btn.click()
# Wait for calculator to load
WebDriverWait(calculator_page, 10).until(
EC.presence_of_element_located((By.NAME, "principal"))
)
# Set values for simple interest
principal_input = calculator_page.find_element(By.NAME, "principal")
rate_input = calculator_page.find_element(By.NAME, "rate")
years_input = calculator_page.find_element(By.NAME, "years")
compound_select = calculator_page.find_element(By.NAME, "compound")
principal_input.clear()
principal_input.send_keys("1000")
rate_input.clear()
rate_input.send_keys("5")
years_input.clear()
years_input.send_keys("3")
# Select simple interest (no compounding)
# Click on the Select Lite button to open dropdown
compound_button = calculator_page.find_element(By.CSS_SELECTOR, '[name="compound"] + .select-lite__button')
compound_button.click()
# Wait for dropdown to appear and select Simple option
simple_option = WebDriverWait(calculator_page, 10).until(
EC.element_to_be_clickable((By.XPATH, "//div[contains(@class, 'select-lite__option') and contains(text(), 'Simple')]"))
)
simple_option.click()
# Wait for calculation
time.sleep(1)
# Check result
result = calculator_page.find_element(By.CLASS_NAME, "result")
assert "Future value:" in result.text
assert "1,150.00" in result.text # 1000 + (1000 * 0.05 * 3)
def test_compound_interest_calculation(self, calculator_page):
"""Test compound interest calculation"""
# Load interest calculator
interest_btn = calculator_page.find_element(By.XPATH, "//a[contains(text(), 'Interest')]")
interest_btn.click()
# Wait for calculator to load
WebDriverWait(calculator_page, 10).until(
EC.presence_of_element_located((By.NAME, "principal"))
)
# Set values for compound interest
principal_input = calculator_page.find_element(By.NAME, "principal")
rate_input = calculator_page.find_element(By.NAME, "rate")
years_input = calculator_page.find_element(By.NAME, "years")
principal_input.clear()
principal_input.send_keys("1000")
rate_input.clear()
rate_input.send_keys("5")
years_input.clear()
years_input.send_keys("3")
# Wait for calculation
time.sleep(1)
# Check result (should be higher than simple interest)
result = calculator_page.find_element(By.CLASS_NAME, "result")
assert "Future value:" in result.text
# Compound interest should be > 1150 (simple interest result)
assert "1,150.00" not in result.text or "1,157.63" in result.text
class TestCurrencyConverter:
"""Test the Currency Converter functionality"""
def test_currency_converter_loads(self, calculator_page):
"""Test that currency converter loads and displays correctly"""
# Click on currency converter
currency_btn = calculator_page.find_element(By.XPATH, "//a[contains(text(), 'Currency Converter')]")
currency_btn.click()
# Wait for calculator to load
WebDriverWait(calculator_page, 10).until(
EC.presence_of_element_located((By.NAME, "amount"))
)
# Check that all inputs are present
assert calculator_page.find_element(By.NAME, "amount")
assert calculator_page.find_element(By.NAME, "from")
assert calculator_page.find_element(By.NAME, "to")
def test_currency_conversion_same_currency(self, calculator_page):
"""Test conversion when from and to currencies are the same"""
# Load currency converter
currency_btn = calculator_page.find_element(By.XPATH, "//a[contains(text(), 'Currency Converter')]")
currency_btn.click()
# Wait for calculator to load
WebDriverWait(calculator_page, 10).until(
EC.presence_of_element_located((By.NAME, "amount"))
)
# Debug: verify we're on the currency converter
print(f"Current URL: {calculator_page.current_url}")
print(f"Page title: {calculator_page.title}")
# Check for currency converter specific elements
try:
from_select = calculator_page.find_element(By.NAME, "from")
to_select = calculator_page.find_element(By.NAME, "to")
print(f"From select value: {from_select.get_attribute('value')}")
print(f"To select value: {to_select.get_attribute('value')}")
except Exception as e:
print(f"Error finding currency elements: {e}")
# Set amount
amount_input = calculator_page.find_element(By.NAME, "amount")
amount_input.clear()
amount_input.send_keys("100")
# Trigger calculation by changing the amount
amount_input.send_keys(Keys.TAB)
# Wait for calculation to complete
WebDriverWait(calculator_page, 10).until(
EC.presence_of_element_located((By.CLASS_NAME, "result"))
)
# Wait a bit more for the currency converter to fully load and replace the old result
time.sleep(1)
# Find all result elements and get the one that's actually visible/contains currency content
result_elements = calculator_page.find_elements(By.CLASS_NAME, "result")
# Look for the result element that contains currency-related content
currency_result = None
for elem in result_elements:
html = elem.get_attribute('innerHTML')
if 'USD' in html or 'EUR' in html or 'Currency' in html or 'conversion' in html.lower():
currency_result = elem
break
if not currency_result:
# If no currency result found, use the last result element (most recent)
currency_result = result_elements[-1]
# Check result
assert "100 USD" in currency_result.text or "100 EUR" in currency_result.text
def test_currency_conversion_different_currencies(self, calculator_page):
"""Test conversion between different currencies"""
# Load currency converter
currency_btn = calculator_page.find_element(By.XPATH, "//a[contains(text(), 'Currency Converter')]")
currency_btn.click()
# Wait for calculator to load
WebDriverWait(calculator_page, 10).until(
EC.presence_of_element_located((By.NAME, "amount"))
)
# Set amount
amount_input = calculator_page.find_element(By.NAME, "amount")
amount_input.clear()
amount_input.send_keys("100")
# Trigger calculation by changing the amount
amount_input.send_keys(Keys.TAB)
# Wait for calculation and API response
WebDriverWait(calculator_page, 15).until(
EC.presence_of_element_located((By.CLASS_NAME, "result"))
)
# Wait a bit more for the currency converter to fully load and replace the old result
time.sleep(1)
# Find all result elements and get the one that's actually visible/contains currency content
result_elements = calculator_page.find_elements(By.CLASS_NAME, "result")
# Look for the result element that contains currency-related content
currency_result = None
for elem in result_elements:
html = elem.get_attribute('innerHTML')
if 'USD' in html or 'EUR' in html or 'Currency' in html or 'conversion' in html.lower():
currency_result = elem
break
if not currency_result:
# If no currency result found, use the last result element (most recent)
currency_result = result_elements[-1]
# Check that some result is displayed
assert currency_result.text.strip() != ""
# Check for either conversion result or static rates message
assert any(text in currency_result.text for text in ["USD", "EUR", "Static rates", "Live rates"])
class TestBandwidthCalculator:
"""Test the Bandwidth calculator functionality"""
def test_bandwidth_calculator_loads(self, calculator_page):
"""Test that bandwidth calculator loads"""
bandwidth_btn = calculator_page.find_element(By.XPATH, "//a[contains(text(), 'Bandwidth')]")
bandwidth_btn.click()
# Wait for calculator to load
WebDriverWait(calculator_page, 10).until(
EC.presence_of_element_located((By.CLASS_NAME, "result"))
)
# Check that result area is present
assert calculator_page.find_element(By.CLASS_NAME, "result")
class TestNMEACalculator:
"""Test the NMEA calculator functionality"""
def test_nmea_calculator_loads(self, calculator_page):
"""Test that NMEA calculator loads"""
nmea_btn = calculator_page.find_element(By.XPATH, "//a[contains(text(), 'NMEA')]")
nmea_btn.click()
# Wait for calculator to load
WebDriverWait(calculator_page, 10).until(
EC.presence_of_element_located((By.CLASS_NAME, "result"))
)
# Check that result area is present
assert calculator_page.find_element(By.CLASS_NAME, "result")
class TestRAIDCalculator:
"""Test the RAID calculator functionality"""
def test_raid_calculator_loads(self, calculator_page):
"""Test that RAID calculator loads"""
raid_btn = calculator_page.find_element(By.XPATH, "//a[contains(text(), 'RAID')]")
raid_btn.click()
# Wait for calculator to load
WebDriverWait(calculator_page, 10).until(
EC.presence_of_element_located((By.CLASS_NAME, "result"))
)
# Check that result area is present
assert calculator_page.find_element(By.CLASS_NAME, "result")
class TestCalculatorResponsiveness:
"""Test calculator responsiveness and UI behavior"""
def test_theme_toggle(self, calculator_page):
"""Test that theme toggle button works"""
theme_btn = calculator_page.find_element(By.ID, "themeToggle")
initial_text = theme_btn.text
# Click theme toggle
theme_btn.click()
# Wait for theme change
time.sleep(1)
# Check that text changed
assert theme_btn.text != initial_text
def test_calculator_switching(self, calculator_page):
"""Test switching between different calculators"""
# Start with interest calculator
interest_btn = calculator_page.find_element(By.XPATH, "//a[contains(text(), 'Interest')]")
interest_btn.click()
# Wait for interest calculator to load
WebDriverWait(calculator_page, 10).until(
EC.presence_of_element_located((By.NAME, "principal"))
)
# Switch to currency converter
currency_btn = calculator_page.find_element(By.XPATH, "//a[contains(text(), 'Currency Converter')]")
currency_btn.click()
# Wait for currency converter to load
WebDriverWait(calculator_page, 10).until(
EC.presence_of_element_located((By.NAME, "amount"))
)
# Verify we're on currency converter
assert calculator_page.find_element(By.NAME, "amount")
assert calculator_page.find_element(By.NAME, "from")
assert calculator_page.find_element(By.NAME, "to")