Skip to content

Commit 2a29fa7

Browse files
authored
Merge pull request #177 from tkloht/react16
React16
2 parents 86a00c0 + 633f05f commit 2a29fa7

File tree

12 files changed

+8229
-82
lines changed

12 files changed

+8229
-82
lines changed

.babelrc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"presets": ["stage-0", "es2015", "react"],
3+
"plugins": [
4+
["transform-class-properties"],
5+
],
6+
}

__mocks__/fileMock.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
module.exports = 'test-file-stub';

__mocks__/react-intl.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import React from 'react';
2+
3+
const Intl = require.requireActual('react-intl');
4+
5+
// Here goes intl context injected into component, feel free to extend
6+
const intl = {
7+
formatMessage: ({defaultMessage}) => defaultMessage
8+
};
9+
10+
Intl.injectIntl = (Node) => {
11+
const renderWrapped = props => <Node {...props} intl={intl} />;
12+
renderWrapped.displayName = Node.displayName
13+
|| Node.name
14+
|| 'Component';
15+
return renderWrapped;
16+
};
17+
18+
module.exports = Intl;

__mocks__/styleMock.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
module.exports = {};

lib/__tests__/.eslintrc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"rules": {
3+
"max-len": 0,
4+
},
5+
}

lib/__tests__/VideoCover.spec.js

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
/* eslint-env mocha*/
2+
import VideoCover from '../index';
3+
import VideoCoverFallback from '../VideoCoverFallback';
4+
5+
import React from 'react';
6+
import { shallow } from 'enzyme';
7+
8+
function setUserAgent(userAgent) {
9+
const originalNavigator = window.navigator;
10+
/* eslint-disable no-native-reassign, no-proto, no-underscore-dangle */
11+
navigator = {};
12+
navigator.__proto__ = originalNavigator;
13+
navigator.__defineGetter__('userAgent', () => userAgent);
14+
/* eslint-enable no-native-reassign, no-proto, no-underscore-dangle */
15+
}
16+
17+
describe('VideoCover', () => {
18+
it('should render a video tag', () => {
19+
const wrapper = shallow(<VideoCover />);
20+
const video = wrapper.find('video');
21+
expect(video).toExist();
22+
});
23+
24+
it('should not render Fallback component by default', () => {
25+
const wrapper = shallow(<VideoCover />);
26+
expect(wrapper.find(VideoCoverFallback)).not.toExist();
27+
});
28+
29+
it('should set classname of <video/> according prop', () => {
30+
const className = 'WhateverClassNameYouWant EvenMultipleClassNames';
31+
const wrapper = shallow(<VideoCover className={className} />);
32+
expect(wrapper).toHaveClassName('WhateverClassNameYouWant');
33+
expect(wrapper).toHaveClassName('EvenMultipleClassNames');
34+
});
35+
36+
it('should render Fallback component if forceFallback prop is set', () => {
37+
const wrapper = shallow(<VideoCover forceFallback />);
38+
expect(wrapper.find(VideoCoverFallback)).toExist();
39+
});
40+
41+
describe('styles without fallback', () => {
42+
it('should have width and height 100% by default', () => {
43+
const wrapper = shallow(<VideoCover />);
44+
expect(wrapper).toHaveStyle('height', '100%');
45+
expect(wrapper).toHaveStyle('width', '100%');
46+
});
47+
it('should have any additional styles passed in via style-prop', () => {
48+
const wrapper = shallow(<VideoCover />);
49+
expect(wrapper).not.toHaveStyle('background-color');
50+
expect(wrapper).not.toHaveStyle('color');
51+
expect(wrapper).not.toHaveStyle('line-height');
52+
const nextWrapper = wrapper.setProps({
53+
style: {
54+
backgroundColor: 'red',
55+
color: 'teal',
56+
lineHeight: 10,
57+
},
58+
});
59+
expect(wrapper).toHaveStyle({
60+
backgroundColor: 'red',
61+
color: 'teal',
62+
lineHeight: 10,
63+
});
64+
});
65+
it('should be possible to override width and height props', () => {
66+
const wrapper = shallow(<VideoCover style={{ width: '50%', height: '50%' }} />);
67+
expect(wrapper).toHaveStyle('height', '50%');
68+
expect(wrapper).toHaveStyle('width', '50%');
69+
});
70+
it('should have object-fit set to cover', () => {
71+
const wrapper = shallow(<VideoCover />);
72+
expect(wrapper).toHaveStyle('objectFit', 'cover');
73+
});
74+
it('should not be possible to override object-fit', () => {
75+
const wrapper = shallow(<VideoCover style={{ objectFit: 'contain' }} />);
76+
expect(wrapper).toHaveStyle('objectFit', 'cover');
77+
});
78+
});
79+
80+
// TODO: couldn't figure out how to mock the useragent with jest/jsdom
81+
// re-enable these tests when fixed (see setUserAgent())
82+
describe.skip('UserAgent', () => {
83+
/* eslint-disable max-len */
84+
const originalNavigator = window.navigator;
85+
const userAgents = [
86+
{
87+
name: 'Trident',
88+
needsFallback: true,
89+
value: `Mozilla/5.0(compatible; MSIE 10.0;
90+
WindowsNT 6.2; Win64; x64; Trident/6.0)`,
91+
},
92+
{
93+
name: 'Edge',
94+
needsFallback: true,
95+
value: `Mozilla/5.0 (Windows NT 6.4; WOW64) AppleWebKit/537.36
96+
(KHTML, like Gecko) Chrome/36.0.1985.143 Safari/537.36 Edge/12.0`,
97+
},
98+
{
99+
name: 'Safari',
100+
needsFallback: false,
101+
value: `Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4)
102+
AppleWebKit/601.5.17 (KHTML, like Gecko) Version/9.1 Safari/601.5.17`,
103+
},
104+
{
105+
name: 'Chrome',
106+
needsFallback: false,
107+
value: `Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4)
108+
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.86 Safari/537.36`,
109+
},
110+
{
111+
name: 'Firefox',
112+
needsFallback: false,
113+
value: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:44.0) Gecko/20100101 Firefox/44.0',
114+
},
115+
];
116+
117+
afterEach(() => {
118+
// reset to original navigator after each test
119+
window.navigator = originalNavigator;
120+
});
121+
122+
/* generate tests for some known userAgents */
123+
userAgents.forEach(({ needsFallback, name, value }) => {
124+
it(`should ${
125+
needsFallback ? '' : 'NOT'
126+
} render Fallback if ${name} userAgent is used`, () => {
127+
setUserAgent(value);
128+
const wrapper = shallow(<VideoCover />);
129+
if (needsFallback) {
130+
expect(wrapper.find(VideoCoverFallback)).toExist();
131+
} else {
132+
expect(wrapper.find(VideoCoverFallback)).not.toExist();
133+
}
134+
});
135+
});
136+
});
137+
});
Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
import VideoCoverFallback from '../VideoCoverFallback';
2+
3+
import React from 'react';
4+
import { shallow, mount } from 'enzyme';
5+
6+
describe('VideoCoverFallback', () => {
7+
it('should update container ratio when mounted', () => {
8+
const spy = jest.fn();
9+
class WithSpy extends VideoCoverFallback {
10+
updateContainerRatio = spy;
11+
}
12+
mount(<WithSpy />);
13+
expect(spy).toBeCalled();
14+
});
15+
16+
it('should call onFallbackDidMount prop when mounted', () => {
17+
const spy = jest.fn();
18+
mount(<VideoCoverFallback onFallbackDidMount={spy} />);
19+
expect(spy).toBeCalled();
20+
});
21+
22+
it('should pass this.updateContainerRatio as parameter in onFallbackWillUnmount', () => {
23+
let resizeNotifier;
24+
const wrapper = mount(<VideoCoverFallback
25+
onFallbackDidMount={result => {
26+
resizeNotifier = result;
27+
}}
28+
/>);
29+
expect(resizeNotifier).toEqual(wrapper.instance().updateContainerRatio);
30+
});
31+
32+
it('should initialize window-resize eventlisteners if props.remeasureOnWindowResize is set', () => {
33+
const spy = jest.fn();
34+
class WithSpy extends VideoCoverFallback {
35+
initEventListeners = spy;
36+
}
37+
mount(<WithSpy remeasureOnWindowResize />);
38+
expect(spy).toBeCalled();
39+
});
40+
41+
it('should NOT initialize window-resize eventlisteners if props.remeasureOnWindowResize is not set', () => {
42+
const spy = jest.fn();
43+
class WithSpy extends VideoCoverFallback {
44+
initEventListeners = spy;
45+
}
46+
mount(<WithSpy />);
47+
expect(spy).not.toBeCalled();
48+
});
49+
50+
it('should remove eventlisteners before unmount', () => {
51+
const spy = jest.fn();
52+
class WithSpy extends VideoCoverFallback {
53+
removeEventListeners = spy;
54+
}
55+
const wrapper = mount(<WithSpy />);
56+
wrapper.unmount();
57+
expect(spy).toBeCalled();
58+
});
59+
60+
it('should add/remove eventlisteners if props.remeasureOnWindowResize changes', () => {
61+
const addSpy = jest.fn();
62+
const removeSpy = jest.fn();
63+
class WithSpy extends VideoCoverFallback {
64+
initEventListeners = addSpy;
65+
removeEventListeners = removeSpy;
66+
}
67+
const wrapper = mount(<WithSpy />);
68+
expect(addSpy).not.toBeCalled();
69+
expect(removeSpy).not.toBeCalled();
70+
wrapper.setProps({ remeasureOnWindowResize: true });
71+
expect(addSpy).toBeCalled();
72+
expect(removeSpy).not.toBeCalled();
73+
wrapper.setProps({ remeasureOnWindowResize: false });
74+
expect(addSpy).toBeCalled();
75+
expect(removeSpy).toBeCalled();
76+
});
77+
78+
it('should render a video tag inside a container-div', () => {
79+
const wrapper = shallow(<VideoCoverFallback />);
80+
expect(wrapper.find('div')).toExist();
81+
expect(wrapper.find('div video')).toExist();
82+
});
83+
84+
it('should pass props.className to the container-div', () => {
85+
const wrapper = shallow(<VideoCoverFallback className="some-classname" />);
86+
expect(wrapper).toHaveClassName('some-classname');
87+
});
88+
89+
it('should invoke updateVideoRatio on loadedData media event', () => {
90+
const spy = jest.fn();
91+
class WithSpy extends VideoCoverFallback {
92+
updateVideoRatio = spy;
93+
}
94+
const wrapper = shallow(<WithSpy />);
95+
const video = wrapper.find('video');
96+
video.simulate('loadedData', {
97+
target: {
98+
videoWidth: 50,
99+
videoHeight: 50,
100+
},
101+
});
102+
expect(spy).toBeCalledWith(50, 50);
103+
});
104+
105+
it('should apply all props.videoOptions to the video tag', () => {
106+
const wrapper = shallow(<VideoCoverFallback
107+
videoOptions={{
108+
src: 'http://some-video-url.mp4',
109+
}}
110+
/>);
111+
expect(wrapper.find('video')).toHaveProp('src', 'http://some-video-url.mp4');
112+
});
113+
114+
describe('container-styles', () => {
115+
it('should apply props.style to the container-div', () => {
116+
const wrapper = shallow(<VideoCoverFallback
117+
style={{
118+
backgroundColor: 'teal',
119+
lineHeight: '100px',
120+
}}
121+
/>);
122+
expect(wrapper).toHaveStyle('backgroundColor', 'teal');
123+
expect(wrapper).toHaveStyle('lineHeight', '100px');
124+
});
125+
126+
it('should set width and height to 100% by default', () => {
127+
const wrapper = shallow(<VideoCoverFallback />);
128+
expect(wrapper).toHaveStyle('height', '100%');
129+
expect(wrapper).toHaveStyle('width', '100%');
130+
});
131+
132+
it('should be possible to override width and height via props.style', () => {
133+
const wrapper = shallow(<VideoCoverFallback style={{ width: '50%', height: '50%' }} />);
134+
expect(wrapper).toHaveStyle('height', '50%');
135+
expect(wrapper).toHaveStyle('width', '50%');
136+
});
137+
138+
it('should set position relative and overflow: hidden', () => {
139+
const wrapper = shallow(<VideoCoverFallback />);
140+
expect(wrapper).toHaveStyle('position', 'relative');
141+
expect(wrapper).toHaveStyle('overflow', 'hidden');
142+
});
143+
144+
it('should not be possible to override position and overflow', () => {
145+
const wrapper = shallow(<VideoCoverFallback
146+
style={{
147+
position: 'fixed',
148+
overflow: 'scroll',
149+
}}
150+
/>);
151+
expect(wrapper).toHaveStyle('position', 'relative');
152+
expect(wrapper).toHaveStyle('overflow', 'hidden');
153+
});
154+
});
155+
156+
// todo: maybe use generated test-data for this?
157+
describe('video-styles', () => {
158+
it('should have width auto, height 100% if innerRatio > outerRatio', () => {
159+
const wrapper = shallow(<VideoCoverFallback />);
160+
wrapper.setState({
161+
innerRatio: 5,
162+
outerRatio: 3,
163+
});
164+
expect(wrapper.find('video')).toHaveStyle('width', 'auto');
165+
expect(wrapper.find('video')).toHaveStyle('height', '100%');
166+
});
167+
it('should have width 100%, height auto if innerRatio <= outerRatio', () => {
168+
const wrapper = shallow(<VideoCoverFallback />);
169+
wrapper.setState({
170+
innerRatio: 3,
171+
outerRatio: 5,
172+
});
173+
expect(wrapper.find('video')).toHaveStyle('width', '100%');
174+
expect(wrapper.find('video')).toHaveStyle('height', 'auto');
175+
});
176+
});
177+
178+
describe('updateContainerRatio()', () => {
179+
it('should set state.outerRatio to ratio of container width/height', () => {
180+
const mockRef = {
181+
getBoundingClientRect: () => {
182+
const result = {
183+
width: 4,
184+
height: 5,
185+
};
186+
return result;
187+
},
188+
};
189+
class WithRef extends VideoCoverFallback {
190+
containerRef = mockRef;
191+
}
192+
const wrapper = shallow(<WithRef />);
193+
wrapper.instance().updateContainerRatio();
194+
expect(wrapper).toHaveState('outerRatio', 4 / 5);
195+
});
196+
});
197+
198+
describe('updateVideoRatio()', () => {
199+
it('should set state.innerRatio to ratio of video width/height', () => {
200+
const wrapper = shallow(<VideoCoverFallback />);
201+
expect(wrapper).toHaveState('innerRatio', undefined);
202+
wrapper.instance().updateVideoRatio(4, 5);
203+
expect(wrapper).toHaveState('innerRatio', 4 / 5);
204+
});
205+
});
206+
});

0 commit comments

Comments
 (0)