Add react-native support (#63)
Some checks failed
Publish / build (push) Waiting to run
Publish / publish-crate (push) Blocked by required conditions
Publish / publish-npm (push) Blocked by required conditions
Publish / publish-pypi (push) Blocked by required conditions
Check / build (push) Has been cancelled

Reviewed-on: https://home.schmelczer.dev/git/git/andras/reconcile/pulls/63
This commit is contained in:
Andras Schmelczer 2026-05-31 20:28:20 +01:00
commit a8fbac6934

View file

@ -1,4 +1,5 @@
import { reconcile, reconcileWithHistory, diff, undiff } from './index';
import * as webApi from './index';
import * as rnApi from './index.rn';
import { installWasmLeakDetector, checkForWasmLeaks } from './wasm-leak-detector';
import * as fs from 'fs';
import * as path from 'path';
@ -17,7 +18,18 @@ afterEach(() => {
}
});
describe('reconcile', () => {
// `./index` is the web/node build (real WebAssembly); `./index.rn` is the React
// Native build (the wasm2js pure-JS translation). Both are thin backends over the
// same `src/core.ts` wrapper and expose an identical public API, so the behavioural
// suite below runs against both to guarantee they stay in lock-step.
const backends = [
{ name: 'web/node (WebAssembly)', api: webApi },
{ name: 'React Native (wasm2js)', api: rnApi },
];
describe.each(backends)('reconcile [$name]', ({ api }) => {
const { reconcile, reconcileWithHistory, diff, undiff } = api;
it('call reconcile without cursors', () => {
expect(reconcile('Hello', 'Hello world', 'Hi world').text).toEqual('Hi world');
});
@ -60,9 +72,26 @@ describe('reconcile', () => {
expect(result.text).toEqual('Hi world');
expect(result.history.length).toBeGreaterThan(0);
});
it('undiff accepts bigint entries (per the Array<number | bigint | string> type)', () => {
const original = 'Hello world';
const changed = 'Hello cruel world';
// `diff` returns plain numbers; emulate a caller that supplies BigInt, which the
// public signature permits. The wasm2js build rejects raw BigInt, so the shared
// wrapper must normalise it — running this on both backends asserts the contract.
const withBigints = diff(original, changed).map((item) =>
typeof item === 'number' ? BigInt(item) : item
);
expect(withBigints.some((item) => typeof item === 'bigint')).toBe(true);
expect(undiff(original, withBigints)).toEqual(changed);
});
});
describe('test_diff_and_undiff_are_inverse', () => {
describe.each(backends)('diff and undiff are inverse [$name]', ({ api }) => {
const { diff, undiff } = api;
const resourcesPath = path.join(__dirname, '../../tests/resources');
const readFileSlice = (fileName: string, start: number, end: number): string => {
@ -93,3 +122,31 @@ describe('test_diff_and_undiff_are_inverse', () => {
});
});
});
// React-Native-only: Hermes exposes no `WebAssembly` global, which is the whole reason
// the RN entry point links a wasm2js build. Only the wasm2js backend can satisfy this.
describe('React Native (wasm2js) Hermes parity', () => {
const { reconcile, reconcileWithHistory, diff, undiff } = rnApi;
it('runs every operation with no WebAssembly global', () => {
const descriptor = Object.getOwnPropertyDescriptor(globalThis, 'WebAssembly');
delete (globalThis as { WebAssembly?: unknown }).WebAssembly;
try {
expect((globalThis as { WebAssembly?: unknown }).WebAssembly).toBeUndefined();
expect(reconcile('Hello', 'Hello world', 'Hi world').text).toEqual('Hi world');
const changes = diff('Hello world', 'Hello cruel world');
expect(undiff('Hello world', changes)).toEqual('Hello cruel world');
expect(
reconcileWithHistory('Hello', 'Hello world', 'Hi world').history.length
).toBeGreaterThan(0);
} finally {
// Restore the global so the leak check and later suites are unaffected.
if (descriptor) {
Object.defineProperty(globalThis, 'WebAssembly', descriptor);
}
}
});
});