Как протестировать загрузку изображения (поток) с помощью супертеста и шутки?

В моем API есть конечная точка загрузки изображений, которая принимает application/octet-stream запросов и обрабатывает эти потоки. Я хотел бы написать тестовое покрытие для этой конечной точки, но не могу понять, как использовать супертест для потоковой передачи изображения.

Вот мой код:

import request from 'supertest'

const testImage = `${__dirname}/../../../assets/test_image.jpg`

describe('Upload endpoint', () => {

  test('Successfully uploads jpg image', async () =>
    request(app)
      .post(`${ROOT_URL}${endpoints.add_image.route}`)
      .set('Authorization', `Bearer ${process.env.testUserJWT}`)
      .set('content-type', 'application/octet-stream')
      .pipe(fs.createReadStream(testImage))
      .on('finish', (something) => {
        console.log(something)
      }))

})

Этот код ничего не производит, событие finish никогда не вызывается, ничего не регистрируется в консоли, и этот набор тестов фактически проходит, так как ничего не ожидается. Я не могу связать .expect с этим запросом, иначе я получаю эту ошибку времени выполнения:

TypeError: (0 , _supertest2.default)(...).post(...).set(...).set(...).pipe(...).expect не является функцией

Как это делается?


person j_d    schedule 27.03.2018    source источник
comment
Чтобы передать данные запросу, вы должны сообщить читаемому потоку передать запрос. например imageStream.pipe(req).   -  person popthestack    schedule 05.04.2018
comment
async/await работает только с промисами, а не с потоками. Вам нужно будет изменить тестовую функцию, чтобы использовать (done) и вызывать done() в событии канала finish/close.   -  person popthestack    schedule 05.04.2018
comment
@popthestack Если вы напишете полный рабочий ответ, я буду рад дать вам награду.   -  person j_d    schedule 06.04.2018
comment
@IsaacHinman, что здесь за объект запроса? Если возможно, предоставьте минимальный репозиторий git, и вы скоро получите исправление.   -  person Tarun Lalwani    schedule 06.04.2018
comment
@TarunLalwani Извините за это, request - это библиотека supertest, как указано в заголовке вопроса.   -  person j_d    schedule 06.04.2018
comment
Можете ли вы предоставить метод загрузки, чтобы я мог протестировать его и убедиться, что он работает нормально?   -  person Tarun Lalwani    schedule 06.04.2018
comment
@IsaacHinman, опубликовал ответ, посмотрим, поможет ли   -  person Tarun Lalwani    schedule 07.04.2018


Ответы (4)


Это должно работать. Чтобы передать данные запросу, вы должны сообщить читаемому потоку передать запрос. Другой способ — получение данных с сервера. Здесь также используется done вместо async, поскольку каналы не работают с async/await.

Также ничего не стоит то, что по умолчанию канал вызовет end, а затем суперагент вызовет end, что приведет к ошибке о двойном вызове end. Чтобы решить эту проблему, вы должны указать вызову канала не делать этого, а затем вызвать end в событии on end потока.

import request from 'supertest'

const testImage = `${__dirname}/../../../assets/test_image.jpg`

describe('Upload endpoint', () => {

  test('Successfully uploads jpg image', (done) => {
      const req = request(app)
          .post(`${ROOT_URL}${endpoints.add_image.route}`)
          .set('Authorization', `Bearer ${process.env.testUserJWT}`)
          .set('content-type', 'application/octet-stream')

      const imgStream = fs.createReadStream(testImage);
      imgStream.on('end', () => req.end(done));
      imgStream.pipe(req, {end: false})
  })
})

Отредактировано для добавления: у меня это сработало с небольшими файлами. Если я попытаюсь протестировать его с помощью большого файла test_image.jpg, время запроса истечет.

person popthestack    schedule 06.04.2018

Мне пришлось сделать предположения о том, что ваш метод загрузки принимает в качестве входных данных тело, а не составные данные формы. Итак, ниже приведен пример, когда необработанное тело передается для загрузки.

const request = require('supertest');
const express = require('express');
const fs = require('fs')
const app = express();
var bodyParser = require('body-parser')
app.use(bodyParser.raw({type: 'application/octet-stream'}))

app.post('/user', function(req, res) {
    res.status(200).json({ name: 'tobi' });
});

testImage = './package.json'

resp = request(app)
    .post('/user')

    resp.set('Authorization', `Bearer Test`).set('Content-Type', 'application/octet-stream')

    resp.send(fs.readFileSync(testImage, 'utf-8'))
    resp.expect(200)
    .then(response => {
        console.log("response",response);
    }).catch((err) => {
        console.log(err)
    })

Если вы используете multipart/form-data, то ниже приведен пример кода

const request = require('supertest');
const express = require('express');
const fs = require('fs')
const app = express();

app.post('/user', function(req, res) {
    // capture the encoded form data
    req.on('data', (data) => {
        console.log(data.toString());
    });

    // send a response when finished reading
    // the encoded form data
    req.on('end', () => {
        res.status(200).json({ name: 'tobi' });
    });

});

testImage = './package.json'

resp = request(app)
    .post('/user')

    resp.set('Authorization', `Bearer Test`)
    resp.attach("file", testImage)
    resp.expect(200)
    .then(response => {
        console.log("response",response);
    }).catch((err) => {
        console.log(err)
    })
person Tarun Lalwani    schedule 07.04.2018

Я думаю, вы на самом деле хотите использовать fs.createReadStream(testImage) для чтения этого изображения в своем запросе, поскольку fs.createWriteStream(testImage) будет записывать данные в предоставленный файловый дескриптор (в данном случае testImage). Не стесняйтесь проверить Node Streams, чтобы узнать, как они работают более подробно.

Я не совсем уверен, откуда вы получаете событие finish для supertest, но вы можете увидеть, как использовать метод .pipe() здесь.

Вы также можете рассмотреть возможность использования supertest составных вложений, если это лучше подходит для вашего теста. .

person mootrichard    schedule 02.04.2018
comment
Извините, это была просто опечатка с моей стороны. Конечно, мы читаем в поток. - person j_d; 03.04.2018

person    schedule
comment
Я не думаю, что вы должны использовать expect и then вместе. В любом случае, при запуске вашего кода (который очень похож на то, что я уже пробовал), я получаю сообщение об ошибке, что тип содержимого заголовка not application/octet-stream. Кажется, метод attach перезаписывает заголовки. - person j_d; 06.04.2018
comment
да, я забыл удалить тип контента. я обновил ответ - person Sajad Khoshnoudi; 06.04.2018
comment
@IsaacHinman, я думаю, это должно сработать, не могли бы вы проверить и обновить? - person Tarun Lalwani; 06.04.2018