<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Sai krishna Oggu]]></title><description><![CDATA[Sai krishna Oggu]]></description><link>https://saikrishnaoggu.hashnode.dev</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1593680282896/kNC7E8IR4.png</url><title>Sai krishna Oggu</title><link>https://saikrishnaoggu.hashnode.dev</link></image><generator>RSS for Node</generator><lastBuildDate>Sun, 20 Sep 2026 04:41:13 GMT</lastBuildDate><atom:link href="https://saikrishnaoggu.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Why Do Playwright Tests Pass Locally but Fail in CI/CD?]]></title><description><![CDATA[“It works perfectly on my machine.”
Every automation engineer has said it.
Your Playwright test passes 20 times locally. You push the code. The CI pipeline starts. And suddenly:
❌ Test failed.
You run]]></description><link>https://saikrishnaoggu.hashnode.dev/why-do-playwright-tests-pass-locally-but-fail-in-ci-cd</link><guid isPermaLink="true">https://saikrishnaoggu.hashnode.dev/why-do-playwright-tests-pass-locally-but-fail-in-ci-cd</guid><category><![CDATA[playwright]]></category><category><![CDATA[QA]]></category><category><![CDATA[automation testing ]]></category><category><![CDATA[ci-cd]]></category><category><![CDATA[Pipeline]]></category><category><![CDATA[test-automation]]></category><category><![CDATA[qa testing]]></category><category><![CDATA[TestAutomation]]></category><category><![CDATA[playwright testing]]></category><category><![CDATA[TestFlakiness]]></category><category><![CDATA[Devops articles]]></category><category><![CDATA[Devops]]></category><category><![CDATA[SoftwareTesting]]></category><category><![CDATA[RemoteQA]]></category><category><![CDATA[remotejobs]]></category><dc:creator><![CDATA[Sai Krishna Oggu]]></dc:creator><pubDate>Sat, 19 Sep 2026 08:18:58 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/696fd0722cb65d1a0796107b/27ca08f3-8e3d-4e03-994f-c64610e1f61f.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>“It works perfectly on my machine.”</p>
<p>Every automation engineer has said it.</p>
<p>Your Playwright test passes 20 times locally. You push the code. The CI pipeline starts. And suddenly:</p>
<p>❌ Test failed.</p>
<p>You run it again locally.</p>
<p>✅ Passed.</p>
<p>So, what changed?</p>
<p>Usually, the test didn’t suddenly become bad. The environment changed.</p>
<p>Here are the most common reasons behind this frustrating problem — and how to debug them.</p>
<ol>
<li>Timing Issues — The Classic Flaky Test Your local machine may give the application enough time to render.</li>
</ol>
<p>CI may be under CPU or memory pressure, making everything slightly slower.</p>
<p>A fragile test might look like:</p>
<p>await page.click('#submit'); await page.waitForTimeout(1000); expect(await page.locator('.success-message').isVisible()).toBeTruthy(); Instead, let Playwright wait for the expected state:</p>
<p>await page.getByRole('button', { name: 'Submit' }).click(); await expect( page.getByText('Success') ).toBeVisible(); Rule: Don’t wait for time. Wait for state.</p>
<p>Avoid using waitForTimeout() as a solution for flaky tests.</p>
<ol>
<li>Your Local Environment ≠ CI Environment This is one of the first things I check. Your local environment might use:</li>
</ol>
<p>QA1 while the pipeline is configured for:</p>
<p>QA2 Or your local .env may contain variables that aren't available in CI.</p>
<p>Check:</p>
<p>baseURL API endpoints environment variables feature flags tenant configuration test credentials database state A test can be perfectly written and still fail because it is talking to the wrong environment.</p>
<ol>
<li>Browser or Playwright Version Differences Your local machine may be running one browser version while CI runs another.</li>
</ol>
<p>Check your Playwright version:</p>
<p>npx playwright --version Make sure your project uses a consistent dependency version and that CI installs the expected browsers.</p>
<p>For CI environments, browser installation should be explicit when needed:</p>
<p>npx playwright install --with-deps Consistency matters.</p>
<p>Same code + different browser/runtime = potentially different behavior.</p>
<ol>
<li>Headless vs Headed Execution Most CI pipelines run Playwright in headless mode.</li>
</ol>
<p>Locally, you may be running:</p>
<p>npx playwright test --headed while CI runs:</p>
<p>npx playwright test This can expose problems involving:</p>
<p>animations responsive layouts viewport assumptions visual elements timing Try reproducing the pipeline locally in headless mode.</p>
<ol>
<li>Parallel Execution Can Expose Hidden Dependencies This is a big one, you might run locally:</li>
</ol>
<p>npx playwright test --workers=1 But your CI pipeline may execute multiple workers, now imagine two tests using the same user:</p>
<p>Test A → Update User Test B → Delete User Run independently:</p>
<p>PASS ✅</p>
<p>Run simultaneously:</p>
<p>FAIL ❌</p>
<p>Shared test data is often the real culprit, watch for dependencies involving:</p>
<p>users database records files API data tenants orders accounts Tests should be as isolated as possible.</p>
<ol>
<li>Test Data Exists Locally — but Not in CI Your local database may already contain:</li>
</ol>
<p>User: testuser123 Order: 45678 Tenant: ABC Your pipeline may not.</p>
<p>Download the Medium app If your test assumes that data exists, it can fail immediately.</p>
<p>Instead of relying on existing state, create the required data as part of the test setup.</p>
<p>For example:</p>
<p>test.beforeEach(async ({ request }) =&gt; { await createTestUser(request); }); A reliable test should control the data it depends on.</p>
<ol>
<li>Authentication &amp; Storage State Another common issue:</li>
</ol>
<p>Local ↓ Valid storageState ↓ Authenticated ↓ Test passes CI:</p>
<p>Missing/expired storageState ↓ Login/session fails ↓ Test fails Check:</p>
<p>cookies access tokens session state authentication setup CI secrets storage state files Don’t assume authentication works simply because it works locally.</p>
<ol>
<li>CI Secrets Are Different You may have:</li>
</ol>
<p>process.env.USERNAME process.env.PASSWORD process.env.BASE_URL working locally because they’re defined in your .env.</p>
<p>But CI needs those values configured separately.</p>
<p>A missing environment variable can create a failure that looks like a Playwright problem — but isn’t.</p>
<ol>
<li>Timezone Differences Here’s a subtle one.</li>
</ol>
<p>Your machine:</p>
<p>IST CI server:</p>
<p>UTC Now consider a test involving:</p>
<p>Today's date Expiry date Scheduled job Booking time Timestamp Your test may behave differently.</p>
<p>If dates matter, make timezone assumptions explicit rather than relying on the machine’s local timezone.</p>
<ol>
<li>Windows Works. Linux Doesn’t. This catches many automation engineers; your local machine may be Windows.</li>
</ol>
<p>Your CI runner may be Linux.</p>
<p>Windows filesystem handling can be different from Linux, particularly around filename casing.</p>
<p>For example:</p>
<p>import LoginPage from './pages/loginpage'; while the actual file is:</p>
<p>LoginPage.ts It may work locally and fail in a Linux pipeline.</p>
<p>Treat filenames and imports as case-sensitive.</p>
<p>The Most Powerful Debugging Tool: Trace Viewer When a test fails in CI, don’t immediately increase the timeout.</p>
<p>First, find out why it failed.</p>
<p>Configure Playwright:</p>
<p>use: { trace: 'retain-on-failure', screenshot: 'only-on-failure', video: 'retain-on-failure' } Then inspect the trace:</p>
<p>npx playwright show-trace trace.zip You can investigate:</p>
<p>the exact action that failed DOM state screenshots network activity console messages timing locator behavior Instead of guessing:</p>
<p>“Maybe the page wasn’t loaded?”</p>
<p>You can actually see what happened.</p>
<p>My CI Debugging Checklist When a Playwright test passes locally but fails in CI, I check these in roughly this order:</p>
<ol>
<li><p>Environment / Base URL ↓</p>
</li>
<li><p>Test data ↓</p>
</li>
<li><p>Authentication ↓</p>
</li>
<li><p>Timing / synchronization ↓</p>
</li>
<li><p>Browser &amp; Playwright versions ↓</p>
</li>
<li><p>Headless execution ↓</p>
</li>
<li><p>Parallel workers ↓</p>
</li>
<li><p>Viewport / responsive behavior ↓</p>
</li>
<li><p>Timezone ↓</p>
</li>
<li><p>CI resources / network Then I reproduce the pipeline conditions locally:</p>
</li>
</ol>
<p>npx playwright test --workers=1 and inspect the trace if the failure persists.</p>
<p>The Bigger Lesson A CI failure isn’t necessarily a Playwright problem.</p>
<p>It can reveal a weakness in your:</p>
<p>test → data → environment → application → infrastructure</p>
<p>chain.</p>
<p>That’s why good automation isn’t just about writing locators.</p>
<p>It’s about creating tests that are:</p>
<p>Reliable. Isolated. Reproducible. Observable.</p>
<p>The goal isn’t to make CI green by adding more waits.</p>
<p>The goal is to understand why it wasn’t green in the first place.</p>
<p>Final Thought Local passing tells you the test can work. CI passing tells you the test can be trusted.</p>
<p>And that’s the real difference between a test that runs and an automation suite you can rely on.</p>
]]></content:encoded></item><item><title><![CDATA[Integrating Playwright with CI/CD Using GitHub Actions]]></title><description><![CDATA[Automating Playwright tests locally is useful, but running them automatically in a CI/CD pipeline gives teams faster feedback on every code change.
In this guide, we'll integrate Playwright with GitHu]]></description><link>https://saikrishnaoggu.hashnode.dev/saikrishnaoggu-playwright-cicd-integration-with-githubactions</link><guid isPermaLink="true">https://saikrishnaoggu.hashnode.dev/saikrishnaoggu-playwright-cicd-integration-with-githubactions</guid><category><![CDATA[playwright]]></category><category><![CDATA[QA automation]]></category><category><![CDATA[qa testing]]></category><category><![CDATA[ci-cd]]></category><category><![CDATA[GitHub Actions]]></category><dc:creator><![CDATA[Sai Krishna Oggu]]></dc:creator><pubDate>Fri, 18 Sep 2026 10:43:34 GMT</pubDate><content:encoded><![CDATA[<p>Automating Playwright tests locally is useful, but running them automatically in a CI/CD pipeline gives teams faster feedback on every code change.</p>
<p>In this guide, we'll integrate Playwright with <strong>GitHub Actions</strong> using a simple YAML workflow.</p>
<h2>1. Project Setup</h2>
<p>Assuming you already have a Playwright project:</p>
<pre><code class="language-text">playwright-project/
├── tests/
├── playwright.config.ts
├── package.json
└── package-lock.json
</code></pre>
<p>Make sure the tests run locally:</p>
<pre><code class="language-bash">npx playwright test
</code></pre>
<h2>2. Create the GitHub Actions Workflow</h2>
<p>Create the following file:</p>
<pre><code class="language-text">.github/workflows/playwright.yml
</code></pre>
<p>Add:</p>
<pre><code class="language-yaml">name: Playwright Tests

on:
  push:
    branches: [main]

  pull_request:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: npm

      - name: Install dependencies
        run: npm ci

      - name: Install Playwright browsers
        run: npx playwright install --with-deps

      - name: Run Playwright tests
        run: npx playwright test

      - name: Upload Playwright report
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: playwright-report
          path: playwright-report/
</code></pre>
<h2>3. How It Works</h2>
<p>Whenever code is pushed to <code>main</code> or a pull request is created, GitHub Actions will:</p>
<pre><code class="language-text">Code Push / Pull Request
          ↓
   Checkout Repository
          ↓
     Install Node.js
          ↓
    Install Dependencies
          ↓
 Install Playwright Browsers
          ↓
    Run Playwright Tests
          ↓
    Generate Test Report
</code></pre>
<p>If a test fails, the workflow fails and the Playwright report is still uploaded because of:</p>
<pre><code class="language-yaml">if: always()
</code></pre>
<p>This makes it easier to investigate failures directly from GitHub Actions.</p>
<h2>4. Why Integrate Playwright with CI/CD?</h2>
<p>CI/CD integration helps teams:</p>
<ul>
<li><p>Run tests automatically</p>
</li>
<li><p>Catch regressions early</p>
</li>
<li><p>Validate pull requests</p>
</li>
<li><p>Execute tests consistently</p>
</li>
<li><p>Store reports and artifacts</p>
</li>
<li><p>Reduce manual testing effort</p>
</li>
</ul>
<p>For larger frameworks, you can extend the pipeline with <strong>parallel execution, environment variables, secrets, scheduled regression runs, test sharding, and deployment gates</strong>.</p>
<h3>Final Thought</h3>
<p>Playwright becomes much more valuable when automation is part of the development pipeline—not just something executed manually on a QA engineer's machine.</p>
<p><strong>Write the tests once. Run them continuously. Get feedback early.</strong></p>
]]></content:encoded></item></channel></rss>