From 8b46e82374e8496cd57be8ec3a728a9167969578 Mon Sep 17 00:00:00 2001 From: Carlos Serrano Date: Mon, 24 Dec 2018 11:39:58 +0100 Subject: [PATCH 1/3] =?UTF-8?q?docs:=20=E2=9C=8F=EF=B8=8F=20hide=20type=20?= =?UTF-8?q?definitions=20from=20sidebar?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/tracker/helpers/pixelTracker.js | 2 ++ src/xml/index.js | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/tracker/helpers/pixelTracker.js b/src/tracker/helpers/pixelTracker.js index 2bd70f6f..830a96c2 100644 --- a/src/tracker/helpers/pixelTracker.js +++ b/src/tracker/helpers/pixelTracker.js @@ -3,6 +3,8 @@ import parseMacro from './parseMacro'; /** * Creates a tracking image with the passed URL macro. * + * @global + * @typedef pixelTracker * @type TrackerFn * @name pixelTracker * @param {string} URLMacro - URL Macro that need to be tracked. diff --git a/src/xml/index.js b/src/xml/index.js index ae46131f..105c3f31 100644 --- a/src/xml/index.js +++ b/src/xml/index.js @@ -13,6 +13,8 @@ const parser = new DOMParser(); /** * Parses the passed xml text. * + * @global + * @typedef parseXml * @throws if there is an error parsing the xml. * @param {string} xmlText - XML text to be parsed. * @returns {Object} - Returns the parsed xml document as a js object. From a5dff38b345c5f7bdead680637c4f38696972ba4 Mon Sep 17 00:00:00 2001 From: Carlos Serrano Date: Mon, 24 Dec 2018 12:01:21 +0100 Subject: [PATCH 2/3] =?UTF-8?q?docs:=20=E2=9C=8F=EF=B8=8F=20fix=20vast=20s?= =?UTF-8?q?pec=20links?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/types.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/types.js b/src/types.js index a2701e32..33ea4a37 100644 --- a/src/types.js +++ b/src/types.js @@ -22,7 +22,7 @@ */ /** - * From [VAST specification]{@link https://www.iab.com/guidelines/digital-video-ad-serving-template-vast-4-0/}: + * From [VAST specification]{@link https://iabtechlab.com/standards/vast/}: * * Sometimes ad servers would like to collect metadata from the video player when tracking * event URIs are accessed. For example, the position of the video player playhead at the time @@ -76,7 +76,7 @@ /** * VastIcon. - * For more info please take a look at the [VAST specification]{@link https://www.iab.com/guidelines/digital-video-ad-serving-template-vast-4-0/} + * For more info please take a look at the [VAST specification]{@link https://iabtechlab.com/standards/vast/} * * @global * @typedef VastIcon @@ -106,7 +106,7 @@ /** * VAST MediaFile representation. - * For more info please take a look at the [VAST specification]{@link https://www.iab.com/guidelines/digital-video-ad-serving-template-vast-4-0/} + * For more info please take a look at the [VAST specification]{@link https://iabtechlab.com/standards/vast/} * * @global * @typedef MediaFile @@ -130,7 +130,7 @@ /** * VastTrackingEvent. - * For more info please take a look at the [VAST specification]{@link https://www.iab.com/guidelines/digital-video-ad-serving-template-vast-4-0/} + * For more info please take a look at the [VAST specification]{@link https://iabtechlab.com/standards/vast/} * * @global * @typedef VastTrackingEvent @@ -195,7 +195,7 @@ /** * {@link VastChain} details object. You can think of it as a summary of the VAST Chain. Useful for debugging purposes and tracking. - * for more info about the returned properties please check [VAST specification]{@link https://www.iab.com/guidelines/digital-video-ad-serving-template-vast-4-0/} + * for more info about the returned properties please check [VAST specification]{@link https://iabtechlab.com/standards/vast/} * * @global * @typedef VastChainDetails From 661d835b7b18bb9459f9eee945c486ad7e9beb3b Mon Sep 17 00:00:00 2001 From: Carlos Serrano Date: Mon, 24 Dec 2018 12:40:03 +0100 Subject: [PATCH 3/3] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20new=20vpaidEnabled?= =?UTF-8?q?=20opt=20to=20disable=20VPAID=20ads?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/runner/__tests__/runWaterfall.spec.js | 42 ++++++++++++++++++++--- src/runner/runWaterfall.js | 15 ++++++++ 2 files changed, 53 insertions(+), 4 deletions(-) diff --git a/src/runner/__tests__/runWaterfall.spec.js b/src/runner/__tests__/runWaterfall.spec.js index 40b57e91..ec6a428f 100644 --- a/src/runner/__tests__/runWaterfall.spec.js +++ b/src/runner/__tests__/runWaterfall.spec.js @@ -1,11 +1,14 @@ /* eslint-disable max-nested-callbacks */ import { - vastWrapperXML, - vastInlineXML, - wrapperParsedXML, + inlineAd, inlineParsedXML, + vastInlineXML, + vastVpaidInlineXML, + vastWrapperXML, + vpaidInlineAd, + vpaidInlineParsedXML, wrapperAd, - inlineAd + wrapperParsedXML } from '../../../fixtures'; import defer from '../../utils/defer'; import requestAd from '../../vastRequest/requestAd'; @@ -117,6 +120,37 @@ describe('runWaterfall', () => { }); describe('after fetching Vast response', () => { + test('must throw if it gets a vpaid ad with vpaidEnabled flag set to false', async () => { + const onError = jest.fn(); + const vpaidChain = [ + { + ad: vpaidInlineAd, + errorCode: null, + parsedXML: vpaidInlineParsedXML, + requestTag: 'https://test.example.com/vastadtaguri', + XML: vastVpaidInlineXML + } + ]; + + requestAd.mockReturnValue(Promise.resolve(vpaidChain)); + + await runWaterfall(adTag, placeholder, { + ...options, + onError, + vpaidEnabled: false + }); + expect(onError).toHaveBeenCalledTimes(1); + + const error = onError.mock.calls[0][0]; + + expect(error.code).toBe(200); + expect(error.message).toBe('VPAID ads are not supported by the current player'); + expect(trackError).toHaveBeenCalledWith(vpaidChain, expect.objectContaining({ + errorCode: 200, + tracker: options.tracker + })); + }); + test('must call onError if Vast response is undefined', async () => { const onError = jest.fn(); diff --git a/src/runner/runWaterfall.js b/src/runner/runWaterfall.js index f1c198be..eac8b46c 100644 --- a/src/runner/runWaterfall.js +++ b/src/runner/runWaterfall.js @@ -2,9 +2,11 @@ import {trackError} from '../tracker'; import requestAd from '../vastRequest/requestAd'; import requestNextAd from '../vastRequest/requestNextAd'; +import {getInteractiveFiles} from '../vastSelectors'; import isIOS from '../utils/isIOS'; import run from './run'; +const isVpaid = (vastChain) => Boolean(getInteractiveFiles(vastChain[0].ad)); const validateVastChain = (vastChain, options) => { if (!vastChain || vastChain.length === 0) { throw new Error('Invalid VastChain'); @@ -12,6 +14,14 @@ const validateVastChain = (vastChain, options) => { const lastVastResponse = vastChain[0]; + if (!options.vpaidEnabled && isVpaid(vastChain)) { + const error = new Error('VPAID ads are not supported by the current player'); + + error.code = 200; + lastVastResponse.errorCode = 200; + lastVastResponse.error = error; + } + if (Boolean(lastVastResponse.error)) { throw lastVastResponse.error; } @@ -138,6 +148,8 @@ const waterfall = async (fetchVastChain, placeholder, options, isCanceled) => { * Defaults to `false` * @param {number} [options.timeout] - timeout number in milliseconds. If set, the video ad will time out if it doesn't start within the specified time. * @param {TrackerFn} [options.tracker] - If provided it will be used to track the VAST events instead of the default {@link pixelTracker}. + * @param {boolean} [options.vpaidEnabled] - if false and it gets a VPAID ad, it will throw an error before starting the ad and continue down in the waterfall. + * Defaults to `true`. * @param {Object} [options.hooks] - Optional map with hooks to configure the behaviour of the ad. * @param {Function} [options.hooks.createSkipControl] - If provided it will be called to generate the skip control. Must return a clickable [HTMLElement](https://developer.mozilla.org/es/docs/Web/API/HTMLElement) that is detached from the DOM. * @param {Function} [options.hooks.validateVastResponse] - If provided it will be called for each valid vast response. Must throw if there is a problem with the vast response. If the Error instance has an `errorCode` number then it will be tracked using the error macros in the Vast response. It will also call {@link runWaterfall~onError} with the thrown error. @@ -153,8 +165,11 @@ const runWaterfall = (adTag, placeholder, options) => { adUnit = newAdUnit; onAdStartHandler(adUnit); }; + const opts = { + vpaidEnabled: true, ...options, + // eslint-disable-next-line sort-keys onAdReady: callbackHandler(options.onAdReady), onAdStart, onError: callbackHandler(options.onError),