I am stuck in one of my tests. In my test, I need to detect that Client (browser) has cancelled or aborted image upload. My problem is how to simulate when the connection is aborted. In my controller, I have, so to speak simulated a connection loss, and my code reacts properly. But as I mentioned issue remains how to trigger that from the tests. I use Mocha 3.2.0 as a test Suite, and on the controller side I use multiparty.
This is the original code:
return new Promise((resolve, reject) => {
let form = new multiparty.Form();
let fileCount = 0;
form.on('part', function (part) {
fileCount++;
let tmpFile = path.join(os.tmpDir(), `${userId}_${timePrefix}_${path.basename(part.filename)}`);
part.pipe(fs.createWriteStream(tmpFile));
part.on('end', () => {
resolve(fs.createReadStream(tmpFile));
});
part.on('error', function (error) {
reject(error);
});
});
form.on('error', (error) => {
reject(new LogicalError(
`Image input request is not valid`, errorCodes.VALIDATION.IMAGE_UPLOAD_DATA_INVALID);
});
form.parse(request);
}).then((imageStream) => {
//AWS S3 is hendled here...
Now I have added a new case, where I trigger that the client connection was cancelled. I have used Throttle. Throttle simulates slow upload, and in the timeout I trigger connection loss.
return new Promise((resolve, reject) => {
let form = new multiparty.Form();
let fileCount = 0;
let throttle = new Throttle(1); //1 = 1 byte. 1000 = 1kb... all per second
form.on('part', function (part) {
fileCount++;
let tmpFile = path.join(os.tmpDir(), `${userId}_${timePrefix}_${path.basename(part.filename)}`);
//part.pipe(fs.createWriteStream(tmpFile));
//Slows down the upload
part.pipe(throttle).pipe(fs.createWriteStream(tmpFile));
//trigger connection aborted
setTimeout(function () {
request.emit('aborted');
},10);
part.on('end', () => {
resolve(fs.createReadStream(tmpFile));
});
part.on('error', function (error) {
reject(error);
});
});
form.on('error', (error) => {
let err = null;
if (error.message.includes('Request aborted')){
err = new LogicalError(
`Client aborted image upload process`, errorCodes.VALIDATION.IMAGE_UPLOAD_CLIENT_REQUEST_ABORTED);
} else {
err = new LogicalError(
`Image input request is not valid`, errorCodes.VALIDATION.IMAGE_UPLOAD_DATA_INVALID);
}
reject(err);
});
form.parse(request);
}).then((imageStream) => {
//AWS S3 is hendled here...
This simulation works as expected. Code recognises proper condition (Request aborted). I can't leave this throttle and setTimeout, of course. How can I trigger it from the test?
This is the current test, that is uploading image, and targets the Controller. Using supertest:
describe('ImageControllerTest', function () {
it('should upload image with name for the given user', (done) => {
request(app)
.put('path-to-controller/test-image.jpg')
.attach('file', imagePath.testImagePath)
.set(cons.TOKEN.HEADERS)
.expect((res) => {
//series of expect statements.
})
.expect(200, done);
});
});
In my second attempt (code is above), I have simulated Connection Abort by doing this:
setTimeout(function () {
request.emit('aborted');
},10);
Multiparty listens to that event, and react accordingly.
How can I do it from the test?
The easy way can be - create client in subprocess using:
const fork = require('child_process').fork;
const path = require('path');
const child = fork(path.join(__dirname, './some-sub.js'));
And when you need to trigger cancel - just close the process:
child.close();
Or from the process itself:
process.exit(0);