Playwright + Chrome Test Runner
Example of using the Playwright Test project to run automated website tests in the cloud and display their results. Usable as an API.
src/main.ts
src/runCodegen.ts
src/transform.ts
1import { execSync } from 'node:child_process';2import fs from 'node:fs';3import path from 'node:path';4
5import { Actor } from 'apify';6import type { Dictionary } from 'apify-client';7
8import log from '@apify/log';9
10import { collectAttachmentPaths, transformToTabular } from './transform.js';11
12function ensureFolder(pathname: string) {13    if (!fs.existsSync(pathname)) {14        fs.mkdirSync(pathname, { recursive: true });15    }16}17
18function getConfigPath() {19    return `${import.meta.dirname}/../playwright.config.ts`;20}21
22function getResultDir() {23    return `${import.meta.dirname}/../playwright-report`;24}25
26const getConfig = (options: {27    screen: { width: number; height: number };28    headful: boolean;29    timeout: number;30    locale: string;31    darkMode: boolean;32    ignoreHTTPSErrors: boolean;33    video: string;34}) => {35    const { screen, headful, timeout, ignoreHTTPSErrors, darkMode, locale, video } = options;36
37    return `38// Watch out! This file gets regenerated on every run of the actor.39// Any changes you make will be lost.40
41// Tweak your configuration through the Actor's input through the Apify console or directly in the \`input.json\` file.42import { defineConfig } from '@playwright/test';43export default defineConfig({44    timeout: ${timeout},45    use: {46        headless: ${!headful},47        viewport: { width: ${screen.width}, height: ${screen.height} },48        ignoreHTTPSErrors: ${ignoreHTTPSErrors},49        colorScheme: '${darkMode ? 'dark' : 'light'}',50        locale: '${locale}',51        video: '${video}',52        launchOptions: {53            args: [54                '--disable-gpu', // Mitigates the "crashing GPU process" issue in Docker containers55            ]56        },57    },58    reporter: [59        ['html', { outputFolder: '${getResultDir()}', open: 'never' }],60        ['json', { outputFile: '${getResultDir()}/test-results.json' }]61    ],62});`;63};64function runTests() {65    try {66        execSync(`npx playwright test --config=${getConfigPath()}`, {67            cwd: import.meta.dirname,68            encoding: 'utf8',69            stdio: 'inherit',70        });71    } catch {72        // suppress error, the report will be generated anyway73    }74}75
76function updateConfig(args: {77    screenWidth?: number;78    screenHeight?: number;79    headful?: boolean;80    timeout?: number;81    darkMode?: boolean;82    locale?: string;83    ignoreHTTPSErrors?: boolean;84    video?: string;85}) {86    const {87        screenWidth = 1280,88        screenHeight = 720,89        headful = false,90        timeout = 60,91        darkMode = false,92        locale = 'en-US',93        ignoreHTTPSErrors = true,94        video = 'off',95    } = args;96
97    const config = getConfig({98        screen: { width: screenWidth, height: screenHeight },99        headful,100        timeout: timeout * 1000,101        locale,102        darkMode,103        ignoreHTTPSErrors,104        video,105    });106    fs.writeFileSync(getConfigPath(), config, { encoding: 'utf-8' });107}108
109await Actor.init();110const input = ((await Actor.getInput()) ?? {}) as Dictionary;111
112ensureFolder(getResultDir());113updateConfig(input);114
115runTests();116
117const kvs = await Actor.openKeyValueStore();118await kvs.setValue('report', fs.readFileSync(path.join(getResultDir(), 'index.html'), { encoding: 'utf-8' }), {119    contentType: 'text/html',120});121const jsonReport = JSON.parse(fs.readFileSync(path.join(getResultDir(), 'test-results.json'), { encoding: 'utf-8' }));122const attachmentPaths = collectAttachmentPaths(jsonReport);123
124const attachmentLinks = await Promise.all(125    attachmentPaths.map(async (x) => {126        const attachment = fs.readFileSync(x.path);127        await kvs.setValue(x.key, attachment, { contentType: x.type ?? 'application/octet' });128        return { ...x, url: kvs.getPublicUrl(x.key) };129    }),130);131
132await Actor.pushData(transformToTabular(jsonReport, attachmentLinks));133
134const reportURL = kvs.getPublicUrl('report');135log.info('The test run has finished! The report is available in the Output tab or at the link below:');136console.log(reportURL);137
138await Actor.exit();Playwright test template
Run your Playwright tests on the Apify platform effectively and easily. Just set up your test environment using a user-friendly UI and let the platform do the rest.
Note: This is a custom version of Playwright Test Runner Actor. Unlike the original Actor, this version reads test suite files from the tests folder and does not allow you to pass the test files via Apify input.
Features
Run your Playwright tests on the Apify platform
No more pre-commit hooks or CI/CD pipelines. Integrate your tests with the Apify Platform using a user-friendly UI and forget about the hassle of setting up your test environment.
 
Collect and analyze your test results online
After running the tests, the Apify platform stores the results in comprehensive datasets. You can view the results directly on the platform or download them to your local machine using a REST API.
 
No more problems with incompatible browser versions
Playwright Test toolkit automatically downloads the latest versions of Chromium, Firefox, and WebKit browsers and installs them in the Apify platform.
This way, you can test your websites using all the popular browsers without worrying about compatibility issues.
 
How to use
Just provide your test suite files in the tests folder and run the Actor. The Actor will automatically run all the tests in the tests folder and store the results in the KVS/dataset fields.
You can also customize the test run by specifying other options in the input, e.g. the screen size, headful/headless execution or the maximum run time.
Test Generator
You can also use the Playwright Codegen to compose your test suites even faster. Just run npm run codegen in your project folder and record your workflow.
The code generator will automatically create a test suite file for you and save it in the tests folder.
Resources
- Original Playwright Test Runner Actor
- Playwright testing: how to write and run E2E tests properly
- Video guide on getting scraped data using Apify API
- Integration with Make, GitHub, Zapier, Google Drive, and other apps
- Video tutorial on how to run end-to-end Playwright tests
- A short guide on how to build web scrapers using code templates
Crawlee + Cheerio
A scraper example that uses Cheerio to parse HTML. It's fast, but it can't run the website's JavaScript or pass JS anti-scraping challenges.
One‑Page HTML Scraper with Cheerio
Scrape single page with provided URL with Axios and extract data from page's HTML with Cheerio.
Crawlee + Puppeteer + Chrome
Example of a Puppeteer and headless Chrome web scraper. Headless browsers render JavaScript and are harder to block, but they're slower than plain HTTP.
Crawlee + Playwright + Chrome
Web scraper example with Crawlee, Playwright and headless Chrome. Playwright is more modern, user-friendly and harder to block than Puppeteer.
Crawlee + Playwright + Camoufox
Web scraper example with Crawlee, Playwright and headless Camoufox. Camoufox is a custom stealthy fork of Firefox. Try this template if you're facing anti-scraping challenges.
Empty TypeScript project
Empty template with basic structure for the Actor with Apify SDK that allows you to easily add your own functionality.