calculator.127local.net/tests/test_converter.py

864 lines
34 KiB
Python
Raw Normal View History

2025-08-16 17:54:12 -07:00
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.common.keys import Keys
import time
@pytest.fixture
def driver():
"""Set up Chrome driver with options"""
options = webdriver.ChromeOptions()
options.add_argument('--headless')
options.add_argument('--no-sandbox')
options.add_argument('--disable-dev-shm-usage')
driver = webdriver.Chrome(options=options)
driver.implicitly_wait(2)
yield driver
driver.quit()
@pytest.fixture
def converter_page(driver, dev_server):
"""Navigate to currency converter page"""
driver.get(f"{dev_server}")
# Wait for page to load and JavaScript to populate navigation
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.CLASS_NAME, "sidenav"))
)
# Wait for JavaScript to populate the navigation with calculator links
WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.XPATH, "//a[contains(text(), 'Currency Converter')]"))
)
# Click on Currency Converter
currency_btn = driver.find_element(By.XPATH, "//a[contains(text(), 'Currency Converter')]")
currency_btn.click()
# Wait for currency converter to load
WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.NAME, "amount"))
)
return driver
class TestCurrencyConverter:
"""Test the Currency Converter functionality"""
def _ensure_calculation(self, converter_page):
"""Helper to trigger calculation and wait for result"""
# Trigger calculation by sending TAB to the amount input
amount_input = converter_page.find_element(By.NAME, "amount")
amount_input.send_keys(Keys.TAB)
# Wait for calculation to complete
WebDriverWait(converter_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)
def _get_currency_result(self, converter_page):
"""Helper to get the correct currency result element"""
# Find all result elements and get the one that's actually visible/contains currency content
result_elements = converter_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 'GBP' 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]
return currency_result
def test_page_loads_with_default_values(self, converter_page):
"""Test that the page loads with default values and shows initial calculation"""
# Wait for the page to load
WebDriverWait(converter_page, 10).until(
EC.presence_of_element_located((By.NAME, "amount"))
)
# Ensure calculation is triggered
self._ensure_calculation(converter_page)
# Get the currency result element
result = self._get_currency_result(converter_page)
# Check that the result contains expected content
assert "USD" in result.text
assert "EUR" in result.text
assert "100" in result.text
def test_currency_selection_works(self, converter_page):
"""Test that currency selection works and updates calculation"""
# Wait for the page to load
WebDriverWait(converter_page, 10).until(
EC.presence_of_element_located((By.NAME, "amount"))
)
# Change from currency to GBP using Select Lite
from_button = converter_page.find_element(By.CSS_SELECTOR, '[name="from"] + .select-lite__button')
from_button.click()
# Wait for and click on GBP option
gbp_option = WebDriverWait(converter_page, 10).until(
EC.element_to_be_clickable((By.XPATH, "//div[contains(@class, 'select-lite__option') and contains(text(), 'GBP')]"))
)
gbp_option.click()
# Ensure calculation is triggered
self._ensure_calculation(converter_page)
# Get the currency result element
result = self._get_currency_result(converter_page)
# Check that the result contains GBP
assert "GBP" in result.text
def test_manual_rate_input_updates_calculation(self, converter_page):
"""Test that manual rate input updates calculation immediately"""
# Wait for the page to load
WebDriverWait(converter_page, 10).until(
EC.presence_of_element_located((By.NAME, "amount"))
)
# Find and update manual rate input
manual_rate_input = converter_page.find_element(By.NAME, "manualRate")
manual_rate_input.clear()
manual_rate_input.send_keys("2.0")
# Ensure calculation is triggered
self._ensure_calculation(converter_page)
# Get the currency result element
result = self._get_currency_result(converter_page)
# Check that the result shows the custom rate
assert "2.0" in result.text
assert "Custom rate" in result.text
def test_manual_rate_overrides_market_rates(self, converter_page):
"""Test that manual rate overrides fetched market rates"""
# Wait for the page to load
WebDriverWait(converter_page, 10).until(
EC.presence_of_element_located((By.NAME, "amount"))
)
# Set a manual rate
manual_rate_input = converter_page.find_element(By.NAME, "manualRate")
manual_rate_input.clear()
manual_rate_input.send_keys("1.5")
# Ensure calculation is triggered
self._ensure_calculation(converter_page)
# Get the currency result element
result = self._get_currency_result(converter_page)
# Check that the result shows the custom rate
assert "1.5" in result.text
assert "Custom rate" in result.text
def test_currency_switching_clears_manual_rate(self, converter_page):
"""Test that switching currencies clears manual rate input"""
# Wait for the page to load
WebDriverWait(converter_page, 10).until(
EC.presence_of_element_located((By.NAME, "amount"))
)
# Set a manual rate
manual_rate_input = converter_page.find_element(By.NAME, "manualRate")
manual_rate_input.clear()
manual_rate_input.send_keys("1.5")
# Change to currency using Select Lite
from_button = converter_page.find_element(By.CSS_SELECTOR, '[name="from"] + .select-lite__button')
from_button.click()
# Wait for and click on GBP option
gbp_option = WebDriverWait(converter_page, 10).until(
EC.element_to_be_clickable((By.XPATH, "//div[contains(@class, 'select-lite__option') and contains(text(), 'GBP')]"))
)
gbp_option.click()
# Ensure calculation is triggered
self._ensure_calculation(converter_page)
# Get the currency result element
result = self._get_currency_result(converter_page)
# Check that the result shows GBP and uses static rates (not custom rate)
assert "GBP" in result.text
assert "Static rates" in result.text
def test_fetch_rates_updates_manual_rate(self, converter_page):
"""Test that fetching rates updates the manual rate input"""
# Wait for the page to load
WebDriverWait(converter_page, 10).until(
EC.presence_of_element_located((By.NAME, "amount"))
)
# Set a manual rate first
manual_rate_input = converter_page.find_element(By.NAME, "manualRate")
manual_rate_input.clear()
manual_rate_input.send_keys("1.0")
# Click the fetch rates button
fetch_button = converter_page.find_element(By.XPATH, "//button[contains(text(), 'Update Exchange Rates')]")
# Use JavaScript to click to avoid interception
converter_page.execute_script("arguments[0].click();", fetch_button)
# Wait for the status to show success
WebDriverWait(converter_page, 15).until(
EC.text_to_be_present_in_element((By.CLASS_NAME, "status"), "Rates updated successfully!")
)
# Clear the manual rate so it will use the fetched rates
manual_rate_input.clear()
# Ensure calculation is triggered
self._ensure_calculation(converter_page)
# Get the currency result element
result = self._get_currency_result(converter_page)
# Check that the result shows live rates (not custom rate)
assert "Live rates" in result.text
def test_same_currency_conversion(self, converter_page):
"""Test conversion when from and to currencies are the same"""
# Wait for the page to load
WebDriverWait(converter_page, 10).until(
EC.presence_of_element_located((By.NAME, "amount"))
)
# Change from currency to EUR using Select Lite (since to is already EUR)
from_button = converter_page.find_element(By.CSS_SELECTOR, '[name="from"] + .select-lite__button')
from_button.click()
# Wait for and click on EUR option
eur_option = WebDriverWait(converter_page, 10).until(
EC.element_to_be_clickable((By.XPATH, "//div[contains(@class, 'select-lite__option') and contains(text(), 'EUR')]"))
)
eur_option.click()
# Ensure calculation is triggered
self._ensure_calculation(converter_page)
# Get the currency result element
result = self._get_currency_result(converter_page)
# Check that the result shows same currency message
assert "Same currency - no conversion needed" in result.text
assert "100.00 EUR" in result.text
def test_amount_input_updates_calculation(self, converter_page):
"""Test that changing amount updates calculation immediately"""
# Wait for the page to load
WebDriverWait(converter_page, 10).until(
EC.presence_of_element_located((By.NAME, "amount"))
)
# Change amount
amount_input = converter_page.find_element(By.NAME, "amount")
amount_input.clear()
amount_input.send_keys("50")
# Ensure calculation is triggered
self._ensure_calculation(converter_page)
# Get the currency result element
result = self._get_currency_result(converter_page)
# Check that the result shows the new amount
assert "50" in result.text
def test_negative_amount_handling(self, converter_page):
"""Test that negative amounts are handled appropriately"""
# Wait for the page to load
WebDriverWait(converter_page, 10).until(
EC.presence_of_element_located((By.NAME, "amount"))
)
# Try to enter negative amount
amount_input = converter_page.find_element(By.NAME, "amount")
amount_input.clear()
amount_input.send_keys("-100")
# Ensure calculation is triggered
self._ensure_calculation(converter_page)
# Get the currency result element
result = self._get_currency_result(converter_page)
# Check that the result shows the validation message
assert "Enter a positive amount to convert" in result.text
def test_zero_amount_handling(self, converter_page):
"""Test that zero amounts are handled appropriately"""
# Wait for the page to load
WebDriverWait(converter_page, 10).until(
EC.presence_of_element_located((By.NAME, "amount"))
)
# Try to enter zero amount
amount_input = converter_page.find_element(By.NAME, "amount")
amount_input.clear()
amount_input.send_keys("0")
# Ensure calculation is triggered
self._ensure_calculation(converter_page)
# Get the currency result element
result = self._get_currency_result(converter_page)
# Check that the result shows the validation message
assert "Enter a positive amount to convert" in result.text
def test_status_message_behavior(self, converter_page):
"""Test that status messages appear and disappear appropriately"""
# Wait for the page to load
WebDriverWait(converter_page, 10).until(
EC.presence_of_element_located((By.NAME, "amount"))
)
# Click the fetch rates button to trigger a status message
fetch_button = converter_page.find_element(By.XPATH, "//button[contains(text(), 'Update Exchange Rates')]")
# Use JavaScript to click to avoid interception
converter_page.execute_script("arguments[0].click();", fetch_button)
# Wait for the status to show success
WebDriverWait(converter_page, 15).until(
EC.text_to_be_present_in_element((By.CLASS_NAME, "status"), "Rates updated successfully!")
)
# Wait for the status message to disappear (should auto-hide after 1.5 seconds)
time.sleep(2)
# Check that the status element is either hidden or empty
status = converter_page.find_element(By.CLASS_NAME, "status")
assert status.text.strip() == "" or status.get_attribute("style").find("display: none") != -1
def test_select_lite_search_functionality(self, converter_page):
"""Test that Select Lite search works for currency selection"""
# Wait for the page to load
WebDriverWait(converter_page, 10).until(
EC.presence_of_element_located((By.NAME, "amount"))
)
# Click on the from currency Select Lite button
from_button = converter_page.find_element(By.CSS_SELECTOR, '[name="from"] + .select-lite__button')
from_button.click()
# Wait for the dropdown to open
WebDriverWait(converter_page, 10).until(
EC.presence_of_element_located((By.CLASS_NAME, "select-lite__menu"))
)
# Type 'g' to search for GBP
from_button.send_keys("g")
# Wait for and verify that GBP option is highlighted/filtered
gbp_option = WebDriverWait(converter_page, 10).until(
EC.presence_of_element_located((By.XPATH, "//div[contains(@class, 'select-lite__option') and contains(text(), 'GBP')]"))
)
# Click on GBP option
gbp_option.click()
# Ensure calculation is triggered
self._ensure_calculation(converter_page)
# Get the currency result element
result = self._get_currency_result(converter_page)
# Check that the result shows GBP
assert "GBP" in result.text
class TestCurrencyConverterEdgeCases:
"""Test edge cases and error conditions for the Currency Converter"""
def _ensure_calculation(self, converter_page):
"""Helper to trigger calculation and wait for result"""
# Trigger calculation by sending TAB to the amount input
amount_input = converter_page.find_element(By.NAME, "amount")
amount_input.send_keys(Keys.TAB)
# Wait for calculation to complete
WebDriverWait(converter_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)
def _get_currency_result(self, converter_page):
"""Helper to get the correct currency result element"""
# Find all result elements and get the one that's actually visible/contains currency content
result_elements = converter_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 'GBP' in html or 'JPY' 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]
return currency_result
def test_extremely_large_amounts(self, converter_page):
"""Test handling of extremely large amounts (overflow protection)"""
# Wait for the page to load
WebDriverWait(converter_page, 10).until(
EC.presence_of_element_located((By.NAME, "amount"))
)
# Test with a very large number
amount_input = converter_page.find_element(By.NAME, "amount")
amount_input.clear()
amount_input.send_keys("999999999999999999")
# Ensure calculation is triggered
self._ensure_calculation(converter_page)
# Get the currency result element
result = self._get_currency_result(converter_page)
# Should handle large numbers gracefully (not crash or show error)
assert result.text.strip() != ""
assert "Unable to calculate conversion" not in result.text
def test_extremely_small_amounts(self, converter_page):
"""Test handling of extremely small amounts (precision limits)"""
# Wait for the page to load
WebDriverWait(converter_page, 10).until(
EC.presence_of_element_located((By.NAME, "amount"))
)
# Test with a very small number
amount_input = converter_page.find_element(By.NAME, "amount")
amount_input.clear()
amount_input.send_keys("0.0000000001")
# Ensure calculation is triggered
self._ensure_calculation(converter_page)
# Get the currency result element
result = self._get_currency_result(converter_page)
# Should handle small numbers gracefully
assert result.text.strip() != ""
assert "Unable to calculate conversion" not in result.text
def test_decimal_precision_limits(self, converter_page):
"""Test handling of many decimal places"""
# Wait for the page to load
WebDriverWait(converter_page, 10).until(
EC.presence_of_element_located((By.NAME, "amount"))
)
# Test with many decimal places
amount_input = converter_page.find_element(By.NAME, "amount")
amount_input.clear()
amount_input.send_keys("100.12345678901234567890")
# Ensure calculation is triggered
self._ensure_calculation(converter_page)
# Get the currency result element
result = self._get_currency_result(converter_page)
# Should handle precision gracefully
assert result.text.strip() != ""
assert "100.12" in result.text # Should round appropriately
def test_empty_amount_input(self, converter_page):
"""Test handling of empty amount input"""
# Wait for the page to load
WebDriverWait(converter_page, 10).until(
EC.presence_of_element_located((By.NAME, "amount"))
)
# Clear amount input completely
amount_input = converter_page.find_element(By.NAME, "amount")
amount_input.clear()
# Send a TAB to trigger calculation
amount_input.send_keys(Keys.TAB)
# Wait for calculation to complete
WebDriverWait(converter_page, 10).until(
EC.presence_of_element_located((By.CLASS_NAME, "result"))
)
# Wait a bit more for the result to update
time.sleep(1)
# Get the currency result element
result = self._get_currency_result(converter_page)
# Should handle empty input gracefully (either show validation message or fall back to previous result)
assert result.text.strip() != ""
# Note: The currency converter may not properly validate empty input, so we just ensure it doesn't crash
def test_whitespace_only_input(self, converter_page):
"""Test handling of whitespace-only input"""
# Wait for the page to load
WebDriverWait(converter_page, 10).until(
EC.presence_of_element_located((By.NAME, "amount"))
)
# Test with whitespace
amount_input = converter_page.find_element(By.NAME, "amount")
amount_input.clear()
amount_input.send_keys(" ")
# Ensure calculation is triggered
self._ensure_calculation(converter_page)
# Get the currency result element
result = self._get_currency_result(converter_page)
# Should handle whitespace gracefully
assert result.text.strip() != ""
def test_manual_rate_edge_cases(self, converter_page):
"""Test edge cases for manual rate input"""
# Wait for the page to load
WebDriverWait(converter_page, 10).until(
EC.presence_of_element_located((By.NAME, "amount"))
)
# Test with zero manual rate
manual_rate_input = converter_page.find_element(By.NAME, "manualRate")
manual_rate_input.clear()
manual_rate_input.send_keys("0")
# Ensure calculation is triggered
self._ensure_calculation(converter_page)
# Get the currency result element
result = self._get_currency_result(converter_page)
# Should fall back to market/static rates when manual rate is 0
assert "Static rates" in result.text or "Live rates" in result.text
# Test with negative manual rate
manual_rate_input.clear()
manual_rate_input.send_keys("-1.5")
# Ensure calculation is triggered
self._ensure_calculation(converter_page)
# Get the currency result element
result = self._get_currency_result(converter_page)
# Should fall back to market/static rates when manual rate is negative
assert "Static rates" in result.text or "Live rates" in result.text
def test_extremely_small_manual_rate(self, converter_page):
"""Test handling of extremely small manual rates"""
# Wait for the page to load
WebDriverWait(converter_page, 10).until(
EC.presence_of_element_located((By.NAME, "amount"))
)
# Test with very small rate
manual_rate_input = converter_page.find_element(By.NAME, "manualRate")
manual_rate_input.clear()
manual_rate_input.send_keys("0.0000000001")
# Ensure calculation is triggered
self._ensure_calculation(converter_page)
# Get the currency result element
result = self._get_currency_result(converter_page)
# Should handle small rates gracefully
assert result.text.strip() != ""
assert "Custom rate" in result.text
def test_extremely_large_manual_rate(self, converter_page):
"""Test handling of extremely large manual rates"""
# Wait for the page to load
WebDriverWait(converter_page, 10).until(
EC.presence_of_element_located((By.NAME, "amount"))
)
# Test with very large rate
manual_rate_input = converter_page.find_element(By.NAME, "manualRate")
manual_rate_input.clear()
manual_rate_input.send_keys("999999999999999999")
# Ensure calculation is triggered
self._ensure_calculation(converter_page)
# Get the currency result element
result = self._get_currency_result(converter_page)
# Should handle large rates gracefully
assert result.text.strip() != ""
assert "Custom rate" in result.text
def test_rapid_currency_switching(self, converter_page):
"""Test rapid switching between currencies to ensure state consistency"""
# Wait for the page to load
WebDriverWait(converter_page, 10).until(
EC.presence_of_element_located((By.NAME, "amount"))
)
# Rapidly switch currencies multiple times
for i in range(3):
# Change from currency using JavaScript to avoid interception
from_button = converter_page.find_element(By.CSS_SELECTOR, '[name="from"] + .select-lite__button')
converter_page.execute_script("arguments[0].click();", from_button)
# Wait for dropdown to open
WebDriverWait(converter_page, 10).until(
EC.presence_of_element_located((By.CLASS_NAME, "select-lite__menu"))
)
# Wait for and click on GBP option
gbp_option = WebDriverWait(converter_page, 10).until(
EC.element_to_be_clickable((By.XPATH, "//div[contains(@class, 'select-lite__option') and contains(text(), 'GBP')]"))
)
converter_page.execute_script("arguments[0].click();", gbp_option)
# Wait for selection to complete
time.sleep(0.5)
# Change back to USD
from_button = converter_page.find_element(By.CSS_SELECTOR, '[name="from"] + .select-lite__button')
converter_page.execute_script("arguments[0].click();", from_button)
# Wait for dropdown to open
WebDriverWait(converter_page, 10).until(
EC.presence_of_element_located((By.CLASS_NAME, "select-lite__menu"))
)
usd_option = WebDriverWait(converter_page, 10).until(
EC.element_to_be_clickable((By.XPATH, "//div[contains(@class, 'select-lite__option') and contains(text(), 'USD')]"))
)
converter_page.execute_script("arguments[0].click();", usd_option)
# Wait for selection to complete
time.sleep(0.5)
# Ensure calculation is triggered
self._ensure_calculation(converter_page)
# Get the currency result element
result = self._get_currency_result(converter_page)
# Should still work correctly after rapid switching
assert result.text.strip() != ""
assert "USD" in result.text
assert "EUR" in result.text
def test_rapid_amount_changes(self, converter_page):
"""Test rapid changes to amount input"""
# Wait for the page to load
WebDriverWait(converter_page, 10).until(
EC.presence_of_element_located((By.NAME, "amount"))
)
# Rapidly change amounts
amount_input = converter_page.find_element(By.NAME, "amount")
for amount in ["100", "200", "50", "75", "100"]:
amount_input.clear()
amount_input.send_keys(amount)
time.sleep(0.1)
# Ensure calculation is triggered
self._ensure_calculation(converter_page)
# Get the currency result element
result = self._get_currency_result(converter_page)
# Should show the final amount correctly
assert result.text.strip() != ""
assert "100" in result.text
def test_concurrent_rate_fetching(self, converter_page):
"""Test multiple rapid clicks on fetch rates button"""
# Wait for the page to load
WebDriverWait(converter_page, 10).until(
EC.presence_of_element_located((By.NAME, "amount"))
)
# Click fetch rates button multiple times rapidly
fetch_button = converter_page.find_element(By.XPATH, "//button[contains(text(), 'Update Exchange Rates')]")
for _ in range(3):
converter_page.execute_script("arguments[0].click();", fetch_button)
time.sleep(0.1)
# Wait for any status message
try:
WebDriverWait(converter_page, 15).until(
EC.presence_of_element_located((By.CLASS_NAME, "status"))
)
except:
pass # Status might not appear if requests are cancelled
# Ensure calculation is triggered
self._ensure_calculation(converter_page)
# Get the currency result element
result = self._get_currency_result(converter_page)
# Should still work correctly after multiple clicks
assert result.text.strip() != ""
def test_invalid_manual_rate_input(self, converter_page):
"""Test handling of invalid manual rate input"""
# Wait for the page to load
WebDriverWait(converter_page, 10).until(
EC.presence_of_element_located((By.NAME, "amount"))
)
# Test with invalid input (letters)
manual_rate_input = converter_page.find_element(By.NAME, "manualRate")
manual_rate_input.clear()
manual_rate_input.send_keys("abc")
# Ensure calculation is triggered
self._ensure_calculation(converter_page)
# Get the currency result element
result = self._get_currency_result(converter_page)
# Should fall back to market/static rates when manual rate is invalid
assert "Static rates" in result.text or "Live rates" in result.text
def test_manual_rate_precision_limits(self, converter_page):
"""Test handling of manual rate with many decimal places"""
# Wait for the page to load
WebDriverWait(converter_page, 10).until(
EC.presence_of_element_located((By.NAME, "amount"))
)
# Test with many decimal places
manual_rate_input = converter_page.find_element(By.NAME, "manualRate")
manual_rate_input.clear()
manual_rate_input.send_keys("1.234567890123456789")
# Ensure calculation is triggered
self._ensure_calculation(converter_page)
# Get the currency result element
result = self._get_currency_result(converter_page)
# Should handle precision gracefully
assert result.text.strip() != ""
assert "Custom rate" in result.text
assert "1.2346" in result.text # Should round appropriately
def test_cache_expiration_edge_case(self, converter_page):
"""Test behavior when cache is about to expire"""
# Wait for the page to load
WebDriverWait(converter_page, 10).until(
EC.presence_of_element_located((By.NAME, "amount"))
)
# This test would require mocking time, but we can test the basic functionality
# by ensuring the cache duration logic doesn't break normal operation
# Click fetch rates button
fetch_button = converter_page.find_element(By.XPATH, "//button[contains(text(), 'Update Exchange Rates')]")
converter_page.execute_script("arguments[0].click();", fetch_button)
# Wait for status to show success
try:
WebDriverWait(converter_page, 15).until(
EC.text_to_be_present_in_element((By.CLASS_NAME, "status"), "Rates updated successfully!")
)
except:
pass # API might fail, that's okay for this test
# Ensure calculation is triggered
self._ensure_calculation(converter_page)
# Get the currency result element
result = self._get_currency_result(converter_page)
# Should still work regardless of cache status
assert result.text.strip() != ""
def test_currency_pair_edge_cases(self, converter_page):
"""Test edge cases with specific currency pairs"""
# Wait for the page to load
WebDriverWait(converter_page, 10).until(
EC.presence_of_element_located((By.NAME, "amount"))
)
# Test with a very small amount to test precision handling
amount_input = converter_page.find_element(By.NAME, "amount")
amount_input.clear()
amount_input.send_keys("0.01")
# Ensure calculation is triggered
self._ensure_calculation(converter_page)
# Get the currency result element
result = self._get_currency_result(converter_page)
# Should handle small amounts correctly
assert result.text.strip() != ""
assert "0.01" in result.text # Should show the small amount
assert "USD" in result.text
assert "EUR" in result.text
def test_empty_manual_rate_after_setting(self, converter_page):
"""Test behavior when manual rate is cleared after being set"""
# Wait for the page to load
WebDriverWait(converter_page, 10).until(
EC.presence_of_element_located((By.NAME, "amount"))
)
# Set a manual rate first
manual_rate_input = converter_page.find_element(By.NAME, "manualRate")
manual_rate_input.clear()
manual_rate_input.send_keys("2.0")
# Ensure calculation is triggered
self._ensure_calculation(converter_page)
# Get the currency result element
result = self._get_currency_result(converter_page)
# Should show custom rate
assert "Custom rate" in result.text
# Now clear the manual rate
manual_rate_input.clear()
# Ensure calculation is triggered
self._ensure_calculation(converter_page)
# Get the currency result element
result = self._get_currency_result(converter_page)
# Should fall back to market/static rates
assert "Static rates" in result.text or "Live rates" in result.text
assert "Custom rate" not in result.text
if __name__ == "__main__":
pytest.main([__file__, "-v"])