<?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: TestCafe</title>
    <description>The latest articles on DEV Community by TestCafe (@dxtestcafe).</description>
    <link>https://dev.to/dxtestcafe</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%2F174074%2F1878df51-b015-4b39-bf26-57a30d98a29d.png</url>
      <title>DEV Community: TestCafe</title>
      <link>https://dev.to/dxtestcafe</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/dxtestcafe"/>
    <language>en</language>
    <item>
      <title>Randomize Your End-to-End Tests: How to Generate Input Data for TestCafe</title>
      <dc:creator>TestCafe</dc:creator>
      <pubDate>Wed, 13 Jan 2021 10:47:11 +0000</pubDate>
      <link>https://dev.to/dxtestcafe/randomize-your-end-to-end-tests-how-to-generate-input-data-for-testcafe-1fba</link>
      <guid>https://dev.to/dxtestcafe/randomize-your-end-to-end-tests-how-to-generate-input-data-for-testcafe-1fba</guid>
      <description>&lt;p&gt;User input can be truly unpredictable, so it's important to use a wide sample of random input data when testing web forms. In this article, we'll take a look at three Node libraries that generate data: &lt;a href="https://github.com/ai/nanoid"&gt;nanoid&lt;/a&gt;, &lt;a href="https://github.com/marak/Faker.js/"&gt;faker&lt;/a&gt;, and &lt;a href="https://github.com/brendanashworth/generate-password"&gt;generate-password&lt;/a&gt;. We'll see how TestCafe can leverage their features to help you improve your test coverage.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://github.com/Farfurix/Generating-input-data"&gt;farfurix/generating-input-data&lt;/a&gt; git repo contains the custom demo page and the test examples created specifically for this article. Clone the repository to follow along.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Basics (nanoid)
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://devexpress.github.io/testcafe/example/"&gt;This example page&lt;/a&gt; contains a text input field. We can use the &lt;code&gt;t.typeText&lt;/code&gt; method to populate it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Selector&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;testcafe&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="nx"&gt;fixture&lt;/span&gt; &lt;span class="s2"&gt;`Random Input Data: example 1`&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://devexpress.github.io/testcafe/example/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Generate a random name&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="nx"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;typeText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#developer-name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Developer Name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;Nanoid&lt;/code&gt; generates random strings when you call the &lt;code&gt;nanoid()&lt;/code&gt; method. We can call this method to randomize our input data.&lt;/p&gt;

&lt;p&gt;Import the &lt;code&gt;nanoid&lt;/code&gt; module in the beginning of the file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;nanoid&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;nanoid&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Declare a constant with a randomly generated name:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;randomDeveloperName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;testuser_&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;nanoid&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replace the &lt;code&gt;'Developer Name'&lt;/code&gt; string with the constant we just declared:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;typeText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#developer-name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;randomDeveloperName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now every time you run the test, the input value will be unique.&lt;/p&gt;

&lt;h2&gt;
  
  
  Input validation (faker, generate-password)
&lt;/h2&gt;

&lt;p&gt;Imagine a more complicated scenario: testing a sign-up form's ability to validate user passwords. We need to make sure that the password chosen by the user contains:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  At least eight symbols&lt;/li&gt;
&lt;li&gt;  At least one digit&lt;/li&gt;
&lt;li&gt;  A lowercase letter&lt;/li&gt;
&lt;li&gt;  An uppercase letter.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;First, we're going to need a valid email address to serve as our username. &lt;code&gt;Faker&lt;/code&gt; — a Node.js library that specializes in generating realistic-looking data, such as home addresses, business details, and emails — can help us. Import the library and call the &lt;code&gt;faker.internet.email()&lt;/code&gt; method to create a valid email address.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;faker&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;faker&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;validEmail&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;faker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;internet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;generate-password&lt;/code&gt; library will give us the passwords we need. We can set password requirements by passing arguments to the generate method of the generator object. Let's import the library:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;generator&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;generate-password&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We're ready to create an array of random, yet valid, passwords. The &lt;code&gt;faker&lt;/code&gt; library will, once again, prove itself useful — this time, it will help us determine the password length.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;validPasswords&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;newRandomPassword&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;generator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;faker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;random&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;min&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;max&lt;/span&gt;&lt;span class="dl"&gt;'&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;// 10-20 characters long&lt;/span&gt;
            &lt;span class="na"&gt;numbers&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="na"&gt;uppercase&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="na"&gt;lowercase&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="na"&gt;strict&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="nx"&gt;validPasswords&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newRandomPassword&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;It's just as easy to generate invalid credentials. Let's use the &lt;code&gt;generateMultiple&lt;/code&gt; method to generate invalid passwords of varying length:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;    &lt;span class="c1"&gt;// These passwords are too short&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;shortPasswords&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;generator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;generateMultiple&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;numbers&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="na"&gt;strict&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="c1"&gt;// These passwords lack uppercase characters&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;passwordsWithoutUppercase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;generator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;generateMultiple&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;numbers&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="na"&gt;uppercase&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;strict&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="c1"&gt;// These passwords lack lowercase characters&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;passwordsWithoutLowercase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;generator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;generateMultiple&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;numbers&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="na"&gt;lowercase&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;strict&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="c1"&gt;// These passwords lack digits&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;passwordsWithoutDigits&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;generator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;generateMultiple&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;strict&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;invalidPasswords&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;shortPasswords&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;passwordsWithoutUppercase&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;passwordsWithoutLowercase&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;passwordsWithoutDigits&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that we have our fake credentials, we can test the web form.&lt;/p&gt;

&lt;p&gt;The first test will feed the form valid passwords. To do this, let's iterate over the &lt;code&gt;validPasswords&lt;/code&gt; array and enter the data it contains into the form. A confirmation of the password's validity should appear every time we click the &lt;code&gt;#submit&lt;/code&gt; button.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;    &lt;span class="nx"&gt;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;Successful password validation&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="nx"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;validPassword&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;validPasswords&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;t&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;typeText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#email&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;validEmail&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;replace&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="nx"&gt;typeText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#password&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;validPassword&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;replace&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="nx"&gt;click&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#submit&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;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Selector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#password-status&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;eql&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Valid password with a length of &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;validPassword&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The second test will iterate over the &lt;code&gt;invalidPasswords&lt;/code&gt; array. The main difference between this test and the previous is the content of the password status message. The message should read: "Invalid password".&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;    &lt;span class="nx"&gt;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;Invalid password warning&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="nx"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;invalidPassword&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;invalidPasswords&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;t&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;typeText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#email&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;validEmail&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;replace&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="nx"&gt;typeText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#password&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;invalidPassword&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;replace&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="nx"&gt;click&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;submit&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Selector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#password-status&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;eql&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Invalid password&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;a href="https://github.com/Farfurix/Generating-input-data"&gt;farfurix/generating-input-data&lt;/a&gt; git repo contains full versions of the examples above, as well as a demo page to run these tests against.&lt;/p&gt;

&lt;p&gt;As we just demonstrated, it's easy to use third-party data generators in conjunction with TestCafe to randomize your tests' user input. Just remember: not all data generators are created equal. Select one based on your website's unique needs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Related Topics:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://devexpress.github.io/testcafe/documentation/guides/advanced-guides/intercept-http-requests.html"&gt;Intercept HTTP Requests&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://devexpress.github.io/testcafe/documentation/guides/basic-guides/obtain-client-side-info.html"&gt;Obtain Client-Side Info&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://devexpress.github.io/testcafe/documentation/guides/basic-guides/interact-with-the-page.html"&gt;Interact with the Page&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>testing</category>
      <category>javascript</category>
      <category>framework</category>
    </item>
    <item>
      <title>Client Functions and Script Injection for Page Interaction</title>
      <dc:creator>TestCafe</dc:creator>
      <pubDate>Mon, 23 Nov 2020 18:00:14 +0000</pubDate>
      <link>https://dev.to/dxtestcafe/client-functions-and-script-injection-for-page-interaction-35g8</link>
      <guid>https://dev.to/dxtestcafe/client-functions-and-script-injection-for-page-interaction-35g8</guid>
      <description>&lt;p&gt;&lt;em&gt;You will learn how to run custom JavaScript code on the tested pages, how to use objects like the page model in this code, how to wait for an arbitrary event in the browser, and the fastest way to run a one-liner or an entire JS module.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;End-to-end tests emulate how users interact with the application. In theory, this interaction consists of simple actions like a mouse click on an element, a key press, drag-and-drop, or file upload. The TestCafe API allows you to perform these basic actions with a single line of code. However, real-world applications tend to be more complicated than a static entry form. Some applications cannot be tested without closer interaction with tested pages. In this article, we review several examples and show how knowledge of TestCafe's internal architecture allows you to test complex or poorly designed pages with the help of client functions and script injection.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use Client Functions to Run Code in the Browser
&lt;/h2&gt;

&lt;p&gt;Let's assume you need to click an element, but another element on the same page overlaps the first one due to design or implementation choices. If you simply call &lt;a href="https://devexpress.github.io/testcafe/documentation/reference/test-api/testcontroller/click.html"&gt;t.click&lt;/a&gt;, TestCafe waits for the target element to appear in the foreground. When a predefined timeout expires, TestCafe will eventually click the overlapping element. If the test author intended this click, the test completes successfully. However, the entire timeout period is wasted on aimless waiting. You can hide the overlapping element and avoid this pause if you run the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;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;Hide element&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="nx"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;hideElement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ClientFunction&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="err"&gt;        &lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;display&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;none&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="err"&gt;    &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; 
&lt;span class="err"&gt;    &lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;hideElement&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; 
&lt;span class="err"&gt;    &lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Selector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;visible&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;notOk&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You may also want to update that code and store the element ID in a variable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;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;Hide element&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="nx"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt;   &lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;elementId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="err"&gt;   &lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;hideElement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ClientFunction&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="err"&gt;       &lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;elementId&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;display&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;none&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="err"&gt;   &lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; 
&lt;span class="err"&gt;   &lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;hideElement&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; 
&lt;span class="err"&gt;   &lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Selector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;elementId&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;visible&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;notOk&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;A variable is a good idea and it can be used, but not in this manner. The test above would fail with an error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;My Fixture
 × Hide element
   1) An error occurred in ClientFunction code:
      ReferenceError: elementId is not defined
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On the surface, your JavaScript programming experience may tell you that the test is fine. Let's look into TestCafe's underlying mechanisms in greater detail to see why the test fails.&lt;/p&gt;

&lt;h3&gt;
  
  
  Under the Hood
&lt;/h3&gt;

&lt;p&gt;The TestCafe framework is based on a client-server architecture. The test code runs in a Node.js process (server) and uses a proxy server to interact with the browser (client).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--DtoZjQfQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/jawze08ch9cjajq3d5c8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--DtoZjQfQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/jawze08ch9cjajq3d5c8.png" alt="TestCafe's client-server architecture"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Considering this fact, you can expect that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The test code has no direct access to the browser context.&lt;/li&gt;
&lt;li&gt;TestCafe interacts with the browser asynchronously (which is why missing &lt;code&gt;await&lt;/code&gt; issues are often posted in GitHub and StackOverflow).&lt;/li&gt;
&lt;li&gt;The server-side TestCafe process and the client-side browser can only exchange serialized data.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We can simplify TestCafe's client-server interactions as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;On the server, the TestCafe API exposes methods that execute actions and user code in the browser. When the API is triggered, TestCafe creates commands and passes them to the proxy: TestCafe Hammerhead.
&lt;/li&gt;
&lt;li&gt;TestCafe Hammerhead transmits commands from the server to the browser and sends back the results when they are ready.&lt;/li&gt;
&lt;li&gt;On the client, TestCafe scripts receive these commands and execute them in the same way the browser handles user actions.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Pass Variables to Client Functions
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;Create parameterized functions or use page model properties on the client side.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Let's get back to our code that tries and fails to introduce a variable.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;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;Hide element&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="nx"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt;   &lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;elementId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt; 
&lt;span class="err"&gt;   &lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;hideElement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ClientFunction&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="err"&gt;       &lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;elementId&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;display&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;none&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="err"&gt;   &lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; 
&lt;span class="err"&gt;   &lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;hideElement&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; 
&lt;span class="err"&gt;   &lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Selector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;elementId&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;visible&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;notOk&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This function has to be executed in the browser. As we mentioned earlier, only serialized data can travel between the client and the server. This is why TestCafe serializes this function (i.e., converts it to a string). This string is then evaluated when received on the browser side. You can now see why closures do not work for client functions.&lt;/p&gt;

&lt;p&gt;What's the solution then? Before TestCafe converts the function to a string, a separate serializer module processes arguments passed to &lt;code&gt;ClientFunction()&lt;/code&gt;. This is the same module that serializes all data that travel between the client and the server. This means that you can easily pass parameters to the client function and they arrive safely.&lt;/p&gt;

&lt;p&gt;In addition, you can also find the &lt;code&gt;dependencies&lt;/code&gt; property among the options that can be passed to the &lt;a href="https://devexpress.github.io/testcafe/documentation/reference/test-api/clientfunction/constructor.html"&gt;ClientFunction&lt;/a&gt; constructor.&lt;/p&gt;

&lt;p&gt;TestCafe offers two options to access variables declared in test code.&lt;/p&gt;

&lt;p&gt;The first option is to pass the variable as an argument:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;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;Hide element&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="nx"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt;   &lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;elementId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; 
&lt;span class="err"&gt;   &lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;hideElement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ClientFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;targetId&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt;       &lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;targetId&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;display&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;none&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="err"&gt;   &lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; 
&lt;span class="err"&gt;   &lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;hideElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;elementId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; 
&lt;span class="err"&gt;   &lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Selector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;elementId&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;visible&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;notOk&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But what if the element has no ID, so that it's not easy to find in the DOM tree? The second option is to pass a selector to the client function. Use the &lt;code&gt;dependencies&lt;/code&gt; option in the &lt;a href="https://devexpress.github.io/testcafe/documentation/reference/test-api/clientfunction/constructor.html"&gt;ClientFunction&lt;/a&gt; constructor:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;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;Hide element&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="nx"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt;   &lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;elementSelector&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Selector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#populate&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; 
&lt;span class="err"&gt;   &lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;hideElement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ClientFunction&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="err"&gt;       &lt;/span&gt; &lt;span class="nx"&gt;elementSelector&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;display&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;none&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="err"&gt;   &lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;dependencies&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;elementSelector&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; 
&lt;span class="err"&gt;   &lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;hideElement&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; 
&lt;span class="err"&gt;   &lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;elementSelector&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;visible&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;notOk&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 client functions and selectors have a lot in common. Methods that create and run selectors derive from similar methods of client functions. To execute a complex selector query, you can pass a function to the &lt;a href="https://devexpress.github.io/testcafe/documentation/reference/test-api/selector/constructor.html"&gt;Selector&lt;/a&gt; constructor, as you do for client functions. The main difference between them is the return type. Selectors should return &lt;code&gt;DOMNode&lt;/code&gt;, while client functions should return any serializable value, or a Promise that resolves to such value.&lt;/p&gt;

&lt;h3&gt;
  
  
  Wait for a Custom Condition
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;You can specify when TestCafe considers a page loaded.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Now let's see why you may want a client function to return a Promise.&lt;/p&gt;

&lt;p&gt;TestCafe is designed to wait for the &lt;code&gt;DOMContentLoaded&lt;/code&gt; and &lt;code&gt;load&lt;/code&gt; events, as well as XHR requests (allowing three seconds for the latter), before tests begin. In rare instances, the wait time may be over before all scripts on the page are initialized. The following client function pauses the test until a custom condition is fulfilled (you can replace it with your own script completion indicator).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;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;Wait for scripts&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="nx"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt;   &lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;waitForScripts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ClientFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;waitTimeout&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt;       &lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;checkCondition&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// Replace this line with a custom condition.&lt;/span&gt;
&lt;span class="err"&gt;           &lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="err"&gt;       &lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="err"&gt;       &lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&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="err"&gt;           &lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="err"&gt;           &lt;/span&gt; &lt;span class="nx"&gt;timeout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;setTimeout&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="err"&gt;               &lt;/span&gt; &lt;span class="nx"&gt;clearInterval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="err"&gt;               &lt;/span&gt; &lt;span class="nx"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Timeout is exceeded.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="err"&gt;           &lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;waitTimeout&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="err"&gt;           &lt;/span&gt; &lt;span class="nx"&gt;interval&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;setInterval&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="err"&gt;               &lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;checkCondition&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt;                   &lt;/span&gt; &lt;span class="nx"&gt;clearTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="err"&gt;                   &lt;/span&gt; &lt;span class="nx"&gt;clearInterval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="err"&gt;                   &lt;/span&gt; &lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="err"&gt;               &lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="err"&gt;           &lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="err"&gt;       &lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="err"&gt;   &lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="err"&gt;   &lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;waitForScripts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2000&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;Even if a browser does not support Promises, this client function still works because TestCafe automatically adds the necessary polyfills when it processes this code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Inject Scripts to Add Code Permanently
&lt;/h2&gt;

&lt;p&gt;Client functions are useful to interact with the tested page when necessary. You can even run a client function without saving it to a variable. However, everything you change in this function on the tested page is reverted once a redirect or page reload occurs. To modify the page permanently, inject client scripts into the tested page. The injected scripts are added to the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; tag.&lt;/p&gt;

&lt;h3&gt;
  
  
  Scripts that Persist Throughout Testing
&lt;/h3&gt;

&lt;p&gt;Should you need to hide a banner, or modify an attribute for some element, you can organize client code that does it in a separate file:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;script.js&lt;/strong&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="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;DOMContentLoaded&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;your-selector&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="err"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;foo-bar&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;baz&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, use your favorite API to attach this file in all tests (which eliminates repetitive &lt;a href="https://devexpress.github.io/testcafe/documentation/reference/test-api/fixture/beforeeach.html"&gt;beforeEach&lt;/a&gt; hooks):&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Command Line Interface&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;testcafe chrome test.js &lt;span class="nt"&gt;--client-scripts&lt;/span&gt; script.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;API&lt;/em&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="nx"&gt;runner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clientScripts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;script.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Configuration file&lt;/em&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;  
    &lt;/span&gt;&lt;span class="nl"&gt;"clientScripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"script.js"&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;h3&gt;
  
  
  Injected Scripts Run First
&lt;/h3&gt;

&lt;p&gt;TestCafe adds the injected scripts to its automation code, so that they run before any other script on the page. You can therefore use injected scripts to alter the page behavior. For instance, you can override the &lt;code&gt;window.open&lt;/code&gt; method for all tests as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="nx"&gt;mockWindowOpen&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;window.open = function () { };&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;fixture&lt;/span&gt;&lt;span class="s2"&gt;`My App`&lt;/span&gt;
&lt;span class="err"&gt;    &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="s2"&gt;`https://devexpress.github.io/testcafe/example/`&lt;/span&gt;
&lt;span class="err"&gt;    &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clientScripts&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="nx"&gt;mockWindowOpen&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;My test 1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* ... */&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;My test 2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* ... */&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your code remains almost unchanged. TestCafe only wraps it to catch exceptions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Checking Other &amp;lt;head&amp;gt; Scripts for Errors
&lt;/h3&gt;

&lt;p&gt;Due to their location inside the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; tags, injected scripts also allow you to access information that is not obtainable by other means.&lt;/p&gt;

&lt;p&gt;Consider a scenario where you need to obtain unhandled exceptions thrown in another script in the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; section. The TestCafe API contains the &lt;a href="https://devexpress.github.io/testcafe/documentation/reference/test-api/testcontroller/getbrowserconsolemessages.html"&gt;t.getBrowserConsoleMessages&lt;/a&gt; method that returns messages printed in the console. However, this method can only access messages posted by the &lt;code&gt;console.log&lt;/code&gt;, &lt;code&gt;console.warn&lt;/code&gt;, and &lt;code&gt;console.error&lt;/code&gt; methods in page code. The &lt;a href="https://devexpress.github.io/testcafe/documentation/reference/test-api/testcontroller/getbrowserconsolemessages.html"&gt;t.getBrowserConsoleMessages&lt;/a&gt; method does not fetch errors thrown by the browser. You could try to use a client function to catch the exception, but client functions are executed after all &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; scripts are completed.&lt;/p&gt;

&lt;p&gt;With script injection, you can add the following code:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;script.js&lt;/strong&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="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;unhandledErrors&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onerror&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;unhandledErrors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In test code, you can create a client function to access messages in &lt;code&gt;window.unhandledErrors&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="nx"&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;Get Unhandled Errors&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="nx"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="nx"&gt;errors&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;eval&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;unhandledErrors&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nx"&gt;clientScripts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;script.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;Client functions and script injection extend TestCafe's capabilities so that you can interact with the page directly. These features can configure your application at low levels to prepare it for testing, or fetch data about its execution in a custom manner. You can think of even more ways to use client functions and injected scripts. We hope this brief overview of the TestCafe architecture and sample usage scenarios help improve your understanding of these tools so that you can use them more effectively.&lt;/p&gt;

&lt;h2&gt;
  
  
  Related Topics
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://devexpress.github.io/testcafe/documentation/guides/advanced-guides/inject-client-scripts.html"&gt;Inject Client Scripts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://devexpress.github.io/testcafe/documentation/guides/basic-guides/obtain-client-side-info.html"&gt;Obtain Client-Side Info&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://devexpress.github.io/testcafe/documentation/guides/basic-guides/select-page-elements.html"&gt;Select Page Elements&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>testing</category>
      <category>testautomation</category>
      <category>webdev</category>
      <category>testcafe</category>
    </item>
    <item>
      <title>The Fastest Way to Your Next Test – TestCafe + TestCafe Studio - Q&amp;A's</title>
      <dc:creator>TestCafe</dc:creator>
      <pubDate>Thu, 24 Sep 2020 17:10:24 +0000</pubDate>
      <link>https://dev.to/dxtestcafe/the-fastest-way-to-your-next-test-testcafe-testcafe-studio-q-a-s-3f0b</link>
      <guid>https://dev.to/dxtestcafe/the-fastest-way-to-your-next-test-testcafe-testcafe-studio-q-a-s-3f0b</guid>
      <description>&lt;p&gt;Thank you to all that attended the recent &lt;a href="https://www.devexpress.com/products/testcafestudio/"&gt;TestCafe Studio&lt;/a&gt; presentation, the questions raised have been answered by the team and listed below.&lt;/p&gt;

&lt;h2&gt;
  
  
  Watch the Webinar
&lt;/h2&gt;

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

&lt;h2&gt;
  
  
  Questions &amp;amp; Answers
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Will the webinar recording on YouTube include the Q&amp;amp;A section?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
We discussed the most popular Q&amp;amp;As at the end of the webinar. This part is included in the &lt;a href="https://youtu.be/3ZsYj1my-us?t=3216"&gt;recording&lt;/a&gt;. The remaining questions are answered in this post.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I test Windows Form applications with TestCafe Studio?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
TestCafe Studio can test web applications only.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Am I allowed to install TestCafe Studio on our customer's site to test it in their environment?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
TestCafe Studio is a desktop application installed on a developer's/tester's local computer, not on a website. You can install TestCafe Studio on any Windows, macOS, or Linux machine. If the machine where TestCafe Studio runs can access the website deployed on your customer's infrastructure, you can simply specify its URL to test it in its native environment.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does TestCafe Studio support multiple languages?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
The TestCafe Studio UI only supports English. If you are asking about programming languages in which you can write tests, TestCafe Studio supports JavaScript, TypeScript, CoffeeScript, and of course tests recorded in TestCafe Studio (&lt;code&gt;*.testcafe&lt;/code&gt; files).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I include TestCafe Studio in Continuous Integration?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
You can use the open-source TestCafe to run tests recorded or written in TestCafe Studio in CI systems. See the &lt;a href="https://docs.devexpress.com/TestCafeStudio/400445/guides/integrate-tests-with-ci-systems"&gt;Integrate Tests with CI Systems&lt;/a&gt; topic for more information.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What value does TestCafe Studio add to an automated CI pipeline in which tests are executed in headless mode?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
TestCafe Studio allows you to create and modify tests with ease. In a CI system, the tests will run with an open-source TestCafe runner that doesn't make any difference between TestCafe Studio recorded tests and JavaScript TestCafe tests. See the &lt;a href="https://docs.devexpress.com/TestCafeStudio/400445/guides/integrate-tests-with-ci-systems"&gt;Integrate Tests with CI Systems&lt;/a&gt; topic for more information. So, TestCafe Studio's goal is to facilitate recording and maintenance.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is there a way to record tests in TestCafe Studio and export them to JavaScript to run individually?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Yes, you can do this. See the &lt;a href="https://docs.devexpress.com/TestCafeStudio/401052/test-directory-structure/test-scripts#convert-recorded-tests-to-javascript"&gt;Convert Recorded Tests to JavaScript&lt;/a&gt; topic for more information.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does TestCafe Studio have any known issues with SPA apps, specifically Angular?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
No, we are not aware of any significant issues with SPAs including Angular applications. You can also make use of the following selector extension that enables you to test Angular applications even easier: &lt;a href="https://github.com/DevExpress/testcafe-angular-selectors"&gt;DevExpress/testcafe-angular-selectors&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Are there any recommendations on the best method for initializing a selector?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
We plan to publish an article that details the best practices for TestCafe tests, including suggestions on how to build effective selectors. In the meantime, refer to the &lt;a href="https://docs.devexpress.com/TestCafeStudio/400407/test-actions/element-selectors"&gt;Element Selectors&lt;/a&gt; topic to learn more about them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does the open-source TestCafe have the reporting and screen capturing capabilities?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Yes, it has both. See the &lt;a href="https://devexpress.github.io/testcafe/documentation/guides/concepts/reporters.html"&gt;Reporters&lt;/a&gt; and &lt;a href="https://devexpress.github.io/testcafe/documentation/guides/advanced-guides/screenshots-and-videos.html"&gt;Screenshots and Videos&lt;/a&gt; topics for details.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I test "concurrent" scenarios where two users use the app and modify the data simultaneously?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
To simulate users interacting with the app concurrently, you need two browser windows. Support for multiple browser windows is currently available in beta for coded tests only. See the details in the open-source TestCafe documentation: &lt;a href="https://devexpress.github.io/testcafe/documentation/guides/advanced-guides/multiple-browser-windows.html"&gt;Multiple Browser Windows&lt;/a&gt;. As an alternative solution, you can try running the same test that edits a data record in different browsers at the same time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I run tests at specific moments in time, e.g. on schedule?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
You can &lt;a href="https://docs.devexpress.com/TestCafeStudio/400445/guides/integrate-tests-with-ci-systems"&gt;integrate your test with any CI service&lt;/a&gt; to run them on schedule.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I receive an email notification with test results once they are done?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
You can &lt;a href="https://docs.devexpress.com/TestCafeStudio/400187/user-interface/report-view#get-more-report-formats"&gt;search for a TestCafe reporter&lt;/a&gt; that sends an email with test run results or &lt;a href="https://devexpress.github.io/testcafe/documentation/guides/extend-testcafe/reporter-plugin.html#generate-a-reporter-project"&gt;create a new custom reporter&lt;/a&gt; for your needs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I deliberately slow down the test run in TestCafe Studio for more convenient viewing?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Yes, you can adjust &lt;a href="https://docs.devexpress.com/TestCafeStudio/400179/guides/debug-tests#test-speed"&gt;the Speed option&lt;/a&gt; to slow down test execution.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do you use the GUI to create a custom attribute for a webpage?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
You can customize &lt;a href="https://docs.devexpress.com/TestCafeStudio/400186/user-interface/record-configuration-dialog#selector-generation"&gt;the selector generation mechanism&lt;/a&gt; to take into account custom attributes. Add a custom attribute name to the list of selector types. TestCafe Studio will then use this attribute to create selectors. On your website end, you should specify the custom attribute for page elements manually.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is it possible to write a text assertion with wildcards in it, so that it matches multiple text values?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Yes, you can use regular expressions for this purpose: &lt;a href="https://docs.devexpress.com/TestCafeStudio/400167/test-actions/assertions#match"&gt;Match Assertion&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is it possible to load user credentials from a file to use them in tests?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
You can use &lt;a href="https://docs.devexpress.com/TestCafeStudio/401265/test-actions/custom-scripts"&gt;the Run TestCafe Script action&lt;/a&gt;. Write a script that imports &lt;a href="https://nodejs.org/api/fs.html"&gt;the fs Node.js module&lt;/a&gt;, reads the file content and saves the credentials in &lt;a href="https://docs.devexpress.com/TestCafeStudio/401265/test-actions/custom-scripts#script-context"&gt;the test context&lt;/a&gt;. Now you can read these values from &lt;code&gt;t.ctx&lt;/code&gt; in other scripts within Run TestCafe Script actions. Currently, you cannot pass the test context to recorded action parameters.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I create variables to store secrets or URLs for different environments?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
TestCafe Studio can save &lt;a href="https://docs.devexpress.com/TestCafeStudio/400401/test-actions/statements"&gt;selectors and functions&lt;/a&gt; to variables. In &lt;a href="https://docs.devexpress.com/TestCafeStudio/401265/test-actions/custom-scripts"&gt;Run TestCafe Script action&lt;/a&gt; code, you can create other types of variables and use them according to your needs. To share variables between different scripts, store them in &lt;a href="https://docs.devexpress.com/TestCafeStudio/401265/test-actions/custom-scripts#script-context"&gt;the test context&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I use conditions, add conditional jumps or go-to statements?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
In recorded tests, you cannot use conditions and go-to statements. You can record test scenarios and then &lt;a href="https://docs.devexpress.com/TestCafeStudio/401052/test-directory-structure/test-scripts#convert-recorded-tests-to-javascript"&gt;convert them to JavaScript&lt;/a&gt; to add conditions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How to organize tests in TestCafe Studio? How can I tag Smoke and Regression tests to distinguish between them? I tried metadata but found it ineffective. Is there an alternative way in TestCafe Studio?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
This is no such capability built in so far. You can split your tests across different directories or &lt;a href="https://docs.devexpress.com/TestCafeStudio/401052/test-directory-structure/test-scripts#convert-recorded-tests-to-javascript"&gt;convert the recorded tests into JavaScript&lt;/a&gt; and &lt;a href="https://devexpress.github.io/testcafe/documentation/guides/basic-guides/organize-tests.html#specify-test-metadata"&gt;use metadata&lt;/a&gt; with the open-source TestCafe test runner.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I use data from external sources (text files or databases) in my tests?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Yes, but not in the Test Editor UI. If you &lt;a href="https://docs.devexpress.com/TestCafeStudio/401052/test-directory-structure/test-scripts#convert-recorded-tests-to-javascript"&gt;convert the recorded tests into JavaScript&lt;/a&gt;, you can use any Node.js or npm module to read data from your files or load from a database to use it in your test cases.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How can I ensure temporary objects that pop up briefly after a button is pushed or the mouse hovers over something are displayed? The display doesn't last long enough for me to click on it after activating the "=" assertion.&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
In recoded tests, you can add &lt;a href="https://docs.devexpress.com/TestCafeStudio/400401/test-actions/statements#define-function"&gt;the Define Function action&lt;/a&gt; that checks if the target element exists every &lt;code&gt;n&lt;/code&gt; milliseconds and returns the result when the element is found (you can use a &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise"&gt;Promise&lt;/a&gt;). Then add an action for click. After that, use the client function's return value in an assertion.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How would I test visuals that indicate drag-and-drop, since that visuals only exist while you are actively dragging?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
TestCafe cannot execute an assertion while you are dragging. We may suggest a multi-step workaround where you &lt;a href="https://devexpress.github.io/testcafe/documentation/guides/advanced-guides/inject-client-scripts.html"&gt;inject&lt;/a&gt; client-side code that is triggered during the drag, checks for the visuals, and stores the result. When drag is finished, you can obtain this value &lt;a href="https://devexpress.github.io/testcafe/documentation/guides/basic-guides/obtain-client-side-info.html"&gt;via a client function&lt;/a&gt; and &lt;a href="https://devexpress.github.io/testcafe/documentation/guides/basic-guides/assert.html"&gt;verify it in an assertion&lt;/a&gt;. For manual verification, you can use the open-source TestCafe to &lt;a href="https://devexpress.github.io/testcafe/documentation/guides/advanced-guides/screenshots-and-videos.html#record-videos"&gt;record a video of a test run&lt;/a&gt; to ensure that the drag-and-drop indicator is displayed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do I run the same test against my app versions deployed in different environments (at different URLs), e.g., FAT/UAT/production?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
In coded tests, you can &lt;a href="https://devexpress.github.io/testcafe/faq/#how-do-i-work-with-configuration-files-and-environment-variables"&gt;specify the test's start page programmatically&lt;/a&gt;. To test multiple versions of your app with the same test suite, start the tests as many times as you need while passing a different URL each time.&lt;/p&gt;

&lt;p&gt;In recorded tests, you can use the same approach, but instead of setting the start page (which is not possible programmatically), begin tests with &lt;a href="https://docs.devexpress.com/TestCafeStudio/401265/test-actions/custom-scripts"&gt;a custom script&lt;/a&gt; that accesses the passed URL and navigates to the required page with the &lt;a href="https://devexpress.github.io/testcafe/documentation/reference/test-api/testcontroller/navigateto.html"&gt;t.navigateTo&lt;/a&gt; method.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can variables be parameterized?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Currently, you cannot use parameters for recorded test steps but you can write any custom code in &lt;a href="https://docs.devexpress.com/TestCafeStudio/401265/test-actions/custom-scripts"&gt;the Run TestCafe Script action&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can the JS scripts act as a REST client to obtain assertion values (via a service call to a helper endpoint)?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Yes, you can use a Node.js HTTP client like &lt;a href="https://www.npmjs.com/package/got"&gt;got&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In our tests, selectors throw errors occasionally. How can we get rid of this irregular behavior?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Let us know how we can replicate this behavior. &lt;a href="https://devexpress.com/ask"&gt;Please submit an issue in the Support Center&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I record accessibility tests with TestCafe Studio?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
No, but you can use &lt;a href="https://www.npmjs.com/package/axe-testcafe"&gt;axe-testcafe&lt;/a&gt; in coded tests for accessibility testing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do I integrate TestCafe reports with Xray?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Check out the following custom reporter plug-in for Xray: &lt;a href="https://github.com/antreyes/testcafe-reporter-xray"&gt;antreyes/testcafe-reporter-xray&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can you show an example of a much more complex real-life test?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
We publish TestCafe examples in this GitHub repository: &lt;a href="https://github.com/DevExpress/testcafe-examples"&gt;DevExpress/testcafe-examples&lt;/a&gt;. You can find both basic examples as well as samples that address some rare scenarios.&lt;/p&gt;

&lt;p&gt;However, you wouldn't find a really complex test among our examples because it's not good practice to overengineer end-to-end tests. After all, we created TestCafe to keep your tests simple.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can you please show an example with the DevExpress Grid Control?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
DevExpress Grid Controls can be easily tested with TestCafe like any other web control/page. You can try to record your own test on &lt;a href="https://js.devexpress.com/Demos/WidgetsGallery/Demo/DataGrid/Overview/jQuery/Light/"&gt;JS Grid demo pages&lt;/a&gt; with TestCafe Studio.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Will TestCafe be able to generate tests in other languages, like C#, or using Selenium API, etc?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Not in the nearest future.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do you offer a testing framework for desktop applications (specifically, .NET)?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Yes, we offer &lt;a href="https://www.devexpress.com/products/net/controls/winforms/coded-ui/"&gt;Coded UI&lt;/a&gt; for WinForms applications.&lt;/p&gt;

</description>
      <category>testing</category>
      <category>webinar</category>
      <category>testcafe</category>
      <category>e2e</category>
    </item>
    <item>
      <title>How TestCafe Can Help You to Deliver Faster</title>
      <dc:creator>TestCafe</dc:creator>
      <pubDate>Thu, 17 Sep 2020 15:51:10 +0000</pubDate>
      <link>https://dev.to/dxtestcafe/how-testcafe-can-help-you-to-deliver-faster-2oei</link>
      <guid>https://dev.to/dxtestcafe/how-testcafe-can-help-you-to-deliver-faster-2oei</guid>
      <description>&lt;p&gt;DevOps teams must make certain that applications ship on time and meet appropriate quality standards. To achieve the latter objective, DevOps must carefully consider what checks to include in the pipeline and what to leave as smoke tests. In this brief article, we argue that end-to-end tests are crucial to product quality and are worth running each time an organization delivers a build. We will illustrate how TestCafe can streamline this process and help you integrate end-to-end tests into your CI/CD workflow with minimum time and effort.&lt;/p&gt;

&lt;h2&gt;
  
  
  Unit Tests are not Enough
&lt;/h2&gt;

&lt;p&gt;As you know, some organizations/dev teams require use of unit tests. Unit tests allow developers to verify whether "small" portions of a solution work as intended, but do so &lt;strong&gt;independent of the whole&lt;/strong&gt;. While it may be tempting to use green unit tests as the prime delivery condition within a CI/CD system, unit tests will always remain granular and limited in scope.&lt;/p&gt;

&lt;p&gt;Unit tests allow developers to flag problematic code modifications, but unit tests cannot accurately determine whether all parts of a given system are working &lt;strong&gt;together flawlessly&lt;/strong&gt;.  Said differently, unit tests cannot establish whether all usage scenarios are fully tested and meet an organization's quality standards.&lt;/p&gt;

&lt;p&gt;By contrast, end-to-end tests can check/analyze whether the entire system operates as expected (the whole and not just its parts). End-to-end tests can emulate user actions and determine whether real output matches expected outcomes. Unit tests are important, but we believe that only end-to-end test automation can deliver the reliability users have come to expect from today's top software organizations.&lt;/p&gt;

&lt;h2&gt;
  
  
  TestCafe – End-to-End Testing Made Easy
&lt;/h2&gt;

&lt;p&gt;TestCafe is an enterprise-ready end-to-end testing framework with an intuitive API. Unlike legacy frameworks such as Selenium, TestCafe is easy to install, run, and integrate within an organization's CI/CD pipeline. You can install the framework via npm with a single command. Since TestCafe does not require tedious configuration or plugins, it can be wound up in a new CI system within minutes. And yes, with TestCafe, you do not need to locate, install, and configure additional testing software/modules. TestCafe is self-contained and only requires Node.js and your preferred browser (no browser plugins are needed).&lt;/p&gt;

&lt;p&gt;In addition, TestCafe allows you to test next-gen web features with absolute ease. TestCafe supports all major modern browsers (either locally or cloud-based) – across a variety of mobile or desktop devices. TestCafe can execute its tests on macOS, Windows, Linux, iOS, and Android. You can use Chrome, Firefox, Safari, Edge and Internet Explorer when and where appropriate – you can even use headless browsers (a great way to decrease testing time and to execute browser tests on VMs with no graphical system).&lt;/p&gt;

&lt;p&gt;As you'll see below, we've taken care of everything under the hood so you and your team can avoid configuration hassles and the steep learning curve associated with legacy testing frameworks.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Integrate TestCafe in Your CI/CD
&lt;/h2&gt;

&lt;p&gt;TestCafe can be incorporated into a pipeline with a few simple steps:  &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Install Node.js&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Install TestCafe&lt;/strong&gt;. As mentioned earlier, TestCafe can be installed with a simple command: &lt;code&gt;npm install -g testcafe&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Run TestCafe tests&lt;/strong&gt;. Only a single command is required to execute a test (for instance: &lt;code&gt;testcafe chrome:headless ./tests&lt;/code&gt;). With this simple command, TestCafe will auto detect the browser (if installed), launch it, and run your tests automatically.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;TestCafe ships with five reporters – modules that can generate test execution reports for your CI/CD. JSON, JUnit, xUnit, and console output (with rich formatting) are built-in. You can also use reporters developed by the TestCafe user community for &lt;a href="https://www.npmjs.com/package/testcafe-reporter-nunit"&gt;NUnit&lt;/a&gt;, &lt;a href="https://www.npmjs.com/package/testcafe-reporter-teamcity"&gt;TeamCity&lt;/a&gt;, &lt;a href="https://www.npmjs.com/package/testcafe-reporter-slack"&gt;Slack&lt;/a&gt;, etc. Should you require these community plugins, you can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Install the desired third-party reporter via npm: &lt;code&gt;npm install testcafe testcafe-reporter-nunit&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;Run TestCafe tests much like step 3: &lt;code&gt;testcafe chrome:headless ./tests -r nunit:report.xml&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can learn more and about TestCafe and CI system integration via the following links:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://devexpress.github.io/testcafe/documentation/guides/continuous-integration/jenkins.html"&gt;Jenkins&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://devexpress.github.io/testcafe/documentation/guides/continuous-integration/github-actions.html"&gt;GitHub Actions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://devexpress.github.io/testcafe/documentation/guides/continuous-integration/travis.html"&gt;Travis&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://devexpress.github.io/testcafe/documentation/guides/continuous-integration/circleci.html"&gt;CircleCI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://devexpress.github.io/testcafe/documentation/guides/continuous-integration/teamcity.html"&gt;TeamCity&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://devexpress.github.io/testcafe/documentation/guides/continuous-integration/gitlab.html"&gt;GitLab&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://devexpress.github.io/testcafe/documentation/guides/continuous-integration/azure-devops.html"&gt;Azure DevOps&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://devexpress.github.io/testcafe/documentation/guides/continuous-integration/bitbucket-pipelines.html"&gt;BitBucket Pipelines&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://devexpress.github.io/testcafe/documentation/guides/continuous-integration/appveyor.html"&gt;AppVeyor&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Note: For Jenkins, TestCafe can post videos and screenshot it captured during test execution. To enable this functionality, you will need to install &lt;a href="https://plugins.jenkins.io/testcafe/"&gt;the Jenkins plugin&lt;/a&gt; and use a dedicated &lt;a href="https://www.npmjs.com/package/testcafe-reporter-jenkins"&gt;Jenkins reporter&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Docker Image
&lt;/h2&gt;

&lt;p&gt;TestCafe is easy to install and requires a very basic environment. Of course, you can wind it up even faster with Docker. To get started, download a pre-configured image from Docker Hub:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker pull testcafe/testcafe
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The image is based on ArcLinux and includes Node.js, TestCafe, Chrome, and Firefox. It is ready to execute tests as needed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-v&lt;/span&gt; //d/tests:/tests &lt;span class="nt"&gt;-it&lt;/span&gt; testcafe/testcafe firefox:headless /tests/&lt;span class="k"&gt;**&lt;/span&gt;/&lt;span class="k"&gt;*&lt;/span&gt;.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also use this image on your computer to perform tests on a host machine or remote machines within your network. See the following help topic for additional Docker-related information: &lt;a href="https://devexpress.github.io/testcafe/documentation/guides/advanced-guides/use-testcafe-docker-image.html"&gt;Use TestCafe's Docker Image&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;The GitHub Actions CI service is ideal for projects developed on GitHub. To help you quickly integrate TestCafe into your Actions workflows, we created the &lt;a href="https://github.com/DevExpress/testcafe-action"&gt;Run TestCafe&lt;/a&gt; action. This action installs TestCafe and runs tests on your behalf. To begin, you simply need to add TestCafe command line arguments:&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;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;DevExpress/testcafe-action@latest&lt;/span&gt;
  &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;chrome&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;tests"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  TestCafe: Adoption Made Easy
&lt;/h2&gt;

&lt;p&gt;Ready to see TestCafe's capabilities in action? Want to see how quickly you can incorporate test automation into your CI/CD workflow?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://devexpress.github.io/testcafe/documentation/getting-started/"&gt;Get Started Today&lt;/a&gt; or &lt;a href="https://devexpress.com/ask"&gt;Ask Us&lt;/a&gt; for more information. We are here to help.&lt;/p&gt;

</description>
      <category>e2e</category>
      <category>javascript</category>
      <category>framework</category>
      <category>devops</category>
    </item>
    <item>
      <title>Introducing Multi-window Tests (Beta)</title>
      <dc:creator>TestCafe</dc:creator>
      <pubDate>Mon, 31 Aug 2020 10:55:36 +0000</pubDate>
      <link>https://dev.to/dxtestcafe/introducing-multi-window-tests-beta-5dod</link>
      <guid>https://dev.to/dxtestcafe/introducing-multi-window-tests-beta-5dod</guid>
      <description>&lt;p&gt;Modern web apps often launch new browser windows to authenticate users through third-party websites or display additional interactive content.&lt;/p&gt;

&lt;p&gt;TestCafe v1.9.0 introduces partial support for multi-window tests. You can now use client-side calls to open and close browser windows. The updated API includes additional window management methods. During the 'beta' stage, this functionality is only enabled in local instances of Chrome and Firefox. Keep in mind that this feature is not ready for use in production environments. Both the syntax and capabilities are subject to change.&lt;/p&gt;

&lt;h2&gt;
  
  
  Client-side window events
&lt;/h2&gt;

&lt;p&gt;The TestCafe browser automation driver detects and automatically activates newly launched windows. After the content is loaded, and all asynchronous requests are resolved, the test continues in the new window. When that window is closed, TestCafe switches back to the parent window and resumes the test.&lt;/p&gt;

&lt;p&gt;The sample code below demonstrates an OAuth login scenario. Lines &lt;code&gt;8&lt;/code&gt; through &lt;code&gt;10&lt;/code&gt; run in the external OAuth window.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;fixture&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Login via &amp;lt;Service Name&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://my-page&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Should log in via &amp;lt;Service Name&amp;gt;&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="nx"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;click&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#login-popup&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;typeText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#username&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;username&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;typeText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#pass&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;mySecret&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;click&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#submit&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;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Selector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#user&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;eql&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello %Username%!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;//Make sure we are logged in&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--YTFYSaXT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/zq0uj624mvweyp53ozym.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--YTFYSaXT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/zq0uj624mvweyp53ozym.jpg" alt="A scheme that illustrates automatic window switching"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You do not need to write extra code to create basic multi-window tests. When you need to arbitrarily open, close and switch between windows, use the &lt;a href="https://devexpress.github.io/testcafe/documentation/guides/advanced-guides/multiple-browser-windows.html"&gt;TestCafe API&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Switch between windows
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://devexpress.github.io/testcafe/documentation/reference/test-api/testcontroller/switchtopreviouswindow.html"&gt;t.switchToPreviousWindow&lt;/a&gt; method activates the last active window. If you only have two windows open, this method will cycle between them. This is useful in a variety of scenarios.&lt;/p&gt;

&lt;p&gt;Imagine, for example, that you're testing a real estate listings website. You want to make sure that once a new property is added, it appears in the window with all available listings. The following test implements this scenario:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;fixture&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Property List&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;page&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://url.com/properties&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Open the listings page&lt;/span&gt;
&lt;span class="nx"&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;Check the property list&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="nx"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;openWindow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://url.com/addnewproperty&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// Open the 'add new property' page in a new window&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;click&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#make-public&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// Publish the listing&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;switchToPreviousWindow&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;// Go back to the listings page&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Selector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.property-list li&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;eql&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;New &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Check if the new listing is displayed&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--HPxT-c9v--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/mn8oq5zw8dlicklwslc5.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--HPxT-c9v--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/mn8oq5zw8dlicklwslc5.jpg" alt="A scheme that illustrates switching between windows"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Manage multiple windows
&lt;/h2&gt;

&lt;p&gt;Test scenarios with more than two open windows require more precision. The &lt;a href="https://devexpress.github.io/testcafe/documentation/reference/test-api/testcontroller/switchtowindow.html"&gt;t.switchToWindow&lt;/a&gt; method can activate any open browser window if you pass a window descriptor object or a predicate function with the window description.&lt;/p&gt;

&lt;p&gt;To obtain a window descriptor, call the &lt;a href="https://devexpress.github.io/testcafe/documentation/reference/test-api/testcontroller/getcurrentwindow.html"&gt;t.getCurrentWindow&lt;/a&gt; method or save the return value when you open a new window.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;windowDesc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;openWindow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://devexpress.github.io/testcafe/&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;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;switchToWindow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;windowDesc&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The predicate function must contain a description of the window's URL or title. The URL object has the same structure as its &lt;a href="https://nodejs.org/api/url.html"&gt;Node.JS counterpart&lt;/a&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="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;openWindow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://devexpress.github.io/testcafe/&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;switchToWindow&lt;/span&gt;&lt;span class="p"&gt;(({&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pathname&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/testcafe&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Imagine you are debugging a task manager app. To ensure that both the task list and the notification feed are updated in real time, use the &lt;a href="https://devexpress.github.io/testcafe/documentation/reference/test-api/testcontroller/switchtowindow.html"&gt;t.switchToWindow&lt;/a&gt; method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;fixture&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Tasks View&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;page&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://url.com/add-task&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  

&lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Add a new task&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="nx"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;openWindow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://url.com/tasks&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// Open a new window with the task list&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;openWindow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://url.com/feed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// Open the notification feed&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;switchToWindow&lt;/span&gt;&lt;span class="p"&gt;(({&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pathname&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/add-task&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// Go back to the new task form&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;typeText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#task-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="s1"&gt;Redesign the landing page by 1 Feb&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// Fill in the new task form&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;click&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#submit-task&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// Submit the task&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;switchToWindow&lt;/span&gt;&lt;span class="p"&gt;(({&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pathname&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/tasks&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// Switch back to the task list&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Selector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.task-item&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;eql&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// Check if the new task is displayed&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;switchToWindow&lt;/span&gt;&lt;span class="p"&gt;(({&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pathname&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;feed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// Switch to the notification feed&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Selector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.message&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;eql&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Redesign the landing page by 1 Feb&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Check for the corresponding notification&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--f0T41X8m--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/nghzu0uqwwiww1llswmg.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--f0T41X8m--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/nghzu0uqwwiww1llswmg.jpg" alt="A scheme that illustrates the task manager example"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  API overview
&lt;/h2&gt;

&lt;p&gt;The updated API includes a number of useful window management methods.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://devexpress.github.io/testcafe/documentation/reference/test-api/testcontroller/openwindow.html"&gt;t.openWindow(url)&lt;/a&gt; opens a new window and points it to the specified URL.
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://devexpress.github.io/testcafe/documentation/reference/test-api/testcontroller/getcurrentwindow.html"&gt;t.getCurrentWindow()&lt;/a&gt; obtains the window descriptor that corresponds to the active window.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://devexpress.github.io/testcafe/documentation/reference/test-api/testcontroller/switchtowindow.html#tswitchtowindowwindow"&gt;t.switchToWindow(windowDescriptor)&lt;/a&gt; activates the window that corresponds to the window descriptor.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://devexpress.github.io/testcafe/documentation/reference/test-api/testcontroller/switchtowindow.html#tswitchtowindowpredicate"&gt;t.switchToWindow(predicate)&lt;/a&gt; uses the predicate function to find a matching window, and activates it. The predicate can include the window's title and URL.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://devexpress.github.io/testcafe/documentation/reference/test-api/testcontroller/switchtoparentwindow.html"&gt;t.switchToParentWindow()&lt;/a&gt; activates the parent of the active window.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://devexpress.github.io/testcafe/documentation/reference/test-api/testcontroller/switchtopreviouswindow.html"&gt;t.switchToPreviousWindow()&lt;/a&gt; activates the last active window.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://devexpress.github.io/testcafe/documentation/reference/test-api/testcontroller/closewindow.html"&gt;t.closeWindow()&lt;/a&gt; closes the active window.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://devexpress.github.io/testcafe/documentation/reference/test-api/testcontroller/closewindow.html"&gt;t.closeWindow(windowDescriptor)&lt;/a&gt; closes the window that corresponds to the window descriptor.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Try the new API and let us know what you think
&lt;/h2&gt;

&lt;p&gt;To try the functionality described in this article:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Install TestCafe version 1.9.0 or later;&lt;/li&gt;
&lt;li&gt;Create a test scenario that incorporates more than one browser window;&lt;/li&gt;
&lt;li&gt;Include the window management methods from this article in the test.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The TestCafe team is proud to create API that realistically model user behavior. If you find that the new window management capabilities can be modified to better serve your needs, please let us know. Submit your feedback and bug reports to &lt;a href="https://github.com/DevExpress/testcafe/issues/new/choose"&gt;our GitHub repository&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Refer to the TestCafe help topics for additional information about these methods.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>framework</category>
      <category>webdev</category>
      <category>testing</category>
    </item>
    <item>
      <title>Upcoming Webinar: The Fastest Way to Your Next Test – TestCafe + TestCafe Studio</title>
      <dc:creator>TestCafe</dc:creator>
      <pubDate>Tue, 25 Aug 2020 09:26:00 +0000</pubDate>
      <link>https://dev.to/dxtestcafe/upcoming-webinar-the-fastest-way-to-your-next-test-testcafe-testcafe-studio-3577</link>
      <guid>https://dev.to/dxtestcafe/upcoming-webinar-the-fastest-way-to-your-next-test-testcafe-testcafe-studio-3577</guid>
      <description>&lt;p&gt;In this webinar, our Technical Evangelist Paul Usher will demonstrate the difference between TestCafe and TestCafe Studio. Paul will show you how to write code-based tests more quickly and he'll explore the power of TestCafe Studio's integrated visual test recorder (for those who don't want to manually write test code).&lt;/p&gt;

&lt;p&gt;Paul's topics will include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How to create and debug tests in TestCafe Studio without writing any code.&lt;/li&gt;
&lt;li&gt;How to create stable selectors for your tests.&lt;/li&gt;
&lt;li&gt;The advantages of TestCafe's Smart Assertion mechanism.&lt;/li&gt;
&lt;li&gt;How to leverage both TestCafe and TestCafe Studio within your organization.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  End-to-End web testing made easy
&lt;/h2&gt;

&lt;p&gt;TestCafe Open Source and TestCafe Studio are driver free and do not require you to manage complex plug-ins. If you're ready to test your web apps and want to deliver more reliable solutions to your end-users, be sure to click the link below and register your interest in this live webinar.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Webinar Date:&lt;/strong&gt; Tuesday, September 8, 2020&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Start Time:&lt;/strong&gt; 10AM Pacific Time&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://dxpr.es/34jU51F"&gt;Register&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>typescript</category>
      <category>testing</category>
      <category>e2e</category>
    </item>
    <item>
      <title>TestCafe Webinar - Your Questions Answered</title>
      <dc:creator>TestCafe</dc:creator>
      <pubDate>Mon, 24 Aug 2020 10:11:42 +0000</pubDate>
      <link>https://dev.to/dxtestcafe/testcafe-webinar-your-questions-answered-4n48</link>
      <guid>https://dev.to/dxtestcafe/testcafe-webinar-your-questions-answered-4n48</guid>
      <description>&lt;p&gt;We recently hosted a webinar on TestCafe and found the response overwhelming. During the presentation a large number of questions were raised, and as promised, the team have been through and answered them all.&lt;/p&gt;

&lt;h2&gt;
  
  
  Watch the Webinar
&lt;/h2&gt;

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

&lt;h2&gt;
  
  
  Webinar Resources
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Does the book (&lt;em&gt;End-to-End Testing with TestCafe&lt;/em&gt; by Dennis Martinez) go over the examples from the Webinar?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
This webinar is based on the book, so you will certainly find details about the examples we showed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is the webinar available in other languages?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
We currently hold online events in English only.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In what language the application you show is written?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
It is JavaScript, the ES6 standard.&lt;/p&gt;
&lt;h2&gt;
  
  
  TestCafe Benefits
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What are the advantages of TestCafe over Selenium/Cypress/Nightwatch.js/Robot Framework/WebdriverIO?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;TestCafe does not require browser plugins, SDKs or other tools and libraries - just Node.js and browsers.&lt;/li&gt;
&lt;li&gt;You don't need to configure testing environment. Install TestCafe from npm and you are ready to test.&lt;/li&gt;
&lt;li&gt;TestCafe is truly cross-browser and cross-platform. It can run tests on Windows, macOS, Linux, iOS, and Android.  Supported browsers include Chrome, Firefox, Safari, Edge, and Internet Explorer.&lt;/li&gt;
&lt;li&gt;TestCafe features a built-in wait mechanism. You don't need to insert manual waiting in your tests. TestCafe waits for all kinds of loadings and animations automatically, so your tests are stable even when they slow down for whatever reason.&lt;/li&gt;
&lt;li&gt;TestCafe allows you to test even the most complex scenarios like those with cross-domain navigation, file upload, sophisticated iframe use cases, secure services (payment, geolocation) or multiple windows (in beta).&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  License
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Do I need to purchase a separate license for TestCafe? Is it included in any of the DevExpress subscriptions?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
TestCafe is open-source and free. It is licensed under &lt;a href="https://github.com/DevExpress/testcafe/blob/master/LICENSE"&gt;the MIT license&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Desktop Application Testing
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Does TestCafe only work in a browser? Can I use it to test desktop applications, like WinForms?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
TestCafe is designed for Web applications only. Thankfully, if you use Electron.js for your desktop application, you can easily &lt;a href="https://github.com/DevExpress/testcafe-browser-provider-electron"&gt;test it with TestCafe&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Parallelization
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Can I start 100 TestCafe tests to simulate high load?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
You can start 100 parallel browser instances if your computer has sufficient resources to run such a number of browsers. But we recommend using TestCafe for end-to-end rather than load testing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I run the tests in parallel in multiple browser windows?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Yes, TestCafe allows you to execute tests concurrently. In concurrent mode, TestCafe invokes multiple instances of each browser. These instances constitute the pool of browsers against which tests run concurrently, i.e. each test runs in the first available instance. You can find information how to run tests in parallel &lt;a href="https://devexpress.github.io/testcafe/documentation/guides/basic-guides/run-tests.html#run-tests-concurrently"&gt;in this topic&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How well does TestCafe scale when it comes to parallelization? What is the ideal number of tests that can be run in parallel?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
You can run any number of tests in concurrent mode. Regarding the number of browser instances that can be used to run these test, it's hard to name an optimal number. It all depends on the resources available on your machine and the tests themselves. It is best to choose this number on a case-by-case basis.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I have multiple TestCafe instances running tests?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Yes, you can use several TestCafe instances. There are no special restrictions here. But in this case you will have to make sure that the instances do not conflict for resources (open ports, access to files, etc.).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is there a way to start more parallel tests in memory without running browsers?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Concurrent mode implies launching the specified number of browser instances. All instances will be launched even if the number of tests is not enough to run at least one on each of them. Therefore, now there is no way to use this mode without launching browsers.&lt;/p&gt;
&lt;h2&gt;
  
  
  Integrations
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Does TestCafe integrate with BrowserStack?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Yes, you can run tests in Cloud Testing Services (BrowserStack, Sauce Labs) via the corresponding plugins. See more &lt;a href="https://devexpress.github.io/testcafe/documentation/guides/concepts/browsers.html#browsers-in-cloud-testing-services"&gt;in the documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I run TestCafe on Azure DevOps?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
You can find a topic about Azure DevOps integration in &lt;a href="https://devexpress.github.io/testcafe/documentation/guides/continuous-integration/azure-devops.html"&gt;the TestCafe documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I run TestCafe on Jenkins where there are no local browsers installed? Should I use headless mode on Jenkins?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
If the machine that runs Jenkins does not have local browsers installed, you can use &lt;a href="https://devexpress.github.io/testcafe/documentation/guides/basic-guides/run-tests.html#test-in-portable-browsers"&gt;portable&lt;/a&gt; browsers or &lt;a href="https://devexpress.github.io/testcafe/documentation/guides/basic-guides/run-tests.html#test-in-cloud-testing-services"&gt;cloud testing services&lt;/a&gt; (BrowserStack, SauceLabs).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://devexpress.github.io/testcafe/documentation/guides/basic-guides/run-tests.html#use-headless-mode"&gt;Headless mode&lt;/a&gt; is supported for both locally installed and portable browsers. We recommend that you use headless mode to decrease testing time. You can run browsers in headless mode even on machines without graphical system.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://devexpress.github.io/testcafe/documentation/guides/continuous-integration/jenkins.html"&gt;This tutorial&lt;/a&gt; describes how to integrate TestCafe with Jenkins.&lt;/p&gt;

&lt;p&gt;You may also wish to check &lt;a href="https://devexpress.github.io/testcafe/media/team-blog/introducing-the-testcafe-jenkins-plugin.html"&gt;the TestCafe plugin for Jenkins&lt;/a&gt; that attaches screenshots and videos to the Jenkins test results page.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is TestCafe compatible with Angular applications?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Yes, TestCafe has full support for Angular applications. You can use &lt;a href="https://github.com/DevExpress/testcafe-angular-selectors"&gt;the Angular selector plugin&lt;/a&gt; that adds selector extensions to make it easier to test Angular applications with TestCafe. These extensions allow you to create a Selector to find elements on the page in a way that is native to Angular applications.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does TestCafe support Vue?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Yes, TestCafe allows you test Vue applications the same way as any other apps. You can use &lt;a href="https://github.com/DevExpress/testcafe-vue-selectors"&gt;the Vue selector plugin&lt;/a&gt; that contains selector extensions to make it easier to test Vue components with TestCafe. These extensions allow you to test Vue component state and result markup alongside.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can TestCafe pick elements by their React component name?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
You can use &lt;a href="https://github.com/DevExpress/testcafe-react-selectors"&gt;the TestCafe selector plugin for React components&lt;/a&gt;. This plugin adds selector extensions that allow you to select page elements in a way that is native to React. For instance, you can use component names to identify page elements.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is TestCafe compatible with Knockout?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Yes, TestCafe can test applications based on Knockout. There are no known issues.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does TestCafe support Bamboo?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
You can use "Script Task" in Bamboo setting to write a wrapper that invokes automated tests. Alternatively, you can use &lt;a href="https://devexpress.github.io/testcafe/documentation/guides/advanced-guides/use-testcafe-docker-image.html"&gt;the TestCafe Docker image&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Blazor
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Can I use TestCafe to test a Blazor application?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
TestCafe supports testing for Blazor apps. You can test your Blazor app the same way as any other application. There are no known issues.&lt;/p&gt;
&lt;h2&gt;
  
  
  Action Chaining
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Are there limitations as to what kinds of actions can be chained? Is it the best practice to chain as many actions as I can?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Almost all TestCafe &lt;a href="https://devexpress.github.io/testcafe/documentation/reference/test-api/testcontroller/"&gt;test controller's methods&lt;/a&gt; can be chained, except those that return a value and hence break the chain:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://devexpress.github.io/testcafe/documentation/reference/test-api/testcontroller/eval.html"&gt;t.eval&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://devexpress.github.io/testcafe/documentation/reference/test-api/testcontroller/getbrowserconsolemessages.html"&gt;t.getBrowserConsoleMessages&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://devexpress.github.io/testcafe/documentation/reference/test-api/testcontroller/getnativedialoghistory.html"&gt;t.getNativeDialogHistory&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can chain these methods in any desirable manner but we recommend adding blank lines between logical parts of the action chain to improve tests readability, e.g.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;click&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#id1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;//some settings&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;click&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#id1&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;click&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#id1&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;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Selector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#result&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;eql&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;expected text&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="c1"&gt;//assertion&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Can I extend the TestController object with my own chainable methods? Or only helpers and pageobjects are the way to go?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
TestController cannot be extended with custom methods at the moment. We may consider adding this feature, but it isn't in our current roadmap. As you correctly suggested, you can use helpers and page objects to implement custom methods.&lt;/p&gt;
&lt;h2&gt;
  
  
  TestCafe Studio
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Can TestCafe record my actions (some tests need many entries and writing them is very time-consuming)?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
You can use &lt;a href="https://www.devexpress.com/products/testcafestudio/"&gt;TestCafe Studio&lt;/a&gt; that has a built-in test recorder. It allows you to record your actions without coding them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is there a user interface for building tests, or is it all JS-based?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
You can use TestCafe Studio which is a UI tool to maintain your tests.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is TestCafe Studio a desktop application or is it available as a Web service?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
TestCafe Studio is a cross-platform desktop application (powered by Electron.js). You can download its installer for Windows, macOS or Linux and install on your machine. Offline registration is available for computers without internet access. Read more in the &lt;a href="https://docs.devexpress.com/TestCafeStudio/400163/guides/installation"&gt;Installation topic&lt;/a&gt; in the Docs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does TestCafe Studio require a license?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Yes, this is a &lt;a href="https://devexpress.com/testcafestudio"&gt;commercial product&lt;/a&gt; that requires obtaining a license. There are two options available: TestCafe Studio and TestCafe Studio Pro with DevExpress Technical support.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can TestCafe Studio generate tests steps in a more user-friendly form than code?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
TestCafe Studio has the built-in &lt;a href="https://docs.devexpress.com/TestCafeStudio/400190/user-interface/test-editor"&gt;Test Editor&lt;/a&gt; designed for codeless test creation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can you change the order of tests on the side panel on the left?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
The &lt;a href="https://docs.devexpress.com/TestCafeStudio/400182/user-interface/explorer-panel"&gt;Explorer Panel&lt;/a&gt; allows you to view and manage files in your testing directory. For recorded tests, the Explorer Panel displays fixtures and tests. You can create new tests, copy/paste them and more. But currently you can't change the order of the tests.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Are there more formats of report logs in TestCafe Studio?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
In the Report View you can see tests run report in the TestCafe Studio format - &lt;a href="https://docs.devexpress.com/TestCafeStudio/400187/user-interface/report-view"&gt;Grid View&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The following built-in reports formats are also available:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;JSON&lt;/li&gt;
&lt;li&gt;xUnit&lt;/li&gt;
&lt;li&gt;List&lt;/li&gt;
&lt;li&gt;Minimal&lt;/li&gt;
&lt;li&gt;Spec&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can install TestCafe reporter plugins to add more formats: &lt;a href="https://docs.devexpress.com/TestCafeStudio/400187/user-interface/report-view#get-more-report-formats"&gt;Get More Report Formats&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is there any guide with comprehensive instructions and examples for TestCafe Studio?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
See the guides, videos, and examples &lt;a href="https://docs.devexpress.com/TestCafeStudio/400157/testcafe-studio"&gt;in the TestCafe Studio documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is the element locator strategy?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
TestCafe Studio use some characteristic of the DOM element in order to identify it on the page, such as id, class, text etc. You can set the usage priority of these characteristics, switch them off (e.g. for auto generated id) or create new ones based on custom attributes. See the details in &lt;a href="https://docs.devexpress.com/TestCafeStudio/400407/test-actions/element-selectors"&gt;the documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is TestCafe Studio a part of the Universal Subscription?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Yes, &lt;a href="https://www.devexpress.com/subscriptions/universal.xml"&gt;TestCafe Studio Pro version is&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does TestCafe Studio support console.log output? I am currently running tests from the command line so I'd like to see my console.log statements.&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
You can add &lt;a href="https://docs.devexpress.com/TestCafeStudio/401265/test-actions/custom-scripts"&gt;the Run TestCafe Script action&lt;/a&gt;. In this action, you can use &lt;code&gt;console.log()&lt;/code&gt; to print messages directly, or even call &lt;a href="https://devexpress.github.io/testcafe/documentation/reference/test-api/testcontroller/getbrowserconsolemessages.html"&gt;t.getBrowserConsoleMessages()&lt;/a&gt; to fetch messages from the browser's console.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can TestCafe Studio generate reports with statistics, graphs, pies, etc., illustrating execution results?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Currently there is no such capability.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In TestCafe Studio, moving a line becomes almost impossible over 100 lines. Is that a memory issue that can be changed via config?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
We cannot reproduce this behavior on our side. Please create an inquiry on &lt;a href="https://www.devexpress.com/ask"&gt;https://www.devexpress.com/ask&lt;/a&gt; and provide more detail about the issue you encounter.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;We are using both DevExpress and custom controls in our application. We record tests in TestCafe Studio, but they fail when we run them. Can you tell why this happens?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
To resolve the issue, please refer to the Troubleshooting section on our &lt;a href="https://docs.devexpress.com/TestCafeStudio/400610/faq"&gt;FAQ page&lt;/a&gt;. If suggestions described there do not help or apply to your case, create a ticket on &lt;a href="https://www.devexpress.com/ask"&gt;https://www.devexpress.com/ask&lt;/a&gt; and describe your issue in detail.&lt;/p&gt;
&lt;h2&gt;
  
  
  Page Model
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Do you create the page models manually? Can the page models be dynamically generated?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Page Models should be created manually, there is no built-in way to generate page models automatically. A page model reflects the internal structure of the testing page: what is the container, what is the parent and what is the child, etc., which distinguishing characteristics are best used to identify elements. Any automatically generated model is unlikely to reflect these semantics.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is it necessary to create selectors with the Selector constructor in a page object class?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
No, you can use CSS strings:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;Page&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;submitButton&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#submit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But if you want to extend or chain such a selector with &lt;a href="https://devexpress.github.io/testcafe/documentation/reference/test-api/selector/"&gt;selector's methods&lt;/a&gt;, you will need to use the Selector constructor:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;Page&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;constructor&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt;       &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Selector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;button&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;submitButton&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;withText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Submit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cancelButton&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;withText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Cancel&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Can I add additional methods to page object in TestCafe?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Yes, you can add methods to a page model. Usually these methods are the most frequently repeated actions specific to this page. See an example in &lt;a href="https://devexpress.github.io/testcafe/documentation/guides/concepts/page-model.html#step-7---add-actions-to-the-page-model"&gt;the TestCafe docs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does TestCafe support the PageObjects library?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
If you mean &lt;a href="https://github.com/devcon5io/pageobjects"&gt;this PageObjects library&lt;/a&gt;, then TestCafe does not support it because this library is designed for Selenium.&lt;/p&gt;
&lt;h2&gt;
  
  
  Database Access
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Can test results be sent to a database?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
There's no built-in functionality for this, but you can certainly &lt;a href="https://devexpress.github.io/testcafe/documentation/guides/extend-testcafe/reporter-plugin.html"&gt;make a plugin&lt;/a&gt; that will do this.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can TestCafe connect to databases to verify that the correct data was written?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
TestCafe doesn't have built-in functionality for interaction with databases. But you can use any npm module for it.&lt;/p&gt;
&lt;h2&gt;
  
  
  Browsers
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Does TestCafe support Microsoft Edge? Can TestCafe create mocks and run tests in IE11?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Yes, TestCafe supports both browsers. You can find the list of supported browsers in &lt;a href="https://devexpress.github.io/testcafe/documentation/guides/concepts/browsers.html#officially-supported-browsers"&gt;the TestCafe docs&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Selectors
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What type of selectors are available? Is it only HTML element IDs and/or classes?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
You can use any &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Selectors"&gt;pure CSS selectors&lt;/a&gt; or &lt;a href="https://devexpress.github.io/testcafe/documentation/reference/test-api/selector/"&gt;TestCafe Selector API&lt;/a&gt; that extends capabilities offered by CSS selectors.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I target elements based on text that is actually visible to the end-user?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
TestCafe Selector's &lt;a href="https://devexpress.github.io/testcafe/documentation/reference/test-api/selector/withtext.html"&gt;withText&lt;/a&gt; method finds elements by text that is visible to the end-user (the element's &lt;code&gt;innerText&lt;/code&gt; property). You can also create a selector that uses custom logic to find an element. Pass a function to the &lt;a href="https://devexpress.github.io/testcafe/documentation/reference/test-api/selector/constructor.html#initialize-selectors"&gt;selector's constructor&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is it possible to set the waiting time for an element? What if I mistyped the selector's "name" or the page is loading really slow? How long does TestCafe wait by default?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
You can specify the Selector's &lt;a href="https://devexpress.github.io/testcafe/documentation/reference/test-api/selector/constructor.html#optionstimeout"&gt;timeout option&lt;/a&gt;. During this timeout, the selector waits for the element. The default timeout duration is &lt;code&gt;10000&lt;/code&gt; ms.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I use auto-generated names for DevExpress control's elements in my application. Can TestCafe interact with them?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Yes, you can identify these elements by their static parts. See an example in &lt;a href="https://devexpress.github.io/testcafe/documentation/guides/basic-guides/select-page-elements.html#select-elements-with-dynamic-ids"&gt;our docs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I use XPath to locate elements?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
XPath selectors are not built-in with TestCafe, but you can implement a simple helper method to use them. &lt;a href="https://github.com/DevExpress/testcafe-examples/tree/master/examples/use-xpath-selectors"&gt;See an example here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I verify a certain element does not exist or will that cause a failure?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
If an element used in some action doesn't exist, a test fails. A test run report then indicates that the test failed because a target element doesn't exist on the page. To check if the element exists before TestCafe attempts to interact with it, use the following approach&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;if&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;Selector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#element&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;exists&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;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;click&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Selector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#element&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For instance, you would use this verification to close ad popups (should they appear).&lt;/p&gt;

&lt;h2&gt;
  
  
  Debug
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Are there any approaches that help debug tests? How can I debug TestCafe and the Hammerhead proxy?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Check out &lt;a href="https://devexpress.github.io/testcafe/media/team-blog/how-to-debug-tests-in-testcafe-quick-guide.html"&gt;this blog post&lt;/a&gt; on how to debug your application and tests.&lt;/p&gt;

&lt;p&gt;You can also find the instruction about how to debug in other IDEs in &lt;a href="https://devexpress.github.io/testcafe/documentation/guides/basic-guides/debug.html"&gt;our guide&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To debug TestCafe and Hammerhead, enable the development mode. Use the &lt;a href="https://devexpress.github.io/testcafe/documentation/reference/command-line-interface.html#--dev"&gt;--dev flag&lt;/a&gt; when you run tests:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;testcafe chrome my-tests &lt;span class="nt"&gt;--dev&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;What are the available debug options?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
The following capabilities help you determine the cause of errors and failures:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://devexpress.github.io/testcafe/documentation/reference/command-line-interface.html#takeonfails"&gt;Take screenshots automatically when tests fail&lt;/a&gt;,&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://devexpress.github.io/testcafe/documentation/reference/command-line-interface.html#--video-basepath"&gt;Capture videos of test runs&lt;/a&gt;,&lt;/li&gt;
&lt;li&gt;&lt;a href="https://devexpress.github.io/testcafe/documentation/reference/command-line-interface.html#--speed-factor"&gt;Set the speed of test execution&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://devexpress.github.io/testcafe/documentation/reference/command-line-interface.html#--debug-on-fail"&gt;Enter debug mode&lt;/a&gt; automatically when the first test fails,&lt;/li&gt;
&lt;li&gt;Execute tests step by step in &lt;a href="https://devexpress.github.io/testcafe/documentation/reference/command-line-interface.html#-d---debug-mode"&gt;debug mode&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Can TestCafe capture a screenshot when a test fails?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Absolutely, enable the &lt;a href="https://devexpress.github.io/testcafe/documentation/reference/command-line-interface.html#takeonfails"&gt;takeOnFails&lt;/a&gt; option to do this.&lt;/p&gt;

&lt;h2&gt;
  
  
  Authentication
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Can I log in once and execute multiple tests under the same account rather than logging in in every test?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Yes, you can use roles to perform actions that log you in only once. In the subsequent tests, you just activate the role you defined earlier to log in without repeating the authentication process each time. See &lt;a href="https://devexpress.github.io/testcafe/documentation/guides/advanced-guides/authentication.html#user-roles"&gt;User Roles&lt;/a&gt; in the documentation for details.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do roles work with auth0/openid which has JWT in headers?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Roles can process the JWT if it is sent in the cookies or stored in the local or session storage.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Would we run into any issues if we're using Microsoft authentication tokens for permissions?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
You should not have any issue. Please try this and see how it works. If you face any issues, let us know, so we can research it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How does TestCafe log out the user to switch to a different role? Does it just re-open the page?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
When you switch to a role that was active previously in the current session, TestCafe restores cookies and browser's local and session storage where authentication data is located. If the new role wasn't used yet, TestCafe just resets the cookies and storage and then performs authentication actions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can you create Roles with API calls instead of functional steps?&lt;/strong&gt;&lt;br&gt;
If your question is about REST API, then yes, you can call REST API to authenticate a user in a role. Just note that you need to use a &lt;a href="https://devexpress.github.io/testcafe/documentation/guides/basic-guides/obtain-client-side-info.html"&gt;client function&lt;/a&gt; to call REST API from the browser. You may want to &lt;a href="https://devexpress.github.io/testcafe/documentation/guides/advanced-guides/inject-client-scripts.html"&gt;inject a library that can call API into the tested page&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What are the options for smart card logins?&lt;/strong&gt;&lt;br&gt;
TestCafe only supports web-based authentication. That is, your website should be able to authenticate you by your actions in the web browser, without relying on additional hardware. The only way is to deploy a testing instance of your web app without smart card authentication.&lt;/p&gt;

&lt;h2&gt;
  
  
  Multiple Apps, Windows, and Tabs
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Can TestCafe test integration across multiple applications?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Yes, you can test any number of web applications.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can you test multiple browser windows at the same time? For example, I may need to access application A, then check application B and come back to A.&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Yes, you can do this. We released multiple window support in beta in v1.9.0. Please find more information in the &lt;a href="https://devexpress.github.io/testcafe/documentation/guides/advanced-guides/multiple-browser-windows.html"&gt;Multiple Browser Windows&lt;/a&gt; topic and don't hesitate to leave your feedback. Your opinion helps us make sure you get the best experience when this feature is released.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does TestCafe support multiple tabs?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
You can open and switch between multiple browser windows with &lt;a href="https://devexpress.github.io/testcafe/documentation/guides/advanced-guides/multiple-browser-windows.html"&gt;this new beta feature&lt;/a&gt;. TestCafe will open a new popup window instead of a tab when necessary. This is because tabs can be throttled which interrupts TestCafe scripts.&lt;/p&gt;

&lt;h2&gt;
  
  
  iframes
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Does TestCafe support iframes?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Yes, TestCafe supports iframes and provides two simple methods to interact with their content: &lt;a href="https://devexpress.github.io/testcafe/documentation/reference/test-api/testcontroller/switchtoiframe.html"&gt;switchToIframe&lt;/a&gt; to switch the test's browsing context to iframe's context and &lt;a href="https://devexpress.github.io/testcafe/documentation/reference/test-api/testcontroller/switchtomainwindow.html"&gt;switchToMainWindow&lt;/a&gt; to switch it back to the main window.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reports
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;How does TestCafe output test run reports? Where can I find test results?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
TestCafe shows the test run report in the console by default. You can redirect output to a file or use dedicated reporters to post reports to a CI system or elsewhere.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What happens when a test fails? What logs are produced?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
If a test fails, you will see a comprehensive report in the console. For instance:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--LTScSNW2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/hfrdodtpkfxgp2wzw0eu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--LTScSNW2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/hfrdodtpkfxgp2wzw0eu.png" alt="Report example"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Multiple report formats are supported, including the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;spec&lt;/li&gt;
&lt;li&gt;list&lt;/li&gt;
&lt;li&gt;minimal&lt;/li&gt;
&lt;li&gt;xUnit&lt;/li&gt;
&lt;li&gt;JSON&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Read more in &lt;a href="https://devexpress.github.io/testcafe/documentation/guides/concepts/reporters.html"&gt;the TestCafe documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In what format does TestCafe generate the reports? Is it XML or HTML?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
The format depends on the reporter. It can be XML, JSON, HTML, and many others. You can &lt;a href="https://www.npmjs.com/search?q=testcafe-reporter"&gt;explore the available reporter packages on npm&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Test Organization
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Can I use logic operators to have different conditional "paths" during a test?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Yes, TestCafe can do conditional testing. You can use standard JavaScript if-clauses to make this happen.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is it possible to share fixtures between test files?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
TestCafe treats fixtures declared in different files separately. If you can share your use case when merging fixtures is useful, please &lt;a href="https://github.com/DevExpress/testcafe/issues/new?template=feature_request.md"&gt;open an issue&lt;/a&gt; on GitHub.&lt;/p&gt;

&lt;h2&gt;
  
  
  How TestCafe Works
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Did I miss what the &lt;code&gt;async&lt;/code&gt; keyword means in code? Is that to say TestCafe commands can run as other tests are running?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;code&gt;async&lt;/code&gt; is a JavaScript keyword that indicates that the function is asynchronous. Technically, an asynchronous function means that this function returns a Promise. TestCafe actions are asynchronous because so are the page events. Page loading, animations, HTTP requests take different amounts of time. The test function is asynchronous as well because it uses asynchronous TestCafe actions.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;await&lt;/code&gt; means that the next command should not execute until the previous ("awaited") command is completed. This is required to execute test actions in the right sequence (and, in the same manner, TestCafe "awaits" tests in a fixture to run them one by one). Note that, by contrast, tests in different browsers can run in parallel, just like in concurrency mode.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Please provide technical insight about how TestCafe avoids installing special plug-ins in order to interact with the browser. How does it actually interact with browsers?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
TestCafe proxies the tested webpage and injects automation scripts right inside the proxied copy. This way, browsers do all the work when they execute the injected scripts. You can find more details in the &lt;a href="https://devexpress.github.io/testcafe/documentation/how-it-works/"&gt;How It Works&lt;/a&gt; article.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is it possible to access runtimeJS objects from application client libraries loaded in the browser?&lt;/strong&gt;&lt;br&gt;
TestCafe is designed to conceal itself from application's JavaScript code. This is necessary to ensure that pages proxied by TestCafe run exactly in the same way as they do on the website. For this reason, application code cannot access TestCafe scripts or test code entities.&lt;/p&gt;

&lt;h2&gt;
  
  
  Waiting and Asynchrony
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What if a portion of a page takes a while to render (for instance, the page uses AJAX). Can TestCafe take it into account?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Yes, TestCafe tests wait automatically until the page is rendered completely. You can also insert manual waiting, but it shouldn't be necessary in almost all cases.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I set up my page in a jQuery callback: &lt;code&gt;$(document).ready(function(){})&lt;/code&gt;. Will there be JS races with TestCafe?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
TestCafe will wait until the page loads completely and run tests only after that. TestCafe wait mechanisms are designed to prevent races with JS code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It is great that TestCafe handles waiting internally. Would there be a need to override default timeout functionality though? How should a user go about it?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
You may need to override the default timeout if your page requires extra long waiting. All TestCafe auto-wait timeouts are customizable. You can find more information in the &lt;a href="https://devexpress.github.io/testcafe/documentation/guides/concepts/built-in-wait-mechanisms.html"&gt;Built-in Wait Mechanisms&lt;/a&gt; topic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Other Features
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Does TestCafe support all ES6 or later features? Do I need plugins to support arrow functions or the async/await syntax?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
TestCafe supports all modern JavaScript and TypeScript features. No plugins needed, everything works out of the box.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can TestCafe work with the Service Worker?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
We are currently in the progress of implementing full support for Service Workers. Stay tuned for our updates to be the first to know when we are ready.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does TestCafe work with Python?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
You can write tests in JavaScript/TypeScript/CoffeeScript only.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does TestCafe support upload ( excel ) data functionality?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
TestCafe can upload files, including Excel, to websites if it is a part of the test scenario. However, if you are asking about API to access Excel data sheets from test code, TestCafe does not provide one out of the box. You can search for npm modules that implement the functionality you need and use them from TestCafe tests.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What about functional test coverage? Does TestCafe support it?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Test coverage estimation is not available at the moment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Miscellaneous
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;If TestCafe runs in headless mode, is it still possible to grab screenshots on failures?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Yes, TestCafe can take screenshots even in headless mode.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does this require a test framework like jest/mocha/jasmine?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
No additional frameworks are required for TestCafe.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How can I use TestCafe to test different resolutions?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
You can use the &lt;a href="https://devexpress.github.io/testcafe/documentation/reference/test-api/testcontroller/resizewindow.html"&gt;t.resizeWindow&lt;/a&gt; action to change the browser window size and test adaptive UIs. TestCafe also supports &lt;a href="https://devexpress.github.io/testcafe/documentation/guides/basic-guides/run-tests.html#enable-mobile-device-emulation"&gt;Chromium device emulation&lt;/a&gt; to test on emulated mobile devices of various sizes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can we use Test Cafe to compare two documents? Like documents with logos, disclaimers and other information?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
If you mean visual comparison, TestCafe does not provide this functionality out of the box. However, you can find multiple open-source packages that try to solve this task, like &lt;a href="https://github.com/tacoss/testcafe-blink-diff"&gt;testcafe-blink-diff&lt;/a&gt;. Note that they are maintained by the community and are not related to the TestCafe team.&lt;/p&gt;

&lt;p&gt;If your goal is to compare HTML, you can pass &lt;code&gt;innerHTML&lt;/code&gt; to a TestCafe assertion as shown in the example in &lt;a href="https://devexpress.github.io/testcafe/documentation/reference/test-api/selector/addcustomdomproperties.html"&gt;this topic&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do you change the base URL to test in different environments?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
You can import the base URL from a configuration file or an environment variable, and then use it to build start page URLs in test code. See &lt;a href="https://devexpress.github.io/testcafe/faq/#how-do-i-work-with-configuration-files-and-environment-variables"&gt;this example&lt;/a&gt; on the FAQ page.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I run TestCafe on a Linux computer without the UI?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Yes, you can run your tests on Linux and use headless browsers to run your tests without the UI.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Could you please share ideas about how to do localization testing? Does TestCafe support that?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
TestCafe does not have built-in functionality for localization testing. As a suggestion, you can fetch the localization strings from a resource file or database with Node.js means or third-party npm modules. Then, you can create &lt;a href="https://devexpress.github.io/testcafe/documentation/recipes/best-practices/create-data-driven-tests.html"&gt;data-driven tests&lt;/a&gt; that check if the displayed strings are localized (present in the localization resources).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When do you plan to release version 1.9.0?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
1.9.0 was released on August 6th. If you are asking about the multi-window support final release, we do not have an exact date yet.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How does TestCafe handle exceptions?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
TestCafe considers the test failed if its code throws an exception. The report will indicate the line of code and call stack where this exception originated. Exceptions in JavaScript code on the tested page also make tests fail. However, this behavior is customizable. You can use the &lt;a href="https://devexpress.github.io/testcafe/documentation/reference/command-line-interface.html#-e---skip-js-errors"&gt;--skip-js-errors&lt;/a&gt; flag to ignore page errors. Similarly, the &lt;a href="https://devexpress.github.io/testcafe/documentation/reference/command-line-interface.html#-u---skip-uncaught-errors"&gt;--skip-uncaught-errors&lt;/a&gt; flag allows you to continue tests when test code throws an exception.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can we measure client-side performance using TestCafe (both HTTP and script execution time)?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
TestCafe is not intended for this task. In fact, TestCafe impacts webpage performance when it runs tests. We are constantly optimizing our code to minimize this slowdown, but we do not aim to precisely match the original performance.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Are tests executed in sequence within a fixture?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Yes, tests are executed as they are declared in code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I add my custom element library to the context object?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
You can add anything to the feature and test context objects. However, keep in mind that test code does not run in the browser, so adding browser libraries to the context objects might not help. If this is the case, you may be more interested in the &lt;a href="https://devexpress.github.io/testcafe/documentation/guides/advanced-guides/inject-client-scripts.html"&gt;custom script injection functionality&lt;/a&gt; designed for user's client libraries.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can TestCafe test HTML5 features like fullscreen, camera, audio, or video interaction?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Yes, you can test these HTML 5 features with TestCafe.&lt;/p&gt;

&lt;p&gt;Note that you might need to set the &lt;code&gt;--autoplay-policy=no-user-gesture-required&lt;/code&gt; browser flag as explained in &lt;a href="https://devexpress.github.io/testcafe/documentation/reference/command-line-interface.html#start-a-browser-with-arguments"&gt;this article&lt;/a&gt; to test the fullscreen mode and audio/video. The camera can be mocked using &lt;a href="https://devexpress.github.io/testcafe/documentation/guides/basic-guides/obtain-client-side-info.html"&gt;ClientFunctions&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does TestCafe support multiple domains in a test?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Yes, navigation and requests between different domains work out of the box. You do not need to care if you visit pages on one or several domains.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What happens if TestCafe loses network connection with a remote device that runs tests?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Tests cannot run without a network connection because TestCafe must be able to send commands to the remote device. If the connection is interrupted, TestCafe will throw an error saying that a browser connection is lost.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is it possible to run all JS in one command? Could you please specify this command?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
If I understand you correctly, yes, you can run all your JS tests using a single console command.&lt;br&gt;
Here is the CLI reference where you can see the &lt;a href="https://devexpress.github.io/testcafe/documentation/reference/command-line-interface.html"&gt;testcafe command syntax&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I noticed non-standard code indentation. Is a respective formatter for VS Code available?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
We didn't release a specific formatter because you can use any indentation you prefer with TestCafe.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I use TestCafe to test the development and production instances of my app? If so, how can I configure different URLs for my instances?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Yes, you can import the base URL from a configuration file or an environment variable, and then use it to build start page URLs in test code. See &lt;a href="https://devexpress.github.io/testcafe/faq/#how-do-i-work-with-configuration-files-and-environment-variables"&gt;this example&lt;/a&gt; on the FAQ page.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does TestCafe have support for file download? Can you set the default file download location using TestCafe API?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Yes, if test actions on the page trigger file download, the browser will download it as usually. Then you can access the file from test code to perform verification. Currently, TestCafe API does not allow you to set the default download location.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>testing</category>
      <category>e2e</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Introducing the TestCafe Jenkins Plugin</title>
      <dc:creator>TestCafe</dc:creator>
      <pubDate>Wed, 05 Aug 2020 10:51:35 +0000</pubDate>
      <link>https://dev.to/dxtestcafe/introducing-the-testcafe-jenkins-plugin-386m</link>
      <guid>https://dev.to/dxtestcafe/introducing-the-testcafe-jenkins-plugin-386m</guid>
      <description>&lt;p&gt;TestCafe can capture videos and screenshots so you can debug your tests and examine page UI. You can record all tests or only those that failed, generate unique video files for each test or record all of them in one take, and single out specific interactions. (For a full list of available options, see the following help topic: &lt;a href="https://devexpress.github.io/testcafe/documentation/guides/advanced-guides/screenshots-and-videos.html"&gt;Screenshots and Videos&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Many TestCafe users take advantage of Jenkins — a CI/CD solution — to automate their tests. Until recently, they had to manually match the screenshots and videos taken by TestCafe to the individual test reports. The newly implemented &lt;a href="https://plugins.jenkins.io/testcafe/"&gt;TestCafe Jenkins plugin&lt;/a&gt; simplifies this process. Links to screenshots and videos taken during the test now automatically appear on the Jenkins test results page. There is no need to keep the testing server running — all required files are stored inside the Jenkins build folder.&lt;/p&gt;

&lt;p&gt;With our plugin enabled, the test results page should appear as follows:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9J8iKHUm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://devexpress.github.io/testcafe/images/jenkins-plugin/test-results-page.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9J8iKHUm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://devexpress.github.io/testcafe/images/jenkins-plugin/test-results-page.png" alt="The updated test results page"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Test case: the disappearing button
&lt;/h2&gt;

&lt;p&gt;Let's assume that the 'Add to Cart' button disappears on the mobile version of your website.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--YfbJuUoA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://devexpress.github.io/testcafe/images/jenkins-plugin/button-example.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--YfbJuUoA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://devexpress.github.io/testcafe/images/jenkins-plugin/button-example.png" alt="The 'Add To Cart' button is absent from the mobile version of the website"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;TestCafe supports the following mobile device emulation methods:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://devexpress.github.io/testcafe/documentation/guides/basic-guides/interact-with-the-page.html#resize-window"&gt;Resize the browser window&lt;/a&gt; during the test&lt;/li&gt;
&lt;li&gt;Run the test through a &lt;a href="https://devexpress.github.io/testcafe/documentation/guides/concepts/browsers.html#browsers-in-cloud-testing-services"&gt;third-party cloud testing service&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Use &lt;a href="https://devexpress.github.io/testcafe/documentation/guides/concepts/browsers.html#use-chromium-device-emulation"&gt;Chromium's built-in emulation mode&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The third option offers greater speed and stability. We describe it going forward and recommend that you use it if possible.&lt;/p&gt;

&lt;p&gt;First, let's write a simple test that checks if the 'Add to Cart' button exists:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;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;`Add To Cart` button should exist&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="nx"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Selector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;button&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;withText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Add To Cart&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;visible&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let's configure Jenkins to launch this test every time we build our project.&lt;/p&gt;

&lt;h2&gt;
  
  
  Basic setup
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step 1. Install prerequisites
&lt;/h3&gt;

&lt;p&gt;TestCafe requires a working Node.js installation to run. If your testing environment does not contain node.js, &lt;a href="https://plugins.jenkins.io/nodejs/"&gt;the Node.js Jenkins plugin&lt;/a&gt; can install it for you. Also ensure that Chromium is installed: TestCafe cannot function without a browser.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2. Install the TestCafe Jenkins plugin
&lt;/h3&gt;

&lt;p&gt;To install the TestCafe Jenkins plugin, click the "Manage Plugins" link on the Manage Jenkins page, select the "Available" tab, and enter "testcafe" into the search field. Check the box next to our plugin and click the 'Install without restart' button below it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--iRULwsgC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://devexpress.github.io/testcafe/images/jenkins-plugin/plugin-search-ui.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--iRULwsgC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://devexpress.github.io/testcafe/images/jenkins-plugin/plugin-search-ui.png" alt="Jenkins plugin search UI"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3. Install the required Node packages
&lt;/h3&gt;

&lt;p&gt;Add the following &lt;em&gt;build step&lt;/em&gt; to your Jenkins project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i testcafe testcafe-reporter-jenkins
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command installs the main testcafe library, as well as the &lt;a href="https://www.npmjs.com/package/testcafe-reporter-jenkins"&gt;testcafe-reporter-jenkins&lt;/a&gt; package. The latter is needed to generate Jenkins-friendly JUnit format reports.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4. Configure the tests
&lt;/h3&gt;

&lt;p&gt;You can configure your tests via:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the &lt;a href="https://devexpress.github.io/testcafe/documentation/reference/command-line-interface.html"&gt;command line interface&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;the JavaScript/TypeScript API&lt;/li&gt;
&lt;li&gt;the .testcaferc.json &lt;a href="https://devexpress.github.io/testcafe/documentation/reference/configuration-file.html"&gt;configuration file&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The last option provides an easy, declarative way to define your test settings. You can store this file in the same folder as your tests. Below is the configuration used in this tutorial:&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="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;browsers&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;chromium:headless:emulation:device=iPhone 4&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;chromium:headless:emulation:device=iPad Mini&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;chromium:headless&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;src&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;test/e2e/**/*&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;screenshots&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;takeOnFails&lt;/span&gt;&lt;span class="dl"&gt;"&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fullPage&lt;/span&gt;&lt;span class="dl"&gt;"&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;videoPath&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;videos&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;reporter&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;jenkins&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;output&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;report.xml&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;appCommand&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;node server.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;em&gt;Browser&lt;/em&gt; array contains the list of browsers TestCafe will use to run our test. The &lt;a href="https://devexpress.github.io/testcafe/documentation/guides/concepts/browsers.html#use-chromium-device-emulation"&gt;TestCafe browser syntax&lt;/a&gt; allows us to specify the mobile devices we want Chromium to emulate.&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;name&lt;/em&gt; property of the &lt;em&gt;reporter&lt;/em&gt; object is set as &lt;em&gt;jenkins&lt;/em&gt;, which ensures that the reports generated by TestCafe can be properly parsed by the server.&lt;/p&gt;

&lt;p&gt;If you decide not to use a config file, be sure to &lt;a href="https://devexpress.github.io/testcafe/documentation/reference/command-line-interface.html#-r-nameoutput---reporter-nameoutput"&gt;manually set&lt;/a&gt; the report format when you launch the tests as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;testcafe chrome test.js &lt;span class="nt"&gt;-r&lt;/span&gt; jenkins:report.xml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Otherwise, simply run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx testcafe
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 5. Configure the reporter
&lt;/h3&gt;

&lt;p&gt;Turn on the &lt;a href="https://plugins.jenkins.io/junit/"&gt;JUnit&lt;/a&gt; reporter plugin: add the "Publish JUnit test result report" &lt;em&gt;post-build action&lt;/em&gt;. To display screenshots and videos alongside your test results, select the "Include links to TestCafe artifacts" option from the "Additional test report features" drop-down menu.&lt;/p&gt;

&lt;p&gt;Important: Remember to check the "Retain long standard output/error" box. Otherwise, the reporter plugin will automatically truncate the URLs of your videos and screenshots.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--yIgnzlmu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://devexpress.github.io/testcafe/images/jenkins-plugin/junit-reporter-configuration.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--yIgnzlmu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://devexpress.github.io/testcafe/images/jenkins-plugin/junit-reporter-configuration.png" alt="JUnit reporter configuration screen"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 6. Run the build
&lt;/h3&gt;

&lt;p&gt;Save the changes to your project and click the "Build now" button on the project page:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--nCZwZhtX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://devexpress.github.io/testcafe/images/jenkins-plugin/build-now-button.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--nCZwZhtX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://devexpress.github.io/testcafe/images/jenkins-plugin/build-now-button.png" alt="Jenkins Project menu with the Build Now Button highlighted"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Review the results
&lt;/h2&gt;

&lt;p&gt;After the tests are completed, click the following link on the build page to view the results:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--EMINFcLf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://devexpress.github.io/testcafe/images/jenkins-plugin/test-results-link.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--EMINFcLf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://devexpress.github.io/testcafe/images/jenkins-plugin/test-results-link.png" alt="Test results link"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You will see links to screenshots and videos taken during the test.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--R50gsF2i--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://devexpress.github.io/testcafe/images/jenkins-plugin/test-results-view.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--R50gsF2i--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://devexpress.github.io/testcafe/images/jenkins-plugin/test-results-view.png" alt="Test results view"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These artifacts instantly indicate if the Cart button is present on the page.&lt;/p&gt;

&lt;h2&gt;
  
  
  Jenkins Pipeline integration
&lt;/h2&gt;

&lt;p&gt;If you do not wish to use the Jenkins GUI to launch these tests, you can always use the &lt;a href="https://www.jenkins.io/doc/book/pipeline/"&gt;Jenkins Pipeline&lt;/a&gt;. It lets you declaratively configure your CI/CD setup via a Jenkinsfile - a text file checked into the project's source control repository. The following is a sample Jenkinsfile to be used with TestCafe:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;pipeline&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;agent&lt;/span&gt; &lt;span class="n"&gt;any&lt;/span&gt;
    &lt;span class="n"&gt;stages&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;stage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;Run&lt;/span&gt; &lt;span class="no"&gt;E2E&lt;/span&gt; &lt;span class="n"&gt;tests&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;steps&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;sh&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="n"&gt;npm&lt;/span&gt; &lt;span class="n"&gt;install&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;
                &lt;span class="n"&gt;sh&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="n"&gt;npm&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;e2e&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
            &lt;span class="n"&gt;post&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;always&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                          &lt;span class="n"&gt;junit&lt;/span&gt; &lt;span class="nl"&gt;keepLongStdio:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                          &lt;span class="nl"&gt;testDataPublishers:&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt;&lt;span class="n"&gt;$class&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;TestCafePublisher&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="o"&gt;]],&lt;/span&gt;
                          &lt;span class="nl"&gt;testResults:&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="o"&gt;*.&lt;/span&gt;&lt;span class="na"&gt;xml&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;
                &lt;span class="o"&gt;}&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note: The &lt;code&gt;test-e2e&lt;/code&gt; npm script in this example launches TestCafe. As mentioned earlier in this topic, be sure to manually set the reporter option. For more information on the TestCafe CLI, see the following help topic: &lt;a href="https://devexpress.github.io/testcafe/documentation/reference/command-line-interface.html"&gt;Command Line Interface&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;--&lt;/p&gt;

&lt;p&gt;If you enjoyed this guide and would like more tips on debugging, please see the following blog articles: &lt;a href="https://devexpress.github.io/testcafe/media/team-blog/how-to-debug-tests-in-testcafe-quick-guide.html"&gt;How to Debug Tests in TestCafe: Quick Guide&lt;/a&gt; and &lt;a href="https://devexpress.github.io/testcafe/media/team-blog/how-to-speed-up-debugging-in-testcafe-tips-and-tricks.html"&gt;How to speed up debugging in TestCafe: Tips and Tricks&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>testing</category>
      <category>javascript</category>
      <category>jenkins</category>
      <category>e2e</category>
    </item>
    <item>
      <title>Upcoming Webinar: 10 Ways to Simplify Your UI Testing</title>
      <dc:creator>TestCafe</dc:creator>
      <pubDate>Tue, 21 Jul 2020 12:31:52 +0000</pubDate>
      <link>https://dev.to/dxtestcafe/upcoming-webinar-10-ways-to-simplify-your-ui-testing-3j7b</link>
      <guid>https://dev.to/dxtestcafe/upcoming-webinar-10-ways-to-simplify-your-ui-testing-3j7b</guid>
      <description>&lt;p&gt;In this free webinar, our Technical Evangelist &lt;a href="https://twitter.com/paul__usher"&gt;Paul Usher&lt;/a&gt; will show you how to easily incorporate UI testing in your development workflow. Paul will demonstrate how TestCafe can fit in any organization and how its features can be leveraged to deliver high quality web apps that always meet end-user expectations.&lt;/p&gt;

&lt;p&gt;In this webinar, you’ll learn:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How to setup TestCafe and start testing in under 10 minutes.&lt;/li&gt;
&lt;li&gt;How to create customizable tests that can easily evolve as business requirements change.&lt;/li&gt;
&lt;li&gt;The purpose of Custom Selectors and why they make web testing so much easier.&lt;/li&gt;
&lt;li&gt;The purpose of the Page Model approach and why it helps increase productivity.&lt;/li&gt;
&lt;li&gt;And you'll learn how to master use of Smart Assertions.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Experience the TestCafe Difference
&lt;/h1&gt;

&lt;p&gt;TestCafe Open Source and TestCafe Studio are driver free and do not require you to manage complex plug-ins. If you’re ready to test your web apps and want to deliver more reliable solutions to your end-users, be sure to click the link below and register your interest in this live webinar.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Webinar Date:&lt;/strong&gt; Wednesday, July 29, 2020&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Start Time:&lt;/strong&gt; 10AM Pacific Time&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://dxpr.es/2WhlBrT"&gt;Register&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>e2e</category>
      <category>testing</category>
      <category>javascript</category>
      <category>webtesting</category>
    </item>
    <item>
      <title>How to Speed up Debugging in TestCafe: Tips and Tricks</title>
      <dc:creator>TestCafe</dc:creator>
      <pubDate>Mon, 13 Jul 2020 12:48:15 +0000</pubDate>
      <link>https://dev.to/dxtestcafe/how-to-speed-up-debugging-in-testcafe-tips-and-tricks-dcd</link>
      <guid>https://dev.to/dxtestcafe/how-to-speed-up-debugging-in-testcafe-tips-and-tricks-dcd</guid>
      <description>&lt;p&gt;In the previous post, we talked about the approaches you can follow to debug TestCafe tests. In this post, we will focus on best practices that help you save time while debugging. We will also mention a few things to keep in mind in order to write easy-to-debug tests.&lt;/p&gt;

&lt;h1&gt;
  
  
  Tips on how to debug tests
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;If you know which test throws an error, run this test separately.&lt;/strong&gt;&lt;br&gt;
If you only need to check one test, do not wait until all tests pass. TestCafe can run any single test separately. Add the &lt;a href="https://devexpress.github.io/testcafe/documentation/reference/command-line-interface.html#-t-name---test-name"&gt;--test shell argument&lt;/a&gt; or use the &lt;a href="https://devexpress.github.io/testcafe/documentation/reference/test-api/test/only.html"&gt;test.only&lt;/a&gt; method in test code. (Be sure to remove &lt;code&gt;.only&lt;/code&gt; before you commit changes.)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;testcafe&lt;/span&gt; &lt;span class="nx"&gt;chrome&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;tests&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="nx"&gt;test&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;My test name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&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;My first test&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cm"&gt;/* ... */&lt;/span&gt;
&lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nx"&gt;only&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Use live mode when you edit tests.&lt;/strong&gt;&lt;br&gt;
If you find yourself running a test repeatedly while you write or debug it, try live mode. In this mode, TestCafe watches the test file and restarts the test automatically after you save changes. To enable live mode, run the test with the &lt;a href="https://devexpress.github.io/testcafe/documentation/reference/command-line-interface.html#-l---live"&gt;--live flag&lt;/a&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="nx"&gt;testcafe&lt;/span&gt; &lt;span class="nx"&gt;chrome&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;tests&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="nx"&gt;live&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;To identify an issue visually, decrease the test speed.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;By default, tests are executed at full speed – with minimum delays between actions and assertions. This makes it difficult to identify problems visually during a test run. To slow the test down, use the &lt;a href="https://devexpress.github.io/testcafe/documentation/reference/command-line-interface.html#--speed-factor"&gt;-speed flag&lt;/a&gt;. The argument value is between &lt;code&gt;1&lt;/code&gt; (fastest) and &lt;code&gt;0.01&lt;/code&gt; (slowest).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;testcafe&lt;/span&gt; &lt;span class="nx"&gt;chrome&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;tests&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="nx"&gt;speed&lt;/span&gt; &lt;span class="mf"&gt;0.1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Use TestCafe Studio to determine why a selector does not work.&lt;/strong&gt;&lt;br&gt;
TestCafe may report that a selector does not return any element, although you have written it correctly. The reason may be an invisible DOM element that matches the same selector expression. To get a better understanding of the issue, record a similar test in TestCafe Studio and compare your selector to the selector that is generated.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If a test fails on CI, use screenshots and videos to clarify the reason.&lt;/strong&gt;&lt;br&gt;
You do not have to run a test locally to determine the reason why a test fails on CI. TestCafe can take a screenshot when the test fails and record a video of the test run. To enable screenshots and video recording, use the &lt;a href="https://devexpress.github.io/testcafe/documentation/reference/command-line-interface.html#-s---screenshots-on-fails"&gt;--screenshots-on-fail&lt;/a&gt; and &lt;a href="https://devexpress.github.io/testcafe/documentation/reference/command-line-interface.html#--video-basepath"&gt;--video&lt;/a&gt; CLI options. See the following help topic for details: &lt;a href="https://devexpress.github.io/testcafe/documentation/guides/advanced-guides/screenshots-and-videos.html"&gt;Screenshots and Videos&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Tips on how to write tests that are easy to debug
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;Tests should be easy to run locally.&lt;/strong&gt;&lt;br&gt;
If it is difficult to run a test locally, developers are likely to delay test fixes, so that they turn 'green' only shortly before the release. These delays may complicate the debug process.&lt;/p&gt;

&lt;p&gt;Developers can easily reproduce test scenarios locally and maintain 'green' tests if the following is true:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tests are isolated from each other.&lt;/li&gt;
&lt;li&gt;The workstation environment is similar to the test environment.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ideally, a developer must be able to run any test locally with a single command, which requires the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The product test build is easy to run in a Docker container (or by another approach that emulates the test environment).&lt;/li&gt;
&lt;li&gt;Test data is seeded in test code (for example, within the before and after hooks).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Tests should be independent.&lt;/strong&gt;&lt;br&gt;
If subsequent tests use data produced by previous tests, you can expect the following two issues:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When a previous test fails, all dependent tests will also fail.&lt;/li&gt;
&lt;li&gt;You cannot debug a test until all previous tests are complete.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To simplify debugging in the future, be sure to avoid dependencies between tests.&lt;/p&gt;

&lt;p&gt;For more best practice tips, see the following help topic: &lt;a href="https://devexpress.github.io/testcafe/media/team-blog/how-to-scroll-web-pages-using-testcafe.html"&gt;How to Scroll Web Pages Using TestCafe&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>e2etesting</category>
      <category>webtesting</category>
      <category>e2e</category>
      <category>webdev</category>
    </item>
    <item>
      <title>TestCafe Studio v1.3.0 - A New Way to Work with Selectors</title>
      <dc:creator>TestCafe</dc:creator>
      <pubDate>Mon, 22 Jun 2020 10:29:09 +0000</pubDate>
      <link>https://dev.to/dxtestcafe/testcafe-studio-v1-3-0-a-new-way-to-work-with-selectors-3pc2</link>
      <guid>https://dev.to/dxtestcafe/testcafe-studio-v1-3-0-a-new-way-to-work-with-selectors-3pc2</guid>
      <description>&lt;p&gt;TestCafe's Visual Test Recorder automatically creates selectors for all elements used in a test. This complicated algorithm balances many different variables, and we just recently added a few options so that you can customize it to meet your specific needs.&lt;/p&gt;

&lt;p&gt;This article first covers what we consider to be a reliable selector. We then mention the pros and cons of various selector strategies, and custom attributes in particular. Finally, we'll show you how to customize TestCafe options so that it builds selectors that are optimized for your website.&lt;/p&gt;

&lt;h1&gt;
  
  
  How TestCafe Studio Generates Selectors
&lt;/h1&gt;

&lt;p&gt;To record an automated test in &lt;a href="https://www.devexpress.com/products/testcafestudio/"&gt;TestCafe Studio&lt;/a&gt;, specify the tested page’s URL and start the recorder. TestCafe Studio launches the selected browser, opens the web page, and records your actions. Once the test scenario is ready, you can run it in any local browser, a mobile device, or as part of your CI pipeline.&lt;/p&gt;

&lt;p&gt;TestCafe Studio not only records your actions (element clicks, text input), but it also creates a selector for every affected page element. The selector generation algorithm was developed to adhere to the following requirements:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Selectors shouldn’t be too specific.&lt;/strong&gt; Otherwise, you might have to rewrite them after each page modification. For instance, &lt;code&gt;Selector(‘body’).find(‘div’).nth(5).find(‘p’).nth(3)&lt;/code&gt; must be revised each time the number of elements on the page changes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Selectors shouldn't be too generic.&lt;/strong&gt; Otherwise, they may return different elements after each markup change. For example, &lt;code&gt;Selector(‘div &amp;gt; button’)&lt;/code&gt; can match multiple elements at once.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Selectors shouldn’t rely on element parameters that are likely to change.&lt;/strong&gt; For instance, &lt;code&gt;Selector('[style*="background-color: red"]')&lt;/code&gt; uses a CSS style that changes frequently.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Selectors should remain readable.&lt;/strong&gt; Selectors should be easy to understand (by you or another developer) for as long as the test is maintained. For instance, it may be difficult to understand which element corresponds to the following selector: &lt;code&gt;Selector(‘div’).find(‘pre’).nextSibling(-1)&lt;/code&gt;. If you use &lt;code&gt;Selector(‘#topContainer’).find(‘.child’).withText(‘Add item’)&lt;/code&gt; instead, the selector is much easier to read.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Selectors should reflect the user’s point of view.&lt;/strong&gt; Since TestCafe supports end-to-end testing, it’s a good idea to build selectors that identify elements as an end-user would. For instance, &lt;code&gt;Selector(‘form’).find(‘[name=”btn-foo-123”]’)&lt;/code&gt; might be stable, but it is written from the programmer’s perspective rather than from the user’s point of view.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In addition to these general requirements for selectors, page organization is also vital in the testing process. Some pages may have stable selectors that rely on the ‘id’ attribute, while other pages use auto-generated ‘id’ attributes - so it does not make sense to use ‘id’ in a selector. This also applies to other attributes such as ‘class’. Text-based selectors can also be ineffective, depending on changes you introduce to the page over time.&lt;/p&gt;

&lt;h1&gt;
  
  
  Why Custom Attributes are Required
&lt;/h1&gt;

&lt;p&gt;Modern web component frameworks, like React, complicate DOM element identification. This is why many developers prefer to assign custom attributes to page elements. Custom attributes enable tests to survive changes in HTML structure, script behavior, and styles.&lt;/p&gt;

&lt;p&gt;Let’s consider the following Populate button on our example page:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;button&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;populate&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;testid&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;populate-button&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Populate&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can build the following selectors for this button:&lt;/p&gt;

&lt;h3&gt;
  
  
  HTML-based
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Selector:&lt;/strong&gt; &lt;code&gt;Selector('input').nth(1)&lt;/code&gt;&lt;br&gt;
&lt;strong&gt;Pros and Cons:&lt;/strong&gt; Too generic.&lt;br&gt;
&lt;strong&gt;Summary:&lt;/strong&gt; Might match the wrong elements because it is vague.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Selector:&lt;/strong&gt; &lt;code&gt;Selector('body').find('form').find('div').find('fieldset').find('input').nth(1)&lt;/code&gt;&lt;br&gt;
&lt;strong&gt;Pros and Cons:&lt;/strong&gt; Too strict.&lt;br&gt;
&lt;strong&gt;Summary:&lt;/strong&gt; May break due to minor changes in HTML structure.&lt;/p&gt;

&lt;h3&gt;
  
  
  ID-based
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Selector:&lt;/strong&gt; &lt;code&gt;Selector('#populate')&lt;/code&gt;&lt;br&gt;
&lt;strong&gt;Pros and Cons:&lt;/strong&gt; Relies on ID only, which could be introduced for styling or event handling, or may be auto-generated.&lt;br&gt;
&lt;strong&gt;Summary:&lt;/strong&gt; Better options are available.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Selector:&lt;/strong&gt; &lt;code&gt;Selector('#main-form').find('input').nth(1)&lt;/code&gt;&lt;br&gt;
&lt;strong&gt;Pros and Cons:&lt;/strong&gt; Similar to the above selector, but relies on the parent ID.&lt;br&gt;
&lt;strong&gt;Summary:&lt;/strong&gt; Appears to be more specific than the above selector, but it is not.&lt;/p&gt;

&lt;h3&gt;
  
  
  Class-based
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Selector:&lt;/strong&gt; &lt;code&gt;Selector('.column.col-1').find('input').nth(1)&lt;/code&gt;&lt;br&gt;
&lt;strong&gt;Pros and Cons:&lt;/strong&gt; The element has no class, so this selector uses the parent class. Classes can change because they are usually assigned for styling purposes.&lt;br&gt;
&lt;strong&gt;Summary:&lt;/strong&gt; Sensitive to CSS modifications; difficult to maintain.&lt;/p&gt;

&lt;h3&gt;
  
  
  Text-based (text matches the attribute value in this case)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Selector:&lt;/strong&gt; &lt;code&gt;Selector('input[value="Populate"]')&lt;/code&gt;&lt;br&gt;
&lt;strong&gt;Pros and Cons:&lt;/strong&gt; Mirrors how users perceive the page, so it may be stable. Detects actual issues caused by accidental text changes.&lt;br&gt;
&lt;strong&gt;Summary:&lt;/strong&gt; Satisfactory, but fails even when text changes are intended.&lt;/p&gt;

&lt;h3&gt;
  
  
  Custom attribute-based
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Selector:&lt;/strong&gt; &lt;code&gt;Selector('[data-testid="populate-button"]')&lt;/code&gt;&lt;br&gt;
&lt;strong&gt;Pros and Cons:&lt;/strong&gt; The most stable selector, since it is not affected by changes.&lt;br&gt;
&lt;strong&gt;Summary:&lt;/strong&gt; The preferred selector type for most scenarios.&lt;/p&gt;

&lt;p&gt;In summary, custom attributes have the following benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Tests do not break based on markup or code changes.&lt;/strong&gt; A test will not fail when you refactor HTML or implement new behavior in JavaScript.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tests do not depend on page styles.&lt;/strong&gt; You can switch themes as many times as you wish - tests will not fail because of a certain style or theme.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Text content modifications do not affect tests.&lt;/strong&gt; Tests are not affected by changes to content, including localization changes. Note, however, that if an element’s text is essential to a test scenario, you should verify the text content or use a text-based selector: &lt;code&gt;Selector(‘div’).withText(‘Add to Cart’).&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Use a custom attribute to indicate that an element is used in tests.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  A New Way to Customize Selectors
&lt;/h1&gt;

&lt;p&gt;When you record a test, TestCafe automatically generates a selector. TestCafe also lets you choose an alternative selector from a drop-down list or create one manually. The latest TestCafe update (v1.3.0) ships with an adjustable selector generation algorithm. You can now configure the selector generator on the fly, based on the tested page:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Prioritize selector types.&lt;/strong&gt; Use this option if you often need to choose a different selector from the suggestion list. The default selector is generated based on your preferences.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jD2_geDG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://community.devexpress.com/blogs/testcafe/Studio1.3.0/1%402x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jD2_geDG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://community.devexpress.com/blogs/testcafe/Studio1.3.0/1%402x.png" alt="Prioritize selector types"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Disable unwanted selector types.&lt;/strong&gt; For instance, your website can generate id, class, or other element attributes automatically, so that they change each time the page reloads. However, you cannot use these values in selectors because the test cannot be replayed. In this instance, you may want to exclude these attributes from selector generation rules. You can now simply disable the corresponding selector type - and switch back to it at any time - without restarting the recorder.&lt;br&gt;
![Disable unwanted selector types](&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--uyj6yS-m--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/7md4rv04r74sugly0vph.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--uyj6yS-m--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/7md4rv04r74sugly0vph.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Add selector types based on custom attributes.&lt;/strong&gt; These selector types are preferred because if you configure them, you won’t have to edit selectors due to changes. The only requirement is that you maintain unique attribute values during development.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Ah_-4Qag--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://community.devexpress.com/blogs/testcafe/Studio1.3.0/3%402x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Ah_-4Qag--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://community.devexpress.com/blogs/testcafe/Studio1.3.0/3%402x.png" alt="Add selector types based on custom attributes"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Recap
&lt;/h1&gt;

&lt;p&gt;TestCafe Studio generates selectors for every page element that takes part in a test. Good selectors must comply with strict guidelines to be stable and reliable. TestCafe algorithms use best practices to generate selectors that meet these criteria. You can also optimize selectors based on your understanding of how the website works. Our latest update (v1.3.0) allows you to instruct TestCafe Studio to use custom attributes in selectors or ignore dynamic IDs. The result is more stable selectors that are easy to read and maintain.&lt;/p&gt;

&lt;p&gt;You can read more about the new adjustable selector generation algorithm in our &lt;a href="https://docs.devexpress.com/TestCafeStudio/400407/test-actions/element-selectors#element-selector-types"&gt;documentation&lt;/a&gt;. As always, we are happy to answer your questions in the comments. Happy testing!&lt;/p&gt;

</description>
      <category>e2etesting</category>
      <category>webtesting</category>
      <category>e2e</category>
      <category>webdev</category>
    </item>
    <item>
      <title>How to Debug Tests in TestCafe: Quick Guide</title>
      <dc:creator>TestCafe</dc:creator>
      <pubDate>Tue, 02 Jun 2020 12:45:53 +0000</pubDate>
      <link>https://dev.to/dxtestcafe/how-to-debug-tests-in-testcafe-quick-guide-2am</link>
      <guid>https://dev.to/dxtestcafe/how-to-debug-tests-in-testcafe-quick-guide-2am</guid>
      <description>&lt;p&gt;If you've ever written a TestCafe test, you may be familiar with the following errors:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cannot obtain information about the node because the specified selector does not match any node in the DOM tree.&lt;/li&gt;
&lt;li&gt;The specified selector does not match any element in the DOM tree.&lt;/li&gt;
&lt;li&gt;The element that matches the specified selector is not visible.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The first two errors are self-explanatory. The last error, however, can easily be misinterpreted. This error frequently occurs if multiple elements match the same selector. The first matching element may be hidden, while the required element is visible.&lt;/p&gt;

&lt;p&gt;What should you do next? How do you update the selector so that it produces expected results? What should you do if the test previously passed, but it now fails?&lt;/p&gt;

&lt;p&gt;First, check the application to ensure that the test didn't fail due to a bug. If the app runs as expected, then you can begin debugging the test.&lt;/p&gt;

&lt;h1&gt;
  
  
  Client-side Debugging
&lt;/h1&gt;

&lt;p&gt;TestCafe uses CSS selectors to identify page elements. To see if a selector matches an element, pause test execution in the browser and debug the test.&lt;/p&gt;

&lt;p&gt;To stop the test, you can use the &lt;a href="https://devexpress.github.io/testcafe/documentation/reference/command-line-interface.html#--debug-on-fail"&gt;--debug-on-fail&lt;/a&gt; CLI flag or the &lt;a href="https://devexpress.github.io/testcafe/documentation/reference/test-api/testcontroller/debug.html"&gt;t.debug()&lt;/a&gt; test action. The difference between these approaches is summarized below:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;code&gt;t.debug()&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;--debug-on-fail&lt;/code&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Allows you to define the moment when the test stops.&lt;/td&gt;
&lt;td&gt;Suspends the test only if it fails.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;You only need to modify the test code to use it.&lt;/td&gt;
&lt;td&gt;Requires that you edit the test run command (which may take longer than the &lt;a href="https://devexpress.github.io/testcafe/documentation/reference/test-api/testcontroller/debug.html"&gt;t.debug()&lt;/a&gt; action).&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Let's look at a test from the TestCafe &lt;a href="https://devexpress.github.io/testcafe/documentation/getting-started/"&gt;Getting Started&lt;/a&gt; topic. Assume the &lt;strong&gt;Submit&lt;/strong&gt; button's selector changed and the test failed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Selector&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;testcafe&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;fixture&lt;/span&gt; &lt;span class="s2"&gt;`Getting Started`&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="s2"&gt;`http://devexpress.github.io/testcafe/example`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;My first test&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;typeText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#developer-name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;John Smith&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;click&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#submit-button-invalid&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;// Use the assertion to check if the actual header text is equal to the expected one&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Selector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#article-header&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;innerText&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;eql&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Thank you, John Smith!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The test now throws the following error when we run it:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--gb16cboc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://devexpress.github.io/testcafe/images/blog/2020-5-25-dev-tools.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gb16cboc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://devexpress.github.io/testcafe/images/blog/2020-5-25-dev-tools.png" alt="Error"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Insert &lt;a href="https://devexpress.github.io/testcafe/documentation/reference/test-api/testcontroller/debug.html"&gt;t.debug()&lt;/a&gt; before the line that fails:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;typeText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#developer-name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;John Smith&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;debug&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;click&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#submit-button-invalid&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The test pauses before the button click. You can now use browser utilities to see if any elements match the selector.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--dmB-VmFh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ww8zoljstqxr0y7qq1yj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dmB-VmFh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ww8zoljstqxr0y7qq1yj.png" alt="Browser utilities"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Since &lt;code&gt;document.querySelectorAll&lt;/code&gt; returns an empty list, you can see that there is no such element on the page, but the &lt;em&gt;Submit&lt;/em&gt; button is visible. Use the &lt;em&gt;Inspect&lt;/em&gt; command to see how this button is rendered in markup:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SI2HDL-K--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://devexpress.github.io/testcafe/images/blog/2020-5-25-inspect.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SI2HDL-K--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://devexpress.github.io/testcafe/images/blog/2020-5-25-inspect.png" alt="Inspect"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The browser's development tools pane shows that the button's ID is &lt;code&gt;submit-button&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;Note.&lt;/em&gt;&lt;/strong&gt; You can use Chrome Dev Tools' shortcuts (&lt;code&gt;$&lt;/code&gt; and &lt;code&gt;$$&lt;/code&gt;) to query selectors. However, if your website uses jQuery, the &lt;code&gt;$&lt;/code&gt; shortcut is overridden. TestCafe searches for elements with &lt;code&gt;document.querySelectorAll&lt;/code&gt;, which behaves in a slightly different way than jQuery. Please keep this in mind.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To use an element inside an iframe, switch the browsing context with &lt;a href="https://devexpress.github.io/testcafe/documentation/reference/test-api/testcontroller/switchtoiframe.html"&gt;t.switchToIframe&lt;/a&gt; before the action.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;Hint.&lt;/em&gt;&lt;/strong&gt; Google Chrome lets you pause complex animations that your website might play when elements appear. To stop JavaScript execution, press &lt;code&gt;F8&lt;/code&gt; when the &lt;strong&gt;Sources&lt;/strong&gt; tab is open.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  Debugging Client Functions
&lt;/h1&gt;

&lt;p&gt;Another client-side debugging trick in TestCafe allows you to execute code within the browser to obtain client-side data or identify page elements.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getStoredValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ClientFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&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;return&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getCell&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Selector&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;table&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;column&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;return&lt;/span&gt; &lt;span class="nx"&gt;table&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;querySelectorAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;tr&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;querySelectorAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;td&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="nx"&gt;column&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To debug this code, add the &lt;code&gt;debugger&lt;/code&gt; statement. The browser will stop the script and open developer tools.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getStoredValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ClientFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&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;debugger&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getCell&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Selector&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;table&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;column&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;debugger&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;table&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;querySelectorAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;tr&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;querySelectorAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;td&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="nx"&gt;column&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;h1&gt;
  
  
  Server-side Debugging
&lt;/h1&gt;

&lt;p&gt;Test flow can be complicated if it includes data preparation, HTTP requests or database access. You can use Node.js to debug this code, along with Visual Studio Code, WebStorm, or Chrome Developer Tools. See the &lt;a href="https://devexpress.github.io/testcafe/documentation/recipes/"&gt;Recipes&lt;/a&gt; for details.&lt;/p&gt;

&lt;p&gt;Note that it is easier to use client-side debugging to execute chained actions step by step. The server treats the entire chain as a single action, so you must divide it into separate actions to debug.&lt;/p&gt;

&lt;h1&gt;
  
  
  Stay Tuned for More Information on Test Debugging
&lt;/h1&gt;

&lt;p&gt;As explained in this blog post, TestCafe and modern browsers offer all the tools necessary to debug your application or test. Note, however, that tools do not always locate errors quickly and easily. We've often spent more time debugging than desired. In our next blog post, I'll share a few techniques that may save time when you debug a test.&lt;/p&gt;

&lt;p&gt;If you have any questions or want to share your test debugging story – write to us directly at &lt;a href="mailto:testcafeteam@devexpress.com"&gt;testcafeteam@devexpress.com&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>e2etesting</category>
      <category>webtesting</category>
      <category>e2e</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
