Selenium2: Taking screenshots with selenium grid 2 - screenshot

Is it possible to take screenshots using selenium grid 2? The RemoteWebDriver class does not implement the TakesScreenshot interface.
Mark

The RemoteWebDriver must be augmented before you can use the screenshot capability. As you have no doubt already found, attempting to cast without augmenting results in an exception.
WebDriver driver = new RemoteWebDriver( ... );
driver = new Augmenter().augment( driver );
( (TakesScreenshot)driver ).getScreenshotAs( ... );

You would need to write a wrapper class that extends RemoteWebDriver and implement TakeScreenshot interface something like below in java.
public class ScreenShotRemoteWebDriver extends RemoteWebDriver implements TakesScreenshot
{
public ScreenShotRemoteWebDriver(URL url, DesiredCapabilities dc) {
super(url, dc);
}
#Override
public <X> X getScreenshotAs(OutputType<X> target) throws WebDriverException {
if ((Boolean)getCapabilities().getCapability(CapabilityType.TAKES_SCREENSHOT)) {
return target.convertFromBase64Png(execute(DriverCommand.SCREENSHOT).getValue().toString());
}
return null;
}
}

Related

Handling scrolling in a page object model

What are the best practices for scrolling to an element in a page when using page object model pattern?
If it matters, my tests are Appium tests that'll run on native iOS and Android apps.
Suppose I have this page:
public class LoginPage {
private AndroidDriver<AndroidElement> driver;
public LoginPage(AndroidDriver<AndroidElement> driver) {
this.driver = driver;
PageFactory.initElements(new AppiumFieldDecorator(driver), this);
}
#AndroidFindBy(className = "UIAKeyboard")
private AndroidElement keyboard;
#AndroidFindBy(id = "name")
private AndroidElement nameElement;
#AndroidFindBy(id = "password")
private AndroidElement passwordElement;
#AndroidFindBy(id = "login")
private AndroidElement loginElement;
public void scrollToLoginButton() {
//......
}
}
Is there some built in way/best practice to scroll down to the login button, aside from manually using FluentWait, activating a TouchAction in the until method every time I don't find the button to be clickable?
driver.findElement(MobileBy.AndroidUIAutomator(
"new UiScrollable(new UiSelector().scrollable(true)).scrollTextIntoView(\"login\")"));
you can use adroidUIAutomater class uiscrollable, see any method thats suites ui
https://developer.android.com/reference/androidx/test/uiautomator/UiScrollable
If you want to use actions class from selenium use :
import org.openqa.selenium.interactions.Actions;
new Actions(driver).clickAndHold(e2).moveByOffset(0, -500).perform();
Note: you have to click and hold element at the bottom of the screen and scroll backwards thats why -500
or move from last element to first element:
Actions action = new Actions(driver);
action.clickAndHold(e2).moveToElement(e1);
action.perform();
I guess you were expecting for this
#AndroidFindBy(uiAutomator = "new UiScrollable(new UiSelector().scrollable(true))" +
".scrollIntoView(new UiSelector().textContains(\"login\"))")
private AndroidElement loginElement;
public void scrollToLoginButton() {
loginElement.click();
}

Create screenshot - Allure, JUnit5, Selenium

Is there any documentation about this? JUnit4 has #Rule and solution is straightforward. For JUnit5 I made a extension public class TestWatcher implements AfterTestExecutionCallback but I don't know what to put in #Override method.
I've managed to solve it. Method for screen capture is default one:
#Attachment(value = "{testName} - screenshot", type = "image/png")
private byte[] makeScreenshotOnFailure(String testName) {
return ((TakesScreenshot) driver).getScreenshotAs(OutputType.BYTES);
}
and TestWatcher (extension):
#Override
public void afterTestExecution(ExtensionContext extensionContext) throws Exception {
Object test = extensionContext.getRequiredTestInstance();
Field a = test.getClass().getDeclaredField("driver");
a.setAccessible(true);
driver = (WebDriver) a.get(test);
Method method = extensionContext.getRequiredTestMethod();
if (extensionContext.getExecutionException().isPresent()) {
makeScreenshotOnFailure(method.getName());
}
}
You can find a sample here. Is it a code from NoraUi Open Source Framework (Java + Selenium).
import org.openqa.selenium.TakesScreenshot;
final byte[] screenshot = ((TakesScreenshot) Context.getDriver()).getScreenshotAs(OutputType.BYTES);

Can I get variable Name and Method name of #Test in After Test call?

#BeforeSuite
public void reports() {
clearreports();
}
#Test(priority = 0,enabled = true)
public void C2410949_VerifyNameIsCorrectlyDisplayedOnHomePage() throws IOException, InterruptedException, ATUTestRecorderException, APIException {
String TestCaseId = "8789740";
ATUTestRecorder record = new ATUTestRecorder("./video",
Thread.currentThread().getStackTrace()[1].getMethodName(), true);
record.start();
launchUrl();
startResult();
startTestCase(Thread.currentThread().getStackTrace()[1].getMethodName().toString());
UserNamePage usernamePage = new UserNamePage();
usernamePage.EnterUsername(BaseClass.username.toUpperCase());
PasswordPage passwordPage = new PasswordPage();
passwordPage.passwordValidator(BaseClass.password);
Thread.sleep(30000);
HomePage homePage = new HomePage();
String actualNickName = homePage.WelcomeMessage.getText().toString().replaceAll("hello,", "").trim();
System.out.println("Actual Nick Name:"+actualNickName);
homePage.Click(homePage.SettingsNHelp);
Thread.sleep(15000);
SettingsAndHelp settingandhelp = new SettingsAndHelp();
settingandhelp.Click(settingandhelp.ChangeContactInformation);
Thread.sleep(5000);
SettingsAndHelp.ChangeContactInformation changeContactInformation = settingandhelp.new ChangeContactInformation();
String expecteduserNickName = changeContactInformation.UserNickName.getText().toString()+"!";
System.out.println(expecteduserNickName);
AssertVerify(actualNickName, expecteduserNickName);
homePage.Click(homePage.Logout);
endTestcase();
endResult();
updateResults(TestCaseId, "PASSED");
record.stop();
}
#AfterTest
public void TearDown() {
endTestcase();
endResult();
driver.close();
}
The above is one of my test case. Here I am struck for two items.
One is Test Rail Integration:
1. I have `testcase Id` in `# Test`. But if test case is passed, then it is all good. But In middle if it fails, I have to fail the test case. I can move that making fail part in #afterTest but test case Id will not be available from #Test.
Is there any way that i can get the test case Id which I used in # Test
2. The recording is also not working if it fails in middle as it is record.stop at the end of the test case. I can initialize and start record in #BeforeTest and Stop in #AfterTest.
But again the I am finding difficult for naming convention for video as i am looking current method name/testcase id as Video name..
Can any one help me on this?
Thanks
You can use ITestContext interface. It allows you to store objects and then retrieve it anywhere you want. It will remain relevant for one whole test run.
How to use:
1) First set your attribute to whatever value you want, in this case the TestCaseId -
#Test(priority = 0,enabled = true)
public void C2410949_VerifyNameIsCorrectlyDisplayedOnHomePage(ITestContext testContext) throws IOException, InterruptedException, ATUTestRecorderException, APIException {
String TestCaseId = "8789740";
testContext.setAttribute("TestCaseID", TestCaseId);
// rest of the code
2) Then retrieve it in your required function -
#AfterTest
public void TearDown(ITestContext testContext) {
String testCaseId = testContext.getAttribute("TestCaseID");
endTestcase();
endResult();
driver.close();
}
Note how I have passed ITestContext testContext as a parameter in both the functions.

How to add RequestInterceptor and change Referer in BrowserMob-Proxy 2.0

I am using BrowserMob-Proxy inside a Selenium test suite. I would like to change the Referer for a few tests. I have added requestInterceptor from the 2.0 docs into our MyProxy class and while it does not generate an error the Referer is not changed.
For now, I am trying to get the requestInterceptor to work in the MyProxy class where the proxy is created. In the end, I would like to be able to specify the Referer in each test.
If anyone has suggestions on getting the requestInterceptor to work please let me know. Here is the MyProxy class. Please let me know if other code examples would be helpful to troubleshoot this.
import org.openqa.selenium.Proxy;
import net.lightbody.bmp.core.har.Har;
import net.lightbody.bmp.proxy.ProxyServer;
import net.lightbody.bmp.proxy.http.BrowserMobHttpRequest;
import net.lightbody.bmp.proxy.http.RequestInterceptor;
public class MyProxy {
private ProxyServer proxy;
private boolean initialized;
public Har endCapture() throws Exception {
Thread.sleep(15000);
return this.proxy.getHar();
}
public Proxy getSeleniumProxy() {
return this.proxy.seleniumProxy();
}
public boolean isInitialized() throws Exception {
return this.initialized;
}
public void start() throws Exception {
int proxyPort = Integer.parseInt(System.getProperty("proxyPort"));
this.proxy = new ProxyServer(proxyPort);
this.proxy.start();
this.proxy.setCaptureHeaders(true);
this.proxy.setCaptureContent(true);
this.proxy.addRequestInterceptor(new RequestInterceptor() {
#Override
public void process(BrowserMobHttpRequest request, Har har) {
request.getMethod().removeHeaders("Referer");
request.getMethod().addHeader("Referer", "http://www.google.com");
}
});
this.initialized = true;
}
public void startCapture() throws Exception{
this.proxy.newHar("MyHar");
}
public void stop() throws Exception {
this.proxy.stop();
this.initialized = false;
}
}
I think the key here is how to test the newly-added header, which is tricky to do manually.
I chose as a test-site: http://headers.cloxy.net/request.php, which simply logs the names and values of all request headers. Having first set up my proxy, I arranged a screenshot to be written after page request completed.
I was able to determine that:
#Override
public void process(BrowserMobHttpRequest req, Har har) {
req.getMethod().removeHeaders("Referer");
req.getMethod().addHeader("Referer", "http://www.google.xyz");
// Some extras
req.getMethod().addHeader("Foo_" + System.currentTimeMillis(), "Bar_" + new java.util.Date());
req.getMethod().setHeader("Lorem_" + System.currentTimeMillis(), "Ipsum_" + new java.util.Date());
}
... successfully adds all the specified headers in both BrowserMob 2.0.0 and 2.1 beta 5. I've confirmed this for each version in Firefox (45), Chrome (49), and PhantomJS.
So, in short:
The OP's header-adding syntax is perfectly fine.
setHeader also works as expected.
BMP version numbers do not affect this (but by all means upgrade to 2.1 as/when it is released)
Browsers do not affect this
Review this issue and see if it describes your problem.
Suggestion is to move to the latest version of BrowserMobProxy which is 2.1.0-beta-5.

TestNG Test Case failing with JMockit "Invalid context for the recording of expectations"

The following TestNG (6.3) test case generates the error "Invalid context for the recording of expectations"
#Listeners({ Initializer.class })
public final class ClassUnderTestTest {
private ClassUnderTest cut;
#SuppressWarnings("unused")
#BeforeMethod
private void initialise() {
cut = new ClassUnderTest();
}
#Test
public void doSomething() {
new Expectations() {
MockedClass tmc;
{
tmc.doMethod("Hello"); result = "Hello";
}
};
String result = cut.doSomething();
assertEquals(result, "Hello");
}
}
The class under test is below.
public class ClassUnderTest {
MockedClass service = new MockedClass();
MockedInterface ifce = new MockedInterfaceImpl();
public String doSomething() {
return (String) service.doMethod("Hello");
}
public String doSomethingElse() {
return (String) ifce.testMethod("Hello again");
}
}
I am making the assumption that because I am using the #Listeners annotation that I do not require the javaagent command line argument. This assumption may be wrong....
Can anyone point out what I have missed?
The JMockit-TestNG Initializer must run once for the whole test run, so using #Listeners on individual test classes won't work.
Instead, simply upgrade to JMockit 0.999.11, which works transparently with TestNG 6.2+, without any need to specify a listener or the -javaagent parameter (unless running on JDK 1.5).