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"])