Search code examples
pythonvue.jstestingcypressistanbul

Vue Cypress code coverage report with python tests


I have Python tests with Selenium to test my Vue webpage. I would like to get code coverage results for those tests. I have installed babel-plugin-istanbul to instrument the application, and it works. I have window.__coverage__ object, which contains the coverage information.

My question is, how can I get coverage reports if I run the tests using Python, not Cypress's testing framework. I have installed cypress/code-coverage, but I don't know how to generate the reports without using Cypress' unit testing framework.

Also, If there is another coverage report framework for Vue, which is more suitable for my use case, I am open to suggestions.


Solution

  • Here is how I managed to do it without any Cypress libraries:

    In the tearDownClass method of the tests file (after all tests), I added this code, to save the window.__coverage__ into the .nyc_output/out.json file:

    @classmethod
    def tearDownClass(cls):
        # Put coverage data into file.
        data = cls.driver.execute_script('return window.__coverage__')
        
        with open(os.path.join(cls.webAppPath, ".nyc_output", "out.json"), 'w') as outfile:
            json.dump(data, outfile)
    
        # Generate HTML coverage report
        os.system("cd %s && %s report --reporter=html -e .vue" % (cls.webAppPath, os.path.join(cls.webAppPath, "node_modules", ".bin", "nyc")))
    

    Note that .nyc_output folder has to be in the web application's folder. Also while testing, the webpage shouldn't be reloaded, because that would reset the coverage counters and thus give incorrect coverage.

    But, this wasn't enough. There is a bug in the istanbul's code, so I used a fix, found here. Before testing, I modify a part of istanbul's code in this way (and then recompile the web app's code):

    # Fix a bug in istanbul code coverage lib
    pathOfFileToModify = os.path.join(webAppPath, "node_modules/istanbul-lib-source-maps/lib/pathutils.js")
    
    with open(pathOfFileToModify, "r") as fileToModify:
        modified = fileToModify.read().replace('relativeTo(file, origFile) {\n        return', 'relativeTo(file, origFile) {\n        if (origFile.indexOf(file) !== -1) { return origFile }\n        return')
    
    with open(pathOfFileToModify, "w") as fileToModify: # TODO Maybe figure out how to use read-write mode?
        fileToModify.write(modified)
    

    If anyone found a better way around that, please let me know in the comments.