Your First Test

Even simple web applications will benefit from integration testing. But as your app grows in complexity, testing becomes essential to ensure your users have a great experience.

Whether you want to develop e2e tests for deployment, production tests for monitoring, visual regression tests, or more, this article will help you get started in no time. Using Playwright and BrowserCat, not only will your tests run reliably, but they’ll run quickly and cheaply as well.

Set up you test environment

Let’s kick things off by setting up a new project. If you already have an existing project where you want to include tests, skip this first step and jump to the next.

# Create a new directory
mkdir my-first-test
cd my-first-test

# Set up a new node project
npm init -y

# Create a new git repo
git init
git add -A
git commit -m "Initial commit"
# Create a new directory
mkdir my-first-test
cd my-first-test

# Set up a new python project
python3 -m venv venv
source venv/bin/activate

# Create a new git repo
git init
git add -A
git commit -m "Initial commit"

Next, we will install the necessary dependencies, including the @playwright/test library. It’s bar none the best automated testing library around, and it supports multiple languages as well.

# Install node dependencies
npm install -D @playwright/test
npm install -D typescript

# Install playwright browsers
npx playwright install
# Install python dependencies
pip install playwright pytest pytest-playwright

# Install playwright browsers
playwright install

That’s it. Now let’s write some tests!

Create your first test

Depending on the testing strategy you want to deploy, you may want to organize your test files differently. But for now, let’s keep things simple. A tests directory will do just fine.

# Create the test file
mkdir -p tests
touch tests/pricing.spec.ts
# Create the test file
mkdir -p tests
touch tests/test_pricing.py

Open tests/pricing.spec.ts in your text editor. Let’s do a quick sanity check to make sure everything is working as expected…

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

test.describe('Pricing', () => {
  test('has a sensible title', async ({page}) => {
    await page.goto('https://www.browsercat.com/pricing');
    await expect(page).toHaveTitle(/pricing/i);
  });
});
import re
from playwright.sync_api import Page, expect

def test_has_a_sensible_title(page):
    page.goto("https://www.browsercat.com/pricing")
    expect(page).to_have_title(re.compile("pricing", re.IGNORECASE))

Let’s run our test and see what happens…

npx playwright test
pytest

If you see 1 passed, great! Otherwise take a deeper look at the previous instructions and make sure you didn’t miss anything.

Now let’s test something a bit more complicated…

Testing behavior and feedback

We’ll start by testing BrowserCat’s dynamic pricing slider behaves as expected. This example will demonstrate different ways of interacting with the browser and the DOM.

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

test.describe('Pricing', () => {
  test('displays savings text for each slider position', async ({ page }) => {
    // Navigate to the pricing page
    await page.goto('https://www.browsercat.com/pricing');

    // Wait for the slider to be interactive
    const sliderSelector = 'input[type="range"]';
    await page.waitForSelector(sliderSelector);

    // Test the slider at various positions
    const $range = page.locator(sliderSelector);
    const $savings = page.locator('#price-savings');
    const min = parseInt(await $range.getAttribute('min') ?? '0');
    const max = parseInt(await $range.getAttribute('max') ?? '0');

    for (let i = min; i <= max; i++) {
      // Set the slider value within the page context
      await $range.evaluate((el: HTMLInputElement, value) => {
        el.value = value.toString();
        el.dispatchEvent(new Event('input'));
      }, i);

      // Verify the displayed savings after the slider moves
      const savings = await $savings.textContent();
      expect(savings).toMatch(/^\d+[kmb]? credits/ui);
    }
  });
});
import re
from playwright.sync_api import Page, expect

def test_displays_savings_text_for_each_slider_position(page):
    # Navigate to the pricing page
    page.goto("https://www.browsercat.com/pricing")

    # Wait for the slider to be interactive
    slider_selector = 'input[type="range"]'
    page.wait_for_selector(slider_selector)

    # Test the slider at various positions
    slider = page.locator(slider_selector)
    savings = page.locator("#price-savings")
    min_value = int(slider.get_attribute('min') or '0')
    max_value = int(slider.get_attribute('max') or '0')
    savings_pattern = re.compile(r'^\d+[kmb]? credits$', re.IGNORECASE | re.UNICODE)

    for i in range(min_value, max_value + 1):
        # Set the slider value within the page context
        page.evaluate(f'element => element.value = "{i}" && element.dispatchEvent(new Event("input"))')

        # Verify the displayed savings after the slider moves
        expect(savings).to_contain_text(savings_pattern)

Let’s run our test again. You should again expect a passing result. If not, take a look at the code and see if you can figure out what’s going on. Here’s some resources:

Still having trouble? Contact us. We’re happy to help!

Running your tests

Now that you’ve got a working test, you’re ready to start making use of it. The challenge is that running a test in your CI/CD pipeline or from a production server requires downloading and hosting a headless browser. Now only is this a pain to set up, but it’s also incredibly slow.

Most CI/CD containers and web servers are very light, and it’s challenging to parallelize your tests so that they run in a reasonable timeframe. Some users’ deployment tests used to take over an hour (!!!) to run.

This is where BrowserCat comes in. Rather than hosting the browsers yourself, you can connect to BrowserCat’s fleet on demand. This allows you to fully parallelize your tests, only paying for the browsers when you’re actually using them.

Jump to our guide on deployment and scaling for more information.