<?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: poponuts</title>
    <description>The latest articles on DEV Community by poponuts (@poponuts).</description>
    <link>https://dev.to/poponuts</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%2F473640%2F812661f2-eb34-4e69-b269-20a020812037.jpeg</url>
      <title>DEV Community: poponuts</title>
      <link>https://dev.to/poponuts</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/poponuts"/>
    <language>en</language>
    <item>
      <title>Running Salesforce CLI (sfdx) on Buildkite pipeline</title>
      <dc:creator>poponuts</dc:creator>
      <pubDate>Fri, 08 Aug 2025 11:47:32 +0000</pubDate>
      <link>https://dev.to/poponuts/running-salesforce-cli-sfdx-on-buildkite-pipeline-46ac</link>
      <guid>https://dev.to/poponuts/running-salesforce-cli-sfdx-on-buildkite-pipeline-46ac</guid>
      <description>&lt;p&gt;Unlike typical web apps, Salesforce usually has its own ecosystem in terms of packaging and deploying its products via its &lt;a href="https://developer.salesforce.com/docs/atlas.en-us.sfdx_setup.meta/sfdx_setup/sfdx_setup_install_cli.htm" rel="noopener noreferrer"&gt;Salesforce CLI (sdfx) package&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In my humble opinion, they are still in the infancy stage of the DevOps movement since there are still steps that require manual intervention. However, I think it's getting there in terms of trying to make everything smooth with one to two-click automation 🤖.&lt;/p&gt;

&lt;p&gt;Here's a guide on how we did it with our current pipelines using Buildkite, which is flexible enough to allow prompts or as they call it &lt;a href="https://buildkite.com/docs/pipelines/block-step" rel="noopener noreferrer"&gt;blocks&lt;/a&gt; 🧱 in between steps. It required heaps of experimentation and iteration before we got to a stage where every developer is comfortable using it.&lt;/p&gt;

&lt;p&gt;We initially used its &lt;a href="https://hub.docker.com/r/salesforce/salesforcedx" rel="noopener noreferrer"&gt;docker image&lt;/a&gt; as most references on the web with SF CI/CD use this but we decided to use the &lt;a href="https://www.npmjs.com/package/@salesforce/cli" rel="noopener noreferrer"&gt;npm package&lt;/a&gt; as its closer to how we do CI/CD for our other web apps.&lt;/p&gt;

&lt;p&gt;Please refer to this boilerplate &lt;a href="https://github.com/poponuts/salesforce-sfdx-buildkite" rel="noopener noreferrer"&gt;github repo&lt;/a&gt; as a guide. Ensure that the CI variables are defined in your Build Steps:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhj33amsquiqua735cjh7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhj33amsquiqua735cjh7.png" alt="Buildkite env variables" width="781" height="583"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For our &lt;strong&gt;Continuous integration (CI)&lt;/strong&gt;:&lt;br&gt;
Every change (update or create) to any git branch (&lt;code&gt;master&lt;/code&gt; or &lt;code&gt;feature&lt;/code&gt;) would trigger running the Buildkite pipeline for Salesforce.&lt;br&gt;
The pipeline would run the following steps in sequence:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Download the &lt;code&gt;@salesforce/cli&lt;/code&gt; npm package&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create a scratch org (temporary org necessary to run unit tests)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Run unit tests (BONUS: security tests using snyk and code coverage using Codecov)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;(if &lt;code&gt;master&lt;/code&gt;) Deploy source package to scratch org&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Delete scratch org&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;code&gt;Makefile&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nl"&gt;test&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;.env&lt;/span&gt;
    &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Running sfdx test"&lt;/span&gt;
    openssl enc &lt;span class="nt"&gt;-nosalt&lt;/span&gt; &lt;span class="nt"&gt;-aes-256-cbc&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;-in&lt;/span&gt; assets/server.key.enc &lt;span class="nt"&gt;-out&lt;/span&gt; assets/server.key &lt;span class="nt"&gt;-base64&lt;/span&gt; &lt;span class="nt"&gt;-K&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;DECRYPTION_KEY&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nt"&gt;-iv&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;DECRYPTION_IV&lt;span class="p"&gt;)&lt;/span&gt;
    docker-compose &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;PATH_DEPLOY&lt;span class="p"&gt;)&lt;/span&gt;/docker-compose.yml run &lt;span class="nt"&gt;--rm&lt;/span&gt; build &lt;span class="s2"&gt;"npm run test"&lt;/span&gt;
    &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Running snyk test"&lt;/span&gt;
    docker-compose &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;PATH_DEPLOY&lt;span class="p"&gt;)&lt;/span&gt;/docker-compose.yml run &lt;span class="nt"&gt;--rm&lt;/span&gt; snyk &lt;span class="s2"&gt;"snyk auth &lt;/span&gt;&lt;span class="p"&gt;$(&lt;/span&gt;&lt;span class="s2"&gt;SNYK_TOKEN&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="s2"&gt; &amp;amp;&amp;amp; npm run snyk"&lt;/span&gt;
    &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Running codecov"&lt;/span&gt;
    docker-compose &lt;span class="nt"&gt;-f&lt;/span&gt; .buildkite/docker-compose.yml run &lt;span class="nt"&gt;--rm&lt;/span&gt; snyk &lt;span class="s2"&gt;"curl -Os https://uploader.codecov.io/latest/linux/codecov &amp;amp;&amp;amp; chmod +x codecov &amp;amp;&amp;amp; ./codecov -t &lt;/span&gt;&lt;span class="p"&gt;$(&lt;/span&gt;&lt;span class="s2"&gt;CODECOV_TOKEN&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="s2"&gt; --flag Apex"&lt;/span&gt;
&lt;span class="nl"&gt;.PHONY&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For our &lt;strong&gt;Continuous deployment (CD)&lt;/strong&gt;:&lt;br&gt;
The aim is to automate the current manual process of creating and installing packages in testing environments.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fveeg1hjk8cimk12hj2p4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fveeg1hjk8cimk12hj2p4.png" alt="Package release workflow" width="800" height="226"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Every &lt;code&gt;feature&lt;/code&gt; merge to &lt;code&gt;master&lt;/code&gt; (a commit without tag) would trigger the following steps on the pipeline:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Prompt to select which component/s to create a package for along with the corresponding package version numbers and dependency configuration for omni-channel and/or test drive.
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvpf2ax55k9oz9s1nv64x.png" alt="Beta package version" width="800" height="1601"&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Package version numbers should follow the format &lt;code&gt;MAJOR.MINOR.PATCH&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;When creating omni-channel and/or test drive package, by default package dependencies are not updated. To update package dependency, select the component to update and specify the core package version ID (if core package has already been created previously) or, leave the field blank to set dependency on the new core package when creating a new core package along with omni-channel and/or test drive package.&lt;/li&gt;
&lt;li&gt;When creating &lt;strong&gt;core package only&lt;/strong&gt;, selecting component/s to update package dependency and/or setting a core package dependency version ID will &lt;strong&gt;NOT&lt;/strong&gt; update omni-channel and/or test drive dependency in &lt;code&gt;sfdx-project.json&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Depending on the selection, update version number (and package dependency) in &lt;code&gt;sfdx-project.json&lt;/code&gt; and create beta package.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create scratch org&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Install beta package(s)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Delete scratch org&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Upload the updated &lt;code&gt;sfdx-project.json&lt;/code&gt; as a build artifact on Buildkite. Devs have the option to download the updated &lt;code&gt;sfdx-project.json&lt;/code&gt; from Buildkite in case errors arise in succeeding build steps.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fggq3cshhsbkqpe3vlaql.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fggq3cshhsbkqpe3vlaql.png" alt="Artifact" width="800" height="121"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Push the updated &lt;code&gt;sfdx-project.json&lt;/code&gt; to a release branch&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Open a Pull Request to &lt;code&gt;master&lt;/code&gt; from the release branch&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F90m6ujvb8nn15tq4cylj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F90m6ujvb8nn15tq4cylj.png" alt="Bitbucket Pull request" width="800" height="40"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Following the above, Devs must assign a reviewer, review and merge the Pull Request. In addition, Devs must create a &lt;code&gt;tag&lt;/code&gt; for the commit to trigger the following build steps on the pipeline:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Prompt to select which package(s) to promote to release version and install in testing environments.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkoov20gu2hdztlzm9hsc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkoov20gu2hdztlzm9hsc.png" alt="Promote install package" width="800" height="977"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Promote package(s) to release version&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Install package(s) to automation org&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Run e2e smoke tests&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Have the option to install package(s) to UAT org&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;As you can see above, it's not very straightforward (more like a partial DevOps) 🤯. Hopefully, Salesforce is working towards improving this process and making lives easier for the developers.&lt;/p&gt;

</description>
      <category>salesforce</category>
      <category>buildkite</category>
      <category>automation</category>
      <category>cicd</category>
    </item>
    <item>
      <title>Automating Android TV app with Nightwatch</title>
      <dc:creator>poponuts</dc:creator>
      <pubDate>Thu, 25 Apr 2024 08:07:46 +0000</pubDate>
      <link>https://dev.to/poponuts/automating-android-tv-app-with-nightwatch-mnh</link>
      <guid>https://dev.to/poponuts/automating-android-tv-app-with-nightwatch-mnh</guid>
      <description>&lt;p&gt;I joined a company that recently introduced a TV app 📺 for their platform. A curious cat 😺 like I am, I raised my hand and immediately jumped into finding ways to automate this piece of art. It is highly similar to Mobile apps but simple clicks and double taps just won't work, we need to use the Directional Pads (DPAD) 🎛️ and their relevant values (aka remote control for TV's).&lt;/p&gt;

&lt;p&gt;I did some googling (aka 'research' in the digital world) and long story short, I ended up using Nightwatch 🦉 since we are also planning to launch it with Apple TV. Hence, there are advantages of having a single tool to automate both.&lt;/p&gt;

&lt;p&gt;First, we need to install 🚀 the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://appium.io/docs/en/2.0/quickstart/install/" rel="noopener noreferrer"&gt;Appium&lt;/a&gt;, the automation framework for mobile &amp;amp; TV apps and Nightwatch runs at the back of this.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developer.android.com/studio" rel="noopener noreferrer"&gt;Android Studio &amp;amp; SDK tools&lt;/a&gt;, IDE used for building and testing Android apps and used to create a TV app emulator&lt;/li&gt;
&lt;li&gt;Create a TV app emulator from Android Studio via Device Manager
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd61n3wmd7k3fyeu1s0vo.png" alt="TV emulator" width="800" height="422"&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.java.com/en/download/apple.jsp" rel="noopener noreferrer"&gt;Java JDK &amp;amp; runtime&lt;/a&gt;, as required for any Android activities&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://nightwatchjs.org/" rel="noopener noreferrer"&gt;Nightwatch&lt;/a&gt; which will prompt to create a boilerplate framework specifically for Mobile / TV apps.&lt;/li&gt;
&lt;li&gt;Create a new folder called &lt;code&gt;apps&lt;/code&gt; and place the &lt;code&gt;.apk&lt;/code&gt; file  there (this is the working package and if you don't have it, ask your friendly dev to give it to you).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then, we need to build the test scripts in the project directory.&lt;br&gt;
The configuration file: &lt;code&gt;nightwatch.conf.js&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app.android.emulator&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="nl"&gt;extends&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app&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;desiredCapabilities&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="c1"&gt;// More capabilities can be found at https://github.com/appium/appium-uiautomator2-driver#capabilities&lt;/span&gt;
          &lt;span class="nl"&gt;browserName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="nx"&gt;platformName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;android&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="c1"&gt;// `appium:options` is not natively supported in Appium v1,but works with Nightwatch.&lt;/span&gt;
          &lt;span class="c1"&gt;// If copying these capabilities elsewhere while using Appium v1,make sure to remove `appium:options`&lt;/span&gt;
          &lt;span class="c1"&gt;// and add `appium:` prefix to each one of its capabilities,e.g. change 'app' to 'appium:app'.&lt;/span&gt;
          &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;appium:options&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="nl"&gt;automationName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;UiAutomator2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="c1"&gt;// Android Virtual Device to run tests on&lt;/span&gt;
          &lt;span class="nx"&gt;avd&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;TV_1080p&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="nx"&gt;orientation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;PORTRAIT&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="c1"&gt;// While Appium v1 supports relative paths,it's more safe to use absolute paths instead.&lt;/span&gt;
          &lt;span class="c1"&gt;// Appium v2 does not support relative paths.&lt;/span&gt;
          &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/apps/tv-app.apk`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="nx"&gt;appActivity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;com.tv.app.MainActivity&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// include this if app does not start on its own - &lt;/span&gt;
          &lt;span class="c1"&gt;// chromedriver executable to use for testing web-views in hybrid apps.&lt;/span&gt;
          &lt;span class="c1"&gt;// add '.exe' at the end below (making it 'chromedriver.exe') if testing on windows.&lt;/span&gt;
          &lt;span class="nx"&gt;chromedriverExecutable&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/chromedriver-mobile/chromedriver`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="nx"&gt;newCommandTimeout&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="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;NOTE: if you don't know the value for &lt;code&gt;appActivity&lt;/code&gt;, open the .apk file in Android Studio then look for AndroidManifest.xml then search for "activity":&lt;/p&gt;

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

&lt;p&gt;The test / spec file &lt;code&gt;nav.spec.js&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="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;navigate the menus&lt;/span&gt;&lt;span class="dl"&gt;'&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="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should be able to navigate left menu&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="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;appium&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pressKeyCode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// presses down once&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;waitForElementVisible&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;xpath&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;//android.widget.TextView[@text="Search"]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;appium&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pressKeyCode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;// presses down once&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;waitForElementVisible&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;xpath&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;//android.widget.TextView[@text="Settings"]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;appium&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pressKeyCode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// presses the centre pad to close the left menu again&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;waitForElementNotPresent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;xpath&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;//android.widget.TextView[@text="Home"]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="c1"&gt;// guide on DPADS keys which you can place in a page object file&lt;/span&gt;
    &lt;span class="c1"&gt;// dpadCenter: 23,&lt;/span&gt;
    &lt;span class="c1"&gt;// dpadLeft: 21,&lt;/span&gt;
    &lt;span class="c1"&gt;// dpadRight: 22,&lt;/span&gt;
    &lt;span class="c1"&gt;// dpadUp: 19,&lt;/span&gt;
    &lt;span class="c1"&gt;// dpadDown: 20&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;NOTE: As mentioned earlier, to simulate real user experience, you need to use the remote or directional pads. Refer to this &lt;a href="https://developer.android.com/reference/android/view/KeyEvent.html#KEYCODE_DPAD_CENTER" rel="noopener noreferrer"&gt;guide&lt;/a&gt; for the complete numeric values.&lt;/p&gt;

&lt;p&gt;Lastly, we need to test and run if the automation actually works:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Run &lt;code&gt;appium&lt;/code&gt; from a separate terminal with the same command &lt;/li&gt;
&lt;li&gt;Open another terminal then open the newly-created emulator with the command &lt;code&gt;emulator -avd TV_1080p&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Run the test with &lt;code&gt;npx nightwatch tests --env app.android.emulator&lt;/code&gt; and watch it work! 🎮&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To inspect elements, it is recommended to download the &lt;a href="https://github.com/appium/appium-inspector/releases" rel="noopener noreferrer"&gt;Appium  Inspector&lt;/a&gt; or use the &lt;a href="https://inspector.appiumpro.com/" rel="noopener noreferrer"&gt;browser version&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I also joined the Nightwatch &lt;a href="https://discord.com/channels/618399631038218240/1227865365053313114" rel="noopener noreferrer"&gt;Discord channel&lt;/a&gt; to ask questions as I had hiccups along the way.&lt;/p&gt;

&lt;p&gt;Enjoy! 🎉&lt;/p&gt;

</description>
      <category>mobile</category>
      <category>tv</category>
      <category>automation</category>
      <category>appium</category>
    </item>
    <item>
      <title>On-demand running of tests via the CI pipeline</title>
      <dc:creator>poponuts</dc:creator>
      <pubDate>Mon, 24 Jul 2023 13:51:24 +0000</pubDate>
      <link>https://dev.to/poponuts/on-demand-running-of-tests-via-the-ci-pipeline-18pk</link>
      <guid>https://dev.to/poponuts/on-demand-running-of-tests-via-the-ci-pipeline-18pk</guid>
      <description>&lt;p&gt;In all the CI/CD tools I've used (Jenkins, TeamCity, Bitbucket Pipelines, Gitlab), I would say Buildkite is my favourite so far 👍. Being a fan of the sayings &lt;em&gt;"right tool for the right problem"&lt;/em&gt; and &lt;em&gt;"it doesn't matter what tool you use"&lt;/em&gt;, it still helps that your DevOps tool offer flexibility with a cleaner and minimalist interface unlike the very cluttered Gitlab 🫣.&lt;/p&gt;

&lt;p&gt;In one of its flexible feature, it allows the user with a conditional modal before the pipeline proceeds to the next steps. They call it &lt;a href="https://buildkite.com/docs/pipelines/block-step" rel="noopener noreferrer"&gt;block step&lt;/a&gt; 🧱 in Buildkite.&lt;/p&gt;

&lt;p&gt;Not all our automated tests are embedded into our build pipelines. We usually enable happy path smoke tests to make our micro-service pipelines run faster. Hence, we allow users to run ad-hoc/on-demand tests based on their preferences.&lt;/p&gt;

&lt;p&gt;We created a standalone test pipeline called &lt;strong&gt;"tests"&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvtqsr66do0qpfy5tgvd5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvtqsr66do0qpfy5tgvd5.png" alt="ad-hoc tests" width="387" height="136"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We set the CI variables / steps with default values then call the &lt;code&gt;pipeline.yml&lt;/code&gt; in our code repository:&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;STAGING_BASE_URL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://staging.mydomain.net&lt;/span&gt;   
  &lt;span class="na"&gt;STAGING_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;def456&lt;/span&gt;
  &lt;span class="na"&gt;TEST_BASE_URL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://test.mydomain.net&lt;/span&gt; 
  &lt;span class="na"&gt;TEST_PASSWORD_TEST&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;abc123&lt;/span&gt;
  &lt;span class="na"&gt;SPECS&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;tests/**/*.spec.ts&lt;/span&gt; &lt;span class="c1"&gt;# will run the whole test suite&lt;/span&gt;
  &lt;span class="na"&gt;BUILDKITE_PARALLEL_RUN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="c1"&gt;# default to 1 but can be overriden&lt;/span&gt;
  &lt;span class="na"&gt;ENVIRONMENT&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;test&lt;/span&gt;

&lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;:pipeline:&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Initiate&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;pipeline'&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;buildkite-agent pipeline upload .buildkite/pipeline.yml&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In our code repository, we have two files, the &lt;code&gt;.buildkite/pipeline.yml&lt;/code&gt; which triggers the block modal:&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;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;block&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;:playwright:&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Run&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;tests&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;on&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;demand'&lt;/span&gt;
    &lt;span class="c1"&gt;# branches: '!master'&lt;/span&gt;
    &lt;span class="na"&gt;fields&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;select&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;:earth_americas:&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Select&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;environment'&lt;/span&gt;
        &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;environment'&lt;/span&gt;
        &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;test'&lt;/span&gt;
        &lt;span class="na"&gt;options&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;test'&lt;/span&gt;
            &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;test'&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;staging'&lt;/span&gt;
            &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;staging'&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;:test_tube:&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Test&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;spec&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;path&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;file&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;(e.g.&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;tests/api/**/*.ts)'&lt;/span&gt;
        &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;tests/e2e/**/*.ts'&lt;/span&gt;
        &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;specs'&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;select&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;:man-running:&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Parallel&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;runs'&lt;/span&gt;
        &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;parallelism'&lt;/span&gt;
        &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3'&lt;/span&gt;
        &lt;span class="na"&gt;options&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;1'&lt;/span&gt;
            &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;1'&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;2'&lt;/span&gt;
            &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;2'&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3'&lt;/span&gt;
            &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3'&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;:buildkite:&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Trigger&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;tests'&lt;/span&gt;
    &lt;span class="na"&gt;commands&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;chmod 777 .buildkite/pipeline-adhoc.sh&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;.buildkite/pipeline-adhoc.sh | buildkite-agent pipeline upload&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;... and the &lt;code&gt;.buildkite/pipeline-adhoc.sh&lt;/code&gt;, which captures the entered values in the block modal and also allows parameterising the &lt;code&gt;parallelism&lt;/code&gt; option in Buildkite as the integer value (currently defaulted to &lt;strong&gt;1&lt;/strong&gt;) can only be updated via a script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;

&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt;

&lt;span class="nv"&gt;ENVIRONMENT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;buildkite-agent meta-data get &lt;span class="s2"&gt;"environment"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;SPECS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;buildkite-agent meta-data get &lt;span class="s2"&gt;"specs"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;PARALLEL_RUN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;buildkite-agent meta-data get &lt;span class="s2"&gt;"parallelism"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;ENVIRONMENT&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"test"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nv"&gt;PASSWORD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;TEST_PASSWORD&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
  &lt;span class="nv"&gt;BASE_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;TEST_BASE_URL&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;else
  &lt;/span&gt;&lt;span class="nv"&gt;PASSWORD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;STAGING_PASSWORD&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
  &lt;span class="nv"&gt;BASE_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;STAGING_BASE_URL&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;fi

&lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;YAML&lt;/span&gt;&lt;span class="sh"&gt;
env:
  ENVIRONMENT: "&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;ENVIRONMENT&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"
  SPECS: "&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;SPECS&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"
  PASSWORD: "&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PASSWORD&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"
  BASE_URL: "&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BASE_URL&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"

steps:
  - label: ':playwright: Run tests'
    if: build.env('SPECS') != null # some components might not have spec files specified so need to skip running tests
    commands:
    - 'npx playwright test'
    parallelism: &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PARALLEL_RUN&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="sh"&gt; # this is defaulted to &amp;gt; 1 so need to set PARALLEL_RUN as a CI variable for repo's with only 1 test spec file so CI doesn't fail with 'no spec files' error
    retry:
      manual: 
        allowed: false
        reason: 'Integration with other platforms means retries should not be performed for tests.'
    plugins: # pass details to Test Analytics
      - test-collector#v1.0.0:
          files: 'test-results/junit-*.xml'
          format: 'junit'
    artifact_paths:
      - 'results/**/*'
&lt;/span&gt;&lt;span class="no"&gt;YAML
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once all these are set up, the pipeline can be triggered anytime and will stop on the step with &lt;strong&gt;block&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F80e2j8wecczknz92ycm9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F80e2j8wecczknz92ycm9.png" alt="pipeline" width="800" height="419"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Clicking the "Run tests on demand" button would take you to the modal where you can choose your own adventure 🤠 then clicking "Continue" button on the modal would trigger the tests based on your selections ✅&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fclq0473d5icj5vfofnmm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fclq0473d5icj5vfofnmm.png" alt="block" width="530" height="647"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>buildkite</category>
      <category>ci</category>
      <category>devops</category>
      <category>playwright</category>
    </item>
    <item>
      <title>Running Gitlab on Backstage locally</title>
      <dc:creator>poponuts</dc:creator>
      <pubDate>Tue, 24 Jan 2023 03:22:19 +0000</pubDate>
      <link>https://dev.to/poponuts/running-gitlab-on-backstage-locally-1eop</link>
      <guid>https://dev.to/poponuts/running-gitlab-on-backstage-locally-1eop</guid>
      <description>&lt;p&gt;Since &lt;a href="https://backstage.io/" rel="noopener noreferrer"&gt;Backstage&lt;/a&gt; is now the default developer portal for global teams nowadays to uplift engineering productivity, understandably, we FOMO'd 👻 and decided to do a PoC on this open-source platform built by Spotify from scratch.&lt;/p&gt;

&lt;p&gt;The easiest way to verify if this baby 👶 works is by integrating it with our existing tech stack.&lt;/p&gt;

&lt;p&gt;Without my typical witty backstory, I realised that I, myself, usually ignore the noise and just go straight to the steps when I'm SPIKE'ing something (see what I did there - used an agile term 🫶). Here's the steps on how I did it locally on a bare basic boilerplate level:&lt;/p&gt;

&lt;p&gt;Cloned and installed a local copy of the &lt;a href="https://backstage.io/docs/getting-started/#create-your-backstage-app" rel="noopener noreferrer"&gt;core Backstage repository&lt;/a&gt; with the following 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 @backstage/create-app@latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note: Follow the prompts such as running &lt;code&gt;npm run dev&lt;/code&gt; and you should be able to access &lt;code&gt;http://localhost:3000&lt;/code&gt;.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff0cqudm4get01j3f6il7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff0cqudm4get01j3f6il7.png" alt="localhost" width="800" height="423"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Installed the &lt;a href="https://github.com/loblaw-sre/backstage-plugin-gitlab" rel="noopener noreferrer"&gt;Backstage Gitlab plugin&lt;/a&gt; with the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# From your Backstage root directory
cd packages/app
npm install @loblaw/backstage-plugin-gitlab
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Added the following on the &lt;code&gt;app-config.yaml&lt;/code&gt; (or &lt;code&gt;app-config.local.yaml&lt;/code&gt; if you like to play safe):&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;integrations&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;gitlab&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gitlab.com&lt;/span&gt;
      &lt;span class="na"&gt;token&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${GITLAB_TOKEN}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note: &lt;strong&gt;GITLAB_TOKEN&lt;/strong&gt; can be grabbed from your Gitlab account &amp;gt; User Settings &amp;gt; Access Tokens&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flscgl6irof6zxm3wjx2i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flscgl6irof6zxm3wjx2i.png" alt="gitlab" width="800" height="140"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Selected an existing local repository and included a &lt;code&gt;catalog-info.yml&lt;/code&gt; then pushed it to the remote Gitlab repository (this step automates the integration) with the following details:&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;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;backstage.io/v1alpha1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Component&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;k6&lt;/span&gt;
  &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;performance tests&lt;/span&gt;
  &lt;span class="na"&gt;annotations&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;gitlab.com/project-id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;41414141'&lt;/span&gt; &lt;span class="c1"&gt;# This must be in quotes and can be found under Settings --&amp;gt; General&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;service&lt;/span&gt;
  &lt;span class="na"&gt;owner&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;poponuts@test.com&lt;/span&gt; &lt;span class="c1"&gt;# This can be your team's distribution list too&lt;/span&gt;
  &lt;span class="na"&gt;lifecycle&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;experimental&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note: &lt;code&gt;type&lt;/code&gt; should have the value &lt;code&gt;service&lt;/code&gt; to render Gitlab entity.&lt;/p&gt;

&lt;p&gt;Refresh or re-run (&lt;code&gt;npm run dev&lt;/code&gt;) the app then go to the service and you should be able to see all the Gitlab details&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs4bu9gi0l6y6rev3a0gn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs4bu9gi0l6y6rev3a0gn.png" alt="catalog" width="800" height="1235"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note: If you like it more fancy and have a separate Gitlab tab as per image above, the &lt;code&gt;.tsx&lt;/code&gt; component files should be &lt;a href="https://github.com/loblaw-sre/backstage-plugin-gitlab#setup" rel="noopener noreferrer"&gt;customised&lt;/a&gt;. &lt;/p&gt;

</description>
      <category>backstage</category>
      <category>gitlab</category>
      <category>webdev</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Easy use of multiple environment variables - Cypress 10+ edition</title>
      <dc:creator>poponuts</dc:creator>
      <pubDate>Mon, 05 Dec 2022 23:14:16 +0000</pubDate>
      <link>https://dev.to/poponuts/easy-use-of-multiple-environment-variables-cypress-10-edition-djf</link>
      <guid>https://dev.to/poponuts/easy-use-of-multiple-environment-variables-cypress-10-edition-djf</guid>
      <description>&lt;p&gt;A couple of years back (which seemed like an eternity), I wrote this &lt;a href="https://dev.to/poponuts/using-config-files-for-multiple-environment-variables-in-cypress-hn3"&gt;piece&lt;/a&gt; where we can use environment json files to easily switch between environment variables in Cypress.&lt;/p&gt;

&lt;p&gt;However, since the use of &lt;code&gt;plugin/index.ts&lt;/code&gt; / &lt;code&gt;plugin/index.js&lt;/code&gt; is &lt;a href="https://docs.cypress.io/guides/references/changelog#10-0-0" rel="noopener noreferrer"&gt;deprecated&lt;/a&gt; (or highly discouraged) now with Cypress 10+, a little tweaking is required to utilise &lt;code&gt;cypress.config.js&lt;/code&gt; / &lt;code&gt;cypress.config.ts&lt;/code&gt; without impacting much of the codebase (considering my rusty Cypress skills now). &lt;em&gt;News flash:&lt;/em&gt; the legacy &lt;code&gt;index&lt;/code&gt; file can still be used so read til the end of this 😉.&lt;/p&gt;

&lt;p&gt;Though I'm still not a fan but we are using Typescript now 🫢 in my new company so if you are using Javascript, just do some refactoring.&lt;/p&gt;

&lt;p&gt;Here's my new code all in &lt;code&gt;cypress.config.ts&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;localEnv&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;domain&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;localhost:8080&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;description&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;This is my local machine!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;protocol&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http://&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;subDirectory&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;helloworld&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;testEnv&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;domain&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;test1.domain.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;description&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;This is the awesome stage environment&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;protocol&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;subDirectory&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/helloworld&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;envConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;switch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;local&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;localEnv&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;test&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;default&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;testEnv&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="nl"&gt;e2e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;env&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="nf"&gt;envConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ENVIRONMENT&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt; &lt;span class="c1"&gt;// override with the environment configuration based on the value passed in CI (e.g. ENVIRONMENT=test)&lt;/span&gt;
            &lt;span class="na"&gt;grepFilterSpecs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&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;Note that we can still add other environment variables that is generic to all environments like &lt;code&gt;grepFilterSpecs&lt;/code&gt; so we don't need to include it in each of the configs. &lt;/p&gt;

&lt;p&gt;Basically, the premise is we can only use &lt;code&gt;Cypress.env&lt;/code&gt; on the test specs but since &lt;code&gt;config.config.ts&lt;/code&gt; runs in node as part of the setup process, then we can't use it yet. It can be reached using &lt;code&gt;process.env&lt;/code&gt;. So, when you use something like &lt;code&gt;ENVIRONMENT=test npx cypress run&lt;/code&gt; on your CLI, the following will appear on the &lt;em&gt;Project settings&lt;/em&gt; of your Cypress runner:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl6174nz342fv5ymqpiip.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl6174nz342fv5ymqpiip.png" alt="Image Cypress env variable" width="800" height="345"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;BONUS:&lt;/strong&gt; The legacy &lt;code&gt;index&lt;/code&gt; file can still be used with the following lines on &lt;code&gt;cypress.config&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;legacyConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./cypress/plugins/index&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;e2e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;setupNodeEvents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;on&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;legacyConfig&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;// since we still use the old plugin file to override configs&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>cypress</category>
      <category>environment</category>
      <category>typescript</category>
      <category>automation</category>
    </item>
    <item>
      <title>This is how my AWS Deep Racer model finished best in 11 seconds</title>
      <dc:creator>poponuts</dc:creator>
      <pubDate>Sat, 09 Jul 2022 10:47:17 +0000</pubDate>
      <link>https://dev.to/poponuts/this-is-how-my-aws-deep-racer-model-finished-best-in-11-seconds-hc9</link>
      <guid>https://dev.to/poponuts/this-is-how-my-aws-deep-racer-model-finished-best-in-11-seconds-hc9</guid>
      <description>&lt;p&gt;My new company flew me to Sydney 🛩️ to attend a 2-day team building event which included half of the day putting our &lt;strong&gt;AWS Deep Racer&lt;/strong&gt; model into action by competing in an actual physical race.&lt;/p&gt;

&lt;p&gt;Despite the workload, I spent time outside working hours to develop our team's model. Since I am a very competitive person (yes, I trash talk my kids when I win a Mario Kart game 🏎️ over them - teaches them resilience 👀), the motivation to win was multi-fold: bragging rights, winning cool prizes (we each got Echo dot and AWS notebooks!) and most importantly, my inclination to learn "real" machine learning (I used to be part of a team "selling" AI/ML but it's all just big data 🤷).&lt;/p&gt;

&lt;p&gt;The awesome AWS team had a couple of workshops with everyone on how to prepare your models (creating accounts, training, simulation, racing with the company-specific community race). Non-technical or newbies don't need to be scared as the AWS console for Deep Racer is quite a user-friendly UI. We only had one track to train on which is the &lt;strong&gt;&lt;em&gt;re:Invent 2018&lt;/em&gt;&lt;/strong&gt; so it was easier to tweak your models.&lt;/p&gt;

&lt;p&gt;I trained multiple models (and iterations) after deep-diving into &lt;em&gt;github&lt;/em&gt; repositories and browsing through multiple online articles&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmpjb02q8qotajkvqfyft.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmpjb02q8qotajkvqfyft.png" alt="AWS Deep Race models" width="800" height="350"&gt;&lt;/a&gt;&lt;br&gt;
Each models were trained between an hour and three hours based on different reward functions. One of the things I learned is that longer training would not mean a better time (as it might pick up some bad habits too as you can see in the graph below where it shows a bit of downward trend at the end)&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fovwseoyqgrfajwthgry8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fovwseoyqgrfajwthgry8.png" alt="Training logs" width="800" height="521"&gt;&lt;/a&gt;&lt;br&gt;
We were allowed to submit any models we have (as many times as we want) and enter into the simulation virtual race. Overall, my entry came 3rd with a time of &lt;strong&gt;34.724&lt;/strong&gt; seconds having no lap going &lt;strong&gt;"off-track"&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffg8xwenrqzv24hze8yu5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffg8xwenrqzv24hze8yu5.png" alt="Race results" width="800" height="565"&gt;&lt;/a&gt;&lt;br&gt;
You can see above that I tried to iterate my &lt;strong&gt;superpumped&lt;/strong&gt; model (sorry, I just watched the Amazon Prime series so that's the first thing that came to my mind, although I'm not a fan of Uber's toxic culture) by tweaking the values in the hyper parameters and reward functions but the &lt;strong&gt;version 2&lt;/strong&gt; did the best time (not bad considering there were 20 entries). Each team then had to download the &lt;em&gt;physical car model&lt;/em&gt; then submit to the AWS team the day before the actual physical race.&lt;/p&gt;

&lt;p&gt;During "race" day 🏁 (thanks AWS team for preparing the track and all the set-ups), we had to drive our models on the track one team at a time for 3 minutes each (so the car can go as many laps as possible and the best lap will be recorded). We were the last team to drive the vehicle (a.k.a. RC model with a camera) and as they say, &lt;em&gt;"saved the best for last"&lt;/em&gt;. Our car clocked &lt;strong&gt;11.04&lt;/strong&gt; seconds, while the runner-up was 8 seconds slower (yep, big gap which validated the hard work!). AWS team also said the fastest ever was 7 seconds so our result was not bad for a first timer 😎. The other thing to note is that there is a &lt;strong&gt;&lt;em&gt;"speed function"&lt;/em&gt;&lt;/strong&gt; introduced while driving the car. The AWS team initially set it to &lt;strong&gt;41%&lt;/strong&gt; and you would need to adjust it accordingly while the car is moving (e.g. turn up the speed when it's a straight path while try to  decrease it when it's curving). There were a couple of times where the car went off-track so I realised, I had to slow it down.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu4ybzqx4xyvt5xu79v89.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu4ybzqx4xyvt5xu79v89.png" alt="Actual race results" width="800" height="704"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;I know you might have skipped the babble above so for those who are just here to check how I did it, click the repository link below containing my reward function:&lt;br&gt;
&lt;a href="https://github.com/poponuts/aws-deepracer-model" rel="noopener noreferrer"&gt;my awesome aws deeprace model&lt;/a&gt;  ⬅️ ⬅️ ⬅️&lt;br&gt;
... with training configuration below:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgpclydybwfb5ft1qxzkt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgpclydybwfb5ft1qxzkt.png" alt="Training config" width="800" height="300"&gt;&lt;/a&gt;&lt;br&gt;
I ran it for 100 minutes (1 hour and 20 minutes) because when I iterated and changed the duration to 3 hours, it just went ballistic and did no good.&lt;/p&gt;

&lt;p&gt;The model focused on accuracy instead of speed where it tries to stay at the centre as much as possible. It rewards the model the closer it is while it penalises if it veers away.&lt;/p&gt;




&lt;p&gt;By no means I am taking full credit for this as I checked out a number of articles and tried out a dozen of models (hence, used up all my training credits). I used the &lt;em&gt;&lt;strong&gt;Example 4&lt;/strong&gt;&lt;/em&gt; from the reference below with only changing the Loss type from &lt;em&gt;Mean Square&lt;/em&gt; to &lt;em&gt;Huber&lt;/em&gt; (by accident... but it worked out well in the end):&lt;br&gt;
&lt;a href="https://www.linkedin.com/pulse/samples-reward-functions-aws-deepracer-bahman-javadi?trk=public_profile_article_view" rel="noopener noreferrer"&gt;https://www.linkedin.com/pulse/samples-reward-functions-aws-deepracer-bahman-javadi?trk=public_profile_article_view&lt;/a&gt;&lt;/p&gt;

</description>
      <category>deepracer</category>
      <category>aws</category>
      <category>machinelearning</category>
      <category>ai</category>
    </item>
    <item>
      <title>Integrate tests with Buildkite Test Analytics</title>
      <dc:creator>poponuts</dc:creator>
      <pubDate>Sun, 26 Jun 2022 11:17:57 +0000</pubDate>
      <link>https://dev.to/poponuts/integrate-tests-with-buildkite-test-analytics-2dgk</link>
      <guid>https://dev.to/poponuts/integrate-tests-with-buildkite-test-analytics-2dgk</guid>
      <description>&lt;p&gt;Buildkite introduced a new feature called &lt;a href="https://buildkite.com/test-analytics" rel="noopener noreferrer"&gt;Test Analytics&lt;/a&gt; 📈 this month and in my attempt to rank high on SEO on this subject, you're in the right article on how I did it (considering you already have access to Buildkite).&lt;/p&gt;

&lt;p&gt;Just a bit of context (which no one cares), I just joined a scale-up where we started tracking &lt;em&gt;stuff&lt;/em&gt; and understandably, it includes the quality of our delivery lifecycle (or else, what's the point of my existence 😂). One of the metrics I personally wanted to check is how predictable and trust-worthy our tests are. The tendency is to ignore tests (especially on the Slack alerts where it becomes normal) when there is pressure to deliver and the amount of failing tests exceed the succeeding ones. That is just unacceptable for me as a Quality engineer and something that should be closely monitored.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;&lt;em&gt;"You can't improve what you don't measure."&lt;/em&gt;&lt;/strong&gt; — Peter Drucker&lt;/p&gt;




&lt;p&gt;For our &lt;code&gt;jest&lt;/code&gt; frontned unit tests, there is a readily-available integrator (which makes life so easy!) where you just simply need to install (and obviously, include in your source code repo) the &lt;code&gt;npm&lt;/code&gt; package called &lt;strong&gt;&lt;em&gt;&lt;a href="https://www.npmjs.com/package/buildkite-test-collector" rel="noopener noreferrer"&gt;buildkite-test-collector&lt;/a&gt;&lt;/em&gt;&lt;/strong&gt; and include the reporter in your config file (e.g. &lt;code&gt;jest.config.js&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;reporters:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;'default'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;'buildkite-test-collector/jest/reporter'&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;testLocationInResults:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;For our &lt;code&gt;cypress&lt;/code&gt; end-to-end tests, it is a bit trickier as it involves a couple more steps. You need to use the default &lt;strong&gt;&lt;em&gt;&lt;a href="https://docs.cypress.io/guides/tooling/reporters" rel="noopener noreferrer"&gt;junit reporter&lt;/a&gt;&lt;/em&gt;&lt;/strong&gt; and include the reporter in your config file (e.g. &lt;code&gt;cypress.json&lt;/code&gt; or &lt;code&gt;cypress.config.ts&lt;/code&gt; for Cypress 10 and above):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nl"&gt;"reporter"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"junit"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"reporterOptions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"mochaFile"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"results/junit-[hash].xml"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"toConsole"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once done, you need to go to your test or build pipeline (or wherever you run your tests) &amp;gt; Build steps (or &lt;code&gt;pipeline.yml&lt;/code&gt;), and &lt;a href="https://buildkite.com/docs/test-analytics/importing-junit-xml" rel="noopener noreferrer"&gt;import the JUnit XML file&lt;/a&gt;. As lazy as I am (some call it smart 😎), I used the &lt;a href="https://github.com/buildkite-plugins/test-collector-buildkite-plugin" rel="noopener noreferrer"&gt;Test collector plugin&lt;/a&gt; in this instance.&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;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;🧪&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Run&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;cypress&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;tests'&lt;/span&gt;
    &lt;span class="na"&gt;commands&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;npx&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;cypress&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;run&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;--record&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;--parallel&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;--ci-build-id&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;$BUILDKITE_BUILD_NUMBER'&lt;/span&gt;
    &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;# pass details to Test Analytics&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;test-collector#v1.0.0&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;files&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;results/junit-*.xml'&lt;/span&gt;
          &lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;junit'&lt;/span&gt;
    &lt;span class="na"&gt;artifact_paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;results/**/*'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the configuration is done, include the &lt;code&gt;BUILDKITE_ANALYTICS_TOKEN&lt;/code&gt; value on your pipeline's &lt;strong&gt;Build Steps&lt;/strong&gt; or &lt;code&gt;pipeline.yml&lt;/code&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3mwnlu6thtzc73x9uo4s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3mwnlu6thtzc73x9uo4s.png" alt="Build step page" width="605" height="316"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once the tokens are set, run your pipelines and then the magic happens! 🪄&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk3m2ba3pqgo0c21335lt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk3m2ba3pqgo0c21335lt.png" alt="Test analytics page" width="800" height="189"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: Unsure why the test summary is not included in the main test suite page for the unit tests (maybe the Buildkite Gods can help us and I will update this write-up).&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Click a specific test suite and the "devil (if heaps of failing tests) is in the details" 👿&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv2gw7gmttjewm2akhueq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv2gw7gmttjewm2akhueq.png" alt="Test suite details page" width="800" height="443"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is good alternative to &lt;a href="https://dashboard.cypress.io/" rel="noopener noreferrer"&gt;Cypress dashboards&lt;/a&gt; too but free of charge if you're already subscribed to Buildkite.&lt;/p&gt;

</description>
      <category>cypress</category>
      <category>jest</category>
      <category>buildkite</category>
      <category>testing</category>
    </item>
    <item>
      <title>Ways to reduce execution time on automated tests</title>
      <dc:creator>poponuts</dc:creator>
      <pubDate>Sun, 20 Mar 2022 00:34:52 +0000</pubDate>
      <link>https://dev.to/poponuts/ways-to-reduce-execution-time-on-automated-tests-2718</link>
      <guid>https://dev.to/poponuts/ways-to-reduce-execution-time-on-automated-tests-2718</guid>
      <description>&lt;p&gt;I was asked a few months ago on potential ways in reducing test automation run time so I opened my &lt;strong&gt;&lt;em&gt;Notion&lt;/em&gt;&lt;/strong&gt; editor ✍🏻 and started compiling a list based on my experience. I've been in companies where tests were running for &lt;strong&gt;HOURS&lt;/strong&gt;! (imagine the long feedback loop and re-work required if something goes wrong! 😱).&lt;/p&gt;

&lt;p&gt;This might be handy to Quality Engineers looking for a test automation strategy. Let's start with the quick wins 💨.&lt;/p&gt;

&lt;p&gt;✅ &lt;strong&gt;Use explicit waits instead of implicit waits&lt;/strong&gt; - This is a well-known anti-pattern in the test automation community, putting a default waiting time attracts longer run-time and flakiness. Explicit waits such as waiting for an expected element to be visible should be used instead.&lt;/p&gt;

&lt;p&gt;✅ &lt;strong&gt;Avoid usage of xpath (if possible)&lt;/strong&gt; - (I understand it is a bit controversial as automation engineers rely on this regularly but hear me out) but xpath identification is generally slower than other direct attributes, so using id or name (if unique) should be the top choices. It is also harder for maintenance as it is not easily visible on the &lt;em&gt;DevTools&lt;/em&gt; when troubleshooting issues. &lt;/p&gt;

&lt;p&gt;✅ &lt;strong&gt;Include unique tag / custom attributes on selectors&lt;/strong&gt; - Instead of traversing the whole DOM, it is usually easier to have a unique identifier for a specific element such as adding data attribute such as &lt;code&gt;data-test-id&lt;/code&gt; on the actual source code.&lt;/p&gt;

&lt;p&gt;✅ &lt;strong&gt;Run via headless mode&lt;/strong&gt; - Headless are much faster than real / headed where the main difference is that the screen / browser is hidden. This can be achieved by CLI options (e.g. &lt;code&gt;npx cypress run --headless&lt;/code&gt; - most frameworks would have this option).&lt;/p&gt;

&lt;p&gt;✅ &lt;strong&gt;Use API / libraries to quickly generate test data&lt;/strong&gt; - Instead of creating test data via the UI, it is significantly faster via API or libraries. Plug-ins such as &lt;a href="https://www.npmjs.com/package/faker/v/5.5.3" rel="noopener noreferrer"&gt;faker&lt;/a&gt; or running API's can be included in the test scripts before any UI functionality is performed.&lt;/p&gt;

&lt;p&gt;✅ &lt;strong&gt;Bypass the UI if not testing those functionalities&lt;/strong&gt; - Similar to the above, for example, if we are not testing the &lt;em&gt;login&lt;/em&gt; functionality, then there should be multiple ways to bypass this. Although, we can still have a separate UI test for login, the other tests (after login) can be checked without going through the long UI login process.&lt;/p&gt;

&lt;p&gt;✅ &lt;strong&gt;Set a scheduled run of tests on a higher frequency&lt;/strong&gt; - This won't reduce the run-time but would be beneficial on continuous health check. A sub-set / smoke tests can be run multiple times in a day or a longer test (e.g. regression) can be run daily overnight via the CI/CD tool.&lt;/p&gt;

&lt;p&gt;✅ &lt;strong&gt;Parallelisation + Deterministic tests&lt;/strong&gt; - Parallelisation allows higher test coverage in a shorter run-time. By making the tests "deterministic" (independent of any other tests, data, environment, etc.), it is easier to de-couple tests and run them in parallel. This can be easily configured as most CI/CD tools are capable of running parallel tests.&lt;/p&gt;

&lt;p&gt;At the same time, let's take a step back and wear our &lt;strong&gt;&lt;em&gt;holistic&lt;/em&gt;&lt;/strong&gt; hat. The following may require longer effort and big mindset shift 🌟.&lt;/p&gt;

&lt;p&gt;✅ &lt;strong&gt;Choose the tooling &amp;amp; language&lt;/strong&gt; - Modern automation tools such as &lt;em&gt;Webdriverio&lt;/em&gt;, &lt;em&gt;Playwright&lt;/em&gt; &amp;amp; &lt;em&gt;Cypress&lt;/em&gt; have smarter ways to make the tests run faster and are scripted via NodeJS / Javascript which allows asynchronous calls so it does not need to wait sequentially for each commands.&lt;/p&gt;

&lt;p&gt;✅ &lt;strong&gt;Clean up the database / environment if possible&lt;/strong&gt; - If there is a way to easily spin up an environment with minimal dataset or a script can clean up the database, then this will speed up the run-time. Assistance from environment owners and building up automated jobs can help fast-track these activities. Note: If you are worried about performance difference with a Production environment, then it's best practice to use a dedicated Production-like environment for Performance testing.&lt;/p&gt;

&lt;p&gt;✅ &lt;strong&gt;Built-in documentation and having developers contribute to the code&lt;/strong&gt; - In the modern testing, even the developers are involved in the test automation. As they would usually know good coding patterns, they can help improve the speed of the tests. Pair programming / testing and continuous collaboration would help build a scalable and robust test automation framework. Include in-line comments help resources to understand the scripts better.&lt;/p&gt;

&lt;p&gt;✅ &lt;strong&gt;Reduce by increasing unit tests as compared to e2e&lt;/strong&gt; - Following the &lt;a href="https://dev.to/poponuts/hour-glass-pyramid-trophy-it-s-simply-test-strategy-4j5e"&gt;test pyramid&lt;/a&gt; principles, there should be a significantly higher coverage of unit and integration tests as compared to e2e tests. Both unit and integration tests run significantly faster too as compared to tests that involve the UI. It is ideal to focus on high-value E2E tests that are critical to the customers and stakeholders. Duplicate tests that have been covered in the earlier level of tests should be considered for streamlining the test suite.&lt;/p&gt;

&lt;p&gt;Again, this is just on my experience and there might be some better ways so just pick the bits and pieces that fit your need 👋.&lt;/p&gt;

</description>
      <category>automation</category>
      <category>testing</category>
      <category>cypress</category>
      <category>selenium</category>
    </item>
    <item>
      <title>Trigger your E2E tests from another repo's Bitbucket Pipeline build</title>
      <dc:creator>poponuts</dc:creator>
      <pubDate>Fri, 06 Aug 2021 03:50:33 +0000</pubDate>
      <link>https://dev.to/poponuts/trigger-your-e2e-tests-from-another-repo-s-bitbucket-pipeline-build-fn5</link>
      <guid>https://dev.to/poponuts/trigger-your-e2e-tests-from-another-repo-s-bitbucket-pipeline-build-fn5</guid>
      <description>&lt;p&gt;There are two school of thoughts on whether End-to-end (E2E) tests should be on same repository or on a separate repository. If its taking you weeks or months to debate on that with your team, then there could be a middle-ground 🤠.&lt;/p&gt;

&lt;p&gt;If there is a separate team / resource working on the E2E tests and another team / resources working on the source code, then how about a compromise to make it work? This is by simply triggering the E2E tests on any changes made in the source code. &lt;/p&gt;

&lt;p&gt;This is highly possible by using Atlassian's &lt;a href="https://bitbucket.org/product/features/pipelines/integrations?p=atlassian/trigger-pipeline" rel="noopener noreferrer"&gt;Pipe - trigger pipeline&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;On the application / source code's &lt;code&gt;bitbucket-pipeline.yml&lt;/code&gt; file, simply add the following as a step:&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="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;step&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nl"&gt;&amp;amp;run-automated-tests&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run E2E and API automated tests&lt;/span&gt;
        &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;pipe&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;atlassian/trigger-pipeline:4.2.1&lt;/span&gt; &lt;span class="c1"&gt;# https://bitbucket.org/product/features/pipelines/integrations?p=atlassian/trigger-pipeline&lt;/span&gt;
            &lt;span class="na"&gt;variables&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;BITBUCKET_USERNAME&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$BITBUCKET_USERNAME&lt;/span&gt;
              &lt;span class="na"&gt;BITBUCKET_APP_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$BITBUCKET_APP_PASSWORD&lt;/span&gt;
              &lt;span class="na"&gt;REPOSITORY&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;my-cypress-tests'&lt;/span&gt;
              &lt;span class="c1"&gt;# ACCOUNT: '&amp;lt;string&amp;gt;' # Optional&lt;/span&gt;
              &lt;span class="na"&gt;BRANCH_NAME&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;master'&lt;/span&gt; &lt;span class="c1"&gt;# Optional&lt;/span&gt;
              &lt;span class="c1"&gt;# CUSTOM_PIPELINE_NAME: '&amp;lt;string&amp;gt;' # Optional&lt;/span&gt;
              &lt;span class="c1"&gt;# PIPELINE_VARIABLES: '&amp;lt;json&amp;gt;' # Optional&lt;/span&gt;
              &lt;span class="c1"&gt;# WAIT: 'true' # Optional - if set to true, it waits for the triggered pipeline to complete. If the triggered pipeline fails, this pipe will also fail.&lt;/span&gt;
              &lt;span class="c1"&gt;# WAIT_MAX_TIMEOUT: '&amp;lt;string&amp;gt;' # Optional&lt;/span&gt;
              &lt;span class="c1"&gt;# DEBUG: '&amp;lt;boolean&amp;gt;' # Optional&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;BITBUCKET_USERNAME&lt;/code&gt; can be hard-coded to your Atlassian username or this can be set under the &lt;strong&gt;&lt;em&gt;Repository settings &amp;gt; Repository variables&lt;/em&gt;&lt;/strong&gt; section of Bitbucket to encrypt secrets.&lt;br&gt;
&lt;code&gt;BITBUCKET_APP_PASSWORD&lt;/code&gt; would need to be generated via &lt;strong&gt;&lt;em&gt;Personal settings &amp;gt; App passwords&lt;/em&gt;&lt;/strong&gt; then creating a new app password.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftq79a4z4p2xeatggnse3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftq79a4z4p2xeatggnse3.png" alt="Screen Shot 2021-08-01 at 4.59.52 pm" width="800" height="212"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Alternatively, a shared account can be created by your Atlassian administrator that can be used across CI/CD pipeline and would not need dependency on resources going in and out of the team / company. &lt;/p&gt;

&lt;p&gt;To add alerting, simply integrate the tests with Slack (include as many stakeholders as possible 😂&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsl8rcp24q1dl8dzfbpml.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsl8rcp24q1dl8dzfbpml.png" alt="Screen Shot 2021-07-30 at 8.32.16 pm" width="800" height="307"&gt;&lt;/a&gt;&lt;br&gt;
This is a good opportunity to say &lt;em&gt;"Sorry Mr. Software Engineer, you can't proceed until you fix your breaking changes (and no, I'm not fixing my tests either!)&lt;/em&gt; Just kidding! Collaborate with your developers as much as possible to resolve the issues 😇&lt;/p&gt;

</description>
      <category>e2e</category>
      <category>cypress</category>
      <category>bitbucket</category>
      <category>pipeline</category>
    </item>
    <item>
      <title>Uses Bitbucket Pipeline but too poor to buy Cypress Dashboard for parallelisation? Look no further...</title>
      <dc:creator>poponuts</dc:creator>
      <pubDate>Sun, 01 Aug 2021 06:40:51 +0000</pubDate>
      <link>https://dev.to/poponuts/uses-bitbucket-pipeline-but-too-poor-to-buy-cypress-dashboard-for-parallelisation-look-no-further-4gpf</link>
      <guid>https://dev.to/poponuts/uses-bitbucket-pipeline-but-too-poor-to-buy-cypress-dashboard-for-parallelisation-look-no-further-4gpf</guid>
      <description>&lt;p&gt;If you've been a &lt;em&gt;"Google"&lt;/em&gt; developer like me then I'm sure by now, you've heard of &lt;a href="https://sorry-cypress.dev/" rel="noopener noreferrer"&gt;sorry-cypress&lt;/a&gt;, an alternative open-source tool for the &lt;a href="https://www.cypress.io/dashboard/" rel="noopener noreferrer"&gt;Cypress dashboard&lt;/a&gt; that usually comes with a price tag 🤑.&lt;/p&gt;

&lt;p&gt;I tried using that on my previous company and was doing my head in for a few months before I finally gave in that's impossible to use that using an old CI pipeline like &lt;strong&gt;TeamCity&lt;/strong&gt;.&lt;br&gt;
Fast-forward to today where my current company is using &lt;strong&gt;Bitbucket Pipeline&lt;/strong&gt; and I thought to myself "finally, just a a unicorn yaml file that does it all!"... well, not too fast, big boy! 👀&lt;/p&gt;

&lt;p&gt;Unfortunately, the way &lt;em&gt;docker&lt;/em&gt; is used in the Atlassian suite is a bit different (In the interest of "that's not what I came here for", I won't explain it here the way the support team explained it to me - as if anyone cares?). As such, I swallowed my ego (that I can do it on my own), and finally gave in sending a desperate support ticket to the Atlassian team begging to assist me! ✌🏻&lt;/p&gt;

&lt;p&gt;To their credit, the Atlassian team went beyond my expectations in terms of support (don't worry, I gave them the highest rating possible in terms of service!). After much iteration and never-ending back and forth time-consuming correspondence ⛑, the one below finally worked in achieving &lt;strong&gt;Parallelisation of Cypress tests in Bitbucket Pipeline&lt;/strong&gt;&lt;br&gt;
using the &lt;code&gt;bitbucket-pipelines.yml&lt;/code&gt;:&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;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cypress/base:14.16.0&lt;/span&gt;
&lt;span class="na"&gt;options&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;max-time&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;60&lt;/span&gt;

&lt;span class="na"&gt;definitions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;caches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;npm&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$HOME/.npm&lt;/span&gt;
    &lt;span class="na"&gt;cypress&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$HOME/.cache/Cypress&lt;/span&gt;

  &lt;span class="c1"&gt;# job definition for running tests&lt;/span&gt;
  &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;step&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nl"&gt;&amp;amp;tests&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run all tests&lt;/span&gt;
        &lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;2x&lt;/span&gt; &lt;span class="c1"&gt;# (optional) recommended by Atlassian team but adds up to your minutes&lt;/span&gt;
        &lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;docker&lt;/span&gt;
        &lt;span class="na"&gt;caches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;npm&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;node&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;cypress&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;docker&lt;/span&gt;
        &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;docker run -d -p 1234:1234 agoldis/sorry-cypress-director&lt;/span&gt; &lt;span class="c1"&gt;# port bindings to enable free parallelisation&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;apt update &amp;amp;&amp;amp; apt install parallel -y&lt;/span&gt; &lt;span class="c1"&gt;# workaround recommended by Atlassian team that runs background job services in Linux where Bitbucket Pipeline is hosted&lt;/span&gt;
          &lt;span class="c1"&gt;# include below the no. of parallel instances you want your (obviously, the more the better but it intermittently messes up reporting&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;echo "npx cypress run --record --key $CYPRESS_DASHBOARD_KEY --parallel --ci-build-id $BITBUCKET_BUILD_NUMBER --browser chrome --spec cypress/integration/$TESTS;" &amp;gt;&amp;gt; jobs.txt&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;echo "npx cypress run --record --key $CYPRESS_DASHBOARD_KEY --parallel --ci-build-id $BITBUCKET_BUILD_NUMBER --browser chrome --spec cypress/integration/$TESTS;" &amp;gt;&amp;gt; jobs.txt&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;echo "npx cypress run --record --key $CYPRESS_DASHBOARD_KEY --parallel --ci-build-id $BITBUCKET_BUILD_NUMBER --browser chrome --spec cypress/integration/$TESTS;" &amp;gt;&amp;gt; jobs.txt&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;parallel&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-j&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;3&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;::::&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;jobs.txt'&lt;/span&gt; &lt;span class="c1"&gt;# &amp;gt;&amp;gt; logs.log'&lt;/span&gt;
        &lt;span class="na"&gt;artifacts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;# store any generates images and videos as artifacts&lt;/span&gt;
          &lt;span class="c1"&gt;# - logs.log # (optional) include this for better troubleshooting&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;jobs.txt&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;cypress/screenshots/**&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;cypress/videos/**&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;cypress/test-reports/*.xml&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;step&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nl"&gt;&amp;amp;tests-non-parallel&lt;/span&gt; &lt;span class="c1"&gt;# non-parallel tests&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run all tests&lt;/span&gt;
        &lt;span class="na"&gt;caches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;# not needed as taking it from the docker image&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;node&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;cypress&lt;/span&gt;
        &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;cypress_version=$HOST npx cypress run --browser chrome --spec cypress/integration/**/*.js&lt;/span&gt; &lt;span class="c1"&gt;# all tests&lt;/span&gt;
        &lt;span class="na"&gt;artifacts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="c1"&gt;# store any generates images and videos as artifacts&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;cypress/screenshots/**&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;cypress/videos/**&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;cypress/test-reports/mocha/*.json&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;cypress/test-reports/*.xml&lt;/span&gt;

&lt;span class="na"&gt;pipelines&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;step&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Prepare dependencies&lt;/span&gt;
      &lt;span class="na"&gt;caches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;npm&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;cypress&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;node&lt;/span&gt;
      &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;npm ci&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;npx @bahmutov/print-env BITBUCKET&lt;/span&gt; &lt;span class="c1"&gt;# let's see the environment variables right away&lt;/span&gt;
        &lt;span class="c1"&gt;# - npm audit # check security vulnerabilities of npm packages&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;sed -i -E 's@(api_url:) (.*)@\1 "http://localhost:1234"@g' /*/.cache/Cypress/*/Cypress/resources/app/packages/server/config/app.yml&lt;/span&gt; &lt;span class="c1"&gt;# reconfigure cypress agent to localhost&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;step&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;*tests&lt;/span&gt;

  &lt;span class="na"&gt;custom&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;non-parallel&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;# non-parallel tests&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;step&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Prepare dependencies&lt;/span&gt;
          &lt;span class="na"&gt;caches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;npm&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;cypress&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;node&lt;/span&gt;
          &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;npm ci&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;npx @bahmutov/print-env BITBUCKET&lt;/span&gt; &lt;span class="c1"&gt;# let's see the environment variables right away&lt;/span&gt;
            &lt;span class="c1"&gt;# - npm audit # check security vulnerabilities of npm packages&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;sed -i -E 's@(api_url:) (.*)@\1 "http://localhost:1234"@g' /*/.cache/Cypress/*/Cypress/resources/app/packages/server/config/app.yml&lt;/span&gt; &lt;span class="c1"&gt;# reconfigure cypress agent to localhost&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;step&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;*tests-non-parallel&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;A few things to note:&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;You can hard-code the &lt;code&gt;CYPRESS_DASHBOARD_KEY&lt;/code&gt; and &lt;code&gt;TESTS&lt;/code&gt; or set them under the &lt;strong&gt;&lt;em&gt;Repository settings &amp;gt; Repository variables&lt;/em&gt;&lt;/strong&gt; section of Bitbucket (as long as you have admin access). &lt;code&gt;CYPRESS_DASHBOARD_KEY&lt;/code&gt; can also be a fixed / random value and you don't necessarily need to create an account in Cypress dashboard to generate one. &lt;code&gt;TESTS&lt;/code&gt; on the other hand can be set to &lt;code&gt;**/*.js&lt;/code&gt; to run all tests or can be more specific e.g. &lt;code&gt;cypress/integration/mytest.js&lt;/code&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft0ir5en2t7tws1nwml1c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft0ir5en2t7tws1nwml1c.png" alt="Screen Shot 2021-08-01 at 4.18.45 pm" width="800" height="302"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;On your &lt;code&gt;cypress.json&lt;/code&gt; file, ensure that the &lt;code&gt;projectId&lt;/code&gt; key it set to the same value in &lt;code&gt;CYPRESS_DASHBOARD_KEY&lt;/code&gt;&lt;br&gt;
e.g. &lt;code&gt;"projectId": "8ghcrb"&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;BITBUCKET_BUILD_NUMBER&lt;/code&gt; is already a reserved variable in &lt;a href="https://support.atlassian.com/bitbucket-cloud/docs/variables-and-secrets/" rel="noopener noreferrer"&gt;Bitbucket&lt;/a&gt; and you would need this parameterised so the parallel tests know its running on the same build.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you are having xvfb issues, you want to include the command on your scripts as recommended by &lt;a href="https://docs.cypress.io/guides/continuous-integration/introduction#Dependencies" rel="noopener noreferrer"&gt;Cypress team&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- apt-get install libgtk2.0-0 libgtk-3-0 libgbm-dev libnotify-dev libgconf-2-4 libnss3 libxss1 libasound2 libxtst6 xauth xvfb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>cypress</category>
      <category>sorrycypress</category>
      <category>bitbucket</category>
      <category>bitbucketpipeline</category>
    </item>
    <item>
      <title>Move over Zephyr, XRAY, TestRail... How to use JIRA itself as a test management tool</title>
      <dc:creator>poponuts</dc:creator>
      <pubDate>Fri, 30 Jul 2021 12:08:18 +0000</pubDate>
      <link>https://dev.to/poponuts/move-over-zephyr-xray-testrail-how-to-use-jira-itself-as-a-test-management-tool-3i6f</link>
      <guid>https://dev.to/poponuts/move-over-zephyr-xray-testrail-how-to-use-jira-itself-as-a-test-management-tool-3i6f</guid>
      <description>&lt;p&gt;Remember the days when &lt;del&gt;HP Quality Centre&lt;/del&gt; ALM used to be the gold standard of test management... well, look at how the tides have changed. Reminds me of how Blockbuster 🎟️ was too late to compete with Netflix and now, they've gone bust. Makes you wonder why Microfocus bought the tool just a couple of years back when everyone is already moving into a more agile, less admin-like (robotic) logging of test cases. It doesn't help that its slow-performing and costs a leg and arm to license it every year 🤯.&lt;br&gt;
In any case, that's not the point of this article (I know, I always gets side-tracked 🤦‍♂️).&lt;br&gt;
My point is that &lt;strong&gt;no one needs test management&lt;/strong&gt; anymore (sheepishly looking at my non-existent sponsors 🤪)! The tendency is teams treat the quantity of test cases as the success metrics for quality, which I beg to disagree! The number of test cases you have does not mean you will deliver a quality product. Imagine, having a single test case for login then another for making a payment - understandably, they don't have the same amount of weight. As the saying goes, the devil is in the detail. Sad truth is having a thousand of tests in a fancy test report always sell 😔!&lt;br&gt;
While there is &lt;em&gt;movement&lt;/em&gt; moving towards testing embedded as part of development process and reporting is done on the CI / automation stage, unfortunately, not all companies are there yet. Hence, some might still need to have a test management tool. However, instead of paying for a JIRA plug-in like Zephyr or XRAY, or an integration like qTest or TestRail, you can use JIRA itself. Less context-switching, less steps 🥂!&lt;br&gt;
&lt;strong&gt;Spoiler alert&lt;/strong&gt;: &lt;em&gt;You need to have JIRA admin rights to make this happen.&lt;/em&gt;&lt;br&gt;
Here's how with my "Marie Kondo"-inspired workflow:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1qojz4fyv5jnuxrrekmp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1qojz4fyv5jnuxrrekmp.png" alt="Screen Shot 2021-07-30 at 8.47.33 pm" width="800" height="352"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Go to &lt;strong&gt;&lt;em&gt;Project settings &amp;gt; Issue types&lt;/em&gt;&lt;/strong&gt; then create an issue type called &lt;strong&gt;Test&lt;/strong&gt; (and/or sub-task called &lt;strong&gt;Sub-test&lt;/strong&gt; if you would like it visible under the User Story)&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqtxyl4rtzpvcdjmzp466.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqtxyl4rtzpvcdjmzp466.png" alt="Screen Shot 2021-07-30 at 9.32.00 pm" width="800" height="427"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Go to &lt;strong&gt;&lt;em&gt;Project settings &amp;gt; Fields &amp;gt; Custom fields&lt;/em&gt;&lt;/strong&gt; then create a new custom field with field type &lt;strong&gt;Text Field (multi-line)&lt;/strong&gt;called &lt;strong&gt;Test Scenarios&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn9pes2051pmrz09h8jxz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn9pes2051pmrz09h8jxz.png" alt="Screen Shot 2021-07-30 at 9.49.49 pm" width="800" height="553"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F824zsl5a6x4cmrzl1wf7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F824zsl5a6x4cmrzl1wf7.png" alt="Screen Shot 2021-07-30 at 9.36.24 pm" width="800" height="138"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Go to &lt;strong&gt;&lt;em&gt;Project settings &amp;gt; Field configurations&lt;/em&gt;&lt;/strong&gt; then find the newly-created custom field. Click &lt;strong&gt;Renderers&lt;/strong&gt; hyperlink then select &lt;strong&gt;Wiki Style Renderer&lt;/strong&gt; to update&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvascza81ttsx3odd7urc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvascza81ttsx3odd7urc.png" alt="Screen Shot 2021-07-30 at 9.47.49 pm" width="800" height="234"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feaxr5vhdhyzvxgvj2zes.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feaxr5vhdhyzvxgvj2zes.png" alt="Screen Shot 2021-07-30 at 9.47.56 pm" width="800" height="322"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Click the horizontal ellipsis then select &lt;strong&gt;Contexts and default value&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3pplybqoyatu2iww2rhm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3pplybqoyatu2iww2rhm.png" alt="Screen Shot 2021-07-30 at 9.38.45 pm" width="800" height="215"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Under the &lt;strong&gt;Default Value&lt;/strong&gt; section, click the &lt;strong&gt;Edit Default Value&lt;/strong&gt; hyperlink&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv02n5qd14y4x6a62ife3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv02n5qd14y4x6a62ife3.png" alt="Screen Shot 2021-07-30 at 9.39.41 pm" width="800" height="517"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Enter the sample table below then hit &lt;strong&gt;Set Default&lt;/strong&gt; to save&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;||Test scenario||Test data||Screenshot||Status||
|Scenario 1|Test data 1|&amp;lt;upload here&amp;gt;|Pass / Fail|
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff6nj3zr7pyhia3j8pocz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff6nj3zr7pyhia3j8pocz.png" alt="Screen Shot 2021-07-30 at 9.43.26 pm" width="800" height="340"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Go to &lt;strong&gt;&lt;em&gt;Project settings &amp;gt; Workflows&lt;/em&gt;&lt;/strong&gt; then create a workflow called &lt;strong&gt;Test Workflow&lt;/strong&gt; and create a flow like below:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb9559518rke8czhmdbis.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb9559518rke8czhmdbis.png" alt="Screen Shot 2021-07-30 at 9.06.58 pm" width="800" height="422"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0v58sswwibail43wt602.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0v58sswwibail43wt602.png" alt="Screen Shot 2021-07-30 at 9.06.37 pm" width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Link the workflow, issue type, and custom field together by googling how to do this (&lt;em&gt;sorry, this part is something that would prolong my article unnecessarily so I'll leave it up to you to sort it out&lt;/em&gt; 🤪)&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You would have something like this where the tests are visible (and no multiple layers / steps needed outside the user story to see the statuses of your test scripts / cases)&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5n7s1qir0h3kt63sjxvs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5n7s1qir0h3kt63sjxvs.png" alt="Screen Shot 2021-07-30 at 9.00.53 pm" width="800" height="554"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note: You can do this (if you're still transitioning from waterfall to agile) or if you want to do hardcore "Agile" then just include them inside the User story's &lt;strong&gt;"Acceptance criteria"&lt;/strong&gt; 😁&lt;/p&gt;

</description>
      <category>testing</category>
      <category>testplan</category>
      <category>jira</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Hour glass? Pyramid? Trophy? It's simply test strategy!</title>
      <dc:creator>poponuts</dc:creator>
      <pubDate>Sat, 19 Jun 2021 09:03:36 +0000</pubDate>
      <link>https://dev.to/poponuts/hour-glass-pyramid-trophy-it-s-simply-test-strategy-4j5e</link>
      <guid>https://dev.to/poponuts/hour-glass-pyramid-trophy-it-s-simply-test-strategy-4j5e</guid>
      <description>&lt;p&gt;If you are involved in startups or scale-ups long enough, thousand pages of test strategy and million lines of code of &lt;del&gt;regression&lt;/del&gt; e2e test suite won't cut it 😴. &lt;/p&gt;

&lt;p&gt;Modern quality engineering thinking suggests that the percentage of testing done at the earliest and lowest level (unit tests) should be significantly higher than integration and e2e tests. Industry-standard says it should be around 70% of unit tests while the rest of the tests should share around 30% of coverage 🤔. IMHO, &lt;strong&gt;&lt;em&gt;it depends&lt;/em&gt;&lt;/strong&gt;! Without understanding your company's current landscape, then there is no silver bullet or "one-fit-for-all" approach. What Quality gurus are preaching nowadays: &lt;em&gt;there are no best practices but only good practices&lt;/em&gt;; Good practices in the context of the company's current and future structure, skillset, tech stacks.&lt;/p&gt;

&lt;p&gt;Usually, if you are someone new to the company and you were given the golden hand to resolve the pain points, you get excited to be the white knight to save the day (maybe I was just talking about myself here 😝). There is nothing wrong with that as that is human nature but, most of the time, it's not as straight-forward as it seems.&lt;/p&gt;

&lt;p&gt;Focusing too much on numbers / quota sways a resource to think that reaching the agreed threshold is good enough even if those tests don't add value. Furthermore, focusing on tooling / framework leans toward just following the requirements / happy path flows, without doing further analysis on what are the other possible scenarios (e.g. edge or negative cases).&lt;/p&gt;

&lt;p&gt;In any case, after reviewing my current company's needs, I came up my own version of the test pyramid or on what I see as more of an umbrella with sprinkles of rain water hovering above it (my editing skills jus't cant find time to draw an umbrella-looking diagram). Regardless of what kind of figure / diagram you make out of it, this is simply our long-term continuous test strategy - which is appropriate enough for a lean + agile company like ours. This will eventually evolve as the company grows and structures change ♻️.&lt;/p&gt;

&lt;p&gt;My attempt to use the objects and colours on Google Slides:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F02pq286h0pwdwm5ug6x8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F02pq286h0pwdwm5ug6x8.png" alt="Test strategy" width="800" height="587"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In my view, percentage of test coverage in each stage matters. However, what matters more is the time spent on two zones I have identified: &lt;strong&gt;Spending maximum amount of time on PROACTIVE ZONE while spending the minimum amount of time on the REACTIVE ZONE&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The ability to plan on delivering quality feature / product has been lost with Agile's thinking of delivering fast.&lt;br&gt;
At the same time, as the role of testers are slowly evolving into being the caretaker of the quality of the whole delivery lifecycle, they (or even your developers who loves testing 😏#sarcasm) should be involved in all levels of this diagram. As you can see, testing is continuous and the time spent on quality as early as possible, the better (I can't emphasise how &lt;strong&gt;&lt;em&gt;shift-left&lt;/em&gt;&lt;/strong&gt; mindset sets the culture of delivery quality products! 🕶️).&lt;/p&gt;

&lt;p&gt;Just to reiterate, the test strategy should evolve based on the changing needs of the company. It shouldn't be fixed on a simple test pyramid. Furthermore, what works for your old company doesn't mean it would work for your new one (my diagram had multiple iterations too). It's worth mentioning that it depends on the products / service offerings too. For example, if your company is offering API and web hook integrations then understandably, there should be more integration and contract tests involved, if your company is offering retail catalogues then there should be more visual or UI tests involved, and so on and so forth.&lt;/p&gt;

&lt;p&gt;In hopefully my next article, I will try to deep dive into those test frameworks.&lt;/p&gt;

</description>
      <category>testing</category>
      <category>testdev</category>
      <category>codequality</category>
      <category>pyramid</category>
    </item>
  </channel>
</rss>
