diff --git a/docs/api/vast-parser.md b/docs/api/vast-parser.md
index b25c96b1..5b35d15b 100644
--- a/docs/api/vast-parser.md
+++ b/docs/api/vast-parser.md
@@ -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.
diff --git a/spec/samples/outdated-vast.xml b/spec/samples/outdated-vast.xml
new file mode 100644
index 00000000..74a5e6bb
--- /dev/null
+++ b/spec/samples/outdated-vast.xml
@@ -0,0 +1,18 @@
+
+
+
+ example-1
+ 123456
+
+
+
+
diff --git a/spec/samples/wrapper-invalid-xmlfile.xml b/spec/samples/wrapper-invalid-xmlfile.xml
deleted file mode 100644
index 625599f1..00000000
--- a/spec/samples/wrapper-invalid-xmlfile.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-
-
-
-
- VAST
- invalid-xmlfile.xml
- http://example.com/wrapper-invalid-xmlfile_wrapper-error
- http://example.com/wrapper-invalid-xmlfile_impression
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/spec/vast_parser.spec.js b/spec/vast_parser.spec.js
index 98433aa2..25ebccd4 100644
--- a/spec/vast_parser.spec.js
+++ b/spec/vast_parser.spec.js
@@ -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'
);
@@ -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,
@@ -480,7 +473,7 @@ 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);
@@ -488,12 +481,12 @@ describe('VASTParser', () => {
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);
diff --git a/src/fetcher/url_handler.js b/src/fetcher/url_handler.js
index d6d7f350..3d88bc86 100644
--- a/src/fetcher/url_handler.js
+++ b/src/fetcher/url_handler.js
@@ -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.';
@@ -66,8 +66,7 @@ async function get(url, options) {
...options,
signal: controller.signal,
credentials: options.withCredentials ? 'include' : 'omit',
- })
- .finally(()=>{
+ }).finally(() => {
clearTimeout(timer);
});
diff --git a/src/parser/vast_parser.js b/src/parser/vast_parser.js
index 3c6d0919..e6e84e1a 100644
--- a/src/parser/vast_parser.js
+++ b/src/parser/vast_parser.js
@@ -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
@@ -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;
}
@@ -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 = [];
@@ -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);
});
@@ -440,7 +449,10 @@ export class VASTParser extends EventEmitter {
// - No Creative case - The parser has dealt with soma or/and an 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(