init
This commit is contained in:
commit
97f9a95415
21 changed files with 2963 additions and 0 deletions
863
tests/test_converter.py
Normal file
863
tests/test_converter.py
Normal file
|
@ -0,0 +1,863 @@
|
|||
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"])
|
Loading…
Add table
Add a link
Reference in a new issue