|
| 1 | +<?php |
| 2 | + |
| 3 | +declare(strict_types=1); |
| 4 | + |
| 5 | +use Relaticle\Flowforge\Tests\Fixtures\Task; |
| 6 | +use Relaticle\Flowforge\Tests\Fixtures\TestBoard; |
| 7 | + |
| 8 | +/** |
| 9 | + * Regression test for GitHub issue #88: |
| 10 | + * Large integer IDs (snowflakes) lose precision when passed through @js() in Blade. |
| 11 | + * JavaScript's Number type uses IEEE 754 doubles, which can only safely represent |
| 12 | + * integers up to 2^53 - 1 (9007199254740991). Snowflake IDs exceed this. |
| 13 | + * |
| 14 | + * @see https://github.com/relaticle/flowforge/issues/88 |
| 15 | + */ |
| 16 | +describe('snowflake ID precision', function () { |
| 17 | + test('formatBoardRecord casts record ID to string to prevent JS precision loss', function () { |
| 18 | + $task = Task::factory()->todo()->withPosition('65535.0000000000')->create(); |
| 19 | + |
| 20 | + $board = app(TestBoard::class)->getBoard(); |
| 21 | + $formatted = $board->formatBoardRecord($task); |
| 22 | + |
| 23 | + // The ID must be a string so @js() emits a JSON string ("123") not a number (123) |
| 24 | + // This prevents JavaScript precision loss for large IDs like snowflakes |
| 25 | + expect($formatted['id'])->toBeString(); |
| 26 | + }); |
| 27 | + |
| 28 | + test('card blade renders recordKey as string in wire:click for large IDs', function () { |
| 29 | + $task = Task::factory()->todo()->withPosition('65535.0000000000')->create(); |
| 30 | + |
| 31 | + // Simulate what @js() does: json_encode the record ID |
| 32 | + // If ID is an integer, json_encode produces a number literal which JS truncates |
| 33 | + $idAsInt = (int) $task->id; |
| 34 | + $jsonFromInt = json_encode(['recordKey' => $idAsInt]); |
| 35 | + |
| 36 | + // If ID is a string, json_encode produces a quoted string which JS preserves |
| 37 | + $idAsString = (string) $task->id; |
| 38 | + $jsonFromString = json_encode(['recordKey' => $idAsString]); |
| 39 | + |
| 40 | + // For a snowflake like 420533451316027392: |
| 41 | + // json_encode(int) -> {"recordKey":420533451316027392} <- JS reads as 420533451316027400 (WRONG) |
| 42 | + // json_encode(string) -> {"recordKey":"420533451316027392"} <- JS reads correctly |
| 43 | + $snowflakeId = 420533451316027392; |
| 44 | + $jsonSnowflakeInt = json_encode(['recordKey' => $snowflakeId]); |
| 45 | + $jsonSnowflakeStr = json_encode(['recordKey' => (string) $snowflakeId]); |
| 46 | + |
| 47 | + // The string version wraps in quotes, preserving exact value |
| 48 | + expect($jsonSnowflakeStr)->toContain('"420533451316027392"'); |
| 49 | + |
| 50 | + // The int version does NOT wrap in quotes -- JS will lose precision |
| 51 | + expect($jsonSnowflakeInt)->not->toContain('"420533451316027392"'); |
| 52 | + }); |
| 53 | +}); |
0 commit comments