From bbc78354e88a49b07bd94eeb29b0aeb3e6309b74 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Tue, 26 Feb 2019 09:23:04 -0600 Subject: [PATCH 1/8] adds same license as autotune --- LICENSE | 27 +++++++++++++++++++++++++++ src/lib/vast_elements/README.md | 30 ++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..b644be1 --- /dev/null +++ b/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2019, Vox Media, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the {organization} nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/src/lib/vast_elements/README.md b/src/lib/vast_elements/README.md index d42f7d8..4c07d90 100644 --- a/src/lib/vast_elements/README.md +++ b/src/lib/vast_elements/README.md @@ -30,3 +30,33 @@ There are three major methods that the extending class must support 1. `setup()` – this will be called once your element class is loaded, use it like a constructor. 1. `onVastReady()` – The vast file has been onVastReady and your selector has been run, you can find your elements loaded in `this.elements` + +### License + +Copyright (c) 2019, Vox Media, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +- Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +- Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +- Neither the name of the {organization} nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. From afb1365d6df84c08db7c7321564e01c1d2258992 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Tue, 26 Feb 2019 09:57:44 -0600 Subject: [PATCH 2/8] remove template variables --- LICENSE | 2 +- package.json | 2 +- src/lib/vast_elements/README.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/LICENSE b/LICENSE index b644be1..f163d3f 100644 --- a/LICENSE +++ b/LICENSE @@ -11,7 +11,7 @@ modification, are permitted provided that the following conditions are met: this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. -* Neither the name of the {organization} nor the names of its +* Neither the name of the Vox Media nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. diff --git a/package.json b/package.json index 877b759..36944e9 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "description": "Simple Vast Parsing for Concert Video Ads", "main": "index.js", "author": "Vox Media", - "license": "MIT", + "license": "BSD 3-Clause \"New\" or \"Revised\" License", "private": false, "scripts": { "test": "jest", diff --git a/src/lib/vast_elements/README.md b/src/lib/vast_elements/README.md index 4c07d90..21bb926 100644 --- a/src/lib/vast_elements/README.md +++ b/src/lib/vast_elements/README.md @@ -46,7 +46,7 @@ modification, are permitted provided that the following conditions are met: this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. -- Neither the name of the {organization} nor the names of its +- Neither the name of the Vox Media nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. From 01b4b4d85dc9506de3bb5c4a356fff9840fa0f84 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Tue, 26 Feb 2019 10:57:37 -0600 Subject: [PATCH 3/8] updates to use the apache 2 license, per legal --- LICENSE | 34 +++++++++------------------- src/lib/vast_elements/README.md | 40 +++++++++++---------------------- 2 files changed, 23 insertions(+), 51 deletions(-) diff --git a/LICENSE b/LICENSE index f163d3f..d743c8c 100644 --- a/LICENSE +++ b/LICENSE @@ -1,27 +1,13 @@ -Copyright (c) 2019, Vox Media, Inc. -All rights reserved. +Copyright 2019 Vox Media -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. + http://www.apache.org/licenses/LICENSE-2.0 -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -* Neither the name of the Vox Media nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/src/lib/vast_elements/README.md b/src/lib/vast_elements/README.md index 21bb926..a745e00 100644 --- a/src/lib/vast_elements/README.md +++ b/src/lib/vast_elements/README.md @@ -33,30 +33,16 @@ There are three major methods that the extending class must support ### License -Copyright (c) 2019, Vox Media, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -- Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -- Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -- Neither the name of the Vox Media nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +Copyright 2019 Vox Media + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. From 20c82e9cb39924d9978e8434e34ccde1c22279d3 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Tue, 26 Feb 2019 11:07:34 -0600 Subject: [PATCH 4/8] using the right readme --- README.md | 53 +++++++++++++++++++++------------ src/lib/vast_elements/README.md | 16 ---------- 2 files changed, 34 insertions(+), 35 deletions(-) diff --git a/README.md b/README.md index 69b515f..245848c 100644 --- a/README.md +++ b/README.md @@ -11,18 +11,18 @@ The Vast Libary offers high and low level interacition with the Vast format. The ``` It's also possible you don't want the preroll behavior, and you can use: ```js -vast.applyToVideoElement(videoElement) +vast.applyToVideoElement(videoElement); ``` #### Doing it on your own @@ -31,10 +31,10 @@ Here is a sample of the public API that is exposed in the ConcertVast Library _( ```js // Find the video element on the page -const videoElement = document.querySelector('video') +const videoElement = document.querySelector('video'); // Instantiate a new ConcertVast object -const cv = new ConcertVast() +const cv = new ConcertVast(); // Load the VAST URL, this is async so you can use // await or .then() to delay execution until the vast @@ -43,7 +43,7 @@ const cv = new ConcertVast() // Optionally a timeout parameter (in ms) can be passed in to specify // how long to wait for a vast response try { - await cv.loadRemoteVast(url, { timeout: 10000 }) + await cv.loadRemoteVast(url, { timeout: 10000 }); } catch (error) { // if this raises an error, it is for the following reasons: // - there was a network error (VastNetworkError) @@ -58,22 +58,22 @@ try { const bestVastVideo = cv.bestVideo({ height: videoElement.clientHeight, width: videoElement.clientWidth, -}) +}); // When using vanilla video element Array.from(videoElement.querySelectorAll('source')).forEach(s => { - s.remove() -}) -const vidSource = document.createElement('source') -vidSource.setAttribute('src', bestVastVideo.url()) -vidSource.setAttribute('type', bestVastVideo.mimeType()) -videoElement.appendChild(vidSource) + s.remove(); +}); +const vidSource = document.createElement('source'); +vidSource.setAttribute('src', bestVastVideo.url()); +vidSource.setAttribute('type', bestVastVideo.mimeType()); +videoElement.appendChild(vidSource); // Need to call load if you change the video source -videoElement.load() +videoElement.load(); // Or if using videojs -const player = videoJs(videoElement) -player.src([{ type: bestVastVideo.mimeType(), src: bestVastVideo.url() }]) +const player = videoJs(videoElement); +player.src([{ type: bestVastVideo.mimeType(), src: bestVastVideo.url() }]); ``` ### Documented Functionality @@ -104,5 +104,20 @@ player.src([{ type: bestVastVideo.mimeType(), src: bestVastVideo.url() }]) ### Important details: - es6 -- no semicolons _(come at me)_ - Strict BDD via [Jest](https://jestjs.io/) + +### License + +Copyright 2019 Vox Media + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/src/lib/vast_elements/README.md b/src/lib/vast_elements/README.md index a745e00..d42f7d8 100644 --- a/src/lib/vast_elements/README.md +++ b/src/lib/vast_elements/README.md @@ -30,19 +30,3 @@ There are three major methods that the extending class must support 1. `setup()` – this will be called once your element class is loaded, use it like a constructor. 1. `onVastReady()` – The vast file has been onVastReady and your selector has been run, you can find your elements loaded in `this.elements` - -### License - -Copyright 2019 Vox Media - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. From b7ab95ba95882ab201be4c8c839b223ed80e9b35 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Tue, 26 Feb 2019 11:09:26 -0600 Subject: [PATCH 5/8] updates to apache 2.0 license per legal --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 36944e9..401dcf6 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "description": "Simple Vast Parsing for Concert Video Ads", "main": "index.js", "author": "Vox Media", - "license": "BSD 3-Clause \"New\" or \"Revised\" License", + "license": "Apache-2.0", "private": false, "scripts": { "test": "jest", From 5e9eccf7e9b6bc03f4f3adf31477499c4f17e55c Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Tue, 26 Feb 2019 11:09:52 -0600 Subject: [PATCH 6/8] adds semicolons to all the things --- .prettierrc | 2 +- src/index.js | 4 +- src/lib/applications/video_element.js | 158 ++++++++++---------- src/lib/quartile_support.js | 36 ++--- src/lib/stream_chooser.js | 61 ++++---- src/lib/supported_formats.js | 16 +- src/lib/vast.js | 126 ++++++++-------- src/lib/vast_elements/clickthrough.js | 16 +- src/lib/vast_elements/error_impression.js | 6 +- src/lib/vast_elements/impression.js | 16 +- src/lib/vast_elements/media_files.js | 54 +++---- src/lib/vast_elements/tracking_events.js | 16 +- src/lib/vast_elements/vast_element_base.js | 32 ++-- test/apply_to_video_element.spec.js | 10 +- test/quartile_support.spec.js | 112 +++++++------- test/stream_chooser.spec.js | 90 +++++------ test/supported_formats.spec.js | 16 +- test/vast.spec.js | 150 +++++++++---------- test/vast_elements/clickthrough.spec.js | 44 +++--- test/vast_elements/error_impression.spec.js | 30 ++-- test/vast_elements/impression.spec.js | 50 +++---- test/vast_elements/media_files.spec.js | 100 ++++++------- test/vast_elements/tracking_events.spec.js | 56 +++---- 23 files changed, 593 insertions(+), 608 deletions(-) diff --git a/.prettierrc b/.prettierrc index 23b8710..fc56e31 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,7 +1,7 @@ { "trailingComma": "es5", "tabWidth": 2, - "semi": false, + "semi": true, "singleQuote": true, "printWidth": 120 } diff --git a/src/index.js b/src/index.js index d6a2299..864127d 100644 --- a/src/index.js +++ b/src/index.js @@ -1,3 +1,3 @@ -import Vast from './lib/vast' +import Vast from './lib/vast'; -export default Vast +export default Vast; diff --git a/src/lib/applications/video_element.js b/src/lib/applications/video_element.js index faa25f0..ebb8595 100644 --- a/src/lib/applications/video_element.js +++ b/src/lib/applications/video_element.js @@ -1,179 +1,179 @@ -import QuartileSupport from '../quartile_support' +import QuartileSupport from '../quartile_support'; const EVENT_MAPPING = { muted: 'mute', pause: 'pause', -} +}; -const VIDEO_CONTROLS_HEIGHT = 50 -const VAST_LOADED_CLASS = 'vast-running' -const VAST_PLAYING_CLASS = 'vast-playing' -const VAST_DELAYED_ATTRIBUTE = 'vast-delayed-src' +const VIDEO_CONTROLS_HEIGHT = 50; +const VAST_LOADED_CLASS = 'vast-running'; +const VAST_PLAYING_CLASS = 'vast-playing'; +const VAST_DELAYED_ATTRIBUTE = 'vast-delayed-src'; export default class VideoElement { constructor({ vast, videoElement }) { - this.vast = vast - this.videoElement = videoElement - this.previousVolume = this.videoElement.volume - this.quartileSupport = new QuartileSupport() - this._vastPresented = null - this.restoreVideoPlayer = false + this.vast = vast; + this.videoElement = videoElement; + this.previousVolume = this.videoElement.volume; + this.quartileSupport = new QuartileSupport(); + this._vastPresented = null; + this.restoreVideoPlayer = false; } applyAsPreroll() { - this._vastPresented = true - this.restoreVideoPlayer = true + this._vastPresented = true; + this.restoreVideoPlayer = true; - this.addClassToVideo() - this.pauseExistingVideoSources() - this.setupQuartileSupport() - this.setupVideoEventListeners() - this.setupImpressions() - this.loadVastVideo() - this.playVideo() + this.addClassToVideo(); + this.pauseExistingVideoSources(); + this.setupQuartileSupport(); + this.setupVideoEventListeners(); + this.setupImpressions(); + this.loadVastVideo(); + this.playVideo(); } applyAsPrimary() { - this.applyAsPreroll() - this.restoreVideoPlayer = false + this.applyAsPreroll(); + this.restoreVideoPlayer = false; } // private pauseExistingVideoSources() { Array.from(this.videoElement.querySelectorAll('source')).forEach(n => { - n.setAttribute(VAST_DELAYED_ATTRIBUTE, n.getAttribute('src')) - n.setAttribute('src', null) - }) + n.setAttribute(VAST_DELAYED_ATTRIBUTE, n.getAttribute('src')); + n.setAttribute('src', null); + }); } setupVideoEventListeners() { // handle mute support - this.videoElement.addEventListener('volumechange', this.muteObserver.bind(this)) + this.videoElement.addEventListener('volumechange', this.muteObserver.bind(this)); for (const nativeEventName in EVENT_MAPPING) { this.videoElement.addEventListener(nativeEventName, () => { - if (!this.vastPresented()) return - this.vast.addImpressionTrackingImagesFor(EVENT_MAPPING[nativeEventName]) - }) + if (!this.vastPresented()) return; + this.vast.addImpressionTrackingImagesFor(EVENT_MAPPING[nativeEventName]); + }); } this.videoElement.addEventListener('timeupdate', () => { - if (!this.vastPresented()) return - this.quartileSupport.setCurrentTime(this.videoElement.currentTime) - }) + if (!this.vastPresented()) return; + this.quartileSupport.setCurrentTime(this.videoElement.currentTime); + }); this.videoElement.addEventListener('play', () => { - if (!this.vastPresented()) return - this.videoElement.classList.add(VAST_PLAYING_CLASS) - }) + if (!this.vastPresented()) return; + this.videoElement.classList.add(VAST_PLAYING_CLASS); + }); - this.videoElement.addEventListener('ended', this.vastVideoEndedObserver.bind(this)) + this.videoElement.addEventListener('ended', this.vastVideoEndedObserver.bind(this)); - this.videoElement.addEventListener('click', this.clickObserver.bind(this)) - this.videoElement.addEventListener('loadedmetadata', this.updateQuartileDuration.bind(this)) - this.videoElement.addEventListener('durationchange', this.updateQuartileDuration.bind(this)) - document.addEventListener('fullscreenchange', this.fullscreenObserver.bind(this)) - document.addEventListener('webkitfullscreenchange', this.fullscreenObserver.bind(this)) + this.videoElement.addEventListener('click', this.clickObserver.bind(this)); + this.videoElement.addEventListener('loadedmetadata', this.updateQuartileDuration.bind(this)); + this.videoElement.addEventListener('durationchange', this.updateQuartileDuration.bind(this)); + document.addEventListener('fullscreenchange', this.fullscreenObserver.bind(this)); + document.addEventListener('webkitfullscreenchange', this.fullscreenObserver.bind(this)); } loadVastVideo() { const bestVideo = this.vast.bestVideo({ height: this.videoElement.clientHeight, width: this.videoElement.clientWidth, - }) - const videoSource = document.createElement('source') + }); + const videoSource = document.createElement('source'); - videoSource.setAttribute('src', bestVideo.url()) - videoSource.setAttribute('vast-added', true) - videoSource.setAttribute('type', bestVideo.mimeType()) - this.videoElement.appendChild(videoSource) - this.videoElement.load() + videoSource.setAttribute('src', bestVideo.url()); + videoSource.setAttribute('vast-added', true); + videoSource.setAttribute('type', bestVideo.mimeType()); + this.videoElement.appendChild(videoSource); + this.videoElement.load(); } updateQuartileDuration() { - this.quartileSupport.setDuration(this.videoElement.duration) + this.quartileSupport.setDuration(this.videoElement.duration); } addClassToVideo() { - this.videoElement.classList.add(VAST_LOADED_CLASS) + this.videoElement.classList.add(VAST_LOADED_CLASS); } setupImpressions() { - this.vast.addImpressionUrls() + this.vast.addImpressionUrls(); } vastVideoEndedObserver() { - if (!this.vastPresented()) return - this.videoElement.classList.remove(VAST_PLAYING_CLASS) + if (!this.vastPresented()) return; + this.videoElement.classList.remove(VAST_PLAYING_CLASS); - if (!this.restoreVideoPlayer) return - this.videoElement.classList.remove(VAST_LOADED_CLASS) + if (!this.restoreVideoPlayer) return; + this.videoElement.classList.remove(VAST_LOADED_CLASS); - this._vastPresented = false + this._vastPresented = false; Array.from(this.videoElement.querySelectorAll('source[vast-added="true"]')).forEach(n => { - n.remove() - }) + n.remove(); + }); Array.from(this.videoElement.querySelectorAll('source')).forEach(n => { - n.setAttribute('src', n.getAttribute(VAST_DELAYED_ATTRIBUTE)) + n.setAttribute('src', n.getAttribute(VAST_DELAYED_ATTRIBUTE)); if (n.removeAttribute) { - n.removeAttribute(VAST_DELAYED_ATTRIBUTE) + n.removeAttribute(VAST_DELAYED_ATTRIBUTE); } - }) + }); - this.videoElement.load() + this.videoElement.load(); } muteObserver() { - if (!this.vastPresented()) return + if (!this.vastPresented()) return; if (this.previousVolume <= 0 && this.videoElement.volume != 0) { - this.vast.addImpressionTrackingImagesFor('unmute') + this.vast.addImpressionTrackingImagesFor('unmute'); } else if ((this.previousVolume > 0 && this.videoElement.volume == 0) || this.videoElement.muted) { - this.vast.addImpressionTrackingImagesFor('mute') + this.vast.addImpressionTrackingImagesFor('mute'); } - this.previousVolume = this.videoElement.muted ? -1 : this.videoElement.volume + this.previousVolume = this.videoElement.muted ? -1 : this.videoElement.volume; } playVideo() { this.videoElement.addEventListener('canplay', () => { - this.videoElement.play() - }) + this.videoElement.play(); + }); } clickObserver(clickEvent) { - if (!this.vastPresented()) return + if (!this.vastPresented()) return; if (clickEvent.target) { - const height = clickEvent.target.clientHeight + const height = clickEvent.target.clientHeight; if (clickEvent.offsetY <= height - 50 && this.isBeyondFirstFrame()) { - this.vast.openClickthroughUrl() + this.vast.openClickthroughUrl(); } } } fullscreenObserver(fullscreenEvent) { - if (!this.vastPresented()) return + if (!this.vastPresented()) return; if (document.fullscreenElement || document.webkitIsFullScreen) { - this.vast.addImpressionTrackingImagesFor('fullscreen') + this.vast.addImpressionTrackingImagesFor('fullscreen'); } } setupQuartileSupport() { this.quartileSupport.onQuartileChange(quartile => { - if (!this.vastPresented()) return - this.vast.addImpressionTrackingImagesFor(quartile) - }) + if (!this.vastPresented()) return; + this.vast.addImpressionTrackingImagesFor(quartile); + }); } isBeyondFirstFrame() { - return this.videoElement.currentTime > 0 + return this.videoElement.currentTime > 0; } vastPresented() { - return this._vastPresented + return this._vastPresented; } } diff --git a/src/lib/quartile_support.js b/src/lib/quartile_support.js index 872fd0c..401d1e7 100644 --- a/src/lib/quartile_support.js +++ b/src/lib/quartile_support.js @@ -4,50 +4,50 @@ const QUARTILES = [ [0.5, 'midpoint'], [0.75, 'thirdQuartile'], [0.99, 'complete'], -] +]; export default class QuartileSupport { constructor() { - this.seenQuartiles = [] - this.callbacks = [] - this.currentTime = 0 - this.duration = Infinity + this.seenQuartiles = []; + this.callbacks = []; + this.currentTime = 0; + this.duration = Infinity; } setDuration(time) { if (time != 0) { - this.duration = time + this.duration = time; } - this.checkForQuartileEvent() + this.checkForQuartileEvent(); } onQuartileChange(func) { - this.callbacks.push(func) + this.callbacks.push(func); } setCurrentTime(currentTime) { - this.currentTime = currentTime - this.checkForQuartileEvent() + this.currentTime = currentTime; + this.checkForQuartileEvent(); } // private checkForQuartileEvent() { - const percentComplete = this.currentTime / this.duration + const percentComplete = this.currentTime / this.duration; const matchingQuartiles = QUARTILES.filter(quartile => { - return quartile[0] < percentComplete - }) + return quartile[0] < percentComplete; + }); matchingQuartiles.forEach(quartile => { - const [percent, name] = quartile + const [percent, name] = quartile; if (!this.seenQuartiles.includes(percent)) { - this.seenQuartiles.push(percent) - this.quartileChangeCallback(name) + this.seenQuartiles.push(percent); + this.quartileChangeCallback(name); } - }) + }); } quartileChangeCallback(quartileName) { - this.callbacks.forEach(fn => fn.call(null, quartileName)) + this.callbacks.forEach(fn => fn.call(null, quartileName)); } } diff --git a/src/lib/stream_chooser.js b/src/lib/stream_chooser.js index bcc1cfe..0d151d2 100644 --- a/src/lib/stream_chooser.js +++ b/src/lib/stream_chooser.js @@ -1,43 +1,41 @@ -import { supportedMimeTypes } from './supported_formats' +import { supportedMimeTypes } from './supported_formats'; export default class StreamChooser { constructor() { - this.videos = null - this.playerWidth = 0 - this.playerHeight = 0 - this.supportedMimeTypes = supportedMimeTypes() - this.bandwidthInKbs = 0 + this.videos = null; + this.playerWidth = 0; + this.playerHeight = 0; + this.supportedMimeTypes = supportedMimeTypes(); + this.bandwidthInKbs = 0; } useVideosFromMediaFile(mediaFiles) { - this.videos = mediaFiles + this.videos = mediaFiles; } setPlayerDimensions({ height, width }) { - this.playerHeight = height - this.playerWidth = width + this.playerHeight = height; + this.playerWidth = width; } setSupportedMimeTypes(types) { - this.supportedMimeTypes = types + this.supportedMimeTypes = types; } setBandwidth(bandwidthInKbs) { - this.bandwidthInKbs = bandwidthInKbs + this.bandwidthInKbs = bandwidthInKbs; } bestVideo() { - const matchingFormats = this.videos.filter(v => this.compatibleFormats(v)) - const closestSize = matchingFormats.sort((a, b) => this.closestSized(a, b)) - const notExceedingBandwidth = closestSize.filter(v => - this.underBandwidth(v) - ) + const matchingFormats = this.videos.filter(v => this.compatibleFormats(v)); + const closestSize = matchingFormats.sort((a, b) => this.closestSized(a, b)); + const notExceedingBandwidth = closestSize.filter(v => this.underBandwidth(v)); - if (matchingFormats.length <= 1) return matchingFormats[0] - if (closestSize.length <= 1) return closestSize[0] - if (notExceedingBandwidth.length == 0) return closestSize[0] + if (matchingFormats.length <= 1) return matchingFormats[0]; + if (closestSize.length <= 1) return closestSize[0]; + if (notExceedingBandwidth.length == 0) return closestSize[0]; - return notExceedingBandwidth[0] + return notExceedingBandwidth[0]; } /** @@ -46,7 +44,7 @@ export default class StreamChooser { * @param {MediaElement} video */ compatibleFormats(video) { - return this.supportedMimeTypes.indexOf(video.mimeType()) != -1 + return this.supportedMimeTypes.indexOf(video.mimeType()) != -1; } /** @@ -57,16 +55,12 @@ export default class StreamChooser { * @param {MediaElement} b the second video in the sort params */ closestSized(a, b) { - const aWProximity = - Math.abs(this.playerWidth - a.width()) / this.playerWidth - const bWProximity = - Math.abs(this.playerWidth - b.width()) / this.playerWidth - const aHProximity = - Math.abs(this.playerHeight - a.height()) / this.playerHeight - const bHProximity = - Math.abs(this.playerHeight - b.height()) / this.playerHeight + const aWProximity = Math.abs(this.playerWidth - a.width()) / this.playerWidth; + const bWProximity = Math.abs(this.playerWidth - b.width()) / this.playerWidth; + const aHProximity = Math.abs(this.playerHeight - a.height()) / this.playerHeight; + const bHProximity = Math.abs(this.playerHeight - b.height()) / this.playerHeight; - return aWProximity * aHProximity - bWProximity * bHProximity + return aWProximity * aHProximity - bWProximity * bHProximity; } /** @@ -76,10 +70,7 @@ export default class StreamChooser { * @param {MediaElement} video */ underBandwidth(video) { - const OVERHEAD_FACTOR_FOR_BANDWIDTH_CALCULATION = 1.25 - return ( - video.bitrate() <= - this.bandwidthInKbs * OVERHEAD_FACTOR_FOR_BANDWIDTH_CALCULATION - ) + const OVERHEAD_FACTOR_FOR_BANDWIDTH_CALCULATION = 1.25; + return video.bitrate() <= this.bandwidthInKbs * OVERHEAD_FACTOR_FOR_BANDWIDTH_CALCULATION; } } diff --git a/src/lib/supported_formats.js b/src/lib/supported_formats.js index 7c9eae3..28714b5 100644 --- a/src/lib/supported_formats.js +++ b/src/lib/supported_formats.js @@ -4,23 +4,21 @@ const FORMATS = { webm: 'video/webm; codecs="vp8, vorbis"', vp9: 'video/webm; codecs="vp9"', hls: 'application/x-mpegURL; codecs="avc1.42E01E"', -} +}; export function supportedFormats({ doc } = { doc: document }) { - const v = doc.createElement('video') - let supported = {} + const v = doc.createElement('video'); + let supported = {}; for (const name in FORMATS) { if (v.canPlayType(FORMATS[name]) === 'probably') { - supported[name] = FORMATS[name] + supported[name] = FORMATS[name]; } } - return supported + return supported; } export function supportedMimeTypes({ doc } = { doc: document }) { - return Object.values(supportedFormats({ doc: doc })).map( - mimeTypeAndCode => mimeTypeAndCode.split(';')[0] - ) + return Object.values(supportedFormats({ doc: doc })).map(mimeTypeAndCode => mimeTypeAndCode.split(';')[0]); } -export default { supportedFormats, supportedMimeTypes } +export default { supportedFormats, supportedMimeTypes }; diff --git a/src/lib/vast.js b/src/lib/vast.js index 7153c08..0e004c1 100644 --- a/src/lib/vast.js +++ b/src/lib/vast.js @@ -1,20 +1,20 @@ -import MediaFiles from './vast_elements/media_files' -import Clickthrough from './vast_elements/clickthrough' -import Impression from './vast_elements/impression' -import ErrorImpression from './vast_elements/error_impression' -import TrackingEvents from './vast_elements/tracking_events' -import StreamChooser from './stream_chooser' -import VideoElementApplication from './applications/video_element' +import MediaFiles from './vast_elements/media_files'; +import Clickthrough from './vast_elements/clickthrough'; +import Impression from './vast_elements/impression'; +import ErrorImpression from './vast_elements/error_impression'; +import TrackingEvents from './vast_elements/tracking_events'; +import StreamChooser from './stream_chooser'; +import VideoElementApplication from './applications/video_element'; export class VastXMLParsingError extends Error {} export class VastNetworkError extends Error {} export default class Vast { constructor({ xml } = {}) { - this.vastXml = null - this.vastUrl = null - this.vastDocument = null - this.bandwidthEstimateInKbs = 0 + this.vastXml = null; + this.vastUrl = null; + this.vastDocument = null; + this.bandwidthEstimateInKbs = 0; this.loadedElements = { MediaFiles: new MediaFiles(this), @@ -22,71 +22,71 @@ export default class Vast { Impression: new Impression(this), ErrorImpression: new ErrorImpression(this), TrackingEvents: new TrackingEvents(this), - } + }; if (xml) { - this.useXmlString(xml) + this.useXmlString(xml); } } useXmlString(xml) { - this.vastXml = xml - this.vastDocument = null - this.parse() + this.vastXml = xml; + this.vastDocument = null; + this.parse(); } bandwidth() { - return this.bandwidthEstimateInKbs + return this.bandwidthEstimateInKbs; } videos() { - return this.loadedElements['MediaFiles'].videos() + return this.loadedElements['MediaFiles'].videos(); } asHLSUrl() { - return this.loadedElements['MediaFiles'].asHLSUrl() + return this.loadedElements['MediaFiles'].asHLSUrl(); } clickthroughUrl() { - return this.loadedElements['Clickthrough'].clickthroughUrl() + return this.loadedElements['Clickthrough'].clickthroughUrl(); } openClickthroughUrl() { - return this.loadedElements['Clickthrough'].openClickthroughUrl() + return this.loadedElements['Clickthrough'].openClickthroughUrl(); } impressionUrls() { - return this.loadedElements['Impression'].impressionUrls() + return this.loadedElements['Impression'].impressionUrls(); } addImpressionUrls(doc = document) { - return this.loadedElements['Impression'].addImpressionUrls(doc) + return this.loadedElements['Impression'].addImpressionUrls(doc); } errorImpressionUrls() { - return this.loadedElements['ErrorImpression'].impressionUrls() + return this.loadedElements['ErrorImpression'].impressionUrls(); } addErrorImpressionUrls(doc = document) { - return this.loadedElements['ErrorImpression'].addImpressionUrls(doc) + return this.loadedElements['ErrorImpression'].addImpressionUrls(doc); } trackingUrlsFor(eventName) { - return this.loadedElements['TrackingEvents'].trackingUrlsFor(eventName) + return this.loadedElements['TrackingEvents'].trackingUrlsFor(eventName); } addImpressionTrackingImagesFor(eventName, doc = document) { - return this.loadedElements['TrackingEvents'].addImpressionTrackingImagesFor(eventName, doc) + return this.loadedElements['TrackingEvents'].addImpressionTrackingImagesFor(eventName, doc); } applyToVideoElementAsPreroll(videoElement) { - const vea = new VideoElementApplication({ vast: this, videoElement: videoElement }) - vea.applyAsPreroll() + const vea = new VideoElementApplication({ vast: this, videoElement: videoElement }); + vea.applyAsPreroll(); } applyToVideoElement(videoElement) { - const vea = new VideoElementApplication({ vast: this, videoElement: videoElement }) - vea.applyAsPrimary() + const vea = new VideoElementApplication({ vast: this, videoElement: videoElement }); + vea.applyAsPrimary(); } bestVideo( @@ -97,62 +97,62 @@ export default class Vast { mimeTypes: null, } ) { - const chooser = new StreamChooser() - chooser.useVideosFromMediaFile(this.videos()) - chooser.setBandwidth(this.bandwidth()) + const chooser = new StreamChooser(); + chooser.useVideosFromMediaFile(this.videos()); + chooser.setBandwidth(this.bandwidth()); - if (bandwidth) chooser.setBandwidth(bandwidth) - if (mimeTypes) chooser.setSupportedMimeTypes(mimeTypes) + if (bandwidth) chooser.setBandwidth(bandwidth); + if (mimeTypes) chooser.setSupportedMimeTypes(mimeTypes); - chooser.setPlayerDimensions({ width: width, height: height }) - return chooser.bestVideo() + chooser.setPlayerDimensions({ width: width, height: height }); + return chooser.bestVideo(); } parse() { if (!this.vastDocument) { - const parser = new DOMParser() - this.vastDocument = parser.parseFromString(this.vastXml, 'application/xml') + const parser = new DOMParser(); + this.vastDocument = parser.parseFromString(this.vastXml, 'application/xml'); if (this.vastDocument.documentElement.nodeName == 'parsererror') { - throw new VastXMLParsingError(`Error parsing ${this.vastXml}. Not valid XML`) + throw new VastXMLParsingError(`Error parsing ${this.vastXml}. Not valid XML`); } - this.processAllElements() + this.processAllElements(); } } async loadRemoteVast(url, { timeout } = { timeout: 10000 }) { return new Promise((resolve, reject) => { - this.vastUrl = url - const request = new XMLHttpRequest() - request.timeout = timeout - let startTime + this.vastUrl = url; + const request = new XMLHttpRequest(); + request.timeout = timeout; + let startTime; request.addEventListener('load', e => { - const downloadTime = new Date().getTime() - startTime - const downloadSize = request.responseText.length - this.bandwidthEstimateInKbs = (downloadSize * 8) / (downloadTime / 1000) / 1024 + const downloadTime = new Date().getTime() - startTime; + const downloadSize = request.responseText.length; + this.bandwidthEstimateInKbs = (downloadSize * 8) / (downloadTime / 1000) / 1024; - this.useXmlString(request.response) - resolve() - }) + this.useXmlString(request.response); + resolve(); + }); request.addEventListener('error', e => { - reject(new VastNetworkError(`Network Error: Request status: ${request.status}, ${request.responseText}`)) - }) + reject(new VastNetworkError(`Network Error: Request status: ${request.status}, ${request.responseText}`)); + }); request.addEventListener('abort', e => { - reject(new VastNetworkError('Network Aborted')) - }) + reject(new VastNetworkError('Network Aborted')); + }); request.addEventListener('timeout', e => { - reject(new VastNetworkError(`Network Timeout: Request did not complete in ${timeout}ms`)) - }) - startTime = new Date().getTime() - request.open('GET', this.vastUrl) - request.send() - }) + reject(new VastNetworkError(`Network Timeout: Request did not complete in ${timeout}ms`)); + }); + startTime = new Date().getTime(); + request.open('GET', this.vastUrl); + request.send(); + }); } processAllElements() { - Object.values(this.loadedElements).forEach(e => e.process()) + Object.values(this.loadedElements).forEach(e => e.process()); } } diff --git a/src/lib/vast_elements/clickthrough.js b/src/lib/vast_elements/clickthrough.js index 7f07d46..79f4ab8 100644 --- a/src/lib/vast_elements/clickthrough.js +++ b/src/lib/vast_elements/clickthrough.js @@ -1,26 +1,26 @@ -import VastElementBase from './vast_element_base' +import VastElementBase from './vast_element_base'; export default class Clickthrough extends VastElementBase { setup() { - this.clickthrough = null + this.clickthrough = null; } static selector() { - return 'Creative VideoClicks ClickThrough' + return 'Creative VideoClicks ClickThrough'; } onVastReady() { this.clickthrough = this.elements.map(el => { - return el.childNodes[0].nodeValue - })[0] + return el.childNodes[0].nodeValue; + })[0]; } clickthroughUrl() { - return this.clickthrough + return this.clickthrough; } openClickthroughUrl() { - const win = window.open(this.clickthroughUrl(), '_blank') - win.focus() + const win = window.open(this.clickthroughUrl(), '_blank'); + win.focus(); } } diff --git a/src/lib/vast_elements/error_impression.js b/src/lib/vast_elements/error_impression.js index 63a2be2..b933291 100644 --- a/src/lib/vast_elements/error_impression.js +++ b/src/lib/vast_elements/error_impression.js @@ -1,11 +1,11 @@ -import Impression from './impression' +import Impression from './impression'; export default class ErrorImpression extends Impression { setup() { - this._impressionUrls = [] + this._impressionUrls = []; } static selector() { - return 'Ad Error' + return 'Ad Error'; } } diff --git a/src/lib/vast_elements/impression.js b/src/lib/vast_elements/impression.js index f38fed4..a2ef448 100644 --- a/src/lib/vast_elements/impression.js +++ b/src/lib/vast_elements/impression.js @@ -1,27 +1,27 @@ -import VastElementBase from './vast_element_base' +import VastElementBase from './vast_element_base'; export default class Impression extends VastElementBase { setup() { - this._impressionUrls = [] + this._impressionUrls = []; } static selector() { - return 'Ad Impression' + return 'Ad Impression'; } onVastReady() { this._impressionUrls = this.elements.map(el => { - return el.childNodes[0].nodeValue - }) + return el.childNodes[0].nodeValue; + }); } impressionUrls() { - return this._impressionUrls + return this._impressionUrls; } addImpressionUrls(doc = document) { this.impressionUrls().forEach(url => { - this.addImpressionUrl(url, { doc: doc }) - }) + this.addImpressionUrl(url, { doc: doc }); + }); } } diff --git a/src/lib/vast_elements/media_files.js b/src/lib/vast_elements/media_files.js index 802b4e3..40412cd 100644 --- a/src/lib/vast_elements/media_files.js +++ b/src/lib/vast_elements/media_files.js @@ -1,68 +1,68 @@ -import VastElementBase from './vast_element_base' +import VastElementBase from './vast_element_base'; class MediaFile { constructor(mediaElement) { - this.element = mediaElement + this.element = mediaElement; } bitrate() { - return parseInt(this.element.getAttribute('bitrate'), 10) + return parseInt(this.element.getAttribute('bitrate'), 10); } width() { - return parseInt(this.element.getAttribute('width'), 10) + return parseInt(this.element.getAttribute('width'), 10); } height() { - return parseInt(this.element.getAttribute('height'), 10) + return parseInt(this.element.getAttribute('height'), 10); } mimeType() { - return this.element.getAttribute('type') + return this.element.getAttribute('type'); } url() { - return this.element.childNodes[0].nodeValue + return this.element.childNodes[0].nodeValue; } codec() { switch (this.mimeType()) { case 'video/mp4': case 'video/3gpp': - return 'mp4v' - break + return 'mp4v'; + break; case 'video/webm': - return 'vp8' - break + return 'vp8'; + break; default: - throw TypeError('Unknown mime type ' + this.mimeType()) + throw TypeError('Unknown mime type ' + this.mimeType()); } } isVideoType() { - return this.mimeType().match(/^video\//) + return this.mimeType().match(/^video\//); } } // class HlsMasterPlaylistFile { constructor(videos = []) { - this.videos = videos + this.videos = videos; } contents() { - let contents = [] - contents.push('#EXTM3U') + let contents = []; + contents.push('#EXTM3U'); contents = [ contents, ...this.videos.map(v => { return `#EXT-X-STREAM-INF:BANDWIDTH=${v.bitrate() * - 1024},RESOLUTION=${v.width()}x${v.height()},CODEC=${v.codec()}\n${v.url()}` + 1024},RESOLUTION=${v.width()}x${v.height()},CODEC=${v.codec()}\n${v.url()}`; }), - ] + ]; - return contents.join('\n') + return contents.join('\n'); } // ---- } @@ -70,31 +70,31 @@ class HlsMasterPlaylistFile { export default class MediaFiles extends VastElementBase { // Think of this as the constructor setup() { - this.mediaFiles = [] + this.mediaFiles = []; } // Selector to consume elements static selector() { - return 'Creative MediaFiles MediaFile' + return 'Creative MediaFiles MediaFile'; } // Elements available onVastReady() { this.mediaFiles = this.elements.map(el => { - return new MediaFile(el) - }) + return new MediaFile(el); + }); } // Private stuff --- videos() { return this.mediaFiles.filter(v => { - return v.isVideoType() - }) + return v.isVideoType(); + }); } asHLSUrl() { - const hlsMaker = new HlsMasterPlaylistFile(this.videos()) - return 'data:application/x-mpegURL;base64,' + btoa(hlsMaker.contents()) + const hlsMaker = new HlsMasterPlaylistFile(this.videos()); + return 'data:application/x-mpegURL;base64,' + btoa(hlsMaker.contents()); } } diff --git a/src/lib/vast_elements/tracking_events.js b/src/lib/vast_elements/tracking_events.js index c82fb01..84cbaa8 100644 --- a/src/lib/vast_elements/tracking_events.js +++ b/src/lib/vast_elements/tracking_events.js @@ -1,27 +1,27 @@ -import VastElementBase from './vast_element_base' +import VastElementBase from './vast_element_base'; export default class TrackingEvents extends VastElementBase { setup() { - this.trackingUrls = [] + this.trackingUrls = []; } static selector() { - return 'Ad TrackingEvents Tracking' + return 'Ad TrackingEvents Tracking'; } onVastReady() { this.trackingUrls = this.elements.map(el => { - return [el.getAttribute('event'), el.childNodes[0].nodeValue] - }) + return [el.getAttribute('event'), el.childNodes[0].nodeValue]; + }); } trackingUrlsFor(eventName) { - return this.trackingUrls.filter(t => t[0] == eventName).map(t => t[1]) + return this.trackingUrls.filter(t => t[0] == eventName).map(t => t[1]); } addImpressionTrackingImagesFor(eventName, doc = document) { this.trackingUrlsFor(eventName).forEach(url => { - this.addImpressionUrl(url, { doc: doc }) - }) + this.addImpressionUrl(url, { doc: doc }); + }); } } diff --git a/src/lib/vast_elements/vast_element_base.js b/src/lib/vast_elements/vast_element_base.js index ffed460..7566a2b 100644 --- a/src/lib/vast_elements/vast_element_base.js +++ b/src/lib/vast_elements/vast_element_base.js @@ -1,8 +1,8 @@ export default class VastElementBase { constructor(vastBase) { - this.vast = vastBase - this.setup() - this.elements = [] + this.vast = vastBase; + this.setup(); + this.elements = []; } // Selector to determine applicable vast elements @@ -16,24 +16,22 @@ export default class VastElementBase { // ---- process() { - if (!this.vast.vastDocument) return + if (!this.vast.vastDocument) return; - const selector = this.constructor.selector() + const selector = this.constructor.selector(); - this.elements = Array.from( - this.vast.vastDocument.querySelectorAll(selector) - ) - this.onVastReady() + this.elements = Array.from(this.vast.vastDocument.querySelectorAll(selector)); + this.onVastReady(); } addImpressionUrl(url, { doc } = { doc: document }) { - const impressionImage = doc.createElement('img') - impressionImage.style.height = 1 - impressionImage.style.width = 1 - impressionImage.style.top = 0 - impressionImage.style.left = 0 - impressionImage.style.visibility = 'hidden' - impressionImage.src = url - doc.body.appendChild(impressionImage) + const impressionImage = doc.createElement('img'); + impressionImage.style.height = 1; + impressionImage.style.width = 1; + impressionImage.style.top = 0; + impressionImage.style.left = 0; + impressionImage.style.visibility = 'hidden'; + impressionImage.src = url; + doc.body.appendChild(impressionImage); } } diff --git a/test/apply_to_video_element.spec.js b/test/apply_to_video_element.spec.js index bea5624..3d89a34 100644 --- a/test/apply_to_video_element.spec.js +++ b/test/apply_to_video_element.spec.js @@ -1,10 +1,10 @@ -import Vast from '../src/lib/vast' -import VideoElement from '../src/lib/applications/video_element' +import Vast from '../src/lib/vast'; +import VideoElement from '../src/lib/applications/video_element'; describe('Apply to Video Element functionality', () => { it('should be able to accept a video element', () => { - expect(typeof VideoElement).toBe('function') - }) + expect(typeof VideoElement).toBe('function'); + }); // it('should all just work', () => { // const vast = new Vast() @@ -14,4 +14,4 @@ describe('Apply to Video Element functionality', () => { // applier.useVast(vast) // applier.apply() // }) -}) +}); diff --git a/test/quartile_support.spec.js b/test/quartile_support.spec.js index 7400c08..4ee1240 100644 --- a/test/quartile_support.spec.js +++ b/test/quartile_support.spec.js @@ -1,85 +1,85 @@ -import QuartileSupport from '../src/lib/quartile_support' +import QuartileSupport from '../src/lib/quartile_support'; describe('Basic Quartile Functionality', () => { it('it has a setDuration function', () => { - const qs = new QuartileSupport() - expect(typeof qs.setDuration).toBe('function') - qs.setDuration(10) - }) + const qs = new QuartileSupport(); + expect(typeof qs.setDuration).toBe('function'); + qs.setDuration(10); + }); it('it has a callback onQuartileChange function', () => { - const qs = new QuartileSupport() - expect(typeof qs.onQuartileChange).toBe('function') - }) + const qs = new QuartileSupport(); + expect(typeof qs.onQuartileChange).toBe('function'); + }); it('it has a setCurrentTime function', () => { - const qs = new QuartileSupport() - expect(typeof qs.setCurrentTime).toBe('function') - }) -}) + const qs = new QuartileSupport(); + expect(typeof qs.setCurrentTime).toBe('function'); + }); +}); describe('Callbacks for changes', () => { - let qs + let qs; beforeEach(() => { - qs = new QuartileSupport() - }) + qs = new QuartileSupport(); + }); it('should not set start on 0s', () => { - let lastQName = null + let lastQName = null; qs.onQuartileChange(quartileName => { - lastQName = quartileName - }) - qs.setDuration(10) - qs.setCurrentTime(0) - expect(lastQName).toEqual(null) - }) + lastQName = quartileName; + }); + qs.setDuration(10); + qs.setCurrentTime(0); + expect(lastQName).toEqual(null); + }); it('should set start on 0.01s', () => { - let lastQName = null + let lastQName = null; qs.onQuartileChange(quartileName => { - lastQName = quartileName - }) - qs.setDuration(100) - qs.setCurrentTime(0.01) - expect(lastQName).toEqual('start') - }) + lastQName = quartileName; + }); + qs.setDuration(100); + qs.setCurrentTime(0.01); + expect(lastQName).toEqual('start'); + }); it('should call a callback after 26 percent complete', () => { - let lastQName = null + let lastQName = null; qs.onQuartileChange(quartileName => { - lastQName = quartileName - }) + lastQName = quartileName; + }); - qs.setDuration(10) - qs.setCurrentTime(4) - expect(lastQName).toBe('firstQuartile') - }) + qs.setDuration(10); + qs.setCurrentTime(4); + expect(lastQName).toBe('firstQuartile'); + }); it('should call all quartiles if moved forward', () => { - let lastQName = null - let calls = 0 + let lastQName = null; + let calls = 0; qs.onQuartileChange(quartileName => { - calls++ - lastQName = quartileName - }) + calls++; + lastQName = quartileName; + }); - qs.setDuration(10) - qs.setCurrentTime(10) - expect(lastQName).toBe('complete') - expect(calls).toBe(5) - }) + qs.setDuration(10); + qs.setCurrentTime(10); + expect(lastQName).toBe('complete'); + expect(calls).toBe(5); + }); it('should handle callbacks if duration changes', () => { - let lastQName = null + let lastQName = null; qs.onQuartileChange(quartileName => { - lastQName = quartileName - }) + lastQName = quartileName; + }); - qs.setDuration(100) - qs.setCurrentTime(4) - expect(lastQName).toBe('start') + qs.setDuration(100); + qs.setCurrentTime(4); + expect(lastQName).toBe('start'); - qs.setDuration(4) - expect(lastQName).toBe('complete') - }) -}) + qs.setDuration(4); + expect(lastQName).toBe('complete'); + }); +}); diff --git a/test/stream_chooser.spec.js b/test/stream_chooser.spec.js index a41985a..66b755a 100644 --- a/test/stream_chooser.spec.js +++ b/test/stream_chooser.spec.js @@ -1,61 +1,61 @@ -import Vast from '../src/lib/vast' -import StreamChooser from '../src/lib/stream_chooser' -import * as fs from 'fs' +import Vast from '../src/lib/vast'; +import StreamChooser from '../src/lib/stream_chooser'; +import * as fs from 'fs'; describe('basic interface for StreamChooser', () => { it('can be instantianted', () => { - const sc = new StreamChooser() - }) + const sc = new StreamChooser(); + }); it('can will consume videos from Vast.videos object', () => { - const sc = new StreamChooser() - const vast = new Vast() - expect(typeof sc.useVideosFromMediaFile).toBe('function') - sc.useVideosFromMediaFile(vast.videos()) - }) + const sc = new StreamChooser(); + const vast = new Vast(); + expect(typeof sc.useVideosFromMediaFile).toBe('function'); + sc.useVideosFromMediaFile(vast.videos()); + }); it('it can accept player dimensions', () => { - const sc = new StreamChooser() - sc.setPlayerDimensions({ height: 100, width: 150 }) - }) -}) + const sc = new StreamChooser(); + sc.setPlayerDimensions({ height: 100, width: 150 }); + }); +}); describe('descision logic for StreamChooser', () => { - let sc - let vast + let sc; + let vast; beforeEach(() => { - vast = new Vast({ xml: fs.readFileSync('./test/fixtures/vast.xml') }) - sc = new StreamChooser() - }) + vast = new Vast({ xml: fs.readFileSync('./test/fixtures/vast.xml') }); + sc = new StreamChooser(); + }); it('will return the choosen format', () => { - expect(typeof sc.bestVideo).toBe('function') - }) + expect(typeof sc.bestVideo).toBe('function'); + }); it('will choose the right format for supported formats', () => { - sc.setSupportedMimeTypes(['video/mp4']) - sc.useVideosFromMediaFile(vast.videos()) - sc.setBandwidth(1500) - sc.setPlayerDimensions({ width: 1200, height: 720 }) - const vid = sc.bestVideo() - expect(vid).not.toBe(null) - expect(vid.constructor.name).toBe('MediaFile') - expect(vid.mimeType()).toBe('video/mp4') - expect(vid.width()).toBe(1280) - expect(vid.height()).toBe(720) - }) + sc.setSupportedMimeTypes(['video/mp4']); + sc.useVideosFromMediaFile(vast.videos()); + sc.setBandwidth(1500); + sc.setPlayerDimensions({ width: 1200, height: 720 }); + const vid = sc.bestVideo(); + expect(vid).not.toBe(null); + expect(vid.constructor.name).toBe('MediaFile'); + expect(vid.mimeType()).toBe('video/mp4'); + expect(vid.width()).toBe(1280); + expect(vid.height()).toBe(720); + }); it('will choose the right format for smaller screens', () => { - sc.setSupportedMimeTypes(['video/mp4']) - sc.useVideosFromMediaFile(vast.videos()) - sc.setBandwidth(600) - sc.setPlayerDimensions({ width: 500, height: 300 }) - const vid = sc.bestVideo() - expect(vid).not.toBe(null) - expect(vid.constructor.name).toBe('MediaFile') - expect(vid.mimeType()).toBe('video/mp4') - expect(vid.width()).toBe(480) - expect(vid.height()).toBe(270) - expect(vid.bitrate()).toBe(385) - }) -}) + sc.setSupportedMimeTypes(['video/mp4']); + sc.useVideosFromMediaFile(vast.videos()); + sc.setBandwidth(600); + sc.setPlayerDimensions({ width: 500, height: 300 }); + const vid = sc.bestVideo(); + expect(vid).not.toBe(null); + expect(vid.constructor.name).toBe('MediaFile'); + expect(vid.mimeType()).toBe('video/mp4'); + expect(vid.width()).toBe(480); + expect(vid.height()).toBe(270); + expect(vid.bitrate()).toBe(385); + }); +}); diff --git a/test/supported_formats.spec.js b/test/supported_formats.spec.js index 015c5d9..8ee4bfa 100644 --- a/test/supported_formats.spec.js +++ b/test/supported_formats.spec.js @@ -1,4 +1,4 @@ -import { supportedFormats } from '../src/lib/supported_formats' +import { supportedFormats } from '../src/lib/supported_formats'; describe('Supported format detection', () => { it('should return a bunch of formats', () => { @@ -9,15 +9,15 @@ describe('Supported format detection', () => { return { canPlayType: mime => { if (mime.match(/mp4/)) { - return 'probably' + return 'probably'; } }, - } + }; } }), - } + }; - const f = supportedFormats({ doc: fakeDoc }) - expect(Object.keys(f).length).toBe(1) - }) -}) + const f = supportedFormats({ doc: fakeDoc }); + expect(Object.keys(f).length).toBe(1); + }); +}); diff --git a/test/vast.spec.js b/test/vast.spec.js index 830b8c5..53f7699 100644 --- a/test/vast.spec.js +++ b/test/vast.spec.js @@ -1,91 +1,91 @@ -import Vast, { VastXMLParsingError, VastNetworkError } from '../src/lib/vast' -import * as fs from 'fs' +import Vast, { VastXMLParsingError, VastNetworkError } from '../src/lib/vast'; +import * as fs from 'fs'; const REMOTE_URL = - 'https://ad.doubleclick.net/ddm/pfadx/N884.154386.EATER.COM/B21643693.231589573;sz=0x0;ord=[timestamp];dc_lat=;dc_rdid=;tag_for_child_directed_treatment=;tfua=;dcmt=text/xml' + 'https://ad.doubleclick.net/ddm/pfadx/N884.154386.EATER.COM/B21643693.231589573;sz=0x0;ord=[timestamp];dc_lat=;dc_rdid=;tag_for_child_directed_treatment=;tfua=;dcmt=text/xml'; describe('Basic Vast class functions', () => { it('it can be instantiated with an xml string', () => { - const vast = new Vast({ xml: '' }) - }) + const vast = new Vast({ xml: '' }); + }); it('handles valid xml and parses it', () => { - const xmlString = fs.readFileSync('./test/fixtures/vast.xml') - const vast = new Vast({ xml: xmlString }) - vast.parse() - }) -}) + const xmlString = fs.readFileSync('./test/fixtures/vast.xml'); + const vast = new Vast({ xml: xmlString }); + vast.parse(); + }); +}); describe('Internal Error Handling', () => { - let vast + let vast; beforeEach(() => { - vast = new Vast({ xml: fs.readFileSync('./test/fixtures/vast.xml') }) - }) + vast = new Vast({ xml: fs.readFileSync('./test/fixtures/vast.xml') }); + }); it('should pass an XML parse error to the callback', () => { expect(() => { - vast.useXmlString('not real xml') - }).toThrow(VastXMLParsingError) - let caughtError + vast.useXmlString('not real xml'); + }).toThrow(VastXMLParsingError); + let caughtError; try { - vast.useXmlString('not real xml') + vast.useXmlString('not real xml'); } catch (error) { - caughtError = error + caughtError = error; } - expect(caughtError.message).toMatch(/error parsing/i) - }) + expect(caughtError.message).toMatch(/error parsing/i); + }); it('should pass a network error to callback', async () => { - mockXhr('error') + mockXhr('error'); - let caughtError + let caughtError; try { - await vast.loadRemoteVast('http://doodle.com') + await vast.loadRemoteVast('http://doodle.com'); } catch (error) { - caughtError = error + caughtError = error; } - expect(caughtError.constructor).toBe(VastNetworkError) - expect(caughtError.message).toMatch(/network error/i) - expect(caughtError.message).toMatch(/status/i) - }) + expect(caughtError.constructor).toBe(VastNetworkError); + expect(caughtError.message).toMatch(/network error/i); + expect(caughtError.message).toMatch(/status/i); + }); it('should send a network error, on timeout', async () => { - mockXhr('timeout', '', 10) + mockXhr('timeout', '', 10); - let caughtError + let caughtError; try { - await vast.loadRemoteVast('http://doodle.com') + await vast.loadRemoteVast('http://doodle.com'); } catch (error) { - caughtError = error + caughtError = error; } - expect(caughtError.constructor).toBe(VastNetworkError) - expect(caughtError.message).toMatch(/timeout/i) - }) -}) + expect(caughtError.constructor).toBe(VastNetworkError); + expect(caughtError.message).toMatch(/timeout/i); + }); +}); describe('vast remote xml loading', () => { beforeEach(() => { - const responseXml = fs.readFileSync('./test/fixtures/vast.xml') - mockXhr('load', responseXml) - }) + const responseXml = fs.readFileSync('./test/fixtures/vast.xml'); + mockXhr('load', responseXml); + }); it('it can be loaded from a remote url', async () => { - const vast = new Vast() - await vast.loadRemoteVast(REMOTE_URL) - const videos = vast.videos() - expect(videos.length).toBeGreaterThan(2) - }) + const vast = new Vast(); + await vast.loadRemoteVast(REMOTE_URL); + const videos = vast.videos(); + expect(videos.length).toBeGreaterThan(2); + }); it('provides bandwidth estimates', async () => { - const vast = new Vast() - await vast.loadRemoteVast(REMOTE_URL) - expect(vast.bandwidth()).toBeGreaterThan(1000) - }) + const vast = new Vast(); + await vast.loadRemoteVast(REMOTE_URL); + expect(vast.bandwidth()).toBeGreaterThan(1000); + }); it('should have zero bandwith estimate before request', () => { - const vast = new Vast() - expect(vast.bandwidth()).toBe(0) - }) + const vast = new Vast(); + expect(vast.bandwidth()).toBe(0); + }); it('should allow for a new timeout value to be set', async () => { // TODO: I don't know how to test this @@ -93,22 +93,22 @@ describe('vast remote xml loading', () => { // mockXhr('load', '', 100) // await vast.loadRemoteVast(REMOTE_URL, {timeout: 1}) // expect(caughtError.constructor).toBe(VastNetworkError) - }) -}) + }); +}); describe('Vast Videos', () => { - let xmlString + let xmlString; beforeEach(() => { - xmlString = fs.readFileSync('./test/fixtures/vast.xml') - }) + xmlString = fs.readFileSync('./test/fixtures/vast.xml'); + }); it('can return a list of video files', () => { - const vast = new Vast({ xml: xmlString }) - const videos = vast.videos() - expect(videos.length).toBe(10) - }) -}) + const vast = new Vast({ xml: xmlString }); + const videos = vast.videos(); + expect(videos.length).toBe(10); + }); +}); /** * This is a bit of a mess, but it allows XHR requests to be mocked @@ -129,25 +129,25 @@ const mockXhr = (eventToFire = 'load', response = '', eventDelay = 100) => { // console.log('adding fake listener for', eventName, 'stimulating', eventToFire) if (eventName == eventToFire) { setTimeout(() => { - func({ message: eventToFire }) - }, eventDelay) + func({ message: eventToFire }); + }, eventDelay); } }), setRequestHeader: jest.fn(), - }) - window.XMLHttpRequest = jest.fn().mockImplementation(xhrMockClass) -} + }); + window.XMLHttpRequest = jest.fn().mockImplementation(xhrMockClass); +}; describe('Vast tag is capable of returning the best video', () => { - let vast + let vast; beforeAll(() => { - const xmlString = fs.readFileSync('./test/fixtures/vast.xml') - vast = new Vast({ xml: xmlString }) - }) + const xmlString = fs.readFileSync('./test/fixtures/vast.xml'); + vast = new Vast({ xml: xmlString }); + }); it('supports bestVideo function', () => { - expect(typeof vast.bestVideo).toBe('function') - const vid = vast.bestVideo({ mimeTypes: ['video/mp4'] }) - expect(vid.constructor.name).toBe('MediaFile') - }) -}) + expect(typeof vast.bestVideo).toBe('function'); + const vid = vast.bestVideo({ mimeTypes: ['video/mp4'] }); + expect(vid.constructor.name).toBe('MediaFile'); + }); +}); diff --git a/test/vast_elements/clickthrough.spec.js b/test/vast_elements/clickthrough.spec.js index dad4a85..419fbf9 100644 --- a/test/vast_elements/clickthrough.spec.js +++ b/test/vast_elements/clickthrough.spec.js @@ -1,35 +1,35 @@ -import Vast from '../../src/lib/vast' -import * as fs from 'fs' +import Vast from '../../src/lib/vast'; +import * as fs from 'fs'; describe('Clickthrough', () => { - let vast + let vast; beforeAll(() => { - const xmlString = fs.readFileSync('./test/fixtures/vast.xml') - vast = new Vast({ xml: xmlString }) - }) + const xmlString = fs.readFileSync('./test/fixtures/vast.xml'); + vast = new Vast({ xml: xmlString }); + }); it('should return a clickthrough url', () => { - expect(vast.clickthroughUrl).not.toBe(undefined) - expect(vast.clickthroughUrl()).toMatch(/^https:\/\/adclick/) - }) + expect(vast.clickthroughUrl).not.toBe(undefined); + expect(vast.clickthroughUrl()).toMatch(/^https:\/\/adclick/); + }); it('should handle clicking through to a URL', () => { - expect(vast.openClickthroughUrl).not.toBe(undefined) - expect(typeof vast.openClickthroughUrl).toBe('function') - }) + expect(vast.openClickthroughUrl).not.toBe(undefined); + expect(typeof vast.openClickthroughUrl).toBe('function'); + }); it('should open the click through URL in a new tab', () => { - let requestedUrl, requestTarget + let requestedUrl, requestTarget; window.open = (url, target) => { - requestedUrl = url - requestTarget = target + requestedUrl = url; + requestTarget = target; return { focus: () => {}, - } - } - vast.openClickthroughUrl() - expect(requestedUrl).toMatch(/^https:\/\/adclick/) - expect(requestTarget).toBe('_blank') - }) -}) + }; + }; + vast.openClickthroughUrl(); + expect(requestedUrl).toMatch(/^https:\/\/adclick/); + expect(requestTarget).toBe('_blank'); + }); +}); diff --git a/test/vast_elements/error_impression.spec.js b/test/vast_elements/error_impression.spec.js index 43f3d2c..465a095 100644 --- a/test/vast_elements/error_impression.spec.js +++ b/test/vast_elements/error_impression.spec.js @@ -1,22 +1,22 @@ -import Vast from '../../src/lib/vast' -import * as fs from 'fs' +import Vast from '../../src/lib/vast'; +import * as fs from 'fs'; describe('External error handling', () => { - let vast + let vast; beforeEach(() => { - vast = new Vast({ xml: fs.readFileSync('./test/fixtures/vast.xml') }) - }) + vast = new Vast({ xml: fs.readFileSync('./test/fixtures/vast.xml') }); + }); it('should support return the error pixel urls', () => { - expect(typeof vast.errorImpressionUrls).toBe('function') - expect(vast.errorImpressionUrls()[0]).toMatch(/^https:\/\/ade\.googlesyndication/) - expect(vast.errorImpressionUrls().length).toBe(1) - }) + expect(typeof vast.errorImpressionUrls).toBe('function'); + expect(vast.errorImpressionUrls()[0]).toMatch(/^https:\/\/ade\.googlesyndication/); + expect(vast.errorImpressionUrls().length).toBe(1); + }); it('should support adding the error pixel(s) to the page on error', () => { - expect(typeof vast.addErrorImpressionUrls).toBe('function') - const imgCount = document.querySelectorAll('img').length - vast.addErrorImpressionUrls() - expect(document.querySelectorAll('img').length).toEqual(imgCount + 1) - }) -}) + expect(typeof vast.addErrorImpressionUrls).toBe('function'); + const imgCount = document.querySelectorAll('img').length; + vast.addErrorImpressionUrls(); + expect(document.querySelectorAll('img').length).toEqual(imgCount + 1); + }); +}); diff --git a/test/vast_elements/impression.spec.js b/test/vast_elements/impression.spec.js index fe5416f..9e81cd0 100644 --- a/test/vast_elements/impression.spec.js +++ b/test/vast_elements/impression.spec.js @@ -1,43 +1,43 @@ -import Vast from '../../src/lib/vast' -import * as fs from 'fs' +import Vast from '../../src/lib/vast'; +import * as fs from 'fs'; describe('Vast Impressions', () => { - let xmlString + let xmlString; beforeAll(() => { - xmlString = fs.readFileSync('./test/fixtures/vast.xml') - }) + xmlString = fs.readFileSync('./test/fixtures/vast.xml'); + }); it('should return a series of impression urls', () => { - const vast = new Vast({ xml: xmlString }) - expect(vast.impressionUrls).not.toBe(undefined) - expect(vast.impressionUrls()[0]).toMatch(/^https:\/\/googleads4/) - expect(vast.impressionUrls().length).toBe(2) - }) + const vast = new Vast({ xml: xmlString }); + expect(vast.impressionUrls).not.toBe(undefined); + expect(vast.impressionUrls()[0]).toMatch(/^https:\/\/googleads4/); + expect(vast.impressionUrls().length).toBe(2); + }); it('should be able to insert these images directly into the document', () => { - const vast = new Vast({ xml: xmlString }) - expect(vast.addImpressionUrls).not.toBe(undefined) - vast.addImpressionUrls() + const vast = new Vast({ xml: xmlString }); + expect(vast.addImpressionUrls).not.toBe(undefined); + vast.addImpressionUrls(); - const images = Array.from(document.querySelectorAll('img')) - expect(images.length).toBe(2) - expect(images[0].src).toBe(vast.impressionUrls()[0]) - }) + const images = Array.from(document.querySelectorAll('img')); + expect(images.length).toBe(2); + expect(images[0].src).toBe(vast.impressionUrls()[0]); + }); it('should be able to add images to a different document', () => { const fakeDoc = { createElement: jest.fn(t => { - return { style: {} } + return { style: {} }; }), body: { appendChild: jest.fn(t => {}), }, - } + }; - const vast = new Vast({ xml: xmlString }) - vast.addImpressionUrls(fakeDoc) - expect(fakeDoc.createElement.mock.calls.length).toBe(2) - expect(fakeDoc.body.appendChild.mock.calls.length).toBe(2) - }) -}) + const vast = new Vast({ xml: xmlString }); + vast.addImpressionUrls(fakeDoc); + expect(fakeDoc.createElement.mock.calls.length).toBe(2); + expect(fakeDoc.body.appendChild.mock.calls.length).toBe(2); + }); +}); diff --git a/test/vast_elements/media_files.spec.js b/test/vast_elements/media_files.spec.js index e892845..c9ff5aa 100644 --- a/test/vast_elements/media_files.spec.js +++ b/test/vast_elements/media_files.spec.js @@ -1,77 +1,75 @@ -import Vast from '../../src/lib/vast' -import * as fs from 'fs' +import Vast from '../../src/lib/vast'; +import * as fs from 'fs'; describe('Media Files extension', () => { - let xmlString - let vast + let xmlString; + let vast; beforeAll(() => { - xmlString = fs.readFileSync('./test/fixtures/vast.xml') - vast = new Vast({ xml: xmlString }) - }) + xmlString = fs.readFileSync('./test/fixtures/vast.xml'); + vast = new Vast({ xml: xmlString }); + }); it('should know about bitrates of video files', () => { - const video = vast.videos()[0] - expect(video.bitrate).not.toBe(undefined) - expect(typeof video.bitrate).toBe('function') - expect(video.bitrate()).toBe(262) - }) + const video = vast.videos()[0]; + expect(video.bitrate).not.toBe(undefined); + expect(typeof video.bitrate).toBe('function'); + expect(video.bitrate()).toBe(262); + }); it('should know what type of video codec via mimeType', () => { - const video = vast.videos()[0] - expect(video.mimeType).not.toBe(undefined) - expect(typeof video.mimeType).toBe('function') - expect(video.mimeType()).toBe('video/mp4') - }) + const video = vast.videos()[0]; + expect(video.mimeType).not.toBe(undefined); + expect(typeof video.mimeType).toBe('function'); + expect(video.mimeType()).toBe('video/mp4'); + }); it('should know about bitrates of video files', () => { - const video = vast.videos()[0] - expect(video.bitrate).not.toBe(undefined) - }) + const video = vast.videos()[0]; + expect(video.bitrate).not.toBe(undefined); + }); it('can return a list of video files', () => { - const videos = vast.videos() - expect(videos.length).toBe(10) - }) + const videos = vast.videos(); + expect(videos.length).toBe(10); + }); it('can get the url of the video', () => { - const video = vast.videos()[0] - expect(video.url).not.toBe(undefined) - expect(typeof video.url).toBe('function') + const video = vast.videos()[0]; + expect(video.url).not.toBe(undefined); + expect(typeof video.url).toBe('function'); expect(video.url()).toBe( 'https://gcdn.2mdn.net/videoplayback/id/fadde8e0a3b24322/itag/18/source/doubleclick_dmm/ratebypass/yes/acao/yes/ip/0.0.0.0/ipbits/0/expire/3680618308/sparams/id,itag,source,ratebypass,acao,ip,ipbits,expire/signature/974EA821C8BCBD176CED7FBDDDF84421BB96D3F7.B210716A5BB26DFD0F70F1D482AA150CB6B9D20/key/ck2/file/file.mp4' - ) - }) + ); + }); it('a video file knows its height and width', () => { - const video = vast.videos()[0] - expect(video.height()).toBe(360) - expect(video.width()).toBe(640) - }) -}) + const video = vast.videos()[0]; + expect(video.height()).toBe(360); + expect(video.width()).toBe(640); + }); +}); describe('MediaFile to HLS Url', () => { - let xmlString - let vast + let xmlString; + let vast; beforeAll(() => { - xmlString = fs.readFileSync('./test/fixtures/vast.xml') - vast = new Vast({ xml: xmlString }) - }) + xmlString = fs.readFileSync('./test/fixtures/vast.xml'); + vast = new Vast({ xml: xmlString }); + }); it('should return a data url', () => { - expect(vast.asHLSUrl()).toBeDefined() - expect(vast.asHLSUrl()).toMatch(/^data:application\/x-mpegURL/) - }) + expect(vast.asHLSUrl()).toBeDefined(); + expect(vast.asHLSUrl()).toMatch(/^data:application\/x-mpegURL/); + }); it('should conform to m3u8 headers', () => { - const dataUrl = vast.asHLSUrl() - const contents = atob(dataUrl.split(',')[1]) - expect(contents).toMatch(/^#EXTM3U/) - const contentArrayAsLines = contents.split('\n') - expect(contentArrayAsLines[1]).toBe( - '#EXT-X-STREAM-INF:BANDWIDTH=268288,RESOLUTION=640x360,CODEC=mp4v' - ) - expect(contentArrayAsLines[2]).toBe(vast.videos()[0].url()) - }) -}) + const dataUrl = vast.asHLSUrl(); + const contents = atob(dataUrl.split(',')[1]); + expect(contents).toMatch(/^#EXTM3U/); + const contentArrayAsLines = contents.split('\n'); + expect(contentArrayAsLines[1]).toBe('#EXT-X-STREAM-INF:BANDWIDTH=268288,RESOLUTION=640x360,CODEC=mp4v'); + expect(contentArrayAsLines[2]).toBe(vast.videos()[0].url()); + }); +}); diff --git a/test/vast_elements/tracking_events.spec.js b/test/vast_elements/tracking_events.spec.js index 9b731ba..12aada8 100644 --- a/test/vast_elements/tracking_events.spec.js +++ b/test/vast_elements/tracking_events.spec.js @@ -1,49 +1,49 @@ -import Vast from '../../src/lib/vast' -import * as fs from 'fs' +import Vast from '../../src/lib/vast'; +import * as fs from 'fs'; describe('Media Files extension', () => { - let xmlString - let vast + let xmlString; + let vast; beforeAll(() => { - xmlString = fs.readFileSync('./test/fixtures/vast.xml') - vast = new Vast({ xml: xmlString }) - }) + xmlString = fs.readFileSync('./test/fixtures/vast.xml'); + vast = new Vast({ xml: xmlString }); + }); it('should be able to return all the tracking events for a given name', () => { - expect(typeof vast.trackingUrlsFor).toBe('function') - }) + expect(typeof vast.trackingUrlsFor).toBe('function'); + }); it('should be return an enumerable Array of the tracking urls for a given name', () => { - expect(vast.trackingUrlsFor('start').constructor).toBe(Array) - }) + expect(vast.trackingUrlsFor('start').constructor).toBe(Array); + }); it('should be able to return all the tracking events for a given name', () => { - expect(vast.trackingUrlsFor('start')[0]).toMatch(/^https:/) - expect(vast.trackingUrlsFor('firstQuartile')[0]).toMatch(/^https:/) - }) + expect(vast.trackingUrlsFor('start')[0]).toMatch(/^https:/); + expect(vast.trackingUrlsFor('firstQuartile')[0]).toMatch(/^https:/); + }); it('should be able return all the tracking events for a given name', () => { - expect(vast.trackingUrlsFor('start').length).toEqual(2) - }) + expect(vast.trackingUrlsFor('start').length).toEqual(2); + }); it('should return an empty array if there are no tracking events matching this tracker', () => { - expect(vast.trackingUrlsFor('hiThereMessay')).toEqual([]) - }) + expect(vast.trackingUrlsFor('hiThereMessay')).toEqual([]); + }); describe('Media Files extension', () => { it('should be able to add an impression tracker to the page for a key', () => { - expect(typeof vast.addImpressionTrackingImagesFor).toBe('function') - }) + expect(typeof vast.addImpressionTrackingImagesFor).toBe('function'); + }); it('should return nothing when adding images to the doc', () => { - expect(vast.addImpressionTrackingImagesFor('start')).toBe(undefined) - }) + expect(vast.addImpressionTrackingImagesFor('start')).toBe(undefined); + }); it('should add some images to the document', () => { - const existingImages = document.querySelectorAll('img').length - vast.addImpressionTrackingImagesFor('start') - expect(document.querySelectorAll('img').length).toBe(2 + existingImages) - }) - }) -}) + const existingImages = document.querySelectorAll('img').length; + vast.addImpressionTrackingImagesFor('start'); + expect(document.querySelectorAll('img').length).toBe(2 + existingImages); + }); + }); +}); From 445b9b55b2cbb756d6e0d45d625c9a0cf0a427f0 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Thu, 28 Feb 2019 11:16:48 -0600 Subject: [PATCH 7/8] one too many ; --- LICENSE | 2 +- README.md | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/LICENSE b/LICENSE index d743c8c..01f3b37 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ Copyright 2019 Vox Media -Licensed under the Apache License, Version 2.0 (the "License"); +Licensed under the Apache License, Version 2.0 (the "License") you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/README.md b/README.md index 245848c..9c5a5a1 100644 --- a/README.md +++ b/README.md @@ -90,9 +90,9 @@ player.src([{ type: bestVastVideo.mimeType(), src: bestVastVideo.url() }]); ### Remaining Work -1. Test this with the HymnalAd SDK Video player -1. Design error handling -1. Open source it 🙏 +1. ~~Test this with the HymnalAd SDK Video player~~ +1. ~~Design error handling~~ +1. ~~Open source it 🙏~~ ### Contributing @@ -110,7 +110,7 @@ player.src([{ type: bestVastVideo.mimeType(), src: bestVastVideo.url() }]); Copyright 2019 Vox Media -Licensed under the Apache License, Version 2.0 (the "License"); +Licensed under the Apache License, Version 2.0 (the "License") you may not use this file except in compliance with the License. You may obtain a copy of the License at From fa4acfb523e32d44b085011dcea5d0a32e14204e Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Thu, 28 Feb 2019 14:15:10 -0600 Subject: [PATCH 8/8] clarifying our vast support --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9c5a5a1..5ffce94 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Concert Vast Parser -This is the Concert Vast Parser. It consumes simple inline video VAST tags and provides a nice wrapper to interact with the XML response in a Concert-opinionated way. +This is an opinionated and minimal Concert Vast parser. It consumes simple InLine video VAST responses and provides a nice wrapper to interact with the XML response in a Concert-opinionated way. ### Using this library