<?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>Forem: Nikola</title>
    <description>The latest articles on Forem by Nikola (@ndenic).</description>
    <link>https://forem.com/ndenic</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%2F857439%2F48dcef86-c98a-4784-b236-ffe6522e8c90.png</url>
      <title>Forem: Nikola</title>
      <link>https://forem.com/ndenic</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/ndenic"/>
    <language>en</language>
    <item>
      <title>AI-Powered Test Automation: How Playwright Agents Plan, Write, and Fix Tests for Us</title>
      <dc:creator>Nikola</dc:creator>
      <pubDate>Tue, 14 Oct 2025 19:08:52 +0000</pubDate>
      <link>https://forem.com/ndenic/ai-powered-test-automation-how-playwright-agents-plan-write-and-fix-tests-for-us-4256</link>
      <guid>https://forem.com/ndenic/ai-powered-test-automation-how-playwright-agents-plan-write-and-fix-tests-for-us-4256</guid>
      <description>&lt;p&gt;There’s a point in every QA engineer’s journey when maintaining automated tests becomes harder than writing them.  
You fix one flaky selector, another breaks - a small refactor ripples through half the suite.&lt;/p&gt;

&lt;p&gt;We’ve spent years making automation smarter with patterns, abstractions, and better reporting - but structure alone can’t keep up with change.&lt;/p&gt;

&lt;p&gt;Now, with &lt;strong&gt;Planner&lt;/strong&gt;, &lt;strong&gt;Generator&lt;/strong&gt;, and &lt;strong&gt;Healer&lt;/strong&gt;, Playwright can analyze your UI, plan test cases, fix broken steps, and explain issues in plain English.  
We’re entering a phase where &lt;strong&gt;AI acts like a test engineer that never sleeps&lt;/strong&gt; - one that learns from every failure.&lt;/p&gt;

&lt;p&gt;In this post, I’ll show how I used &lt;strong&gt;Playwright Agents&lt;/strong&gt; on a simple Dockerized Juice Shop app - how they plan, write, and fix tests on their own, and what that means for QA.&lt;/p&gt;

&lt;h3&gt;&lt;strong&gt;Setting the Stage: Starting with Structure&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;Before generating anything, I wanted the AI to understand my folder logic - a clean structure is half the battle in Playwright automation.&lt;/p&gt;

&lt;p&gt;To help the Agent learn that structure, I first created the folders manually inside VS Code Insider - one for each part of the framework: components, fixtures, pages, selectors, tests, and utils.  
Once the structure was ready, I opened the workspace and prompted the Agent to explore it.  
From that point, every generated file automatically followed the same naming and placement pattern I had defined.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;💡 Tip:&lt;/strong&gt; Always define your folder structure before running the Planner.  
This gives the AI context about your framework organization, so instead of creating random files, it will follow your layout and naming conventions.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;PLAYWRIGHT-AGENT-DEMO
components/  = reusable UI logic and visual parts
fixtures/    = shared test data and setup helpers
pages/       = page objects with user flows
selectors/   = locators and test IDs
tests/       = main test specs
utils/       = helper methods and utilities
&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;&lt;strong&gt;Setting Up Playwright Agents&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;With the structure ready, it’s time to bring the Agents to life.&lt;/p&gt;

&lt;h4&gt;&lt;strong&gt;1️⃣ Use VS Code Insiders&lt;/strong&gt;&lt;/h4&gt;

&lt;p&gt;Playwright Agents need &lt;strong&gt;VS Code Insiders&lt;/strong&gt; for full automation - the regular version can only suggest, not act.&lt;br&gt;
👉 &lt;a href="https://code.visualstudio.com/insiders" rel="noopener noreferrer"&gt;https://code.visualstudio.com/insiders&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;&lt;strong&gt;2️⃣ Initialize Playwright Agents&lt;/strong&gt;&lt;/h4&gt;

&lt;p&gt;Run this inside your project:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;npx playwright init-agents --loop=vscode
&lt;/code&gt;&lt;/pre&gt;

&lt;ul&gt;
  &lt;li&gt;Creates all necessary AI agent files inside &lt;code&gt;.github/chatmodes/&lt;/code&gt;
&lt;/li&gt;
  &lt;li&gt;Sets up three roles:&lt;strong&gt;Planner&lt;/strong&gt;,&lt;strong&gt;Generator&lt;/strong&gt;, and &lt;strong&gt;Healer&lt;/strong&gt;
&lt;/li&gt;
  &lt;li&gt;Re-run after major Playwright updates to refresh definitions&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;&lt;strong&gt;Enabling File Editing in Chat Mode&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;Before using the Agents, give them permission to edit your workspace:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Command Palette → Chat → Configure Tools&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;✅ &lt;strong&gt;Edit workspace files&lt;/strong&gt;
&lt;/li&gt;
  &lt;li&gt;✅ &lt;strong&gt;Run commands&lt;/strong&gt;
&lt;/li&gt;
  &lt;li&gt;✅ &lt;strong&gt;Search files&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This allows the Agents to actually create and modify files, not just suggest code.&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%2F3h7i227lgjctkteynkn1.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%2F3h7i227lgjctkteynkn1.png" alt="enabling file editing in chat mode" width="800" height="425"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;&lt;strong&gt;Planner: From Prompt to Login Test Plan&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Prompt I used for the Planner:&lt;/strong&gt; this is the message I sent to the Agent to generate a test plan&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Plan a concise login test for Juice Shop (http://localhost:3000) - happy path + invalid creds, with ACs and selector/fixture notes. Output to /specs/login-plan.md.
&lt;/code&gt;&lt;/pre&gt;

&lt;ul&gt;
  &lt;li&gt;Planner explored the login screen at &lt;code&gt;http://localhost:3000&lt;/code&gt;
&lt;/li&gt;
  &lt;li&gt;Read my workspace and recognized folder structure&lt;/li&gt;
  &lt;li&gt;Produced &lt;code&gt;/specs/login-plan.md&lt;/code&gt; with ACs and implementation notes&lt;/li&gt;
&lt;/ul&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%2Fxvm9z7260mjkr36bm1nn.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%2Fxvm9z7260mjkr36bm1nn.png" alt="pw-planner" width="800" height="408"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;&lt;strong&gt;Generator: From a Simple Plan to a Complete Login Suite&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Prompt I used for the Generator:&lt;/strong&gt; the message I sent to make the Agent build my entire login flow - pages, selectors, fixtures, tests, and the config - all structured and ready to run.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Generate all login files per /specs/login-plan.md into my folders (components/fixtures/pages/selectors/tests/utils) and include/update playwright.config.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;What the Generator did:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Created &lt;code&gt;login.components.ts&lt;/code&gt; for form logic&lt;/li&gt;
  &lt;li&gt;Added &lt;code&gt;users.json&lt;/code&gt; fixture with test data&lt;/li&gt;
  &lt;li&gt;Generated &lt;code&gt;LoginPage.ts&lt;/code&gt; (page object)&lt;/li&gt;
  &lt;li&gt;Defined &lt;code&gt;login.selectors.ts&lt;/code&gt; for stable locators&lt;/li&gt;
  &lt;li&gt;Created four spec files:
    &lt;ul&gt;
      &lt;li&gt;&lt;code&gt;login-happy-path.spec.ts&lt;/code&gt;&lt;/li&gt;
      &lt;li&gt;&lt;code&gt;login-invalid-credentials.spec.ts&lt;/code&gt;&lt;/li&gt;
      &lt;li&gt;&lt;code&gt;login-security.spec.ts&lt;/code&gt;&lt;/li&gt;
      &lt;li&gt;&lt;code&gt;login-smoke.spec.ts&lt;/code&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;⚙️ Updated &lt;code&gt;playwright.config.ts&lt;/code&gt; and &lt;code&gt;package.json&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&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%2Fuq6ime8981earwwyy5er.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%2Fuq6ime8981earwwyy5er.png" alt="pw-generator" width="618" height="1006"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note:&lt;/em&gt; The output depends on how detailed your test plan is.  
Since mine was for the OWASP Juice Shop app, the Agent also generated some &lt;strong&gt;security-related tests&lt;/strong&gt;.  
They weren’t needed for my scope, but I let it run just to see what it could do.&lt;/p&gt;

&lt;h3&gt;&lt;strong&gt;Healer: Fixing Broken Tests&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;To test reliability, I intentionally broke a selector in &lt;code&gt;login.selectors.ts&lt;/code&gt; - changing &lt;code&gt;#email&lt;/code&gt; to &lt;code&gt;#mail&lt;/code&gt;.  
The Healer analyzed the DOM, found the mismatch, and fixed it automatically.&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%2Flcxb2bejd07hdvswp7ws.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%2Flcxb2bejd07hdvswp7ws.png" alt="wrong selector" width="800" height="403"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This was a small example, but it showed real potential.  
Beyond broken selectors, the Healer can also refactor - remove redundant code, simplify methods, and clean up repetition.&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%2Fecrar733hqn28cuytzo6.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%2Fecrar733hqn28cuytzo6.png" alt="healer result" width="800" height="1317"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Observation:&lt;/strong&gt; the Healer isn’t always consistent - sometimes a one-line fix becomes a long refactor.  
Still, it gets the job done, tirelessly, while you focus on bigger problems.&lt;/p&gt;

&lt;h3&gt;&lt;strong&gt;✅ Running the Complete Test Suite&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;After the Planner created the test plan, the Generator built all the files, and the Healer fixed a few initial issues - I hadn’t written a single line of code myself.&lt;/p&gt;

&lt;p&gt;Everything was planned, generated, and healed automatically by the Playwright Agents.&lt;/p&gt;

&lt;p&gt;When I finally ran the full test suite, this is how it looked in the terminal:&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%2Fo9vma6jho7c4wgs2qskb.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%2Fo9vma6jho7c4wgs2qskb.png" alt=" " width="800" height="494"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;All login-related scenarios - valid, invalid, and security - executed successfully across multiple browsers.  
Seeing all tests green without touching a single spec file really shows how far automation has come.&lt;/p&gt;

&lt;h3&gt;&lt;strong&gt;💭 Final Thoughts&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;After using these Playwright Agents, I can say this is a big step forward for smarter, faster testing.  
They widen coverage, reduce time on repetitive tasks, and make automation feel more collaborative.&lt;/p&gt;

&lt;p&gt;Everything depends on how clearly you describe and structure things - the better your setup, the better the results.  
I wanted this post to be more hands-on than theoretical - similar to what Debbie O’Brien showed in the Playwright Live session.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;Generator&lt;/strong&gt; does a solid job but still needs guidance - sometimes repeating logic or overcomplicating simple functions.  
That’s where we, as QA engineers, come in: to fine-tune, guide, or rewrite when needed.  
For example, it often adds a &lt;code&gt;.goto('/') &lt;/code&gt; in every test - not ideal, but easy to fix and impressive for a start.&lt;/p&gt;

&lt;p&gt;I also noticed that sometimes even simple tests get generated in a broken state - for example, with incorrect assertions or missing waits.  
However, the &lt;strong&gt;Healer&lt;/strong&gt; usually steps in and fixes them automatically once you run the suite.  
Still, it’s clear that without our QA intuition and manual oversight, these agents wouldn’t deliver tests in the exact way we expect them to behave.  
A quick look at a failing report is often enough to spot what went wrong and understand how the AI reasoned its way to that error - which is fascinating in itself.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;Healer&lt;/strong&gt; can overdo things but always finds a way back.  
Later, you can run the Generator again to tidy up the result.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Recommendation:&lt;/strong&gt; try these Agents, even on a demo app.  
You’ll quickly see how much time they save and how AI can become your QA teammate.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Thanks for reading!&lt;/em&gt;  
Feel free to share your thoughts or questions in the comments - let’s keep learning and stay in step with the future of testing. 🚀&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%2F1bspjwpfhygq5an2am47.webp" 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%2F1bspjwpfhygq5an2am47.webp" alt="gif-video" width="498" height="277"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>testing</category>
      <category>qa</category>
      <category>ai</category>
      <category>playwright</category>
    </item>
    <item>
      <title>Dive into API Testing with Playwright in Java</title>
      <dc:creator>Nikola</dc:creator>
      <pubDate>Thu, 08 Aug 2024 18:15:08 +0000</pubDate>
      <link>https://forem.com/ndenic/dive-into-api-testing-with-playwright-in-java-2fmi</link>
      <guid>https://forem.com/ndenic/dive-into-api-testing-with-playwright-in-java-2fmi</guid>
      <description>&lt;h2&gt;
  
  
  🎯 Overview
&lt;/h2&gt;

&lt;p&gt;Welcome to the world of API testing with Playwright in Java!&lt;br&gt;
If you’re tired of wrestling with boilerplate code and tedious setup processes, you’re in luck. I’ve already set up everything for you in a neat, ready-to-use GitHub repository. All you need to do is clone the project and follow along.&lt;/p&gt;

&lt;p&gt;In this post, we’ll explore the ins and outs of the framework I’ve crafted. You’ll learn how to use it, understand its components, and see how it all fits together to make API testing a breeze.&lt;/p&gt;
&lt;h3&gt;
  
  
  Framework Structure Overview
&lt;/h3&gt;

&lt;p&gt;The repository contains a detailed README file that explains the project structure in depth. Here’s a brief overview:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;playwright-api-testing-framework&lt;/span&gt;
&lt;span class="err"&gt;├─&lt;/span&gt; &lt;span class="nt"&gt;src&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="err"&gt;├─&lt;/span&gt; &lt;span class="nt"&gt;main&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="err"&gt;└─&lt;/span&gt; &lt;span class="nt"&gt;java&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="err"&gt;│&lt;/span&gt;     &lt;span class="err"&gt;└─&lt;/span&gt; &lt;span class="nt"&gt;io&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="err"&gt;│&lt;/span&gt;        &lt;span class="err"&gt;└─&lt;/span&gt; &lt;span class="nt"&gt;ndenic&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="err"&gt;│&lt;/span&gt;           &lt;span class="err"&gt;└─&lt;/span&gt; &lt;span class="nt"&gt;apitesting&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="err"&gt;│&lt;/span&gt;              &lt;span class="err"&gt;├─&lt;/span&gt; &lt;span class="nt"&gt;service&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="err"&gt;│&lt;/span&gt;              &lt;span class="err"&gt;├─&lt;/span&gt; &lt;span class="nt"&gt;model&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="err"&gt;│&lt;/span&gt;              &lt;span class="err"&gt;└─&lt;/span&gt; &lt;span class="nt"&gt;utils&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="err"&gt;└─&lt;/span&gt; &lt;span class="nt"&gt;test&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;     &lt;span class="err"&gt;├─&lt;/span&gt; &lt;span class="nt"&gt;java&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;     &lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="err"&gt;└─&lt;/span&gt; &lt;span class="nt"&gt;io&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;     &lt;span class="err"&gt;│&lt;/span&gt;     &lt;span class="err"&gt;└─&lt;/span&gt; &lt;span class="nt"&gt;ndenic&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;     &lt;span class="err"&gt;│&lt;/span&gt;        &lt;span class="err"&gt;└─&lt;/span&gt; &lt;span class="nt"&gt;apitesting&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;     &lt;span class="err"&gt;│&lt;/span&gt;           &lt;span class="err"&gt;├─&lt;/span&gt; &lt;span class="nt"&gt;tests&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;     &lt;span class="err"&gt;│&lt;/span&gt;           &lt;span class="err"&gt;└─&lt;/span&gt; &lt;span class="nt"&gt;util&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;     &lt;span class="err"&gt;└─&lt;/span&gt; &lt;span class="nt"&gt;resources&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;        &lt;span class="err"&gt;├─&lt;/span&gt; &lt;span class="nt"&gt;testdata&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;        &lt;span class="err"&gt;└─&lt;/span&gt; &lt;span class="nt"&gt;schemas&lt;/span&gt;
&lt;span class="err"&gt;├─&lt;/span&gt; &lt;span class="nt"&gt;test-suite&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="err"&gt;└─&lt;/span&gt; &lt;span class="nt"&gt;testng&lt;/span&gt;&lt;span class="nc"&gt;.xml&lt;/span&gt;
&lt;span class="err"&gt;└─&lt;/span&gt; &lt;span class="nt"&gt;pom&lt;/span&gt;&lt;span class="nc"&gt;.xml&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a detailed explanation of each component and directory, please refer to the &lt;code&gt;README.md&lt;/code&gt; file in the root of the repository. It includes specific details on the framework structure and how to use each part effectively.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Components
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;src/main/java/io/ndenic/apitesting/service&lt;/code&gt;&lt;/strong&gt;: Contains the API service classes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;src/main/java/io/ndenic/apitesting/model&lt;/code&gt;&lt;/strong&gt;: Houses the POJO classes. The &lt;code&gt;rest-countries&lt;/code&gt; branch includes the &lt;code&gt;Country&lt;/code&gt; class used for parsing API responses.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;src/main/java/io/ndenic/apitesting/utils&lt;/code&gt;&lt;/strong&gt;: Utility classes to support the testing framework.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;src/test/java/io/ndenic/apitesting/tests&lt;/code&gt;&lt;/strong&gt;: Where the test cases are located.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🚀 Getting Started
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Clone the Repository
&lt;/h3&gt;

&lt;p&gt;First things first, grab the project from GitHub. Head over to &lt;a href="https://github.com/ndenic/Playwright-API-testing-framework-template" rel="noopener noreferrer"&gt;this repository&lt;/a&gt; and clone it to your local machine:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;Playwright-API-testing-framework-template
git clone https://github.com/ndenic/Playwright-API-testing-framework-template.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Switch to the &lt;code&gt;rest-countries&lt;/code&gt; Branch
&lt;/h3&gt;

&lt;p&gt;To explore the &lt;code&gt;Country&lt;/code&gt; POJO class and the main setup, switch to the &lt;code&gt;rest-countries&lt;/code&gt; branch:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git checkout rest-countries
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Install Dependencies
&lt;/h3&gt;

&lt;p&gt;Next, navigate to the project directory and install the necessary dependencies. The project uses Maven for dependency management, so you’ll need to run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mvn clean &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command will pull in all the libraries and plugins we use for API testing.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Explore the Structure
&lt;/h3&gt;

&lt;p&gt;Here’s a brief overview of the project structure and key components:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;src/main/java/io/ndenic/apitesting&lt;/code&gt;&lt;/strong&gt;: Contains the core code for interacting with APIs.

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;service&lt;/code&gt;&lt;/strong&gt;: This is where the magic happens. It contains the &lt;code&gt;APIService&lt;/code&gt; class that handles the API requests and responses.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;model&lt;/code&gt;&lt;/strong&gt;: Includes the POJO classes representing the data structures you’ll interact with.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&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%2F7urtx1saerv7fcctpf8l.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%2F7urtx1saerv7fcctpf8l.png" alt="country pojo class and apiservice structure" width="800" height="552"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;src/test/java/io/ndenic/apitesting/tests&lt;/code&gt;&lt;/strong&gt;: Houses your test cases.

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;CountryTests.java&lt;/code&gt;&lt;/strong&gt;: This is where you’ll write your test cases. It uses Playwright to send requests and validate responses.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&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%2Fcit2smgceywqtc2htlou.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%2Fcit2smgceywqtc2htlou.png" alt="country test class" width="800" height="432"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;src/test/resources&lt;/code&gt;&lt;/strong&gt;: Contains configuration and test data.

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;config.dev.properties&lt;/code&gt;&lt;/strong&gt;: Configuration for the development environment.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;config.prod.properties&lt;/code&gt;&lt;/strong&gt;: Configuration for the production environment.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&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%2F2rtfqu7my1dw3k038ftw.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%2F2rtfqu7my1dw3k038ftw.png" alt="resources" width="800" height="211"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;testng.xml&lt;/code&gt;&lt;/strong&gt;: Defines the test suite and includes Allure for reporting.&lt;/li&gt;
&lt;/ul&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%2Fwbwf5v6egs2id8ko1fzm.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%2Fwbwf5v6egs2id8ko1fzm.png" alt="testng.xml" width="705" height="485"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Run Tests
&lt;/h3&gt;

&lt;p&gt;To run the tests, simply execute 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;mvn &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will run the tests defined in &lt;code&gt;CountryTests.java&lt;/code&gt; and generate reports using Allure.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Configuration and Customization
&lt;/h3&gt;

&lt;p&gt;The project is configured to use different environments and tags. You can customize the environment by setting the &lt;code&gt;ENV&lt;/code&gt; parameter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mvn &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="nt"&gt;-DENV&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Similarly, run tests by tags using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mvn &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="nt"&gt;-Dtags&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;smoke
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnqdqd9z0lazzm742dbrr.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%2Fnqdqd9z0lazzm742dbrr.png" alt="mvn-test-output" width="769" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  7. Generating Allure Reports
&lt;/h3&gt;

&lt;p&gt;Once you've successfully run your tests and want to see those beautiful reports that give you insights into your API test results, it's time to generate the Allure report. Allure reports provide a detailed and visual overview of your test results, making it easier to spot issues and track progress.&lt;/p&gt;

&lt;p&gt;After running your tests with &lt;code&gt;mvn test&lt;/code&gt;, you can generate the Allure report by running 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;mvn allure:report
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command will create an Allure report in the &lt;code&gt;target/site/allure-maven-plugin&lt;/code&gt; directory. To view the report in your browser, you can serve it using 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;mvn allure:serve
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjxmrhj7o60m7yehwbo29.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%2Fjxmrhj7o60m7yehwbo29.png" alt="allure-report" width="800" height="380"&gt;&lt;/a&gt;&lt;br&gt;
This will start a local server and open the report in your default browser. You'll see a comprehensive breakdown of your test cases, complete with execution history&lt;/p&gt;

&lt;h3&gt;
  
  
  📚 Conclusion
&lt;/h3&gt;

&lt;p&gt;Setting up an API testing framework with Playwright in Java doesn’t have to be overwhelming. With this guide and the provided framework, you can jumpstart your API testing journey and focus on what truly matters—writing and executing effective tests.&lt;/p&gt;

&lt;p&gt;For a detailed breakdown of the project structure and more information on usage, visit the &lt;a href="https://github.com/ndenic/Playwright-API-testing-framework-template" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt; and check out the &lt;code&gt;README.md&lt;/code&gt; file. Feel free to reach out with any questions or feedback!&lt;/p&gt;

&lt;p&gt;Happy testing!&lt;/p&gt;

</description>
      <category>playwright</category>
      <category>api</category>
      <category>testing</category>
      <category>java</category>
    </item>
    <item>
      <title>Set up your test automation project with Playwright using Typescript</title>
      <dc:creator>Nikola</dc:creator>
      <pubDate>Mon, 11 Jul 2022 07:04:35 +0000</pubDate>
      <link>https://forem.com/ndenic/set-up-your-test-automation-project-in-playwright-using-typescript-21jf</link>
      <guid>https://forem.com/ndenic/set-up-your-test-automation-project-in-playwright-using-typescript-21jf</guid>
      <description>&lt;p&gt;&lt;strong&gt;Playwright is a powerful framework, which provides cross-browser automation through a single API, but this post is not entirely about it, but about how to set up a project in a good way. I will use Playwright for this purpose&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;What you will not find in this post is an initial level explanation of the playwright framework. I think there is already a lot about it on the internet. This is pure practice, something that will serve you well if you are the first to break the ice in terms of setting up a project.&lt;/p&gt;

&lt;p&gt;You started working on a new project (or an old one) and a request came or you decided to use Playwright yourself. It's ok to start writing tests just after you install playwright, but in fact, this kind of start will affect your later more complex tests, where your code will be difficult to maintain and even more difficult to add new tests. I will try to make this part easier for you and to help you set good roots at the very beginning.&lt;/p&gt;

&lt;p&gt;What you will learn from this post is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Project setup starts with a good folder structure&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Which design pattern is good for that purpose&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A step-by-step explanation of what you need so that you can just write the tests afterwards without a headache&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Warm-up
&lt;/h2&gt;

&lt;p&gt;If you haven't written a single basic test or at least spent a few hours in this framework, I suggest you first visit their official site (&lt;a href="https://playwright.dev/" rel="noopener noreferrer"&gt;https://playwright.dev/&lt;/a&gt;) and look around a bit and write some tests. It's not difficult, and believe me if you deal with test automation at work, you will like this.&lt;br&gt;
I have been using this framework for a year or so. I can tell you that the transition from Selenium/Java to Playwright/TypeScript was not the best.&lt;br&gt;
I'm not saying it was difficult, but I wasn't the happiest at that moment.&lt;/p&gt;

&lt;p&gt;But we won't talk about that, now I efficiently use that tool to finish all the work with quality and speed. So in this post, we are working with Playwright using Typescript. These are some general things and can be applied with different tools and it's not related only to the playwright.&lt;/p&gt;

&lt;h2&gt;
  
  
  Blasting off
&lt;/h2&gt;

&lt;p&gt;We will start with setting up the project. Of course, we need nodejs (&lt;a href="https://nodejs.org/en/" rel="noopener noreferrer"&gt;https://nodejs.org/en/&lt;/a&gt;)&lt;br&gt;
We will create an empty directory, for example, pw-test-automation and after that, we will open an IDE, some code editor. I use VSCode for this purpose, so I will show an example using that code editor&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%2Fk1o7hxjbm9l069z81n48.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%2Fk1o7hxjbm9l069z81n48.png" alt="VSCode project" width="800" height="137"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then we will need to open terminal and do&lt;br&gt;
&lt;code&gt;npm init&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;After that, we will add the dependencies that are basic for our work, which is only Playwright. You can add everything else as you wish, test runners or any other dependencies.&lt;br&gt;
So next things are&lt;br&gt;
&lt;code&gt;npm i -D @playwright/test&lt;/code&gt;&lt;br&gt;&lt;br&gt;
&lt;code&gt;npm i -D playwright&lt;/code&gt; &lt;/p&gt;

&lt;p&gt;After we have successfully installed the dependencies, we will see the versions of the playwright in the package.json file.&lt;/p&gt;

&lt;h2&gt;
  
  
  Design pattern
&lt;/h2&gt;

&lt;p&gt;Ok, let's move on to something more serious. We will use what some call the &lt;strong&gt;Business-Layer Page-Object Pattern&lt;/strong&gt;, where the tests will have a clear structure of what is happening there. So we don't catch the selectors in tests, we don't go through the lists, but we call the functions that contain it and which are named enough that someone who doesn't have that much knowledge in that area can understand what's happening there.&lt;br&gt;
Don't worry, it will become clearer to you soon if it hasn't already.&lt;br&gt;
This is my way of implementing this design pattern and it works well for me.&lt;/p&gt;

&lt;p&gt;Let's create inside pw-test-automation folder (root folder)&lt;br&gt;
services folder, then inside we will create two more - &lt;strong&gt;pages&lt;/strong&gt; and &lt;strong&gt;steps&lt;/strong&gt;&lt;br&gt;
We need one more folder inside the root folder and that's&lt;br&gt;
&lt;strong&gt;tests&lt;/strong&gt;. Where we will create our test files&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%2Foxw84fr432auped26uhx.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%2Foxw84fr432auped26uhx.png" alt="Business-Layer POM" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Config files
&lt;/h2&gt;

&lt;p&gt;We will quickly create a tsconfig.json file (in root folder), to use better the TS features and avoid some JS syntax errors which will appear without a config file.&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%2Fosxv257y3tsiegc77oxt.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%2Fosxv257y3tsiegc77oxt.png" alt="TS config file" width="446" height="245"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Those are just some basic compilerOptions , but of course you can expand it.&lt;/p&gt;

&lt;p&gt;Next, we'll create a playwright config file so we can configure our tests to run the way we want. And of course we have the possibility to expand if the project requires it. &lt;br&gt;
(&lt;a href="https://playwright.dev/docs/test-configuration" rel="noopener noreferrer"&gt;https://playwright.dev/docs/test-configuration&lt;/a&gt;)&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%2Fuju2nyol6iywqlir46ix.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%2Fuju2nyol6iywqlir46ix.png" alt="playwright config" width="800" height="320"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here we have some simple things configured.&lt;br&gt;
As u can see for key &lt;strong&gt;baseURL&lt;/strong&gt; we just added URL, but in real projects we won't have one environment, this means that we will have to change the URL as soon as we want to run our tests on another environment. &lt;br&gt;
Now let's change that so that we can change the environment based on the entered input parameters.&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%2Fti5446hp8c2xqagnjfvp.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%2Fti5446hp8c2xqagnjfvp.png" alt="Environments" width="800" height="403"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I have created one more JSON file which is for environments and it contains two keys. One key is prod, other is dev. But that's all up to you and your project. It depends which environments you got and how are they called.&lt;/p&gt;

&lt;p&gt;Okay we added process environment variable ENV, so how to specify that and when? &lt;br&gt;
Next step , we should open package.json and change scripts -&amp;gt; test&lt;br&gt;
&lt;code&gt;"scripts": {&lt;br&gt;
    "test": "ENV=$npm_config_ENV playwright test"&lt;br&gt;
  },&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now we just set that if in the future we wanted to run a test based on some environment, we would type, for example, &lt;code&gt;npm run test --ENV=prod&lt;/code&gt; or dev in our case. At the moment we don't have a single test, so we have nothing to run, but no rush.&lt;/p&gt;

&lt;p&gt;When setting up a project, you have to do it thoroughly and think many steps ahead. Now let's do it again as for the environment, but this time we need to run the tests by tags as well. For example run all regression tests&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%2Favlkq9d9mtxvlklprg1b.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%2Favlkq9d9mtxvlklprg1b.png" alt="Run tests by tags" width="800" height="408"&gt;&lt;/a&gt;&lt;br&gt;
And then update also test script in package JSON file with latest changes &lt;br&gt;
&lt;code&gt;"scripts": {&lt;br&gt;
    "test": "ENV=$npm_config_ENV TAGS=$npm_config_TAGS playwright test"&lt;br&gt;
  },&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Ok, I think you get the point. A lot of things can be configured this way. I'll give you a hint for further options, what if we want to run by browser type?&lt;/p&gt;

&lt;p&gt;I didn't spend time explaining to you what each key in the config file means individually because I think there is no better explanation than the documentation itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Selectors
&lt;/h2&gt;

&lt;p&gt;Let's go to the next section.&lt;br&gt;
We will need to store selectors, somewhere. My advice is to have separate file for that purpose. There are many options -&amp;gt; create only one &lt;strong&gt;selectors.json&lt;/strong&gt; file or have folder selectors which contains JSON files for each Page. I prefer first option , because we have enough freedom to create nested JSON object and store selectors in similar way as to create N amount of files.&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%2Fvqnj8gzmq3d3g3rcy3sj.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%2Fvqnj8gzmq3d3g3rcy3sj.png" alt="Selectors" width="764" height="327"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Services
&lt;/h2&gt;

&lt;p&gt;Now we have the selectors, we have the config file, we have the basic structure according to the Business-Layer Page-Object Pattern and we are starting to create, for example, the HomePage.&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%2F7dg4os6lmdxsgc1306jc.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%2F7dg4os6lmdxsgc1306jc.png" alt="home.page.ts" width="800" height="382"&gt;&lt;/a&gt;&lt;br&gt;
The point is that here we use the selectors that we saved in the json file later in the functions and return them as a Locator object that we can work with.&lt;/p&gt;

&lt;p&gt;Let's create steps for HomePage&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%2F3ryqe7qvm3hdwyikh79c.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%2F3ryqe7qvm3hdwyikh79c.png" alt="Home page steps" width="800" height="284"&gt;&lt;/a&gt;&lt;br&gt;
Now you can already understand that we will only call those steps in the test files. This is just an example and in reality we will have a lot of steps/functions here.&lt;/p&gt;

&lt;h2&gt;
  
  
  Test data
&lt;/h2&gt;

&lt;p&gt;And now you will definitely need &lt;strong&gt;Test data&lt;/strong&gt;, so for example you pass some data to the function with which you want to test&lt;br&gt;
For this purpose, my suggestion is to create a &lt;strong&gt;test-data&lt;/strong&gt; folder in the root folder and create as many JSON (or any other type) files with test data as you need.&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%2Fvw4iunvqgmryxs7xkho6.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%2Fvw4iunvqgmryxs7xkho6.png" alt="Almost complete structure" width="360" height="459"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see, the project setup seems almost complete. Everything is clearly separated into units.&lt;br&gt;
But of course CI/CD integration is also needed here, which is not difficult at all, but it takes this story to the other side. I'll leave that up to you, and I'll be there to help you if you need it, of course don't hesitate to ask a question.&lt;/p&gt;

&lt;p&gt;It's not over yet, hold on :) &lt;/p&gt;

&lt;p&gt;The last thing in that magic circle of POM model is the Test file. So we created a folder in the start for that purpose -&amp;gt; tests.&lt;/p&gt;

&lt;p&gt;In that folder we will create, for example, the &lt;br&gt;
home-page-tests.spec.ts file&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%2Fn4c0p86opf70e66r7bjl.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%2Fn4c0p86opf70e66r7bjl.png" alt="Home page test file" width="800" height="266"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the test file, in this case, we have beforeEach, but don't pay attention to that now, because it could also be beforeAll, and in that case, it would be desirable to have afterEach or afterAll as well.&lt;br&gt;
We initialize the page in the before method so that we can pass it to the constructor of the steps class.&lt;/p&gt;

&lt;p&gt;We do not use the HomePage functions in tests, unless there is an overwhelming need for it and in some cases it is unavoidable. We already used only Steps functions that do all the work. For example, we have inputTextWithTestData() and after that we add a function for assertion in steps and name it appropriately.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What do we get with this kind of structure ?&lt;/strong&gt;&lt;br&gt;
&lt;em&gt;Easier maintenance of tests&lt;/em&gt; (more precisely steps)&lt;br&gt;
&lt;em&gt;Code redundancy is avoided&lt;/em&gt; (we don't have to repeat ourselves, we can use the same step in several test cases if there is a need for it)&lt;/p&gt;

&lt;p&gt;Do you need more?&lt;/p&gt;

&lt;p&gt;At the end of the day, someone who doesn't understand the code that much will understand what the test is about. You get an almost Gherkin-like syntax, if you look at the "before" method as GIVEN and the rest of the action WHEN insertInputTextWithTestData , THEN assertion&lt;/p&gt;

&lt;p&gt;So let me repeat the most &lt;strong&gt;important&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Service folder contains Page and Steps&lt;br&gt;
Page functions are functions that return Locators or Promises&amp;lt;&amp;gt; that we solve later. We use those functions in the Steps class.&lt;br&gt;
The Steps class literally contains the steps that we will do in the test files to execute a test case (add a book to the cart, open the cart, confirm that the book is in the cart).&lt;br&gt;
We don't want it all to be in one function, but several smaller ones, so that they can be used again if we need to perform the same actions again and also so that the name of the function itself is short and clear.&lt;br&gt;
In the test file, we initialize page and steps, write test() and call functions from the steps class.&lt;/em&gt; And let the game begin&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&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%2Fqrb7ru0acndd2qra4bhm.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%2Fqrb7ru0acndd2qra4bhm.png" alt="Final" width="800" height="438"&gt;&lt;/a&gt;&lt;br&gt;
This is how it might look in the end. I added the pipeline YML file, .jenkinsfile and the helper class&lt;br&gt;
Now you can start writing your e2e/UI tests or eventually expand that framework by your project needs.&lt;/p&gt;

&lt;p&gt;And yeah, finally, this would be an example of how we will run the tests&lt;br&gt;
&lt;code&gt;npm run test --ENV=dev --TAGS=regression&lt;/code&gt;&lt;br&gt;
but we will probably have more parameters to manage what and how we will run in our tests.&lt;/p&gt;

&lt;p&gt;Thanks for reading, I hope this will help you if you find yourself in the situation of setting up a project from scratch and of course shoot your questions if you have any.&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%2Fqfy1noybqyg2t4yd2fji.gif" 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%2Fqfy1noybqyg2t4yd2fji.gif" alt=" " width="498" height="277"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>playwright</category>
      <category>typescript</category>
      <category>testautomation</category>
    </item>
  </channel>
</rss>
