fix(detox): fix name with camel case (#27602)

<!-- Please make sure you have read the submission guidelines before
posting an PR -->
<!--
https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr
-->

<!-- Please make sure that your commit message follows our format -->
<!-- Example: `fix(nx): must begin with lowercase` -->

<!-- If this is a particularly complex change or feature addition, you
can request a dedicated Nx release for this pull request branch. Mention
someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they
will confirm if the PR warrants its own release for testing purposes,
and generate it for you if appropriate. -->

## Current Behavior
<!-- This is the behavior we have today -->
- when create an app with `--appName <app name in camel case>`, it
currently has an error. it is caused by line:
```
  const { root: appRoot } = readProjectConfiguration(
    host,
    names(options.appProject).fileName
  );
```
it should not convert appProject to fileName, it should just take the
appProject as it is:
```
const { root: appRoot } = readProjectConfiguration(host, options.appProject);
```

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

Fixes https://github.com/nrwl/nx/issues/24080
This commit is contained in:
Emily Xiong 2024-08-29 16:54:39 -04:00 committed by GitHub
parent ab408ab30c
commit 79b75ad140
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 52 additions and 42 deletions

View File

@ -9,26 +9,21 @@ import {
describe('@nx/detox', () => { describe('@nx/detox', () => {
let project: string; let project: string;
let appName: string; let reactNativeAppName: string;
let expoAppName: string;
beforeAll(() => { beforeAll(() => {
project = newProject(); project = newProject();
appName = uniq('app'); reactNativeAppName = uniq('appTest');
expoAppName = uniq('expoAppTest');
runCLI( runCLI(
`generate @nx/react-native:app ${appName} --e2eTestRunner=detox --install=false --project-name-and-root-format=as-provided --interactive=false` `generate @nx/react-native:app ${reactNativeAppName} --e2eTestRunner=detox --install=false --project-name-and-root-format=as-provided --interactive=false`
); );
updateJson(`${appName}-e2e/.detoxrc.json`, (json) => { runCLI(
json.apps['e2e.debug'] = { `generate @nx/expo:app ${expoAppName} --e2eTestRunner=detox --project-name-and-root-format=as-provided --interactive=false`
type: 'ios.app', );
build: `echo "building ${appName}"`, updateAppDetoxJson(reactNativeAppName);
binaryPath: 'dist', updateAppDetoxJson(expoAppName);
};
json.configurations['e2e.sim.debug'] = {
device: 'simulator',
app: 'e2e.debug',
};
return json;
});
}); });
afterAll(() => cleanupProject()); afterAll(() => cleanupProject());
@ -47,12 +42,34 @@ describe('@nx/detox', () => {
it('should build the app', async () => { it('should build the app', async () => {
const result = runCLI( const result = runCLI(
`build ${appName}-e2e -- --configuration e2e.sim.debug` `build ${reactNativeAppName}-e2e -- --configuration e2e.sim.debug`
);
expect(result).toContain(`building ${reactNativeAppName}`);
expect(result).toContain(
`Successfully ran target build for project ${reactNativeAppName}`
); );
expect(result).toContain(`building ${appName}`); const expoResult = runCLI(
expect(result).toContain( `build ${expoAppName}-e2e -- --configuration e2e.sim.debug`
`Successfully ran target build for project ${appName}` );
expect(expoResult).toContain(`building ${expoAppName}`);
expect(expoResult).toContain(
`Successfully ran target build for project ${expoAppName}`
); );
}, 200_000); }, 200_000);
}); });
function updateAppDetoxJson(appName: string) {
updateJson(`${appName}-e2e/.detoxrc.json`, (json) => {
json.apps['e2e.debug'] = {
type: 'ios.app',
build: `echo "building ${appName}"`,
binaryPath: 'dist',
};
json.configurations['e2e.sim.debug'] = {
device: 'simulator',
app: 'e2e.debug',
};
return json;
});
}

View File

@ -41,7 +41,7 @@ describe('Normalize Options', () => {
}); });
it('should normalize options with name in camel case', async () => { it('should normalize options with name in camel case', async () => {
addProjectConfiguration(appTree, 'my-app', { addProjectConfiguration(appTree, 'myApp', {
root: 'apps/my-app', root: 'apps/my-app',
targets: {}, targets: {},
}); });
@ -73,8 +73,8 @@ describe('Normalize Options', () => {
}); });
const schema: Schema = { const schema: Schema = {
framework: 'react-native', framework: 'react-native',
e2eName: 'myAppE2e', e2eName: 'my-app-e2e',
appProject: 'myApp', appProject: 'my-app',
appDisplayName: 'app display name', appDisplayName: 'app display name',
}; };
const options = await normalizeOptions(appTree, schema); const options = await normalizeOptions(appTree, schema);
@ -86,7 +86,7 @@ describe('Normalize Options', () => {
appFileName: 'my-app', appFileName: 'my-app',
appRoot: 'apps/my-app', appRoot: 'apps/my-app',
e2eName: 'my-app-e2e', e2eName: 'my-app-e2e',
appProject: 'myApp', appProject: 'my-app',
e2eProjectName: 'my-app-e2e', e2eProjectName: 'my-app-e2e',
e2eProjectRoot: 'apps/my-app-e2e', e2eProjectRoot: 'apps/my-app-e2e',
framework: 'react-native', framework: 'react-native',

View File

@ -3,8 +3,8 @@ import { determineProjectNameAndRootOptions } from '@nx/devkit/src/generators/pr
import { Schema } from '../schema'; import { Schema } from '../schema';
export interface NormalizedSchema extends Schema { export interface NormalizedSchema extends Schema {
appFileName: string; // the file name of app to be tested appFileName: string; // the file name of app to be tested in kebab case
appClassName: string; // the class name of app to be tested appClassName: string; // the class name of app to be tested in pascal case
appExpoName: string; // the expo name of app to be tested in class case appExpoName: string; // the expo name of app to be tested in class case
appRoot: string; // the root path of e2e project. e.g. apps/app-directory/app appRoot: string; // the root path of e2e project. e.g. apps/app-directory/app
e2eProjectName: string; // the name of e2e project e2eProjectName: string; // the name of e2e project
@ -32,10 +32,7 @@ export async function normalizeOptions(
const { fileName: appFileName, className: appClassName } = names( const { fileName: appFileName, className: appClassName } = names(
options.appName || options.appProject options.appName || options.appProject
); );
const { root: appRoot } = readProjectConfiguration( const { root: appRoot } = readProjectConfiguration(host, options.appProject);
host,
names(options.appProject).fileName
);
return { return {
...options, ...options,

View File

@ -2,9 +2,9 @@ import type { ProjectNameAndRootFormat } from '@nx/devkit/src/generators/project
import type { Linter, LinterType } from '@nx/eslint'; import type { Linter, LinterType } from '@nx/eslint';
export interface Schema { export interface Schema {
appProject: string; // name of the project app to be tested (directory + app name in kebab class) appProject: string; // name of the project app to be tested (directory + app name), case insensitive
appDisplayName?: string; // display name of the app to be tested appDisplayName?: string; // display name of the app to be tested
appName?: string; // name of app to be tested if different form appProject, case insenstive appName?: string; // name of app to be tested if different form appProject, case insensitive
e2eDirectory?: string; // the directory where e2e app going to be located e2eDirectory?: string; // the directory where e2e app going to be located
projectNameAndRootFormat?: ProjectNameAndRootFormat; projectNameAndRootFormat?: ProjectNameAndRootFormat;
e2eName: string; // name of the e2e app e2eName: string; // name of the e2e app

View File

@ -8,11 +8,8 @@ import {
runTasksInSerial, runTasksInSerial,
Tree, Tree,
} from '@nx/devkit'; } from '@nx/devkit';
import { import { addPluginV1 } from '@nx/devkit/src/utils/add-plugin';
addPluginV1, import { createNodes } from '../../plugins/plugin';
generateCombinations,
} from '@nx/devkit/src/utils/add-plugin';
import { createNodes, DetoxPluginOptions } from '../../plugins/plugin';
import { detoxVersion, nxVersion } from '../../utils/versions'; import { detoxVersion, nxVersion } from '../../utils/versions';
import { Schema } from './schema'; import { Schema } from './schema';

View File

@ -15,7 +15,7 @@ export interface Schema {
js: boolean; // default is false js: boolean; // default is false
linter: Linter | LinterType; // default is eslint linter: Linter | LinterType; // default is eslint
setParserOptionsProject?: boolean; // default is false setParserOptionsProject?: boolean; // default is false
e2eTestRunner: 'cypress' | 'playwright' | 'detox' | 'none'; // default is playwright e2eTestRunner: 'cypress' | 'playwright' | 'detox' | 'none'; // default is none
standaloneConfig?: boolean; standaloneConfig?: boolean;
skipPackageJson?: boolean; // default is false skipPackageJson?: boolean; // default is false
addPlugin?: boolean; addPlugin?: boolean;

View File

@ -3,7 +3,6 @@ import {
GeneratorCallback, GeneratorCallback,
joinPathFragments, joinPathFragments,
output, output,
readCachedProjectGraph,
readJson, readJson,
runTasksInSerial, runTasksInSerial,
Tree, Tree,

View File

@ -78,7 +78,7 @@ describe('Normalize Options', () => {
bundler: 'vite', bundler: 'vite',
linter: Linter.None, linter: Linter.None,
rootProject: false, rootProject: false,
e2eProjectName: 'my-app-e2e', e2eProjectName: 'myApp-e2e',
e2eProjectRoot: 'myApp-e2e', e2eProjectRoot: 'myApp-e2e',
}); });
}); });
@ -152,7 +152,7 @@ describe('Normalize Options', () => {
bundler: 'vite', bundler: 'vite',
linter: Linter.None, linter: Linter.None,
rootProject: false, rootProject: false,
e2eProjectName: 'directory/my-app-e2e', e2eProjectName: 'my-app-e2e',
e2eProjectRoot: 'directory/my-app-e2e', e2eProjectRoot: 'directory/my-app-e2e',
}); });
}); });

View File

@ -7,7 +7,7 @@ import { ReactNativePluginOptions } from '../../../../plugins/plugin';
export interface NormalizedSchema extends Schema { export interface NormalizedSchema extends Schema {
className: string; // app name in class case className: string; // app name in class case
fileName: string; // app name in file class fileName: string; // app name in file class
projectName: string; // directory + app name in kebab case projectName: string; // directory + app name, case based on user input
appProjectRoot: string; // app directory path appProjectRoot: string; // app directory path
lowerCaseName: string; // app name in lower case lowerCaseName: string; // app name in lower case
iosProjectRoot: string; iosProjectRoot: string;
@ -47,7 +47,7 @@ export async function normalizeOptions(
const androidProjectRoot = joinPathFragments(appProjectRoot, 'android'); const androidProjectRoot = joinPathFragments(appProjectRoot, 'android');
const rootProject = appProjectRoot === '.'; const rootProject = appProjectRoot === '.';
const e2eProjectName = rootProject ? 'e2e' : `${fileName}-e2e`; const e2eProjectName = rootProject ? 'e2e' : `${appProjectName}-e2e`;
const e2eProjectRoot = rootProject ? 'e2e' : `${appProjectRoot}-e2e`; const e2eProjectRoot = rootProject ? 'e2e' : `${appProjectRoot}-e2e`;
const parsedTags = options.tags const parsedTags = options.tags