Skip to content
Open
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"@fastify/swagger": "^9.0.0",
"@fastify/swagger-ui": "^5.0.0",
"@types/node": "^25.0.3",
"ajv": "^8.17.1",
"benchmark": "^2.1.4",
"c8": "^10.1.3",
"climem": "^2.0.0",
Expand All @@ -37,7 +38,7 @@
"start": "CLIMEM=8999 node -r climem ./examples/example",
"test": "npm run test:unit && npm run test:typescript",
"test:typescript": "tsd",
"test:unit": "c8 --100 node --test"
"test:unit": "c8 --100 node --test test/*.test.js"
},
"repository": {
"type": "git",
Expand Down Expand Up @@ -85,7 +86,7 @@
],
"license": "MIT",
"tsd": {
"directory": "test"
"directory": "test/types"
},
"publishConfig": {
"access": "public"
Expand Down
44 changes: 21 additions & 23 deletions test/multipart-ajv-file.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ const test = require('node:test')

const filePath = path.join(__dirname, '../README.md')

test('show modify the generated schema', async t => {
t.plan(4)
test('show modify the generated schema', async (t) => {
t.plan(6)

const fastify = Fastify({
ajv: {
Expand Down Expand Up @@ -52,29 +52,23 @@ test('show modify the generated schema', async t => {

await fastify.ready()

t.assert.deepStrictEqual(fastify.swagger().paths, {
'/': {
post: {
operationId: 'test',
requestBody: {
content: {
'multipart/form-data': {
schema: {
type: 'object',
properties: {
field: { type: 'string', format: 'binary' }
}
}
}
},
required: true,
},
responses: {
200: { description: 'Default Response' }
const post = fastify.swagger().paths['/'].post
t.assert.strictEqual(post.operationId, 'test')
// requestBody.required is not asserted because @fastify/swagger v9.7.0
// introduced it (fastify/fastify-swagger#903), making it version-dependent.
t.assert.deepStrictEqual(post.requestBody.content, {
'multipart/form-data': {
schema: {
type: 'object',
properties: {
field: { type: 'string', format: 'binary' }
}
}
}
})
t.assert.deepStrictEqual(post.responses, {
200: { description: 'Default Response' }
})

await fastify.listen({ port: 0 })

Expand All @@ -90,7 +84,9 @@ test('show modify the generated schema', async t => {
method: 'POST'
})

form.append('field', JSON.stringify({}), { contentType: 'application/json' })
form.append('field', JSON.stringify({}), {
contentType: 'application/json'
})
form.pipe(req)

const [res] = await once(req, 'response')
Expand All @@ -111,7 +107,9 @@ test('show modify the generated schema', async t => {
method: 'POST'
})

form.append('field', fs.createReadStream(filePath), { contentType: 'multipart/form-data' })
form.append('field', fs.createReadStream(filePath), {
contentType: 'multipart/form-data'
})
form.pipe(req)

const [res] = await once(req, 'response')
Expand Down
14 changes: 13 additions & 1 deletion test/multipart-incomplete-upload.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,19 @@ test('should finish with error on partial upload - saveRequestFiles', async func
const [res] = await once(req, 'response')
t.assert.strictEqual(res.statusCode, 500)

// Retry with exponential backoff until temp files are cleaned up.
// File cleanup is async and may not complete immediately on macOS.
for (const tmpUpload of tmpUploads) {
await t.assert.rejects(fs.access(tmpUpload))
let deleted = false
for (let i = 0; i < 5; i++) {
try {
await fs.access(tmpUpload)
await sleep(50 * Math.pow(2, i))
} catch {
deleted = true
break
}
}
t.assert.ok(deleted, `tmp file ${tmpUpload} should be deleted`)
}
})
20 changes: 20 additions & 0 deletions test/types/ajv-plugin.test-d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import fastify from 'fastify'
import { expectType } from 'tsd'
import type Ajv from 'ajv'
import { fastifyMultipart, ajvFilePlugin } from '../..'

// Test: ajvFilePlugin should be compatible with Fastify's ajv.plugins option
const app = fastify({
ajv: {
plugins: [
ajvFilePlugin,
(await import('../..')).ajvFilePlugin
]
}
})

app.register(fastifyMultipart)

// Test: ajvFilePlugin should accept Ajv and return Ajv
declare const ajv: Ajv
expectType<Ajv>(ajvFilePlugin(ajv))
2 changes: 1 addition & 1 deletion types/index.test-d.ts → test/types/index.test-d.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* eslint-disable @typescript-eslint/no-unused-expressions */
import fastify from 'fastify'
import fastifyMultipart, { MultipartValue, MultipartFields, MultipartFile } from '..'
import fastifyMultipart, { MultipartValue, MultipartFields, MultipartFile } from '../..'
import * as util from 'node:util'
import { pipeline } from 'node:stream'
import * as fs from 'node:fs'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import fastify from 'fastify'
import { fastifyMultipart } from '..'
import { fastifyMultipart } from '../..'

const app = fastify()

Expand Down
13 changes: 0 additions & 13 deletions types/avj-plugin.test-d.ts

This file was deleted.

3 changes: 2 additions & 1 deletion types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { BusboyConfig, BusboyFileStream } from '@fastify/busboy'
import { FastifyPluginCallback, FastifyRequest } from 'fastify'
import { Readable } from 'node:stream'
import { FastifyErrorConstructor } from '@fastify/error'
import type Ajv from 'ajv'

declare module 'fastify' {
interface FastifyRequest {
Expand Down Expand Up @@ -200,7 +201,7 @@ declare namespace fastifyMultipart {
/**
* Adds a new type `isFile` to help @fastify/swagger generate the correct schema.
*/
export function ajvFilePlugin (ajv: any): void
export function ajvFilePlugin (ajv: Ajv): Ajv

export const fastifyMultipart: FastifyMultipartPlugin
export { fastifyMultipart as default }
Expand Down