Skip to content

Commit 3636a30

Browse files
omacrangerLogan Graham
and
Logan Graham
authored
[Java] Integration tests (#233)
Co-authored-by: Logan Graham <[email protected]>
1 parent d4ae0aa commit 3636a30

File tree

15 files changed

+1947
-11
lines changed

15 files changed

+1947
-11
lines changed

.github/workflows/java-build.yml

+21-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,9 @@ jobs:
3737
run: mvn -B verify --file pom.xml
3838
if: matrix.version == '11'
3939

40-
integration-test:
40+
# Runs the ENV integration test, using our single test suite for all SDKs & a dockerfile for each.
41+
# Has specific expectations for a limited number of results so adding more here isn't ideal.
42+
integration-test-env:
4143
runs-on: ubuntu-latest
4244
steps:
4345
- uses: actions/checkout@v4
@@ -59,3 +61,21 @@ jobs:
5961
SAUCE_USERNAME: ${{ secrets.SAUCE_USERNAME }}
6062
SAUCE_ACCESS_KEY: ${{ secrets.SAUCE_ACCESS_KEY }}
6163
CONTAINER_IMAGE_NAME: saucelabs/visual-java
64+
65+
# Houses all the 'standard' integration tests for local & Sauce session support.
66+
integration-tests:
67+
runs-on: ubuntu-latest
68+
steps:
69+
- uses: actions/checkout@v4
70+
- name: Setup Java
71+
uses: actions/setup-java@v4
72+
with:
73+
distribution: 'temurin'
74+
java-version: '11'
75+
cache: 'maven'
76+
- name: Run integration tests
77+
env:
78+
SAUCE_USERNAME: ${{ secrets.SAUCE_USERNAME }}
79+
SAUCE_ACCESS_KEY: ${{ secrets.SAUCE_ACCESS_KEY }}
80+
run: |
81+
./mvnw -q test -Dtest=com.saucelabs.visual.integration.**

visual-java/Dockerfile

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,4 @@ COPY ./mvnw /workspace/
1010

1111
RUN ./mvnw -q clean test-compile
1212

13-
ENTRYPOINT ["./mvnw", "-q", "test" ,"-Dtest=com.saucelabs.visual.integration.**"]
13+
ENTRYPOINT ["./mvnw", "-q", "test" ,"-Dtest=com.saucelabs.visual.env.**"]

visual-java/pom.xml

+6
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,12 @@
8585
<version>7.5.1</version>
8686
<scope>provided</scope>
8787
</dependency>
88+
<dependency>
89+
<groupId>io.github.origin-energy</groupId>
90+
<artifactId>java-snapshot-testing-junit5</artifactId>
91+
<version>4.0.8</version>
92+
<scope>test</scope>
93+
</dependency>
8894

8995

9096
<dependency>

visual-java/src/main/java/com/saucelabs/visual/VisualApi.java

+21-8
Original file line numberDiff line numberDiff line change
@@ -522,8 +522,8 @@ public void check(String name, CheckOptions options) {
522522
*
523523
* @param snapshotName A name for the snapshot
524524
*/
525-
public void sauceVisualCheck(String snapshotName) {
526-
sauceVisualCheck(snapshotName, new CheckOptions());
525+
public String sauceVisualCheck(String snapshotName) {
526+
return sauceVisualCheck(snapshotName, new CheckOptions());
527527
}
528528

529529
/**
@@ -532,15 +532,15 @@ public void sauceVisualCheck(String snapshotName) {
532532
* @param snapshotName A name for the snapshot
533533
* @param options Options for the API
534534
*/
535-
public void sauceVisualCheck(String snapshotName, CheckOptions options) {
535+
public String sauceVisualCheck(String snapshotName, CheckOptions options) {
536536
if (isSauceSession()) {
537-
sauceVisualCheckSauce(snapshotName, options);
537+
return sauceVisualCheckSauce(snapshotName, options);
538538
} else {
539-
sauceVisualCheckLocal(snapshotName, options);
539+
return sauceVisualCheckLocal(snapshotName, options);
540540
}
541541
}
542542

543-
private void sauceVisualCheckSauce(String snapshotName, CheckOptions options) {
543+
private String sauceVisualCheckSauce(String snapshotName, CheckOptions options) {
544544
DiffingMethod diffingMethod = toDiffingMethod(options);
545545

546546
CreateSnapshotFromWebDriverMutation.CreateSnapshotFromWebDriverIn input =
@@ -598,10 +598,21 @@ private void sauceVisualCheckSauce(String snapshotName, CheckOptions options) {
598598
if (check != null && check.result != null) {
599599
uploadedDiffIds.addAll(
600600
check.result.diffs.getNodes().stream().map(Diff::getId).collect(Collectors.toList()));
601+
602+
return check.result.id;
601603
}
604+
605+
return null;
606+
}
607+
608+
/**
609+
* Expose execute binding directly, allowing queries to the Visual API using the existing client.
610+
*/
611+
public <D> D execute(GraphQLOperation operation, Class<D> responseType) {
612+
return this.client.execute(operation, responseType);
602613
}
603614

604-
private void sauceVisualCheckLocal(String snapshotName, CheckOptions options) {
615+
private String sauceVisualCheckLocal(String snapshotName, CheckOptions options) {
605616
Window window = new Window(this.driver);
606617
Rectangle viewport = window.getViewport();
607618

@@ -712,7 +723,9 @@ private void sauceVisualCheckLocal(String snapshotName, CheckOptions options) {
712723
.orElse(null))
713724
.withName(snapshotName)
714725
.build());
715-
this.client.execute(snapshotMutation, CreateSnapshotMutation.Data.class);
726+
CreateSnapshotMutation.Data result =
727+
this.client.execute(snapshotMutation, CreateSnapshotMutation.Data.class);
728+
return result.result.getId();
716729
}
717730

718731
/** Parse the Selenium parsed value from window.devicePixelRatio into a Double for our API */

visual-java/src/main/java/com/saucelabs/visual/model/FullPageScreenshotConfig.java

+2
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ public class FullPageScreenshotConfig {
1818
private SelectorIn nativeClipSelector;
1919
private ScrollOption scrollOption;
2020

21+
public FullPageScreenshotConfig() {}
22+
2123
public FullPageScreenshotConfig(
2224
int delayAfterScrollMs,
2325
Boolean disableCSSAnimation,

visual-java/src/test/java/com/saucelabs/visual/integration/LoginPageIT.java renamed to visual-java/src/test/java/com/saucelabs/visual/env/LoginPageIT.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package com.saucelabs.visual.integration;
1+
package com.saucelabs.visual.env;
22

33
import com.saucelabs.saucebindings.SaucePlatform;
44
import com.saucelabs.saucebindings.UnhandledPromptBehavior;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package com.saucelabs.visual.integration;
2+
3+
import com.fasterxml.jackson.annotation.JsonCreator;
4+
import com.fasterxml.jackson.core.JsonProcessingException;
5+
import com.fasterxml.jackson.databind.ObjectMapper;
6+
import com.fasterxml.jackson.databind.SerializationFeature;
7+
import com.saucelabs.visual.graphql.GraphQLOperation;
8+
import com.saucelabs.visual.graphql.type.DiffStatus;
9+
import java.util.Collections;
10+
import java.util.LinkedHashMap;
11+
import java.util.Map;
12+
13+
class CheckSnapshotOperation implements GraphQLOperation {
14+
private final String snapshotId;
15+
16+
public CheckSnapshotOperation(String snapshotId) {
17+
this.snapshotId = snapshotId;
18+
}
19+
20+
@Override
21+
public String getQuery() {
22+
return "query GetSnapshot($snapshotId: UUID!) { snapshot(id: $snapshotId) { name suiteName testName operatingSystem operatingSystemVersion device devicePixelRatio hasDom diffs { nodes { status diffClusters { x y width height } } } ignoreRegions { x y width height } } }";
23+
}
24+
25+
@Override
26+
public Map<String, Object> getVariables() {
27+
return Collections.singletonMap("snapshotId", snapshotId);
28+
}
29+
30+
static class Result {
31+
String data;
32+
DiffStatus status;
33+
34+
@JsonCreator
35+
Result(LinkedHashMap<String, LinkedHashMap> data) throws JsonProcessingException {
36+
this.data =
37+
new ObjectMapper().enable(SerializationFeature.INDENT_OUTPUT).writeValueAsString(data);
38+
status =
39+
DiffStatus.valueOf(
40+
new ObjectMapper()
41+
.readTree(this.data)
42+
.at("/snapshot/diffs/nodes/0")
43+
.get("status")
44+
.textValue());
45+
}
46+
}
47+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package com.saucelabs.visual.integration;
2+
3+
import au.com.origin.snapshots.Expect;
4+
import au.com.origin.snapshots.junit5.SnapshotExtension;
5+
import com.saucelabs.visual.CheckOptions;
6+
import com.saucelabs.visual.junit5.TestMetaInfoExtension;
7+
import org.junit.jupiter.api.BeforeAll;
8+
import org.junit.jupiter.api.Test;
9+
import org.junit.jupiter.api.extension.ExtendWith;
10+
import org.openqa.selenium.By;
11+
12+
@ExtendWith({TestMetaInfoExtension.class, SnapshotExtension.class})
13+
public class ClippingIT extends IntegrationBase {
14+
Expect expect;
15+
16+
@BeforeAll
17+
public static void login() {
18+
LoginPage loginPage = new LoginPage();
19+
loginPage.open();
20+
loginPage.login();
21+
InventoryLongPage inventoryPage = new InventoryLongPage();
22+
inventoryPage.open();
23+
}
24+
25+
@Test
26+
public void clipToSelectorOnThePage() {
27+
String id =
28+
sauceVisualCheck(
29+
"Clipped selector",
30+
new CheckOptions.Builder().withClipSelector(".inventory_list").build());
31+
String result = getSnapshotResult(id);
32+
expect.toMatchSnapshot(result);
33+
}
34+
35+
@Test
36+
public void clipToElementOnThePage() {
37+
String id =
38+
sauceVisualCheck(
39+
"Clipped element",
40+
new CheckOptions.Builder()
41+
.withClipElement(driver.findElement(By.cssSelector(".inventory_list")))
42+
.build());
43+
String result = getSnapshotResult(id);
44+
expect.toMatchSnapshot(result);
45+
}
46+
47+
@Test
48+
public void scrollToElementBeforeClipping() {
49+
String id =
50+
sauceVisualCheck(
51+
"Scroll to element before clipping",
52+
new CheckOptions.Builder()
53+
.withClipElement(
54+
driver.findElement(By.cssSelector(".inventory_item:nth-child(21)")))
55+
.build());
56+
String result = getSnapshotResult(id);
57+
expect.toMatchSnapshot(result);
58+
}
59+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package com.saucelabs.visual.integration;
2+
3+
import au.com.origin.snapshots.Expect;
4+
import au.com.origin.snapshots.junit5.SnapshotExtension;
5+
import com.saucelabs.visual.CheckOptions;
6+
import com.saucelabs.visual.junit5.TestMetaInfoExtension;
7+
import com.saucelabs.visual.model.FullPageScreenshotConfig;
8+
import org.junit.jupiter.api.BeforeAll;
9+
import org.junit.jupiter.api.Test;
10+
import org.junit.jupiter.api.extension.ExtendWith;
11+
12+
@ExtendWith({TestMetaInfoExtension.class, SnapshotExtension.class})
13+
public class FullPageScreenshotIT extends IntegrationBase {
14+
Expect expect;
15+
16+
@BeforeAll
17+
public static void login() {
18+
LoginPage loginPage = new LoginPage();
19+
loginPage.open();
20+
loginPage.login();
21+
InventoryLongPage inventoryPage = new InventoryLongPage();
22+
inventoryPage.open();
23+
}
24+
25+
@Test
26+
public void takeAFPSWithDefaultSettings() {
27+
String id =
28+
sauceVisualCheck(
29+
"FPS",
30+
new CheckOptions.Builder().withFullPageConfig(new FullPageScreenshotConfig()).build());
31+
String result = getSnapshotResult(id);
32+
expect.toMatchSnapshot(result);
33+
}
34+
35+
@Test
36+
public void takeAFPSAndDisplayScrollBars() {
37+
String id =
38+
sauceVisualCheck(
39+
"FPS hideScrollBars=false",
40+
new CheckOptions.Builder()
41+
.withHideScrollBars(false)
42+
.withFullPageConfig(new FullPageScreenshotConfig())
43+
.build());
44+
String result = getSnapshotResult(id);
45+
expect.toMatchSnapshot(result);
46+
}
47+
48+
@Test
49+
public void takeAFPSWithScrollLimit() {
50+
String id =
51+
sauceVisualCheck(
52+
"FPS scrollLimit=1",
53+
new CheckOptions.Builder()
54+
.withHideScrollBars(true)
55+
.withFullPageConfig(new FullPageScreenshotConfig())
56+
.build());
57+
String result = getSnapshotResult(id);
58+
expect.toMatchSnapshot(result);
59+
}
60+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
package com.saucelabs.visual.integration;
2+
3+
import au.com.origin.snapshots.Expect;
4+
import au.com.origin.snapshots.junit5.SnapshotExtension;
5+
import com.saucelabs.visual.CheckOptions;
6+
import com.saucelabs.visual.junit5.TestMetaInfoExtension;
7+
import com.saucelabs.visual.model.FullPageScreenshotConfig;
8+
import org.junit.jupiter.api.BeforeAll;
9+
import org.junit.jupiter.api.Test;
10+
import org.junit.jupiter.api.extension.ExtendWith;
11+
import org.openqa.selenium.By;
12+
13+
@ExtendWith({TestMetaInfoExtension.class, SnapshotExtension.class})
14+
public class IgnoreRegionsIT extends IntegrationBase {
15+
Expect expect;
16+
17+
@BeforeAll
18+
public static void login() {
19+
LoginPage loginPage = new LoginPage();
20+
loginPage.open();
21+
loginPage.login();
22+
InventoryLongPage inventoryPage = new InventoryLongPage();
23+
inventoryPage.open();
24+
}
25+
26+
final By ignoreSelectors = By.cssSelector(".inventory_item_img,.btn_inventory");
27+
28+
@Test
29+
public void checkDefaultStandardIgnoreRegions() {
30+
String id =
31+
sauceVisualCheck(
32+
"Standard",
33+
new CheckOptions.Builder()
34+
.withIgnoreElements(driver.findElements(ignoreSelectors))
35+
.build());
36+
String result = getSnapshotResult(id);
37+
expect.toMatchSnapshot(result);
38+
}
39+
40+
@Test
41+
public void checkPositionRegionsOnClippedSnapshot() {
42+
String id =
43+
sauceVisualCheck(
44+
"Clipped",
45+
new CheckOptions.Builder()
46+
.withClipElement(driver.findElement(By.cssSelector(".inventory_list")))
47+
.withIgnoreElements(driver.findElements(ignoreSelectors))
48+
.build());
49+
String result = getSnapshotResult(id);
50+
expect.toMatchSnapshot(result);
51+
}
52+
53+
@Test
54+
public void checkPositionRegionsOnFPS() {
55+
String id =
56+
sauceVisualCheck(
57+
"FPS",
58+
new CheckOptions.Builder()
59+
.withFullPageConfig(new FullPageScreenshotConfig.Builder().build())
60+
.withIgnoreElements(driver.findElements(ignoreSelectors))
61+
.build());
62+
String result = getSnapshotResult(id);
63+
expect.toMatchSnapshot(result);
64+
}
65+
66+
@Test
67+
public void checkPositionRegionsOnFPSWhenClipped() {
68+
String id =
69+
sauceVisualCheck(
70+
"Clipped (FPS)",
71+
new CheckOptions.Builder()
72+
.withFullPageConfig(new FullPageScreenshotConfig.Builder().build())
73+
.withIgnoreElements(driver.findElements(ignoreSelectors))
74+
.withClipElement(driver.findElement(By.cssSelector(".inventory_list")))
75+
.build());
76+
String result = getSnapshotResult(id);
77+
expect.toMatchSnapshot(result);
78+
}
79+
80+
@Test
81+
public void checkPositionRegionsOnFPSWhenScrolledPriorToClip() {
82+
driver.executeScript("window.scrollBy(0, 100)");
83+
84+
String id =
85+
sauceVisualCheck(
86+
"FPS (scrolled)",
87+
new CheckOptions.Builder()
88+
.withFullPageConfig(new FullPageScreenshotConfig.Builder().build())
89+
.withIgnoreElements(driver.findElements(ignoreSelectors))
90+
.withClipElement(driver.findElement(By.cssSelector(".inventory_list")))
91+
.build());
92+
String result = getSnapshotResult(id);
93+
expect.toMatchSnapshot(result);
94+
}
95+
}

0 commit comments

Comments
 (0)