Add UTS test specs for LiveObjects path-based API#473
Conversation
f355624 to
2e12074
Compare
f8f1b71 to
08789a6
Compare
08789a6 to
97d02db
Compare
Complete portable test suite covering the LiveObjects path-based API: 21 files across unit tests (pure + mock WebSocket), integration tests (sandbox), and proxy integration tests. Covers PathObject, Instance, BatchContext, LiveCounter/LiveMap CRDTs, ObjectsPool sync state machine, value types, subscriptions, and GC. Includes table-driven validation tests, bytes/binary data coverage, and REST fixture provisioning. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove client-side allocated_port/port_base patterns from all proxy test specs and helper docs. Port is now auto-assigned by the proxy when omitted from create_proxy_session(). Matches uts-proxy v0.2.0. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Align all ~330 LiveObjects UTS test specs with the squashed spec revision a397e34 (LiveObjects path-based API). Key changes: - Add parent_references.md (20 tests): RTLO3f, RTLO4g/4h, RTLO4f, RTO5c10 - Add public_object_message.md (13 tests): PAOM1-3, PAOOP1-3 - Thread ObjectMessage through all CRDT operations and LiveObjectUpdate - Add RTO25 (access preconditions) and RTO26 (write preconditions) - Update subscription model: subscribe returns Subscription object - Add RTO24 (PathObjectSubscriptionRegister) dispatch tests - Add parentReferences maintenance tests to live_map.md (+8 tests) - Add post-sync parentReferences rebuild tests to objects_pool.md (+3) - Rename "consume"/"consumption" to "evaluate"/"evaluation" in value_types - Remove batch.md (Batch API deferred from current spec revision) - Remove subscribeIterator and LiveObject#unsubscribe tests - Update PLAN.md to reflect new file structure and test counts Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
97d02db to
2fba05e
Compare
| ASSERT attach_frames.length == 1 | ||
| ``` | ||
|
|
||
| ## Protocol Message Action Numbers |
| @@ -157,7 +157,6 @@ Proxy tests additionally set up a proxy session per test or group of tests. See | |||
| BEFORE EACH TEST: | |||
| session = create_proxy_session( | |||
| endpoint: "nonprod:sandbox", | |||
There was a problem hiding this comment.
The endpoint client option is not available in ably-java, and I'm not sure whether it's supported in ably-swift ( Open PR for ably-cocoa endpoint clientOption ).
As far as I know, endpoint is only available in ably-js and ably-go ( I contributed to the ably-go PR that added support for it).
To ensure broader SDK compatibility, we should explicitly configure both restHost and realtimeHost instead of relying on endpoint.
There was a problem hiding this comment.
This needs to be updated at all places wherever endpoint is used
There was a problem hiding this comment.
Or we should add endpoint support to both ably-java and ably-cocoa ( PR already open )
There was a problem hiding this comment.
It was decided in the standup to use old restHost and realtimeHost in the SDKs if endpoint clientOption doesn't exist.
This will be added for the given SDK uts-to-tests claude skill.
There was a problem hiding this comment.
(Optional) We can add it as a note somewhere in uts/README.md
| @@ -20,7 +20,6 @@ | |||
| # 1. Create a proxy session with rules | |||
| session = create_proxy_session( | |||
| endpoint: "nonprod:sandbox", | |||
| @@ -0,0 +1,201 @@ | |||
| # Objects Batch Integration Tests | |||
|
|
|||
| Spec points: `RTPO22`, `RTBC12`–`RTBC15` | |||
There was a problem hiding this comment.
Are we planning to add UTS test specs for in progress PR for LiveObjects BatchContext -> https://github.com/ably/specification/pull/471/changes.
Currently, PR for spec points RTBC12–RTBC15 not merged yet : (
There was a problem hiding this comment.
As per standup discussion, we will only respect liveobjects spec landed on the main branch. So, we should get rid of uts/objects/integration/objects_batch_test.md.
There was a problem hiding this comment.
- We also need to update
Spec File Countssection at uts/README.md. - Looks like the
Directory structuresection needs an update as well. We could potentially remove it altogether—I’m not sure it serves much purpose anymore. WDYT?
|
|
||
| ```pseudo | ||
| BEFORE ALL TESTS: | ||
| response = POST https://sandbox-rest.ably.io/apps |
There was a problem hiding this comment.
Blocker — wrong sandbox host.
https://sandbox-rest.ably.io is not the host the UTS suite uses. Every other integration file in the repo (and uts/docs/integration-testing.md) provisions apps against https://sandbox.realtime.ably-nonprod.net. The same string also appears at L16 and L30 in this file.
Convention: uts/docs/integration-testing.md#sandbox-setup — BEFORE ALL TESTS: response = POST https://sandbox.realtime.ably-nonprod.net/apps.
Reasoning: as-is this test would either 404 or hit an unintended environment. The proxy integration file uts/objects/integration/proxy/objects_faults.md already uses the correct host, so the PR is internally inconsistent.
Proposed fix: replace all three occurrences (L16, L22/L23, L30) of https://sandbox-rest.ably.io with https://sandbox.realtime.ably-nonprod.net.
|
|
||
| ```pseudo | ||
| BEFORE ALL TESTS: | ||
| response = POST https://sandbox-rest.ably.io/apps |
There was a problem hiding this comment.
Similar to above comment #473 (comment)
Convention: uts/docs/integration-testing.md#sandbox-setup — BEFORE ALL TESTS: response = POST https://sandbox.realtime.ably-nonprod.net/apps.
Proposed fix: replace all three occurrences (L16, L22/L23, L30) of https://sandbox-rest.ably.io with https://sandbox.realtime.ably-nonprod.net.
|
|
||
| ```pseudo | ||
| BEFORE ALL TESTS: | ||
| response = POST https://sandbox-rest.ably.io/apps |
There was a problem hiding this comment.
Similar to above comment #473 (comment)
Convention: uts/docs/integration-testing.md#sandbox-setup — BEFORE ALL TESTS: response = POST https://sandbox.realtime.ably-nonprod.net/apps.
Proposed fix: replace all three occurrences (L16, L22/L23, L30) of https://sandbox-rest.ably.io with https://sandbox.realtime.ably-nonprod.net.
|
|
||
| ```pseudo | ||
| BEFORE ALL TESTS: | ||
| response = POST https://sandbox-rest.ably.io/apps |
There was a problem hiding this comment.
Similar to above comment #473 (comment)
Convention: uts/docs/integration-testing.md#sandbox-setup — BEFORE ALL TESTS: response = POST https://sandbox.realtime.ably-nonprod.net/apps.
Proposed fix: replace all three occurrences (L16, L22/L23, L30) of https://sandbox-rest.ably.io with https://sandbox.realtime.ably-nonprod.net.
|
|
||
| ### Test Steps | ||
| ```pseudo | ||
| AWAIT root.increment(10) |
There was a problem hiding this comment.
Blocker — root.increment(...) on a PathObject rooted at /.
root is the PathObject returned by channel.object.get() with path: [] (RTO23d). When PathObject#increment is invoked, it resolves the path to the root LiveMap, then per RTPO17e the increment-on-non-counter branch throws an ErrorInfo with code: 92007 before the test reaches any subsequent assertion.
Affected lines in this file (all 10 verified): L258, L304, L348, L376, L408, L1040, L1074, L1098, L1131, L1166. The same bug recurs at five sites in uts/objects/unit/live_counter_api.md — see the comment there.
Reasoning: every one of these tests intends to exercise an operation on the counter stored at root["score"]. The fix is to navigate to that counter first via PathObject#get, then call the mutation on the returned PathObject.
Proposed fix (mechanical):
sed -i '' 's/root\.increment(/root.get("score").increment(/g; \
s/root\.decrement(/root.get("score").decrement(/g' \
uts/objects/unit/realtime_object.md \
uts/objects/unit/live_counter_api.mduts/objects/unit/path_object_mutations.md is untouched — L219, L298 in that file intentionally call root.increment(...) to test the 92007 throw (this is in scope of RTPO17e negative-path coverage, not in scope of this fix).
|
|
||
| ### Test Steps | ||
| ```pseudo | ||
| AWAIT root.increment(25) |
There was a problem hiding this comment.
Blocker — same root.increment(...) / root.decrement(...) bug.
Affected lines in this file: L82, L109, L140, L188, L257. See the matching comment on uts/objects/unit/realtime_object.md L258 for full reasoning and a sed one-liner that fixes both files.
Spec: RTPO17e (PathObject#increment on a non-counter throws 92007).
After the fix the existing assertion at L90 (ASSERT obj_msg.operation.objectId == "counter:score@1000") will actually be checking the right thing — currently the test never gets past root.increment(25).
| ### Test Steps | ||
| ```pseudo | ||
| instance = root.instance() | ||
| AWAIT instance.clear() |
There was a problem hiding this comment.
Blocker — instance.clear() does not exist in the public API.
grep -n "clear" specifications/objects-features.md returns only the clearTimeserial field and the MAP_CLEAR inbound operation (RTLM24). RTLM24 describes how an incoming MAP_CLEAR is applied to a LiveMap — it does not define a clear() method on Instance, PathObject, or LiveMap.
The IDL block at the bottom of objects-features.md confirms: no clear() member on Instance (RTINS), PathObject (RTPO), or LiveMap (RTLM).
Reasoning: as written, this test references an API surface that doesn't exist. Derived SDKs will not be able to translate it.
Proposed fix: delete this section (L428–L451). Optionally insert a placeholder:
## RTLM24 - MAP_CLEAR application
**Status:** No outbound API test — `MAP_CLEAR` is currently inbound-only.
See `live_map.md` for the inbound-application coverage of [RTLM24](https://sdk.ably.com/builds/ably/specification/main/objects-features/#RTLM24).If a public clear() is desired, that's a spec change — open an issue and re-add the test once spec'd.
There was a problem hiding this comment.
Maybe we should be specific about what we really want to clear from LiveMap
| }) | ||
| channel.attach() | ||
| AWAIT_STATE channel.state == DETACHED | ||
| root_path = channel.object.getRoot() |
There was a problem hiding this comment.
Blocker — channel.object.getRoot() does not exist.
RealtimeObject exposes get() (RTO23), not getRoot(). The IDL has no getRoot member.
A secondary problem: even if you swap in get(), the test setup forces the channel to DETACHED at L94 before calling it — and RTO23b / RTO25b require get() to throw 90001 on a DETACHED channel. So the test never reaches the root.subscribe(...) step it's trying to exercise.
Proposed fix: restructure so the PathObject is obtained while the channel is attached, then detach:
{ client, channel, root, mock_ws } = AWAIT setup_synced_channel("test")
# Now detach AFTER root is obtained
mock_ws.send_to_client(ProtocolMessage(
action: DETACHED, channel: "test",
error: { code: 90000, statusCode: 400, message: "Channel detached" }
))
AWAIT_STATE channel.state == DETACHED
### Test Steps
root.subscribe((event) => {}) FAILS WITH error
### Assertions
ASSERT error.code == 90001
ASSERT error.statusCode == 400
This actually tests the RTPO19b precondition (subscribe-on-detached fails).
There was a problem hiding this comment.
We have migrated to channel.object.get() from channel.object.getRoot(), all relevant references should be updated in all test files
| ### Assertions | ||
| ```pseudo | ||
| ASSERT updates.length == 1 | ||
| ASSERT updates[0].objectMessage IS NOT null |
There was a problem hiding this comment.
Blocker — assertions reference fields of the wrong event type.
The file header documents this as RTLO4b* coverage (LiveObject#subscribe), but every test in the file calls instance.subscribe(...) (Instance#subscribe, RTINS16). The two emit different event types:
LiveObject#subscribe(RTLO4b) emits aLiveObjectUpdatewith fieldstombstone,noop,objectMessage,update(RTLO4b4)Instance#subscribe(RTINS16) emits anInstanceSubscriptionEventof shape{ object: Instance, message: PublicAPI::ObjectMessage? }(RTINS16e)
This file asserts updates[0].tombstone == true (L353, L385), updates[0].objectMessage.serial == "99" (L316), etc. — those are LiveObjectUpdate fields, not present on InstanceSubscriptionEvent.
Proposed fix: add a test seam to helpers/standard_test_pool.md that exposes the internal LiveObject so we can subscribe on it directly:
get_live_object(channel, object_id):
# Internal test seam; SDKs expose this via package-private hooks.
RETURN channel._realtimeObject._pool[object_id]
Then replace each instance.subscribe(...) with get_live_object(channel, "counter:score@1000").subscribe(...). The current assertions then check the right type.
Bonus bug at L147–179 (RTLO4b4c1 noop-no-trigger-0): the COUNTER_INC noop reuses the same serial "01" as the prior message, so RTLO4a6 (newness check) suppresses it before RTLO4b4c1 (noop suppression) can fire. Advance the serial to "02" so only the noop path can be the reason the listener wasn't called.
| ### Setup | ||
| ```pseudo | ||
| { client, channel, root, mock_ws } = AWAIT setup_synced_channel("test") | ||
| site_serials_before = root.get("score").instance()._liveObject.siteTimeserials |
There was a problem hiding this comment.
Blocker — reaches into a private/internal field via _liveObject.
root.get("score").instance()._liveObject.siteTimeserials — there is no public path from Instance to LiveObject.siteTimeserials in RTINS3-RTINS16 or RTLO3. The _liveObject field is invented by this test.
Spec being verified is RTO20f ("Apply-on-ACK does not update siteTimeserials"). That requirement is already covered by observable behaviour:
live_counter.md → RTLC7c/local-source-no-serial-update-0at L391 already proves that LOCAL-sourceapplyOperationdoesn't writesiteTimeserials.
Proposed fix (preferred): delete this RTO20f test (L1057–L1081) as redundant. The pure-unit test at live_counter.md L391 covers the same requirement without internal access.
Alternative: verify the requirement through observable behaviour — after a local increment, send an inbound COUNTER_INC echo with a different siteCode + serial. The counter should still apply it (because LOCAL did not claim that site's serial). No private-field access needed.
There was a problem hiding this comment.
I think we can keep this test, provided _liveObject is exposed in test suite in downsteam SDKs
|
|
||
| ```pseudo | ||
| provision_objects_via_rest(api_key, channel_name, operations): | ||
| POST https://sandbox-rest.ably.io/channels/{encode_uri_component(channel_name)}/objects |
There was a problem hiding this comment.
High — provision_objects_via_rest calls an unspecified REST endpoint.
The spec (https://sdk.ably.com/builds/ably/specification/main/objects-features/#) has no /channels/{name}/objects REST surface — grep "REST" specifications/objects-features.md returns nothing. The endpoint exists in ably-js's test apparatus, but it's not part of any SDK spec. PLAN.md L20 acknowledges this.
The only consumer is objects_lifecycle_test.md → RTPO15/rest-provisioned-data-sync-0 (L278).
Reasoning: derived tests in other SDKs cannot translate this — there is no RestClient method that corresponds.
Proposed fix (preferred): rewrite RTPO15/rest-provisioned-data-sync-0 to provision via a side realtime client (same pattern as objects_sync_test.md → RTO5-RTO17/two-clients-sync-0):
provisioner = Realtime(options: { key: api_key })
AWAIT_STATE provisioner.connection.state == CONNECTED
prov_channel = provisioner.channels.get(channel_name, { modes: ["OBJECT_PUBLISH", "OBJECT_SUBSCRIBE"] })
prov_root = AWAIT prov_channel.object.get()
AWAIT prov_root.set("provisioned", "from_rest")
provisioner.close()
Then delete provision_objects_via_rest from this helper file.
Alternative: delete provision_objects_via_rest and the dependent test, add a // TODO: REST provisioning when spec'd note.
There was a problem hiding this comment.
Since there is only a single consumer, does it make sense to add helper in uts/objects/helpers/standard_test_pool.md? Also, since this is related to REST api, are we planning to include it in current UTS test spec
There was a problem hiding this comment.
Rest api spec doesn't block us and uts suggests making simple request call. I believe everything is correct here, no need to change
| ### Setup | ||
| ```pseudo | ||
| pool = ObjectsPool() | ||
| pool.appliedOnAckSerials = {"serial-1", "serial-2"} |
There was a problem hiding this comment.
High — appliedOnAckSerials / bufferedObjectOperations are tested as members of ObjectsPool, but the spec puts them on RealtimeObject.
Spec:
- RTO7a: "The
RealtimeObjectinstance has an internal attributebufferedObjectOperations" - RTO7b: "The
RealtimeObjectinstance has an internal attributeappliedOnAckSerials"
PLAN.md L376 corroborates: "appliedOnAckSerials on RealtimeObject (RTO7b), not on pool".
Yet this file references both as pool members at: L302, L320, L352, L396, L439, L456, L483, L744, L756, L819, L865.
Reasoning: when ported, an SDK following the spec will not have these as ObjectsPool members and the test will not compile or will silently bind to nothing.
Proposed fix: add a RealtimeObject test seam in the affected setups:
pool = ObjectsPool()
realtime_object = RealtimeObject(pool: pool)
Then replace every pool.appliedOnAckSerials with realtime_object.appliedOnAckSerials, and pool.bufferedObjectOperations with realtime_object.bufferedObjectOperations. About 10 lines, mechanical.
If implementations choose to colocate the structures on the pool for locality, document that delegation in PLAN — but tests and PLAN should not contradict each other.
There was a problem hiding this comment.
true, generated js test also use RealtimeObject. On the setup phase it use setupSyncedChannel helper, worth to update tests here
| ```pseudo | ||
| channel_name = "objects-lifecycle-" + random_id() | ||
|
|
||
| client_a = Realtime(options: { key: api_key }) |
There was a problem hiding this comment.
High — direct sandbox tests use a sub-standard ClientOptions block.
uts/docs/integration-testing.md L165–176 prescribes:
client = Realtime(options: ClientOptions(
key: api_key,
endpoint: "nonprod:sandbox", # or restHost/realtimeHost per the open PR thread
useBinaryProtocol: false,
autoConnect: false
))
This file (and objects_sync_test.md, objects_gc_test.md, objects_batch_test.md) use Realtime(options: { key: api_key }) only — missing useBinaryProtocol, autoConnect, and any sandbox host configuration. Verified locations: this file L50–51, L101–102, L148–149, L200–201, L250, L301; plus the three sibling files.
Consequences:
- No host config: client falls back to production endpoint (REC1a default →
realtime.ably.io). The "Sandbox Setup" header in this file claims sandbox but the client never reaches it. useBinaryProtocolmissing: JS defaults tofalse, but Java/.NET/Cocoa default to msgpack. Tests will diverge across SDKs.autoConnectmissing: subsequentclient.connect()is a no-op when autoConnect defaults to true.
Proposed fix (and to avoid the endpoint portability issue raised on uts/docs/integration-testing.md L159):
client = Realtime(options: ClientOptions(
key: api_key,
restHost: "sandbox.realtime.ably-nonprod.net",
realtimeHost: "sandbox.realtime.ably-nonprod.net",
useBinaryProtocol: false,
autoConnect: false
))
client.connect()
AWAIT_STATE client.connection.state == CONNECTED
Or factor into a helpers/standard_test_pool.md helper like connect_sandbox_client(). ~20 call sites across 4 files.
There was a problem hiding this comment.
Yeah, will be helpful to have connect_sandbox_client inside helpers/standard_test_pool.md. It will be reused by all integration/integration-proxy tests.
There was a problem hiding this comment.
We can also have ready to use get_connected_sandbox_client and get_channel_objects helper methods in helpers/standard_test_pool.md which returns connected client along with channel.objects reference for given channelName. This will avoid tons of repetition in integration/integration-proxy tests.
|
|
||
| Spec points: `RTO23`, `RTPO15`, `RTPO17` | ||
|
|
||
| ## Test Type |
There was a problem hiding this comment.
High — data-path integration tests need ## Protocol Variants.
uts/docs/integration-testing.md L262: "Integration tests that exercise the data encoding/decoding path must run with both JSON and msgpack". uts/docs/writing-test-specs.md L17 echoes this.
LiveObjects tests are squarely data-path: every root.set(...), counter.increment(...), and OBJECT_SYNC fixture passes through the SDK's wire-encoding layer. OM4 encoding rules in objects-features.md apply per protocol — e.g. bytes is base64 in JSON, raw binary in msgpack.
Three files need this annotation: this file, objects_sync_test.md, objects_gc_test.md.
(objects_faults.md is proxy and correctly JSON-only; objects_batch_test.md is forward-looking per §0.2 — defer.)
Proposed fix: immediately after ## Test Type, insert:
## Protocol Variants
json, msgpack
Each test in this file runs once per protocol variant. The `PROTOCOL` variable
is set to `"json"` or `"msgpack"` for the current run. Client options should set
`useBinaryProtocol: PROTOCOL == "msgpack"`.Then update the ClientOptions block (after §0.11's fix) to set useBinaryProtocol: PROTOCOL == "msgpack". Also extend the "Annotated specs" list in integration-testing.md L290–306 with a new LiveObjects: heading.
There was a problem hiding this comment.
Yeah, we need to add Protocol Variants to all liveobjects tests involving data intensive operations.
|
|
||
| --- | ||
|
|
||
| ## RTO5c9, RTO20 - appliedOnAckSerials cleared on re-sync |
There was a problem hiding this comment.
High — assertion does not actually prove appliedOnAckSerials was cleared.
The test asserts score == 100 after re-sync. That passes whether the set was cleared or not — the OBJECT_SYNC overwrites score regardless. So the test would silently still pass if RTO5c9 was never implemented.
Reasoning: RTO5c9 requires clearing appliedOnAckSerials at sync completion specifically so that subsequent inbound OBJECTs with previously-deduped serials are no longer treated as echoes.
Proposed fix: after re-sync, replay the previously-applied-on-ACK serial as an inbound OBJECT and verify it now APPLIES rather than dedupes:
AWAIT root.get("score").increment(10) # local apply via ACK, serial "ack-0:0" added
# Trigger re-sync (clears appliedOnAckSerials per RTO5c9)
mock_ws.send_to_client(ProtocolMessage(action: ATTACHED, ... channelSerial: "sync2:cursor", flags: HAS_OBJECTS))
mock_ws.send_to_client(build_object_sync_message("test", "sync2:", STANDARD_POOL_OBJECTS))
# Replay the same serial as an inbound OBJECT — should APPLY (not dedup)
mock_ws.send_to_client(build_object_message("test", [
build_counter_inc("counter:score@1000", 10, "ack-0:0", "test-site")
]))
poll_until(root.get("score").value() == 110, timeout: 5s)
ASSERT root.get("score").value() == 110 # proves dedup didn't fire — set was cleared
If the dedup set was NOT cleared, the inbound echo would dedup and the value would stay at 100.
|
|
||
| ### Setup | ||
| ```pseudo | ||
| enable_fake_timers() |
There was a problem hiding this comment.
High — enable_fake_timers() in an integration test does not affect the sandbox.
Both tests in this file (L50, L103) call enable_fake_timers() then ADVANCE_TIME(86400000 + 300000). Fake timers only manipulate the SDK's view of time. The sandbox server has its own clock, GC scheduler, and grace period — the ADVANCE_TIME call has no effect on it.
Reasoning: RTO10 GC depends on server-side state and the server's objectsGCGracePeriod returned via ConnectionDetails (RTO10b1). An integration test that doesn't actually wait can't observe real GC.
Proposed fix — pick one:
(a) Move to mock-WS unit — convert both tests to use setup_synced_channel with enable_fake_timers() properly. The mock loop respects fake timers; the sandbox doesn't. Move to uts/objects/unit/realtime_object.md (under the existing RTO10 heading) or a new uts/objects/unit/gc_test.md.
(b) Keep as integration but use a short real-time wait — configure the sandbox app with objectsGCGracePeriod: 5000 in BEFORE ALL TESTS setup, then real-wait 5+ seconds. Slower test, but actually exercises end-to-end GC.
Additionally, the comment on L68 — // Remove it (tombstones the entry and the object) — is wrong. root.remove("counter") is a MAP_REMOVE, which tombstones the entry per RTLM8, not the counter object. The counter object lives on. Rename the test to RTLM19/tombstoned-entry-gc-recreate-0 and update the comment to reflect entry-level GC (RTLM19).
|
|
||
| --- | ||
|
|
||
| ## RTO20e - publishAndApply fails when channel enters FAILED during SYNCING |
There was a problem hiding this comment.
High — error.cause is not asserted, even though RTO20e1 requires it.
RTO20e1: "cause set to the RealtimeChannel.errorReason if it is set". This test injects a channel-level ERROR with code: 90000 but the assertion block (around L367) only checks error.code == 92008 — it doesn't verify the cause chain.
Reasoning: SDKs that implement 92008 without populating cause would pass this test, missing a spec-required field.
Proposed fix: after the existing assertions, add:
ASSERT error.cause IS NOT null
ASSERT error.cause.code == 90000 # the injected channel error surfaces as cause
There was a problem hiding this comment.
Optional, but better to expose underlying cause for better debugging.
|
|
||
| --- | ||
|
|
||
| ## RTLCV3c - No validation at creation time |
There was a problem hiding this comment.
I believe this is very js-specific test and it simply can't be implemented in any statically typed language, let's delete it
Summary
uts/objects/Test plan
LiveMap#clear())🤖 Generated with Claude Code