Skip to content

Commit c946c71

Browse files
authored
test: clean up Mocha setup code withVersions and withExports (#5785)
1 parent 6bfd2dd commit c946c71

File tree

1 file changed

+120
-73
lines changed

1 file changed

+120
-73
lines changed

packages/dd-trace/test/setup/mocha.js

Lines changed: 120 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
require('./core')
44

5-
const os = require('os')
5+
const { platform } = require('os')
66
const path = require('path')
77
const semver = require('semver')
88
const externals = require('../plugins/externals.json')
@@ -12,6 +12,8 @@ const Nomenclature = require('../../src/service-naming')
1212
const { storage } = require('../../../datadog-core')
1313
const { getInstrumentation } = require('./helpers/load-inst')
1414

15+
const NODE_PATH_SEP = platform() === 'win32' ? ';' : ':'
16+
1517
global.withVersions = withVersions
1618
global.withExports = withExports
1719
global.withNamingSchema = withNamingSchema
@@ -141,112 +143,157 @@ function withPeerService (tracer, pluginName, spanGenerationFn, service, service
141143
})
142144
}
143145

146+
/**
147+
* @overload
148+
* @param {string|Plugin} plugin - The name of the plugin to test, e.g. 'fastify', or the exports object of an already
149+
* loaded plugin
150+
* @param {string|string[]} modules - The name(s) of the module(s) to test, e.g. 'fastify' or ['fastify', 'middie']
151+
* @param {withVersionsCallback} cb - The callback function to call with the test case data
152+
* @returns {void}
153+
*
154+
* @overload
155+
* @param {string|Plugin} plugin - The name of the plugin to test, e.g. 'fastify', or the exports object of an already
156+
* loaded plugin
157+
* @param {string|string[]} modules - The name(s) of the module(s) to test, e.g. 'fastify' or ['fastify', 'middie']
158+
* @param {string} range - The specific version or range of versions to test, e.g. '>=3' or '3.1.2'
159+
* @param {withVersionsCallback} cb - The callback function to call with the test case data
160+
* @returns {void}
161+
*
162+
* @typedef {object} Plugin
163+
* @property {string} name
164+
* @property {string} version
165+
*
166+
* @callback withVersionsCallback
167+
* @param {string} versionKey - The version string used in the module path
168+
* @param {string} moduleName - The name of the module being tested
169+
* @param {string} resolvedVersion - The specific version of the module being tested
170+
*/
144171
function withVersions (plugin, modules, range, cb) {
145-
const instrumentations = typeof plugin === 'string' ? getInstrumentation(plugin) : [].concat(plugin)
146-
const names = instrumentations.map(instrumentation => instrumentation.name)
172+
if (typeof range === 'function') {
173+
cb = range
174+
range = undefined
175+
}
147176

148-
modules = [].concat(modules)
177+
const instrumentations = typeof plugin === 'string' ? getInstrumentation(plugin) : [plugin]
178+
const names = new Set(instrumentations.map(instrumentation => instrumentation.name))
149179

150-
names.forEach(name => {
151-
if (externals[name]) {
152-
[].concat(externals[name]).forEach(external => {
153-
instrumentations.push(external)
154-
})
180+
for (const name of names) {
181+
if (!externals[name]) continue
182+
for (const external of externals[name]) {
183+
instrumentations.push(external)
155184
}
156-
})
157-
158-
if (!cb) {
159-
cb = range
160-
range = null
161185
}
162186

163-
modules.forEach(moduleName => {
187+
for (const moduleName of Array.isArray(modules) ? modules : [modules]) {
164188
if (process.env.PACKAGE_NAMES) {
165189
const packages = process.env.PACKAGE_NAMES.split(',')
166190

167191
if (!packages.includes(moduleName)) return
168192
}
169193

194+
/** @type {Map<string, {versionRange: string, versionKey: string, resolvedVersion: string}>} */
170195
const testVersions = new Map()
171196

172-
instrumentations
173-
.filter(instrumentation => instrumentation.name === moduleName)
174-
.forEach(instrumentation => {
175-
const versions = process.env.PACKAGE_VERSION_RANGE
176-
? [process.env.PACKAGE_VERSION_RANGE]
177-
: instrumentation.versions
178-
versions
179-
.filter(version => !process.env.RANGE || semver.subset(version, process.env.RANGE))
180-
.forEach(version => {
181-
if (version !== '*') {
182-
const min = semver.coerce(version).version
197+
for (const instrumentation of instrumentations) {
198+
if (instrumentation.name !== moduleName) continue
199+
200+
const versions = process.env.PACKAGE_VERSION_RANGE
201+
? [process.env.PACKAGE_VERSION_RANGE]
202+
: instrumentation.versions
203+
204+
for (const version of versions) {
205+
if (process.env.RANGE && !semver.subset(version, process.env.RANGE)) continue
206+
if (version !== '*') {
207+
const result = semver.coerce(version)
208+
if (!result) throw new Error(`Invalid version: ${version}`)
209+
const min = result.version
210+
testVersions.set(min, { versionRange: version, versionKey: min, resolvedVersion: min })
211+
}
212+
213+
const max = require(getModulePath(moduleName, version)).version()
214+
testVersions.set(max, { versionRange: version, versionKey: version, resolvedVersion: max })
215+
}
216+
}
183217

184-
testVersions.set(min, { range: version, test: min })
185-
}
218+
const testCases = Array.from(testVersions.values())
219+
.filter(({ resolvedVersion }) => !range || semver.satisfies(resolvedVersion, range))
220+
.sort(({ resolvedVersion }) => resolvedVersion.localeCompare(resolvedVersion))
186221

187-
const max = require(`../../../../versions/${moduleName}@${version}`).version()
222+
for (const testCase of testCases) {
223+
const absBasePath = path.resolve(__dirname, getModulePath(moduleName, testCase.versionKey))
224+
const absNodeModulesPath = `${absBasePath}/node_modules`
188225

189-
testVersions.set(max, { range: version, test: version })
190-
})
191-
})
226+
describe(`with ${moduleName} ${testCase.versionRange} (${testCase.resolvedVersion})`, () => {
227+
let nodePath
192228

193-
Array.from(testVersions)
194-
.filter(v => !range || semver.satisfies(v[0], range))
195-
.sort(v => v[0].localeCompare(v[0]))
196-
.map(v => Object.assign({}, v[1], { version: v[0] }))
197-
.forEach(v => {
198-
const versionPath = path.resolve(
199-
__dirname, '../../../../versions/',
200-
`${moduleName}@${v.test}/node_modules`
201-
)
202-
203-
describe(`with ${moduleName} ${v.range} (${v.version})`, () => {
204-
let nodePath
205-
206-
before(() => {
207-
// set plugin name and version to later report to test agent regarding tested integrations and
208-
// their tested range of versions
209-
const lastPlugin = testedPlugins[testedPlugins.length - 1]
210-
if (!lastPlugin || lastPlugin.pluginName !== plugin || lastPlugin.pluginVersion !== v.version) {
211-
testedPlugins.push({ pluginName: plugin, pluginVersion: v.version })
212-
}
213-
214-
nodePath = process.env.NODE_PATH
215-
process.env.NODE_PATH = [process.env.NODE_PATH, versionPath]
216-
.filter(x => x && x !== 'undefined')
217-
.join(os.platform() === 'win32' ? ';' : ':')
218-
219-
require('module').Module._initPaths()
220-
})
229+
before(() => {
230+
// set plugin name and version to later report to test agent regarding tested integrations and their tested
231+
// range of versions
232+
const lastPlugin = testedPlugins.at(-1)
233+
if (
234+
!lastPlugin || lastPlugin.pluginName !== plugin || lastPlugin.pluginVersion !== testCase.resolvedVersion
235+
) {
236+
testedPlugins.push({ pluginName: plugin, pluginVersion: testCase.resolvedVersion })
237+
}
238+
239+
nodePath = process.env.NODE_PATH
240+
process.env.NODE_PATH += `${NODE_PATH_SEP}${absNodeModulesPath}`
241+
242+
require('module').Module._initPaths()
243+
})
221244

222-
cb(v.test, moduleName, v.version)
245+
cb(testCase.versionKey, moduleName, testCase.resolvedVersion)
223246

224-
after(() => {
225-
process.env.NODE_PATH = nodePath
226-
require('module').Module._initPaths()
227-
})
247+
after(() => {
248+
process.env.NODE_PATH = nodePath
249+
require('module').Module._initPaths()
228250
})
229251
})
230-
})
252+
}
253+
}
231254
}
232255

233-
function withExports (moduleName, version, exportNames, versionRange, fn) {
234-
const getExport = () => require(`../../../../versions/${moduleName}@${version}`).get()
235-
describe('with the default export', () => fn(getExport))
236-
256+
/**
257+
* @overload
258+
* @param {string} moduleName - The name of the module being tested
259+
* @param {string} version - The specific version of the module being tested
260+
* @param {string[]} exportNames - The names of the module exports to be tested (the default export will always be
261+
* tested)
262+
* @param {withExportsCallback} cb
263+
*
264+
* @overload
265+
* @param {string} moduleName - The name of the module being tested
266+
* @param {string} version - The specific version of the module being tested
267+
* @param {string[]} exportNames - The names of the module exports to be tested (the default export will always be
268+
* tested)
269+
* @param {string} versionRange - The version range in which the given version should reside. If not within this range,
270+
* only the default export will be tested.
271+
* @param {withExportsCallback} cb
272+
*
273+
* @callback withExportsCallback
274+
* @param {function} getExport - A function that returns the module export to test
275+
*/
276+
function withExports (moduleName, version, exportNames, versionRange, cb) {
237277
if (typeof versionRange === 'function') {
238-
fn = versionRange
278+
cb = versionRange
239279
versionRange = '*'
240280
}
241281

282+
const getExport = () => require(getModulePath(moduleName, version)).get()
283+
describe('with the default export', () => cb(getExport))
284+
242285
if (!semver.intersects(version, versionRange)) return
243286

244287
for (const exportName of exportNames) {
245-
const getExport = () => require(`../../../../versions/${moduleName}@${version}`).get()[exportName]
246-
describe(`with exports.${exportName}`, () => fn(getExport))
288+
const getExport = () => require(getModulePath(moduleName, version)).get()[exportName]
289+
describe(`with exports.${exportName}`, () => cb(getExport))
247290
}
248291
}
249292

293+
function getModulePath (moduleName, version) {
294+
return `../../../../versions/${moduleName}@${version}`
295+
}
296+
250297
exports.mochaHooks = {
251298
afterEach () {
252299
agent.reset()

0 commit comments

Comments
 (0)