UNPKG

@financial-times/o-ads

Version:

This package contains the core functionality used by the FT in providing ads across all of its sites. This includes ft.com, howtospendit.com, ftadviser.com and other specialist titles.

431 lines (326 loc) 11.1 kB
/* global sinon: false, $: false, QUnit: false */ 'use strict'; //eslint-disable-line Object.defineProperty(exports, "__esModule", { value: true }); exports.default = exports.deleteCookie = exports.clear = exports.localStorage = exports.meta = exports.viewport = exports.server = exports.date = exports.mock = exports.stub = exports.spy = exports.sandbox = exports.trigger = exports.warn = exports.fixtures = exports.createDummyFrame = exports.fixturesContainer = exports.nullUrl = exports.gpt = void 0; var _oViewport = _interopRequireDefault(require("@financial-times/o-viewport")); var _index = _interopRequireDefault(require("../../dist-esm/js/utils/index.js")); var _gptMock = _interopRequireDefault(require("./mocks/gpt-mock.js")); var _userApiResponse = _interopRequireDefault(require("../fixtures/user-api-response.json")); var _userApiAnonymousResponse = _interopRequireDefault(require("../fixtures/user-api-anonymous-response.json")); var _contentApiResponse = _interopRequireDefault(require("../fixtures/content-api-response.json")); var _anotherContentApiResponse = _interopRequireDefault(require("../fixtures/another-content-api-response.json")); var _conceptApiResponse = _interopRequireDefault(require("../fixtures/concept-api-response.json")); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } const gpt = _gptMock.default.googletag; /* a URL that can be used in tests without causing 404 errors */ exports.gpt = gpt; const nullUrl = 'base/test/qunit/mocks/null.js'; /* container for fixtures */ exports.nullUrl = nullUrl; const fixturesContainer = { get: () => document.getElementById('qunit-fixtures'), add: html => { fixturesContainer.get().insertAdjacentHTML('beforeend', html); return fixturesContainer.get().lastChild; } }; /* create an iframe and return it's context for testing post message */ exports.fixturesContainer = fixturesContainer; const createDummyFrame = function (content, target) { target = target || document.getElementById('qunit-fixtures'); const iframe = document.createElement('iframe'); iframe.id = 'postMessage'; target.appendChild(iframe); if (content) { iframe.contentDocument.body.insertAdjacentHTML('beforeEnd', content); } return { node: iframe, window: iframe.contentWindow }; }; exports.createDummyFrame = createDummyFrame; const fixtures = { user: _userApiResponse.default, userAnonymous: _userApiAnonymousResponse.default, content: _contentApiResponse.default, anotherContent: _anotherContentApiResponse.default, concept: _conceptApiResponse.default }; /* A method for logging warnings about tests that didn't run for some reason */ /* such as tests that mock read only properties in a browser that doesn't allow this */ exports.fixtures = fixtures; const warn = function (message) { /* jshint devel: true */ if (console) { const log = console.warn || console.log; log.call(console, message); } }; /* trigger a dom event */ exports.warn = warn; const trigger = function (element, eventType, bubble, cancelable, data) { let event; element = element || document.body; element = $.type(element) === 'string' ? document.querySelector(element) : element; if (document.createEvent) { event = document.createEvent('HTMLEvents'); event.initEvent(eventType, bubble || true, cancelable || true); if (data) { _index.default.extend(event, data); } element.dispatchEvent(event); } else { event = document.createEventObject(); event.eventType = eventType; event.cancelBubble = bubble ? false : true; if (data) { _index.default.extend(event, {}, data); } element.fireEvent('on' + event.eventType, event); } return event; }; /* Setup a sinon sandbox to easily clear mocks */ exports.trigger = trigger; const sandbox = QUnit.sandbox = sinon.sandbox.create(); /* Shortcuts to Sinon sandbox methods */ exports.sandbox = sandbox; const spy = function () { return sandbox.spy.apply(sandbox, [].slice.call(arguments)); }; exports.spy = spy; const stub = function () { return sandbox.stub.apply(sandbox, [].slice.call(arguments)); }; exports.stub = stub; const mock = function () { return sandbox.mock.apply(sandbox, [].slice.call(arguments)); }; /* decorate document.body add/remove EventListener so we can remove any attached events */ exports.mock = mock; const _addEventListener = document.body.addEventListener; const _removeEventListener = document.body.removeEventListener; sandbox._eventListeners = []; document.body.addEventListener = function (type, listener) { sandbox._eventListeners.push({ type: type, listener: listener }); _addEventListener(type, listener); }; document.body.removeEventListener = function (type, listener) { let remove; sandbox._eventListeners.forEach(function (item, index) { if (item.type === type && listener === listener) { //eslint-disable-line no-self-compare remove = index; } }); if (remove) { sandbox._eventListeners.splice(remove, 1); } _removeEventListener(type, listener); }; const _addWindowEventListener = window.addEventListener; const _removeWindowEventListener = window.removeEventListener; sandbox._windowEventListeners = []; window.addEventListener = function (type, listener) { sandbox._windowEventListeners.push({ type: type, listener: listener }); _addWindowEventListener(type, listener); }; window.removeEventListener = function (type, listener) { let remove; sandbox._windowEventListeners.forEach(function (item, index) { if (item.type === type && listener === listener) { //eslint-disable-line no-self-compare remove = index; } }); if (remove) { sandbox._windowEventListeners.splice(remove, 1); } _removeWindowEventListener(type, listener); }; /* mock dates */ const date = function (time) { let clock; if (isNaN(time)) { clock = sandbox.useFakeTimers(); } else { clock = sandbox.useFakeTimers(time); } return clock; }; /* mock xml http requests */ exports.date = date; const server = function (clock) { if (clock) { return sandbox.useFakeServerWithClock(); } else { return sandbox.useFakeServer(); } }; /* mock viewport dimensions */ // In order to mock the results from oViewport.getSize we stub Math.max // and return the mocked width or height when the actual width and height are provided as arguments // this could go bad if your code is using Math.max and happens to provide the window width/height as an argument exports.server = server; const viewport = function (width, height) { if (_oViewport.default.getSize.restore) { _oViewport.default.getSize.restore(); } this.stub(_oViewport.default, 'getSize', function () { return { height: height, width: width }; }); }; /* Add meta data to the page */ exports.viewport = viewport; const meta = function (data) { let name; let attr; let metatag; let attrs = ''; if ($.isPlainObject(data)) { for (name in data) { if (data.hasOwnProperty(name)) { if ($.type(data[name]) === 'string') { attrs += 'content="' + data[name] + '"'; } else if ($.isPlainObject(data[name])) { for (attr in data[name]) { if (data[name].hasOwnProperty(attr)) { attrs += attr + '=\'' + data[name][attr] + '\' '; } } } metatag = '<meta name="' + name + '" ' + attrs + ' remove>'; $(metatag).appendTo('head'); } } } else { throw new MetaException('invalid data to build meta tags'); } return data; }; /* Mock localStorage */ exports.meta = meta; const localStorage = function (data) { let canMock = Boolean(window.localStorage); let fake; if (canMock) { // remember original local storage sandbox._localStorage = window.localStorage; if ($.isPlainObject(data)) { const fakes = { getItem: function (key) { return data[key] || null; }, setItem: function (key, value) { data[key] = value; }, removeItem: function (key) { delete data[key]; }, key: function (index) { const keys = Object.keys(data); index = index || 0; return data[keys[index]] || null; } }; try { // remove the original delete window.localStorage; // set up mock Object.defineProperty(window, 'localStorage', { value: fakes, configurable: true, writable: true }); } catch (err) { // this will fail in some browsers where you can't override host properties (Safari) // localStorage tests need to be skipped in those browsers canMock = false; delete sandbox._localStorage; } // replaces the original set of fakes with stubs for (fake in fakes) { if (fakes.hasOwnProperty(fake)) { sandbox.stub(window.localStorage, fake, fakes[fake]); } } } else { new LocalStorageException('Invalid data for localStorage'); } } return canMock; }; /* clear out anyting added to the page by tests */ /* and reset all the sinon mocks in the sandbox */ exports.localStorage = localStorage; const clear = function () { // remove any tags added during testing $('[remove],[o-ads]').remove(); // empty the fixtures container $('#qunit-fixtures').empty(); // clear localStorage mock if (sandbox._localStorage) { window.localStorage = sandbox._localStorage; delete sandbox._localStorage; } // delete global vars if (sandbox._globals) { Object.keys(sandbox._globals).forEach(function (name) { delete window[name]; }); } // remove attached events sandbox._eventListeners.forEach(function (item) { _removeEventListener(item.type, item.listener); }); sandbox._eventListeners = []; _oViewport.default.stopListeningTo('all'); // remove attached events sandbox._windowEventListeners.forEach(function (item) { _removeWindowEventListener(item.type, item.listener); }); sandbox._windowEventListeners = []; // restore stubs & mocks _gptMock.default.restore(); sandbox.restore(); }; exports.clear = clear; const deleteCookie = function (name) { document.cookie = name + '=; expires=Thu, 01 Jan 1970 00:00:01 GMT;'; }; /* exception to be thrown by meta if invalid data is supplied */ exports.deleteCookie = deleteCookie; function MetaException(message) { this.message = message; this.name = 'MetaException'; } /* exception to be thrown by localStorage if invalid data is supplied */ function LocalStorageException(message) { this.message = message; this.name = 'LocalStorageException'; } var _default = { gpt, nullUrl, fixturesContainer, createDummyFrame, fixtures, warn, trigger, sandbox, spy, stub, mock, date, server, viewport, meta, localStorage, clear, deleteCookie }; exports.default = _default;