TestKase
TestKase
|Docs
Visual

Uploading from CI

Your tests take the screenshots. We tell you what changed.

Your tests already sign in, fill the basket and open the modal. Let them take a screenshot, send us the folder, and we will tell you what changed.

Works with Playwright, Cypress, Puppeteer, Selenium — anything that writes a PNG.

Three steps

1. Take a screenshot in your tests

await page.screenshot({ path: "shots/home.png", fullPage: true });

fullPage: true matters — without it you only check the top of the page.

2. Upload the folder when the suite finishes

- run: npx playwright test

- run: npx @testkase/visual upload ./shots --project "Marketing"
  env:
    TESTKASE_TOKEN: ${{ secrets.TESTKASE_TOKEN }}

3. Read the result

Build 12 of "Marketing" — 40 pictures.
  feature/blue-button · a1b2c3d · PR #214
  checkout          same
  home              same
  pricing           CHANGED  2.14% different

40 screens · 1 changed · 0 new · 1 to review

It exits 1 when something changed, so your pipeline fails like any other test. Open Visual → Builds to approve it or report a bug.

You need three things

  • A Visual subscription
  • A project, made in Visual first — see Getting Started
  • A token — your API key from profile menu → API Keys, saved as TESTKASE_TOKEN

One rule: keep your filenames the same

shots/home.png is the screen home. Next week's shots/home.png is compared against it.

If your filenames change, every picture looks new — so nothing is compared and the build passes while checking nothing. Run --dry-run first to see the names, and watch for the warning when a whole run matches nothing.

npx @testkase/visual upload ./shots --project "Marketing" --dry-run
3 pictures would be uploaded to project "Marketing":
  shots/home.png      →  home
  shots/pricing.png   →  pricing
  shots/checkout.png  →  checkout

To name a screen yourself, use --name for one file or --map for a folder.

What the words mean

WordMeaning
newFirst time we have seen this screen. It becomes the baseline.
sameIdentical to the approved version.
CHANGEDDifferent. Someone needs to look.
failedWe could not compare it. The picture is saved — run it again.
Exit codeMeaning
0Nothing to review
1Something changed, or a picture could not be uploaded
2The command was wrong

Options

OptionWhat it does
--project <name>Required. Which project these screens belong to.
--dry-runPrint the names and upload nothing.
--name / --mapName a screen yourself, for one file or a folder.
--files / --ignoreWhich files to include or skip. Default **/*.png.
--browser / --osPass these if you run the same suite twice — each gets its own baselines.
--concurrency <n>Uploads at once. Default 5, maximum 10.
--build / --no-finishFor a suite split across machines. See below.
--branch / --commit / --prRead from your CI automatically. Pass them only if yours is not recognised.
--exit-zero-on-changesAlways exit 0, for your first pipeline.

npx @testkase/visual --help has the rest.

A suite split across machines

Make one build and have them all join it, or five machines make five builds and your reviewer gets five lists.

# the first machine starts it and leaves it open — it prints the id
npx @testkase/visual upload ./shots-1 --project "Marketing" --no-finish

# the rest join it; the last one finishes and reports the result
npx @testkase/visual upload ./shots-2 --project "Marketing" --build <id> --no-finish
npx @testkase/visual upload ./shots-3 --project "Marketing" --build <id>

FAQ

▶Does this use my Live or Automate minutes?

No. Uploading never starts a session or claims a device. Visual is counted in pictures compared, on its own plan.

▶Do the images go through your servers?

No. They go straight from your CI to our storage — our API only hands out the address. That keeps it fast however many you send.

▶What size should the screenshots be?

Whatever your tests produce. Screens are matched on width, so a desktop shot and a mobile shot are tracked separately. Height is not part of the match, so a page that grows taller is still the same screen.

▶How does it know my branch?

It reads the variables your CI already sets — GitHub Actions, GitLab, CircleCI, Bitbucket, Buildkite and Jenkins. On your own machine it says nothing rather than guessing.

▶What if a picture cannot be compared?

It is reported as failed and the run exits 1. The picture is saved, so running the build again is enough.