如何使用 supertest 和 jest 测试图像上传(流)?
How to test image upload (stream) with supertest and jest?
我的 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 is not a function
这样的事情是怎么做到的?
我认为您实际上想使用 fs.createReadStream(testImage)
将该图像读入您的请求,因为 fs.createWriteStream(testImage)
会将数据写入提供的文件描述符(在本例中为 testImage
) . Feel free to checkout Node Streams to see how they work in more detail.
我不太确定您从哪里获得 supertest
的 finish
事件,但您可以了解如何使用 .pipe()
方法 here .
如果更适合您的测试,您可能还想考虑使用 supertest
multipart attachments。
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}`)
.attach("name",testImage,{ contentType: 'application/octet-stream' })
.expect(200)
.then(response => {
console.log("response",response);
})
);
});
这应该有效。要将数据通过管道传输到请求,您必须告诉可读流通过管道传输到请求。另一种方式是从服务器接收数据。这也使用 done
而不是 async
因为管道不适用于 async/await.
同样一无是处的是,默认情况下管道会调用end
,然后superagent会调用end
,导致有关end
被调用两次的错误。要解决这个问题,您必须告诉管道调用不要这样做,然后在流的 on end 事件中调用 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 测试它,请求超时。
我不得不假设您的上传方法将正文作为输入而不是多部分 form-data。因此,下面是一个示例,其中传递原始正文以进行上传
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)
})
我的 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 is not a function
这样的事情是怎么做到的?
我认为您实际上想使用 fs.createReadStream(testImage)
将该图像读入您的请求,因为 fs.createWriteStream(testImage)
会将数据写入提供的文件描述符(在本例中为 testImage
) . Feel free to checkout Node Streams to see how they work in more detail.
我不太确定您从哪里获得 supertest
的 finish
事件,但您可以了解如何使用 .pipe()
方法 here .
如果更适合您的测试,您可能还想考虑使用 supertest
multipart attachments。
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}`)
.attach("name",testImage,{ contentType: 'application/octet-stream' })
.expect(200)
.then(response => {
console.log("response",response);
})
);
});
这应该有效。要将数据通过管道传输到请求,您必须告诉可读流通过管道传输到请求。另一种方式是从服务器接收数据。这也使用 done
而不是 async
因为管道不适用于 async/await.
同样一无是处的是,默认情况下管道会调用end
,然后superagent会调用end
,导致有关end
被调用两次的错误。要解决这个问题,您必须告诉管道调用不要这样做,然后在流的 on end 事件中调用 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 测试它,请求超时。
我不得不假设您的上传方法将正文作为输入而不是多部分 form-data。因此,下面是一个示例,其中传递原始正文以进行上传
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)
})