<?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: davert</title>
    <description>The latest articles on DEV Community by davert (@davert).</description>
    <link>https://dev.to/davert</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%2F79818%2F3f1bbcfa-b724-4b42-952b-434e1f2ec1a7.jpg</url>
      <title>DEV Community: davert</title>
      <link>https://dev.to/davert</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/davert"/>
    <language>en</language>
    <item>
      <title>Unleashing AI to Heal Flaky Tests in CodeceptJS with Playwright</title>
      <dc:creator>davert</dc:creator>
      <pubDate>Sun, 21 Apr 2024 23:18:18 +0000</pubDate>
      <link>https://dev.to/davert/unleashing-ai-to-heal-flaky-tests-in-codeceptjs-with-playwright-10do</link>
      <guid>https://dev.to/davert/unleashing-ai-to-heal-flaky-tests-in-codeceptjs-with-playwright-10do</guid>
      <description>&lt;p&gt;Dealing with flaky tests is one of the biggest pain points for anyone doing browser and end-to-end test automation. You know the drill - tests that started to fail without any reason. Intermittent failures that sap confidence in the test suite and prevent stable deployments. &lt;strong&gt;Maintaining tests can take up to 50% of the time for QA test automation engineer&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Usually, the cause of failure is quite simple: the element name has changed, or a new modal window appeared. What if we could use AI to identify the root cause and try to fix the test on the fly, instead of distracting engineer from their actual work? &lt;/p&gt;

&lt;p&gt;That's what I did.&lt;/p&gt;

&lt;p&gt;Rather than just re-running flaky tests hoping they'll pass, or manually debugging every failure, I tried several popular AI models with new &lt;a href="https://codecept.io/ai/#self-healing-tests" rel="noopener noreferrer"&gt;AI healing feature of CodeceptJS&lt;/a&gt; to fix failing tests. &lt;/p&gt;

&lt;p&gt;The results were quite promising...&lt;/p&gt;

&lt;h2&gt;
  
  
  TLDR: AI CAN FIX YOUR TESTS!
&lt;/h2&gt;

&lt;p&gt;But you still need to read further, to learn which models I used and how to configure them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Failing Test
&lt;/h2&gt;

&lt;p&gt;I started with a failing test which opens GitHub login page but uses incorrect locators. &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;
&lt;span class="nc"&gt;Scenario&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Github login&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="nx"&gt;I&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;I&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;amOnPage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://github.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;I&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&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;Sign in&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;I&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fillField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Username&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="s1"&gt;davert&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;I&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fillField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Password&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="s1"&gt;123345&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;I&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&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;Login&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;I&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;see&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Incorrect username or password&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;This test is executed by &lt;strong&gt;CodeceptJS&lt;/strong&gt; using Playwright as an engine. As an alternative, you can use webdriverio as the engine of choice, but I prefer Playwright as it is faster.&lt;/p&gt;

&lt;p&gt;This test fails because there is no "Login" button on the page and no "Username" field. So test won't get to the assertion step and fail on interaction. &lt;/p&gt;

&lt;p&gt;The failing test runs ~4 secs. We need to keep that information to see how using AI impacts the speed of a test.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Fixing tests on the fly is possible with &lt;a href="https://codecept.io/heal.html" rel="noopener noreferrer"&gt;&lt;code&gt;heal&lt;/code&gt; plugin&lt;/a&gt; of CodeceptJS. &lt;a href="https://codecept.io/ai/#how-ai-improves-automated-testing" rel="noopener noreferrer"&gt;It should be enabled&lt;/a&gt; in &lt;code&gt;codecept.conf.js&lt;/code&gt; as well as AI provider to make things work. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  ChatGPT
&lt;/h2&gt;

&lt;p&gt;This was my first stop, as OpenAI's ChatGPT has been a game-changer in making AI accessible. My model of choice was &lt;code&gt;gpt-3.5-turbo-0125&lt;/code&gt;. To start using it I had to fill my credits balance in &lt;a href="https://platform.openai.com" rel="noopener noreferrer"&gt;OpenAI Console&lt;/a&gt;. ChatGPT is still free but if you use it via API, you need to have pre-paid credits. However, it's relatively cheap. I spent only a few cents playing with it.&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%2Fu5b6grhny7g2islj2iod.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%2Fu5b6grhny7g2islj2iod.png" alt="open ai console billing"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I updated my &lt;code&gt;codecept.conf.js&lt;/code&gt; file to use it as AI provider:&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;ai&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;request&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;messages&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;completion&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;openai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;completions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;gpt-3.5-turbo-0125&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;completion&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;choices&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="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;content&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;blockquote&gt;
&lt;p&gt;The complete configuration is &lt;a href="https://codecept.io/ai/#how-ai-improves-automated-testing" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I executed the test few times and with &lt;code&gt;--ai&lt;/code&gt; mode and test has passed. Yey!&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%2Fymmjeyqi9q5cwn81x5a0.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%2Fymmjeyqi9q5cwn81x5a0.png" alt="gpr-results"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I received very sane suggestions to fix tests:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. To fix Github login
  Replace the failed code: (suggested by ai)
- I.fillField("Username", "davert")
+ I.fillField("input#login_field", "davert")
at Test.&amp;lt;anonymous&amp;gt; (./tests/ai_test.js:12:5)

2. To fix Github login
  Replace the failed code: (suggested by ai)
- I.click("Login")
+ I.click("input[value='Sign in']")
at Test.&amp;lt;anonymous&amp;gt; (./tests/ai_test.js:14:5)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Both are correct. However, test duration has risen &lt;strong&gt;from 4s to 12s&lt;/strong&gt; which is not great not terrible. I can assume that every call to OpenAI can take an additional ~4s (or more).&lt;/p&gt;

&lt;h2&gt;
  
  
  Claude (Anthropic)
&lt;/h2&gt;

&lt;p&gt;I then tried the impressive Claude model from Anthropic. Claude seemed to have stronger reasoning capabilities and was able to provide more nuanced suggestions. I liked Claude more than ChatGPT 3.5 when I had to solve my daily programming tasks. How good Claude is when it comes to fixing tests on the fly?&lt;/p&gt;

&lt;p&gt;Claude provides free 5$ credits to start. Nice!&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%2Fgm86z0ylmcoxwbvvnm4d.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%2Fgm86z0ylmcoxwbvvnm4d.png" alt="claude console"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I updated my config to use &lt;code&gt;claude-2.1&lt;/code&gt; model via Anthropic SDK:&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;ai&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;request&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;messages&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;resp&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;anthropic&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;claude-2.1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;max_tokens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;messages&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;      
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;c&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;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\n\n&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;This model also provided valid results:&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%2Fzuskcqbdlr1j0rnhx7p2.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%2Fzuskcqbdlr1j0rnhx7p2.png" alt="claude"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. To fix Github login
  Replace the failed code: (suggested by ai)
- I.fillField("Username", "davert")
+ I.fillField('#login_field', 'davert');
at Test.&amp;lt;anonymous&amp;gt; (./tests/ai_test.js:12:5)

2. To fix Github login
  Replace the failed code: (suggested by ai)
- I.click("Login")
+ I.click('.js-sign-in-button');
at Test.&amp;lt;anonymous&amp;gt; (./tests/ai_test.js:14:5)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;But took almost 25 secs! That's too long! &lt;/p&gt;

&lt;p&gt;However, I used the legacy Claude 2.1 model, Anthropic recommends &lt;code&gt;Haiku&lt;/code&gt; model as a lightweight replacement for it.&lt;/p&gt;

&lt;p&gt;So I updated my config:&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;request&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;messages&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;resp&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;anthropic&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;claude-3-haiku-20240307&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;max_tokens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;messages&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;      
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;c&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;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\n\n&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;However, it was not faster than claude 2.1. It took 25s.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AI assistant took 25s and used ~3K input tokens. Tokens limit: 1000K

===================
Self-Healing Report:
2 steps were healed

Suggested changes:

1. To fix Github login
  Replace the failed code: (suggested by ai)
- I.fillField("Username", "davert")
+ I.fillField('#login_field', 'davert');
at Test.&amp;lt;anonymous&amp;gt; (./tests/ai_test.js:12:5)

2. To fix Github login
  Replace the failed code: (suggested by ai)
- I.click("Login")
+ I.click('Sign in');
at Test.&amp;lt;anonymous&amp;gt; (./tests/ai_test.js:14:5)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;I think Claude's general purpose model is not the best choice for healing tests. &lt;/p&gt;

&lt;h2&gt;
  
  
  Mixtral
&lt;/h2&gt;

&lt;p&gt;Mixtral was something new to me. I never tried to use mostly because it doesn't have common chat interface as Claude or ChatGPT. But recently I discovered service &lt;a href="https://groq.com" rel="noopener noreferrer"&gt;Groq&lt;/a&gt; that provides the same experience as ChatGPT and Claude but for opensource models like Mixtral.&lt;/p&gt;

&lt;p&gt;Btw, this model is opensource so you can run it on Claudeflare, Google, Amazon, or locally. However, I will use groq due to its simplicity. &lt;/p&gt;

&lt;p&gt;And at this moment it's free to use!&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%2Fyvgyndqfu3tf6kln16al.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%2Fyvgyndqfu3tf6kln16al.png" alt="groq service"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I updated my config to use mixtral via groq:&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;request&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;messages&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;chatCompletion&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;groq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;completions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
          &lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;mixtral-8x7b-32768&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;  &lt;span class="c1"&gt;// llama2-70b-4096 || gemma-7b-it || llama3-70b-8192 || mixtral-8x7b-32768&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;chatCompletion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;choices&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="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt; &lt;span class="o"&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Well, this was faaast!&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%2F9zqmthcknnwgs3g97uid.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%2F9zqmthcknnwgs3g97uid.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The suggestions were good, and quite surprisingly it took 7s to fix 2 steps!&lt;/p&gt;

&lt;h2&gt;
  
  
  LLAMA
&lt;/h2&gt;

&lt;p&gt;Another opensource model available from Groq is LLAMA from Meta. Let's try llama2:&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;request&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;messages&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;chatCompletion&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;groq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;completions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
          &lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;llama2-70b-4096&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;chatCompletion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;choices&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="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt; &lt;span class="o"&gt;||&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;Llama2 failed to provide a fix.&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%2Frqb12u5w8wwrt5q5ztu3.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%2Frqb12u5w8wwrt5q5ztu3.png" alt="llama2-result"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;According to the logs it suggested code fixes for Codeception PHP testing framework, which didn't work in JS:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Here's an example code snippet that demonstrates how to adjust the `click` method to fix the test:

$I-&amp;gt;click('Login');
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Very bad. Maybe llama3 is better? I also tried &lt;code&gt;llama3-70b-8192&lt;/code&gt; model:&lt;/p&gt;

&lt;p&gt;It failed &lt;br&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%2Fa51h401aqolngpsjganp.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%2Fa51h401aqolngpsjganp.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;but after a few tries it resulted in fixing one step&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%2Fdh950qhe3gl6eq43a2rx.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%2Fdh950qhe3gl6eq43a2rx.png" alt="llama3-result"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Also, I don't like the suggested locator&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. To fix Github login
  Replace the failed code: (suggested by ai)
- I.click("Login")
+ I.click('a[href*="login"]')
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Llama seems like very fast (7s) but very unstable for tasks like this. Maybe another day?&lt;/p&gt;

&lt;h2&gt;
  
  
  Gemma
&lt;/h2&gt;

&lt;p&gt;Groq provides access to Gemma model from Google. Why not adding model &lt;code&gt;gemma-7b-it&lt;/code&gt; to competition?&lt;/p&gt;

&lt;p&gt;It worked and worked fast!&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%2Fs6jgzjwuzhdayyn9my0c.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%2Fs6jgzjwuzhdayyn9my0c.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But after a few tries, I didn't manage to reproduce the result. Sometimes its response is not valid JS code so it can't be taken into action:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;**Solution:**

The adjusted locator `'.auth-form-body form button[type="submit"]:contains("Sign in")'` addresses the issue by:
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Unfortunately, CodeceptJS can't run the code from its words.&lt;/p&gt;

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

&lt;p&gt;AI can improve the way we keep our end-2-end tests up to date. If you run a lot of browser tests on CI you should already try to use AI assistant to reduce flakiness of your tests. Just why not? &lt;/p&gt;

&lt;p&gt;If it fixes a test, it will use much less time then you would do reproducing and re-running this test.&lt;/p&gt;

&lt;p&gt;If it fails, you lose nothing. AI is quite cheap, esp comparing to QA engineers rates.&lt;/p&gt;

&lt;p&gt;As of &lt;strong&gt;April 2024 the best model you can use to heal flaky tests is Mixtral &lt;code&gt;mixtral-8x7b-32768&lt;/code&gt;&lt;/strong&gt;. True winner! It took about 1s for request. You can enable it today with Groq in your CodeceptJS setup and have your tests fixed up on the fly!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ChatGPT-Turbo &lt;code&gt;gpt-3.5-turbo-0125&lt;/code&gt; also showed a good result&lt;/strong&gt;. Last year on same task it took ~20-30s per request. Serious improvement, as the request time was reduced to 4s.&lt;/p&gt;

&lt;p&gt;P.S. Sure, general LLM are not stable and can't guarantee the same results. But even if they can fix 10% of failures for you, that can make huge impact! &lt;/p&gt;




&lt;p&gt;Source code:&lt;br&gt;
&lt;a href="https://github.com/DavertMik/codecept-ai-demo/tree/demo" rel="noopener noreferrer"&gt;https://github.com/DavertMik/codecept-ai-demo/tree/demo&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How to fake time inside Docker container</title>
      <dc:creator>davert</dc:creator>
      <pubDate>Mon, 23 Oct 2023 16:46:00 +0000</pubDate>
      <link>https://dev.to/davert/how-to-fake-time-inside-docker-container-581k</link>
      <guid>https://dev.to/davert/how-to-fake-time-inside-docker-container-581k</guid>
      <description>&lt;p&gt;Let me share a working advice you can use in case you need to jump in time in a Docker container. You may need this for testing purposes, for instance, to test some events in the future.&lt;/p&gt;

&lt;p&gt;You will need a Docker Image of the app you need want to launch.&lt;/p&gt;

&lt;p&gt;Create Docker file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM my-image
RUN apt update -y &amp;amp;&amp;amp; apt install -y faketime
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Build a container naming it &lt;code&gt;fake-time&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker build &lt;span class="nt"&gt;-t&lt;/span&gt; fake-time &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run new container&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run fake-time:latest faketime &lt;span class="s1"&gt;'2030-12-18 19:46:00'&lt;/span&gt; ./your-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or use it inside docker-compose:&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;service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;fake-time:latest"&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;faketime&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;'2030-12-18&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;19:46:00'&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;./your-app&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;a href="https://x.com/davert"&gt;Follow me on X for more&lt;/a&gt; development tips.&lt;/p&gt;

</description>
      <category>docker</category>
      <category>time</category>
      <category>container</category>
      <category>testing</category>
    </item>
    <item>
      <title>Practical Introduction to CodeceptJS: Writing End-to-end Test for Checkout Form</title>
      <dc:creator>davert</dc:creator>
      <pubDate>Fri, 02 Dec 2022 03:51:00 +0000</pubDate>
      <link>https://dev.to/davert/practical-introduction-to-codeceptjs-writing-end-to-end-test-for-checkout-form-577n</link>
      <guid>https://dev.to/davert/practical-introduction-to-codeceptjs-writing-end-to-end-test-for-checkout-form-577n</guid>
      <description>&lt;p&gt;The heart of every ecommerce website is its 'checkout' process. Whatever happens to a shop this should work to ensure the cashflow. That's why the checkout should be regularly tested. To reduce human factor and establish stability of the process we recommend using test automation framework. The simplest one to start is CodeceptJS&lt;/p&gt;

&lt;h2&gt;
  
  
  What-what? Did you say CodeceptJS?
&lt;/h2&gt;

&lt;p&gt;Yes! &lt;strong&gt;&lt;a href="https://codecept.io"&gt;CodeceptJS&lt;/a&gt; is a popular open-source testing framework&lt;/strong&gt; for JavaScript. It is designed to make it easy to write and maintain end-to-end tests for web applications, using a readable and intuitive syntax. To run tests in browser it uses &lt;strong&gt;&lt;a href="https://playwright.dev"&gt;Playwright&lt;/a&gt;&lt;/strong&gt; library from Microsoft.&lt;/p&gt;

&lt;p&gt;CodeceptJS was first released in 2015, and it has since become a popular testing framework for JavaScript developers. It is widely used by organizations of all sizes, from startups to large enterprises.&lt;/p&gt;

&lt;h2&gt;
  
  
  Let's get CodeceptJS installed!
&lt;/h2&gt;

&lt;p&gt;To install CodeceptJS, you will need to have Node.js and npm (the Node.js package manager) installed on your system. You can check if you already have these tools installed by running the following commands in a terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;node &lt;span class="nt"&gt;--version&lt;/span&gt;
npm &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If either of these commands return an error, you will need to install Node.js and npm before you can install CodeceptJS. You can download and install the latest version of Node.js from the official website, which includes npm.&lt;/p&gt;

&lt;p&gt;To install CodeceptJS create a new folder and run command form terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx create-codeceptjs .
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you run the npx create-codeceptjs . command, it will install CodeceptJS with Playwright in the current directory. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The &lt;code&gt;npx&lt;/code&gt; command is a tool that comes with npm (the Node.js package manager) and it allows you to run npm packages without having to install them globally on your system.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It may take some time as it downloads browsers: Chrome, Firefox and Safari and creates a demo project.&lt;/p&gt;

&lt;p&gt;But we are here to write a checkout test, right?&lt;/p&gt;

&lt;p&gt;Let's initialize a new project for that!&lt;/p&gt;

&lt;p&gt;Run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx codeceptjs init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agree on defaults (press Enter for every question asked). When asked for base site URL, provide a URL of a ecommerce website you are testing. For instance, it could be: &lt;code&gt;https://myshop.com&lt;/code&gt; if you test already published website or &lt;code&gt;http://localhost&lt;/code&gt; if you run the website locally. &lt;/p&gt;

&lt;p&gt;When asked for a test name and suite name write "Checkout". It will create the following dirctory structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.
├── codecept.conf.js
├── package.json
└── Checkout_test.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;codecept.conf.js&lt;/code&gt; file in the root of the project directory contains the global configuration settings for CodeceptJS.&lt;/p&gt;

&lt;p&gt;Now open a test:&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;Feature&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Checkout&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;Scenario&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;test something&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="nx"&gt;I&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;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inside the Scenario block you write a test. &lt;/p&gt;

&lt;p&gt;Add &lt;code&gt;I.amOnPage('/')&lt;/code&gt; into it. It will open the browser on a URL you specified as a base.&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;Feature&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Checkout&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;Scenario&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;test something&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="nx"&gt;I&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;I&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;amOnPage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But you may want to ask...&lt;/p&gt;

&lt;h2&gt;
  
  
  What is I?
&lt;/h2&gt;

&lt;p&gt;Glad you asked! &lt;/p&gt;

&lt;p&gt;In CodeceptJS, the &lt;code&gt;I&lt;/code&gt; object is used to represent the user performing actions in a test scenario. It provides a number of methods (also known as actions) that can be used to simulate user interactions with the application under test.&lt;/p&gt;

&lt;p&gt;Some of the most popular actions of the I object are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;I.amOnPage(url)&lt;/code&gt;: This action navigates the user to the specified URL.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;I.click(locator)&lt;/code&gt;: This action simulates a click on the element identified by the given locator.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;I.fillField(field, value)&lt;/code&gt;: This action fills the specified field with the given value.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;I.see(text, context)&lt;/code&gt;: This action checks that the given text is visible on the page (or in the specified context).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;I.selectOption(select, option)&lt;/code&gt;: This action selects the specified option from the given select dropdown.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;I.waitForElement(locator, timeout)&lt;/code&gt;: This action waits for the specified element to appear on the page, up to the given timeout.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;I.waitForText(text, timeout, context)&lt;/code&gt;: This action waits for the given text to appear on the page (or in the specified context), up to the given timeout.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We will need to use them to navigate into Checkout process. How do we navigate web? Sure by clicking on links!&lt;/p&gt;

&lt;p&gt;Let's use &lt;code&gt;I.click()&lt;/code&gt; for that.&lt;/p&gt;

&lt;p&gt;But how we can access elements on a webpage? &lt;/p&gt;

&lt;p&gt;CodeceptJS is smart enough to locate clickable elements by their visible text. For instance, if on your ecommerce website you have a product 'Coffee Cup' with that exact name you can use&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;I&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;Coffee Cup&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;But sometimes elements are not as easy to locate, so you can use CSS or XPath locators to locate them.&lt;/p&gt;

&lt;p&gt;For instance, locating Coffee Cup via CSS can take into accont HTML structure of a page and element attributes. For instance, it can be like this:&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;I&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;div.products a.product-name[title="Coffee Cup"]&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 this example, the &lt;code&gt;div.products&lt;/code&gt; part of the selector specifies a div element with the &lt;code&gt;products&lt;/code&gt; class, and the &lt;code&gt;a.product-name[title="Coffee Cup"]&lt;/code&gt; part specifies an a element with &lt;code&gt;the product-name&lt;/code&gt; class and the &lt;code&gt;title&lt;/code&gt; attribute set to Coffee Cup. &lt;/p&gt;

&lt;p&gt;You can read more about HTML and CSS locators, and basically that's all what you need to know to start writing a checkout test!&lt;/p&gt;

&lt;h2&gt;
  
  
  Get back to Checkout
&lt;/h2&gt;

&lt;p&gt;Let's see how a regular checkout script may look in CodeceptJS:&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;Scenario&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;test the checkout form&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;I&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="c1"&gt;// we select one product and switched to checkout project&lt;/span&gt;
  &lt;span class="nx"&gt;I&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;amOnPage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;I&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;Coffee Cup&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;I&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;Purchase&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;I&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;Checkout&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// fill in the shipping address&lt;/span&gt;
  &lt;span class="nx"&gt;I&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fillField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;First Name&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="s1"&gt;John&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;I&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fillField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Last Name&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="s1"&gt;Doe&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;I&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fillField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Address&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="s1"&gt;123 Main St.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;I&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fillField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;City&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="s1"&gt;New York&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;I&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;selectOption&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;State&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="s1"&gt;New York&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;I&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fillField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Zip Code&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="s1"&gt;10001&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// select a payment method&lt;/span&gt;
  &lt;span class="nx"&gt;I&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;#credit-card-option&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;I&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fillField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Card Number&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="s1"&gt;1234-5678-9012-3456&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;I&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fillField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Expiration Date&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="s1"&gt;12/22&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;I&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fillField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Security Code&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="s1"&gt;123&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// click the checkout button&lt;/span&gt;
  &lt;span class="nx"&gt;I&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;Checkout&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// verify that the checkout was successful&lt;/span&gt;
  &lt;span class="nx"&gt;I&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;see&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Your order has been placed successfully!&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;Sure, in relaity your script might be more complicated. As you have noticed, we used CSS locator &lt;code&gt;'#credit-card-option'&lt;/code&gt;  to get select a payment option. However, the test is simple and you can follow user steps through it.&lt;/p&gt;

&lt;p&gt;Please note, that you shouldn't use a real credit card number here. Good news, you don't need to. Payment providers like Strip provide dummy card numbers for testing purposes. &lt;/p&gt;

&lt;p&gt;Run the test with next command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx codeceptjs run --debug -p pauseOnFail
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What are special options here?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;--debug&lt;/code&gt; flag is used to output additional information to the console, such as the details of each step in the test, the values of variables, and the results of test assertions. This can help you to identify and fix any issues in your tests.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-p pauseOnFail&lt;/code&gt; option is also used to keep the browser opened even if a test fails. It will help us to identify to which point test was executed and what can be improved.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Add more test steps if needed, update locators, and notify business owners that all that purchases are made by you so your collegues won't call you in the night asking when you want to get a coffee cup 😀 Also the good idea is to run tests on staging website, to not interfere with business process.&lt;/p&gt;

&lt;p&gt;What a test is complete you can run it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx codeceptjs run
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you are annoyed to see a browser window you can use &lt;code&gt;HEADLESS&lt;/code&gt; environment variable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;HEADLESS=true codeceptjs run
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;for Windows users HEADLESS should be set in a different manner:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;set HEADLESS=true&amp;amp;&amp;amp; codeceptjs run
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The tests will pass but no browser is shown, so you can watch YouTube videos while it goes!&lt;/p&gt;

&lt;h2&gt;
  
  
  Refactoring
&lt;/h2&gt;

&lt;p&gt;What if you need to check more purchases? Should you copy paste your code for that?&lt;/p&gt;

&lt;p&gt;No! You can use Page Object pattern to put repeating interactions into the reusable functions.&lt;/p&gt;

&lt;p&gt;You can create a page object via next command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx codeceptjs gpo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sure, we will call it &lt;code&gt;Checkout&lt;/code&gt;. It will be created in &lt;code&gt;./pages/Checkout.js&lt;/code&gt; file. You should enable it in &lt;code&gt;codecept.conf.js&lt;/code&gt; inside &lt;code&gt;include&lt;/code&gt; section:&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;include&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;checkoutPage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./pages/Checkout.js&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 open this file:&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="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;I&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;inject&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="p"&gt;{&lt;/span&gt;

  &lt;span class="c1"&gt;// insert your locators and methods here&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Feels really empty. What should we do about it? Should we write more code? No, we already have it. Let's copy code blocks from a test we have it and place them under a corredponnding function names:&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;connst&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;I&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;inject&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="p"&gt;{&lt;/span&gt;

  &lt;span class="nx"&gt;fillShippingAddress&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;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;city&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;zip&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;I&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fillField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Name&lt;/span&gt;&lt;span class="dl"&gt;'&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;I&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fillField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Address&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;I&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fillField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;City&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;city&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;I&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fillField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;State&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;I&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fillField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Zip&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;zip&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;

  &lt;span class="nx"&gt;fillValidCreditCard&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;I&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;#credit-card-option&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;I&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fillField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Card Number&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="s1"&gt;1234-5678-9012-3456&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;I&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fillField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Expiration Date&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="s1"&gt;12/22&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;I&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fillField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Security Code&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="s1"&gt;123&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="nx"&gt;checkout&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;I&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;Checkout&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;After that we can update our test to use the created page object. Note, that we import Checkout PageObject by its name &lt;code&gt;checkoutPage&lt;/code&gt; we previously defined in a config.&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;Scenario&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;test the checkout form&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;I&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;checkoutPage&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;I&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;amOnPage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;I&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;Coffee Cup&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;I&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;Purchase&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;I&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;Checkout&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// fill in the shipping address using the page object&lt;/span&gt;
  &lt;span class="nx"&gt;checkoutPage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fillShippingAddress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;John&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="s1"&gt;Doe&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="s1"&gt;123 Main St.&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="s1"&gt;New York&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="s1"&gt;New York&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="s1"&gt;10001&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;checkoutPage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fillValidCreditCard&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;checkoutPage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;checkout&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;// verify that the checkout was successful&lt;/span&gt;
  &lt;span class="nx"&gt;I&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;see&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Your order has been placed successfully!&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;As you see the code of a test was reduced. And we can write the similar tests on the same manner.&lt;/p&gt;

&lt;p&gt;By applying more and more cases you can test a website to all behaviors.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;This was a deep dive! If you think on just starting test automation, CodeceptJS is the best choice for you as it uses native language to pass commands to browser. &lt;/p&gt;

&lt;p&gt;If you already skilled in JavaScript, with CodeceptJS you can focus on business level of your test, instead of writing code for browser. This way you can keep your tests stable and maintainable.&lt;/p&gt;

&lt;p&gt;To provide a day-to-day status of a tested website use &lt;a href="https://testomat.io"&gt;Testomat.io&lt;/a&gt; for test reporting. So you always know when the last checks were executed and which of tests passed and failed.&lt;/p&gt;

&lt;p&gt;Enjoy the testing!&lt;/p&gt;

</description>
      <category>codeceptjs</category>
      <category>playwright</category>
      <category>testing</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Planning Your Next Cypress.io Tests with Testomat.io</title>
      <dc:creator>davert</dc:creator>
      <pubDate>Tue, 05 Apr 2022 23:52:03 +0000</pubDate>
      <link>https://dev.to/davert/planning-your-next-cypressio-tests-with-testomatio-3fio</link>
      <guid>https://dev.to/davert/planning-your-next-cypressio-tests-with-testomatio-3fio</guid>
      <description>&lt;p&gt;It is so easy to start writing tests with &lt;a href="https://cypress.io" rel="noopener noreferrer"&gt;Cypress.io&lt;/a&gt;. It seems that Cypress opened doors to testing for everyone with basic JavaScript knowledge. However, when the number of tests grows writing new tests becomes harder. And the issue is not just about writing code. Planning new test scenarios, refactoring, configuring pipelines, and getting test run reports. The more people involved in the product development the more visibility the testing process needs.&lt;/p&gt;

&lt;p&gt;To keep end 2 end tests organized, following questions should be answered:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;what tests do we have?&lt;/li&gt;
&lt;li&gt;what parts of an application are covered with tests?&lt;/li&gt;
&lt;li&gt;what new test scenarios should be implemented?&lt;/li&gt;
&lt;li&gt;what is the current state for passed and failed tests?&lt;/li&gt;
&lt;li&gt;if there are flaky tests on a project?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🤔 &lt;/p&gt;

&lt;p&gt;Cypress.io is just a test runner, but it can be paired with &lt;a href="https://testomat.io" rel="noopener noreferrer"&gt;Testomat.io&lt;/a&gt;, a test management system for automated tests. &lt;br&gt;
Let's see how &lt;a href="https://testomat.io" rel="noopener noreferrer"&gt;Testomat.io&lt;/a&gt; can answer the questions risen above. We will use &lt;a href="https://github.com/cypress-io/cypress-realworld-app" rel="noopener noreferrer"&gt;Cypress Realworld App&lt;/a&gt;, which is a real-world project (as you might have guessed)  with a well-written Cypress tests.&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%2Fboakdlcfsz2v7bapso5w.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%2Fboakdlcfsz2v7bapso5w.png" alt="Creating project in Testomat.io"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  🤔 What tests do we have?
&lt;/h2&gt;

&lt;p&gt;But answering the very first question is not as simple as it seems. &lt;/p&gt;

&lt;p&gt;All Cypress.io end 2 end tests are written as JavaScript code so to read them a person should be at least familiar with JavaScript, GitHub, etc. So this already clothes doors for business analysts, product managers, and manual QAs, for all these folks who do not actually code.&lt;/p&gt;

&lt;p&gt;That's why we can import a Cypress realworld app into a newly created project on Testomat.io. &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%2F2sn5xn9rosmpdsw4f19m.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%2F2sn5xn9rosmpdsw4f19m.png" alt="Import project from source code in Testomat.io"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Importing happens with a magical &lt;code&gt;npx check-tests&lt;/code&gt; command which scans all the tests on a project and imports them into UI without executing them. This way Testomat.io can present those tests to non-tech folks. &lt;/p&gt;

&lt;p&gt;To import only UI tests from realworld app project, we need to run &lt;code&gt;check-tests&lt;/code&gt; command with &lt;code&gt;--typescript&lt;/code&gt; flag (as the project is written in TypeScript) specifying that we use Cypress.io and the path to tests via &lt;code&gt;--dir&lt;/code&gt; parameter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TESTOMATIO=a9ae6798atoj npx check-tests@latest Cypress.io "**/*{.,_}{test,spec}.ts" --dir cypress/tests
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;a9ae6798atoj&lt;/code&gt; is an API key of a project you are importing to, so in your case, it will be a different one. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you use &lt;strong&gt;Import from Source&lt;/strong&gt; button, you will get this command generated. Take note, that by default it imports tests from &lt;code&gt;cypress/integration&lt;/code&gt; folder which doesn't exist in cypress-realworld project. So you need to change path and use &lt;code&gt;cypress/tests&lt;/code&gt; instead.&lt;/p&gt;

&lt;p&gt;Importing is fast, it takes just a few seconds to get this output.&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%2Flywmfv0gwo203r9ozfrv.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%2Flywmfv0gwo203r9ozfrv.png" alt="Import output of Cypress.io project in Testomat.io"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then all imported tests can be reviewed.&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%2Fs4zdrfzvmdfeblefbwp5.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%2Fs4zdrfzvmdfeblefbwp5.png" alt="Listed Cypress.io tests in Testomat.io"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That's great that all tests are finally visible to team members. But is there a way they could be linked to specifications they are testing? Yes, and that answers the next question:&lt;/p&gt;

&lt;h2&gt;
  
  
  🤔 What parts of an application are covered with tests?
&lt;/h2&gt;

&lt;p&gt;If the development management happens in Jira, Testomatio can link automated tests to Jira issue. You can link tests from a Cypress spec to an Issue:&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%2Foxy7jv43om12bpaaz9s3.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%2Foxy7jv43om12bpaaz9s3.png" alt="Linking Test to Jira Issue in Testomat.io"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now all tests will be available within Jira, so can be taken into the development process. Revealing automated tests to Jira Issues helps managers and business analysts to understand more information on quality control. They don't need to leave Jira to see those automated tests! &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%2F2hdq34d5d6bf0tlm5ljs.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%2F2hdq34d5d6bf0tlm5ljs.png" alt="Automated Tests in Jira Testomat.io Plugin"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The only thing needed, is a &lt;a href="https://marketplace.atlassian.com/apps/1224120/testomatio" rel="noopener noreferrer"&gt;Testomatio Jira plugin&lt;/a&gt; should be installed from a marketplace and a Jira Project to be &lt;a href="https://docs.testomat.io/integration/jira/" rel="noopener noreferrer"&gt;connected to Testomatio project&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;And we are almost ready to answer the next question:&lt;/p&gt;

&lt;h2&gt;
  
  
  🤔 What new test scenarios should be implemented?
&lt;/h2&gt;

&lt;p&gt;A project manager or a business analyst knows what features are coming next so they are the right person to propose the next tests. &lt;/p&gt;

&lt;p&gt;As they can't be asked to write a code, or open an issue for each test, they could create in Testomat.io test directly from Jira. After that, a developer can take the written scenario and implement it using Cypress.io.&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%2F4kzi0bh692ftobakx9k0.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%2F4kzi0bh692ftobakx9k0.png" alt="Writing Tests inside Jira Testomat.io plugin"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;As you see on the screenshot, step autocompletion can be used to help non-tech folks write scenarios efficiently.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The test with a description is treated as a manual test, but once it is implemented as Cypress test, and re-imported it will be marked as automated.&lt;/p&gt;

&lt;h2&gt;
  
  
  🤔 What is the current state for passed and failed tests
&lt;/h2&gt;

&lt;p&gt;Testomat.io can display and store Cypress reports. To send run reports to Testomat.io a &lt;code&gt;@testomatio/reporter&lt;/code&gt; package should be installed and enabled in &lt;code&gt;cypress/plugins/index.ts&lt;/code&gt;.&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;// inside cypress/plugins/index.ts&lt;/span&gt;
&lt;span class="c1"&gt;// require testomatio reporter package:&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;testomatioReporter&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;@testomatio/reporter/lib/adapter/cypress-plugin&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="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;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;testomatioReporter&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="c1"&gt;// ....&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This reporter can be added to any Cypress.io project, following instructions from Testomat.io &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%2Fzo8dsv4o3t081qll3tbe.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%2Fzo8dsv4o3t081qll3tbe.png" alt="Setting up reporting in Testomat.io"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then tests should be executed via &lt;code&gt;npx cypress run&lt;/code&gt; with few extra parameters:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TESTOMATIO=a9ae6798atoj npx cypress run
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;a9ae6798atoj&lt;/code&gt; is an API key of a project to which reports will be sent.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A report will contain a list of passed and failed tests, with videos and screenshots. External S3 storage from one of the cloud providers (AWS, DigitalOcean, Google Cloud, etc) can be used to keep &lt;strong&gt;unlimited screenshots and videos&lt;/strong&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%2Fx820usb05bcrimf4luu4.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%2Fx820usb05bcrimf4luu4.png" alt="Unlimited Test Artifacts for Cypress.io Tests in Testomat.io"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Videos and screenshots can be enabled in Testomatio by adding S3 credentials into &lt;code&gt;.env&lt;/code&gt; file of Cypress Realworld project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;S3_ACCESS_KEY_ID=aws-key
S3_SECRET_ACCESS_KEY=aws-secret
S3_REGION=ap-south-1
S3_BUCKET=testomatio-test
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A complete historical data of all Cypress.io test executions are also available:&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%2F44bpfakxlkck7ow0ojuf.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%2F44bpfakxlkck7ow0ojuf.png" alt="Run Reports in Testomat.io"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If we have this data the final question can be answered:&lt;/p&gt;

&lt;h2&gt;
  
  
  🤔 Are there flaky tests on a project?
&lt;/h2&gt;

&lt;p&gt;Testomat.io has an analytics dashboard where all tests are analyzed to provide valuable insights. For instance, it is important to keep track of flaky tests, and slowest tests, and check for the most common defects across tests.&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%2Fa6weabvexiytg7c2plfb.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%2Fa6weabvexiytg7c2plfb.png" alt="Flaky Tests Detection in Testomat.io"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Developing end-2-end tests with Cypress.io is fun. But making them first-class citizens in project development is also important. Cypress End 2 end tests must be visible to the whole team, so even team members who are not directly involved in testing could track the progress, propose new changes to tests, and see the actual test coverage.&lt;/p&gt;

&lt;p&gt;Testing is a crucial part of the development process. The more clear it is and the more team members are aware of it, the more quality software can be delivered. While Cypress.io helps build efficient and fast tests for the modern web, &lt;a href="https://testomat.io" rel="noopener noreferrer"&gt;Testomat.io&lt;/a&gt; provides a feature-rich test management solution for all kinds of automated tests. &lt;/p&gt;

&lt;p&gt;P.S. Testomat.io is absolutely free to use for personal projects. Try it out with Cypress  realworld app, or any other Cypress project.&lt;/p&gt;

</description>
      <category>testing</category>
      <category>cypress</category>
      <category>javascript</category>
      <category>typescript</category>
    </item>
    <item>
      <title>5 reasons you should not use Protractor in 2020</title>
      <dc:creator>davert</dc:creator>
      <pubDate>Fri, 27 Sep 2019 12:49:15 +0000</pubDate>
      <link>https://dev.to/davert/5-reasons-you-should-not-use-protractor-in-2019-3l4b</link>
      <guid>https://dev.to/davert/5-reasons-you-should-not-use-protractor-in-2019-3l4b</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;TLDR: There is a chance that you might still want to use Protractor when version 6 is released. But not today. As of today, it is recommended to switch to modern frameworks like &lt;a href="https://webdriver.io"&gt;webdriverio&lt;/a&gt; or &lt;a href="https://codecept.io"&gt;codeceptjs&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Protractor is a very popular end 2 end testing framework for NodeJS. It was started as a testing tool for &lt;a href="https://angular.io"&gt;Angular&lt;/a&gt; Framework but then overgrew to become a de facto standard of testing in JavaScript. However, nowadays, it doesn't feel so well. The web has changed, the JavaScript ecosystem has changed, the Selenium has changed, but Protractor didn't. And if you still use it, or you consider using it because of its popularity - stop that. Today is not a good day. &lt;/p&gt;

&lt;p&gt;So what happened to Protractor?&lt;/p&gt;

&lt;h1&gt;
  
  
  1. Protractor is not updated
&lt;/h1&gt;

&lt;p&gt;Protractor was not actively updated for a few years. No major improvements, no bug fixes, no documentation updates. You can see tons of old issues in the main repo and absolutely no movement in commits for a few months.&lt;/p&gt;

&lt;p&gt;It also became out of sync with its main dependency Selenium WebDriver JS. Right, Protractor is based on the official Selenium WebDriver library to drive browsers over W3C protocol. However, &lt;a href="https://www.npmjs.com/package/selenium-webdriver"&gt;Selenium WebDriver was not updated for two years and now they are moving to 4.0&lt;/a&gt;. Protractor was not actively developed as well for those years, and you may see outdated documentation or long-standing issues. Protractor is almost ready to switch to this version but this still a big issue to end-users. As they will need to rewrite all their tests!&lt;/p&gt;

&lt;h1&gt;
  
  
  2. Protractor 6 will break compatibility
&lt;/h1&gt;

&lt;p&gt;In Protractor 5 promises were synchronized using control-flow mechanism. This was also taken from the selenium-webdriver library. However, selenium-webdriver is dropping support of control flow in version 4. This means that once Protractor is upgraded to selenium-webdriver 4 it will drop it as well. So all your tests should be rewritten using the async/await pattern. &lt;/p&gt;

&lt;p&gt;Using async/await gives you better understanding and more control over promises. However, it can be harder for developers in tests to switch to this new style if they are not familiar with it. Currently, Protractor follows Java-style syntax, so engineers experienced with Java can easily go to Protractor. After a switch, each browser call should be wrapped with &lt;code&gt;await&lt;/code&gt; keyword. Missing even one await will lead to broken and unpredictable tests.&lt;/p&gt;

&lt;p&gt;So async/await is coming. You will need to update your codebase and train your engineers. The problem is we don't know when exactly it is coming! Protractor 6 was tagged but never released due to some critical issues. And no estimates when a new version will be released!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--HCQjoIFr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2AVYYBBHeF0S5wZ6-ZyWVCZw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--HCQjoIFr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2AVYYBBHeF0S5wZ6-ZyWVCZw.png" alt=""&gt;&lt;/a&gt;&lt;br&gt;
(from: &lt;a href="https://github.com/angular/protractor/issues/5290"&gt;https://github.com/angular/protractor/issues/5290&lt;/a&gt;)&lt;/p&gt;
&lt;h1&gt;
  
  
  3. Protractor is overcomplicated
&lt;/h1&gt;

&lt;p&gt;The next problem of Protractor is the design which is highly inspired by Java and is very complicated for the JavaScript world. Protractor adds thousands of lines of code on top of a very big selenium-webdriver library and when something goes wrong you don't have any idea why and where the bug has happened. &lt;/p&gt;

&lt;p&gt;Protractor tries to tie up selenium-webdriver, Jasmine, Angular but in the end, they produced a very complicated setup with huge configs, and hard to read tests. At least senior JavaScript developer is required to prepare a good Protractor setup.&lt;/p&gt;

&lt;p&gt;Protractor exposes WebElements into tests. So instead of controlling a browser, you control only some HTML elements on a page. But you can't get direct access to those elements from a test, as your browser is executed externally. &lt;/p&gt;

&lt;p&gt;Wrapping hundreds of elements, calling commands on them, filtering them and mapping brings you out of the scope of testing. You spend most of the time not writing tests but fighting web elements. Congrats! Now you are a senior element controlling engineer! Whatever it means.&lt;/p&gt;
&lt;h1&gt;
  
  
  4. Protractor not driving a good design
&lt;/h1&gt;

&lt;p&gt;Take a look of this code. This is quite a common picture of what Protractor tests can become. You don't understand what happens and you don't even want to look into this hell!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;product&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="nx"&gt;all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;by&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;xpath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cons&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;xpathproductRate&lt;/span&gt;&lt;span class="p"&gt;())).&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;products&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;products&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;loop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;product&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cons&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;xpathproductRate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;product&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="nx"&gt;by&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;xpath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;product&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="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;waitForElementAndClick&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;cons&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;linkRemoveproduct&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;waitForElementAndClick&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;cons&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;radiobtnRemoveAll&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;waitForElementAndClick&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;cons&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;btnRemoveproduct&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&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="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                            &lt;span class="nx"&gt;loop&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;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;You can say that bad code can happen everywhere. But this is a result of overcomplicated design in Protractor. The indirect control of web elements with promises everywhere tends to drive design full of chained methods and loops.&lt;/p&gt;

&lt;p&gt;This makes tests unstable and not readable to humans.&lt;/p&gt;

&lt;h1&gt;
  
  
  5 Protractor is not required for Angular
&lt;/h1&gt;

&lt;p&gt;Protractor started as a primary tool for the AngularJS framework. It was the most popular framework for single-page applications when there was no React or VueJS. Angular is still widely popular but the truth is that you don't need Protractor to test Angular application. &lt;/p&gt;

&lt;p&gt;The only key feature of Protractor for Angular was synchronization. Protractor waits for Angular to finish rendering before taking any action on-page. This worked fine in the era of AngularJS 1 but it is less and less stable as Angular evolves. Modern Single Page Applications are built around components and there is no single point of truth if a component has finished rendering or not.&lt;/p&gt;

&lt;p&gt;So instead of relying on Angular to synchronize components by some magic, it is more reliable to use explicit Selenium waits like &lt;code&gt;browser.wait(EC.visibilityOf($('#abc')), 5000);&lt;/code&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  So what are alternatives to Protractor today?
&lt;/h1&gt;

&lt;p&gt;Today Cypress.io takes popularity. Should you rewrite your tests to it? &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The answer is NO!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Picking a tool by their popularity is a bad idea at first. But Cypress is quite different technology for different tasks than Protractor. It plays well for testing components of a web application, but it can't replace Protractor as Cypress does not support:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;iframes&lt;/li&gt;
&lt;li&gt;file uploads &lt;/li&gt;
&lt;li&gt;native events&lt;/li&gt;
&lt;li&gt;any other browser except Chrome&lt;/li&gt;
&lt;li&gt;xpath&lt;/li&gt;
&lt;li&gt;multiple windows and tabs&lt;/li&gt;
&lt;li&gt;testing sites you don't control&lt;/li&gt;
&lt;li&gt;page objects&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So if you want to have the cross-browser support for a test, rich ecosystem with services like SauceLabs or BrowserStack, you should look for other Selenium tools instead.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://webdriver.io"&gt;webdriverio&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://webdriver.io"&gt;Webdriverio&lt;/a&gt; is an alternative webdriver implementation not based on selenium-webdriver with elegant and more consistent API. webdriverio also support testing native mobile apps with appium.&lt;/p&gt;

&lt;p&gt;As of today, webdriverio is the best webdriver implementation in JavaScript. It has rich functionality including react selectors, shadow dom support, it can even use DevTools protocol for testing! &lt;/p&gt;

&lt;p&gt;Unlike, Protractor webdriverio receive constant updates, it has a very active community of developers, and it just rocks!&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://codecept.io"&gt;codeceptjs&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Another alternative would be to use &lt;a href="https://codecept.io"&gt;CodeceptJS&lt;/a&gt; - a framework for supercharged end 2 end testing. Unlike, Protractor CodeceptJS do not expose web elements, its tests are written in a scenario-based manner, where all actions are explained from the eyes of a user:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;Scenario&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;create todo item&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="nx"&gt;I&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;I&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;amOnPage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;I&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dontSeeElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#todo-count&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;I&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fillField&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;newTodo&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="s1"&gt;Write a guide&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;I&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pressKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Enter&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;I&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;see&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Write a guide&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;repeater&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;todo in todos&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="nx"&gt;I&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;see&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1 item left&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="s1"&gt;#todo-count&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;CodeceptJS do not control a browser by its own. Instead, it delegates a browser control to other libraries, like webdriverio or Protractor. So yes, you can still execute tests in Protractor without the pain of maintaining Protractor code! &lt;/p&gt;

&lt;p&gt;CodeceptJS takes a different approach in the end to end testing. But because you don't need to think about how to control web elements your tests become easy to follow, write, and debug. CodeceptJS provides you not only a tool to run browsers but best practice architecture to build sustainable end 2 end tests.&lt;/p&gt;

&lt;p&gt;If you didn't have a chance to look into CodeceptJS, it's a good time to do so!&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;Protractor powers lots of tests out there. But it doesn't stand a test of time. Maintaining old code written in the days of Protractor and Angular glory can be more expensive than rewriting all tests from scratch! Nowadays, it is no use to rewrite those tests in Protractor as its future is not clear. However, it's a good day to try modern frameworks like &lt;a href="https://webdriver.io"&gt;webdriverio&lt;/a&gt; or &lt;a href="https://codecept.io"&gt;codeceptjs&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>protractor</category>
      <category>javascript</category>
      <category>endtoend</category>
      <category>testing</category>
    </item>
  </channel>
</rss>
