Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/npm/cli.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRuy Adorno <ruyadorno@hotmail.com>2020-07-30 01:11:43 +0300
committerisaacs <i@izs.me>2020-08-04 07:18:27 +0300
commit68a16d6dbc796f8f527bc28643a111c3ca2a9b1d (patch)
tree509efbc3af70dc3be50e31bcf462fffeebccb10d /test/lib/fund.js
parent5473bbda76fd0fbb3d8321c19bc045c71c06a44c (diff)
chore: refactor fund tests to test/lib
Refactored `npm fund` tests to use new `test/lib/` unit tests structure. ref: npm/statusboard#151 PR-URL: https://github.com/npm/cli/pull/1582 Credit: @ruyadorno Close: #1582 Reviewed-by: @isaacs
Diffstat (limited to 'test/lib/fund.js')
-rw-r--r--test/lib/fund.js729
1 files changed, 729 insertions, 0 deletions
diff --git a/test/lib/fund.js b/test/lib/fund.js
new file mode 100644
index 000000000..cd9ac97ff
--- /dev/null
+++ b/test/lib/fund.js
@@ -0,0 +1,729 @@
+'use strict'
+
+const { test } = require('tap')
+const requireInject = require('require-inject')
+
+const version = '1.0.0'
+const funding = {
+ type: 'individual',
+ url: 'http://example.com/donate'
+}
+
+const maintainerOwnsAllDeps = {
+ 'package.json': JSON.stringify({
+ name: 'maintainer-owns-all-deps',
+ version,
+ funding,
+ dependencies: {
+ 'dep-foo': '*',
+ 'dep-bar': '*'
+ }
+ }),
+ node_modules: {
+ 'dep-foo': {
+ 'package.json': JSON.stringify({
+ name: 'dep-foo',
+ version,
+ funding,
+ dependencies: {
+ 'dep-sub-foo': '*'
+ }
+ }),
+ node_modules: {
+ 'dep-sub-foo': {
+ 'package.json': JSON.stringify({
+ name: 'dep-sub-foo',
+ version,
+ funding
+ })
+ }
+ }
+ },
+ 'dep-bar': {
+ 'package.json': JSON.stringify({
+ name: 'dep-bar',
+ version,
+ funding
+ })
+ }
+ }
+}
+
+const nestedNoFundingPackages = {
+ 'package.json': JSON.stringify({
+ name: 'nested-no-funding-packages',
+ version,
+ dependencies: {
+ foo: '*'
+ },
+ devDependencies: {
+ lorem: '*'
+ }
+ }),
+ node_modules: {
+ foo: {
+ 'package.json': JSON.stringify({
+ name: 'foo',
+ version,
+ dependencies: {
+ bar: '*'
+ }
+ }),
+ node_modules: {
+ bar: {
+ 'package.json': JSON.stringify({
+ name: 'bar',
+ version,
+ funding
+ }),
+ node_modules: {
+ 'sub-bar': {
+ 'package.json': JSON.stringify({
+ name: 'sub-bar',
+ version,
+ funding: 'https://example.com/sponsor'
+ })
+ }
+ }
+ }
+ }
+ },
+ lorem: {
+ 'package.json': JSON.stringify({
+ name: 'lorem',
+ version,
+ funding: {
+ url: 'https://example.com/lorem'
+ }
+ })
+ }
+ }
+}
+
+const nestedMultipleFundingPackages = {
+ 'package.json': JSON.stringify({
+ name: 'nested-multiple-funding-packages',
+ version,
+ funding: [
+ 'https://one.example.com',
+ 'https://two.example.com'
+ ],
+ dependencies: {
+ foo: '*'
+ },
+ devDependencies: {
+ bar: '*'
+ }
+ }),
+ node_modules: {
+ foo: {
+ 'package.json': JSON.stringify({
+ name: 'foo',
+ version,
+ funding: [
+ 'http://example.com',
+ { url: 'http://sponsors.example.com/me' },
+ 'http://collective.example.com'
+ ]
+ })
+ },
+ bar: {
+ 'package.json': JSON.stringify({
+ name: 'bar',
+ version,
+ funding: [
+ 'http://collective.example.com',
+ { url: 'http://sponsors.example.com/you' }
+ ]
+ })
+ }
+ }
+}
+
+const conflictingFundingPackages = {
+ 'package.json': JSON.stringify({
+ name: 'conflicting-funding-packages',
+ version,
+ dependencies: {
+ foo: '1.0.0'
+ },
+ devDependencies: {
+ bar: '1.0.0'
+ }
+ }),
+ node_modules: {
+ foo: {
+ 'package.json': JSON.stringify({
+ name: 'foo',
+ version: '1.0.0',
+ funding: 'http://example.com/1'
+ })
+ },
+ bar: {
+ node_modules: {
+ foo: {
+ 'package.json': JSON.stringify({
+ name: 'foo',
+ version: '2.0.0',
+ funding: 'http://example.com/2'
+ })
+ }
+ },
+ 'package.json': JSON.stringify({
+ name: 'bar',
+ version: '1.0.0',
+ dependencies: {
+ foo: '2.0.0'
+ }
+ })
+ }
+ }
+}
+
+let result = ''
+let printUrl = ''
+const _flatOptions = {
+ json: false,
+ global: false,
+ prefix: undefined,
+ unicode: false,
+ which: undefined
+}
+let openUrl = (url, msg, cb) => {
+ if (url === 'http://npmjs.org') {
+ cb(new Error('ERROR'))
+ return
+ }
+ if (_flatOptions.json) {
+ printUrl = JSON.stringify({
+ title: msg,
+ url: url
+ })
+ } else {
+ printUrl = `${msg}:\n ${url}`
+ }
+ cb()
+}
+const fund = requireInject('../../lib/fund.js', {
+ '../../lib/npm.js': {
+ flatOptions: _flatOptions,
+ get prefix () { return _flatOptions.prefix }
+ },
+ '../../lib/utils/open-url.js': openUrl,
+ '../../lib/utils/output.js': msg => { result += msg + '\n' },
+ 'pacote': {
+ manifest: (arg) => arg.name === 'ntl'
+ ? Promise.resolve({
+ funding: 'http://example.com/pacote'
+ })
+ : Promise.reject(new Error('ERROR'))
+ }
+})
+
+
+test('fund with no package containing funding', t => {
+ _flatOptions.prefix = t.testdir({
+ 'package.json': JSON.stringify({
+ name: 'no-funding-package',
+ version: '0.0.0'
+ })
+ })
+
+ fund([], (err) => {
+ t.ifError(err, 'should not error out')
+ t.matchSnapshot(result, 'should print empty funding info')
+ result = ''
+ t.end()
+ })
+})
+
+test('fund in which same maintainer owns all its deps', t => {
+ _flatOptions.prefix = t.testdir(maintainerOwnsAllDeps)
+
+ fund([], (err) => {
+ t.ifError(err, 'should not error out')
+ t.matchSnapshot(result, 'should print stack packages together')
+ result = ''
+ t.end()
+ })
+})
+
+test('fund in which same maintainer owns all its deps, using --json option', t => {
+ _flatOptions.json = true
+ _flatOptions.prefix = t.testdir(maintainerOwnsAllDeps)
+
+ fund([], (err) => {
+ t.ifError(err, 'should not error out')
+ t.deepEqual(
+ JSON.parse(result),
+ {
+ length: 3,
+ name: 'maintainer-owns-all-deps',
+ version: '1.0.0',
+ funding: { type: 'individual', url: 'http://example.com/donate' },
+ dependencies: {
+ 'dep-bar': {
+ version: '1.0.0',
+ funding: { type: 'individual', url: 'http://example.com/donate' }
+ },
+ 'dep-foo': {
+ version: '1.0.0',
+ funding: { type: 'individual', url: 'http://example.com/donate' },
+ dependencies: {
+ 'dep-sub-foo': {
+ version: '1.0.0',
+ funding: { type: 'individual', url: 'http://example.com/donate' }
+ }
+ }
+ }
+ }
+ },
+ 'should print stack packages together'
+ )
+
+ result = ''
+ _flatOptions.json = false
+ t.end()
+ })
+})
+
+test('fund containing multi-level nested deps with no funding', t => {
+ _flatOptions.prefix = t.testdir(nestedNoFundingPackages)
+
+ fund([], (err) => {
+ t.ifError(err, 'should not error out')
+ t.matchSnapshot(
+ result,
+ 'should omit dependencies with no funding declared'
+ )
+
+ result = ''
+ t.end()
+ })
+})
+
+test('fund containing multi-level nested deps with no funding, using --json option', t => {
+ _flatOptions.prefix = t.testdir(nestedNoFundingPackages)
+ _flatOptions.json = true
+
+ fund([], (err) => {
+ t.ifError(err, 'should not error out')
+ t.deepEqual(
+ JSON.parse(result),
+ {
+ length: 2,
+ name: 'nested-no-funding-packages',
+ version: '1.0.0',
+ dependencies: {
+ lorem: {
+ version: '1.0.0',
+ funding: { url: 'https://example.com/lorem' }
+ },
+ bar: {
+ version: '1.0.0',
+ funding: { type: 'individual', url: 'http://example.com/donate' }
+ }
+ }
+ },
+ 'should omit dependencies with no funding declared in json output'
+ )
+
+ result = ''
+ _flatOptions.json = false
+ t.end()
+ })
+})
+
+test('fund containing multi-level nested deps with no funding, using --json option', t => {
+ _flatOptions.prefix = t.testdir(nestedMultipleFundingPackages)
+ _flatOptions.json = true
+
+ fund([], (err) => {
+ t.ifError(err, 'should not error out')
+ t.deepEqual(
+ JSON.parse(result),
+ {
+ length: 2,
+ name: 'nested-multiple-funding-packages',
+ version: '1.0.0',
+ funding: [
+ {
+ url: 'https://one.example.com'
+ },
+ {
+ url: 'https://two.example.com'
+ }
+ ],
+ dependencies: {
+ bar: {
+ version: '1.0.0',
+ funding: [
+ {
+ url: 'http://collective.example.com'
+ },
+ {
+ url: 'http://sponsors.example.com/you'
+ }
+ ]
+ },
+ foo: {
+ version: '1.0.0',
+ funding: [
+ {
+ url: 'http://example.com'
+ },
+ {
+ url: 'http://sponsors.example.com/me'
+ },
+ {
+ url: 'http://collective.example.com'
+ }
+ ]
+ }
+ }
+ },
+ 'should list multiple funding entries in json output'
+ )
+
+ result = ''
+ _flatOptions.json = false
+ t.end()
+ })
+})
+
+test('fund does not support global', t => {
+ _flatOptions.prefix = t.testdir({})
+ _flatOptions.global = true
+
+ fund([], (err) => {
+ t.match(err.code, 'EFUNDGLOBAL', 'should throw EFUNDGLOBAL error')
+
+ result = ''
+ _flatOptions.global = false
+ t.end()
+ })
+})
+
+test('fund using package argument', t => {
+ _flatOptions.prefix = t.testdir(maintainerOwnsAllDeps)
+
+ fund(['.'], (err) => {
+ t.ifError(err, 'should not error out')
+ t.matchSnapshot(printUrl, 'should open funding url')
+
+ printUrl = ''
+ t.end()
+ })
+})
+
+test('fund does not support global, using --json option', t => {
+ _flatOptions.prefix = t.testdir({})
+ _flatOptions.global = true
+ _flatOptions.json = true
+
+ fund([], (err) => {
+ t.equal(err.code, 'EFUNDGLOBAL', 'should use EFUNDGLOBAL error code')
+ t.equal(
+ err.message,
+ '`npm fund` does not support global packages',
+ 'should use expected error msg'
+ )
+
+ _flatOptions.global = false
+ _flatOptions.json = false
+ t.end()
+ })
+})
+
+test('fund using string shorthand', t => {
+ _flatOptions.prefix = t.testdir({
+ 'package.json': JSON.stringify({
+ name: 'funding-string-shorthand',
+ version: '0.0.0',
+ funding: 'https://example.com/sponsor'
+ })
+ })
+
+ fund(['.'], (err) => {
+ t.ifError(err, 'should not error out')
+ t.matchSnapshot(printUrl, 'should open string-only url')
+
+ printUrl = ''
+ t.end()
+ })
+})
+
+test('fund using nested packages with multiple sources', t => {
+ _flatOptions.prefix = t.testdir(nestedMultipleFundingPackages)
+
+ fund(['.'], (err) => {
+ t.ifError(err, 'should not error out')
+ t.matchSnapshot(result, 'should prompt with all available URLs')
+
+ result = ''
+ t.end()
+ })
+})
+
+test('fund using symlink ref', t => {
+ _flatOptions.prefix = t.testdir({
+ 'package.json': JSON.stringify({
+ name: 'using-symlink-ref',
+ version: '1.0.0'
+ }),
+ 'a': {
+ 'package.json': JSON.stringify({
+ name: 'a',
+ version: '1.0.0',
+ funding: 'http://example.com/a'
+ })
+ },
+ node_modules: {
+ a: t.fixture('symlink', '../a')
+ }
+ })
+
+ // using symlinked ref
+ fund(['./node_modules/a'], (err) => {
+ t.ifError(err, 'should not error out')
+ t.match(
+ printUrl,
+ 'http://example.com/a',
+ 'should retrieve funding url from symlink'
+ )
+
+ printUrl = ''
+
+ // using target ref
+ fund(['./a'], (err) => {
+ t.match(
+ printUrl,
+ 'http://example.com/a',
+ 'should retrieve funding url from symlink target'
+ )
+
+ printUrl = ''
+ result = ''
+ t.end()
+ })
+ })
+})
+
+test('fund using data from actual tree', t => {
+ _flatOptions.prefix = t.testdir({
+ 'package.json': JSON.stringify({
+ name: 'using-actual-tree',
+ version: '1.0.0'
+ }),
+ node_modules: {
+ a: {
+ 'package.json': JSON.stringify({
+ name: 'a',
+ version: '1.0.0',
+ funding: 'http://example.com/a'
+ })
+ },
+ b: {
+ 'package.json': JSON.stringify({
+ name: 'a',
+ version: '1.0.0',
+ funding: 'http://example.com/b'
+ }),
+ node_modules: {
+ a: {
+ 'package.json': JSON.stringify({
+ name: 'a',
+ version: '1.0.1',
+ funding: 'http://example.com/_AAA'
+ })
+ }
+ }
+ }
+ }
+ })
+
+ // using symlinked ref
+ fund(['a'], (err) => {
+ t.ifError(err, 'should not error out')
+ t.match(
+ printUrl,
+ 'http://example.com/_AAA',
+ 'should retrieve fund info from actual tree, using greatest version found'
+ )
+
+ printUrl = ''
+ t.end()
+ })
+})
+
+test('fund using nested packages with multiple sources, with a source number', t => {
+ _flatOptions.prefix = t.testdir(nestedMultipleFundingPackages)
+ _flatOptions.which = '1'
+
+ fund(['.'], (err) => {
+ t.ifError(err, 'should not error out')
+ t.matchSnapshot(printUrl, 'should open the numbered URL')
+
+ _flatOptions.which = undefined
+ printUrl = ''
+ t.end()
+ })
+})
+
+test('fund using pkg name while having conflicting versions', t => {
+ _flatOptions.prefix = t.testdir(conflictingFundingPackages)
+ _flatOptions.which = '1'
+
+ fund(['foo'], (err) => {
+ t.ifError(err, 'should not error out')
+ t.matchSnapshot(printUrl, 'should open greatest version')
+
+ printUrl = ''
+ t.end()
+ })
+})
+
+test('fund using package argument with no browser, using --json option', t => {
+ _flatOptions.prefix = t.testdir(maintainerOwnsAllDeps)
+ _flatOptions.json = true
+
+ fund(['.'], (err) => {
+ t.ifError(err, 'should not error out')
+ t.deepEqual(
+ JSON.parse(printUrl),
+ {
+ title: 'individual funding available at the following URL',
+ url: 'http://example.com/donate'
+ },
+ 'should open funding url using json output'
+ )
+
+ _flatOptions.json = false
+ printUrl = ''
+ t.end()
+ })
+})
+
+test('fund using package info fetch from registry', t => {
+ _flatOptions.prefix = t.testdir({})
+
+ fund(['ntl'], (err) => {
+ t.ifError(err, 'should not error out')
+ t.match(
+ printUrl,
+ /http:\/\/example.com\/pacote/,
+ 'should open funding url that was loaded from registry manifest'
+ )
+
+ printUrl = ''
+ t.end()
+ })
+})
+
+test('fund tries to use package info fetch from registry but registry has nothing', t => {
+ _flatOptions.prefix = t.testdir({})
+
+ fund(['foo'], (err) => {
+ t.equal(err.code, 'ENOFUND', 'should have ENOFUND error code')
+ t.equal(
+ err.message,
+ 'No valid funding method available for: foo',
+ 'should have no valid funding message'
+ )
+
+ printUrl = ''
+ t.end()
+ })
+})
+
+test('fund but target module has no funding info', t => {
+ _flatOptions.prefix = t.testdir(nestedNoFundingPackages)
+
+ fund(['foo'], (err) => {
+ t.equal(err.code, 'ENOFUND', 'should have ENOFUND error code')
+ t.equal(
+ err.message,
+ 'No valid funding method available for: foo',
+ 'should have no valid funding message'
+ )
+
+ result = ''
+ t.end()
+ })
+})
+
+test('fund using bad which value', t => {
+ _flatOptions.prefix = t.testdir(nestedMultipleFundingPackages)
+ _flatOptions.which = 3
+
+ fund(['bar'], (err) => {
+ t.equal(err.code, 'EFUNDNUMBER', 'should have EFUNDNUMBER error code')
+ t.equal(
+ err.message,
+ '`npm fund [<@scope>/]<pkg> [--which=fundingSourceNumber]` must be given a positive integer',
+ 'should have bad which option error message'
+ )
+
+ _flatOptions.which = undefined
+ result = ''
+ t.end()
+ })
+})
+
+test('fund pkg missing version number', t => {
+ _flatOptions.prefix = t.testdir({
+ 'package.json': JSON.stringify({
+ name: 'foo',
+ funding: 'http://example.com/foo'
+ })
+ })
+
+ fund([], (err) => {
+ t.ifError(err, 'should not error out')
+ t.matchSnapshot(result, 'should print name only')
+ result = ''
+ t.end()
+ })
+})
+
+test('fund a package throws on openUrl', t => {
+ _flatOptions.prefix = t.testdir({
+ 'package.json': JSON.stringify({
+ name: 'foo',
+ version: '1.0.0',
+ funding: 'http://npmjs.org'
+ })
+ })
+
+ fund(['.'], (err) => {
+ t.equal(err.message, 'ERROR', 'should throw unknown error')
+ result = ''
+ t.end()
+ })
+})
+
+test('fund a package with type and multiple sources', t => {
+ _flatOptions.prefix = t.testdir({
+ 'package.json': JSON.stringify({
+ name: 'foo',
+ funding: [
+ {
+ type: 'Foo',
+ url: 'http://example.com/foo'
+ },
+ {
+ type: 'Lorem',
+ url: 'http://example.com/foo-lorem'
+ }
+ ]
+ })
+ })
+
+ fund(['.'], (err) => {
+ t.ifError(err, 'should not error out')
+ t.matchSnapshot(result, 'should print prompt select message')
+
+ result = ''
+ t.end()
+ })
+})