Skip to content

Pass the element to afterEach - #1575

Merged
tanem merged 1 commit into
masterfrom
identify-the-failed-element
Aug 4, 2026
Merged

Pass the element to afterEach#1575
tanem merged 1 commit into
masterfrom
identify-the-failed-element

Conversation

@tanem

@tanem tanem commented Aug 4, 2026

Copy link
Copy Markdown
Owner

afterEach was called with the error and, on success, the injected SVG. On failure there is neither, so a caller that passed a collection could not say which of its placeholders failed. The error message is not a way back: several of the library's messages do not name their URL, and a URL is not an element in any case, since two placeholders sharing one data-src is the normal case for a sprite.

element is the element that was passed in, and is present on every call, failures included.

SVGInjector(document.querySelectorAll('[data-src]'), {
  afterEach(error, svg, element) {
    if (error) {
      element.replaceWith(fallbackFor(element))
      return
    }
  },
})

Notes

  • Nothing is threaded through the pipeline. svg-injector.ts already holds the element in a closure at both injectElement call sites, so the argument is supplied where the errback is wrapped. inject-element.ts, load-svg-cached.ts and load-svg-uncached.ts are unchanged, and the load path stays per-URL, which is what it should be given sprites.
  • element is non-optional, because every afterEach path bottoms out in one of those two closures, including the ones that fail before a URL is known.
  • Errback split. One type served both the public option and the internal load callback. Only the public half gains the element, so AfterEach is new and Errback stays as it was, still exported.
  • svg? became svg: SVGSVGElement | undefined, because a required parameter cannot follow an optional one. Not breaking: in a callback position fewer parameters is always assignable, and svg? already had that type. Checked against @tanem/react-svg, whose afterEach takes two parameters and is unaffected.
  • beforeEach deliberately left alone. It has the same shortcoming, but only fires on the success path, where the SVG that replaced the element already identifies it.

Tests

14 new tests in test/aftereach-element.test.ts, written first, enumerating every path the way callback-timing.test.ts does — success, cache hit, data URL, load failure, rejected content type, missing data-src, unparseable data URL, unparseable URL, missing symbol, in-flight guard, null parent, a mixed collection, two placeholders sharing one URL, and the single-element branch. The red run confirmed all 14 failed with element undefined.

examples/error-handling drops the afterAll sweep it needed in order to place its fallbacks, and places each one as its element fails. It also passes the live HTMLCollection directly again, since the snapshot only existed to support the sweep.

npm test green: 402 in the main suite (360 before), 19 in the examples suite, all three browser projects. size-limit 4.3 kB against the 5.5 kB budget, so no budget change.

Not checked by hand in a browser: nothing here is engine-dependent — one closure variable and a type — and the suite exercises all 14 paths in Chromium, Firefox and WebKit. make-ajax-request.ts and load-svg-cached.ts are untouched, so the test/manual/ transport checks did not need rerunning.

🤖 Generated with Claude Code

`afterEach` was called with the error and, on success, the injected SVG.
On failure there is neither, so a caller that passed a collection could
not say which of its placeholders failed. The error message is not a way
back: several of the library's messages do not name their URL, and a URL
is not an element in any case, since two placeholders sharing one
`data-src` is the normal case for a sprite.

`element` is the element that was passed in, and is present on every
call, failures included. It is supplied where the errback is wrapped in
`svg-injector.ts`, which already holds the element in a closure at both
`injectElement` call sites, so the pipeline below it stays per-URL and
unchanged.

`Errback` served both this option and the internal load callback, so the
public half splits off as `AfterEach`. `Errback` keeps its shape and its
export. `svg` is written `SVGSVGElement | undefined` rather than `svg?`
because a required parameter cannot follow an optional one; in a
callback position that is not a breaking change, and existing
two-parameter callbacks still typecheck.

`examples/error-handling` drops the `afterAll` sweep it needed in order
to place its fallbacks, and places each one as its element fails.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@tanem
tanem merged commit b084981 into master Aug 4, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant