<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Jeremy SFEZ</title>
    <description>The latest articles on DEV Community by Jeremy SFEZ (@jsfez).</description>
    <link>https://dev.to/jsfez</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F533298%2Ff46fef5c-3b33-483d-8f65-3820d2d21956.jpg</url>
      <title>DEV Community: Jeremy SFEZ</title>
      <link>https://dev.to/jsfez</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jsfez"/>
    <language>en</language>
    <item>
      <title>Why Playwright visual testing doesn't scale</title>
      <dc:creator>Jeremy SFEZ</dc:creator>
      <pubDate>Fri, 11 Apr 2025 09:18:26 +0000</pubDate>
      <link>https://dev.to/jsfez/why-playwright-visual-testing-doesnt-scale-1ole</link>
      <guid>https://dev.to/jsfez/why-playwright-visual-testing-doesnt-scale-1ole</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;You touch a &lt;strong&gt;shared component&lt;/strong&gt; and knowing it will affect multiple screens.&lt;/p&gt;

&lt;p&gt;So you run your Playwright tests locally to regenerate the visual screenshots. It takes &lt;strong&gt;40 minutes&lt;/strong&gt;...&lt;/p&gt;

&lt;p&gt;Once it's done, you go through the diffs. Some changes are expected, others are noise; fonts shift slightly, anti-aliasing artifacts, platform quirks.&lt;/p&gt;

&lt;p&gt;You commit the new images and push your branch.&lt;/p&gt;

&lt;p&gt;Then you notice a &lt;strong&gt;real visual bug&lt;/strong&gt; you missed. Back to the tests. Another &lt;strong&gt;40 minutes&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;And if someone else touched the same screenshots? &lt;strong&gt;Merge conflicts&lt;/strong&gt;, reruns, frustration.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This isn't just slow. It breaks your flow.&lt;/p&gt;

&lt;p&gt;And this isn't a tooling problem. It's a model problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why local visual testing breaks down in a team
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;You have to run the full test suite locally just to regenerate screenshots before pushing&lt;/li&gt;
&lt;li&gt;You're comparing against screenshots you pulled which may already be outdated&lt;/li&gt;
&lt;li&gt;Screenshots live in Git, polluting diffs and causing merge conflicts&lt;/li&gt;
&lt;li&gt;Tests are flaky due to environment inconsistencies (OS, browser, rendering)&lt;/li&gt;
&lt;li&gt;Reviewing visual diffs is hard when you're limited to raw image diffs&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Bootstrap a solution? A misguided approach
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa60wl44qw6jmcwchf30n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa60wl44qw6jmcwchf30n.png" alt="Image description" width="800" height="266"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It's technically possible to run visual testing with Playwright in CI. You can use GitHub Actions and the artifacts system to store and compare screenshots automatically. Here is a &lt;a href="https://medium.com/@mikestopcontinues/how-to-run-snapshot-tests-in-ci-cd-with-playwright-7f78ff6ae4e8" rel="noopener noreferrer"&gt;full guide that explains how&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It includes maintaining custom scripts, juggling artifact storage, reverse-engineering Git history to find the right baseline, and constantly debugging flaky tests from subtle rendering differences.&lt;/p&gt;

&lt;p&gt;The result is a fragile, time-consuming setup with no built-in UI to review visual changes. It works, but it's far from ergonomic or team-friendly.&lt;/p&gt;

&lt;h2&gt;
  
  
  A different approach: generate in CI, compare to production
&lt;/h2&gt;

&lt;p&gt;A scalable visual testing workflow needs to flip the model.&lt;/p&gt;

&lt;p&gt;Instead of running tests locally and storing screenshots in Git, what if:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Screenshots were generated automatically in CI&lt;/li&gt;
&lt;li&gt;Comparisons are always made against the actual state of your production&lt;/li&gt;
&lt;li&gt;No one had to commit images manually&lt;/li&gt;
&lt;li&gt;Reviews in a dedicated UI where you can inspect visual diffs, accept or reject them, and track changes history&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is the model &lt;a href="https://www.argos-ci.com" rel="noopener noreferrer"&gt;Argos&lt;/a&gt; follows.&lt;/p&gt;

&lt;p&gt;You push your branch. Screenshots are captured automatically in CI.&lt;br&gt;
They're compared to the single source of truth: &lt;code&gt;main&lt;/code&gt;.&lt;br&gt;
You get a visual diff. No manual test runs, no image files in Git, no guesswork.&lt;/p&gt;

&lt;p&gt;You review the changes in the UI. If they look correct, you click “Accept” and done!&lt;/p&gt;
&lt;h2&gt;
  
  
  Visual reviews that fit into your workflow
&lt;/h2&gt;

&lt;p&gt;Argos integrates tightly with GitHub and GitLab. Visual diffs are posted as comments with status checks directly in your pull requests.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv9zhbcgeycpuihss9ego.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv9zhbcgeycpuihss9ego.png" alt="Image description" width="800" height="230"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8w8z0891egfoc8wehcrx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8w8z0891egfoc8wehcrx.png" alt="Image description" width="800" height="296"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;See what changed in every pull request&lt;/li&gt;
&lt;li&gt;Accept changes with a single click&lt;/li&gt;
&lt;li&gt;View the history of a given page or component's appearance across time&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You review inline, with full context, and move on without pushing updated screenshots or rerunning tests.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyrdl2q1hh1xth62xj9pz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyrdl2q1hh1xth62xj9pz.png" alt="Image description" width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Less noise, more trust
&lt;/h2&gt;

&lt;p&gt;Argos also tackles another major pain point: stability.&lt;/p&gt;

&lt;p&gt;Because screenshots are captured in a controlled CI environment, and processed with Argos' own stabilization algorithm:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You benefit from &lt;strong&gt;consistent comparisons&lt;/strong&gt; across all environments&lt;/li&gt;
&lt;li&gt;You see fewer diffs, and the ones you do see are meaningful&lt;/li&gt;
&lt;li&gt;Your workflow becomes streamlined, allowing you to focus on shipping features&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Stabilizing visual tests with custom Playwright scripts is a never-ending task.&lt;br&gt;
At Argos, we've built a dedicated stabilization algorithm based on years of studying why visual tests fail.&lt;br&gt;
It automatically handles animation disabling, font loading, image normalization, and many subtle sources of &lt;strong&gt;false diffs&lt;/strong&gt;, so you don't have to.&lt;/p&gt;

&lt;p&gt;You can &lt;strong&gt;trust the output&lt;/strong&gt;.&lt;br&gt;
You don't need to double-check every time.&lt;/p&gt;


&lt;h2&gt;
  
  
  Setting it up Argos with Playwright takes 5 minutes
&lt;/h2&gt;

&lt;p&gt;Integrating &lt;a href="https://www.argos-ci.com/docs/playwright" rel="noopener noreferrer"&gt;Argos into a Playwright&lt;/a&gt; project is straightforward.&lt;br&gt;
Basically, replace &lt;code&gt;toHaveScreenshot&lt;/code&gt; with &lt;code&gt;argosScreenshot&lt;/code&gt; in your tests.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// example.spec.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;argosScreenshot&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@argos-ci/playwright&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;test&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@playwright/test&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;example test&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;goto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://playwright.dev&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;argosScreenshot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;homepage&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And, update your &lt;code&gt;playwright.config.ts&lt;/code&gt; file to upload screenshots to Argos at the end of the test run.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// playwright.config.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;defineConfig&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@playwright/test&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;defineConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;reporter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="c1"&gt;// Use "dot" reporter on CI, "list" otherwise (Playwright default).&lt;/span&gt;
    &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;CI&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dot&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;list&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="c1"&gt;// Add Argos reporter. Upload on CI only.&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@argos-ci/playwright/reporter&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;uploadToArgos&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;CI&lt;/span&gt; &lt;span class="p"&gt;}],&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;

  &lt;span class="c1"&gt;// Setup test debugging on CI.&lt;/span&gt;
  &lt;span class="na"&gt;use&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;trace&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;on-first-retry&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;screenshot&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;only-on-failure&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Curious? Try Argos on your next pull request:&lt;/strong&gt; &lt;a href="https://www.argos-ci.com" rel="noopener noreferrer"&gt;argos-ci.com&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion: This isn't a plugin. It's a different model.
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;toMatchSnapshot&lt;/code&gt; isn't broken.&lt;br&gt;
It's just not designed for projects that scale: for teams, CI, or long-lived codebases with multiple contributors.&lt;/p&gt;

&lt;p&gt;At some point, what was once a convenience becomes a bottleneck.&lt;br&gt;
The visual testing tool becomes the thing slowing you down.&lt;/p&gt;

&lt;p&gt;When that happens, the right move isn't to stop testing visuals.&lt;br&gt;
It's to adopt a model that fits the way your team actually works.&lt;/p&gt;

</description>
      <category>playwright</category>
      <category>qa</category>
      <category>typescript</category>
      <category>visualtesting</category>
    </item>
    <item>
      <title>How to Stabilize Flaky Screenshots for visual testing</title>
      <dc:creator>Jeremy SFEZ</dc:creator>
      <pubDate>Tue, 27 Feb 2024 07:00:00 +0000</pubDate>
      <link>https://dev.to/jsfez/how-to-stabilize-flaky-screenshots-for-visual-testing-1529</link>
      <guid>https://dev.to/jsfez/how-to-stabilize-flaky-screenshots-for-visual-testing-1529</guid>
      <description>&lt;p&gt;Visual testing is the most efficient way to test your app as it's &lt;strong&gt;fast&lt;/strong&gt; and &lt;strong&gt;robust&lt;/strong&gt; (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 &lt;strong&gt;common culprits responsible for flaky screenshots and how to fix them&lt;/strong&gt;. I'll also introduce &lt;a href="https://argos-ci.com"&gt;Argos&lt;/a&gt;'s solutions to stabilize screenshots.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a Flaky Test?
&lt;/h2&gt;

&lt;p&gt;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 &lt;strong&gt;network latency, lazy loading, animations, and dynamic content like dates and external scripts&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Disclaimer&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://rauchg.com/2020/2019-in-review#flaky-tests-flaky-ux"&gt;Flaky Tests mean Flaky UX&lt;/a&gt; — Guillermo Rauch&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h2&gt;
  
  
  Network Latency
&lt;/h2&gt;

&lt;p&gt;Network latency can cause flaky screenshots if assets (&lt;strong&gt;font&lt;/strong&gt;, &lt;strong&gt;images&lt;/strong&gt;, ...) are not fully loaded before the screenshot is taken.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5gm3x4uaymqhm3qunbm8.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5gm3x4uaymqhm3qunbm8.jpg" alt="font-not-loaded" width="416" height="117"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To stabilize screenshots, you must ensure your resources are fully loaded before capturing screenshots. For example, the &lt;code&gt;argosScreenshot&lt;/code&gt; command waits for resources to load before taking a screenshot.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lazy Loading
&lt;/h2&gt;

&lt;p&gt;Lazy loading can cause flaky screenshots if the screenshot is taken before the elements are fully loaded.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4nginqza6q17jvrqs16r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4nginqza6q17jvrqs16r.png" alt="loader" width="600" height="258"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To stabilize screenshots, use a loading indicator and wait for its removal before proceeding. &lt;a href="https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-busy"&gt;Aligning with ARIA specification&lt;/a&gt;, I recommend using the &lt;code&gt;[aria-busy]&lt;/code&gt; attribute on your loader component. At Argos, the &lt;code&gt;argosScreenshot&lt;/code&gt; command delays the screenshot capture until all components with the &lt;code&gt;[aria-busy]&lt;/code&gt; attribute are removed.&lt;/p&gt;

&lt;p&gt;Example of a loader component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;loader&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;aria&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;busy&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Dynamic Content
&lt;/h2&gt;

&lt;p&gt;By nature, dynamic elements like &lt;strong&gt;dates or time&lt;/strong&gt; 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 &lt;code&gt;data-visual-test&lt;/code&gt; attribute to hide these elements from the screenshot.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;clock&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;visual&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;transparent&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For dates, another solution is to use a fixed date for your test environment. You can see here &lt;a href="https://docs.cypress.io/api/commands/clock"&gt;how to do it with Cypress&lt;/a&gt;. But this solution is not always possible in a real-world scenario.&lt;/p&gt;

&lt;h2&gt;
  
  
  Animation
&lt;/h2&gt;

&lt;p&gt;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 &lt;code&gt;data-visual-test&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: If an animation causes layout shifts, it's recommended to remove it from the DOM with &lt;code&gt;data-visual-test="removed"&lt;/code&gt; instead of merely hiding it with &lt;code&gt;data-visual-test="transparent"&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  External Scripts and Iframes
&lt;/h2&gt;

&lt;p&gt;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:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Avoid loading external scripts in your test environment.&lt;/li&gt;
&lt;li&gt;Inject CSS to hide their UI impacts.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;argosScreenshot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;homepage&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;argosCSS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
    .__argos__ iframe {
      display: none;
    }
  `&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Wait for the iframe's content to be loaded before taking the screenshot. If you follow this path, I recommend reading &lt;a href="https://twitter.com/debs_obrien"&gt;Debbie O'Brien&lt;/a&gt;'s article about how to &lt;a href="https://debbie.codes/blog/testing-iframes-with-playwright/"&gt;test an iframes with Playwright&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Data inconsistency
&lt;/h2&gt;

&lt;p&gt;The two main causes of data inconsistency are &lt;strong&gt;randomized data seed&lt;/strong&gt; and &lt;strong&gt;missing sorting order&lt;/strong&gt;. Usually, it's easy to fix by using a fixed dataset for your test environment. But if not, you can use the &lt;code&gt;data-visual-test&lt;/code&gt; attribute to hide the area where the data is displayed but still keep the layout consistent in the screenshot.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;article&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;title&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;visual&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;blackout&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Breaking&lt;/span&gt; &lt;span class="nx"&gt;news&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;XXX&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;content&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;visual&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;blackout&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/article&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Mobile Status Bars
&lt;/h2&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;Example with Argos' WebDriverIO integration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;argosScreenshot&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@argos-ci/webdriverio&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;browser&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@wdio/globals&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Integration test with visual testing&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;covers homepage&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http://localhost:3000&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;argosScreenshot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;homepage&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;mask&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1170&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;120&lt;/span&gt; &lt;span class="p"&gt;}],&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Browser-Related Inconsistencies
&lt;/h2&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Common browser inconsistency causes:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Glitches&lt;/strong&gt;: border radius, shadow, scrolling bar, and caret visibility&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rendering&lt;/strong&gt;: text aliasing, image rendering&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Navigation&lt;/strong&gt;: random focus, random hover, and scrolling position&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Cropped Screenshots Due to Layout Shift
&lt;/h2&gt;

&lt;p&gt;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!&lt;/p&gt;

&lt;h2&gt;
  
  
  Capturing Screenshots on CI/CD or Locally
&lt;/h2&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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 &lt;a href="https://argos-ci.com/discord"&gt;Argos' Discord community&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>testing</category>
      <category>cypress</category>
      <category>playwright</category>
    </item>
    <item>
      <title>Time-Travel Debugging: A Playwright Traces Tutorial</title>
      <dc:creator>Jeremy SFEZ</dc:creator>
      <pubDate>Wed, 17 Jan 2024 10:32:29 +0000</pubDate>
      <link>https://dev.to/jsfez/time-travel-debugging-a-playwright-traces-tutorial-o5f</link>
      <guid>https://dev.to/jsfez/time-travel-debugging-a-playwright-traces-tutorial-o5f</guid>
      <description>&lt;p&gt;&lt;strong&gt;Ever wished you could replay a test that failed in your CI?&lt;/strong&gt; That's where Playwright Traces come in! This guide shows how it seamlessly fits into your CI workflow, making bug-hunting easier and more effective.&lt;/p&gt;

&lt;h2&gt;
  
  
  Debugging Trace in Action
&lt;/h2&gt;

&lt;p&gt;Let's jump right into a practical scenario. In the video below, I'll show how to use the Playwright Trace Viewer to inspect a failed test, identify the issue, and apply a fix.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/MTgNbdG6I3A"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;In this video, I focus on resolving a complex locator issue. Besides this, Playwright Trace Viewer offers an extensive array of features for pinpointing test failures, including network logs, and console messages or step-by-step snapshots, not covered here.&lt;/p&gt;

&lt;h2&gt;
  
  
  Integrating with Your CI
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Record Traces when a Test Fails
&lt;/h3&gt;

&lt;p&gt;To automatically record traces on your CI, simply update your Playwright config file with this option:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;use&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;trace&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;on-first-retry&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, whenever a test fails, a trace file is generated, ready for download or online viewing with a third-party reporter.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Open Trace Files
&lt;/h3&gt;

&lt;p&gt;To open a Trace file, either upload it to &lt;a href="https://trace.playwright.dev" rel="noopener noreferrer"&gt;trace.playwright.dev&lt;/a&gt; or run the command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx playwright show-trace &amp;lt;TRACE_FILE_PATH&amp;gt;.zip
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Third-Party Reporting with Argos
&lt;/h3&gt;

&lt;p&gt;To enhance your workflow, you can integrate your CI with &lt;a href="https://argos-ci.com" rel="noopener noreferrer"&gt;Argos&lt;/a&gt; for direct access to Playwright Traces online. This seamless connection eliminates the need to download trace files, offering a more streamlined approach.&lt;/p&gt;

&lt;p&gt;Check out the &lt;a href="https://argos-ci.com/docs/quickstart/playwright" rel="noopener noreferrer"&gt;Argos Playwright setup guide&lt;/a&gt; for easy integration steps.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frtfqg293cx1z2ebpd5kr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frtfqg293cx1z2ebpd5kr.png" alt="Github fail test"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8ec6ynjjslthxw7jznai.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8ec6ynjjslthxw7jznai.png" alt="Argos with Trace"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://playwright.dev/docs/trace-viewer" rel="noopener noreferrer"&gt;Playwright Trace Viewer Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.argos-ci.com" rel="noopener noreferrer"&gt;Argos Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.youtube.com/watch?v=lfxjs--9ZQs" rel="noopener noreferrer"&gt;Debbie O'Brien's Video on Playwright Traces&lt;/a&gt; by &lt;a href="https://twitter.com/debs_obrien" rel="noopener noreferrer"&gt;Debbie O'Brien&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>playwright</category>
      <category>testing</category>
      <category>javascript</category>
      <category>node</category>
    </item>
    <item>
      <title>TWC is not a revolution but…</title>
      <dc:creator>Jeremy SFEZ</dc:creator>
      <pubDate>Wed, 27 Dec 2023 17:37:49 +0000</pubDate>
      <link>https://dev.to/jsfez/twc-is-not-a-revolution-but-mb9</link>
      <guid>https://dev.to/jsfez/twc-is-not-a-revolution-but-mb9</guid>
      <description>&lt;p&gt;I'm a true fan of &lt;a href="https://ui.shadcn.com/docs"&gt;shadcn/ui&lt;/a&gt; as it offers out-of-the-box components that are highly customizable. By blending &lt;a href="https://tailwindcss.com/"&gt;TailwindCSS&lt;/a&gt; for styling and theming, along with &lt;a href="https://www.radix-ui.com/"&gt;Radix&lt;/a&gt; for accessibility, it provides a smart kick-start for product development.&lt;/p&gt;

&lt;p&gt;However, at some point, you will have to create your own React-TypeScript components, which can become complicated, even for coding a simple styled &lt;code&gt;div&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;cn&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@/lib/utils&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Card&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;forwardRef&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;
  &lt;span class="nx"&gt;HTMLDivElement&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;HTMLAttributes&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;HTMLDivElement&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(({&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;
    &lt;span class="na"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;cn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;rounded-xl border bg-card text-card-foreground shadow&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;className&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Enter &lt;a href="https://react-twc.vercel.app/"&gt;TWC&lt;/a&gt;, that dramatically simplifies this with a straightforward syntax:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;twc&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-twc&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Card&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;twc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="s2"&gt;`rounded-xl border bg-card text-card-foreground shadow`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Among other features TWC offers some useful helpers like handling &lt;a href="https://react-twc.vercel.app/docs/guides/adapting-based-on-props"&gt;conditional classes&lt;/a&gt;,  &lt;a href="https://react-twc.vercel.app/docs/guides/adapting-based-on-props#use-with-cva"&gt;cva support&lt;/a&gt; and &lt;a href="https://react-twc.vercel.app/docs/guides/additional-props"&gt;conditional props&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;twc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;TwcComponentProps&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-twc&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;ButtonProps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;TwcComponentProps&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;button&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;$primary&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// Conditional ClassNames&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Button&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;twc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ButtonProps&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;font-semibold border border-blue-500 rounded&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$primary&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bg-blue-500 text-white&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bg-white text-gray-800&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;twc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;TwcComponentProps&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-twc&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Adds `target` and `rel` attributes on external links&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Anchor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;twc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;attrs&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;AnchorProps&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$external&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;_blank&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;rel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;noopener noreferrer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;`appearance-none size-4 border-2 border-blue-500 rounded-sm bg-white`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Integration with Other Libraries
&lt;/h2&gt;

&lt;p&gt;TWC &lt;a href="https://react-twc.vercel.app/docs/guides/styling-any-component"&gt;can be used to&lt;/a&gt; add TailwindCSS classes on several design systems components including &lt;a href="https://www.radix-ui.com/"&gt;Radix&lt;/a&gt; or &lt;a href="https://react-spectrum.adobe.com/react-aria"&gt;React Aria&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaway
&lt;/h2&gt;

&lt;p&gt;TWC is not a revolution, but it's a lib crafted by an experienced developer (&lt;a href="https://twitter.com/gregberge_"&gt;gregberge&lt;/a&gt;), that  addresses the frustrations of building React components in modern stacks. For me, it's a ❤️ tool that enhances development experience, and my productivity.&lt;/p&gt;

</description>
      <category>react</category>
      <category>tailwindcss</category>
      <category>javascript</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Enforce API Stability with Zod and Argos</title>
      <dc:creator>Jeremy SFEZ</dc:creator>
      <pubDate>Thu, 14 Dec 2023 08:00:00 +0000</pubDate>
      <link>https://dev.to/jsfez/enforce-api-stability-with-zod-and-argos-5de6</link>
      <guid>https://dev.to/jsfez/enforce-api-stability-with-zod-and-argos-5de6</guid>
      <description>&lt;p&gt;API changes frequently result in broken applications, largely due to the difficulty in monitoring their ripple effects. This article discusses the practical benefits of using Zod to enforce API stability and detect regressions through visual testing with Argos.&lt;/p&gt;

&lt;p&gt;Let's see the advantages of this method before diving into the technical stuff.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key Benefits for Developers&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Fast Feedback&lt;/strong&gt;: Quick identification of API contract issues.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reliability&lt;/strong&gt;: Detects both type and visual regressions effectively.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;High Coverage&lt;/strong&gt;: Covers all pages with a single line of code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No Maintenance&lt;/strong&gt;: No need to update your tests when UI or API changes.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Zod: Streamlining Type Safety
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://zod.dev/" rel="noopener noreferrer"&gt;Zod&lt;/a&gt; is a TypeScript-first library for schema declaration and validation. As it excels in enforcing type safety, we can use it to ensuring API response integrity and maintains the API contract over time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;With this method frontend developers can rely on type safety, while backend developers can quickly identify regressions in API responses.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Zod schema example for API response testing&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;zod&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;SneakerSchema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;object&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;number&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="na"&gt;picture&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="na"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;number&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="na"&gt;brand&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getSneakers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/api/sneakers&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;API error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;SneakerSchema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Validates against the schema&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Zod can be used to ensure API integrity, but manually checking each route response after each update is impractical. Argos streamlines this, safeguarding the entire app more efficiently.&lt;/p&gt;

&lt;h2&gt;
  
  
  Argos: Simplifying Visual Testing
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://argos-ci.com/docs" rel="noopener noreferrer"&gt;Argos&lt;/a&gt; integrates with CI/CD pipelines, facilitating UI change verification within pull requests. Basically, it streamlines visual regression detection and give feedback into GitHub directly.&lt;/p&gt;

&lt;p&gt;It takes a few lines in your E2E test suite to cover your whole application:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Playwright E2E test: screenshot app's pages&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;argosScreenshot&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@argos-ci/playwright&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;test&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@playwright/test&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;baseUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http://localhost:3000&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;homepage&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;product-list&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/explore&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;product-detail&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/preview/404758&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;contact&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/contact-us&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;screenshot pages&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;pages&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;goto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;baseUrl&lt;/span&gt;&lt;span class="p"&gt;}${&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;argosScreenshot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Combined Impact of Zod and Argos
&lt;/h2&gt;

&lt;p&gt;Utilizing Zod in tandem with Argos empowers developers to swiftly pinpoint and address broken pages caused by API modifications throughout their application. &lt;/p&gt;

&lt;p&gt;When Zod flags a type error during runtime, it throws an error in console and render a blank page. That's where Argos steps in to detect this visual regression, and then delivers prompt feedback during code reviews, enhancing the overall development process.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiaevfaxd6rcolrqwc8ng.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiaevfaxd6rcolrqwc8ng.png" alt="Argos check status on PR"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://app.argos-ci.com/argos-ci/snkr-shop/builds/24/67606393" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyx8fffmph76r31kjn3g8.png" alt="Zod error detected in Argos"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The synergy of Argos and Zod redefine API contract testing, seamlessly bridging data integrity with UI consistency. &lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This powerful combination not only makes monitoring API changes across applications both efficient and cost-effective but also integrates effortlessly into your workflow. It's a toolset that empowers developers with rapid feedback, streamlining the path to a more robust and swiftly delivered product.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>testing</category>
      <category>opensource</category>
      <category>node</category>
    </item>
    <item>
      <title>Startup Testing Dilemma: E2E or Not E2E?</title>
      <dc:creator>Jeremy SFEZ</dc:creator>
      <pubDate>Mon, 16 Oct 2023 14:13:15 +0000</pubDate>
      <link>https://dev.to/jsfez/startup-testing-dilemma-e2e-or-not-e2e-46nj</link>
      <guid>https://dev.to/jsfez/startup-testing-dilemma-e2e-or-not-e2e-46nj</guid>
      <description>&lt;p&gt;In a fast-growing startup I'm part of, a question sparked intense debates among senior developers: with all the setup and maintenance time it cost, is E2E testing really worth our time?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;We all prioritize fast delivery, and figuring out how to keep that momentum in long term was the crux of our chats&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Quick note: The other perspective would be to bypass E2E, let a few bugs sneak by QA, and patched things up when they showed in production.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The E2E Test Paradox in Startups
&lt;/h2&gt;

&lt;p&gt;End-to-end (E2E) tests are often seen as the gold standard in quality assurance. They replicate real user actions and make sure everything in the application runs smoothly. But in a startup environment, they can be a double-edged sword.&lt;/p&gt;

&lt;p&gt;Imagine investing hours crafting a detailed E2E test suite for a feature. The next week, based on new insights, that feature undergoes a revamp or is replaced entirely. Now, not only do you need to rewrite the feature, but you also have the unenviable task of overhauling the test suite. This cycle can be both mentally exhausting and time-consuming.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--w64AtZTy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gurx47qpy87vmkpctyvb.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--w64AtZTy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gurx47qpy87vmkpctyvb.jpg" alt="Developer struggling with E2E testing" width="500" height="281"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To counter the challenges posed by E2E testing and its associated maintenance costs, we explored an alternative: visual testing.&lt;/p&gt;

&lt;h2&gt;
  
  
  🧿 Visual Testing: Agile’s Best Friend
&lt;/h2&gt;

&lt;p&gt;In the dynamic landscape of startups, where changes are frequent, visual testing emerges as the optimal solution. Here's why:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Trust in Every Change&lt;/strong&gt;: With visual testing, changes become transparent. Approve expected updates and reject unintended alterations.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Minimal Effort, Maximum Coverage&lt;/strong&gt;: Efficiently use one line of code to visually verify a full page's layout and content, eliminating the need for extensive scripts.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Cut the Maintenance Chain&lt;/strong&gt;: Even if your product evolves constantly, no need to update the test code. Simply approve or reject the updated screenshots.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  ⚒️  Our Go-To Tool
&lt;/h2&gt;

&lt;p&gt;We've been using &lt;a href="https://www.argos-ci.com/"&gt;Argos&lt;/a&gt; for visual testing. It's a dev tool that allows to review the changes a pull request brings. It's easy to onboard and it slides right into our workflow.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Homepage test file. No maintenance needed! &lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;test&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@playwright/test&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;argosScreenshot&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@argos-ci/playwright&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;homepage&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;goto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http://localhost:3000&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;argosScreenshot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;homepage&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://www.argos-ci.com/"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--A5-lzdRW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/z0r1b4mp2l127dcyl109.png" alt="Argos demo" width="800" height="383"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;An example of Argos build, where the dev can review the PR's visual changes.&lt;/p&gt;

&lt;h2&gt;
  
  
  ⚖️ Balancing Act: E2E and Visual Testing
&lt;/h2&gt;

&lt;p&gt;While visual tests shine in adaptability, the value of E2E tests remains unmatched for mission-critical functionalities. The key is balance. For core features with less frequent changes, E2E tests guarantee stability. For others that are in flux, visual tests provide adequate coverage without the maintenance headache.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In the fast-paced world of startup development, agility is critical. While robust testing remains essential, the type of testing needs to align with the product's stage and volatility. Visual testing provides the flexibility startups need without compromising on quality, making it a crucial part of any developer's toolkit today.&lt;/p&gt;

&lt;p&gt;Have you faced similar testing dilemmas in your startup? How did you navigate them? Share your experiences in the comments.&lt;/p&gt;

</description>
      <category>testing</category>
      <category>programming</category>
      <category>agile</category>
    </item>
    <item>
      <title>How to Connect Your Google Sheet to ChatGPT</title>
      <dc:creator>Jeremy SFEZ</dc:creator>
      <pubDate>Thu, 16 Feb 2023 08:20:30 +0000</pubDate>
      <link>https://dev.to/jsfez/how-to-connect-your-google-sheet-to-chatgpt-9kk</link>
      <guid>https://dev.to/jsfez/how-to-connect-your-google-sheet-to-chatgpt-9kk</guid>
      <description>&lt;p&gt;If you're looking to leverage the power of AI to interact with your Google Sheet content, connecting your sheet to ChatGPT is a great way to get started. In this post, we'll walk through the steps required to connect your sheet to ChatGPT and start using its capabilities to answer questions about your data.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0f6tiba1t233t784d1f8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0f6tiba1t233t784d1f8.png" alt="Google sheet connected to ChatGPT"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Up Google Apps Script
&lt;/h2&gt;

&lt;p&gt;Before we get started with ChatGPT, you'll need to set up Google Apps Script. If you're not already familiar with Google Apps Script, you can get started with the documentation &lt;a href="https://developers.google.com/apps-script" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Javascript code snippet
&lt;/h3&gt;

&lt;p&gt;The code is available in this &lt;a href="https://gist.github.com/jsfez/e91c1cae51c5a7d01cc96e0c36439ec1" rel="noopener noreferrer"&gt;GitHub gist&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Load OpenAI API key from script properties
const openaiApiKey = "YOUR_API_KEY";

// Load Google Sheet data
const sheet =
  SpreadsheetApp.getActiveSpreadsheet().getActiveSheet() ||
  SpreadsheetApp.getActiveSpreadsheet().getSheets()[0];
const data = sheet.getDataRange().getValues();

// Fetch response from OpenAI's completion API
function generateResponse(prompt) {
  if (!openaiApiKey) throw new Error("OpenAI API key not found.");
  const openaiUrl = "https://api.openai.com/v1/completions";
  const response = UrlFetchApp.fetch(openaiUrl, {
    method: "post",
    headers: {
      "Content-Type": "application/json",
      Authorization: `Bearer ${openaiApiKey}`,
    },
    payload: JSON.stringify({
      prompt,
      model: "text-davinci-003",
      max_tokens: 1024,
      n: 1,
      stop: null,
      temperature: 0.5,
      presence_penalty: 0,
      frequency_penalty: 0,
      best_of: 1,
    }),
  });

  const responseData = JSON.parse(response.getContentText());
  return responseData.choices[0].text.trim();
}

function gpt(prompt) {
  const response = generateResponse(
    `${data.map((row) =&amp;gt; row.join("\t")).join("\n")}\n\n${prompt}`
  );
  Logger.log(response);
  return response;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Connecting Your Google Sheet to ChatGPT
&lt;/h2&gt;

&lt;p&gt;To connect your Google Sheet to ChatGPT, you'll need to follow these steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Copy the code provided above and paste it into Google Apps Script.&lt;/li&gt;
&lt;li&gt;Replace "YOUR_API_KEY" with your ChatGPT API key.&lt;/li&gt;
&lt;li&gt;Save and execute the code.&lt;/li&gt;
&lt;li&gt;Allow the necessary Google authorizations.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Once you've completed these steps, you'll be able to use the &lt;code&gt;=gpt()&lt;/code&gt; formula in your Google Sheet to query ChatGPT about your sheet content. This will allow you to get intelligent responses to your questions based on the data in your sheet.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Connecting your Google Sheet to ChatGPT is a powerful way to take advantage of AI to interact with your data. With the help of Google Apps Script, it's easy to set up and start using in your sheet. By following the steps outlined above, you'll be able to get started quickly and start benefiting from the power of ChatGPT in no time.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>googlesheet</category>
      <category>chatgpt</category>
      <category>googleappscript</category>
    </item>
    <item>
      <title>Automating Visual Testing with Playwright, Argos and GitHub Actions</title>
      <dc:creator>Jeremy SFEZ</dc:creator>
      <pubDate>Wed, 25 Jan 2023 07:37:06 +0000</pubDate>
      <link>https://dev.to/jsfez/automating-visual-testing-with-playwright-argos-and-github-actions-2fp1</link>
      <guid>https://dev.to/jsfez/automating-visual-testing-with-playwright-argos-and-github-actions-2fp1</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--HmOs1OXd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wzaixdximfunc81vj2ot.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--HmOs1OXd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wzaixdximfunc81vj2ot.jpg" alt="Black mask" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Photo de &lt;a href="https://unsplash.com/@theonlynoonan?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;John Noonan&lt;/a&gt; sur &lt;a href="https://unsplash.com/fr/photos/QM_LE41VJJ4?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Visual testing allows developers to identify and fix visual bugs in applications before they become a problem. By automating visual testing, developers can ensure that their web applications look and function as intended when they make changes and updates.&lt;/p&gt;

&lt;p&gt;In this guide, we will show how to automate visual testing with &lt;a href="https://playwright.dev/docs/intro"&gt;Playwright&lt;/a&gt;, &lt;a href="https://argos-ci.com/"&gt;Argos&lt;/a&gt;, and &lt;a href="https://github.com/features/actions"&gt;GitHub Actions&lt;/a&gt;. The goal is to be notified of visual changes on each pull-request directly within GitHub, and fix visual bugs before they make it into production.&lt;/p&gt;

&lt;h2&gt;
  
  
  Install the Argos GitHub App
&lt;/h2&gt;

&lt;p&gt;To get started with Argos, you'll first need to install the Argos GitHub App. This will allow Argos to access your repositories, add test statuses on pull-request, and notify you when visual changes are detected.&lt;/p&gt;

&lt;p&gt;To install Argos app, go to the &lt;a href="https://github.com/marketplace/argos-ci"&gt;GitHub Marketplace&lt;/a&gt;, subscribe to an Argos plan and complete the installation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Playwright and Argos setup
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://playwright.dev/docs/intro"&gt;Playwright&lt;/a&gt; is a powerful testing framework that provides a great developer experience and good out-of-the-box features for end-to-end testing. To install Playwright, execute the following command in your terminal and answer the questions in the prompt:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm init playwright@latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To use Playwright with Argos, you will also have to install the following packages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--save-dev&lt;/span&gt; @argos-ci/cli  @argos-ci/playwright
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://argos-ci.com/docs/argos-cli"&gt;@argos-ci/cli&lt;/a&gt;: easiest and fastest way to upload screenshots to the Argos.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://argos-ci.com/docs/playwright"&gt;@argos-ci/playwright&lt;/a&gt;: improve screenshot stability and expose CSS to hide content.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Capture the screenshots
&lt;/h2&gt;

&lt;p&gt;Once Playwright and Argos app are installed, you can create test files to capture screenshots of your application. Use the &lt;code&gt;argosScreenshot&lt;/code&gt; function provided by &lt;code&gt;@argos-ci/playwright&lt;/code&gt; insure stable screenshots.&lt;/p&gt;

&lt;p&gt;For example, the following test file will take a screenshot of your homepage:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// tests/homepage.spec.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;test&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@playwright/test&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;argosScreenshot&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@argos-ci/playwright&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Homepage&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;take screenshot&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;goto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http://localhost:3000/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;argosScreenshot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;homepage&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To run the test, use the playwright test command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx playwright &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If everything is set up correctly, the test should pass and you should find a new screenshot in the &lt;code&gt;/screenshots&lt;/code&gt; folder.&lt;/p&gt;

&lt;h2&gt;
  
  
  Integrate with GitHub Actions
&lt;/h2&gt;

&lt;p&gt;With the screenshots captured, you can now integrate the Visual Testing into your GitHub Actions Continuous Integration. To do this, you have to create a new GitHub Actions workflow file that runs Playwright tests and uploads screenshots to Argos.&lt;/p&gt;

&lt;p&gt;Create a new file called &lt;code&gt;.github/workflows/main.yml&lt;/code&gt; in the root directory of your repository with the following content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# file: .github/workflows/main.yml&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;CI&lt;/span&gt;
&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;main&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;main&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;e2e&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v3&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Setup Node.js&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v3&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;18&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install dependencies&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm ci&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run tests&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npx playwright test&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Upload screenshots to Argos&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npx @argos-ci/cli upload screenshots&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This workflow defines a job that runs on pull requests to the main branch. The job does the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Checkout the code from GitHub&lt;/li&gt;
&lt;li&gt;Setup Node.js 18&lt;/li&gt;
&lt;li&gt;Install dependencies&lt;/li&gt;
&lt;li&gt;Run the tests with Playwright&lt;/li&gt;
&lt;li&gt;Upload the screenshots to Argos&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once you have added the workflow file, you can commit and push the changes to your repository. GitHub will automatically start running the workflow on each pull request.&lt;/p&gt;

&lt;h2&gt;
  
  
  Monitor Visual Changes
&lt;/h2&gt;

&lt;p&gt;You can now start monitoring visual changes in your web application. Argos will detect and report any visual changes between your pull request branch and your &lt;code&gt;main&lt;/code&gt; branch.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GitHub check status&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Oed8Ia1k--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/smooth/image/upload/c_scale%2Cw_700/v1674471231/Argos/github-check-status.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Oed8Ia1k--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/smooth/image/upload/c_scale%2Cw_700/v1674471231/Argos/github-check-status.png" alt="GitHub check status" width="700" height="234"&gt;&lt;/a&gt;&lt;br&gt;
By clicking on "Details" link, you can review the results of the comparison in Argos.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Argos example build&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--BbXBlFJ7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/smooth/image/upload/v1674471477/Argos/argos-build-example.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--BbXBlFJ7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/smooth/image/upload/v1674471477/Argos/argos-build-example.png" alt="argos-build" width="800" height="389"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Read &lt;a href="https://argos-ci.com/docs/visual-testing"&gt;this documentation&lt;/a&gt; if you need more information about visual testing workflow.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this guide, we have shown you how to automate visual testing with Playwright, Argos, and GitHub Actions. By integrating visual testing into your CI workflow, you can catch and fix visual bugs before they make it into production. With Argos, you can easily configure baseline, monitor visual changes, and collaborate with your team to fix issues. By following the steps outlined in this guide, you can be sure that your web application looks and functions as intended, even as you make changes and updates.&lt;/p&gt;




&lt;p&gt;We hope this post has been helpful. If you're interested in learning about how Argos can help you improve the quality of your web applications, take a look at our &lt;a href="https://argos-ci.com/docs/installation"&gt;documentation&lt;/a&gt;. And if you're ready to start automating your visual testing, feel free to sign up for a &lt;a href="https://github.com/marketplace/argos-ci"&gt;free trial&lt;/a&gt; and see how Argos can help you catch bugs.&lt;/p&gt;

&lt;p&gt;If you need more information about Visual Testing, it would be a pleasure to help you on our &lt;a href="https://discord.gg/pK79sv85Vg"&gt;Discord community&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>testing</category>
      <category>playwright</category>
      <category>javascript</category>
      <category>argos</category>
    </item>
    <item>
      <title>How to improve developer experience (DX) with visual testing</title>
      <dc:creator>Jeremy SFEZ</dc:creator>
      <pubDate>Wed, 21 Dec 2022 08:56:48 +0000</pubDate>
      <link>https://dev.to/jsfez/how-to-improve-developer-experience-dx-with-visual-testing-ifm</link>
      <guid>https://dev.to/jsfez/how-to-improve-developer-experience-dx-with-visual-testing-ifm</guid>
      <description>&lt;p&gt;As a developer, there's nothing more frustrating than spending hours, if not days, working on a feature or bug fix, only to have it break the visual layout of the app. This not only slows down the development process, but it can also lead to frustration and loss of confidence in the quality of the work being delivered.&lt;/p&gt;

&lt;p&gt;That's where visual testing comes in.&lt;/p&gt;

&lt;h2&gt;
  
  
  Developer experience (DX)
&lt;/h2&gt;

&lt;p&gt;Developer experience refers to the overall satisfaction and efficiency of development tools, including design, usability, documentation, support, and working workflows.&lt;/p&gt;

&lt;p&gt;A good developer experience is important for maintaining a high level of productivity and software quality. Efficient tools and workflows allow developers to iterate quickly, and ultimately resulting in higher software quality and positive experiences for developers and users.&lt;/p&gt;

&lt;h2&gt;
  
  
  Visual testing to ship with confidence
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://argos-ci.com/blog/visual-testing" rel="noopener noreferrer"&gt;Visual testing&lt;/a&gt; is a type of testing that focuses on the visual aspects of an application, such as layout, design, and user interface elements. One way visual testing can be implemented is through the use of screenshot comparison tools. These tools allow developers to take screenshots of the app before and after a change is made.&lt;/p&gt;

&lt;p&gt;With visual testing tools like &lt;a href="https://argos-ci.com/" rel="noopener noreferrer"&gt;Argos&lt;/a&gt;, the screenshots are&lt;br&gt;
automatically compared, and if any differences are detected, the developer is alerted, allowing them to fix the potential issues before it becomes a problem.&lt;/p&gt;

&lt;p&gt;In addition, a visual tests suite can be created to ensure that the visual aspects of the app are consistent across different devices and screen sizes and catch visual issues early on. By implementing visual testing, developers can be confident that their work won't cause any visual issues that could break the app.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Overall, visual testing is invaluable for any developer looking to deliver high-quality, bug-free applications. Automatic visual testing improves software crafting workflow by giving developers more confidence in feature delivery and save time and effort in the long run.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Photo by &lt;a href="https://unsplash.com/@devn?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;devn&lt;/a&gt; on &lt;a href=""&gt;Unsplash&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>watercooler</category>
    </item>
    <item>
      <title>Set up Argos with Cypress and GitHub Actions in minutes</title>
      <dc:creator>Jeremy SFEZ</dc:creator>
      <pubDate>Fri, 09 Dec 2022 13:47:05 +0000</pubDate>
      <link>https://dev.to/jsfez/set-up-argos-with-cypress-and-github-actions-in-minutes-4g33</link>
      <guid>https://dev.to/jsfez/set-up-argos-with-cypress-and-github-actions-in-minutes-4g33</guid>
      <description>&lt;h2&gt;
  
  
  Argos visual testing
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.argos-ci.com/?utm_source=dev.to&amp;amp;utm_medium=blog&amp;amp;utm_campaign=cypress-github-article"&gt;Argos&lt;/a&gt; is a beautiful open-source app for visual testing.&lt;br&gt;
It is easy to install and less expensive than it's competitors.&lt;/p&gt;

&lt;p&gt;Visual testing is a scalable way to ensure the visual integrity of your web application and catch any potential visual bugs before they become a problem.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qcMl_njq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f8zv8jxdwq273ab3bgm2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qcMl_njq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f8zv8jxdwq273ab3bgm2.png" alt="Argos build" width="800" height="378"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Argos build example&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;When visual testing is combined with a CI workflow, you get an immediate feedback cycle that highlights visual diffs across browsers and screen resolutions for each pull request.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  5 steps installation
&lt;/h2&gt;

&lt;p&gt;Setting up Argos is blazing fast if you're working on a project that already uses Cypress for end-to-end testing and GitHub Actions as CI.&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 1 - Install the GitHub app
&lt;/h3&gt;

&lt;p&gt;Subscribe to a plan on &lt;a href="https://github.com/marketplace/argos-ci"&gt;GitHub Marketplace&lt;/a&gt; and follow the installation tunnel to authorize the GitHub app.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Argos is free up to 5K screenshots monthly.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  Step 2 - Install Argos' packages
&lt;/h3&gt;

&lt;p&gt;Install Argos CLI and the Argos Cypress plugin in your project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i &lt;span class="nt"&gt;--save-dev&lt;/span&gt; @argos-ci/cli @argos-ci/cypress
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 3 - Configure Cypress
&lt;/h3&gt;

&lt;p&gt;Add the following code to &lt;code&gt;cypress/support/index.js&lt;/code&gt; to enable the Argos Cypress plugin and use the &lt;code&gt;argosScreenshot&lt;/code&gt; command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// file: cypress/support/index.js&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@argos-ci/cypress/support&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 4 - Take a screenshot
&lt;/h3&gt;

&lt;p&gt;In your Cypress test files, use the &lt;code&gt;argosScreenshot&lt;/code&gt; command to take a screenshot of the page for visual testing with Argos. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// file: cypress/e2e/homepage.cy.js&lt;/span&gt;

&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Homepage&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;screenshots the page&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;visit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http://localhost:3000&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;argosScreenshot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;home&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;argosScreenshot&lt;/code&gt; command increases screenshot stability, but you can use the cypress' native screenshot command instead.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 5 - Configure GitHub Actions
&lt;/h3&gt;

&lt;p&gt;Add a command to your GitHub Actions config file to upload the screenshots to Argos.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# file: .github/workflows/ci.yml&lt;/span&gt;

&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;CI&lt;/span&gt;
  &lt;span class="s"&gt;build&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
      &lt;span class="s"&gt;- uses&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v3&lt;/span&gt;

      &lt;span class="s"&gt;# 👉 Insert the steps to execute Cypress tests&lt;/span&gt;

      &lt;span class="s"&gt;# 👇 Insert this command to upload screenshots to Argos&lt;/span&gt;
      &lt;span class="s"&gt;- name&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Upload screenshots to argos-ci.com&lt;/span&gt;
        &lt;span class="s"&gt;run&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npx @argos-ci/cli cypress/screenshots&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;h3&gt;
  
  
  Congratulation
&lt;/h3&gt;

&lt;p&gt;That's it! Argos will automatically receive screenshots of your pages when you push a commit to GitHub. In addition, Argos will compare them to previous versions to ensure no unexpected changes.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--yyuctNR0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9id9elq7o6ut3qt8fodj.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--yyuctNR0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9id9elq7o6ut3qt8fodj.jpeg" alt="congratulation meme" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Review visible changes
&lt;/h3&gt;

&lt;p&gt;You can now review the visual diffs on Argos and avoid regression. In your pull request, click on &lt;strong&gt;details&lt;/strong&gt; link in front of the Argos check to open the build on Argos.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--FJNPCCxO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tc3d0y7fgbyps0rek87v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--FJNPCCxO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tc3d0y7fgbyps0rek87v.png" alt="Argos check status" width="800" height="363"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Credit and sources
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Photo by &lt;a href="https://unsplash.com/fr/@pheiskan"&gt;Petri Heiskanen&lt;/a&gt; on Unsplash.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.argos-ci.com/?utm_source=dev.to&amp;amp;utm_medium=blog&amp;amp;utm_campaign=cypress-github-article"&gt;Argos website&lt;/a&gt; and &lt;a href="https://docs.argos-ci.com/?utm_source=dev.to&amp;amp;utm_medium=blog&amp;amp;utm_campaign=cypress-github-article"&gt;docs&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.argos-ci.com/argos-cli?utm_source=dev.to&amp;amp;utm_medium=blog&amp;amp;utm_campaign=cypress-github-article"&gt;Argos CLI&lt;/a&gt; and &lt;a href="https://docs.argos-ci.com/cypress?utm_source=dev.to&amp;amp;utm_medium=blog&amp;amp;utm_campaign=cypress-github-article"&gt;Argos Cypress plugin&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>testing</category>
      <category>javascript</category>
      <category>opensource</category>
      <category>github</category>
    </item>
  </channel>
</rss>
