7

Can anyone help me to take a full page screenshot using Selenium webdriver. I am using c#/Nunit. The current method i am using is not taking the full browser page.

I am using the code below to take the screenshot.

public void TakeScreenShot(IWebDriver webDriver,string testName,string className)
{          

string folderName = String.Format("{0}.{1}", className, testName);

// Create Screenshot folder
string createdFolderLocation = CreateFolder(folderName);

// Take the screenshot            
Screenshot ss = ((ITakesScreenshot)webDriver).GetScreenshot();            
string screenshot = ss.AsBase64EncodedString;
byte[] screenshotAsByteArray = ss.AsByteArray;

// Save the screenshot
ss.SaveAsFile((string.Format("{0}\\{1}",createdFolderLocation,testName + ".Jpeg")), System.Drawing.Imaging.ImageFormat.Jpeg);
ss.ToString();

}
anil
  • 117
  • 1
  • 1
  • 7

10 Answers10

6

You can use this package https://www.nuget.org/packages/Noksa.WebDriver.ScreenshotsExtensions/

In order to take a screenshot of the entire page, use the VerticalCombineDecorator:

var vcs = new VerticalCombineDecorator(new ScreenshotMaker());
var screen = _driver.TakeScreenshot(vcs);
Noksa
  • 71
  • 1
  • 1
  • I started using it recently and I liked it, but it seems to have memory issues sometimes and its getting hung while generating HTML reports – rkkreddy Jul 26 '19 at 13:36
4

"Full-page" screenshots are defined by WebDriver to include the entirety of the page displayed in the browser, not the browser chrome (URL bar, toolbar, window resizing handles, and so on). If you don't care about getting the full DOM in your screenshot, you don't need to use WebDriver to get your screenshot. You can use the API of your operating system to handle that instead.

JimEvans
  • 27,201
  • 7
  • 83
  • 108
2

This one I used in our solution:

 public byte[] TakeScreenshot()
    {
      try
      {
        var getMaxSide = "return Math.max(document.body.scroll{0}, document.body.offset{0}, document.documentElement.client{0}, document.documentElement.scroll{0}, document.documentElement.offset{0})";
        var scrollHeight = (Driver as IJavaScriptExecutor).ExecuteScript(string.Format(getMaxSide, "Height"));
        var scrollWidth = (Driver as IJavaScriptExecutor).ExecuteScript(string.Format(getMaxSide, "Width"));
        Driver.Manage().Window.Size = new Size(int.Parse(scrollWidth.ToString()), int.Parse(scrollHeight.ToString()));
        return (Driver as ITakesScreenshot).GetScreenshot().AsByteArray;
      }
      catch
      {
        return Array.Empty<byte>();
      }
    }

Then you can use the result to attach it to e.g. Allure or NUnit test results:

 private void AttachScreenshot()
    {
      var screenshot = _browser?.TakeScreenshot();
      if (screenshot.Length > 0)
      {
        // add screenshot to test results
        var path = DateTime.Now.Ticks.ToString() + ".png";
        File.WriteAllBytes(path, screenshot);
        TestContext.AddTestAttachment(path, "screenshot");

        // attach screenshot to Allure report
        AllureLifecycle.Instance.AddAttachment("screenshot", "image/png", screenshot);
      }
    }
1

Try changing the size of the browser window to something huge before taking your screen shot. I have the size to 10 less than the width, and 10 less than the height. Try adding rather than subtracting.

    driver = new FirefoxDriver(firefoxProfile);

    if (Config.MAXIMIZE_BROWSER_WINDOW)
    {
        driver.Manage().Window.Size = new System.Drawing.Size(System.Windows.Forms.Screen.PrimaryScreen.WorkingArea.Width - 10, System.Windows.Forms.Screen.PrimaryScreen.WorkingArea.Height - 10);
    }
JustBeingHelpful
  • 18,332
  • 38
  • 160
  • 245
1

you may try this

IWebDriver driver = new PhantomJSDriver();
driver.Navigate().GoToUrl("http://www.google.com");
((ITakesScreenshot)driver).GetScreenshot().SaveAsFile("image.png", ImageFormat.Png);
salih
  • 108
  • 1
  • 4
  • this is for taking a screenshot using selenium webdriver with phantomjs. If you wish to use firefox or chrome. you may just change PhantomJSDriver() to the driver which you wish to use. – salih Oct 21 '15 at 11:30
  • @Salih I was able to get a screenshot capture to work with the `((ITakesScreenshot)driver).GetScreenshot().SaveAsFile(); ` approach, thank you for sharing that! – Rick Johnson Jun 09 '16 at 20:38
1

Greetings from 2017))!

If the page size is larger than the screen size - you can use the PhantomJS driver (PhantomJS download page)

var fileName = "test.png";
var size = new Size(800, 2000);
var url = "https://stackoverflow.com/";

using (var driver = new PhantomJSDriver())
{
    driver.Manage().Window.Size = size;
    driver.Navigate().GoToUrl(url);
    ((ITakesScreenshot)driver)
        .GetScreenshot()
        .SaveAsFile(fileName, ImageFormat.Png);

    driver.Close();
}
morphey83
  • 111
  • 2
0

I remeber that ((ITakesScreenshot)webDriver).GetScreenshot(); takes full page screenshot but if you have some ajax request and other loading elements you can add scrolling and at the end to wait some seconds, after that you will know that it took full loaded page screenshot.

        for (int second = 0;; second++)
        {
            if (second >= 4)
            {
                break;
            }

            ((IJavaScriptExecutor)Global.Driver).ExecuteScript("window.scrollBy(0,800)", string.Empty);
            Thread.Sleep(500);
        }

        Thread.Sleep(3000);
Andrian Durlestean
  • 1,730
  • 1
  • 19
  • 30
0

Try this hope it will work fine for u.

public void TakeScreenshot(string SSName)
        {
            try
            {
                string path = "D:\\WorkSpace\\Screenshot\\";
                Screenshot ss = ((ITakesScreenshot)driver).GetScreenshot();
                ss.SaveAsFile((path + SSName), System.Drawing.Imaging.ImageFormat.Jpeg);
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
                throw;
            }
        }
Arnab
  • 271
  • 2
  • 7
  • 18
0

Changing browser height doesn't always work. This is the solution I used. It scrolls through the page and composes the full-page screenshot.

public static Image TakeFullPageScreenshot(this RemoteWebDriver driver, int maxHeight = 10000)
    {
        Bitmap fullPageScreenshot = null;
        using (var fullMs = new MemoryStream((driver.GetScreenshot()).AsByteArray)) { 
            fullPageScreenshot = Image.FromStream(fullMs) as Bitmap;
        }
        var originalPageOffset = driver.GetPageOffset();

        var prevPageOffset = 0;
        var currentPageOffset = 0;
        var scrollLength = (int)(driver.Manage().Window.Size.Height / 1.5);
        while (fullPageScreenshot.Height < maxHeight)
        {
            prevPageOffset = driver.GetPageOffset().Y;
                       
            driver.ScrollPageBy(0, scrollLength);
            System.Threading.Thread.Sleep(500);

            currentPageOffset = driver.GetPageOffset().Y;

            if (prevPageOffset == currentPageOffset)
            {
                break;
            }
            var pageMovedBy = currentPageOffset - prevPageOffset;
            using (var ms = new MemoryStream(driver.GetScreenshot().AsByteArray))
            {
                using (var viewPortScreenshot = Image.FromStream(ms) as Bitmap)
                {
                    var croppedScreenshot = CropBitmapAtRect(viewPortScreenshot, new Rectangle(0, viewPortScreenshot.Height - pageMovedBy, viewPortScreenshot.Width, pageMovedBy));
                    var newFullPage = AppendBitmap(fullPageScreenshot, croppedScreenshot);
                    fullPageScreenshot.Dispose();
                    fullPageScreenshot = newFullPage;
                }
            }
        }
        driver.ScrollPageTo(originalPageOffset.X, originalPageOffset.Y);
        return fullPageScreenshot;
    }

    public static Bitmap CropBitmapAtRect(Bitmap b, Rectangle r)
    {
        Bitmap nb = new Bitmap(r.Width, r.Height);
        using (Graphics g = Graphics.FromImage(nb))
        {
            g.DrawImage(b, -r.X, -r.Y);
            return nb;
        }
    }

    public static Bitmap AppendBitmap(Bitmap source, Bitmap target, int spacing = 0)
    {
        int w = Math.Max(source.Width, target.Width);
        int h = source.Height + target.Height + spacing;
        Bitmap bmp = new Bitmap(w, h);

        using (Graphics g = Graphics.FromImage(bmp))
        {
            g.DrawImage(source, 0, 0);
            g.DrawImage(target, 0, source.Height + spacing);
        }

        return bmp;
    }

    public static void ScrollPageBy(this RemoteWebDriver driver, int x = 0, int y = 0)
    {
        driver.ExecuteScript(@"window.scroll(window.pageXOffset + arguments[0], window.pageYOffset + arguments[1]);", x, y);
    }

    public static void ScrollPageTo(this RemoteWebDriver driver, int x = 0, int y = 0)
    {
        driver.ExecuteScript(@"window.scroll(arguments[0], arguments[1]);", x, y);
    }

    public static Point GetPageOffset(this RemoteWebDriver driver)
    {
        var offsetArray = driver.ExecuteScript(@"return [window.pageXOffset, window.pageYOffset];") as ReadOnlyCollection<object>;
        var x = (long)offsetArray[0];
        var y = (long)offsetArray[1];
        return new Point((int)x, (int)y);
    }
Michal Kalous
  • 114
  • 1
  • 2
  • 4
0

based on the answer from @Michal Kalous I created an etension class. This also takes into account the font size currently set in widows and the real viewport size and removes the vertical scrollbar by setting body.style.overflowY to hidden.

Usage

RemoteWebDriver driver = new EdgeDriver();
driver.SetViewportSize(1200, 1200);

driver.Navigate().GoToUrl("https://www.bikereview.info/en/ktm-1290-super-duke-rr-innerhalb-von-48-minuten-ausverkauft.html");
Image tempImage = driver.TakeFullPageScreenshot();
tempImage.Save(@"c:\full.png", ImageFormat.Png);
driver.Close();
driver.Quit();

Extension-Class

using System;
using System.Drawing;
using System.IO;
using OpenQA.Selenium.Remote;
using System.Collections.ObjectModel;
using System.Runtime.InteropServices;
using OpenQA.Selenium;

namespace TestRenderHtmlToPng
{


    public static class RemoteWebDriverExtensions
    {

        public static Image TakeFullPageScreenshot(this RemoteWebDriver driver, int maxHeight = 10000)
        {

            //Screenshots depend on fontscaleing-property in windows
            double DpiScalingFactor = GetDpiScalingFactor();

            Bitmap fullPageScreenshot = null;
            using (var fullMs = new MemoryStream((driver.GetScreenshotOverflowHidden()).AsByteArray))
            {
                fullPageScreenshot = Image.FromStream(fullMs) as Bitmap;
            }
            var originalPageOffset = driver.GetPageOffset();

            var prevPageOffset = 0;
            var currentPageOffset = 0;
            var scrollLength = driver.GetWindowInnerHeight();

            while (fullPageScreenshot.Height < maxHeight)
            {
                prevPageOffset = driver.GetPageOffset().Y;

                driver.ScrollPageBy(0, scrollLength);
                System.Threading.Thread.Sleep(100);

                currentPageOffset = driver.GetPageOffset().Y;

                if (prevPageOffset == currentPageOffset)
                {
                    break;
                }
                var pageMovedBy = currentPageOffset - prevPageOffset;
                pageMovedBy = (int)(pageMovedBy * DpiScalingFactor);

                using (var ms = new MemoryStream(driver.GetScreenshotOverflowHidden().AsByteArray))
                {
                    Bitmap fullPageScreenshot1 = Image.FromStream(ms) as Bitmap;
                    using (var viewPortScreenshot = Image.FromStream(ms) as Bitmap)
                    {
                        var s = driver.Manage().Window.Size;

                        var croppedScreenshot = CropBitmapAtRect(viewPortScreenshot, new Rectangle(0, viewPortScreenshot.Height - pageMovedBy, viewPortScreenshot.Width, pageMovedBy));

                        var newFullPage = AppendBitmap(fullPageScreenshot, croppedScreenshot);

                        fullPageScreenshot.Dispose();
                        fullPageScreenshot = newFullPage;
                    }
                }
            }
            driver.ScrollPageTo(originalPageOffset.X, originalPageOffset.Y);
            return fullPageScreenshot;
        }



        private static Bitmap CropBitmapAtRect(Bitmap b, Rectangle r)
        {
            Bitmap nb = new Bitmap(r.Width, r.Height);
            using (Graphics g = Graphics.FromImage(nb))
            {
                g.DrawImage(b, -r.X, -r.Y);
                return nb;
            }
        }

        private static Bitmap AppendBitmap(Bitmap source, Bitmap target, int spacing = 0)
        {
            int w = Math.Max(source.Width, target.Width);
            int h = source.Height + target.Height + spacing;
            Bitmap bmp = new Bitmap(w, h);

            using (Graphics g = Graphics.FromImage(bmp))
            {
                g.DrawImage(source, 0, 0);
                g.DrawImage(target, 0, source.Height + spacing);
            }

            return bmp;
        }

        private static Screenshot GetScreenshotOverflowHidden(this RemoteWebDriver driver)
        {
            driver.ExecuteScript(@" document.body.style.overflowY = ""hidden"";");
            var s = driver.GetScreenshot();
            driver.ExecuteScript(@" document.body.style.overflowY = """";");
            return s;
        }

        private static void ScrollPageBy(this RemoteWebDriver driver, int x = 0, int y = 0)
        {
            driver.ExecuteScript(@"window.scroll(window.pageXOffset + arguments[0], window.pageYOffset + arguments[1]);", x, y);
        }
        private static void ScrollPageTo(this RemoteWebDriver driver, int x = 0, int y = 0)
        {
            driver.ExecuteScript(@"window.scroll(arguments[0], arguments[1]);", x, y);
        }

        public static void SetViewportSize(this RemoteWebDriver driver, int width, int height)
        {
            var jsGetPadding = @"return [ window.outerWidth - window.innerWidth,window.outerHeight - window.innerHeight ];";
            var paddingArray = driver.ExecuteScript(jsGetPadding) as ReadOnlyCollection<object>;
            driver.Manage().Window.Size = new Size(width + int.Parse(paddingArray[0].ToString()), height + int.Parse(paddingArray[1].ToString()));

        }

        private static Point GetPageOffset(this RemoteWebDriver driver)
        {
            var offsetArray = driver.ExecuteScript(@"return [window.pageXOffset, window.pageYOffset];") as ReadOnlyCollection<object>;
            var x = int.Parse(offsetArray[0].ToString());
            var y = int.Parse(offsetArray[1].ToString().Split(',')[0]);
            return new Point((int)x, (int)y);
        }
        private static int GetWindowInnerHeight(this RemoteWebDriver driver)
        {
            var Value = driver.ExecuteScript(@"return [window.innerHeight];") as ReadOnlyCollection<object>;
            return int.Parse(Value[0].ToString());

        }

        [DllImport("gdi32.dll")]
        private static extern int GetDeviceCaps(IntPtr hdc, int nIndex);
        public enum DeviceCap
        {
            VERTRES = 10,
            DESKTOPVERTRES = 117,

            // http://pinvoke.net/default.aspx/gdi32/GetDeviceCaps.html
            // https://stackoverflow.com/questions/5977445/how-to-get-windows-display-settings#answer-21450169
        }


        private static float GetDpiScalingFactor()
        {
            Graphics g = Graphics.FromHwnd(IntPtr.Zero);
            IntPtr desktop = g.GetHdc();
            int LogicalScreenHeight = GetDeviceCaps(desktop, (int)DeviceCap.VERTRES);
            int PhysicalScreenHeight = GetDeviceCaps(desktop, (int)DeviceCap.DESKTOPVERTRES);

            float ScreenScalingFactor = (float)PhysicalScreenHeight / (float)LogicalScreenHeight;

            return ScreenScalingFactor; // 1.25 = 125%
        }

    }
}
Chris Berlin
  • 744
  • 6
  • 15