1const spawnAsync = require('@expo/spawn-async'); 2const fs = require('fs/promises'); 3const glob = require('glob'); 4const path = require('path'); 5 6const projectRoot = path.resolve(__dirname, '..'); 7const notifyStrings = [ 8 'test-update-1', 9 'test-update-2', 10 'test-update-3', 11 'test-update-invalid-hash', 12 'test-update-older', 13 'test-assets-1', 14]; 15 16createTestUpdateBundles(projectRoot, notifyStrings); 17 18/////////////////////////////////////////////////////////////// 19 20/** 21 * Originally, the E2E tests would directly modify the text of the minified JS in update bundles 22 * when testing to make sure that the correct update was applied. 23 * 24 * Since Hermes bundles are bytecode and not readable JS, we instead pre-generate Hermes bundles 25 * corresponding to each test case, and save them in the `test-update-bundles` directory in the test app. 26 */ 27async function createTestUpdateBundles(projectRoot, notifyStrings) { 28 // export update for test server to host 29 await createUpdateBundleAsync(projectRoot); 30 31 // move exported update to "updates" directory for EAS testing 32 await fs.rm(path.join(projectRoot, 'updates'), { recursive: true, force: true }); 33 await fs.rename(path.join(projectRoot, 'dist'), path.join(projectRoot, 'updates')); 34 35 const testUpdateBundlesPath = path.join(projectRoot, 'test-update-bundles'); 36 await fs.rm(testUpdateBundlesPath, { recursive: true, force: true }); 37 await fs.mkdir(testUpdateBundlesPath); 38 const appJsPath = path.join(projectRoot, 'App.tsx'); 39 const originalAppJs = await fs.readFile(appJsPath, 'utf-8'); 40 const testUpdateJson = {}; 41 for (const notifyString of ['test', ...notifyStrings]) { 42 console.log(`Creating bundle for string '${notifyString}'...`); 43 const modifiedAppJs = originalAppJs.replace( 44 /testID="updateString" value="test"/g, 45 `testID="updateString" value="${notifyString}"` 46 ); 47 await fs.rm(appJsPath); 48 await fs.writeFile(appJsPath, modifiedAppJs, 'utf-8'); 49 await createUpdateBundleAsync(projectRoot); 50 const manifestJsonString = await fs.readFile( 51 path.join(projectRoot, 'dist', 'metadata.json'), 52 'utf-8' 53 ); 54 const manifest = JSON.parse(manifestJsonString); 55 const iosBundlePath = path.join(projectRoot, 'dist', manifest.fileMetadata.ios.bundle); 56 const androidBundlePath = path.join(projectRoot, 'dist', manifest.fileMetadata.android.bundle); 57 const iosBundleDestPath = path.join(testUpdateBundlesPath, path.basename(iosBundlePath)); 58 const androidBundleDestPath = path.join( 59 testUpdateBundlesPath, 60 path.basename(androidBundlePath) 61 ); 62 await fs.copyFile(iosBundlePath, iosBundleDestPath); 63 await fs.copyFile(androidBundlePath, androidBundleDestPath); 64 testUpdateJson[notifyString] = { 65 ios: path.basename(iosBundlePath), 66 android: path.basename(androidBundlePath), 67 }; 68 } 69 const testUpdateBundlesJsonPath = path.join(testUpdateBundlesPath, 'test-updates.json'); 70 await fs.writeFile(testUpdateBundlesJsonPath, JSON.stringify(testUpdateJson, null, 2), 'utf-8'); 71 await fs.rm(appJsPath); 72 await fs.writeFile(appJsPath, originalAppJs, 'utf-8'); 73 console.log('Done creating test bundles'); 74} 75 76async function createUpdateBundleAsync(projectRoot, localCliBin) { 77 await fs.rm(path.join(projectRoot, 'dist'), { force: true, recursive: true }); 78 await spawnAsync('npx', ['expo', 'export'], { 79 cwd: projectRoot, 80 stdio: 'inherit', 81 }); 82} 83