1import { fs } from 'memfs'; 2import path from 'path'; 3import temporary from 'tempy'; 4 5import * as GitIgnore from '../mergeGitIgnorePaths'; 6 7const testRoot = temporary.directory(); 8beforeAll(async () => { 9 await fs.promises.mkdir(testRoot, { recursive: true }); 10}); 11afterAll(async () => { 12 await fs.promises.rm(testRoot, { recursive: true, force: true }); 13}); 14 15const gitignore1 = ` 16# hello world 17*/foo 18 19ios/ 20 21/android 22## bar 23 24`; 25 26// A gitignore with an old generated section 27const gitignore2 = `a 28b 29${GitIgnore.createGeneratedHeaderComment('...')} 30foo 31bar 32${GitIgnore.generatedFooterComment} 33c 34d`; 35 36// A broken generated section 37const gitignore3 = `a 38b 39${GitIgnore.createGeneratedHeaderComment('...')} 40foo 41bar 42c 43d`; 44 45// Footer is before header 46const gitignore4 = `a 47b 48${GitIgnore.generatedFooterComment} 49foo 50bar 51${GitIgnore.createGeneratedHeaderComment('...')} 52c 53d`; 54 55it(`sanitizes comments, new lines, and sort order`, () => { 56 expect(GitIgnore.getSanitizedGitIgnoreLines(gitignore1)).toStrictEqual([ 57 '*/foo', 58 '/android ', 59 'ios/', 60 ]); 61}); 62 63describe('removeGeneratedGitIgnoreContents', () => { 64 it(`removes a generated gitignore`, () => { 65 expect(GitIgnore.removeGeneratedGitIgnoreContents(gitignore2)?.split('\n')).toStrictEqual([ 66 'a', 67 'b', 68 'c', 69 'd', 70 ]); 71 }); 72 it(`removes nothing from a regular gitignore`, () => { 73 expect(GitIgnore.removeGeneratedGitIgnoreContents(gitignore1)).toBe(null); 74 }); 75 it(`removes nothing when the generated footer is missing`, () => { 76 expect(GitIgnore.removeGeneratedGitIgnoreContents(gitignore3)).toBe(null); 77 }); 78 it(`removes nothing when the footer precede the header`, () => { 79 expect(GitIgnore.removeGeneratedGitIgnoreContents(gitignore4)).toBe(null); 80 }); 81}); 82 83describe('mergeGitIgnore', () => { 84 it(`skips merging if the target file is missing`, async () => { 85 // fs 86 const projectRoot = path.join(testRoot, 'merge-git-ignore-skip-when-target-missing'); 87 await fs.promises.mkdir(projectRoot, { recursive: true }); 88 // Setup 89 90 const targetGitIgnorePath = path.join(projectRoot, '.gitignore'); 91 // Skip writing a gitignore 92 93 const sourceGitIgnorePath = path.join(projectRoot, '.gitignore-other'); 94 await fs.promises.writeFile( 95 sourceGitIgnorePath, 96 [ 97 'alpha', 98 'beta', 99 // in the future we may want to merge this value with the existing matching value 100 // or maybe we could keep the code simple and not do that :] 101 'bar', 102 ].join('\n') 103 ); 104 105 expect(GitIgnore.mergeGitIgnorePaths(targetGitIgnorePath, sourceGitIgnorePath)).toBe(null); 106 expect(fs.existsSync(targetGitIgnorePath)).toBe(false); 107 }); 108 it(`merges two git ignore files in the filesystem`, async () => { 109 // fs 110 const projectRoot = path.join(testRoot, 'merge-git-ignore-works'); 111 await fs.promises.mkdir(projectRoot, { recursive: true }); 112 // Setup 113 const targetGitIgnorePath = path.join(projectRoot, '.gitignore'); 114 await fs.promises.writeFile( 115 targetGitIgnorePath, 116 [ 117 'foo', 118 // Test a duplicate value 119 'bar', 120 ].join('\n') 121 ); 122 123 const sourceGitIgnorePath = path.join(projectRoot, '.gitignore-other'); 124 await fs.promises.writeFile( 125 sourceGitIgnorePath, 126 [ 127 'alpha', 128 'beta', 129 // in the future we may want to merge this value with the existing matching value 130 // or maybe we could keep the code simple and not do that :] 131 'bar', 132 ].join('\n') 133 ); 134 135 const results = GitIgnore.mergeGitIgnorePaths(targetGitIgnorePath, sourceGitIgnorePath); 136 expect(results).not.toBe(null); 137 expect(results.contents).toMatch( 138 /generated expo-cli sync-69a5afdba5ff28bbd11618f94ae2dc4bfdfd7cae/ 139 ); 140 expect(results.contents).toMatch(/foo/); 141 expect(results.contents).toMatch(/alpha/); 142 expect(results.didMerge).toBe(true); 143 144 expect(fs.readFileSync(targetGitIgnorePath, 'utf8')).toBe(results.contents); 145 }); 146}); 147