<?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: Mauro Laurenzi</title>
    <description>The latest articles on DEV Community by Mauro Laurenzi (@mauro_laurenzi).</description>
    <link>https://dev.to/mauro_laurenzi</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%2F1450066%2Ff9f06b1e-391d-408b-9205-2d1a52a07c4f.jpg</url>
      <title>DEV Community: Mauro Laurenzi</title>
      <link>https://dev.to/mauro_laurenzi</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mauro_laurenzi"/>
    <language>en</language>
    <item>
      <title>How to interact with Stripe's iframes using WebdriverIO</title>
      <dc:creator>Mauro Laurenzi</dc:creator>
      <pubDate>Sat, 27 Apr 2024 00:52:38 +0000</pubDate>
      <link>https://dev.to/mauro_laurenzi/how-to-interact-with-stripes-iframes-using-webdriverio-568k</link>
      <guid>https://dev.to/mauro_laurenzi/how-to-interact-with-stripes-iframes-using-webdriverio-568k</guid>
      <description>&lt;p&gt;Many test automation developers will, at some point, come across the challenging task of automating a payment flow for the app that they're testing. This task becomes even more challenging when the integration with the payment services provider in the UI is done via &lt;strong&gt;iframes&lt;/strong&gt;, as commonly happens with &lt;strong&gt;Stripe&lt;/strong&gt;. In this guide, I will try to make the process of interacting with those iframes a little more straightforward using &lt;strong&gt;JavaScript&lt;/strong&gt; and the &lt;strong&gt;WebdriverIO&lt;/strong&gt; framework.&lt;/p&gt;

&lt;h2&gt;
  
  
  What are iframes?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Inline frames&lt;/strong&gt; or &lt;strong&gt;iframes&lt;/strong&gt; can be thought of as little windows within a web page. Developers use them to embed one web page inside another, which allows them to display content from an external source within their own website. Stripe makes use of this concept and provides its own web elements, which are used inside iframes.&lt;br&gt;
Now, while this is very handy for web developers as they can integrate different web elements smoothly, it's also tricky for QA engineers to automate tests that involve working with iframes, because of their encapsulated nature. The automation tool that we choose is important because it needs to be able to &lt;strong&gt;switch the context&lt;/strong&gt; to interact with the elements inside the iframe.&lt;/p&gt;
&lt;h2&gt;
  
  
  Example
&lt;/h2&gt;

&lt;p&gt;We'll use WebdriverIO to automate the flow to add new credit card information to a web app that integrates with Stripe.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Obtaining the iframe locator:&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F90xetnrrtxkmb1ibu7dg.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F90xetnrrtxkmb1ibu7dg.jpeg" alt="Screenshot of the iframe element locator through the DevTools." width="800" height="186"&gt;&lt;/a&gt;&lt;br&gt;
We'll have to inspect the input element through the Chrome DevTools and search for the Stripe iframe that contains it. In this case, as we can see, the iframe doesn't have a unique ID, so one way to identify it could be with its &lt;em&gt;title&lt;/em&gt; value. The &lt;strong&gt;xpath&lt;/strong&gt; will look like this: &lt;code&gt;'iframe[title="Secure card payment input frame"]'&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Switching the browsing context to the Stripe iframe:&lt;/strong&gt;&lt;br&gt;
Once we have found the correct locator for pointing out to the desired iframe, we have to switch the context from the parent frame (webpage) to the particular one that we want to interact with, in WebdriverIO this can be done like this:&lt;br&gt;
&lt;code&gt;await browser.switchToFrame(await $('iframe[title="Secure card payment input frame"]'));&lt;/code&gt;&lt;br&gt;
Basically, we create an &lt;strong&gt;Element&lt;/strong&gt; object with &lt;em&gt;await $('locator')&lt;/em&gt; and pass it as a parameter to the &lt;a href="https://webdriver.io/docs/api/webdriver/#switchtoframe"&gt;switchToFrame()&lt;/a&gt; command.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Interacting with the elements inside the iframe:&lt;/strong&gt;&lt;br&gt;
Now that we have switched the browsing context to the particular iframe, we can perform some actions to the elements inside of it. Like adding the card number:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fen7jbkbzedm83m7fofhs.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fen7jbkbzedm83m7fofhs.jpeg" alt="Screenshot of the card number input element locator inside the Stripe iframe through the DevTools." width="800" height="161"&gt;&lt;/a&gt;&lt;br&gt;
One possible locator for the Card number input field could be &lt;code&gt;//input[@name="cardnumber"]&lt;/code&gt;, so we can write something like: &lt;br&gt;
&lt;code&gt;await $('//input[@name="cardnumber"]').setValue(cardNumber);&lt;/code&gt;&lt;br&gt;
And the same goes for the rest of the input fields, like the &lt;em&gt;expiration date&lt;/em&gt;, &lt;em&gt;CVC&lt;/em&gt; and &lt;em&gt;zip code&lt;/em&gt;.&lt;br&gt;
It's important to note that if we don't switch the context to the iframe like we did in &lt;strong&gt;step 2&lt;/strong&gt;, this locator &lt;code&gt;//input[@name="cardnumber"]&lt;/code&gt; will not be recognized by the test-runner, the only way to access it is by previously switching to the specific iframe context.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Switching back to parent frame:&lt;/strong&gt;&lt;br&gt;
After we have filled all the necessary values for the credit card info, we'll want to click the &lt;em&gt;“Save Payment Method”&lt;/em&gt; button, which is outside of the Stripe iframe, so if we try to run something like: &lt;br&gt;
&lt;code&gt;await $('//button[contains(text(),"SAVE PAYMENT METHOD")]').click()&lt;/code&gt; &lt;br&gt;
it won't work since we're still inside the Stripe iframe context; we first need to switch back to the parent frame context to interact with the elements of the main webpage. For this we can use the &lt;a href="https://webdriver.io/docs/api/webdriver/#switchtoparentframe"&gt;switchToParentFrame()&lt;/a&gt; WebdriverIO command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;await browser.switchToParentFrame();
await $('//button[contains(text(),"SAVE PAYMENT METHOD")]').click();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, our method for adding the credit card info will look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;async addNewCreditCard(cardNumber, expirationDate, cvc, zip) {
    await browser.switchToFrame(await $('iframe[title="Secure card payment input frame"]'));
    await $('//input[@name="cardnumber"]').setValue(cardNumber);
    await $('//input[@name="exp-date"]').setValue(expirationDate);
    await $('//input[@name="cvc"]').setValue(cvc);
    await $('//input[@name="zip"]').setValue(zip);
    await browser.switchToParentFrame();
    await $('//button[contains(text(),"SAVE PAYMENT METHOD")]').click();
}

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

&lt;/div&gt;



&lt;p&gt;And this is how, using WebdriverIO's switchToFrame() and switchToParentFrame() commands, we can interact with the elements inside Stripe's iframes after correctly identifying all the necessary locators.&lt;/p&gt;

</description>
      <category>testing</category>
      <category>tutorial</category>
      <category>webdriverio</category>
      <category>stripe</category>
    </item>
    <item>
      <title>How to test Chrome extensions in headless mode with WebdriverIO</title>
      <dc:creator>Mauro Laurenzi</dc:creator>
      <pubDate>Thu, 25 Apr 2024 22:48:18 +0000</pubDate>
      <link>https://dev.to/mauro_laurenzi/how-to-test-chrome-extensions-in-headless-mode-with-webdriverio-20a6</link>
      <guid>https://dev.to/mauro_laurenzi/how-to-test-chrome-extensions-in-headless-mode-with-webdriverio-20a6</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fokrd2kcbh1r0agnuhx0r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fokrd2kcbh1r0agnuhx0r.png" alt="Image description" width="800" height="208"&gt;&lt;/a&gt;&lt;br&gt;
Hi! In this article I will try to explain, step by step, how we can load an extension in a Google Chrome browser for test automation and then run our tests in headless mode using the &lt;strong&gt;WebdriverIO&lt;/strong&gt; framework. &lt;br&gt;
First, let's understand what headless mode means and why it could be beneficial for running automated tests on a Chrome extension. &lt;strong&gt;“Headless mode”&lt;/strong&gt; refers to executing a test with no graphical user interface (GUI), meaning that the browser works in the background, without displaying any windows or UI elements.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why would we want to execute tests this way?
&lt;/h2&gt;

&lt;p&gt;The principal reasons are speed, resource efficiency and compatibility. &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Speed&lt;/strong&gt;: Tests running in headless mode tend to be faster because the test-runner doesn’t have to waste time rendering the UI, it only focuses on executing test commands.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resource efficiency&lt;/strong&gt;: Given that UI elements don’t need to be rendered, tests running in headless mode tend to use fewer system resources like memory and CPU. This becomes particularly important when running several tests in parallel or on machines with limited resources. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compatibility&lt;/strong&gt;: Tests can behave differently in different browsers or environments. Headless mode can help mitigate this by providing a consistent testing environment across different platforms and browsers, since there is no UI rendering involved.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  How can we run automated tests in headless mode with a browser extension installed?
&lt;/h2&gt;

&lt;p&gt;Now that we understand the benefits of headless mode for test automation, let’s see how we can implement this approach when testing a Chrome extension with &lt;strong&gt;WebdriverIO&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;The first thing you will need is the &lt;code&gt;.dist&lt;/code&gt; folder containing the extension you want to test. This is a generated folder that normally contains files like a &lt;code&gt;background.js&lt;/code&gt;, &lt;code&gt;content.css&lt;/code&gt;, &lt;code&gt;content.js&lt;/code&gt;, &lt;code&gt;assets&lt;/code&gt;; and most importantly, a &lt;code&gt;manifest.json&lt;/code&gt; that has all the necessary parameters and values for launching the extension.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Once you obtain the &lt;code&gt;.dist&lt;/code&gt; folder, you can manually make sure that it works by opening a new Chrome instance, clicking on &lt;em&gt;&lt;strong&gt;Extensions -&amp;gt; Manage Extensions&lt;/strong&gt;&lt;/em&gt;, turning in the &lt;em&gt;&lt;strong&gt;Developer mode&lt;/strong&gt;&lt;/em&gt; toggle, clicking &lt;em&gt;&lt;strong&gt;Load unpacked&lt;/strong&gt;&lt;/em&gt; and selecting the &lt;code&gt;.dist&lt;/code&gt; folder. If the extension loads without any errors, then the &lt;code&gt;.dist&lt;/code&gt; folder is ready to be used for test automation.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Go to the &lt;strong&gt;WebdriverIO config file&lt;/strong&gt; from your project and edit the &lt;strong&gt;capabilities&lt;/strong&gt; section to look something like this:&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;capabilities: [
    {
        maxInstances: 1,
        browserName: "chrome",
        browserVersion: "stable",
        "goog:chromeOptions": {
            args: [
                "--load-extension=path/to/extension",
                "--disable-gpu",
                "--headless=new",
            ],
        },
    },
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For this to work, it’s important that you use the &lt;code&gt;--headless=new&lt;/code&gt; flag instead of the old &lt;code&gt;--headless&lt;/code&gt; one. For more information on how the &lt;code&gt;--headless=new&lt;/code&gt; command flag supports test automation of Chrome extensions, unlike the old one, refer to &lt;a href="https://developer.chrome.com/docs/chromium/new-headless#whats_new_in_headless"&gt;this&lt;/a&gt; &lt;em&gt;Chrome for Developers&lt;/em&gt; article.&lt;br&gt;
It is also important that you use the &lt;strong&gt;WDIO ChromeDriver Service&lt;/strong&gt; version &lt;strong&gt;8&lt;/strong&gt; or above for the supported &lt;code&gt;--headless=new&lt;/code&gt; command flag.&lt;/p&gt;

&lt;p&gt;That 's it! you’re now ready to run your tests in headless mode with your extension installed in your Chrome browser.&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>testing</category>
      <category>webdriverio</category>
      <category>extensions</category>
    </item>
  </channel>
</rss>
