TESTEVERYTHING

Showing posts with label Browser. Show all posts
Showing posts with label Browser. Show all posts

Friday, 16 October 2026

Performance Testing with K6 and Playwright

 

Performance Testing with K6 and Playwright

A step-by-step guide from setup to execution—combining functional browser journeys with realistic performance testing.

K6PlaywrightBrowser performanceCI/CD ready
In brief: Playwright validates that a user journey works. k6 measures how that journey behaves under load. This guide shows how to use both in one JavaScript-oriented workflow.

Why Combine K6 with Playwright?

Modern web applications must be fast and functionally correct under real-world traffic. Playwright is excellent for end-to-end verification, while k6 is purpose-built for load and performance testing. K6’s experimental browser module provides a Playwright-inspired API for browser-level performance checks.

Playwrightk6
Primary purposeFunctional and E2E testingLoad and performance testing
Execution modelReal browser, single/few sessionsThousands of VUs at protocol level, or smaller browser-level loads
ScriptingJavaScript/TypeScript, Python, Java, .NETJavaScript (Goja runtime)
MetricsPass/fail assertionsLatency, throughput, error rate, thresholds
Browser APINativek6/experimental/browser, Playwright-inspired

Pairing the tools lets teams reuse selectors and user flows, validate critical journeys such as login or checkout, capture browser metrics alongside load metrics, and run tests from CI/CD.

Prerequisites and Setup

You’ll need Node.js v16 or later with npm, a code editor, optional Git, basic JavaScript and selector knowledge, and administrator or sudo access for k6 and browser dependencies.

Initialize a Node.js project

mkdir k6-playwright-perf-test
cd k6-playwright-perf-test
npm init -y

Install Playwright

npm install -D @playwright/test
npx playwright install --with-deps

Keep a Playwright functional suite in the repository so the journey can be verified before it is performance-tested.

Install k6

# macOS
brew install k6

# Windows
choco install k6

# Debian / Ubuntu
sudo apt-get update
sudo apt-get install k6

# Docker alternative
docker pull grafana/k6

k6 version

Enable the browser module

Modern k6 releases bundle the experimental browser module. A recent release such as k6 v0.47.0 or later is recommended. Older releases may require an xk6 custom build:

go install go.k6.io/xk6/cmd/xk6@latest
xk6 build --with github.com/grafana/xk6-browser@latest

Recommended project structure

k6-playwright-perf-test/
├── playwright-tests/
│   └── login.spec.js
├── k6-tests/
│   └── login.perf.js
├── package.json
└── playwright.config.js

Writing the Playwright Functional Test

First validate the login flow functionally, then translate the same selectors and steps into the k6 script.

// playwright-tests/login.spec.js
const { test, expect } = require('@playwright/test');

test('user can log in', async ({ page }) => {
  await page.goto('https://test.k6.io/my_messages.php');
  await page.fill('#login', 'admin');
  await page.fill('#password', '123');
  await page.click('input[type="submit"]');
  await expect(page.locator('h3')).toContainText('Welcome, admin!');
});
npx playwright test playwright-tests/login.spec.js

Writing the K6 Performance Test

import { browser } from 'k6/experimental/browser';
import { check } from 'k6';

export const options = {
  scenarios: {
    ui: {
      executor: 'shared-iterations',
      vus: 5,
      iterations: 10,
      options: { browser: { type: 'chromium' } },
    },
  },
  thresholds: {
    checks: ['rate==1.0'],
    browser_http_req_duration: ['p(95)<2000'],
  },
};

export default async function () {
  const page = browser.newPage();
  try {
    await page.goto('https://test.k6.io/my_messages.php');
    await page.locator('#login').type('admin');
    await page.locator('#password').type('123');
    await Promise.all([
      page.waitForNavigation(),
      page.locator('input[type="submit"]').click(),
    ]);
    const heading = page.locator('h3');
    check(heading, {
      'welcome message is visible': (h) =>
        h.textContent().includes('Welcome, admin!'),
    });
  } finally {
    page.close();
  }
}

Key concepts: browser.newPage() creates a browser page, page.locator() mirrors Playwright’s selector model, scenarios define the load shape, thresholds define objective pass/fail criteria, and check() records assertions without acting like a test-runner exception.

Configuring Test Options

export const options = {
  scenarios: {
    ui: {
      executor: 'ramping-vus',
      startVUs: 1,
      stages: [
        { duration: '30s', target: 5 },
        { duration: '1m', target: 5 },
        { duration: '30s', target: 0 },
      ],
      options: { browser: { type: 'chromium' } },
    },
  },
  thresholds: {
    browser_http_req_duration: ['p(90)<1500', 'p(95)<2500'],
    checks: ['rate>0.95'],
  },
};
  • Executors: Choose shared-iterations, per-vu-iterations, constant-vus, ramping-vus, constant-arrival-rate, or ramping-arrival-rate according to the desired concurrency or arrival rate.
  • Stages: Ramp VUs gradually. Browser VUs are resource-intensive; keep counts modest, typically under 10–20 concurrent browser VUs per machine.
  • Thresholds: Tie automated pass/fail behavior to measurable SLAs.

Executing the Performance Test

k6 run k6-tests/login.perf.js

# Docker
docker run --rm -i -v $(pwd):/scripts grafana/k6 \
  run /scripts/k6-tests/login.perf.js

# JSON output
k6 run --out json=results.json k6-tests/login.perf.js

# InfluxDB output
k6 run --out influxdb=http://localhost:8086/k6 k6-tests/login.perf.js

Analyzing and Interpreting Results

checks.........................: 100.00% ✓ 10  ✗ 0
browser_http_req_duration......: avg=812ms p(95)=1.3s
browser_web_vital_lcp...........: avg=1.1s
iteration_duration..............: avg=2.3s
vus..............................: 5
  • checks: The pass rate of all check() assertions.
  • browser_http_req_duration: Time taken by browser-initiated HTTP requests.
  • browser_web_vital_*: Browser-level LCP, FCP, and CLS metrics when supported.
  • iteration_duration: Total duration of a complete script iteration.
  • Threshold results: k6 returns a non-zero exit status when a threshold fails, making it suitable for CI/CD gates.

Best Practices and Common Pitfalls

  • Keep browser-level VUs low. Use protocol-level k6 tests for high concurrency and browser tests for representative journeys.
  • Separate concerns. Use Playwright for strict functional assertions and cross-browser coverage; use k6 for performance-focused checks.
  • Use realistic think-time. Prefer wait-for-selector patterns or carefully chosen pauses to mimic user pacing.
  • Set meaningful thresholds tied to actual service-level objectives.
  • Run in CI/CD and use k6’s exit code as a quality gate.
  • Isolate test data with unique users or records per VU and iteration.
  • Monitor the test runner. CPU and memory limits can bottleneck the generator before the target system.

Conclusion

Combining k6 with a Playwright-style browser API provides a consistent way to validate functional correctness and real-world performance. Verify the flow with Playwright, translate it to a k6 browser script, define a realistic scenario and thresholds, execute it, and use the resulting metrics to catch regressions early.

Frequently Asked Questions

Is k6’s browser module the same as Playwright?

No. It is a Playwright-inspired API designed for performance testing in k6. Playwright remains the dedicated functional and E2E tool.

Can I run thousands of virtual users with the browser module?

Browser-level VUs are resource-heavy. Use protocol-level k6 tests for high-concurrency load and browser-level tests for smaller, representative populations.

Do I need Playwright installed to use k6’s browser module?

No. k6 runs its browser module independently. Playwright is complementary and useful for validating flows and reusing selectors.

Can these tests run in a CI/CD pipeline?

Yes. Both tools are CLI-driven and return process exit codes suitable for GitHub Actions, GitLab CI, Jenkins, and similar systems.

Version note: The browser module is experimental and its API may change. Verify code samples and configuration against the current official k6 and Playwright documentation before publishing or adopting them in production.

Thursday, 10 November 2016

Webdriver/Selenium Difference between methods .isDisplayed() and .isEnabled()?

Hi All,
I have seen so many posts where people asked the differences between .isDisplayed() and .isEnabled() in Selenium/Webdriver automation and found mostly people are still confused.
The methods .isDisplayed() and .isEnabled() have nothing in common.
 Here I am trying to explain the read differences between .isDisplayed() and .isEnabled(). As name itself clearly says .isDisplayed() means is my object are visible or not on my webpage means Am I able to see my element through my eyes.


Method .isDisplayed() :


An element is considered displayed when it is perceptually visible to the human eye.
The element displayed algorithm is a boolean state where true signifies that the element is displayed and false signifies that the element is not displayed.

To compute the state on element:
  • ·         If the attribute hidden is set, return false.
  • ·         If the computed value of the display style property is "none", return false.

Like
<input type="hidden" name="abc" value="10" id="hiddenFiled1" />

Observe the output, since element with id hiddenField1 is hidden from web page, so isDisplayed method return false, whereas isEnabled() method return true.



OR

Refer below link


Try to run with display: block;  and display: none;




Method .isEnabled() :


An element is considered enabled if it's not a form control (button, input, textarea, select or option) or when the user interactions and focus are not blocked with the disabled attribute/property.
Is Element Enabled determines if the referenced element is enabled or not. This operation only makes sense on form controls.

Like
Last name: <input type="text" name="lname" disabled><br>













Last name: <input type="text" name="lname" enabled><br>


 
Refer below link


Last name: <input type="text" name="lname" disabled><br>



Monday, 1 August 2016

XPath unable to find text with   or   using webdriver /

Hi,

Some times we face issues to create XPath of  WebElement which have space in starting of it and then we check the element html source where we found &nbsp; or &nbsp is added before the element text while it display as space on UI. Normally we create the XPath to identify this element by adding space in the starting of it but his will not identify the element. There are another workaround to identify this element by contains text method. But if we have to identify the element with exact text having starting space or ending space  then we can use following way to do this.

lets see this example

<div class="myclass">
<label>AgendaShowCapacity&nbsp;</label>
</div>

OR

<div class="myclass">
<label>
&nbspAgendaShowCapacity</label>
</div>

Following XPath will not work for this

//label[text()='AgendaShowCapacity&nbsp;'] doesn't work


Here we have to use following text to identify the element

&nbsp; = \u00a0

&nbsp = \u0160


So XPath will be like this


//label[text()='AgendaShowCapacity\u00a0']


//label[text()='
\u0160AgendaShowCapacity']

Monday, 23 May 2011

Close All Browsers Except OLD One QTP VB

Hi All,
Some times we required that Only OLD open Browser Window( Only for IE) will remain Open and rest of all should be closed during QTP scripting. Here is the Function which will close all the open Browsers except OLD Open browser (Work only for Internet Explorer using QTP)


Public function fn_CloseAllBrowsersExceptOLD
      rem create Browser description object

         Set brwsr=Description.Create

         brwsr(“micclass”).value=”Browser”

         Set obj=Desktop.ChildObjects(brwsr)

          browserCount= obj.count

         Set obj=nothing

         If  browserCount >1  Then

         do

            Browser(“CreationTime:=1″).Close

            Set obj=Desktop.ChildObjects(brwsr)

            browserCount= obj.count

            Set obj=nothing

         loop  until  browserCount =1

        End If
End Function

call  fn_CloseAllBrowsersExceptOLD( )

Translate







Tweet