1b6b91c50SEvan Bacon/* eslint-env jest */
2b6b91c50SEvan Baconimport execa from 'execa';
3b6b91c50SEvan Baconimport fs from 'fs-extra';
4b6b91c50SEvan Baconimport klawSync from 'klaw-sync';
5b6b91c50SEvan Baconimport path from 'path';
6b6b91c50SEvan Bacon
7fd2402c1SEvan Baconimport { execute, projectRoot, getLoadedModulesAsync, bin } from './utils';
8b6b91c50SEvan Bacon
9b6b91c50SEvan Baconconst originalForceColor = process.env.FORCE_COLOR;
10b6b91c50SEvan Baconconst originalCI = process.env.CI;
11b6b91c50SEvan Bacon
12b6b91c50SEvan BaconbeforeAll(async () => {
13b6b91c50SEvan Bacon  await fs.mkdir(projectRoot, { recursive: true });
14b6b91c50SEvan Bacon  process.env.FORCE_COLOR = '0';
15b6b91c50SEvan Bacon  process.env.CI = '1';
16f479be69SEvan Bacon  process.env._EXPO_E2E_USE_PATH_ALIASES = '1';
17b6b91c50SEvan Bacon});
18b6b91c50SEvan Bacon
19b6b91c50SEvan BaconafterAll(() => {
20b6b91c50SEvan Bacon  process.env.FORCE_COLOR = originalForceColor;
21b6b91c50SEvan Bacon  process.env.CI = originalCI;
22f479be69SEvan Bacon  delete process.env._EXPO_E2E_USE_PATH_ALIASES;
23b6b91c50SEvan Bacon});
24b6b91c50SEvan Bacon
25b6b91c50SEvan Baconit('loads expected modules by default', async () => {
26b6b91c50SEvan Bacon  const modules = await getLoadedModulesAsync(
27b6b91c50SEvan Bacon    `require('../../build/src/export/embed').expoExportEmbed`
28b6b91c50SEvan Bacon  );
29b6b91c50SEvan Bacon  expect(modules).toStrictEqual([
304067174dSWill Schurman    '../node_modules/ansi-styles/index.js',
31b6b91c50SEvan Bacon    '../node_modules/arg/index.js',
32b6b91c50SEvan Bacon    '../node_modules/chalk/source/index.js',
33b6b91c50SEvan Bacon    '../node_modules/chalk/source/util.js',
34b6b91c50SEvan Bacon    '../node_modules/has-flag/index.js',
35b6b91c50SEvan Bacon    '../node_modules/supports-color/index.js',
36b6b91c50SEvan Bacon    '@expo/cli/build/src/export/embed/index.js',
37b6b91c50SEvan Bacon    '@expo/cli/build/src/log.js',
38b6b91c50SEvan Bacon    '@expo/cli/build/src/utils/args.js',
39b6b91c50SEvan Bacon  ]);
40b6b91c50SEvan Bacon});
41b6b91c50SEvan Bacon
42b6b91c50SEvan Baconit('runs `npx expo export:embed --help`', async () => {
43b6b91c50SEvan Bacon  const results = await execute('export:embed', '--help');
44b6b91c50SEvan Bacon  expect(results.stdout).toMatchInlineSnapshot(`
45b6b91c50SEvan Bacon    "
46b6b91c50SEvan Bacon      Info
47b6b91c50SEvan Bacon        (Internal) Export the JavaScript bundle during a native build script for embedding in a native binary
48b6b91c50SEvan Bacon
49b6b91c50SEvan Bacon      Usage
50b6b91c50SEvan Bacon        $ npx expo export:embed <dir>
51b6b91c50SEvan Bacon
52b6b91c50SEvan Bacon      Options
53b6b91c50SEvan Bacon        <dir>                                  Directory of the Expo project. Default: Current working directory
54b6b91c50SEvan Bacon        --entry-file <path>                    Path to the root JS file, either absolute or relative to JS root
55b6b91c50SEvan Bacon        --platform <string>                    Either "ios" or "android" (default: "ios")
56b6b91c50SEvan Bacon        --transformer <string>                 Specify a custom transformer to be used
57b6b91c50SEvan Bacon        --dev [boolean]                        If false, warnings are disabled and the bundle is minified (default: true)
58b6b91c50SEvan Bacon        --minify [boolean]                     Allows overriding whether bundle is minified. This defaults to false if dev is true, and true if dev is false. Disabling minification can be useful for speeding up production builds for testing purposes.
59b6b91c50SEvan Bacon        --bundle-output <string>               File name where to store the resulting bundle, ex. /tmp/groups.bundle
60b6b91c50SEvan Bacon        --bundle-encoding <string>             Encoding the bundle should be written in (https://nodejs.org/api/buffer.html#buffer_buffer). (default: "utf8")
61b6b91c50SEvan Bacon        --max-workers <number>                 Specifies the maximum number of workers the worker-pool will spawn for transforming files. This defaults to the number of the cores available on your machine.
62b6b91c50SEvan Bacon        --sourcemap-output <string>            File name where to store the sourcemap file for resulting bundle, ex. /tmp/groups.map
63b6b91c50SEvan Bacon        --sourcemap-sources-root <string>      Path to make sourcemap's sources entries relative to, ex. /root/dir
64b6b91c50SEvan Bacon        --sourcemap-use-absolute-path          Report SourceMapURL using its full path
65b6b91c50SEvan Bacon        --assets-dest <string>                 Directory name where to store assets referenced in the bundle
66b6b91c50SEvan Bacon        --asset-catalog-dest <string>          Directory to create an iOS Asset Catalog for images
67b6b91c50SEvan Bacon        --unstable-transform-profile <string>  Experimental, transform JS for a specific JS engine. Currently supported: hermes, hermes-canary, default
68b6b91c50SEvan Bacon        --reset-cache                          Removes cached files
69b6b91c50SEvan Bacon        -v, --verbose                          Enables debug logging
70b6b91c50SEvan Bacon        --config <string>                      Path to the CLI configuration file
71b6b91c50SEvan Bacon        --read-global-cache                    Try to fetch transformed JS code from the global cache, if configured.
72b6b91c50SEvan Bacon        -h, --help                             Usage info
73b6b91c50SEvan Bacon    "
74b6b91c50SEvan Bacon  `);
75b6b91c50SEvan Bacon});
76b6b91c50SEvan Bacon
77fd2402c1SEvan Baconfunction ensureTesterReady(fixtureName: string): string {
78fd2402c1SEvan Bacon  const root = path.join(__dirname, '../../../../../apps/router-e2e');
79fd2402c1SEvan Bacon  // Clear metro cache for the env var to be updated
80fd2402c1SEvan Bacon  // await fs.remove(path.join(root, "node_modules/.cache/metro"));
81fd2402c1SEvan Bacon
82fd2402c1SEvan Bacon  // @ts-ignore
83fd2402c1SEvan Bacon  process.env.E2E_ROUTER_SRC = fixtureName;
84fd2402c1SEvan Bacon
85fd2402c1SEvan Bacon  return root;
86fd2402c1SEvan Bacon}
87fd2402c1SEvan Bacon
88b6b91c50SEvan Baconit(
89b6b91c50SEvan Bacon  'runs `npx expo export:embed`',
90b6b91c50SEvan Bacon  async () => {
91fd2402c1SEvan Bacon    const projectRoot = ensureTesterReady('static-rendering');
92fd2402c1SEvan Bacon    const output = 'dist-export-embed';
93fd2402c1SEvan Bacon    await fs.remove(path.join(projectRoot, output));
94fd2402c1SEvan Bacon    await fs.ensureDir(path.join(projectRoot, output));
95fd2402c1SEvan Bacon
96b6b91c50SEvan Bacon    await execa(
97b6b91c50SEvan Bacon      'node',
98b6b91c50SEvan Bacon      [
99b6b91c50SEvan Bacon        bin,
100b6b91c50SEvan Bacon        'export:embed',
101b6b91c50SEvan Bacon        '--entry-file',
102fd2402c1SEvan Bacon        path.join(projectRoot, './index.js'),
103b6b91c50SEvan Bacon        '--bundle-output',
104fd2402c1SEvan Bacon        `./${output}/output.js`,
105b6b91c50SEvan Bacon        '--assets-dest',
106fd2402c1SEvan Bacon        output,
107b6b91c50SEvan Bacon        '--platform',
108b6b91c50SEvan Bacon        'ios',
109fd2402c1SEvan Bacon        '--dev',
110fd2402c1SEvan Bacon        'false',
111b6b91c50SEvan Bacon      ],
112b6b91c50SEvan Bacon      {
113b6b91c50SEvan Bacon        cwd: projectRoot,
114fd2402c1SEvan Bacon        env: {
115fd2402c1SEvan Bacon          NODE_ENV: 'production',
116*46f023faSEvan Bacon          EXPO_USE_STATIC: 'static',
117fd2402c1SEvan Bacon          E2E_ROUTER_SRC: 'static-rendering',
118fd2402c1SEvan Bacon          E2E_ROUTER_ASYNC: 'development',
119fd2402c1SEvan Bacon        },
120b6b91c50SEvan Bacon      }
121b6b91c50SEvan Bacon    );
122b6b91c50SEvan Bacon
123fd2402c1SEvan Bacon    const outputDir = path.join(projectRoot, 'dist-export-embed');
124b6b91c50SEvan Bacon    // List output files with sizes for snapshotting.
125b6b91c50SEvan Bacon    // This is to make sure that any changes to the output are intentional.
126b6b91c50SEvan Bacon    // Posix path formatting is used to make paths the same across OSes.
127b6b91c50SEvan Bacon    const files = klawSync(outputDir)
128b6b91c50SEvan Bacon      .map((entry) => {
129b6b91c50SEvan Bacon        if (entry.path.includes('node_modules') || !entry.stats.isFile()) {
130b6b91c50SEvan Bacon          return null;
131b6b91c50SEvan Bacon        }
132b6b91c50SEvan Bacon        return path.posix.relative(outputDir, entry.path);
133b6b91c50SEvan Bacon      })
134b6b91c50SEvan Bacon      .filter(Boolean);
135b6b91c50SEvan Bacon
136b6b91c50SEvan Bacon    // If this changes then everything else probably changed as well.
137b6b91c50SEvan Bacon    expect(files).toEqual([
138fd2402c1SEvan Bacon      'assets/__e2e__/static-rendering/sweet.ttf',
139fd2402c1SEvan Bacon      'assets/__packages/expo-router/assets/error.png',
140fd2402c1SEvan Bacon      'assets/__packages/expo-router/assets/file.png',
141fd2402c1SEvan Bacon      'assets/__packages/expo-router/assets/forward.png',
142fd2402c1SEvan Bacon      'assets/__packages/expo-router/assets/pkg.png',
143429dc7fcSEvan Bacon      'assets/assets/icon.png',
144b6b91c50SEvan Bacon      'output.js',
145b6b91c50SEvan Bacon    ]);
146b6b91c50SEvan Bacon  },
147b6b91c50SEvan Bacon  // Could take 45s depending on how fast npm installs
148b6b91c50SEvan Bacon  120 * 1000
149b6b91c50SEvan Bacon);
150