Skip to content

Commit 98df40f

Browse files
committed
chore: cleanup and test useParallax hook
1 parent cde557f commit 98df40f

File tree

3 files changed

+187
-41
lines changed

3 files changed

+187
-41
lines changed

src/helpers/getParallaxProps.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { ParallaxElementConfig } from 'parallax-controller';
2+
import { removeUndefinedObjectKeys } from '../utils/removeUndefinedObjectKeys';
3+
4+
export function getParallaxProps(
5+
props: ParallaxElementConfig
6+
): ParallaxElementConfig {
7+
return removeUndefinedObjectKeys({
8+
speed: props.speed,
9+
translateX: props.translateX,
10+
translateY: props.translateY,
11+
disabled: props.disabled,
12+
rotate: props.rotate,
13+
rotateX: props.rotateX,
14+
rotateY: props.rotateY,
15+
rotateZ: props.rotateZ,
16+
scale: props.scale,
17+
scaleX: props.scaleX,
18+
scaleY: props.scaleY,
19+
scaleZ: props.scaleZ,
20+
opacity: props.opacity,
21+
easing: props.easing,
22+
rootMargin: props.rootMargin,
23+
shouldStartAnimationInitialInView: props.shouldStartAnimationInitialInView,
24+
onProgressChange: props.onProgressChange,
25+
onChange: props.onChange,
26+
onEnter: props.onEnter,
27+
onExit: props.onExit,
28+
startScroll: props.startScroll,
29+
endScroll: props.endScroll,
30+
targetElement: props.targetElement,
31+
});
32+
}

src/hooks/useParallax.test.tsx

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
import React, { PropsWithChildren, useRef } from 'react';
2+
import { renderHook, act } from '@testing-library/react-hooks';
3+
import { ParallaxController, ScrollAxis, Element } from 'parallax-controller';
4+
import { MockProvider } from '../testUtils/MockProvider';
5+
import { useParallax } from './useParallax';
6+
7+
jest.mock('react', () => {
8+
return {
9+
...jest.requireActual<typeof React>('react'),
10+
useRef: jest.fn(() => ({
11+
current: document.createElement('div'),
12+
})),
13+
};
14+
});
15+
16+
describe('given useParallax hook', () => {
17+
beforeAll(() => {
18+
// NOTE: stop console warning of expected error
19+
jest.spyOn(console, 'error').mockImplementation(() => {});
20+
});
21+
22+
afterEach(() => {
23+
jest.clearAllMocks();
24+
// @ts-expect-error
25+
useRef.mockImplementation(
26+
jest.fn(() => ({
27+
current: document.createElement('div'),
28+
}))
29+
);
30+
});
31+
32+
afterAll(() => {
33+
jest.resetAllMocks();
34+
});
35+
36+
describe('when not wrapped by the ParallaxProvider', () => {
37+
test('then it should throw an error', () => {
38+
try {
39+
const { result } = renderHook(() =>
40+
useParallax({ translateX: [0, 100] })
41+
);
42+
43+
act(() => {
44+
result.current.controller?.update();
45+
});
46+
47+
expect(result.error).toEqual(
48+
Error(
49+
'Could not find `react-scroll-parallax` context value. Please ensure the component is wrapped in a <ParallaxProvider>'
50+
)
51+
);
52+
} catch (e) {}
53+
});
54+
});
55+
56+
describe('when wrapped by the ParallaxProvider', () => {
57+
describe('when ref is not assigned', () => {
58+
test('then it should throw an error', () => {
59+
// NOTE: must override the useRef mock that returns an element
60+
// @ts-expect-error
61+
useRef.mockImplementation(
62+
jest.fn(() => ({
63+
current: null,
64+
}))
65+
);
66+
67+
try {
68+
const controller = ParallaxController.init({
69+
scrollAxis: ScrollAxis.vertical,
70+
});
71+
controller.createElement = jest.fn(controller.createElement);
72+
const Wrapper = (props: PropsWithChildren<{}>) => (
73+
<MockProvider controllerMock={controller}>
74+
{props.children}
75+
</MockProvider>
76+
);
77+
78+
const { result } = renderHook(
79+
() => useParallax({ translateX: [0, 100] }),
80+
{ wrapper: Wrapper }
81+
);
82+
83+
expect(result.error).toEqual(
84+
Error(
85+
'You must assign the ref returned by the useParallax() hook to an HTML Element.'
86+
)
87+
);
88+
} catch (e) {}
89+
});
90+
});
91+
});
92+
93+
describe('when wrapped by the ParallaxProvider', () => {
94+
test('then it should return an instance of the controller', () => {
95+
const controller = ParallaxController.init({
96+
scrollAxis: ScrollAxis.vertical,
97+
});
98+
controller.createElement = jest.fn(controller.createElement);
99+
const Wrapper = (props: PropsWithChildren<{}>) => (
100+
<MockProvider controllerMock={controller}>
101+
{props.children}
102+
</MockProvider>
103+
);
104+
105+
const { result } = renderHook(
106+
() =>
107+
useParallax<HTMLDivElement>({
108+
translateX: [0, 100],
109+
}),
110+
{ wrapper: Wrapper }
111+
);
112+
113+
expect(result.current.controller).toBeInstanceOf(ParallaxController);
114+
});
115+
116+
test('then it should return the created element', () => {
117+
const controller = ParallaxController.init({
118+
scrollAxis: ScrollAxis.vertical,
119+
});
120+
controller.createElement = jest.fn(controller.createElement);
121+
const Wrapper = (props: PropsWithChildren<{}>) => (
122+
<MockProvider controllerMock={controller}>
123+
{props.children}
124+
</MockProvider>
125+
);
126+
127+
const { result } = renderHook(
128+
() =>
129+
useParallax<HTMLDivElement>({
130+
translateX: [0, 100],
131+
}),
132+
{ wrapper: Wrapper }
133+
);
134+
135+
expect(result.current.element).toBeInstanceOf(Element);
136+
expect(result.current.element?.props.translateX).toEqual([0, 100]);
137+
});
138+
});
139+
});

src/hooks/useParallax.ts

Lines changed: 16 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import { CreateElementOptions, Element } from 'parallax-controller';
22
import { useEffect, useRef, useState } from 'react';
33
import { useVerifyController } from '../components/Parallax/hooks';
4+
import { getParallaxProps } from '../helpers/getParallaxProps';
45
import { ParallaxProps } from '../types';
5-
import { removeUndefinedObjectKeys } from '../utils/removeUndefinedObjectKeys';
66
import { useController } from './useController';
77

88
export function useParallax<T extends HTMLElement>(props: ParallaxProps) {
@@ -11,46 +11,23 @@ export function useParallax<T extends HTMLElement>(props: ParallaxProps) {
1111

1212
useVerifyController(controller);
1313

14-
function _getElementOptions(): CreateElementOptions {
15-
return {
16-
// @ts-expect-error
17-
el: ref.current,
18-
props: removeUndefinedObjectKeys({
19-
speed: props.speed,
20-
translateX: props.translateX,
21-
translateY: props.translateY,
22-
disabled: props.disabled,
23-
rotate: props.rotate,
24-
rotateX: props.rotateX,
25-
rotateY: props.rotateY,
26-
rotateZ: props.rotateZ,
27-
scale: props.scale,
28-
scaleX: props.scaleX,
29-
scaleY: props.scaleY,
30-
scaleZ: props.scaleZ,
31-
opacity: props.opacity,
32-
easing: props.easing,
33-
rootMargin: props.rootMargin,
34-
shouldStartAnimationInitialInView:
35-
props.shouldStartAnimationInitialInView,
36-
onProgressChange: props.onProgressChange,
37-
onChange: props.onChange,
38-
onEnter: props.onEnter,
39-
onExit: props.onExit,
40-
startScroll: props.startScroll,
41-
endScroll: props.endScroll,
42-
targetElement: props.targetElement,
43-
}),
44-
};
45-
}
46-
4714
const [element, setElement] = useState<Element>();
4815

4916
// create element
5017
useEffect(() => {
51-
const newElement = controller?.createElement(_getElementOptions());
52-
53-
setElement(newElement);
18+
let newElement: Element | undefined;
19+
if (ref.current instanceof HTMLElement) {
20+
const options: CreateElementOptions = {
21+
el: ref.current,
22+
props: getParallaxProps(props),
23+
};
24+
newElement = controller?.createElement(options);
25+
setElement(newElement);
26+
} else {
27+
throw new Error(
28+
'You must assign the ref returned by the useParallax() hook to an HTML Element.'
29+
);
30+
}
5431

5532
return () => {
5633
if (newElement) {
@@ -65,10 +42,8 @@ export function useParallax<T extends HTMLElement>(props: ParallaxProps) {
6542
if (props.disabled) {
6643
controller?.resetElementStyles(element);
6744
} else {
68-
controller?.updateElementPropsById(
69-
element.id,
70-
_getElementOptions().props
71-
);
45+
const newProps = getParallaxProps(props);
46+
controller?.updateElementPropsById(element.id, newProps);
7247
}
7348
}
7449
}, [

0 commit comments

Comments
 (0)