Skip to content

Commit b15b44f

Browse files
committed
feat: add test case and update IntersectionObserver use
1 parent 143e87b commit b15b44f

File tree

8 files changed

+241
-19
lines changed

8 files changed

+241
-19
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,3 +55,4 @@ website
5555
.docz
5656
lib/**
5757
es
58+
coverage/

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@
2323
"dev": "cross-env NODE_ENV=development webpack-serve --config=./build/dev.conf.js --host 0.0.0.0 --port 2222",
2424
"pub": "npm run lint && npm run build:rollup && npm publish --registry http://registry.npmjs.org --access=public",
2525
"test": "cross-env NODE_ENV=test jest",
26-
"test-watch": "cross-env NODE_ENV=test jest --watchAll"
26+
"test-watch": "cross-env NODE_ENV=test jest --watchAll",
27+
"test-coverage": "cross-env NODE_ENV=test jest --coverage"
2728
},
2829
"author": "zhengzwing@gmail.com",
2930
"license": "MIT",
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import React from 'react'
2+
import ImageComponent from '..'
3+
import { shallow, mount } from 'enzyme'
4+
5+
function getComp(prop) {
6+
return <ImageComponent src="test.png" {...prop} />
7+
}
8+
9+
describe('test when IntersectionObserver is true', () => {
10+
const observe = jest.fn()
11+
const unobserve = jest.fn()
12+
beforeAll(() => {
13+
window.IntersectionObserver = jest.fn(function() {
14+
this.observe = observe
15+
this.unobserve = unobserve
16+
})
17+
})
18+
it('observe img', () => {
19+
const wrapper = shallow(getComp())
20+
expect(observe).toBeCalledTimes(1)
21+
expect(wrapper.instance().state.loadObserve).toBeFalsy()
22+
expect(wrapper.find('img').length).toEqual(0)
23+
const observerCallback = window.IntersectionObserver.mock.calls[0][0]
24+
observerCallback([
25+
{ target: wrapper.instance().refDom.current, intersectionRatio: 100 }
26+
])
27+
expect(unobserve).toBeCalledTimes(1)
28+
expect(wrapper.instance().state.loadObserve).toBeTruthy()
29+
expect(wrapper.find('img').length).toEqual(1)
30+
wrapper.instance().componentWillUnmount()
31+
expect(unobserve).toBeCalledTimes(1)
32+
})
33+
})
Lines changed: 114 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,117 @@
1-
import React from 'react'
2-
import Image from '..'
3-
import { shallow } from 'enzyme'
41

5-
describe('Image', () => {
6-
it('Image Mounted', () => {
7-
const result = shallow(<Image src='test.png'/>)
8-
expect(result.instance().props.src).toEqual('test.png')
2+
import React from 'react'
3+
import ImageComponent from '..'
4+
import { shallow, mount } from 'enzyme'
5+
import ErrorIcon from '../../ErrorIcon'
6+
function getComp(prop) {
7+
return <ImageComponent src="test.png" {...prop}/>
8+
}
9+
describe('test when IntersectionObserver is false', () => {
10+
it('Image set src prop', () => {
11+
const result = mount(getComp())
12+
expect(result.props().src).toEqual('test.png')
13+
result.setProps({ src: 'test2.png' })
14+
expect(result.props().src).toEqual('test2.png')
15+
})
16+
it('test onClick', () => {
17+
const onClick = jest.fn().mockReturnValue(null)
18+
const result = shallow(getComp({onClick}))
19+
result.find('img').simulate('click')
20+
expect(onClick).toBeCalledTimes(1)
21+
})
22+
it('test onLoad, and LoadingIcon should hide', () => {
23+
const onLoad = jest.fn().mockReturnValue(null)
24+
const result = mount(getComp({onLoad}))
25+
expect(result.instance().state.isLoading).toBe(true)
26+
result.find('img').simulate('load')
27+
expect(onLoad).toBeCalledTimes(1)
28+
expect(result.instance().state.isLoading).toBe(false)
29+
expect(result.find('.mask-loading').length).toEqual(0)
30+
})
31+
it('test onError, and ErrorIcon should show', () => {
32+
const onError = jest.fn().mockReturnValue(null)
33+
const result = mount(getComp({onError}))
34+
expect(result.instance().state.isError).toBe(false)
35+
result.find('img').simulate('error')
36+
expect(onError).toBeCalledTimes(1)
37+
expect(result.instance().state.isError).toBe(true)
38+
expect(result.find(ErrorIcon).length).toEqual(1)
39+
})
40+
it('test delete', () => {
41+
const onDelete = jest.fn().mockReturnValue(null)
42+
const result = mount(getComp({onDelete}))
43+
result.find('.react-image-icon').simulate('click')
44+
expect(onDelete).toBeCalledTimes(1)
45+
})
46+
it('test group & preview prop', () => {
47+
const group = '100'
48+
const result = mount(getComp({group}))
49+
expect(result.find('.mask-img').prop('data-img-group')).toEqual('100')
50+
})
51+
it('data-index-group is "null" when preview is false', () => {
52+
const result = mount(
53+
getComp({group: '100', preview: false})
54+
)
55+
expect(result.find('.mask-img').prop('data-img-group')).toEqual(null)
56+
})
57+
it('test className prop', () => {
58+
const className = 'test'
59+
const result = shallow(
60+
getComp({className})
61+
)
62+
expect(result.find('.mask-img').hasClass('test')).toBe(true)
63+
})
64+
it('test "style", "width" and "height" props', () => {
65+
const style = { background: 'red', testStyle: '1' }
66+
let result = shallow(
67+
getComp({width: 120, style})
68+
)
69+
expect(result.instance().style).toEqual({
70+
width: '120px',
71+
height: 'initial',
72+
background: 'red',
73+
testStyle: '1'
74+
})
75+
result = shallow(getComp({height: 100}))
76+
expect(result.instance().style).toEqual({
77+
width: '100px',
78+
height: '100px'
79+
})
80+
})
81+
it('test img style, style.display is "none" when "isLoading" or "isError" is true', () => {
82+
const imgStyle = { testImgStyle: 'test' }
83+
const result = shallow(
84+
getComp({
85+
imgProps: {style: imgStyle},
86+
objectFit: 'scale-down'
87+
})
88+
)
89+
const commonExpect = {
90+
objectFit: 'scale-down',
91+
testImgStyle: 'test'
92+
}
93+
expect(result.instance().imgStyle).toEqual({
94+
display: 'none',
95+
...commonExpect
96+
})
97+
result.find('img').simulate('load')
98+
expect(result.instance().imgStyle).toEqual({
99+
display: '',
100+
...commonExpect
101+
})
102+
})
103+
it('test img prop', () => {
104+
const imgProps = { 'data-index': 10 }
105+
const result = shallow(getComp({imgProps}))
106+
expect(result.find('img').prop('data-index')).toEqual(10)
107+
})
108+
it('test mask prop', () => {
109+
const mask = false
110+
const result = shallow(getComp({mask}))
111+
expect(result.find('.mask-img').hasClass('mask')).toBeFalsy()
112+
})
113+
it('test refDom', () => {
114+
const result = mount(<ImageComponent src="test.png" />)
115+
expect(result.instance().refDom.current).toBeTruthy()
9116
})
10117
})
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import {
2+
CanUseIntersecion, createObserver, observe, unobserve
3+
} from '../observer'
4+
5+
describe('test when IntersectionObserver is false', () => {
6+
const observeFn = jest.fn()
7+
const unobserveFn = jest.fn()
8+
beforeAll(() => {
9+
window.IntersectionObserver = jest.fn(function(excute, opt) {
10+
this.observe = observeFn
11+
this.unobserve = unobserveFn
12+
this.root = opt.root
13+
})
14+
})
15+
it('CanUseIntersecion return true', () => {
16+
expect(CanUseIntersecion()).toBeTruthy()
17+
})
18+
it('createObserver', () => {
19+
const observer1 = createObserver()
20+
expect(observer1).toBeTruthy()
21+
const observer2 = createObserver(document.body)
22+
expect(observer2.root).toBe(document.body)
23+
})
24+
it('observe callback', () => {
25+
const observeCb = jest.fn()
26+
const dom = document.body
27+
observe(dom, observeCb)
28+
const observerCallback = window.IntersectionObserver.mock.calls[0][0]
29+
observerCallback([
30+
{ target: dom, intersectionRatio: 100 }
31+
])
32+
expect(observeCb).toBeCalledTimes(1)
33+
expect(unobserveFn).toBeCalledTimes(1)
34+
observerCallback([
35+
{ target: dom, intersectionRatio: 100 }
36+
])
37+
expect(observeCb).toBeCalledTimes(1)
38+
expect(unobserveFn).toBeCalledTimes(1)
39+
})
40+
})
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import {
2+
CanUseIntersecion, createObserver, observe, unobserve
3+
} from '../observer'
4+
5+
describe('test when IntersectionObserver is false', () => {
6+
it('CanUseIntersecion return Falsy', () => {
7+
expect(CanUseIntersecion()).toBeFalsy()
8+
})
9+
it('createObserver return null', () => {
10+
expect(createObserver()).toBeNull()
11+
})
12+
it('observe and unobserve return undefined', () => {
13+
expect(observe()).toBeUndefined()
14+
expect(unobserve()).toBeUndefined()
15+
})
16+
})

src/lib/Image/index.jsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ export default class ReactImage extends React.PureComponent {
5353
state = {
5454
isError: false,
5555
isLoading: true,
56-
loadObserve: !CanUseIntersecion // InterseciontObserver, 监听图片是否出现在viewport
56+
loadObserve: !CanUseIntersecion() // InterseciontObserver, 监听图片是否出现在viewport
5757
}
5858

5959
get style() {
@@ -123,7 +123,9 @@ export default class ReactImage extends React.PureComponent {
123123
}
124124

125125
componentWillUnmount() {
126-
unobserve(this.refDom.current, this.props.observer)
126+
if(!this.state.loadObserve) {
127+
unobserve(this.refDom.current, this.props.observer)
128+
}
127129
}
128130

129131
render() {

src/lib/Image/observer.js

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,19 @@
44
* 出现才进行加载
55
* 如果浏览器不支持InterseciontObserver, 则不作操作
66
*/
7-
export const CanUseIntersecion = 'IntersectionObserver' in window
7+
let canUse = null
8+
export const CanUseIntersecion = function() {
9+
if(canUse !== null) {
10+
return canUse
11+
}
12+
canUse = 'IntersectionObserver' in window
13+
return canUse
14+
}
815
// const targets = []
916
const targets = new Map()
1017
/* eslint-disable */
1118
export function createObserver(container) {
12-
if(!CanUseIntersecion) {
19+
if(!CanUseIntersecion()) {
1320
return null
1421
}
1522
const opt = {}
@@ -19,24 +26,37 @@ export function createObserver(container) {
1926
return new IntersectionObserver(excute, opt)
2027
}
2128
// const ins = CanUseIntersecion ? new IntersectionObserver(excute) : null
22-
const ins = createObserver()
29+
let ins = null
30+
31+
function getObserve(observer) {
32+
if(observer) {
33+
return observer
34+
}
35+
if(!ins) {
36+
ins = createObserver()
37+
}
38+
return ins
39+
}
40+
2341
/* eslint-enable */
2442

25-
export function observe(element, cb, observer = ins) {
26-
if(!CanUseIntersecion) {
43+
export function observe(element, cb, obs) {
44+
if(!CanUseIntersecion()) {
2745
return
2846
}
47+
const observer = getObserve(obs)
2948
observer.observe(element)
3049
targets.set(element, {
3150
cb,
3251
observer
3352
})
3453
}
3554

36-
export function unobserve(element, observer = ins) {
37-
if(!CanUseIntersecion) {
55+
export function unobserve(element, obs) {
56+
if(!CanUseIntersecion()) {
3857
return
3958
}
59+
const observer = getObserve(obs)
4060
targets.delete(element)
4161
observer.unobserve(element)
4262
}
@@ -46,8 +66,10 @@ function excute(entries) {
4666
const { target, intersectionRatio } = each
4767
if(intersectionRatio > 0) {
4868
const tar = targets.get(target)
49-
tar.cb(each)
50-
unobserve(target, tar.observer)
69+
if(tar) {
70+
tar.cb(each)
71+
unobserve(target, tar.observer)
72+
}
5173
}
5274
})
5375
}

0 commit comments

Comments
 (0)