Git Product home page Git Product logo

Comments (24)

ndelon avatar ndelon commented on June 7, 2024

Hello,

Well, there is no special here except using the selenium API to "capture a screenshot when a check fails or error occurs" (it totally depends on what you are doing in your tests) and then saving this screenshot using the attachment logging functions (see http://docs.lemoncheesecake.io/en/latest/logging.html#attachments).

Regards.

from lemoncheesecake.

anarang avatar anarang commented on June 7, 2024

okay, thank you for your answer. I was looking for something like: a global block of code which says that if a failure occurs at any step perform a 'capture screenshot'. So, Protractor offers something like this so I thought if lcc had it too from the setup or teardown methods in some way.

from lemoncheesecake.

ndelon avatar ndelon commented on June 7, 2024

Ok, I understand that you're looking for a kind of exception handler global to the test.
So no, there is no such things in lemoncheesecake, but you could implement something on your own using a context manager or a decorator for instance.

from lemoncheesecake.

anarang avatar anarang commented on June 7, 2024

okay, thanks for the pointer there. Let me know if you have a link to refer or I 'll try to figure it out if I can. Thanks. :)

from lemoncheesecake.

ndelon avatar ndelon commented on June 7, 2024

I think you will find plenty of online resources about context managers and decorators.
The idea is to use them to wrap your test, catch a given (selenium) exception, take a screenshot and save it.

from lemoncheesecake.

anarang avatar anarang commented on June 7, 2024

sure, will find that out. thanks for sharing the information. :)

from lemoncheesecake.

ndelon avatar ndelon commented on June 7, 2024

@anarang I just remembered the existence of the teardown_test hook: http://docs.lemoncheesecake.io/en/latest/setup-and-teardown-suites.html.
It works this way:

@lcc.suite("MySuite")
class mysuite:
    [...]
    def teardown_test(self, test, status):
        [...]

You won't be able to get the possible exception that has been raised within your test but you will be able to get the test's status (passed or failed) and to make and log a screenshot upon failure.

from lemoncheesecake.

anarang avatar anarang commented on June 7, 2024

thank you for the headsup here.I will give that a try and see if it works, but with this I think this will need to be included in every suite.

from lemoncheesecake.

ndelon avatar ndelon commented on June 7, 2024

If you are implementing suites as classes, you can:

  • implement a base class that does the teardown_test
  • inherit this base class in your suite classes

from lemoncheesecake.

anarang avatar anarang commented on June 7, 2024

well, I am not implement suites as classes but using the SUITE variable to define a suite.

from lemoncheesecake.

ndelon avatar ndelon commented on June 7, 2024

Then, you can implement your teardown_test function in some shared module and then simply import it in your various suite modules.

from lemoncheesecake.

anarang avatar anarang commented on June 7, 2024

Do you mean something like this:
suites/ - shared_test.py -> this will have only the test_teardown method
and then import shared_test.py in other modules at the same level.

from lemoncheesecake.

ndelon avatar ndelon commented on June 7, 2024

Not something in the "suites" directory because it will be interpreted as a suite, which is not.
And import the function itself (from something import test_teardown), not the module itself, otherwise the test_teardown won't be visible in the suite's module namespace.

from lemoncheesecake.

anarang avatar anarang commented on June 7, 2024

Hi @ndelon , thanks for the suggestion. The test_teardown is working as expected when imported, but it is unable to access the driver object and use the driver.get_screenshot_as_file. Below is a layout of how I use and initialise the webdriver object.

 fixtures/fixture.py
@lcc.fixture(names=("driver", "driver_obj"), scope="session")
def setup():
    lcc.log_info("Initialising the webdriver object, opening the browser...")
    # Initialise the global webdriver, open the browser and maximise the
    # browser window
    driver = webdriver.Chrome(ChromeDriverManager(path=os.environ['PYTHONPATH']).install())
        logging.info("Chrome driver has been initialised successfully")
    driver.maximize_window()
    driver.implicitly_wait(15)
    driver.get(url)
 
    # the global driver object can be used globally in the tests.
    yield driver

driver.close()
    driver.quit()

helpers/capture_screenshot.py

import lemoncheesecake.api as lcc
def teardown_test(test, status):
    lcc.log_info(test.name)
    lcc.log_info(status)
    if status == "passed":
        lcc.log_info("no failure")
    else:
        lcc.log_info("status was: failed")
        driver.get_screenshot_as_file("s1.png")
        lcc.log_info("saved screenshot")
        lcc.save_attachment_file("s1.png")

suites/test1.py

from helpers.capture_screenshot import teardown_test
SUITE = {
    "description": "Create a new test"
}

@lcc.test('test description')
--> the fixture "driver" is being called in every test in each suite to use the same driver object.
def create_test_test(driver):
    #perform tests
    check_that("test","a", equal_to("b"))
    check_that("test", "a", equal_to("a"))

--> But the error I see: NameError: name 'driver' is not defined    

I even tried :

def teardown_test(test, status, driver):
but that is unacceptable too.

The tear down test works correctly after each test in the suite but it is giving the error: name 'driver' is not defined. I tried it without the driver.screenshot and it worked well. Let me know if you didn't get my question.
I am unable to figure out how to use the fixture which initiates the driver object for this teardown_test.
Thanks, looking forward to your expert advice. :)

from lemoncheesecake.

ndelon avatar ndelon commented on June 7, 2024

Hello,

That's normal:

  1. you can't access a fixture from anywhere in the code
  2. the teardown function does not take fixtures argument

A solution would be to implement the suite as a class, like this:

# suites/test1.py
import lemoncheesecake.api as lcc
from lemoncheesecake.matching import *


@lcc.suite("Test 1")
class test1:
    driver = lcc.inject_fixture()

    @lcc.test('test description')
    def create_test_test(self):
        check_that("test","a", equal_to("b"))
        check_that("test", "a", equal_to("a"))
        # you can also do something with your driver using "self.driver"

    def teardown_test(self, test, status):
        lcc.log_info(test.name)
        lcc.log_info(status)
        if status == "passed":
            lcc.log_info("no failure")
        else:
            lcc.log_info("status was: failed")
            self.driver.get_screenshot_as_file("s1.png")
            lcc.log_info("saved screenshot")
            lcc.save_attachment_file("s1.png")

And of course, if every test suite follow the same pattern (having a "driver" fixture, having "teardown_test" method, etc...) you can extract it in a base class and inherit this base class in your actual test suites.

from lemoncheesecake.

anarang avatar anarang commented on June 7, 2024

Okay, so for the base class would it be something like this:

helpers/capture_screenshot.py:
import lemoncheesecake.api as lcc

class Screenshot:
    driver = None

    def teardown_test(self, test, status):
        lcc.log_info(test.name)
        lcc.log_info(status)
       if status == "passed":
            lcc.log_info("no failure")
        else:
            lcc.log_info("status was: failed")
            self.driver.get_screenshot_as_file("s1.png")
            lcc.log_info("saved screenshot")
            lcc.save_attachment_file("s1.png")

And, then I make every suite into a class instead of a module and do this:

#suites/test1.py
from helpers.capture_screenshot import Screenshot

@lcc.suite("Create new product", rank="1")
class test_create_product(Screenshot):
    driver = lcc.inject_fixture()  ---> is the 'driver' here the name of the fixture? aren't we supposed to pass the name of the fixture here as lcc.inject_fixture("name_of_fixture"), it is working as expected ways.

    @lcc.test('Verify that Warning is displayed when no product name is being entered')
    def create_product_blank_name(self):
        self.driver.get("url")
        check_that("test","a", equal_to("b"))
        check_that("test", "a", equal_to("a"))

driver=lcc.inject_fixture would be a part of every suite, correct?

from lemoncheesecake.

ndelon avatar ndelon commented on June 7, 2024

Simply do the driver = lcc.inject_fixture() in your base test suite, not in the derived classes.

About lcc.inject_fixture(): http://docs.lemoncheesecake.io/en/latest/api.html#lemoncheesecake.api.inject_fixture . So yes: if you don't specify an argument, it will lookup the fixture to inject from the assignment variable name.

from lemoncheesecake.

anarang avatar anarang commented on June 7, 2024

Base test suite as in suites/screenshot.py? I was keeping the above code in helpers/screenshot.py as it’s not a test suite.

from lemoncheesecake.

ndelon avatar ndelon commented on June 7, 2024

Yes, keep it in helpers/screenshot.py: it's not an actual test suite, it's just a base class.

from lemoncheesecake.

anarang avatar anarang commented on June 7, 2024

@ndelon thanks a lot for all the help. It worked for me. I would like to raise a PR for this in your docs for anyone to refer. Can you tell me what section would be the correct one in the docs to a PR to lemoncheesecake.
I am thinking of introducing something like:
How to capture screenshots using selenium + lemoncheesecake? or anything that you suggest. Let me know. thanks :)

from lemoncheesecake.

ndelon avatar ndelon commented on June 7, 2024

Thanks for wanting to help but this is far too much specific (selenium + the way you want to handle errors) to go to the standard documentation.

from lemoncheesecake.

anarang avatar anarang commented on June 7, 2024

okay, let me know if there is anything that I can contribute to. thanks for the help @ndelon :)

from lemoncheesecake.

ndelon avatar ndelon commented on June 7, 2024

Hello @anarang ,

FYI lemoncheesecake-selenium (https://lemoncheesecake-selenium.readthedocs.io/en/latest/) has just been released and should help you with some of the problematic you raised in this ticket.

Regards,

Nicolas.

from lemoncheesecake.

anarang avatar anarang commented on June 7, 2024

@ndelon ack, thanks for notifying.

from lemoncheesecake.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.