Skip to content

Support getter/accessor syntax for name, data, and expect - #151

Closed
LeaVerou wants to merge 1 commit into
mainfrom
claude/serene-thompson-ZJmwx
Closed

Support getter/accessor syntax for name, data, and expect#151
LeaVerou wants to merge 1 commit into
mainfrom
claude/serene-thompson-ZJmwx

Conversation

@LeaVerou

Copy link
Copy Markdown
Member

Summary

Refactor property handling in Test.js to 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, and expect: These properties can now be defined as getters that run lazily with this bound to the Test instance, receiving this.args and this.data in context.

  • Function shorthand conversion: When name, data, or expect are 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:

    • name getter failures fall back to stringify(args[0]) for leaf tests
    • data getter failures fall back to an empty object
    • expect getter failures fall back to args[0]
  • Proper descriptor inheritance: Properties are now copied via Object.defineProperties() and Object.getOwnPropertyDescriptor() to preserve accessor descriptors through the inheritance chain. Literal name and data values 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.md and SKILL.md now 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.js and tests/data.js covering inheritance, fallbacks, and precedence rules.

  • TestResult compatibility: Updated TestResult.js to use Object.defineProperty() when setting expect from assertion errors, ensuring compatibility with accessor-based expect.

Implementation Details

  • New defineLazy() helper creates one-shot lazy properties that cache their result.
  • Constants INHERITED_PROPS and ACCESSOR_INHERITED_PROPS clarify which properties inherit and how.
  • Property copying now uses Object.getOwnPropertyDescriptors() to preserve accessor descriptors during inheritance.
  • Inheritance logic distinguishes between regular properties (inherit values) and name/data (inherit accessor descriptors only, not values).
  • All changes are backward compatible — existing code using getData, getName, getExpect, or literal values continues to work unchanged.

https://claude.ai/code/session_01EFM1qJJBFmTsckYiwwhitG

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
@netlify

netlify Bot commented May 24, 2026

Copy link
Copy Markdown

Deploy Preview for h-test ready!

Name Link
🔨 Latest commit 2923c0f
🔍 Latest deploy log https://app.netlify.com/projects/h-test/deploys/6a1323a960162200079e974a
😎 Deploy Preview https://deploy-preview-151--h-test.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@DmitrySharabin

Copy link
Copy Markdown
Member

All changes are backward compatible — existing code using getData, getName, getExpect, or literal values continues to work unchanged.

I wonder if we really have to keep all that legacy baggage and drag it into a new release. 🤔 getData is brand new and not yet released. getExpect helps in edge cases and, I suppose, is not that widely used in the wild (if it is, I might suggest that it’s our libs). The only thing that might be used the most (and even in that case, I’d argue it’s not that wide) is getName. I’d propose dropping all those legacy getters, introducing a breaking change, and releasing the first minor version—0.1.0. Even with the breaking change, the fix is trivial. The IDE will handle it easily. What do you think?

@LeaVerou LeaVerou closed this May 24, 2026
@LeaVerou

Copy link
Copy Markdown
Member Author

All changes are backward compatible — existing code using getData, getName, getExpect, or literal values continues to work unchanged.

I wonder if we really have to keep all that legacy baggage and drag it into a new release. 🤔 getData is brand new and not yet released. getExpect helps in edge cases and, I suppose, is not that widely used in the wild (if it is, I might suggest that it’s our libs). The only thing that might be used the most (and even in that case, I’d argue it’s not that wide) is getName. I’d propose dropping all those legacy getters, introducing a breaking change, and releasing the first minor version—0.1.0. Even with the breaking change, the fix is trivial. The IDE will handle it easily. What do you think?

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.

@DmitrySharabin

Copy link
Copy Markdown
Member

Maybe this one is better? getName and getExpect are preserved (but marked as legacy).

#153

@LeaVerou

Copy link
Copy Markdown
Member Author

Maybe this one is better? getName and getExpect are preserved (but marked as legacy).

#153

That's it, that's why we still need getXXX(). It allows you to provide a generator function AND a different value for the current test. So I think we still need these.

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.

3 participants