# How to Build a Playwright Smoke Test in GitHub Actions

> Cara membuat smoke test Playwright for beginners: install, write three critical-path checks, run them in GitHub Actions and upload the HTML report.

URL: https://www.matthewswong.com/en/blog/cara-smoke-test-playwright-github-actions/

- Author: Matthews Wong (https://www.matthewswong.com/en/about/)
- Published: 2026-10-17
- Updated: 2026-10-17
- Category: Web Dev

> **Key takeaway:** To build a Playwright smoke test, install it with npm init playwright@latest, write three checks on your most important path, let webServer in playwright.config.ts start the built app, then run npx playwright test in GitHub Actions and upload the playwright-report folder as an artifact. Keep it small so it stays fast and stable.

The build is green, every unit test passes, you deploy, and then the home page turns out blank because one script throws in the browser. No test saw it, because no test ever opened a browser. A smoke test closes that gap: it opens the built app and checks that the few things that must work, do.

This post takes you from nothing to a Playwright smoke test running on every pull request. Every command and option was checked against the official Playwright and GitHub documentation, and the pattern matches the game-smoke.yml workflow that guards the game page on this site.

Want the reasoning behind each step, including the wait loop and the server log on failure? Take the free lesson

Playwright smoke test in GitHub Actions

. This post is its hands-on version, step by step.

## What you need

Not much. The examples use a Next.js project, but the same pattern works for any web app you can build and start with one command.

Node.js and a web project that has npm run build and npm run start scripts.

A GitHub repository, so GitHub Actions can run the tests.

A terminal and some comfort with npm. You do not need to have used Playwright before.

## Step 1: Install Playwright

Run one command in the project folder. Playwright asks a few questions: TypeScript or JavaScript, the tests folder name, whether to add a GitHub Actions workflow, and whether to install browsers right away. Answer no to the workflow, because we write it ourselves in Step 5 so you understand what is in it.

You end up with playwright.config.ts, a tests folder with one example test, and Playwright recorded in package.json and the lockfile. Delete the example test, because it opens someone else's website. We will write tests for your own app.

## Step 2: Write the first smoke test

Create tests/smoke.spec.ts. Each test opens a page and checks something a user sees: the title, the main heading, and one click on the most important path. Replace My App and Blog with text that really exists in your app. Playwright waits for elements to be ready before acting, so you never need a sleep.

One habit beginners often get wrong: calling isVisible() and comparing the result yourself. It asks once, at that instant. Use the assertion that waits, await expect(...).toBeVisible(), which the docs say waits until the condition is met.

## Step 3: Set up the config and webServer

In playwright.config.ts, the webServer block tells Playwright how to start the app and which address to check. Playwright waits for that address to answer before it runs the tests, so you do not write a wait loop yourself. baseURL makes page.goto('/') go to your app. We also limit the projects to chromium, because one browser is enough for a smoke test.

Three things matter in this config. First, the port in command, url and baseURL must match. Second, the webServer timeout defaults to 60000 ms. Third, reuseExistingServer is true locally so a server you already run gets reused, and false on CI so it always starts a fresh one.

## Step 4: Run it on your machine first

Do not jump straight to CI. Build first, then run the tests locally, because a failure here is far quicker to read than one in the GitHub log. Tests run headless by default, so add --headed if you want to watch the browser move.

When everything passes, the terminal summarises how many tests passed. When something fails, the HTML report opens by itself and shows which step failed. If Playwright complains about webServer, it is almost always because npm run build has not run yet.

## Step 5: Run it in GitHub Actions

Create .github/workflows/smoke.yml. The order is: checkout, set up Node, npm ci, build, install Chromium, run the tests, upload the report. The browser is installed after npm ci because each Playwright version needs specific browser binaries, so the install command must read the version that is actually installed.

On this site, game-smoke.yml does the same job another way: it starts npm start in the background and waits with a curl loop instead of using webServer. Both are valid, and the free lesson below covers the loop version. The workflow also matches it in three ways: it installs only Chromium, cancels the older run on the same branch, and grants only read access to the repository contents.

> The report upload step must use if with !cancelled(). Without it, steps after a failed test are skipped, and a failed test is exactly when you need the report.

## Step 6: Download and read the report when it fails

When a run fails, open the run page on GitHub, find the Artifacts section and download playwright-report. Extract the zip, then serve it through Playwright. The HTML report needs a web server, so opening index.html straight from the folder will not work.

In our config, retries is 2 on CI and the trace is recorded on the first retry. A failing test therefore carries a trace you can open from the report: you see every step and how the page looked, instead of guessing from error text.

## Step 7: Keep it small

A smoke test is a tripwire, not a regression suite. Three to five checks on the most important path are enough: the home page renders, the main navigation works, and one core action completes. The Playwright docs advise testing only what you control.

Every extra test is one more way to fail for reasons unrelated to your change. If the app calls a third-party service, the docs suggest using the Playwright Network API to guarantee the response you need, so an outside site cannot turn the run red. Put deeper testing elsewhere.

## Common errors and how to fix them

The six problems that most often break a new smoke test on CI, with their causes and fixes.

| Symptom | Cause | Fix |
| --- | --- | --- |
| The run fails before the first test, with a message about webServer not answering | The address in url did not answer within the timeout (60000 ms by default): the app was not built, or the port differs from the command | Run npm run build in a step before the tests, and make the port in command, url and baseURL the same. Raise the timeout only if the server really is slow |
| An error saying something is already running at the webServer address | reuseExistingServer is false and another server is already listening there | Stop the old server, or use reuseExistingServer: !process.env.CI so local runs reuse the running one |
| The browser cannot be found when tests launch on CI | The browser install step is missing, or runs before npm ci so the version does not match | Add npx playwright install --with-deps chromium after npm ci, in the same job |
| Firefox or WebKit tests fail on CI | The default config runs three browsers, but the workflow installed only Chromium | Keep only the chromium project in the config, or install every browser you use |
| A test failed but there is no report in Artifacts | An upload step with no condition is skipped because an earlier step failed | Add if with !cancelled() to the upload-artifact step |
| The report's index.html opens but shows nothing | The HTML report was opened straight from a file, but it needs a web server | Run npx playwright show-report followed by the extracted folder name |

## Checklist before you push

npm run build then npx playwright test passes on your machine.

There are only three to five tests, all on the most important path, and none loads a site you do not own.

The port in command, url and baseURL match, and projects are limited to the browsers you install.

The workflow installs the browser after npm ci and builds before the tests.

The report upload step uses if with !cancelled(), and forbidOnly is on for CI.

## Go deeper

The free lesson

 covers the other way to start the server, a curl wait loop, and printing the server log when a test fails. If you are curious about AI agents that drive a browser, compare the approaches in

.

The rule to carry: a smoke test is a few checks on the most important path, run against the built app in a real browser, with the report always uploaded on failure. Start with three tests, and add one only when a failure that slipped through proves you need it.

## Sources and references

- Playwright docs: Setting up CI (GitHub Actions)
- Playwright docs: Web server (webServer)
- Playwright docs: Test configuration
- Playwright docs: Best practices
- GitHub: actions/upload-artifact

## Source links

- https://playwright.dev/docs/ci-intro
- https://playwright.dev/docs/test-webserver
- https://playwright.dev/docs/test-configuration
- https://playwright.dev/docs/best-practices
- https://github.com/actions/upload-artifact

## FAQ

### What is a Playwright smoke test and how is it different from a unit test?

A smoke test opens the built app in a real browser and checks a few things that must work, such as the home page and main navigation. A unit test calls functions directly and never loads the bundle. That is why a smoke test can catch a page that compiles but renders blank, which a unit test cannot.

### Why does my Playwright test pass locally but fail in GitHub Actions?

The usual causes are a missing browser install step, an app that was not built before the tests, or a port that differs between command, url and baseURL. On CI, reuseExistingServer is false, so a fresh server must start and answer within the webServer timeout. Download the playwright-report artifact and open the trace to see the exact failing step.

### Do I need to install all browsers in GitHub Actions?

No. A smoke test needs only one browser, so install just Chromium with npx playwright install --with-deps chromium and keep only the chromium project in playwright.config.ts. If the config still lists Firefox and WebKit, those tests fail because their browsers are missing.

### How many tests should a smoke test have?

Keep it to a few checks on the most important path, such as three to five. A smoke test is a tripwire, so a failure should mean something is clearly broken. More tests add more chances to fail for unrelated reasons and make the run slower.

### How do I open the Playwright report after a failed run?

Open the run on GitHub, download the playwright-report artifact from the Artifacts section and extract the zip. Then run npx playwright show-report followed by the folder name. Opening index.html directly does not work, because the report needs a web server.

---

- HTML version: https://www.matthewswong.com/en/blog/cara-smoke-test-playwright-github-actions/
- Bahasa Indonesia: https://www.matthewswong.com/id/blog/cara-smoke-test-playwright-github-actions/
- Site index for agents: https://www.matthewswong.com/llms.txt
- Sitemap: https://www.matthewswong.com/sitemap.xml
- API description (OpenAPI): https://www.matthewswong.com/openapi.json
