BinderTestUtils
Shared harness for the Binder specs. BinderTestUtils.setup boots binders the way production code
boots them: registered on a BinderProvider that is Init/Start'd through a ServiceBag and torn
down through serviceBag:Destroy(). Adornees are parented into a workspace container because
CollectionService.GetInstanceAddedSignal only fires for instances that live in the DataModel.
Tags are global and the test place is shared across a batch run, so every binder gets a distinct
tag from a single module-level counter -- shared across every spec file that requires this module,
so tags never collide between files -- and each controller cleans up after itself via destroy().
Functions
makeTrackingClass
BinderTestUtils.makeTrackingClass() → TrackingClassA minimal bound class that records its instance and whether it was destroyed. It deliberately does NOT retain its constructor varargs: the ServiceBag is injected as a constructor arg, and its object graph contains Quenty Signals whose strict __index makes jest's deep-equality traversal throw. Keeping the class free of them lets toEqual compare instances safely.
awaitUnbound
Returns once inst is no longer bound. CollectionService tag removal is synchronous here, so the
class is usually already gone by the time we check; the guarded wait also covers a deferred case.
noopConstructor
BinderTestUtils.noopConstructor() → tableA no-op constructor that still returns a value, so Binder's generic bound type stays inhabited.
setup
BinderTestUtils.setup() → {...}
Builds the controller the Binder specs share. Register binders with addBinder, boot them all at
once through a ServiceBag with boot, create adornees with newInstance, and tear everything down
with destroy (or just the service bag with destroyServiceBag).
Fields: container.
Builders: addBinder(constructor, ...) -> Binder, newInstance(parent?, className?) -> Instance.
Lifecycle: boot(), destroyServiceBag(), destroy().
Helpers: uniqueTag() -> string.