summaryrefslogtreecommitdiff
path: root/preact/hooks/test/browser/useImperativeHandle.test.js
diff options
context:
space:
mode:
Diffstat (limited to 'preact/hooks/test/browser/useImperativeHandle.test.js')
-rw-r--r--preact/hooks/test/browser/useImperativeHandle.test.js182
1 files changed, 182 insertions, 0 deletions
diff --git a/preact/hooks/test/browser/useImperativeHandle.test.js b/preact/hooks/test/browser/useImperativeHandle.test.js
new file mode 100644
index 0000000..52cc073
--- /dev/null
+++ b/preact/hooks/test/browser/useImperativeHandle.test.js
@@ -0,0 +1,182 @@
+import { createElement, render } from 'preact';
+import { setupScratch, teardown } from '../../../test/_util/helpers';
+import { useImperativeHandle, useRef, useState } from 'preact/hooks';
+import { setupRerender } from 'preact/test-utils';
+
+/** @jsx createElement */
+
+describe('useImperativeHandle', () => {
+ /** @type {HTMLDivElement} */
+ let scratch;
+
+ /** @type {() => void} */
+ let rerender;
+
+ beforeEach(() => {
+ scratch = setupScratch();
+ rerender = setupRerender();
+ });
+
+ afterEach(() => {
+ teardown(scratch);
+ });
+
+ it('Mutates given ref', () => {
+ let ref;
+
+ function Comp() {
+ ref = useRef({});
+ useImperativeHandle(ref, () => ({ test: () => 'test' }), []);
+ return <p>Test</p>;
+ }
+
+ render(<Comp />, scratch);
+ expect(ref.current).to.have.property('test');
+ expect(ref.current.test()).to.equal('test');
+ });
+
+ it('calls createHandle after every render by default', () => {
+ let ref,
+ createHandleSpy = sinon.spy();
+
+ function Comp() {
+ ref = useRef({});
+ useImperativeHandle(ref, createHandleSpy);
+ return <p>Test</p>;
+ }
+
+ render(<Comp />, scratch);
+ expect(createHandleSpy).to.have.been.calledOnce;
+
+ render(<Comp />, scratch);
+ expect(createHandleSpy).to.have.been.calledTwice;
+
+ render(<Comp />, scratch);
+ expect(createHandleSpy).to.have.been.calledThrice;
+ });
+
+ it('calls createHandle only on mount if an empty array is passed', () => {
+ let ref,
+ createHandleSpy = sinon.spy();
+
+ function Comp() {
+ ref = useRef({});
+ useImperativeHandle(ref, createHandleSpy, []);
+ return <p>Test</p>;
+ }
+
+ render(<Comp />, scratch);
+ expect(createHandleSpy).to.have.been.calledOnce;
+
+ render(<Comp />, scratch);
+ expect(createHandleSpy).to.have.been.calledOnce;
+ });
+
+ it('Updates given ref when args change', () => {
+ let ref,
+ createHandleSpy = sinon.spy();
+
+ function Comp({ a }) {
+ ref = useRef({});
+ useImperativeHandle(
+ ref,
+ () => {
+ createHandleSpy();
+ return { test: () => 'test' + a };
+ },
+ [a]
+ );
+ return <p>Test</p>;
+ }
+
+ render(<Comp a={0} />, scratch);
+ expect(createHandleSpy).to.have.been.calledOnce;
+ expect(ref.current).to.have.property('test');
+ expect(ref.current.test()).to.equal('test0');
+
+ render(<Comp a={1} />, scratch);
+ expect(createHandleSpy).to.have.been.calledTwice;
+ expect(ref.current).to.have.property('test');
+ expect(ref.current.test()).to.equal('test1');
+
+ render(<Comp a={0} />, scratch);
+ expect(createHandleSpy).to.have.been.calledThrice;
+ expect(ref.current).to.have.property('test');
+ expect(ref.current.test()).to.equal('test0');
+ });
+
+ it('Updates given ref when passed-in ref changes', () => {
+ let ref1, ref2;
+
+ /** @type {(arg: any) => void} */
+ let setRef;
+
+ /** @type {() => void} */
+ let updateState;
+
+ const createHandleSpy = sinon.spy(() => ({
+ test: () => 'test'
+ }));
+
+ function Comp() {
+ ref1 = useRef({});
+ ref2 = useRef({});
+
+ const [ref, setRefInternal] = useState(ref1);
+ setRef = setRefInternal;
+
+ let [value, setState] = useState(0);
+ updateState = () => setState((value + 1) % 2);
+
+ useImperativeHandle(ref, createHandleSpy, []);
+ return <p>Test</p>;
+ }
+
+ render(<Comp a={0} />, scratch);
+ expect(createHandleSpy).to.have.been.calledOnce;
+
+ updateState();
+ rerender();
+ expect(createHandleSpy).to.have.been.calledOnce;
+
+ setRef(ref2);
+ rerender();
+ expect(createHandleSpy).to.have.been.calledTwice;
+
+ updateState();
+ rerender();
+ expect(createHandleSpy).to.have.been.calledTwice;
+
+ setRef(ref1);
+ rerender();
+ expect(createHandleSpy).to.have.been.calledThrice;
+ });
+
+ it('should not update ref when args have not changed', () => {
+ let ref,
+ createHandleSpy = sinon.spy(() => ({ test: () => 'test' }));
+
+ function Comp() {
+ ref = useRef({});
+ useImperativeHandle(ref, createHandleSpy, [1]);
+ return <p>Test</p>;
+ }
+
+ render(<Comp />, scratch);
+ expect(createHandleSpy).to.have.been.calledOnce;
+ expect(ref.current.test()).to.equal('test');
+
+ render(<Comp />, scratch);
+ expect(createHandleSpy).to.have.been.calledOnce;
+ expect(ref.current.test()).to.equal('test');
+ });
+
+ it('should not throw with nullish ref', () => {
+ function Comp() {
+ useImperativeHandle(null, () => ({ test: () => 'test' }), [1]);
+ return <p>Test</p>;
+ }
+
+ expect(() => render(<Comp />, scratch)).to.not.throw();
+ });
+});