diff --git a/client/admin/pages_know_info.test.tsx b/client/admin/pages_know_info.test.tsx deleted file mode 100644 index 9f76896..0000000 --- a/client/admin/pages_know_info.test.tsx +++ /dev/null @@ -1,543 +0,0 @@ -import { JSDOM } from 'jsdom' -import React from 'react' -import {render, waitFor, within, fireEvent} from '@testing-library/react' -import {userEvent} from '@testing-library/user-event' -import { QueryClient, QueryClientProvider } from '@tanstack/react-query' -import { createBrowserRouter, RouterProvider } from 'react-router' -import { - assertEquals, - assertExists, - assertNotEquals, - assertRejects, - assert, -} from "https://deno.land/std@0.217.0/assert/mod.ts"; -import axios from 'axios'; -import { KnowInfoPage } from "./pages_know_info.tsx" -import { AuthProvider } from './hooks_sys.tsx' -import { ProtectedRoute } from './components_protected_route.tsx' - -// 拦截React DOM中的attachEvent和detachEvent错误 -const originalError = console.error; -console.error = (...args) => { - // 过滤掉attachEvent和detachEvent相关的错误 - if (args[0] instanceof Error) { - if (args[0].message?.includes('attachEvent is not a function') || - args[0].message?.includes('detachEvent is not a function')) { - return; // 不输出这些错误 - } - } else if (typeof args[0] === 'string') { - if (args[0].includes('attachEvent is not a function') || - args[0].includes('detachEvent is not a function')) { - return; // 不输出这些错误 - } - } - originalError(...args); -}; - -// 应用入口组件 -const App = () => { - // 路由配置 - const router = createBrowserRouter([ - { - path: '/', - element: ( - - - - ) - }, - ]); - return -}; -// setup function -function setup() { - - const dom = new JSDOM(``, { - runScripts: "dangerously", - pretendToBeVisual: true, - url: "http://localhost", - }); - - // 模拟浏览器环境 - globalThis.window = dom.window; - globalThis.document = dom.window.document; - - // 添加必要的 DOM 配置 - globalThis.Node = dom.window.Node; - globalThis.Document = dom.window.Document; - globalThis.HTMLInputElement = dom.window.HTMLInputElement; - globalThis.HTMLButtonElement = dom.window.HTMLButtonElement; - - // 定义浏览器环境所需的类 - globalThis.Element = dom.window.Element; - globalThis.HTMLElement = dom.window.HTMLElement; - globalThis.ShadowRoot = dom.window.ShadowRoot; - globalThis.SVGElement = dom.window.SVGElement; - - - - // 模拟 getComputedStyle - globalThis.getComputedStyle = (elt) => { - const style = new dom.window.CSSStyleDeclaration(); - style.getPropertyValue = () => ''; - return style; - }; - - // 模拟matchMedia函数 - globalThis.matchMedia = (query) => ({ - matches: query.includes('max-width'), - media: query, - onchange: null, - addListener: () => {}, - removeListener: () => {}, - addEventListener: () => {}, - removeEventListener: () => {}, - dispatchEvent: () => false, - }); - - // 模拟动画相关API - globalThis.AnimationEvent = globalThis.AnimationEvent || dom.window.Event; - globalThis.TransitionEvent = globalThis.TransitionEvent || dom.window.Event; - - // 模拟requestAnimationFrame - globalThis.requestAnimationFrame = globalThis.requestAnimationFrame || ((cb) => setTimeout(cb, 0)); - globalThis.cancelAnimationFrame = globalThis.cancelAnimationFrame || clearTimeout; - - // 设置浏览器尺寸相关方法 - window.resizeTo = (width, height) => { - window.innerWidth = width || window.innerWidth; - window.innerHeight = height || window.innerHeight; - window.dispatchEvent(new Event('resize')); - }; - window.scrollTo = () => {}; - - - const customScreen = within(document.body); - - const user = userEvent.setup({ - document: dom.window.document, - delay: 10, - skipAutoClose: true, - }); - - localStorage.setItem('token', 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsInNlc3Npb25JZCI6Ijk4T2lzTW5SMm0zQ0dtNmo4SVZrNyIsInJvbGVJbmZvIjpudWxsLCJpYXQiOjE3NDQzNjIzNTUsImV4cCI6MTc0NDQ0ODc1NX0.k1Ld7qWAZmdzsbjmrl_0ec1FqF_GimaOuQIic4znRtc'); - - axios.defaults.baseURL = 'https://23957.dev.d8dcloud.com' - - const queryClient = new QueryClient() - - return { - user, - // Import `render` from the framework library of your choice. - // See https://testing-library.com/docs/dom-testing-library/install#wrappers - ...render( - - - - - - ), - } -} - -// // 使用异步测试处理组件渲染 -// Deno.test({ -// name: '知识库管理页面基础测试', -// fn: async (t) => { -// // 存储所有需要清理的定时器 -// const timers: number[] = []; -// const originalSetTimeout = globalThis.setTimeout; -// const originalSetInterval = globalThis.setInterval; - -// // 重写定时器方法以跟踪所有创建的定时器 -// globalThis.setTimeout = ((callback, delay, ...args) => { -// const id = originalSetTimeout(callback, delay, ...args); -// timers.push(id); -// return id; -// }) as typeof setTimeout; - -// globalThis.setInterval = ((callback, delay, ...args) => { -// const id = originalSetInterval(callback, delay, ...args); -// timers.push(id); -// return id; -// }) as typeof setInterval; - -// // 清理函数 -// const cleanup = () => { -// for (const id of timers) { -// clearTimeout(id); -// clearInterval(id); -// } -// // 恢复原始定时器方法 -// globalThis.setTimeout = originalSetTimeout; -// globalThis.setInterval = originalSetInterval; -// }; - - - -// try { - - -// // // 渲染组件 -// // const { -// // findByText, findByPlaceholderText, queryByText, -// // findByRole, findAllByRole, findByLabelText, findAllByText, debug, -// // queryByRole - -// // } = render( -// // -// // -// // -// // -// // -// // ); - -// // 测试1: 基本渲染 -// await t.step('应正确渲染页面元素', async () => { -// const { findByText } = setup() -// await waitFor(async () => { -// const title = await findByText(/知识库管理/i); -// assertExists(title, '未找到知识库管理标题'); -// }, { -// timeout: 1000 * 5, -// }); -// }); - -// // 初始加载表格数据 -// await t.step('初始加载表格数据', async () => { -// const { findByRole } = setup() -// await waitFor(async () => { -// const table = await findByRole('table'); -// const rows = await within(table).findAllByRole('row'); - -// // 应该大于2行 -// assert(rows.length > 2, '表格没有数据'); // 1是表头行 2是数据行 - -// }, { -// timeout: 1000 * 5, -// }); -// }); - -// // 测试2: 搜索表单功能 -// await t.step('搜索表单应正常工作', async () => { -// const {findByPlaceholderText, findByText, findByRole, user} = setup() - -// // 等待知识库管理标题出现 -// await waitFor(async () => { -// const title = await findByText(/知识库管理/i); -// assertExists(title, '未找到知识库管理标题'); -// }, { -// timeout: 1000 * 5, -// }); - -// // 直接查找标题搜索输入框和搜索按钮 -// const searchInput = await findByPlaceholderText(/请输入文章标题/i) as HTMLInputElement; -// const searchButton = await findByText(/搜 索/i); - -// assertExists(searchInput, '未找到搜索输入框'); -// assertExists(searchButton, '未找到搜索按钮'); - -// // 输入搜索内容 -// await user.type(searchInput, '数据分析') -// assertEquals(searchInput.value, '数据分析', '搜索输入框值未更新'); - -// // 提交搜索 -// await user.click(searchButton); - - -// let rows: HTMLElement[] = []; - - -// const table = await findByRole('table'); -// assertExists(table, '未找到数据表格'); - -// // 等待表格刷新并验证 -// await waitFor(async () => { -// rows = await within(table).findAllByRole('row'); -// assert(rows.length === 2, '表格未刷新'); -// }, { -// timeout: 1000 * 5, -// onTimeout: () => new Error('等待表格刷新超时') -// }); - -// // 等待搜索结果并验证 -// await waitFor(async () => { -// rows = await within(table).findAllByRole('row'); -// assert(rows.length > 2, '表格没有数据'); -// }, { -// timeout: 1000 * 5, -// onTimeout: () => new Error('等待搜索结果超时') -// }); - - - -// // 检查至少有一行包含"数据分析" -// const matchResults = await Promise.all(rows.map(async row => { -// try{ -// const cells = await within(row).findAllByRole('cell'); -// return cells.some(cell => { -// return cell.textContent?.includes('数据分析') -// }); -// } catch (error: unknown) { -// // console.error('搜索结果获取失败', error) -// return false -// } -// })) -// // console.log('matchResults', matchResults) -// const hasMatch = matchResults.some(result => result); - -// assert(hasMatch, '搜索结果中没有找到包含"数据分析"的文章'); -// }); - -// // 测试3: 表格数据加载 -// await t.step('表格应加载并显示数据', async () => { -// const {findByRole, queryByText} = setup() -// // 等待数据加载完成或表格出现,最多等待5秒 -// await waitFor(async () => { -// // 检查加载状态是否消失 -// const loading = queryByText(/正在加载数据/i); -// if (loading) { -// throw new Error('数据仍在加载中'); -// } - -// // 检查表格是否出现 -// const table = await findByRole('table'); -// assertExists(table, '未找到数据表格'); - -// // 检查表格是否有数据行 -// const rows = await within(table).findAllByRole('row'); -// assertNotEquals(rows.length, 1, '表格没有数据行'); // 1是表头行 -// }, { -// timeout: 5000, // 5秒超时 -// onTimeout: (error) => { -// return new Error(`数据加载超时: ${error.message}`); -// } -// }); -// }); - -// // 测试4: 添加文章功能 -// await t.step('应能打开添加文章模态框', async () => { -// const {findByText, findByRole, user} = setup() -// // 等待知识库管理标题出现 -// await waitFor(async () => { -// const title = await findByText(/知识库管理/i); -// assertExists(title, '未找到知识库管理标题'); -// }, { -// timeout: 1000 * 5, -// }); - -// const addButton = await findByText(/添加文章/i); -// assertExists(addButton, '未找到添加文章按钮'); - -// await user.click(addButton); - -// // 找到模态框 -// const modal = await findByRole('dialog'); -// assertExists(modal, '未找到模态框'); - -// const modalTitle = await within(modal).findByText(/添加知识库文章/i); -// assertExists(modalTitle, '未找到添加文章模态框'); - -// // 验证表单字段 -// const titleInput = await within(modal).findByPlaceholderText(/请输入文章标题/i); -// assertExists(titleInput, '未找到标题输入框'); - -// const contentInput = await within(modal).findByPlaceholderText(/请输入文章内容/i); -// assertExists(contentInput, '未找到文章内容输入框'); - -// // 取消 -// const cancelButton = await within(modal).findByText(/取 消/i); -// assertExists(cancelButton, '未找到取消按钮'); -// await user.click(cancelButton); - -// // 验证模态框是否关闭 -// await waitFor(async () => { - -// const modalTitle = await within(modal).findByText(/添加知识库文章/i); -// assertExists(!modalTitle, '模态框未关闭'); -// }, { -// timeout: 1000 * 5, -// onTimeout: () => new Error('等待模态框关闭超时') -// }); -// }); - -// } finally { -// // 确保清理所有定时器 -// cleanup(); -// } -// }, -// sanitizeOps: false, // 禁用操作清理检查 -// sanitizeResources: false, // 禁用资源清理检查 -// }); - -Deno.test({ - name: '知识库管理页面新增测试', - fn: async (t) => { - // 存储所有需要清理的定时器 - const timers: number[] = []; - const originalSetTimeout = globalThis.setTimeout; - const originalSetInterval = globalThis.setInterval; - - // 重写定时器方法以跟踪所有创建的定时器 - globalThis.setTimeout = ((callback, delay, ...args) => { - const id = originalSetTimeout(callback, delay, ...args); - timers.push(id); - return id; - }) as typeof setTimeout; - - globalThis.setInterval = ((callback, delay, ...args) => { - const id = originalSetInterval(callback, delay, ...args); - timers.push(id); - return id; - }) as typeof setInterval; - - // 清理函数 - const cleanup = () => { - for (const id of timers) { - clearTimeout(id); - clearInterval(id); - } - // 恢复原始定时器方法 - globalThis.setTimeout = originalSetTimeout; - globalThis.setInterval = originalSetInterval; - }; - - - - try { - - - // // 渲染组件 - // const { - // findByText, findByPlaceholderText, queryByText, - // findByRole, findAllByRole, findByLabelText, findAllByText, debug, - // queryByRole - - // } = render( - // - // - // - // - // - // ); - - - // 测试5: 完整添加文章流程 - await t.step('应能完整添加一篇文章', async () => { - const {findByText, findByRole, debug, user} = setup() - // 等待知识库管理标题出现 - await waitFor(async () => { - const title = await findByText(/知识库管理/i); - assertExists(title, '未找到知识库管理标题'); - }, { - timeout: 1000 * 5, - }); - // 打开添加模态框 - const addButton = await findByText(/添加文章/i); - assertExists(addButton, '未找到添加文章按钮'); - - await user.click(addButton); - - // 找到模态框 - const modal = await findByRole('dialog'); - assertExists(modal, '未找到模态框'); - - const modalTitle = await within(modal).findByText(/添加知识库文章/i); - assertExists(modalTitle, '未找到添加文章模态框'); - - // 确保上一个测试的输入框值不会影响这个测试 - // 在模态框内查找标题和内容输入框 - const titleInput = await within(modal).findByPlaceholderText(/请输入文章标题/i) as HTMLInputElement; - const contentInput = await within(modal).findByPlaceholderText(/请输入文章内容/i) as HTMLTextAreaElement; - const submitButton = await within(modal).findByText(/确 定/i); - - assertExists(titleInput, '未找到模态框中的标题输入框'); - assertExists(contentInput, '未找到文章内容输入框'); - assertExists(submitButton, '未找到提交按钮'); - - // 先清空输入框,以防止之前的测试影响 - // await user.clear(titleInput); - // await user.clear(contentInput); - - // 输入新值 - await user.type(titleInput, '测试文章标题'); - await user.type(contentInput, '这是测试文章内容'); - - debug(titleInput); - debug(contentInput); - debug(submitButton); - - // 提交表单 - await user.click(submitButton); - - // 验证表单字段 - assertEquals(titleInput.value, '测试文章标题', '模态框中标题输入框值未更新'); - assertEquals(contentInput.value, '这是测试文章内容', '内容输入框值未更新'); - - let rows: HTMLElement[] = []; - - - const table = await findByRole('table'); - assertExists(table, '未找到数据表格'); - - // 等待表格刷新并验证 - await waitFor(async () => { - rows = await within(table).findAllByRole('row'); - assert(rows.length === 2, '表格未刷新'); - }, { - timeout: 1000 * 5, - onTimeout: () => new Error('等待表格刷新超时') - }); - - // 等待搜索结果并验证 - await waitFor(async () => { - rows = await within(table).findAllByRole('row'); - assert(rows.length > 2, '表格没有数据'); - }, { - timeout: 1000 * 5, - onTimeout: () => new Error('等待搜索结果超时') - }); - - // 检查至少有一行包含"测试文章标题" - const matchResults = await Promise.all(rows.map(async row => { - try{ - const cells = await within(row).findAllByRole('cell'); - return cells.some(cell => { - return cell.textContent?.includes('测试文章标题') - }); - } catch (error: unknown) { - // console.error('搜索结果获取失败', error) - return false - } - })) - // console.log('matchResults', matchResults) - const hasMatch = matchResults.some(result => result); - - assert(hasMatch, '搜索结果中没有找到包含"测试文章标题"的文章'); - }); - - // // 测试5: 分页功能 - // await t.step('应显示分页控件', async () => { - // const pagination = await findByRole('navigation'); - // assertExists(pagination, '未找到分页控件'); - - // const pageItems = await findAllByRole('button', { name: /1|2|3|下一页|上一页/i }); - // assertNotEquals(pageItems.length, 0, '未找到分页按钮'); - // }); - - // // 测试6: 操作按钮 - // await t.step('应显示操作按钮', async () => { - // const editButtons = await findAllByText(/编辑/i); - // assertNotEquals(editButtons.length, 0, '未找到编辑按钮'); - - // const deleteButtons = await findAllByText(/删除/i); - // assertNotEquals(deleteButtons.length, 0, '未找到删除按钮'); - // }); - } finally { - // 确保清理所有定时器 - cleanup(); - } - }, - sanitizeOps: false, // 禁用操作清理检查 - sanitizeResources: false, // 禁用资源清理检查 -}); \ No newline at end of file diff --git a/client/admin/pages_theme_setting.test.tsx b/client/admin/pages_theme_setting.test.tsx deleted file mode 100644 index 3ed0d48..0000000 --- a/client/admin/pages_theme_setting.test.tsx +++ /dev/null @@ -1,115 +0,0 @@ -import { JSDOM } from 'jsdom' -import React from 'react' -import {render, fireEvent, within, screen} from '@testing-library/react' -import { ThemeSettingsPage } from "./pages_theme_settings.tsx" -import { ThemeProvider } from "./hooks_sys.tsx" -import { QueryClient, QueryClientProvider } from '@tanstack/react-query' -import { - assertEquals, - assertExists, - assertNotEquals, - assertRejects, -} from "https://deno.land/std@0.217.0/assert/mod.ts"; - -const queryClient = new QueryClient() - - -const dom = new JSDOM(``, { - runScripts: "dangerously", - pretendToBeVisual: true, - url: "http://localhost" -}); - -// 模拟浏览器环境 -globalThis.window = dom.window; -globalThis.document = dom.window.document; - -// 定义浏览器环境所需的类 -globalThis.Element = dom.window.Element; -globalThis.HTMLElement = dom.window.HTMLElement; -globalThis.ShadowRoot = dom.window.ShadowRoot; -globalThis.SVGElement = dom.window.SVGElement; - -// 模拟 getComputedStyle -globalThis.getComputedStyle = (elt) => { - const style = new dom.window.CSSStyleDeclaration(); - style.getPropertyValue = () => ''; - return style; -}; - -// 模拟matchMedia函数 -globalThis.matchMedia = (query) => ({ - matches: query.includes('max-width'), - media: query, - onchange: null, - addListener: () => {}, - removeListener: () => {}, - addEventListener: () => {}, - removeEventListener: () => {}, - dispatchEvent: () => false, -}); - -// 模拟动画相关API -globalThis.AnimationEvent = globalThis.AnimationEvent || dom.window.Event; -globalThis.TransitionEvent = globalThis.TransitionEvent || dom.window.Event; - -// 模拟requestAnimationFrame -globalThis.requestAnimationFrame = globalThis.requestAnimationFrame || ((cb) => setTimeout(cb, 0)); -globalThis.cancelAnimationFrame = globalThis.cancelAnimationFrame || clearTimeout; - -// 设置浏览器尺寸相关方法 -window.resizeTo = (width, height) => { - window.innerWidth = width || window.innerWidth; - window.innerHeight = height || window.innerHeight; - window.dispatchEvent(new Event('resize')); -}; -window.scrollTo = () => {}; - -const customScreen = within(document.body); - -// 使用异步测试处理真实API调用 -Deno.test('主题设置页面测试', async (t) => { - // 渲染组件 - const {findByRole, debug} = render( - - - - - - ) - - // debug(await findByRole('radio', { name: /浅色模式/i })) - - // 测试1: 渲染基本元素 - await t.step('应渲染主题设置标题', async () => { - const title = await customScreen.findByText(/主题设置/i) - assertExists(title, '未找到主题设置标题') - }) - - // 测试2: 表单初始化状态 - await t.step('表单应正确初始化', async () => { - // 检查主题模式选择 - const lightRadio = await customScreen.findByRole('radio', { name: /浅色模式/i }) - assertExists(lightRadio, '未找到浅色模式单选按钮') - - // 检查主题模式标签 - const themeModeLabel = await customScreen.findByText(/主题模式/i) - assertExists(themeModeLabel, '未找到主题模式标签') - - // // 检查主题模式选择器 - Ant Design 使用 div 包裹 radio 而不是 radiogroup - // const themeModeField = await customScreen.findByTestId('theme-mode-selector') - // assertExists(themeModeField, '未找到主题模式选择器') - }) - - // 测试3: 配色方案选择 - await t.step('应显示配色方案选项', async () => { - // 查找预设配色方案标签 - const colorSchemeLabel = await customScreen.findByText('预设配色方案') - assertExists(colorSchemeLabel, '未找到预设配色方案标签') - - // 查找配色方案按钮 - const colorSchemeButtons = await customScreen.findAllByRole('button') - assertNotEquals(colorSchemeButtons.length, 0, '未找到配色方案按钮') - }) -}) -