6-mils
Version:
A JS library for sending, receiving, and parsing cXML messages.
280 lines (235 loc) • 10.1 kB
JavaScript
/* eslint-env mocha */
/**
* Code under test.
* @type {any}
*/
const T = require('./index.js')
const VALID_CXML = '<?xml version="1.0"?><!DOCTYPE cXML SYSTEM "http://xml.cxml.org/schemas/cXML/1.2.011/cXML.dtd"><cXML xml:lang="en-US" payloadID="successful.order@test.com" timestamp="2019-03-12T18:39:09-08:00"><Response><Status code="400" text="Failure">XML document contained a doctype but failed validation.</Status></Response></cXML>'
describe('the "InboundCxmlMessage" module', function () {
it('must export a constructor', function () {
const expected = 'function'
const actual = typeof T
expect(actual).to.equal(expected)
})
describe('the exported constructor', function () {
const ERR_INVALID_INPUT = 'The constructor requires a value that must be a valid cXML string, or the special value %%EMPTY%%.'
it('must create unique instances', function () {
const a = new T('%%EMPTY%%')
const b = new T('%%EMPTY%%')
expect(a).to.not.equal(b)
})
describe('each instance', function () {
let instance = null
it('must have the expected properties', function () {
const expected = [
'payloadId',
'timestamp',
'version',
'statusCode',
'statusText'
]
instance = new T('%%EMPTY%%')
expected.forEach((name) => {
expect(instance).to.have.property(name)
})
})
context('when constructed with no value', function () {
it('must throw', function () {
expect(() => {
instance = new T()
}).to.throw(ERR_INVALID_INPUT)
})
})
context('when constructed with `null`', function () {
it('must throw', function () {
expect(() => {
instance = new T(null)
}).to.throw(ERR_INVALID_INPUT)
})
})
context('when constructed with an empty string', function () {
it('must throw', function () {
expect(() => {
instance = new T('')
}).to.throw(ERR_INVALID_INPUT)
})
})
context('when constructed with a value that is not a string', function () {
it('must throw', function () {
expect(() => {
instance = new T(new Date())
}).to.throw(ERR_INVALID_INPUT)
})
})
context('when constructed with a string value that is not valid XML', function () {
it('must throw', function () {
expect(() => {
instance = new T('not valid <xml>??')
}).to.throw(ERR_INVALID_INPUT)
})
})
context('when constructed with the special value "%%EMPTY%%"', function () {
beforeEach(function () {
instance = new T('%%EMPTY%%')
})
describe('the "payloadId" property', function () {
it('must have the correct value', function () {
const expected = /\d+\.\d+\.\w+@6-mils$/
const actual = instance.payloadId
expect(actual).to.match(expected)
})
})
describe('the "timestamp" property', function () {
it('must have the correct value', function () {
const now = new Date()
const then = new Date(instance.timestamp)
expect(now.getTime() - then.getTime()).to.be.lessThan(5)
})
it('must be in ISO8601 format', function () {
const format = /^20\d{2}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{3})?(Z|[+-]\d{1,2}:\d{2})$/
expect(instance.timestamp).to.match(format)
})
})
describe('the "version" property', function () {
it('must have the correct value', function () {
const expected = '1.2.045'
const actual = instance.version
expect(actual).to.equal(expected)
})
})
describe('the "statusCode" property', function () {
it('must have the correct value', function () {
const expected = '200'
const actual = instance.statusCode
expect(actual).to.equal(expected)
})
})
describe('the "statusText" property', function () {
it('must have the correct value', function () {
const expected = 'success'
const actual = instance.statusText
expect(actual).to.equal(expected)
})
})
describe('the "toString" method', function () {
it('must return a blank string', function () {
const expected = ''
const actual = instance.toString()
expect(actual).to.equal(expected)
})
it('must return a blank string when formatted', function () {
const expected = ''
const actual = instance.toString({ format: true })
expect(actual).to.equal(expected)
})
})
})
context('when constructed with a value that is valid cXML', function () {
beforeEach(function () {
instance = new T(VALID_CXML)
})
describe('the "payloadId" property', function () {
it('must have the correct value', function () {
const expected = 'successful.order@test.com'
const actual = instance.payloadId
expect(actual).to.equal(expected)
})
})
describe('the "timestamp" property', function () {
it('must have the correct value', function () {
const expected = '2019-03-12T18:39:09-08:00'
const actual = instance.timestamp
expect(actual).to.equal(expected)
})
})
describe('the "version" property', function () {
it('must have the correct value', function () {
const expected = '1.2.011'
const actual = instance.version
expect(actual).to.equal(expected)
})
})
describe('the "statusCode" property', function () {
it('must have the correct value', function () {
const expected = '400'
const actual = instance.statusCode
expect(actual).to.equal(expected)
})
})
describe('the "statusText" property', function () {
it('must have the correct value', function () {
const expected = 'XML document contained a doctype but failed validation.'
const actual = instance.statusText
expect(actual).to.equal(expected)
})
it('must have the correct value (if the response does not contain a status description)', function () {
const modifiedCxml = VALID_CXML.replace('XML document contained a doctype but failed validation.', '')
const t = new T(modifiedCxml)
const expected = 'Failure'
const actual = t.statusText
expect(actual).to.equal(expected)
})
})
})
it('must not have a method called "parse"', function () {
expect(instance).to.not.have.property('parse')
})
it('must have a method called "query"', function () {
expect(instance).to.have.property('query')
})
describe('the "query" method', function () {
const ERR_INVALID_INPUT = 'The parameter value for "query" is required and must be a string containing a valid XPath expression.'
beforeEach(function () {
instance = new T(VALID_CXML)
})
context('with no parameter value', function () {
it('must throw', function () {
expect(() => {
instance.query()
}).to.throw(ERR_INVALID_INPUT)
})
})
context('with a parameter value that is an empty string', function () {
it('must throw', function () {
expect(() => {
instance.query('')
}).to.throw(ERR_INVALID_INPUT)
})
})
context('with a parameter value that is not a string', function () {
it('must throw', function () {
expect(() => {
instance.query(new Date())
}).to.throw(ERR_INVALID_INPUT)
})
})
context('with a parameter value that is not a valid XPath expression', function () {
it('must throw', function () {
expect(() => {
instance.query('\not\valid:xpath[[1]]*')
}).to.throw(ERR_INVALID_INPUT)
})
})
context('with a parameter value that is a valid XPath expression', function () {
it('must return the correct value', function () {
const expected = 'en-US'
const actual = instance.query('/cXML/@xml:lang/data()')
expect(actual).to.equal(expected)
})
it('must return the expected value if the query resolves to more than one node', function () {
const t = new T('<?xml version="1.0"?><!DOCTYPE cXML SYSTEM "http://xml.cxml.org/schemas/cXML/1.2.011/cXML.dtd"><cXML xml:lang="en-US" payloadID="unsuccessful.order@test.com" timestamp="2019-03-12T18:39:09-08:00"><FakeResponse><Status code="400" text="Failure"></Status><Status code="401" text="Failure"></Status></FakeResponse></cXML>')
const expected = '400 401'
const actual = t.query('//cXML/FakeResponse/Status/@code')
expect(actual).to.equal(expected)
})
it('must return the expected value if the query does not resolve', function () {
const t = new T('<?xml version="1.0"?><!DOCTYPE cXML SYSTEM "http://xml.cxml.org/schemas/cXML/1.2.011/cXML.dtd"><cXML xml:lang="en-US" payloadID="unsuccessful.order@test.com" timestamp="2019-03-12T18:39:09-08:00"><FakeResponse><Status code="400" text="Failure"></Status><Status code="401" text="Failure"></Status></FakeResponse></cXML>')
const expected = ''
const actual = t.query('//cXML/FakeResponse/DoesNotExist')
expect(actual).to.equal(expected)
})
})
})
})
})
})