diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..6f64542 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,119 @@ +name: Python Selenium Tests with Allure Report + +on: + push: + branches: + - main + pull_request: + branches: + - main + +jobs: + build: + name: 'Run Pytest + Generate Allure Report' + runs-on: ubuntu-latest + + steps: + # 1 Checkout repository + - name: Checkout repository + uses: actions/checkout@v4.2.2 + + # 2 Set up Python + - name: Set up Python + uses: actions/setup-python@v5.2.0 + with: + python-version: '3.12' + + # 3 Set up Chrome for Selenium + - name: Set up Chrome and Chromedriver + uses: browser-actions/setup-chrome@v1 + + # 4 Install dependencies + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements.txt + pip install allure-pytest + + # 5 Verify installed packages + - name: Verify installed packages + run: pip freeze + + # 6 Run tests with Allure results + - name: Run tests + run: | + pytest --alluredir=allure-results --disable-warnings -q + + - name: Install Allure + run: | + sudo apt-add-repository ppa:qameta/allure -y + sudo apt-get update + sudo apt-get install allure -y + + # 7 Generate Allure report + - name: Generate Allure report + run: | + allure generate allure-results --clean -o allure-report + + # 8 Upload screenshots (optional) + - name: Upload screenshots + if: always() + uses: actions/upload-artifact@v4 + with: + name: screenshots + path: screenshots + + # 9 Upload Allure report as artifact + - name: Upload Allure report + if: always() + uses: actions/upload-artifact@v4 + with: + name: allure-report + path: allure-report + + # 10 Get previous Allure history for gh-pages + - name: Get Allure history + uses: actions/checkout@v4 + if: always() + continue-on-error: true + with: + ref: gh-pages + path: gh-pages + + # 11 Build Allure report for Pages + - name: Build Allure report for GitHub Pages + if: always() + uses: simple-elf/allure-report-action@master + id: allure-report + with: + allure_results: allure-results + gh_pages: gh-pages + allure_report: allure-report + allure_history: allure-history + ref: gh-pages + path: gh-pages + keep_reports: 30 + + # 12 Publish Allure report to GitHub Pages + - name: Publish Allure report to GitHub Pages + if: always() + uses: peaceiris/actions-gh-pages@v4 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: allure-history + force_orphan: true + + # 13 Save logs if not-success + - name: Save test logs + if: failure() + run: | + pytest --log-cli-level=INFO --capture=tee-sys --disable-warnings > pytest.log || true + shell: bash + + # 14 Loading logs as artifacts + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v4.4.3 + with: + name: pytest-logs + path: pytest.log \ No newline at end of file diff --git a/.gitignore b/.gitignore index ada9db8..3a6ba70 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ .venv .idea +.idea/ *.log __pycache__ allure-results diff --git a/.idea/workspace.xml b/.idea/workspace.xml index fe2c703..e6eb8b7 100644 --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -5,24 +5,12 @@ - - - - - - - - + - - - - - - - + + + @@ -55,15 +48,19 @@ "keyToString": { "Python tests.Python tests for home_page_test.test_get_url.executor": "Run", "Python tests.Python tests for home_page_test.test_gotoElements_page.executor": "Run", + "Python tests.Python tests for tests.home_page_test.HomePageTest.executor": "Run", + "Python tests.Python tests for tests.home_page_test.HomePageTest.test_get_url.executor": "Run", "Python tests.Python tests for tests.home_page_test.test_get_url.executor": "Run", "Python tests.Python tests for tests.home_page_test.test_goto_elements_page.executor": "Run", + "Python tests.Python tests for tests.test_fixture.TestMainPage1.executor": "Run", + "Python tests.Python tests for tests.test_fixture.TestMainPage1.test_guest_should_see_login_link.executor": "Run", "Python tests.Python tests for tests.text_box_test.test_text_box.executor": "Run", "Python.home_page_test.executor": "Run", "RunOnceActivity.OpenProjectViewOnStart": "true", "RunOnceActivity.ShowReadmeOnStart": "true", "RunOnceActivity.TerminalTabsStorage.copyFrom.TerminalArrangementManager.252": "true", "RunOnceActivity.git.unshallow": "true", - "git-widget-placeholder": "main", + "git-widget-placeholder": "test__demoqa", "settings.editor.selected.configurable": "com.jetbrains.python.configuration.PyActiveSdkModuleConfigurable" } } @@ -74,45 +71,38 @@ - - + + - + - + - + - + - - - - + + + + diff --git a/conftest.py b/conftest.py index 847e2ce..a2f20ce 100644 --- a/conftest.py +++ b/conftest.py @@ -1,3 +1,7 @@ +import shutil +import tempfile + +import os import pytest from selenium import webdriver @@ -7,17 +11,47 @@ @pytest.fixture(scope="function") def driver(): - # === BEFORE test === - chrome_options = webdriver.ChromeOptions() - chrome_options.add_argument("--incognito") - chrome_options.add_argument("--window-size = 1400, 1080") - service_properties = Service(executable_path=ChromeDriverManager().install()) - driver = webdriver.Chrome(service=service_properties, options=chrome_options) + chrome_options = webdriver.ChromeOptions() # <-- исправлено + + # Check run in CI (GitHub Actions) + is_ci = os.environ.get("CI") == "true" + + if is_ci: + # === For CI === + chrome_options.add_argument("--headless=new") + chrome_options.add_argument("--no-sandbox") + chrome_options.add_argument("--disable-dev-shm-usage") + chrome_options.add_argument("--disable-gpu") + chrome_options.add_argument("--window-size=1920,1080") + chrome_options.add_argument("--disable-software-rasterizer") + chrome_options.add_argument("--remote-debugging-port=9222") + chrome_options.add_argument("--disable-extensions") + chrome_options.add_argument("--disable-infobars") + chrome_options.add_argument("--disable-browser-side-navigation") + chrome_options.add_argument("--disable-features=VizDisplayCompositor") + + # uniq profile + user_data_dir = tempfile.mkdtemp() + chrome_options.add_argument(f"--user-data-dir={user_data_dir}") + else: + # === Local run === + chrome_options.add_argument("--incognito") + chrome_options.add_argument("--window-size=1400,1080") + + # Create driver + service = Service(ChromeDriverManager().install()) + driver = webdriver.Chrome(service=service, options=chrome_options) + driver.set_page_load_timeout(60) + driver.implicitly_wait(10) yield driver driver.quit() + if is_ci: + shutil.rmtree(user_data_dir, ignore_errors=True) + + # === AFTER test === @pytest.hookimpl(hookwrapper=True, tryfirst=True) def pytest_runtest_makereport(item, call): diff --git a/pages/elements/text_box_page.py b/pages/elements/text_box_page.py index 1c3faf4..8cf56f0 100644 --- a/pages/elements/text_box_page.py +++ b/pages/elements/text_box_page.py @@ -22,7 +22,6 @@ def submit_data(self): def check_result(self): self.driver.implicitly_wait(6) get_text_name = self.driver.find_element(By.ID, LocatorsTextBox.name).text - # self.wait5().until(lambda _ : get_text_name.is_displayed()) return get_text_name diff --git a/pytest.ini b/pytest.ini index 91021f9..923acb2 100644 --- a/pytest.ini +++ b/pytest.ini @@ -1,3 +1,6 @@ [pytest] addopts = --alluredir allure-results - --clean-alluredir \ No newline at end of file + --clean-alluredir +markers = + smoke: marker for smoke + regression: marker for regression tests \ No newline at end of file diff --git a/tests/home_page_test.py b/tests/home_page_test.py index d71afff..1c1f260 100644 --- a/tests/home_page_test.py +++ b/tests/home_page_test.py @@ -1,3 +1,5 @@ +import pytest + from pages.elements.elements_page import ElementsPage from pages.home_page import HomePage from conftest import driver @@ -9,15 +11,17 @@ @allure.story("Homepage") def test_get_url(driver): home_page = HomePage(driver) - home_page.open()\ - .get_title() + home_page.open() \ + .get_title() +# @pytest.mark.smoke def test_goto_elements_page(driver): - title = HomePage(driver)\ - .open()\ - .scroll_page()\ - .goto_elements_page\ - .get_title() + title = HomePage(driver) \ + .open() \ + .scroll_page() \ + .goto_elements_page \ + .get_title() assert title.__eq__("DEMOQA") + diff --git a/tests/test_fixture.py b/tests/test_fixture.py new file mode 100644 index 0000000..bb8c139 --- /dev/null +++ b/tests/test_fixture.py @@ -0,0 +1,26 @@ +import pytest +from selenium import webdriver +from selenium.webdriver.common.by import By + +link = "http://selenium1py.pythonanywhere.com/" + + +@pytest.fixture +def browser(): + print("\nstart browser for test..") + browser = webdriver.Chrome() + yield browser + # этот код выполнится после завершения теста + print("\nquit browser..") + browser.quit() + + +class TestMainPage1(): + # вызываем фикстуру в тесте, передав ее как параметр + def test_guest_should_see_login_link(self, browser): + browser.get(link) + browser.find_element(By.CSS_SELECTOR, "#login_link") + + def test_guest_should_see_basket_link_on_the_main_page(self, browser): + browser.get(link) + browser.find_element(By.CSS_SELECTOR, ".basket-mini .btn-group > a") diff --git a/tests/text_box_test.py b/tests/text_box_test.py index 02844ba..2c428ab 100644 --- a/tests/text_box_test.py +++ b/tests/text_box_test.py @@ -1,7 +1,9 @@ +import pytest from pages.home_page import HomePage name = "Ola" +@pytest.mark.regression def test_text_box(driver): result: str = HomePage(driver)\ .open() \