• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1'use strict'
2var test = require('tap').test
3var common = require('../common-tap.js')
4var path = require('path')
5var rimraf = require('rimraf')
6var mkdirp = require('mkdirp')
7var fs = require('graceful-fs')
8var tar = require('tar')
9var basepath = common.pkg
10var fixturepath = path.resolve(basepath, 'npm-test-files')
11var targetpath = path.resolve(basepath, 'target')
12var Tacks = require('tacks')
13var File = Tacks.File
14var Dir = Tacks.Dir
15
16test('basic file inclusion', function (t) {
17  var fixture = new Tacks(
18    Dir({
19      'package.json': File({
20        name: 'npm-test-files',
21        version: '1.2.5',
22        files: [
23          'include',
24          'sub/include'
25        ]
26      }),
27      include: File(''),
28      sub: Dir({ include: File('') }),
29      notincluded: File('')
30    })
31  )
32  withFixture(t, fixture, function (done) {
33    t.ok(fileExists('include'), 'toplevel file included')
34    t.ok(fileExists('sub/include'), 'nested file included')
35    t.notOk(fileExists('notincluded'), 'unspecified file not included')
36    done()
37  })
38})
39
40test('basic file exclusion', function (t) {
41  var fixture = new Tacks(
42    Dir({
43      'package.json': File({
44        name: 'npm-test-files',
45        version: '1.2.5'
46      }),
47      '.npmignore': File(
48        'ignore\n' +
49        'sub/ignore\n'
50      ),
51      include: File(''),
52      ignore: File(''),
53      sub: Dir({ ignore: File('') })
54    })
55  )
56  withFixture(t, fixture, function (done) {
57    t.notOk(fileExists('ignore'), 'toplevel file excluded')
58    t.notOk(fileExists('sub/ignore'), 'nested file excluded')
59    t.ok(fileExists('include'), 'unignored file included')
60    done()
61  })
62})
63
64test('toplevel-only and blanket ignores', function (t) {
65  var fixture = new Tacks(
66    Dir({
67      'package.json': File({
68        name: 'npm-test-files',
69        version: '1.2.5'
70      }),
71      '.npmignore': File(
72        './shallow1\n' +
73        '/shallow2\n' +
74        '/sub/onelevel\n' +
75        'deep\n' +
76        ''
77      ),
78      shallow1: File(''),
79      shallow2: File(''),
80      deep: File(''),
81      sub: Dir({
82        shallow1: File(''),
83        shallow2: File(''),
84        onelevel: File(''),
85        deep: File(''),
86        sub: Dir({
87          deep: File(''),
88          onelevel: File('')
89        })
90      })
91    })
92  )
93  withFixture(t, fixture, function (done) {
94    t.notOk(fileExists('shallow2'), '/ file excluded')
95    t.ok(fileExists('sub/shallow1'), 'nested ./ file included')
96    t.ok(fileExists('sub/shallow2'), 'nested / file included')
97    t.ok(fileExists('sub/sub/onelevel'), 'double-nested file included')
98    t.notOk(fileExists('sub/onelevel'), 'nested / file excluded')
99    t.notOk(fileExists('deep'), 'deep file excluded')
100    t.notOk(fileExists('sub/deep'), 'nested deep file excluded')
101    t.notOk(fileExists('sub/sub/deep'), 'double-nested deep file excluded')
102    t.ok(fileExists('shallow1'), './ file included')
103    done()
104  })
105})
106
107test('.npmignore works for nested directories recursively', function (t) {
108  var fixture = new Tacks(
109    Dir({
110      'package.json': File({
111        name: 'npm-test-files',
112        version: '1.2.5'
113      }),
114      '.npmignore': File(
115        '/ignore\n' +
116        'deep\n'
117      ),
118      include: File(''),
119      ignore: File(''),
120      deep: File(''),
121      sub: Dir({
122        ignore: File(''),
123        include: File(''),
124        deep: File(''),
125        sub: Dir({
126          '.npmignore': File(
127            '/ignore\n'
128          ),
129          ignore: File(''),
130          include: File(''),
131          deep: File('')
132        })
133      })
134    })
135  )
136  withFixture(t, fixture, function (done) {
137    t.notOk(fileExists('ignore'), 'toplevel file excluded')
138    t.ok(fileExists('include'), 'unignored file included')
139    t.ok(fileExists('sub/ignore'), 'same-name file in nested dir included')
140    t.ok(fileExists('sub/include'), 'unignored nested dir file included')
141    t.notOk(fileExists('sub/sub/ignore'), 'sub-sub-directory file excluded')
142    t.ok(fileExists('sub/sub/include'), 'sub-sube-directory file included')
143    t.notOk(fileExists('deep'), 'deep file excluded')
144    t.notOk(fileExists('sub/deep'), 'sub-dir deep file excluded')
145    t.notOk(fileExists('sub/sub/deep'), 'sub-sub-dir deep file excluded')
146    done()
147  })
148})
149
150test('.gitignore should have identical semantics', function (t) {
151  var fixture = new Tacks(
152    Dir({
153      'package.json': File({
154        name: 'npm-test-files',
155        version: '1.2.5'
156      }),
157      '.gitignore': File(
158        './shallow1\n' +
159        '/shallow2\n' +
160        '/sub/onelevel\n' +
161        'deep\n' +
162        ''
163      ),
164      shallow1: File(''),
165      shallow2: File(''),
166      deep: File(''),
167      sub: Dir({
168        shallow1: File(''),
169        shallow2: File(''),
170        onelevel: File(''),
171        deep: File(''),
172        sub: Dir({
173          deep: File(''),
174          onelevel: File('')
175        })
176      })
177    })
178  )
179  withFixture(t, fixture, function (done) {
180    t.notOk(fileExists('shallow2'), '/ file excluded')
181    t.ok(fileExists('sub/shallow1'), 'nested ./ file included')
182    t.ok(fileExists('sub/shallow2'), 'nested / file included')
183    t.ok(fileExists('sub/sub/onelevel'), 'double-nested file included')
184    t.notOk(fileExists('sub/onelevel'), 'nested / file excluded')
185    t.notOk(fileExists('deep'), 'deep file excluded')
186    t.notOk(fileExists('sub/deep'), 'nested deep file excluded')
187    t.notOk(fileExists('sub/sub/deep'), 'double-nested deep file excluded')
188    t.ok(fileExists('shallow1'), './ file included')
189    done()
190  })
191})
192
193test('.npmignore should always be overridden by files array', function (t) {
194  var fixture = new Tacks(
195    Dir({
196      'package.json': File({
197        name: 'npm-test-files',
198        version: '1.2.5',
199        files: [
200          'include',
201          'sub'
202        ]
203      }),
204      '.npmignore': File(
205        'include\n' +
206        'ignore\n' +
207        'sub/included\n'
208      ),
209      include: File(''),
210      ignore: File(''),
211      sub: Dir({
212        included: File('')
213      })
214    })
215  )
216  withFixture(t, fixture, function (done) {
217    t.notOk(fileExists('ignore'), 'toplevel file excluded')
218    t.ok(fileExists('include'), 'unignored file included')
219    t.ok(fileExists('sub/included'), 'nested file included')
220    done()
221  })
222})
223
224test('.gitignore supported for ignores', function (t) {
225  var fixture = new Tacks(
226    Dir({
227      'package.json': File({
228        name: 'npm-test-files',
229        version: '1.2.5'
230      }),
231      '.gitignore': File(
232        'ignore\n' +
233        'sub/ignore\n'
234      ),
235      include: File(''),
236      ignore: File(''),
237      sub: Dir({ ignore: File('') })
238    })
239  )
240  withFixture(t, fixture, function (done) {
241    t.notOk(fileExists('ignore'), 'toplevel file excluded')
242    t.notOk(fileExists('sub/ignore'), 'nested file excluded')
243    t.ok(fileExists('include'), 'unignored file included')
244    done()
245  })
246})
247
248test('.npmignore completely overrides .gitignore', function (t) {
249  var fixture = new Tacks(
250    Dir({
251      'package.json': File({
252        name: 'npm-test-files',
253        version: '1.2.5'
254      }),
255      '.npmignore': File(
256        'ignore\n' +
257        'sub/ignore\n'
258      ),
259      '.gitignore': File(
260        'include\n' +
261        'sub/include\n' +
262        'extra\n'
263      ),
264      include: File(''),
265      sub: Dir({ include: File('') }),
266      extra: File('')
267    })
268  )
269  withFixture(t, fixture, function (done) {
270    t.ok(fileExists('include'), 'gitignored toplevel file included')
271    t.ok(fileExists('extra'), 'gitignored extra toplevel file included')
272    t.ok(fileExists('sub/include'), 'gitignored nested file included')
273    t.notOk(fileExists('ignore'), 'toplevel file excluded')
274    t.notOk(fileExists('sub/ignore'), 'nested file excluded')
275    done()
276  })
277})
278
279test('files array overrides .npmignore', function (t) {
280  var fixture = new Tacks(
281    Dir({
282      'package.json': File({
283        name: 'npm-test-files',
284        version: '1.2.5',
285        files: [
286          'include',
287          'sub/include'
288        ]
289      }),
290      '.npmignore': File(
291        'include\n' +
292        'sub/include\n'
293      ),
294      include: File(''),
295      sub: Dir({ include: File('') })
296    })
297  )
298  withFixture(t, fixture, function (done) {
299    t.ok(fileExists('include'), 'toplevel file included')
300    t.ok(fileExists('sub/include'), 'nested file included')
301    done()
302  })
303})
304
305test('includes files regardless of emptiness', function (t) {
306  var fixture = new Tacks(
307    Dir({
308      'package.json': File({
309        name: 'npm-test-files',
310        version: '1.2.5',
311        files: [
312          'full',
313          'empty'
314        ]
315      }),
316      full: File('This file has contents~'),
317      empty: File('')
318    })
319  )
320  withFixture(t, fixture, function (done) {
321    t.ok(fileExists('full'), 'contentful file included')
322    t.ok(fileExists('empty'), 'empty file included')
323    done()
324  })
325})
326
327test('.npmignore itself gets included', function (t) {
328  var fixture = new Tacks(
329    Dir({
330      'package.json': File({
331        name: 'npm-test-files',
332        version: '1.2.5',
333        files: [
334          '.npmignore'
335        ]
336      }),
337      '.npmignore': File('')
338    })
339  )
340  withFixture(t, fixture, function (done) {
341    t.ok(fileExists('.npmignore'), '.npmignore included')
342    done()
343  })
344})
345
346test('include default files when missing files spec', function (t) {
347  var fixture = new Tacks(
348    Dir({
349      'package.json': File({
350        name: 'npm-test-files',
351        version: '1.2.5'
352      }),
353      'index.js': File(''),
354      foo: File(''),
355      node_modules: Dir({foo: Dir({bar: File('')})})
356    })
357  )
358  withFixture(t, fixture, function (done) {
359    t.ok(fileExists('index.js'), 'index.js included')
360    t.ok(fileExists('foo'), 'foo included')
361    t.notOk(fileExists('node_modules'), 'node_modules not included')
362    done()
363  })
364})
365
366test('include main file', function (t) {
367  var fixture = new Tacks(
368    Dir({
369      'package.json': File({
370        name: 'npm-test-files',
371        version: '1.2.5',
372        main: 'foo.js',
373        files: []
374      }),
375      'index.js': File(''),
376      'foo.js': File('')
377    })
378  )
379  withFixture(t, fixture, function (done) {
380    t.ok(fileExists('foo.js'), 'foo.js included because of main')
381    t.notOk(fileExists('index.js'), 'index.js not included')
382    done()
383  })
384})
385
386test('certain files ignored by default', function (t) {
387  var fixture = new Tacks(
388    Dir({
389      'package.json': File({
390        name: 'npm-test-files',
391        version: '1.2.5'
392      }),
393      '.git': Dir({foo: File('')}),
394      '.svn': Dir({foo: File('')}),
395      'CVS': Dir({foo: File('')}),
396      '.hg': Dir({foo: File('')}),
397      '.lock-wscript': File(''),
398      '.wafpickle-0': File(''),
399      '.wafpickle-5': File(''),
400      '.wafpickle-50': File(''),
401      'build': Dir({'config.gypi': File('')}),
402      'npm-debug.log': File(''),
403      '.npmrc': File(''),
404      '.foo.swp': File(''),
405      'core': Dir({core: File(''), foo: File('')}),
406      '.DS_Store': Dir({foo: File('')}),
407      '._ohno': File(''),
408      '._ohnoes': Dir({noes: File('')}),
409      'foo.orig': File(''),
410      'package-lock.json': File('')
411    })
412  )
413  withFixture(t, fixture, function (done) {
414    t.notOk(fileExists('.git'), '.git not included')
415    t.notOk(fileExists('.svn'), '.svn not included')
416    t.notOk(fileExists('CVS'), 'CVS not included')
417    t.notOk(fileExists('.hg'), '.hg not included')
418    t.notOk(fileExists('.lock-wscript'), '.lock-wscript not included')
419    t.notOk(fileExists('.wafpickle-0'), '.wafpickle-0 not included')
420    t.notOk(fileExists('.wafpickle-5'), '.wafpickle-5 not included')
421    t.notOk(fileExists('.wafpickle-50'), '.wafpickle-50 not included')
422    t.notOk(fileExists('build/config.gypi'), 'build/config.gypi not included')
423    t.notOk(fileExists('npm-debug.log'), 'npm-debug.log not included')
424    t.notOk(fileExists('.npmrc'), '.npmrc not included')
425    t.notOk(fileExists('.foo.swp'), '.foo.swp not included')
426    t.ok(fileExists('core'), 'core/ included')
427    t.ok(fileExists('core/foo'), 'core/foo included')
428    t.notOk(fileExists('core/core'), 'core/core not included')
429    t.notOk(fileExists('.DS_Store'), '.DS_Store not included')
430    t.notOk(fileExists('.DS_Store/foo'), '.DS_Store/foo not included')
431    t.notOk(fileExists('._ohno'), '._ohno not included')
432    t.notOk(fileExists('._ohnoes'), '._ohnoes not included')
433    t.notOk(fileExists('foo.orig'), 'foo.orig not included')
434    t.notOk(fileExists('package-lock.json'), 'package-lock.json not included')
435    done()
436  })
437})
438
439test('default-ignored files can be explicitly included', function (t) {
440  var fixture = new Tacks(
441    Dir({
442      'package.json': File({
443        name: 'npm-test-files',
444        version: '1.2.5',
445        files: [
446          '.git',
447          '.svn',
448          'CVS',
449          '.hg',
450          '.lock-wscript',
451          '.wafpickle-0',
452          '.wafpickle-5',
453          '.wafpickle-50',
454          'build/config.gypi',
455          'npm-debug.log',
456          '.npmrc',
457          '.foo.swp',
458          'core',
459          '.DS_Store',
460          '._ohno',
461          '._ohnoes',
462          'foo.orig',
463          'package-lock.json'
464        ]
465      }),
466      '.git': Dir({foo: File('')}),
467      '.svn': Dir({foo: File('')}),
468      'CVS': Dir({foo: File('')}),
469      '.hg': Dir({foo: File('')}),
470      '.lock-wscript': File(''),
471      '.wafpickle-0': File(''),
472      '.wafpickle-5': File(''),
473      '.wafpickle-50': File(''),
474      'build': Dir({'config.gypi': File('')}),
475      'npm-debug.log': File(''),
476      '.npmrc': File(''),
477      '.foo.swp': File(''),
478      'core': Dir({core: File(''), foo: File('')}),
479      '.DS_Store': Dir({foo: File('')}),
480      '._ohno': File(''),
481      '._ohnoes': Dir({noes: File('')}),
482      'foo.orig': File(''),
483      'package-lock.json': File('')
484    })
485  )
486  withFixture(t, fixture, function (done) {
487    t.notOk(fileExists('.git'), '.git should never be included')
488    t.ok(fileExists('.svn'), '.svn included')
489    t.ok(fileExists('CVS'), 'CVS included')
490    t.ok(fileExists('.hg'), '.hg included')
491    t.ok(fileExists('.lock-wscript'), '.lock-wscript included')
492    t.ok(fileExists('.wafpickle-0'), '.wafpickle-0 included')
493    t.ok(fileExists('.wafpickle-5'), '.wafpickle-5 included')
494    t.ok(fileExists('.wafpickle-50'), '.wafpickle-50 included')
495    t.ok(fileExists('build/config.gypi'), 'build/config.gypi included')
496    t.ok(fileExists('npm-debug.log'), 'npm-debug.log included')
497    t.ok(fileExists('.npmrc'), '.npmrc included')
498    t.ok(fileExists('.foo.swp'), '.foo.swp included')
499    t.ok(fileExists('core'), 'core/ included')
500    t.ok(fileExists('core/foo'), 'core/foo included')
501    t.ok(fileExists('core/core'), 'core/core included')
502    t.ok(fileExists('.DS_Store'), '.DS_Store included')
503    t.ok(fileExists('._ohno'), '._ohno included')
504    t.ok(fileExists('._ohnoes'), '._ohnoes included')
505    t.ok(fileExists('foo.orig'), 'foo.orig included')
506    t.ok(fileExists('package-lock.json'), 'package-lock.json included')
507    done()
508  })
509})
510
511test('certain files included unconditionally', function (t) {
512  var fixture = new Tacks(
513    Dir({
514      'package.json': File({
515        name: 'npm-test-files',
516        version: '1.2.5'
517      }),
518      '.npmignore': File(
519        'package.json',
520        'README',
521        'Readme',
522        'readme.md',
523        'readme.randomext',
524        'changelog',
525        'CHAngelog',
526        'ChangeLOG.txt',
527        'history',
528        'HistorY',
529        'HistorY.md',
530        'license',
531        'licence',
532        'LICENSE',
533        'LICENCE'
534      ),
535      'README': File(''),
536      'Readme': File(''),
537      'readme.md': File(''),
538      'readme.randomext': File(''),
539      'changelog': File(''),
540      'CHAngelog': File(''),
541      'ChangeLOG.txt': File(''),
542      'history': File(''),
543      'HistorY': File(''),
544      'HistorY.md': File(''),
545      'license': File(''),
546      'licence': File(''),
547      'LICENSE': File(''),
548      'LICENCE': File('')
549    })
550  )
551  withFixture(t, fixture, function (done) {
552    t.ok(fileExists('package.json'), 'package.json included')
553    t.ok(fileExists('README'), 'README included')
554    t.ok(fileExists('Readme'), 'Readme included')
555    t.ok(fileExists('readme.md'), 'readme.md included')
556    t.ok(fileExists('readme.randomext'), 'readme.randomext included')
557    t.ok(fileExists('changelog'), 'changelog included')
558    t.ok(fileExists('CHAngelog'), 'CHAngelog included')
559    t.ok(fileExists('ChangeLOG.txt'), 'ChangeLOG.txt included')
560    t.ok(fileExists('license'), 'license included')
561    t.ok(fileExists('licence'), 'licence included')
562    t.ok(fileExists('LICENSE'), 'LICENSE included')
563    t.ok(fileExists('LICENCE'), 'LICENCE included')
564    done()
565  })
566})
567
568test('unconditional inclusion does not capture modules', function (t) {
569  var fixture = new Tacks(
570    Dir({
571      'package.json': File({
572        name: 'npm-test-files',
573        version: '1.2.5'
574      }),
575      'node_modules': Dir({
576        'readme': Dir({ 'file': File('') }),
577        'README': Dir({ 'file': File('') }),
578        'licence': Dir({ 'file': File('') }),
579        'license': Dir({ 'file': File('') }),
580        'history': Dir({ 'file': File('') }),
581        'History': Dir({ 'file': File('') }),
582        'changelog': Dir({ 'file': File('') }),
583        'ChangeLOG': Dir({ 'file': File('') })
584      })
585    })
586  )
587  withFixture(t, fixture, function (done) {
588    t.notOk(fileExists('node_modules/readme/file'), 'readme module not included')
589    t.notOk(fileExists('node_modules/README/file'), 'README module not included')
590    t.notOk(fileExists('node_modules/licence/file'), 'licence module not included')
591    t.notOk(fileExists('node_modules/license/file'), 'license module not included')
592    t.notOk(fileExists('node_modules/history/file'), 'history module not included')
593    t.notOk(fileExists('node_modules/History/file'), 'History module not included')
594    t.notOk(fileExists('node_modules/changelog/file'), 'changelog module not included')
595    t.notOk(fileExists('node_modules/ChangeLOG/file'), 'ChangeLOG module not included')
596
597    done()
598  })
599})
600
601test('folder-based inclusion works', function (t) {
602  var fixture = new Tacks(
603    Dir({
604      'package.json': File({
605        name: 'npm-test-files',
606        version: '1.2.5',
607        files: [
608          'sub1/sub',
609          'sub2'
610        ]
611      }),
612      sub1: Dir({
613        sub: Dir({
614          include1: File(''),
615          include2: File('')
616        }),
617        ignored: File('')
618      }),
619      sub2: Dir({
620        include1: File(''),
621        include2: File(''),
622        empty: Dir({})
623      })
624    })
625  )
626  withFixture(t, fixture, function (done) {
627    t.ok(fileExists('sub1/sub/include1'), 'nested dir included')
628    t.ok(fileExists('sub1/sub/include2'), 'nested dir included')
629    t.notOk(fileExists('sub1/ignored'), 'unspecified file not included')
630
631    t.ok(fileExists('sub2/include1'), 'dir contents included')
632    t.ok(fileExists('sub2/include2'), 'dir contents included')
633    t.notOk(fileExists('sub2/empty'), 'empty dir not included')
634
635    done()
636  })
637})
638
639test('file that starts with @ sign included normally', (t) => {
640  const fixture = new Tacks(
641    Dir({
642      'package.json': File({
643        name: 'npm-test-files',
644        version: '1.2.5'
645      }),
646      '@sub1': Dir({
647        sub: Dir({
648          include1: File('')
649        })
650      }),
651      sub2: Dir({
652        '@include': File(''),
653        '@sub3': Dir({
654          include1: File('')
655        })
656      })
657    })
658  )
659  withFixture(t, fixture, function (done) {
660    t.ok(fileExists('@sub1/sub/include1'), '@ dir included')
661
662    t.ok(fileExists('sub2/@include'), '@ file included')
663    t.ok(fileExists('sub2/@sub3/include1'), 'nested @ dir included')
664
665    done()
666  })
667})
668
669function fileExists (file) {
670  try {
671    return !!fs.statSync(path.resolve(targetpath, 'package', file))
672  } catch (_) {
673    return false
674  }
675}
676
677function withFixture (t, fixture, tester) {
678  fixture.create(fixturepath)
679  mkdirp.sync(targetpath)
680  common.npm(['pack', fixturepath], {cwd: basepath}, extractAndCheck)
681  function extractAndCheck (err, code) {
682    if (err) throw err
683    t.is(code, 0, 'pack went ok')
684    extractTarball(checkTests)
685  }
686  function checkTests (err) {
687    if (err) throw err
688    tester(removeAndDone)
689  }
690  function removeAndDone (err) {
691    if (err) throw err
692    fixture.remove(fixturepath)
693    rimraf.sync(basepath)
694    t.done()
695  }
696}
697
698function extractTarball (cb) {
699  // Unpack to disk so case-insensitive filesystems are consistent
700  tar.extract({
701    file: basepath + '/npm-test-files-1.2.5.tgz',
702    cwd: targetpath,
703    sync: true
704  })
705
706  cb()
707}
708