-
-
Notifications
You must be signed in to change notification settings - Fork 35
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #155 from thc202/browsers-screenshots
Allow to obtain a screenshot from the browsers
Showing
4 changed files
with
487 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
154 changes: 154 additions & 0 deletions
154
src/main/java/org/mozilla/zest/core/v1/ZestClientScreenshot.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,154 @@ | ||
/* This Source Code Form is subject to the terms of the Mozilla Public | ||
* License, v. 2.0. If a copy of the MPL was not distributed with this | ||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | ||
package org.mozilla.zest.core.v1; | ||
|
||
import java.io.ByteArrayInputStream; | ||
import java.io.IOException; | ||
import java.nio.file.Files; | ||
import java.nio.file.Paths; | ||
import java.util.Base64; | ||
|
||
import org.openqa.selenium.OutputType; | ||
import org.openqa.selenium.TakesScreenshot; | ||
import org.openqa.selenium.WebDriver; | ||
|
||
/** | ||
* A {@link ZestClient} action that takes a screenshot. | ||
* <p> | ||
* The screenshot can be saved to a file and/or to a variable (for the latter Base64 encoded). | ||
* | ||
* @since 0.14 | ||
*/ | ||
public class ZestClientScreenshot extends ZestClient { | ||
|
||
private String windowHandle; | ||
private String filePath; | ||
private String variableName; | ||
|
||
/** | ||
* Constructs a {@code ZestClientScreenshot} with no file path nor variable name. | ||
*/ | ||
public ZestClientScreenshot() { | ||
super(); | ||
} | ||
|
||
/** | ||
* Constructs a {@code ZestClientScreenshot} with the given file path and variable name. | ||
* | ||
* @param windowHandle the window handle to obtain the client. | ||
* @param filePath the path to the file where to save the screenshot, might be {@code null}. | ||
* @param variableName the name of the variable where to save the screenshot (Base64 encoded), might be {@code null}. | ||
*/ | ||
public ZestClientScreenshot(String windowHandle, String filePath, String variableName) { | ||
super(); | ||
this.windowHandle = windowHandle; | ||
this.filePath = filePath; | ||
this.variableName = variableName; | ||
} | ||
|
||
/** | ||
* Gets the window handle. | ||
* | ||
* @return the window handle, might be {@code null}. | ||
*/ | ||
public String getWindowHandle() { | ||
return windowHandle; | ||
} | ||
|
||
/** | ||
* Sets the window handle. | ||
* | ||
* @param windowHandle the new window handle. | ||
*/ | ||
public void setWindowHandle(String windowHandle) { | ||
this.windowHandle = windowHandle; | ||
} | ||
|
||
/** | ||
* Gets the path to the file. | ||
* | ||
* @return the path to the file, might be {@code null}. | ||
*/ | ||
public String getFilePath() { | ||
return filePath; | ||
} | ||
|
||
/** | ||
* Sets the path to the file. | ||
* <p> | ||
* Variables are replaced before using the path. | ||
* | ||
* @param filePath the path to the file. | ||
*/ | ||
public void setFilePath(String filePath) { | ||
this.filePath = filePath; | ||
} | ||
|
||
/** | ||
* Gets the name of the variable. | ||
* | ||
* @return the name of the variable, might be {@code null}. | ||
*/ | ||
public String getVariableName() { | ||
return variableName; | ||
} | ||
|
||
/** | ||
* Sets the name of the variable. | ||
* | ||
* @param variableName the name of the variable. | ||
*/ | ||
public void setVariableName(String variableName) { | ||
this.variableName = variableName; | ||
} | ||
|
||
@Override | ||
public String invoke(ZestRuntime runtime) throws ZestClientFailException { | ||
WebDriver wd = runtime.getWebDriver(this.getWindowHandle()); | ||
if (wd == null) { | ||
throw new ZestClientFailException(this, "No client: " + runtime.getVariable(getWindowHandle())); | ||
} | ||
if (!(wd instanceof TakesScreenshot)) { | ||
throw new ZestClientFailException( | ||
this, | ||
"Client does not take screenshots: " + runtime.getVariable(getWindowHandle())); | ||
} | ||
|
||
boolean saveToVariable = variableName != null && !variableName.isEmpty(); | ||
boolean saveToFile = filePath != null && !filePath.isEmpty(); | ||
if (!saveToVariable && !saveToFile) { | ||
throw new ZestClientFailException(this, "No file nor variable specified."); | ||
} | ||
|
||
byte[] screenshot = ((TakesScreenshot) wd).getScreenshotAs(OutputType.BYTES); | ||
|
||
if (saveToVariable) { | ||
runtime.setVariable(variableName, Base64.getEncoder().encodeToString(screenshot)); | ||
} | ||
|
||
if (saveToFile) { | ||
String finalFilePath = runtime.replaceVariablesInString(filePath, false); | ||
try { | ||
Files.copy(new ByteArrayInputStream(screenshot), Paths.get(finalFilePath)); | ||
} catch (IOException e) { | ||
throw new ZestClientFailException(this, "Failed to save the screenshot to file.", e); | ||
} | ||
} | ||
|
||
return null; | ||
} | ||
|
||
@Override | ||
public ZestClientScreenshot deepCopy() { | ||
ZestClientScreenshot copy = new ZestClientScreenshot(getWindowHandle(), getFilePath(), getVariableName()); | ||
copy.setEnabled(isEnabled()); | ||
return copy; | ||
} | ||
|
||
@Override | ||
public boolean isPassive() { | ||
return true; | ||
} | ||
|
||
} |
318 changes: 318 additions & 0 deletions
318
src/test/java/org/mozilla/zest/test/v1/ZestClientScreenshotUnitTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,318 @@ | ||
/* This Source Code Form is subject to the terms of the Mozilla Public | ||
* License, v. 2.0. If a copy of the MPL was not distributed with this | ||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | ||
package org.mozilla.zest.test.v1; | ||
|
||
import static org.junit.Assert.assertEquals; | ||
import static org.junit.Assert.assertTrue; | ||
import static org.mockito.ArgumentMatchers.any; | ||
import static org.mockito.Mockito.mock; | ||
import static org.mockito.Mockito.verify; | ||
import static org.mockito.Mockito.when; | ||
import static org.mockito.Mockito.withSettings; | ||
|
||
import java.nio.file.Files; | ||
import java.nio.file.Path; | ||
import java.util.Arrays; | ||
|
||
import org.junit.Rule; | ||
import org.junit.Test; | ||
import org.junit.rules.TemporaryFolder; | ||
import org.mozilla.zest.core.v1.ZestClientFailException; | ||
import org.mozilla.zest.core.v1.ZestClientScreenshot; | ||
import org.mozilla.zest.core.v1.ZestJSON; | ||
import org.mozilla.zest.core.v1.ZestRuntime; | ||
import org.openqa.selenium.TakesScreenshot; | ||
import org.openqa.selenium.WebDriver; | ||
|
||
/** | ||
* Unit test for {@link ZestClientScreenshot}. | ||
*/ | ||
public class ZestClientScreenshotUnitTest { | ||
|
||
private static final byte[] SCREENSHOT_DATA = { 0x00, 0x01, 0x02 }; | ||
private static final String SCREENSHOT_DATA_BASE_64 = "AAEC"; | ||
|
||
@Rule | ||
public TemporaryFolder folder = new TemporaryFolder(); | ||
|
||
@Test | ||
public void shouldBePassive() { | ||
// Given / When | ||
ZestClientScreenshot clientScreenshot = new ZestClientScreenshot(); | ||
// Then | ||
assertEquals(true, clientScreenshot.isPassive()); | ||
} | ||
|
||
@Test | ||
public void shouldNotHaveWindowHandleByDefault() { | ||
// Given / When | ||
ZestClientScreenshot clientScreenshot = new ZestClientScreenshot(); | ||
// Then | ||
assertEquals(null, clientScreenshot.getWindowHandle()); | ||
} | ||
|
||
@Test | ||
public void shouldNotHaveFilePathByDefault() { | ||
// Given / When | ||
ZestClientScreenshot clientScreenshot = new ZestClientScreenshot(); | ||
// Then | ||
assertEquals(null, clientScreenshot.getFilePath()); | ||
} | ||
|
||
@Test | ||
public void shouldNotHaveVariableNameByDefault() { | ||
// Given / When | ||
ZestClientScreenshot clientScreenshot = new ZestClientScreenshot(); | ||
// Then | ||
assertEquals(null, clientScreenshot.getVariableName()); | ||
} | ||
|
||
@Test | ||
public void shouldBeEnabledByDefault() { | ||
// Given / When | ||
ZestClientScreenshot clientScreenshot = new ZestClientScreenshot(); | ||
// Then | ||
assertEquals(true, clientScreenshot.isEnabled()); | ||
} | ||
|
||
@Test | ||
public void shouldConstructWithFilePathAndVariableName() { | ||
// Given | ||
String windowHandle = "windowHandle"; | ||
String filePath = "/path"; | ||
String variableName = "variableName"; | ||
// When | ||
ZestClientScreenshot clientScreenshot = new ZestClientScreenshot(windowHandle, filePath, variableName); | ||
// Then | ||
assertEquals(windowHandle, clientScreenshot.getWindowHandle()); | ||
assertEquals(filePath, clientScreenshot.getFilePath()); | ||
assertEquals(variableName, clientScreenshot.getVariableName()); | ||
} | ||
|
||
@Test | ||
public void shouldSetWindowHandle() { | ||
// Given | ||
String windowHandle = "windowHandle"; | ||
ZestClientScreenshot clientScreenshot = new ZestClientScreenshot(); | ||
// When | ||
clientScreenshot.setWindowHandle(windowHandle); | ||
// Then | ||
assertEquals(windowHandle, clientScreenshot.getWindowHandle()); | ||
} | ||
|
||
@Test | ||
public void shouldSetFilePath() { | ||
// Given | ||
String filePath = "/path"; | ||
ZestClientScreenshot clientScreenshot = new ZestClientScreenshot(); | ||
// When | ||
clientScreenshot.setFilePath(filePath); | ||
// Then | ||
assertEquals(filePath, clientScreenshot.getFilePath()); | ||
} | ||
|
||
@Test | ||
public void shouldSetVariableName() { | ||
// Given | ||
String variableName = "variableName"; | ||
ZestClientScreenshot clientScreenshot = new ZestClientScreenshot(); | ||
// When | ||
clientScreenshot.setVariableName("variableName"); | ||
// Then | ||
assertEquals(variableName, clientScreenshot.getVariableName()); | ||
} | ||
|
||
@Test | ||
public void shouldSetEnabled() { | ||
// Given | ||
boolean enabled = false; | ||
ZestClientScreenshot clientScreenshot = new ZestClientScreenshot(); | ||
// When | ||
clientScreenshot.setEnabled(enabled); | ||
// Then | ||
assertEquals(enabled, clientScreenshot.isEnabled()); | ||
} | ||
|
||
@Test(expected = NullPointerException.class) | ||
public void shouldFailWhenInvokingWithNullRuntime() throws Exception { | ||
// Given | ||
ZestClientScreenshot clientScreenshot = new ZestClientScreenshot("handle", "/path", "variableName"); | ||
ZestRuntime runtime = null; | ||
// When | ||
clientScreenshot.invoke(runtime); | ||
// Then = NullPointerException | ||
} | ||
|
||
@Test(expected = ZestClientFailException.class) | ||
public void shouldFailToInvokeIfWindowHandleNotAvailable() throws Exception { | ||
// Given | ||
ZestClientScreenshot clientScreenshot = new ZestClientScreenshot("handle", "/path", "variableName"); | ||
ZestRuntime runtime = runtime(); | ||
// When | ||
clientScreenshot.invoke(runtime); | ||
// Then = ZestClientFailException | ||
} | ||
|
||
@Test(expected = ZestClientFailException.class) | ||
public void shouldFailToInvokeIfClientDoesNotTakeScreenshots() throws Exception { | ||
// Given | ||
String windowHandle = "handle"; | ||
ZestClientScreenshot clientScreenshot = new ZestClientScreenshot(windowHandle, "/path", "variableName"); | ||
ZestRuntime runtime = runtimeWithWebDriver(windowHandle); | ||
// When | ||
clientScreenshot.invoke(runtime); | ||
// Then = ZestClientFailException | ||
} | ||
|
||
@Test(expected = ZestClientFailException.class) | ||
public void shouldFailToInvokeIfClientTakeScreenshotsButFileAndVariableAreNull() throws Exception { | ||
// Given | ||
String windowHandle = "windowHandle"; | ||
ZestClientScreenshot clientScreenshot = new ZestClientScreenshot(windowHandle, null, null); | ||
ZestRuntime runtime = runtimeWithWebDriverThatTakesScreenshot(windowHandle); | ||
// When | ||
clientScreenshot.invoke(runtime); | ||
// Then = ZestClientFailException | ||
} | ||
|
||
@Test(expected = ZestClientFailException.class) | ||
public void shouldFailToInvokeIfClientTakeScreenshotsButFileAndVariableAreEmpty() throws Exception { | ||
// Given | ||
String windowHandle = "windowHandle"; | ||
ZestClientScreenshot clientScreenshot = new ZestClientScreenshot(windowHandle, "", ""); | ||
ZestRuntime runtime = runtimeWithWebDriverThatTakesScreenshot(windowHandle); | ||
// When | ||
clientScreenshot.invoke(runtime); | ||
// Then = ZestClientFailException | ||
} | ||
|
||
@Test(expected = ZestClientFailException.class) | ||
public void shouldFailToSaveScreenshotToFileAlreadyExists() throws Exception { | ||
// Given | ||
Path path = folder.newFile().toPath(); | ||
String windowHandle = "windowHandle"; | ||
String filePath = path.toString(); | ||
ZestClientScreenshot clientScreenshot = new ZestClientScreenshot(windowHandle, filePath, null); | ||
ZestRuntime runtime = runtimeWithWebDriverThatTakesScreenshot(windowHandle, SCREENSHOT_DATA); | ||
when(runtime.replaceVariablesInString(filePath, false)).thenReturn(filePath); | ||
// When | ||
clientScreenshot.invoke(runtime); | ||
// Then = ZestClientFailException | ||
} | ||
|
||
@Test(expected = ZestClientFailException.class) | ||
public void shouldFailToSaveScreenshotToFileDirectory() throws Exception { | ||
// Given | ||
Path path = folder.newFolder().toPath(); | ||
String windowHandle = "windowHandle"; | ||
String filePath = path.toString(); | ||
ZestClientScreenshot clientScreenshot = new ZestClientScreenshot(windowHandle, filePath, null); | ||
ZestRuntime runtime = runtimeWithWebDriverThatTakesScreenshot(windowHandle, SCREENSHOT_DATA); | ||
when(runtime.replaceVariablesInString(filePath, false)).thenReturn(filePath); | ||
// When | ||
clientScreenshot.invoke(runtime); | ||
// Then = ZestClientFailException | ||
} | ||
|
||
@Test | ||
public void shouldSaveScreenshotToFile() throws Exception { | ||
// Given | ||
Path path = folder.getRoot().toPath().resolve("zcs-file-only.png"); | ||
String windowHandle = "windowHandle"; | ||
String filePath = path.toString(); | ||
ZestClientScreenshot clientScreenshot = new ZestClientScreenshot(windowHandle, filePath, null); | ||
ZestRuntime runtime = runtimeWithWebDriverThatTakesScreenshot(windowHandle, SCREENSHOT_DATA); | ||
when(runtime.replaceVariablesInString(filePath, false)).thenReturn(filePath); | ||
// When | ||
clientScreenshot.invoke(runtime); | ||
// Then | ||
assertTrue(Arrays.equals(SCREENSHOT_DATA, Files.readAllBytes(path))); | ||
} | ||
|
||
@Test | ||
public void shouldSaveScreenshotToVariable() throws Exception { | ||
// Given | ||
String windowHandle = "windowHandle"; | ||
String variableName = "variableName"; | ||
ZestClientScreenshot clientScreenshot = new ZestClientScreenshot(windowHandle, null, variableName); | ||
ZestRuntime runtime = runtimeWithWebDriverThatTakesScreenshot(windowHandle, SCREENSHOT_DATA); | ||
// When | ||
clientScreenshot.invoke(runtime); | ||
// Then | ||
verify(runtime).setVariable(variableName, SCREENSHOT_DATA_BASE_64); | ||
} | ||
|
||
@Test | ||
public void shouldSaveScreenshotToFileAndVariable() throws Exception { | ||
// Given | ||
Path path = folder.getRoot().toPath().resolve("zcs-file-var.png"); | ||
String windowHandle = "windowHandle"; | ||
String filePath = path.toString(); | ||
String variableName = "variableName"; | ||
ZestClientScreenshot clientScreenshot = new ZestClientScreenshot(windowHandle, filePath, variableName); | ||
ZestRuntime runtime = runtimeWithWebDriverThatTakesScreenshot(windowHandle, SCREENSHOT_DATA); | ||
when(runtime.replaceVariablesInString(filePath, false)).thenReturn(filePath); | ||
// When | ||
clientScreenshot.invoke(runtime); | ||
// Then | ||
verify(runtime).setVariable(variableName, SCREENSHOT_DATA_BASE_64); | ||
assertTrue(Arrays.equals(SCREENSHOT_DATA, Files.readAllBytes(path))); | ||
} | ||
|
||
@Test | ||
public void shouldSerialiseAndDeserialise() { | ||
// Given | ||
ZestClientScreenshot original = new ZestClientScreenshot("windowHandle", "/path", "variableName"); | ||
original.setEnabled(false); | ||
// When | ||
String serialisation = ZestJSON.toString(original); | ||
ZestClientScreenshot deserialised = (ZestClientScreenshot) ZestJSON.fromString(serialisation); | ||
// Then | ||
assertEquals(deserialised.getElementType(), original.getElementType()); | ||
assertEquals(deserialised.getWindowHandle(), original.getWindowHandle()); | ||
assertEquals(deserialised.getFilePath(), original.getFilePath()); | ||
assertEquals(deserialised.getVariableName(), original.getVariableName()); | ||
assertEquals(deserialised.isEnabled(), original.isEnabled()); | ||
} | ||
|
||
@Test | ||
public void shouldDeepCopy() throws Exception { | ||
// Given | ||
ZestClientScreenshot original = new ZestClientScreenshot("windowHandle", "/path", "variableName"); | ||
original.setEnabled(false); | ||
// When | ||
ZestClientScreenshot copy = original.deepCopy(); | ||
// Then | ||
assertTrue(copy != original); | ||
assertEquals(copy.getElementType(), original.getElementType()); | ||
assertEquals(copy.getWindowHandle(), original.getWindowHandle()); | ||
assertEquals(copy.getFilePath(), original.getFilePath()); | ||
assertEquals(copy.getVariableName(), original.getVariableName()); | ||
assertEquals(copy.isEnabled(), original.isEnabled()); | ||
} | ||
|
||
private static ZestRuntime runtime() { | ||
return mock(ZestRuntime.class); | ||
} | ||
|
||
private static ZestRuntime runtimeWithWebDriver(String windowHandle) { | ||
ZestRuntime runtime = runtime(); | ||
when(runtime.getWebDriver(windowHandle)).thenReturn(mock(WebDriver.class)); | ||
return runtime; | ||
} | ||
|
||
private static ZestRuntime runtimeWithWebDriverThatTakesScreenshot(String windowHandle) { | ||
ZestRuntime runtime = runtime(); | ||
when(runtime.getWebDriver(windowHandle)) | ||
.thenReturn(mock(WebDriver.class, withSettings().extraInterfaces(TakesScreenshot.class))); | ||
return runtime; | ||
} | ||
|
||
private static ZestRuntime runtimeWithWebDriverThatTakesScreenshot(String windowHandle, byte[] screenshotData) { | ||
ZestRuntime runtime = runtimeWithWebDriverThatTakesScreenshot(windowHandle); | ||
when(((TakesScreenshot) runtime.getWebDriver(windowHandle)).getScreenshotAs(any())).thenReturn(screenshotData); | ||
return runtime; | ||
} | ||
|
||
} |