Skip to content

Commit

Permalink
fix(supportRef): fix the supportRef function (#2056)
Browse files Browse the repository at this point in the history
* fix(supportRef): fix the supportRef function

* chore(.vscode): add extensions.json file

Co-authored-by: maxin <maxin@growingio.com>
  • Loading branch information
nnmax and maxin committed Jun 2, 2022
1 parent d541ec6 commit 8092d69
Show file tree
Hide file tree
Showing 7 changed files with 126 additions and 171 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
.tmp
.vscode/*
!.vscode/settings.json
!.vscode/extensions.json
build
.umi
dist
Expand Down Expand Up @@ -36,4 +37,4 @@ storybook-static
*-report.json
*-report.xml
build-storybook.log
.eslintcache
.eslintcache
3 changes: 3 additions & 0 deletions .vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"recommendations": ["esbenp.prettier-vscode"]
}
96 changes: 54 additions & 42 deletions src/list/__tests__/ListItem.test.tsx
Original file line number Diff line number Diff line change
@@ -1,40 +1,45 @@
import { act, fireEvent, render, screen } from "@testing-library/react"
import React from "react"
import List, { Item } from "..";
import BaseItem from "../inner/baseItem"
import CascaderItem from "../inner/CascaderItem";
import CheckboxItem from "../inner/CheckboxItem";
import { act, fireEvent, render, screen } from '@testing-library/react';
import React from 'react';
import List, { Item } from '..';
import BaseItem from '../inner/baseItem';
import CascaderItem from '../inner/CascaderItem';
import CheckboxItem from '../inner/CheckboxItem';

describe('testing list item', () => {
afterEach(() => {
jest.useRealTimers()
})
jest.useRealTimers();
});
it('baseItem', () => {
const { container } = render(<BaseItem value={1} label="1" selected />);

expect(screen.queryByTestId('item-base')).toBeTruthy();
expect(container.querySelector('.gio-list--item--actived')).toBeTruthy()
expect(container.querySelector('.gio-list--item--actived')).toBeTruthy();
});
it('baseItem with children', () => {
const { container } = render(<BaseItem label="item2" value={1}>item1</BaseItem>);
const { container } = render(
<BaseItem label="item2" value={1}>
item1
</BaseItem>
);

expect(screen.queryByTestId('item-base')).toBeTruthy();
expect(screen.queryByText('item2')).toBeTruthy();
expect(container.querySelector('.gio-list--item')).toBeTruthy()
expect(container.querySelector('.gio-list--item')).toBeTruthy();
});
it('baseItem fire events', () => {
jest.useFakeTimers()
jest.useFakeTimers('modern');
const mockMouseEnter = jest.fn();
const mockMouseLeave = jest.fn();
const mockClick = jest.fn();
const { container } = render(<BaseItem value={1} label="1" onClick={mockClick} onMouseEnter={mockMouseEnter} onMouseLeave={mockMouseLeave} />);
const ele = screen.queryByTestId('item-base')
const { container } = render(
<BaseItem value={1} label="1" onClick={mockClick} onMouseEnter={mockMouseEnter} onMouseLeave={mockMouseLeave} />
);
const ele = screen.queryByTestId('item-base');

expect(ele).toBeTruthy();
act(() => {
fireEvent.mouseEnter(ele);

})
});
jest.runAllTimers();
expect(container.querySelector('.gio-list--item--hovered')).toBeTruthy();
expect(mockMouseEnter).toHaveBeenCalled();
Expand All @@ -44,11 +49,9 @@ describe('testing list item', () => {

act(() => {
fireEvent.mouseLeave(ele);

})
});
jest.runAllTimers();
expect(container.querySelector('.gio-list--item--hovered')).toBeFalsy();

});
});

Expand All @@ -60,57 +63,66 @@ describe('cascader item testing', () => {
it('render', () => {
const { container } = render(<CascaderItem label="1" value={1} items={null} />);
expect(container.querySelector('.gio-cascader--item')).toBeTruthy();
})
});

it('should not fire click when disabled', () => {

const mockClick = jest.fn();
render(<CascaderItem disabled onClick={mockClick} label="1" value={1} items={[{ value: 2, label: '2' }, undefined]} />);
render(
<CascaderItem disabled onClick={mockClick} label="1" value={1} items={[{ value: 2, label: '2' }, undefined]} />
);
expect(screen.queryByTestId('item-base')).toBeTruthy();

const clickEle = screen.getByText('1');
fireEvent.click(clickEle);
expect(mockClick).not.toHaveBeenCalled();
})
});
it('fire list click when click item', () => {
const mockClick = jest.fn();
const itemClick = jest.fn();
render(<List onClick={mockClick}><CascaderItem onClick={itemClick} label="1" value={1} /></List>);
render(
<List onClick={mockClick}>
<CascaderItem onClick={itemClick} label="1" value={1} />
</List>
);
const clickEle = screen.getByText('1');
fireEvent.click(clickEle);
expect(mockClick).toHaveBeenCalled();
})
});
it('should trigger events ', () => {
jest.useFakeTimers()
jest.useFakeTimers();

const mockClick = jest.fn();
const Render = () => <CascaderItem onClick={mockClick} label="1" value={1} >
<List>
<BaseItem value={1.1} label="1.1" />
</List>
</CascaderItem>
const Render = () => (
<CascaderItem onClick={mockClick} label="1" value={1}>
<List>
<BaseItem value={1.1} label="1.1" />
</List>
</CascaderItem>
);
render(<Render />);
expect(screen.queryByTestId('item-base')).toBeTruthy();

const clickEle = screen.getByText('1')

const clickEle = screen.getByText('1');

act(() => {
fireEvent.mouseEnter(clickEle);
})
});
jest.runOnlyPendingTimers();
fireEvent.click(clickEle);
expect(mockClick).toHaveBeenCalled();
})
})
});
});

describe('CheckboxItem', () => {
it('trigger click event when click item', () => {
const mockClick = jest.fn();
render(<List model="multiple">
<Item onClick={mockClick} value="1">List Item 1</Item>

</List>);
render(
<List model="multiple">
<Item onClick={mockClick} value="1">
List Item 1
</Item>
</List>
);
const items = screen.queryAllByTestId('checkbox');
fireEvent.click(items[0]);

Expand All @@ -128,5 +140,5 @@ describe('CheckboxItem', () => {
const { container } = render(<CheckboxItem value={1} prefix={<span>$</span>} suffix={<span>%</span>} />);
expect(container.querySelector('.gio-list--item-prefix-icon')).toBeTruthy();
expect(container.querySelector('.gio-list--item-suffix-icon')).toBeTruthy();
})
})
});
});
125 changes: 32 additions & 93 deletions src/utils/__test__/composeRef.test.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
/* eslint-disable @typescript-eslint/ban-ts-comment */
/* eslint-disable max-classes-per-file */
// @ts-nocheck
import React from 'react';
import { render } from '@testing-library/react';
import React, { Component, forwardRef, memo } from 'react';
import { composeRef, supportRef } from '../composeRef';

describe('ref', () => {
Expand All @@ -23,8 +19,8 @@ describe('ref', () => {
});

it('object ref', () => {
const ref1 = { current: null };
const ref2 = { current: null };
const ref1 = { current: null } as any;
const ref2 = { current: null } as any;
const mergedRef = composeRef(ref1, ref2);
if (typeof mergedRef === 'function') {
const refObj = {};
Expand All @@ -36,105 +32,48 @@ describe('ref', () => {
});

describe('supportRef', () => {
class Holder extends React.Component {
render() {
// eslint-disable-next-line react/destructuring-assignment
return this.props.children;
}
}

it('function component', () => {
const holderRef = React.createRef();

function FC() {
return <div />;
}

render(
<Holder ref={holderRef}>
<FC />
</Holder>
);
expect(supportRef(FC)).toBeFalsy();
expect(supportRef((holderRef.current as any).props.children)).toBeFalsy();
it('Function Component should not support ref', () => {
const FC = () => <div />;
expect(supportRef(<FC />)).toBe(false);
});

it('arrow function component', () => {
const holderRef = React.createRef();

// Use eval since jest will convert arrow function to function
// eslint-disable-next-line no-eval
const FC = eval('() => null');
render(
<Holder ref={holderRef}>
<FC />
</Holder>
);
expect(supportRef(FC)).toBeFalsy();
expect(supportRef((holderRef.current as any).props.children)).toBeFalsy();
it('forwardRef(FC) should support ref', () => {
const FC = forwardRef(() => <div />);
expect(supportRef(<FC />)).toBe(true);
});

it('forwardRef function component', () => {
const holderRef = React.createRef();

const FRC = React.forwardRef(() => <div />);
render(
<Holder ref={holderRef}>
<FRC />
</Holder>
);
expect(supportRef(FRC)).toBeTruthy();
expect(supportRef(holderRef.current.props.children)).toBeTruthy();
it('Native tag should support ref', () => {
expect(supportRef(<div />)).toBe(true);
});

it('class component', () => {
const holderRef = React.createRef();
it('memo(FC) should not support ref', () => {
const FC = memo(() => <div />);
expect(supportRef(<FC />)).toBe(false);
});

class CC extends React.Component {
constructor() {
super();
this.state = {};
}
it('memo(forwardRef(FC)) should support ref', () => {
const FC = memo(forwardRef(() => <div />));
expect(supportRef(<FC />)).toBe(true);
});

it('Class Component should support ref', () => {
// eslint-disable-next-line react/prefer-stateless-function
class CC extends Component {
render() {
return null;
return <div />;
}
}
render(
<Holder ref={holderRef}>
<CC />
</Holder>
);
expect(supportRef(CC)).toBeTruthy();
expect(supportRef(holderRef.current.props.children)).toBeTruthy();
});

it('memo of function component', () => {
const holderRef = React.createRef();

const FC = () => <div />;
const MemoFC = React.memo(FC);
render(
<Holder ref={holderRef}>
<MemoFC />
</Holder>
);
expect(supportRef(MemoFC)).toBeFalsy();
expect(supportRef(holderRef.current.props.children)).toBeFalsy();
expect(supportRef(<CC />)).toBe(true);
});

it('memo of forwardRef function component', () => {
const holderRef = React.createRef();

const FRC = React.forwardRef(() => <div />);
const MemoFC = React.memo(FRC);
render(
<Holder ref={holderRef}>
<MemoFC />
</Holder>
);
expect(supportRef(MemoFC)).toBeTruthy();
expect(supportRef(holderRef.current.props.children)).toBeTruthy();
it('Only React Element support ref', () => {
expect(supportRef('string')).toBe(false);
expect(supportRef(123)).toBe(false);
expect(supportRef({})).toBe(false);
expect(supportRef(true)).toBe(false);
expect(supportRef(null)).toBe(false);
expect(supportRef(undefined)).toBe(false);
expect(supportRef(Symbol('sym'))).toBe(false);
});
});
});

1 comment on commit 8092d69

@vercel
Copy link

@vercel vercel bot commented on 8092d69 Jun 2, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

gio-design – ./

gio-design-growingio.vercel.app
gio-design.vercel.app
gio-design-git-master-growingio.vercel.app

Please sign in to comment.