Support getter/accessor syntax for name, data, and expect - #151
Conversation
Test definitions can now use native getters (and function shorthand) for `name`, `data`, and `expect`. The getter is preserved on the Test instance, runs once when the property is first accessed, and the result is cached. Accessor descriptors are inherited from parent to child (so a parent's `get name ()` is reused by each child with its own `this`). The legacy `getName` / `getData` / `getExpect` methods continue to work unchanged. Accessor wins if both are defined on the same property. https://claude.ai/code/session_01EFM1qJJBFmTsckYiwwhitG
✅ Deploy Preview for h-test ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
I wonder if we really have to keep all that legacy baggage and drag it into a new release. 🤔 |
I'm not convinced all their use cases are covered by getters. If so, we can definitely remove them, but need to make sure first. Also I closed this PR because I didn't like Claude's implementation. |
|
Maybe this one is better? |
That's it, that's why we still need |
Summary
Refactor property handling in
Test.jsto support ES getter syntax (get name () { ... }) as a modern alternative to legacy function shorthands and eager generator functions. This enables lazy evaluation, better IDE support, and more idiomatic JavaScript while maintaining full backward compatibility.Key Changes
Getter support for
name,data, andexpect: These properties can now be defined as getters that run lazily withthisbound to the Test instance, receivingthis.argsandthis.datain context.Function shorthand conversion: When
name,data, orexpectare defined as functions (e.g.,name () { ... }), they are automatically converted to getters internally.Lazy evaluation with caching: User-defined getters are wrapped with
defineLazy()— the getter runs once per instance, then the result replaces itself as a writable data property. This prevents repeated computation while allowing override.Safe fallbacks:
namegetter failures fall back tostringify(args[0])for leaf testsdatagetter failures fall back to an empty objectexpectgetter failures fall back toargs[0]Proper descriptor inheritance: Properties are now copied via
Object.defineProperties()andObject.getOwnPropertyDescriptor()to preserve accessor descriptors through the inheritance chain. Literalnameanddatavalues are not inherited, but their accessor descriptors are (allowing children to inherit a parent's generator and invoke it with their own context).Accessor wins over legacy functions: When both a getter and legacy function (e.g.,
getName,getData,getExpect) are defined, the getter takes precedence.Updated documentation:
docs/define/README.mdandSKILL.mdnow document the new getter syntax and clarify that legacy functions are now optional and eager (evaluated at construction time).Test coverage: Added comprehensive test suites in
tests/getters.jsandtests/data.jscovering inheritance, fallbacks, and precedence rules.TestResult compatibility: Updated
TestResult.jsto useObject.defineProperty()when settingexpectfrom assertion errors, ensuring compatibility with accessor-basedexpect.Implementation Details
defineLazy()helper creates one-shot lazy properties that cache their result.INHERITED_PROPSandACCESSOR_INHERITED_PROPSclarify which properties inherit and how.Object.getOwnPropertyDescriptors()to preserve accessor descriptors during inheritance.name/data(inherit accessor descriptors only, not values).getData,getName,getExpect, or literal values continues to work unchanged.https://claude.ai/code/session_01EFM1qJJBFmTsckYiwwhitG