tooltip.test.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  1. import { clear } from 'jest-date-mock';
  2. import * as _ from 'lodash';
  3. import Tooltip from '../index';
  4. import Button from '../../button';
  5. import Select from '../../select';
  6. import { BASE_CLASS_PREFIX } from '../../../semi-foundation/base/constants';
  7. import { strings } from '../../../semi-foundation/tooltip/constants';
  8. import { genAfterEach, genBeforeEach, mount, sleep } from '../../_test_/utils';
  9. describe(`Tooltip`, () => {
  10. beforeEach(() => {
  11. clear();
  12. genBeforeEach()();
  13. });
  14. afterEach(genAfterEach());
  15. it(`test appearance`, async () => {
  16. const containerId = `container`;
  17. const scrollItemId = `scroll-item`;
  18. const scrollContainerId = `scroll-container`;
  19. const triggerId = `trigger`;
  20. const demo = mount(
  21. <div
  22. style={{
  23. height: 320,
  24. width: 320,
  25. display: 'inline-block',
  26. overflow: 'auto',
  27. padding: 50,
  28. marginTop: 100,
  29. }}
  30. id={scrollContainerId}
  31. >
  32. <div style={{ height: 480, width: 320 }} id={scrollItemId}>
  33. <div id={containerId}></div>
  34. <Tooltip
  35. motion={false}
  36. content={'Content'}
  37. visible={true}
  38. trigger={'click'}
  39. getPopupContainer={() => document.getElementById(containerId)}
  40. >
  41. <Button id={triggerId}>Click here</Button>
  42. </Tooltip>
  43. </div>
  44. </div>
  45. );
  46. const elem = demo.find(Tooltip);
  47. const tooltipOuter = document.querySelector(`.${BASE_CLASS_PREFIX}-portal-inner`);
  48. // check if rendered
  49. expect(document.querySelectorAll(`.${BASE_CLASS_PREFIX}-tooltip-wrapper`).length).toBe(1);
  50. // scroll
  51. await sleep(100);
  52. const deltaY = 50;
  53. const scrollContainer = demo.find(`#${scrollContainerId}`);
  54. const oldTop = window.getComputedStyle(tooltipOuter).top;
  55. scrollContainer.getDOMNode().scrollTop += deltaY;
  56. scrollContainer.simulate('scroll');
  57. await sleep(100);
  58. const curTop = window.getComputedStyle(tooltipOuter).top;
  59. expect(oldTop).toBe(curTop);
  60. // click inside
  61. document.querySelector(`.${BASE_CLASS_PREFIX}-tooltip-wrapper`).click();
  62. await sleep(100);
  63. expect(elem.state(`visible`)).toBe(true);
  64. // click outside
  65. // document.body.click();
  66. document.dispatchEvent(new Event('mousedown', { bubbles: true, cancelable: true }));
  67. // demo.find(`#${triggerId}`)
  68. // .at(0)
  69. // .simulate(`mouseDown`);
  70. await sleep(100);
  71. expect(elem.state('visible')).toBe(false);
  72. // click button to show tooltip
  73. document.getElementById(triggerId).click();
  74. await sleep(100);
  75. expect(elem.state('visible')).toBe(true);
  76. // unmount elem
  77. demo.unmount();
  78. await sleep(100);
  79. // document.body.click();
  80. document.dispatchEvent(new Event('mousedown', { bubbles: true, cancelable: true }));
  81. expect(document.getElementsByClassName(`${BASE_CLASS_PREFIX}-tooltip-wrapper`).length).toBe(0);
  82. });
  83. test(`test appearance with motion`, async () => {
  84. const containerId = 'container';
  85. const scrollItemId = `scroll-item`;
  86. const scrollContainerId = `scroll-container`;
  87. const triggerId = `trigger`;
  88. const refObj = { current: null };
  89. const refFn = sinon.spy();
  90. const demo = mount(
  91. <div style={{ height: 2000 }}>
  92. <div
  93. style={{
  94. height: 320,
  95. width: 320,
  96. display: 'inline-block',
  97. overflow: 'auto',
  98. padding: 50,
  99. marginTop: 100,
  100. }}
  101. id={scrollContainerId}
  102. >
  103. <div style={{ height: 480, width: 320 }} id={scrollItemId}>
  104. <div id={containerId}></div>
  105. <Tooltip
  106. motion={true}
  107. showArrow={true}
  108. content={'Content'}
  109. visible={true}
  110. trigger={'click'}
  111. getPopupContainer={() => document.getElementById(containerId)}
  112. >
  113. <Button ref={refObj} id={triggerId}>
  114. Click here
  115. </Button>
  116. </Tooltip>
  117. {/* <Tooltip
  118. disabled={true}
  119. motion={true}
  120. showArrow={true}
  121. content={'Content'}
  122. visible={true}
  123. trigger={'click'}
  124. getPopupContainer={() => document.getElementById(containerId)}
  125. >
  126. <Button disabled block>
  127. Click here
  128. </Button>
  129. </Tooltip> */}
  130. <Tooltip
  131. motion={true}
  132. showArrow={true}
  133. content={'Content'}
  134. visible={true}
  135. trigger={'click'}
  136. // getPopupContainer={() => document.getElementById(containerId)}
  137. wrapWhenSpecial={false}
  138. >
  139. <Button ref={refFn}>Click here</Button>
  140. </Tooltip>
  141. </div>
  142. </div>
  143. </div>
  144. );
  145. await sleep(100);
  146. const portalInners = document.querySelectorAll(`.${BASE_CLASS_PREFIX}-portal-inner`);
  147. expect(portalInners.length).toBe(2);
  148. expect(refObj.current).not.toBeNull();
  149. expect(refFn.called).toBeTruthy();
  150. // click outside
  151. // document.body.click();
  152. document.dispatchEvent(new Event('mousedown', { bubbles: true, cancelable: true }));
  153. await sleep(100);
  154. expect(
  155. demo
  156. .find(Tooltip)
  157. .map(el => el.state('visible'))
  158. .reduce((count, v) => (v ? count + 1 : count), 0)
  159. ).toBe(0);
  160. });
  161. test(`test special appearance`, async () => {
  162. const containerId = 'container';
  163. const scrollItemId = `scroll-item`;
  164. const scrollContainerId = `scroll-container`;
  165. const demo = mount(
  166. <div style={{ height: 2000 }}>
  167. <div
  168. style={{
  169. height: 320,
  170. width: 320,
  171. display: 'inline-block',
  172. overflow: 'auto',
  173. padding: 50,
  174. marginTop: 100,
  175. }}
  176. id={scrollContainerId}
  177. >
  178. <div style={{ height: 480, width: 320 }} id={scrollItemId}>
  179. <div id={containerId}></div>
  180. <Tooltip motion={true} showArrow={true} content={'Content'} visible={true} trigger={'click'}>
  181. <span style={{ display: 'block' }}>Click here</span>
  182. </Tooltip>
  183. <Tooltip motion={true} showArrow={true} content={'Content'} visible={true} trigger={'click'}>
  184. <Button block>Click here</Button>
  185. </Tooltip>
  186. <Tooltip motion={true} showArrow={true} content={'Content'} visible={true} trigger={'click'}>
  187. Click Me
  188. </Tooltip>
  189. </div>
  190. </div>
  191. </div>
  192. );
  193. await sleep(100);
  194. expect(document.querySelectorAll(`.${BASE_CLASS_PREFIX}-portal-inner`).length).toBe(3);
  195. // expect(document.querySelectorAll(`.${BASE_CLASS_PREFIX}-icons-triangle_arrow`).length).toBe(3);
  196. });
  197. test(`test events`, async () => {
  198. const close = sinon.spy(() => {
  199. demo.setProps({ visible: false });
  200. });
  201. const demo = mount(
  202. <Tooltip
  203. motion={true}
  204. showArrow={true}
  205. content={
  206. <article>
  207. <Button onClick={close} />
  208. </article>
  209. }
  210. visible={true}
  211. trigger={'click'}
  212. >
  213. <span style={{ display: 'block' }}>Click here</span>
  214. </Tooltip>
  215. );
  216. await sleep(100);
  217. expect(document.querySelectorAll(`.${BASE_CLASS_PREFIX}-portal-inner`).length).toBe(1);
  218. document.querySelector(`.${BASE_CLASS_PREFIX}-portal-inner .${BASE_CLASS_PREFIX}-button`).click();
  219. await sleep(100);
  220. expect(demo.state('visible')).toBe(false);
  221. });
  222. test(`vertical position: `, async () => {
  223. const close = sinon.spy(() => {
  224. demo.setProps({ visible: false });
  225. });
  226. const demo = mount(
  227. <Tooltip
  228. position="left"
  229. motion={true}
  230. showArrow={true}
  231. content={
  232. <article>
  233. <Button onClick={close} />
  234. </article>
  235. }
  236. visible={true}
  237. trigger={'click'}
  238. motion={() => false}
  239. >
  240. <span style={{ display: 'block' }}>Click here</span>
  241. </Tooltip>
  242. );
  243. await sleep(100);
  244. expect(document.querySelector(`.${BASE_CLASS_PREFIX}-portal-inner svg path`).getAttribute('d')).toBe('M0 0L1 0C1 4, 2 5.5, 4 7.5S7,10 7,12S6 14.5, 4 16.5S1,20 1,24L0 24L0 0z');
  245. });
  246. test(`test position: `, async () => {
  247. const positionList = strings.POSITION_SET
  248. for (const position of positionList) {
  249. const demo = mount(
  250. <Tooltip
  251. position={position}
  252. content={
  253. <article>
  254. 1
  255. </article>
  256. }
  257. visible={true}
  258. >
  259. <span style={{ display: 'block' }}>Click here</span>
  260. </Tooltip>
  261. );
  262. await sleep(100);
  263. expect(document.querySelector(`.${BASE_CLASS_PREFIX}-tooltip-wrapper`).getAttribute('x-placement')).toBe(position);
  264. }
  265. });
  266. it(`test click outside handler`, async () => {
  267. const containerId = `container`;
  268. const demo = mount(
  269. <div style={{ height: 480, width: 320 }}>
  270. <div id={containerId}>Hello Semi</div>
  271. <Tooltip
  272. content='Content'
  273. trigger='click'
  274. >
  275. <Button >Click here</Button>
  276. </Tooltip>
  277. </div>
  278. );
  279. const toolTipElem = demo.find(Tooltip);
  280. const buttonElem = demo.find(Button);
  281. // click inside
  282. buttonElem.simulate('click');
  283. toolTipElem.update();
  284. await sleep(100);
  285. expect(toolTipElem.state(`visible`)).toBe(true);
  286. // click outside
  287. // document.body.click();
  288. document.dispatchEvent(new Event('mousedown', { bubbles: true, cancelable: true }));
  289. toolTipElem.update();
  290. await sleep(100);
  291. expect(toolTipElem.state('visible')).toBe(false);
  292. // click button to show tooltip
  293. buttonElem.simulate('click');
  294. toolTipElem.update();
  295. await sleep(100);
  296. expect(toolTipElem.state('visible')).toBe(true);
  297. document.getElementById(containerId).dispatchEvent(new Event('mousedown', { bubbles: true, cancelable: true }));
  298. toolTipElem.update();
  299. await sleep(100);
  300. expect(toolTipElem.state('visible')).toBe(false);
  301. });
  302. });
  303. it('wrapperClassName', () => {
  304. const wrapperWithMultipleChildren = mount(
  305. <Tooltip wrapperClassName='test' content={'hi bytedance'}>
  306. <Button>正常的多个按钮</Button>
  307. <Button>正常的多个按钮</Button>
  308. </Tooltip>
  309. );
  310. expect(wrapperWithMultipleChildren.exists('.test')).toEqual(true);
  311. const wrapperWithDisabledButton = mount(
  312. <Tooltip wrapperClassName='test' content={'hi bytedance'}>
  313. <Button disabled>正常的多个按钮</Button>
  314. </Tooltip>
  315. );
  316. expect(wrapperWithDisabledButton.exists('.test')).toEqual(true);
  317. const wrapperWithDisabledSelect = mount(
  318. <Tooltip wrapperClassName='test' content={'hi bytedance'}>
  319. <Select disabled placeholder='请选择业务线' style={{ width: 120 }}>
  320. <Select.Option value='abc'>抖音</Select.Option>
  321. <Select.Option value='hotsoon'>火山</Select.Option>
  322. <Select.Option value='jianying' disabled>剪映</Select.Option>
  323. <Select.Option value='xigua'>西瓜视频</Select.Option>
  324. </Select>
  325. </Tooltip>
  326. );
  327. expect(wrapperWithDisabledSelect.exists('.test')).toEqual(true);
  328. });