1dc51e206SEvan Bacon/* eslint-env jest */ 2dc51e206SEvan Baconimport JsonFile from '@expo/json-file'; 3dc51e206SEvan Baconimport execa from 'execa'; 4dc51e206SEvan Baconimport fs from 'fs-extra'; 5dc51e206SEvan Baconimport klawSync from 'klaw-sync'; 6dc51e206SEvan Baconimport path from 'path'; 7dc51e206SEvan Bacon 80a6ddb20SEvan Baconimport { 90a6ddb20SEvan Bacon execute, 100a6ddb20SEvan Bacon projectRoot, 110a6ddb20SEvan Bacon getLoadedModulesAsync, 120a6ddb20SEvan Bacon setupTestProjectAsync, 130a6ddb20SEvan Bacon bin, 140a6ddb20SEvan Bacon ensurePortFreeAsync, 150a6ddb20SEvan Bacon} from './utils'; 16dc51e206SEvan Bacon 17dc51e206SEvan Baconconst originalForceColor = process.env.FORCE_COLOR; 18dc51e206SEvan Baconconst originalCI = process.env.CI; 19dc51e206SEvan Bacon 20dc51e206SEvan BaconbeforeAll(async () => { 21dc51e206SEvan Bacon await fs.mkdir(projectRoot, { recursive: true }); 22dc51e206SEvan Bacon process.env.FORCE_COLOR = '0'; 23dc51e206SEvan Bacon process.env.CI = '1'; 24f479be69SEvan Bacon process.env._EXPO_E2E_USE_PATH_ALIASES = '1'; 259580591fSEvan Bacon delete process.env.EXPO_WEB_OUTPUT_MODE; 26dc51e206SEvan Bacon}); 27dc51e206SEvan Bacon 28dc51e206SEvan BaconafterAll(() => { 29dc51e206SEvan Bacon process.env.FORCE_COLOR = originalForceColor; 30dc51e206SEvan Bacon process.env.CI = originalCI; 31f479be69SEvan Bacon delete process.env._EXPO_E2E_USE_PATH_ALIASES; 32dc51e206SEvan Bacon}); 33dc51e206SEvan Bacon 34dc51e206SEvan Baconit('loads expected modules by default', async () => { 35dc51e206SEvan Bacon const modules = await getLoadedModulesAsync(`require('../../build/src/export').expoExport`); 36dc51e206SEvan Bacon expect(modules).toStrictEqual([ 374067174dSWill Schurman '../node_modules/ansi-styles/index.js', 38dc51e206SEvan Bacon '../node_modules/arg/index.js', 39dc51e206SEvan Bacon '../node_modules/chalk/source/index.js', 40dc51e206SEvan Bacon '../node_modules/chalk/source/util.js', 41dc51e206SEvan Bacon '../node_modules/has-flag/index.js', 42dc51e206SEvan Bacon '../node_modules/supports-color/index.js', 43dc51e206SEvan Bacon '@expo/cli/build/src/export/index.js', 44dc51e206SEvan Bacon '@expo/cli/build/src/log.js', 45dc51e206SEvan Bacon '@expo/cli/build/src/utils/args.js', 46dc51e206SEvan Bacon '@expo/cli/build/src/utils/errors.js', 47dc51e206SEvan Bacon ]); 48dc51e206SEvan Bacon}); 49dc51e206SEvan Bacon 50dc51e206SEvan Baconit('runs `npx expo export --help`', async () => { 51dc51e206SEvan Bacon const results = await execute('export', '--help'); 52dc51e206SEvan Bacon expect(results.stdout).toMatchInlineSnapshot(` 53dc51e206SEvan Bacon " 5483d464dcSEvan Bacon Info 55dc51e206SEvan Bacon Export the static files of the app for hosting it on a web server 56dc51e206SEvan Bacon 57dc51e206SEvan Bacon Usage 5883d464dcSEvan Bacon $ npx expo export <dir> 59dc51e206SEvan Bacon 60dc51e206SEvan Bacon Options 6183d464dcSEvan Bacon <dir> Directory of the Expo project. Default: Current working directory 62dc51e206SEvan Bacon --dev Configure static files for developing locally using a non-https server 6383d464dcSEvan Bacon --output-dir <dir> The directory to export the static files to. Default: dist 64dc51e206SEvan Bacon --max-workers <number> Maximum number of tasks to allow the bundler to spawn 65dc51e206SEvan Bacon --dump-assetmap Dump the asset map for further processing 66dc51e206SEvan Bacon --dump-sourcemap Dump the source map for debugging the JS bundle 67185ef548SEvan Bacon -p, --platform <platform> Options: android, ios, web, all. Default: all 681a3d836eSEvan Bacon --no-minify Prevent minifying source 69dc51e206SEvan Bacon -c, --clear Clear the bundler cache 7083d464dcSEvan Bacon -h, --help Usage info 71dc51e206SEvan Bacon " 72dc51e206SEvan Bacon `); 73dc51e206SEvan Bacon}); 74dc51e206SEvan Bacon 750a6ddb20SEvan Bacondescribe('server', () => { 7647d62600SKudo Chien beforeEach(() => ensurePortFreeAsync(8081)); 77dc51e206SEvan Bacon it( 78dc51e206SEvan Bacon 'runs `npx expo export`', 79dc51e206SEvan Bacon async () => { 80dc51e206SEvan Bacon const projectRoot = await setupTestProjectAsync('basic-export', 'with-assets'); 81dc51e206SEvan Bacon // `npx expo export` 82dc51e206SEvan Bacon await execa('node', [bin, 'export', '--dump-sourcemap', '--dump-assetmap'], { 83dc51e206SEvan Bacon cwd: projectRoot, 84dc51e206SEvan Bacon }); 85dc51e206SEvan Bacon 86dc51e206SEvan Bacon const outputDir = path.join(projectRoot, 'dist'); 87dc51e206SEvan Bacon // List output files with sizes for snapshotting. 88dc51e206SEvan Bacon // This is to make sure that any changes to the output are intentional. 89dc51e206SEvan Bacon // Posix path formatting is used to make paths the same across OSes. 90dc51e206SEvan Bacon const files = klawSync(outputDir) 91dc51e206SEvan Bacon .map((entry) => { 92dc51e206SEvan Bacon if (entry.path.includes('node_modules') || !entry.stats.isFile()) { 93dc51e206SEvan Bacon return null; 94dc51e206SEvan Bacon } 95dc51e206SEvan Bacon return path.posix.relative(outputDir, entry.path); 96dc51e206SEvan Bacon }) 97dc51e206SEvan Bacon .filter(Boolean); 98dc51e206SEvan Bacon 99dc51e206SEvan Bacon const metadata = await JsonFile.readAsync(path.resolve(outputDir, 'metadata.json')); 100dc51e206SEvan Bacon 101dc51e206SEvan Bacon expect(metadata).toEqual({ 102dc51e206SEvan Bacon bundler: 'metro', 103dc51e206SEvan Bacon fileMetadata: { 104dc51e206SEvan Bacon android: { 105dc51e206SEvan Bacon assets: [ 106dc51e206SEvan Bacon { 107dc51e206SEvan Bacon ext: 'png', 108dc51e206SEvan Bacon path: 'assets/fb960eb5e4eb49ec8786c7f6c4a57ce2', 109dc51e206SEvan Bacon }, 110dc51e206SEvan Bacon { 111dc51e206SEvan Bacon ext: 'png', 112dc51e206SEvan Bacon path: 'assets/9ce7db807e4147e00df372d053c154c2', 113dc51e206SEvan Bacon }, 114dc51e206SEvan Bacon { 115dc51e206SEvan Bacon ext: 'ttf', 116dc51e206SEvan Bacon path: 'assets/3858f62230ac3c915f300c664312c63f', 117dc51e206SEvan Bacon }, 118dc51e206SEvan Bacon ], 119*af7ecef3SGabriel Donadel Dall'Agnol bundle: expect.stringMatching(/bundles\/android-.*\.hbc/), 120dc51e206SEvan Bacon }, 121dc51e206SEvan Bacon ios: { 122dc51e206SEvan Bacon assets: [ 123dc51e206SEvan Bacon { 124dc51e206SEvan Bacon ext: 'png', 125dc51e206SEvan Bacon path: 'assets/fb960eb5e4eb49ec8786c7f6c4a57ce2', 126dc51e206SEvan Bacon }, 127dc51e206SEvan Bacon { 128dc51e206SEvan Bacon ext: 'png', 129dc51e206SEvan Bacon path: 'assets/9ce7db807e4147e00df372d053c154c2', 130dc51e206SEvan Bacon }, 131dc51e206SEvan Bacon { 132dc51e206SEvan Bacon ext: 'ttf', 133dc51e206SEvan Bacon path: 'assets/2f334f6c7ca5b2a504bdf8acdee104f3', 134dc51e206SEvan Bacon }, 135dc51e206SEvan Bacon ], 136*af7ecef3SGabriel Donadel Dall'Agnol bundle: expect.stringMatching(/bundles\/ios-.*\.hbc/), 137dc51e206SEvan Bacon }, 138dc51e206SEvan Bacon }, 139dc51e206SEvan Bacon version: 0, 140dc51e206SEvan Bacon }); 141dc51e206SEvan Bacon 142dc51e206SEvan Bacon const assetmap = await JsonFile.readAsync(path.resolve(outputDir, 'assetmap.json')); 143dc51e206SEvan Bacon expect(assetmap).toEqual({ 144dc51e206SEvan Bacon '2f334f6c7ca5b2a504bdf8acdee104f3': { 145dc51e206SEvan Bacon __packager_asset: true, 146dc51e206SEvan Bacon fileHashes: ['2f334f6c7ca5b2a504bdf8acdee104f3'], 147dc51e206SEvan Bacon fileSystemLocation: expect.stringMatching(/\/.*\/basic-export\/assets/), 148dc51e206SEvan Bacon files: [expect.stringMatching(/\/.*\/basic-export\/assets\/font\.ios\.ttf/)], 149dc51e206SEvan Bacon hash: '2f334f6c7ca5b2a504bdf8acdee104f3', 150dc51e206SEvan Bacon httpServerLocation: '/assets/assets', 151dc51e206SEvan Bacon name: 'font', 152dc51e206SEvan Bacon scales: [1], 153dc51e206SEvan Bacon type: 'ttf', 154dc51e206SEvan Bacon }, 155dc51e206SEvan Bacon 156dc51e206SEvan Bacon '3858f62230ac3c915f300c664312c63f': { 157dc51e206SEvan Bacon __packager_asset: true, 158dc51e206SEvan Bacon fileHashes: ['3858f62230ac3c915f300c664312c63f'], 159dc51e206SEvan Bacon fileSystemLocation: expect.stringMatching(/\/.*\/basic-export\/assets/), 160dc51e206SEvan Bacon files: [expect.stringMatching(/\/.*\/basic-export\/assets\/font\.ttf/)], 161dc51e206SEvan Bacon hash: '3858f62230ac3c915f300c664312c63f', 162dc51e206SEvan Bacon httpServerLocation: '/assets/assets', 163dc51e206SEvan Bacon name: 'font', 164dc51e206SEvan Bacon scales: [1], 165dc51e206SEvan Bacon type: 'ttf', 166dc51e206SEvan Bacon }, 167dc51e206SEvan Bacon d48d481475a80809fcf9253a765193d1: { 168dc51e206SEvan Bacon __packager_asset: true, 169dc51e206SEvan Bacon fileHashes: ['fb960eb5e4eb49ec8786c7f6c4a57ce2', '9ce7db807e4147e00df372d053c154c2'], 170dc51e206SEvan Bacon fileSystemLocation: expect.stringMatching(/\/.*\/basic-export\/assets/), 171dc51e206SEvan Bacon files: [ 172dc51e206SEvan Bacon expect.stringMatching(/\/.*\/basic-export\/assets\/icon\.png/), 173dc51e206SEvan Bacon expect.stringMatching(/\/.*\/basic-export\/assets\/icon@2x\.png/), 174dc51e206SEvan Bacon ], 175dc51e206SEvan Bacon hash: 'd48d481475a80809fcf9253a765193d1', 176dc51e206SEvan Bacon height: 1, 177dc51e206SEvan Bacon httpServerLocation: '/assets/assets', 178dc51e206SEvan Bacon name: 'icon', 179dc51e206SEvan Bacon scales: [1, 2], 180dc51e206SEvan Bacon type: 'png', 181dc51e206SEvan Bacon width: 1, 182dc51e206SEvan Bacon }, 183dc51e206SEvan Bacon }); 184dc51e206SEvan Bacon 185dc51e206SEvan Bacon // If this changes then everything else probably changed as well. 186dc51e206SEvan Bacon expect(files).toEqual([ 187dc51e206SEvan Bacon 'assetmap.json', 188dc51e206SEvan Bacon 'assets/2f334f6c7ca5b2a504bdf8acdee104f3', 189dc51e206SEvan Bacon 'assets/3858f62230ac3c915f300c664312c63f', 190dc51e206SEvan Bacon 'assets/9ce7db807e4147e00df372d053c154c2', 1916d6b81f9SEvan Bacon 'assets/assets/font.ttf', 1926d6b81f9SEvan Bacon 'assets/assets/icon.png', 1936d6b81f9SEvan Bacon 'assets/assets/icon@2x.png', 1946d6b81f9SEvan Bacon 195dc51e206SEvan Bacon 'assets/fb960eb5e4eb49ec8786c7f6c4a57ce2', 196*af7ecef3SGabriel Donadel Dall'Agnol expect.stringMatching(/bundles\/android-[\w\d]+\.hbc/), 197dc51e206SEvan Bacon expect.stringMatching(/bundles\/android-[\w\d]+\.map/), 198*af7ecef3SGabriel Donadel Dall'Agnol expect.stringMatching(/bundles\/ios-[\w\d]+\.hbc/), 199dc51e206SEvan Bacon expect.stringMatching(/bundles\/ios-[\w\d]+\.map/), 2006d6b81f9SEvan Bacon expect.stringMatching(/bundles\/web-[\w\d]+\.js/), 2016d6b81f9SEvan Bacon expect.stringMatching(/bundles\/web-[\w\d]+\.map/), 202dc51e206SEvan Bacon 'debug.html', 2036d6b81f9SEvan Bacon 'favicon.ico', 2046d6b81f9SEvan Bacon 'index.html', 205dc51e206SEvan Bacon 'metadata.json', 206dc51e206SEvan Bacon ]); 207dc51e206SEvan Bacon }, 208dc51e206SEvan Bacon // Could take 45s depending on how fast npm installs 209dc51e206SEvan Bacon 120 * 1000 210dc51e206SEvan Bacon ); 2110a6ddb20SEvan Bacon}); 212