Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Selenium to determine the visibility of elements for Print media

I would like to determine if particular elements on a page are visible when printed as controlled by CSS @media rules.

Is there a way to do this with Selenium?

I know there is the isDisplayed method, which takes the CSS into account, but there is nothing I can find to tell Selenium which media type to apply.

Is there a way to do this?

Or is there another way to test web pages to make sure the elements you want are printed (and those you don't aren't)?

Update:

For clarity, there are no plans to have a javascript print button. The users will print using the normal print functionality of the browser (Chrome, FF and IE). @media css rules will be used to control what is shown and hidden. I would like Selenium to pretend it is a printer instead of a screen, so I can test if certain elements will be visible in what would be the printed version of the page.

like image 492
Tom Howard Avatar asked Jun 02 '14 02:06

Tom Howard


People also ask

How do you check if an element is visible on the web page in Selenium Python?

We can also verify if an element is present in the page, with the help of find_elements() method. This method returns a list of matching elements. We can get the size of the list with the len method. If the len is greater than 0, we can confirm that the element exists on the page.

How to get all page content in Selenium?

findElement(By. tagName("body")); String t = l. getText(); The next approach to get the content of the entire page is to use the getPageSource() method.


1 Answers

I've managed to write a script that does just what you want: it hides screen-only styles and sets print-only styles to be screen-only.

You need to inject the following JavaScript with Selenium:

(function pretendToBeAPrinter() {
    //For looking up if something is in the media list
    function hasMedia(list, media) {
        if (!list) return false;

        var i = list.length;
        while (i--) {
            if (list[i] === media) {
                return true;
            }
        }
        return false;
    }

    //Loop though all stylesheets
    for (var styleSheetNo = 0; styleSheetNo < document.styleSheets.length; styleSheetNo++) {
        //Current stylesheet
        var styleSheet = document.styleSheets[styleSheetNo];

        //Output debug information
        console.info("Stylesheet #" + styleSheetNo + ":");
        console.log(styleSheet);

        //First, check if any media queries have been defined on the <style> / <link> tag

        //Disable screen-only sheets
        if (hasMedia(styleSheet.media, "screen") && !hasMedia(styleSheet.media, "print")) {
            styleSheet.disabled = true;
        }

        //Display "print" stylesheets
        if (!hasMedia(styleSheet.media, "screen") && hasMedia(styleSheet.media, "print")) {
            //Add "screen" media to show on screen
            styleSheet.media.appendMedium("screen");
        }

        // Get the CSS rules in a cross-browser compatible way
        var rules;
        try {
            rules = styleSheet.cssRules;
        } catch (error) {
            console.log(error);
        }

        try {
          rules = styleSheet.rules;
        } catch (error) {
          console.log(error);
        }

        // Handle cases where styleSheet.rules is null
        if (!rules) {
            continue;
        }

        //Second, loop through all the rules in a stylesheet
        for (var ruleNo = 0; ruleNo < rules.length; ruleNo++) {
            //Current rule
            var rule = rules[ruleNo];

            //Hide screen-only rules
            if (hasMedia(rule.media, "screen") && !hasMedia(rule.media, "print")) {
                //Rule.disabled doesn't work here, so we remove the "screen" rule and add the "print" rule so it isn't shown
                console.info('Rule.media:');
                console.log(rule.media)
                rule.media.appendMedium(':not(screen)');
                rule.media.deleteMedium('screen');
                console.info('Rule.media after tampering:');
                console.log(rule.media)
            }

            //Display "print" rules
            if (!hasMedia(rule.media, "screen") && hasMedia(rule.media, "print")) {
                //Add "screen" media to show on screen
                rule.media.appendMedium("screen");
            }
        }
    }
})()

You can see it in action at JSFiddle.

Bookmarklet

You can also install it as a bookmarklet.

More information:

  • About mediaList
  • About document.styleSheets

Note: I've only tested this in Google Chrome and Mozilla Firefox. It may or may not work in other browsers.

like image 150
user2428118 Avatar answered Oct 09 '22 22:10

user2428118