+ vast-client.js use case
+ This page aim to demonstrate how to use the vast-client.js library and implement a simple preroll using a html5 video tag.
+
+
+
+ Companion ad slot
+
+
+
+
+
+
+
diff --git a/examples/src/index.js b/examples/src/index.js
new file mode 100644
index 00000000..2f6c2fd9
--- /dev/null
+++ b/examples/src/index.js
@@ -0,0 +1,5 @@
+import { playPreroll } from './utils';
+
+const videoPlayer = document.getElementById('myVideo');
+
+videoPlayer.addEventListener('play', playPreroll, { once: true });
diff --git a/examples/src/styles.css b/examples/src/styles.css
new file mode 100644
index 00000000..ff340e05
--- /dev/null
+++ b/examples/src/styles.css
@@ -0,0 +1,13 @@
+main {
+ display: flex;
+ align-items: center;
+ flex-direction: column;
+}
+
+h1 {
+ font-size: 25px;
+}
+
+#variationContainer {
+ display: none;
+}
diff --git a/examples/src/utils.js b/examples/src/utils.js
new file mode 100644
index 00000000..b268d84c
--- /dev/null
+++ b/examples/src/utils.js
@@ -0,0 +1,317 @@
+//eslint-disable-next-line
+import { VASTClient, VASTTracker } from '@dailymotion/vast-client';
+
+const mainContent =
+ 'https://dmplayer.storage.googleapis.com/tech_test/midnight_sun_720p.mp4';
+const videoPlayer = document.getElementById('myVideo');
+const variationImg = document.getElementById('variationImg');
+const variationContainer = document.getElementById('variationContainer');
+
+//vastTracker for linear ads
+let vastTracker = null;
+//vastTracker for companion ads
+let companionVastTracker = null;
+
+/**
+ * Get the first valid creative from an ad
+ */
+export const getCreative = (ad) => {
+ if (!ad.creatives) {
+ return null;
+ }
+
+ return ad.creatives.find((creative) => creative.mediaFiles) || null;
+};
+
+/**
+ * Get the URL of the first media file in the creative
+ */
+
+export const getMediaFileUrl = (creative) => {
+ const mediaFiles = creative.mediaFiles;
+ if (!mediaFiles.length) {
+ return null;
+ }
+
+ return mediaFiles.find((mediaFile) => mediaFile.fileURL).fileURL || null;
+};
+
+/**
+ * @returns a promise that resolves with the parsed VAST
+ */
+
+export const parsePreroll = async () => {
+ const VAST = 'https://statics.dmcdn.net/h/html/vast/simple-inline.xml';
+
+ const vastClient = new VASTClient();
+ try {
+ return vastClient.get(VAST);
+ } catch (error) {
+ // eslint-disable-next-line no-console
+ console.error(error);
+ }
+};
+
+/**
+ * play a preroll
+ */
+
+export const playPreroll = async () => {
+ const parsedVAST = await parsePreroll();
+ // here we are using the first ad from the parsed vast that contain creatives,
+ // however, this logic can depend on you player implementation logic
+ const validAd = parsedVAST.ads.find((ads) => ads.creatives.length > 0);
+ if (!validAd) {
+ return;
+ }
+
+ const creative = getCreative(validAd);
+ const mediaFileUrl = getMediaFileUrl(creative);
+ const variationData = getVariationData(validAd);
+ const companionCreative = getCreativeCompanion(validAd);
+
+ videoPlayer.src = mediaFileUrl;
+ videoPlayer.play();
+
+ // listen the ended event to stop the ad and remove trackers
+ videoPlayer.addEventListener('ended', stopAd);
+
+ // once we have the parsed vast we can instantiate the vastTracker
+ vastTracker = new VASTTracker(null, validAd, creative);
+
+ //if we have a companion ad we instantiate the companionVastTracker
+ if (variationData.variation) {
+ companionVastTracker = new VASTTracker(
+ null,
+ validAd,
+ companionCreative,
+ variationData.variation
+ );
+ }
+
+ displayVariation(variationData);
+ initTrackers();
+};
+
+/**
+ * Stop the ad and remove all EventListeners
+ */
+
+export const stopAd = () => {
+ videoPlayer.src = mainContent;
+ videoPlayer.load();
+ videoPlayer.play();
+ variationContainer.style.display = 'none';
+ removeTrackers(videoPlayer);
+};
+
+/**
+ * attach all the EventListeners to the videoPlayer
+ */
+export const initTrackers = () => {
+ videoPlayer.addEventListener('volumechange', handleMuteTrackers);
+ videoPlayer.addEventListener('click', handleClickTrackers);
+ videoPlayer.addEventListener('canplay', handleImpressionTrackers);
+ videoPlayer.addEventListener('canplay', handleCompanionImpressionTrackers);
+ videoPlayer.addEventListener('timeupdate', handleTimeUpdateTrackers);
+ videoPlayer.addEventListener('ended', handleCompleteTrackers);
+ videoPlayer.addEventListener('play', handleResumeTrackers);
+ videoPlayer.addEventListener('pause', handlePauseTrackers);
+ videoPlayer.addEventListener('error', handleErrorTrackers);
+ //listener on the variation container to detect the click an fire the tracker
+ variationImg.addEventListener('click', handleCompanionClickTrackers);
+};
+
+/**
+ * removes all the EventListeners from the videoPlayer
+ */
+export const removeTrackers = () => {
+ videoPlayer.removeEventListener('volumechange', handleMuteTrackers);
+ videoPlayer.removeEventListener('click', handleClickTrackers);
+ videoPlayer.removeEventListener('canplay', handleImpressionTrackers);
+ videoPlayer.removeEventListener('canplay', handleCompanionImpressionTrackers);
+ videoPlayer.removeEventListener('timeupdate', handleTimeUpdateTrackers);
+ videoPlayer.removeEventListener('play', handleResumeTrackers);
+ videoPlayer.removeEventListener('pause', handlePauseTrackers);
+ videoPlayer.removeEventListener('ended', handleCompleteTrackers);
+ videoPlayer.removeEventListener('error', handleErrorTrackers);
+ variationImg.removeEventListener('click', handleCompanionClickTrackers);
+};
+
+/**
+ * Send mute and unmute trackers using the vastTracker
+ */
+const handleMuteTrackers = (e) => {
+ if (!vastTracker) {
+ return;
+ }
+
+ const muted = e.target.muted;
+ vastTracker.setMuted(muted);
+};
+
+/**
+ * Send click trackers using the vastTracker
+ */
+const handleClickTrackers = (e) => {
+ if (!vastTracker) {
+ return;
+ }
+
+ // The values for the CLICKPOS macros depends on your player implementations logic
+ vastTracker.click(null, { CLICKPOS: [e.clientX, e.clientY] });
+ vastTracker.on('clickthrough', (url) => {
+ window.open(url, '_blank');
+ });
+};
+
+/**
+ * Send companion click trackers using the vastTracker
+ */
+const handleCompanionClickTrackers = () => {
+ if (!companionVastTracker) {
+ return;
+ }
+ companionVastTracker.click();
+ companionVastTracker.on('clickthrough', (url) => {
+ window.open(url, '_blank');
+ });
+};
+
+/**
+ * Send impression trackers for linear ads using the vastTracker
+ */
+const handleImpressionTrackers = () => {
+ if (!vastTracker) {
+ return;
+ }
+ vastTracker.trackImpression();
+};
+
+/**
+ * Send impression trackers for companion ads using the vastTracker
+ */
+const handleCompanionImpressionTrackers = () => {
+ if (!companionVastTracker) {
+ return;
+ }
+ companionVastTracker.trackImpression();
+};
+
+/**
+ * Send complete tracker using the vastTracker
+ */
+const handleCompleteTrackers = () => {
+ if (!vastTracker) {
+ return;
+ }
+ vastTracker.complete();
+};
+
+/**
+ * Send pause tracker using the vastTracker
+ */
+
+const handlePauseTrackers = () => {
+ if (!vastTracker) {
+ return;
+ }
+ vastTracker.setPaused(true);
+};
+
+/**
+ * Send resume tracker using the vastTracker
+ */
+const handleResumeTrackers = () => {
+ if (!vastTracker) {
+ return;
+ }
+ vastTracker.setPaused(false);
+};
+
+/**
+ * Send progress tracker(firstQuartile, midpoint...) using the vastTracker
+ */
+const handleTimeUpdateTrackers = () => {
+ if (!vastTracker) {
+ return;
+ }
+ vastTracker.setProgress(videoPlayer.currentTime);
+};
+
+/**
+ * Send error trackers using the vastTracker
+ */
+
+const handleErrorTrackers = () => {
+ if (!vastTracker) {
+ return;
+ }
+ vastTracker.error();
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////COMPANION HANDLING////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * @returns the first valid companion creative
+ */
+const getCreativeCompanion = (ad) => {
+ if (!ad.creatives) {
+ return null;
+ }
+
+ const validCreative = ad.creatives.find(
+ (creative) => creative.type === 'companion'
+ );
+
+ return validCreative || null;
+};
+
+/**
+ * @returns an Object containing the image url and the variation
+ */
+
+const getVariationData = (ad) => {
+ if (!ad.creatives) {
+ return null;
+ }
+ const validCreative = getCreativeCompanion(ad);
+
+ if (!validCreative.variations.length) {
+ return null;
+ }
+
+ return {
+ imgUrl: getVariationUrl(validCreative.variations[0]),
+ variation: validCreative.variations[0],
+ };
+};
+
+/**
+ * @returns the image url of the variation to display
+ */
+
+const getVariationUrl = (variation) => {
+ if (!variation.staticResources.length) {
+ return null;
+ }
+
+ return variation.staticResources[0].url;
+};
+
+const displayVariation = (variationData) => {
+ const { imgUrl, variation } = variationData;
+ if (!variation) {
+ return null;
+ }
+ variationImg.src = imgUrl;
+ variationImg.style.height = `${variation.assetHeight}px`;
+ variationImg.style.assetWIdth = `${variation.assetWidth}px`;
+ variationContainer.style.display = 'block';
+ variationContainer.style.width = `${variation.width}px`;
+ variationContainer.style.height = `${variation.height}px`;
+ variationImg.style.maxWidth = `${variation.expandedWidth}px`;
+ variationImg.style.maxHeight = `${variation.expandedHeight}px`;
+};
diff --git a/package-lock.json b/package-lock.json
index f80b6769..9480b4d0 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -27,7 +27,6 @@
"eslint-plugin-import": "^2.25.4",
"husky": "^8.0.3",
"jest": "^26.6.3",
- "mocha": "^10.0.0",
"path": "^0.12.7",
"prettier": "^2.5.1",
"pretty-quick": "^3.1.3",
@@ -4360,15 +4359,6 @@
"node": ">=0.10.0"
}
},
- "node_modules/binary-extensions": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
- "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
@@ -4397,12 +4387,6 @@
"integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==",
"dev": true
},
- "node_modules/browser-stdout": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz",
- "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==",
- "dev": true
- },
"node_modules/browserslist": {
"version": "4.21.10",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.10.tgz",
@@ -4583,33 +4567,6 @@
"node": ">=10"
}
},
- "node_modules/chokidar": {
- "version": "3.5.3",
- "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
- "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
- "dev": true,
- "funding": [
- {
- "type": "individual",
- "url": "https://paulmillr.com/funding/"
- }
- ],
- "dependencies": {
- "anymatch": "~3.1.2",
- "braces": "~3.0.2",
- "glob-parent": "~5.1.2",
- "is-binary-path": "~2.1.0",
- "is-glob": "~4.0.1",
- "normalize-path": "~3.0.0",
- "readdirp": "~3.6.0"
- },
- "engines": {
- "node": ">= 8.10.0"
- },
- "optionalDependencies": {
- "fsevents": "~2.3.2"
- }
- },
"node_modules/chownr": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz",
@@ -5079,15 +5036,6 @@
"node": ">=8"
}
},
- "node_modules/diff": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz",
- "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==",
- "dev": true,
- "engines": {
- "node": ">=0.3.1"
- }
- },
"node_modules/diff-sequences": {
"version": "26.6.2",
"resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-26.6.2.tgz",
@@ -6149,15 +6097,6 @@
"node": ">=8"
}
},
- "node_modules/flat": {
- "version": "5.0.2",
- "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz",
- "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==",
- "dev": true,
- "bin": {
- "flat": "cli.js"
- }
- },
"node_modules/flat-cache": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz",
@@ -6674,15 +6613,6 @@
"node": ">=0.10.0"
}
},
- "node_modules/he": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
- "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
- "dev": true,
- "bin": {
- "he": "bin/he"
- }
- },
"node_modules/home-or-tmp": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz",
@@ -6931,18 +6861,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/is-binary-path": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
- "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
- "dev": true,
- "dependencies": {
- "binary-extensions": "^2.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/is-boolean-object": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz",
@@ -7163,15 +7081,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/is-plain-obj": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz",
- "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/is-plain-object": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
@@ -7290,18 +7199,6 @@
"integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==",
"dev": true
},
- "node_modules/is-unicode-supported": {
- "version": "0.1.0",
- "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz",
- "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==",
- "dev": true,
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
"node_modules/is-weakref": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz",
@@ -9283,92 +9180,6 @@
"integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==",
"dev": true
},
- "node_modules/log-symbols": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz",
- "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==",
- "dev": true,
- "dependencies": {
- "chalk": "^4.1.0",
- "is-unicode-supported": "^0.1.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/log-symbols/node_modules/ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
- "dependencies": {
- "color-convert": "^2.0.1"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
- }
- },
- "node_modules/log-symbols/node_modules/chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "dev": true,
- "dependencies": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/chalk?sponsor=1"
- }
- },
- "node_modules/log-symbols/node_modules/color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
- "dependencies": {
- "color-name": "~1.1.4"
- },
- "engines": {
- "node": ">=7.0.0"
- }
- },
- "node_modules/log-symbols/node_modules/color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
- },
- "node_modules/log-symbols/node_modules/has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/log-symbols/node_modules/supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "dev": true,
- "dependencies": {
- "has-flag": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/lolex": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/lolex/-/lolex-1.6.0.tgz",
@@ -9604,317 +9415,6 @@
"mkdirp": "bin/cmd.js"
}
},
- "node_modules/mocha": {
- "version": "10.2.0",
- "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz",
- "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==",
- "dev": true,
- "dependencies": {
- "ansi-colors": "4.1.1",
- "browser-stdout": "1.3.1",
- "chokidar": "3.5.3",
- "debug": "4.3.4",
- "diff": "5.0.0",
- "escape-string-regexp": "4.0.0",
- "find-up": "5.0.0",
- "glob": "7.2.0",
- "he": "1.2.0",
- "js-yaml": "4.1.0",
- "log-symbols": "4.1.0",
- "minimatch": "5.0.1",
- "ms": "2.1.3",
- "nanoid": "3.3.3",
- "serialize-javascript": "6.0.0",
- "strip-json-comments": "3.1.1",
- "supports-color": "8.1.1",
- "workerpool": "6.2.1",
- "yargs": "16.2.0",
- "yargs-parser": "20.2.4",
- "yargs-unparser": "2.0.0"
- },
- "bin": {
- "_mocha": "bin/_mocha",
- "mocha": "bin/mocha.js"
- },
- "engines": {
- "node": ">= 14.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/mochajs"
- }
- },
- "node_modules/mocha/node_modules/ansi-colors": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz",
- "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==",
- "dev": true,
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/mocha/node_modules/ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
- "dependencies": {
- "color-convert": "^2.0.1"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
- }
- },
- "node_modules/mocha/node_modules/argparse": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
- "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
- "dev": true
- },
- "node_modules/mocha/node_modules/cliui": {
- "version": "7.0.4",
- "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
- "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
- "dev": true,
- "dependencies": {
- "string-width": "^4.2.0",
- "strip-ansi": "^6.0.0",
- "wrap-ansi": "^7.0.0"
- }
- },
- "node_modules/mocha/node_modules/color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
- "dependencies": {
- "color-name": "~1.1.4"
- },
- "engines": {
- "node": ">=7.0.0"
- }
- },
- "node_modules/mocha/node_modules/color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
- },
- "node_modules/mocha/node_modules/escape-string-regexp": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
- "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
- "dev": true,
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/mocha/node_modules/find-up": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
- "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
- "dev": true,
- "dependencies": {
- "locate-path": "^6.0.0",
- "path-exists": "^4.0.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/mocha/node_modules/glob": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz",
- "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==",
- "dev": true,
- "dependencies": {
- "fs.realpath": "^1.0.0",
- "inflight": "^1.0.4",
- "inherits": "2",
- "minimatch": "^3.0.4",
- "once": "^1.3.0",
- "path-is-absolute": "^1.0.0"
- },
- "engines": {
- "node": "*"
- },
- "funding": {
- "url": "https://github.com/sponsors/isaacs"
- }
- },
- "node_modules/mocha/node_modules/glob/node_modules/minimatch": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
- "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
- "dev": true,
- "dependencies": {
- "brace-expansion": "^1.1.7"
- },
- "engines": {
- "node": "*"
- }
- },
- "node_modules/mocha/node_modules/has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/mocha/node_modules/js-yaml": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
- "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
- "dev": true,
- "dependencies": {
- "argparse": "^2.0.1"
- },
- "bin": {
- "js-yaml": "bin/js-yaml.js"
- }
- },
- "node_modules/mocha/node_modules/locate-path": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
- "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
- "dev": true,
- "dependencies": {
- "p-locate": "^5.0.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/mocha/node_modules/minimatch": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz",
- "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==",
- "dev": true,
- "dependencies": {
- "brace-expansion": "^2.0.1"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/mocha/node_modules/minimatch/node_modules/brace-expansion": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
- "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
- "dev": true,
- "dependencies": {
- "balanced-match": "^1.0.0"
- }
- },
- "node_modules/mocha/node_modules/ms": {
- "version": "2.1.3",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
- "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
- "dev": true
- },
- "node_modules/mocha/node_modules/p-limit": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
- "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
- "dev": true,
- "dependencies": {
- "yocto-queue": "^0.1.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/mocha/node_modules/p-locate": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
- "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
- "dev": true,
- "dependencies": {
- "p-limit": "^3.0.2"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/mocha/node_modules/supports-color": {
- "version": "8.1.1",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
- "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
- "dev": true,
- "dependencies": {
- "has-flag": "^4.0.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/supports-color?sponsor=1"
- }
- },
- "node_modules/mocha/node_modules/wrap-ansi": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
- "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
- "dev": true,
- "dependencies": {
- "ansi-styles": "^4.0.0",
- "string-width": "^4.1.0",
- "strip-ansi": "^6.0.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
- }
- },
- "node_modules/mocha/node_modules/y18n": {
- "version": "5.0.8",
- "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
- "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
- "dev": true,
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/mocha/node_modules/yargs": {
- "version": "16.2.0",
- "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz",
- "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==",
- "dev": true,
- "dependencies": {
- "cliui": "^7.0.2",
- "escalade": "^3.1.1",
- "get-caller-file": "^2.0.5",
- "require-directory": "^2.1.1",
- "string-width": "^4.2.0",
- "y18n": "^5.0.5",
- "yargs-parser": "^20.2.2"
- },
- "engines": {
- "node": ">=10"
- }
- },
"node_modules/mri": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz",
@@ -9952,18 +9452,6 @@
"integrity": "sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==",
"dev": true
},
- "node_modules/nanoid": {
- "version": "3.3.3",
- "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz",
- "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==",
- "dev": true,
- "bin": {
- "nanoid": "bin/nanoid.cjs"
- },
- "engines": {
- "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
- }
- },
"node_modules/nanomatch": {
"version": "1.2.13",
"resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz",
@@ -11027,18 +10515,6 @@
"node": ">= 6"
}
},
- "node_modules/readdirp": {
- "version": "3.6.0",
- "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
- "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
- "dev": true,
- "dependencies": {
- "picomatch": "^2.2.1"
- },
- "engines": {
- "node": ">=8.10.0"
- }
- },
"node_modules/regenerate": {
"version": "1.4.2",
"resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz",
@@ -11740,15 +11216,6 @@
"semver": "bin/semver.js"
}
},
- "node_modules/serialize-javascript": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz",
- "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==",
- "dev": true,
- "dependencies": {
- "randombytes": "^2.1.0"
- }
- },
"node_modules/set-blocking": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
@@ -13441,12 +12908,6 @@
"string-width": "^1.0.2 || 2 || 3 || 4"
}
},
- "node_modules/workerpool": {
- "version": "6.2.1",
- "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz",
- "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==",
- "dev": true
- },
"node_modules/wrap-ansi": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
@@ -13579,54 +13040,6 @@
"node": ">=8"
}
},
- "node_modules/yargs-parser": {
- "version": "20.2.4",
- "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz",
- "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==",
- "dev": true,
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/yargs-unparser": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz",
- "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==",
- "dev": true,
- "dependencies": {
- "camelcase": "^6.0.0",
- "decamelize": "^4.0.0",
- "flat": "^5.0.2",
- "is-plain-obj": "^2.1.0"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/yargs-unparser/node_modules/camelcase": {
- "version": "6.3.0",
- "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz",
- "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==",
- "dev": true,
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/yargs-unparser/node_modules/decamelize": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz",
- "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==",
- "dev": true,
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
"node_modules/yargs/node_modules/yargs-parser": {
"version": "18.1.3",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz",
@@ -13639,18 +13052,6 @@
"engines": {
"node": ">=6"
}
- },
- "node_modules/yocto-queue": {
- "version": "0.1.0",
- "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
- "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
- "dev": true,
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
}
}
}
diff --git a/package.json b/package.json
index d1bc0371..33bc5974 100644
--- a/package.json
+++ b/package.json
@@ -19,6 +19,12 @@
"engines": {
"node": ">=12.22.1"
},
+ "browserslist": [
+ "chrome >= 63",
+ "firefox >= 67",
+ "edge >= 79",
+ "safari >= 12.1"
+ ],
"publishConfig": {
"registry": "https://registry.npmjs.org"
},
@@ -28,11 +34,11 @@
"performance": "node performance/performance_test.js",
"prebuild": "rm -rf dist_old && mkdir dist_old && cp -a dist/. dist_old/",
"build": "rollup -c",
+ "watch": "rollup -c --watch",
"postbuild": "node bundle_size.js",
"lint": "eslint .",
"precommit": "eslint . --max-warnings 0 && pretty-quick --staged",
- "test": "mocha --require @babel/register && jest",
- "jest": "jest"
+ "test": "jest"
},
"devDependencies": {
"@babel/core": "^7.16.12",
@@ -50,7 +56,6 @@
"eslint-plugin-import": "^2.25.4",
"husky": "^8.0.3",
"jest": "^26.6.3",
- "mocha": "^10.0.0",
"path": "^0.12.7",
"prettier": "^2.5.1",
"pretty-quick": "^3.1.3",
diff --git a/rollup.config.js b/rollup.config.js
index eee0f840..01f05672 100644
--- a/rollup.config.js
+++ b/rollup.config.js
@@ -1,6 +1,5 @@
import babel from '@rollup/plugin-babel';
import { terser } from 'rollup-plugin-terser';
-import alias from '@rollup/plugin-alias';
import resolve from '@rollup/plugin-node-resolve';
const babelPlugin = babel({
@@ -15,74 +14,76 @@ function onwarn(warning) {
}
}
-function minify(config) {
- const minifiedConfig = Object.assign({}, config);
- minifiedConfig.output = Object.assign({}, config.output);
- minifiedConfig.plugins = Object.assign([], config.plugins);
+const createNodeConfig = (filePath, minifiedOutput, notMinifiedOutput) => {
+ const baseConfig = {
+ input: filePath,
+ output: {
+ format: 'cjs',
+ dir: 'dist',
+ manualChunks: {
+ xmldom: ['@xmldom/xmldom'],
+ },
+ },
+ plugins: [
+ resolve({
+ preferBuiltins: true,
+ }),
+ babelPlugin,
+ ],
+ onwarn,
+ };
- const outputFile = minifiedConfig.output.file;
- const extensionIndex = outputFile.lastIndexOf('.js');
- minifiedConfig.output.file =
- outputFile.substr(0, extensionIndex) +
- '.min' +
- outputFile.substr(extensionIndex);
+ const nonMinifiedConfig = {
+ ...baseConfig,
+ output: {
+ ...baseConfig.output,
+ entryFileNames: notMinifiedOutput,
+ chunkFileNames: 'chunks/[name]-[hash].js',
+ },
+ };
- minifiedConfig.plugins.push(terser());
+ const minifiedConfig = {
+ ...baseConfig,
+ output: {
+ ...baseConfig.output,
+ entryFileNames: minifiedOutput,
+ chunkFileNames: 'chunks/[name]-[hash].min.js',
+ },
+ plugins: [...baseConfig.plugins, terser()],
+ };
- return minifiedConfig;
-}
-
-const browserConfig = {
- input: 'src/index.js',
- output: {
- name: 'VAST',
- format: 'umd',
- file: 'dist/vast-client.js',
- },
- plugins: [babelPlugin],
+ return [nonMinifiedConfig, minifiedConfig];
};
-const browserScriptConfig = {
- input: 'src/index.js',
- output: {
- name: 'VAST',
- format: 'iife',
- file: 'dist/vast-client-browser.js',
- },
- plugins: [babelPlugin],
-};
+const createBrowserConfig = (filePath, minifiedOutput, notMinifiedOutput) => {
+ let config = {
+ input: filePath,
+ output: [
+ {
+ format: 'es',
+ dir: 'dist',
+ entryFileNames: notMinifiedOutput,
+ },
+ {
+ format: 'es',
+ dir: 'dist',
+ entryFileNames: minifiedOutput,
+ plugins: [terser()],
+ },
+ ],
+ plugins: [babelPlugin],
+ };
-const nodeConfig = {
- input: 'src/index.js',
- output: {
- format: 'cjs',
- file: 'dist/vast-client-node.js',
- },
- plugins: [
- alias({
- entries: [
- {
- find: './urlhandlers/mock_node_url_handler',
- replacement: './urlhandlers/node_url_handler',
- },
- ],
- }),
- resolve({
- preferBuiltins: true,
- }),
- babelPlugin,
- ],
- onwarn,
+ return config;
};
export default [
- // Browser-friendly UMD build [package.json "browser"]
- browserConfig,
- minify(browserConfig),
-
+ // Browser-friendly build [package.json "browser"]
+ createBrowserConfig('src/index.js', 'vast-client.min.js', 'vast-client.js'),
// CommonJS build for Node usage [package.json "main"]
- nodeConfig,
- minify(nodeConfig),
-
- minify(browserScriptConfig),
+ ...createNodeConfig(
+ 'src/index.js',
+ 'vast-client-node.min.js',
+ 'vast-client-node.js'
+ ),
];
diff --git a/spec/fetcher.spec.js b/spec/fetcher.spec.js
new file mode 100644
index 00000000..7c2f3fbf
--- /dev/null
+++ b/spec/fetcher.spec.js
@@ -0,0 +1,253 @@
+import { Fetcher } from '../src/fetcher/fetcher';
+import { VASTParser } from '../src/parser/vast_parser';
+import * as Bitrate from '../src/parser/bitrate';
+import { urlHandler } from '../src/fetcher/url_handler';
+import { expect } from '@jest/globals';
+import { getNodesFromXml } from './utils/utils';
+
+describe('Fetcher', () => {
+ let fetcher, mockEmit;
+ const xml = getNodesFromXml('