Example structure of the test framework is following: every test class is one big E2E scenario, e.g. test product purchase, and every test method in it should be a step of this scenario with it's own asserts, e.g. log in -> add product -> fill checkout data -> make purchase. So i want to provide browser instance for a given class and then create single page to use it, but i have a problem to handle it across test methods
here is browser fixture from conftest.py
:
@pytest.fixture(scope="class")
def browser(request):
with sync_playwright() as playwright:
browser = playwright.firefox.launch()
yield browser
browser.close()
here is example test class:
@pytest.mark.usefixtures("browser")
class TestCart:
#load_test_data is fixture that provide some data from input setup file
@pytest.fixture(autouse=True)
def setup_data(self, load_test_data, browser: Browser):
self.base_url = load_test_data['base_url']
self.standard_user_data = load_test_data['test_users']['standard']
self.page = browser.new_page()
def test_login(self):
self.page.goto(self.base_url)
self.page.locator("#user-name").fill(self.standard_user_data['username'])
self.page.locator("#password").fill(self.standard_user_data['password'])
self.page.locator("#login-button").click()
expect(self.page.locator("#header_container")).to_be_visible()
def test_add_product(self):
self.page.locator('.shopping_cart_link').click()
expect(self.page.locator("#continue-shopping")).to_be_visible()
Once test_login
is finished, new empty browser with empty page starts for the test_add_product
execution, while old one left hanging on the background.
I can't fgure out, why it starts new browser and new page instead of using one that is created in setup_data
? Is it mismatched/missing scope of fixtures somewhere or the whole setup to be redone? What is the best solution for such flows? Thanks.
Don't create a fixture in the class. Set up the page base URL and the test data outside. Also, I would recommend creating a proxy fixture with the function scope to reset the page state after each test to make them more independent.
import pytest
@pytest.fixture(scope="class")
def fix_cls():
data = []
assert len(data) == 0
yield data
assert len(data) == 3
@pytest.fixture(scope="function")
def fix_func(fix_cls):
# reset the data, reload the page
yield fix_cls
print('------>', fix_cls)
class TestCls:
def test_a1(self, fix_func):
fix_func.append(1)
def test_a2(self, fix_func):
fix_func.append(2)
def test_a3(self, fix_func):
fix_func.append(3)
If the tests must be sequential (even if it is not recommended), use the following advice:
pytest-ordering
Plugin+