Open History to see the last commit
1import * as NodeFS from "node:fs";
2import * as NodeHttp from "node:http";
3import type * as NodeNet from "node:net";
4import * as NodeOS from "node:os";
5import * as NodePath from "node:path";
6import { afterEach, describe, expect, it } from "vite-plus/test";
7
8import {
9 buildDsymUpload,
10 buildSourceMapUpload,
11 otaSourceMapUploads,
12 uploadSourceMap,
13} from "./sourcemap-upload.mts";
14
15const directories: Array<string> = [];
16const tempDir = () => {
17 const dir = NodeFS.mkdtempSync(NodePath.join(NodeOS.tmpdir(), "sourcemap-upload-"));
18 directories.push(dir);
19 return dir;
20};
21const writeFile = (path: string, contents: string) => {
22 NodeFS.mkdirSync(NodePath.dirname(path), { recursive: true });
23 NodeFS.writeFileSync(path, contents);
24};
25
26afterEach(() => {
27 for (const dir of directories.splice(0)) NodeFS.rmSync(dir, { recursive: true, force: true });
28});
29
30describe("uploadSourceMap", () => {
31 it("PUTs each published update's map, only what the relay reads, under its update id", async () => {
32 const dist = tempDir();
33 writeFile(
34 NodePath.join(dist, "metadata.json"),
35 JSON.stringify({
36 fileMetadata: {
37 android: { bundle: "_expo/static/js/android/index-abc.hbc" },
38 ios: { bundle: "_expo/static/js/ios/index-def.hbc" },
39 },
40 }),
41 );
42 writeFile(
43 NodePath.join(dist, "eas-update-metadata.json"),
44 JSON.stringify({
45 updates: [
46 { id: "update-android", platform: "android" },
47 { id: "update-ios", platform: "ios" },
48 { id: "update-web", platform: "web" },
49 ],
50 }),
51 );
52 for (const platform of ["android", "ios"]) {
53 writeFile(
54 NodePath.join(
55 dist,
56 `_expo/static/js/${platform}/index-${platform === "ios" ? "def" : "abc"}.hbc.map`,
57 ),
58 JSON.stringify({
59 version: 3,
60 sources: [`${platform}.ts`],
61 sourcesContent: ["secret"],
62 names: ["render"],
63 x_facebook_sources: [[null]],
64 mappings: "",
65 }),
66 );
67 }
68
69 const requests: Array<{ method?: string; url?: string; auth?: string; body: string }> = [];
70 const server = NodeHttp.createServer((request, response) => {
71 let body = "";
72 request.on("data", (chunk) => (body += chunk));
73 request.on("end", () => {
74 requests.push({
75 method: request.method,
76 url: request.url,
77 auth: request.headers.authorization,
78 body,
79 });
80 response.end();
81 });
82 });
83 await new Promise<void>((resolve) => server.listen(0, "127.0.0.1", resolve));
84 try {
85 const address = server.address() as NodeNet.AddressInfo;
86 const credentials = {
87 endpoint: `http://127.0.0.1:${address.port}`,
88 bucketName: "maps",
89 accessKeyId: "key-id",
90 secretAccessKey: "secret-key",
91 };
92 for (const upload of otaSourceMapUploads(dist)) {
93 await uploadSourceMap(credentials, upload);
94 }
95 expect(requests).toEqual(
96 ["android", "ios"].map((platform) => ({
97 method: "PUT",
98 url: `/maps/${platform}/ota/update-${platform}.map`,
99 auth: expect.stringMatching(/^AWS4-HMAC-SHA256 Credential=key-id\/\d{8}\/auto\/s3\//),
100 body: JSON.stringify({ version: 3, sources: [`${platform}.ts`], mappings: "" }),
101 })),
102 );
103 } finally {
104 server.close();
105 }
106 });
107});
108
109describe("buildSourceMapUpload", () => {
110 it("names the EAS build's embedded bundle map under its build id", () => {
111 const project = tempDir();
112 const androidMap = NodePath.join(
113 project,
114 "android/app/build/generated/sourcemaps/react/release/index.android.bundle.map",
115 );
116 writeFile(androidMap, "{}");
117 expect(
118 buildSourceMapUpload({ EAS_BUILD_PLATFORM: "android", EAS_BUILD_ID: "build-1" }, project),
119 ).toEqual({ key: "android/build/build-1.map", path: androidMap });
120 expect(
121 buildSourceMapUpload(
122 { EAS_BUILD_PLATFORM: "ios", EAS_BUILD_ID: "build-2", SOURCEMAP_FILE: "/tmp/main.map" },
123 project,
124 ),
125 ).toEqual({ key: "ios/build/build-2.map", path: "/tmp/main.map" });
126 });
127
128 it("names an iOS build's dSYMs under its build id", () => {
129 const project = tempDir();
130 const dsym = NodePath.join(project, "ios/build/T3Code.app.dSYM.zip");
131 writeFile(dsym, "zip");
132 expect(
133 buildDsymUpload({ EAS_BUILD_PLATFORM: "ios", EAS_BUILD_ID: "build-3" }, project),
134 ).toEqual({ key: "ios/dsym/build-3.zip", path: dsym });
135 });
136});