diff --git a/__e2e__/__snapshots__/config.test.ts.snap b/__e2e__/__snapshots__/config.test.ts.snap new file mode 100644 index 000000000..01ee539b2 --- /dev/null +++ b/__e2e__/__snapshots__/config.test.ts.snap @@ -0,0 +1,70 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`shows up current config without unnecessary output 1`] = ` +{ + "root": "<>/TestProject", + "reactNativePath": "<>/TestProject/node_modules/react-native", + "dependencies": {}, + "commands": [ + { + "name": "log-ios", + "description": "starts iOS device syslog tail" + }, + { + "name": "run-ios", + "description": "builds your app and starts it on iOS simulator", + "examples": [ + "<>" + ], + "options": [ + "<>" + ] + }, + { + "name": "log-android", + "description": "starts logkitty" + }, + { + "name": "run-android", + "description": "builds your app and starts it on a connected Android emulator or device", + "options": [ + "<>" + ] + } + ], + "assets": [], + "platforms": { + "ios": {}, + "android": {} + }, + "project": { + "ios": { + "sourceDir": "<>/TestProject/ios", + "folder": "<>/TestProject", + "pbxprojPath": "<>/TestProject/ios/TestProject.xcodeproj/project.pbxproj", + "podfile": "<>/TestProject/ios/Podfile", + "podspecPath": null, + "projectPath": "<>/TestProject/ios/TestProject.xcodeproj", + "projectName": "TestProject.xcodeproj", + "libraryFolder": "Libraries", + "sharedLibraries": [], + "plist": [], + "scriptPhases": [] + }, + "android": { + "sourceDir": "<>/TestProject/android", + "isFlat": true, + "folder": "<>/TestProject", + "stringsPath": "<>/TestProject/android/app/src/main/res/values/strings.xml", + "manifestPath": "<>/TestProject/android/app/src/main/AndroidManifest.xml", + "buildGradlePath": "<>/TestProject/android/build.gradle", + "settingsGradlePath": "<>/TestProject/android/settings.gradle", + "assetsPath": "<>/TestProject/android/app/src/main/assets", + "mainFilePath": "<>/TestProject/android/app/src/main/java/com/testproject/MainApplication.java", + "packageName": "com.testproject", + "packageFolder": "com/testproject", + "appName": "app" + } + } +} +`; diff --git a/__e2e__/config.test.ts b/__e2e__/config.test.ts new file mode 100644 index 000000000..c452dd540 --- /dev/null +++ b/__e2e__/config.test.ts @@ -0,0 +1,93 @@ +import path from 'path'; +import fs from 'fs'; +import {wrap} from 'jest-snapshot-serializer-raw'; +import { + runCLI, + getTempDirectory, + cleanup, + writeFiles, + spawnScript, + replaceProjectRootInOutput, +} from '../jest/helpers'; + +const DIR = getTempDirectory('test_root'); + +function isValidJSON(text: string) { + try { + JSON.parse(text); + return true; + } catch { + return false; + } +} + +// We have to check whether setup_env script fails, if it does then we shouldn't log any info to the console +function createCorruptedSetupEnvScript() { + const originalSetupEnvPath = path.join( + __dirname, + '../packages/cli/setup_env.sh', + ); + const originalSetupEnv = fs.readFileSync(originalSetupEnvPath); + const corruptedScript = '#!/bin/sh\n exit 1;'; + fs.writeFileSync(originalSetupEnvPath, corruptedScript); + return () => { + fs.writeFileSync(originalSetupEnvPath, originalSetupEnv); + }; +} + +beforeAll(() => { + // Register all packages to be linked + for (const pkg of ['platform-ios', 'platform-android']) { + spawnScript('yarn', ['link'], { + cwd: path.join(__dirname, `../packages/${pkg}`), + }); + } + + // Clean up folder and re-create a new project + cleanup(DIR); + writeFiles(DIR, {}); + + // Initialise React Native project + + runCLI(DIR, ['init', 'TestProject']); + + // Link CLI to the project + const pkgs = [ + '@react-native-community/cli-platform-ios', + '@react-native-community/cli-platform-android', + ]; + + spawnScript('yarn', ['link', ...pkgs], { + cwd: path.join(DIR, 'TestProject'), + }); +}); + +afterAll(() => { + cleanup(DIR); +}); + +test('shows up current config without unnecessary output', () => { + const {stdout} = runCLI(path.join(DIR, 'TestProject'), ['config']); + const parsedStdout = JSON.parse(stdout); + // Strip unnecessary parts + parsedStdout.commands = parsedStdout.commands.map((command: any) => ({ + ...command, + examples: command.examples && ['<>'], + options: command.options && ['<>'], + })); + + const configWithReplacedProjectRoots = replaceProjectRootInOutput( + JSON.stringify(parsedStdout, null, 2).replace(/\\\\/g, '\\'), + DIR, + ); + expect(wrap(configWithReplacedProjectRoots)).toMatchSnapshot(); +}); + +test('should log only valid JSON config if setting up env throws an error', () => { + const restoreOriginalSetupEnvScript = createCorruptedSetupEnvScript(); + const {stdout, stderr} = runCLI(path.join(DIR, 'TestProject'), ['config']); + + restoreOriginalSetupEnvScript(); + expect(isValidJSON(stdout)).toBe(true); + expect(stderr).toBe(''); +}); diff --git a/jest.config.js b/jest.config.js index 09aa62018..f64bc3341 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,4 +1,7 @@ -const common = {testEnvironment: 'node'}; +const common = { + testEnvironment: 'node', + snapshotSerializers: [require.resolve('jest-snapshot-serializer-raw')], +}; module.exports = { projects: [ diff --git a/jest/__tests__/replaceProjectRootInOutput.test.ts b/jest/__tests__/replaceProjectRootInOutput.test.ts new file mode 100644 index 000000000..a2dc2fa27 --- /dev/null +++ b/jest/__tests__/replaceProjectRootInOutput.test.ts @@ -0,0 +1,14 @@ +import {replaceProjectRootInOutput} from '../helpers'; + +test('should replace project root in output with <> value', () => { + const cwd = '/var/folders/zt/917v0jxx6lg3p_zfh9s_02bm0000gn/T/'; + const output = `{ + "root": "/private${cwd}/test_root/TestProject", + }`; + const outputWithReplacedProjectRoot = `{ + "root": "<>/test_root/TestProject", + }`; + expect(replaceProjectRootInOutput(output, cwd)).toBe( + outputWithReplacedProjectRoot, + ); +}); diff --git a/jest/helpers.ts b/jest/helpers.ts index be514ec58..d949bd382 100644 --- a/jest/helpers.ts +++ b/jest/helpers.ts @@ -6,6 +6,7 @@ import {createDirectory} from 'jest-util'; import rimraf from 'rimraf'; import execa from 'execa'; import chalk from 'chalk'; +import slash from 'slash'; // @ts-ignore jsfile import {Writable} from 'readable-stream'; @@ -196,3 +197,8 @@ ${chalk.bold('stdout:')} ${result.stdout} ${chalk.bold('code:')} ${result.code}`); } } + +export function replaceProjectRootInOutput(output: string, testFolder: string) { + const regex = new RegExp(`(:\\s").*(${slash(testFolder)})`, 'g'); + return slash(output).replace(regex, '$1<>'); +} diff --git a/package.json b/package.json index 8b8569e99..7ff7877a4 100644 --- a/package.json +++ b/package.json @@ -47,11 +47,13 @@ "execa": "^1.0.0", "glob": "^7.1.3", "jest": "^25.2.4", + "jest-snapshot-serializer-raw": "^1.1.0", "lerna": "^3.18.4", "metro-memory-fs": "^0.58.0", "micromatch": "^3.1.10", "mkdirp": "^0.5.3", "rimraf": "^3.0.2", + "slash": "^3.0.0", "string-length": "^2.0.0", "typescript": "^3.8.0" }, diff --git a/packages/cli/src/index.ts b/packages/cli/src/index.ts index 0b18426af..88105662c 100644 --- a/packages/cli/src/index.ts +++ b/packages/cli/src/index.ts @@ -180,6 +180,13 @@ async function run() { async function setupAndRun() { // Commander is not available yet + + // when we run `config`, we don't want to output anything to the console. We + // expect it to return valid JSON + if (process.argv.includes('config')) { + logger.disable(); + } + logger.setVerbose(process.argv.includes('--verbose')); // We only have a setup script for UNIX envs currently @@ -206,12 +213,6 @@ async function setupAndRun() { } try { - // when we run `config`, we don't want to output anything to the console. We - // expect it to return valid JSON - if (process.argv.includes('config')) { - logger.disable(); - } - const ctx = loadConfig(); logger.enable(); diff --git a/yarn.lock b/yarn.lock index 7311e8d47..e62618995 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6861,6 +6861,11 @@ jest-serializer@^25.2.1: resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-25.2.1.tgz#51727a5fc04256f461abe0fa024a022ba165877a" integrity sha512-fibDi7M5ffx6c/P66IkvR4FKkjG5ldePAK1WlbNoaU4GZmIAkS9Le/frAwRUFEX0KdnisSPWf+b1RC5jU7EYJQ== +jest-snapshot-serializer-raw@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/jest-snapshot-serializer-raw/-/jest-snapshot-serializer-raw-1.1.0.tgz#1d7f09c02f3dbbc3ae70b5b7598fb2f45e37d6c8" + integrity sha512-OL3bXRCnSn7Kur3YTGYj+A3Hwh2eyb5QL5VLQ9OSsPBOva7r3sCB0Jf1rOT/KN3ypzH42hrkDz96lpbiMo+AlQ== + jest-snapshot@^25.1.0, jest-snapshot@^25.2.4: version "25.2.4" resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-25.2.4.tgz#08d4517579c864df4280bcc948ceea34327a4ded"