Skip to content

Commit

Permalink
chore: add unit test (#12)
Browse files Browse the repository at this point in the history
* test: add unit test

* chore: add unit-test

* chore: update

* chore: fix ci
  • Loading branch information
Wxh16144 authored Apr 14, 2024
1 parent d4fb5d4 commit d12a3ce
Show file tree
Hide file tree
Showing 8 changed files with 298 additions and 1 deletion.
4 changes: 4 additions & 0 deletions .dumi/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"extends": "../tsconfig.json",
"include": ["**/*"]
}
8 changes: 8 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,14 @@ jobs:
restore-keys: |
${{ runner.os }}-pnpm-store-
- name: Set up Cypress binary cache
uses: actions/cache@v3
with:
path: ~/.cache/Cypress
key: ${{ runner.os }}-cypress-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-cypress-
- name: Install deps
run: pnpm install

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`ActionIcon > should render correctly 1`] = `
<div>
<button
class="ant-btn ant-btn-default ant-btn-icon-only ant-action-icon"
style="max-height: 22px;"
type="button"
>
<span
class="ant-btn-icon"
>
<svg>
o
</svg>
</span>
</button>
</div>
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`RecordShortcutInput > should render correctly 1`] = `
<div>
<span
class="ant-input-affix-wrapper ant-input-affix-wrapper-readonly ant-record-hotkey-input"
>
<input
class="ant-input"
placeholder="Double click to edit"
readonly=""
type="text"
value=""
/>
<span
class="ant-input-suffix"
>
<button
class="ant-btn ant-btn-text ant-btn-sm ant-btn-icon-only ant-action-icon"
style="max-height: 22px;"
type="button"
>
<span
class="ant-btn-icon"
>
<span
aria-label="edit"
class="anticon anticon-edit"
role="img"
>
<svg
aria-hidden="true"
data-icon="edit"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M257.7 752c2 0 4-.2 6-.5L431.9 722c2-.4 3.9-1.3 5.3-2.8l423.9-423.9a9.96 9.96 0 000-14.1L694.9 114.9c-1.9-1.9-4.4-2.9-7.1-2.9s-5.2 1-7.1 2.9L256.8 538.8c-1.5 1.5-2.4 3.3-2.8 5.3l-29.5 168.2a33.5 33.5 0 009.4 29.8c6.6 6.4 14.9 9.9 23.8 9.9zm67.4-174.4L687.8 215l73.3 73.3-362.7 362.6-88.9 15.7 15.6-89zM880 836H144c-17.7 0-32 14.3-32 32v36c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-36c0-17.7-14.3-32-32-32z"
/>
</svg>
</span>
</span>
</button>
</span>
</span>
</div>
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import { fireEvent, render } from '@test/utils';
import { ConfigProvider } from 'antd';
import ActionIcon from '../ActionIcon';

const Icon = () => <svg>o</svg>;

describe('ActionIcon', () => {
it('should render correctly', () => {
const { container } = render(<ActionIcon icon={<Icon />} />);
expect(container).toMatchSnapshot();
});

it('should render with className', () => {
const { getByRole } = render(<ActionIcon icon={<Icon />} className="test" />);
expect(getByRole('button')).toHaveClass('test');
});

it('should render with onClick', () => {
const onClick = vi.fn();
const { getByRole } = render(<ActionIcon icon={<Icon />} onClick={onClick} />);
fireEvent.click(getByRole('button'));
expect(onClick).toBeCalled();
});

describe('disabled', () => {
it('should render with disabled', () => {
const onClick = vi.fn();
const { getByRole } = render(<ActionIcon icon={<Icon />} disabled onClick={onClick} />);
expect(getByRole('button')).toBeDisabled();
fireEvent.click(getByRole('button'));
expect(onClick).not.toBeCalled();
});

it('should render with disabled by antd ConfigProvider', () => {
const { getByRole } = render(
<ConfigProvider componentDisabled>
<ActionIcon icon={<Icon />} />,
</ConfigProvider>,
);
expect(getByRole('button')).toBeDisabled();
});
});

it('should render with style', () => {
const { getByRole } = render(<ActionIcon icon={<Icon />} style={{ color: 'red' }} />);
expect(getComputedStyle(getByRole('button')).color).toBe('rgb(255, 0, 0)');
});

describe('size', () => {
it('should render', () => {
const { getByRole } = render(<ActionIcon icon={<Icon />} size="large" />);
expect(getByRole('button')).toHaveClass('ant-btn-lg');
expect(getComputedStyle(getByRole('button')).maxHeight).toBeFalsy();
});

it.each([void 0, 'small', 'middle'])('should render with size %s', (size: any) => {
const { getByRole } = render(<ActionIcon icon={<Icon />} size={size} />);
expect(getComputedStyle(getByRole('button')).maxHeight).toBeTruthy();
});

it('overwrites max-height', () => {
const { getByRole } = render(
<ActionIcon icon={<Icon />} size="small" style={{ maxHeight: 100 }} />,
);
expect(getComputedStyle(getByRole('button')).maxHeight).toBe('100px');
});

it('should render with size by antd ConfigProvider', () => {
const { getByRole } = render(
<ConfigProvider componentSize="small">
<ActionIcon icon={<Icon />} />,
</ConfigProvider>,
);
expect(getByRole('button')).toHaveClass('ant-btn-sm');
expect(getComputedStyle(getByRole('button')).maxHeight).toBeTruthy();
});
});
});
137 changes: 137 additions & 0 deletions packages/antd-record-hotkey-input/src/__tests__/input.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
import { fireEvent, render, waitFakeTimer } from '@test/utils';
import { ConfigProvider } from 'antd';
import en_US from 'antd/locale/en_US';
import zh_CN from 'antd/locale/zh_CN';
import RecordShortcutInput from '../RecordShortcutInput';

// 抽离一个录制快捷键的测试用例
async function recordShortcut(input: HTMLElement, container: HTMLElement) {
fireEvent.dblClick(input); // 双击输入框进入编辑模式

await waitFakeTimer();

expect(container.querySelector('.ant-record-hotkey-input-recording')).toBeInTheDocument();

// 按下 shift + a
fireEvent.keyDown(input, { keyCode: 16, shiftKey: true, code: 'ShiftLeft' });
fireEvent.keyDown(input, { keyCode: 65, shiftKey: true, code: 'KeyA' });

// 按下回车结束录制
fireEvent.keyDown(input, { keyCode: 13, code: 'Enter' });

expect(input).toHaveValue('Shift + A');
}

describe('RecordShortcutInput', () => {
it('should render correctly', () => {
const { container } = render(<RecordShortcutInput />);
expect(container).toMatchSnapshot();
});

it('正常录制快捷键', async () => {
const { getByRole, container } = render(<RecordShortcutInput />);

const input = getByRole('textbox');

expect(input).toBeInTheDocument();

await recordShortcut(input, container);
});

it('should clear value when click clear icon', async () => {
const { getByRole, getAllByRole, container } = render(<RecordShortcutInput allowClear />);
const input = getByRole('textbox');

await recordShortcut(input, container);

expect(getAllByRole('button')).toHaveLength(2);

// 点击清除按钮
fireEvent.click(getAllByRole('button').at(-1)!);
expect(input).toHaveValue('');
});

it('should not record when disabled', async () => {
const { getByRole, container } = render(<RecordShortcutInput disabled />);
const input = getByRole('textbox');

fireEvent.dblClick(input);

await waitFakeTimer();

// 断言输入框未进入录制状态
expect(container.querySelector('.ant-record-hotkey-input-recording')).not.toBeInTheDocument();
});

it('should render placeholder correctly', () => {
const { getByPlaceholderText } = render(<RecordShortcutInput placeholder="请输入快捷键" />);
expect(getByPlaceholderText('请输入快捷键')).toBeInTheDocument();
});

it('should render placeholder function correctly', () => {
const placeholder = vi.fn((recording) => (recording ? 'foo' : 'bar'));
const { getByRole } = render(<RecordShortcutInput placeholder={placeholder} />);

const input = getByRole('textbox');

expect(input).toHaveAttribute('placeholder', 'bar');

fireEvent.dblClick(input);

expect(input).toHaveAttribute('placeholder', 'foo');
});

describe('模拟录制一半退出', () => {
it('should stop recording when blur', async () => {
const { getByRole, container } = render(<RecordShortcutInput />);
const input = getByRole('textbox');
fireEvent.dblClick(input);

await waitFakeTimer();

expect(container.querySelector('.ant-record-hotkey-input-recording')).toBeInTheDocument();
fireEvent.blur(input);
fireEvent.keyDown(input, { keyCode: 16, shiftKey: true, code: 'ShiftLeft' });
expect(container.querySelector('.ant-record-hotkey-input-recording')).not.toBeInTheDocument();
expect(input).toHaveValue('');
});

it('should stop recording when press esc', async () => {
const { getByRole, container } = render(<RecordShortcutInput />);
const input = getByRole('textbox');
fireEvent.dblClick(input);

await waitFakeTimer();

expect(container.querySelector('.ant-record-hotkey-input-recording')).toBeInTheDocument();
fireEvent.keyDown(input, { keyCode: 27, code: 'Escape' });
expect(container.querySelector('.ant-record-hotkey-input-recording')).not.toBeInTheDocument();
expect(input).toHaveValue('');
});
});

describe('i18n', () => {
it('should render correct i18n text', () => {
const { getByRole } = render(<RecordShortcutInput />);
expect(getByRole('textbox')).toHaveAttribute('placeholder', 'Double click to edit');
});

it('should render correct i18n text with ConfigProvider', () => {
const { getByRole, rerender } = render(
<ConfigProvider locale={zh_CN}>
<RecordShortcutInput />
</ConfigProvider>,
);

expect(getByRole('textbox')).toHaveAttribute('placeholder', '双击以编辑');

rerender(
<ConfigProvider locale={en_US}>
<RecordShortcutInput />
</ConfigProvider>,
);

expect(getByRole('textbox')).toHaveAttribute('placeholder', 'Double click to edit');
});
});
});
2 changes: 1 addition & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"types": ["vitest/globals"],
"paths": {
"@@/*": [".dumi/tmp/*"],
"@test/*": ["tests"],
"@test/*": ["tests/*"],
"antd-record-hotkey-input": ["packages/antd-record-hotkey-input/src"],
"react-use-record-hotkey": ["packages/react-use-record-hotkey/src"]
}
Expand Down
1 change: 1 addition & 0 deletions vitest.config.mts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export default defineConfig({
alias: {
'antd-record-hotkey-input': resolve(__dirname, './packages/antd-record-hotkey-input/src'),
'react-use-record-hotkey': resolve(__dirname, './packages/react-use-record-hotkey/src'),
"@test": resolve(__dirname, './tests'),
},
coverage: {
reporter: ['text', 'text-summary', 'json', 'lcov'],
Expand Down

0 comments on commit d12a3ce

Please sign in to comment.