From a27b4c8782e0c2bde3b0dde5ebab849c3407623e Mon Sep 17 00:00:00 2001 From: Robert Knight Date: Thu, 8 Apr 2021 17:10:45 +0100 Subject: [PATCH] Support `invoke` API Support the `invoke` API [1] introduced in Enzyme v3.11.0 that invokes a prop function within an `act` call and then updates the wrapper afterwards. Currently `invoke` is only supported in `mount` rendering. [1] https://github.com/enzymejs/enzyme/blob/master/docs/api/ReactWrapper/invoke.md --- src/MountRenderer.ts | 8 ++++++++ test/MountRenderer_test.tsx | 12 ++++++++++++ test/integration_test.tsx | 23 +++++++++++++++++++++++ 3 files changed, 43 insertions(+) diff --git a/src/MountRenderer.ts b/src/MountRenderer.ts index fe41749..b606c6b 100644 --- a/src/MountRenderer.ts +++ b/src/MountRenderer.ts @@ -111,4 +111,12 @@ export default class MountRenderer implements AbstractMountRenderer { container() { return this._container; } + + wrapInvoke(callback: () => any) { + let result; + act(() => { + result = callback(); + }); + return result; + } } diff --git a/test/MountRenderer_test.tsx b/test/MountRenderer_test.tsx index bb14463..d5ec047 100644 --- a/test/MountRenderer_test.tsx +++ b/test/MountRenderer_test.tsx @@ -212,4 +212,16 @@ describe('MountRenderer', () => { }); }); }); + + describe('#wrapInvoke', () => { + it('returns result of callback', () => { + const Widget = () =>
; + const renderer = new MountRenderer(); + renderer.render(); + + const result = renderer.wrapInvoke(() => 'test'); + + assert.equal(result, 'test'); + }); + }); }); diff --git a/test/integration_test.tsx b/test/integration_test.tsx index 3c6d9a0..584d612 100644 --- a/test/integration_test.tsx +++ b/test/integration_test.tsx @@ -7,6 +7,7 @@ import { } from 'enzyme'; import { Component, Fragment, options } from './preact'; import * as preact from 'preact'; +import { useEffect, useState } from 'preact/hooks'; import { ReactElement } from 'react'; import { assert } from 'chai'; @@ -401,6 +402,28 @@ describe('integration tests', () => { assert.ok(container.querySelector('button')); wrapper.detach(); }); + + it('flushes effects and state updates when using `invoke`', () => { + let effectCount = 0; + + const Child = ({ children, onClick }: any) => ( + + ); + const Parent = () => { + const [count, setCount] = useState(0); + useEffect(() => { + effectCount = count; + }, [count]); + return setCount(c => c + 1)}>{count}; + }; + + const wrapper = mount(); + // @ts-ignore - `onClick` type is wrong + wrapper.find('Child').invoke('onClick')(); + + assert.equal(wrapper.text(), '1'); + assert.equal(effectCount, 1); + }); }); describe('"shallow" rendering', () => {