I'm working on a node
app that communicates with soap services, using the foam
module to parse json into a valid soap request and back again when the response is received. This all works fine when communicating with the soap services.
The issue I'm having is writing unit tests for this (integration tests work fine). I'm using nock
to mock the http service and send a reply. This reply does get parsed by foam
and then I can make assertions against the response.
So I cannot pass a json object as a reply because foam
expects a soap response. If I try to do this I get the error:
Error: Start tag expected, '<' not found
Storing XML in javascript variables is painful and doesn't work (i.e. wrapping it in quotes and escaping inner quotes isn't valid), so I wanted to put the mocked XML response into a file and pass that as a reply.
I've tried reading the file in as a stream
return fs.createReadStream('response.xml')
...and replying with a file
.replyWithFile(201, __dirname + 'response.xml');
Both fail with an error of
TypeError: Cannot read property 'ObjectReference' of undefined
Here is the XML in the file
<env:Envelope xmlns:env='http://schemas.xmlsoap.org/soap/envelope/'>
<env:Header></env:Header>
<env:Body>
<FLNewIndividualID xmlns='http://www.lagan.com/wsdl/FLTypes'>
<ObjectType>1</ObjectType>
<ObjectReference>12345678</ObjectReference>
<ObjectReference xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xsi:nil='true'/>
<ObjectReference xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xsi:nil='true'/>
</FLNewIndividualID>
</env:Body>
</env:Envelope>
The module being tested is
var foam = require('./foam-promise.js');
module.exports = {
createUserRequest: function(url, operation, action, message, namespace) {
var actionOp = action + '/actionRequestOp',
uri = url + '/actionRequest';
return new Promise(function(resolve, reject) {
foam.soapRequest(uri, operation, actionOp, message, namespace)
.then(function(response) {
resolve(response.FLNewIndividualID.ObjectReference[0]);
})
.catch(function(err) {
reject(err);
});
});
}
};
The assertion is using should-promised
return myRequest(url, operation, action, data, namespace)
.should.finally.be.exactly('12345678');
So it looks like the xml parser won't just accept a file (which makes sense). Does the stream not complete before it is tested?
Can an XML reply be mocked successfully with nock?
I also raised this on Github
Following pgte's advice here https://github.com/pgte/nock/issues/326 I was able to get this working by setting the correct headers, replying with an xml string (with escaped quotes).
From pgte:
It can. I don't know foam well, but I guess you have to set the response content type header (see https://github.com/pgte/nock#specifying-reply-headers ) so that the client can parse the XML correctly.
Here's how the working test looks:
it('should return a user ID', function(){
var response = '<env:Envelope xmlns:env=\'http://schemas.xmlsoap.org/soap/envelope/\'><env:Header></env:Header><env:Body><UserReference>12345678</UserReference></env:Body></env:Envelope>'
nock(url)
.post('/createUserRequest')
.reply(201, response, {
'Content-Type': 'application/xml'
}
);
return createUserRequest(url, operation, action, message, options)
.should.be.fulfilledWith('12345678');
});
it('should be rejected if the request fails', function() {
nock(url)
.post('/createCaseRequest')
.replyWithError('The request failed');
return createUserRequest(url, operation, action, message, options)
.should.be.rejected;
});