Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
5e534f9
test: migrate from tap to node "multipart-ajv-file.test.js"
matteo-gobbo Mar 15, 2025
444aaaf
test: migrate from tap to node multipart-attach-body.test.js
matteo-gobbo Mar 15, 2025
f154c29
test: migrate from tap to node multipart-big-stream.test.js
matteo-gobbo Mar 15, 2025
3ee0710
test: migrate from tap to node multipart-body-schema.js
matteo-gobbo Mar 15, 2025
9de0cc0
test: migrate from tap to node multipart-concat.test.js
matteo-gobbo Mar 15, 2025
631c942
test: migrate from tap to node multipart-disk.test.js
matteo-gobbo Mar 15, 2025
53267d9
test: migrate from tap to node multipart-duplicate-save-request-file.…
matteo-gobbo Mar 15, 2025
a24dcd1
test: migrate from tap to node multipart-empty-body.test.js
matteo-gobbo Mar 15, 2025
8760045
test: migrate from tap to node multipart-fileLimit.test.js
matteo-gobbo Mar 15, 2025
9168d50
test: migrate from tap to node multipart-http2.test.js
matteo-gobbo Mar 15, 2025
d2d702e
fix
matteo-gobbo Mar 15, 2025
d4fbc35
test: migrate from tap to node multipart-incomplete-upload.test.js
matteo-gobbo Mar 15, 2025
cd66f7a
test: migrate from tap to node multipart-json.test.js
matteo-gobbo Mar 15, 2025
f9694b3
test: migrate from tap to node multipart-security.test.js
matteo-gobbo Mar 15, 2025
7049313
test: migrate from tap to node multipart-small-stream.test.js
matteo-gobbo Mar 15, 2025
5f165c2
test: migrate from tap to node multipart-update-options-types.test.js
matteo-gobbo Mar 15, 2025
128aa55
test: migrate from tap to node multipart.test.js
matteo-gobbo Mar 16, 2025
c181b2b
test: migrate from tap to node stream-consumer.test.js
matteo-gobbo Mar 16, 2025
c6b1238
test: migrate from tap to node fix-313.test.js
matteo-gobbo Mar 16, 2025
d34c2c8
test: migrate from tap to node generate-id.test.js
matteo-gobbo Mar 16, 2025
49f1fa0
test: migrate from tap to node big.test.js
matteo-gobbo Mar 16, 2025
a9ced93
chore: remove tap
matteo-gobbo Mar 16, 2025
4429642
chore: add c8 for coverage
matteo-gobbo Mar 16, 2025
5be684f
chore: remove -taprc
matteo-gobbo Mar 16, 2025
72ba484
fix: update temporary directory path in multipart-disk.test.js
matteo-gobbo Aug 23, 2025
c326ea4
refactor: replace deepEqual with deepStrictEqual
matteo-gobbo Aug 25, 2025
3ad90af
fix: use ifError for error assertion
matteo-gobbo Aug 27, 2025
adcd75e
fix: standardize assertions using fail
matteo-gobbo Aug 30, 2025
3c40164
fix: remove second argument to ifError
matteo-gobbo Aug 30, 2025
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
2 changes: 0 additions & 2 deletions .taprc

This file was deleted.

5 changes: 2 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"@fastify/busboy": "^3.0.0",
"@fastify/deepmerge": "^3.0.0",
"@fastify/error": "^4.0.0",
"c8": "^10.1.3",
"fastify-plugin": "^5.0.0",
"secure-json-parse": "^4.0.0"
},
Expand All @@ -28,18 +29,16 @@
"noop-stream": "^0.1.0",
"pump": "^3.0.0",
"readable-stream": "^4.5.2",
"tap": "^18.6.1",
"tsd": "^0.33.0"
},
"scripts": {
"coverage": "npm run test:unit -- --coverage-report=html",
"climem": "climem 8999 localhost",
"lint": "eslint",
"lint:fix": "eslint --fix",
"start": "CLIMEM=8999 node -r climem ./examples/example",
"test": "npm run test:unit && npm run test:typescript",
"test:typescript": "tsd",
"test:unit": "tap -t 120"
"test:unit": "c8 --100 node --test"
},
"repository": {
"type": "git",
Expand Down
38 changes: 22 additions & 16 deletions test/big.test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use strict'

const test = require('tap').test
const test = require('node:test')
const FormData = require('form-data')
const Fastify = require('fastify')
const multipart = require('..')
Expand All @@ -12,13 +12,13 @@ const crypto = require('node:crypto')
const streamToNull = require('../lib/stream-consumer')

// skipping on Github Actions because it takes too long
test('should upload a big file in constant memory', { skip: process.env.CI }, function (t) {
test('should upload a big file in constant memory', { skip: process.env.CI }, function (t, done) {
t.plan(10)

const fastify = Fastify()
const hashInput = crypto.createHash('sha256')

t.teardown(fastify.close.bind(fastify))
t.after(() => fastify.close())

fastify.register(multipart, {
limits: {
Expand All @@ -28,23 +28,23 @@ test('should upload a big file in constant memory', { skip: process.env.CI }, fu
})

fastify.post('/', async function (req, reply) {
t.ok(req.isMultipart())
t.assert.ok(req.isMultipart())

for await (const part of req.parts()) {
if (part.file) {
t.equal(part.type, 'file')
t.equal(part.fieldname, 'upload')
t.equal(part.filename, 'random-data')
t.equal(part.encoding, '7bit')
t.equal(part.mimetype, 'binary/octet-stream')
t.assert.strictEqual(part.type, 'file')
t.assert.strictEqual(part.fieldname, 'upload')
t.assert.strictEqual(part.filename, 'random-data')
t.assert.strictEqual(part.encoding, '7bit')
t.assert.strictEqual(part.mimetype, 'binary/octet-stream')

await streamToNull(part.file)
}
}

const memory = process.memoryUsage()
t.ok(memory.rss < 500 * 1024 * 1024)
t.ok(memory.heapTotal < 500 * 1024 * 1024)
t.assert.ok(memory.rss < 500 * 1024 * 1024)
t.assert.ok(memory.heapTotal < 500 * 1024 * 1024)

reply.send()
})
Expand All @@ -66,7 +66,7 @@ test('should upload a big file in constant memory', { skip: process.env.CI }, fu
total -= n

if (total === 0) {
t.pass('finished generating')
t.assert.ok('finished generating')
hashInput.end()
this.push(null)
}
Expand All @@ -88,12 +88,18 @@ test('should upload a big file in constant memory', { skip: process.env.CI }, fu
method: 'POST'
}

const req = http.request(opts, () => { fastify.close(noop) })
const req = http.request(opts, (res) => {
res.on('data', () => {})

res.on('end', () => {
fastify.close(() => {
done()
})
})
})
Comment on lines +91 to +99
Copy link

Copilot AI Sep 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The response handling has been changed to call done() inside the fastify.close() callback, but this creates a race condition. If the pump operation fails, done() will never be called, causing the test to hang.

Copilot uses AI. Check for mistakes.

pump(form, req, function (err) {
t.error(err, 'client pump: no err')
t.assert.ifError(err, 'client pump: no err')
})
})
})

function noop () { }
62 changes: 31 additions & 31 deletions test/fix-313.test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use strict'

const test = require('tap').test
const test = require('node:test')
const FormData = require('form-data')
const Fastify = require('fastify')
const multipart = require('..')
Expand All @@ -17,38 +17,38 @@ test('should store file on disk, remove on response when attach fields to body i
t.plan(25)

const fastify = Fastify()
t.teardown(fastify.close.bind(fastify))
t.after(() => fastify.close())

fastify.register(multipart, {
attachFieldsToBody: true
})

fastify.post('/', async function (req, reply) {
t.ok(req.isMultipart())
t.assert.ok(req.isMultipart())

const files = await req.saveRequestFiles()

t.ok(files[0].filepath)
t.equal(files[0].type, 'file')
t.equal(files[0].fieldname, 'upload')
t.equal(files[0].filename, 'README.md')
t.equal(files[0].encoding, '7bit')
t.equal(files[0].mimetype, 'text/markdown')
t.ok(files[0].fields.upload)
t.ok(files[1].filepath)
t.equal(files[1].type, 'file')
t.equal(files[1].fieldname, 'upload')
t.equal(files[1].filename, 'README.md')
t.equal(files[1].encoding, '7bit')
t.equal(files[1].mimetype, 'text/markdown')
t.ok(files[1].fields.upload)
t.ok(files[2].filepath)
t.equal(files[2].type, 'file')
t.equal(files[2].fieldname, 'other')
t.equal(files[2].filename, 'README.md')
t.equal(files[2].encoding, '7bit')
t.equal(files[2].mimetype, 'text/markdown')
t.ok(files[2].fields.upload)
t.assert.ok(files[0].filepath)
t.assert.strictEqual(files[0].type, 'file')
t.assert.strictEqual(files[0].fieldname, 'upload')
t.assert.strictEqual(files[0].filename, 'README.md')
t.assert.strictEqual(files[0].encoding, '7bit')
t.assert.strictEqual(files[0].mimetype, 'text/markdown')
t.assert.ok(files[0].fields.upload)
t.assert.ok(files[1].filepath)
t.assert.strictEqual(files[1].type, 'file')
t.assert.strictEqual(files[1].fieldname, 'upload')
t.assert.strictEqual(files[1].filename, 'README.md')
t.assert.strictEqual(files[1].encoding, '7bit')
t.assert.strictEqual(files[1].mimetype, 'text/markdown')
t.assert.ok(files[1].fields.upload)
t.assert.ok(files[2].filepath)
t.assert.strictEqual(files[2].type, 'file')
t.assert.strictEqual(files[2].fieldname, 'other')
t.assert.strictEqual(files[2].filename, 'README.md')
t.assert.strictEqual(files[2].encoding, '7bit')
t.assert.strictEqual(files[2].mimetype, 'text/markdown')
t.assert.ok(files[2].fields.upload)

await access(files[0].filepath, fs.constants.F_OK)
await access(files[1].filepath, fs.constants.F_OK)
Expand All @@ -63,8 +63,8 @@ test('should store file on disk, remove on response when attach fields to body i
try {
await access(request.tmpUploads[0], fs.constants.F_OK)
} catch (error) {
t.equal(error.code, 'ENOENT')
t.pass('Temp file was removed after response')
t.assert.strictEqual(error.code, 'ENOENT')
t.assert.ok('Temp file was removed after response')
ee.emit('response')
}
})
Expand All @@ -89,7 +89,7 @@ test('should store file on disk, remove on response when attach fields to body i
form.pipe(req)

const [res] = await once(req, 'response')
t.equal(res.statusCode, 200)
t.assert.strictEqual(res.statusCode, 200)
res.resume()
await once(res, 'end')
await once(ee, 'response')
Expand All @@ -99,7 +99,7 @@ test('should throw on saving request files when attach fields to body is true bu
t.plan(3)

const fastify = Fastify()
t.teardown(fastify.close.bind(fastify))
t.after(() => fastify.close())

fastify.register(multipart, {
attachFieldsToBody: true,
Expand All @@ -111,13 +111,13 @@ test('should throw on saving request files when attach fields to body is true bu
})

fastify.post('/', async function (req, reply) {
t.ok(req.isMultipart())
t.assert.ok(req.isMultipart())

try {
await req.saveRequestFiles()
reply.code(200).send()
} catch (error) {
t.ok(error instanceof fastify.multipartErrors.FileBufferNotFoundError)
t.assert.ok(error instanceof fastify.multipartErrors.FileBufferNotFoundError)
reply.code(500).send()
}
})
Expand All @@ -140,7 +140,7 @@ test('should throw on saving request files when attach fields to body is true bu
form.pipe(req)

const [res] = await once(req, 'response')
t.equal(res.statusCode, 500)
t.assert.strictEqual(res.statusCode, 500)
res.resume()
await once(res, 'end')
})
14 changes: 7 additions & 7 deletions test/generate-id.test.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
'use strict'

const { test } = require('tap')
const { test } = require('node:test')
const { generateId } = require('../lib/generateId')

test('returns', t => {
t.plan(3)
t.type(generateId, 'function', 'is a function')
t.type(generateId(), 'string', '~> returns a string')
t.equal(generateId().length, 16, '~> has 16 characters (default)')
t.assert.strictEqual(typeof generateId, 'function', 'is a function')
t.assert.strictEqual(typeof generateId(), 'string', '~> returns a string')
t.assert.strictEqual(generateId().length, 16, '~> has 16 characters (default)')
})

test('length', t => {
Expand All @@ -18,18 +18,18 @@ test('length', t => {
let tmp = ''
for (; i < iterations; ++i) {
tmp = generateId()
t.equal(tmp.length, 16, `"${tmp}" is 16 characters`)
t.assert.strictEqual(tmp.length, 16, `"${tmp}" is 16 characters`)
}
})

test('unique /1', t => {
t.plan(1)
t.not(generateId(), generateId(), '~> single')
t.assert.notStrictEqual(generateId(), generateId(), '~> single')
})

test('unique /2', t => {
t.plan(1)
const items = new Set()
for (let i = 5e6; i--;) items.add(generateId())
t.equal(items.size, 5e6, '~> 5,000,000 unique ids')
t.assert.strictEqual(items.size, 5e6, '~> 5,000,000 unique ids')
})
44 changes: 21 additions & 23 deletions test/multipart-ajv-file.test.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
'use strict'

const test = require('tap').test
const Fastify = require('fastify')
const FormData = require('form-data')
const http = require('node:http')
const multipart = require('..')
const { once } = require('node:events')
const fs = require('node:fs')
const path = require('node:path')
const test = require('node:test')

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

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

const fastify = Fastify({
Expand All @@ -20,7 +20,7 @@ test('show modify the generated schema', async function (t) {
}
})

t.teardown(fastify.close.bind(fastify))
t.after(() => fastify.close())

await fastify.register(multipart, { attachFieldsToBody: true })
await fastify.register(require('@fastify/swagger'), {
Expand All @@ -31,7 +31,7 @@ test('show modify the generated schema', async function (t) {
}
})

await fastify.post(
fastify.post(
'/',
{
schema: {
Expand All @@ -52,26 +52,24 @@ test('show modify the generated schema', async function (t) {

await fastify.ready()

t.match(fastify.swagger(), {
paths: {
'/': {
post: {
operationId: 'test',
requestBody: {
content: {
'multipart/form-data': {
schema: {
type: 'object',
properties: {
field: { type: 'string', format: 'binary' }
}
t.assert.deepStrictEqual(fastify.swagger().paths, {
'/': {
post: {
operationId: 'test',
requestBody: {
content: {
'multipart/form-data': {
schema: {
type: 'object',
properties: {
field: { type: 'string', format: 'binary' }
}
}
}
},
responses: {
200: { description: 'Default Response' }
}
},
responses: {
200: { description: 'Default Response' }
}
}
}
Expand All @@ -97,7 +95,7 @@ test('show modify the generated schema', async function (t) {
const [res] = await once(req, 'response')
res.resume()
await once(res, 'end')
t.equal(res.statusCode, 400) // body/field should be a file
t.assert.strictEqual(res.statusCode, 400) // body/field should be a file
}

// request with file
Expand All @@ -118,7 +116,7 @@ test('show modify the generated schema', async function (t) {
const [res] = await once(req, 'response')
res.resume()
await once(res, 'end')
t.equal(res.statusCode, 200)
t.assert.strictEqual(res.statusCode, 200)
}
t.pass('res ended successfully')
t.assert.ok('res ended successfully')
})
Loading
Loading