diff --git a/packages/cli/package.json b/packages/cli/package.json index 812ed4367..73d6275ce 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -49,6 +49,7 @@ "semver": "^5.0.3", "serve-static": "^1.13.1", "shell-quote": "1.6.1", + "slash": "^2.0.0", "ws": "^1.1.0", "xcode": "^1.0.0", "xmldoc": "^0.4.0" diff --git a/packages/cli/src/link/__tests__/android/makeSettingsPatch-test.js b/packages/cli/src/link/__tests__/android/makeSettingsPatch-test.js index e16adbbaf..404a5352d 100644 --- a/packages/cli/src/link/__tests__/android/makeSettingsPatch-test.js +++ b/packages/cli/src/link/__tests__/android/makeSettingsPatch-test.js @@ -4,78 +4,98 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @format - * @emails oncall+javascript_foundation + * @flow */ -const path = require('path'); const makeSettingsPatch = require('../../android/patches/makeSettingsPatch'); -const normalizeProjectName = require('../../android/patches/normalizeProjectName'); -const name = 'test'; -const scopedName = '@scoped/test'; -const normalizedScopedName = normalizeProjectName('@scoped/test'); const projectConfig = { sourceDir: '/home/project/android/app', settingsGradlePath: '/home/project/android/settings.gradle', }; -const dependencyConfig = { - sourceDir: `/home/project/node_modules/${name}/android`, -}; -const scopedDependencyConfig = { - sourceDir: `/home/project/node_modules/${scopedName}/android`, -}; -describe('makeSettingsPatch', () => { +describe('makeSettingsPatch with package "test"', () => { + const name = 'test'; + const dependencyConfig = { + sourceDir: `/home/project/node_modules/${name}/android`, + }; + it('should build a patch function', () => { expect( - Object.prototype.toString( - makeSettingsPatch(name, dependencyConfig, projectConfig) - ) - ).toBe('[object Object]'); + makeSettingsPatch(name, dependencyConfig, projectConfig) + ).toMatchObject({ + pattern: '\n', + patch: expect.any(String), + }); }); - it('should make a correct patch', () => { - const projectDir = path.relative( - path.dirname(projectConfig.settingsGradlePath), - dependencyConfig.sourceDir - ); - + it('includes project with correct path', () => { const { patch } = makeSettingsPatch(name, dependencyConfig, projectConfig); - expect(patch).toBe( - `include ':${name}'\n` + - `project(':${name}').projectDir = ` + - `new File(rootProject.projectDir, '${projectDir}')\n` + expect(patch).toMatchInlineSnapshot(` +"include ':test' +project(':test').projectDir = new File(rootProject.projectDir, '../node_modules/test/android') +" +`); + }); + + // Simulate Windows environment on POSIX filesystem + // TODO: scope this test to Windows-only once we setup CI on Windows + it('includes project with correct path on Windows', () => { + jest.resetModules(); + jest.doMock('path', () => { + const path = jest.requireActual('path'); + path.dirname = path.win32.dirname; + path.relative = path.win32.relative; + return path; + }); + // eslint-disable-next-line no-shadow + const makeSettingsPatch = require('../../android/patches/makeSettingsPatch'); + const projectConfigWindows = { + sourceDir: 'C:\\home\\project\\android\\app', + settingsGradlePath: 'C:\\home\\project\\android\\settings.gradle', + }; + const dependencyConfigWindows = { + sourceDir: `C:\\home\\project\\node_modules\\${name}\\android`, + }; + const { patch } = makeSettingsPatch( + name, + dependencyConfigWindows, + projectConfigWindows ); + + jest.dontMock('path'); + + expect(patch).toMatchInlineSnapshot(` +"include ':test' +project(':test').projectDir = new File(rootProject.projectDir, '../node_modules/test/android') +" +`); }); }); -describe('makeSettingsPatchWithScopedPackage', () => { +describe('makeSettingsPatch with scoped package "@scoped/test"', () => { + const name = '@scoped/test'; + const dependencyConfig = { + sourceDir: `/home/project/node_modules/${name}/android`, + }; + it('should build a patch function', () => { expect( - Object.prototype.toString( - makeSettingsPatch(scopedName, scopedDependencyConfig, projectConfig) - ) - ).toBe('[object Object]'); + makeSettingsPatch(name, dependencyConfig, projectConfig) + ).toMatchObject({ + pattern: '\n', + patch: expect.any(String), + }); }); - it('should make a correct patch', () => { - const projectDir = path.relative( - path.dirname(projectConfig.settingsGradlePath), - scopedDependencyConfig.sourceDir - ); - - const { patch } = makeSettingsPatch( - scopedName, - scopedDependencyConfig, - projectConfig - ); + it('includes project with correct path', () => { + const { patch } = makeSettingsPatch(name, dependencyConfig, projectConfig); - expect(patch).toBe( - `include ':${normalizedScopedName}'\n` + - `project(':${normalizedScopedName}').projectDir = ` + - `new File(rootProject.projectDir, '${projectDir}')\n` - ); + expect(patch).toMatchInlineSnapshot(` +"include ':@scoped_test' +project(':@scoped_test').projectDir = new File(rootProject.projectDir, '../node_modules/@scoped/test/android') +" +`); }); }); diff --git a/packages/cli/src/link/android/patches/makeSettingsPatch.js b/packages/cli/src/link/android/patches/makeSettingsPatch.js index 43fc36f56..081768d16 100644 --- a/packages/cli/src/link/android/patches/makeSettingsPatch.js +++ b/packages/cli/src/link/android/patches/makeSettingsPatch.js @@ -8,6 +8,7 @@ */ const path = require('path'); +const slash = require('slash'); const normalizeProjectName = require('./normalizeProjectName'); module.exports = function makeSettingsPatch( @@ -15,9 +16,12 @@ module.exports = function makeSettingsPatch( androidConfig, projectConfig ) { - const projectDir = path.relative( - path.dirname(projectConfig.settingsGradlePath), - androidConfig.sourceDir + // Gradle expects paths to be posix even on Windows + const projectDir = slash( + path.relative( + path.dirname(projectConfig.settingsGradlePath), + androidConfig.sourceDir + ) ); const normalizedProjectName = normalizeProjectName(name); diff --git a/yarn.lock b/yarn.lock index 51f2ef7c3..6a03f0429 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8192,6 +8192,7 @@ slash@^1.0.0: slash@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/slash/-/slash-2.0.0.tgz#de552851a1759df3a8f206535442f5ec4ddeab44" + integrity sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A== slice-ansi@1.0.0: version "1.0.0"