UNPKG

react-native-integrate

Version:

Automate integration of additional code into React Native projects

467 lines (466 loc) 19.4 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); /* eslint-disable @typescript-eslint/no-unsafe-call */ const { mockFs, writeMockAppDelegate, writeMockLock, } = require('../mocks/mockAll'); const mockSpawn = jest.spyOn(require('child_process'), 'spawn'); const mockRunTask = jest.spyOn(require('../../utils/runTask'), 'runTask'); const mockParseConfig = jest.spyOn(require('../../utils/parseConfig'), 'parseConfig'); const path_1 = __importDefault(require("path")); const constants_1 = require("../../constants"); const integrate_1 = require("../../integrate"); const options_1 = require("../../options"); const mockAll_1 = require("../mocks/mockAll"); describe('integrate', () => { beforeEach(() => { mockSpawn.mockImplementationOnce(() => ({ on: (_event, cb) => { cb(0); }, stdout: { on: (_event, cb) => { cb('stdout'); }, }, stderr: { on: (_event, cb) => { cb('stderr'); }, }, })); }); it('should not run tasks when lock does not exist (first run)', async () => { const spinner = mockAll_1.mockPrompter.spinner(); spinner.stop.mockReset(); const appDelegatePath = writeMockAppDelegate(); await (0, integrate_1.integrate)(); const content = mockFs.readFileSync(appDelegatePath); expect(content).not.toContain('[FIRApp configure];'); expect(spinner.stop).toHaveBeenCalledWith(expect.stringContaining('first run')); }); it('should run tasks when lock exists', async () => { const lockPath = writeMockLock({ lockfileVersion: constants_1.Constants.CURRENT_LOCK_VERSION, packages: {}, }); const appDelegatePath = writeMockAppDelegate(); await (0, integrate_1.integrate)(); const content = mockFs.readFileSync(appDelegatePath); expect(content).toContain('[FIRApp configure];'); const lockContent = mockFs.readFileSync(lockPath); const lockData = JSON.parse(lockContent); expect(lockData.packages['mock-package']).toEqual({ version: '^1.2.3', integrated: true, }); }); it('should run tasks for a package when lock does not exist', async () => { const lockPath = path_1.default.resolve(__dirname, `../mock-project/${constants_1.Constants.LOCK_FILE_NAME}`); const appDelegatePath = writeMockAppDelegate(); await (0, integrate_1.integrate)('mock-package'); const content = mockFs.readFileSync(appDelegatePath); expect(content).toContain('[FIRApp configure];'); const lockContent = mockFs.readFileSync(lockPath); const lockData = JSON.parse(lockContent); expect(lockData.packages['mock-package']).toEqual({ version: '^1.2.3', integrated: true, }); }); it('should run tasks for a package when lock exist', async () => { const lockPath = writeMockLock({ lockfileVersion: constants_1.Constants.CURRENT_LOCK_VERSION, packages: {}, }); const appDelegatePath = writeMockAppDelegate(); await (0, integrate_1.integrate)('mock-package'); const content = mockFs.readFileSync(appDelegatePath); expect(content).toContain('[FIRApp configure];'); const lockContent = mockFs.readFileSync(lockPath); const lockData = JSON.parse(lockContent); expect(lockData.packages['mock-package']).toEqual({ version: '^1.2.3', integrated: true, }); }); it('should handle package that doesnt exist', async () => { const appDelegatePath = writeMockAppDelegate(); await (0, integrate_1.integrate)('random-package'); const content = mockFs.readFileSync(appDelegatePath); expect(content).not.toContain('[FIRApp configure];'); }); it('should handle package that doesnt have config', async () => { (0, mockAll_1.writeMockProject)({ name: 'mock-project', version: '0.0.0', description: 'Mock project', dependencies: { 'mock-package-fail': '^1.2.3', }, }); const appDelegatePath = writeMockAppDelegate(); await (0, integrate_1.integrate)('mock-package-fail'); const content = mockFs.readFileSync(appDelegatePath); expect(content).not.toContain('[FIRApp configure];'); }); it('should handle deleted packages', async () => { (0, mockAll_1.writeMockProject)({ name: 'mock-project', version: '0.0.0', description: 'Mock project', dependencies: {}, }); const lockPath = writeMockLock({ lockfileVersion: constants_1.Constants.CURRENT_LOCK_VERSION, packages: { 'deleted-package': { version: '1.2.3', integrated: true, }, }, }); await (0, integrate_1.integrate)(); const content = mockFs.readFileSync(lockPath); const lockData = JSON.parse(content); expect(lockData.packages).toEqual({}); }); it('should handle no changes', async () => { (0, mockAll_1.writeMockProject)({ name: 'mock-project', version: '0.0.0', description: 'Mock project', dependencies: { 'mock-package': '^1.2.3', }, }); const lockPath = writeMockLock({ lockfileVersion: constants_1.Constants.CURRENT_LOCK_VERSION, packages: { 'mock-package': { version: '1.2.3', integrated: true, }, }, }); await (0, integrate_1.integrate)(); const content = mockFs.readFileSync(lockPath); const lockData = JSON.parse(content); expect(lockData.packages['mock-package']).toEqual({ version: '1.2.3', integrated: true, }); }); it('should handle packages with no config', async () => { (0, mockAll_1.writeMockProject)({ name: 'mock-project', version: '0.0.0', description: 'Mock project', dependencies: { 'mock-package-fail': '^1.2.3', }, }); const lockPath = writeMockLock({ lockfileVersion: constants_1.Constants.CURRENT_LOCK_VERSION, packages: {}, }); await (0, integrate_1.integrate)(); const content = mockFs.readFileSync(lockPath); const lockData = JSON.parse(content); // console.log('mockFs',mockFs.getStore()); expect(lockData.packages['mock-package']).toEqual(undefined); }); it('should handle user rejecting to integrate', async () => { options_1.options.get().interactive = true; mockAll_1.mockPrompter.confirm.mockImplementationOnce(() => false); mockAll_1.mockPrompter.log.step.mockReset(); const lockPath = writeMockLock({ lockfileVersion: constants_1.Constants.CURRENT_LOCK_VERSION, packages: {}, }); await (0, integrate_1.integrate)(); const content = mockFs.readFileSync(lockPath); expect(mockAll_1.mockPrompter.log.step).toHaveBeenCalledWith(expect.stringContaining('skipped package integration')); expect(content).not.toContain('[FIRApp configure];'); }); it('should handle task errors', async () => { mockRunTask.mockImplementationOnce(() => { throw new Error('test error'); }); mockAll_1.mockPrompter.log.error.mockReset(); const lockPath = writeMockLock({ lockfileVersion: constants_1.Constants.CURRENT_LOCK_VERSION, packages: {}, }); await (0, integrate_1.integrate)(); const content = mockFs.readFileSync(lockPath); expect(mockAll_1.mockPrompter.log.error).toHaveBeenCalledWith(expect.stringContaining('test error')); expect(content).not.toContain('[FIRApp configure];'); }); it('should handle parse error', async () => { mockParseConfig.mockImplementationOnce(() => { throw new Error('test error'); }); mockAll_1.mockPrompter.log.error.mockReset(); const lockPath = writeMockLock({ lockfileVersion: constants_1.Constants.CURRENT_LOCK_VERSION, packages: {}, }); await (0, integrate_1.integrate)(); const content = mockFs.readFileSync(lockPath); expect(mockAll_1.mockPrompter.log.error).toHaveBeenCalledWith(expect.stringContaining('test error')); expect(content).not.toContain('[FIRApp configure];'); }); it('should add dependencies to integration queue', async () => { (0, mockAll_1.writeMockProject)({ name: 'mock-project', version: '0.0.0', description: 'Mock project', dependencies: { 'mock-package-with-deps': '^1.2.3', 'react-native': '^0.0.0', 'dep-package': '^1.2.3', 'dep-package-2': '^1.2.3', }, }); const appDelegatePath = writeMockAppDelegate(); writeMockLock({ lockfileVersion: constants_1.Constants.CURRENT_LOCK_VERSION, packages: {}, }); let content = mockFs.readFileSync(appDelegatePath); expect(content).not.toContain('[FIRApp configure];'); await (0, integrate_1.integrate)(); content = mockFs.readFileSync(appDelegatePath); expect(content).toContain('[FIRApp configure];'); expect(content).toContain('// with-deps'); }); it('should skip dependencies when already integrated', async () => { (0, mockAll_1.writeMockProject)({ name: 'mock-project', version: '0.0.0', description: 'Mock project', dependencies: { 'mock-package-with-deps': '^1.2.3', 'react-native': '^0.0.0', 'dep-package': '^1.2.3', 'dep-package-2': '^1.2.3', }, }); const appDelegatePath = writeMockAppDelegate(); writeMockLock({ lockfileVersion: constants_1.Constants.CURRENT_LOCK_VERSION, packages: { 'dep-package': { version: '1.2.3', integrated: true, }, 'dep-package-2': { version: '1.2.3', integrated: true, }, }, }); let content = mockFs.readFileSync(appDelegatePath); expect(content).not.toContain('[FIRApp configure];'); await (0, integrate_1.integrate)(); content = mockFs.readFileSync(appDelegatePath); expect(content).not.toContain('[FIRApp configure];'); expect(content).toContain('// with-deps'); }); it('should add installed but non integrated dependencies to integration queue', async () => { (0, mockAll_1.writeMockProject)({ name: 'mock-project', version: '0.0.0', description: 'Mock project', dependencies: { 'mock-package-with-deps': '^1.2.3', 'react-native': '^0.0.0', 'dep-package': '^1.2.3', 'dep-package-2': '^1.2.3', }, }); const appDelegatePath = writeMockAppDelegate(); writeMockLock({ lockfileVersion: constants_1.Constants.CURRENT_LOCK_VERSION, packages: { 'dep-package': { version: '1.2.3', integrated: false, }, 'dep-package-2': { version: '1.2.3', integrated: false, }, }, }); mockAll_1.mockPrompter.log.info.mockClear(); await (0, integrate_1.integrate)(); const content = mockFs.readFileSync(appDelegatePath); expect(content).toContain('[FIRApp configure];'); expect(content).toContain('// with-deps'); expect(mockAll_1.mockPrompter.log.info).toHaveBeenCalledWith(expect.stringContaining('has dependencies that require integration')); }); it('should warn and exit when dependencies is not installed', async () => { (0, mockAll_1.writeMockProject)({ name: 'mock-project', version: '0.0.0', description: 'Mock project', dependencies: { 'mock-package-with-deps': '^1.2.3', 'react-native': '^0.0.0', }, }); writeMockLock({ lockfileVersion: constants_1.Constants.CURRENT_LOCK_VERSION, packages: {}, }); mockAll_1.mockPrompter.log.warning.mockClear(); await (0, integrate_1.integrate)(); expect(mockAll_1.mockPrompter.log.warning).toHaveBeenCalledWith(expect.stringContaining('please install it first and try again')); }); it('should warn and exit when minimum rn version is not installed', async () => { (0, mockAll_1.writeMockProject)({ name: 'mock-project', version: '0.0.0', description: 'Mock project', dependencies: { 'mock-package-with-min-rn': '^1.2.3', }, }); writeMockLock({ lockfileVersion: constants_1.Constants.CURRENT_LOCK_VERSION, packages: {}, }); mockAll_1.mockPrompter.log.warning.mockClear(); await (0, integrate_1.integrate)(); expect(mockAll_1.mockPrompter.log.warning).toHaveBeenCalledWith(expect.stringContaining('React Native not installed')); }); it('should warn and exit when minimum rn version is less than installed one', async () => { (0, mockAll_1.writeMockProject)({ name: 'mock-project', version: '0.0.0', description: 'Mock project', dependencies: { 'mock-package-with-min-rn': '^1.2.3', 'react-native': '^0.0.0', }, }); writeMockLock({ lockfileVersion: constants_1.Constants.CURRENT_LOCK_VERSION, packages: {}, }); mockAll_1.mockPrompter.log.warning.mockClear(); await (0, integrate_1.integrate)(); expect(mockAll_1.mockPrompter.log.warning).toHaveBeenCalledWith(expect.stringContaining('requires React Native')); }); it('should not warn and exit when minimum rn version is higher than installed one', async () => { (0, mockAll_1.writeMockProject)({ name: 'mock-project', version: '0.0.0', description: 'Mock project', dependencies: { 'mock-package-with-min-rn': '^1.2.3', 'react-native': '^1.0.0', }, }); writeMockLock({ lockfileVersion: constants_1.Constants.CURRENT_LOCK_VERSION, packages: {}, }); mockAll_1.mockPrompter.log.warning.mockClear(); await (0, integrate_1.integrate)(); expect(mockAll_1.mockPrompter.log.warning).not.toHaveBeenCalledWith(expect.stringContaining('requires React Native')); }); it('should not warn and exit when minimum rn version is invalid', async () => { (0, mockAll_1.writeMockProject)({ name: 'mock-project', version: '0.0.0', description: 'Mock project', dependencies: { 'mock-package-with-invalid-min-rn': '^1.2.3', 'react-native': '^1.2.3', }, }); writeMockLock({ lockfileVersion: constants_1.Constants.CURRENT_LOCK_VERSION, packages: {}, }); mockAll_1.mockPrompter.log.warning.mockClear(); await (0, integrate_1.integrate)(); expect(mockAll_1.mockPrompter.log.warning).not.toHaveBeenCalledWith(expect.stringContaining('requires React Native')); }); it('should not warn and exit when rn version is invalid', async () => { (0, mockAll_1.writeMockProject)({ name: 'mock-project', version: '0.0.0', description: 'Mock project', dependencies: { 'mock-package-with-min-rn': '^1.2.3', 'react-native': '^invalid', }, }); writeMockLock({ lockfileVersion: constants_1.Constants.CURRENT_LOCK_VERSION, packages: {}, }); mockAll_1.mockPrompter.log.warning.mockClear(); await (0, integrate_1.integrate)(); expect(mockAll_1.mockPrompter.log.warning).not.toHaveBeenCalledWith(expect.stringContaining('requires React Native')); }); it('should warn and exit when minimum package version is not installed', async () => { (0, mockAll_1.writeMockProject)({ name: 'mock-project', version: '0.0.0', description: 'Mock project', dependencies: { 'mock-package-with-min-v': '^0.0.0', 'react-native': '^0.0.0', }, }); writeMockLock({ lockfileVersion: constants_1.Constants.CURRENT_LOCK_VERSION, packages: {}, }); mockAll_1.mockPrompter.log.warning.mockClear(); await (0, integrate_1.integrate)(); expect(mockAll_1.mockPrompter.log.warning).toHaveBeenCalledWith(expect.stringContaining('requires version')); }); it('should not warn and exit when minimum package version is higher than installed one', async () => { (0, mockAll_1.writeMockProject)({ name: 'mock-project', version: '0.0.0', description: 'Mock project', dependencies: { 'mock-package-with-min-v': '^1.2.3', 'react-native': '^0.0.0', }, }); writeMockLock({ lockfileVersion: constants_1.Constants.CURRENT_LOCK_VERSION, packages: {}, }); mockAll_1.mockPrompter.log.warning.mockClear(); await (0, integrate_1.integrate)(); expect(mockAll_1.mockPrompter.log.warning).not.toHaveBeenCalledWith(expect.stringContaining('requires React Native')); }); it('should not warn and exit when minimum package version is invalid', async () => { (0, mockAll_1.writeMockProject)({ name: 'mock-project', version: '0.0.0', description: 'Mock project', dependencies: { 'mock-package-with-invalid-min-v': '^invalid', 'react-native': '^0.0.0', }, }); writeMockLock({ lockfileVersion: constants_1.Constants.CURRENT_LOCK_VERSION, packages: {}, }); mockAll_1.mockPrompter.log.warning.mockClear(); await (0, integrate_1.integrate)(); expect(mockAll_1.mockPrompter.log.warning).not.toHaveBeenCalledWith(expect.stringContaining('requires React Native')); }); });