Skip to content

Commit 968e124

Browse files
authored
chore: add option for strict mock registry (#5902)
1 parent 153c142 commit 968e124

File tree

2 files changed

+61
-27
lines changed

2 files changed

+61
-27
lines changed

mock-registry/lib/index.js

Lines changed: 59 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ class MockRegistry {
1010
#authorization
1111
#basic
1212
#debug
13+
#strict
1314

1415
constructor (opts) {
1516
if (!opts.registry) {
@@ -19,20 +20,48 @@ class MockRegistry {
1920
this.#authorization = opts.authorization
2021
this.#basic = opts.basic
2122
this.#debug = opts.debug
23+
this.#strict = opts.strict
2224
// Required for this.package
2325
this.#tap = opts.tap
26+
if (this.#tap) {
27+
this.startNock()
28+
}
2429
}
2530

26-
static tnock (t, host, opts, { debug = false } = {}) {
27-
if (debug) {
28-
Nock.emitter.on('no match', req => console.error('NO MATCH', req.options))
31+
static tnock (t, host, opts, { debug = false, strict = false } = {}) {
32+
const noMatch = (req) => {
33+
if (strict) {
34+
// There are network requests that get caught regardless of error code.
35+
// Turning on strict mode requires that those requests get explicitly
36+
// mocked with a 404, 500, etc.
37+
// XXX: this is opt-in currently because it breaks some existing CLI
38+
// tests. We should work towards making this the default for all tests.
39+
t.fail(`Unmatched request: ${JSON.stringify(req.options, null, 2)}`)
40+
}
41+
if (debug) {
42+
console.error('NO MATCH', t.name, req.options)
43+
}
2944
}
45+
46+
Nock.emitter.on('no match', noMatch)
3047
Nock.disableNetConnect()
3148
const server = Nock(host, opts)
49+
50+
if (strict) {
51+
// this requires that mocks not be shared between sub tests but it helps
52+
// find mistakes quicker instead of waiting for the entire test to end
53+
t.afterEach((t) => {
54+
t.strictSame(server.pendingMocks(), [], 'no pending mocks after each')
55+
t.strictSame(server.activeMocks(), [], 'no active mocks after each')
56+
})
57+
}
58+
3259
t.teardown(() => {
3360
Nock.enableNetConnect()
3461
server.done()
62+
Nock.emitter.off('no match', noMatch)
3563
})
64+
3665
return server
3766
}
3867

@@ -41,31 +70,38 @@ class MockRegistry {
4170
}
4271

4372
get nock () {
44-
if (!this.#nock) {
45-
if (!this.#tap) {
46-
throw new Error('cannot mock packages without a tap fixture')
47-
}
48-
const reqheaders = {}
49-
if (this.#authorization) {
50-
reqheaders.authorization = `Bearer ${this.#authorization}`
51-
}
52-
if (this.#basic) {
53-
reqheaders.authorization = `Basic ${this.#basic}`
54-
}
55-
this.#nock = MockRegistry.tnock(
56-
this.#tap,
57-
this.#registry,
58-
{ reqheaders },
59-
{ debug: this.#debug }
60-
)
61-
}
6273
return this.#nock
6374
}
6475

6576
set nock (nock) {
6677
this.#nock = nock
6778
}
6879

80+
startNock () {
81+
if (this.nock) {
82+
return
83+
}
84+
85+
if (!this.#tap) {
86+
throw new Error('cannot mock packages without a tap fixture')
87+
}
88+
89+
const reqheaders = {}
90+
if (this.#authorization) {
91+
reqheaders.authorization = `Bearer ${this.#authorization}`
92+
}
93+
if (this.#basic) {
94+
reqheaders.authorization = `Basic ${this.#basic}`
95+
}
96+
97+
this.nock = MockRegistry.tnock(
98+
this.#tap,
99+
this.#registry,
100+
{ reqheaders },
101+
{ debug: this.#debug, strict: this.#strict }
102+
)
103+
}
104+
69105
search ({ responseCode = 200, results = [], error }) {
70106
// the flags, score, and searchScore parts of the response are never used
71107
// by npm, only package is used
@@ -296,13 +332,14 @@ class MockRegistry {
296332
manifest.users = users
297333
}
298334
for (const packument of packuments) {
335+
const unscoped = name.includes('/') ? name.split('/')[1] : name
299336
manifest.versions[packument.version] = {
300337
_id: `${name}@${packument.version}`,
301338
name,
302339
description: 'test package mock manifest',
303340
dependencies: {},
304341
dist: {
305-
tarball: `${this.#registry}/${name}/-/${name}-${packument.version}.tgz`,
342+
tarball: `${this.#registry}/${name}/-/${unscoped}-${packument.version}.tgz`,
306343
},
307344
maintainers: [],
308345
...packument,

smoke-tests/test/fixtures/setup.js

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ module.exports = async (t, { testdir = {}, debug } = {}) => {
8484
tap: t,
8585
registry: 'http://smoke-test-registry.club/',
8686
debug,
87+
strict: true,
8788
})
8889
const httpProxyRegistry = `http://localhost:${PORT}`
8990
const proxy = httpProxy.createProxyServer({})
@@ -92,12 +93,8 @@ module.exports = async (t, { testdir = {}, debug } = {}) => {
9293
t.teardown(() => server.close())
9394

9495
// update notifier should never be written
95-
t.afterEach(async (t) => {
96+
t.afterEach((t) => {
9697
t.equal(existsSync(join(paths.cache, '_update-notifier-last-checked')), false)
97-
// this requires that mocks not be shared between sub tests but it helps
98-
// find mistakes quicker instead of waiting for the entire test to end
99-
t.strictSame(registry.nock.pendingMocks(), [], 'no pending mocks after each')
100-
t.strictSame(registry.nock.activeMocks(), [], 'no active mocks after each')
10198
})
10299

103100
const debugLog = debug || CI ? (...a) => console.error(...a) : () => {}

0 commit comments

Comments
 (0)