tooltip.test.js 13 KB

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