Playwright Scripts

Playwright scripts let you use standard Playwright Test code for your load testing and monitoring in Loadster. They’re a code-first alternative to Browser Bots for developers who have Playwright experience or just prefer writing JavaScript tests with the open source framework.

Playwright scripting in Loadster is in early access preview and currently invite-only. If you’re interested in trying it out, please contact help@loadster.app to request access!

If you’ve worked with the Playwright Test framework before, you already know how to write Loadster Playwright scripts! Just write the same JavaScript code you’d write for any Playwright test and Loadster takes care of the rest.

We highly recommend checking out the Official Playwright Test Documentation since most of what you read there will apply in Loadster as well.

When to Use Playwright Scripts in Loadster

When it comes to load testing and monitoring in Loadster, Playwright scripts are a good fit when:

  • You’re comfortable writing JavaScript
  • You want precise control over browser automation
  • You have existing Playwright tests you’d like to reuse
  • You prefer writing code over visual editors

For simpler use cases or if you prefer a visual approach, Browser Bots might make it easier to get up and running quickly. For API testing without browser overhead, Protocol Bots are more efficient.

Playwright Test vs Playwright

Loadster supports Playwright Test scripts, not ordinary Playwright browser automation library scripts. In short, your scripts must use the test function from the @playwright/test library.

import {test, expect} from '@playwright/test';

test('my test', async ({page}) => {
    await page.goto('https://example.com');
    await expect(page).toHaveTitle(/Example/);
});

Scripts that launch browsers manually with chromium.launch() won’t work here, because Loadster ties into the Playwright Test framework and manages the browser lifecycle for you.

If you have existing Playwright automation scripts that aren’t Playwright Test and want to convert them to the Playwright Test framework, you can pretty much wrap the automation in a test() block and using the provided fixtures.

Creating a Playwright Script

When you create a new Playwright script in Loadster, it will start with a template containing one empty test case:

import {test} from '@playwright/test';

test('main test case', async ({page}) => {
    // TODO: Add your test steps here
});

If you define multiple test cases in a single script, Loadster will execute them in series. However, for most load testing and monitoring use cases we recommend a single focused test case.

Editing Playwright Scripts

The Playwright script editor in Loadster provides:

  • A syntax highlighting text editor for JavaScript with Playwright APIs
  • A Play button to execute the script in the editor and validate it works
  • A results panel showing the playback results timeline, screenshots, and traces

Unlike Browser Bot scripts, Playwright scripts are written entirely in code, but you can use them for load testing and monitoring in much the same way.

Playing Playwright Scripts

Playing a script in the editor is your chance to verify and debug your script before putting it to use in a load test or monitor. You can play it in the editor as many times as you need to get it right.

When you play in the editor, Loadster runs the script once with a single bot and reports detailed diagnostics, giving you an opportunity to find and fix errors.

This is different from running a load test (where many bots execute the script concurrently) or using the script as a monitor (where a single bot runs on a schedule to check availability). Playing in the editor is for development and troubleshooting.

Click the Play button to execute your script. Loadster will:

  1. Save any pending changes
  2. Execute the script on a cloud engine
  3. Stream results back in real time
  4. Display each test case as a card in the results timeline

While running, you’ll see:

  • Test case names and their status (running, passed, failed)
  • Execution time for each test
  • Screenshots captured during execution
  • Any errors or failures with details

Always play through your script in the editor after writing or making changes to make sure it runs as intended.

Viewing Script Results

After execution, each test case displays as a result card showing its name, status, execution time, and a screenshot thumbnail (if available). Click on any result card to expand it and view full details.

Result Details

  • Status — Whether the test passed or failed
  • Duration — How long the test took to execute
  • Error details — Stack traces and failure messages for failed tests

Screenshots

Playwright automatically captures screenshots during test execution. These appear in the Screenshots tab of the result modal. You can also explicitly capture screenshots in your code:

await page.screenshot({path: 'screenshot.png'});

Video Recording

In most cases, when you play from the script editor a video recording of the test execution are available in the Videos tab.

Playwright Traces

Loadster integrates with Playwright’s Trace Viewer. Click the trace link in your Playwright results to download and inspect:

  • Timeline of actions
  • DOM snapshots before/after each action
  • Network requests
  • Console logs

Console Output

The Console tab shows all log output from your test, including console.log() statements and Playwright’s internal logging.

Using Script Variables

Loadster’s standard Variables and Expressions don’t currently work with Playwright scripts, so you won’t be able to use Datasets with them either.

For now, if you need to include a variety of user accounts or other data with your Playwright script you can include them in a JavaScript array or other data structure in the script itself. Please contact help@loadster.app if this presents a problem or to ask about the timeframe for supporting Loadster datasets in Playwright.

Using Playwright Scripts for Load Testing

Playwright scripts can be added to load test scenarios just like Protocol Bot or Browser Bot scripts:

  1. Create or open a load test scenario
  2. In the population editor, selectyour Playwright script
  3. Configure the number of bots and ramp settings
  4. Run the load test

Each bot in a load test executes the Playwright script independently, simulating real browser traffic at scale. This is useful for:

  • Testing single-page applications under load
  • Validating that user journeys work under concurrent usage
  • Measuring real browser rendering and JavaScript execution times

Using Playwright Scripts for Monitoring

Playwright scripts work seamlessly for site monitoring:

  1. Create a new monitor
  2. Select your Playwright script
  3. Configure the check interval and locations
  4. Set up alerting thresholds and escalations

The monitor will execute your Playwright script at the configured interval from your selected locations. You’ll see:

  • Pass/fail status for each check cycle
  • Response time trends
  • Screenshots from each execution
  • Full result details including traces

This is particularly useful for:

  • Monitoring JavaScript-heavy applications
  • Validating complete user flows (login, checkout, etc.)
  • Detecting visual or functional regressions
  • Checking that third-party integrations work correctly

Playwright Best Practices in Loadster

Keep Your Tests Focused

Each Playwright script should test a specific user journey or feature. Smaller, focused tests are easier to debug and provide clearer metrics.

When a focused test fails, you know exactly which user journey has a problem. When a sprawling test that covers many different flows fails, you have to dig through the results to figure out what actually went wrong. Focused tests also give you more granular response time metrics in your load test results—you can see exactly how long each specific action takes rather than just getting one big number for the whole script.

If you want to test multiple behaviors together you can include multiple test cases. You can also run multiple bot groups in a load test with each running a different script.

Use Meaningful Test Names

Test names appear in results and monitoring dashboards, so descriptive names make it much easier to understand what’s happening at a glance—especially when you’re troubleshooting a failure at 3am or reviewing load test results weeks later.

// Good - you know exactly what this test does
test('complete checkout with credit card', async ({page}) => {
});

// Less helpful - what does this even test?
test('test 1', async ({page}) => {
});

Handle Dynamic Content

Modern web applications often load content asynchronously, which means elements might not be immediately available when the page first loads. Using Playwright’s built-in waiting mechanisms makes your tests more reliable than using fixed delays.

// Good - waits for specific element, proceeds as soon as it appears
await page.waitForSelector('.product-loaded');

// Avoid - arbitrary delay that might be too short (causing failures) or too long (wasting time)
await page.waitForTimeout(5000);

Fixed delays are problematic for two reasons. If the page loads faster than the delay, you’re wasting time on every iteration—and that adds up quickly in a load test with hundreds of bots. If the page loads slower (maybe because it’s under load), the test fails even though the application might still be working correctly. Waiting for specific elements handles both cases gracefully.

Clean Up State Afterwards

If your test creates data (like a new user account, a saved item, or a draft document), consider cleaning it up at the end of the test. This prevents “test pollution” where leftover data from previous runs affects future runs.

test('create and delete item', async ({page}) => {
    // Create item
    await page.click('button.create');

    // Verify and clean up
    await page.click('button.delete');
});

This matters in load testing or monitoring if another bot will be trying to do the same thing soon afterwards and expects a clean state.

Use Assertions

Playwright Test includes the expect API for assertions. Assertions verify that the application is actually behaving correctly, not just that it didn’t crash.

import {test, expect} from '@playwright/test';

test('homepage loads correctly', async ({page}) => {
    await page.goto('https://example.com');
    await expect(page).toHaveTitle(/Example/);
    await expect(page.locator('h1')).toBeVisible();
});

Without assertions, a test might “pass” even when something is wrong. For example, if your login page accidentally redirects to an error page, a test without assertions would happily report success because no exception was thrown. Adding assertions like await expect(page).toHaveURL(/dashboard/) catches these problems. In load testing and monitoring, assertions help distinguish between “the server responded” and “the server responded correctly”.

Limitations

  • No recording. Unlike Browser Bot scripts, Playwright scripts are written manually. You can use Playwright’s codegen tool externally and paste the result into Loadster.
  • Single code block. Each Playwright script contains one code editor, not multiple visual steps like browser scripts.
  • No datasets or Loadster variables. As we mentioned above, there’s not yet a way to reference datasets in a Playwright script, so if you need bulk test data you would need to include it in the script itself.

Playwright Test Script Examples

Here are a few examples of Playwright Test scripts, just so you can get an idea. You can find many more examples elsewhere, and LLMs are quite good at it too!

Playwright Basic Navigation Example

import {test, expect} from '@playwright/test';

test('homepage loads and displays welcome message', async ({page}) => {
    await page.goto('https://example.com');

    await expect(page.locator('h1')).toContainText('Welcome');
    await expect(page.locator('.hero-image')).toBeVisible();
});

Playwright Form Submission Example

import {test, expect} from '@playwright/test';

test('contact form submission', async ({page}) => {
    await page.goto('https://example.com/contact');

    await page.fill('input[name="email"]', 'test@example.com');
    await page.fill('textarea[name="message"]', 'Hello from Loadster!');
    await page.click('button[type="submit"]');

    await expect(page.locator('.success-message')).toBeVisible();
});

Playwright Authentication Flow Example

import {test, expect} from '@playwright/test';

test('user can log in', async ({page}) => {
    await page.goto('https://example.com/login');

    await page.fill('input[name="username"]', '${USERNAME}');
    await page.fill('input[name="password"]', '${PASSWORD}');
    await page.click('button[type="submit"]');

    await expect(page).toHaveURL(/dashboard/);
    await expect(page.locator('.user-menu')).toContainText('${USERNAME}');
});

Playwright User Journey Example

import {test, expect} from '@playwright/test';

test('complete purchase flow', async ({page}) => {
    // Browse to product
    await page.goto('https://shop.example.com');
    await page.click('.product-card >> nth=0');

    // Add to cart
    await page.click('button.add-to-cart');
    await expect(page.locator('.cart-count')).toContainText('1');

    // Go to checkout
    await page.click('a.checkout');
    await expect(page).toHaveURL(/checkout/);

    // Fill shipping info
    await page.fill('input[name="address"]', '123 Test St');
    await page.fill('input[name="city"]', 'Test City');
    await page.click('button.continue');

    // Verify order summary
    await expect(page.locator('.order-total')).toBeVisible();
});