Skip to content

108: Fix the report's baseline path and duplicate image keys - #330

Merged
DanielJette merged 2 commits into
mainfrom
108-report-entry-delineation
Oct 3, 2026
Merged

DanielJette merged 2 commits into
mainfrom
108-report-entry-delineation

Conversation

@DanielJette

@DanielJette DanielJette commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

What does this change accomplish?

Fixes #108

Two defects in report.yml. The second is the one filed; the first was found while verifying it and
is arguably worse.

1. baseline_image names a file that does not exist.

Reporter.getBaselinePath() built the path from the test method name, but baselines are stored as
<Class>_<method>.png — that is what loadBaselineBitmapForComparison() resolves, via
TestDescription.name. The committed report.yml in this repo shows the two side by side in a single
entry:

    - test:
        name: default
        class: ClientListActivityScreenshotTest
        baseline_image: assets/screenshots/30-1080x1920@420dp-en_US/default.png
        test_image:  /data/.../screenshots/30-1080x1920@420dp-en_US/ClientListActivityScreenshotTest_default.png

test_image is right; baseline_image is missing the class prefix. Every baseline_image line
Testify has ever written points at nothing, so any tool following that path gets a missing file.

2. Duplicate keys when a test asserts more than once.

startTest() runs once per test method, but captureOutput() runs from every assertSame(). A
second assertion appended another baseline_image: / test_image: pair inside the same - test:
entry
, which is duplicate keys and therefore invalid YAML.

Worth being precise about the scope, because the issue title is broader than what is left to fix.
The cross-method bug #108 actually reports — two methods collapsed under one - test: — was real,
and is already fixed on main. The report pasted into that issue has no skipped: row, so it
predates the current insertHeader() / headerLineCount, and the issue's own repro now produces two
properly separated entries. What remains broken is the multiple-assertions-per-method case, which is
what the guard below addresses.

How have you achieved it?

  • getBaselinePath() now uses testDescription.name instead of testDescription.methodName, so it
    matches the loader exactly.
  • captureOutput() records the image paths once per test, guarded by a hasCapturedOutput flag that
    startTest() resets.

The guard is deliberately the conservative half of the fix. Emitting one report entry per assertion —
a nested captures: list — is the shape the report probably wants long term, but it changes the
report contract that the Bitrise step and reportShow consume, and it is really part of #85
(assertSame(name)). This keeps the YAML valid today without pre-empting that design.

Scope of Impact and Testing instructions

baseline_image values change for every test, from <method>.png to <Class>_<method>.png. That is
the fix, but anything parsing report.yml and resolving that path should be aware. test_image,
status, cause and description are untouched.

The two places that document a report.yml sample are updated to match —
docs/docs/get-started/8-use-gradle-plugin.md and Plugins/Gradle/README.md. Both were stale in a
second way as well: neither showed the skipped: row that insertSessionInfo() has emitted since
the header rework, which is the same staleness that produced the report in #108.

CHANGELOG entries added under Unreleased for both.

Two existing assertions in ReporterTest encoded the old, wrong path and are updated. Three tests
added:

  • getBaselinePath() matches the file name the baseline is loaded from — asserts against
    TestDescription.name so it fails if the two paths diverge again.
  • captureOutput() called twice in one test records the image paths once.
  • startTest() allows the next test to record its own image paths — guards against the flag sticking
    across tests.

Verified locally:

./gradlew Library:ktlintCheck Library:testDebugUnitTest   # BUILD SUCCESSFUL

@AndroidTestifyBot AndroidTestifyBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes requested

Both code changes are correct. What's missing is around them.

1. The documented report example now shows the wrong format

baseline_image changes shape for every test, but the two places that document report.yml still show the old one:

  • docs/docs/get-started/8-use-gradle-plugin.md:532 — baseline_image: assets/screenshots/29-1080x2220@440dp-en_US/withFocusOnBackground.png
  • Plugins/Gradle/README.md:469 — same line

The committed report.yml at the repo root has it too (it's the file the PR description quotes as evidence). Please update the two docs examples to <Class>_<method>.png, and either regenerate or drop the root file.

2. CI is red

Legacy Sample failed and Library / Plugin are pending. This PR changes the reporter and the Legacy sample is the module with testify-reporter enabled, so it can't be waved through. For what it's worth I could not reproduce it — LegacySample:screenshotTest on this branch gives OK (88 tests) locally, and #329 failed the same way in the same window — so I expect a re-run to pass. It needs to actually be green.

3. The description mischaracterises #108

delineation between test methods is correct, and always was

The report in #108 shows two different methods (default, usingLayoutResName) under a single - test:. That is not the multiple-assertSame() case; it is a dropped - test: line between methods, and that header has no skipped: row, so it predates the current headerLineCount. It is fixed on main today, but "always was" is contradicted by the issue itself. I ran the issue's exact repro on this branch:

./gradlew LegacySample:screenshotTest -PtestClass=dev.testify.sample.clients.details.ClientDetailsViewScreenshotTest
./gradlew LegacySample:reportPull
    - test:
        name: default
        baseline_image: assets/screenshots/37-1080x2220@440dp-en_US/ClientDetailsViewScreenshotTest_default.png
        status: PASS
    - test:
        name: usingLayoutResName
        baseline_image: assets/screenshots/37-1080x2220@440dp-en_US/ClientDetailsViewScreenshotTest_usingLayoutResName.png
        status: PASS

So closing #108 is justified, and the new baseline_image values name files that exist. Please correct the description so the issue isn't closed with the wrong explanation attached.

Verified correct

  • getBaselinePath() now matches loadBaselineBitmapForComparison()'s description.name.
  • The hasCapturedOutput guard loses nothing: both assertions in one method resolve the same output file name, so the dropped pair would have been an exact duplicate.
  • Library:ktlintCheck Library:testDebugUnitTest pass locally.
  • CHANGELOG hunk conflicts with the other five open code PRs.

@DanielJette

Copy link
Copy Markdown
Contributor Author

Agreed on all three, and point 3 is a fair hit — I overclaimed.

1. Documented examples updated

docs/docs/get-started/8-use-gradle-plugin.md:532 and Plugins/Gradle/README.md:469 now show ClientListActivityScreenshotTest_withFocusOnBackground.png.

Both were stale in a second way you did not mention: neither carried the skipped: row that ReportSession.insertSessionInfo() emits. Added, since it is the same staleness that produced the report in #108 and leaving it would invite the next reader to reproduce the confusion.

On the root report.yml — it is not committed. git log --all -- report.yml is empty and it is gitignored at .gitignore:9; what we both have is an untracked artifact from a local run in October 2025. So there is nothing to regenerate or drop in the repo, and I have left your copy alone. It is still useful as evidence, since it shows a wrong baseline_image next to a correct test_image in one entry — I have just stopped calling it "committed".

2. The #108 characterisation — you are right, and I was wrong

The report in #108 shows default and usingLayoutResName under a single - test:. That is a dropped - test: line between two methods, not two assertSame() calls in one. So cross-method delineation was broken; saying it "always was" correct contradicts the issue I was closing.

The corroborating detail is the one you spotted: that header has no skipped: row, so it predates the current insertHeader() / headerLineCount, which is where it got fixed. Your repro on this branch producing two properly separated entries is the confirmation.

Description rewritten to say the cross-method bug was real and is already fixed on main, and that what remains — and what the guard here addresses — is the multiple-assertions-per-method case.

3. CI

Agreed it has to be actually green rather than argued green. Nothing in this PR touches the Legacy sample, and your local OK (88 tests) plus #329 failing identically in the same window both point at a flake, but that is a reason to re-run rather than to wave it through. The new commit will have triggered a fresh run — I will keep an eye on it and chase it properly if it comes back red rather than assuming.

CHANGELOG conflicts

Noted, and expected: all six code PRs insert at the same Unreleased anchor. Whichever merges first wins and the rest need a one-line rebase. Happy to serialise them in whatever order you prefer.

@AndroidTestifyBot AndroidTestifyBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved

All three points are resolved.

  • Both documented report.yml examples now show <Class>_<method>.png, and adding the missing skipped: row was a good catch on top of what I asked for.
  • You're right about the root report.yml: it's gitignored and untracked. My mistake for calling it committed.
  • The description now says the cross-method bug in #108 was real and is already fixed on main, and that this PR's guard is for multiple assertions in one method. That's accurate, and it matches the repro I ran on this branch earlier (two correctly separated entries for ClientDetailsViewScreenshotTest).
  • CI is green on the new head, including Legacy Sample, Library and Plugin. The docs build is clean.

Merge-order note only: the CHANGELOG hunk will still conflict with whichever of the other code PRs lands first.

@DanielJette
DanielJette merged commit 6677b67 into main Oct 3, 2026
12 checks passed
@DanielJette
DanielJette deleted the 108-report-entry-delineation branch October 3, 2026 20:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Test reporter is not correctly delineating test cases in a single class

2 participants