5

Background:

I'm using py.test together with pytest-selenium, now I would like to take a screenshot of page when assertion fails.

Currently I have defined small helper method in my base page object class:

class PageBase(object):
    def __init__(self,driver):
        self.driver = driver
        self.fake = Factory.create()

    def screenshot(self,name):
        self.driver.save_screenshot(datetime.now().strftime('%Y-%m-%d %H:%M:%S') + 'scr_'+name+'.png')

    @contextmanager
    def wait_for_page_load(self, timeout=45):
        old_page = self.driver.find_element_by_tag_name('html')
        yield
        WebDriverWait(self.driver, timeout).until(
            EC.staleness_of(old_page)
        )

The problem is that I would like to make it automated mechanism instead of "manual" usage: (test class example):

class TestLogin:
    @allure.feature('Ability to login into admin panel')
    def test_admin_login(self, prepare, page):

        print URLMap.admin('test')
        driver = prepare
        driver.get(URLMap.admin(page))

        login_page = LoginPage(driver)
        assert login_page.is_page_correct(),'Login page not loaded correctly'

        login_page.fill_login_data('testadmin','testadmin')
        login_page.click_login_button()
        assert login_page.is_user_logged_in(),'User cannot log in with provided credentials'
        login_page.screenshot(page+'_logged_in')

How to run certain method for every assertion failure?

Ilja Everilä
  • 50,538
  • 7
  • 126
  • 127
stawek
  • 257
  • 2
  • 5
  • 13
  • You could look into the hooks exposed for plugins: https://pytest.org/latest/writing_plugins.html – jonrsharpe May 20 '16 at 07:50
  • What you need is an @AfterMethod. In this method you can check if your test failed or not and make a screenshot accordingly. – RemcoW May 20 '16 at 09:41

3 Answers3

0

I personally haven't used but this might be your solution: https://pytest.org/latest/example/simple.html#writing-well-integrated-assertion-helpers

Also this could help: https://pytest.org/latest/assert.html#advanced-assertion-introspection

Dmitry Tokarev
  • 1,851
  • 15
  • 29
0

You have to use hooks. https://docs.pytest.org/en/latest/example/simple.html#post-process-test-reports-failures

@pytest.hookimpl(hookwrapper=True, tryfirst=True)
def pytest_runtest_makereport(item, call):
    outcome = yield
    rep = outcome.get_result()
    setattr(item, "rep_" + rep.when, rep)
    return rep

@pytest.fixture(autouse=True, scope='session')
def driver(platform, request):
    """ some driver setup code """
    yield driver

    if request.node.rep_call.failed:
        try:
            driver.get_screenshot_as_png()
        except:
            pass

    driver.quit()

And if you want to attach a screenshot to allure report, simply do:

@pytest.fixture(autouse=True, scope='session')
def driver(platform, request):
    """ some driver setup code """
    yield driver

    if request.node.rep_call.failed:
        # Make the screen-shot if test failed:
        try:
            allure.attach(
                driver.get_screenshot_as_png(),
                name=request.function.__name__,
                attachment_type=allure.attachment_type.PNG)
        except: 
            """ do something """

        driver.quit()
bvrch
  • 53
  • 5
  • I don't think you need the hook to notify the fixture that the test failed. You can use `request.session.testsfailed`. See https://stackoverflow.com/a/53274402/733092. – Noumenon Oct 27 '19 at 15:14
-1

I think that screenShotInSelenium page should give you enough information regarding how you create a screenshot when an assert condition is met.

What you are missing is the use of @AfterMethod

sorin
  • 161,544
  • 178
  • 535
  • 806