UNPKG

6-mils

Version:

A JS library for sending, receiving, and parsing cXML messages.

280 lines (235 loc) 10.1 kB
/* 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) }) }) }) }) }) })