Skip to content

fix(scanner): report a not-found barcode as not found - #712

Open
EugeneSusla wants to merge 4 commits into
simonoppowa:developfrom
EugeneSusla:fix/scanner-not-found-message
Open

fix(scanner): report a not-found barcode as not found#712
EugeneSusla wants to merge 4 commits into
simonoppowa:developfrom
EugeneSusla:fix/scanner-not-found-message

Conversation

@EugeneSusla

Copy link
Copy Markdown

Problem

Scanning a barcode that Open Food Facts does not have shows "Error while fetching product data" with a Retry button, rather than the "Product not found" message the app already ships.

ScannerBloc classifies the failure with:

if (exception == ProductNotFoundException) {

That compares the caught exception object against the type, which is never equal. The productNotFound branch is therefore unreachable, and every OFF 404 falls through to the generic error state. errorProductNotFound and its wiring in scanner_screen.dart were already in place and simply never reached.

The Retry button is especially misleading here: OFFDataSource deliberately does not retry a not-found (shouldRetry: (e) => e is! ProductNotFoundException), so retrying a 404 can never succeed.

Reproduces with any barcode absent from OFF — for example an in-store GS1-128 label, whose GTIN is restricted-circulation and so never registered globally.

Change

  • exception == ProductNotFoundExceptionexception is ProductNotFoundException.
  • Adds ScannerBloc tests covering both failure classifications.

The test asserts the barcode actually reached the search use case, and that the settled state is a failure rather than filtering the stream for one, so a swallowed exception fails with a readable diff instead of passing on the bloc's catch-all.

Verification

  • New test verified red before the fix, green after.
  • flutter analyze clean; full suite green (964 tests).

The failure branch compared the caught exception object against the
ProductNotFoundException *type*, which is never equal, so the
productNotFound state was unreachable and every OFF 404 surfaced as
"Error while fetching product data" with a Retry button that could not
help. Use an `is` check so the existing errorProductNotFound string and
its UI wiring are actually reached.

Adds a ScannerBloc test covering both failure classifications.
Both cases asserted only on the emitted failure type, which the bloc also
produces for an unexpected throw from anywhere inside its try — a misused
fake, or a future reordering that queries config before the search. The
helper now asserts the barcode reached the search use case, and the seeded
error is a required non-null constructor argument so a null-deref cannot
stand in for it.

Also asserts the settled state is a failure instead of filtering the stream
for one, with a timeout, so a bloc that loads a product or emits nothing
fails with a readable diff rather than hanging.
The config fake threw, and the bloc queries config inside the same try as
the search, so a swallowed search exception still surfaced as a generic
failure — the state assertion could never see ScannerLoadedState and the
comment claiming otherwise was wrong. Return a real ConfigEntity, matching
the fake in scanner_screen_pick_mode_test.dart, so dropping the exception
now fails with a readable diff.

Also keeps the bloc nullable so a future non-scanning test cannot trip a
LateInitializationError in teardown, and names the settle timeout with the
reason it cannot race a loaded machine.
30s matched package:test's own default per-test timeout, so a hung stream
would likely have failed as the harness's generic timeout rather than the
diagnostic this guard exists to raise. Back to 5s, with the constraint
written down.

Also closes every bloc a test builds rather than just the last one, and
notes that the config fake's values are placeholders — the bloc only reads
usesImperialFoodUnits, and only on a path these tests never take.
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.

1 participant