Gleam integration tests with large API IDs: gleeunit suite behaves differently across Erlang and JavaScript targets
0 reputation · 01 Jun 2024, 19:46 UTC
0 reputation · 01 Jun 2024, 19:46 UTC
I'm designing an integration test suite for a Gleam service that talks to an external API. Following the documented gleam test workflow with gleeunit, the plan is to inject configuration (base URL, token) via environment variables and pass a fake HTTP client into the application code so tests return canned gleam/http responses instead of hitting production. No real credentials would ever be needed in CI.
The unresolved concern is test fidelity across compilation targets. The same suite is intended to run on both the Erlang target and the JavaScript target, and the upstream API returns very large integer identifiers. My understanding is that Gleam's Int is arbitrary precision on Erlang but constrained by JavaScript's safe-integer range, which suggests decoding or comparing those IDs could behave differently per target even though the test code is identical.
Assume a recent Gleam toolchain with current gleeunit; exact versions to be confirmed before implementation.
Is target-dependent integer representation the right explanation for potential cross-target divergence in such a suite, and how do teams normally structure ID handling so one test codebase stays valid on both targets? Is there a documented convention for gating or marking target-specific tests in gleeunit, given it has no built-in tagging mechanism?
30275 reputation · 01 Jun 2024, 20:47 UTC
Yes, the differing representation of Int is the most likely cause of the divergence you’re seeing. On the Erlang target Int is an arbitrary‑precision integer, but on the JavaScript target it becomes a Number, which can only represent integers safely up to 2^53‑1 (~9 × 10¹⁵). If your API returns IDs larger than that, decoding them into an Int on the JS target will silently lose precision, causing equality checks in your tests to fail while the Erlang run passes.
String (or a thin wrapper type) in the public API and in the test suite. Strings are safe on both targets and preserve the exact value.
2^53‑1 before converting to Int on the JS target, or use gleam/js’s js.BigInt for arithmetic.
pub type Id = String and use it throughout your code. This keeps the semantics clear and avoids accidental integer overflows.
Gleeunit has no built‑in tagging. Common patterns are:
tests/js/ and Erlang‑only tests in tests/erlang/. Run gleam test --target javascript tests/js/ or the Erlang equivalent.
--define IS_JS=true when building for JS. In your test code write
let IS_JS = @define IS_JS
if IS_JS {
// JS‑specific assertions
} else {
// Erlang‑specific assertions
}
process.env.GLEAM_TARGET (available in JS) or a custom env var in Erlang. Conditionally skip or adapt tests.
2^53‑1 into a field of type Int. Assert that the value equals the literal.
gleam test --target erlang – it should pass.
gleam test --target javascript – it should fail, showing the loss of precision.
Int field with String (or a wrapper). Repeat the runs; both should now pass.
--define IS_JS=true and a conditional test that only triggers on the JS target. Verify that the test is excluded when the flag is absent.
To tailor the recommendation further, could you confirm the exact size of the IDs you receive from the external API? Knowing whether they exceed 2^53‑1 will determine if you need the wrapper approach or if a simple numeric check suffices.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.