tooltip.test.js 13 KB

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