jaydenseric / graphql-upload

Middleware and a scalar Upload to add support for GraphQL multipart requests (file uploads via queries and mutations) to various Node.js GraphQL servers.
https://npm.im/graphql-upload
MIT License
1.43k stars 132 forks source link

How to test file upload using supertest, apollo-server-express and Jest, #279

Closed SamuelNoB closed 2 years ago

SamuelNoB commented 2 years ago

Hi, I was trying to create a jest test with supertest that uploads a file to the client. i've already found issue #125 that faced the similar problem, and I already tried jaydenseric and awilderink answers, but none of them worked. Bellow is my code right now

const graphql = async (query, variables= {}, options) => {

  const map = { "1": ["variables.input.File"]}
  const file = variables.input.File
  const operations = JSON.stringify({ query, variables })
  //global.request  = supertest(app)
  const req = global.request.post('/graphql')
    .field("Content-Type", "multipart/form-data")
    .field('operations', operations)
    .field('map', JSON.stringify(map))
    .attach('1', file)
    .set('Cookie', options.cookie);

  return req;
};
it('should test creation of file by a User that is a Workspace admin', async () => {
 const response = await graphql(
      `
        mutation ($permission: IsAllowed, $input: AddFileInput) {
            addFile(permission: $permission, input: $input)
            {
                ID
                FileName
                URL
            }
        }
        `,
      {
        permission: {
          JobCode: aJob.ID,
          WorkspaceCode: aUser.workspaceID
        },
        input: {
          FileName: 'foo bar baz',
          Description: 'foo bar',
          File: path.resolve(__dirname, './utils/fileToUpload.txt'),
          RelatedObject: {
            ObjectCode: aJob.ID,
            ObjectType: "JOB"
          }
        }
      }, {
        cookie: aUser.auth
      }
    );
}

As you can see, my input.File is the file that represents my Upload field.

Unfortunatelly when I run the test an error is shown.

Error: Aborted

    at Test.<anonymous> (C:\Users\samue\Área de Trabalho\TRABALHO\SmartKanvas\node_modules\superagent\src\request-base.js:304:21)
    at Test.emit (events.js:400:28)
    at Test.abort (C:\Users\samue\Área de Trabalho\TRABALHO\SmartKanvas\node_modules\superagent\src\request-base.js:510:8)
    at FormData.<anonymous> (C:\Users\samue\Área de Trabalho\TRABALHO\SmartKanvas\node_modules\superagent\src\node\index.js:281:12)
    at FormData.emit (events.js:412:35)
    at FormData.Object.<anonymous>.CombinedStream._emitError (C:\Users\samue\Área de Trabalho\TRABALHO\SmartKanvas\node_modules\combined-stream\lib\combined_stream.js:207:8)
    at DelayedStream.<anonymous> (C:\Users\samue\Área de Trabalho\TRABALHO\SmartKanvas\node_modules\combined-stream\lib\combined_stream.js:133:10)
    at DelayedStream.emit (events.js:412:35)
    at DelayedStream.<anonymous> (C:\Users\samue\Área de Trabalho\TRABALHO\SmartKanvas\node_modules\delayed-stream\lib\delayed_stream.js:69:15)
    at Array.forEach (<anonymous>)

How can I implement that test correctly?

jaydenseric commented 2 years ago

Without looking in detail at the code you are sharing, generally when there are errors about an abort or disconnect it can be because you are not correctly promisifying and awaiting the individual file uploads in your GraphQL API resolvers. As per the Tips section of the readme:

Promisify and await file upload streams in resolvers or the server will send a response to the client before uploads are complete, causing a disconnect. — https://github.com/jaydenseric/graphql-upload#tips

Here is an example of promisifying the upload's read stream:

https://github.com/jaydenseric/apollo-upload-examples/blob/e1131d21b54d66391da342fb81981e805b857c8a/api/storeUpload.mjs#L10-L42

SamuelNoB commented 2 years ago

Without looking in detail at the code you are sharing, generally when there are errors about an abort or disconnect it can be because you are not correctly promisifying and awaiting the individual file uploads in your GraphQL API resolvers. As per the Tips section of the readme:

Promisify and await file upload streams in resolvers or the server will send a response to the client before uploads are complete, causing a disconnect. — https://github.com/jaydenseric/graphql-upload#tips

Here is an example of promisifying the upload's read stream:

https://github.com/jaydenseric/apollo-upload-examples/blob/e1131d21b54d66391da342fb81981e805b857c8a/api/storeUpload.mjs#L10-L42

thanks for the answer but that's not the cause of the error. when I run the test in debug mode, I can se that my addFile resolver doesn't even get called because none of the breakpoints are activated.

jaydenseric commented 2 years ago

Closing because this issue is more of a request for help debugging project code than a graphql-upload bug report or feature request, which are the only kinds of issues we keep open.

You absolutely can test file uploads (I do so in all sorts of projects), so keep at it and you'll get it going with your chosen tools eventually. I suggest keeping away from bloated testing frameworks like jest and supertest and write as close to standard JavaScript code as you can, using standard fetch, FormData and File/Blob APIs. The code will be a lot less mysterious and maintainable, and you will understand better how the systems being tested actually work in production.

Good luck!

garrettg123 commented 1 year ago

This repo seems to have a lot of answers that can be boiled down to "if you keep trying, you can figure it out," leading to the issue getting closed. This shouldn't be closed — there's no easy way to test this library when using apollo-server-express. A working example piece of code would be great.