Skip to content

Commit b82fa5d

Browse files
committed
Refactor tests
1 parent c15cc12 commit b82fa5d

File tree

6 files changed

+135
-123
lines changed

6 files changed

+135
-123
lines changed

test/_common.ts

Lines changed: 40 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,63 @@
11
import path from 'node:path'
22
import { fileURLToPath } from 'node:url'
3-
import type { Plugin, RollupError, ObjectHook } from 'rollup'
3+
import type { Plugin, RollupError, ObjectHook, PluginContextMeta, PluginHooks, PluginContext, NormalizedInputOptions } from 'rollup'
44
import { nodeExternals, type ExternalsOptions } from '../source/index.ts'
55

66
const __dirname = path.dirname(fileURLToPath(import.meta.url))
77

8-
const warnings: string[] = []
9-
const fakePluginContext = {
10-
meta: {
11-
watchMode: false
12-
},
8+
class MockPluginContext {
9+
private readonly externals: Plugin
10+
readonly warnings: string[]
11+
readonly meta: PluginContextMeta
12+
13+
constructor(externals: Plugin) {
14+
this.externals = externals
15+
this.warnings = []
16+
this.meta = {
17+
rollupVersion: '4.9.6',
18+
watchMode: false
19+
}
20+
}
21+
22+
async buildStart() {
23+
let { buildStart } = this.externals
24+
if (typeof buildStart === 'object')
25+
buildStart = buildStart.handler
26+
if (typeof buildStart === 'function')
27+
return await buildStart.call(this as any, {} as NormalizedInputOptions)
28+
throw new Error('Ooops')
29+
}
30+
31+
async resolveId(specifier: string, importer: string | undefined) {
32+
let { resolveId } = this.externals
33+
if (typeof resolveId === 'object')
34+
resolveId = resolveId.handler
35+
if (typeof resolveId === 'function')
36+
return await resolveId.call(this as any, specifier, importer, { attributes: {}, isEntry: typeof importer === 'string' ? false : true })
37+
throw new Error('Ooops')
38+
}
1339

1440
error(err: string | RollupError): never {
1541
const message: string = typeof err === 'string'
1642
? err
1743
: err.message
1844
throw new Error(message)
19-
},
45+
}
2046

2147
warn(message: string): void {
22-
warnings.push(message)
23-
},
48+
this.warnings.push(message)
49+
}
2450

2551
addWatchFile(_file: string) {
2652
// nop
2753
}
2854
}
2955

30-
// node-externals only implements these hooks
31-
type ImplementedHooks =
32-
| 'buildStart'
33-
| 'resolveId'
34-
35-
export async function callHook(plugin: Plugin, hookName: ImplementedHooks, ...args: any[]) {
36-
const hook = plugin[hookName] as ObjectHook<(this: typeof fakePluginContext, ...args: any) => any>
37-
if (typeof hook === 'function')
38-
return hook.apply(fakePluginContext, args)
39-
if (typeof hook === 'object' && typeof hook.handler === 'function')
40-
return hook.handler.apply(fakePluginContext, args)
41-
throw new Error('Ooops')
42-
}
43-
44-
export async function initPlugin(options: ExternalsOptions = {}): Promise<{ plugin: Plugin, warnings: string[] }> {
45-
warnings.splice(0, Infinity)
46-
47-
const plugin = nodeExternals(options)
48-
await callHook(plugin, 'buildStart')
49-
return { plugin, warnings }
56+
export async function initPlugin(options: ExternalsOptions = {}) {
57+
const plugin = await nodeExternals(options)
58+
const context = new MockPluginContext(plugin)
59+
await context.buildStart()
60+
return context
5061
}
5162

5263
export function fixture(...parts: string[]) {

test/builtins.test.ts

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,78 +1,78 @@
11
import test from 'ava'
2-
import { initPlugin, callHook } from './_common.ts'
2+
import { initPlugin } from './_common.ts'
33

44
test("Marks Node builtins external by default", async t => {
5-
const { plugin } = await initPlugin()
5+
const context = await initPlugin()
66
for (const builtin of [ 'path', 'node:fs' ]) {
7-
t.like(await callHook(plugin, 'resolveId', builtin, 'index.js'), {
7+
t.like(await context.resolveId(builtin, 'index.js'), {
88
external: true
99
})
1010
}
1111
})
1212

1313
test("Does NOT mark Node builtins external when builtins=false", async t => {
14-
const { plugin } = await initPlugin({ builtins: false })
14+
const context = await initPlugin({ builtins: false })
1515
for (const builtin of [ 'path', 'node:fs' ]) {
16-
t.like(await callHook(plugin, 'resolveId', builtin, 'index.js'), {
16+
t.like(await context.resolveId(builtin, 'index.js'), {
1717
external: false
1818
})
1919
}
2020
})
2121

2222
test("Does NOT mark Node builtins external when implicitely excluded", async t => {
23-
const { plugin } = await initPlugin({ exclude: [ 'path', 'node:fs' ]})
23+
const context = await initPlugin({ exclude: [ 'path', 'node:fs' ]})
2424
for (const builtin of [ 'path', 'node:fs' ]) {
25-
t.like(await callHook(plugin, 'resolveId', builtin, 'index.js'), {
25+
t.like(await context.resolveId(builtin, 'index.js'), {
2626
external: false
2727
})
2828
}
2929
})
3030

3131
test("Marks Node builtins external when builtins=false and implicitly included", async t => {
32-
const { plugin } = await initPlugin({ builtins: false, include: [ 'path', 'node:fs' ] })
32+
const context = await initPlugin({ builtins: false, include: [ 'path', 'node:fs' ] })
3333
for (const builtin of [ 'path', 'node:fs' ]) {
34-
t.like(await callHook(plugin, 'resolveId', builtin, 'index.js'), {
34+
t.like(await context.resolveId(builtin, 'index.js'), {
3535
external: true
3636
})
3737
}
3838
})
3939

4040
test("Adds 'node:' prefix to builtins by default", async t => {
41-
const { plugin } = await initPlugin()
41+
const context = await initPlugin()
4242
for (const builtin of [ 'node:path', 'path' ]) {
43-
t.like(await callHook(plugin, 'resolveId', builtin, 'index.js'), {
43+
t.like(await context.resolveId(builtin, 'index.js'), {
4444
id: 'node:path'
4545
})
4646
}
4747
})
4848

4949
test("Removes 'node:' prefix when using builtinsPrefix='strip'", async t => {
50-
const { plugin } = await initPlugin({ builtinsPrefix: 'strip' })
50+
const context = await initPlugin({ builtinsPrefix: 'strip' })
5151
for (const builtin of [ 'node:path', 'path' ]) {
52-
t.like(await callHook(plugin, 'resolveId', builtin, 'index.js'), {
52+
t.like(await context.resolveId(builtin, 'index.js'), {
5353
id: 'path'
5454
})
5555
}
5656
})
5757

5858
test("Does NOT remove 'node:test' prefix even with builtinsPrefix='add'", async t => {
59-
const { plugin } = await initPlugin({ builtinsPrefix: 'strip' })
59+
const context = await initPlugin({ builtinsPrefix: 'strip' })
6060
for (const builtin of [ 'node:test' ]) {
61-
t.like(await callHook(plugin, 'resolveId', builtin, 'index.js'), {
61+
t.like(await context.resolveId(builtin, 'index.js'), {
6262
id: builtin
6363
})
6464
}
6565
})
6666

6767
test("Does not recognize 'test' as a Node builtin", async t => {
68-
const { plugin } = await initPlugin()
69-
t.is(await callHook(plugin, 'resolveId', 'node', 'index.js'), null)
68+
const context = await initPlugin()
69+
t.is(await context.resolveId('node', 'index.js'), null)
7070
})
7171

7272
test("Ignores 'node:' prefix when using builtinsPrefix='ignore'", async t => {
73-
const { plugin } = await initPlugin({ builtinsPrefix: 'ignore' })
73+
const context = await initPlugin({ builtinsPrefix: 'ignore' })
7474
for (const builtin of [ 'node:path', 'path' ]) {
75-
t.like(await callHook(plugin, 'resolveId', builtin, 'index.js'), {
75+
t.like(await context.resolveId(builtin, 'index.js'), {
7676
id: builtin
7777
})
7878
}

test/monorepo.test.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,29 @@
11
import fs from 'node:fs/promises'
22
import test from 'ava'
3-
import { initPlugin, callHook, fixture } from './_common.ts'
3+
import { initPlugin, fixture } from './_common.ts'
44

55
// These two tests need to be run in sequence
66
test.serial('git monorepo usage', async t => {
77
await fs.mkdir(fixture('01_monorepo/.git'), { recursive: true })
88
process.chdir(fixture('01_monorepo/one'))
99

1010
// Should gather dependencies up to ./test/fixtures/01_monorepo
11-
const { plugin } = await initPlugin()
11+
const context = await initPlugin()
1212

1313
// Should be external
1414
for (const dependency of [
1515
'moment', // dependency in ./test/fixtures/01_monorepo/one/package.json (picked)
1616
'chalk' // dependency in ./test/fixtures/01_monorepo/package.json (picked)
1717
]) {
18-
t.false(await callHook(plugin, 'resolveId', dependency, 'index.js'))
18+
t.false(await context.resolveId(dependency, 'index.js'))
1919
}
2020

2121
// Should be ignored
2222
for (const dependency of [
2323
'react', // dependency in ./test/fixtures/01_monorepo/two/package.json (not picked)
2424
'test-dep' // dependency in ./test/fixtures/package.json (not picked)
2525
]) {
26-
t.is(await callHook(plugin, 'resolveId', dependency, 'index.js'), null)
26+
t.is(await context.resolveId(dependency, 'index.js'), null)
2727
}
2828
})
2929

@@ -32,7 +32,7 @@ test.serial('non-git monorepo usage', async t => {
3232
process.chdir(fixture('01_monorepo/one'))
3333

3434
// Should gather dependencies up to . !
35-
const { plugin } = await initPlugin()
35+
const context = await initPlugin()
3636

3737
// Should be external
3838
for (const dependency of [
@@ -41,13 +41,13 @@ test.serial('non-git monorepo usage', async t => {
4141
'test-dep', // dependency in ./test/fixtures/package.json (picked)
4242
'rollup', // peer dependency in ./package.json (picked !)
4343
]) {
44-
t.false(await callHook(plugin, 'resolveId', dependency, 'index.js'))
44+
t.false(await context.resolveId(dependency, 'index.js'))
4545
}
4646

4747
// Should be ignored
4848
for (const dependency of [
4949
'react' // dependency in ./test/fixtures/01_monorepo/two/package.json (not picked)
5050
]) {
51-
t.is(await callHook(plugin, 'resolveId', dependency, 'index.js'), null)
51+
t.is(await context.resolveId(dependency, 'index.js'), null)
5252
}
5353
})

test/options.test.ts

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import test from 'ava'
22
import { testProp, fc } from '@fast-check/ava'
33
import type { Arbitrary } from 'fast-check'
4-
import { initPlugin, callHook, fixture } from './_common.ts'
4+
import { initPlugin, fixture } from './_common.ts'
55
import { type ExternalsOptions } from '../source/index.ts'
66

77
// Ensures tests use local package.json
@@ -35,28 +35,29 @@ testProp(
3535
}
3636
)
3737

38-
// Must be serial because it uses the 'warnings' global in _common.ts.
39-
test.serial("Warns when given invalid include or exclude entry", async t => {
38+
test("Warns when given invalid include or exclude entry", async t => {
4039
const okay = 'some_dep' // string is ok
4140
const notOkay = 1 // number is not (unless 0, which is falsy)
4241

43-
const { warnings } = await initPlugin({
44-
include: [ okay, notOkay as any ]
42+
const context = await initPlugin({
43+
include: [ okay, notOkay as any ],
44+
exclude: [ okay, notOkay as any ],
4545
})
4646

47-
t.is(warnings.length, 1)
48-
t.is(warnings[0], `Ignoring wrong entry type #1 in 'include' option: ${JSON.stringify(notOkay)}`)
47+
t.is(context.warnings.length, 2)
48+
t.is(context.warnings[0], `Ignoring wrong entry type #1 in 'include' option: ${JSON.stringify(notOkay)}`)
49+
t.is(context.warnings[1], `Ignoring wrong entry type #1 in 'exclude' option: ${JSON.stringify(notOkay)}`)
4950
})
5051

5152
test("Obeys 'packagePath' option (single file name)", async t => {
52-
const { plugin } = await initPlugin({
53+
const context = await initPlugin({
5354
packagePath: '00_simple/package.json'
5455
})
55-
t.false(await callHook(plugin, 'resolveId', 'simple-dep', 'index.js'))
56+
t.false(await context.resolveId('simple-dep', 'index.js'))
5657
})
5758

5859
test("Obeys 'packagePath' option (multiple file names)", async t => {
59-
const { plugin } = await initPlugin({
60+
const context = await initPlugin({
6061
packagePath: [
6162
'00_simple/package.json',
6263
'01_monorepo/package.json'
@@ -68,6 +69,6 @@ test("Obeys 'packagePath' option (multiple file names)", async t => {
6869
'simple-dep', // 00_simple/package.json
6970
'chalk', // 01_monorepo/package.json
7071
]) {
71-
t.false(await callHook(plugin, 'resolveId', dependency, 'index.js'))
72+
t.false(await context.resolveId(dependency, 'index.js'))
7273
}
7374
})

0 commit comments

Comments
 (0)