@@ -2,21 +2,59 @@ const t = require('tap')
2
2
const { basename } = require('node:path')
3
3
const tmock = require('../../fixtures/tmock')
4
4
const mockNpm = require('../../fixtures/mock-npm')
5
+
const MockRegistry = require('@npmcli/mock-registry')
6
+
const mockGlobals = require('@npmcli/mock-globals')
5
7
6
8
const CURRENT_VERSION = '123.420.69'
7
9
const CURRENT_MAJOR = '122.420.69'
8
10
const CURRENT_MINOR = '123.419.69'
9
11
const CURRENT_PATCH = '123.420.68'
10
12
const NEXT_VERSION = '123.421.70'
13
+
const NEXT_VERSION_ENGINE_COMPATIBLE = '123.421.60'
14
+
const NEXT_VERSION_ENGINE_COMPATIBLE_MINOR = `123.420.70`
15
+
const NEXT_VERSION_ENGINE_COMPATIBLE_PATCH = `123.421.58`
11
16
const NEXT_MINOR = '123.420.70'
12
17
const NEXT_PATCH = '123.421.69'
13
18
const CURRENT_BETA = '124.0.0-beta.99999'
14
19
const HAVE_BETA = '124.0.0-beta.0'
15
20
21
+
const packumentResponse = {
22
+
_id: 'npm',
23
+
name: 'npm',
24
+
'dist-tags': {
25
+
latest: CURRENT_VERSION,
26
+
},
27
+
access: 'public',
28
+
versions: {
29
+
[CURRENT_VERSION]: { version: CURRENT_VERSION, engines: { node: '>1' } },
30
+
[CURRENT_MAJOR]: { version: CURRENT_MAJOR, engines: { node: '>1' } },
31
+
[CURRENT_MINOR]: { version: CURRENT_MINOR, engines: { node: '>1' } },
32
+
[CURRENT_PATCH]: { version: CURRENT_PATCH, engines: { node: '>1' } },
33
+
[NEXT_VERSION]: { version: NEXT_VERSION, engines: { node: '>1' } },
34
+
[NEXT_MINOR]: { version: NEXT_MINOR, engines: { node: '>1' } },
35
+
[NEXT_PATCH]: { version: NEXT_PATCH, engines: { node: '>1' } },
36
+
[CURRENT_BETA]: { version: CURRENT_BETA, engines: { node: '>1' } },
37
+
[HAVE_BETA]: { version: HAVE_BETA, engines: { node: '>1' } },
38
+
[NEXT_VERSION_ENGINE_COMPATIBLE]: {
39
+
version: NEXT_VERSION_ENGINE_COMPATIBLE,
40
+
engiges: { node: '<=1' },
41
+
},
42
+
[NEXT_VERSION_ENGINE_COMPATIBLE_MINOR]: {
43
+
version: NEXT_VERSION_ENGINE_COMPATIBLE_MINOR,
44
+
engines: { node: '<=1' },
45
+
},
46
+
[NEXT_VERSION_ENGINE_COMPATIBLE_PATCH]: {
47
+
version: NEXT_VERSION_ENGINE_COMPATIBLE_PATCH,
48
+
engines: { node: '<=1' },
49
+
},
50
+
},
51
+
}
52
+
16
53
const runUpdateNotifier = async (t, {
17
54
STAT_ERROR,
18
55
WRITE_ERROR,
19
56
PACOTE_ERROR,
57
+
PACOTE_MOCK_REQ_COUNT = 1,
20
58
STAT_MTIME = 0,
21
59
mocks: _mocks = {},
22
60
command = 'help',
@@ -51,24 +89,7 @@ const runUpdateNotifier = async (t, {
51
89
},
52
90
}
53
91
54
-
const MANIFEST_REQUEST = []
55
-
const mockPacote = {
56
-
manifest: async (spec) => {
57
-
if (!spec.match(/^npm@/)) {
58
-
t.fail('no pacote manifest allowed for non npm packages')
59
-
}
60
-
MANIFEST_REQUEST.push(spec)
61
-
if (PACOTE_ERROR) {
62
-
throw PACOTE_ERROR
63
-
}
64
-
const manifestV = spec === 'npm@latest' ? CURRENT_VERSION
65
-
: /-/.test(spec) ? CURRENT_BETA : NEXT_VERSION
66
-
return { version: manifestV }
67
-
},
68
-
}
69
-
70
92
const mocks = {
71
-
pacote: mockPacote,
72
93
'node:fs/promises': mockFs,
73
94
'{ROOT}/package.json': { version },
74
95
'ci-info': { isCI: false, name: null },
@@ -83,124 +104,125 @@ const runUpdateNotifier = async (t, {
83
104
prefixDir,
84
105
argv,
85
106
})
107
+
const registry = new MockRegistry({
108
+
tap: t,
109
+
registry: mock.npm.config.get('registry'),
110
+
})
111
+
112
+
if (PACOTE_MOCK_REQ_COUNT > 0) {
113
+
registry.nock.get('/npm').times(PACOTE_MOCK_REQ_COUNT).reply(200, packumentResponse)
114
+
}
115
+
86
116
const updateNotifier = tmock(t, '{LIB}/cli/update-notifier.js', mocks)
87
117
88
118
const result = await updateNotifier(mock.npm)
89
119
90
120
return {
91
121
wroteFile,
92
122
result,
93
-
MANIFEST_REQUEST,
94
123
}
95
124
}
96
125
97
126
t.test('duration has elapsed, no updates', async t => {
98
-
const { wroteFile, result, MANIFEST_REQUEST } = await runUpdateNotifier(t)
127
+
const { wroteFile, result } = await runUpdateNotifier(t)
99
128
t.equal(wroteFile, true)
100
129
t.not(result)
101
-
t.equal(MANIFEST_REQUEST.length, 1)
102
130
})
103
131
104
132
t.test('situations in which we do not notify', t => {
105
133
t.test('nothing to do if notifier disabled', async t => {
106
-
const { wroteFile, result, MANIFEST_REQUEST } = await runUpdateNotifier(t, {
134
+
const { wroteFile, result } = await runUpdateNotifier(t, {
135
+
PACOTE_MOCK_REQ_COUNT: 0,
107
136
'update-notifier': false,
108
137
})
109
138
t.equal(wroteFile, false)
110
139
t.equal(result, null)
111
-
t.strictSame(MANIFEST_REQUEST, [], 'no requests for manifests')
112
140
})
113
141
114
142
t.test('do not suggest update if already updating', async t => {
115
-
const { wroteFile, result, MANIFEST_REQUEST } = await runUpdateNotifier(t, {
143
+
const { wroteFile, result } = await runUpdateNotifier(t, {
144
+
PACOTE_MOCK_REQ_COUNT: 0,
116
145
command: 'install',
117
146
prefixDir: { 'package.json': `{"name":"${t.testName}"}` },
118
147
argv: ['npm'],
119
148
global: true,
120
149
})
121
150
t.equal(wroteFile, false)
122
151
t.equal(result, null)
123
-
t.strictSame(MANIFEST_REQUEST, [], 'no requests for manifests')
124
152
})
125
153
126
154
t.test('do not suggest update if already updating with spec', async t => {
127
-
const { wroteFile, result, MANIFEST_REQUEST } = await runUpdateNotifier(t, {
155
+
const { wroteFile, result } = await runUpdateNotifier(t, {
156
+
PACOTE_MOCK_REQ_COUNT: 0,
128
157
command: 'install',
129
158
prefixDir: { 'package.json': `{"name":"${t.testName}"}` },
130
159
argv: ['npm@latest'],
131
160
global: true,
132
161
})
133
162
t.equal(wroteFile, false)
134
163
t.equal(result, null)
135
-
t.strictSame(MANIFEST_REQUEST, [], 'no requests for manifests')
136
164
})
137
165
138
166
t.test('do not update if same as latest', async t => {
139
-
const { wroteFile, result, MANIFEST_REQUEST } = await runUpdateNotifier(t)
167
+
const { wroteFile, result } = await runUpdateNotifier(t)
140
168
t.equal(wroteFile, true)
141
169
t.equal(result, null)
142
-
t.strictSame(MANIFEST_REQUEST, ['npm@latest'], 'requested latest version')
143
170
})
144
171
t.test('check if stat errors (here for coverage)', async t => {
145
172
const STAT_ERROR = new Error('blorg')
146
-
const { wroteFile, result, MANIFEST_REQUEST } = await runUpdateNotifier(t, { STAT_ERROR })
173
+
const { wroteFile, result } = await runUpdateNotifier(t, { STAT_ERROR })
147
174
t.equal(wroteFile, true)
148
175
t.equal(result, null)
149
-
t.strictSame(MANIFEST_REQUEST, ['npm@latest'], 'requested latest version')
150
176
})
151
177
t.test('ok if write errors (here for coverage)', async t => {
152
178
const WRITE_ERROR = new Error('grolb')
153
-
const { wroteFile, result, MANIFEST_REQUEST } = await runUpdateNotifier(t, { WRITE_ERROR })
179
+
const { wroteFile, result } = await runUpdateNotifier(t, { WRITE_ERROR })
154
180
t.equal(wroteFile, true)
155
181
t.equal(result, null)
156
-
t.strictSame(MANIFEST_REQUEST, ['npm@latest'], 'requested latest version')
157
182
})
158
183
t.test('ignore pacote failures (here for coverage)', async t => {
159
184
const PACOTE_ERROR = new Error('pah-KO-tchay')
160
-
const { wroteFile, result, MANIFEST_REQUEST } = await runUpdateNotifier(t, { PACOTE_ERROR })
185
+
const { wroteFile, result } = await runUpdateNotifier(t, {
186
+
PACOTE_ERROR, PACOTE_MOCK_REQ_COUNT: 0,
187
+
})
161
188
t.equal(result, null)
162
189
t.equal(wroteFile, true)
163
-
t.strictSame(MANIFEST_REQUEST, ['npm@latest'], 'requested latest version')
164
190
})
165
191
t.test('do not update if newer than latest, but same as next', async t => {
166
192
const {
167
193
wroteFile,
168
194
result,
169
-
MANIFEST_REQUEST,
170
195
} = await runUpdateNotifier(t, { version: NEXT_VERSION })
171
196
t.equal(result, null)
172
197
t.equal(wroteFile, true)
173
-
const reqs = ['npm@latest', `npm@^${NEXT_VERSION}`]
174
-
t.strictSame(MANIFEST_REQUEST, reqs, 'requested latest and next versions')
175
198
})
176
199
t.test('do not update if on the latest beta', async t => {
177
200
const {
178
201
wroteFile,
179
202
result,
180
-
MANIFEST_REQUEST,
181
203
} = await runUpdateNotifier(t, { version: CURRENT_BETA })
182
204
t.equal(result, null)
183
205
t.equal(wroteFile, true)
184
-
const reqs = [`npm@^${CURRENT_BETA}`]
185
-
t.strictSame(MANIFEST_REQUEST, reqs, 'requested latest and next versions')
186
206
})
187
207
188
208
t.test('do not update in CI', async t => {
189
-
const { wroteFile, result, MANIFEST_REQUEST } = await runUpdateNotifier(t, { mocks: {
209
+
const { wroteFile, result } = await runUpdateNotifier(t, { mocks: {
190
210
'ci-info': { isCI: true, name: 'something' },
191
-
} })
211
+
},
212
+
PACOTE_MOCK_REQ_COUNT: 0 })
192
213
t.equal(wroteFile, false)
193
214
t.equal(result, null)
194
-
t.strictSame(MANIFEST_REQUEST, [], 'no requests for manifests')
195
215
})
196
216
197
217
t.test('only check weekly for GA releases', async t => {
198
218
// One week (plus five minutes to account for test environment fuzziness)
199
219
const STAT_MTIME = Date.now() - 1000 * 60 * 60 * 24 * 7 + 1000 * 60 * 5
200
-
const { wroteFile, result, MANIFEST_REQUEST } = await runUpdateNotifier(t, { STAT_MTIME })
220
+
const { wroteFile, result } = await runUpdateNotifier(t, {
221
+
STAT_MTIME,
222
+
PACOTE_MOCK_REQ_COUNT: 0,
223
+
})
201
224
t.equal(wroteFile, false, 'duration was not reset')
202
225
t.equal(result, null)
203
-
t.strictSame(MANIFEST_REQUEST, [], 'no requests for manifests')
204
226
})
205
227
206
228
t.test('only check daily for betas', async t => {
@@ -209,37 +231,48 @@ t.test('situations in which we do not notify', t => {
209
231
const {
210
232
wroteFile,
211
233
result,
212
-
MANIFEST_REQUEST,
213
-
} = await runUpdateNotifier(t, { STAT_MTIME, version: HAVE_BETA })
234
+
} = await runUpdateNotifier(t, { STAT_MTIME, version: HAVE_BETA, PACOTE_MOCK_REQ_COUNT: 0 })
214
235
t.equal(wroteFile, false, 'duration was not reset')
215
236
t.equal(result, null)
216
-
t.strictSame(MANIFEST_REQUEST, [], 'no requests for manifests')
217
237
})
218
238
219
239
t.end()
220
240
})
221
241
242
+
t.test('notification situation with engine compatibility', async t => {
243
+
// no version which are greater than node 1.0.0 should be selected.
244
+
mockGlobals(t, { 'process.version': 'v1.0.0' }, { replace: true })
245
+
246
+
const {
247
+
wroteFile,
248
+
result,
249
+
} = await runUpdateNotifier(t, {
250
+
version: NEXT_VERSION_ENGINE_COMPATIBLE_MINOR,
251
+
PACOTE_MOCK_REQ_COUNT: 1 })
252
+
253
+
t.matchSnapshot(result)
254
+
t.equal(wroteFile, true)
255
+
})
256
+
222
257
t.test('notification situations', async t => {
223
258
const cases = {
224
-
[HAVE_BETA]: [`^{V}`],
225
-
[NEXT_PATCH]: [`latest`, `^{V}`],
226
-
[NEXT_MINOR]: [`latest`, `^{V}`],
227
-
[CURRENT_PATCH]: ['latest'],
228
-
[CURRENT_MINOR]: ['latest'],
229
-
[CURRENT_MAJOR]: ['latest'],
259
+
[HAVE_BETA]: 1,
260
+
[NEXT_PATCH]: 2,
261
+
[NEXT_MINOR]: 2,
262
+
[CURRENT_PATCH]: 1,
263
+
[CURRENT_MINOR]: 1,
264
+
[CURRENT_MAJOR]: 1,
230
265
}
231
266
232
-
for (const [version, reqs] of Object.entries(cases)) {
267
+
for (const [version, requestCount] of Object.entries(cases)) {
233
268
for (const color of [false, 'always']) {
234
269
await t.test(`${version} - color=${color}`, async t => {
235
270
const {
236
271
wroteFile,
237
272
result,
238
-
MANIFEST_REQUEST,
239
-
} = await runUpdateNotifier(t, { version, color })
273
+
} = await runUpdateNotifier(t, { version, color, PACOTE_MOCK_REQ_COUNT: requestCount })
240
274
t.matchSnapshot(result)
241
275
t.equal(wroteFile, true)
242
-
t.strictSame(MANIFEST_REQUEST, reqs.map(r => `npm@${r.replace('{V}', version)}`))
243
276
})
244
277
}
245
278
}
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4