DEV Community

Cover image for The 23 syntax formats of SeleniumBase
Michael Mintz for SeleniumBase

Posted on • Edited on

The 23 syntax formats of SeleniumBase

The 23 syntax formats / design patterns

(Watch this tutorial on YouTube)


SeleniumBase currently supports 23 unique syntax formats (AKA "design patterns") for structuring tests.


Table of Contents / Navigation:


1. BaseCase direct class inheritance

This format is used by most of the examples in the SeleniumBase examples folder. It's a great starting point for anyone learning SeleniumBase, and it follows good object-oriented programming principles. In this format, BaseCase is imported at the top of a Python file, followed by a Python class inheriting BaseCase. Then, any test method defined in that class automatically gains access to SeleniumBase methods, including the setUp() and tearDown() methods that are automatically called to spin up and spin down web browsers at the beginning and end of test methods. Here's an example of that:

from seleniumbase import BaseCase

class MyTestClass(BaseCase):
    def test_demo_site(self):
        self.open("https://seleniumbase.io/demo_page")
        self.type("#myTextInput", "This is Automated")
        self.click("#myButton")
        self.assert_element("tbody#tbodyId")
        self.assert_text("Automation Practice", "h3")
        self.click_link("SeleniumBase Demo Page")
        self.assert_exact_text("Demo Page", "h1")
        self.assert_no_js_errors()
Enter fullscreen mode Exit fullscreen mode

(See examples/test_demo_site.py for the full test.)

2. BaseCase subclass inheritance

There are situations where you may want to customize the setUp and tearDown of your tests. Maybe you want to have all your tests login to a specific web site first, or maybe you want to have your tests report results through an API call depending on whether a test passed or failed. This can be done by creating a subclass of BaseCase and then carefully creating custom setUp() and tearDown() methods that don't overwrite the critical functionality of the default SeleniumBase setUp() and tearDown() methods. Afterwards, your test classes will inherit the subclass of BaseCase with the added functionality, rather than directly inheriting BaseCase itself. Here's an example of that:

from seleniumbase import BaseCase

class BaseTestCase(BaseCase):
    def setUp(self):
        super(BaseTestCase, self).setUp()
        # <<< Run custom setUp() code for tests AFTER the super().setUp() >>>

    def tearDown(self):
        self.save_teardown_screenshot()  # If test fails, or if "--screenshot"
        if self.has_exception():
            # <<< Run custom code if the test failed. >>>
            pass
        else:
            # <<< Run custom code if the test passed. >>>
            pass
        # (Wrap unreliable tearDown() code in a try/except block.)
        # <<< Run custom tearDown() code BEFORE the super().tearDown() >>>
        super(BaseTestCase, self).tearDown()

    def login(self):
        # <<< Placeholder. Add your code here. >>>
        # Reduce duplicate code in tests by having reusable methods like this.
        # If the UI changes, the fix can be applied in one place.
        pass

    def example_method(self):
        # <<< Placeholder. Add your code here. >>>
        pass

class MyTests(BaseTestCase):
    def test_example(self):
        self.login()
        self.example_method()
        self.type("input", "Name")
        self.click("form button")
        ...
Enter fullscreen mode Exit fullscreen mode

(See examples/boilerplates/base_test_case.py for more info.)

3. The "sb" pytest fixture (no class)

The pytest framework comes with a unique system called fixtures, which replaces import statements at the top of Python files by importing libraries directly into test definitions. More than just being an import, a pytest fixture can also automatically call predefined setUp() and tearDown() methods at the beginning and end of test methods. To work, sb is added as an argument to each test method definition that needs SeleniumBase functionality. This means you no longer need import statements in your Python files to use SeleniumBase. If using other pytest fixtures in your tests, you may need to use the SeleniumBase fixture (instead of BaseCase class inheritance) for compatibility reasons. Here's an example of the sb fixture in a test that does not use Python classes:

def test_sb_fixture_with_no_class(sb):
    sb.open("https://google.com/ncr")
    sb.type('[title="Search"]', 'SeleniumBase\n')
    sb.click('a[href*="github.com/seleniumbase/SeleniumBase"]')
    sb.click('a[title="seleniumbase"]')
Enter fullscreen mode Exit fullscreen mode

(See the top of examples/test_sb_fixture.py for the test.)

4. The "sb" pytest fixture (in class)

The sb pytest fixture can also be used inside of a class. There is a slight change to the syntax because that means test methods must also include self in their argument definitions when test methods are defined. (The self argument represents the class object, and is used in every test method that lives inside of a class.) Once again, no import statements are needed in your Python files for this to work. Here's an example of using the sb fixture in a test method that lives inside of a Python class:

class Test_SB_Fixture:
    def test_sb_fixture_inside_class(self, sb):
        sb.open("https://google.com/ncr")
        sb.type('[title="Search"]', 'SeleniumBase\n')
        sb.click('a[href*="github.com/seleniumbase/SeleniumBase"]')
        sb.click('a[title="examples"]')
Enter fullscreen mode Exit fullscreen mode

(See the bottom of examples/test_sb_fixture.py for the test.)

5. Page Object Model with BaseCase

With SeleniumBase, you can use Page Objects to break out code from tests, but remember, the self variable (from test methods that inherit BaseCase) contains the driver and all other framework-specific variable definitions. Therefore, that self must be passed as an arg into any outside class method in order to call SeleniumBase methods from there. In the example below, the self variable from the test method is passed into the sb arg of the Page Object class method because the self arg of the Page Object class method is already being used for its own class. Every Python class method definition must include the self as the first arg.

from seleniumbase import BaseCase

class LoginPage:
    def login_to_swag_labs(self, sb, username):
        sb.open("https://www.saucedemo.com")
        sb.type("#user-name", username)
        sb.type("#password", "secret_sauce")
        sb.click('input[type="submit"]')

class MyTests(BaseCase):
    def test_swag_labs_login(self):
        LoginPage().login_to_swag_labs(self, "standard_user")
        self.assert_element("div.inventory_list")
        self.assert_element('div:contains("Sauce Labs Backpack")')
Enter fullscreen mode Exit fullscreen mode

(See examples/boilerplates/samples/swag_labs_test.py for the full test.)

6. Page Object Model with the "sb" fixture

This is similar to the classic Page Object Model with BaseCase inheritance, except that this time we pass the sb pytest fixture from the test into the sb arg of the page object class method, (instead of passing self). Now that you're using sb as a pytest fixture, you no longer need to import BaseCase anywhere in your code. See the example below:

class LoginPage:
    def login_to_swag_labs(self, sb, username):
        sb.open("https://www.saucedemo.com")
        sb.type("#user-name", username)
        sb.type("#password", "secret_sauce")
        sb.click('input[type="submit"]')

class MyTests:
    def test_swag_labs_login(self, sb):
        LoginPage().login_to_swag_labs(sb, "standard_user")
        sb.assert_element("div.inventory_list")
        sb.assert_element('div:contains("Sauce Labs Backpack")')
Enter fullscreen mode Exit fullscreen mode

(See examples/boilerplates/samples/sb_swag_test.py for the full test.)

7. Using "request" to get "sb" (no class)

The pytest request fixture can be used to retrieve other pytest fixtures from within tests, such as the sb fixture. This allows you to have more control over when fixtures get initialized because the fixture no longer needs to be loaded at the very beginning of test methods. This is done by calling request.getfixturevalue('sb') from the test. Here's an example of using the pytest request fixture to load the sb fixture in a test method that does not use Python classes:

def test_request_sb_fixture(request):
    sb = request.getfixturevalue('sb')
    sb.open("https://seleniumbase.io/demo_page")
    sb.assert_text("SeleniumBase", "#myForm h2")
    sb.assert_element("input#myTextInput")
    sb.type("#myTextarea", "This is me")
    sb.click("#myButton")
    sb.tearDown()
Enter fullscreen mode Exit fullscreen mode

(See the top of examples/test_request_sb_fixture.py for the test.)

8. Using "request" to get "sb" (in class)

The pytest request fixture can also be used to get the sb fixture from inside a Python class. Here's an example of that:

class Test_Request_Fixture:
    def test_request_sb_fixture_in_class(self, request):
        sb = request.getfixturevalue('sb')
        sb.open("https://seleniumbase.io/demo_page")
        sb.assert_element("input#myTextInput")
        sb.type("#myTextarea", "Automated")
        sb.assert_text("This Text is Green", "#pText")
        sb.click("#myButton")
        sb.assert_text("This Text is Purple", "#pText")
        sb.tearDown()
Enter fullscreen mode Exit fullscreen mode

(See the bottom of examples/test_request_sb_fixture.py for the test.)

9. Overriding the driver via BaseCase

When you want to use SeleniumBase methods via BaseCase, but you want total freedom to control how you spin up your web browsers, this is the format you want. Although SeleniumBase gives you plenty of command-line options to change how your browsers are launched, this format gives you more control when the existing options aren't enough. Here's an example of that:

from selenium import webdriver
from seleniumbase import BaseCase

class OverrideDriverTest(BaseCase):
    def get_new_driver(self, *args, **kwargs):
        """This method overrides get_new_driver() from BaseCase."""
        options = webdriver.ChromeOptions()
        options.add_argument("--disable-3d-apis")
        options.add_argument("--disable-notifications")
        if self.headless:
            options.add_argument("--headless")
            options.add_argument("--disable-gpu")
        options.add_experimental_option(
            "excludeSwitches", ["enable-automation", "enable-logging"],
        )
        prefs = {
            "credentials_enable_service": False,
            "profile.password_manager_enabled": False,
        }
        options.add_experimental_option("prefs", prefs)
        return webdriver.Chrome(options=options)

    def test_simple(self):
        self.open("https://seleniumbase.io/demo_page")
        self.assert_text("Demo Page", "h1")
Enter fullscreen mode Exit fullscreen mode

(From examples/test_override_driver.py)

The above format can let you use selenium-wire to intercept & inspect requests and responses during SeleniumBase tests. Here's how the selenium-wire integration may look:

from seleniumbase import BaseCase
from seleniumwire import webdriver  # Requires "pip install selenium-wire"


class WireTestCase(BaseCase):
    def get_new_driver(self, *args, **kwargs):
        options = webdriver.ChromeOptions()
        options.add_experimental_option(
            "excludeSwitches", ["enable-automation"]
        )
        options.add_experimental_option("useAutomationExtension", False)
        return webdriver.Chrome(options=options)

    def test_simple(self):
        self.open("https://seleniumbase.io/demo_page")
        for request in self.driver.requests:
            print(request.url)
Enter fullscreen mode Exit fullscreen mode

10. Overriding the driver via "sb" fixture

When you want to use SeleniumBase methods via the sb pytest fixture, but you want total freedom to control how you spin up your web browsers, this is the format you want. Although SeleniumBase gives you plenty of command-line options to change how your browsers are launched, this format gives you more control when the existing options aren't enough.

"""Overriding the "sb" fixture to override the driver."""
import pytest

@pytest.fixture()
def sb(request):
    from selenium import webdriver
    from seleniumbase import BaseCase
    from seleniumbase import config as sb_config

    class BaseClass(BaseCase):
        def get_new_driver(self, *args, **kwargs):
            """This method overrides get_new_driver() from BaseCase."""
            options = webdriver.ChromeOptions()
            if self.headless:
                options.add_argument("--headless=new")
                options.add_argument("--disable-gpu")
            options.add_experimental_option(
                "excludeSwitches", ["enable-automation"],
            )
            return webdriver.Chrome(options=options)

        def setUp(self):
            super().setUp()

        def base_method(self):
            pass

        def tearDown(self):
            self.save_teardown_screenshot()  # On failure or "--screenshot"
            super().tearDown()

    if request.cls:
        request.cls.sb = BaseClass("base_method")
        request.cls.sb.setUp()
        request.cls.sb._needs_tearDown = True
        request.cls.sb._using_sb_fixture = True
        request.cls.sb._using_sb_fixture_class = True
        sb_config._sb_node[request.node.nodeid] = request.cls.sb
        yield request.cls.sb
        if request.cls.sb._needs_tearDown:
            request.cls.sb.tearDown()
            request.cls.sb._needs_tearDown = False
    else:
        sb = BaseClass("base_method")
        sb.setUp()
        sb._needs_tearDown = True
        sb._using_sb_fixture = True
        sb._using_sb_fixture_no_class = True
        sb_config._sb_node[request.node.nodeid] = sb
        yield sb
        if sb._needs_tearDown:
            sb.tearDown()
            sb._needs_tearDown = False

def test_override_fixture_no_class(sb):
    sb.open("https://seleniumbase.io/demo_page")
    sb.type("#myTextInput", "This is Automated")

class TestOverride:
    def test_override_fixture_inside_class(self, sb):
        sb.open("https://seleniumbase.io/demo_page")
        sb.type("#myTextInput", "This is Automated")
Enter fullscreen mode Exit fullscreen mode

(From examples/test_override_sb_fixture.py)

Here's how the selenium-wire integration may look when overriding the sb pytest fixture to override the driver:

import pytest

@pytest.fixture()
def sb(request):
    import sys
    from seleniumbase import BaseCase
    from seleniumbase import config as sb_config
    from seleniumwire import webdriver  # Requires "pip install selenium-wire"

    class BaseClass(BaseCase):
        def get_new_driver(self, *args, **kwargs):
            options = webdriver.ChromeOptions()
            if "linux" in sys.platform:
                options.add_argument("--headless=new")
            options.add_experimental_option(
                "excludeSwitches", ["enable-automation"],
            )
            return webdriver.Chrome(options=options)

        def setUp(self):
            super().setUp()

        def tearDown(self):
            self.save_teardown_screenshot()  # On failure or "--screenshot"
            super().tearDown()

        def base_method(self):
            pass

    if request.cls:
        request.cls.sb = BaseClass("base_method")
        request.cls.sb.setUp()
        request.cls.sb._needs_tearDown = True
        request.cls.sb._using_sb_fixture = True
        request.cls.sb._using_sb_fixture_class = True
        sb_config._sb_node[request.node.nodeid] = request.cls.sb
        yield request.cls.sb
        if request.cls.sb._needs_tearDown:
            request.cls.sb.tearDown()
            request.cls.sb._needs_tearDown = False
    else:
        sb = BaseClass("base_method")
        sb.setUp()
        sb._needs_tearDown = True
        sb._using_sb_fixture = True
        sb._using_sb_fixture_no_class = True
        sb_config._sb_node[request.node.nodeid] = sb
        yield sb
        if sb._needs_tearDown:
            sb.tearDown()
            sb._needs_tearDown = False

def test_wire_with_no_class(sb):
    sb.open("https://seleniumbase.io/demo_page")
    for request in sb.driver.requests:
        print(request.url)

class TestWire:
    def test_wire_inside_class(self, sb):
        sb.open("https://seleniumbase.io/demo_page")
        for request in sb.driver.requests:
            print(request.url)
Enter fullscreen mode Exit fullscreen mode

11. BaseCase with Chinese translations

This format is similar to the English version with BaseCase inheritance, but there's a different import statement, and method names have been translated into Chinese. Here's an example of that:

from seleniumbase.translate.chinese import 硒测试用例

class 我的测试类(硒测试用例):
    def test_例子1(self):
        self.开启("https://zh.wikipedia.org/wiki/")
        self.断言标题("维基百科,自由的百科全书")
        self.断言元素('a[title="Wikipedia:关于"]')
        self.断言文本("新闻动态", "span#新闻动态")
        self.输入文本('input[name="search"]', "舞龍")
        self.单击('button:contains("搜索")')
        self.断言文本("舞龍", "#firstHeading")
        self.断言元素('img[src*="Chinese_draak.jpg"]')
        self.回去()
        self.输入文本('input[name="search"]', "麻婆豆腐")
        self.单击('button:contains("搜索")')
        self.断言文本("麻婆豆腐", "#firstHeading")
        self.断言元素('figure:contains("一家中餐館的麻婆豆腐")')
        self.回去()
        self.输入文本('input[name="search"]', "精武英雄")
        self.单击('button:contains("搜索")')
        self.断言元素('img[src*="Fist_of_legend.jpg"]')
        self.断言文本("李连杰", 'li a[title="李连杰"]')
Enter fullscreen mode Exit fullscreen mode

(See examples/translations/chinese_test_1.py for the Chinese test.)

12. BaseCase with Dutch translations

This format is similar to the English version with BaseCase inheritance, but there's a different import statement, and method names have been translated into Dutch. Here's an example of that:

from seleniumbase.translate.dutch import Testgeval

class MijnTestklasse(Testgeval):
    def test_voorbeeld_1(self):
        self.openen("https://nl.wikipedia.org/wiki/Hoofdpagina")
        self.controleren_element('a[title*="hoofdpagina gaan"]')
        self.controleren_tekst("Welkom op Wikipedia", "td.hp-welkom")
        self.typ("#searchInput", "Stroopwafel")
        self.klik("#searchButton")
        self.controleren_tekst("Stroopwafel", "#firstHeading")
        self.controleren_element('img[src*="Stroopwafels"]')
        self.typ("#searchInput", "Rijksmuseum Amsterdam")
        self.klik("#searchButton")
        self.controleren_tekst("Rijksmuseum", "#firstHeading")
        self.controleren_element('img[src*="Rijksmuseum"]')
        self.terug()
        self.controleren_url_bevat("Stroopwafel")
        self.vooruit()
        self.controleren_url_bevat("Rijksmuseum")
Enter fullscreen mode Exit fullscreen mode

(See examples/translations/dutch_test_1.py for the Dutch test.)

13. BaseCase with French translations

This format is similar to the English version with BaseCase inheritance, but there's a different import statement, and method names have been translated into French. Here's an example of that:

from seleniumbase.translate.french import CasDeBase

class MaClasseDeTest(CasDeBase):
    def test_exemple_1(self):
        self.ouvrir("https://fr.wikipedia.org/wiki/")
        self.vérifier_texte("Wikipédia")
        self.vérifier_élément('[alt="Wikipédia"]')
        self.js_taper("#searchform input", "Crème brûlée")
        self.cliquer("#searchform button")
        self.vérifier_texte("Crème brûlée", "#firstHeading")
        self.vérifier_élément('img[alt*="Crème brûlée"]')
        self.js_taper("#searchform input", "Jardin des Tuileries")
        self.cliquer("#searchform button")
        self.vérifier_texte("Jardin des Tuileries", "#firstHeading")
        self.vérifier_élément('img[alt*="Jardin des Tuileries"]')
        self.retour()
        self.vérifier_url_contient("brûlée")
        self.en_avant()
        self.vérifier_url_contient("Jardin")
Enter fullscreen mode Exit fullscreen mode

(See examples/translations/french_test_1.py for the French test.)

14. BaseCase with Italian translations

This format is similar to the English version with BaseCase inheritance, but there's a different import statement, and method names have been translated into Italian. Here's an example of that:

from seleniumbase.translate.italian import CasoDiProva

class MiaClasseDiTest(CasoDiProva):
    def test_esempio_1(self):
        self.apri("https://it.wikipedia.org/wiki/")
        self.verificare_testo("Wikipedia")
        self.verificare_elemento('a[title="Lingua italiana"]')
        self.digitare("#searchInput", "Pizza")
        self.fare_clic("#searchButton")
        self.verificare_testo("Pizza", "#firstHeading")
        self.verificare_elemento('figure img[src*="pizza"]')
        self.digitare("#searchInput", "Colosseo")
        self.fare_clic("#searchButton")
        self.verificare_testo("Colosseo", "#firstHeading")
        self.verificare_elemento('figure img[src*="Colosseo"]')
        self.indietro()
        self.verificare_url_contiene("Pizza")
        self.avanti()
        self.verificare_url_contiene("Colosseo")
Enter fullscreen mode Exit fullscreen mode

(See examples/translations/italian_test_1.py for the Italian test.)

15. BaseCase with Japanese translations

This format is similar to the English version with BaseCase inheritance, but there's a different import statement, and method names have been translated into Japanese. Here's an example of that:

from seleniumbase.translate.japanese import セレニウムテストケース

class 私のテストクラス(セレニウムテストケース):
    def test_例1(self):
        self.を開く("https://ja.wikipedia.org/wiki/")
        self.テキストを確認する("ウィキペディア")
        self.要素を確認する('[title*="ウィキペディアへようこそ"]')
        self.JS入力('input[name="search"]', "アニメ")
        self.クリックして("#searchform button")
        self.テキストを確認する("アニメ", "#firstHeading")
        self.JS入力('input[name="search"]', "寿司")
        self.クリックして("#searchform button")
        self.テキストを確認する("寿司", "#firstHeading")
        self.要素を確認する('img[alt="握り寿司"]')
        self.JS入力("#searchInput", "レゴランド・ジャパン")
        self.クリックして("#searchform button")
        self.要素を確認する('img[src*="LEGOLAND_JAPAN"]')
        self.リンクテキストを確認する("名古屋城")
        self.リンクテキストをクリックします("テーマパーク")
        self.テキストを確認する("テーマパーク", "#firstHeading")
Enter fullscreen mode Exit fullscreen mode

(See examples/translations/japanese_test_1.py for the Japanese test.)

16. BaseCase with Korean translations

This format is similar to the English version with BaseCase inheritance, but there's a different import statement, and method names have been translated into Korean. Here's an example of that:

from seleniumbase.translate.korean import 셀레늄_테스트_케이스

class 테스트_클래스(셀레늄_테스트_케이스):
    def test_실시예_1(self):
        self.열기("https://ko.wikipedia.org/wiki/")
        self.텍스트_확인("위키백과")
        self.요소_확인('[title="위키백과:소개"]')
        self.JS_입력("#searchform input", "김치")
        self.클릭("#searchform button")
        self.텍스트_확인("김치", "#firstHeading")
        self.요소_확인('img[src*="Various_kimchi.jpg"]')
        self.링크_텍스트_확인("한국 요리")
        self.JS_입력("#searchform input", "비빔밥")
        self.클릭("#searchform button")
        self.텍스트_확인("비빔밥", "#firstHeading")
        self.요소_확인('img[src*="Dolsot-bibimbap.jpg"]')
        self.링크_텍스트를_클릭합니다("돌솥비빔밥")
        self.텍스트_확인("돌솥비빔밥", "#firstHeading")
Enter fullscreen mode Exit fullscreen mode

(See examples/translations/korean_test_1.py for the Korean test.)

17. BaseCase with Portuguese translations

This format is similar to the English version with BaseCase inheritance, but there's a different import statement, and method names have been translated into Portuguese. Here's an example of that:

from seleniumbase.translate.portuguese import CasoDeTeste

class MinhaClasseDeTeste(CasoDeTeste):
    def test_exemplo_1(self):
        self.abrir("https://pt.wikipedia.org/wiki/")
        self.verificar_texto("Wikipédia")
        self.verificar_elemento('[title="Língua portuguesa"]')
        self.digitar("#searchform input", "João Pessoa")
        self.clique("#searchform button")
        self.verificar_texto("João Pessoa", "#firstHeading")
        self.verificar_elemento('img[alt*="João Pessoa"]')
        self.digitar("#searchform input", "Florianópolis")
        self.clique("#searchform button")
        self.verificar_texto("Florianópolis", "h1#firstHeading")
        self.verificar_elemento('td:contains("Avenida Beira-Mar")')
        self.voltar()
        self.verificar_url_contém("João_Pessoa")
        self.atualizar_a_página()
        self.js_digitar("#searchform input", "Teatro Amazonas")
        self.clique("#searchform button")
        self.verificar_texto("Teatro Amazonas", "#firstHeading")
        self.verificar_texto_do_link("Festival Amazonas de Ópera")
Enter fullscreen mode Exit fullscreen mode

(See examples/translations/portuguese_test_1.py for the Portuguese test.)

18. BaseCase with Russian translations

This format is similar to the English version with BaseCase inheritance, but there's a different import statement, and method names have been translated into Russian. Here's an example of that:

from seleniumbase.translate.russian import ТестНаСелен

class МойТестовыйКласс(ТестНаСелен):
    def test_пример_1(self):
        self.открыть("https://ru.wikipedia.org/wiki/")
        self.подтвердить_элемент('[title="Русский язык"]')
        self.подтвердить_текст("Википедия", "h2.main-wikimedia-header")
        self.введите("#searchInput", "МГУ")
        self.нажмите("#searchButton")
        self.подтвердить_текст("университет", "#firstHeading")
        self.подтвердить_элемент('img[alt*="Главное здание МГУ"]')
        self.введите("#searchInput", "приключения Шурика")
        self.нажмите("#searchButton")
        self.подтвердить_текст("Операция «Ы» и другие приключения Шурика")
        self.подтвердить_элемент('img[alt="Постер фильма"]')
        self.назад()
        self.подтвердить_URL_содержит("университет")
        self.вперед()
        self.подтвердить_URL_содержит("Шурика")
Enter fullscreen mode Exit fullscreen mode

(See examples/translations/russian_test_1.py for the Russian test.)

19. BaseCase with Spanish translations

This format is similar to the English version with BaseCase inheritance, but there's a different import statement, and method names have been translated into Spanish. Here's an example of that:

from seleniumbase.translate.spanish import CasoDePrueba

class MiClaseDePrueba(CasoDePrueba):
    def test_ejemplo_1(self):
        self.abrir("https://es.wikipedia.org/wiki/")
        self.verificar_texto("Wikipedia")
        self.verificar_elemento('[title="Wikipedia:Bienvenidos"]')
        self.escriba('[name="search"]', "Parque de Atracciones Tibidabo")
        self.haga_clic('button:contains("Buscar")')
        self.verificar_texto("Tibidabo", "#firstHeading")
        self.verificar_elemento('img[src*="Tibidabo"]')
        self.escriba('input[name="search"]', "Palma de Mallorca")
        self.haga_clic('button:contains("Buscar")')
        self.verificar_texto("Palma de Mallorca", "#firstHeading")
        self.verificar_elemento('img[src*="Palma"]')
        self.volver()
        self.verificar_url_contiene("Tibidabo")
        self.adelante()
        self.verificar_url_contiene("Mallorca")
Enter fullscreen mode Exit fullscreen mode

(See examples/translations/spanish_test_1.py for the Spanish test.)

20. Gherkin syntax with "behave" BDD runner

With Behave's BDD Gherkin format, you can use natural language to write tests that work with SeleniumBase methods. Behave tests are run by calling behave on the command-line. This requires some special files in a specific directory structure. Here's an example of that structure:

features/
├── __init__.py
├── behave.ini
├── environment.py
├── feature_file.feature
└── steps/
    ├── __init__.py
    ├── imported.py
    └── step_file.py
Enter fullscreen mode Exit fullscreen mode

A *.feature file might look like this:

Feature: SeleniumBase scenarios for the RealWorld App

  Scenario: Verify RealWorld App (log in / sign out)
    Given Open "seleniumbase.io/realworld/login"
    And Clear Session Storage
    When Type "demo_user" into "#username"
    And Type "secret_pass" into "#password"
    And Do MFA "GAXG2MTEOR3DMMDG" into "#totpcode"
    Then Assert exact text "Welcome!" in "h1"
    And Highlight "img#image1"
    And Click 'a:contains("This Page")'
    And Save screenshot to logs
    When Click link "Sign out"
    Then Assert element 'a:contains("Sign in")'
    And Assert text "You have been signed out!"
Enter fullscreen mode Exit fullscreen mode

(From examples/behave_bdd/features/realworld.feature)

You'll need the environment.py file for tests to work. Here it is:

from seleniumbase import BaseCase
from seleniumbase.behave import behave_sb
behave_sb.set_base_class(BaseCase)  # Accepts a BaseCase subclass
from seleniumbase.behave.behave_sb import before_all  # noqa
from seleniumbase.behave.behave_sb import before_feature  # noqa
from seleniumbase.behave.behave_sb import before_scenario  # noqa
from seleniumbase.behave.behave_sb import before_step  # noqa
from seleniumbase.behave.behave_sb import after_step  # noqa
from seleniumbase.behave.behave_sb import after_scenario  # noqa
from seleniumbase.behave.behave_sb import after_feature  # noqa
from seleniumbase.behave.behave_sb import after_all  # noqa
Enter fullscreen mode Exit fullscreen mode

(From examples/behave_bdd/features/environment.py)

Inside that file, you can use BaseCase (or a subclass) for the inherited class.

For your behave tests to have access to SeleniumBase Behave steps, you can create an imported.py file with the following line:

from seleniumbase.behave import steps  # noqa
Enter fullscreen mode Exit fullscreen mode

That will allow you to use lines like this in your *.feature files:

Feature: SeleniumBase scenarios for the RealWorld App

  Scenario: Verify RealWorld App (log in / sign out)
    Given Open "seleniumbase.io/realworld/login"
    And Clear Session Storage
    When Type "demo_user" into "#username"
    And Type "secret_pass" into "#password"
    And Do MFA "GAXG2MTEOR3DMMDG" into "#totpcode"
    Then Assert exact text "Welcome!" in "h1"
    And Highlight "img#image1"
    And Click 'a:contains("This Page")'
    And Save screenshot to logs
Enter fullscreen mode Exit fullscreen mode

You can also create your own step files (Eg. step_file.py):

from behave import step

@step("Open the Swag Labs Login Page")
def go_to_swag_labs(context):
    sb = context.sb
    sb.open("https://www.saucedemo.com")
    sb.clear_local_storage()

@step("Login to Swag Labs with {user}")
def login_to_swag_labs(context, user):
    sb = context.sb
    sb.type("#user-name", user)
    sb.type("#password", "secret_sauce\n")
Enter fullscreen mode Exit fullscreen mode

(For more information, see the SeleniumBase Behave BDD ReadMe.)

21. SeleniumBase SB (Python context manager)

This format provides a pure Python way of using SeleniumBase without a test runner. Options can be passed via method instantiation or from the command-line. When setting the test option to True (or calling python --test), then standard test logging will occur, such as screenshots and reports for failing tests. All the usual SeleniumBase options are available, such as customizing the browser settings, etc. Here are some examples:

from seleniumbase import SB

with SB() as sb:  # By default, browser="chrome" if not set.
    sb.open("https://seleniumbase.github.io/realworld/login")
    sb.type("#username", "demo_user")
    sb.type("#password", "secret_pass")
    sb.enter_mfa_code("#totpcode", "GAXG2MTEOR3DMMDG")  # 6-digit
    sb.assert_text("Welcome!", "h1")
    sb.highlight("img#image1")  # A fancier assert_element() call
    sb.click('a:contains("This Page")')  # Use :contains() on any tag
    sb.click_link("Sign out")  # Link must be "a" tag. Not "button".
    sb.assert_element('a:contains("Sign in")')
    sb.assert_exact_text("You have been signed out!", "#top_message")
Enter fullscreen mode Exit fullscreen mode

(See examples/raw_sb.py for the test.)

Here's another example, which uses test mode:

from seleniumbase import SB

with SB(test=True) as sb:
    sb.open("https://google.com/ncr")
    sb.type('[name="q"]', "SeleniumBase on GitHub\n")
    sb.click('a[href*="github.com/seleniumbase"]')
    sb.highlight("div.Layout-main")
    sb.highlight("div.Layout-sidebar")
    sb.sleep(0.5)

with SB(test=True, rtf=True, demo=True) as sb:
    sb.open("seleniumbase.github.io/demo_page")
    sb.type("#myTextInput", "This is Automated")
    sb.assert_text("This is Automated", "#myTextInput")
    sb.assert_text("This Text is Green", "#pText")
    sb.click('button:contains("Click Me")')
    sb.assert_text("This Text is Purple", "#pText")
    sb.click("#checkBox1")
    sb.assert_element_not_visible("div#drop2 img#logo")
    sb.drag_and_drop("img#logo", "div#drop2")
    sb.assert_element("div#drop2 img#logo")
Enter fullscreen mode Exit fullscreen mode

(See examples/raw_test_scripts.py for the test.)

22. The driver manager (via context manager)

This pure Python format gives you a raw webdriver instance in a with block. The SeleniumBase Driver Manager will automatically make sure that your driver is compatible with your browser version. It gives you full access to customize driver options via method args or via the command-line. The driver will automatically call quit() after the code leaves the with block. Here are some examples:

"""Can run with "python". (pytest not needed)."""
from seleniumbase import DriverContext

with DriverContext() as driver:
    driver.get("https://seleniumbase.github.io/")
    driver.highlight('img[alt="SeleniumBase"]', loops=6)

with DriverContext(browser="chrome", incognito=True) as driver:
    driver.get("https://seleniumbase.io/apps/calculator")
    driver.click('[id="4"]')
    driver.click('[id="2"]')
    driver.assert_text("42", "#output")
    driver.highlight("#output", loops=6)

with DriverContext() as driver:
    driver.get("https://seleniumbase.github.io/demo_page")
    driver.highlight("h2")
    driver.type("#myTextInput", "Automation")
    driver.click("#checkBox1")
    driver.highlight("img", loops=6)
Enter fullscreen mode Exit fullscreen mode

(See examples/raw_driver_context.py for an example.)

23. The driver manager (via direct import)

Another way of running Selenium tests with pure python (as opposed to using pytest or nosetests) is by using this format, which bypasses BaseCase methods while still giving you a flexible driver with a manager. SeleniumBase includes helper files such as page_actions.py, which may help you get around some of the limitations of bypassing BaseCase. Here's an example:

"""Driver() test. Runs with "python". (pytest not needed)."""
from seleniumbase import Driver

driver = Driver(browser="chrome", headless=False)
try:
    driver.get("https://seleniumbase.io/apps/calculator")
    driver.click('[id="4"]')
    driver.click('[id="2"]')
    driver.assert_text("42", "#output")
    driver.highlight("#output", loops=6)
finally:
    driver.quit()

driver = Driver()
try:
    driver.get("https://seleniumbase.github.io/demo_page")
    driver.highlight("h2")
    driver.type("#myTextInput", "Automation")
    driver.click("#checkBox1")
    driver.highlight("img", loops=6)
finally:
    driver.quit()
Enter fullscreen mode Exit fullscreen mode

(From examples/raw_browser_launcher.py)

The above format can be used as a drop-in replacement for virtually every Python/selenium framework, as it uses the raw driver instance for handling commands. The Driver() method simplifies the work of managing drivers with optimal settings, and it can be configured via multiple method args. The Driver also accepts command-line options (such as python --headless) so that you don't need to modify your tests directly to use different settings. These command-line options only take effect if the associated method args remain unset (or set to None) for the specified options.


Top comments (0)