Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/native-sourcecode-scripturl.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"vitest-native": patch
---

Provide `SourceCode.getConstants().scriptURL` at the native boundary. RN's `getDevServer` (`Libraries/Core/Devtools/getDevServer.js`) reads `scriptURL` and calls `.match()` on it; under the native engine the value was `undefined`, so `getDevServer` threw and took down any test whose module graph reached it. The boundary now returns a `file://` (bundled) URL for the `SourceCode` native module. It is deliberately not an `http(s)` URL: `getDevServer` only treats `http(s)` script URLs as a live dev server, so a `file://` value keeps `bundleLoadedFromServer` false — tests run as if loaded from a bundle rather than a Metro dev server, which prevents RN internals and third-party SDKs from believing they're connected to a packager and attempting real network I/O against `localhost:8081`. This mirrors the intent of RN's own Jest mock (which keeps that flag off).
17 changes: 17 additions & 0 deletions packages/vitest-native/src/native/boundary.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,23 @@ function deviceConstants(platform, reactNativeVersion) {
doLeftAndRightSwapInRTL: true,
localeIdentifier: "en_US",
},
// RN's getDevServer (Libraries/Core/Devtools/getDevServer.js) reads
// SourceCode.getConstants().scriptURL and calls .match() on it — undefined
// there throws and takes the whole file down. Expo's async-require
// (messageSocket) pulls this in on any Expo-core-importing test. Provide a
// defined string so the lookup resolves instead of crashing.
//
// Deliberately a file:// (bundled/release) URL, NOT http(s): getDevServer only
// treats http(s) scriptURLs as a live server, so a file:// value keeps
// `bundleLoadedFromServer` false — tests run as if loaded from a bundle, not a
// Metro dev server. That stops RN internals (AssetSourceResolver,
// symbolicateStackTrace, DevTools) and third-party SDKs from believing they're
// connected to a packager and attempting real network I/O against localhost:8081.
// Mirrors RN's own jest mock, which keeps this flag off (scriptURL: null there,
// but null would re-introduce the .match crash, so we use a bundled URL).
SourceCode: {
scriptURL: "file:///index.bundle",
},
};
}

Expand Down
27 changes: 27 additions & 0 deletions packages/vitest-native/tests-native/dev-server.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/**
* Proof: RN's `getDevServer` resolves under the native engine because the boundary
* provides `SourceCode.getConstants().scriptURL`. Without it, getDevServer calls
* `.match()` on `undefined` and throws — which under the native engine takes down
* any test whose module graph reaches it (Expo's async-require `messageSocket`
* pulls it in on Expo-core-importing suites). Surfaced by the obytes bake-off,
* where the whole login-form file failed to collect for this reason.
*/
import { describe, it, expect } from "vitest";
// eslint-disable-next-line
import getDevServer from "react-native/Libraries/Core/Devtools/getDevServer";

describe("native engine: getDevServer / SourceCode.scriptURL", () => {
it("resolves instead of crashing on undefined scriptURL", () => {
// A non-string scriptURL would throw inside getDevServer (`.match`) before
// returning; reaching here at all proves the boundary provides a string.
const server = getDevServer();
expect(typeof server.url).toBe("string");
});

it("reports the bundle as NOT loaded from a dev server (no network I/O)", () => {
// The scriptURL is a file:// (bundled) URL, so getDevServer must not treat the
// test as connected to Metro — otherwise RN internals / third-party SDKs would
// attempt real fetches/WebSockets against localhost:8081.
expect(getDevServer().bundleLoadedFromServer).toBe(false);
});
});
Loading