diff --git a/modules/videoModule/index.js b/modules/videoModule/index.js
index 2f618bc4733..bd249a1586d 100644
--- a/modules/videoModule/index.js
+++ b/modules/videoModule/index.js
@@ -4,10 +4,12 @@ import { allVideoEvents } from './constants/events.js';
import CONSTANTS from '../../src/constants.json';
import { videoCoreFactory } from './coreVideo.js';
import { coreAdServerFactory } from './adServer.js';
+import find from 'core-js-pure/features/array/find.js';
+import { vastXmlEditorFactory } from './shared/vastXmlEditor.js';
events.addEvents(allVideoEvents);
-export function PbVideo(videoCore_, getConfig_, pbGlobal_, pbEvents_, videoEvents_, adServerCore_) {
+export function PbVideo(videoCore_, getConfig_, pbGlobal_, pbEvents_, videoEvents_, adServerCore_, vastXmlEditor_) {
const videoCore = videoCore_;
const getConfig = getConfig_;
const pbGlobal = pbGlobal_;
@@ -15,6 +17,7 @@ export function PbVideo(videoCore_, getConfig_, pbGlobal_, pbEvents_, videoEvent
const pbEvents = pbEvents_;
const videoEvents = videoEvents_;
const adServerCore = adServerCore_;
+ const vastXmlEditor = vastXmlEditor_;
function init() {
getConfig('video', ({ video }) => {
@@ -42,6 +45,20 @@ export function PbVideo(videoCore_, getConfig_, pbGlobal_, pbEvents_, videoEvent
}
});
});
+
+ const cache = getConfig('cache');
+ if (!cache) {
+ return;
+ }
+
+ pbEvents.on(CONSTANTS.EVENTS.BID_ADJUSTMENT, function (bid) {
+ const adUnitCode = bid.adUnitCode;
+ const adUnit = find(pbGlobal.adUnits, adUnit => adUnitCode === adUnit.code);
+ const videoConfig = adUnit && adUnit.video;
+ const adServerConfig = videoConfig && videoConfig.adServer;
+ const trackingConfig = adServerConfig && adServerConfig.tracking;
+ addTrackingNodesToVastXml(bid, trackingConfig);
+ });
}
return { init };
@@ -81,12 +98,44 @@ export function PbVideo(videoCore_, getConfig_, pbGlobal_, pbEvents_, videoEvent
options.adXml = highestBid.vastXml;
videoCore.setAdTagUrl(adTagUrl, divId, options);
}
+
+ function addTrackingNodesToVastXml(bid, trackingConfig) {
+ if (!trackingConfig) {
+ return;
+ }
+
+ let { vastXml, vastUrl, adId } = bid;
+ let impressionUrl;
+ let impressionId;
+ let errorUrl;
+
+ const impressionTracking = trackingConfig.impression;
+ const errorTracking = trackingConfig.error;
+
+ if (impressionTracking) {
+ impressionUrl = impressionTracking.url;
+ impressionId = impressionTracking.id || adId + '-impression';
+ }
+
+ if (errorTracking) {
+ errorUrl = errorTracking.url;
+ }
+
+ if (vastXml) {
+ vastXml = vastXmlEditor.getVastXmlWithTrackingNodes(vastXml, impressionUrl, impressionId, errorUrl);
+ } else if (vastUrl) {
+ vastXml = vastXmlEditor.buildVastWrapper(adId, vastUrl, impressionUrl, impressionId, errorUrl);
+ }
+
+ bid.vastXml = vastXml;
+ }
}
export function pbVideoFactory() {
const videoCore = videoCoreFactory();
const adServerCore = coreAdServerFactory();
- const pbVideo = PbVideo(videoCore, config.getConfig, $$PREBID_GLOBAL$$, events, allVideoEvents, adServerCore);
+ const vastXmlEditor = vastXmlEditorFactory();
+ const pbVideo = PbVideo(videoCore, config.getConfig, $$PREBID_GLOBAL$$, events, allVideoEvents, adServerCore, vastXmlEditor);
pbVideo.init();
return pbVideo;
}
diff --git a/modules/videoModule/shared/vastXmlBuilder.js b/modules/videoModule/shared/vastXmlBuilder.js
new file mode 100644
index 00000000000..8f029c2c678
--- /dev/null
+++ b/modules/videoModule/shared/vastXmlBuilder.js
@@ -0,0 +1,76 @@
+
+export function buildVastWrapper(adId, adTagUrl, impressionUrl, impressionId, errorUrl) {
+ let wrapperBody = getAdSystemNode('Prebid org', $$PREBID_GLOBAL$$.version);
+
+ if (adTagUrl) {
+ wrapperBody += getAdTagUriNode(adTagUrl);
+ }
+
+ if (impressionUrl) {
+ wrapperBody += getImpressionNode(impressionUrl, impressionId);
+ }
+
+ if (errorUrl) {
+ wrapperBody += getErrorNode(errorUrl);
+ }
+
+ return getVastNode(getAdNode(getWrapperNode(wrapperBody), adId), '4.2');
+}
+
+export function getVastNode(body, vastVersion) {
+ return getNode('VAST', body, { version: vastVersion });
+}
+
+export function getAdNode(body, adId) {
+ return getNode('Ad', body, { id: adId });
+}
+
+export function getWrapperNode(body) {
+ return getNode('Wrapper', body);
+}
+
+export function getAdSystemNode(system, version) {
+ return getNode('AdSystem', system, { version });
+}
+
+export function getAdTagUriNode(adTagUrl) {
+ return getUrlNode('VASTAdTagURI', adTagUrl);
+}
+
+export function getImpressionNode(pingUrl, id) {
+ return getUrlNode('Impression', pingUrl, { id });
+}
+
+export function getErrorNode(pingUrl) {
+ return getUrlNode('Error', pingUrl);
+}
+
+// Helpers
+
+function getUrlNode(labelName, url, attributes) {
+ const body = ``;
+ return getNode(labelName, body, attributes);
+}
+
+function getNode(labelName, body, attributes) {
+ const openingLabel = getOpeningLabel(labelName, attributes);
+ return `<${openingLabel}>${body}${labelName}>`;
+}
+
+/*
+attributes is a KVP Object.
+ */
+function getOpeningLabel(name, attributes) {
+ if (!attributes) {
+ return name;
+ }
+
+ return Object.keys(attributes).reduce((label, key) => {
+ const value = attributes[key];
+ if (!value) {
+ return label;
+ }
+
+ return label + ` ${key}="${value}"`;
+ }, name);
+}
diff --git a/modules/videoModule/shared/vastXmlEditor.js b/modules/videoModule/shared/vastXmlEditor.js
new file mode 100644
index 00000000000..c5cb113c299
--- /dev/null
+++ b/modules/videoModule/shared/vastXmlEditor.js
@@ -0,0 +1,98 @@
+import { getErrorNode, getImpressionNode, buildVastWrapper } from './vastXmlBuilder.js';
+
+export const XML_MIME_TYPE = 'application/xml';
+
+export function VastXmlEditor(xmlUtil_) {
+ const xmlUtil = xmlUtil_;
+
+ function getVastXmlWithTrackingNodes(vastXml, impressionUrl, impressionId, errorUrl) {
+ const impressionDoc = getImpressionDoc(impressionUrl, impressionId);
+ const errorDoc = getErrorDoc(errorUrl);
+ if (!impressionDoc && !errorDoc) {
+ return vastXml;
+ }
+
+ const vastXmlDoc = xmlUtil.parse(vastXml);
+ const nodes = vastXmlDoc.querySelectorAll('InLine,Wrapper');
+ const nodeCount = nodes.length;
+ for (let i = 0; i < nodeCount; i++) {
+ const node = nodes[i];
+ // A copy of the child is required until we reach the last node.
+ const requiresCopy = i < nodeCount - 1;
+ appendChild(node, impressionDoc, requiresCopy);
+ appendChild(node, errorDoc, requiresCopy);
+ }
+
+ return xmlUtil.serialize(vastXmlDoc);
+ }
+
+ return {
+ getVastXmlWithTrackingNodes,
+ buildVastWrapper
+ }
+
+ function getImpressionDoc(impressionUrl, impressionId) {
+ if (!impressionUrl) {
+ return;
+ }
+
+ const impressionNode = getImpressionNode(impressionUrl, impressionId);
+ return xmlUtil.parse(impressionNode);
+ }
+
+ function getErrorDoc(errorUrl) {
+ if (!errorUrl) {
+ return;
+ }
+
+ const errorNode = getErrorNode(errorUrl);
+ return xmlUtil.parse(errorNode);
+ }
+
+ function appendChild(node, child, copy) {
+ if (!child) {
+ return;
+ }
+
+ const doc = copy ? child.cloneNode(true) : child;
+ node.appendChild(doc.documentElement);
+ }
+}
+
+function XMLUtil() {
+ let parser;
+ let serializer;
+
+ function getParser() {
+ if (!parser) {
+ // DOMParser instantiation is costly; instantiate only once throughout Prebid lifecycle.
+ parser = new DOMParser();
+ }
+ return parser;
+ }
+
+ function getSerializer() {
+ if (!serializer) {
+ // XMLSerializer instantiation is costly; instantiate only once throughout Prebid lifecycle.
+ serializer = new XMLSerializer();
+ }
+ return serializer;
+ }
+
+ function parse(xmlString) {
+ return getParser().parseFromString(xmlString, XML_MIME_TYPE);
+ }
+
+ function serialize(xmlDoc) {
+ return getSerializer().serializeToString(xmlDoc);
+ }
+
+ return {
+ parse,
+ serialize
+ };
+}
+
+export function vastXmlEditorFactory() {
+ return VastXmlEditor(XMLUtil());
+}
diff --git a/test/spec/modules/videoModule/pbVideo_spec.js b/test/spec/modules/videoModule/pbVideo_spec.js
index ea0a54dc2eb..b46741312f0 100644
--- a/test/spec/modules/videoModule/pbVideo_spec.js
+++ b/test/spec/modules/videoModule/pbVideo_spec.js
@@ -1,5 +1,6 @@
import { expect } from 'chai';
import { PbVideo } from 'modules/videoModule/index.js';
+import CONSTANTS from 'src/constants.json';
let ortbParamsMock;
let videoCoreMock;
@@ -9,6 +10,7 @@ let pbGlobalMock;
let pbEventsMock;
let videoEventsMock;
let adServerMock;
+let vastXmlEditorMock;
function resetTestVars() {
ortbParamsMock = {
@@ -38,16 +40,21 @@ function resetTestVars() {
registerAdServer: sinon.spy(),
getAdTagUrl: sinon.spy()
};
+ vastXmlEditorMock = {
+ getVastXmlWithTrackingNodes: sinon.spy(),
+ buildVastWrapper: sinon.spy()
+ };
}
-let pbVideoFactory = (videoCore, getConfig, pbGlobal, pbEvents, videoEvents, adServer) => {
+let pbVideoFactory = (videoCore, getConfig, pbGlobal, pbEvents, videoEvents, adServer, vastXmlEditor) => {
const pbVideo = PbVideo(
videoCore || videoCoreMock,
getConfig || getConfigMock,
pbGlobal || pbGlobalMock,
pbEvents || pbEventsMock,
videoEvents || videoEventsMock,
- adServer || adServerMock
+ adServer || adServerMock,
+ vastXmlEditor || vastXmlEditorMock
);
pbVideo.init();
return pbVideo;
@@ -59,8 +66,10 @@ describe('Prebid Video', function () {
describe('Setting video to config', function () {
let providers = [{ divId: 'div1' }, { divId: 'div2' }];
let getConfigCallback;
- let getConfig = (video, callback) => {
- getConfigCallback = callback;
+ let getConfig = (propertyName, callback) => {
+ if (propertyName === 'video') {
+ getConfigCallback = callback;
+ }
};
beforeEach(() => {
@@ -213,4 +222,105 @@ describe('Prebid Video', function () {
expect(videoCoreMock.setAdTagUrl.args[0][2]).to.have.property('adXml', expectedVastXml);
});
});
+
+ describe('Ad tracking', function () {
+ let bidAdjustmentCb;
+ const adUnitCode = 'test_ad_unit_code';
+ const sampleBid = {
+ adId: 'test_ad_id',
+ adUnitCode,
+ vastUrl: 'test_ad_url'
+ };
+ const sampleAdUnit = {
+ code: adUnitCode,
+ };
+ const pbEvents = {
+ on: (event, callback) => {
+ if (event === CONSTANTS.EVENTS.BID_ADJUSTMENT) {
+ bidAdjustmentCb = callback;
+ }
+ },
+ emit: () => {}
+ };
+ const expectedImpressionUrl = 'test_impression_url';
+ const expectedImpressionId = 'test_impression_id';
+ const expectedErrorUrl = 'test_error_url';
+ const expectedVastXml = 'test_xml';
+
+ it('should not listen for bid adjustments when caching is not configured', function () {
+ pbVideoFactory(null, () => null);
+ expect(pbEventsMock.on.neverCalledWith(CONSTANTS.EVENTS.BID_ADJUSTMENT)).to.be.true;
+ });
+
+ it('should not modify the bid\'s adXml when the tracking config is omitted', function () {
+ const adUnit = Object.assign({}, sampleAdUnit, { video: { adServer: { tracking: null } } });
+ const pbGlobal = Object.assign({}, pbGlobalMock, { adUnits: [ adUnit ] });
+ pbVideoFactory(null, () => ({}), pbGlobal, pbEvents);
+
+ bidAdjustmentCb(sampleBid);
+ expect(vastXmlEditorMock.getVastXmlWithTrackingNodes.called).to.be.false;
+ expect(vastXmlEditorMock.buildVastWrapper.called).to.be.false;
+ });
+
+ it('should request a vast wrapper when only an ad url is provided', function () {
+ const adUnit = Object.assign({}, sampleAdUnit, { video: { adServer: { tracking: { } } } });
+ const pbGlobal = Object.assign({}, pbGlobalMock, { adUnits: [ adUnit ] });
+ pbVideoFactory(null, () => ({}), pbGlobal, pbEvents);
+
+ bidAdjustmentCb(sampleBid);
+ expect(vastXmlEditorMock.getVastXmlWithTrackingNodes.called).to.be.false;
+ expect(vastXmlEditorMock.buildVastWrapper.called).to.be.true;
+ });
+
+ it('should request the addition of tracking nodes when an ad xml is provided', function () {
+ const adUnit = Object.assign({}, sampleAdUnit, { video: { adServer: { tracking: { } } } });
+ const pbGlobal = Object.assign({}, pbGlobalMock, { adUnits: [ adUnit ] });
+ pbVideoFactory(null, () => ({}), pbGlobal, pbEvents);
+
+ const bid = Object.assign({}, sampleBid, { vastXml: 'test_xml' });
+ bidAdjustmentCb(bid);
+ expect(vastXmlEditorMock.getVastXmlWithTrackingNodes.called).to.be.true;
+ expect(vastXmlEditorMock.buildVastWrapper.called).to.be.false;
+ });
+
+ it('should pass the tracking information as args to the xml editing function', function () {
+ const adUnit = Object.assign({}, sampleAdUnit, { video: { adServer: { tracking: {
+ impression: {
+ url: expectedImpressionUrl,
+ id: expectedImpressionId
+ },
+ error: {
+ url: expectedErrorUrl
+ }
+ } } } });
+ const pbGlobal = Object.assign({}, pbGlobalMock, { adUnits: [ adUnit ] });
+ pbVideoFactory(null, () => ({}), pbGlobal, pbEvents);
+
+ const bid = Object.assign({}, sampleBid, { vastXml: expectedVastXml });
+ bidAdjustmentCb(bid);
+ expect(vastXmlEditorMock.getVastXmlWithTrackingNodes.called).to.be.true;
+ expect(vastXmlEditorMock.getVastXmlWithTrackingNodes.calledWith(expectedVastXml, expectedImpressionUrl, expectedImpressionId, expectedErrorUrl))
+ expect(vastXmlEditorMock.buildVastWrapper.called).to.be.false;
+ });
+
+ it('should generate the impression id when not specified in config', function () {
+ const adUnit = Object.assign({}, sampleAdUnit, { video: { adServer: { tracking: {
+ impression: {
+ url: expectedImpressionUrl,
+ },
+ error: {
+ url: expectedErrorUrl
+ }
+ } } } });
+ const pbGlobal = Object.assign({}, pbGlobalMock, { adUnits: [ adUnit ] });
+ pbVideoFactory(null, () => ({}), pbGlobal, pbEvents);
+
+ const bid = Object.assign({}, sampleBid, { vastXml: expectedVastXml });
+ bidAdjustmentCb(bid);
+ const expectedGeneratedId = sampleBid.adId + '-impression';
+ expect(vastXmlEditorMock.getVastXmlWithTrackingNodes.called).to.be.true;
+ expect(vastXmlEditorMock.getVastXmlWithTrackingNodes.calledWith(expectedVastXml, expectedImpressionUrl, expectedGeneratedId, expectedErrorUrl))
+ expect(vastXmlEditorMock.buildVastWrapper.called).to.be.false;
+ });
+ });
});
diff --git a/test/spec/modules/videoModule/shared/vastXmlBuilder_spec.js b/test/spec/modules/videoModule/shared/vastXmlBuilder_spec.js
new file mode 100644
index 00000000000..1007e3898c2
--- /dev/null
+++ b/test/spec/modules/videoModule/shared/vastXmlBuilder_spec.js
@@ -0,0 +1,103 @@
+import { buildVastWrapper, getVastNode, getAdNode, getWrapperNode, getAdSystemNode,
+ getAdTagUriNode, getErrorNode, getImpressionNode } from 'modules/videoModule/shared/vastXmlBuilder.js';
+import { expect } from 'chai';
+
+describe('buildVastWrapper', function () {
+ it('should include impression and error nodes when requested', function () {
+ const vastXml = buildVastWrapper(
+ 'adId123',
+ 'http://wwww.testUrl.com/redirectUrl.xml',
+ 'http://wwww.testUrl.com/impression.jpg',
+ 'impressionId123',
+ 'http://wwww.testUrl.com/error.jpg'
+ );
+ expect(vastXml).to.be.equal(`Prebid org`);
+ });
+
+ it('should omit error nodes when excluded', function () {
+ const vastXml = buildVastWrapper(
+ 'adId123',
+ 'http://wwww.testUrl.com/redirectUrl.xml',
+ 'http://wwww.testUrl.com/impression.jpg',
+ 'impressionId123',
+ );
+ expect(vastXml).to.be.equal(`Prebid org`);
+ });
+
+ it('should omit impression nodes when excluded', function () {
+ const vastXml = buildVastWrapper(
+ 'adId123',
+ 'http://wwww.testUrl.com/redirectUrl.xml',
+ );
+ expect(vastXml).to.be.equal(`Prebid org`);
+ });
+});
+
+describe('getVastNode', function () {
+ it('should return well formed Vast node', function () {
+ const vastNode = getVastNode('body', '4.0');
+ expect(vastNode).to.be.equal('body');
+ });
+
+ it('should omit version when missing', function() {
+ const vastNode = getVastNode('body');
+ expect(vastNode).to.be.equal('body');
+ });
+});
+
+describe('getAdNode', function () {
+ it('should return well formed Ad node', function () {
+ const adNode = getAdNode('body', 'adId123');
+ expect(adNode).to.be.equal('body');
+ });
+
+ it('should omit id when missing', function() {
+ const adNode = getAdNode('body');
+ expect(adNode).to.be.equal('body');
+ });
+});
+
+describe('getWrapperNode', function () {
+ it('should return well formed Wrapper node', function () {
+ const wrapperNode = getWrapperNode('body');
+ expect(wrapperNode).to.be.equal('body');
+ });
+});
+
+describe('getAdSystemNode', function () {
+ it('should return well formed AdSystem node', function () {
+ const adSystemNode = getAdSystemNode('testSysName', '5.0');
+ expect(adSystemNode).to.be.equal('testSysName');
+ });
+
+ it('should omit version when missing', function() {
+ const adSystemNode = getAdSystemNode('testSysName');
+ expect(adSystemNode).to.be.equal('testSysName');
+ });
+});
+
+describe('getAdTagUriNode', function () {
+ it('should return well formed ad tag URI node', function () {
+ const adTagNode = getAdTagUriNode('http://wwww.testUrl.com/ad.xml');
+ expect(adTagNode).to.be.equal('');
+ });
+});
+
+describe('getImpressionNode', function () {
+ it('should return well formed Impression node', function () {
+ const impressionNode = getImpressionNode('http://wwww.testUrl.com/adImpression.jpg', 'impresionId123');
+ expect(impressionNode).to.be.equal('');
+ });
+
+ it('should omit id when missing', function() {
+ const impressionNode = getImpressionNode('http://wwww.testUrl.com/adImpression.jpg');
+ expect(impressionNode).to.be.equal('');
+ });
+});
+
+describe('getErrorNode', function () {
+ it('should return well formed Error node', function () {
+ const errorNode = getErrorNode('http://wwww.testUrl.com/adError.jpg');
+ expect(errorNode).to.be.equal('');
+ });
+});
diff --git a/test/spec/modules/videoModule/shared/vastXmlEditor_spec.js b/test/spec/modules/videoModule/shared/vastXmlEditor_spec.js
new file mode 100644
index 00000000000..3040e54a571
--- /dev/null
+++ b/test/spec/modules/videoModule/shared/vastXmlEditor_spec.js
@@ -0,0 +1,183 @@
+import { vastXmlEditorFactory } from 'modules/videoModule/shared/vastXmlEditor.js';
+import { expect } from 'chai';
+
+describe('Vast XML Editor', function () {
+ const adWrapperXml = `
+
+
+
+ Prebid org
+
+
+
+
+`;
+
+ const inlineXml = `
+
+
+
+ Prebid org
+ Random Title
+
+
+
+`;
+
+ const inLineWithWrapper = `
+
+
+
+ Prebid org
+
+
+
+
+
+ Prebid org
+ Random Title
+
+
+
+`;
+
+ const vastXmlEditor = vastXmlEditorFactory();
+ const expectedImpressionUrl = 'https://test.impression.com/ping.gif';
+ const expectedImpressionId = 'test-impression-id';
+ const expectedErrorUrl = 'https://test.error.com/ping.gif';
+
+ it('should add Impression Nodes to the Ad Wrapper', function () {
+ const vastXml = vastXmlEditor.getVastXmlWithTrackingNodes(adWrapperXml, expectedImpressionUrl, expectedImpressionId);
+ const expectedXml = `
+
+
+ Prebid org
+
+
+
+`;
+ expect(vastXml).to.equal(expectedXml);
+ });
+
+ it('should add Impression Nodes to the InLine', function () {
+ const vastXml = vastXmlEditor.getVastXmlWithTrackingNodes(inlineXml, expectedImpressionUrl, expectedImpressionId);
+ const expectedXml = `
+
+
+ Prebid org
+ Random Title
+
+
+`;
+ expect(vastXml).to.equal(expectedXml);
+ });
+
+ it('should add Impression Nodes to the Ad Wrapper and Inline', function () {
+ const vastXml = vastXmlEditor.getVastXmlWithTrackingNodes(inLineWithWrapper, expectedImpressionUrl, expectedImpressionId);
+ const expectedXml = `
+
+
+ Prebid org
+
+
+
+
+
+ Prebid org
+ Random Title
+
+
+`;
+ expect(vastXml).to.equal(expectedXml);
+ });
+
+ it('should add Error Nodes to the Ad Wrapper', function () {
+ const vastXml = vastXmlEditor.getVastXmlWithTrackingNodes(adWrapperXml, null, null, expectedErrorUrl);
+ const expectedXml = `
+
+
+ Prebid org
+
+
+
+`;
+ expect(vastXml).to.equal(expectedXml);
+ });
+
+ it('should add Error Nodes to the InLine', function () {
+ const vastXml = vastXmlEditor.getVastXmlWithTrackingNodes(inlineXml, null, null, expectedErrorUrl);
+ const expectedXml = `
+
+
+ Prebid org
+ Random Title
+
+
+`;
+ expect(vastXml).to.equal(expectedXml);
+ });
+
+ it('should add Error Nodes to the Ad Wrapper and Inline', function () {
+ const vastXml = vastXmlEditor.getVastXmlWithTrackingNodes(inLineWithWrapper, null, null, expectedErrorUrl);
+ const expectedXml = `
+
+
+ Prebid org
+
+
+
+
+
+ Prebid org
+ Random Title
+
+
+`;
+ expect(vastXml).to.equal(expectedXml);
+ });
+
+ it('should add Impression Nodes and Error Nodes to the Ad Wrapper', function () {
+ const vastXml = vastXmlEditor.getVastXmlWithTrackingNodes(adWrapperXml, expectedImpressionUrl, expectedImpressionId, expectedErrorUrl);
+ const expectedXml = `
+
+
+ Prebid org
+
+
+
+`;
+ expect(vastXml).to.equal(expectedXml);
+ });
+
+ it('should add Impression Nodes and Error Nodes to the InLine', function () {
+ const vastXml = vastXmlEditor.getVastXmlWithTrackingNodes(inlineXml, expectedImpressionUrl, expectedImpressionId, expectedErrorUrl);
+ const expectedXml = `
+
+
+ Prebid org
+ Random Title
+
+
+`;
+ expect(vastXml).to.equal(expectedXml);
+ });
+
+ it('should add Impression Nodes and Error Nodes to the Ad Wrapper and Inline', function () {
+ const vastXml = vastXmlEditor.getVastXmlWithTrackingNodes(inLineWithWrapper, expectedImpressionUrl, expectedImpressionId, expectedErrorUrl);
+ const expectedXml = `
+
+
+ Prebid org
+
+
+
+
+
+ Prebid org
+ Random Title
+
+
+`;
+ expect(vastXml).to.equal(expectedXml);
+ });
+});