This repository demonstrates running Playwright tests in GitHub Actions using Playwright Workspaces, publishing HTML reports to an Azure Storage static website, and maintaining a small JSON feed that the lightweight index.html viewer consumes.
Sample Report: https://pwwdemoreportsstorage.z7.web.core.windows.net/
At a high level:
- GitHub Actions (see
.github/workflows/playwright-workspaces.yml) runs Playwright tests (configured inplaywright.service.config.ts). - The workflow assembles an HTML report (Playwright report), creates a
meta.jsondescribing the run, uploads the report to an Azure Storage static website ($web), and merges a new feed entry intofeed.json. index.htmlin this repo is a viewer that readsfeed.jsonand displays available test run reports (it expectsmeta.jsonand related report content to be present under the run folder on the static website).
This README documents how the pieces fit together and how to configure Azure and GitHub Secrets to run the sample.
.github/workflows/playwright-workspaces.yml— the GitHub Actions pipeline that runs tests and uploads the HTML report andmeta.jsonto Azure. It also updatesfeed.json.playwright.service.config.ts— Playwright configuration used by the sample tests (the repo includes a Playwright test intests/).index.html— static viewer that loadsfeed.jsonand renders the list of reports (and pullsdata/report.jsonfrom each report URL to show stats when available).
-
On
push/pull_request, the workflow checks out the repo and installs dependencies. -
It runs Playwright tests (the workflow uses
npx playwright test -c playwright.service.config.tsand expects the Playwright Service environment variables if required).Note: the workflow uses the Playwright
blobreporter and merges it into an HTML report in CI so an HTML report is produced and uploaded. -
The job ensures a minimal HTML exists for
playwright-report/index.htmland then buildsmeta.jsoncontaining metadata about the run (title, subtitle, dates, commitSha, runId, reportUrl, outcome). -
It uploads the contents of
./playwright-reportto Azure Storage static website under a run directory (e.g.$web/run-<id>-<attempt>/...). -
The workflow writes
meta.jsonand then merges a new feed entry into the globalfeed.json(also stored in the$webstatic website container) —index.htmlpulls this feed.
index.html then fetches feed.json at runtime, lists entries, and loads data/report.json from each report URL to show test stats (if present).
The workflow uploads generated reports and metadata into the storage account's $web container (static website hosting). There are two primary setup tasks:
- Create an Azure Storage account and enable static website hosting
- Create a service principal for
azcopyto authenticate from GitHub Actions
Below are example az commands to provision resources (replace placeholders):
# create resource group
az group create --name my-playwright-rg --location eastus
# create a StorageV2 account
az storage account create \
--resource-group my-playwright-rg \
--name <STORAGE_ACCOUNT_NAME> \
--location eastus \
--sku Standard_LRS \
--kind StorageV2
# enable static website and set index / error docs
az storage blob service-properties update \
--account-name <STORAGE_ACCOUNT_NAME> \
--static-website --index-document index.html --404-document 404.html
# get the static website endpoint (use this to preview uploads)
az storage account show -n <STORAGE_ACCOUNT_NAME> -g my-playwright-rg --query primaryEndpoints.web -o tsvCreate a service principal used by azcopy in the Actions runner. Grant it at least the Storage Blob Data Contributor role on the storage account (scoping more narrowly is recommended):
az ad sp create-for-rbac \
--name "azcopy-playwright-ci" \
--role "Storage Blob Data Contributor" \
--scopes "/subscriptions/<SUBSCRIPTION_ID>/resourceGroups/my-playwright-rg/providers/Microsoft.Storage/storageAccounts/<STORAGE_ACCOUNT_NAME>"The above command prints JSON with appId, password, tenant. Save those and add to GitHub secrets.
Create your Playwright Workspaces resource by following the Azure quickstart:
After the workspace is created, open the workspace in the Azure portal and copy the region-specific service endpoint from the Get Started page — this is the PLAYWRIGHT_SERVICE_URL you will store in GitHub Secrets.
Below is a quick mapping of the GitHub secrets used by the workflow and how to obtain each value.
This sample uses Playwright Workspaces access token authentication. You only need the PLAYWRIGHT_SERVICE_URL and PLAYWRIGHT_SERVICE_ACCESS_TOKEN for the test runs. The azcopy-related secrets are required for uploading reports to the static website (see below).
-
PLAYWRIGHT_SERVICE_URL— workspace service endpoint (Get Started page in the workspace)- Portal: workspace → Get Started → copy the endpoint URL (region-specific)
-
PLAYWRIGHT_SERVICE_ACCESS_TOKEN— Playwright Workspaces access token (used in this sample)- Portal: workspace → Access / API tokens → Create a token, copy the generated token value and add it to GitHub secrets as
PLAYWRIGHT_SERVICE_ACCESS_TOKEN. - Treat this token like a password: do not check it into source control.
- Portal: workspace → Access / API tokens → Create a token, copy the generated token value and add it to GitHub secrets as
-
STORAGE_ACCOUNT_NAME— Azure Storage account name used for hosting static website- Portal: Storage account → Overview → Account name
- CLI: output from
az storage account createoraz storage account list
-
AZCOPY_SPA_APPLICATION_ID,AZCOPY_SPA_CLIENT_SECRET,AZCOPY_TENANT_ID— credentials forazcopy(if you are using a service principal to upload)- Create a service principal scoped to your storage account and save the
appIdandpasswordvalues:az ad sp create-for-rbac --name "azcopy-playwright-ci" \ --role "Storage Blob Data Contributor" \ --scopes "/subscriptions/<SUBSCRIPTION_ID>/resourceGroups/<RG>/providers/Microsoft.Storage/storageAccounts/<STORAGE_ACCOUNT_NAME>"
- Use the returned
appIdasAZCOPY_SPA_APPLICATION_ID - Use the returned
passwordasAZCOPY_SPA_CLIENT_SECRET - Use the returned
tenantasAZCOPY_TENANT_ID
- Use the returned
- Create a service principal scoped to your storage account and save the
Notes:
- For best security, use Microsoft Entra ID + GitHub OIDC (configure a federated identity credential on the App Registration or create a user-assigned managed identity) instead of long-lived client secrets where possible. The workflow supports Entra ID authentication via the
azure/loginaction (see the quickstart link). - The Playwright workspace service endpoint (the
PLAYWRIGHT_SERVICE_URL) is region-specific and must match the workspace you created.
Add the following repository secrets (Repository settings → Secrets → Actions). These are referenced by the workflow:
STORAGE_ACCOUNT_NAME— the storage account name used for static website uploadsAZCOPY_SPA_APPLICATION_ID— the service principal app id (valueappId)AZCOPY_SPA_CLIENT_SECRET— the service principal password (valuepassword)AZCOPY_TENANT_ID— the tenant id (valuetenant)PLAYWRIGHT_SERVICE_URL— (optional) Playwright Service URL if you run tests against a Playwright test servicePLAYWRIGHT_SERVICE_ACCESS_TOKEN— (optional) Playwright Service token
The workflow uses azcopy with service principal env vars (set as above). It also uses jq in the runner to build meta.json and to merge feed.json entries.
- The workflow writes a
meta.jsonper run (contains title, date, updated, branch, commitSha, reportUrl, outcome, runId etc.). - The workflow merges a feed entry into
feed.jsonat the repository static site root.index.htmlfetchesfeed.jsonand renders entries; it will fetchdata/report.jsonfrom each report URL to show stats in the viewer when available.
If you are adapting this example, keep meta.json fields the same (title, updated, generatedAt, reportUrl, outcome) so index.html can show the run properly.
- Ensure the service principal has
Storage Blob Data Contributorrole on the storage account resource (otherwiseazcopywill get 403). - The workflow ensures
meta.jsonis uploaded with--cache-control "no-cache, no-store, must-revalidate"to reduce stale content issues. - If
index.htmlshows "No matching reports", check thatfeed.jsonis present at the static website root ($web/feed.json) and that entries havereportUrlpointing to the correct run folder. - Use
az storage account show -n <ACCOUNT> -g <RG> --query primaryEndpoints.web -o tsvto find the static website endpoint.
This repository is a small sample. Use the code as you see fit.