<?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: Marcelo C.</title>
    <description>The latest articles on DEV Community by Marcelo C. (@marcelo_sqe).</description>
    <link>https://dev.to/marcelo_sqe</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%2F1805681%2Fe450e775-428b-46c4-9bb6-869551761185.jpg</url>
      <title>DEV Community: Marcelo C.</title>
      <link>https://dev.to/marcelo_sqe</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/marcelo_sqe"/>
    <language>en</language>
    <item>
      <title>How I stopped declaring login in each of my 5k tests</title>
      <dc:creator>Marcelo C.</dc:creator>
      <pubDate>Fri, 27 Feb 2026 19:26:44 +0000</pubDate>
      <link>https://dev.to/cypress/how-i-stopped-declaring-login-in-each-of-my-5k-tests-37km</link>
      <guid>https://dev.to/cypress/how-i-stopped-declaring-login-in-each-of-my-5k-tests-37km</guid>
      <description>&lt;p&gt;Have you ever encountered a testing codebase that many portions are repeated over and over? We all have! Of course, I could be talking about DRY princples (Don't Repeat Yourself), but lets keep that aside for now and focus on a Cypress trick up it's sleeve that can go unnoticed for many senior devs: the global hooks.&lt;/p&gt;

&lt;p&gt;And what do I mean by "global" hooks? They're called like that because you only declare them once and they're applied to all your tests instantly. &lt;/p&gt;

&lt;p&gt;So let's get to the grain here: when installing Cypress it already comes with a file at created at &lt;code&gt;cypress/support/e2e.&amp;lt;ts|js&amp;gt;&lt;/code&gt; level. This is usually where you declare some important commands &lt;em&gt;imports&lt;/em&gt; that your E2E testing will need to access and run properly.&lt;/p&gt;

&lt;p&gt;But it's also responsible for adding let's say &lt;em&gt;before&lt;/em&gt;, &lt;em&gt;beforeEach&lt;/em&gt;, or &lt;em&gt;after&lt;/em&gt;, &lt;em&gt;afterEach&lt;/em&gt; hooks that will be applied by all your tests. This can be responsible for login hooks, clean-ups to the database after the tests run, screenshots resolutions configuration -- a million of possibilities here.&lt;/p&gt;

&lt;p&gt;I guess that the "global hooks" makes more sense now, right? &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The challenge&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;At my workplace, I encountered the command to login, called &lt;code&gt;cy.login&lt;/code&gt;, declared in each of the 5.634 tests that we have. For a while it bothered me a lot, because I always wanted to remove this codelines, and make my life easier with a simple &lt;code&gt;e2e.ts&lt;/code&gt; file that handled all existing and new login logic for future tests.&lt;/p&gt;

&lt;p&gt;But if I knew how it worked, why didn't I just do it already? &lt;/p&gt;

&lt;p&gt;Becuase, for the first time (for me), I was dealing with a really complex system: a big chunk of the legacy tests ran with &lt;code&gt;testIsolation: false&lt;/code&gt;. That meant that they only login once, and the &lt;code&gt;it&lt;/code&gt; blocks don't load a new baseURL after each one is done. They do it all in one session.&lt;/p&gt;

&lt;p&gt;Because? Well, that would be another story, so let's just accept their done like that for "system requirements" at the time.&lt;/p&gt;

&lt;p&gt;Ok, so I basically needed:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;before() → cy.login()&lt;br&gt;
beforeEach() → cy.login() only if testIsolation is true&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Easy right? Not yet. The complexity resides because different spec families have different needs: different credentials, different environments, different session strategies, and different testIsolation settings. &lt;/p&gt;

&lt;p&gt;There are two needs here to login:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Which login method?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;cy.login(): Default specs with standard app with default credential.&lt;/li&gt;
&lt;li&gt;cy.loginDemo(): Presentation specs with different environment, likely SSO or different credentials.&lt;/li&gt;
&lt;li&gt;Custom (own login): Need specific credentials or totally different E2E tests outside enviroment.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;When to login? (before vs beforeEach)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is driven by Cypress's testIsolation setting:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;testIsolation: true&lt;/code&gt; — Cypress clears browser state (cookies, storage) between each test. Session is lost → must re-login before each test.&lt;br&gt;
&lt;code&gt;testIsolation: false&lt;/code&gt; — Cookies persist across tests in the same spec → login once is enough.&lt;/p&gt;

&lt;p&gt;Now, here is where the plot thickens. I had to declare folders, tests, paths that needed to be skipped (or not), because on the same folder I had &lt;code&gt;testIsolation: true/false&lt;/code&gt;. So, follow me along:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Legacy specs (/legacy/ folder)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;before()&lt;/code&gt; → skip entirely&lt;br&gt;
&lt;code&gt;beforeEach()&lt;/code&gt; → only call cy.login() if testIsolation is true&lt;/p&gt;

&lt;p&gt;Legacy specs use specific credentials. If the global before() called cy.login() first, cy.session() would cache the wrong credentials, causing 500 errors when the spec then tries to login with different ones. So global before() is completely skipped. In beforeEach(), it only re-validates when state is actually cleared (testIsolation: true).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Training portal specs (/training/ folder) + Custom login specs&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;before()&lt;/code&gt; → skip entirely&lt;br&gt;
&lt;code&gt;beforeEach()&lt;/code&gt; → skip entirely&lt;/p&gt;

&lt;p&gt;These specs manage their own login end-to-end. The global hooks stay completely out of the way. Some tests likely test login flows themselves or use role-specific credentials.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. BEFORE_LOGIN_DEMO_SPECS&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;before()&lt;/code&gt; → &lt;code&gt;cy.loginDemo() + cy.goToHome()&lt;/code&gt;&lt;br&gt;
&lt;code&gt;beforeEach()&lt;/code&gt; → skip (already logged in)&lt;/p&gt;

&lt;p&gt;Login once per spec, reused across all tests. These are demo/presentation specs where re-logging in per test would be slow and unnecessary.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. BEFORE_EACH_LOGIN_DEMO_SPECS&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;&lt;code&gt;before()&lt;/code&gt; → nothing&lt;br&gt;
&lt;code&gt;beforeEach() → cy.loginDemo() + cy.goToHome()&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Similar to above but login is repeated per test because &lt;code&gt;testIsolation: true&lt;/code&gt;, the state is cleared between tests, so they must re-login each time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. LOGIN_DEMO_SPECIAL_SPECS&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;before() → nothing&lt;br&gt;
beforeEach() → override baseUrl + timeout + idp_active env, then cy.loginDemo()&lt;/p&gt;

&lt;p&gt;This spec runs against a completely different server, with an IDP/SSO active flag and a much longer timeout. The config must be set before each test because test isolation may reset Cypress config state.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. Default specs (everything else, A.K.A the MOST important logic!)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;before() → cy.login()&lt;br&gt;
beforeEach() → cy.login() only if testIsolation is true&lt;/p&gt;

&lt;p&gt;Standard app, default credentials. Login once in before(), then beforeEach() only re-validates the session if Cypress actually cleared it (testIsolation: true). If testIsolation is false, cookies persist and calling cy.login() again would navigate back to home, breaking any test that expects to be on a specific page.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The key insight: why before AND beforeEach?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You're asking "are you mental? why on earth would you declare login TWICE?", basically because:&lt;/p&gt;

&lt;p&gt;before()     → establishes the initial session (runs once)&lt;br&gt;
beforeEach() → re-validates/restores the session if testIsolation cleared it&lt;/p&gt;

&lt;p&gt;For specs with testIsolation: false, beforeEach() is a no-op (or returns early) because the session is still alive. For specs with testIsolation: true, beforeEach() must re-run the login to restore the cleared session — but it uses cy.session() internally which caches credentials.&lt;/p&gt;

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

&lt;p&gt;Here's a sneak peek of how my &lt;code&gt;e2e.ts&lt;/code&gt; file looks in it's (hopefully) final form:&lt;/p&gt;

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

&lt;p&gt;And I basically removed the cy.login function from more than 1k files in my codebase, leaving me or any other engineer to not worry anymore about the login being declared at test level, it handles everything for me now, as it should.&lt;/p&gt;

&lt;p&gt;What about you? Have you ever encountered a challenging and complex test codebase to deal with? What was the most difficult change you had to make? Leave me a comment, I would love to hear!&lt;/p&gt;

</description>
      <category>cypress</category>
      <category>e2etesting</category>
      <category>typescript</category>
      <category>login</category>
    </item>
    <item>
      <title>How to validate tables, rows or any content of an Excel file using Cypress</title>
      <dc:creator>Marcelo C.</dc:creator>
      <pubDate>Fri, 31 Oct 2025 11:43:24 +0000</pubDate>
      <link>https://dev.to/cypress/how-to-validate-a-content-of-an-xlsx-file-using-cypress-45da</link>
      <guid>https://dev.to/cypress/how-to-validate-a-content-of-an-xlsx-file-using-cypress-45da</guid>
      <description>&lt;p&gt;At the company I work for, we already have many test cases to validate a key behavior of our SaaS, which through the user downloads a table as an Excel file of the information needed. But there was a need to validate some edge cases, in which we also needed to validate that the content corresponds to what the table showed.&lt;/p&gt;

&lt;p&gt;This would mean that Cypress needs to deterministically validate rows, numbers, names and even colors inside the Excel file set by our user flows. After some research, we basically came upon two &lt;em&gt;Node.js&lt;/em&gt; libs: &lt;code&gt;@e965/xlsx&lt;/code&gt; and &lt;code&gt;exceljs&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;While &lt;code&gt;@e965/xlsx&lt;/code&gt; is mostly used for data content validation, as in validating a JSON rows straight from the sheet - &lt;code&gt;exceljs&lt;/code&gt; is more focused for style assertion, meaning assertions like “is A1 light-green?”. All right, so now we could split keeps tests readable and fast.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Configuring &lt;a class="mentioned-user" href="https://dev.to/e965"&gt;@e965&lt;/a&gt;/xlsx library&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;First, wire up the configuration in Cypress. Head off to Node with cy.task(). It’s the official way to run filesystem code from Cypress tests: register tasks in setupNodeEvents and they’ll return values back to your spec.&lt;/p&gt;

&lt;p&gt;Remember to also import the package on the config file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//cypress.config.ts

const xlsx = require('@e965/xlsx');
...
...
...
      on('task', {
        async readExcelByPattern(pattern: string, timeoutMs = 15000) {
          const re = new RegExp(pattern);
          const end = Date.now() + timeoutMs;

          while (Date.now() &amp;lt; end) {
            const files = fs.readdirSync(downloadsDir).filter(f =&amp;gt; re.test(f) &amp;amp;&amp;amp; !f.endsWith('.crdownload') &amp;amp;&amp;amp; !f.endsWith('.tmp'));

            if (files.length) {
              const { fullPath } = files
                .map(f =&amp;gt; {
                  const fullPath = path.join(downloadsDir, f);
                  return { fullPath, mtime: fs.statSync(fullPath).mtimeMs };
                })
                .sort((a, b) =&amp;gt; b.mtime - a.mtime)[0];

              await sleep(200);

              const wb = xlsx.readFile(fullPath);
              const sheet = wb.Sheets[wb.SheetNames[0]];
              const data = xlsx.utils.sheet_to_json(sheet);
              return { fileName: path.basename(fullPath), data };
            }

            await sleep(300);
          }

          throw new Error(`File .xlsx taht matches /${pattern}/ not found on "${downloadsDir}" inside ${timeoutMs}ms`);
        },
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can see that &lt;code&gt;readExcelByPattern&lt;/code&gt; is the task we should call to validate the content like rows, tables and any information inside the Excel file. You can then define it inside your test context and methods (or define it globally over &lt;code&gt;commands.ts&lt;/code&gt; if you plan to use it in many tests), but for a single test it should look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//my-testing-context.ts

  @step('Read downloaded excel values')
  readExcelDownloadedFile(
    pathToFile: string = 'excel_export/bugs/',
    fixture: string,
    fileName: string
  ): ExportPrintableReportContext&amp;lt;TParent&amp;gt; {
    cy.fixture(pathToFile + fixture).then((expected: any[]) =&amp;gt; {
      cy.task('readExcelByPattern', fileName).then(({ data }: { data: any[] }) =&amp;gt; {
        expect(data.length, 'Table length').to.equal(expected.length);
        expected.forEach((expectedRow, i) =&amp;gt; {
          const actualRow = data[i];
          Object.entries(expectedRow).forEach(([key, expectedValue]) =&amp;gt; {
            const actualValue = actualRow[key] === undefined ? null : actualRow[key];
            expect(actualValue, `Row ${i} - Column "${key}"`).to.equal(expectedValue);
          });
        });
      });
    });
    return this;
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see it's pretty straight forward, it calls for a JSON file inside 'fixtures/excel_export/bugs/' that already has the values you want to validate and should be equal to the Excel file and executes a forEach of the Table length, and each row, which already awaits for a value.&lt;/p&gt;

&lt;p&gt;And this is how it would look inside a test:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { testContext } from '@/my-testing-context'

const testingContext = new testContext();

describe('example of reading excel files', =&amp;gt; ()
  it('case 1', () =&amp;gt; {
    testingContext.readExcelDownloadedFile('excel_export/bugs/', tk, 'Excel.xlsx');
  });
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Basically it checked 171 rows of the file content and succeeded in 40 seconds.&lt;/p&gt;

&lt;p&gt;For the second part of this tutorial, I'll expand on how to validate Excel colors as well. Happy testing!&lt;/p&gt;

</description>
      <category>node</category>
      <category>javascript</category>
      <category>testing</category>
      <category>automation</category>
    </item>
    <item>
      <title>How to get most out of cy.prompt() - 6 tips and tricks for your new AI tool!</title>
      <dc:creator>Marcelo C.</dc:creator>
      <pubDate>Thu, 09 Oct 2025 13:54:06 +0000</pubDate>
      <link>https://dev.to/cypress/how-to-get-most-out-of-cyprompt-6-tips-and-tricks-for-your-new-ai-tool-425l</link>
      <guid>https://dev.to/cypress/how-to-get-most-out-of-cyprompt-6-tips-and-tricks-for-your-new-ai-tool-425l</guid>
      <description>&lt;p&gt;I know, I know, Cypress has just announced a game changing feature with &lt;a href="https://www.cypress.io/blog/cy-prompt-frequently-asked-questions" rel="noopener noreferrer"&gt;cy.prompt()&lt;/a&gt; that is going to change the way we test - or at least approach how we think of it. You're going to use Natural Language all the way to test your new app? Read through my recommendations then!&lt;/p&gt;

&lt;p&gt;As a Cypress Ambassador I was lucky enough to be using &lt;a href="https://dev.to/marcelo_sqe/how-cypress-will-revolutionize-the-use-of-ai-in-testing-with-cyprompt-5gm2-temp-slug-2006966?preview=9c4ef5e51e58155f38ad1dcbf9f431475aa6874a9ce433001e022fdfd3b97ca85fd89420f5701d27bf06a28628c31b13e4802cb49d6966bf50a7aaee"&gt;cy.prompt&lt;/a&gt; for the past weeks and here are a few tips to make your testing and usage go a bit smoothly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1) Start your phrase with the action or assertion you want&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Instead of giving it an instruction like:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;When the page loads, check that the header is seen and then click on Create button&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Would be better to:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Wait 8 seconds for the page to load&lt;/code&gt;&lt;br&gt;
&lt;code&gt;Assert that the header is visible&lt;/code&gt;&lt;br&gt;
&lt;code&gt;Click on create button&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now Cypress will translate your instructions more easily - a hardcoded &lt;em&gt;wait&lt;/em&gt;, followed by an &lt;em&gt;assertion&lt;/em&gt;, followed by a &lt;em&gt;click&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2) Try to separate instructions&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The previous step gave it away already! Cypress prompt works as any other LLM - give clear instructions of what you want to do and it'll have a better chance to execute it.&lt;/p&gt;

&lt;p&gt;Do not mix assertions, with force clicks, with reloads in the same line of action! The prompt needs to go through, so in a way try to act as a &lt;em&gt;prompt engineer&lt;/em&gt; and step by step you'll get there.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3) You can have up to 20 steps for each prompt you execute&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;20 is the limit, ok. But that doesn't mean that you need to have 20 steps each prompt. Also, the more steps you add, the prone it is to ask for clarifications or make mistakes.&lt;/p&gt;

&lt;p&gt;Think of it as this: each plain English text line you introduce is an abstraction layer, right? Do want an over-complicated test, or a easy to read through, understandable (for non-developers specially) test?&lt;/p&gt;

&lt;p&gt;Lesser is better in some cases!&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;4) Leave some tests in prompt in order to validate flaky behavior&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Got a new feature? Want to avoid brittle in your E2E test? Want to check for any weird behavior here and there? Then cy.prompt is your way to go! You can always leave your tests in plain English to see if the BDD/TDD behavior stays the same. &lt;/p&gt;

&lt;p&gt;Remember: it works in both local and CI - but it only supports Chrome or Chromium browsers (Edge/Electron). Any others are out (sorry Firefox!). Leave it a few days or weeks in your CI in prompt scenario and see what happens.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5) Portability first?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For me any test that is written in plain English has a natural advantage over each other. It doesn't need to be refactored into any other programming language. So if you already know that the application you're working now is starting to be ported into another modern framework, leave your tests in prompt format. Your devs will appreaciate!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6) It's always cached&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Another advantage with cy.prompt is that once it runs, it will cache the steps in order to avoid LLM interaction. But if you change one line in your prompt - wait 15 seconds instead of 8, for example - it will execute all over again.&lt;/p&gt;

&lt;p&gt;Remember this to focus on speed and reliability in your tests!&lt;/p&gt;

</description>
      <category>ai</category>
      <category>testing</category>
      <category>javascript</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>How Cypress will revolutionize the use of AI in testing with cy.prompt()</title>
      <dc:creator>Marcelo C.</dc:creator>
      <pubDate>Thu, 09 Oct 2025 10:28:22 +0000</pubDate>
      <link>https://dev.to/cypress/how-cypress-will-revolutionize-the-use-of-ai-in-testing-with-cyprompt-fe9</link>
      <guid>https://dev.to/cypress/how-cypress-will-revolutionize-the-use-of-ai-in-testing-with-cyprompt-fe9</guid>
      <description>&lt;p&gt;Cypress has become the go-to testing framework for SDETs and QA engineers to validate modern web apps. It’s fast, reliable, and backed by a mature ecosystem—both in &lt;a href="https://docs.cypress.io/app/references/changelog" rel="noopener noreferrer"&gt;software updates&lt;/a&gt; and excellent &lt;a href="https://docs.cypress.io/app/get-started/why-cypress" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;. Add to that the vibrant community building powerful &lt;a href="https://dev.to/sebastianclavijo/my-top-191-favorite-cypress-plugins-for-testing-with-wick-like-precision-3fhh"&gt;plugins and extensions&lt;/a&gt;, and it’s clear why Cypress dominates the testing landscape.&lt;/p&gt;

&lt;p&gt;Cypress is taking a bold step into AI-powered testing with the upcoming &lt;a href="https://www.cypress.io/blog/cy-prompt-frequently-asked-questions" rel="noopener noreferrer"&gt;cy.prompt()&lt;/a&gt;. Unlike typical AI integrations that act as external copilots or rely on general-purpose &lt;em&gt;MCP-style&lt;/em&gt; assistants, &lt;code&gt;cy.prompt()&lt;/code&gt; adds the intent (what we want) built directly into the testing workflow.&lt;/p&gt;

&lt;p&gt;This means no context switching, no juggling between an IDE plugin and your test runner. Instead, Cypress allows you to describe your intent in plain English, and the AI automatically generates selectors, actions, and assertions right inside your test.&lt;/p&gt;

&lt;p&gt;It’s a shift from writing tests line by line to guiding your tests conversationally. Think less about &lt;code&gt;cy.get()&lt;/code&gt; or &lt;code&gt;cy.click()&lt;/code&gt; and more about telling Cypress what you want verified, letting the framework translate that into executable code.&lt;/p&gt;

&lt;p&gt;Here’s a video demonstration of &lt;code&gt;cy.prompt()&lt;/code&gt; in action:&lt;/p&gt;

&lt;p&gt;

  &lt;iframe src="https://www.youtube.com/embed/Z_u8R3Z5spw"&gt;
  &lt;/iframe&gt;


&lt;/p&gt;

&lt;p&gt;This is the code that I used in the validation:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz55buxl9xe4od78p2oox.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz55buxl9xe4od78p2oox.png" alt=" raw `cy.prompt()` endraw  in action"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And here is what the prompt suggests of code locators right after is executed:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fag177k1he4h8hj438fik.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fag177k1he4h8hj438fik.png" alt="After usage,  raw `cy.prompt()` endraw  can insert the needed code into your IDE"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Also, you can leave the prompt as it is and push to your CI/CD pipeline:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqxcvxemz08kdy0nwyw91.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqxcvxemz08kdy0nwyw91.png" alt="Github Actions running directly with the prompt and passing"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With &lt;code&gt;cy.prompt()&lt;/code&gt;, Cypress is no longer “just” a testing framework—it’s stepping into the AI-assisted development era. For SDETs and QA engineers, this means faster authoring, smarter locator handling, and easier onboarding for teams.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The possibilities of cy.prompt()&lt;/strong&gt;&lt;br&gt;
&lt;br&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cy.prompt focus on the intent:&lt;/strong&gt; what we want, not how do do it. It's a great tool for non-developers, or anyone who doesn’t want to dive deep into app implementation.

&lt;/li&gt;
&lt;li&gt;Imagine writing the &lt;strong&gt;BDD&lt;/strong&gt; (Behavior Driven Development) acceptance criteria directly into the test. You'll have the best of both worlds here, BDD criteria that is understood by all stakeholders (Project Managers, Product Owners), and the code being executed in the background.

&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;TDD&lt;/strong&gt; (Test-Driven-Development) is also covered for the developers. Imagine developing a feature until is ready and, step by step (word by word, line by line) it start to pass. Until is ready for deployment.

&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Portability is here:&lt;/strong&gt; Need to refactor your project? Move from one programming language to another? Don't need to change a thing in your tests written in plain English, they can be easily shared, exported, or integrated across different systems.

&lt;/li&gt;
&lt;li&gt;Also, another great benefit here are the &lt;strong&gt;self-healing&lt;/strong&gt; tests, they’re more resilient to changes in the DOM or selectors. This feature could fundamentally change how we approach automation. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The future of QA is not just code—it’s collaboration between AI and testers.&lt;/p&gt;

&lt;p&gt;What are your thoughts? &lt;/p&gt;

&lt;p&gt;Share, comment or connect with me directly in &lt;a href="https://www.linkedin.com/in/marceloc/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>cypress</category>
      <category>ai</category>
      <category>promptengineering</category>
      <category>testing</category>
    </item>
  </channel>
</rss>
