Skip to content
This repository has been archived by the owner on Nov 29, 2018. It is now read-only.

Screenshots stopped working #5087

Closed
lukeis opened this issue Mar 4, 2016 · 7 comments
Closed

Screenshots stopped working #5087

lukeis opened this issue Mar 4, 2016 · 7 comments

Comments

@lukeis
Copy link
Member

lukeis commented Mar 4, 2016

Originally reported on Google Code with ID 5087

Before filing an issue, please read the page at
http://code.google.com/p/selenium/wiki/SeleniumHelp This contains lot of
information about how best to get help, and tells you what we need to know.

Still here? We know that bugs are frustrating and annoying things. We also
know that you've probably spent ages trying to figure out what's wrong. The
more information you give us now, the more likely it is that we'll be able
to help.

What steps will reproduce the problem?
1. A code that worked fine in 2.24:
// webDriver is an instance of a CustomFirefoxDriver that extends FirefoxDriver

final WebDriver augmentedDriver = new Augmenter().augment(webDriver);
final File screenshot = ((TakesScreenshot) augmentedDriver ).getScreenshotAs(OutputType.FILE);

Throws java.lang.IllegalAccessException-->Class org.openqa.selenium.remote.Augmenter$CompoundHandler
can not access a member of class org.openqa.selenium.firefox.FirefoxDriver with modifiers
"protected"

What is the expected output? What do you see instead?
Expected: screenshot. Instead - I see this error.

Selenium version: 2.28
OS: Windows
Browser: Firefox
Browser version: 18


Please provide any additional information below. A sample reduced test
case, or a public URL that demonstrates the problem will intrigue our merry
band of Open Source developers far more than nothing at all: they'll be far
more likely to look at your problem if you make it easy for them!

It was working in 2.24 and before.

Reported by bogdan.watula on 2013-01-29 05:30:57

@lukeis
Copy link
Member Author

lukeis commented Mar 4, 2016

Reported by barancev on 2013-01-29 13:53:01

  • Labels added: Lang-Java

@lukeis
Copy link
Member Author

lukeis commented Mar 4, 2016

Augmenter can (and should) be used to augment RemoteWebDriver only. As soon as your
CustomFirefoxDriver extends FirefoxDriver, it implements TakesScreenshot interface
and you don't need to augment it, just cast to this interface:

WebDriver driver = new CustomFirefoxDriver();
...
File screenshot = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);

Reported by barancev on 2013-01-29 19:09:26

  • Status changed: WorkingAsIntended
  • Labels removed: Status-Untriaged

@lukeis
Copy link
Member Author

lukeis commented Mar 4, 2016

@barancev, what do you mean? A FirefoxDriver is a RemoteWebDriver according to the code
hierarchy. This is just bad programming :(

Reported by Wattos on 2014-05-21 15:00:42

@lukeis
Copy link
Member Author

lukeis commented Mar 4, 2016

The fact that a class extends RemoteWebDriver does not mean it can be augmented.

Morover, it should not be augmented (that is in essense just adding interfaces that
correspond to the browser capabilities) because it implements already all the requred
interfaces.

Augmentation is required only in the case when you don't know what browser is on the
remote end and what capabilities it has.

Reported by barancev on 2014-05-21 15:13:40

@lukeis
Copy link
Member Author

lukeis commented Mar 4, 2016

@barancev, That is exactly the point. I only have a WebDriver element in my hand. We
create the web driver based on command line arguments in a completely different place.


It could be one of FirefoxDriver, ChromeDriver, IEDriver, etc. It could be any of those.
Part of what makes Object Orientation so nice, is that I do not need to care. The substitution
rule should apply.

If somebody provides API which takes in a WebDriver, then it should work for any instance
which is a WebDriver (e.g. FirefoxDriver, ChromeDriver, IEDriver). Your API states
that I can augment anything which is a RemoteWebDriver. A Firefox driver is a RemoteWebDriver,
E.g. I can have a variable of type RemoteWebDriver and assign it a FirefoxDriver.

If your augmentation cannot work (or has no effect on a subclass) then you should just
return the driver. In fact, it seems like you already do something like this, but it
does not work correctly.

 public WebDriver augment(WebDriver driver) {
    RemoteWebDriver remoteDriver = extractRemoteWebDriver(driver);
    if (remoteDriver == null) {
      return driver;
    }
    return create(remoteDriver, driverAugmentors, driver);
  }

The extract method looks like:

   if (driver instanceof RemoteWebDriver) {
      return (RemoteWebDriver) driver;
    } else {
      return null;
    }

Even if your statement holds, you still have a bug in your API since I have fulfilled
the pre conditions which stated in the javadoc (e.g. I am passing an instance which
is a RemoteWebDriver), but the method still fails.

That API you have there is just bad API. As it was stated by the creator of this issue,
this even used to work in 2.24. If you do not care about having good API, then I guess
it is fine if you never fix this issue. Now you force every client code to do the following:

TakesScreenshot result= null;
if (driver instanceof TakesScreenshot) {
    result= (TakesScreenshot)driver;
} else if (driver.getClass() == RemoteWebDriver.class) {
    //Augmenter can only be called on RemoteWebDriver and none of the child classes. See
https://code.google.com/p/selenium/issues/detail?id=5087
    result= (TakesScreenshot)new Augmenter().augment(driver);
}

if (result != null) {
    return result.getScreenshotAs(BYTES);
}

Just to take a screenshot. And every client has to do that. It would be much easier
to just do new Augmenter().augment(driver).getScreenshotAs(BYTES).

Thanks



Reported by Wattos on 2014-05-22 05:33:07

@lukeis
Copy link
Member Author

lukeis commented Mar 4, 2016

1. Sinse version 2.42 the class RemoteWebDriver implements TakesScreenshot, so you can
remove autmentation at all if you need this feature only.

2. Yes API was not ideal, that's why we've changed it in 2.42.

Now Augmenter augments only instances of classes that are marked by @Augmentable annotation
and does not touch other ones.

That is:

if (driver.getClass().isAnnotationPresent(Augmentable.class)) {
  System.out.println("Аugmentable");
  driver = new Augmenter().augment(driver);
} else {
  System.out.println("Non augmentable, so augmentation can be performed but does nothing");
  driver = new Augmenter().augment(driver);
}

So you can simply write

driver = new Augmenter().augment(driver);

and augmentable driver will be augmented, whereas nonaugmentable one will be returned
as is.

Reported by barancev on 2014-05-22 08:23:18

  • Status changed: Fixed

@lukeis
Copy link
Member Author

lukeis commented Mar 4, 2016

Reported by luke.semerau on 2015-09-17 18:16:38

  • Labels added: Restrict-AddIssueComment-Commit

@lukeis lukeis closed this as completed Mar 4, 2016
@SeleniumHQ SeleniumHQ locked and limited conversation to collaborators Mar 4, 2016
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

1 participant