Skip to content

test attempt#583

Open
ValdemarGr wants to merge 4 commits into
zth:masterfrom
ValdemarGr:master
Open

test attempt#583
ValdemarGr wants to merge 4 commits into
zth:masterfrom
ValdemarGr:master

Conversation

@ValdemarGr
Copy link
Copy Markdown
Contributor

No description provided.

drewwestphal added a commit to drewwestphal/rescript-relay-custom-scalar-null-2026 that referenced this pull request Jun 1, 2026
ValdemarGr's stale PR zth#583 added a schema input shape, two custom
scalar modules, and a relay-config registration to reproduce issue
zth#582 (encoding doesn't always apply scalar encoders). This commit
lifts those fixtures in preparation for a full integration test for
zth#582 and broader regression coverage in this PR. ValdemarGr's
ObjectScalar serializers and parsers also log to the console, which
the harness in a later commit uses to assert which converters
actually ran for a given operation.

The Datetime and Number serializers in TestsUtils gain similar
console.log lines (matching the existing pattern in IntString) so a
follow-up zth#407 regression test can verify that a non-array custom
scalar variable still has its serializer run when it follows an
array-backed scalar variable in the same operation.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
zth pushed a commit that referenced this pull request Jun 1, 2026
* Add ObjectScalar custom-scalar fixtures from #583

ValdemarGr's stale PR #583 added a schema input shape, two custom
scalar modules, and a relay-config registration to reproduce issue
#582 (encoding doesn't always apply scalar encoders). This commit
lifts those fixtures in preparation for a full integration test for
#582 and broader regression coverage in this PR. ValdemarGr's
ObjectScalar serializers and parsers also log to the console, which
the harness in a later commit uses to assert which converters
actually ran for a given operation.

The Datetime and Number serializers in TestsUtils gain similar
console.log lines (matching the existing pattern in IntString) so a
follow-up #407 regression test can verify that a non-array custom
scalar variable still has its serializer run when it follows an
array-backed scalar variable in the same operation.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Add integration test for #582 (encoding) — ca followed by c in mutation input

Reproduces the bug ValdemarGr reported in issue #582 using
SerializeMultipleCustomScalars: the input has `os1s: [ObjectScalar1!]!`
followed by `os2: ObjectScalar2`. On master the early-return in the
`ca` branch of traverse (utils.js:109-113) skips the `c` instruction
for `os2`, so ObjectScalar2.serialize is never called. The harness
asserts that both serializers' log lines fire.

The fix for #582 lands later in this PR; on this commit the test
fails for the right reason.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Add integration test for #582 (decoding) — c following ca in response

Read-side analog of the bug ValdemarGr's #582 reports on the
encoding side: a `c` custom-scalar field (createdAt: Datetime!)
follows a `ca` custom-scalar array (intStrings) in a query
selection. On master the early-return in traverse (utils.js:109-113)
leaks the raw wire string through Object.assign untouched, so
createdAt never reaches Datetime.parse. The harness renders
`createdAt->Date.getTime->Float.toString` — Date.getTime on a raw
string throws, so the assertion never resolves on master.

Fails on this commit, passes once the fix lands later in this PR.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Add integration test for #407 — c-array sibling-skip regression

The `c && Array.isArray` branch in traverse (utils.js:134-138) was
added by PR #434 to close issue #407 ("Array scalars are not well
behaved"). It correctly handles single custom scalars whose ReScript
representation is an array — but it terminates with `return` instead
of `continue`, so sibling fields processed after the array-backed
scalar in the same selection set have their converters skipped.

This test runs a query with two variables: `$aaNumber: Number!`
(custom scalar whose underlying type is array<int>) and
`$beforeDate: Datetime`. relay-compiler sorts variables
alphabetically in the generated record, so the `aa` prefix forces
the array-backed scalar to be iterated first. On master only
Number.serialize runs; Datetime.serialize is silently skipped. The
fix later in this PR extends #434's intent so trailing fields are
preserved.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Add integration test for #631 — nullable scalars following a custom-scalar array

A query selects `intStrings` (a `[IntString!]`, `ca`) followed by
nullable plain scalars on the same parent. On master the early-
return in the `ca` branch of traverse (utils.js:109-113) leaves
those siblings copied through Object.assign untouched, so their raw
wire `null` reaches the caller without going through the null
coercion at the top of the per-key loop. ReScript then reads the
leaked `null` as `Some(null)` instead of `None` (pattern matches
take the wrong branch).

The harness uses Type.classify (via Obj.magic + Null.toOption) on
the `private` payload so the rendered DOM literally reads
`private=Some(null)` on master — the smoking-gun assertion. The
fix later in this PR turns the `return` into `continue` and the
DOM reads `private=None`.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Add c/ca behavioral matrix to utils-tests.js

Maps the converter-instruction surface area covered by this PR.
Twenty-five direct calls into `traverser` covering each `c` and
`ca` wire-payload shape in both directions (read with
nullableValue=undefined, write with nullableValue=null), plus
explicit regression cells for the three open/closed issues the fix
addresses:

  - #631 — `ca` followed by null sibling
  - #582 — `ca` followed by another `c`
  - #407 — single `c` whose underlying type is an array

Plus sequencing cells that document order-dependence (two `ca`s in
a row, `ca` followed by a nested object with its own `c`, and a
null sibling BEFORE `ca` as a positive control showing the bug only
fires when `ca` precedes other fields).

Two cells under "ca — custom scalar array (read/write)" explicitly
lock in the CURRENT BEHAVIOR for `[T]!` and `[T]` (nullable-element)
arrays. relay-compiler emits the same `ca` instruction for all four
GraphQL array nullability variants, and the existing fast-path
calls `converter(null)` on null elements. That is almost certainly
a separate latent bug — out of scope for this PR. The cells make it
explicit so a future fix is a deliberate change.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Fix traverse exiting early after custom-scalar conversion

The two custom-scalar branches in `traverse` (utils.js) exit the
per-key loop with `return newObj` instead of moving on with
`continue`:

  - line 112 — `shouldConvertCustomFieldArray && Array.isArray(...)`
    (`ca` instruction, e.g. `[IntString!]`).
  - line 137 — `shouldConvertCustomField && Array.isArray(...)`
    (`c` instruction whose runtime value is an array, e.g. a custom
    scalar like `Number = array<int>`. This branch was added by
    PR #434 to close issue #407.)

In both cases the shallow `Object.assign({}, currentObj)` done by
`getNewObj` has already copied subsequent keys to `newObj`, so
their raw values reach the caller without going through the
null-coercion at the top of the loop (lines 76-79) or the rest of
the per-key logic. The visible symptoms surfaced in three open
issues:

  - #631 (this PR): ReScript reads leaked response-side `null` as
    `Some(null)` instead of `None`; pattern matches take the wrong
    branch.
  - #582 (ValdemarGr): the next variable's `c` instruction never
    runs, so the raw ReScript value ships on the wire instead of
    the serialized form.
  - #407 trailing-field regression: same as above but for a single
    array-backed scalar followed by another converted field —
    silently leaked.

The leading comment on each branch ("Ensures we don't accidentally
move into the array when we're not supposed to") matches the intent
of skipping the remaining branches for the current key, i.e.
`continue`. `return` exits the whole function and was unintended.

Closes #582. Extends #434's fix for #407.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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.

1 participant