Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for non supported vast error #481

Merged
merged 3 commits into from
Nov 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/api/vast-parser.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ Whenever an error occurs during the VAST parsing, the parser will call automatic

- `no_ad`: The VAST document is empty
- VAST error `101`: VAST schema validation error.
- VAST error `102`: VAST version of response not supported.
- VAST error `301`: Timeout of VAST URI provided in Wrapper element.
- VAST error `302`: Wrapper limit reached.
- VAST error `303`: No VAST response after one or more Wrappers.
Expand Down
18 changes: 18 additions & 0 deletions spec/samples/outdated-vast.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<VideoAdServingTemplate>
<Ad id="preroll-1">
<InLine>
<AdSystem>example-1</AdSystem>
<AdTitle>123456</AdTitle>
<Video>
<Duration>00:00:15</Duration>
<AdID>preroll-1</AdID>
<MediaFiles>
<MediaFile width="600" type="video/x-flv" height="396" delivery="progressive"
bitrate="496">
<URL><![CDATA[http://example.com/ads/mediafile1.flv]]></URL>
</MediaFile>
</MediaFiles>
</Video>
</InLine>
</Ad>
</VideoAdServingTemplate>
38 changes: 0 additions & 38 deletions spec/samples/wrapper-invalid-xmlfile.xml

This file was deleted.

51 changes: 22 additions & 29 deletions spec/vast_parser.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,42 +27,18 @@ const nodeUrlHandler = {
const wrapperAVastUrl = urlFor('wrapper-a.xml');
const wrapperBVastUrl = urlFor('wrapper-b.xml');
const inlineSampleVastUrl = urlFor('sample.xml');
const inlineVpaidVastUrl = urlFor('vpaid.xml');
const inlineInvalidVastUrl = urlFor('invalid-xmlfile.xml');
const wrapperWithAttributesVastUrl = urlFor(
'wrapper-attributes-multiple-ads.xml'
);
const wrapperInvalidVastUrl = urlFor('wrapper-invalid-xmlfile.xml');
const vastWithErrorUrl = urlFor('empty-no-ad.xml');
const ad = {
id: null,
sequence: 1,
system: { value: 'VAST', version: null },
title: null,
description: null,
advertiser: null,
pricing: null,
survey: null,
errorURLTemplates: ['http://example.com/wrapperA-error'],
impressionURLTemplates: [],
creatives: [],
extensions: [],
adVerifications: [],
trackingEvents: { nonlinear: [], linear: [] },
videoClickTrackingURLTemplates: [],
videoCustomClickURLTemplates: [],
viewableImpression: [],
};

describe('VASTParser', () => {
let vastClient;
let VastParser;
let fetcher;
let inlineXml, invalidXml, errorXml, wrapperXml;
let inlineXml, invalidXml, errorXml, wrapperXml, outdatedXml;

beforeAll(async () => {
inlineXml = await nodeUrlHandler.get('./spec/samples/sample.xml');
errorXml = await nodeUrlHandler.get('./spec/samples/empty-no-ad.xml');
outdatedXml = await nodeUrlHandler.get('./spec/samples/outdated-vast.xml');
wrapperXml = await nodeUrlHandler.get(
'./spec/samples/wrapper-attributes-multiple-ads.xml'
);
Expand Down Expand Up @@ -136,6 +112,23 @@ describe('VASTParser', () => {
}
});

it('throw a error for non supported XML vast', () => {
try {
VastParser.parseVastXml(outdatedXml.xml, {
isRootVAST: true,
url: null,
wrapperDepth: 0,
});
} catch (e) {
expect(e.message).toBe('VAST response version not supported');
expect(VastParser.emit).toHaveBeenLastCalledWith('VAST-ad-parsed', {
type: 'ERROR',
url: null,
wrapperDepth: 0,
});
}
});

it('gets vast version from original vast', () => {
VastParser.parseVastXml(inlineXml.xml, {
isRootVAST: true,
Expand Down Expand Up @@ -480,20 +473,20 @@ describe('VASTParser', () => {
});

describe('Wrapper URL unavailable/timeout', () => {
it('sould emits a VAST-error and track', async () => {
it('should emits a VAST-error and track', async () => {
const url = './spec/samples/wrapper-unavailable-url.xml';

const response = await nodeUrlHandler.get(url);

fetcher.setOptions({ ...options, url: url, previousUrl: url });
VastParser.fetchingCallback = fetcher.fetchVAST.bind(fetcher);

const vastXML = await VastParser.parseVAST(response.xml, {
const vast = await VastParser.parseVAST(response.xml, {
url: url,
previousUrl: url,
});
// Response doesn't have any ads
expect(vastXML.ads).toEqual([]);
expect(vast.ads).toEqual([]);
// Error has been trigered
expect(dataTriggered.length).toBe(1);
expect(dataTriggered[0].ERRORCODE).toBe(301);
Expand Down
5 changes: 2 additions & 3 deletions src/fetcher/url_handler.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ async function handleResponse(response) {
*/
function handleError(response) {
if (
window.location.protocol === 'https:' &&
window?.location?.protocol === 'https:' &&
response.url.includes('http://')
) {
return 'URLHandler: Cannot go from HTTPS to HTTP.';
Expand Down Expand Up @@ -66,8 +66,7 @@ async function get(url, options) {
...options,
signal: controller.signal,
credentials: options.withCredentials ? 'include' : 'omit',
})
.finally(()=>{
}).finally(() => {
clearTimeout(timer);
});

Expand Down
22 changes: 17 additions & 5 deletions src/parser/vast_parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ const DEFAULT_EVENT_DATA = {
ERRORCODE: 900,
extensions: [],
};

const INVALID_VAST_ERROR = 'Invalid VAST XMLDocument';
const NON_SUPPORTED_VAST_VERSION = 'VAST response version not supported';
/**
* This class provides methods to fetch and parse a VAST document.
* @export
Expand All @@ -25,7 +26,10 @@ export class VASTParser extends EventEmitter {
constructor({ fetcher } = {}) {
super();
this.maxWrapperDepth = null;
this.rootErrorURLTemplates = [];
this.errorURLTemplates = [];
this.remainingAds = [];
this.parsingOptions = {};
this.fetcher = fetcher || null;
}

Expand Down Expand Up @@ -173,7 +177,12 @@ export class VASTParser extends EventEmitter {
url,
wrapperDepth,
});
throw new Error('Invalid VAST XMLDocument');
// VideoAdServingTemplate node is used for VAST 1.0
const isNonSupportedVast =
vastXml?.documentElement?.nodeName === 'VideoAdServingTemplate';
throw new Error(
isNonSupportedVast ? NON_SUPPORTED_VAST_VERSION : INVALID_VAST_ERROR
);
}

const ads = [];
Expand Down Expand Up @@ -414,8 +423,8 @@ export class VASTParser extends EventEmitter {
})
.catch((err) => {
// Timeout of VAST URI provided in Wrapper element, or of VAST URI provided in a subsequent Wrapper element.
// (URI was either unavailable or reached a timeout as defined by the video player.)
ad.errorCode = 301;
// (URI was either unavailable or reached a timeout as defined by the video player)
ad.errorCode = err.message === NON_SUPPORTED_VAST_VERSION ? 102 : 301;
ad.errorMessage = err.message;
resolve(ad);
});
Expand All @@ -440,7 +449,10 @@ export class VASTParser extends EventEmitter {
// - No Creative case - The parser has dealt with soma <Ad><Wrapper> or/and an <Ad><Inline> elements
// but no creative was found
const ad = vastResponse.ads[index];
if ((ad.errorCode || ad.creatives.length === 0) && !ad.VASTAdTagURI) {
const noMediaFilesAvailable = !ad.creatives.some(
(creative) => creative.mediaFiles?.length > 0
);
if ((ad.errorCode || noMediaFilesAvailable) && !ad.VASTAdTagURI) {
// If VASTAdTagURI is in the vastResponse, it means we are dealing with a Wrapper when using parseVAST from the VASTParser.
// In that case, we dont want to modify the vastResponse since the creatives node is not required in a wrapper.
this.trackVastError(
Expand Down