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