How to send a formData object with supertest?
Asked Answered
H

2

10

I just started to learn do test with supertest and mocha. I've read the api document of supertest and it said that supertest support all lower-level API provided by superagent. SuperAgent said we can send a formData object by:

request.post('/user')
    .send(new FormData(document.getElementById('myForm')))
    .then(callback)

But when I try to send a formData object with supertest like this:

server
    .post('/goal_model/images/' + userId + '/' + tmid)
    .set('Authorization',`Bearer ${token}`)
    .send(formData)
    .expect("Content-type",/json/)
    .expect(201)
    .end(function(err,res){
         should(res.status).equal(201);
         console.log(res.message);
         done();
    });

Where the formData is like:

let file;
let formData = new FormData();
let fn = "../../../Downloads/Images/5k.jpg";
formData.append("image", file);

Then when I try to send this object it just said:

TypeError: "string" must be a string, Buffer, or ArrayBuffer

Does it possible to send a formData object in this way? What did I do wrong or how to do that? If not, why? I've searched many relative questions but none can solve my problem. I'm really in struglling now.

Halimeda answered 17/9, 2018 at 2:9 Comment(0)
P
5

You can use .attach() method of supertest to send your file to the server. Function signature of .attach:

attach(field: string, file: MultipartValueSingle, options?: string | { filename?: string; contentType?: string }): this;

The data type of file parameter can be:

type MultipartValueSingle = Blob | Buffer | fs.ReadStream | string | boolean | number;

Here I pass a file path to .attach method.

E.g.

server.ts:

import express from 'express';
import multer from 'multer';
import path from 'path';

const app = express();
const port = 3000;
const upload = multer({ dest: path.resolve(__dirname, 'uploads/') });
app.post('/upload', upload.single('avatar'), (req, res) => {
  console.log('file:', req.file);
  console.log('content-type:', req.get('Content-Type'));
  res.sendStatus(200);
});

if (require.main === module) {
  app.listen(port, () => {
    console.log(`HTTP server is listening on http://localhost:${port}`);
  });
}

export { app };

server.test.ts:

import { app } from './server';
import request from 'supertest';
import path from 'path';

describe('52359964', () => {
  it('should pass', () => {
    return request(app)
      .post('/upload')
      .attach('avatar', path.resolve(__dirname, './downloads/5k.jpg'))
      .expect(200);
  });
});

integration test results:

  52359964
file: { fieldname: 'avatar',
  originalname: '5k.jpg',
  encoding: '7bit',
  mimetype: 'image/jpeg',
  destination:
   '/Users/ldu020/workspace/github.com/mrdulin/expressjs-research/src/stackoverflow/52359964/uploads',
  filename: '329756ab22bf7abe2d27866a322c2f30',
  path:
   '/Users/ldu020/workspace/github.com/mrdulin/expressjs-research/src/stackoverflow/52359964/uploads/329756ab22bf7abe2d27866a322c2f30',
  size: 0 }
content-type: multipart/form-data; boundary=--------------------------777489367435889931561092
    ✓ should pass (42ms)


  1 passing (48ms)
Polycarp answered 30/3, 2020 at 3:42 Comment(0)
L
0

Recently went throught the same problem. Below is my working code . If you are sending both data and file to the api endpoint you should use .field() to send values and .attach to send files.

`

describe('Admin Routes', () => { let user, restaurant;

beforeAll(async () => {
    user = await User.create({username: 'aman', password: 'password', email: '[email protected]', phone: 123, restaurantOwner: true});
    restaurant = await Restaurant.create({name: 'taj', phone: 123, ownerId: user._id});
    const mockPayload = { userId: user._id, restaurantOwner: true };
    jest.spyOn(jwt, 'verify').mockReturnValue(mockPayload);

});
let dishId ;

it('should create dish with an image and form data', async () => {
    // ... (rest of your test)
    const res = await request(app)
        .post('/admin/create')
        .set({ Authorization: '123' })
        .field('name', 'someName')
        .field('restaurantId', restaurant._id.toString())
        .field('price', String(10))
        .field('description', 'Some Description')
        .attach('image',path.resolve(__dirname, '../../images/dish.jpg'));
    expect(res.status).toBe(201)

});`

If you get Error Like

Aborted

      at Test.<anonymous> (node_modules/superagent/src/request-base.js:278:23)
      at Test.abort (node_modules/superagent/src/request-base.js:510:8)
      at FormData.<anonymous> (node_modules/superagent/src/node/index.js:288:12)
      at FormData.Object.<anonymous>.CombinedStream._emitError (node_modules/combined-stream/lib/combined_stream.js:207:8)
      at DelayedStream.<anonymous> (node_modules/combined-stream/lib/combined_stream.js:133:10)
      at DelayedStream.Object.<anonymous>.DelayedStream._handleEmit (node_modules/delayed-stream/lib/delayed_stream.js:82:15)
      at ReadStream.source.emit (node_modules/delayed-stream/lib/delayed_stream.js:29:19)

It is possibly due to the your image path being wrong. __dirname is path of the folder where the test file is, so the next argument should be set accordingly.

Leggat answered 27/3 at 12:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.