<?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: Mike Shi</title>
    <description>The latest articles on DEV Community by Mike Shi (@mikeshi).</description>
    <link>https://dev.to/mikeshi</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%2F832034%2F10092dca-8f3b-44f7-97c2-13232b6667f9.jpg</url>
      <title>DEV Community: Mike Shi</title>
      <link>https://dev.to/mikeshi</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mikeshi"/>
    <language>en</language>
    <item>
      <title>5 Ways to Better Debug Failing Cypress Tests in CI</title>
      <dc:creator>Mike Shi</dc:creator>
      <pubDate>Thu, 19 Jan 2023 20:20:44 +0000</pubDate>
      <link>https://dev.to/mikeshi/5-ways-to-better-debug-failing-cypress-tests-in-ci-133n</link>
      <guid>https://dev.to/mikeshi/5-ways-to-better-debug-failing-cypress-tests-in-ci-133n</guid>
      <description>&lt;p&gt;Debugging Cypress tests when they fail only in CI can be a challenging task. With the right tools and techniques, it’s possible to gather the debug info needed to fix a test, instead of just hitting retry one more time.&lt;/p&gt;

&lt;p&gt;We’ll walk through a few tips you can use to pull more debug information out of your Cypress tests when they fail in CI. If you'd like, you can read the &lt;a href="https://www.deploysentinel.com/blog/debug-failing-cypress-tests-in-ci" rel="noopener noreferrer"&gt;original version of this article directly on our blog&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Add Debug Data via &lt;code&gt;cy.log&lt;/code&gt;
&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%2Ftlivnys05ww5115ioqja.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%2Ftlivnys05ww5115ioqja.png" alt="cy.log demo in command log" width="800" height="274"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;cy.log&lt;/code&gt; is a powerful tool to help annotate your tests with debug information for both local and remote development. &lt;code&gt;cy.log&lt;/code&gt; output will show up in the command log UI and console.log of the test browser. This means in CI, information in &lt;code&gt;cy.log&lt;/code&gt; can be seen in the screenshots or videos.&lt;/p&gt;

&lt;p&gt;You can use &lt;code&gt;cy.log&lt;/code&gt; to anotate what part of the test is running, or to print out test state like the ID of the fake user that's being used in the test to correlate with backend logs.&lt;/p&gt;

&lt;p&gt;While this is the easiest method of adding additional debug information, the fact that it’s limited to being shown in videos or screenshots makes its utility&lt;br&gt;
limited.&lt;/p&gt;
&lt;h2&gt;
  
  
  Output Debug Data via stdout
&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%2Frd7hfjpykhafmndiog68.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%2Frd7hfjpykhafmndiog68.png" alt="cy.task log to stdout demo" width="800" height="164"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Often times debugging starts with looking through the logs of your CI output. However, you’ll quickly realize that regular &lt;code&gt;console.log&lt;/code&gt; in Cypress tests won’t actually show up in your CI logs. While &lt;code&gt;cy.log&lt;/code&gt; can help surface information inside of a video or screenshot, we can actually push data directly into standard output/CI logs.&lt;/p&gt;

&lt;p&gt;We’ll need to do this via introducing a new &lt;code&gt;cy.task&lt;/code&gt; to push debug information from your test script running in the browser, to the Node process that can output the information to the CLI.&lt;/p&gt;

&lt;p&gt;In your Cypress config file (&lt;code&gt;cypress.config.js&lt;/code&gt;) you’ll need to define the following :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&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="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cypress&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&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;e2e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setupNodeEvents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;on&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;task&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;log&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;message&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;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
          &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&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="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 within your test, you can easily call &lt;code&gt;cy.task("log", ...anyDebugDataHere);&lt;/code&gt; to output debug information straight into your CI logs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Install Terminal Report Plugin
&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%2F8le1nqoux91kgld34z5z.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%2F8le1nqoux91kgld34z5z.png" alt="Cypress Terminal Report plugin demo" width="800" height="310"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/archfz/cypress-terminal-report" rel="noopener noreferrer"&gt;Cypress terminal report&lt;/a&gt; is an open source Cypress plugin that outputs actions, intercepted requests, console messages and errors directly to stdout in a convenient format. It’s a more-complete version of using either &lt;code&gt;cy.task&lt;/code&gt; or &lt;code&gt;cy.log&lt;/code&gt; to output basic debug information to the CLI and can help surface more debug information for tricky test cases.&lt;/p&gt;

&lt;p&gt;Getting it installed is really easy:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Run &lt;code&gt;npm i --save-dev cypress-terminal-report&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Install the plugin (in &lt;code&gt;cypress.config.js&lt;/code&gt;)
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&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;e2e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setupNodeEvents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;on&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cypress-terminal-report/src/installLogsPrinter&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="nx"&gt;on&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;ol&gt;
&lt;li&gt;Install the support file (in &lt;code&gt;cypress/support/e2e.js&lt;/code&gt;)
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cypress-terminal-report/src/installLogsCollector&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;p&gt;Afterwards you’ll be able to see action logs and other debug information in your stdout when a test fails.&lt;/p&gt;

&lt;h2&gt;
  
  
  Output Verbose Debug Logs from Cypress
&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%2Fadnu0zilnj6e3ydv6pde.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%2Fadnu0zilnj6e3ydv6pde.png" alt="Cypress debug profiler for memory leaks" width="800" height="142"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If the test failure is particularly tricky, you can try enabling debug logs in Cypress to check for issues around excess memory/CPU usage (which can cause flakes) or specific network errors.&lt;/p&gt;

&lt;p&gt;You can enable network logging by prepending &lt;code&gt;DEBUG=cypress:net*&lt;/code&gt; in front of your Cypress run command like the following: &lt;code&gt;DEBUG=cypress:net* yarn run cypress run --browser chrome&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;You can enable memory/CPU logging by prepending &lt;code&gt;DEBUG=cypress:server:util:process_profiler&lt;/code&gt; in front of your Cypress run command.&lt;/p&gt;

&lt;p&gt;However, these log messages are typically extremely verbose and can be difficult to sift through, so I’d only recommend trying to use these as a last resort, and keeping them disabled normally to keep your CI logs usable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Install DeploySentinel Cypress Debugger Plugin
&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%2F4tynss4tda9eesfi30qq.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%2F4tynss4tda9eesfi30qq.png" alt="DeploySentinel Cypress debugger for CI" width="800" height="510"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://www.deploysentinel.com/docs" rel="noopener noreferrer"&gt;DeploySentinel Cypress debugger plugin&lt;/a&gt; automatically collects every DOM snapshot, console logs, network request, memory usage, and more automatically and displays it within a &lt;code&gt;cypress open&lt;/code&gt;-like debugging interface. It makes it easier to sift through and correlate mountains of debug information that can be put out by the tools above.&lt;/p&gt;

&lt;p&gt;Getting it installed is as easy as any other Cypress plugin:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Run &lt;code&gt;npm i --save-dev @deploysentinel/cypress-debugger&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Install the plugin (in &lt;code&gt;cypress.config.js&lt;/code&gt;)
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&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="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cypress&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&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;e2e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setupNodeEvents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;on&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;config&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="nx"&gt;on&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@deploysentinel/cypress-debugger/plugin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;
        &lt;span class="nx"&gt;on&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;config&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="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Install the support file (in &lt;code&gt;cypress/support/e2e.js&lt;/code&gt;)
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@deploysentinel/cypress-debugger/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;ol&gt;
&lt;li&gt;Run with a DeploySentinel API key (&lt;a href="https://www.deploysentinel.com/register" rel="noopener noreferrer"&gt;get started for free&lt;/a&gt;)
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;CYPRESS_DEPLOYSENTINEL_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;YOUR_API_KEY&lt;/span&gt; &lt;span class="nx"&gt;npx&lt;/span&gt; &lt;span class="nx"&gt;cypress&lt;/span&gt; &lt;span class="nx"&gt;run&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="nx"&gt;browser&lt;/span&gt; &lt;span class="nx"&gt;chrome&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From there, you’ll be able to debug test failures directly in the DeploySentinel web app, with all the telemetry you can get locally, and more!&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Setting up Cypress with Github Actions and Heroku Review Apps</title>
      <dc:creator>Mike Shi</dc:creator>
      <pubDate>Thu, 13 Oct 2022 19:03:29 +0000</pubDate>
      <link>https://dev.to/mikeshi/setting-up-cypress-with-github-actions-and-heroku-review-apps-1k6o</link>
      <guid>https://dev.to/mikeshi/setting-up-cypress-with-github-actions-and-heroku-review-apps-1k6o</guid>
      <description>&lt;p&gt;I’ve spent this past weekend setting up Cypress tests for a project hosted on Heroku. I used Heroku's preview environments along with Github Actions to quickly set up Cypress to run against PRs in just a few minutes. Let's dive into what it takes to get it set up!&lt;/p&gt;

&lt;h2&gt;
  
  
  Set Up Heroku Review Apps
&lt;/h2&gt;

&lt;p&gt;First we’ll want to enable review apps on Heroku, fortunately it’s super easy to get started. Heroku’s docs are &lt;a href="https://devcenter.heroku.com/articles/github-integration-review-apps"&gt;available here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The most important part is to choose the &lt;a href="https://devcenter.heroku.com/articles/github-integration-review-apps#selecting-the-url-pattern"&gt;predictable review app URL&lt;/a&gt;&lt;br&gt;
option - this makes it easy for your Cypress to know how to connect to your Heroku preview instance. We'll use this later in our Github workflow.&lt;/p&gt;
&lt;h2&gt;
  
  
  Set up Github Action Workflow
&lt;/h2&gt;

&lt;p&gt;With our Github action workflow, we’re going to use the&lt;br&gt;
&lt;a href="https://docs.github.com/en/actions/learn-github-actions/contexts"&gt;Github Action context&lt;/a&gt; to access the current PR number, which will let us specify the review app URL. So we can specify the review app URL like:&lt;br&gt;
&lt;code&gt;https://cy-heroku-review-pr-${{github.event.pull_request.number }}.herokuapp.com&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;In this example, I chose &lt;code&gt;cy-heroku-review&lt;/code&gt; as my review app prefix, you'll need to replace it with the predictable URL pattern you chose earlier in this guide.&lt;/p&gt;

&lt;p&gt;Additionally, we’ll be using the &lt;a href="https://www.npmjs.com/package/wait-on"&gt;&lt;code&gt;wait-on&lt;/code&gt; npm package&lt;/a&gt; to have our&lt;br&gt;
Github runner wait until the URL is available on Heroku before triggering Cypress. This allows us to have more control on waiting for the review app to be available than just letting Cypress retry itself (ex. if you want a longer wait period).&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="na"&gt;on&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;test-heroku&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-20.04&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;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Checkout&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@v2&lt;/span&gt;
      &lt;span class="pi"&gt;-&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;yarn install&lt;/span&gt;
      &lt;span class="c1"&gt;# Here we're waiting for the Heroku preview instance to boot up&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;Wait for Server&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 wait-on https://cy-heroku-review-pr-${{&lt;/span&gt;
          &lt;span class="s"&gt;github.event.pull_request.number }}.herokuapp.com&lt;/span&gt;
      &lt;span class="c1"&gt;# Here we're running the test, specifying the baseUrl via the CLI&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 E2E 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;yarn test --config baseUrl=https://cy-heroku-review-pr-${{&lt;/span&gt;
          &lt;span class="s"&gt;github.event.pull_request.number }}.herokuapp.com&lt;/span&gt;
        &lt;span class="c1"&gt;# Adding the DeploySentinel debugger&lt;/span&gt;
        &lt;span class="c1"&gt;# So we can easily debug test failures in case anything goes wrong 😉&lt;/span&gt;
        &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;CYPRESS_DEPLOYSENTINEL_KEY&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.CYPRESS_DEPLOYSENTINEL_KEY }}&lt;/span&gt;
          &lt;span class="na"&gt;ELECTRON_EXTRA_LAUNCH_ARGS&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;--remote-debugging-port=40500'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Run the Test!
&lt;/h2&gt;

&lt;p&gt;With the review app configured, and the Github action workflow in place, you can open a new PR and see the new workflow kick off and run your tests against a Heroku preview instance!&lt;/p&gt;

&lt;p&gt;I have a &lt;a href="https://github.com/DeploySentinel/heroku-review-cypress-github-action-demo"&gt;full demo repo available here&lt;/a&gt; to check out.&lt;/p&gt;

&lt;p&gt;Feel free to message me any thoughts/questions @ &lt;a href="mailto:mike@deploysentinel.com"&gt;mike@deploysentinel.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>tutorial</category>
      <category>testing</category>
      <category>github</category>
    </item>
    <item>
      <title>No Tears Guide to Creating E2E Test Scripts for Playwright &amp; Puppeteer</title>
      <dc:creator>Mike Shi</dc:creator>
      <pubDate>Thu, 17 Mar 2022 20:29:30 +0000</pubDate>
      <link>https://dev.to/mikeshi/no-tears-guide-to-creating-e2e-test-scripts-for-playwright-puppeteer-127a</link>
      <guid>https://dev.to/mikeshi/no-tears-guide-to-creating-e2e-test-scripts-for-playwright-puppeteer-127a</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published on the &lt;a href="https://www.deploysentinel.com/blog/no-tears-guide-creating-e2e-tests-playwright-puppeteer"&gt;DeploySentinel Blog&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Getting browser automation scripts to do exactly what you want can feel like a never-ending battle between you and your code. I still remember vividly when I was up late one night years ago writing a Selenium script for a change I was making. I was banging my head against the table as I was running out of Selenium incantations to cast on my test to make it work.&lt;/p&gt;

&lt;p&gt;Fast forward to today, I’m writing up this guide on a few tricks I wish I knew at the time, to quickly craft reliable E2E tests, instead of crying over error logs and wrangling clueless automation scripts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use a Recorder
&lt;/h2&gt;

&lt;p&gt;A recorder is a tool that can record the browser actions you take, and turn those actions into a fully-working automation script. So you can start coding out your test, by simply stepping through your user flow as a user would.&lt;/p&gt;

&lt;p&gt;I know there are people who might be skeptical, but hear me out. Just as automation frameworks have dramatically improved over time, test recorders have gotten some serious love over time as well.&lt;/p&gt;

&lt;p&gt;I find test recorders pretty useful for a few reasons:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;No more hunting for selectors&lt;/strong&gt; - There’s no reason to be hunting for selectors yourself, when you can automate the work away. The best recorders use selector logic that will give you stable selectors, rather than trying to enumerate every div and class name on the way to your element. (We’ll also talk more about selectors later!)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;No more manually writing commands&lt;/strong&gt; - Just like selectors, there’s no need to manually type out every “click” “fill” and “waitFor” command, when you can get all of that for free by just simply walking through your web pages.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Best practices are built in&lt;/strong&gt; - While recorders won’t generate perfect code, they will have best-practices built-in. Instead of needing to worry about using “fill” instead of “type”, or remembering how to await for text in Puppeteer, you can just let the recorder generate code that’s aligned with best practices, so you can focus on the rest of your work.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Ultimately, using a test recorder can give you a head start, save you from doing the boring parts of testing, and let you focus on the harder parts of perfecting a test automation script.&lt;/p&gt;

&lt;p&gt;Here’s a few recorders that can help you get started:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://deploysentinel.com/recorder"&gt;DeploySentinel Recorder&lt;/a&gt;: A Chrome/Firefox Extension that generates Playwright/Puppeteer scripts (Disclaimer: I am one of the authors, but only because I wanted to build the most accurate recorder available)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://playwright.dev/docs/codegen"&gt;Playwright Codegen&lt;/a&gt;: A CLI tool included in Playwright.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://developer.chrome.com/docs/devtools/recorder/"&gt;Puppeteer Chrome DevTool Recorder&lt;/a&gt;: A recorder built into Chrome for Puppeteer.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://chrome.google.com/webstore/detail/headless-recorder/djeegiggegleadkkbgopoonhjimgehda?hl=en"&gt;Headless Recorder&lt;/a&gt;: A Chrome Extension that can automate some simpler actions.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Use Stable Selectors
&lt;/h2&gt;

&lt;p&gt;As dynamic CSS classes and elements are the norm today, it can be difficult to try to pick selectors that are robust to a rapidly changing code base, or even a rapidly changing web page due to async logic.&lt;/p&gt;

&lt;p&gt;Especially if your project uses something like Tailwinds, styled-components, or even a JS framework like React or Vue that use async logic to render elements, you might be struggling to figure out how to target the right element reliably.&lt;/p&gt;

&lt;h3&gt;
  
  
  First Solution: Test IDs
&lt;/h3&gt;

&lt;p&gt;The best way to combat these issues is to explicitly introduce a stable selector to elements you’re looking to test, and nothing beats stability like introducing test IDs to your application. &lt;/p&gt;

&lt;p&gt;The concept is very simple: for elements you need to interact with, append a &lt;code&gt;data-test-id=”my-element”&lt;/code&gt; attribute to the HTML element. In your automation scripts, you can easily target the element with&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;await&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;click&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[data-test-id="my-element"]&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;p&gt;Now you’ll never need to worry about your selectors breaking the next time your team decides to change button colors or re-builds the application with a new minified class name.&lt;/p&gt;

&lt;p&gt;However, this requires adding new attributes to elements you need to target. Depending on how open the application owners are to adding these new attributes, it may be difficult to rely on them. If test IDs aren’t possible, I’d fall back to the next best solution.&lt;/p&gt;

&lt;h3&gt;
  
  
  Second Solution: Accessibility Selectors
&lt;/h3&gt;

&lt;p&gt;Luckily with accessibility becoming a higher priority for web applications, more and more critical elements that need to be interacted with might already have a machine-friendly label attached to it.&lt;/p&gt;

&lt;p&gt;Usually you’ll see attributes such as &lt;code&gt;aria-label&lt;/code&gt;, &lt;code&gt;alt&lt;/code&gt;, or &lt;code&gt;title&lt;/code&gt; for elements you want to interact with. Those attributes tend to be more stable than CSS classes and can serve as a good stop-gap measure until you’re able to implement test IDs for the elements you need to test.&lt;/p&gt;

&lt;p&gt;A script that utilizes these attributes might look like&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;await&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;click&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[alt="Main Logo"]&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;
  
  
  Last Solution: Text Content Selectors
&lt;/h3&gt;

&lt;p&gt;If you’re testing an application that might not have all the accessibility selectors built out yet, and haven’t had time to implement test IDs, the last solution you can look towards is targeting elements by text content.&lt;/p&gt;

&lt;p&gt;At first glance, it might sound like an incredibly fragile proposition. Indeed it can be for certain elements, but for others it may be the best stable solution available. Can you remember the last time your team updated the “Sign In” button text on your application?&lt;/p&gt;

&lt;p&gt;For elements with non-dynamic text content, usually buttons or input placeholders, text content can be a fairly reliable way of target elements.&lt;/p&gt;

&lt;p&gt;Luckily in Playwright, it’s incredibly easy to target elements by text like so:&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="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;click&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text=Sign In&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;p&gt;In Puppeteer, you’ll need to dip into XPaths to target elements by text:&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;await&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;waitForXPath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;//*[contains(., "Sign In")]&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="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;]&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;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$x&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;//*[contains(., "Sign In")]&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="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;click&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Automate Selector Picking
&lt;/h3&gt;

&lt;p&gt;These best practices of stable selectors mentioned here and more are already built-in to &lt;a href="https://deploysentinel.com/recorder"&gt;DeploySentinel Recorder’s&lt;/a&gt; selector picking logic. So you don’t have to hunt for a specific test ID or accessibility selector.&lt;/p&gt;

&lt;h2&gt;
  
  
  Flip On the Debug Features
&lt;/h2&gt;

&lt;p&gt;If you’re banging your head against a test script trying to figure out why it isn’t working, whipping out the debugging modes is probably the fastest way to find out why your script isn’t doing what you want.&lt;/p&gt;

&lt;h3&gt;
  
  
  Playwright’s Inspector and Trace Viewer
&lt;/h3&gt;

&lt;p&gt;With Playwright, it’s incredibly easy to append &lt;code&gt;PWDEBUG=1&lt;/code&gt; in front of your script to pull up &lt;a href="https://playwright.dev/docs/inspector"&gt;Playwright Inspector&lt;/a&gt;, where it’ll be able to step through everything Playwright is doing in great detail during the test. If there’s a step you have issues with, you can add &lt;code&gt;await page.pause()&lt;/code&gt; to pause the test run so you can inspect the page at that point in time.&lt;/p&gt;

&lt;p&gt;If you’re executing the script in a remote environment, you can take advantage of Playwright’s &lt;a href="https://playwright.dev/docs/trace-viewer"&gt;Trace Viewer&lt;/a&gt; which records detailed logs and DOM snapshots before and after every action.&lt;/p&gt;

&lt;p&gt;If you’re using DeploySentinel to run your test - Playwright traces are captured by default and viewable at any time to debug test runs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Headed Mode and Slow Mo
&lt;/h3&gt;

&lt;p&gt;In general you can also enable headed mode with slow motion enabled to visually see what your script is doing. Both Playwright and Puppeteer support this with just two extra lines of code. See the docs for &lt;a href="https://playwright.dev/docs/debug#run-in-headed-mode"&gt;Playwright&lt;/a&gt; and &lt;a href="https://github.com/puppeteer/puppeteer/blob/main/README.md#debugging-tips"&gt;Puppeteer&lt;/a&gt; here.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://deploysentinel.com/recorder"&gt;DeploySentinel Recorder&lt;/a&gt; will always have these two options commented out but inserted as part of every script generated to make it easy to debug locally.&lt;/p&gt;

&lt;h3&gt;
  
  
  Enable Chrome Dev Tools
&lt;/h3&gt;

&lt;p&gt;Lastly if there’s an issue that requires you to look at network requests or browser logs, you can have Playwright and Puppeteer open the Chrome dev tools panel on browser launch so all logs and network requests are captured from the start automatically for you. See the &lt;a href="https://playwright.dev/docs/debug#browser-developer-tools"&gt;Playwright docs&lt;/a&gt; here or the dev tools section of &lt;a href="https://github.com/puppeteer/puppeteer/blob/main/README.md#debugging-tips"&gt;Puppeteer’s debugging docs&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  You’re All Set!
&lt;/h2&gt;

&lt;p&gt;I hope this list of tips helps you out in creating testing scripts for Puppeteer or Playwright.&lt;/p&gt;

&lt;p&gt;If you’re looking to run tests easily and affordably - you can &lt;a href="https://deploysentinel.com/"&gt;try DeploySentinel for free&lt;/a&gt;, with many of the above best practices included for you with no extra effort.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>playwright</category>
      <category>tutorial</category>
      <category>testing</category>
    </item>
  </channel>
</rss>
