package ru.yandex.qatools.ashot.shooting;
import org.hamcrest.Matchers;
import org.junit.Before;
import org.junit.Test;
import org.mockito.MockSettings;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.WebDriver;
import ru.yandex.qatools.ashot.coordinates.Coords;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
import static java.awt.image.BufferedImage.TYPE_4BYTE_ABGR_PRE;
import static java.util.Collections.singleton;
import static org.hamcrest.CoreMatchers.everyItem;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
import static org.mockito.Mockito.*;
public class VerticalPastingShootingStrategyTest {
private static final int VIEWPORT_HEIGHT = 80;
private static final int DEFAULT_PAGE_HEIGHT = VIEWPORT_HEIGHT * 10 + VIEWPORT_HEIGHT / 2;
private static final int PAGE_WIDTH = 100;
private static final int DEFAULT_COORDS_INDENT = VIEWPORT_HEIGHT / 2;
private static final double DEFAULT_COORDS_SHIFT = DEFAULT_COORDS_INDENT / 2;
private static final int SHOOT_COORDS_OFFSET_Y = VIEWPORT_HEIGHT * 4;
private MockSettings wdSettings = withSettings().extraInterfaces(JavascriptExecutor.class, TakesScreenshot.class);
private WebDriver wd = mock(WebDriver.class, wdSettings);
private BufferedImage viewPortShot = new BufferedImage(PAGE_WIDTH, VIEWPORT_HEIGHT, TYPE_4BYTE_ABGR_PRE);
private Set<Coords> coordsSet;
private BufferedImage screenshot;
private Set<Coords> preparedCoords;
private MockVerticalPastingShootingDecorator shootingStrategy;
private Coords shootingCoords;
@Before
public void setUp() throws Exception {
coordsSet = new HashSet<>();
MockVerticalPastingShootingDecorator shootingStrategy =
new MockVerticalPastingShootingDecorator(new SimpleShootingStrategy());
shootingStrategy.withScrollTimeout(0);
this.shootingStrategy = spy(shootingStrategy);
when(((TakesScreenshot) wd).getScreenshotAs(any(OutputType.class))).thenReturn(getImageAsBytes());
}
@Test
public void testCoordsShiftWithDefaultIndent() throws Exception {
givenCoordsWithHeight(VIEWPORT_HEIGHT / 3);
whenTakingScreenshot(shootingCoords);
whenPreparingCoords(singleton(shootingCoords));
thenCoordsShiftedWith(DEFAULT_COORDS_SHIFT);
}
@Test
public void testTimesWhenCoordsEqualsViewport() throws Exception {
givenCoordsWithHeight(VIEWPORT_HEIGHT);
whenTakingScreenshot(shootingCoords);
thenScrollTimes(2);
thenShootTimes(2);
}
@Test
public void testTimesWhenCoordsLargerThanViewport() throws Exception {
givenCoordsWithHeight(VIEWPORT_HEIGHT * 3);
whenTakingScreenshot(shootingCoords);
thenScrollTimes(4);
thenShootTimes(4);
}
@Test
public void testTimesWhenCoordsLessThanViewport() throws Exception {
givenCoordsWithHeight(VIEWPORT_HEIGHT / 2);
whenTakingScreenshot(shootingCoords);
thenScrollTimes(1);
thenShootTimes(1);
}
@Test
public void testScreenshotHeight() throws Exception {
givenCoordsWithHeight(VIEWPORT_HEIGHT / 3);
whenTakingScreenshot(shootingCoords);
thenScreenshotIsHeight(VIEWPORT_HEIGHT / 3 + DEFAULT_COORDS_INDENT);
}
@Test
public void testScreenshotCoordsZeroHeight() throws Exception {
shootingCoords = new Coords(0, SHOOT_COORDS_OFFSET_Y, PAGE_WIDTH, 0);
whenTakingScreenshot(shootingCoords);
thenScreenshotIsHeight(DEFAULT_COORDS_INDENT);
}
@Test
public void testScreenshotFullPage() throws Exception {
whenTakingScreenshot();
thenShootTimes(11);
thenScrollTimes(11);
thenScreenshotIsHeight(DEFAULT_PAGE_HEIGHT);
}
private byte[] getImageAsBytes() throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(viewPortShot, "PNG", baos);
return baos.toByteArray();
}
private void givenCoordsWithHeight(int height) {
shootingCoords = new Coords(0, SHOOT_COORDS_OFFSET_Y, PAGE_WIDTH, height);
}
private void whenTakingScreenshot() {
screenshot = shootingStrategy.getScreenshot(wd);
}
private void whenTakingScreenshot(Coords coords) {
coordsSet.add(coords);
screenshot = shootingStrategy.getScreenshot(wd, coordsSet);
}
private void whenPreparingCoords(Set<Coords> coords) {
preparedCoords = shootingStrategy.prepareCoords(coords);
}
private void thenCoordsShiftedWith(double shootCoordsOffsetY) {
assertThat("Coords should be shifted correctly", preparedCoords, everyItem(Matchers.<Coords>hasProperty("y", Matchers.is(shootCoordsOffsetY))));
}
private void thenScreenshotIsHeight(int shotHeight) {
assertThat("Screenshot height should be correct", screenshot.getHeight(), is(shotHeight));
}
/**
* Math.ceil(DEFAULT_PAGE_HEIGHT / VIEWPORT_HEIGHT)
*/
private void thenScrollTimes(int times) {
verify(shootingStrategy, times(times)).scrollVertically(any(JavascriptExecutor.class), anyInt());
}
private void thenShootTimes(int times) {
verify(((TakesScreenshot) wd), times(times)).getScreenshotAs(any(OutputType.class));
}
class MockVerticalPastingShootingDecorator extends ViewportPastingDecorator {
int pageHeight = DEFAULT_PAGE_HEIGHT;
int pageWidth = PAGE_WIDTH;
int viewportHeight = VIEWPORT_HEIGHT;
int currentScrollY = 0;
public MockVerticalPastingShootingDecorator(ShootingStrategy strategy) {
super(strategy);
}
@Override
public int getFullHeight(WebDriver driver) {
return pageHeight;
}
@Override
public int getFullWidth(WebDriver driver) {
return pageWidth;
}
@Override
public int getWindowHeight(WebDriver driver) {
return viewportHeight;
}
@Override
public int getCurrentScrollY(JavascriptExecutor js) {
return currentScrollY;
}
}
}