Skip to content

Commit edbd884

Browse files
committed
chore: remove mocks from npm audit tests
1 parent ef2a8a3 commit edbd884

File tree

3 files changed

+215
-111
lines changed

3 files changed

+215
-111
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/* IMPORTANT
2+
* This snapshot file is auto-generated, but designed for humans.
3+
* It should be checked into source control and tracked carefully.
4+
* Re-generate by setting TAP_SNAPSHOT=1 and running tests.
5+
* Make sure to inspect the output below. Do not ignore changes!
6+
*/
7+
'use strict'
8+
exports[`test/lib/commands/audit.js TAP audit fix > must match snapshot 1`] = `
9+
10+
added 1 package, and audited 2 packages in 120ms
11+
12+
found 0 vulnerabilities
13+
`
14+
15+
exports[`test/lib/commands/audit.js TAP json audit > must match snapshot 1`] = `
16+
{
17+
"auditReportVersion": 2,
18+
"vulnerabilities": {
19+
"test-dep-a": {
20+
"name": "test-dep-a",
21+
"severity": "high",
22+
"isDirect": true,
23+
"via": [
24+
{
25+
"source": 100,
26+
"name": "test-dep-a",
27+
"dependency": "test-dep-a",
28+
"title": "Test advisory 100",
29+
"url": "https://github.com/advisories/GHSA-100",
30+
"severity": "high",
31+
"range": "*"
32+
}
33+
],
34+
"effects": [],
35+
"range": "*",
36+
"nodes": [
37+
"node_modules/test-dep-a"
38+
],
39+
"fixAvailable": false
40+
}
41+
},
42+
"metadata": {
43+
"vulnerabilities": {
44+
"info": 0,
45+
"low": 0,
46+
"moderate": 0,
47+
"high": 1,
48+
"critical": 0,
49+
"total": 1
50+
},
51+
"dependencies": {
52+
"prod": 2,
53+
"dev": 0,
54+
"optional": 0,
55+
"peer": 0,
56+
"peerOptional": 0,
57+
"total": 1
58+
}
59+
}
60+
}
61+
`
62+
63+
exports[`test/lib/commands/audit.js TAP normal audit > must match snapshot 1`] = `
64+
# npm audit report
65+
66+
test-dep-a *
67+
Severity: high
68+
Test advisory 100 - https://github.com/advisories/GHSA-100
69+
No fix available
70+
node_modules/test-dep-a
71+
72+
1 high severity vulnerability
73+
74+
Some issues need review, and may require choosing
75+
a different dependency.
76+
`

test/fixtures/mock-registry.js

+20-1
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,24 @@ class MockRegistry {
4444
this.nock.get('/-/whoami').reply(200, { username })
4545
}
4646

47+
advisory (advisory = {}) {
48+
const id = advisory.id || parseInt(Math.random() * 1000000)
49+
return {
50+
id,
51+
url: `https://github.com/advisories/GHSA-${id}`,
52+
title: `Test advisory ${id}`,
53+
severity: 'high',
54+
vulnerable_versions: '*',
55+
cwe: [
56+
'cwe-0',
57+
],
58+
cvss: {
59+
score: 0,
60+
},
61+
...advisory,
62+
}
63+
}
64+
4765
async package ({ manifest, times = 1, query, tarballs }) {
4866
let nock = this.nock
4967
nock = nock.get(`/${manifest.name}`).times(times)
@@ -52,7 +70,8 @@ class MockRegistry {
5270
}
5371
nock = nock.reply(200, manifest)
5472
if (tarballs) {
55-
for (const version in manifest.versions) {
73+
for (const version in tarballs) {
74+
// for (const version in manifest.versions) {
5675
const packument = manifest.versions[version]
5776
const dist = new URL(packument.dist.tarball)
5877
const tarball = await pacote.tarball(tarballs[version])

test/lib/commands/audit.js

+119-110
Original file line numberDiff line numberDiff line change
@@ -1,139 +1,148 @@
11
const t = require('tap')
2-
const { load: _loadMockNpm } = require('../../fixtures/mock-npm')
32

4-
t.test('should audit using Arborist', async t => {
5-
let ARB_ARGS = null
6-
let AUDIT_CALLED = false
7-
let REIFY_FINISH_CALLED = false
8-
let AUDIT_REPORT_CALLED = false
9-
let ARB_OBJ = null
3+
const { load: loadMockNpm } = require('../../fixtures/mock-npm')
4+
const MockRegistry = require('../../fixtures/mock-registry.js')
5+
const util = require('util')
6+
const zlib = require('zlib')
7+
const gzip = util.promisify(zlib.gzip)
8+
const path = require('path')
109

11-
const loadMockNpm = (t) => _loadMockNpm(t, {
12-
mocks: {
13-
'npm-audit-report': () => {
14-
AUDIT_REPORT_CALLED = true
15-
return {
16-
report: 'there are vulnerabilities',
17-
exitCode: 0,
18-
}
10+
const tree = {
11+
'package.json': JSON.stringify({
12+
name: 'test-dep',
13+
version: '1.0.0',
14+
dependencies: {
15+
'test-dep-a': '*',
16+
},
17+
}),
18+
'package-lock.json': JSON.stringify({
19+
name: 'test-dep',
20+
version: '1.0.0',
21+
lockfileVersion: 2,
22+
requires: true,
23+
packages: {
24+
'': {
25+
xname: 'scratch',
26+
version: '1.0.0',
27+
dependencies: {
28+
'test-dep-a': '*',
29+
},
30+
devDependencies: {},
1931
},
20-
'@npmcli/arborist': function (args) {
21-
ARB_ARGS = args
22-
ARB_OBJ = this
23-
this.audit = () => {
24-
AUDIT_CALLED = true
25-
this.auditReport = {}
26-
}
32+
'node_modules/test-dep-a': {
33+
name: 'test-dep-a',
34+
version: '1.0.0',
2735
},
28-
'../../lib/utils/reify-finish.js': (npm, arb) => {
29-
if (arb !== ARB_OBJ) {
30-
throw new Error('got wrong object passed to reify-output')
31-
}
32-
33-
REIFY_FINISH_CALLED = true
36+
},
37+
dependencies: {
38+
'test-dep-a': {
39+
version: '1.0.0',
3440
},
3541
},
36-
})
42+
}),
43+
'test-dep-a': {
44+
'package.json': JSON.stringify({
45+
name: 'test-dep-a',
46+
version: '1.0.1',
47+
}),
48+
'fixed.txt': 'fixed test-dep-a',
49+
},
50+
}
3751

38-
t.test('audit', async t => {
39-
const { npm, outputs } = await loadMockNpm(t)
40-
await npm.exec('audit', [])
41-
t.match(ARB_ARGS, { audit: true, path: npm.prefix })
42-
t.equal(AUDIT_CALLED, true, 'called audit')
43-
t.equal(AUDIT_REPORT_CALLED, true, 'called audit report')
44-
t.match(outputs, [['there are vulnerabilities']])
52+
t.test('normal audit', async t => {
53+
const { npm, joinedOutput } = await loadMockNpm(t, {
54+
prefixDir: tree,
55+
})
56+
const registry = new MockRegistry({
57+
tap: t,
58+
registry: npm.config.get('registry'),
4559
})
4660

47-
t.test('audit fix', async t => {
48-
const { npm } = await loadMockNpm(t)
49-
await npm.exec('audit', ['fix'])
50-
t.equal(REIFY_FINISH_CALLED, true, 'called reify output')
61+
const manifest = registry.manifest({
62+
name: 'test-dep-a',
63+
packuments: [{ version: '1.0.0' }, { version: '1.0.1' }],
5164
})
65+
await registry.package({ manifest })
66+
const advisory = registry.advisory({ id: 100 })
67+
const bulkBody = await gzip(JSON.stringify({ 'test-dep-a': ['1.0.0'] }))
68+
registry.nock.post('/-/npm/v1/security/advisories/bulk', bulkBody)
69+
.reply(200, {
70+
'test-dep-a': [advisory],
71+
})
72+
73+
await npm.exec('audit', [])
74+
t.ok(process.exitCode, 'would have exited uncleanly')
75+
process.exitCode = 0
76+
t.matchSnapshot(joinedOutput())
5277
})
5378

54-
t.test('should audit - json', async t => {
55-
t.plan(1)
56-
const { npm } = await _loadMockNpm(t, {
57-
mocks: {
58-
'npm-audit-report': (_, opts) => {
59-
t.match(opts.reporter, 'json')
60-
return {
61-
report: 'there are vulnerabilities',
62-
exitCode: 0,
63-
}
64-
},
65-
'@npmcli/arborist': function () {
66-
this.audit = () => {
67-
this.auditReport = {}
68-
}
69-
},
70-
'../../lib/utils/reify-output.js': () => {},
71-
},
79+
t.test('json audit', async t => {
80+
const { npm, joinedOutput } = await loadMockNpm(t, {
81+
prefixDir: tree,
7282
config: {
7383
json: true,
7484
},
7585
})
86+
const registry = new MockRegistry({
87+
tap: t,
88+
registry: npm.config.get('registry'),
89+
})
90+
91+
const manifest = registry.manifest({
92+
name: 'test-dep-a',
93+
packuments: [{ version: '1.0.0' }, { version: '1.0.1' }],
94+
})
95+
await registry.package({ manifest })
96+
const advisory = registry.advisory({ id: 100 })
97+
const bulkBody = await gzip(JSON.stringify({ 'test-dep-a': ['1.0.0'] }))
98+
registry.nock.post('/-/npm/v1/security/advisories/bulk', bulkBody)
99+
.reply(200, {
100+
'test-dep-a': [advisory],
101+
})
102+
76103
await npm.exec('audit', [])
104+
t.ok(process.exitCode, 'would have exited uncleanly')
105+
process.exitCode = 0
106+
t.matchSnapshot(joinedOutput())
77107
})
78108

79-
t.test('report endpoint error', async t => {
80-
const loadMockNpm = (t, options) => _loadMockNpm(t, {
81-
mocks: {
82-
'npm-audit-report': () => {
83-
throw new Error('should not call audit report when there are errors')
84-
},
85-
'@npmcli/arborist': function () {
86-
this.audit = () => {
87-
this.auditReport = {
88-
error: {
89-
message: 'hello, this didnt work',
90-
method: 'POST',
91-
uri: 'https://example.com/',
92-
headers: {
93-
head: ['ers'],
94-
},
95-
statusCode: 420,
96-
body: 'this is a string',
97-
},
98-
}
99-
}
100-
},
101-
'../../lib/utils/reify-output.js': () => {},
102-
},
103-
...options,
109+
t.test('audit fix', async t => {
110+
const { npm, joinedOutput } = await loadMockNpm(t, {
111+
prefixDir: tree,
104112
})
105-
106-
t.test('json=false', async t => {
107-
const { npm, outputs, logs } = await loadMockNpm(t, { config: { json: false } })
108-
await t.rejects(npm.exec('audit', []), 'audit endpoint returned an error')
109-
t.match(logs.warn, [['audit', 'hello, this didnt work']])
110-
t.strictSame(outputs, [['this is a string']])
113+
const registry = new MockRegistry({
114+
tap: t,
115+
registry: npm.config.get('registry'),
111116
})
112-
113-
t.test('json=true', async t => {
114-
const { npm, outputs, logs } = await loadMockNpm(t, { config: { json: true } })
115-
await t.rejects(npm.exec('audit', []), 'audit endpoint returned an error')
116-
t.match(logs.warn, [['audit', 'hello, this didnt work']])
117-
t.strictSame(outputs, [[
118-
'{\n' +
119-
' "message": "hello, this didnt work",\n' +
120-
' "method": "POST",\n' +
121-
' "uri": "https://example.com/",\n' +
122-
' "headers": {\n' +
123-
' "head": [\n' +
124-
' "ers"\n' +
125-
' ]\n' +
126-
' },\n' +
127-
' "statusCode": 420,\n' +
128-
' "body": "this is a string"\n' +
129-
'}',
130-
],
131-
])
117+
// with fix
118+
const manifest = registry.manifest({
119+
name: 'test-dep-a',
120+
packuments: [{ version: '1.0.0' }, { version: '1.0.1' }],
121+
})
122+
await registry.package({
123+
manifest,
124+
tarballs: {
125+
'1.0.1': path.join(npm.prefix, 'test-dep-a'),
126+
},
132127
})
128+
const advisory = registry.advisory({ id: 100, vulnerable_versions: '1.0.0' })
129+
// Can't validate this request body because it changes with each node
130+
// version/npm version and nock's body validation is not async, while
131+
// zlib.gunzip is
132+
registry.nock.post('/-/npm/v1/security/advisories/bulk')
133+
.reply(200, { // first audit
134+
'test-dep-a': [advisory],
135+
})
136+
.post('/-/npm/v1/security/advisories/bulk')
137+
.reply(200, { // after fix
138+
'test-dep-a': [advisory],
139+
})
140+
await npm.exec('audit', ['fix'])
141+
t.matchSnapshot(joinedOutput())
133142
})
134143

135144
t.test('completion', async t => {
136-
const { npm } = await _loadMockNpm(t)
145+
const { npm } = await loadMockNpm(t)
137146
const audit = await npm.cmd('audit')
138147
t.test('fix', async t => {
139148
await t.resolveMatch(

0 commit comments

Comments
 (0)