From ed38f16e8dfe63664a0f3b98121643f09cb5bdcf Mon Sep 17 00:00:00 2001 From: Harminder Virk Date: Sun, 7 Jan 2024 18:43:42 +0530 Subject: [PATCH] refactor: fix issues post merge --- src/multipart/file.ts | 220 +++++ src/multipart/main.ts | 270 +++--- tests/body_parser.spec.ts | 1807 +++++++++++++++++-------------------- 3 files changed, 1159 insertions(+), 1138 deletions(-) create mode 100644 src/multipart/file.ts diff --git a/src/multipart/file.ts b/src/multipart/file.ts new file mode 100644 index 0000000..dd695dd --- /dev/null +++ b/src/multipart/file.ts @@ -0,0 +1,220 @@ +/* + * @adonisjs/bodyparser + * + * (c) AdonisJS + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +import { join } from 'node:path' +import { Exception } from '@poppinss/utils' +import Macroable from '@poppinss/macroable' + +import { moveFile } from '../helpers.js' +import { SizeValidator } from './validators/size.js' +import { ExtensionValidator } from './validators/extensions.js' +import type { FileJSON, FileUploadError, FileValidationOptions } from '../types.js' + +/** + * The file holds the meta/data for an uploaded file, along with + * an errors occurred during the upload process. + */ +export class MultipartFile extends Macroable { + /** + * File validators + */ + #sizeValidator = new SizeValidator(this) + #extensionValidator = new ExtensionValidator(this) + + /** + * A boolean to know if file is an instance of this class + * or not + */ + isMultipartFile: true = true + + /** + * Field name is the name of the field + */ + fieldName: string + + /** + * Client name is the file name on the user client + */ + clientName: string + + /** + * The headers sent as part of the multipart request + */ + headers: Record + + /** + * File size in bytes + */ + size: number = 0 + + /** + * The extname for the file. + */ + extname?: string + + /** + * Upload errors + */ + errors: FileUploadError[] = [] + + /** + * Type and subtype are extracted from the `content-type` + * header or from the file magic number + */ + type?: string + subtype?: string + + /** + * File path is only set after the move operation + */ + filePath?: string + + /** + * File name is only set after the move operation. It is the relative + * path of the moved file + */ + fileName?: string + + /** + * Tmp path, only exists when file is uploaded using the + * classic mode. + */ + tmpPath?: string + + /** + * The file meta data + */ + meta: any = {} + + /** + * The state of the file + */ + state: 'idle' | 'streaming' | 'consumed' | 'moved' = 'idle' + + /** + * Whether or not the validations have been executed + */ + get validated(): boolean { + return this.#sizeValidator.validated && this.#extensionValidator.validated + } + + /** + * A boolean to know if file has one or more errors + */ + get isValid() { + return this.errors.length === 0 + } + + /** + * Opposite of [[this.isValid]] + */ + get hasErrors() { + return !this.isValid + } + + /** + * The maximum file size limit + */ + get sizeLimit() { + return this.#sizeValidator.maxLimit + } + + set sizeLimit(limit: number | string | undefined) { + this.#sizeValidator.maxLimit = limit + } + + /** + * Extensions allowed + */ + get allowedExtensions() { + return this.#extensionValidator.extensions + } + + set allowedExtensions(extensions: string[] | undefined) { + this.#extensionValidator.extensions = extensions + } + + constructor( + data: { fieldName: string; clientName: string; headers: any }, + validationOptions: Partial + ) { + super() + this.sizeLimit = validationOptions.size + this.allowedExtensions = validationOptions.extnames + this.fieldName = data.fieldName + this.clientName = data.clientName + this.headers = data.headers + } + + /** + * Validate the file + */ + validate() { + this.#extensionValidator.validate() + this.#sizeValidator.validate() + } + + /** + * Mark file as moved + */ + markAsMoved(fileName: string, filePath: string) { + this.filePath = filePath + this.fileName = fileName + this.state = 'moved' + } + + /** + * Moves the file to a given location. Multiple calls to the `move` method are allowed, + * incase you want to move a file to multiple locations. + */ + async move(location: string, options?: { name?: string; overwrite?: boolean }): Promise { + if (!this.tmpPath) { + throw new Exception('property "tmpPath" must be set on the file before moving it', { + status: 500, + code: 'E_MISSING_FILE_TMP_PATH', + }) + } + + options = Object.assign({ name: this.clientName, overwrite: true }, options) + const filePath = join(location, options.name!) + + try { + await moveFile(this.tmpPath, filePath, { overwrite: options.overwrite! }) + this.markAsMoved(options.name!, filePath) + } catch (error) { + if (error.message.includes('destination file already')) { + throw new Exception( + `"${options.name!}" already exists at "${location}". Set "overwrite = true" to overwrite it` + ) + } + throw error + } + } + + /** + * Returns file JSON representation + */ + toJSON(): FileJSON { + return { + fieldName: this.fieldName, + clientName: this.clientName, + size: this.size, + filePath: this.filePath, + fileName: this.fileName, + type: this.type, + extname: this.extname, + subtype: this.subtype, + state: this.state, + isValid: this.isValid, + validated: this.validated, + errors: this.errors, + meta: this.meta, + } + } +} diff --git a/src/multipart/main.ts b/src/multipart/main.ts index 97f87a3..11a9241 100644 --- a/src/multipart/main.ts +++ b/src/multipart/main.ts @@ -8,20 +8,20 @@ */ // @ts-expect-error -import multiparty from "@poppinss/multiparty"; +import multiparty from '@poppinss/multiparty' -import bytes from "bytes"; -import { Exception } from "@poppinss/utils"; -import type { HttpContext } from "@adonisjs/http-server"; +import bytes from 'bytes' +import { Exception } from '@poppinss/utils' +import type { HttpContext } from '@adonisjs/http-server' -import debug from "../debug.js"; -import { FormFields } from "../form_fields.js"; -import { PartHandler } from "./part_handler.js"; +import debug from '../debug.js' +import { FormFields } from '../form_fields.js' +import { PartHandler } from './part_handler.js' import type { MultipartStream, FileValidationOptions, PartHandler as PartHandlerType, -} from "../types.js"; +} from '../types.js' /** * Multipart class offers a low level API to interact the incoming @@ -29,87 +29,85 @@ import type { * write files to s3 without saving them to the disk first. */ export class Multipart { - #ctx: HttpContext; + #ctx: HttpContext #config: Partial<{ - limit: string | number; - fieldsLimit: string | number; - maxFields: number; - convertEmptyStringsToNull: boolean; - }>; + limit: string | number + fieldsLimit: string | number + maxFields: number + convertEmptyStringsToNull: boolean + }> /** * The registered handlers to handle the file uploads */ #handlers: { [key: string]: { - handler: PartHandlerType; - options: Partial; - }; - } = {}; + handler: PartHandlerType + options: Partial + } + } = {} /** * Collected fields from the multipart stream */ - #fields: FormFields; + #fields: FormFields /** * Collected files from the multipart stream. Files are only collected * when there is an attached listener for a given file. */ - #files: FormFields; + #files: FormFields /** * We track the finishing of `this.onFile` async handlers * to make sure that `process` promise resolves for all * handlers to finish. */ - #pendingHandlers = 0; + #pendingHandlers = 0 /** * The reference to underlying multiparty form */ - #form: multiparty.Form; + #form: multiparty.Form /** * Total size limit of the multipart stream. If it goes beyond * the limit, then an exception will be raised. */ - #upperLimit?: number; + #upperLimit?: number /** * Total size in bytes for all the fields (not the files) */ - #maxFieldsSize?: number; + #maxFieldsSize?: number /** * A track of total number of file bytes processed so far */ - #processedBytes: number = 0; + #processedBytes: number = 0 /** * The current state of the multipart form handler */ - state: "idle" | "processing" | "error" | "success" = "idle"; + state: 'idle' | 'processing' | 'error' | 'success' = 'idle' constructor( ctx: HttpContext, config: Partial<{ - limit: string | number; - fieldsLimit: string | number; - maxFields: number; - convertEmptyStringsToNull: boolean; - }> = {}, + limit: string | number + fieldsLimit: string | number + maxFields: number + convertEmptyStringsToNull: boolean + }> = {} ) { - this.#ctx = ctx; - this.#config = config; + this.#ctx = ctx + this.#config = config this.#fields = new FormFields({ - convertEmptyStringsToNull: - this.#config.convertEmptyStringsToNull === true, - }); + convertEmptyStringsToNull: this.#config.convertEmptyStringsToNull === true, + }) this.#files = new FormFields({ - convertEmptyStringsToNull: - this.#config.convertEmptyStringsToNull === true, - }); + convertEmptyStringsToNull: this.#config.convertEmptyStringsToNull === true, + }) } /** @@ -117,7 +115,7 @@ export class Multipart { * consumed along with all handlers execution */ #isClosed(): boolean { - return this.#form["flushing"] <= 0 && this.#pendingHandlers <= 0; + return this.#form['flushing'] <= 0 && this.#pendingHandlers <= 0 } /** @@ -125,7 +123,7 @@ export class Multipart { * find the handler */ #getHandlerName(name: string): string { - return name.replace(/\[\d*\]/, ""); + return name.replace(/\[\d*\]/, '') } /** @@ -134,15 +132,15 @@ export class Multipart { */ #validateProcessedBytes(chunkLength: number) { if (!this.#upperLimit) { - return; + return } - this.#processedBytes += chunkLength; + this.#processedBytes += chunkLength if (this.#processedBytes > this.#upperLimit) { - return new Exception("request entity too large", { - code: "E_REQUEST_ENTITY_TOO_LARGE", + return new Exception('request entity too large', { + code: 'E_REQUEST_ENTITY_TOO_LARGE', status: 413, - }); + }) } } @@ -158,78 +156,78 @@ export class Multipart { * and empty name is more of a bad client scanerio. */ if (!part.name || !part.filename) { - part.resume(); - return; + part.resume() + return } - const name = this.#getHandlerName(part.name); + const name = this.#getHandlerName(part.name) /** * Skip, if their is no handler to consume the part. */ - const handler = this.#handlers[name] || this.#handlers["*"]; + const handler = this.#handlers[name] || this.#handlers['*'] if (!handler) { - debug('skipping multipart part as there are no handlers "%s"', name); - part.resume(); - return; + debug('skipping multipart part as there are no handlers "%s"', name) + part.resume() + return } - debug('processing multipart part "%s"', name); - this.#pendingHandlers++; + debug('processing multipart part "%s"', name) + this.#pendingHandlers++ /** * Instantiate the part handler */ - const partHandler = new PartHandler(part, handler.options); - partHandler.begin(); + const partHandler = new PartHandler(part, handler.options) + partHandler.begin() /** * Track the file instance created by the part handler. The end user * must be able to access these files. */ - this.#files.add(partHandler.file.fieldName, partHandler.file); - part.file = partHandler.file; + this.#files.add(partHandler.file.fieldName, partHandler.file) + part.file = partHandler.file try { const response = await handler.handler(part, async (line) => { - if (this.state !== "processing") { - return; + if (this.state !== 'processing') { + return } - const lineLength = line.length; + const lineLength = line.length /** * Keeping an eye on total bytes processed so far and shortcircuit * request when more than expected bytes have been received. */ - const error = this.#validateProcessedBytes(lineLength); + const error = this.#validateProcessedBytes(lineLength) if (error) { - part.emit("error", error); - this.abort(error); - return; + part.emit('error', error) + this.abort(error) + return } try { - await partHandler.reportProgress(line, lineLength); + await partHandler.reportProgress(line, lineLength) } catch (err) { this.#ctx.logger.fatal( - 'Unhandled multipart stream error. Make sure to handle "error" events for all manually processed streams', - ); + 'Unhandled multipart stream error. Make sure to handle "error" events for all manually processed streams' + ) } - }); + }) /** * Stream consumed successfully */ - await partHandler.reportSuccess(response || {}); + await partHandler.reportSuccess(response || {}) } catch (error) { /** * The stream handler reported an exception */ - await partHandler.reportError(error); + await partHandler.reportError(error) } - this.#pendingHandlers--; + this.#pendingHandlers-- } /** @@ -237,48 +235,44 @@ export class Multipart { */ #handleField(key: string, value: string) { if (!key) { - return; + return } - this.#fields.add(key, value); + this.#fields.add(key, value) } /** * Processes the user config and computes the `upperLimit` value from * it. */ - #processConfig( - config?: Partial<{ limit: string | number; maxFields: number }>, - ) { - this.#config = Object.assign(this.#config, config); + #processConfig(config?: Partial<{ limit: string | number; maxFields: number }>) { + this.#config = Object.assign(this.#config, config) /** * Getting bytes from the `config.fieldsLimit` option, which can * also be a string. */ this.#maxFieldsSize = - typeof this.#config!.fieldsLimit === "string" + typeof this.#config!.fieldsLimit === 'string' ? bytes(this.#config.fieldsLimit) - : this.#config!.fieldsLimit; + : this.#config!.fieldsLimit /** * Getting bytes from the `config.limit` option, which can * also be a string */ this.#upperLimit = - typeof this.#config!.limit === "string" - ? bytes(this.#config!.limit) - : this.#config!.limit; + typeof this.#config!.limit === 'string' ? bytes(this.#config!.limit) : this.#config!.limit } /** * Mark the process as finished */ - #finish(newState: "error" | "success") { - if (this.state === "idle" || this.state === "processing") { - this.state = newState; - (this.#ctx.request as any)["__raw_files"] = this.#files.get(); - this.#ctx.request.setInitialBody(this.#fields.get()); + #finish(newState: 'error' | 'success') { + if (this.state === 'idle' || this.state === 'processing') { + this.state = newState + ;(this.#ctx.request as any)['__raw_files'] = this.#files.get() + this.#ctx.request.setInitialBody(this.#fields.get()) } } @@ -298,92 +292,90 @@ export class Multipart { onFile( name: string, options: Partial, - handler: PartHandlerType, + handler: PartHandlerType ): this { - this.#handlers[name] = { handler, options }; - return this; + this.#handlers[name] = { handler, options } + return this } /** * Abort request by emitting error */ abort(error: any): void { - this.#form.emit("error", error); + this.#form.emit('error', error) } /** * Process the request by going all the file and field * streams. */ - process( - config?: Partial<{ limit: string | number; maxFields: number }>, - ): Promise { + process(config?: Partial<{ limit: string | number; maxFields: number }>): Promise { return new Promise((resolve, reject) => { - if (this.state !== "idle") { + if (this.state !== 'idle') { reject( - new Exception("multipart stream has already been consumed", { - code: "E_RUNTIME_EXCEPTION", - }), - ); - return; + new Exception('multipart stream has already been consumed', { + code: 'E_RUNTIME_EXCEPTION', + }) + ) + return } - this.state = "processing"; - this.#processConfig(config); + this.state = 'processing' + this.#processConfig(config) this.#form = new multiparty.Form({ maxFields: this.#config!.maxFields, maxFieldsSize: this.#maxFieldsSize, - }); + }) - debug("processing multipart body"); + debug('processing multipart body') /** * Raise error when form encounters an * error */ - this.#form.on("error", (error: Error) => { - this.#finish("error"); + this.#form.on('error', (error: Error) => { + this.#finish('error') process.nextTick(() => { if (this.#ctx.request.request.readable) { - this.#ctx.request.request.resume(); + this.#ctx.request.request.resume() } if (error.message.match(/stream ended unexpectedly/)) { reject( - new Exception("Invalid multipart request", { + new Exception('Invalid multipart request', { status: 400, - code: "E_INVALID_MULTIPART_REQUEST", - }), - ); + code: 'E_INVALID_MULTIPART_REQUEST', + }) + ) } else if (error.message.match(/maxFields [0-9]+ exceeded/)) { reject( - new Exception("Fields length limit exceeded", { + new Exception('Fields length limit exceeded', { status: 413, - code: "E_REQUEST_ENTITY_TOO_LARGE", - }), - ); + code: 'E_REQUEST_ENTITY_TOO_LARGE', + }) + ) } else if (error.message.match(/maxFieldsSize [0-9]+ exceeded/)) { reject( - new Exception("Fields size in bytes exceeded", { + new Exception('Fields size in bytes exceeded', { status: 413, - code: "E_REQUEST_ENTITY_TOO_LARGE", - }), - ); + code: 'E_REQUEST_ENTITY_TOO_LARGE', + }) + ) } else { - reject(error); + reject(error) } - }); - }); + }) + }) /** * Process each part at a time and also resolve the * promise when all parts are consumed and processed * by their handlers */ - this.#form.on("part", async (part: MultipartStream) => { - await this.#handlePart(part); + this.#form.on('part', async (part: MultipartStream) => { + await this.#handlePart(part) /** * When a stream finishes before the handler, the close `event` @@ -391,34 +383,34 @@ export class Multipart { * check and resolve from here */ if (this.#isClosed()) { - this.#finish("success"); - resolve(); + this.#finish('success') + resolve() } - }); + }) /** * Listen for fields */ - this.#form.on("field", (key: string, value: any) => { + this.#form.on('field', (key: string, value: any) => { try { - this.#handleField(key, value); + this.#handleField(key, value) } catch (error) { - this.abort(error); + this.abort(error) } - }); + }) /** * Resolve promise on close, when all internal * file handlers are done processing files */ - this.#form.on("close", () => { + this.#form.on('close', () => { if (this.#isClosed()) { - this.#finish("success"); - resolve(); + this.#finish('success') + resolve() } - }); + }) - this.#form.parse(this.#ctx.request.request); - }); + this.#form.parse(this.#ctx.request.request) + }) } } diff --git a/tests/body_parser.spec.ts b/tests/body_parser.spec.ts index d77595c..370caec 100644 --- a/tests/body_parser.spec.ts +++ b/tests/body_parser.spec.ts @@ -7,906 +7,782 @@ * file that was distributed with this source code. */ -import "reflect-metadata"; -import { fetch } from "undici"; -import { tmpdir } from "node:os"; -import { join } from "node:path"; -import supertest from "supertest"; -import { test } from "@japa/runner"; -import { pathExists } from "fs-extra"; -import { createServer } from "node:http"; -import { readFile } from "node:fs/promises"; +import 'reflect-metadata' +import { fetch } from 'undici' +import { tmpdir } from 'node:os' +import { join } from 'node:path' +import supertest from 'supertest' +import { test } from '@japa/runner' +import { pathExists } from 'fs-extra' +import { createServer } from 'node:http' +import { readFile } from 'node:fs/promises' import { RequestFactory, ResponseFactory, HttpContextFactory, -} from "@adonisjs/http-server/factories"; -import { Multipart } from "../src/multipart/main.js"; -import { MultipartFile } from "../src/multipart/file.js"; -import { BodyParserMiddlewareFactory } from "../factories/middleware_factory.js"; -import { - packageFilePath, - packageFileSize, - unicornFilePath, -} from "../tests_helpers/main.js"; - -test.group("BodyParser Middleware", () => { - test("do not parse get requests", async ({ assert }) => { +} from '@adonisjs/http-server/factories' +import { Multipart } from '../src/multipart/main.js' +import { MultipartFile } from '../src/multipart/file.js' +import { BodyParserMiddlewareFactory } from '../factories/middleware_factory.js' +import { packageFilePath, packageFileSize, unicornFilePath } from '../tests_helpers/main.js' + +test.group('BodyParser Middleware', () => { + test('do not parse get requests', async ({ assert }) => { const server = createServer(async (req, res) => { - const request = new RequestFactory().merge({ req, res }).create(); - const response = new ResponseFactory().merge({ req, res }).create(); - const ctx = new HttpContextFactory() - .merge({ request, response }) - .create(); - const middleware = new BodyParserMiddlewareFactory().create(); + const request = new RequestFactory().merge({ req, res }).create() + const response = new ResponseFactory().merge({ req, res }).create() + const ctx = new HttpContextFactory().merge({ request, response }).create() + const middleware = new BodyParserMiddlewareFactory().create() await middleware.handle(ctx, async () => { - res.writeHead(200, { "content-type": "application/json" }); - res.end(JSON.stringify(ctx.request.all())); - }); - }); + res.writeHead(200, { 'content-type': 'application/json' }) + res.end(JSON.stringify(ctx.request.all())) + }) + }) - const { body } = await supertest(server) - .get("/") - .type("json") - .send({ username: "virk" }); + const { body } = await supertest(server).get('/').type('json').send({ username: 'virk' }) - assert.deepEqual(body, {}); - }); + assert.deepEqual(body, {}) + }) - test("by pass when body is empty", async ({ assert }) => { + test('by pass when body is empty', async ({ assert }) => { const server = createServer(async (req, res) => { - const request = new RequestFactory().merge({ req, res }).create(); - const response = new ResponseFactory().merge({ req, res }).create(); - const ctx = new HttpContextFactory() - .merge({ request, response }) - .create(); - const middleware = new BodyParserMiddlewareFactory().create(); + const request = new RequestFactory().merge({ req, res }).create() + const response = new ResponseFactory().merge({ req, res }).create() + const ctx = new HttpContextFactory().merge({ request, response }).create() + const middleware = new BodyParserMiddlewareFactory().create() await middleware.handle(ctx, async () => { - res.writeHead(200, { "content-type": "application/json" }); - res.end(JSON.stringify(ctx.request.all())); - }); - }); + res.writeHead(200, { 'content-type': 'application/json' }) + res.end(JSON.stringify(ctx.request.all())) + }) + }) - const { body } = await supertest(server).post("/").type("json"); + const { body } = await supertest(server).post('/').type('json') - assert.deepEqual(body, {}); - }); + assert.deepEqual(body, {}) + }) - test("by pass when content type is not supported", async ({ assert }) => { + test('by pass when content type is not supported', async ({ assert }) => { const server = createServer(async (req, res) => { - const request = new RequestFactory().merge({ req, res }).create(); - const response = new ResponseFactory().merge({ req, res }).create(); - const ctx = new HttpContextFactory() - .merge({ request, response }) - .create(); - const middleware = new BodyParserMiddlewareFactory().create(); + const request = new RequestFactory().merge({ req, res }).create() + const response = new ResponseFactory().merge({ req, res }).create() + const ctx = new HttpContextFactory().merge({ request, response }).create() + const middleware = new BodyParserMiddlewareFactory().create() await middleware.handle(ctx, async () => { - res.writeHead(200, { "content-type": "application/json" }); - res.end(JSON.stringify(ctx.request.all())); - }); - }); + res.writeHead(200, { 'content-type': 'application/json' }) + res.end(JSON.stringify(ctx.request.all())) + }) + }) const { body } = await supertest(server) - .post("/") - .set("content-type", "my-type") - .send(JSON.stringify({ username: "virk" })); + .post('/') + .set('content-type', 'my-type') + .send(JSON.stringify({ username: 'virk' })) - assert.deepEqual(body, {}); - }); -}); + assert.deepEqual(body, {}) + }) +}) -test.group("BodyParser Middleware | form data", () => { - test("handle request with form data", async ({ assert }) => { +test.group('BodyParser Middleware | form data', () => { + test('handle request with form data', async ({ assert }) => { const server = createServer(async (req, res) => { - const request = new RequestFactory().merge({ req, res }).create(); - const response = new ResponseFactory().merge({ req, res }).create(); - const ctx = new HttpContextFactory() - .merge({ request, response }) - .create(); - const middleware = new BodyParserMiddlewareFactory().create(); + const request = new RequestFactory().merge({ req, res }).create() + const response = new ResponseFactory().merge({ req, res }).create() + const ctx = new HttpContextFactory().merge({ request, response }).create() + const middleware = new BodyParserMiddlewareFactory().create() await middleware.handle(ctx, async () => { - res.writeHead(200, { "content-type": "application/json" }); - res.end(JSON.stringify(ctx.request.all())); - }); - }); + res.writeHead(200, { 'content-type': 'application/json' }) + res.end(JSON.stringify(ctx.request.all())) + }) + }) - const { body } = await supertest(server) - .post("/") - .type("form") - .send({ username: "virk" }); + const { body } = await supertest(server).post('/').type('form').send({ username: 'virk' }) - assert.deepEqual(body, { username: "virk" }); - }); + assert.deepEqual(body, { username: 'virk' }) + }) - test("abort if request size is over limit", async ({ assert }) => { + test('abort if request size is over limit', async ({ assert }) => { const server = createServer(async (req, res) => { - const request = new RequestFactory().merge({ req, res }).create(); - const response = new ResponseFactory().merge({ req, res }).create(); - const ctx = new HttpContextFactory() - .merge({ request, response }) - .create(); + const request = new RequestFactory().merge({ req, res }).create() + const response = new ResponseFactory().merge({ req, res }).create() + const ctx = new HttpContextFactory().merge({ request, response }).create() const middleware = new BodyParserMiddlewareFactory() .merge({ form: { limit: 2, }, }) - .create(); + .create() try { - await middleware.handle(ctx, async () => {}); + await middleware.handle(ctx, async () => {}) } catch (error) { - res.writeHead(error.status); - res.end(error.message); + res.writeHead(error.status) + res.end(error.message) } - }); + }) const { text } = await supertest(server) - .post("/") - .type("form") - .send({ username: "virk" }) - .expect(413); + .post('/') + .type('form') + .send({ username: 'virk' }) + .expect(413) - assert.deepEqual(text, "request entity too large"); - }); + assert.deepEqual(text, 'request entity too large') + }) - test("abort if specified encoding is not supported", async ({ assert }) => { + test('abort if specified encoding is not supported', async ({ assert }) => { const server = createServer(async (req, res) => { - const request = new RequestFactory().merge({ req, res }).create(); - const response = new ResponseFactory().merge({ req, res }).create(); - const ctx = new HttpContextFactory() - .merge({ request, response }) - .create(); + const request = new RequestFactory().merge({ req, res }).create() + const response = new ResponseFactory().merge({ req, res }).create() + const ctx = new HttpContextFactory().merge({ request, response }).create() const middleware = new BodyParserMiddlewareFactory() .merge({ form: { - encoding: "foo", + encoding: 'foo', }, }) - .create(); + .create() try { - await middleware.handle(ctx, async () => {}); + await middleware.handle(ctx, async () => {}) } catch (error) { - res.writeHead(error.status); - res.end(error.message); + res.writeHead(error.status) + res.end(error.message) } - }); + }) const { text } = await supertest(server) - .post("/") - .type("form") - .send({ username: "virk" }) - .expect(415); + .post('/') + .type('form') + .send({ username: 'virk' }) + .expect(415) - assert.deepEqual(text, "specified encoding unsupported"); - }); + assert.deepEqual(text, 'specified encoding unsupported') + }) - test("ignore fields with empty name", async ({ assert }) => { + test('ignore fields with empty name', async ({ assert }) => { const server = createServer(async (req, res) => { - const request = new RequestFactory().merge({ req, res }).create(); - const response = new ResponseFactory().merge({ req, res }).create(); - const ctx = new HttpContextFactory() - .merge({ request, response }) - .create(); - const middleware = new BodyParserMiddlewareFactory().create(); + const request = new RequestFactory().merge({ req, res }).create() + const response = new ResponseFactory().merge({ req, res }).create() + const ctx = new HttpContextFactory().merge({ request, response }).create() + const middleware = new BodyParserMiddlewareFactory().create() await middleware.handle(ctx, async () => { - res.writeHead(200, { "content-type": "application/json" }); - res.end(JSON.stringify(ctx.request.all())); - }); - }); + res.writeHead(200, { 'content-type': 'application/json' }) + res.end(JSON.stringify(ctx.request.all())) + }) + }) - const { body } = await supertest(server) - .post("/") - .type("form") - .send({ "": "virk" }); - assert.deepEqual(body, {}); - }); + const { body } = await supertest(server).post('/').type('form').send({ '': 'virk' }) + assert.deepEqual(body, {}) + }) - test("convert empty strings to null", async ({ assert }) => { + test('convert empty strings to null', async ({ assert }) => { const server = createServer(async (req, res) => { - const request = new RequestFactory().merge({ req, res }).create(); - const response = new ResponseFactory().merge({ req, res }).create(); - const ctx = new HttpContextFactory() - .merge({ request, response }) - .create(); - const middleware = new BodyParserMiddlewareFactory().create(); + const request = new RequestFactory().merge({ req, res }).create() + const response = new ResponseFactory().merge({ req, res }).create() + const ctx = new HttpContextFactory().merge({ request, response }).create() + const middleware = new BodyParserMiddlewareFactory().create() await middleware.handle(ctx, async () => { - res.writeHead(200, { "content-type": "application/json" }); - res.end(JSON.stringify(ctx.request.all())); - }); - }); + res.writeHead(200, { 'content-type': 'application/json' }) + res.end(JSON.stringify(ctx.request.all())) + }) + }) - const { body } = await supertest(server) - .post("/") - .type("form") - .send({ name: "" }); + const { body } = await supertest(server).post('/').type('form').send({ name: '' }) assert.deepEqual(body, { name: null, - }); - }); + }) + }) - test("abort when multipart body is invalid", async ({ assert, cleanup }) => { + test('abort when multipart body is invalid', async ({ assert, cleanup }) => { const server = createServer(async (req, res) => { - const request = new RequestFactory().merge({ req, res }).create(); - const response = new ResponseFactory().merge({ req, res }).create(); - const ctx = new HttpContextFactory() - .merge({ request, response }) - .create(); - const middleware = new BodyParserMiddlewareFactory().create(); + const request = new RequestFactory().merge({ req, res }).create() + const response = new ResponseFactory().merge({ req, res }).create() + const ctx = new HttpContextFactory().merge({ request, response }).create() + const middleware = new BodyParserMiddlewareFactory().create() try { - await middleware.handle(ctx, async () => {}); + await middleware.handle(ctx, async () => {}) } catch (error) { - res.writeHead(error.status); - res.end(error.message); + res.writeHead(error.status) + res.end(error.message) } - }); + }) cleanup(() => { - server.close(); - }); + server.close() + }) - await new Promise((resolve) => - server.listen(3333, "localhost", () => resolve()), - ); + await new Promise((resolve) => server.listen(3333, 'localhost', () => resolve())) - const response = await fetch("http://localhost:3333", { - method: "POST", + const response = await fetch('http://localhost:3333', { + method: 'POST', headers: { - "Content-type": `multipart/form-data; boundary=9d01a3fb93deedb4d0a81389271d097f28fd67e2fcbff2932befc0458ad7`, + 'Content-type': `multipart/form-data; boundary=9d01a3fb93deedb4d0a81389271d097f28fd67e2fcbff2932befc0458ad7`, }, body: '--9d01a3fb93deedb4d0a81389271d097f28fd67e2fcbff2932befc0458ad7\x0d\x0aContent-Disposition: form-data; name="test"; filename="csv_files/test.csv"\x0d\x0aContent-Type: application/octet-stream\x0d\x0a\x0d\x0atest123', - }); + }) - assert.equal(await response.text(), "Invalid multipart request"); - }); + assert.equal(await response.text(), 'Invalid multipart request') + }) - test("abort when multipart body is invalid newline characters", async ({ - assert, - cleanup, - }) => { + test('abort when multipart body is invalid newline characters', async ({ assert, cleanup }) => { const server = createServer(async (req, res) => { - const request = new RequestFactory().merge({ req, res }).create(); - const response = new ResponseFactory().merge({ req, res }).create(); - const ctx = new HttpContextFactory() - .merge({ request, response }) - .create(); - const middleware = new BodyParserMiddlewareFactory().create(); + const request = new RequestFactory().merge({ req, res }).create() + const response = new ResponseFactory().merge({ req, res }).create() + const ctx = new HttpContextFactory().merge({ request, response }).create() + const middleware = new BodyParserMiddlewareFactory().create() try { - await middleware.handle(ctx, async () => {}); + await middleware.handle(ctx, async () => {}) } catch (error) { - res.writeHead(error.status); - res.end(error.message); + res.writeHead(error.status) + res.end(error.message) } - }); + }) cleanup(() => { - server.close(); - }); - await new Promise((resolve) => - server.listen(3333, "localhost", () => resolve()), - ); - - const response = await fetch("http://localhost:3333", { - method: "POST", + server.close() + }) + await new Promise((resolve) => server.listen(3333, 'localhost', () => resolve())) + + const response = await fetch('http://localhost:3333', { + method: 'POST', headers: { - "Content-type": `multipart/form-data; boundary=XXX`, + 'Content-type': `multipart/form-data; boundary=XXX`, }, body: '--XXX\nContent-Disposition: form-data; name="file"; filename="filename.csv"\nContent-Type: text/csv\n\nA,B,C\n1,1.1,name1\n2,2.2,name2\n\n--XXX--', - }); + }) - assert.equal(await response.text(), "Expected CR Received 10"); - }); -}); + assert.equal(await response.text(), 'Expected CR Received 10') + }) +}) -test.group("BodyParser Middleware | json", () => { - test("handle request with json body", async ({ assert }) => { +test.group('BodyParser Middleware | json', () => { + test('handle request with json body', async ({ assert }) => { const server = createServer(async (req, res) => { - const request = new RequestFactory().merge({ req, res }).create(); - const response = new ResponseFactory().merge({ req, res }).create(); - const ctx = new HttpContextFactory() - .merge({ request, response }) - .create(); - const middleware = new BodyParserMiddlewareFactory().create(); + const request = new RequestFactory().merge({ req, res }).create() + const response = new ResponseFactory().merge({ req, res }).create() + const ctx = new HttpContextFactory().merge({ request, response }).create() + const middleware = new BodyParserMiddlewareFactory().create() await middleware.handle(ctx, async () => { - res.writeHead(200, { "content-type": "application/json" }); - res.end(JSON.stringify(ctx.request.all())); - }); - }); + res.writeHead(200, { 'content-type': 'application/json' }) + res.end(JSON.stringify(ctx.request.all())) + }) + }) - const { body } = await supertest(server) - .post("/") - .type("json") - .send({ username: "virk" }); + const { body } = await supertest(server).post('/').type('json').send({ username: 'virk' }) - assert.deepEqual(body, { username: "virk" }); - }); + assert.deepEqual(body, { username: 'virk' }) + }) - test("abort if request size is over limit", async ({ assert }) => { + test('abort if request size is over limit', async ({ assert }) => { const server = createServer(async (req, res) => { - const request = new RequestFactory().merge({ req, res }).create(); - const response = new ResponseFactory().merge({ req, res }).create(); - const ctx = new HttpContextFactory() - .merge({ request, response }) - .create(); + const request = new RequestFactory().merge({ req, res }).create() + const response = new ResponseFactory().merge({ req, res }).create() + const ctx = new HttpContextFactory().merge({ request, response }).create() const middleware = new BodyParserMiddlewareFactory() .merge({ json: { limit: 2, }, }) - .create(); + .create() try { - await middleware.handle(ctx, async () => {}); + await middleware.handle(ctx, async () => {}) } catch (error) { - res.writeHead(error.status); - res.end(error.message); + res.writeHead(error.status) + res.end(error.message) } - }); + }) const { text } = await supertest(server) - .post("/") - .type("json") - .send({ username: "virk" }) - .expect(413); + .post('/') + .type('json') + .send({ username: 'virk' }) + .expect(413) - assert.deepEqual(text, "request entity too large"); - }); + assert.deepEqual(text, 'request entity too large') + }) - test("ignore fields with empty name", async ({ assert }) => { + test('ignore fields with empty name', async ({ assert }) => { const server = createServer(async (req, res) => { - const request = new RequestFactory().merge({ req, res }).create(); - const response = new ResponseFactory().merge({ req, res }).create(); - const ctx = new HttpContextFactory() - .merge({ request, response }) - .create(); - const middleware = new BodyParserMiddlewareFactory().create(); + const request = new RequestFactory().merge({ req, res }).create() + const response = new ResponseFactory().merge({ req, res }).create() + const ctx = new HttpContextFactory().merge({ request, response }).create() + const middleware = new BodyParserMiddlewareFactory().create() await middleware.handle(ctx, async () => { - res.writeHead(200, { "content-type": "application/json" }); - res.end(JSON.stringify(ctx.request.all())); - }); - }); + res.writeHead(200, { 'content-type': 'application/json' }) + res.end(JSON.stringify(ctx.request.all())) + }) + }) - const { body } = await supertest(server) - .post("/") - .type("json") - .send({ "": "virk" }); + const { body } = await supertest(server).post('/').type('json').send({ '': 'virk' }) - assert.deepEqual(body, { "": "virk" }); - }); + assert.deepEqual(body, { '': 'virk' }) + }) - test("convert empty strings to null", async ({ assert }) => { + test('convert empty strings to null', async ({ assert }) => { const server = createServer(async (req, res) => { - const request = new RequestFactory().merge({ req, res }).create(); - const response = new ResponseFactory().merge({ req, res }).create(); - const ctx = new HttpContextFactory() - .merge({ request, response }) - .create(); - const middleware = new BodyParserMiddlewareFactory().create(); + const request = new RequestFactory().merge({ req, res }).create() + const response = new ResponseFactory().merge({ req, res }).create() + const ctx = new HttpContextFactory().merge({ request, response }).create() + const middleware = new BodyParserMiddlewareFactory().create() await middleware.handle(ctx, async () => { - res.writeHead(200, { "content-type": "application/json" }); - res.end(JSON.stringify(ctx.request.all())); - }); - }); + res.writeHead(200, { 'content-type': 'application/json' }) + res.end(JSON.stringify(ctx.request.all())) + }) + }) - const { body } = await supertest(server) - .post("/") - .type("json") - .send({ name: "" }); + const { body } = await supertest(server).post('/').type('json').send({ name: '' }) assert.deepEqual(body, { name: null, - }); - }); -}); + }) + }) +}) -test.group("BodyParser Middleware | raw body", () => { - test("handle request with raw body", async ({ assert }) => { +test.group('BodyParser Middleware | raw body', () => { + test('handle request with raw body', async ({ assert }) => { const server = createServer(async (req, res) => { - const request = new RequestFactory().merge({ req, res }).create(); - const response = new ResponseFactory().merge({ req, res }).create(); - const ctx = new HttpContextFactory() - .merge({ request, response }) - .create(); - const middleware = new BodyParserMiddlewareFactory().create(); + const request = new RequestFactory().merge({ req, res }).create() + const response = new ResponseFactory().merge({ req, res }).create() + const ctx = new HttpContextFactory().merge({ request, response }).create() + const middleware = new BodyParserMiddlewareFactory().create() await middleware.handle(ctx, async () => { - res.writeHead(200, { "content-type": "application/json" }); - res.end(ctx.request.raw()); - }); - }); + res.writeHead(200, { 'content-type': 'application/json' }) + res.end(ctx.request.raw()) + }) + }) const { body } = await supertest(server) - .post("/") - .type("text") - .send(JSON.stringify({ username: "virk" })); + .post('/') + .type('text') + .send(JSON.stringify({ username: 'virk' })) - assert.deepEqual(body, { username: "virk" }); - }); + assert.deepEqual(body, { username: 'virk' }) + }) - test("abort if request size is over limit", async ({ assert }) => { + test('abort if request size is over limit', async ({ assert }) => { const server = createServer(async (req, res) => { - const request = new RequestFactory().merge({ req, res }).create(); - const response = new ResponseFactory().merge({ req, res }).create(); - const ctx = new HttpContextFactory() - .merge({ request, response }) - .create(); + const request = new RequestFactory().merge({ req, res }).create() + const response = new ResponseFactory().merge({ req, res }).create() + const ctx = new HttpContextFactory().merge({ request, response }).create() const middleware = new BodyParserMiddlewareFactory() .merge({ raw: { limit: 2, }, }) - .create(); + .create() try { - await middleware.handle(ctx, async () => {}); + await middleware.handle(ctx, async () => {}) } catch (error) { - res.writeHead(error.status); - res.end(error.message); + res.writeHead(error.status) + res.end(error.message) } - }); + }) const { text } = await supertest(server) - .post("/") - .type("text") - .send(JSON.stringify({ username: "virk" })) - .expect(413); + .post('/') + .type('text') + .send(JSON.stringify({ username: 'virk' })) + .expect(413) - assert.deepEqual(text, "request entity too large"); - }); -}); + assert.deepEqual(text, 'request entity too large') + }) +}) -test.group("BodyParser Middleware | multipart", () => { - test("handle request with just files", async ({ assert }) => { +test.group('BodyParser Middleware | multipart', () => { + test('handle request with just files', async ({ assert }) => { const server = createServer(async (req, res) => { - const request = new RequestFactory().merge({ req, res }).create(); - const response = new ResponseFactory().merge({ req, res }).create(); - const ctx = new HttpContextFactory() - .merge({ request, response }) - .create(); - const middleware = new BodyParserMiddlewareFactory().create(); + const request = new RequestFactory().merge({ req, res }).create() + const response = new ResponseFactory().merge({ req, res }).create() + const ctx = new HttpContextFactory().merge({ request, response }).create() + const middleware = new BodyParserMiddlewareFactory().create() await middleware.handle(ctx, async () => { - const pkgFile = ctx.request["__raw_files"].package as MultipartFile; + const pkgFile = ctx.request['__raw_files'].package as MultipartFile - res.writeHead(200, { "content-type": "application/json" }); + res.writeHead(200, { 'content-type': 'application/json' }) res.end( JSON.stringify({ tmpPath: pkgFile.tmpPath, size: pkgFile.size, validated: pkgFile.validated, - }), - ); - }); - }); + }) + ) + }) + }) - const { body } = await supertest(server) - .post("/") - .attach("package", packageFilePath); + const { body } = await supertest(server).post('/').attach('package', packageFilePath) - assert.isAbove(body.size, 0); - assert.exists(body.tmpPath); - assert.isFalse(body.validated); - }); + assert.isAbove(body.size, 0) + assert.exists(body.tmpPath) + assert.isFalse(body.validated) + }) - test("handle request with files and fields", async ({ assert }) => { + test('handle request with files and fields', async ({ assert }) => { const server = createServer(async (req, res) => { - const request = new RequestFactory().merge({ req, res }).create(); - const response = new ResponseFactory().merge({ req, res }).create(); - const ctx = new HttpContextFactory() - .merge({ request, response }) - .create(); - const middleware = new BodyParserMiddlewareFactory().create(); + const request = new RequestFactory().merge({ req, res }).create() + const response = new ResponseFactory().merge({ req, res }).create() + const ctx = new HttpContextFactory().merge({ request, response }).create() + const middleware = new BodyParserMiddlewareFactory().create() await middleware.handle(ctx, async () => { - const pkgFile = ctx.request["__raw_files"].package as MultipartFile; + const pkgFile = ctx.request['__raw_files'].package as MultipartFile - res.writeHead(200, { "content-type": "application/json" }); + res.writeHead(200, { 'content-type': 'application/json' }) res.end( JSON.stringify({ size: pkgFile.size, validated: pkgFile.validated, - username: ctx.request.input("username"), - }), - ); - }); - }); + username: ctx.request.input('username'), + }) + ) + }) + }) const { body } = await supertest(server) - .post("/") - .attach("package", packageFilePath) - .field("username", "virk"); + .post('/') + .attach('package', packageFilePath) + .field('username', 'virk') - assert.isAbove(body.size, 0); - assert.equal(body.username, "virk"); - assert.isFalse(body.validated); - }); + assert.isAbove(body.size, 0) + assert.equal(body.username, 'virk') + assert.isFalse(body.validated) + }) - test("handle request array of files", async ({ assert }) => { + test('handle request array of files', async ({ assert }) => { const server = createServer(async (req, res) => { - const request = new RequestFactory().merge({ req, res }).create(); - const response = new ResponseFactory().merge({ req, res }).create(); - const ctx = new HttpContextFactory() - .merge({ request, response }) - .create(); - const middleware = new BodyParserMiddlewareFactory().create(); + const request = new RequestFactory().merge({ req, res }).create() + const response = new ResponseFactory().merge({ req, res }).create() + const ctx = new HttpContextFactory().merge({ request, response }).create() + const middleware = new BodyParserMiddlewareFactory().create() await middleware.handle(ctx, async () => { - res.writeHead(200, { "content-type": "application/json" }); + res.writeHead(200, { 'content-type': 'application/json' }) res.end( JSON.stringify({ - multiple: Array.isArray(ctx.request["__raw_files"].package), - }), - ); - }); - }); + multiple: Array.isArray(ctx.request['__raw_files'].package), + }) + ) + }) + }) const { body } = await supertest(server) - .post("/") - .attach("package[]", packageFilePath) - .attach("package[]", packageFilePath); + .post('/') + .attach('package[]', packageFilePath) + .attach('package[]', packageFilePath) - assert.deepEqual(body, { multiple: true }); - }); + assert.deepEqual(body, { multiple: true }) + }) - test("abort request when total bytes are over limit", async ({ assert }) => { - let index = 0; + test('abort request when total bytes are over limit', async ({ assert }) => { + let index = 0 const server = createServer(async (req, res) => { - const request = new RequestFactory().merge({ req, res }).create(); - const response = new ResponseFactory().merge({ req, res }).create(); - const ctx = new HttpContextFactory() - .merge({ request, response }) - .create(); + const request = new RequestFactory().merge({ req, res }).create() + const response = new ResponseFactory().merge({ req, res }).create() + const ctx = new HttpContextFactory().merge({ request, response }).create() const middleware = new BodyParserMiddlewareFactory() .merge({ multipart: { tmpFileName() { - return `${index++}.tmp`; + return `${index++}.tmp` }, limit: packageFileSize * 2 - 10, }, }) - .create(); + .create() try { - await middleware.handle(ctx, async () => {}); + await middleware.handle(ctx, async () => {}) } catch (error) { - res.writeHead(error.status); - res.end(error.message); + res.writeHead(error.status) + res.end(error.message) } - }); + }) const { text } = await supertest(server) - .post("/") - .attach("package[]", packageFilePath) - .attach("package[]", packageFilePath); + .post('/') + .attach('package[]', packageFilePath) + .attach('package[]', packageFilePath) - assert.equal(text, "request entity too large"); + assert.equal(text, 'request entity too large') - const file1 = await pathExists(join(tmpdir(), "0.tmp")); - const file2 = await pathExists(join(tmpdir(), "1.tmp")); + const file1 = await pathExists(join(tmpdir(), '0.tmp')) + const file2 = await pathExists(join(tmpdir(), '1.tmp')) - assert.isTrue(file1); - assert.isFalse(file2); - }).retry(2); + assert.isTrue(file1) + assert.isFalse(file2) + }).retry(2) - test("handle request with empty field name", async ({ assert }) => { + test('handle request with empty field name', async ({ assert }) => { const server = createServer(async (req, res) => { - const request = new RequestFactory().merge({ req, res }).create(); - const response = new ResponseFactory().merge({ req, res }).create(); - const ctx = new HttpContextFactory() - .merge({ request, response }) - .create(); - const middleware = new BodyParserMiddlewareFactory().create(); + const request = new RequestFactory().merge({ req, res }).create() + const response = new ResponseFactory().merge({ req, res }).create() + const ctx = new HttpContextFactory().merge({ request, response }).create() + const middleware = new BodyParserMiddlewareFactory().create() await middleware.handle(ctx, async () => { - res.writeHead(200, { "content-type": "application/json" }); - res.end(JSON.stringify(ctx.request.all())); - }); - }); + res.writeHead(200, { 'content-type': 'application/json' }) + res.end(JSON.stringify(ctx.request.all())) + }) + }) const { body } = await supertest(server) - .post("/") - .attach("package", packageFilePath) - .field("", "virk"); + .post('/') + .attach('package', packageFilePath) + .field('', 'virk') - assert.deepEqual(body, {}); - }); + assert.deepEqual(body, {}) + }) - test("handle request with empty file name", async ({ assert }) => { + test('handle request with empty file name', async ({ assert }) => { const server = createServer(async (req, res) => { - const request = new RequestFactory().merge({ req, res }).create(); - const response = new ResponseFactory().merge({ req, res }).create(); - const ctx = new HttpContextFactory() - .merge({ request, response }) - .create(); - const middleware = new BodyParserMiddlewareFactory().create(); + const request = new RequestFactory().merge({ req, res }).create() + const response = new ResponseFactory().merge({ req, res }).create() + const ctx = new HttpContextFactory().merge({ request, response }).create() + const middleware = new BodyParserMiddlewareFactory().create() await middleware.handle(ctx, async () => { - res.writeHead(200); - res.end(String(Object.keys(ctx.request["__raw_files"]).length)); - }); - }); + res.writeHead(200) + res.end(String(Object.keys(ctx.request['__raw_files']).length)) + }) + }) - const { text } = await supertest(server) - .post("/") - .attach("", packageFilePath); + const { text } = await supertest(server).post('/').attach('', packageFilePath) - assert.deepEqual(text, "0"); - }); + assert.deepEqual(text, '0') + }) - test("do not process request when autoProcess is false", async ({ - assert, - }) => { - assert.plan(2); + test('do not process request when autoProcess is false', async ({ assert }) => { + assert.plan(2) const server = createServer(async (req, res) => { - const request = new RequestFactory().merge({ req, res }).create(); - const response = new ResponseFactory().merge({ req, res }).create(); - const ctx = new HttpContextFactory() - .merge({ request, response }) - .create(); + const request = new RequestFactory().merge({ req, res }).create() + const response = new ResponseFactory().merge({ req, res }).create() + const ctx = new HttpContextFactory().merge({ request, response }).create() const middleware = new BodyParserMiddlewareFactory() .merge({ multipart: { autoProcess: false, }, }) - .create(); + .create() await middleware.handle(ctx, async () => { - assert.deepEqual(ctx.request["__raw_files"], {}); - assert.instanceOf(ctx.request["multipart"], Multipart); - await ctx.request["multipart"].process(); - res.end(); - }); - }); - - await supertest(server) - .post("/") - .attach("package", packageFilePath) - .field("username", "virk"); - }).retry(3); - - test("do not process request when processManually static route matches", async ({ - assert, - }) => { - assert.plan(2); + assert.deepEqual(ctx.request['__raw_files'], {}) + assert.instanceOf(ctx.request['multipart'], Multipart) + await ctx.request['multipart'].process() + res.end() + }) + }) + + await supertest(server).post('/').attach('package', packageFilePath).field('username', 'virk') + }).retry(3) + + test('do not process request when processManually static route matches', async ({ assert }) => { + assert.plan(2) const server = createServer(async (req, res) => { - const request = new RequestFactory().merge({ req, res }).create(); - const response = new ResponseFactory().merge({ req, res }).create(); - const ctx = new HttpContextFactory() - .merge({ request, response }) - .create(); + const request = new RequestFactory().merge({ req, res }).create() + const response = new ResponseFactory().merge({ req, res }).create() + const ctx = new HttpContextFactory().merge({ request, response }).create() ctx.route = { - pattern: "/", + pattern: '/', execute: () => {}, handler: () => {}, meta: {}, middleware: {} as any, - }; + } const middleware = new BodyParserMiddlewareFactory() .merge({ multipart: { autoProcess: true, - processManually: ["/"], + processManually: ['/'], }, }) - .create(); + .create() await middleware.handle(ctx, async () => { - assert.deepEqual(ctx.request.__raw_files, {}); - assert.instanceOf(ctx.request.multipart, Multipart); - await ctx.request.multipart.process(); - res.end(); - }); - }); - - await supertest(server) - .post("/") - .attach("package", packageFilePath) - .field("username", "virk"); - }).retry(3); - - test("do not process request when processManually has dynamic route", async ({ - assert, - }) => { - assert.plan(2); + assert.deepEqual(ctx.request.__raw_files, {}) + assert.instanceOf(ctx.request.multipart, Multipart) + await ctx.request.multipart.process() + res.end() + }) + }) + + await supertest(server).post('/').attach('package', packageFilePath).field('username', 'virk') + }).retry(3) + + test('do not process request when processManually has dynamic route', async ({ assert }) => { + assert.plan(2) const server = createServer(async (req, res) => { - const request = new RequestFactory().merge({ req, res }).create(); - const response = new ResponseFactory().merge({ req, res }).create(); - const ctx = new HttpContextFactory() - .merge({ request, response }) - .create(); + const request = new RequestFactory().merge({ req, res }).create() + const response = new ResponseFactory().merge({ req, res }).create() + const ctx = new HttpContextFactory().merge({ request, response }).create() ctx.route = { - pattern: "/project/:id/file", + pattern: '/project/:id/file', execute: () => {}, handler: () => {}, meta: {}, middleware: {} as any, - }; + } const middleware = new BodyParserMiddlewareFactory() .merge({ multipart: { autoProcess: true, - processManually: ["/project/:id/file"], + processManually: ['/project/:id/file'], }, }) - .create(); + .create() await middleware.handle(ctx, async () => { - assert.deepEqual(ctx.request["__raw_files"], {}); - assert.instanceOf(ctx.request["multipart"], Multipart); - await ctx.request["multipart"].process(); - res.end(); - }); - }); - - await supertest(server) - .post("/") - .attach("package", packageFilePath) - .field("username", "virk"); - }); - - test("do not process request when autoProcess route does not match", async ({ - assert, - }) => { - assert.plan(2); + assert.deepEqual(ctx.request['__raw_files'], {}) + assert.instanceOf(ctx.request['multipart'], Multipart) + await ctx.request['multipart'].process() + res.end() + }) + }) + + await supertest(server).post('/').attach('package', packageFilePath).field('username', 'virk') + }) + + test('do not process request when autoProcess route does not match', async ({ assert }) => { + assert.plan(2) const server = createServer(async (req, res) => { - const request = new RequestFactory().merge({ req, res }).create(); - const response = new ResponseFactory().merge({ req, res }).create(); - const ctx = new HttpContextFactory() - .merge({ request, response }) - .create(); + const request = new RequestFactory().merge({ req, res }).create() + const response = new ResponseFactory().merge({ req, res }).create() + const ctx = new HttpContextFactory().merge({ request, response }).create() ctx.route = { - pattern: "/project/:id/file", + pattern: '/project/:id/file', execute: () => {}, handler: () => {}, meta: {}, middleware: {} as any, - }; + } const middleware = new BodyParserMiddlewareFactory() .merge({ multipart: { - autoProcess: ["/projects/:id/assets"], + autoProcess: ['/projects/:id/assets'], }, }) - .create(); + .create() await middleware.handle(ctx, async () => { - assert.deepEqual(ctx.request["__raw_files"], {}); - assert.instanceOf(ctx.request["multipart"], Multipart); - await ctx.request["multipart"].process(); - res.end(); - }); - }); - - await supertest(server) - .post("/") - .attach("package", packageFilePath) - .field("username", "virk"); - }); - - test("process request when autoProcess route does matches", async ({ - assert, - }) => { + assert.deepEqual(ctx.request['__raw_files'], {}) + assert.instanceOf(ctx.request['multipart'], Multipart) + await ctx.request['multipart'].process() + res.end() + }) + }) + + await supertest(server).post('/').attach('package', packageFilePath).field('username', 'virk') + }) + + test('process request when autoProcess route does matches', async ({ assert }) => { const server = createServer(async (req, res) => { - const request = new RequestFactory().merge({ req, res }).create(); - const response = new ResponseFactory().merge({ req, res }).create(); - const ctx = new HttpContextFactory() - .merge({ request, response }) - .create(); + const request = new RequestFactory().merge({ req, res }).create() + const response = new ResponseFactory().merge({ req, res }).create() + const ctx = new HttpContextFactory().merge({ request, response }).create() ctx.route = { - pattern: "/projects/:id/assets", + pattern: '/projects/:id/assets', execute: () => {}, handler: () => {}, meta: {}, middleware: {} as any, - }; + } const middleware = new BodyParserMiddlewareFactory() .merge({ multipart: { - autoProcess: ["/projects/:id/assets"], + autoProcess: ['/projects/:id/assets'], }, }) - .create(); + .create() await middleware.handle(ctx, async () => { - const pkgFile = ctx.request["__raw_files"].package as MultipartFile; + const pkgFile = ctx.request['__raw_files'].package as MultipartFile - res.writeHead(200, { "content-type": "application/json" }); + res.writeHead(200, { 'content-type': 'application/json' }) res.end( JSON.stringify({ tmpPath: pkgFile.tmpPath, size: pkgFile.size, validated: pkgFile.validated, - }), - ); - }); - }); + }) + ) + }) + }) - const { body } = await supertest(server) - .post("/") - .attach("package", packageFilePath); + const { body } = await supertest(server).post('/').attach('package', packageFilePath) - assert.isAbove(body.size, 0); - assert.exists(body.tmpPath); - assert.isFalse(body.validated); - }); + assert.isAbove(body.size, 0) + assert.exists(body.tmpPath) + assert.isFalse(body.validated) + }) - test("detect file ext and mime type using magic number", async ({ - assert, - }) => { + test('detect file ext and mime type using magic number', async ({ assert }) => { const server = createServer(async (req, res) => { - const request = new RequestFactory().merge({ req, res }).create(); - const response = new ResponseFactory().merge({ req, res }).create(); - const ctx = new HttpContextFactory() - .merge({ request, response }) - .create(); - const middleware = new BodyParserMiddlewareFactory().create(); + const request = new RequestFactory().merge({ req, res }).create() + const response = new ResponseFactory().merge({ req, res }).create() + const ctx = new HttpContextFactory().merge({ request, response }).create() + const middleware = new BodyParserMiddlewareFactory().create() await middleware.handle(ctx, async () => { - const avatar = ctx.request["__raw_files"].avatar as MultipartFile; + const avatar = ctx.request['__raw_files'].avatar as MultipartFile - res.writeHead(200, { "content-type": "application/json" }); + res.writeHead(200, { 'content-type': 'application/json' }) res.end( JSON.stringify({ type: avatar.type, subtype: avatar.subtype, extname: avatar.extname, - }), - ); - }); - }); + }) + ) + }) + }) - const { body } = await supertest(server) - .post("/") - .attach("avatar", unicornFilePath, { - contentType: "application/json", - }); + const { body } = await supertest(server).post('/').attach('avatar', unicornFilePath, { + contentType: 'application/json', + }) assert.deepEqual(body, { - type: "image", - subtype: "png", - extname: "png", - }); - }); + type: 'image', + subtype: 'png', + extname: 'png', + }) + }) - test("validate file when access via request.file method", async ({ - assert, - }) => { + test('validate file when access via request.file method', async ({ assert }) => { const server = createServer(async (req, res) => { - const request = new RequestFactory().merge({ req, res }).create(); - const response = new ResponseFactory().merge({ req, res }).create(); - const ctx = new HttpContextFactory() - .merge({ request, response }) - .create(); - const middleware = new BodyParserMiddlewareFactory().create(); + const request = new RequestFactory().merge({ req, res }).create() + const response = new ResponseFactory().merge({ req, res }).create() + const ctx = new HttpContextFactory().merge({ request, response }).create() + const middleware = new BodyParserMiddlewareFactory().create() await middleware.handle(ctx, async () => { - res.writeHead(200, { "content-type": "application/json" }); - const pkgFile = ctx.request.file("package", { size: 10 })!; + res.writeHead(200, { 'content-type': 'application/json' }) + const pkgFile = ctx.request.file('package', { size: 10 })! res.end( JSON.stringify({ @@ -915,107 +791,97 @@ test.group("BodyParser Middleware | multipart", () => { validated: pkgFile.validated, isValid: pkgFile.isValid, errors: pkgFile.errors, - }), - ); - }); - }); + }) + ) + }) + }) - const { body } = await supertest(server) - .post("/") - .attach("package", packageFilePath); + const { body } = await supertest(server).post('/').attach('package', packageFilePath) - assert.equal(body.size, packageFileSize); - assert.exists(body.tmpPath); - assert.isTrue(body.validated); - assert.isFalse(body.isValid); + assert.equal(body.size, packageFileSize) + assert.exists(body.tmpPath) + assert.isTrue(body.validated) + assert.isFalse(body.isValid) assert.deepEqual(body.errors, [ { - fieldName: "package", - clientName: "package.json", - message: "File size should be less than 10B", - type: "size", + fieldName: 'package', + clientName: 'package.json', + message: 'File size should be less than 10B', + type: 'size', }, - ]); - }); + ]) + }) - test("validate array of files when access via request.file method", async ({ - assert, - }) => { + test('validate array of files when access via request.file method', async ({ assert }) => { const server = createServer(async (req, res) => { - const request = new RequestFactory().merge({ req, res }).create(); - const response = new ResponseFactory().merge({ req, res }).create(); - const ctx = new HttpContextFactory() - .merge({ request, response }) - .create(); - const middleware = new BodyParserMiddlewareFactory().create(); + const request = new RequestFactory().merge({ req, res }).create() + const response = new ResponseFactory().merge({ req, res }).create() + const ctx = new HttpContextFactory().merge({ request, response }).create() + const middleware = new BodyParserMiddlewareFactory().create() await middleware.handle(ctx, async () => { - res.writeHead(200, { "content-type": "application/json" }); - const pkgFiles = ctx.request - .files("package", { size: 10 }) - .map((pkgFile) => { - return { - tmpPath: pkgFile.tmpPath!, - size: pkgFile.size, - validated: pkgFile.validated, - isValid: pkgFile.isValid, - errors: pkgFile.errors, - }; - }); - - res.end(JSON.stringify(pkgFiles)); - }); - }); + res.writeHead(200, { 'content-type': 'application/json' }) + const pkgFiles = ctx.request.files('package', { size: 10 }).map((pkgFile) => { + return { + tmpPath: pkgFile.tmpPath!, + size: pkgFile.size, + validated: pkgFile.validated, + isValid: pkgFile.isValid, + errors: pkgFile.errors, + } + }) + + res.end(JSON.stringify(pkgFiles)) + }) + }) const { body } = await supertest(server) - .post("/") - .attach("package[0]", packageFilePath) - .attach("package[1]", packageFilePath); + .post('/') + .attach('package[0]', packageFilePath) + .attach('package[1]', packageFilePath) - assert.lengthOf(body, 2); - assert.equal(body[0].size, packageFileSize); - assert.equal(body[1].size, packageFileSize); + assert.lengthOf(body, 2) + assert.equal(body[0].size, packageFileSize) + assert.equal(body[1].size, packageFileSize) - assert.exists(body[0].tmpPath); - assert.exists(body[1].tmpPath); + assert.exists(body[0].tmpPath) + assert.exists(body[1].tmpPath) - assert.isTrue(body[0].validated); - assert.isTrue(body[1].validated); + assert.isTrue(body[0].validated) + assert.isTrue(body[1].validated) - assert.isFalse(body[0].isValid); - assert.isFalse(body[1].isValid); + assert.isFalse(body[0].isValid) + assert.isFalse(body[1].isValid) assert.deepEqual(body[0].errors, [ { - fieldName: "package[0]", - clientName: "package.json", - message: "File size should be less than 10B", - type: "size", + fieldName: 'package[0]', + clientName: 'package.json', + message: 'File size should be less than 10B', + type: 'size', }, - ]); + ]) assert.deepEqual(body[1].errors, [ { - fieldName: "package[1]", - clientName: "package.json", - message: "File size should be less than 10B", - type: "size", + fieldName: 'package[1]', + clientName: 'package.json', + message: 'File size should be less than 10B', + type: 'size', }, - ]); - }); + ]) + }) - test("pull first file even when source is an array", async ({ assert }) => { + test('pull first file even when source is an array', async ({ assert }) => { const server = createServer(async (req, res) => { - const request = new RequestFactory().merge({ req, res }).create(); - const response = new ResponseFactory().merge({ req, res }).create(); - const ctx = new HttpContextFactory() - .merge({ request, response }) - .create(); - const middleware = new BodyParserMiddlewareFactory().create(); + const request = new RequestFactory().merge({ req, res }).create() + const response = new ResponseFactory().merge({ req, res }).create() + const ctx = new HttpContextFactory().merge({ request, response }).create() + const middleware = new BodyParserMiddlewareFactory().create() await middleware.handle(ctx, async () => { - res.writeHead(200, { "content-type": "application/json" }); - const pkgFile = ctx.request.file("package", { size: 10 })!; + res.writeHead(200, { 'content-type': 'application/json' }) + const pkgFile = ctx.request.file('package', { size: 10 })! res.end( JSON.stringify({ @@ -1024,82 +890,76 @@ test.group("BodyParser Middleware | multipart", () => { validated: pkgFile.validated, isValid: pkgFile.isValid, errors: pkgFile.errors, - }), - ); - }); - }); + }) + ) + }) + }) const { body } = await supertest(server) - .post("/") - .attach("package[0]", packageFilePath) - .attach("package[1]", packageFilePath); - - assert.equal(body.size, packageFileSize); - assert.exists(body.tmpPath); - assert.isTrue(body.validated); - assert.isFalse(body.isValid); + .post('/') + .attach('package[0]', packageFilePath) + .attach('package[1]', packageFilePath) + + assert.equal(body.size, packageFileSize) + assert.exists(body.tmpPath) + assert.isTrue(body.validated) + assert.isFalse(body.isValid) assert.deepEqual(body.errors, [ { - fieldName: "package[0]", - clientName: "package.json", - message: "File size should be less than 10B", - type: "size", + fieldName: 'package[0]', + clientName: 'package.json', + message: 'File size should be less than 10B', + type: 'size', }, - ]); - }); + ]) + }) test("return null when file doesn't exists", async ({ assert }) => { const server = createServer(async (req, res) => { - const request = new RequestFactory().merge({ req, res }).create(); - const response = new ResponseFactory().merge({ req, res }).create(); - const ctx = new HttpContextFactory() - .merge({ request, response }) - .create(); - const middleware = new BodyParserMiddlewareFactory().create(); + const request = new RequestFactory().merge({ req, res }).create() + const response = new ResponseFactory().merge({ req, res }).create() + const ctx = new HttpContextFactory().merge({ request, response }).create() + const middleware = new BodyParserMiddlewareFactory().create() await middleware.handle(ctx, async () => { - res.writeHead(200, { "content-type": "application/json" }); - const pkgFile = ctx.request.file("package", { size: 10 }); - res.end(JSON.stringify(pkgFile)); - }); - }); + res.writeHead(200, { 'content-type': 'application/json' }) + const pkgFile = ctx.request.file('package', { size: 10 }) + res.end(JSON.stringify(pkgFile)) + }) + }) - const { body } = await supertest(server).post("/"); - assert.isNull(body); - }); + const { body } = await supertest(server).post('/') + assert.isNull(body) + }) test("return empty array file doesn't exists", async ({ assert }) => { const server = createServer(async (req, res) => { - const request = new RequestFactory().merge({ req, res }).create(); - const response = new ResponseFactory().merge({ req, res }).create(); - const ctx = new HttpContextFactory() - .merge({ request, response }) - .create(); - const middleware = new BodyParserMiddlewareFactory().create(); + const request = new RequestFactory().merge({ req, res }).create() + const response = new ResponseFactory().merge({ req, res }).create() + const ctx = new HttpContextFactory().merge({ request, response }).create() + const middleware = new BodyParserMiddlewareFactory().create() await middleware.handle(ctx, async () => { - res.writeHead(200, { "content-type": "application/json" }); - const pkgFile = ctx.request.files("package", { size: 10 }); - res.end(JSON.stringify(pkgFile)); - }); - }); + res.writeHead(200, { 'content-type': 'application/json' }) + const pkgFile = ctx.request.files('package', { size: 10 }) + res.end(JSON.stringify(pkgFile)) + }) + }) - const { body } = await supertest(server).post("/"); - assert.deepEqual(body, []); - }); + const { body } = await supertest(server).post('/') + assert.deepEqual(body, []) + }) - test("get file from nested object", async ({ assert }) => { + test('get file from nested object', async ({ assert }) => { const server = createServer(async (req, res) => { - const request = new RequestFactory().merge({ req, res }).create(); - const response = new ResponseFactory().merge({ req, res }).create(); - const ctx = new HttpContextFactory() - .merge({ request, response }) - .create(); - const middleware = new BodyParserMiddlewareFactory().create(); + const request = new RequestFactory().merge({ req, res }).create() + const response = new ResponseFactory().merge({ req, res }).create() + const ctx = new HttpContextFactory().merge({ request, response }).create() + const middleware = new BodyParserMiddlewareFactory().create() await middleware.handle(ctx, async () => { - res.writeHead(200, { "content-type": "application/json" }); - const pkgFile = ctx.request.file("user.package")!; + res.writeHead(200, { 'content-type': 'application/json' }) + const pkgFile = ctx.request.file('user.package')! res.end( JSON.stringify({ @@ -1108,147 +968,123 @@ test.group("BodyParser Middleware | multipart", () => { validated: pkgFile.validated, isValid: pkgFile.isValid, errors: pkgFile.errors, - }), - ); - }); - }); + }) + ) + }) + }) - const { body } = await supertest(server) - .post("/") - .attach("user.package", packageFilePath); + const { body } = await supertest(server).post('/').attach('user.package', packageFilePath) - assert.equal(body.size, packageFileSize); - assert.exists(body.tmpPath); - assert.isTrue(body.validated); - assert.isTrue(body.isValid); - assert.deepEqual(body.errors, []); - }); + assert.equal(body.size, packageFileSize) + assert.exists(body.tmpPath) + assert.isTrue(body.validated) + assert.isTrue(body.isValid) + assert.deepEqual(body.errors, []) + }) - test("move file to a given location", async ({ assert, fs }) => { + test('move file to a given location', async ({ assert, fs }) => { const server = createServer(async (req, res) => { - const request = new RequestFactory().merge({ req, res }).create(); - const response = new ResponseFactory().merge({ req, res }).create(); - const ctx = new HttpContextFactory() - .merge({ request, response }) - .create(); - const middleware = new BodyParserMiddlewareFactory().create(); + const request = new RequestFactory().merge({ req, res }).create() + const response = new ResponseFactory().merge({ req, res }).create() + const ctx = new HttpContextFactory().merge({ request, response }).create() + const middleware = new BodyParserMiddlewareFactory().create() await middleware.handle(ctx, async () => { - const pkgFile = ctx.request.file("package")!; + const pkgFile = ctx.request.file('package')! try { - await pkgFile.move(fs.basePath); - assert.equal(pkgFile.state, "moved"); - res.writeHead(200, { "content-type": "application/json" }); - res.end(); + await pkgFile.move(fs.basePath) + assert.equal(pkgFile.state, 'moved') + res.writeHead(200, { 'content-type': 'application/json' }) + res.end() } catch (error) { - res.writeHead(500, { "content-type": "application/json" }); - res.end(error.message); + res.writeHead(500, { 'content-type': 'application/json' }) + res.end(error.message) } - }); - }); + }) + }) - await supertest(server) - .post("/") - .attach("package", packageFilePath) - .expect(200); + await supertest(server).post('/').attach('package', packageFilePath).expect(200) - const uploadedFileContents = await fs.contents("package.json"); - const originalFileContents = await readFile(packageFilePath, "utf-8"); - assert.equal(uploadedFileContents, originalFileContents); - }); + const uploadedFileContents = await fs.contents('package.json') + const originalFileContents = await readFile(packageFilePath, 'utf-8') + assert.equal(uploadedFileContents, originalFileContents) + }) - test("move file with custom name", async ({ assert, fs }) => { + test('move file with custom name', async ({ assert, fs }) => { const server = createServer(async (req, res) => { - const request = new RequestFactory().merge({ req, res }).create(); - const response = new ResponseFactory().merge({ req, res }).create(); - const ctx = new HttpContextFactory() - .merge({ request, response }) - .create(); - const middleware = new BodyParserMiddlewareFactory().create(); + const request = new RequestFactory().merge({ req, res }).create() + const response = new ResponseFactory().merge({ req, res }).create() + const ctx = new HttpContextFactory().merge({ request, response }).create() + const middleware = new BodyParserMiddlewareFactory().create() await middleware.handle(ctx, async () => { - const pkgFile = ctx.request.file("package")!; + const pkgFile = ctx.request.file('package')! try { await pkgFile.move(fs.basePath, { name: `myapp.${pkgFile.subtype}`, - }); - assert.equal(pkgFile.state, "moved"); - res.writeHead(200, { "content-type": "application/json" }); - res.end(); + }) + assert.equal(pkgFile.state, 'moved') + res.writeHead(200, { 'content-type': 'application/json' }) + res.end() } catch (error) { - res.writeHead(500, { "content-type": "application/json" }); - res.end(error.message); + res.writeHead(500, { 'content-type': 'application/json' }) + res.end(error.message) } - }); - }); + }) + }) - await supertest(server) - .post("/") - .attach("package", packageFilePath) - .expect(200); + await supertest(server).post('/').attach('package', packageFilePath).expect(200) - const uploadedFileContents = await fs.contents("myapp.json"); - const originalFileContents = await readFile(packageFilePath, "utf-8"); - assert.equal(uploadedFileContents, originalFileContents); - }); + const uploadedFileContents = await fs.contents('myapp.json') + const originalFileContents = await readFile(packageFilePath, 'utf-8') + assert.equal(uploadedFileContents, originalFileContents) + }) - test("raise error when destination file already exists", async ({ - assert, - fs, - }) => { + test('raise error when destination file already exists', async ({ assert, fs }) => { const server = createServer(async (req, res) => { - const request = new RequestFactory().merge({ req, res }).create(); - const response = new ResponseFactory().merge({ req, res }).create(); - const ctx = new HttpContextFactory() - .merge({ request, response }) - .create(); - const middleware = new BodyParserMiddlewareFactory().create(); + const request = new RequestFactory().merge({ req, res }).create() + const response = new ResponseFactory().merge({ req, res }).create() + const ctx = new HttpContextFactory().merge({ request, response }).create() + const middleware = new BodyParserMiddlewareFactory().create() await middleware.handle(ctx, async () => { - const pkgFile = ctx.request.file("package")!; + const pkgFile = ctx.request.file('package')! try { - await pkgFile.move(fs.basePath, { overwrite: false }); + await pkgFile.move(fs.basePath, { overwrite: false }) } catch (error) { assert.equal( error.message, - `"package.json" already exists at "${fs.basePath}". Set "overwrite = true" to overwrite it`, - ); - assert.equal(pkgFile.state, "consumed"); - res.writeHead(200, { "content-type": "application/json" }); - res.end(); + `"package.json" already exists at "${fs.basePath}". Set "overwrite = true" to overwrite it` + ) + assert.equal(pkgFile.state, 'consumed') + res.writeHead(200, { 'content-type': 'application/json' }) + res.end() } - }); - }); + }) + }) - await fs.create("package.json", JSON.stringify({})); - await supertest(server) - .post("/") - .attach("package", packageFilePath) - .expect(200); - }); + await fs.create('package.json', JSON.stringify({})) + await supertest(server).post('/').attach('package', packageFilePath).expect(200) + }) - test("validate file extension and file size seperately", async ({ - assert, - }) => { + test('validate file extension and file size seperately', async ({ assert }) => { const server = createServer(async (req, res) => { - const request = new RequestFactory().merge({ req, res }).create(); - const response = new ResponseFactory().merge({ req, res }).create(); - const ctx = new HttpContextFactory() - .merge({ request, response }) - .create(); - const middleware = new BodyParserMiddlewareFactory().create(); + const request = new RequestFactory().merge({ req, res }).create() + const response = new ResponseFactory().merge({ req, res }).create() + const ctx = new HttpContextFactory().merge({ request, response }).create() + const middleware = new BodyParserMiddlewareFactory().create() await middleware.handle(ctx, async () => { - res.writeHead(200, { "content-type": "application/json" }); - const pkgFile = ctx.request.file("package")!; - pkgFile.sizeLimit = 10; - pkgFile.validate(); + res.writeHead(200, { 'content-type': 'application/json' }) + const pkgFile = ctx.request.file('package')! + pkgFile.sizeLimit = 10 + pkgFile.validate() - pkgFile.allowedExtensions = ["jpg"]; - pkgFile.validate(); + pkgFile.allowedExtensions = ['jpg'] + pkgFile.validate() res.end( JSON.stringify({ @@ -1257,56 +1093,52 @@ test.group("BodyParser Middleware | multipart", () => { validated: pkgFile.validated, isValid: pkgFile.isValid, errors: pkgFile.errors, - }), - ); - }); - }); + }) + ) + }) + }) - const { body } = await supertest(server) - .post("/") - .attach("package", packageFilePath); + const { body } = await supertest(server).post('/').attach('package', packageFilePath) - assert.equal(body.size, packageFileSize); - assert.exists(body.tmpPath); - assert.isTrue(body.validated); - assert.isFalse(body.isValid); + assert.equal(body.size, packageFileSize) + assert.exists(body.tmpPath) + assert.isTrue(body.validated) + assert.isFalse(body.isValid) assert.deepEqual(body.errors, [ { - fieldName: "package", - clientName: "package.json", - message: "File size should be less than 10B", - type: "size", + fieldName: 'package', + clientName: 'package.json', + message: 'File size should be less than 10B', + type: 'size', }, { - fieldName: "package", - clientName: "package.json", - message: "Invalid file extension json. Only jpg is allowed", - type: "extname", + fieldName: 'package', + clientName: 'package.json', + message: 'Invalid file extension json. Only jpg is allowed', + type: 'extname', }, - ]); - }); + ]) + }) - test("calling validate multiple times must be a noop", async ({ assert }) => { + test('calling validate multiple times must be a noop', async ({ assert }) => { const server = createServer(async (req, res) => { - const request = new RequestFactory().merge({ req, res }).create(); - const response = new ResponseFactory().merge({ req, res }).create(); - const ctx = new HttpContextFactory() - .merge({ request, response }) - .create(); - const middleware = new BodyParserMiddlewareFactory().create(); + const request = new RequestFactory().merge({ req, res }).create() + const response = new ResponseFactory().merge({ req, res }).create() + const ctx = new HttpContextFactory().merge({ request, response }).create() + const middleware = new BodyParserMiddlewareFactory().create() await middleware.handle(ctx, async () => { - res.writeHead(200, { "content-type": "application/json" }); - const pkgFile = ctx.request.file("package")!; - pkgFile.sizeLimit = 10; - pkgFile.validate(); - pkgFile.validate(); - pkgFile.validate(); - - pkgFile.allowedExtensions = ["jpg"]; - pkgFile.validate(); - pkgFile.validate(); - pkgFile.validate(); + res.writeHead(200, { 'content-type': 'application/json' }) + const pkgFile = ctx.request.file('package')! + pkgFile.sizeLimit = 10 + pkgFile.validate() + pkgFile.validate() + pkgFile.validate() + + pkgFile.allowedExtensions = ['jpg'] + pkgFile.validate() + pkgFile.validate() + pkgFile.validate() res.end( JSON.stringify({ @@ -1315,52 +1147,48 @@ test.group("BodyParser Middleware | multipart", () => { validated: pkgFile.validated, isValid: pkgFile.isValid, errors: pkgFile.errors, - }), - ); - }); - }); + }) + ) + }) + }) - const { body } = await supertest(server) - .post("/") - .attach("package", packageFilePath); + const { body } = await supertest(server).post('/').attach('package', packageFilePath) - assert.equal(body.size, packageFileSize); - assert.exists(body.tmpPath); - assert.isTrue(body.validated); - assert.isFalse(body.isValid); + assert.equal(body.size, packageFileSize) + assert.exists(body.tmpPath) + assert.isTrue(body.validated) + assert.isFalse(body.isValid) assert.deepEqual(body.errors, [ { - fieldName: "package", - clientName: "package.json", - message: "File size should be less than 10B", - type: "size", + fieldName: 'package', + clientName: 'package.json', + message: 'File size should be less than 10B', + type: 'size', }, { - fieldName: "package", - clientName: "package.json", - message: "Invalid file extension json. Only jpg is allowed", - type: "extname", + fieldName: 'package', + clientName: 'package.json', + message: 'Invalid file extension json. Only jpg is allowed', + type: 'extname', }, - ]); - }); + ]) + }) - test("validate file size using request.file method and extension manually", async ({ + test('validate file size using request.file method and extension manually', async ({ assert, }) => { const server = createServer(async (req, res) => { - const request = new RequestFactory().merge({ req, res }).create(); - const response = new ResponseFactory().merge({ req, res }).create(); - const ctx = new HttpContextFactory() - .merge({ request, response }) - .create(); - const middleware = new BodyParserMiddlewareFactory().create(); + const request = new RequestFactory().merge({ req, res }).create() + const response = new ResponseFactory().merge({ req, res }).create() + const ctx = new HttpContextFactory().merge({ request, response }).create() + const middleware = new BodyParserMiddlewareFactory().create() await middleware.handle(ctx, async () => { - res.writeHead(200, { "content-type": "application/json" }); - const pkgFile = ctx.request.file("package", { size: 10 })!; + res.writeHead(200, { 'content-type': 'application/json' }) + const pkgFile = ctx.request.file('package', { size: 10 })! - pkgFile.allowedExtensions = ["jpg"]; - pkgFile.validate(); + pkgFile.allowedExtensions = ['jpg'] + pkgFile.validate() res.end( JSON.stringify({ @@ -1369,118 +1197,103 @@ test.group("BodyParser Middleware | multipart", () => { validated: pkgFile.validated, isValid: pkgFile.isValid, errors: pkgFile.errors, - }), - ); - }); - }); + }) + ) + }) + }) - const { body } = await supertest(server) - .post("/") - .attach("package", packageFilePath); + const { body } = await supertest(server).post('/').attach('package', packageFilePath) - assert.equal(body.size, packageFileSize); - assert.exists(body.tmpPath); - assert.isTrue(body.validated); - assert.isFalse(body.isValid); + assert.equal(body.size, packageFileSize) + assert.exists(body.tmpPath) + assert.isTrue(body.validated) + assert.isFalse(body.isValid) assert.deepEqual(body.errors, [ { - fieldName: "package", - clientName: "package.json", - message: "File size should be less than 10B", - type: "size", + fieldName: 'package', + clientName: 'package.json', + message: 'File size should be less than 10B', + type: 'size', }, { - fieldName: "package", - clientName: "package.json", - message: "Invalid file extension json. Only jpg is allowed", - type: "extname", + fieldName: 'package', + clientName: 'package.json', + message: 'Invalid file extension json. Only jpg is allowed', + type: 'extname', }, - ]); - }); + ]) + }) - test("updating sizeLimit multiple times must not be allowed", async ({ - assert, - }) => { + test('updating sizeLimit multiple times must not be allowed', async ({ assert }) => { const server = createServer(async (req, res) => { - const request = new RequestFactory().merge({ req, res }).create(); - const response = new ResponseFactory().merge({ req, res }).create(); - const ctx = new HttpContextFactory() - .merge({ request, response }) - .create(); - const middleware = new BodyParserMiddlewareFactory().create(); + const request = new RequestFactory().merge({ req, res }).create() + const response = new ResponseFactory().merge({ req, res }).create() + const ctx = new HttpContextFactory().merge({ request, response }).create() + const middleware = new BodyParserMiddlewareFactory().create() await middleware.handle(ctx, async () => { - const pkgFile = ctx.request.file("package", { size: 10 })!; + const pkgFile = ctx.request.file('package', { size: 10 })! try { - pkgFile.sizeLimit = 20; - res.writeHead(200); - res.end(); + pkgFile.sizeLimit = 20 + res.writeHead(200) + res.end() } catch (error) { - res.writeHead(500); - res.end(error.message); + res.writeHead(500) + res.end(error.message) } - }); - }); + }) + }) const { text } = await supertest(server) - .post("/") - .attach("package", packageFilePath) - .expect(500); + .post('/') + .attach('package', packageFilePath) + .expect(500) - assert.equal(text, "Cannot reset sizeLimit after file has been validated"); - }); + assert.equal(text, 'Cannot reset sizeLimit after file has been validated') + }) - test("updating allowedExtensions multiple times must not be allowed", async ({ - assert, - }) => { + test('updating allowedExtensions multiple times must not be allowed', async ({ assert }) => { const server = createServer(async (req, res) => { - const request = new RequestFactory().merge({ req, res }).create(); - const response = new ResponseFactory().merge({ req, res }).create(); - const ctx = new HttpContextFactory() - .merge({ request, response }) - .create(); - const middleware = new BodyParserMiddlewareFactory().create(); + const request = new RequestFactory().merge({ req, res }).create() + const response = new ResponseFactory().merge({ req, res }).create() + const ctx = new HttpContextFactory().merge({ request, response }).create() + const middleware = new BodyParserMiddlewareFactory().create() await middleware.handle(ctx, async () => { - const pkgFile = ctx.request.file("package", { extnames: ["json"] })!; + const pkgFile = ctx.request.file('package', { extnames: ['json'] })! try { - pkgFile.allowedExtensions = ["jpg"]; - res.writeHead(200); - res.end(); + pkgFile.allowedExtensions = ['jpg'] + res.writeHead(200) + res.end() } catch (error) { - res.writeHead(500); - res.end(error.message); + res.writeHead(500) + res.end(error.message) } - }); - }); + }) + }) const { text } = await supertest(server) - .post("/") - .attach("package", packageFilePath) - .expect(500); + .post('/') + .attach('package', packageFilePath) + .expect(500) - assert.equal( - text, - "Cannot update allowed extension names after file has been validated", - ); - }); + assert.equal(text, 'Cannot update allowed extension names after file has been validated') + }) - test("get all files as an object", async ({ assert }) => { + test('get all files as an object', async ({ assert }) => { const server = createServer(async (req, res) => { - const request = new RequestFactory().merge({ req, res }).create(); - const response = new ResponseFactory().merge({ req, res }).create(); - const ctx = new HttpContextFactory() - .merge({ request, response }) - .create(); - const middleware = new BodyParserMiddlewareFactory().create(); + const request = new RequestFactory().merge({ req, res }).create() + const response = new ResponseFactory().merge({ req, res }).create() + const ctx = new HttpContextFactory().merge({ request, response }).create() + const middleware = new BodyParserMiddlewareFactory().create() await middleware.handle(ctx, async () => { - res.writeHead(200, { "content-type": "application/json" }); - const allFiles = ctx.request.allFiles(); + res.writeHead(200, { 'content-type': 'application/json' }) + const allFiles = ctx.request.allFiles() const files = Object.keys(allFiles).map((field) => { - const file = allFiles[field] as MultipartFile; + const file = allFiles[field] as MultipartFile return { field: field, tmpPath: file.tmpPath!, @@ -1488,46 +1301,42 @@ test.group("BodyParser Middleware | multipart", () => { validated: file.validated, isValid: file.isValid, errors: file.errors, - }; - }); + } + }) - res.end(JSON.stringify(files)); - }); - }); + res.end(JSON.stringify(files)) + }) + }) - const { body } = await supertest(server) - .post("/") - .attach("package", packageFilePath); - - assert.lengthOf(body, 1); - assert.equal(body[0].size, packageFileSize); - assert.exists(body[0].tmpPath); - assert.isFalse(body[0].validated); - assert.isTrue(body[0].isValid); - assert.lengthOf(body[0].errors, 0); - }); - - test("convert empty strings to null", async ({ assert }) => { + const { body } = await supertest(server).post('/').attach('package', packageFilePath) + + assert.lengthOf(body, 1) + assert.equal(body[0].size, packageFileSize) + assert.exists(body[0].tmpPath) + assert.isFalse(body[0].validated) + assert.isTrue(body[0].isValid) + assert.lengthOf(body[0].errors, 0) + }) + + test('convert empty strings to null', async ({ assert }) => { const server = createServer(async (req, res) => { - const request = new RequestFactory().merge({ req, res }).create(); - const response = new ResponseFactory().merge({ req, res }).create(); - const ctx = new HttpContextFactory() - .merge({ request, response }) - .create(); - const middleware = new BodyParserMiddlewareFactory().create(); + const request = new RequestFactory().merge({ req, res }).create() + const response = new ResponseFactory().merge({ req, res }).create() + const ctx = new HttpContextFactory().merge({ request, response }).create() + const middleware = new BodyParserMiddlewareFactory().create() await middleware.handle(ctx, async () => { - res.writeHead(200, { "content-type": "application/json" }); - const body = ctx.request.all(); - res.end(JSON.stringify(body)); - }); - }); + res.writeHead(200, { 'content-type': 'application/json' }) + const body = ctx.request.all() + res.end(JSON.stringify(body)) + }) + }) const { body } = await supertest(server) - .post("/") - .attach("package", packageFilePath) - .field("username", ""); + .post('/') + .attach('package', packageFilePath) + .field('username', '') - assert.deepEqual(body, { username: null }); - }); -}); + assert.deepEqual(body, { username: null }) + }) +})