From 2f55c2321b91cd79347e81d7ebbdf23b63927f53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?kiner-tang=28=E6=96=87=E8=BE=89=29?= <1127031143@qq.com> Date: Wed, 11 Jan 2023 11:20:15 +0800 Subject: [PATCH] fix: solve findDOMNode throw warning in strict mode problem (#28) * fix: fix findDOMNOde throw wraning in strict mode problem * fix: fix findDOMNOde throw wraning in strict mode problem * feat: code optimize * feat: remove redundant code * feat: update test case * chore: update dumi version --- docs/demo/strictMode.md | 8 + docs/examples/strictMode.tsx | 47 ++++ package.json | 2 +- src/Tour.tsx | 6 + tests/__snapshots__/index.test.tsx.snap | 303 ++++++++++++++++++++++++ tests/index.test.tsx | 99 +++++++- 6 files changed, 451 insertions(+), 14 deletions(-) create mode 100644 docs/demo/strictMode.md create mode 100644 docs/examples/strictMode.tsx diff --git a/docs/demo/strictMode.md b/docs/demo/strictMode.md new file mode 100644 index 0000000..35f0cb8 --- /dev/null +++ b/docs/demo/strictMode.md @@ -0,0 +1,8 @@ +--- +title: strictMode +nav: + title: Demo + path: /demo +--- + + diff --git a/docs/examples/strictMode.tsx b/docs/examples/strictMode.tsx new file mode 100644 index 0000000..a862528 --- /dev/null +++ b/docs/examples/strictMode.tsx @@ -0,0 +1,47 @@ +import React, { StrictMode, useRef } from 'react'; +import Tour from '../../src/index'; +import './basic.less'; + +const App = () => { + const [open, setOpen] = React.useState(false); + const btn1 = useRef(null); + + return ( +
+ + + + setOpen(false)} + steps={[ + { + title: '创建', + description: '创建一条数据', + target: undefined, + }, + { + title: '更新', + description: '更新一条数据', + target: () => btn1.current, + }, + ]} + /> +
+ ); +}; + +export default () => { + return ( + + + + ); +}; diff --git a/package.json b/package.json index d841186..f1cb1e1 100644 --- a/package.json +++ b/package.json @@ -52,7 +52,7 @@ "@types/react": "^18.0.0", "@types/react-dom": "^18.0.0", "@umijs/fabric": "^2.5.2", - "dumi": "^2.0.0", + "dumi": "^2.1.2", "eslint": "^7.18.0", "father": "^4.0.0-rc.8", "gh-pages": "^3.1.0", diff --git a/src/Tour.tsx b/src/Tour.tsx index e7b0b78..de13a58 100644 --- a/src/Tour.tsx +++ b/src/Tour.tsx @@ -165,6 +165,11 @@ const Tour = (props: TourProps) => { const mergedShowMask = typeof mergedMask === "boolean" ? mergedMask : !!mergedMask; const mergedMaskStyle = typeof mergedMask === "boolean" ? undefined : mergedMask; + + // when targetElement is not exist, use body as triggerDOMNode + const getTriggerDOMNode = (node) => { + return node || targetElement || document.body + }; return ( <> @@ -181,6 +186,7 @@ const Tour = (props: TourProps) => { forceRender={false} destroyPopupOnHide zIndex={1090} + getTriggerDOMNode={getTriggerDOMNode} >
`; +exports[`Tour run in strict mode 1`] = ` + +
+
+ + +
+
+
+
+
+
+
+ + + + + + + + +
+
+
+
+
+
+
+ +
+
+ 创建 +
+
+
+ 创建一条数据 +
+ +
+
+
+
+
+ +`; + +exports[`Tour run in strict mode 2`] = ` + +
+
+ + +
+
+
+
+
+
+
+ + + + + + + + + + + + + +
+
+
+
+
+
+
+
+ +
+
+ 更新 +
+
+
+ 更新一条数据 +
+ +
+
+
+
+
+ +`; + exports[`Tour should keep current when controlled 1`] = `
diff --git a/tests/index.test.tsx b/tests/index.test.tsx index 63e7771..a7a249e 100644 --- a/tests/index.test.tsx +++ b/tests/index.test.tsx @@ -1,4 +1,4 @@ -import React, { useState, useRef } from 'react'; +import React, { useState, useRef, StrictMode } from 'react'; import { fireEvent, render, screen } from '@testing-library/react'; import Tour from '../src/index'; import { spyElementPrototypes } from 'rc-util/lib/test/domHook'; @@ -6,12 +6,24 @@ import { act } from 'react-dom/test-utils'; import { resizeWindow } from './utils'; describe('Tour', () => { + let spy: jest.SpyInstance; + + beforeAll(() => { + spy = jest.spyOn(console, 'error').mockImplementation(() => {}); + }); + + afterAll(() => { + spy.mockRestore(); + }); + beforeEach(() => { + jest.resetModules(); jest.useFakeTimers(); }); afterEach(() => { jest.useRealTimers(); + spy.mockReset(); }); it('steps in undefined', async () => { @@ -277,7 +289,7 @@ describe('Tour', () => { ); }; - const { rerender,baseElement } = render(); + const { rerender, baseElement } = render(); expect(document.querySelector(`.rc-tour-arrow`)).toBeTruthy(); arrow = false; @@ -473,16 +485,20 @@ describe('Tour', () => { return (
- - + + { target: () => btn2Ref.current, mask: { style: { - boxShadow: 'inset 0 0 30px green' + boxShadow: 'inset 0 0 30px green', }, - color: 'rgba(80,0,0,0.5)' - } + color: 'rgba(80,0,0,0.5)', + }, }, ]} /> @@ -508,10 +524,67 @@ describe('Tour', () => { }; const { baseElement } = render(); - expect(baseElement.querySelector('.rc-tour-mask')).toHaveStyle('box-shadow: inset 0 0 80px #333'); - expect(baseElement.querySelectorAll('rect')[2]).toHaveAttribute('fill', 'rgba(255,0,0,0.5)'); + expect(baseElement.querySelector('.rc-tour-mask')).toHaveStyle( + 'box-shadow: inset 0 0 80px #333', + ); + expect(baseElement.querySelectorAll('rect')[2]).toHaveAttribute( + 'fill', + 'rgba(255,0,0,0.5)', + ); fireEvent.click(document.querySelector('.rc-tour-next-btn')); - expect(baseElement.querySelector('.rc-tour-mask')).toHaveStyle('box-shadow: inset 0 0 30px green'); - expect(baseElement.querySelectorAll('rect')[2]).toHaveAttribute('fill', 'rgba(80,0,0,0.5)'); + expect(baseElement.querySelector('.rc-tour-mask')).toHaveStyle( + 'box-shadow: inset 0 0 30px green', + ); + expect(baseElement.querySelectorAll('rect')[2]).toHaveAttribute( + 'fill', + 'rgba(80,0,0,0.5)', + ); + }); + it('run in strict mode', () => { + const App = () => { + const [open, setOpen] = React.useState(false); + const btn1 = useRef(null); + + return ( + +
+ + + + setOpen(false)} + steps={[ + { + title: '创建', + description: '创建一条数据', + target: undefined, + }, + { + title: '更新', + description: '更新一条数据', + target: () => btn1.current, + }, + ]} + /> +
+
+ ); + }; + const { baseElement } = render(); + fireEvent.click(baseElement.querySelector('.btn1')); + expect(baseElement).toMatchSnapshot(); + fireEvent.click(screen.getByRole('button', { name: 'Next' })); + expect(baseElement).toMatchSnapshot(); + fireEvent.click(screen.getByRole('button', { name: 'Finish' })); + expect(spy).not.toHaveBeenCalled(); }); });