typescriptgraphqlnestjssupertest

Why am I getting "POST body missing" error while uploading files in a GraphQL request with Supertest?


Problem Description:

I am trying to test a file upload mutation in my GraphQL server using Supertest. server: Nestjs+GraphQL FYI: The API is working fine with appolo graphql client and postman.

However, I keep getting the following error:

Error: cannot POST /graphql (500)
          at Response.toError (/src/node_modules/superagent/src/node/response.js:110:17)
          at Response._setStatusProperties (/src/node_modules/superagent/src/response-base.js:107:48)
          at new Response (/src/node_modules/superagent/src/node/response.js:41:8)
          at Test._emitResponse (/src/node_modules/superagent/src/node/index.js:953:20)
          at IncomingMessage.<anonymous> (/src/node_modules/superagent/src/node/index.js:1166:38)
          at IncomingMessage.emit (node:events:525:35)
          at IncomingMessage.emit (node:domain:489:12)
          at endReadableNT (node:internal/streams/readable:1358:12)
          at processTicksAndRejections (node:internal/process/task_queues:83:21) {
        status: 500,
        text: 'POST body missing. Did you forget use body-parser middleware?',
        method: 'POST',
        path: '/graphql'
      }

Expected Behavior:

The mutation should work as expected and process the file upload successfully.


What I Tried:

Here is the test code I am using:

const filePath = path.join(__dirname, '1.png');
    const serverInstance = await integrationTestManager.getServerInstance()

const graphqlRequest = request(serverInstance).post('/graphql')
  .field('operations', jsonRequestBodyString)
  .set('Content-Type', 'multipart/form-data')
  .field("map", JSON.stringify({
    "0": ["variables.picUpload"],
  }))
  .attach("0", filePath)
  .set('Authorization', testingContext.users[user].token);

const testResponse = await graphqlRequest;

Error Details:


Additional Context:


server file

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import * as cors from 'cors';
import { graphqlUploadExpress } from 'graphql-upload';
import { ConfigService } from './common/config/config.service';
import { NestExpressApplication } from '@nestjs/platform-express';
import { join } from 'path';
import * as bodyParser from 'body-parser';
const config: ConfigService = new ConfigService(`.env.${process.env.NODE_ENV}`);

async function bootstrap() {
  try {
    const app = await NestFactory.create<NestExpressApplication>(AppModule);
    const port = process.env.PORT || config.get('PORT');
    // app.useStaticAssets(join(__dirname, '..', 'public'));

    app.use(bodyParser.json());
    app.use(bodyParser.urlencoded({ extended: true }));
    app.getHttpAdapter().getInstance().disable('x-powered-by');
    app.use(graphqlUploadExpress({ maxFileSize: 5242880, maxFiles: 10 }));
    app.setBaseViewsDir(join(__dirname, '../..', 'src/views'));
    app.setViewEngine('ejs');
    app.use(cors());
    console.log('port :>> ', port);
    await app.listen(port);
    console.log(`App running on port ${port}`)
  } catch (error) {
    return { error }
  }
}
bootstrap();

Any insights or solutions to resolve this issue would be greatly appreciated!


Solution

  • I don't see the whole test but I assume that you have something like this:

    let app: INestApplication;
    
    beforeEach(async () => {
        const module = await Test.createTestingModule({ imports: [AppModule] })
            .compile();
    
        app = module.createNestApplication();
        // etc..
    });
    

    If so, the graphqlUpload middleware won't be added to your application created during test. As I can see you add it in bootstrap tho, so that may explain why it works outside tests.

    If my guess is correct you should add middleware to your test too. For example:

    let app: INestApplication;
    
    beforeEach(async () => {
        const module = await Test.createTestingModule({ imports: [AppModule] })
            .compile();
    
        app = module.createNestApplication();
        app.use(graphqlUploadExpress({ maxFileSize: 5242880, maxFiles: 10 }))
    
        // etc..
    });
    

    If it won't help could you please share implementation of integrationTestManager.getServerInstance()?