We've seen how to use Applitools as a replacement for our own homegrown visual validation framework; now let's examine a couple of the more advanced features it provides.
First, let's explore one more awesome aspect of the Applitools SDK which goes above and beyond what we were able to do with Appium on our own, namely, the ability to compare full-screen images.
To make this work, we have to add basically one line to our code. What we're going to do is, before we start our visual testing session, tell the Eyes SDK that we want to use full-page screenshots.
We do that by calling a method [eyes.setForceFullPageScreenshot
] on the Eyes SDK.
To see this in action, let's open up a new test. This one is called “ApplitoolsFullPageTest.java”.
import io.appium.java_client.MobileBy;
import java.net.URISyntaxException;
import org.junit.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
public class ApplitoolsFullPageTest extends BaseApplitoolsTest {
private final static String CHECK_HOME = "home_screen_full";
private final static By LOGIN_SCREEN = MobileBy.AccessibilityId("Login Screen");
@Override
protected DesiredCapabilities getCaps() throws URISyntaxException {
DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setCapability("platformName", "Android");
capabilities.setCapability("deviceName", "Android Emulator");
capabilities.setCapability("automationName", "UiAutomator2");
capabilities.setCapability("app", getResource("apps/TheApp-v1.apk").toString());
// make sure we uninstall the app before each test regardless of version
capabilities.setCapability("uninstallOtherPackages", "io.cloudgrey.the_app");
return capabilities;
}
private WebElement waitForElement(WebDriverWait wait, By selector) {
WebElement el = wait.until(ExpectedConditions.presenceOfElementLocated(selector));
try { Thread.sleep(750); } catch (InterruptedException ign) {}
return el;
}
@Test
public void testFullPageHomeScreen() {
eyes.setForceFullPageScreenshot(true);
eyes.open(driver, "TheApp", "full page home screen test");
WebDriverWait wait = new WebDriverWait(driver, 5);
// wait for an element that's on the home screen
waitForElement(wait, LOGIN_SCREEN);
// now we know the home screen is loaded, so do a visual check
eyes.checkWindow(CHECK_HOME);
eyes.close();
}
}
I've switched to this new file, which is very similar to the last test we looked at. The main difference here is we are just looking at the home screen, not the login screen as well, so we're only doing one visual check.
I've also changed the name of our visual check to “home_screen_full” and the name of the test to “testFullPageHomeScreen” so that it shows up separately on the Applitools website from what we did previously.
Otherwise, the important change is here, at the beginning of our test method where we call the Eyes SDK method — `eyes.setForceFullPageScreenshot(true)’ — to true, so that's it.
Let's give this a run and see what happens, and note that we're currently using V1 of the app.
Again, we'll be running on our local Appium instance using our local Android emulator.
Great. The test is running, and we won't really see anything happen in this test because we're just dealing with the home screen.
But if we go back to IntelliJ, we'll see that, indeed, the test passed, which is what we expected.
Now, let's run the app again with version 2 so we can compare.
And we have a failure as expected.
So let's go check it out by clicking the link that's provided by the SDK.
Wow, there's a lot of pink here!
It's a bit hard to see exactly what changed, so I'm going to change the view mode to show both the baseline and the current screenshot using show both.
Aha, we can easily tell the problem now.
There were actually multiple new list items added in V2 of the app. Our previous test only caught that there was a single edition, this geolocation demo.
But the Eyes SDK actually scrolled the list for us, which you might have seen as the test was proceeding, and it stitched the screenshots into one coherent full-page image.
You can tell that the dimensions are different. Because the full-screen image and the non-full-screen image are different lengths. There's a huge amount of visual difference between the two, but it's pretty easy for our eyes to see what happened.
So, at this point, I can accept the change and save the new baseline just as we did before, so I'll click the Save button.
Now, let's take a look at a feature which is very useful as tests change and grow over time, and that's the ability to ignore certain regions of a screenshot.
To illustrate this, I'm going to run a very simple visual test of another portion of the test app we've been using.
First of all, let's look at the behavior I want to automate. I'll load up the app.
In this test, we're going to navigate to the echo box, which is simply a place where we can type something in a box, and have it displayed back to us.
For example, we can type in, "Hi," and it will say, "Hi,” back to us. I'm going to test this feature with Appium functionally as well as using Applitools visually, so let's check out the test.
Back in IntelliJ, I'm going to open up a new file called “ApplitoolsIgnoreTest.java”.
import io.appium.java_client.MobileBy;
import java.net.URISyntaxException;
import org.junit.Assert;
import org.junit.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
public class ApplitoolsIgnoreTest extends BaseApplitoolsTest {
private final static String CHECK_MSG = "saved_message";
private final static By ECHO_SCREEN = MobileBy.AccessibilityId("Echo Box");
private final static By MSG_BOX = MobileBy.AccessibilityId("messageInput");
private final static By SAVE_BTN = MobileBy.AccessibilityId("messageSaveBtn");
@Override
protected DesiredCapabilities getCaps() throws URISyntaxException {
DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setCapability("platformName", "Android");
capabilities.setCapability("deviceName", "Android Emulator");
capabilities.setCapability("automationName", "UiAutomator2");
capabilities.setCapability("app", getResource("apps/TheApp-v2.apk").toString());
// make sure we uninstall the app before each test regardless of version
capabilities.setCapability("uninstallOtherPackages", "io.cloudgrey.the_app");
return capabilities;
}
@Test
public void testIgnoredRegion() {
String msg = "hello";
eyes.open(driver, "TheApp", "saved message test");
WebDriverWait wait = new WebDriverWait(driver, 5);
// wait for an element that's on the home screen
wait.until(ExpectedConditions.presenceOfElementLocated(ECHO_SCREEN)).click();
wait.until(ExpectedConditions.presenceOfElementLocated(MSG_BOX)).sendKeys(msg);
driver.findElement(SAVE_BTN).click();
WebElement savedMsg = wait.until(ExpectedConditions.presenceOfElementLocated(MobileBy.AccessibilityId(msg)));
Assert.assertEquals(msg, savedMsg.getText());
// now we know the home screen is loaded, so do a visual check
eyes.checkWindow(CHECK_MSG);
eyes.close();
}
}
Of course, it's very similar to our previous tests.
I simply have a few new constants up top. The name we're going to give the particular Applitools check will differ, and the elements we need to interact with will also differ, so we just define them up here.
We're starting the same app, so our getCaps
method is all the same.
Now, let's take a look at the test.
First of all, we define the String that we're going to type, namely, “hello”, and validate the functional test against.
Then we initiate the Eyes SDK.
Then we navigate to the "Echo Screen" using WebDriver waits
and element interactions, all the typical Appium stuff you're already familiar with.
Finally, we type our String into the box, click the submit button, and then assert that the text which is displayed matches what we typed.
This constitutes a functional test to this feature, but we also want a visual test, so we call eyes.checkWindow
to make sure that in subsequent runs of this test we get a check of the visual design as well.
Let's go ahead and run this.
We can watch the test as it runs and does its thing, and here's our message, which we saved, and as we expected, from IntelliJ's perspective, we got a pass.
Okay, now let's change things up again.
What if one day we decide we want to change the String being tested?
** **For example, let's change “hello” to “world” [String msg = "world";
].
Functionally, everything should work because we're just reusing the variable that holds the String in our sendKeys
as well as our assertion. but, visually, we might run into a problem because a screen with the text “hello” on it does not match a screen with the text “world” on it. So, what do we do?
Let's first run it and see what happens.
Okay, here, we typed in our new String, and we're sending the screenshot to Applitools, and we've got a failure as expected
And, indeed, it is the Applitools' failure of visual differences. So, let's follow the link and see what happened.
Now that we've clicked into the test case, we can see that, yes, the difference between these Strings, “hello” and “world”, is the problem. So, what to do?
We can direct Applitools to ignore certain regions of the screen so that differences in those regions don't count as a failure when it's matched against the baseline.
Let's try to ignore these regions now.
We do that by clicking this box icon here and drawing different boxes, so I'm going to draw one here, which will be ignored.
And I'll draw another one here.
Great. Now, I'm going to say that this change was actually okay and save it because it wasn't a visual bug, it was just different texts. Now I'll save the change.
To see whether this worked, let's go back and try yet another String in our test. Let's try the string “Appium” and run the test again.
If all goes well, the functional part of the test will pass, proving indeed that we typed “Appium”; and the visual part of the test will also pass, proving that the new and different text was appropriately ignored.
There we go, and what does IntelliJ say? We have a pass. Excellent.
This is how we can get some advanced visual testing going with our mobile apps. There's lots more to explore in this world, so definitely check out the other courses on this subject from Test Automation University.
Okay, we're done.
Congratulations on making it this far.
It's been a pleasure to go through this course with you.
Don't forget to sign up for the Appium Pro newsletter at appiumpro.com to keep up to date with all kinds of mobile testing tips and tutorials, and reach out to us at Cloud Grey if you have any further mobile automation strategy questions or needs.
Cheers and happy testing.