Skip to content

test(ember): drive addon/ coverage behind a per-file 100% gate - #310

Draft
roncodes wants to merge 91 commits into
mainfrom
feature/fleetops-addon-coverage-loop-cfd7dd
Draft

test(ember): drive addon/ coverage behind a per-file 100% gate#310
roncodes wants to merge 91 commits into
mainfrom
feature/fleetops-addon-coverage-loop-cfd7dd

Conversation

@roncodes

@roncodes roncodes commented Sep 4, 2026

Copy link
Copy Markdown
Member

Drives addon/ toward 100% coverage behind a per-file gate, with the LCOV uploaded to Codecov under a frontend flag.

This is a draft: the gate is still red on purpose. pnpm run test:ci exits 1 because the campaign is not finished — 83 blueprint it renders scaffolds have never been green (DEFECTS #4) and coverage is at 32%, not 100%. The branch is green in the sense that matters day to day: no test that passes today fails because of this work, and every iteration has been verified against a full run.

Where it stands

baseline (iteration 1) now
statements 3,213/18,831 (17.1%) 6,042/18,609 (32.5%)
branches 1,862/12,335 (15.1%) 4,035/12,099 (33.3%)
functions 1,092/5,526 (19.8%) 1,795/5,491 (32.7%)
tests 832: 502 pass / 330 fail 1,289: 1,206 pass / 83 fail

309 files are at 100% on all four metrics. 69 commits: 48 test, 21 fix.

What is in it

Phase A — the gate. ember-cli-code-coverage + ember-window-mock, coverage config with the pnpm-symlink excludes, stamp-coverage-run / check-coverage / check-coverage-test, the Testem.afterTests upload (a plain QUnit.done truncates the multi-MB POST size-dependently), the test:ci script set, codecov.yml with backend and frontend flags both carrying forward, and the Test with coverage job. The gate enforces 100% on all four metrics per file, that every eligible addon/ file appears in the report, and that the artifacts came from the run that just finished.

Getting the baseline honest. It started at 775/827 red. Eight harness root causes are fixed and recorded (undeclared tracked-built-ins, host-console module shims, initializer test paths, ember-intl locale hydration, a missing dummy model, testem's bail_on_uncaught_error, fetch's config.API).

Phase B — the grind, file by file with each batch slice-verified before commit.

Production fixes found while covering

21 of them, each in its own commit, never bundled into a coverage commit. A representative few:

  • fix(order) — the route-optimization error reached nobody: the component called intl.t(...) in a catch without injecting intl, and asked for a key that does not exist. Two commits.
  • fix(map) — the device drawer showed the wrong list, and its Device column opened a panel bound to the event rather than the device.
  • fix(order) — every selected document uploaded twice; the tracking lookup form reloaded the page; the active tracking stop matched on undefined ids.
  • fix(components) — seven components had no app/ re-export at all, so the resolver could not find them; four app-tree templates were shadowing the addon's co-located ones.
  • fix(vehicle,driver) — 23 form fields ignored the write permission.
  • fix(map)assignPane handed a layer the whole { pane, paneName } pair where Leaflet wants the name.

Decisions waiting on you

DEFECTS.md carries the full worklist. Three entries are genuinely yours to call, and I have not picked for you:

  • fix: Place creation and validation #37 / feature: Internationalization #38 custom-entity/form — the image upload reads a config nothing provides, and the dasherized type never sticks.
  • v0.4.16 #83 services/leaflet-draw-restriction.js — an entire service with no consumer anywhere in addon/, reading this.map and this.notifications it never declares, so its guards cannot bind and its six user-facing warnings are all no-ops. Wire it up or delete it.

One more is outside this package: #75, six fleetops-data models declare a custom-field-value relationship no package defines. Worked around in the dummy app so the suite can run.

Reviewing

The per-iteration ledger is COVERAGE-PROGRESS.md — numbers, what each batch covered, and the traps found. DEFECTS.md is the worklist, in the format the ember-ui campaign used: every unreachable-code claim is traced to the caller, template or constant that closes it off, never "appears unused".

Phase A of the addon/ coverage campaign. Ports the ember-ui coverage
setup (ember-cli-code-coverage 3.1.0 behind COVERAGE=true, per-file
100% gate with artifact-freshness check and its self-test, Testem
afterTests upload, codecov.yml with backend+frontend flags, a "Test with
coverage" CI job that uploads with if: always()) and repairs the harness
so the existing suite can run at all.

Baseline before: 775/827 tests red, no coverage artifact possible.
Baseline after:  832 tests, 502 pass / 330 fail (223 of the failures
are untouched `ember generate` scaffolds, DEFECTS #4).

Coverage baseline (denominator for the campaign):
  Statements 3213/18831 (17.1%) · Branches 1862/12335 (15.1%)
  Functions  1092/5526  (19.8%) · Lines    3123/17868 (17.5%)
  530/746 addon files have gaps; 3 never load (see ledger).

Harness root causes fixed (DEFECTS #1-#3, #5-#11): ember-core imports
tracked-built-ins without declaring it; ember-core imports host-console
modules (config/environment, extensions, the `fetch` AMD shim) and reads
config.API at load; ember-intl hydrates every bundled locale and the
browser lacks mn-mn ICU data; the dummy app had no file model, no
hostRouter, and EXTEND_PROTOTYPES off while the console runs with it
on; testem's bail_on_uncaught_error truncated runs; a test assigned the
real window.location and navigated the browser away; eight tests
imported non-existent dummy/ initializer paths.

Coverage plumbing traps: ember-cli-code-coverage 3.x has no included
hook, so the istanbul plugin is wired in index.js; for an ember-engines
buildEngine addon the babel key must be top-level in that config; the
json reporter must be requested; and both plugin and middleware read
coverage.js from ember-addon.configPath (tests/dummy/config).
…currency-decorators import

- addon/helpers/is-active-route.js re-exported @fleetbase/console/helpers/is-active-route,
  a module that exists nowhere; nothing referenced the helper (DEFECTS #12).
- order/details/proof.js imported ember-concurrency-decorators, which this package does not
  declare; ember-concurrency (already used everywhere else) exports the same task decorator
  (DEFECTS #13).

Both modules threw on evaluation and were absent from the coverage report.
All 20 real tests in layout/fleet-ops-sidebar-test.js now pass (13 were red).
Every failure was test-side, against ember-ui's current navigator markup:

- the nested view's back control is a sibling <button>, so :first-of-type
  and :nth-of-type(n) never addressed menu items; items are now looked up
  by their own index through findAll
- qunit-dom includesText only inspects the first match; container-level
  checks are used where the test meant "any item"
- search results are portaled to #application-root-wormhole; the suite
  mounts that inside #ember-testing (ember-ui's idiom) and asserts on the
  full result list, since branch items legitimately match by keyword
- the universe stub lacked the Evented surface the component subscribes to
- common.create-new-resource is a host-console translation; added
  tests/helpers/host-translations.js, applied via addTranslations for every
  rendering test

Coverage: 3213/18831 -> 3219/18856 statements (17.07%); tests 502 -> 513 pass.
fleet-ops-sidebar.js 77/94 statements, 43/48 functions.
addon/helpers/format-duration.js only re-exported ember-ui's helper; nothing imports
the addon module and templates resolve the helper from ember-ui's own app re-export.
Being a pure re-export it also never entered the coverage report (DEFECTS #14).
Replaces the two blueprint scaffolds under layout/fleet-ops-sidebar/ with real
rendering suites: store queries and their params, error reporting, universe-driven
reloads, live-map focusing (ready and deferred, including a failed transition),
panel-title routing with the fleets-index collapse, permission-gated panel
dropdown, and every row dropdown action delegating to the actions services.
FleetListingPanel is replaced by a template-only stand-in so the listing is
tested in isolation.

Coverage: 3219 -> 3280/18856 statements (17.39%); tests 513 -> 534 pass (851 total).
driver-listing.js 43/43 statements, fleet-listing.js 40/43.
Adds a registry-and-search suite for the sidebar: items and panels other extensions
register through the universe menu registry (root, per-section, in-place footer
components, nested panels, pinned items, priority ties), the API search provider
(merged after local matches; empty and failing responses swallowed), the primary
action, and the default-orders-landing predicate including a null router URL.

Removes nine fallbacks in the component that no caller can reach (DEFECTS #15):
five default arguments, the eight @Tracked list initializers the constructor always
overwrites before any read, the ?? [] in withRegistryItems, the console.-prefix guard
in fullRoute and the ?? 0 in defaultPriorityForRoute. The empty-query guard in
searchNavigation stays behind an istanbul ignore naming the navigator's own filter.

fleet-ops-sidebar.js: 83/83 statements, 41/41 branches, 48/48 functions.
Coverage: 3280 -> 3290/18845 statements (17.45%); tests 534 -> 543 pass (860 total).
Adds an actions-and-layout suite for the sidebar operations monitor: store
normalisation (including hosts without pushPayload and record-like fleets),
request failure, universe-driven reloads, live-map sources, per-tab filters and
empty states, fleet expansion with embedded members, filtered fleet rows, every
row dropdown action, locate flows, alternative fleet identifiers and null entries,
and the list-height observers with all three boundary fallbacks.

Removes code no path can reach (DEFECTS #16): three unreferenced getters, the
empty-query guard in resourceMatches, the expandedFleetIds initializer, two
never-nullish ?? 0 fallbacks and nine default arguments; the trailing tab check in
performEmptyStateAction is now unconditional. Non-browser host guards, the
did-insert ordering guard and the EXTEND_PROTOTYPES-shadowed Array.isArray branch
carry istanbul ignores naming their reason.

operations-monitor.js: 242/242 statements, 98/98 branches, 113/113 functions.
Coverage: 3290 -> 3359/18827 statements (17.84%); tests 543 -> 563 pass (880 total).
Real suites for order-route-type, part-identity, equipment-identity, driver-identity,
device-identity and vehicle-identity; the driver-name, vehicle-name and place-address
scaffolds replaced; residue cases appended to attached-vehicle, telematic-device and
telematic-provider. The pre-existing resource-identities suite passes again: its red
tests passed @column={{hash}}, and a bare helper as a named argument is rejected at
template compile time in Ember 5 ({{(hash)}} invokes it).

Removes three click guards the templates already enforce (DEFECTS #17): the
attached-vehicle hasVehicle check, the telematic-provider `?? row` fallback and the
driver-identity `column ?? {}` in a compact-only getter.

All 12 files in addon/components/cell/ are at 100% statements, branches and functions.
Coverage: 3359 -> 3462/18825 statements (18.39%); tests 563 -> 627 pass (935 total).
…fully

Rewrites the 14 red `Unit | Utility` suites (13 of them `assert.ok(result)`
scaffolds, one stale against commit f784e71) and adds order-route-summary,
to-calendar-date and waypoint-label tests. All 16 utils are at 100% on every
metric; the loader suite is deterministic (no network, no free-running
timers).

Source, all recorded in DEFECTS #18-#22:
- leaflet-to-geojson: createFeatureCollectionFromLayers passed an object to a
  constructor that needs an array and always threw; fixed. normalizeToRings'
  duplicate trailing return merged.
- utils/geojson/geo-json.js: dead duplicate importing a missing sibling;
  deleted with its app shim and scaffold.
- map-drawer-dropdown-position: reads window via ember-window-mock.
- leaflet-plugin-loader: dead defaults at single-caller internals deleted,
  non-browser guards istanbul-ignored with reasons.
- setup-customer-portal, to-calendar-date, to-multi-polygon: unreachable
  defensive fallbacks deleted.
- utils/leaflet: Leaflet global resolved lazily instead of at module load.

Coverage: statements 3462/18825 -> 3682/18813, branches 2135 -> 2364,
functions 1197 -> 1243; tests 627 pass / 308 fail -> 690 / 290; files fully
covered 229 -> 246.
Two harness root causes, recorded in DEFECTS #23:
- ember-local-storage caches storageFor proxies at module level; the first
  test app destroys them and later apps assert "Cannot create a new tag ...
  after it has been destroyed" on any currentUser/appCache read. The shared
  setup helpers now reset that cache after every test.
- route-optimization and leaflet-routing-control register through
  universe.getApplicationInstance(), which only the console sets; those
  suites hand the universe the test owner.

Six suites corrected to the source contract (DEFECTS #24): stubs moved off
getter-only @action members onto the host router, the contextmenu removal
count, device panel.view's warning return, and geofence's multi-hop reload
wait.

Coverage: statements 3682 -> 3808/18813, branches 2364 -> 2412,
functions 1243 -> 1277; tests 690 pass / 290 fail -> 709 / 271. No
source change.
…r/route suites

- Move 16 unit tests from connectivity/telematics/index/* to the current
  connectivity/telematics/* paths (the subtree was moved without its tests);
  drop one stale duplicate and one mis-generated duplicate (DEFECTS #25).
- Add the two missing app/ re-export shims for controllers/operations/orders/
  index and controllers/operations/routes/index; the dummy app could not
  resolve either (#26).
- Correct the orders-details route test to the route's delegation to the
  controller teardown methods, fix the attachments assertion count, and
  replace the register-osrm scaffold with a real registration test (#27).
- Record the pre-existing "Failed to fetch" spill from form scaffolds (#28).

Coverage: statements 3808 -> 3891/18813, branches 2412 -> 2449,
functions 1277 -> 1299; tests 709 pass / 271 fail -> 735 / 244.
Eight tests corrected to the source contract (DEFECTS #29): the
vehicle-details controller passes the vehicle public id (a9eed9c), the
map settings payload carries the tile-url keys, two prototype-based fakes
shadow getters / bind @action through an inheriting object, and the three
helper scaffolds became real tests.

Both Leaflet initializer tests now drive the initializer's 100ms poll
through a captured setInterval. They used to leak that poll into the next
test, and in a full run the polyfill's leaked poll crashed on the stub
Leaflet global the next test installed. Both initializers are at 100%.

Everything outside `Integration | Component` is green.

Coverage: statements 3891 -> 3904/18813, branches 2449 -> 2459,
functions 1299 -> 1300; tests 735 pass / 244 fail -> 747 / 236; files
fully covered 246 -> 249. No source change.
…p tile-url arguments

Replaces the scaffolds for fuel-report, warranty, place, integrated-vendor,
service-area and zone details with real suites (13 tests) and adds a shared
register-template-only helper that stands in ember-ui's network-backed
CustomField::Yield and CountryName.

Source (DEFECTS #30): five map templates passed `@url={{leaflet-tile-url}}`
as a bare named argument, which Ember 5 rejects at render, so the place,
service-area and zone details views and the two map modals could not render.
All five now use `{{(leaflet-tile-url)}}`. The helper's dead `= {}` hash
default is trimmed and it has its own test.

Coverage: statements 3904 -> 3916/18813, branches 2459 -> 2465,
functions 1300 -> 1304; tests 747 pass / 236 fail -> 761 / 230; files
fully covered 249 -> 250.
Replaces the fuel-report, warranty, place, integrated-vendor, service-area
and zone form scaffolds with real suites (13 tests). A shared helper stands
in the store-backed ember-ui inputs and provides a record-like fixture whose
modelName/isNew let `cannot-write` resolve a real permission, so both the
enabled and disabled states are exercised. All six form components are at
100%.

Source (DEFECTS #31): fuel-report/form's onAutocomplete and
integrated-vendor/form's showAdvancedOptions/toggleAdvancedOptions were
referenced by no template; deleted.

Coverage: statements 3916 -> 3921/18808, branches 2465 -> 2469,
functions 1304 -> 1306; tests 761 pass / 230 fail -> 772 / 224; files fully
covered 250 -> 253.
…omponents

Replaces nine scaffolds with real rendering suites: modals/place-details,
modals/point-map, device/pill, driver/pill, vehicle/pill, entity/card,
vehicle/card, driver/panel-header and vehicle/panel-header (23 tests).

Source (DEFECTS #32): vehicle/pill.hbs passed `@this.resource=` instead of
`@resource=` to the Pill, so click handlers got no vehicle and the online
dot was always offline, and its tooltip invoked a string as a helper. Both
fixed.

Coverage unchanged (these components carry no JS to count); tests
772 pass / 224 fail -> 791 / 215.
Real suites for route-optimization-engine-select-button, order-progress-bar,
display-place, order-list-overlay/order and fleet/form (15 tests); all five
components are at 100% on every metric. The shared model-select stand-in
gained a clear button so relationship-clearing paths are testable.

Source (DEFECTS #33): fleet/form's unread `writePermission` getter and
`statusOptions` field, and order-progress-bar's dead lazy `progress`
initializer and unread `order` field, are deleted.

Coverage: statements 3920 -> 3930/18804, branches 2469 -> 2484,
functions 1306 -> 1311; tests 791 pass / 215 fail -> 806 / 210; files fully
covered 253 -> 258.
…order progress card

Real suites for vendor/form, sensor/form, contact/form and
order-progress-card (14 tests); all four components are at 100%.

Source (DEFECTS #34): the sensor form's never-invoked photo-upload task and
its injections are deleted, and the progress card's tracker guard tests the
order before dereferencing it, so a card without an order returns instead
of throwing 100ms after render.

Coverage: statements 3930 -> 3977/18800, branches 2484 -> 2507,
functions 1311 -> 1325; tests 806 pass / 210 fail -> 818 / 206; files fully
covered 258 -> 262.
…he entity form

Real suites for vendor/details, customer/details, driver/details and
entity/form (10 tests); all four components are at 100%.

Source (DEFECTS #35): vendor/details now branches on
`@resource.isIntegratedVendor` and passes `@vendor` to
IntegratedVendor::Details (the integrated view was unreachable and
mis-wired); customer/details labels the phone field correctly;
driver/details and order/details/detail call `join` with the separator
first; entity/form loses a dead lazy initializer and an unreachable
null-clear guard.

Coverage: statements 3977 -> 3986/18799, branches 2507 -> 2511,
functions 1325 -> 1330; tests 818 pass / 206 fail -> 828 / 202; files fully
covered 262 -> 264.
…nd global search

Real suites for driver-onboard-settings, widget/fleet-ops-key-metrics and
global-search (8 tests); all three components are at 100%. Both fetching
components were origins of the DEFECTS #28 fetch spill, which halves.

Source (DEFECTS #36): the onboarding settings load coalesces a null payload
instead of throwing on it; unreachable guards, parameter defaults and lazy
tracked initializers in both components are deleted.

Coverage: statements 3986 -> 4039/18794, branches 2511 -> 2541,
functions 1330 -> 1349; tests 828 pass / 202 fail -> 836 / 199; files fully
covered 264 -> 267.
…atar picker and custom entity form

The last "Failed to fetch" origin was ember-ui's CountryName mounted by
Vendor::PanelHeader; its suite now stands the component in and a full
run logs zero spills (DEFECTS #28 closed).

Real suites replace the scaffolds for device/form, avatar-picker and
custom-entity/form. A dead post-load guard in the avatar picker and an
uncalled save action in the custom entity form are deleted (#39). Two
findings are recorded for decision: the custom entity image upload reads
a config nothing provides (#37) and its dasherized type handler is
overwritten by the two-way Input (#38).

Coverage: statements 21.49% -> 21.66%, branches 20.71% -> 20.9%,
functions 24.42% -> 24.55%, lines 21.83% -> 22.01%; 850 pass / 194 fail
(+14 pass); 271 files fully covered (+4).
…completes

The admin settings passed `@disable` to ember-ui's Toggle, which only
knows `@disabled`, so the toggle stayed active while the panel below it
said onboarding had to finish first.
…activity form and event selector

Real suites replace the scaffolds for customer/admin-settings,
device/manager, activity/event-selector and activity/form; all four are
at 100% on every metric. Dead code found while profiling is deleted
(DEFECTS #41): an unread field, an uncalled save task, twelve optional-
chain branches around an injected intl service, a lazy initializer and
two guards for a no-resource render the template cannot survive.
DEFECTS #38 is amended with the activity form's key/code inputs, which
share the two-way Input race.

customer/admin-settings now reads `window` through ember-window-mock and
the dummy config mirrors the console's `stripe` block.

Coverage: statements 21.66% -> 22.09%, branches 20.9% -> 21.12%,
functions 24.55% -> 24.91%, lines 22.01% -> 22.45%; 862 pass / 190 fail
(+12 pass); 275 files fully covered (+4).
…ate every vehicle field on write permission

Both forms handed `this.controller` to their RegistryYield components, a
property neither component defines, so registered extensions always
received `undefined` even though both routes pass `@controller`. The
vehicle form also left four `<Input>`s and nineteen shorthand
InputGroups without the `cannot-write` gate the rest of the form uses.
A real suite replaces the vehicle/form scaffold: every bound text input
in DOM order, the eleven selects, the unit/money/date pickers, the five
registries, driver assignment, status pick, checkbox toggle, upload
success and failure, and the no-write state. Two unused actions and an
unused field are deleted (DEFECTS #44); the template fixes for the
controller argument and the ungated fields landed separately (#42, #43).

Coverage: statements 22.09% -> 22.13%, branches 21.12% -> 21.14%,
functions 24.91% -> 24.98%, lines 22.45% -> 22.49%; 864 pass / 189 fail
(+2 pass); 276 files fully covered (+1).
Both "create user" action buttons sent `subject_uui` for the upload's
subject, so the uploaded avatar was never associated with the user record.
A real suite replaces the driver/form scaffold: bindings, the user
details block, the three model selects, status, upload success and
failure, the create-user action button through its modal callbacks, and
the no-write state. The `subject_uui` typo it exposed landed separately
(DEFECTS #45).

Coverage: statements 22.13% -> 22.16%, functions 24.98% -> 25.05%,
lines 22.49% -> 22.53%; 867 pass / 188 fail (+3 pass); 277 files fully
covered (+1).
…ction buttons

The customer/form integration suite is rewritten on real record fixtures
and per-suite stand-ins: bindings, the address flow, the welcome-email
opt-in with and without existing meta, the hidden states and the
read-only state. The form's never-rendered "create user" action-button
block and its two injections are deleted (DEFECTS #47); the translation
typo it exposed landed separately (#46).

Coverage: statements 22.16% -> 22.24%, functions 25.05% -> 25.16%,
lines 22.53% -> 22.61%; 871 pass / 183 fail (+4 pass, -5 fail); 278
files fully covered (+1).
…ides carry

`matchesStop` compared `stop.id === activeStop.id` even when neither had
an `id`, so `undefined === undefined` made the first stop the active one
whenever stops were keyed by `uuid`/`public_id` alone; the "now heading
to" label and marker then pointed at stop 1 regardless of progress.
…hole component

Three harness faults kept all eleven order/details/tracking tests red: a
stub without `viewLabel`, an order builder whose trailing spread replaced
its merged tracker payload, and a "Due now" expectation for a rendering
removed in 9356fb6 (DEFECTS #49). Nine tests are added over the
lifecycle fallbacks, confidence and diagnostics, active-stop labelling,
reported ETA lookup, progress fallbacks, ping driver and the
assign-driver no-op; three unrendered getters and seven guards the
template already makes are deleted (#50). The active-stop matching bug
the suite exposed landed separately (#48).

Coverage: statements 22.24% -> 22.47%, branches 21.16% -> 21.5%,
functions 25.16% -> 25.28%, lines 22.61% -> 22.84%; 891 pass / 172 fail
(+20 pass, -11 fail); 280 files fully covered (+2).
`ensurePane` returns `{ pane, paneName }`, but `assignPane` assigned
that object to `layer.options.pane`. Leaflet's Map.getPane hands a
non-string straight back, so the object ended up where a DOM parent is
expected, and the service's own `#getPaneForLayer` then read
`pane.style?.display` off it as undefined -- meaning isLayerHidden's
category check could never fire for such a layer.

Latent rather than live: nothing outside the service calls assignPane
today. DEFECTS #82.
…t run

services/leaflet-layer-visibility-manager.js reaches 154/154
statements, 152/152 branches and 21/21 functions on fourteen tests,
driving a real Leaflet map through a stubbed leafletMapManager.

Covered: pane creation and reuse, assignPane including a throwing
redraw, the category show/hide/toggle cycle, registration by category
and id, showAll/hideAll in both modes, single-layer soft and hard
hiding across every layer shape, the re-add hook, element resolution
through getElement/_path/_icon, tooltip and popup close-and-restore,
and the full isLayerHidden ladder.

Dead code removed: #getOrCreateRendererForPane was a #private with no
in-class caller -- unreachable by construction -- so it, its
#renderersByPane map, the never-touched #paneState and the module-scope
`const L` it alone used are deleted. Both `if (!set) continue;` guards
go too (the key came from keys(), so get cannot miss), as does
#hideOverlays's `remember = true` default. DEFECTS #81 style traces
throughout; one istanbul ignore remains on the overlayPane fallback.

DEFECTS #83 records services/leaflet-draw-restriction.js as NEEDS
DECISION: no consumer anywhere, and it reads two collaborators it never
declares.

Statements 5297 -> 5446, branches 3411 -> 3563, functions 1694 -> 1715,
lines 5073 -> 5195. 309 files fully covered.
services/map-adapter/google.js -- the addon's largest file at 2,281
lines -- goes 113/1114 -> 340/1114 statements, 41/791 -> 233/791
branches, 6/148 -> 27/148 functions on fifteen tests.

The window.google fake was the whole unlock, and it is cheap: the
adapter reads the global inside each method, so extending the suite's
existing stub with LatLng, LatLngBounds, Marker, Size, Point, an
AdvancedMarkerElement and event.addListenerOnce was enough. No build
change needed, unlike the Leaflet adapter's module-scope capture.

Viewport: every no-map early return, centre with and without zoom, pan,
zoom in/out, getCenter/getBounds through Google's function-style
accessors and their empty answers, flyTo's immediate pan and deferred
zoom, and fitBounds across a LatLngBounds, a corner pair, loose points
and nested arrays, with padding defaults and the maxZoom ceiling in
both directions.

Markers: the classic path with waypoint badge, icon url and size
defaults; the advanced path building, labelling and rotating its own
content; updateMarkerPosition outright, at zero duration, animated to
completion, cancelling a running animation, and jumping when there is
no position to ease from or setPosition refuses; rotation; and removal
with animation cancel, tooltip cleanup and both detach styles.

Statements 5446 -> 5673, branches 3563 -> 3750, functions 1715 -> 1737,
lines 5195 -> 5402. Statements past 30% for the first time.
services/map-adapter/google.js goes 340/1114 -> 507/1114 statements,
233/791 -> 419/791 branches, 27/148 -> 51/148 functions on thirteen
tests, all green first time.

Overlays: the three shapes with Fleet-Ops defaults and every caller
override, the too-few-points rejections, a polygon accepting one flat
ring, nested rings, or a mixed list where a short ring is dropped, the
click and right-click that record _selectedOverlay, and removal with
tooltip cleanup.

Routing controls: one polyline per style, the unstyled route blue with
its precedence rules, a route with no coordinates, unique generated
ids, markers suppressed, overridden or skipped, and removal by id, by
handle, of an unknown id and of an empty handle.

positionWaypoints across the lone-point flyTo with its deferred pan,
both zoom ceilings, declared bounds and an empty list. removeLayer
across all three detach styles with draft and selection bookkeeping,
and the whole Layer Visibility section including a layer carrying a
label marker.

Statements 5673 -> 5840, branches 3750 -> 3936, functions 1737 -> 1761,
lines 5402 -> 5545.
…ties

services/map-adapter/google.js goes 507/1114 -> 633/1114 statements,
419/791 -> 492/791 branches, 51/148 -> 78/148 functions on fourteen
tests.

Drawing modes with every shape mapped to its OverlayType, an
unsupported shape, the create handler armed and cleared, the no-manager
return, and disableDrawingMode's synthetic drawstop -- including a
listener that throws not stopping the others.

Popups with string or element content. Context menus registered, read
back and removed, and the DOM renderer driven end to end: the point-less
and item-less rejections, a latlng as numbers or as functions, the menu
placed at the pointer or the origin, items and separators, an item click
handing the action the point and closing the menu, and a second menu
replacing the first.

The whole Events section -- subscription under Google's own names,
payload normalisation across three shapes, draw listeners held on the
adapter, unsubscription releasing the Google listener, and one-shot
listeners for both kinds -- plus distanceBetween, geojson layers, and
the custom tile layer built from its url template.

Statements 5840 -> 5966, branches 3936 -> 4009, functions 1761 -> 1788,
lines 5545 -> 5661.
services/map-adapter/google.js goes 633/1114 -> 709/1114 statements,
492/791 -> 518/791 branches, 78/148 -> 85/148 functions on seven tests.

The toolbar built once into the map's own element and not rebuilt on a
second show, with the config remembered even when it arrives before the
map exists; the three shape buttons rendered by default, narrowed by a
tools config, labelled for screen readers, and starting their drawing
mode on click; edit and delete appearing only when allowed, with the
action section hidden when neither is; a defaultMode starting a shape
straight away; hideDrawControl hiding the toolbar, detaching the action
bar, putting back a draft a delete was holding and switching drawing
off; hiding a control that was never shown; and the top offset tracking
#map-topbar-container.

Statements 5966 -> 6042, branches 4009 -> 4035, functions 1788 -> 1795,
lines 5661 -> 5735.

assert.dom('[data-test-fetch-select]').doesNotExist('a persisted vendor has no setup panel');
const values = findAll('input').map((element) => element.value);
assert.true(values.includes('Acme') && values.includes('ops@acme.test') && values.includes('https://acme.test'));
@codecov

codecov Bot commented Sep 4, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 80.40%. Comparing base (a9131da) to head (35ecbe9).
⚠️ Report is 2 commits behind head on main.

❌ Your project check has failed because the head coverage (80.40%) is below the target coverage (100.00%). You can increase the head coverage or adjust the target coverage.

❗ There is a different number of reports uploaded between BASE (a9131da) and HEAD (35ecbe9). Click for more details.

HEAD has 1 upload less than BASE
Flag BASE (a9131da) HEAD (35ecbe9)
backend 2 1
Additional details and impacted files
@@              Coverage Diff               @@
##                main     #310       +/-   ##
==============================================
- Coverage     100.00%   80.40%   -19.60%     
  Complexity      9899     9899               
==============================================
  Files            526     1085      +559     
  Lines          38163    55770    +17607     
==============================================
+ Hits           38163    44841     +6678     
- Misses             0    10929    +10929     
Flag Coverage Δ
backend 100.00% <ø> (ø)
frontend 37.92% <100.00%> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
addon/components/activity/event-selector.js 100.00% <ø> (ø)
addon/components/activity/form.js 100.00% <ø> (ø)
addon/components/avatar-picker.js 100.00% <ø> (ø)
addon/components/cell/attached-vehicle.js 100.00% <ø> (ø)
addon/components/cell/driver-identity.js 100.00% <ø> (ø)
addon/components/cell/telematic-provider.js 100.00% <ø> (ø)
addon/components/custom-entity/form.js 33.33% <ø> (ø)
addon/components/customer/admin-settings.js 100.00% <ø> (ø)
addon/components/customer/form.js 100.00% <ø> (ø)
addon/components/device/manager.js 100.00% <ø> (ø)
... and 41 more

... and 508 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

services/map-adapter/google.js goes 709/1114 -> 858/1114 statements,
518/791 -> 579/791 branches, 85/148 -> 105/148 functions on nine tests.

A polygon given a tooltip is labelled at the centroid of its ring; the
label overlay draws its container into the map pane at the projected
point, removes it on detach, and survives a draw after removal; it
leaves its anchor to follow the cursor on hover, tracks it on move,
returns on mouseout and ignores an event with no pointer; the three
hover listeners are released when the overlay goes; showing a layer
whose overlay was lost rebuilds the label and re-centres it on the
shape as it is now; a layer whose path cannot be read falls back to the
ring it was built with; and both marker-tooltip attachers.

Worth knowing: the label is deliberately built detached -- addPolygon
never calls setMap, and google-live-map hides the polygon on the next
line -- so showLayer is what attaches it.

Statements 6042 -> 6191, branches 4035 -> 4096, functions 1795 -> 1815,
lines 5735 -> 5880.
services/map-adapter/google.js goes 858/1114 -> 953/1114 statements,
579/791 -> 619/791 branches, 105/148 -> 119/148 functions on eight
tests, driven through the toolbar buttons rather than the private
methods behind them.

Editing: the four refusals, the happy path opening a Save/Cancel bar and
firing draw:edited with its own geometry, and Cancel writing the
captured ring back. Capture and restore for all three shapes -- a
polygon by its path, a rectangle by its bounds, a circle by its centre
and radius.

Deletion: both refusals, a draft held aside and hidden with a
Save/Cancel/Clear All bar, Save firing draw:deleted per held draft and
clearing the selection, Cancel bringing the draft back, and Clear All
sweeping every draft into the pending set.

Statements 6191 -> 6286, branches 4096 -> 4135, functions 1815 -> 1829,
lines 5880 -> 5971.
destroyMap clears every other register -- markers, overlays, routing
controls, popups, context menus, event listeners, drafts -- but never
touched _geojsonLayers. The layers kept a reference to the destroyed
map, and the ids survived into the next one, so a removeGeoJson on the
rebuilt map would detach a layer belonging to the old one.
initializeMap calls destroyMap first, so this accumulated on every
re-initialisation.

The sibling leaflet adapter already clears it. DEFECTS #84.
services/map-adapter/google.js goes 953/1114 -> 992/1117 statements,
619/791 -> 639/791 branches, 119/148 -> 126/148 functions on eight
tests.

A finished polygon becoming a selected draft with a closed ring,
announced to both the create handler and draw:created, with drawing
switched off after; the draft's own click and right-click selection --
which is #bindOverlaySelection, reachable only from here -- and a shape
that cannot listen still being selected; each shape turned into its own
geometry, including a marker with no shape and an unmapped type passed
through as it came; the drawing library failing to load leaving the
adapter usable; destroyMap clearing every register; the advanced-marker
decision across no map id, the placeholder and a real one;
re-initialisation tearing the old map down; and getMarker/getOverlay.

Statements 6286 -> 6327, branches 4135 -> 4160, functions 1829 -> 1838,
lines 5971 -> 6010.
toggleDrawControl treated both '' and 'none' as hidden, and those are
the only two values the toolbar's display ever holds -- '' from
showDrawControl, 'none' from the container's own cssText and from
hideDrawControl. So isHidden was always true and hideDrawControl was
unreachable from the toggle: the button opened the drawing toolbar and
could never close it.

Only 'none' means hidden. DEFECTS #86.
Profiled the residue by kind first, then wrote one test per shape
rather than walking methods. services/map-adapter/google.js goes
992/1117 -> 1033/1117 statements, 639/791 -> 674/781 branches,
126/148 -> 134/148 functions on eight tests.

The coordinate readers and map centring across a usable point, an
unusable one and no event; invalidateSize; applyViewSettings adding,
reusing and detaching the traffic and transit layers and appending
caller styles to the base set; toggleDrawControl; panBy; a labelled
route marker drawn as a badge on the advanced path; and the API loader
both short-circuiting on an API already present and reporting a script
that will not load.

Statements 6327 -> 6368, branches 4160 -> 4195, functions 1838 -> 1846,
lines 6010 -> 6047.
Seven tests for the public editPolygon (the one geofence reaches through
map-manager): its three refusals, a focus fitted before the edit opens,
Save resolving with the ring as it now stands, Cancel restoring the
captured ring, and the settled guard. The classic marker tooltip's
pointer tracking end to end, the context menu's outside-click close, and
a defaults sweep across applyViewSettings, showContextMenu, addPolyline,
fitBounds padding and an unreadable environment config.

Five gaps were unreachable rather than untested and were deleted, not
covered (DEFECTS #87, #88): #ensureTooltipOverlayView, a private method
whose name appears once in the file — its own declaration — along with
the permanently-null _tooltipOverlayView it was the only writer of; and
four defaults their callers always supply, including addRoutingControl's
`?? []` below a guard that has already proved route.waypoints non-empty.

map-adapter/google.js  1033/1117 -> 1065/1105 stmts,
                        674/781  -> 702/772   branches,
                        134/148  -> 143/145   functions
Totals  statements 6368 -> 6400 (34.41%)  branches 4195 -> 4223 (34.96%)
        functions  1846 -> 1855            lines    6047 -> 6076
Tests 1322 -> 1329, passing 1239 -> 1246; failures unchanged at 83.
Seven tests: a marker tooltip carrying markup and a pointerless move
falling back to the origin; a layer stamped with __labelText after it
was drawn getting its label when next shown — the real google-live-map
path for a service area first drawn while it had no name; the three ways
a label cannot be built; a ring of plain numbers and a ring of rings; the
overlay left alone when the projection gives nothing; bounds collected
through a null; and a polygon hovered after its map has gone.

Most of this block's residue was unreachable and was deleted, not
covered (DEFECTS #89): #normalizeDrawEvent, a second private method whose
name appears once in the file, and five `if (!x) return` guards that each
duplicate a test the immediate caller already makes. One fallback was
kept behind an istanbul ignore instead — it is the contract for the
__labelText stamping google-live-map.js does from outside this file.

map-adapter/google.js  1065/1105 -> 1068/1094 stmts,
                        702/772  -> 706/747   branches
Totals  statements 6400 -> 6403 (34.45%)  branches 4223 -> 4227 (35.06%)
        lines      6076 -> 6072            functions 1855 (unchanged)
Line coverage reads 34.44% -> 34.43%: the deletions and the pragma took
covered lines out of the numerator along with the uncovered ones.
Tests 1329 -> 1336, passing 1246 -> 1253; failures unchanged at 83.
Eleven tests close the last four pieces and the defensive arms under
them: rectangle and circle drafts saving as their own geometry through
editPolygon; a draft with no __overlayType announced as a polygon; the
API loader resolving when the injected script calls back; the classic
marker path; an advanced marker moved by assignment and a frame already
dispatched when the cancel lands — driven through a hand-stubbed
requestAnimationFrame so no platform gets a vote on that race; polyline
points given as objects; destroyMap cancelling a running animation; and
the small defensive arms around them.

Nine redundant arms and #drawEvent were deleted rather than covered
(DEFECTS #90) — the third private method in this file whose name appears
exactly once, after #87 and #89.

map-adapter/google.js is now 100% on all four metrics:
  1076/1076 stmts, 718/718 branches, 145/145 fns, 995/995 lines.
It is the addon's largest file; iterations 48-55 took it from 113/1114.

Totals  statements 6403 -> 6411 (34.52%)  branches 4227 -> 4238 (35.24%)
        functions  1855 -> 1857            lines    6072 -> 6080
Files fully covered 309 -> 310.
Tests 1336 -> 1347, passing 1253 -> 1264; failures unchanged at 83.
The workbench had no test file at all. This adds the rendering harness —
the five Orchestrator panels and LeafletMap stubbed as template-only
stand-ins, since ember-leaflet is not installed here and <LeafletMap>
cannot otherwise resolve — and thirteen tests over the lifecycle and
orchestration flow: the five parallel loads and what each asks for, every
load failing, the toolbar panels, both side panels collapsing, a run
proposing a plan and drawing one routing control per vehicle, the
formatters the plan viewer is handed, a run that places nothing, a run
and a commit the server refuses, committing and reloading, and discarding
taking the routes off the map.

The plan-viewer stub calls the formatter callbacks it is handed, exactly
as the real one does, so the wiring is what is under test.

orchestrator-workbench.js  0/428 -> 274/428 stmts,
                          13/261 -> 127/261 branches,
                          17/94  -> 51/94   functions
Totals  statements 6411 -> 6685 (36.00%)  branches 4238 -> 4366 (36.30%)
        functions  1857 -> 1908            lines    6080 -> 6334
Tests 1347 -> 1360, passing 1264 -> 1277; failures unchanged at 83.
…hases

Thirteen more tests: all three selection toggles and clears, with
clearing drivers releasing their vehicles; a selection narrowing the run,
including the driver-tab resolution to a vehicle_id; an order dragged
onto a vehicle joining the plan, one already in it rewritten in place,
and two drops that change nothing; two phases running in sequence with
prior_assignments carried forward and autoCommit landing between them;
the run message dismissed, the import modal reloading the pool, card
fields saving, the left panel collapsing, and both resize handles dragged
through their stops.

The phase-builder and map stubs became real components reading from a
test-bed service: a template-only stand-in has only @Args, so it cannot
hand the component a value the test chose, and onMapLoad needs a real
map instance to call setView on.

orchestrator-workbench.js  274/428 -> 377/428 stmts,
                           127/261 -> 174/261 branches,
                            51/94  ->  84/94  functions
Totals  statements 6685 -> 6788 (36.55%)  branches 4366 -> 4413 (36.70%)
        functions  1908 -> 1941            lines    6334 -> 6430
Tests 1360 -> 1373, passing 1277 -> 1290; failures unchanged at 83.
Builds the yielding LeafletMap stand-in — it yields (hash tile= marker=)
and the marker yields (hash popup= tooltip=), matching ember-leaflet's
shape, with div-icon/icon/point-to-coordinates registered as helpers that
hand back their named args. That unlocked the half of the template that
had never rendered.

Ten tests: order stops pinned as P/D badges with popups and tooltips; a
multi-drop order pinned per waypoint in its own order, with 0,0 dropped;
_placeCoords across the shapes it accepts and three it does not; a driver
pinned with their status; several stops fitted as a box and one zoomed
to; the browser location centring the map, arriving late and being
ignored, and being refused; a plan's A1/A2/B stop labels; and a driver
matched to a group by vehicle_id.

Three selection getters were deleted rather than covered (DEFECTS #91) —
the callers a grep appears to find are the sub-components' own
identically-named getters, and the workbench template never reads them.

orchestrator-workbench.js  377/428 -> 409/425 stmts,
                           174/261 -> 223/261 branches,
                            84/94  ->  91/91  functions (all of them)
Totals  statements 6788 -> 6820 (36.73%)  branches 4413 -> 4462 (37.10%)
        functions  1941 -> 1948            lines    6430 -> 6458
Tests 1373 -> 1383, passing 1290 -> 1300; failures unchanged at 83.
Eight tests, one per shape: a response missing the key it was asked for;
a selected driver with no vehicle; a commit reporting no count; a route
returned with no geometry skipped while the other is still drawn; a plan
naming an unknown vehicle tagged through the whole ?? chain; a waypoint
that is itself the place; a group with no timings getting an empty
summary; a map mounting after the orders and re-centring on them; and the
formatters at their edges.

DEFECTS #92 (NEEDS DECISION): formatIsoTime's try/catch cannot fire —
new Date() does not throw on bad input and toLocaleTimeString returns the
string "Invalid Date" rather than throwing, so the '' the catch exists to
produce is unreachable and an unparseable time window is shown to a
dispatcher as the words "Invalid Date". The dead catch is deleted
(behaviour-neutral); the one-line real fix is left for Ron, since it
changes behaviour on a path no test exercises against real data.

orchestrator-workbench.js  409/425 -> 415/423 stmts,
                           223/261 -> 246/261 branches
Totals  statements 6820 -> 6826 (36.77%)  branches 4462 -> 4484 (37.29%)
        lines      6458 -> 6460            functions 1948 (unchanged)
Tests 1383 -> 1391, passing 1300 -> 1308; failures unchanged at 83.
Seven tests close the last reachable residue: a run reporting no
assignments key; a drop onto a plan of several; the dark tile theme; a
stop on the equator pinned but unable to anchor a route leg; null island
rejected in all four shapes; unnumbered waypoints keeping their order;
and a card-fields read that raises before returning a promise.

Traced-dead and deleted: commitPlan's plan-length guard and
onDropOnVehicle's two ?? operands (every caller has already proved them),
the _resizing field, and _draggingOrder with its three writes — nothing
reads either.

Five @Tracked initialisers are pragma'd with the specific writer that
beats them: with the decorator transform an initialiser evaluates on
first read, so a field written first never runs it.

orchestrator-workbench.js  255/255 branches, 91/91 functions (both done)
                           415/423 -> 409/411 stmts (99.51%)
Two initialisers remain, recorded as DEFECTS #93 (OPEN): the statementMap
is offset from the source, and I could not place them to the standard §4
asks for. Not pragma'd on inference — an untrue reason is worse than an
uncovered line.

Totals  statements 6826 -> 6820 (36.76%)  branches 4484 -> 4493 (37.38%)
        lines      6460 -> 6454            functions 1948 (unchanged)
Tests 1391 -> 1398, passing 1308 -> 1315; failures unchanged at 83.
Closes DEFECTS #93. The two remaining statements could not be placed from
the coverage map — its positions land on the divider comments — so they
were identified by bisection: pragma a candidate, re-run, and watch
whether the uncovered count falls or only the denominator does.

They were not the same kind of thing. availableEngines is genuinely
unreachable: its only reader is the phase builder, rendered only while
that panel is open, so loadEngines assigns it before anything reads it
and the lazy @Tracked initialiser never evaluates. It now carries a
pragma naming that gate.

cardFields was the harness, not the component. The real OrderPool reads
@cardFields; the stand-in for it did not, and Ember argument references
are lazy — the getter runs only when a child consumes the argument. The
stub now renders it as the real component does, and a test asserts the
settings endpoint's fields arrive.

orchestrator-workbench.js is now 100% on all four:
  410/410 stmts, 255/255 branches, 91/91 fns, 375/375 lines.
Iterations 56-61 took it from 0/428.

Files fully covered 310 -> 311.
Totals  statements 6820 -> 6821  branches 4493 -> 4494  lines 6454 -> 6455
Tests 1398, passing 1315; failures unchanged at 83.
Stands up the harness for the 962-line customer order form and covers its
lifecycle: the enabled-order-configs filter picking only what the
customer is entitled to and applying the first to the order, both
settings reads failing and being reported, the payments config, and an
order carrying its own customer versus falling back to the session.

This replaces the generated `it renders` stub, which failed because the
component reads this.order.customer in its constructor while the stub
rendered it with no arguments — so this is the first of the 83 blueprint
scaffolds to be retired, and DEFECTS #4's count is now 82.

Harness notes: ember-file-upload and ember-model-select are not installed
here, so FileDropzone and friends need stand-ins; order.customer is a
polymorphic belongsTo and rejects a plain object; and the component calls
order.set(), so the order must be a real record.

create-order-form.js  5/395 -> 56/395 stmts, 7/197 -> 13/197 branches,
                      6/67  -> 10/67  functions
Totals  statements 6821 -> 6872 (37.04%)  branches 4494 -> 4506 (37.49%)
        functions  1948 -> 1957            lines    6455 -> 6505
Tests 1398 -> 1403, passing 1315 -> 1321, failures 83 -> 82.
A thin iteration: create-order-form.js 56/395 -> 75/395 statements on one
new test. Most of the time went on harness discovery.

What landed: an abilities stub, without which every control on this form
is disabled — `cannot "fleet-ops create order"` gates the entity buttons,
the notes textarea and the dropzone; a DragSortList stand-in that yields
|item index| and reports reorders through @dragEndAction; and a
ModelSelect stand-in reporting the choice from a test-bed service.

What did not: setPayloadPlace cannot be driven without a real Leaflet
map, because previewDraftOrderRoute does control.addTo(this.map) and
leaflet-routing-machine throws from its own onAdd when that is undefined.
Giving the harness an L.map is next iteration's setup and unlocks the
whole route-preview block.

create-order-form.js  56/395 -> 75/395 stmts, 13/197 -> 17/197 branches,
                      10/67  -> 12/67  functions
Totals  statements 6872 -> 6891 (37.14%)  branches 4506 -> 4510
        functions  1957 -> 1959            lines    6505 -> 6524
Tests 1403 -> 1404, passing 1321 -> 1322; failures unchanged at 82.
A sized div inside #ember-testing with window.L.map() on it, passed as
@Map and torn down in afterEach. That was the unlock: choosing a pickup
and a dropoff through the place selects now runs setPayloadPlace,
updatePayloadCoordinates, createPlaceArrayFromPayload,
previewDraftOrderRoute, removeRoutingControlPreview and getRoute, and
attaches a real routing control.

DEFECTS #94 (OPEN), a live bug found while covering:
previewDraftOrderRoute warns when there is nothing to route and then
carries on — no return — so it calls map.flyToBounds([]) and Leaflet
throws reading .lat off an undefined corner. The template's "remove
address" links call setPayloadPlace(prop, null), so a customer clearing
their only address takes the exception. The fix is a one-line return,
left for Ron.

The defect could not be pinned by a test: the throw escapes Ember's error
handling — it neither rejects the click promise nor reaches setupOnerror,
because Leaflet throws from flyToBounds' own animation frame. That path
is left uncovered and the DEFECTS entry carries the testing note.

create-order-form.js  75/395 -> 124/395 stmts, 17/197 -> 38/197 branches,
                      12/67  ->  23/67  functions
Totals  statements 6891 -> 6945 (37.43%)  branches 4510 -> 4530 (37.69%)
        functions  1959 -> 1972            lines    6524 -> 6576
Tests 1404 -> 1405, passing 1322 -> 1323; failures unchanged at 82.
ember-ui's Toggle renders a <span role="checkbox" aria-checked> — neither
a button nor an input, which is why an earlier probe missed it. Three
tests: switching multiple-dropoffs on adds the first waypoint row; a
waypoint takes a place through its own select, a second is added and one
of the two removed; and proof of delivery takes `scan` by default and
gives it up when switched off.

DEFECTS #95 (OPEN), found while reading: clearWaypoints calls
this.previewRoute(false), and previewRoute is not defined anywhere in the
file — one call site, no declaration, no mixin supplying it. Since
isViewingRoutePreview is set by previewDraftOrderRoute, turning
multiple-dropoffs off after entering any waypoint address throws, leaves
the waypoints uncleared and the pickup/dropoff half-applied. The intended
call is almost certainly removeRoutingControlPreview().

Two live defects in this component now (#94, #95) shape how it can be
tested: anything reaching previewDraftOrderRoute with nothing to route
hits #94, so the removal test starts from two waypoints, and the
multi-drop off path cannot be driven until #95 is fixed.

create-order-form.js  124/395 -> 162/395 stmts, 38/197 -> 51/197 branches,
                       23/67  ->  31/67  functions
Totals  statements 6945 -> 6979 (37.62%)  branches 4530 -> 4544 (37.80%)
        functions  1972 -> 1979            lines    6576 -> 6608
Tests 1405 -> 1408, passing 1323 -> 1326; failures unchanged at 82.
Four tests over createOrder: submitting with no route does nothing and
says nothing, since isValid refuses silently and the disabled controls
are the only feedback; a routed order saves once, fires the creating and
created universe events, is tracked, and is handed back through
@onOrderCreated; custom fields that fail validation stop the submission
and list every missing field in one message; and a save the server
refuses is reported with the order kept and no created event.

Harness: the custom-fields stand-in now answers validateRequired() and
saveTo(), the universe and events stubs record what they are told, and
order.save is overridden on the record itself rather than through an
adapter — the component calls it directly.

create-order-form.js  162/395 -> 202/395 stmts, 51/197 -> 68/197 branches,
                       31/67  ->  34/67  functions
Totals  statements 6979 -> 7019 (37.83%)  branches 4544 -> 4561 (37.95%)
        functions  1979 -> 1982            lines    6608 -> 6647
Tests 1408 -> 1412, passing 1326 -> 1330; failures unchanged at 82.
Four tests over getQuotes: a routed order asks service-quotes/preliminary
once there are two coordinates and normalises the response into records;
a response that is not a list is taken as no quotes rather than an error;
a refused request is reported; and no quotes are asked for while a
checkout session is being completed, which also brought
restoreFromServiceQuote into coverage.

DEFECTS #96 (OPEN), found while reading: the quote request body includes
a `service` key that is not a local. There is no declaration anywhere in
the file — the only `service` in scope is line 4's `import { inject as
service }`, so the request sends Ember's inject decorator, JSON drops it,
and the field never reaches the wire. No linter catches it: no-undef is
satisfied by the import and no-unused-vars sees it used. The test pins it
with typeof body.service === 'function'.

That is the third live defect in this component (#94, #95, #96), all
found by reading or by asserting what the code does, all recorded rather
than fixed.

create-order-form.js  202/395 -> 231/395 stmts, 68/197 -> 93/197 branches
Totals  statements 7019 -> 7049 (37.99%)  branches 4561 -> 4586 (38.15%)
        functions  1982 -> 1983            lines    6647 -> 6677
Tests 1412 -> 1416, passing 1330 -> 1334; failures unchanged at 82.
…locked

An honest no-progress iteration on coverage. create-order-form.js is
unchanged at 231/395 statements — the one test that landed asserts real
behaviour (returning from a checkout puts up a dialog that cannot be
dismissed by clicking away) but crosses only lines the previous
iteration already reached. Three of the four tests I set out to write do
not work yet.

isPaymentRequired() needs four conditions, and from the test's side all
four hold — verified by probe. The branch is still not taken. Two
candidates remain and I did not separate them: the addon's ember-get-config
may not be the module instance the test mutates, or selectedServiceQuote
may not survive the quote round-trip. The ledger records both and the
cheapest experiment to tell them apart.

One real cause was found and fixed on the way: getQuotes reads
serviceQuotes.firstObject, so a plain array response leaves
selectedServiceQuote unset silently. Quote fixtures now use A([...]).

Totals  statements 7049 -> 7048  branches 4586 -> 4585  lines 6677 -> 6676
Tests 1416 -> 1417, passing 1334 -> 1335; failures unchanged at 82.
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.

2 participants