cbPlaywright

End-to-End Tests with Playwright and TestBox

https://slides.com/elpete/itb2023-cbplaywright

What this talk is

  • An overview of cbPlaywright
  • An overview of Playwright Java
  • How to use the companion CommandBox library
  • A few end-to-end testing selector strategies
  • Live coding cbPlaywright tests

What this talk isn't

  • About unit, integration, or any other kind of testing besides end-to-end (or browser) tests
  • Comparison to other end-to-end testing tools
  • Deep dive into end-to-end testing best practices

What is cbPlaywright?

  • Includes the necessary jars and drivers to run Playwright Java
  • Provides integration with TestBox and ColdBox tests
  • Helper methods for making interacting with Playwright Java easier

What is cbPlaywright?

So...what is Playwright?

CFML

If Playwright Java exists...why would I use cbPlaywright?

Includes the necessary jars to run Playwright Java

Companion CommandBox module for downloading the correct platform drivers

Helper functions to turn this....

var screenshotOptions = createObject( "java", "com.microsoft.playwright.Page$ScreenshotOptions" ).init();
var screenshotPath = createObject( "java", "java.nio.file.Paths" ).get(
    javacast( "String", expandPath( "/tests/results/screenshotOne.png" ) ), javacast( "String[]", [] )
);
screenshotOptions.setPath( screenshotPath );
page.screenshot( screenshotOptions );

...into this

screenshotPage( page, "/tests/results/screenshotOne.png" );

Installation

box install cbPlaywright

Unfortunately, there is more this time....

There's this thing called a driver....

  • Running the driver from the Playwright Java jars was finicky
  • The driver-bundle jar is very large (about 200 MB unzipped)
  • The driver-bundle included versions for all the platforms
  • You ended up downloading a full driver-bundle for every cbPlaywright installation.
  • Interacting with the driver CLI was a pain

CommandBox cbPlaywright

CommandBox cbPlaywright

  • Installs as a dependency of cbPlaywright
  • Manages installing the correct driver for your platform
  • Automatically downloads a driver on install
  • Provides a passthrough to the Playwright CLI
# Install the Playwright driver
cbplaywright driver install

# Install Chromium as a test browser
playwright install chromium

Configuration

// tests/Application.cfc
component {

    this.javaSettings = {
        loadPaths: directoryList(
            rootPath & "modules/cbPlaywright/lib",
            true,
            "array",
            "*jar"
        ),
        loadColdFusionClassPath: true,
        reloadOnChange: false
    };
      
}

Add the Jar Paths

// tests/Application.cfc
component {

    this.mappings[ "/cbPlaywright" ] = rootPath & "/modules/cbPlaywright";
      
}

Create a Mapping

// .env
CBPLAYWRIGHT_DRIVER_DIR=/path/to/driver/directory

Set the Driver Path

(OPTIONAL)

Usage

Creating a Test

component extends="cbPlaywright.models.PlaywrightTestCase" {
	
    function run() {
        // ...
    }

}

Extend the Playwright Test Case

component extends="cbPlaywright.models.ColdBoxPlaywrightTestCase" {
	
    function run() {
        // ...
    }

}
component extends="cbPlaywright.models.PlaywrightTestCase" {
	
    function run() {
        describe( "Playwright Tests", () => {
            it( "can visit the Google homepage", () => {
                var browser = launchBrowser( variables.playwright.chromium() );
                var page = browser.newPage();
                navigate( page, "https://google.com" );
                waitForLoadState( page );
                expect( page.title() ).toBe( "Google" );
            } );
        } );
    }

}

Visit a Page

component extends="cbPlaywright.models.PlaywrightTestCase" {
	
    function run() {
        describe( "Playwright Tests", () => {
            it( "can perform a search on Google", () => {
                var browser = launchBrowser( variables.playwright.chromium() );
                var page = browser.newPage();
                navigate( page, "https://google.com" );
                waitForLoadState( page );

                var searchBox = locateElement( page, '[aria-label="Search"]' );
                fill( searchBox, "playwright" );
                press( searchBox, "Enter" );
              
                expect( page.url() ).toInclude( "https://www.google.com/search?q=playwright" );
            } );
        } );
    }

}

Fill Out a Form

What makes a good Selector?

  • Role
  • Label Text
  • Placeholder Text
  • Text
  • Display Value

What makes a good Selector?

1. Queries Accessible to Everyone

2. Semantic Queries

3. Test IDs

  • Alt Text
  • Title
component extends="cbPlaywright.models.PlaywrightTestCase" {
	
    function run() {
        describe( "Playwright Tests", () => {
            it( "can visit the Google homepage", () => {
                var browser = launchBrowser( variables.playwright.chromium() );
                var page = browser.newPage();
                navigate( page, "https://google.com" );
                waitForLoadState( page );
                expect( page.title() ).toBe( "Google" );
                screenshotPage( page, "/tests/results/homepage.png" );
            } );
        } );
    }

}

Take a Screenshot

component extends="cbPlaywright.models.PlaywrightTestCase" {
	
    function run() {
        describe( "Playwright Tests", () => {
            it( "fill out the search form and click a link", () => {
                var browser = launchBrowser( variables.playwright.chromium() );
                newRecordedContextForBrowser( browser,  "/tests/results/videos", ( context ) => {
                    var page = context.newPage();
                    navigate( page, "https://google.com" );
                    waitForLoadState( page );

                    var searchBox = locateElement( page, '[aria-label="Search"]' );
                    fill( searchBox, "playwright" );
                    press( searchBox, "Enter" );
              
                    expect( page.url() ).toInclude( "https://www.google.com/search?q=playwright" );
                  
                    click(
                        locateElement(
                            page,
                            "text=Playwright: Fast and reliable end-to-end testing for modern ..."
                        )
                    );
                  
                    waitForUrl( page, "https://playwright.dev/" );
                } );
            } );
        } );
    }

}

Record a Video

component extends="cbPlaywright.models.PlaywrightTestCase" {
    function run() {
        describe( "Playwright Tests", () => {
            it( "fill out the search form and click a link", () => {
                var browser = launchBrowser( variables.playwright.chromium() );
                var context = browser.newContext();
                traceContext( context, "/tests/results/trace.zip", function() {
                    var page = context.newPage();
                    navigate( page, "https://google.com" );
                    waitForLoadState( page );

                    var searchBox = locateElement( page, '[aria-label="Search"]' );
                    fill( searchBox, "playwright" );
                    press( searchBox, "Enter" );
              
                    expect( page.url() ).toInclude( "https://www.google.com/search?q=playwright" );
                  
                    click(
                        locateElement(
                            page,
                            "text=Playwright: Fast and reliable end-to-end testing for modern ..."
                        )
                    );
                  
                    waitForUrl( page, "https://playwright.dev/" );
                } );
            } );
        } );
    }
}

Save a Trace

Save a Trace

Demo

Bonus

name: PRs and Branches

on:
  - push

jobs:
  tests:
    runs-on: ubuntu-latest
    name: Tests
    steps:
      - name: Checkout Repository
        uses: actions/checkout@v2

      - name: Setup Java JDK
        uses: actions/setup-java@v1.4.3
        with:
          java-version: 11

      - name: Set Up CommandBox
        uses: elpete/setup-commandbox@v1.0.0

      - name: Install dependencies
        run: box install

      - name: Start server
        run: box server start

      - name: Install Playwright dependencies
        run: |
          box playwright-cli install-deps
          box playwright-cli install chromium

      - name: Run TestBox Tests
        run: box testbox run

GitHub Actions

CFCamp 2023 — cbPlaywright

By Eric Peterson

CFCamp 2023 — cbPlaywright

  • 325