-
-
Notifications
You must be signed in to change notification settings - Fork 0
Add Selenium UI tests for language switcher, OS tabs, and code tabs #2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,150 @@ | ||
| import pytest | ||
| import time | ||
| from selenium.webdriver.common.by import By | ||
| from core.base_test import BaseTest | ||
|
|
||
| OS_KEYWORDS = [ | ||
| 'Ubuntu', 'Debian', 'Centos', 'RHEL', 'MacOS', | ||
| 'Windows', 'Docker', 'Kubernetes', 'Alma', 'Amazon', 'Oracle', 'Mint', | ||
| ] | ||
|
|
||
|
|
||
| @pytest.mark.usefixtures("setup_driver") | ||
| class TestCodeTabsSqlJson(BaseTest): | ||
| """Tests for SQL/HTTP/PHP code tab switching in documentation examples.""" | ||
|
|
||
| PAGE_URL = "https://manual.manticoresearch.com/Quick_start_guide" | ||
|
|
||
| def _find_code_tab_blocks(self, tab_names): | ||
| """Find all visible code lang-sel blocks containing specified tab names. | ||
|
|
||
| Returns a list of WebElements. Excludes OS-related tab blocks. | ||
| """ | ||
| blocks = self.driver.find_elements(By.CSS_SELECTOR, "div.lang-sel") | ||
| result = [] | ||
| for block in blocks: | ||
| example = block.find_element( | ||
| By.XPATH, "./ancestor::div[contains(@class, 'example')]" | ||
| ) | ||
| if not example.is_displayed(): | ||
| continue | ||
| tabs = block.find_elements( | ||
| By.CSS_SELECTOR, "ul.lang-tabs li span.lang-text" | ||
| ) | ||
| tab_texts = [t.get_attribute("textContent").strip() for t in tabs] | ||
| if any(kw in text for kw in OS_KEYWORDS for text in tab_texts): | ||
| continue | ||
| if all(name in tab_texts for name in tab_names): | ||
| result.append(block) | ||
| return result | ||
|
|
||
| def _find_code_tab_block(self, tab_names): | ||
| """Find the first visible code lang-sel block with specified tabs.""" | ||
| blocks = self._find_code_tab_blocks(tab_names) | ||
| if not blocks: | ||
| pytest.fail(f"Code tab block with tabs {tab_names} not found") | ||
| return blocks[0] | ||
|
|
||
| def _get_visible_body_text(self, block): | ||
| """Get text of the currently visible example-body.""" | ||
| example = block.find_element( | ||
| By.XPATH, "./ancestor::div[contains(@class, 'example')]" | ||
| ) | ||
| bodies = example.find_elements(By.CSS_SELECTOR, ".example-body") | ||
| for body in bodies: | ||
| if body.is_displayed(): | ||
| return body.text.strip() | ||
| return "" | ||
|
|
||
| def _get_active_tab_text(self, block): | ||
| """Get the text of the currently active tab.""" | ||
| active = block.find_element( | ||
| By.CSS_SELECTOR, "li.active span.lang-text" | ||
| ) | ||
| return active.get_attribute("textContent").strip() | ||
|
|
||
| def _click_tab(self, block, text): | ||
| """Click a tab by its text content.""" | ||
| tabs = block.find_elements(By.CSS_SELECTOR, "ul.lang-tabs li") | ||
| for tab in tabs: | ||
| span = tab.find_element(By.CSS_SELECTOR, "span.lang-text") | ||
| if span.get_attribute("textContent").strip() == text: | ||
| tab.click() | ||
| time.sleep(2) | ||
| return | ||
| pytest.fail(f"Tab '{text}' not found in block") | ||
|
|
||
| def test_default_tab_is_sql(self): | ||
| """Verify that SQL is the default active tab in code examples.""" | ||
| self.driver.get(self.PAGE_URL) | ||
| time.sleep(2) | ||
|
|
||
| block = self._find_code_tab_block(["SQL", "HTTP"]) | ||
| active = self._get_active_tab_text(block) | ||
| assert active == "SQL", f"Default active tab should be 'SQL', got: '{active}'" | ||
|
|
||
| @pytest.mark.parametrize("tab_name", ["HTTP", "PHP", "Python"]) | ||
| def test_switch_to_tab(self, tab_name): | ||
| """Verify switching to a specific tab activates it and shows different content.""" | ||
| self.driver.get(self.PAGE_URL) | ||
| time.sleep(2) | ||
|
|
||
| block = self._find_code_tab_block(["SQL", tab_name]) | ||
|
|
||
| self._click_tab(block, "SQL") | ||
| sql_content = self._get_visible_body_text(block) | ||
|
|
||
| self._click_tab(block, tab_name) | ||
|
|
||
| active = self._get_active_tab_text(block) | ||
| assert active == tab_name, f"Active tab should be '{tab_name}', got: '{active}'" | ||
|
|
||
| content = self._get_visible_body_text(block) | ||
| assert content, f"{tab_name} tab should have visible content" | ||
| assert content != sql_content, f"{tab_name} content should differ from SQL content" | ||
|
|
||
| def test_tab_content_changes_on_switch(self): | ||
| """Verify that content changes when switching tabs and restores when switching back.""" | ||
| self.driver.get(self.PAGE_URL) | ||
| time.sleep(2) | ||
|
|
||
| block = self._find_code_tab_block(["SQL", "HTTP"]) | ||
|
|
||
| self._click_tab(block, "SQL") | ||
| sql_content = self._get_visible_body_text(block) | ||
|
|
||
| self._click_tab(block, "HTTP") | ||
| http_content = self._get_visible_body_text(block) | ||
|
|
||
| self._click_tab(block, "SQL") | ||
| sql_again = self._get_visible_body_text(block) | ||
|
|
||
| assert sql_content != http_content, \ | ||
| "SQL and HTTP content should be different" | ||
| assert sql_content == sql_again, \ | ||
| "SQL content should be the same after switching back" | ||
|
|
||
| def test_global_tab_sync(self): | ||
| """Verify that switching a code tab in one block syncs all code blocks. | ||
|
|
||
| The documentation site syncs tab selection globally — switching to HTTP | ||
| in one block should switch all blocks to HTTP. | ||
| """ | ||
| self.driver.get(self.PAGE_URL) | ||
| time.sleep(2) | ||
|
|
||
| code_blocks = self._find_code_tab_blocks(["SQL", "HTTP"]) | ||
| if len(code_blocks) < 2: | ||
| pytest.skip("Need at least 2 visible SQL/HTTP code blocks") | ||
|
|
||
| block1, block2 = code_blocks[0], code_blocks[1] | ||
|
|
||
| self._click_tab(block1, "SQL") | ||
| assert self._get_active_tab_text(block1) == "SQL" | ||
|
|
||
| # Switch block1 to HTTP — block2 should sync automatically | ||
| self._click_tab(block1, "HTTP") | ||
|
|
||
| active2 = self._get_active_tab_text(block2) | ||
| assert active2 == "HTTP", \ | ||
| f"Tab sync: block2 should also switch to HTTP, got: '{active2}'" | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,91 @@ | ||
| import pytest | ||
| import time | ||
| from selenium.webdriver.common.by import By | ||
| from selenium.webdriver.support.ui import Select, WebDriverWait | ||
| from selenium.webdriver.support import expected_conditions as EC | ||
| from core.base_test import BaseTest | ||
|
|
||
|
|
||
| @pytest.mark.usefixtures("setup_driver") | ||
| class TestLanguageSwitcher(BaseTest): | ||
| """Tests for language switching functionality on the documentation site.""" | ||
|
|
||
| BASE_URL = "https://manual.manticoresearch.com/" | ||
|
|
||
| def test_switch_to_russian(self): | ||
| """Verify switching language to Russian changes content and URL.""" | ||
| self.driver.get(self.BASE_URL) | ||
| time.sleep(2) | ||
|
|
||
| select = Select(self.driver.find_element(By.ID, "language-select")) | ||
| select.select_by_value("ru") | ||
| time.sleep(2) | ||
|
|
||
| assert "/ru/" in self.driver.current_url, \ | ||
| f"URL should contain '/ru/', got: {self.driver.current_url}" | ||
|
|
||
| h1 = self.driver.find_element(By.TAG_NAME, "h1") | ||
| assert h1.text == "Введение", \ | ||
| f"H1 should be 'Введение', got: '{h1.text}'" | ||
|
|
||
|
|
||
| def test_switch_to_chinese(self): | ||
| """Verify switching language to Chinese changes content and URL.""" | ||
| self.driver.get(self.BASE_URL) | ||
| time.sleep(2) | ||
|
|
||
| select = Select(self.driver.find_element(By.ID, "language-select")) | ||
| select.select_by_value("zh") | ||
| time.sleep(2) | ||
|
|
||
| assert "/zh/" in self.driver.current_url, \ | ||
| f"URL should contain '/zh/', got: {self.driver.current_url}" | ||
|
|
||
|
|
||
| def test_switch_back_to_english(self): | ||
| """Verify switching from Russian back to English restores content.""" | ||
| self.driver.get(self.BASE_URL) | ||
| time.sleep(2) | ||
|
|
||
| # Switch to Russian first | ||
| select = Select(self.driver.find_element(By.ID, "language-select")) | ||
| select.select_by_value("ru") | ||
| time.sleep(2) | ||
|
|
||
| assert "/ru/" in self.driver.current_url | ||
|
|
||
| # Switch back to English | ||
| select = Select(self.driver.find_element(By.ID, "language-select")) | ||
| select.select_by_value("") | ||
| time.sleep(2) | ||
|
|
||
| assert "/ru/" not in self.driver.current_url, \ | ||
| f"URL should not contain '/ru/' after switching back, got: {self.driver.current_url}" | ||
|
|
||
| h1 = self.driver.find_element(By.TAG_NAME, "h1") | ||
| assert h1.text == "Introduction", \ | ||
| f"H1 should be 'Introduction', got: '{h1.text}'" | ||
|
|
||
|
|
||
| def test_language_cookie_persists(self): | ||
| """Verify that language selection is saved in cookie.""" | ||
| self.driver.get(self.BASE_URL) | ||
| time.sleep(2) | ||
|
|
||
| select = Select(self.driver.find_element(By.ID, "language-select")) | ||
| select.select_by_value("ru") | ||
| time.sleep(2) | ||
|
|
||
| cookies = {c['name']: c['value'] for c in self.driver.get_cookies()} | ||
| assert cookies.get('selected-language') == 'ru', \ | ||
| f"Cookie 'selected-language' should be 'ru', got: {cookies.get('selected-language')}" | ||
|
|
||
| # Navigate to another page — language should persist | ||
| self.driver.get("https://manual.manticoresearch.com/ru/Starting_the_server/Linux") | ||
| time.sleep(2) | ||
|
|
||
| select_after = Select(self.driver.find_element(By.ID, "language-select")) | ||
| selected_option = select_after.first_selected_option | ||
| assert selected_option.get_attribute("value") == "ru", \ | ||
| f"Language selector should still be 'ru', got: '{selected_option.get_attribute('value')}'" | ||
|
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,153 @@ | ||
| import pytest | ||
| import time | ||
| from selenium.webdriver.common.by import By | ||
| from selenium.webdriver.support.ui import WebDriverWait | ||
| from selenium.webdriver.support import expected_conditions as EC | ||
| from core.base_test import BaseTest | ||
|
|
||
|
|
||
| @pytest.mark.usefixtures("setup_driver") | ||
| class TestOsTabsInstallation(BaseTest): | ||
| """Tests for OS tab switching on the Installation page.""" | ||
|
|
||
| INSTALL_URL = "https://manual.manticoresearch.com/Installation/Installation" | ||
|
|
||
| def _get_tab_block(self): | ||
| """Find the OS tabs block on the Installation page.""" | ||
| self.driver.get(self.INSTALL_URL) | ||
| time.sleep(2) | ||
|
|
||
| # Find the lang-sel block that contains OS tabs (RHEL, Debian, etc.) | ||
| blocks = self.driver.find_elements(By.CSS_SELECTOR, "div.lang-sel") | ||
| for block in blocks: | ||
| tabs = block.find_elements(By.CSS_SELECTOR, "li span.lang-text") | ||
| tab_texts = [t.get_attribute("textContent").strip() for t in tabs] | ||
| if any("RHEL" in t for t in tab_texts): | ||
| return block | ||
| pytest.fail("OS tabs block not found on Installation page") | ||
|
|
||
| def _get_visible_body_text(self, block): | ||
| """Get text content of the currently visible example-body.""" | ||
| example = block.find_element(By.XPATH, "./ancestor::div[contains(@class, 'example')]") | ||
| bodies = example.find_elements(By.CSS_SELECTOR, ".example-body") | ||
| for body in bodies: | ||
| if body.is_displayed(): | ||
| return body.text.strip() | ||
| return "" | ||
|
|
||
| def _get_active_tab_text(self, block): | ||
| """Get the text of the currently active tab.""" | ||
| active_li = block.find_element(By.CSS_SELECTOR, "li.active span.lang-text") | ||
| return active_li.get_attribute("textContent").strip() | ||
|
|
||
| def _click_tab(self, block, tab_text): | ||
| """Click a tab by its text content.""" | ||
| old_content = self._get_visible_body_text(block) | ||
| tabs = block.find_elements(By.CSS_SELECTOR, "li") | ||
| for tab in tabs: | ||
| span = tab.find_element(By.CSS_SELECTOR, "span.lang-text") | ||
| if span.get_attribute("textContent").strip() == tab_text: | ||
| self.driver.execute_script("arguments[0].click();", tab) | ||
| # Wait for content to change (up to 5 seconds) | ||
| for _ in range(10): | ||
| time.sleep(0.5) | ||
| new_content = self._get_visible_body_text(block) | ||
| if new_content != old_content: | ||
| break | ||
| return | ||
| pytest.fail(f"Tab '{tab_text}' not found") | ||
|
|
||
| def test_default_tab_is_rhel(self): | ||
| """Verify that RHEL tab is active by default.""" | ||
| block = self._get_tab_block() | ||
|
|
||
| active = self._get_active_tab_text(block) | ||
| assert "RHEL" in active, \ | ||
| f"Default active tab should contain 'RHEL', got: '{active}'" | ||
|
|
||
| content = self._get_visible_body_text(block) | ||
| assert "yum install" in content, \ | ||
| f"RHEL tab should show yum install command, got: '{content[:100]}'" | ||
|
|
||
|
|
||
| def test_switch_to_debian(self): | ||
| """Verify switching to Debian tab shows apt/wget commands.""" | ||
| block = self._get_tab_block() | ||
|
|
||
| self._click_tab(block, "Debian, Ubuntu, Mint") | ||
|
|
||
| active = self._get_active_tab_text(block) | ||
| assert "Debian" in active, \ | ||
| f"Active tab should contain 'Debian', got: '{active}'" | ||
|
|
||
| content = self._get_visible_body_text(block) | ||
| assert "wget" in content or "apt" in content, \ | ||
| f"Debian tab should show wget/apt commands, got: '{content[:100]}'" | ||
|
|
||
|
|
||
| def test_switch_to_docker(self): | ||
| """Verify switching to Docker tab shows docker commands.""" | ||
| block = self._get_tab_block() | ||
|
|
||
| self._click_tab(block, "Docker") | ||
|
|
||
| active = self._get_active_tab_text(block) | ||
| assert "Docker" in active, \ | ||
| f"Active tab should be 'Docker', got: '{active}'" | ||
|
|
||
| content = self._get_visible_body_text(block) | ||
| assert "docker" in content.lower(), \ | ||
| f"Docker tab should show docker commands, got: '{content[:100]}'" | ||
|
|
||
|
|
||
| def test_switch_to_macos(self): | ||
| """Verify switching to MacOS tab shows brew commands.""" | ||
| block = self._get_tab_block() | ||
|
|
||
| self._click_tab(block, "MacOS") | ||
|
|
||
| active = self._get_active_tab_text(block) | ||
| assert "MacOS" in active, \ | ||
| f"Active tab should be 'MacOS', got: '{active}'" | ||
|
|
||
| content = self._get_visible_body_text(block) | ||
| assert "brew" in content, \ | ||
| f"MacOS tab should show brew command, got: '{content[:100]}'" | ||
|
|
||
|
|
||
| def test_switch_to_kubernetes(self): | ||
| """Verify switching to Kubernetes tab shows helm commands.""" | ||
| block = self._get_tab_block() | ||
|
|
||
| self._click_tab(block, "Kubernetes") | ||
|
|
||
| active = self._get_active_tab_text(block) | ||
| assert "Kubernetes" in active, \ | ||
| f"Active tab should be 'Kubernetes', got: '{active}'" | ||
|
|
||
| content = self._get_visible_body_text(block) | ||
| assert "helm" in content, \ | ||
| f"Kubernetes tab should show helm commands, got: '{content[:100]}'" | ||
|
|
||
|
|
||
| def test_switching_tabs_changes_content(self): | ||
| """Verify that switching between tabs actually changes visible content.""" | ||
| block = self._get_tab_block() | ||
|
|
||
| # Explicitly select RHEL first | ||
| self._click_tab(block, "RHEL, Centos, Alma, Amazon, Oracle") | ||
| rhel_content = self._get_visible_body_text(block) | ||
|
|
||
| # Switch to Docker | ||
| self._click_tab(block, "Docker") | ||
| docker_content = self._get_visible_body_text(block) | ||
|
|
||
| assert rhel_content != docker_content, \ | ||
| "Content should change when switching between RHEL and Docker tabs" | ||
|
|
||
| # Switch back to RHEL | ||
| self._click_tab(block, "RHEL, Centos, Alma, Amazon, Oracle") | ||
| rhel_again = self._get_visible_body_text(block) | ||
|
|
||
| assert rhel_again == rhel_content, \ | ||
| "Content should be the same when switching back to RHEL" |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.