diff --git a/.eslintrc b/.eslintrc index 587e81d..550b769 100644 --- a/.eslintrc +++ b/.eslintrc @@ -2,5 +2,17 @@ "extends": "standard-with-typescript", "parserOptions": { "project": "./tsconfig.json" - } + }, + "rules": { + // conflict between standard and standard-typescript + "no-void": ["error", { "allowAsStatement": true }] + }, + "overrides": [ + { + "files": [ "**/*.test.ts"], + "rules": { + "@typescript-eslint/no-floating-promises": "off" + } + } + ] } \ No newline at end of file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ffc13f5..60f4892 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,12 +14,15 @@ env: COVERALLS: 0 jobs: - build: + test: runs-on: ${{ matrix.os }} + outputs: + COVERALLS: ${{ steps.coveralls-trigger.outputs.COVERALLS_TRIGGER }} + strategy: matrix: # Maintenance and active LTS - node-version: [12, 14, 16] + node-version: [10, 12, 14, 16] os: [ubuntu-latest, windows-latest, macOS-latest] name: Node ${{ matrix.node-version }} @@ -28,7 +31,7 @@ jobs: - name: Use Node.js id: setup_node - uses: actions/setup-node@v2.4.0 + uses: actions/setup-node@v2.4.1 with: node-version: ${{ matrix.node-version }} @@ -50,19 +53,26 @@ jobs: run: npm run coverage - name: Coveralls Parallel + id: coveralls-parallel + continue-on-error: true uses: coverallsapp/github-action@1.1.3 with: github-token: ${{ secrets.GITHUB_TOKEN }} parallel: true flag-name: run-${{ matrix.node-version }}-${{ matrix.os }} - - name: Typescript - id: typescript_test - run: npm run typescript --if-present + - name: Should Trigger coverallsapp/github-action@1.1.3 + id: coveralls-trigger + # https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#steps-context + # when continue-on-error failed, outcome is failure and conclusion is success + if: steps.coveralls-parallel.conclusion == 'success' && steps.coveralls-parallel.outcome != 'success' + run: | + echo "::set-output name=COVERALLS_TRIGGER::failure" coverage: - needs: build + needs: test runs-on: ubuntu-latest + if: needs.test.outputs.COVERALLS != 'failure' steps: - name: Coveralls Finished uses: coverallsapp/github-action@1.1.3 @@ -71,10 +81,10 @@ jobs: parallel-finished: true automerge: - needs: build + needs: test runs-on: ubuntu-latest steps: - - uses: fastify/github-action-merge-dependabot@v2.4.0 + - uses: fastify/github-action-merge-dependabot@v2.5.0 if: ${{ github.actor == 'dependabot[bot]' && github.event_name == 'pull_request' }} with: github-token: ${{secrets.GITHUB_TOKEN}} \ No newline at end of file diff --git a/.github/workflows/package-manager-ci.yml b/.github/workflows/package-manager-ci.yml index 26a4d56..5626c1a 100644 --- a/.github/workflows/package-manager-ci.yml +++ b/.github/workflows/package-manager-ci.yml @@ -4,6 +4,7 @@ on: push: branches: - master + - main jobs: pnpm: @@ -12,14 +13,14 @@ jobs: strategy: matrix: # Maintenance and active LTS - node-version: [12, 14, 16] + node-version: [10, 12, 14, 16] os: [ubuntu-latest] steps: - uses: actions/checkout@v2 - name: Use Node.js - uses: actions/setup-node@v2.4.0 + uses: actions/setup-node@v2.4.1 id: setup_node with: node-version: ${{ matrix.node-version }} @@ -39,7 +40,7 @@ jobs: strategy: matrix: # Maintenance and active LTS - node-version: [12, 14, 16] + node-version: [10, 12, 14, 16] os: [ubuntu-latest] steps: @@ -47,7 +48,7 @@ jobs: - name: Use Node.js id: setup_node - uses: actions/setup-node@v2.4.0 + uses: actions/setup-node@v2.4.1 with: node-version: ${{ matrix.node-version }} diff --git a/.taprc b/.taprc new file mode 100644 index 0000000..25ec37d --- /dev/null +++ b/.taprc @@ -0,0 +1,5 @@ +ts: true +jsx: false +flow: false +check-coverage: true +coverage: true \ No newline at end of file diff --git a/jest.config.js b/jest.config.js deleted file mode 100644 index 251220e..0000000 --- a/jest.config.js +++ /dev/null @@ -1,6 +0,0 @@ -module.exports = { - verbose: true, - preset: 'ts-jest', - testEnvironment: 'node', - collectCoverageFrom: ['lib/**/*'] -} diff --git a/lib/index.ts b/lib/index.ts index 6106ec0..9319b65 100644 --- a/lib/index.ts +++ b/lib/index.ts @@ -69,7 +69,7 @@ const plugin: FastifyPluginAsync = async function (fas await fs.promises.mkdir(options.formidable.uploadDir, { recursive: true }) } - const formidable = new IncomingForm(options.formidable) + const formidable = options.formidable instanceof IncomingForm ? options.formidable : new IncomingForm(options.formidable) fastify.decorateRequest(kIsMultipart, false) fastify.decorateRequest(kIsMultipartParsed, false) diff --git a/package.json b/package.json index 9729463..8a8baa2 100644 --- a/package.json +++ b/package.json @@ -14,13 +14,14 @@ "lib": "lib" }, "scripts": { + "clean": "npx rimraf \"lib/**/*.js\" \"lib/**/*.map\" \"lib/**/*.d.ts\" \"test/**/*.js\" \"test/**/*.map\" \"test/**/*.d.ts\"", "lint": "eslint --ext .ts lib test", "lint:fix": "npm run lint -- --fix", "build": "rollup -c", "build:tsc": "tsc -b", - "unit": "jest", + "unit": "tap", "test": "npm run lint && npm run unit", - "coverage": "jest --coverage", + "coverage": "tap --coverage --coverage-report=lcovonly", "prepublishOnly": "npm run build" }, "publishConfig": { @@ -40,29 +41,21 @@ }, "devDependencies": { "@rollup/plugin-typescript": "^8.2.1", - "@types/jest": "^27.0.1", - "@typescript-eslint/eslint-plugin": "4", - "eslint": "7", - "eslint-config-standard-with-typescript": "^20.0.0", - "eslint-plugin-import": "2", - "eslint-plugin-node": "11", - "eslint-plugin-promise": "5", - "eslint-plugin-standard": "5", + "@types/tap": "^15.0.5", + "@typescript-eslint/eslint-plugin": "^4.0.1", + "eslint": "^7.12.1", + "eslint-config-standard-with-typescript": "^21.0.1", + "eslint-plugin-import": "^2.22.1", + "eslint-plugin-node": "^11.1.0", + "eslint-plugin-promise": "^5.0.0", "fastify": "^3.19.0", "fastify-swagger": "^4.8.2", "form-data": "^4.0.0", - "husky": "^7.0.1", - "jest": "^27.0.6", "prettier": "^2.3.2", "rollup": "^2.53.1", - "ts-jest": "^27.0.3", + "tap": "^15.0.10", + "ts-node": "^10.4.0", "typescript": "^4.3.5", "undici": "^4.1.0" - }, - "husky": { - "hooks": { - "pre-commit": "npm test", - "pre-push": "npm test" - } } } diff --git a/test/addContentTypeParser.test.ts b/test/addContentTypeParser.test.ts index 8fa4efd..7a14e70 100644 --- a/test/addContentTypeParser.test.ts +++ b/test/addContentTypeParser.test.ts @@ -1,36 +1,41 @@ import * as fs from 'fs' import { AddressInfo } from 'net' import * as path from 'path' +import t from 'tap' import { createFastify } from './createFastify' import { request } from './request' import FormData = require('form-data') const filePath = path.join(__dirname, '../package.json') -describe('addContentTypeParser', function () { - test('single file', async function () { - const fastify = await createFastify({ addContentTypeParser: true }) +t.plan(1) +t.test('addContentTypeParser', function (t) { + t.plan(2) + + t.test('single file', async function (t) { + t.plan(5) + + const fastify = await createFastify(t, { addContentTypeParser: true }) const form = new FormData() form.append('foo', 'bar') form.append('file', fs.createReadStream(filePath)) const response = await request(`http://localhost:${(fastify.server.address() as AddressInfo).port}`, form) - - expect(response.status).toStrictEqual(200) + t.equal(response.status, 200) const json = await response.json() - expect(json.body.foo).toStrictEqual('bar') - expect(/upload_/.test(json.body.file)).toStrictEqual(true) - expect(json.files.file).toBeDefined() - expect(json.files.file.name).toStrictEqual('package.json') - - await fastify.close() + t.equal(json.body.foo, 'bar') + t.equal(/upload_/.test(json.body.file), true) + t.ok(json.files.file) + t.equal(json.files.file.name, 'package.json') }) - test('multiple files', async function () { - const fastify = await createFastify({ addContentTypeParser: true, formidable: { multiples: true } }) + t.test('multiple files', async function (t) { + t.plan(6) + + const fastify = await createFastify(t, { addContentTypeParser: true, formidable: { multiples: true } }) const form = new FormData() form.append('foo', 'bar') @@ -39,16 +44,14 @@ describe('addContentTypeParser', function () { const response = await request(`http://localhost:${(fastify.server.address() as AddressInfo).port}`, form) - expect(response.status).toStrictEqual(200) + t.equal(response.status, 200) const json = await response.json() - expect(json.body.foo).toStrictEqual('bar') - expect(Array.isArray(json.body.file)).toStrictEqual(true) - expect(json.files.file).toBeDefined() - expect(json.files.file[0].name).toStrictEqual('package.json') - expect(json.files.file[1].name).toStrictEqual('package.json') - - await fastify.close() + t.equal(json.body.foo, 'bar') + t.equal(Array.isArray(json.body.file), true) + t.ok(json.files.file) + t.equal(json.files.file[0].name, 'package.json') + t.equal(json.files.file[1].name, 'package.json') }) }) diff --git a/test/addHooks.test.ts b/test/addHooks.test.ts index baaafce..44dce88 100644 --- a/test/addHooks.test.ts +++ b/test/addHooks.test.ts @@ -1,15 +1,21 @@ import * as fs from 'fs' import { AddressInfo } from 'net' import * as path from 'path' +import t from 'tap' import { createFastify } from './createFastify' -import { request } from './request' +import { request, requestJSON } from './request' import FormData = require('form-data') const filePath = path.join(__dirname, '../package.json') -describe('addHooks', function () { - test('single file', async function () { - const fastify = await createFastify({ addHooks: true }) +t.plan(1) +t.test('addHooks', function (t) { + t.plan(3) + + t.test('single file', async function (t) { + t.plan(5) + + const fastify = await createFastify(t, { addHooks: true }) const form = new FormData() form.append('foo', 'bar') @@ -17,20 +23,20 @@ describe('addHooks', function () { const response = await request(`http://localhost:${(fastify.server.address() as AddressInfo).port}`, form) - expect(response.status).toStrictEqual(200) + t.equal(response.status, 200) const json = await response.json() - expect(json.body.foo).toStrictEqual('bar') - expect(/upload_/.test(json.body.file)).toStrictEqual(true) - expect(json.files.file).toBeDefined() - expect(json.files.file.name).toStrictEqual('package.json') - - await fastify.close() + t.equal(json.body.foo, 'bar') + t.equal(/upload_/.test(json.body.file), true) + t.ok(json.files.file) + t.equal(json.files.file.name, 'package.json') }) - test('multiple files', async function () { - const fastify = await createFastify({ addHooks: true, formidable: { multiples: true } }) + t.test('multiple files', async function (t) { + t.plan(6) + + const fastify = await createFastify(t, { addHooks: true, formidable: { multiples: true } }) const form = new FormData() form.append('foo', 'bar') @@ -39,16 +45,31 @@ describe('addHooks', function () { const response = await request(`http://localhost:${(fastify.server.address() as AddressInfo).port}`, form) - expect(response.status).toStrictEqual(200) + t.equal(response.status, 200) const json = await response.json() - expect(json.body.foo).toStrictEqual('bar') - expect(Array.isArray(json.body.file)).toStrictEqual(true) - expect(json.files.file).toBeDefined() - expect(json.files.file[0].name).toStrictEqual('package.json') - expect(json.files.file[1].name).toStrictEqual('package.json') + t.equal(json.body.foo, 'bar') + t.equal(Array.isArray(json.body.file), true) + t.ok(json.files.file) + t.equal(json.files.file[0].name, 'package.json') + t.equal(json.files.file[1].name, 'package.json') + }) + + t.test('non-multipart', async function (t) { + t.plan(3) + + const fastify = await createFastify(t, { addHooks: true, removeFilesFromBody: true }) + + const response = await requestJSON(`http://localhost:${(fastify.server.address() as AddressInfo).port}`, { + foo: 'bar' + } as any) + + t.equal(response.status, 200) + + const json = await response.json() - await fastify.close() + t.equal(json.body.foo, 'bar') + t.equal(json.files, null) }) }) diff --git a/test/createFastify.ts b/test/createFastify.ts index fffb1d0..b0b2747 100644 --- a/test/createFastify.ts +++ b/test/createFastify.ts @@ -6,7 +6,7 @@ import FastifyFormidable, { ajvBinaryFormat, FastifyFormidableOptions } from '.. // reduce keep alive to prevent `undici` keep the socket open export const fastifyOptions = { keepAliveTimeout: 100 } -export async function createFastify (options: FastifyFormidableOptions, inline: boolean | Options = false): Promise { +export async function createFastify (t: Tap.Test, options: FastifyFormidableOptions, inline: boolean | Options = false): Promise { const fastify = Fastify(fastifyOptions) await fastify.register(FastifyFormidable, options) @@ -22,10 +22,12 @@ export async function createFastify (options: FastifyFormidableOptions, inline: await fastify.listen(0) + t.teardown(fastify.close) + return await fastify } -export async function createIntegrationFastify (options: FastifyFormidableOptions, schema: any, inline: boolean = false): Promise { +export async function createIntegrationFastify (t: Tap.Test, options: FastifyFormidableOptions, schema: any, inline: boolean = false): Promise { const fastify = Fastify({ ...fastifyOptions, ajv: { @@ -48,5 +50,7 @@ export async function createIntegrationFastify (options: FastifyFormidableOption await fastify.listen(0) + t.teardown(fastify.close) + return await fastify } diff --git a/test/error.test.ts b/test/error.test.ts index 83c7360..29b8f40 100644 --- a/test/error.test.ts +++ b/test/error.test.ts @@ -1,14 +1,65 @@ -import { createFastify } from './createFastify' +import Fastify from 'fastify' +import { IncomingForm } from 'formidable' +import * as fs from 'fs' +import { AddressInfo } from 'net' +import * as path from 'path' +import t from 'tap' +import FastifyFormidable from '../lib' +import { createFastify, fastifyOptions } from './createFastify' +import { request } from './request' +import FormData = require('form-data') + +const filePath = path.join(__dirname, '../package.json') + +t.plan(1) +t.test('error', function (t) { + t.plan(2) + + t.test('`addContentTypeParser` and `addHooks`', async function (t) { + t.plan(2) -describe('error', function () { - test('`addContentTypeParser` and `addHooks`', async function () { try { - await createFastify({ addHooks: true, addContentTypeParser: true }) + await createFastify(t, { addHooks: true, addContentTypeParser: true }) // should not get here - expect(true).toStrictEqual(false) - } catch (err) { - expect(err).toBeDefined() - expect(err.message).toStrictEqual('Cannot enable `addContentTypeParser` togather with `addHooks`') + t.fail() + } catch (err: any) { + t.ok(err) + t.equal(err.message, 'Cannot enable `addContentTypeParser` togather with `addHooks`') } }) + + t.test('parse error', async function (t) { + t.plan(1) + + const fastify = Fastify(fastifyOptions) + + t.teardown(fastify.close) + + const formidable = new IncomingForm() + formidable.parse = function (_, callback: Function) { + callback(new Error('parse error')) + } + + await fastify.register(FastifyFormidable, { + formidable: formidable as any + }) + + fastify.post<{ Body: { foo: String, file: string } }>('/', async function (request, reply) { + const body = await request.parseMultipart() + return await reply.code(200).send({ + body: body, + files: request.files + }) + }) + + await fastify.listen(0) + + const form = new FormData() + form.append('foo', 'bar') + form.append('file', fs.createReadStream(filePath)) + + const response = await request(`http://localhost:${(fastify.server.address() as AddressInfo).port}`, form) + + t.equal(response.status, 500) + }) }) diff --git a/test/integration.test.ts b/test/integration.test.ts index a6dbdd7..55ba5ee 100644 --- a/test/integration.test.ts +++ b/test/integration.test.ts @@ -1,15 +1,21 @@ import * as fs from 'fs' import { AddressInfo } from 'net' import * as path from 'path' +import t from 'tap' import { createIntegrationFastify } from './createFastify' import { request } from './request' import FormData = require('form-data') const filePath = path.join(__dirname, '../package.json') -describe('integration', function () { - test('single file', async function () { - const fastify = await createIntegrationFastify({ addContentTypeParser: true }, { +t.plan(1) +t.test('integration', function (t) { + t.plan(2) + + t.test('single file', async function (t) { + t.plan(5) + + const fastify = await createIntegrationFastify(t, { addContentTypeParser: true }, { body: { type: 'object', properties: { @@ -25,20 +31,20 @@ describe('integration', function () { const response = await request(`http://localhost:${(fastify.server.address() as AddressInfo).port}`, form) - expect(response.status).toStrictEqual(200) + t.equal(response.status, 200) const json = await response.json() - expect(json.body.foo).toStrictEqual('bar') - expect(/upload_/.test(json.body.file)).toStrictEqual(true) - expect(json.files.file).toBeDefined() - expect(json.files.file.name).toStrictEqual('package.json') - - await fastify.close() + t.equal(json.body.foo, 'bar') + t.equal(/upload_/.test(json.body.file), true) + t.ok(json.files.file) + t.equal(json.files.file.name, 'package.json') }) - test('multiple files', async function () { - const fastify = await createIntegrationFastify({ addContentTypeParser: true, formidable: { multiples: true } }, { + t.test('multiple files', async function (t) { + t.plan(6) + + const fastify = await createIntegrationFastify(t, { addContentTypeParser: true, formidable: { multiples: true } }, { body: { type: 'object', properties: { @@ -55,16 +61,14 @@ describe('integration', function () { const response = await request(`http://localhost:${(fastify.server.address() as AddressInfo).port}`, form) - expect(response.status).toStrictEqual(200) + t.equal(response.status, 200) const json = await response.json() - expect(json.body.foo).toStrictEqual('bar') - expect(Array.isArray(json.body.file)).toStrictEqual(true) - expect(json.files.file).toBeDefined() - expect(json.files.file[0].name).toStrictEqual('package.json') - expect(json.files.file[1].name).toStrictEqual('package.json') - - await fastify.close() + t.equal(json.body.foo, 'bar') + t.equal(Array.isArray(json.body.file), true) + t.ok(json.files.file) + t.equal(json.files.file[0].name, 'package.json') + t.equal(json.files.file[1].name, 'package.json') }) }) diff --git a/test/parseMultipart.test.ts b/test/parseMultipart.test.ts index 8fb28d1..f0e7e32 100644 --- a/test/parseMultipart.test.ts +++ b/test/parseMultipart.test.ts @@ -1,15 +1,21 @@ import * as fs from 'fs' import { AddressInfo } from 'net' import * as path from 'path' +import t from 'tap' import { createFastify } from './createFastify' import { request } from './request' import FormData = require('form-data') const filePath = path.join(__dirname, '../package.json') -describe('parseMultipart', function () { - test('single file', async function () { - const fastify = await createFastify({ }, true) +t.plan(1) +t.test('parseMultipart', function (t) { + t.plan(4) + + t.test('single file', async function (t) { + t.plan(5) + + const fastify = await createFastify(t, { }, true) const form = new FormData() form.append('foo', 'bar') @@ -17,20 +23,20 @@ describe('parseMultipart', function () { const response = await request(`http://localhost:${(fastify.server.address() as AddressInfo).port}`, form) - expect(response.status).toStrictEqual(200) + t.equal(response.status, 200) const json = await response.json() - expect(json.body.foo).toStrictEqual('bar') - expect(/upload_/.test(json.body.file)).toStrictEqual(true) - expect(json.files.file).toBeDefined() - expect(json.files.file.name).toStrictEqual('package.json') - - await fastify.close() + t.equal(json.body.foo, 'bar') + t.equal(/upload_/.test(json.body.file), true) + t.ok(json.files.file) + t.equal(json.files.file.name, 'package.json') }) - test('multiple files', async function () { - const fastify = await createFastify({ formidable: { multiples: true } }, true) + t.test('multiple files', async function (t) { + t.plan(6) + + const fastify = await createFastify(t, { formidable: { multiples: true } }, true) const form = new FormData() form.append('foo', 'bar') @@ -39,21 +45,21 @@ describe('parseMultipart', function () { const response = await request(`http://localhost:${(fastify.server.address() as AddressInfo).port}`, form) - expect(response.status).toStrictEqual(200) + t.equal(response.status, 200) const json = await response.json() - expect(json.body.foo).toStrictEqual('bar') - expect(Array.isArray(json.body.file)).toStrictEqual(true) - expect(json.files.file).toBeDefined() - expect(json.files.file[0].name).toStrictEqual('package.json') - expect(json.files.file[1].name).toStrictEqual('package.json') - - await fastify.close() + t.equal(json.body.foo, 'bar') + t.equal(Array.isArray(json.body.file), true) + t.ok(json.files.file) + t.equal(json.files.file[0].name, 'package.json') + t.equal(json.files.file[1].name, 'package.json') }) - test('options - single file', async function () { - const fastify = await createFastify({ }, {}) + t.test('options - single file', async function (t) { + t.plan(5) + + const fastify = await createFastify(t, { }, {}) const form = new FormData() form.append('foo', 'bar') @@ -61,20 +67,20 @@ describe('parseMultipart', function () { const response = await request(`http://localhost:${(fastify.server.address() as AddressInfo).port}`, form) - expect(response.status).toStrictEqual(200) + t.equal(response.status, 200) const json = await response.json() - expect(json.body.foo).toStrictEqual('bar') - expect(/upload_/.test(json.body.file)).toStrictEqual(true) - expect(json.files.file).toBeDefined() - expect(json.files.file.name).toStrictEqual('package.json') - - await fastify.close() + t.equal(json.body.foo, 'bar') + t.equal(/upload_/.test(json.body.file), true) + t.ok(json.files.file) + t.equal(json.files.file.name, 'package.json') }) - test('options - multiple files', async function () { - const fastify = await createFastify({ }, { multiples: true }) + t.test('options - multiple files', async function (t) { + t.plan(6) + + const fastify = await createFastify(t, { }, { multiples: true }) const form = new FormData() form.append('foo', 'bar') @@ -83,16 +89,14 @@ describe('parseMultipart', function () { const response = await request(`http://localhost:${(fastify.server.address() as AddressInfo).port}`, form) - expect(response.status).toStrictEqual(200) + t.equal(response.status, 200) const json = await response.json() - expect(json.body.foo).toStrictEqual('bar') - expect(Array.isArray(json.body.file)).toStrictEqual(true) - expect(json.files.file).toBeDefined() - expect(json.files.file[0].name).toStrictEqual('package.json') - expect(json.files.file[1].name).toStrictEqual('package.json') - - await fastify.close() + t.equal(json.body.foo, 'bar') + t.equal(Array.isArray(json.body.file), true) + t.ok(json.files.file) + t.equal(json.files.file[0].name, 'package.json') + t.equal(json.files.file[1].name, 'package.json') }) }) diff --git a/test/removeFilesFromBody.test.ts b/test/removeFilesFromBody.test.ts index 2f1275a..29b10fe 100644 --- a/test/removeFilesFromBody.test.ts +++ b/test/removeFilesFromBody.test.ts @@ -1,7 +1,8 @@ -import Fastify, { FastifyInstance } from 'fastify' +import Fastify from 'fastify' import * as fs from 'fs' import { AddressInfo } from 'net' import * as path from 'path' +import t from 'tap' import FastifyFormidable from '../lib' import { fastifyOptions } from './createFastify' import { request } from './request' @@ -9,11 +10,17 @@ import FormData = require('form-data') const filePath = path.join(__dirname, '../package.json') -describe('removeFilesFromBody', function () { - let fastify: FastifyInstance +t.plan(1) +t.test('removeFilesFromBody', function (t) { + t.plan(4) + + t.test('with addContentTypeParser', async function (t) { + t.plan(5) + + const fastify = Fastify(fastifyOptions) + + t.teardown(fastify.close) - test('with addContentTypeParser', async function () { - fastify = Fastify(fastifyOptions) await fastify.register(FastifyFormidable, { addContentTypeParser: true, removeFilesFromBody: true @@ -34,18 +41,23 @@ describe('removeFilesFromBody', function () { const response = await request(`http://localhost:${(fastify.server.address() as AddressInfo).port}`, form) - expect(response.status).toStrictEqual(200) + t.equal(response.status, 200) const json = await response.json() - expect(json.body.foo).toStrictEqual('bar') - expect(json.body.file).toBeUndefined() - expect(json.files.file).toBeDefined() - expect(json.files.file.name).toStrictEqual('package.json') + t.equal(json.body.foo, 'bar') + t.notOk(json.body.file) + t.ok(json.files.file) + t.equal(json.files.file.name, 'package.json') }) - test('with addHooks', async function () { - fastify = Fastify(fastifyOptions) + t.test('with addHooks', async function (t) { + t.plan(5) + + const fastify = Fastify(fastifyOptions) + + t.teardown(fastify.close) + await fastify.register(FastifyFormidable, { addHooks: true, removeFilesFromBody: true @@ -66,18 +78,23 @@ describe('removeFilesFromBody', function () { const response = await request(`http://localhost:${(fastify.server.address() as AddressInfo).port}`, form) - expect(response.status).toStrictEqual(200) + t.equal(response.status, 200) const json = await response.json() - expect(json.body.foo).toStrictEqual('bar') - expect(json.body.file).toBeUndefined() - expect(json.files.file).toBeDefined() - expect(json.files.file.name).toStrictEqual('package.json') + t.equal(json.body.foo, 'bar') + t.notOk(json.body.file) + t.ok(json.files.file) + t.equal(json.files.file.name, 'package.json') }) - test('with parseMultipart', async function () { - fastify = Fastify(fastifyOptions) + t.test('with parseMultipart', async function (t) { + t.plan(5) + + const fastify = Fastify(fastifyOptions) + + t.teardown(fastify.close) + await fastify.register(FastifyFormidable, { removeFilesFromBody: true }) @@ -98,17 +115,48 @@ describe('removeFilesFromBody', function () { const response = await request(`http://localhost:${(fastify.server.address() as AddressInfo).port}`, form) - expect(response.status).toStrictEqual(200) + t.equal(response.status, 200) const json = await response.json() - expect(json.body.foo).toStrictEqual('bar') - expect(json.body.file).toBeUndefined() - expect(json.files.file).toBeDefined() - expect(json.files.file.name).toStrictEqual('package.json') + t.equal(json.body.foo, 'bar') + t.notOk(json.body.file) + t.ok(json.files.file) + t.equal(json.files.file.name, 'package.json') }) - afterEach(async function () { - await fastify.close() + t.test('no file', async function (t) { + t.plan(4) + + const fastify = Fastify(fastifyOptions) + + t.teardown(fastify.close) + + await fastify.register(FastifyFormidable, { + addContentTypeParser: true, + removeFilesFromBody: true + }) + + fastify.post<{ Body: { foo: String, file: string } }>('/', async function (request, reply) { + return await reply.code(200).send({ + body: request.body, + files: request.files + }) + }) + + await fastify.listen(0) + + const form = new FormData() + form.append('foo', 'bar') + + const response = await request(`http://localhost:${(fastify.server.address() as AddressInfo).port}`, form) + + t.equal(response.status, 200) + + const json = await response.json() + + t.equal(json.body.foo, 'bar') + t.notOk(json.body.file) + t.notOk(json.files.file) }) }) diff --git a/test/request.ts b/test/request.ts index 5d58cff..9a57671 100644 --- a/test/request.ts +++ b/test/request.ts @@ -34,3 +34,23 @@ export async function request (url: string, formData: FormData): Promise<{ statu } } } + +export async function requestJSON (url: string, json: any): Promise<{ status: number, body: string, json: () => any }> { + const response = await undici.request(url, { + method: 'POST', + body: JSON.stringify(json), + headers: { + 'content-type': 'application/json' + } + }) + + const responseBody = await resolve(response.body) + + return { + status: response.statusCode, + body: responseBody, + json () { + return JSON.parse(responseBody) + } + } +} diff --git a/test/uploadDir.test.ts b/test/uploadDir.test.ts index 64e0b55..7e340d9 100644 --- a/test/uploadDir.test.ts +++ b/test/uploadDir.test.ts @@ -1,12 +1,18 @@ import Fastify from 'fastify' import * as fs from 'fs' import * as path from 'path' +import t from 'tap' import FastifyFormidable from '../lib' const uploadDir = path.resolve('tmp') -describe('uploadDir', function () { - test('create', async function () { +t.plan(1) +t.test('uploadDir', function (t) { + t.plan(1) + + t.test('create', async function (t) { + t.plan(1) + const fastify = Fastify() await fastify.register(FastifyFormidable, { formidable: { @@ -15,11 +21,11 @@ describe('uploadDir', function () { }) const stat = await fs.promises.lstat(uploadDir) - expect(stat.isDirectory()).toStrictEqual(true) - }) + t.equal(stat.isDirectory(), true) - afterEach(async function () { + t.teardown(async function () { // clean up - await fs.promises.rmdir(uploadDir) + await fs.promises.rmdir(uploadDir) + }) }) }) diff --git a/test/warning.test.ts b/test/warning.test.ts new file mode 100644 index 0000000..adf16be --- /dev/null +++ b/test/warning.test.ts @@ -0,0 +1,63 @@ +import Fastify from 'fastify' +import * as fs from 'fs' +import { AddressInfo } from 'net' +import * as path from 'path' +import t from 'tap' +import FastifyFormidable from '../lib' +import { fastifyOptions } from './createFastify' +import { request } from './request' +import FormData = require('form-data') + +const filePath = path.join(__dirname, '../package.json') + +t.plan(1) +t.test('warning', function (t) { + t.plan(1) + + t.test('multipart already parsed', async function (t) { + t.plan(6) + + const fastify = Fastify(fastifyOptions) + + t.teardown(fastify.close) + + await fastify.register(FastifyFormidable, { + addContentTypeParser: true, + removeFilesFromBody: true + }) + + fastify.post<{ Body: { foo: String, file: string } }>('/', { + onRequest (request, _, done) { + request.log = { + warn (msg: string) { + t.equal(msg, 'multipart already parsed, you probably need to check your code why it is parsed twice.') + } + } as any + done() + } + }, async function (request, reply) { + await request.parseMultipart() + return await reply.code(200).send({ + body: request.body, + files: request.files + }) + }) + + await fastify.listen(0) + + const form = new FormData() + form.append('foo', 'bar') + form.append('file', fs.createReadStream(filePath)) + + const response = await request(`http://localhost:${(fastify.server.address() as AddressInfo).port}`, form) + + t.equal(response.status, 200) + + const json = await response.json() + + t.equal(json.body.foo, 'bar') + t.notOk(json.body.file) + t.ok(json.files.file) + t.equal(json.files.file.name, 'package.json') + }) +})