diff --git a/docs/generated/packages/detox/generators/init.json b/docs/generated/packages/detox/generators/init.json index 15159e77fb3fa..32f80a10fe8da 100644 --- a/docs/generated/packages/detox/generators/init.json +++ b/docs/generated/packages/detox/generators/init.json @@ -18,6 +18,12 @@ "default": false, "description": "Do not add dependencies to `package.json`.", "x-priority": "internal" + }, + "framework": { + "type": "string", + "description": "App framework to test", + "enum": ["react-native", "expo"], + "default": "react-native" } }, "required": [], diff --git a/docs/generated/packages/expo/executors/build.json b/docs/generated/packages/expo/executors/build.json index 6c6f9687f7247..af3bac780941c 100644 --- a/docs/generated/packages/expo/executors/build.json +++ b/docs/generated/packages/expo/executors/build.json @@ -38,6 +38,10 @@ "description": "Run build locally [experimental]", "default": false }, + "output": { + "type": "string", + "description": "Output path for local build" + }, "wait": { "type": "boolean", "description": "Wait for build(s) to complete", diff --git a/packages/detox/migrations.json b/packages/detox/migrations.json index bd7a433df8b2e..3613afcc7c4be 100644 --- a/packages/detox/migrations.json +++ b/packages/detox/migrations.json @@ -29,6 +29,12 @@ "version": "16.0.0-beta.3", "description": "Update .detoxrc.json and jest.config.json for detox 20", "implementation": "./src/migrations/update-16-0-0/update-detoxrc-json" + }, + "update-detoxrc-json-expo-16-1-4": { + "cli": "nx", + "version": "16.1.4-beta.0", + "description": "Update .detoxrc.json for expo", + "implementation": "./src/migrations/update-16-1-4/update-detoxrc-json-expo" } }, "packageJsonUpdates": { @@ -222,6 +228,19 @@ "alwaysAddToPackageJson": false } } + }, + "16.1.1": { + "version": "16.1.1-beta.0", + "packages": { + "detox": { + "version": "~20.8.0", + "alwaysAddToPackageJson": false + }, + "@config-plugins/detox": { + "version": "~5.0.1", + "alwaysAddToPackageJson": false + } + } } } } diff --git a/packages/detox/package.json b/packages/detox/package.json index 813822f76f93a..e0a8bb2f0804a 100644 --- a/packages/detox/package.json +++ b/packages/detox/package.json @@ -32,7 +32,7 @@ "@nx/react": "file:../react" }, "peerDependencies": { - "detox": "~20.7.0" + "detox": "~20.8.0" }, "builders": "./executors.json", "ng-update": { diff --git a/packages/detox/src/generators/application/application.spec.ts b/packages/detox/src/generators/application/application.spec.ts index ab1b7e8b42714..1092d41a388af 100644 --- a/packages/detox/src/generators/application/application.spec.ts +++ b/packages/detox/src/generators/application/application.spec.ts @@ -345,14 +345,14 @@ describe('detox application generator', () => { 'android.eas': { binaryPath: '../../../my-dir/my-app/dist/MyDirMyApp.apk', build: - 'npx nx run my-dir-my-app:download --platform android --output=my-dir/my-app/dist/', - type: 'ios.app', + 'npx nx run my-dir-my-app:download --platform android --output=../../../my-dir/my-app/dist/', + type: 'android.apk', }, 'android.local': { binaryPath: '../../../my-dir/my-app/dist/MyDirMyApp.apk', build: - 'npx nx run my-dir-my-app:build --platform android --profile preview --wait --local --no-interactive --output=my-dir/my-app/dist/', - type: 'ios.app', + 'npx nx run my-dir-my-app:build --platform android --profile preview --wait --local --no-interactive --output=../../../my-dir/my-app/dist/MyDirMyApp.apk', + type: 'android.apk', }, 'android.release': { binaryPath: @@ -371,13 +371,13 @@ describe('detox application generator', () => { 'ios.eas': { binaryPath: '../../../my-dir/my-app/dist/MyDirMyApp.app', build: - 'npx nx run my-dir-my-app:download --platform ios --distribution simulator --output=my-dir/my-app/dist/', + 'npx nx run my-dir-my-app:download --platform ios --distribution simulator --output=../../../my-dir/my-app/dist/', type: 'ios.app', }, 'ios.local': { binaryPath: '../../../my-dir/my-app/dist/MyDirMyApp.app', build: - 'npx nx run my-dir-my-app:build --platform ios --profile preview --wait --local --no-interactive --output=my-dir/my-app/dist/', + 'npx nx run my-dir-my-app:build --platform ios --profile preview --wait --local --no-interactive --output=../../../my-dir/my-app/dist/MyDirMyApp.tar.gz', type: 'ios.app', }, 'ios.release': { diff --git a/packages/detox/src/generators/application/files/app/.detoxrc.json.template b/packages/detox/src/generators/application/files/app/.detoxrc.json.template index 21af13eeeb0c6..815c1826b6081 100644 --- a/packages/detox/src/generators/application/files/app/.detoxrc.json.template +++ b/packages/detox/src/generators/application/files/app/.detoxrc.json.template @@ -22,12 +22,12 @@ <% if (framework === 'expo') { %> "ios.eas": { "type": "ios.app", - "build": "<%= exec %> nx run <%= appFileName %>:download --platform ios --distribution simulator --output=<%= appRoot %>/dist/", + "build": "<%= exec %> nx run <%= appFileName %>:download --platform ios --distribution simulator --output=<%= offsetFromRoot %><%= appRoot %>/dist/", "binaryPath": "<%= offsetFromRoot %><%= appRoot %>/dist/<%= appExpoName %>.app" }, "ios.local": { "type": "ios.app", - "build": "<%= exec %> nx run <%= appFileName %>:build --platform ios --profile preview --wait --local --no-interactive --output=<%= appRoot %>/dist/", + "build": "<%= exec %> nx run <%= appFileName %>:build --platform ios --profile preview --wait --local --no-interactive --output=<%= offsetFromRoot %><%= appRoot %>/dist/<%= appExpoName %>.tar.gz", "binaryPath": "<%= offsetFromRoot %><%= appRoot %>/dist/<%= appExpoName %>.app" }, <% } %> @@ -43,13 +43,13 @@ }, <% if (framework === 'expo') { %> "android.eas": { - "type": "ios.app", - "build": "<%= exec %> nx run <%= appFileName %>:download --platform android --output=<%= appRoot %>/dist/", + "type": "android.apk", + "build": "<%= exec %> nx run <%= appFileName %>:download --platform android --output=<%= offsetFromRoot %><%= appRoot %>/dist/", "binaryPath": "<%= offsetFromRoot %><%= appRoot %>/dist/<%= appExpoName %>.apk" }, "android.local": { - "type": "ios.app", - "build": "<%= exec %> nx run <%= appFileName %>:build --platform android --profile preview --wait --local --no-interactive --output=<%= appRoot %>/dist/", + "type": "android.apk", + "build": "<%= exec %> nx run <%= appFileName %>:build --platform android --profile preview --wait --local --no-interactive --output=<%= offsetFromRoot %><%= appRoot %>/dist/<%= appExpoName %>.apk", "binaryPath": "<%= offsetFromRoot %><%= appRoot %>/dist/<%= appExpoName %>.apk" }, <% } %> @@ -97,11 +97,11 @@ }, <% if (framework === 'expo') { %> "android.emu.eas": { - "device": "simulator", + "device": "emulator", "app": "android.eas" }, "android.emu.local": { - "device": "simulator", + "device": "emulator", "app": "android.local" }, <% } %> diff --git a/packages/detox/src/generators/application/lib/get-targets.spec.ts b/packages/detox/src/generators/application/lib/get-targets.spec.ts new file mode 100644 index 0000000000000..4ffddd609da9a --- /dev/null +++ b/packages/detox/src/generators/application/lib/get-targets.spec.ts @@ -0,0 +1,45 @@ +import { expoBuildTarget, expoTestTarget } from './get-targets'; + +describe('getTargets', () => { + it('should return ios test target for expo projects', () => { + expect(expoTestTarget('ios.sim', 'test')).toEqual({ + options: { + detoxConfiguration: 'ios.sim.eas', + buildTarget: 'test:build-ios', + }, + configurations: { + local: { + detoxConfiguration: 'ios.sim.local', + buildTarget: 'test:build-ios:local', + }, + bare: { + detoxConfiguration: 'ios.sim.debug', + buildTarget: 'test:build-ios:bare', + }, + production: { + detoxConfiguration: 'ios.sim.release', + buildTarget: 'test:build-ios:production', + }, + }, + }); + }); + + it('should return ios build target for expo projects', () => { + expect(expoBuildTarget('ios.sim')).toEqual({ + options: { + detoxConfiguration: 'ios.sim.eas', + }, + configurations: { + local: { + detoxConfiguration: 'ios.sim.local', + }, + bare: { + detoxConfiguration: 'ios.sim.debug', + }, + production: { + detoxConfiguration: 'ios.sim.release', + }, + }, + }); + }); +}); diff --git a/packages/detox/src/generators/application/lib/get-targets.ts b/packages/detox/src/generators/application/lib/get-targets.ts index 9c0ad6e0e77ee..b2bee0d29063d 100644 --- a/packages/detox/src/generators/application/lib/get-targets.ts +++ b/packages/detox/src/generators/application/lib/get-targets.ts @@ -14,7 +14,7 @@ export function reactNativeBuildTarget(platform: 'ios.sim' | 'android.emu') { export function expoBuildTarget(platform: 'ios.sim' | 'android.emu') { return { options: { - detoxConfiguration: `${platform}.debug`, + detoxConfiguration: `${platform}.eas`, }, configurations: { local: { diff --git a/packages/detox/src/generators/init/init.ts b/packages/detox/src/generators/init/init.ts index 6af85ac9327f6..a7dc66ad6e1f1 100644 --- a/packages/detox/src/generators/init/init.ts +++ b/packages/detox/src/generators/init/init.ts @@ -11,6 +11,7 @@ import { jestVersion, typesNodeVersion } from '@nx/jest/src/utils/versions'; import { Schema } from './schema'; import { + configPluginsDetoxVersion, detoxVersion, nxVersion, testingLibraryJestDom, @@ -21,7 +22,7 @@ export async function detoxInitGenerator(host: Tree, schema: Schema) { if (!schema.skipPackageJson) { tasks.push(moveDependency(host)); - tasks.push(updateDependencies(host)); + tasks.push(updateDependencies(host, schema)); } if (!schema.skipFormat) { @@ -31,7 +32,7 @@ export async function detoxInitGenerator(host: Tree, schema: Schema) { return runTasksInSerial(...tasks); } -export function updateDependencies(host: Tree) { +export function updateDependencies(host: Tree, schema: Schema) { return addDependenciesToPackageJson( host, {}, @@ -41,6 +42,9 @@ export function updateDependencies(host: Tree) { '@testing-library/jest-dom': testingLibraryJestDom, '@types/node': typesNodeVersion, 'jest-circus': jestVersion, + ...(schema.framework === 'expo' + ? { '@config-plugins/detox': configPluginsDetoxVersion } + : {}), } ); } diff --git a/packages/detox/src/generators/init/schema.d.ts b/packages/detox/src/generators/init/schema.d.ts index bf951b8a4dad5..7481d6c823432 100644 --- a/packages/detox/src/generators/init/schema.d.ts +++ b/packages/detox/src/generators/init/schema.d.ts @@ -1,4 +1,5 @@ export interface Schema { skipFormat?: boolean; skipPackageJson?: boolean; //default is false + framework?: 'react-native' | 'expo'; } diff --git a/packages/detox/src/generators/init/schema.json b/packages/detox/src/generators/init/schema.json index 5bc0ad9d29d07..a9d0fdf0a8222 100644 --- a/packages/detox/src/generators/init/schema.json +++ b/packages/detox/src/generators/init/schema.json @@ -15,6 +15,12 @@ "default": false, "description": "Do not add dependencies to `package.json`.", "x-priority": "internal" + }, + "framework": { + "type": "string", + "description": "App framework to test", + "enum": ["react-native", "expo"], + "default": "react-native" } }, "required": [] diff --git a/packages/detox/src/migrations/update-16-0-0/update-detoxrc-json.spec.ts b/packages/detox/src/migrations/update-16-0-0/update-detoxrc-json.spec.ts index c65e2616d4368..95f1221b3e998 100644 --- a/packages/detox/src/migrations/update-16-0-0/update-detoxrc-json.spec.ts +++ b/packages/detox/src/migrations/update-16-0-0/update-detoxrc-json.spec.ts @@ -13,7 +13,7 @@ describe('Update detoxrc for detox 20', () => { sourceRoot: 'apps/products/src', targets: { 'test-ios': { - executor: '@nrwl/detox:test', + executor: '@nx/detox:test', }, }, }); @@ -31,6 +31,10 @@ describe('Update detoxrc for detox 20', () => { '/src/**/*.test.ts?(x)', '/src/**/*.spec.ts?(x)', ], + globalSetup: 'detox/runners/jest/globalSetup', + globalTeardown: 'detox/runners/jest/globalTeardown', + reporter: ['detox/runners/jest/reporter'], + verbose: true, }); }); diff --git a/packages/detox/src/migrations/update-16-0-0/update-detoxrc-json.ts b/packages/detox/src/migrations/update-16-0-0/update-detoxrc-json.ts index 8d885630ff33d..e588cc3bf6722 100644 --- a/packages/detox/src/migrations/update-16-0-0/update-detoxrc-json.ts +++ b/packages/detox/src/migrations/update-16-0-0/update-detoxrc-json.ts @@ -12,13 +12,13 @@ import { * - update keys: runnerConfig * Update jest.config.json under detox project: * - remove key: transform - * - add key: rootDir, testMatch + * - add key: rootDir, testMatch, reporter, globalSetup, globalTeardown, verbose */ export default async function update(tree: Tree) { const projects = getProjects(tree); projects.forEach((project) => { - if (project.targets?.['test-ios']?.executor !== '@nrwl/detox:test') return; + if (project.targets?.['test-ios']?.executor !== '@nx/detox:test') return; updateDetoxrcJson(tree, project); updateJestConfigJson(tree, project); }); @@ -62,6 +62,10 @@ function updateJestConfigJson(host: Tree, project: ProjectConfiguration) { '/src/**/*.spec.ts?(x)', ]; } + json.reporter = ['detox/runners/jest/reporter']; + json.globalSetup = 'detox/runners/jest/globalSetup'; + json.globalTeardown = 'detox/runners/jest/globalTeardown'; + json.verbose = true; return json; }); } diff --git a/packages/detox/src/migrations/update-16-1-4/update-detoxrc-json-expo.spec.ts b/packages/detox/src/migrations/update-16-1-4/update-detoxrc-json-expo.spec.ts new file mode 100644 index 0000000000000..7d59284fe4362 --- /dev/null +++ b/packages/detox/src/migrations/update-16-1-4/update-detoxrc-json-expo.spec.ts @@ -0,0 +1,127 @@ +import { addProjectConfiguration, readJson, Tree } from '@nx/devkit'; +import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; + +import update from './update-detoxrc-json-expo'; + +describe('Update detoxrc for expo projects', () => { + let tree: Tree; + + beforeEach(async () => { + tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' }); + addProjectConfiguration(tree, 'products', { + root: 'apps/products', + sourceRoot: 'apps/products/src', + targets: { + 'test-ios': { + executor: '@nx/detox:test', + options: { + detoxConfiguration: 'ios.sim.eas', + }, + }, + 'build-ios': { + executor: '@nx/detox:build', + options: { + detoxConfiguration: 'random value', + }, + }, + 'test-android': { + executor: '@nx/detox:test', + options: { + detoxConfiguration: 'android.sim.eas', + }, + }, + 'build-android': { + executor: '@nx/detox:build', + options: { + detoxConfiguration: 'random value', + }, + }, + }, + }); + tree.write('apps/products/jest.config.json', `{"transform": {}}`); + tree.write( + 'apps/products/.detoxrc.json', + `{"apps": {"ios.eas": {}, "android.eas": {}, "ios.local": {}, "android.local": {}}}` + ); + }); + + it(`should update .detoxrc.json`, async () => { + await update(tree); + + const detoxrcJson = readJson(tree, 'apps/products/.detoxrc.json'); + expect(detoxrcJson).toEqual({ + apps: { + 'ios.eas': { + build: + 'npx nx run products:download --platform ios --distribution simulator --output=../../apps/products/dist/', + }, + 'android.eas': { + build: + 'npx nx run products:download --platform android --distribution simulator --output=../../apps/products/dist/', + type: 'android.apk', + }, + 'ios.local': { + build: + 'npx nx run products:build --platform ios --configuration=debug --output=../../apps/products/dist/Products.tar.gz', + }, + 'android.local': { + build: + 'npx nx run products:build --platform android --configuration=debug --output=../../apps/products/dist/Products.apk', + type: 'android.apk', + }, + }, + }); + }); + + it(`should update project.json`, async () => { + await update(tree); + + const projectJson = readJson(tree, 'apps/products/project.json'); + expect(projectJson).toEqual({ + $schema: '../../node_modules/nx/schemas/project-schema.json', + name: 'products', + sourceRoot: 'apps/products/src', + targets: { + 'build-android': { + executor: '@nx/detox:build', + options: { + detoxConfiguration: 'android.sim.eas', + }, + }, + 'build-ios': { + executor: '@nx/detox:build', + options: { + detoxConfiguration: 'ios.sim.eas', + }, + }, + 'test-android': { + configurations: { + bare: { + buildTarget: 'products:build-android:bare', + detoxConfiguration: 'android.emu.debug', + }, + local: { + buildTarget: 'products:build-android:local', + detoxConfiguration: 'android.emu.local', + }, + production: { + buildTarget: 'products:build-android:production', + detoxConfiguration: 'android.emu.release', + }, + }, + executor: '@nx/detox:test', + options: { + buildTarget: 'products:build-android', + detoxConfiguration: 'android.sim.eas', + }, + }, + 'test-ios': { + executor: '@nx/detox:test', + options: { + detoxConfiguration: 'ios.sim.eas', + }, + }, + }, + }); + }); +}); diff --git a/packages/detox/src/migrations/update-16-1-4/update-detoxrc-json-expo.ts b/packages/detox/src/migrations/update-16-1-4/update-detoxrc-json-expo.ts new file mode 100644 index 0000000000000..2b9f8cfb35976 --- /dev/null +++ b/packages/detox/src/migrations/update-16-1-4/update-detoxrc-json-expo.ts @@ -0,0 +1,101 @@ +import { + Tree, + formatFiles, + getProjects, + updateJson, + ProjectConfiguration, + offsetFromRoot, + detectPackageManager, + getPackageManagerCommand, + names, + updateProjectConfiguration, +} from '@nx/devkit'; + +/** + * Update .detoxrc.json under detox project for expo: + * - fix the eas build command + * - fix the local build command + * - update project.json targets + */ +export default async function update(tree: Tree) { + const projects = getProjects(tree); + + projects.forEach((project) => { + if (project.targets?.['test-ios']?.executor !== '@nx/detox:test') return; + updateDetoxrcJson(tree, project); + updateProjectJson(tree, project); + }); + + await formatFiles(tree); +} + +function updateDetoxrcJson(host: Tree, project: ProjectConfiguration) { + const detoxConfigPath = `${project.root}/.detoxrc.json`; + const projectName = project.name; + const appName = names(projectName).className; + const offset = offsetFromRoot(project.root); + const exec = getPackageManagerCommand(detectPackageManager(host.root)).exec; + if (!host.exists(detoxConfigPath)) return; + updateJson(host, detoxConfigPath, (json) => { + if (json.apps?.['ios.eas']) { + json.apps[ + 'ios.eas' + ].build = `${exec} nx run ${projectName}:download --platform ios --distribution simulator --output=${offset}${project.root}/dist/`; + } + if (json.apps?.['android.eas']) { + json.apps[ + 'android.eas' + ].build = `${exec} nx run ${projectName}:download --platform android --distribution simulator --output=${offset}${project.root}/dist/`; + json.apps['android.eas'].type = 'android.apk'; + } + if (json.apps?.['ios.local']) { + json.apps[ + 'ios.local' + ].build = `${exec} nx run ${projectName}:build --platform ios --configuration=debug --output=${offset}${project.root}/dist/${appName}.tar.gz`; + } + if (json.apps?.['android.local']) { + json.apps[ + 'android.local' + ].build = `${exec} nx run ${projectName}:build --platform android --configuration=debug --output=${offset}${project.root}/dist/${appName}.apk`; + json.apps['android.local'].type = 'android.apk'; + } + return json; + }); +} + +function updateProjectJson(host: Tree, project: ProjectConfiguration) { + if ( + project.targets?.['test-ios']?.options?.detoxConfiguration == 'ios.sim.eas' + ) { + project.targets['build-ios'].options.detoxConfiguration = 'ios.sim.eas'; + } + if ( + project.targets?.['test-android']?.options?.detoxConfiguration == + 'android.sim.eas' + ) { + project.targets['build-android'].options.detoxConfiguration = + 'android.sim.eas'; + project.targets['test-android'] = { + executor: '@nx/detox:test', + options: { + detoxConfiguration: 'android.sim.eas', + buildTarget: `${project.name}:build-android`, + }, + configurations: { + local: { + detoxConfiguration: 'android.emu.local', + buildTarget: `${project.name}:build-android:local`, + }, + bare: { + detoxConfiguration: 'android.emu.debug', + buildTarget: `${project.name}:build-android:bare`, + }, + production: { + detoxConfiguration: 'android.emu.release', + buildTarget: `${project.name}:build-android:production`, + }, + }, + }; + } + updateProjectConfiguration(host, project.name, project); +} diff --git a/packages/detox/src/utils/versions.ts b/packages/detox/src/utils/versions.ts index c6a45246c0505..e8cb95f49f585 100644 --- a/packages/detox/src/utils/versions.ts +++ b/packages/detox/src/utils/versions.ts @@ -1,4 +1,5 @@ export const nxVersion = require('../../package.json').version; -export const detoxVersion = '~20.7.0'; +export const detoxVersion = '~20.8.0'; export const testingLibraryJestDom = '5.16.5'; +export const configPluginsDetoxVersion = '~5.0.1'; // only required for expo diff --git a/packages/expo/migrations.json b/packages/expo/migrations.json index 8b4181684bd93..9cc1e9426502f 100644 --- a/packages/expo/migrations.json +++ b/packages/expo/migrations.json @@ -54,11 +54,17 @@ "description": "Replace @nrwl/expo with @nx/expo", "implementation": "./src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages" }, - "update-eas-scripts": { + "update-eas-scripts-16-1-4": { "cli": "nx", "version": "16.1.4-beta.0", "description": "Update package.json eas build lifecycle scripts", "implementation": "./src/migrations/update-16-1-4/update-eas-scripts" + }, + "add-detox-app-json-16-1-4": { + "version": "16.1.4-beta.0", + "cli": "nx", + "description": "Add app.json for detox", + "factory": "./src/migrations/update-16-1-4/add-detox-app-json" } }, "packageJsonUpdates": { diff --git a/packages/expo/src/executors/build/build.impl.ts b/packages/expo/src/executors/build/build.impl.ts index 8fbd1ce645d1c..5fbfd16de62aa 100644 --- a/packages/expo/src/executors/build/build.impl.ts +++ b/packages/expo/src/executors/build/build.impl.ts @@ -1,10 +1,12 @@ import { ExecutorContext, names } from '@nx/devkit'; -import { join } from 'path'; +import { join, normalize, sep } from 'path'; import { ChildProcess, fork } from 'child_process'; import { ensureNodeModulesSymlink } from '../../utils/ensure-node-modules-symlink'; +import { copyBuildFile, unzipBuild } from '../download/download.impl'; import { ExpoEasBuildOptions } from './schema'; +import { removeSync } from 'fs-extra'; export interface ReactNativeBuildOutput { success: boolean; @@ -21,7 +23,20 @@ export default async function* buildExecutor( ensureNodeModulesSymlink(context.root, projectRoot); try { + // remove the output app if it already existed + if (options.local && options.output) { + removeSync(options.output); + } + await runCliBuild(context.root, projectRoot, options); + + // unzip the build if it's a tar.gz + if (options.local && options.output && options.output.endsWith('.tar.gz')) { + const directoryPath = normalize(options.output).split(sep); + directoryPath.pop(); + const outputDirectory = directoryPath.join(sep); + await unzipBuild(options.output, outputDirectory); + } yield { success: true }; } finally { if (childProcess) { @@ -39,7 +54,10 @@ function runCliBuild( childProcess = fork( join(workspaceRoot, './node_modules/eas-cli/bin/run'), ['build', ...createBuildOptions(options)], - { cwd: join(workspaceRoot, projectRoot), env: process.env } + { + cwd: join(workspaceRoot, projectRoot), + env: process.env, + } ); // Ensure the child process is killed when the parent exits diff --git a/packages/expo/src/executors/build/schema.json b/packages/expo/src/executors/build/schema.json index 053f1b1459617..c18d315994e73 100644 --- a/packages/expo/src/executors/build/schema.json +++ b/packages/expo/src/executors/build/schema.json @@ -35,6 +35,10 @@ "description": "Run build locally [experimental]", "default": false }, + "output": { + "type": "string", + "description": "Output path for local build" + }, "wait": { "type": "boolean", "description": "Wait for build(s) to complete", diff --git a/packages/expo/src/executors/download/download.impl.ts b/packages/expo/src/executors/download/download.impl.ts index 971ff779dc017..28dc180b42758 100644 --- a/packages/expo/src/executors/download/download.impl.ts +++ b/packages/expo/src/executors/download/download.impl.ts @@ -5,7 +5,8 @@ import { createWriteStream, existsSync, mkdirSync, -} from 'fs'; + removeSync, +} from 'fs-extra'; import fetch from 'node-fetch'; import { promisify } from 'util'; import { pipeline } from 'stream'; @@ -56,6 +57,10 @@ export default async function* downloadExecutor( const appName = `${names(build.project?.name).className}${appExtension}`; const outputFilePath = join(options.output, appName); + if (existsSync(outputFilePath)) { + removeSync(outputFilePath); + } + if (downloadFileName.endsWith('.tar.gz')) { await unzipBuild(downloadFilePath, options.output); } else { diff --git a/packages/expo/src/generators/application/application.spec.ts b/packages/expo/src/generators/application/application.spec.ts index 30bebfec88000..d50490b4d25ad 100644 --- a/packages/expo/src/generators/application/application.spec.ts +++ b/packages/expo/src/generators/application/application.spec.ts @@ -124,14 +124,14 @@ describe('app', () => { 'android.eas': { binaryPath: '../../../apps/my-dir/my-app/dist/MyApp.apk', build: - 'npx nx run my-app:download --platform android --output=apps/my-dir/my-app/dist/', - type: 'ios.app', + 'npx nx run my-app:download --platform android --output=../../../apps/my-dir/my-app/dist/', + type: 'android.apk', }, 'android.local': { binaryPath: '../../../apps/my-dir/my-app/dist/MyApp.apk', build: - 'npx nx run my-app:build --platform android --profile preview --wait --local --no-interactive --output=apps/my-dir/my-app/dist/', - type: 'ios.app', + 'npx nx run my-app:build --platform android --profile preview --wait --local --no-interactive --output=../../../apps/my-dir/my-app/dist/MyApp.apk', + type: 'android.apk', }, 'android.release': { binaryPath: @@ -150,13 +150,13 @@ describe('app', () => { 'ios.eas': { binaryPath: '../../../apps/my-dir/my-app/dist/MyApp.app', build: - 'npx nx run my-app:download --platform ios --distribution simulator --output=apps/my-dir/my-app/dist/', + 'npx nx run my-app:download --platform ios --distribution simulator --output=../../../apps/my-dir/my-app/dist/', type: 'ios.app', }, 'ios.local': { binaryPath: '../../../apps/my-dir/my-app/dist/MyApp.app', build: - 'npx nx run my-app:build --platform ios --profile preview --wait --local --no-interactive --output=apps/my-dir/my-app/dist/', + 'npx nx run my-app:build --platform ios --profile preview --wait --local --no-interactive --output=../../../apps/my-dir/my-app/dist/MyApp.tar.gz', type: 'ios.app', }, 'ios.release': { @@ -199,14 +199,14 @@ describe('app', () => { 'android.eas': { binaryPath: '../../apps/my-app/dist/MyApp.apk', build: - 'npx nx run my-app:download --platform android --output=apps/my-app/dist/', - type: 'ios.app', + 'npx nx run my-app:download --platform android --output=../../apps/my-app/dist/', + type: 'android.apk', }, 'android.local': { binaryPath: '../../apps/my-app/dist/MyApp.apk', build: - 'npx nx run my-app:build --platform android --profile preview --wait --local --no-interactive --output=apps/my-app/dist/', - type: 'ios.app', + 'npx nx run my-app:build --platform android --profile preview --wait --local --no-interactive --output=../../apps/my-app/dist/MyApp.apk', + type: 'android.apk', }, 'android.release': { binaryPath: @@ -225,13 +225,13 @@ describe('app', () => { 'ios.eas': { binaryPath: '../../apps/my-app/dist/MyApp.app', build: - 'npx nx run my-app:download --platform ios --distribution simulator --output=apps/my-app/dist/', + 'npx nx run my-app:download --platform ios --distribution simulator --output=../../apps/my-app/dist/', type: 'ios.app', }, 'ios.local': { binaryPath: '../../apps/my-app/dist/MyApp.app', build: - 'npx nx run my-app:build --platform ios --profile preview --wait --local --no-interactive --output=apps/my-app/dist/', + 'npx nx run my-app:build --platform ios --profile preview --wait --local --no-interactive --output=../../apps/my-app/dist/MyApp.tar.gz', type: 'ios.app', }, 'ios.release': { @@ -275,14 +275,14 @@ describe('app', () => { 'android.eas': { binaryPath: '../../apps/my-app/dist/myappname.apk', build: - 'npx nx run my-app:download --platform android --output=apps/my-app/dist/', - type: 'ios.app', + 'npx nx run my-app:download --platform android --output=../../apps/my-app/dist/', + type: 'android.apk', }, 'android.local': { binaryPath: '../../apps/my-app/dist/myappname.apk', build: - 'npx nx run my-app:build --platform android --profile preview --wait --local --no-interactive --output=apps/my-app/dist/', - type: 'ios.app', + 'npx nx run my-app:build --platform android --profile preview --wait --local --no-interactive --output=../../apps/my-app/dist/myappname.apk', + type: 'android.apk', }, 'android.release': { binaryPath: @@ -301,13 +301,13 @@ describe('app', () => { 'ios.eas': { binaryPath: '../../apps/my-app/dist/myappname.app', build: - 'npx nx run my-app:download --platform ios --distribution simulator --output=apps/my-app/dist/', + 'npx nx run my-app:download --platform ios --distribution simulator --output=../../apps/my-app/dist/', type: 'ios.app', }, 'ios.local': { binaryPath: '../../apps/my-app/dist/myappname.app', build: - 'npx nx run my-app:build --platform ios --profile preview --wait --local --no-interactive --output=apps/my-app/dist/', + 'npx nx run my-app:build --platform ios --profile preview --wait --local --no-interactive --output=../../apps/my-app/dist/myappname.tar.gz', type: 'ios.app', }, 'ios.release': { diff --git a/packages/expo/src/generators/application/files/app.json.template b/packages/expo/src/generators/application/files/app.json.template index 524287dd5f126..b01971a14ef57 100644 --- a/packages/expo/src/generators/application/files/app.json.template +++ b/packages/expo/src/generators/application/files/app.json.template @@ -28,6 +28,15 @@ "web": { "favicon": "./assets/favicon.png", "bundler": "metro" - } + }, + "plugins": [ + [ + "@config-plugins/detox", + { + "skipProguard": false, + "subdomains": ["10.0.2.2", "localhost"] + } + ] + ] } } diff --git a/packages/expo/src/migrations/update-14-5-1/add-eas-update-target.ts b/packages/expo/src/migrations/update-14-5-1/add-eas-update-target.ts index fa10ffa1dcc80..9339ecde50beb 100644 --- a/packages/expo/src/migrations/update-14-5-1/add-eas-update-target.ts +++ b/packages/expo/src/migrations/update-14-5-1/add-eas-update-target.ts @@ -19,9 +19,8 @@ export default async function update(tree: Tree) { options: {}, }; } + updateProjectConfiguration(tree, name, config); } - - updateProjectConfiguration(tree, name, config); } await formatFiles(tree); diff --git a/packages/expo/src/migrations/update-16-1-4/add-detox-app-json.spec.ts b/packages/expo/src/migrations/update-16-1-4/add-detox-app-json.spec.ts new file mode 100644 index 0000000000000..235c75a74d7e0 --- /dev/null +++ b/packages/expo/src/migrations/update-16-1-4/add-detox-app-json.spec.ts @@ -0,0 +1,40 @@ +import { addProjectConfiguration, getProjects, Tree } from '@nx/devkit'; +import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; +import update from './add-detox-app-json'; + +describe('add-eas-update-target', () => { + let tree: Tree; + + beforeEach(async () => { + tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' }); + addProjectConfiguration(tree, 'product', { + root: 'apps/product', + sourceRoot: 'apps/product/src', + targets: { + start: { + executor: '@nrwl/expo:start', + }, + }, + }); + tree.write('apps/product/app.json', '{"expo": {}}'); + }); + + it(`should update app.json with plugin detox`, async () => { + await update(tree); + + const appJson = JSON.parse(tree.read('apps/product/app.json').toString()); + expect(appJson).toEqual({ + expo: { + plugins: [ + [ + '@config-plugins/detox', + { + skipProguard: false, + subdomains: ['10.0.2.2', 'localhost'], + }, + ], + ], + }, + }); + }); +}); diff --git a/packages/expo/src/migrations/update-16-1-4/add-detox-app-json.ts b/packages/expo/src/migrations/update-16-1-4/add-detox-app-json.ts new file mode 100644 index 0000000000000..5b1d496686267 --- /dev/null +++ b/packages/expo/src/migrations/update-16-1-4/add-detox-app-json.ts @@ -0,0 +1,34 @@ +import { + Tree, + formatFiles, + getProjects, + updateJson, + updateProjectConfiguration, +} from '@nx/devkit'; + +/** + * Add detox plugin to app.json for expo + */ +export default async function update(tree: Tree) { + const projects = getProjects(tree); + + projects.forEach((config) => { + if (config.targets?.['start']?.executor === '@nrwl/expo:start') { + updateJson(tree, `${config.root}/app.json`, (json) => { + if (!json.expo.plugins) { + json.expo.plugins = []; + } + json.expo.plugins.push([ + '@config-plugins/detox', + { + skipProguard: false, + subdomains: ['10.0.2.2', 'localhost'], + }, + ]); + return json; + }); + } + }); + + await formatFiles(tree); +}