strong-tie/inbound-calls
0
1'use strict'2 3const { test } = require('node:test')4const proxyquire = require('proxyquire')5const fp = require('../plugin')6const Fastify = require('fastify')7 8const pkg = require('../package.json')9 10test('fastify-plugin is a function', (t) => {11 t.plan(1)12 t.assert.ok(typeof fp === 'function')13})14 15test('should return the function with the skip-override Symbol', (t) => {16 t.plan(1)17 18 function plugin (fastify, opts, next) {19 next()20 }21 22 fp(plugin)23 t.assert.ok(plugin[Symbol.for('skip-override')])24})25 26test('should support "default" function from babel module', (t) => {27 t.plan(1)28 29 const plugin = {30 default: () => { }31 }32 33 try {34 fp(plugin)35 t.assert.ok(true)36 } catch (e) {37 t.assert.strictEqual(e.message, 'fastify-plugin expects a function, instead got a \'object\'')38 }39})40 41test('should throw if the plugin is not a function', (t) => {42 t.plan(1)43 44 try {45 fp('plugin')46 t.assert.fail()47 } catch (e) {48 t.assert.strictEqual(e.message, 'fastify-plugin expects a function, instead got a \'string\'')49 }50})51 52test('should check the fastify version', (t) => {53 t.plan(1)54 55 function plugin (fastify, opts, next) {56 next()57 }58 59 try {60 fp(plugin, { fastify: '>=0.10.0' })61 t.assert.ok(true)62 } catch (e) {63 t.assert.fail()64 }65})66 67test('should check the fastify version', (t) => {68 t.plan(1)69 70 function plugin (fastify, opts, next) {71 next()72 }73 74 try {75 fp(plugin, '>=0.10.0')76 t.assert.ok(true)77 } catch (e) {78 t.assert.fail()79 }80})81 82test('the options object should be an object', (t) => {83 t.plan(2)84 85 try {86 fp(() => { }, null)87 t.assert.fail()88 } catch (e) {89 t.assert.strictEqual(e.message, 'The options object should be an object')90 }91 92 try {93 fp(() => { }, [])94 t.assert.fail()95 } catch (e) {96 t.assert.strictEqual(e.message, 'The options object should be an object')97 }98})99 100test('should throw if the version number is not a string', (t) => {101 t.plan(1)102 103 try {104 fp(() => { }, { fastify: 12 })105 t.assert.fail()106 } catch (e) {107 t.assert.strictEqual(e.message, 'fastify-plugin expects a version string, instead got \'number\'')108 }109})110 111test('Should accept an option object', (t) => {112 t.plan(2)113 114 const opts = { hello: 'world' }115 116 function plugin (fastify, opts, next) {117 next()118 }119 120 fp(plugin, opts)121 122 t.assert.ok(plugin[Symbol.for('skip-override')], 'skip-override symbol should be present')123 t.assert.deepStrictEqual(plugin[Symbol.for('plugin-meta')], opts, 'plugin-meta should match opts')124})125 126test('Should accept an option object and checks the version', (t) => {127 t.plan(2)128 129 const opts = { hello: 'world', fastify: '>=0.10.0' }130 131 function plugin (fastify, opts, next) {132 next()133 }134 135 fp(plugin, opts)136 t.assert.ok(plugin[Symbol.for('skip-override')])137 t.assert.deepStrictEqual(plugin[Symbol.for('plugin-meta')], opts)138})139 140test('should set anonymous function name to file it was called from with a counter', (t) => {141 const fp = proxyquire('../plugin.js', { stubs: {} })142 143 const fn = fp((fastify, opts, next) => {144 next()145 })146 147 t.assert.strictEqual(fn[Symbol.for('plugin-meta')].name, 'test-auto-0')148 t.assert.strictEqual(fn[Symbol.for('fastify.display-name')], 'test-auto-0')149 150 const fn2 = fp((fastify, opts, next) => {151 next()152 })153 154 t.assert.strictEqual(fn2[Symbol.for('plugin-meta')].name, 'test-auto-1')155 t.assert.strictEqual(fn2[Symbol.for('fastify.display-name')], 'test-auto-1')156})157 158test('should set function name if Error.stackTraceLimit is set to 0', (t) => {159 const stackTraceLimit = Error.stackTraceLimit = 0160 161 const fp = proxyquire('../plugin.js', { stubs: {} })162 163 const fn = fp((fastify, opts, next) => {164 next()165 })166 167 t.assert.strictEqual(fn[Symbol.for('plugin-meta')].name, 'test-auto-0')168 t.assert.strictEqual(fn[Symbol.for('fastify.display-name')], 'test-auto-0')169 170 const fn2 = fp((fastify, opts, next) => {171 next()172 })173 174 t.assert.strictEqual(fn2[Symbol.for('plugin-meta')].name, 'test-auto-1')175 t.assert.strictEqual(fn2[Symbol.for('fastify.display-name')], 'test-auto-1')176 177 Error.stackTraceLimit = stackTraceLimit178})179 180test('should set display-name to meta name', (t) => {181 t.plan(2)182 183 const functionName = 'superDuperSpecialFunction'184 185 const fn = fp((fastify, opts, next) => next(), {186 name: functionName187 })188 189 t.assert.strictEqual(fn[Symbol.for('plugin-meta')].name, functionName)190 t.assert.strictEqual(fn[Symbol.for('fastify.display-name')], functionName)191})192 193test('should preserve fastify version in meta', (t) => {194 t.plan(1)195 196 const opts = { hello: 'world', fastify: '>=0.10.0' }197 198 const fn = fp((fastify, opts, next) => next(), opts)199 200 t.assert.strictEqual(fn[Symbol.for('plugin-meta')].fastify, '>=0.10.0')201})202 203test('should check fastify dependency graph - plugin', async (t) => {204 t.plan(1)205 const fastify = Fastify()206 207 fastify.register(fp((fastify, opts, next) => next(), {208 fastify: '5.x',209 name: 'plugin1-name'210 }))211 212 fastify.register(fp((fastify, opts, next) => next(), {213 fastify: '5.x',214 name: 'test',215 dependencies: ['plugin1-name', 'plugin2-name']216 }))217 218 await t.assert.rejects(fastify.ready(), { message: "The dependency 'plugin2-name' of plugin 'test' is not registered" })219})220 221test('should check fastify dependency graph - decorate', async (t) => {222 t.plan(1)223 const fastify = Fastify()224 225 fastify.decorate('plugin1', fp((fastify, opts, next) => next(), {226 fastify: '5.x',227 name: 'plugin1-name'228 }))229 230 fastify.register(fp((fastify, opts, next) => next(), {231 fastify: '5.x',232 name: 'test',233 decorators: { fastify: ['plugin1', 'plugin2'] }234 }))235 236 await t.assert.rejects(fastify.ready(), { message: "The decorator 'plugin2' required by 'test' is not present in Fastify" })237})238 239test('should check fastify dependency graph - decorateReply', async (t) => {240 t.plan(1)241 const fastify = Fastify()242 243 fastify.decorateReply('plugin1', fp((fastify, opts, next) => next(), {244 fastify: '5.x',245 name: 'plugin1-name'246 }))247 248 fastify.register(fp((fastify, opts, next) => next(), {249 fastify: '5.x',250 name: 'test',251 decorators: { reply: ['plugin1', 'plugin2'] }252 }))253 254 await t.assert.rejects(fastify.ready(), { message: "The decorator 'plugin2' required by 'test' is not present in Reply" })255})256 257test('should accept an option to encapsulate', async (t) => {258 t.plan(3)259 260 const fastify = Fastify()261 262 fastify.register(fp((fastify, opts, next) => {263 fastify.decorate('accessible', true)264 next()265 }, {266 name: 'accessible-plugin'267 }))268 269 fastify.register(fp((fastify, opts, next) => {270 fastify.decorate('alsoAccessible', true)271 next()272 }, {273 name: 'accessible-plugin2',274 encapsulate: false275 }))276 277 fastify.register(fp((fastify, opts, next) => {278 fastify.decorate('encapsulated', true)279 next()280 }, {281 name: 'encapsulated-plugin',282 encapsulate: true283 }))284 285 await fastify.ready()286 287 t.assert.ok(fastify.hasDecorator('accessible'))288 t.assert.ok(fastify.hasDecorator('alsoAccessible'))289 t.assert.ok(!fastify.hasDecorator('encapsulated'))290})291 292test('should check dependencies when encapsulated', async (t) => {293 t.plan(1)294 const fastify = Fastify()295 296 fastify.register(fp((fastify, opts, next) => next(), {297 name: 'test',298 dependencies: ['missing-dependency-name'],299 encapsulate: true300 }))301 302 await t.assert.rejects(fastify.ready(), { message: "The dependency 'missing-dependency-name' of plugin 'test' is not registered" })303})304 305test(306 'should check version when encapsulated',307 { skip: /\d-.+/.test(pkg.devDependencies.fastify) },308 async (t) => {309 t.plan(1)310 const fastify = Fastify()311 312 fastify.register(fp((fastify, opts, next) => next(), {313 name: 'test',314 fastify: '<=2.10.0',315 encapsulate: true316 }))317 318 await t.assert.rejects(fastify.ready(), { message: /fastify-plugin: test - expected '<=2.10.0' fastify version, '\d.\d+.\d+' is installed/ })319 }320)321 322test('should check decorators when encapsulated', async (t) => {323 t.plan(1)324 const fastify = Fastify()325 326 fastify.decorate('plugin1', 'foo')327 328 fastify.register(fp((fastify, opts, next) => next(), {329 fastify: '5.x',330 name: 'test',331 encapsulate: true,332 decorators: { fastify: ['plugin1', 'plugin2'] }333 }))334 335 await t.assert.rejects(fastify.ready(), { message: "The decorator 'plugin2' required by 'test' is not present in Fastify" })336})337 338test('plugin name when encapsulated', async (t) => {339 t.plan(6)340 const fastify = Fastify()341 342 fastify.register(function plugin (instance, opts, next) {343 next()344 })345 346 fastify.register(fp(getFn('hello'), {347 fastify: '5.x',348 name: 'hello',349 encapsulate: true350 }))351 352 fastify.register(function plugin (fastify, opts, next) {353 fastify.register(fp(getFn('deep'), {354 fastify: '5.x',355 name: 'deep',356 encapsulate: true357 }))358 359 fastify.register(fp(function genericPlugin (fastify, opts, next) {360 t.assert.strictEqual(fastify.pluginName, 'deep-deep', 'should be deep-deep')361 362 fastify.register(fp(getFn('deep-deep-deep'), {363 fastify: '5.x',364 name: 'deep-deep-deep',365 encapsulate: true366 }))367 368 fastify.register(fp(getFn('deep-deep -> not-encapsulated-2'), {369 fastify: '5.x',370 name: 'not-encapsulated-2'371 }))372 373 next()374 }, {375 fastify: '5.x',376 name: 'deep-deep',377 encapsulate: true378 }))379 380 fastify.register(fp(getFn('plugin -> not-encapsulated'), {381 fastify: '5.x',382 name: 'not-encapsulated'383 }))384 385 next()386 })387 388 await fastify.ready()389 390 function getFn (expectedName) {391 return function genericPlugin (fastify, opts, next) {392 t.assert.strictEqual(fastify.pluginName, expectedName, `should be ${expectedName}`)393 next()394 }395 }396})397 