<?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: autonekoqa</title>
    <description>The latest articles on DEV Community by autonekoqa (@autonekoqa).</description>
    <link>https://dev.to/autonekoqa</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%2F3927374%2F1069f542-1a6a-4928-984b-9be2afe60089.png</url>
      <title>DEV Community: autonekoqa</title>
      <link>https://dev.to/autonekoqa</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/autonekoqa"/>
    <language>en</language>
    <item>
      <title>Playwright Basics: Your First Test with Page, Test Structure, and Codegen</title>
      <dc:creator>autonekoqa</dc:creator>
      <pubDate>Tue, 12 May 2026 14:21:59 +0000</pubDate>
      <link>https://dev.to/autonekoqa/playwright-basics-your-first-test-with-page-test-structure-and-codegen-592</link>
      <guid>https://dev.to/autonekoqa/playwright-basics-your-first-test-with-page-test-structure-and-codegen-592</guid>
      <description>&lt;p&gt;If you are starting with Playwright, the first real hurdle is not syntax.&lt;/p&gt;

&lt;p&gt;It is understanding three things clearly:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;what the &lt;code&gt;page&lt;/code&gt; object actually represents&lt;/li&gt;
&lt;li&gt;how a test file should be structured so it stays readable&lt;/li&gt;
&lt;li&gt;how to use Codegen without blindly trusting generated code&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I wrote a longer version on Auto Neko here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://autoneko.com/en/posts/playwright-basic-first-test/" rel="noopener noreferrer"&gt;Playwright Basics — Your First Test: Page, Test File Structure &amp;amp; Codegen&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This DEV version is the shorter, practical walkthrough.&lt;/p&gt;

&lt;h2&gt;
  
  
  What &lt;code&gt;page&lt;/code&gt; really is
&lt;/h2&gt;

&lt;p&gt;In Playwright, &lt;code&gt;page&lt;/code&gt; is the browser tab you control in code.&lt;/p&gt;

&lt;p&gt;That means when you write:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;goto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://coffee.autoneko.com/&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;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getByRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;link&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="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sr"&gt;/login/i&lt;/span&gt; &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;you are telling Playwright:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;open a real page&lt;/li&gt;
&lt;li&gt;wait until it is actionable&lt;/li&gt;
&lt;li&gt;perform the interaction like a user would&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That mental model matters because a lot of beginner confusion comes from treating Playwright as "just a list of commands" instead of "a model of browser interaction".&lt;/p&gt;

&lt;h2&gt;
  
  
  A clean first test
&lt;/h2&gt;

&lt;p&gt;Here is a simple first example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&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="nx"&gt;expect&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="s2"&gt;@playwright/test&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;open homepage and verify title&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="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="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;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;goto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://coffee.autoneko.com/&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="nf"&gt;expect&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="nf"&gt;toHaveTitle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/Neko Coffee/i&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 already teaches four important habits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;keep one clear scenario per test&lt;/li&gt;
&lt;li&gt;always &lt;code&gt;await&lt;/code&gt; browser actions&lt;/li&gt;
&lt;li&gt;prefer Playwright assertions like &lt;code&gt;toHaveTitle()&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;verify behavior, not just "the page opened"&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A better structure than one giant script
&lt;/h2&gt;

&lt;p&gt;Beginners often write long, flat test scripts.&lt;/p&gt;

&lt;p&gt;A better pattern is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&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="nx"&gt;expect&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="s2"&gt;@playwright/test&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user can open login page&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="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="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;test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;step&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Go to homepage&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="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;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;goto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://coffee.autoneko.com/&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="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;step&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Open login page&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="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;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getByRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;link&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="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sr"&gt;/login/i&lt;/span&gt; &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;click&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;test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;step&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Verify login form is visible&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="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;await&lt;/span&gt; &lt;span class="nf"&gt;expect&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="nf"&gt;getByRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;heading&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="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sr"&gt;/login/i&lt;/span&gt; &lt;span class="p"&gt;})).&lt;/span&gt;&lt;span class="nf"&gt;toBeVisible&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;Why this helps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;reports are easier to read&lt;/li&gt;
&lt;li&gt;failures tell you which step broke&lt;/li&gt;
&lt;li&gt;future you will hate the test less&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Codegen is useful, but not sacred
&lt;/h2&gt;

&lt;p&gt;Playwright Codegen is great for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;discovering selectors&lt;/li&gt;
&lt;li&gt;recording rough flows&lt;/li&gt;
&lt;li&gt;learning the API quickly&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Run it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx playwright codegen https://coffee.autoneko.com/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But after recording, clean the output.&lt;/p&gt;

&lt;p&gt;Typical cleanup:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;replace fragile selectors with &lt;code&gt;getByRole()&lt;/code&gt; or &lt;code&gt;getByLabel()&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;remove extra clicks&lt;/li&gt;
&lt;li&gt;add assertions&lt;/li&gt;
&lt;li&gt;rename the test so it describes user intent&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Codegen should give you a draft, not the final version.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common beginner mistakes
&lt;/h2&gt;

&lt;p&gt;These are the ones I see most often:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;putting everything into one test&lt;/li&gt;
&lt;li&gt;using weak selectors when better accessible locators exist&lt;/li&gt;
&lt;li&gt;copying Codegen output without refactoring&lt;/li&gt;
&lt;li&gt;verifying too little&lt;/li&gt;
&lt;li&gt;treating failures as "Playwright is flaky" when the real issue is poor test design&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  A good first practice path
&lt;/h2&gt;

&lt;p&gt;If you want a sensible order for learning Playwright, I would go like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;first test with &lt;code&gt;page&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;locator basics&lt;/li&gt;
&lt;li&gt;auto-waiting and actionability&lt;/li&gt;
&lt;li&gt;web-first assertions&lt;/li&gt;
&lt;li&gt;cleaner test data and reusable structure&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The full step-by-step article, with examples and a more detailed breakdown, is here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://autoneko.com/en/posts/playwright-basic-first-test/" rel="noopener noreferrer"&gt;Read the full tutorial on Auto Neko&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If this helps, the next article to read is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://autoneko.com/en/posts/playwright-auto-waiting-web-first-assertions/" rel="noopener noreferrer"&gt;Playwright Basics — Lesson 2: Auto-waiting, Actionability Checks, and Web-First Assertions&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>playwright</category>
      <category>testing</category>
      <category>typescript</category>
      <category>automation</category>
    </item>
  </channel>
</rss>
