diff --git a/src/__tests__/__snapshots__/mountSpec.js.snap b/src/__tests__/__snapshots__/mountSpec.js.snap new file mode 100644 index 0000000..6a62f44 --- /dev/null +++ b/src/__tests__/__snapshots__/mountSpec.js.snap @@ -0,0 +1,97 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`UIAtoms mount rendering should render atoms with noscript tag - disabled by $Settings, overriden by props: Iframe without noscript tag 1`] = ` +"
" +`; + +exports[`UIAtoms mount rendering should render atoms with noscript tag - disabled by $Settings, overriden by props: Image without noscript tag 1`] = ` +"
" +`; + +exports[`UIAtoms mount rendering should render atoms with noscript tag - disabled by $Settings, overriden by props: Video without noscript tag 1`] = ` +"
" +`; + +exports[`UIAtoms mount rendering should render atoms with noscript tag: should render Iframe with noscript tag 1`] = ` +"
" +`; + +exports[`UIAtoms mount rendering should render atoms with noscript tag: should render Image with noscript tag 1`] = ` +"
" +`; + +exports[`UIAtoms mount rendering should render atoms with noscript tag: should render Video with noscript tag 1`] = ` +"
" +`; + +exports[`UIAtoms mount rendering should render atoms without noscript tag - disabled by $Settings: Iframe without noscript tag 1`] = `"
"`; + +exports[`UIAtoms mount rendering should render atoms without noscript tag - disabled by $Settings: Image without noscript tag 1`] = `"
"`; + +exports[`UIAtoms mount rendering should render atoms without noscript tag - disabled by $Settings: Video without noscript tag 1`] = `"
"`; + +exports[`UIAtoms mount rendering should render atoms without noscript tag - disabled by props: Iframe without noscript tag 1`] = `"
"`; + +exports[`UIAtoms mount rendering should render atoms without noscript tag - disabled by props: Image without noscript tag 1`] = `"
"`; + +exports[`UIAtoms mount rendering should render atoms without noscript tag - disabled by props: Video without noscript tag 1`] = `"
"`; + +exports[`UIAtoms mount rendering should render atoms without noscript tag - enabled by $Settings, overriden by props: Iframe without noscript tag 1`] = `"
"`; + +exports[`UIAtoms mount rendering should render atoms without noscript tag - enabled by $Settings, overriden by props: Image without noscript tag 1`] = `"
"`; + +exports[`UIAtoms mount rendering should render atoms without noscript tag - enabled by $Settings, overriden by props: Video without noscript tag 1`] = `"
"`; diff --git a/src/__tests__/mountSpec.js b/src/__tests__/mountSpec.js new file mode 100644 index 0000000..5794d1e --- /dev/null +++ b/src/__tests__/mountSpec.js @@ -0,0 +1,288 @@ +import { mount } from 'enzyme'; +import React from 'react'; +import PropTypes from 'prop-types'; +import { toMockedInstance } from 'to-mock'; +import classnames from 'classnames'; + +import * as UIAtoms from '../main'; +import UIComponentHelper from '../UIComponentHelper'; +import ComponentPositions from '../ComponentPositions'; +import Visibility from '../Visibility'; +import { Infinite } from 'infinite-circle'; + +import { JSDOM } from 'jsdom'; +const jsdom = new JSDOM(''); +const { window } = jsdom; + +import _router from '../mocks/router'; +import _window from '../mocks/window'; +import _settings from '../mocks/settings'; + +global.window = window; +global.document = window.document; +global.navigator = { + userAgent: 'node.js' +}; + +const visibility = toMockedInstance(Visibility); +const mockPosition = { + height: 0 +}; +const componentPositions = toMockedInstance(ComponentPositions, { + getWindowViewportRect: () => mockPosition +}); +const infinite = toMockedInstance(Infinite); + +const childContextTypes = { + $Utils: PropTypes.shape({}), + $Settings: PropTypes.shape({}) +}; + +function getComponentOptions(overrideSettings = {}) { + const $Settings = Object.assign({}, _settings, overrideSettings); + + const $UIComponentHelper = new UIComponentHelper( + _router, + _window, + componentPositions, + visibility, + infinite, + classnames, + $Settings + ); + + const context = { + $Utils: { + $Settings, + $UIComponentHelper + } + }; + const mountOptions = { + context, + childContextTypes, + someProp: true + }; + + return mountOptions; +} + +describe('UIAtoms mount rendering', () => { + let wrapper = null; + + afterEach(() => { + if (wrapper) { + wrapper.unmount(); + } + }); + + describe('should render atoms with noscript tag: ', () => { + let mountOptions = getComponentOptions(); + + it('should render Image with noscript tag', () => { + const Component = UIAtoms.Image; + wrapper = mount(, mountOptions); + + expect(wrapper.html()).toMatchSnapshot(); + expect(wrapper.find('noscript').length).toEqual(1); + }); + + it('should render Video with noscript tag', () => { + const Component = UIAtoms.Video; + wrapper = mount(, mountOptions); + + expect(wrapper.html()).toMatchSnapshot(); + expect(wrapper.find('noscript').length).toEqual(1); + }); + + it('should render Iframe with noscript tag', () => { + const Component = UIAtoms.Iframe; + wrapper = mount(, mountOptions); + + expect(wrapper.html()).toMatchSnapshot(); + expect(wrapper.find('noscript').length).toEqual(1); + }); + }); + + describe('should render atoms without noscript tag - disabled by props: ', () => { + let mountOptions = getComponentOptions(); + + it('Image without noscript tag', () => { + const Component = UIAtoms.Image; + wrapper = mount( + , + mountOptions + ); + + expect(wrapper.html()).toMatchSnapshot(); + expect(wrapper.find('noscript').length).toEqual(0); + }); + + it('Video without noscript tag', () => { + const Component = UIAtoms.Video; + wrapper = mount( + , + mountOptions + ); + + expect(wrapper.html()).toMatchSnapshot(); + expect(wrapper.find('noscript').length).toEqual(0); + }); + + it('Iframe without noscript tag', () => { + const Component = UIAtoms.Iframe; + wrapper = mount( + , + mountOptions + ); + + expect(wrapper.html()).toMatchSnapshot(); + expect(wrapper.find('noscript').length).toEqual(0); + }); + }); + + describe('should render atoms without noscript tag - disabled by $Settings: ', () => { + let mountOptions = getComponentOptions({ + plugin: { + imaUiAtoms: { + useIntersectionObserver: { + iframes: true, + images: true, + videos: true + }, + disableNoScript: { + iframes: true, + images: true, + videos: true + } + } + } + }); + + it('Image without noscript tag', () => { + const Component = UIAtoms.Image; + wrapper = mount(, mountOptions); + + expect(wrapper.html()).toMatchSnapshot(); + expect(wrapper.find('noscript').length).toEqual(0); + }); + it('Video without noscript tag', () => { + const Component = UIAtoms.Video; + wrapper = mount(, mountOptions); + + expect(wrapper.html()).toMatchSnapshot(); + expect(wrapper.find('noscript').length).toEqual(0); + }); + + it('Iframe without noscript tag', () => { + const Component = UIAtoms.Iframe; + wrapper = mount(, mountOptions); + + expect(wrapper.html()).toMatchSnapshot(); + expect(wrapper.find('noscript').length).toEqual(0); + }); + }); + + describe('should render atoms with noscript tag - disabled by $Settings, overriden by props: ', () => { + let mountOptions = getComponentOptions({ + plugin: { + imaUiAtoms: { + useIntersectionObserver: { + iframes: true, + images: true, + videos: true + }, + disableNoScript: { + iframes: true, + images: true, + videos: true + } + } + } + }); + + it('Image without noscript tag', () => { + const Component = UIAtoms.Image; + wrapper = mount( + , + mountOptions + ); + + expect(wrapper.html()).toMatchSnapshot(); + expect(wrapper.find('noscript').length).toEqual(1); + }); + + it('Video without noscript tag', () => { + const Component = UIAtoms.Video; + wrapper = mount( + , + mountOptions + ); + + expect(wrapper.html()).toMatchSnapshot(); + expect(wrapper.find('noscript').length).toEqual(1); + }); + + it('Iframe without noscript tag', () => { + const Component = UIAtoms.Iframe; + wrapper = mount( + , + mountOptions + ); + + expect(wrapper.html()).toMatchSnapshot(); + expect(wrapper.find('noscript').length).toEqual(1); + }); + }); + + describe('should render atoms without noscript tag - enabled by $Settings, overriden by props: ', () => { + let mountOptions = getComponentOptions({ + plugin: { + imaUiAtoms: { + useIntersectionObserver: { + iframes: true, + images: true, + videos: true + }, + disableNoScript: { + iframes: false, + images: false, + videos: false + } + } + } + }); + + it('Image without noscript tag', () => { + const Component = UIAtoms.Image; + wrapper = mount( + , + mountOptions + ); + + expect(wrapper.html()).toMatchSnapshot(); + expect(wrapper.find('noscript').length).toEqual(0); + }); + + it('Video without noscript tag', () => { + const Component = UIAtoms.Video; + wrapper = mount( + , + mountOptions + ); + + expect(wrapper.html()).toMatchSnapshot(); + expect(wrapper.find('noscript').length).toEqual(0); + }); + + it('Iframe without noscript tag', () => { + const Component = UIAtoms.Iframe; + wrapper = mount( + , + mountOptions + ); + + expect(wrapper.html()).toMatchSnapshot(); + expect(wrapper.find('noscript').length).toEqual(0); + }); + }); +}); diff --git a/src/iframe/HtmlIframe.jsx b/src/iframe/HtmlIframe.jsx index 3b5ebf0..cc3cb28 100644 --- a/src/iframe/HtmlIframe.jsx +++ b/src/iframe/HtmlIframe.jsx @@ -35,6 +35,9 @@ export default class HtmlIframe extends React.PureComponent { this._onVisibilityWriter = this.onVisibilityWriter.bind(this); this._rootElement = React.createRef(); + + this._helper = this.utils.$UIComponentHelper; + this._settings = this.utils.$Settings; } get utils() { @@ -42,14 +45,20 @@ export default class HtmlIframe extends React.PureComponent { } get useIntersectionObserver() { - return !( - this.utils.$Settings && - this.utils.$Settings.plugin && - this.utils.$Settings.plugin.imaUiAtoms && - this.utils.$Settings.plugin.imaUiAtoms.useIntersectionObserver && - this.utils.$Settings.plugin.imaUiAtoms.useIntersectionObserver.iframes === - false - ); + return this.props.useIntersectionObserver !== undefined + ? this.props.useIntersectionObserver + : this._settings.plugin.imaUiAtoms.useIntersectionObserver.iframes !== + undefined + ? this._settings.plugin.imaUiAtoms.useIntersectionObserver.iframes + : this._settings.plugin.imaUiAtoms.useIntersectionObserver; + } + + get disableNoScript() { + return this.props.disableNoScript !== undefined + ? this.props.disableNoScript + : this._settings.plugin.imaUiAtoms.disableNoScript.iframes !== undefined + ? this._settings.plugin.imaUiAtoms.disableNoScript.iframes + : this._settings.plugin.imaUiAtoms.disableNoScript; } componentDidMount() { @@ -63,12 +72,10 @@ export default class HtmlIframe extends React.PureComponent { } render() { - let helper = this.utils.$UIComponentHelper; - return (
+ {...this._helper.getDataProps(this.props)}> {this.props.layout === 'responsive' ? ( ) : null} -
); } @@ -168,28 +183,25 @@ export default class HtmlIframe extends React.PureComponent { _unregisterToCheckingVisibility() { if (this._registeredVisibilityId) { - this.utils.$UIComponentHelper.visibility.unregister( - this._registeredVisibilityId - ); + this._helper.visibility.unregister(this._registeredVisibilityId); this._registeredVisibilityId = null; } } _registerToCheckingVisibility() { - let { $UIComponentHelper } = this.utils; let extendedPadding = Math.max( - $UIComponentHelper.componentPositions.getWindowViewportRect().height / 2, + this._helper.componentPositions.getWindowViewportRect().height / 2, MIN_EXTENDED_PADDING ); - this._registeredVisibilityId = $UIComponentHelper.visibility.register( - $UIComponentHelper.getVisibilityReader(this._rootElement.current, { + this._registeredVisibilityId = this._helper.visibility.register( + this._helper.getVisibilityReader(this._rootElement.current, { useIntersectionObserver: this.useIntersectionObserver, extendedPadding, width: this.props.width, height: this.props.height }), - $UIComponentHelper.wrapVisibilityWriter(this._onVisibilityWriter) + this._helper.wrapVisibilityWriter(this._onVisibilityWriter) ); } } diff --git a/src/image/HtmlImage.jsx b/src/image/HtmlImage.jsx index f7d220e..4ac7646 100644 --- a/src/image/HtmlImage.jsx +++ b/src/image/HtmlImage.jsx @@ -52,6 +52,9 @@ export default class HtmlImage extends React.PureComponent { this._onVisibilityWriter = this.onVisibilityWriter.bind(this); this._rootElement = React.createRef(); + + this._helper = this.utils.$UIComponentHelper; + this._settings = this.utils.$Settings; } get utils() { @@ -59,14 +62,20 @@ export default class HtmlImage extends React.PureComponent { } get useIntersectionObserver() { - return !( - this.utils.$Settings && - this.utils.$Settings.plugin && - this.utils.$Settings.plugin.imaUiAtoms && - this.utils.$Settings.plugin.imaUiAtoms.useIntersectionObserver && - this.utils.$Settings.plugin.imaUiAtoms.useIntersectionObserver.images === - false - ); + return this.props.useIntersectionObserver !== undefined + ? this.props.useIntersectionObserver + : this._settings.plugin.imaUiAtoms.useIntersectionObserver.images !== + undefined + ? this._settings.plugin.imaUiAtoms.useIntersectionObserver.images + : this._settings.plugin.imaUiAtoms.useIntersectionObserver; + } + + get disableNoScript() { + return this.props.disableNoScript !== undefined + ? this.props.disableNoScript + : this._settings.plugin.imaUiAtoms.disableNoScript.images !== undefined + ? this._settings.plugin.imaUiAtoms.disableNoScript.images + : this._settings.plugin.imaUiAtoms.disableNoScript; } componentDidMount() { @@ -97,12 +106,10 @@ export default class HtmlImage extends React.PureComponent { } render() { - let helper = this.utils.$UIComponentHelper; - return (
+ {...this._helper.getDataProps(this.props)}> {this.props.layout === 'responsive' ? ( ) : null} {this.state.showLoader && !this.state.noloading ? ( ) : null} -
); } @@ -172,32 +183,29 @@ export default class HtmlImage extends React.PureComponent { _unregisterToCheckingVisibility() { if (this._registeredVisibilityId) { - this.utils.$UIComponentHelper.visibility.unregister( - this._registeredVisibilityId - ); + this._helper.visibility.unregister(this._registeredVisibilityId); this._registeredVisibilityId = null; } } _registerToCheckingVisibility() { - let { $UIComponentHelper } = this.utils; let extendedPadding = this.props.extendedPadding || Math.max( Math.round( - $UIComponentHelper.componentPositions.getWindowViewportRect().height + this._helper.componentPositions.getWindowViewportRect().height ), MIN_EXTENDED_PADDING ); - this._registeredVisibilityId = $UIComponentHelper.visibility.register( - $UIComponentHelper.getVisibilityReader(this._rootElement.current, { + this._registeredVisibilityId = this._helper.visibility.register( + this._helper.getVisibilityReader(this._rootElement.current, { extendedPadding, useIntersectionObserver: this.useIntersectionObserver, width: this.props.width, height: this.props.height }), - $UIComponentHelper.wrapVisibilityWriter(this._onVisibilityWriter) + this._helper.wrapVisibilityWriter(this._onVisibilityWriter) ); } diff --git a/src/main.js b/src/main.js index 9f666e9..6118fde 100644 --- a/src/main.js +++ b/src/main.js @@ -31,9 +31,9 @@ import Sizer from './sizer/Sizer'; import Video from './video/Video'; -let defaultDependencies = ['$Router', ComponentPositions, Visibility]; +const defaultDependencies = ['$Router', ComponentPositions, Visibility]; -let $registerImaPlugin = ns => { +const $registerImaPlugin = ns => { ns.namespace('ima.ui.atom'); ns.namespace('ima.ui.atom.headline'); ns.namespace('ima.ui.atom.iframe'); @@ -45,7 +45,7 @@ let $registerImaPlugin = ns => { ns.namespace('ima.ui.atom.sizer'); ns.namespace('ima.ui.atom.video'); - let nsHeadline = ns.ima.ui.atom.headline; + const nsHeadline = ns.ima.ui.atom.headline; nsHeadline.Headline = Headline; nsHeadline.Headline1 = Headline1; nsHeadline.Headline2 = Headline2; @@ -68,7 +68,7 @@ let $registerImaPlugin = ns => { ns.ima.ui.atom.link.Link = Link; ns.ima.ui.atom.link.A = Link; - let nsList = ns.ima.ui.atom.list; + const nsList = ns.ima.ui.atom.list; nsList.List = List; nsList.ListItem = ListItem; nsList.OrderedList = OrderedList; @@ -92,15 +92,36 @@ let $registerImaPlugin = ns => { ns.ima.ui.atom.defaultDependencies = defaultDependencies; }; -let initBind = (ns, oc) => { +const initBind = (ns, oc) => { oc.inject(Infinite, []); //oc.inject(UIComponentHelper, defaultDependencies); }; -let initServices = (ns, oc) => { +const initServices = (ns, oc) => { oc.get(UIComponentHelper).init(); }; +const initSettings = () => { + return { + prod: { + plugin: { + imaUiAtoms: { + useIntersectionObserver: { + iframes: true, + images: true, + videos: true + }, + disableNoScript: { + iframes: false, + images: false, + videos: false + } + } + } + } + }; +}; + export { UIComponentHelper, Visibility, @@ -138,6 +159,7 @@ export { Video, initBind, initServices, + initSettings, $registerImaPlugin, Circle, Infinite, diff --git a/src/mocks/settings.js b/src/mocks/settings.js new file mode 100644 index 0000000..f2f0df3 --- /dev/null +++ b/src/mocks/settings.js @@ -0,0 +1,18 @@ +const settings = { + plugin: { + imaUiAtoms: { + useIntersectionObserver: { + iframes: true, + images: true, + videos: true + }, + disableNoScript: { + iframes: false, + images: false, + videos: false + } + } + } +}; + +export default settings; diff --git a/src/video/HtmlVideo.jsx b/src/video/HtmlVideo.jsx index 5a569b3..e5193b1 100644 --- a/src/video/HtmlVideo.jsx +++ b/src/video/HtmlVideo.jsx @@ -33,6 +33,9 @@ export default class HtmlVideo extends React.PureComponent { this._onVisibilityWriter = this.onVisibilityWriter.bind(this); this._rootElement = React.createRef(); + + this._helper = this.utils.$UIComponentHelper; + this._settings = this.utils.$Settings; } get utils() { @@ -40,23 +43,27 @@ export default class HtmlVideo extends React.PureComponent { } get useIntersectionObserver() { - return !( - this.utils.$Settings && - this.utils.$Settings.plugin && - this.utils.$Settings.plugin.imaUiAtoms && - this.utils.$Settings.plugin.imaUiAtoms.useIntersectionObserver && - this.utils.$Settings.plugin.imaUiAtoms.useIntersectionObserver.videos === - false - ); + return this.props.useIntersectionObserver !== undefined + ? this.props.useIntersectionObserver + : this._settings.plugin.imaUiAtoms.useIntersectionObserver.videos !== + undefined + ? this._settings.plugin.imaUiAtoms.useIntersectionObserver.videos + : this._settings.plugin.imaUiAtoms.useIntersectionObserver; } - render() { - let helper = this.utils.$UIComponentHelper; + get disableNoScript() { + return this.props.disableNoScript !== undefined + ? this.props.disableNoScript + : this._settings.plugin.imaUiAtoms.disableNoScript.videos !== undefined + ? this._settings.plugin.imaUiAtoms.disableNoScript.videos + : this._settings.plugin.imaUiAtoms.disableNoScript; + } + render() { return (
+ {...this._helper.getDataProps(this.props)}> {this.props.layout === 'responsive' ? ( + {...this._helper.getAriaProps(this.props)}>
{this.props.children} ) : null} -
); } @@ -142,29 +153,26 @@ export default class HtmlVideo extends React.PureComponent { _unregisterToCheckingVisibility() { if (this._registeredVisibilityId) { - this.utils.$UIComponentHelper.visibility.unregister( - this._registeredVisibilityId - ); + this._helper.visibility.unregister(this._registeredVisibilityId); this._registeredVisibilityId = null; } } _registerToCheckingVisibility() { - let { $UIComponentHelper } = this.utils; let extendedPadding = Math.max( Math.round( - $UIComponentHelper.componentPositions.getWindowViewportRect().height / 2 + this._helper.componentPositions.getWindowViewportRect().height / 2 ), EXTENDED_PADDING ); - this._registeredVisibilityId = $UIComponentHelper.visibility.register( - $UIComponentHelper.getVisibilityReader(this._rootElement.current, { + this._registeredVisibilityId = this._helper.visibility.register( + this._helper.getVisibilityReader(this._rootElement.current, { useIntersectionObserver: this.useIntersectionObserver, extendedPadding, width: this.props.width, height: this.props.height }), - $UIComponentHelper.wrapVisibilityWriter(this._onVisibilityWriter) + this._helper.wrapVisibilityWriter(this._onVisibilityWriter) ); }