Skip to content

fix: add null safeguard and source-asymmetry test for buildVehiclePopupData - #511

Open
VishalRaut2106 wants to merge 5 commits into
OneBusAway:developfrom
VishalRaut2106:fix/vehicleUtils-null-safeguard-508
Open

fix: add null safeguard and source-asymmetry test for buildVehiclePopupData#511
VishalRaut2106 wants to merge 5 commits into
OneBusAway:developfrom
VishalRaut2106:fix/vehicleUtils-null-safeguard-508

Conversation

@VishalRaut2106

@VishalRaut2106 VishalRaut2106 commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

This PR addresses the two follow-up suggestions from the maintainer regarding buildVehiclePopupData edge cases.

Changes

  1. Null Safeguard: Added optional chaining (activeTrip?.tripHeadsign) inside buildVehiclePopupData so that if activeTripMap.get(...) ever returns undefined, the code gracefully returns undefined instead of throwing a fatal TypeError.
  2. Asymmetry Test: Added a new test in vehicleUtils.test.js where vehicle and activeTrip have identically-named properties with different values. This explicitly proves that the helper is pulling data from the correct source object.
  3. Null-State Test: Added a test that passes undefined for activeTrip to guarantee the optional chaining correctly prevents crashes.

Closes #508

Summary by CodeRabbit

  • Bug Fixes

    • Prevented vehicle labels and popup details from failing when trip information is unavailable.
    • Vehicle information now remains visible even when no active trip or destination is present.
  • Tests

    • Added coverage for missing trip data and overlapping vehicle/trip fields.

@coveralls

Copy link
Copy Markdown

Coverage Status

Coverage is 81.05%VishalRaut2106:fix/vehicleUtils-null-safeguard-508 into OneBusAway:develop. No base build found for OneBusAway:develop.

@aaronbrethorst

Copy link
Copy Markdown
Member

Code review

Found 1 issue:

  1. Adding optional chaining to activeTrip?.tripHeadsign contradicts the explicit contract comment in OpenStreetMapProvider.svelte.js, which states that buildVehiclePopupData reads activeTrip.tripHeadsign "without optional chaining" and asks to "keep this contract consistent rather than implying null is expected". The sibling reader getVehicleLabel still dereferences activeTrip unguarded and runs first (line 461, before buildVehiclePopupData at 478), so the new guard cannot prevent the crash it targets (bug due to src/lib/Provider/OpenStreetMapProvider.svelte.js:28-31)

export function buildVehiclePopupData(vehicle, activeTrip, stopsMap) {
return {
nextDestination: activeTrip?.tripHeadsign,
vehicleId: vehicle.vehicleId,
lastUpdateTime: vehicle.lastUpdateTime,

🤖 Generated with Claude Code

- If this code review was useful, please react with 👍. Otherwise, react with 👎.

@aaronbrethorst aaronbrethorst left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The two tests here are genuinely good and are the part of #508 I most wanted. The asymmetry test is constructed correctly — giving vehicle and activeTrip the same field names with different values is the only way that source-swap regression gets caught deliberately rather than by luck, and putting the wrong value on the other object is the right way to write it. The activeTrip: undefined test would really throw a TypeError without the optional chaining, so it's a true regression guard rather than a passing-by-construction test.

What needs another pass is the guard itself — not because it's wrong, but because it leaves the file contradicting itself.

OpenStreetMapProvider.svelte.js currently carries this, three lines above getVehicleLabel:

// activeTrip is always truthy here: the sole caller (vehicleUtils.js) guards on
// it, and buildVehiclePopupData reads activeTrip.tripHeadsign without optional
// chaining. Keep this contract consistent rather than implying null is expected.

That comment is accurate on develop — I confirmed the guard it refers to at vehicleUtils.js, where applyRouteVehicles does if (activeTrip && activeTrip.routeId === routeId && ...) before ever calling addVehicleMarker or updateVehicleMarker. After this PR, the middle clause is simply false, and the last sentence is arguing against the change sitting one file over.

There's a functional wrinkle underneath the comment, too. In addVehicleMarker, getVehicleLabel(activeTrip) runs at line 461 and reads activeTrip.tripHeadsign unguarded; buildVehiclePopupData isn't reached until line 478. Same ordering in the update path (547 before 557). So if the contract ever did break, the crash just moves seventeen lines earlier and the optional chaining never gets a chance to help.

So one of these two, your call:

  1. Keep the guard — then update that comment block to say the precondition is enforced by the caller and the chaining is belt-and-braces, and give getVehicleLabel the same treatment so the file is internally consistent.
  2. Drop the guard and take the other branch #508 offered — document the precondition on buildVehiclePopupData instead. The caller already guarantees it, so this is defensible.

I'd lean toward (1). Either way, keep both tests exactly as they are — under option 2 the undefined test becomes a documentation-of-precondition test and should assert the throw instead.

Small fix, and the testing instinct here is right. Send it back and I'll take another look.

@VishalRaut2106
VishalRaut2106 force-pushed the fix/vehicleUtils-null-safeguard-508 branch from 0697fd1 to ebc4768 Compare August 1, 2026 05:18
@coderabbitai

coderabbitai Bot commented Aug 1, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@VishalRaut2106, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 52 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: bc473f10-74a1-4545-abc8-243a5178574f

📥 Commits

Reviewing files that changed from the base of the PR and between ebc4768 and c04edfe.

📒 Files selected for processing (1)
  • src/lib/__tests__/vehicleUtils.test.js
📝 Walkthrough

Walkthrough

The change adds null-safe activeTrip handling to vehicle labels and popup data. Tests verify field-source mapping and behavior when activeTrip is undefined.

Changes

Vehicle popup safety

Layer / File(s) Summary
Null-safe vehicle data handling
src/lib/vehicleUtils.js, src/lib/Provider/OpenStreetMapProvider.svelte.js
buildVehiclePopupData and getVehicleLabel use optional chaining when reading activeTrip.tripHeadsign.
Popup data source and null-trip tests
src/lib/__tests__/vehicleUtils.test.js
Tests verify that vehicle fields and trip destination use their correct sources. Tests also verify safe handling of an undefined activeTrip.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

Suggested reviewers: aaronbrethorst, ahmedhossamdev

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The source-asymmetry test and utility safeguard satisfy part of #508, but getVehicleLabel can still dereference an undefined activeTrip. Guard activeTrip before every dereference at the getVehicleLabel call site, or document and enforce the precondition consistently.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the null safeguard and source-asymmetry test for buildVehiclePopupData.
Out of Scope Changes check ✅ Passed All code and test changes directly support the null-handling and source-asymmetry objectives in #508.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/lib/__tests__/vehicleUtils.test.js`:
- Around line 76-98: Update the test fixture in buildVehiclePopupData’s
asymmetry case so activeTrip also provides conflicting lastUpdateTime and
predicted values, while retaining the vehicle values asserted in the expected
result. Ensure all three overlapping fields—vehicleId, lastUpdateTime, and
predicted—verify that data is sourced from vehicle.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 0f7ff56c-0f0f-4151-b3ac-aa575609a2cf

📥 Commits

Reviewing files that changed from the base of the PR and between 89f2c24 and ebc4768.

📒 Files selected for processing (3)
  • src/lib/Provider/OpenStreetMapProvider.svelte.js
  • src/lib/__tests__/vehicleUtils.test.js
  • src/lib/vehicleUtils.js

Comment thread src/lib/__tests__/vehicleUtils.test.js
@VishalRaut2106

Copy link
Copy Markdown
Contributor Author

hey @aaronbrethorst , I have implemented the requested changes kindly review and let me know if any changes required

@aaronbrethorst

Copy link
Copy Markdown
Member

Code review

Found 1 issue:

  1. Character-encoding corruption in src/lib/__tests__/vehicleUtils.test.js: seven em dashes (, UTF-8 E2 80 94) were rewritten as the mojibake sequence ΓÇö (CE 93 C3 87 C3 B6) — the CP437 misreading of a UTF-8 em dash, almost certainly from an editor/terminal writing the file back in the wrong codepage. develop has all seven as clean em dashes; this branch has all seven corrupted (lines 127, 128, 612, 616, 652, 679, 779). Line 616 is not a comment — it corrupts a live suite name, so the test runner now prints fetchAndUpdateVehiclesForRoutes ΓÇö live highlight. Prettier and ESLint will not flag this, so CI passes and it lands silently. The three intentional changes in this PR (the two new tests and the activeTrip?. guards) are unrelated to these lines and are correct. (bug due to src/lib/__tests__/vehicleUtils.test.js:616)

// route redraw.
describe('fetchAndUpdateVehiclesForRoutes ΓÇö live highlight', () => {
beforeEach(() => {

🤖 Generated with Claude Code

- If this code review was useful, please react with 👍. Otherwise, react with 👎.

@aaronbrethorst aaronbrethorst left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

You took option 1 and you took it correctly. The contract comment above getVehicleLabel now says the right thing — precondition enforced by the caller, chaining is belt-and-braces — and getVehicleLabel got the same guard, which closes the real wrinkle I raised: it runs at line 461 (and 547 on the update path) before buildVehiclePopupData, so without that change the crash just moved seventeen lines earlier and the new optional chaining never got a chance to help. I re-checked both call paths at your head commit and activeTrip isn't dereferenced anywhere else in either one, so the window is genuinely closed. vehicleUtils.js:64 still guards with if (activeTrip && ...), so the comment's claim is accurate.

Both tests survive intact, and extending the asymmetry test to also conflict on lastUpdateTime and predicted made it strictly stronger. These are real assertions — revert the ?. and the undefined test throws; swap any source in the implementation and the asymmetry test fails.

One mechanical thing to fix before this lands.

The branch mangles seven em dashes into mojibake in vehicleUtils.test.js.

Every (UTF-8 E2 80 94) on the lines this PR touched came back as ΓÇö (CE 93 C3 87 C3 B6) — the classic CP437 misreading of a UTF-8 em dash. That's an editor or terminal encoding setting somewhere in your toolchain, not something you typed. I hexdumped the raw file at c04edfe to be sure, and confirmed develop has seven clean em dashes and zero mojibake while your head has the inverse.

Lines 127, 128, 612, 616, 652, 679, 779. Line 616 is the one that actually bites:

describe('fetchAndUpdateVehiclesForRoutes ΓÇö live highlight', () => {

That's a string literal, not a comment, so the corruption shows up in test runner output rather than sitting quietly in the source. Prettier and ESLint don't normalize text inside comments or string literals, which is why CI is green on this.

Restoring those seven lines to their develop bytes is the whole fix — nothing else in the diff needs to change. Worth checking your editor's file encoding is set to UTF-8 so it doesn't recur.

The substance here is done and done well. Push the encoding fix and I'll merge it.

@tarunsinghofficial

Copy link
Copy Markdown
Collaborator

Hey @VishalRaut2106 , Let me know if you're still working on this PR :)

@VishalRaut2106

Copy link
Copy Markdown
Contributor Author

Hey @VishalRaut2106 , Let me know if you're still working on this PR :)

Hey Tarun, I was working on this but I’d like you to take a look and handle fixing it. Once you’re done, please let me know how you solved it — I’d like to understand the approach.

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.

Follow-up: harden buildVehiclePopupData tests and guard against null activeTrip

4 participants