Skip to content

Commit 7e352a3

Browse files
committed
blog: screenshot stabilisation article
1 parent efa6bb0 commit 7e352a3

File tree

2 files changed

+143
-0
lines changed

2 files changed

+143
-0
lines changed
+143
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
---
2+
title: "Stabilize Flaky Tests for Visual Testing"
3+
description: "Explore common use-cases responsible for flaky tests in visual testing and best practices to resolve them."
4+
category: Visual testing
5+
author: Jeremy Sfez
6+
date: 2024-02-15
7+
image: ./main.jpg
8+
imageAlt: Image not loaded
9+
---
10+
11+
Visual testing is the most efficient way to test your app as it's **fast** and **robust** (doesn't require maintenance). Yet, flaky tests create frustration and erode developers' trust in their testing suite, potentially leading to the abandonment of visual testing altogether. In this article, I'll describe the **common culprits responsible for flaky screenshots and how to fix them**. I'll also introduce [Argos](https://argos-ci.com)'s solutions to stabilize screenshots.
12+
13+
<MainImage />
14+
15+
## What is a Flaky Test?
16+
17+
In visual testing, a flaky test produces screenshots that differ randomly between test runs without any changes to the code. The common causes are often **network latency, lazy loading, animations, and dynamic content like dates and external scripts**.
18+
19+
#### Disclaimer
20+
21+
> [Flaky Tests mean Flaky UX](https://rauchg.com/2020/2019-in-review#flaky-tests-flaky-ux) — Guillermo Rauch
22+
23+
Flaky screenshots are usually a sign of underlying instability in the app's UI. To minimize flaky tests, the first step is to minimize random behaviors and ensure the UI is as stable as possible. For example, if you have a news website, you should rely on a stable dataset for your test environment.
24+
25+
## Network Latency
26+
27+
Network latency can cause flaky screenshots if assets (**font**, **images**, ...) are not fully loaded before the screenshot is taken.
28+
29+
<img
30+
src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5gm3x4uaymqhm3qunbm8.jpg"
31+
width={600}
32+
alt="font-not-loaded"
33+
/>
34+
35+
To stabilize screenshots, you must ensure your resources are fully loaded before capturing screenshots. For example, the `argosScreenshot` command waits for resources to load before taking a screenshot.
36+
37+
## Lazy Loading
38+
39+
Lazy loading can cause flaky screenshots if the screenshot is taken before the elements are fully loaded.
40+
41+
<img
42+
src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4nginqza6q17jvrqs16r.png"
43+
width={600}
44+
alt="loader"
45+
/>
46+
47+
To stabilize screenshots, use a loading indicator and wait for its removal before proceeding. [Aligning with ARIA specification](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-busy), I recommend using the `[aria-busy]` attribute on your loader component. At Argos, the `argosScreenshot` command delays the screenshot capture until all components with the `[aria-busy]` attribute are removed.
48+
49+
Example of a loader component:
50+
51+
```JavaScript
52+
<div id="loader" aria-busy />
53+
```
54+
55+
## Dynamic Content
56+
57+
By nature, dynamic elements like **dates or time** introduce variability in screenshots. The easiest solution is to hide these elements by injecting CSS before taking a screenshot. With Argos, you can use the `data-visual-test` attribute to hide these elements from the screenshot.
58+
59+
```JavaScript
60+
<div id="clock" data-visual-test="transparent">...</div>
61+
```
62+
63+
For dates, another solution is to use a fixed date for your test environment. You can see here [how to do it with Cypress](https://docs.cypress.io/api/commands/clock). But this solution is not always possible in a real-world scenario.
64+
65+
## Animation
66+
67+
Capturing a screenshot during an animation will lead to flaky screenshots. They must be either completed or paused before taking a screenshot. With Argos, CSS animations are automatically paused, but JavaScript animations require manual intervention or hiding with `data-visual-test`.
68+
69+
**Note**: If an animation causes layout shifts, it's recommended to remove it from the DOM with `data-visual-test="removed"` instead of merely hiding it with `data-visual-test="transparent"`.
70+
71+
## External Scripts and Iframes
72+
73+
External scripts and iframes (e.g. Intercom snippet) introduce flakiness due to network latency or rendering inconsistencies. There are several solutions to avoid flakiness, consider the following in this order:
74+
75+
1. Avoid loading external scripts in your test environment.
76+
2. Inject CSS to hide their UI impacts.
77+
78+
```JavaScript
79+
await argosScreenshot(page, "homepage", {
80+
argosCSS: `
81+
.__argos__ iframe {
82+
display: none;
83+
}
84+
`,
85+
});
86+
```
87+
88+
3. Wait for the iframe's content to be loaded before taking the screenshot. If you follow this path, I recommend reading [Debbie O'Brien](https://twitter.com/debs_obrien)'s article about how to [test an iframes with Playwright](https://debbie.codes/blog/testing-iframes-with-playwright/).
89+
90+
## Data inconsistency
91+
92+
The two main causes of data inconsistency are **randomized data seed** and **missing sorting order**. Usually, it's easy to fix by using a fixed dataset for your test environment. But if not, you can use the `data-visual-test` attribute to hide the area where the data is displayed but still keep the layout consistent in the screenshot.
93+
94+
```JavaScript
95+
<article>
96+
<div class="title" data-visual-test="blackout">Breaking news: XXX</div>
97+
<div class="content" data-visual-test="blackout">...</div>
98+
</article>
99+
```
100+
101+
## Mobile Status Bars
102+
103+
Mobile status bars introduce flakiness in screenshots due to their dynamic nature: notifications, battery, and time. The best practice is to hide the mobile status bar before taking a screenshot, crop it out, or ignore this area in the comparison. Argos offers a mask option for the latter.
104+
105+
Example with Argos' WebDriverIO integration:
106+
107+
```JavaScript
108+
import { argosScreenshot } from "@argos-ci/webdriverio";
109+
import { browser } from "@wdio/globals";
110+
111+
describe("Integration test with visual testing", () => {
112+
it("covers homepage", async () => {
113+
await browser.url("http://localhost:3000");
114+
await argosScreenshot(browser, "homepage", {
115+
mask: [{ x: 0, y: 0, width: 1170, height: 120 }],
116+
});
117+
});
118+
});
119+
```
120+
121+
## Browser-Related Inconsistencies
122+
123+
Browser-related inconsistencies are challenging because they are generated from the browser itself, not your code. Addressing them requires in-depth research and development. Nevertheless, Argos provides built-in solutions for most of them, ensuring screenshot consistency across runs.
124+
125+
**Common browser inconsistency causes:**
126+
127+
- **Glitches**: border radius, shadow, scrolling bar, and caret visibility
128+
- **Rendering**: text aliasing, image rendering
129+
- **Navigation**: random focus, random hover, and scrolling position
130+
131+
## Cropped Screenshots Due to Layout Shift
132+
133+
Sometimes, flaky tests produce cropped screenshots because Playwright (or another browser automation library) measures the page size before a layout shift, then takes the screenshot after the shift. The best way to fix this is to identify and correct the root cause of the layout shift. It can be challenging!
134+
135+
## Capturing Screenshots on CI/CD or Locally
136+
137+
Capturing screenshots on different machines introduces variability, as each device's settings can affect the output. Using a CI/CD pipeline for screenshot capture standardizes the environment and enforces stability, ensuring every screenshot is produced under identical conditions.
138+
139+
## Conclusion
140+
141+
Flaky tests are a common challenge in visual testing, but once you know the patterns, it will be easier to stabilize your screenshots. The most important thing is to not give up on any flaky test and risk introducing a bug in your app. Keeping your test suite stable might seem tough and thankless at times, but in the end, it's always worth the effort.
142+
143+
I hope these best practices help you stabilize your visual testing suite. If you have any questions or want to share your experience, feel free to reach out or join [Argos' Discord community](https://argos-ci.com/discord).
88.8 KB
Loading

0 commit comments

Comments
 (0)