Files
testing-tool/pages/Base64Converter/__tests__/ImageMode.test.tsx
T
雨霖铃 8ec36ac3b3 test: fix i18n namespace assertions in Base64Converter and QrCode tests
Align test selectors with useLazyTranslation mock which prefixes keys
with namespace (e.g. base64Converter:encode). Also remove obsolete
page title assertions for components that no longer render titles.
2026-05-23 14:04:10 +08:00

183 lines
6.2 KiB
TypeScript

import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { act, fireEvent, render, screen, waitFor } from '@testing-library/react';
import ImageMode from '../ImageMode';
// Mock CopyButton
vi.mock('@/components/CopyButton', () => ({
default: ({ text, tooltip }: { text: string; tooltip?: string }) => (
<button data-testid="copy-button" data-tooltip={tooltip}>
{text.slice(0, 20)}
</button>
),
}));
beforeEach(() => {
localStorage.clear();
vi.useFakeTimers({ shouldAdvanceTime: true });
});
afterEach(() => {
vi.useRealTimers();
});
const waitForStorageReady = () => act(() => Promise.resolve());
describe('ImageMode', () => {
it('应该渲染图像上传区域', async () => {
render(<ImageMode />);
await waitForStorageReady();
expect(screen.getByText('base64Converter:clickOrDropToImage')).toBeInTheDocument();
expect(screen.getByText('base64Converter:supportedFormats')).toBeInTheDocument();
});
it('应该接受有效的图像文件', async () => {
render(<ImageMode />);
await waitForStorageReady();
const file = new File(['fake-image-data'], 'test.png', { type: 'image/png' });
const hiddenInput = document.querySelector('input[type="file"]') as HTMLInputElement;
fireEvent.change(hiddenInput, { target: { files: [file] } });
await waitFor(() => {
expect(screen.getByText('test.png')).toBeInTheDocument();
expect(screen.getByText('base64Converter:base64Output')).toBeInTheDocument();
});
});
it('应该拒绝非图像文件', async () => {
render(<ImageMode />);
await waitForStorageReady();
const file = new File(['not an image'], 'test.txt', { type: 'text/plain' });
const hiddenInput = document.querySelector('input[type="file"]') as HTMLInputElement;
fireEvent.change(hiddenInput, { target: { files: [file] } });
await waitFor(() => {
expect(screen.getByRole('alert')).toHaveTextContent('base64Converter:unsupportedImageType');
});
});
it('应该拒绝超出大小限制的图像', async () => {
render(<ImageMode />);
await waitForStorageReady();
const largeContent = new Uint8Array(11 * 1024 * 1024);
const file = new File([largeContent], 'large.png', { type: 'image/png' });
const hiddenInput = document.querySelector('input[type="file"]') as HTMLInputElement;
fireEvent.change(hiddenInput, { target: { files: [file] } });
await waitFor(() => {
expect(screen.getByRole('alert')).toHaveTextContent('base64Converter:fileSizeExceeded');
});
});
it('应该通过扩展名识别图像', async () => {
render(<ImageMode />);
await waitForStorageReady();
// 没有 MIME 类型但有正确扩展名
const file = new File(['fake'], 'test.jpg');
const hiddenInput = document.querySelector('input[type="file"]') as HTMLInputElement;
fireEvent.change(hiddenInput, { target: { files: [file] } });
await waitFor(() => {
expect(screen.getByText('test.jpg')).toBeInTheDocument();
});
});
it('点击清除按钮应该清空图像状态', async () => {
render(<ImageMode />);
await waitForStorageReady();
const file = new File(['fake'], 'test.png', { type: 'image/png' });
const hiddenInput = document.querySelector('input[type="file"]') as HTMLInputElement;
fireEvent.change(hiddenInput, { target: { files: [file] } });
await waitFor(() => {
expect(screen.getByText('test.png')).toBeInTheDocument();
});
fireEvent.click(screen.getByText('base64Converter:clear'));
await waitFor(() => {
expect(screen.queryByText('test.png')).not.toBeInTheDocument();
expect(screen.getByText('base64Converter:clickOrDropToImage')).toBeInTheDocument();
});
});
it('应该显示图像预览', async () => {
render(<ImageMode />);
await waitForStorageReady();
const file = new File(['fake-image'], 'test.png', { type: 'image/png' });
const hiddenInput = document.querySelector('input[type="file"]') as HTMLInputElement;
fireEvent.change(hiddenInput, { target: { files: [file] } });
await waitFor(() => {
const img = screen.getByAltText('preview');
expect(img).toBeInTheDocument();
expect(img.tagName.toLowerCase()).toBe('img');
});
});
it('应该渲染 encode/decode 切换按钮', async () => {
render(<ImageMode />);
await waitForStorageReady();
expect(screen.getByText('base64Converter:encode')).toBeInTheDocument();
expect(screen.getByText('base64Converter:decode')).toBeInTheDocument();
});
it('解码 PNG Base64 后应该显示图像预览', async () => {
render(<ImageMode />);
await waitForStorageReady();
fireEvent.click(screen.getByText('base64Converter:decode'));
const input = await screen.findByPlaceholderText('base64Converter:decodeBase64Placeholder');
fireEvent.change(input, { target: { value: 'iVBORw0KGgo=' } });
act(() => {
vi.advanceTimersByTime(250);
});
await waitFor(() => {
expect(screen.getByText('base64Converter:decodedImageOutput')).toBeInTheDocument();
const img = screen.getByAltText('decoded preview');
expect(img).toBeInTheDocument();
expect(img.tagName.toLowerCase()).toBe('img');
});
});
it('解码后默认文件名应该为 decoded.png', async () => {
render(<ImageMode />);
await waitForStorageReady();
fireEvent.click(screen.getByText('base64Converter:decode'));
const input = await screen.findByPlaceholderText('base64Converter:decodeBase64Placeholder');
fireEvent.change(input, { target: { value: 'iVBORw0KGgo=' } });
act(() => {
vi.advanceTimersByTime(250);
});
expect(await screen.findByDisplayValue('decoded.png')).toBeInTheDocument();
});
it('解码非法 Base64 应该显示 invalidBase64 错误', async () => {
render(<ImageMode />);
await waitForStorageReady();
fireEvent.click(screen.getByText('base64Converter:decode'));
const input = await screen.findByPlaceholderText('base64Converter:decodeBase64Placeholder');
fireEvent.change(input, { target: { value: '!!!not base64' } });
act(() => {
vi.advanceTimersByTime(250);
});
await waitFor(() => {
expect(screen.getByText('base64Converter:invalidBase64')).toBeInTheDocument();
});
});
});