UNPKG

@luminati-io/mountebank

Version:

Over the wire test doubles

96 lines (84 loc) 2.65 kB
'use strict'; const xpath = require('xpath'), xmlDom = require('@xmldom/xmldom'), errors = require('../util/errors.js'), helpers = require('../util/helpers.js'); /** * Shared logic for xpath selector * @module */ function xpathSelect (selectFn, selector, doc) { if (!helpers.defined(doc)) { return []; } if (doc && doc.implementation) { // Monkey patch due to some legacy case sensitivity check in xpath // Couldn't find a way to patch xpath due to closures so patched the dom instead const originalHasFeature = doc.implementation.hasFeature; doc.implementation.hasFeature = (feature, version) => { if (feature === 'HTML' && version === '2.0') { return false; } else { return originalHasFeature.apply(doc.implementation, [feature, version]); } }; } try { return selectFn(selector, doc); } catch (e) { throw errors.ValidationError('malformed xpath predicate selector', { source: selector, inner: e }); } } function nodeValue (node) { if (node.nodeType === node.TEXT_NODE) { return node.nodeValue; } else if (node.nodeType === node.ATTRIBUTE_NODE) { return node.value; } else if (node.firstChild) { // Converting to a string allows exists to return true if the node exists, // even if there's no data return String(node.firstChild.data); } else { return String(node.data); } } /** * Returns xpath value(s) from given xml * @param {String} selector - The xpath selector * @param {Object} ns - The namespace map * @param {String} possibleXML - the xml * @param {Object} logger - Optional, used to log XML parsing errors * @returns {Object} */ function select (selector, ns, possibleXML, logger) { const DOMParser = xmlDom.DOMParser, parser = new DOMParser({ errorHandler: (level, message) => { const warn = (logger || {}).warn || (() => {}); warn('%s (source: %s)', message, JSON.stringify(possibleXML)); } }), doc = parser.parseFromString(possibleXML), selectFn = xpath.useNamespaces(ns || {}), result = xpathSelect(selectFn, selector, doc); let nodeValues; if (['number', 'boolean'].indexOf(typeof result) >= 0) { return result; } nodeValues = result.map(nodeValue); if (nodeValues.length === 0) { return undefined; } else { return nodeValues; } } module.exports = { select };