diff --git a/apps/web/src/test/utils/renderWithProviders.test.tsx b/apps/web/src/test/utils/renderWithProviders.test.tsx
new file mode 100644
index 0000000..dc61e2d
--- /dev/null
+++ b/apps/web/src/test/utils/renderWithProviders.test.tsx
@@ -0,0 +1,26 @@
+import { describe, it, expect } from 'vitest';
+import { screen } from '@testing-library/react';
+import { renderWithProviders } from './renderWithProviders';
+
+function DummyPage() {
+ return
Hello Test
;
+}
+
+describe('renderWithProviders', () => {
+ it('renders child component', () => {
+ renderWithProviders();
+ expect(screen.getByTestId('dummy')).toHaveTextContent('Hello Test');
+ });
+
+ it('wraps with MemoryRouter — Link renders without error', () => {
+ function PageWithLink() {
+ return (
+
+ );
+ }
+ renderWithProviders();
+ expect(screen.getByText('Go')).toHaveAttribute('href', '/test');
+ });
+});
diff --git a/apps/web/src/test/utils/renderWithProviders.tsx b/apps/web/src/test/utils/renderWithProviders.tsx
new file mode 100644
index 0000000..0fc6d3c
--- /dev/null
+++ b/apps/web/src/test/utils/renderWithProviders.tsx
@@ -0,0 +1,25 @@
+import { ReactElement } from 'react';
+import { render, RenderOptions } from '@testing-library/react';
+import { MemoryRouter } from 'react-router-dom';
+import { ConfigProvider } from 'antd';
+import zhCN from 'antd/locale/zh_CN';
+
+interface CustomRenderOptions extends Omit {
+ route?: string;
+}
+
+export function renderWithProviders(ui: ReactElement, options: CustomRenderOptions = {}) {
+ const { route = '/', ...renderOptions } = options;
+
+ function Wrapper({ children }: { children: React.ReactNode }) {
+ return (
+
+ {children}
+
+ );
+ }
+
+ return render(ui, { wrapper: Wrapper, ...renderOptions });
+}
+
+export * from '@testing-library/react';