
大数据数据库后端【免费下载链接】prestoThe official home of the Presto distributed SQL query engine for big data项目地址https://gitcode.com/gh_mirrors/pre/presto点击查看免费下载Presto 分布式 SQL 查询引擎的 Web 管理界面presto-ui内置了一套完整的 React 组件测试基础设施涵盖 Jest 配置、公共测试工具函数、Mock 体系与测试数据工厂。本文以presto-ui/src/__tests__/README.md为骨架结合仓库中jest.config.js、setupTests.ts、testUtils.tsx、setupHelpers.ts等真实源码系统讲解该测试体系的设计与用法帮助读者快速上手编写稳定、高效、可维护的 Presto UI 测试用例。快速开始运行与编写你的第一个测试运行测试的命令在presto-ui目录下package.json中的 scripts 已定义好全部测试命令执行# 运行全部测试 yarn test # 监听模式运行文件变更自动重跑 yarn test:watch # 带覆盖率统计运行 yarn test:coverage # 只运行指定测试文件 yarn test QueryList.test.jsx此外presto-ui/src/package.json还额外提供了面向 CI 的命令test:cijest --ci --coverage --maxWorkers2适用于流水线场景。注意package.json要求 Node.js 版本22.15.1。编写第一个测试测试文件一般与被测组件同级放置如components/MyComponent.test.tsx并统一从src/__tests__下导入测试基础设施import { render, screen } from ../__tests__/utils/testUtils; import { setupCommonMocks } from ../__tests__/utils/setupHelpers; import { createMockQuery } from ../__tests__/fixtures; import MyComponent from ./MyComponent; describe(MyComponent, () { setupCommonMocks(); it(renders correctly, () { const query createMockQuery(); render(MyComponent query{query} /); expect(screen.getByText(/expected text/i)).toBeInTheDocument(); }); });testUtils.tsx内部会export * from testing-library/react并额外导出userEvent因此从该文件导入的render、screen与直接使用 Testing Library 完全等价。测试目录结构按presto-ui/src/__tests__/README.md的约定测试相关代码按职责划分为三层src/ ├── __tests__/ # 测试基础设施不含测试用例本身 │ ├── fixtures/ # 测试数据工厂 │ │ ├── index.ts # Barrel 统一出口 │ │ ├── queryFixtures.js │ │ ├── infoFixtures.ts │ │ ├── stageFixtures.ts │ │ └── clusterFixtures.ts │ ├── mocks/ # Mock 工具 │ │ ├── index.ts # Barrel 统一出口 │ │ ├── apiMocks.ts # Fetch API 拦截 │ │ ├── jqueryMock.ts # jQuery 选择性 Mock │ │ └── browserMocks.ts # 浏览器 API Mock │ ├── utils/ # 测试工具函数 │ │ ├── testUtils.tsx # 通用断言/交互助手 │ │ └── setupHelpers.ts # 通用 setup 模式 │ └── README.md # 本文档 ├── components/ │ └── MyComponent.test.tsx └── router/ └── QueryList.test.jsx该目录结构在仓库中已完整落地fixtures/、mocks/、utils/三个子目录及对应文件均可直接在presto-ui/src/__tests__/下找到。三个目录均提供index.ts作为 barrel 出口测试代码中统一使用../__tests__/mocks、../__tests__/fixtures、../__tests__/utils/testUtils形式的导入无需关心内部文件拆分。测试工具函数testUtilspresto-ui/src/__tests__/utils/testUtils.tsx提供了一组覆盖加载状态、文本匹配、下拉框、表单、定时器与交互等待的公共助手。以下为 README 中的完整用法加载状态助手import { waitForLoadingToFinish, expectLoading } from ../__tests__/utils/testUtils; // 等待 loading 指示消失内部轮询直到页面上不再出现 /loading/i 文本 render(Component /); await waitForLoadingToFinish(); // 断言 loading 正在展示 render(Component /); expectLoading();源码层面waitForLoadingToFinish实现为waitFor(() expect(screen.queryByText(/loading/i)).not.toBeInTheDocument())expectLoading则断言/loading/i文本存在见 testUtils.tsx。文本内容精确匹配器当目标文本被拆散到多个子元素中时普通getByText无法精确匹配整段文本此时使用基于textContent的精确匹配import { findByTextContent, getByTextContent, queryByTextContent } from ../__tests__/utils/testUtils; // 按完整文本内容异步查找 const element await findByTextContent(Total: 100); // 按完整文本内容同步获取找不到直接抛错 const element getByTextContent(Total: 100); // 查询找不到返回 null便于反向断言 const element queryByTextContent(Total: 100);三者的底层实现均通过screen.getByText((content, element) element?.textContent text)这类回调式匹配器完成见 testUtils.tsx。下拉框助手import { clickDropdownOption, selectDropdownByRole } from ../__tests__/utils/testUtils; // 点击文本为 Sort By 的下拉框再选择 Name 选项 await clickDropdownOption(Sort By, Name); // 按 ARIA role 定位下拉框如 combobox并选择选项 await selectDropdownByRole(combobox, Option 1);表单交互助手import { typeIntoInput, setInputValue, clickButton, clickButtonSync, appendToInput, } from ../__tests__/utils/testUtils; // 真实输入先 clear 再逐键输入模拟用户行为 await typeIntoInput(/search/i, test query); // 直接赋值走 fireEvent.change速度快适合非交互测试 setInputValue(/search/i, test query); // 真实点击按钮按可访问名称定位 await clickButton(/submit/i); // 同步点击fireEvent.click更快 clickButtonSync(/submit/i); // 追加输入不清空已有内容 await appendToInput(/search/i, more text);何时用 async 版本、何时用 sync 版本测试真实用户交互行为如输入、点击的完整事件序列时使用async 助手clickButton、typeIntoInput其内部基于testing-library/user-event模拟仅需触发状态变更、不关心交互细节时使用sync 助手clickButtonSync、setInputValue内部基于fireEvent速度更快。定时器助手import { advanceTimersAndWait, typeWithDebounce } from ../__tests__/utils/testUtils; // 推进定时器并等待 React 更新常用于防抖场景 await typeIntoInput(/search/i, test); await advanceTimersAndWait(300); // 等待 300ms 防抖触发 // 输入并自动处理防抖 const input screen.getByPlaceholderText(/search/i); await typeWithDebounce(input, test, 300);需要特别说明的是advanceTimersAndWait依赖 Jest 假定时器。若未启用它会抛出一条带引导信息的错误提示先调用setupFakeTimers()或setupIntegrationTest()见 testUtils.tsx。这正是 README 在「Configuration」章节中专门压制假定时器告警的原因。交互等待助手import { clickAndWait, clickAndWaitForRemoval } from ../__tests__/utils/testUtils; // 点击后等待某段文本出现如成功提示 await clickAndWait(button, /success/i); // 点击后等待元素从 DOM 中消失如删除按钮 await clickAndWaitForRemoval(deleteButton);组件级 Setup 助手setupHelperspresto-ui/src/__tests__/utils/setupHelpers.ts将常见测试的前置准备Mock 清理、浏览器 API、假定时器封装为可在describe块中直接调用的模式。源码中提供了三个通用组合见 setupHelpers.tsimport { setupCommonMocks, setupFakeTimers, setupIntegrationTest } from ../__tests__/utils/setupHelpers; // 通用 Mock 组合beforeEach 中 clearAllMocks setupAllBrowserMocks describe(MyComponent, () { setupCommonMocks(); it(test, () { /* ... */ }); }); // 假定时器组合beforeEach 启用、afterEach 恢复真实定时器 describe(MyComponent, () { setupFakeTimers(); it(test with timers, () { /* ... */ }); }); // 集成测试组合同时启用假定时器并清理 Mock describe(MyComponent Integration, () { setupIntegrationTest(); it(integration test, async () { /* ... */ }); });README 还记录了针对 Presto UI 核心页面的专用 setup 模式其组件级实现位于setupHelpers.ts的 Custom Setup Builders 区域QueryList Setupimport { setupQueryListTest } from ../__tests__/utils/setupHelpers; import { createRunningQuery, createFinishedQuery } from ../__tests__/fixtures; const { mockQueries } setupQueryListTest([ createRunningQuery({ queryId: q1 }), createFinishedQuery({ queryId: q2 }), ]); render(QueryList /);QueryDetail Setupimport { setupQueryDetailTest } from ../__tests__/utils/setupHelpers; import { createMockQuery } from ../__tests__/fixtures; const { mockQuery } setupQueryDetailTest(createMockQuery({ queryId: test_123 }), { includeStages: true }); render(QueryDetail queryIdtest_123 /);ClusterHUD Setupimport { setupClusterHUDTest } from ../__tests__/utils/setupHelpers; const { clusterData } setupClusterHUDTest({ clusterData: { runningQueries: 10 }, workerData: [{ workerId: w1, state: ACTIVE }], }); render(ClusterHUD /);Mock 体系Mock 统一从__tests__/mocks导入覆盖 jQuery、Fetch API 与浏览器 API 三类外部依赖。jQuery MockPresto UI 使用 jQuery 4.0.0见package.json依赖声明测试采用保留真实 jQuery、选择性 Mock 插件的策略import { mockJQueryGet, mockJQueryAjax } from ../__tests__/mocks; // Mock $.get mockJQueryGet(/api/query, { queryId: 123, state: RUNNING }); // Mock $.ajax mockJQueryAjax({ url: /api/query, success: (data) data, error: (xhr, status, error) error, });Fetch API Mockimport { mockFetchByUrl } from ../__tests__/mocks; import { createMockQuery } from ../__tests__/fixtures; mockFetchByUrl({ /v1/query: [createMockQuery()], /v1/info: { runningQueries: 5 }, });浏览器 API Mockimport { setupAllBrowserMocks } from ../__tests__/mocks; beforeEach(() { setupAllBrowserMocks(); });浏览器 API Mock 的全局装配发生在 setupTests.ts该文件在每个测试文件执行前依次调用setupAllBrowserMocks()覆盖matchMedia、hljs、clipboard、document等浏览器 API、setupFetchMock()集中的 Fetch 拦截与setupJQuery()选择性 jQuery Mock。这意味着大多数测试无需手动配置这些 Mock直接通过组件级 setup 即可使用。测试数据工厂FixturesFixtures 为测试数据提供带合理默认值的工厂函数统一从__tests__/fixtures导入。查询类 Fixturesimport { createMockQuery, createRunningQuery, createFinishedQuery, createFailedQuery } from ../__tests__/fixtures; // 基础查询对象 const query createMockQuery(); // 运行中查询可覆盖字段 const runningQuery createRunningQuery({ queryId: custom_123, query: SELECT * FROM users, }); // 已完成查询 const finishedQuery createFinishedQuery({ elapsedTime: 5.2s, }); // 失败查询 const failedQuery createFailedQuery({ errorType: USER_ERROR, errorCode: { name: SYNTAX_ERROR }, });其他 Fixturesimport { createMockInfo, createMockStage, createMockCluster } from ../__tests__/fixtures; const info createMockInfo({ runningQueries: 10 }); const stage createMockStage({ stageId: 0 }); const cluster createMockCluster({ activeWorkers: 5 });这些工厂函数与createMockQuery一样都接受覆盖对象参数未提供的字段自动取默认值从而避免在测试中手写冗长的完整数据对象。测试模式Testing Patterns单元测试import { render, screen } from ../__tests__/utils/testUtils; import { setupCommonMocks } from ../__tests__/utils/setupHelpers; import { createMockQuery } from ../__tests__/fixtures; import QueryListItem from ./QueryListItem; describe(QueryListItem, () { setupCommonMocks(); it(displays query ID, () { const query createMockQuery({ queryId: test_123 }); render(QueryListItem query{query} /); expect(screen.getByText(test_123)).toBeInTheDocument(); }); });集成测试import { render, screen } from ../__tests__/utils/testUtils; import { setupIntegrationTest, setupQueryListTest } from ../__tests__/utils/setupHelpers; import { clickButton } from ../__tests__/utils/testUtils; import { createRunningQuery, createFinishedQuery } from ../__tests__/fixtures; import QueryList from ./QueryList; describe(QueryList Integration, () { setupIntegrationTest(); it(filters queries by state, async () { setupQueryListTest([createRunningQuery({ queryId: q1 }), createFinishedQuery({ queryId: q2 })]); render(QueryList /); await clickButton(/FINISHED/i); expect(screen.getByText(q2)).toBeInTheDocument(); expect(screen.queryByText(q1)).not.toBeInTheDocument(); }); });定时器测试防抖场景import { render, screen } from ../__tests__/utils/testUtils; import { setupFakeTimers } from ../__tests__/utils/setupHelpers; import { typeIntoInput, advanceTimersAndWait } from ../__tests__/utils/testUtils; describe(SearchComponent, () { setupFakeTimers(); it(debounces search input, async () { render(SearchComponent /); await typeIntoInput(/search/i, test); await advanceTimersAndWait(300); expect(screen.getByText(/results for test/i)).toBeInTheDocument(); }); });测试环境配置Jest 配置要点测试配置位于 jest.config.js注意配置文件在src/目录下而不是模块根目录。核心配置项包括presetts-jest配合transform规则TS/TSX 走ts-jestJS/JSX 走babel-jest同时支持 TS 与 JS 测试文件testEnvironmentjsdom模拟浏览器 DOMtestMatch匹配**/__tests__/**/*.(ts|tsx|js|jsx)以及*.test.*/*.spec.*文件setupFilesAfterEnvrootDir/setupTests.ts即全局测试初始化moduleNameMapper将 CSS/LESS/SCSS/SASS 映射为identity-obj-proxy避免样式导入导致测试失败transformIgnorePatterns白名单放行dagre-d3-es、d3等 ESM 依赖确保它们可被转换collectCoverageFrom / testPathIgnorePatterns覆盖统计与测试发现均排除sql-parser、static、templates以及__tests__下的工具、Mock、Fixtures 目录这些是基础设施而非测试用例覆盖率阈值当前被注释禁用README 注释为先保证测试通过率后续再开启覆盖率报告格式为text、lcov、html。依赖版本README 记载的测试技术栈为Jest 29.7.0ts-jest babel-jest、React Testing Library 16.1.0、testing-library/user-event 14.5.2而presto-ui/src/package.json中实际声明的版本为jest ^30.3.0、testing-library/react ^16.3.2、testing-library/user-event ^14.6.1、ts-jest ^29.4.9并配套testing-library/jest-dom ^6.9.1提供toBeInTheDocument等自定义匹配器。实际运行时以package.json锁定的依赖为准。假定时器告警压制在启用假定时器的测试中异步助手调用jest.advanceTimersByTime()会触发 Jest 的已知误报警告A function to advance timers was called but the timers APIs are not replaced…。setupTests.ts 在 Jest 环境通过process.env.JEST_WORKER_ID判断下对该告警进行精确前缀匹配并静默同时保留其他所有合法告警const originalWarn console.warn; const JEST_FAKE_TIMER_WARNING A function to advance timers was called but the timers APIs are not replaced with fake timers. Call jest.useFakeTimers() in this test file or enable fake timers for all tests by setting fakeTimers: {enableGlobally: true} in Jest configuration file.; if (process.env.JEST_WORKER_ID ! undefined) { console.warn (...args: any[]) { const message args[0]?.toString() || ; if (message.startsWith(JEST_FAKE_TIMER_WARNING)) { return; } originalWarn.apply(console, args); }; }该设计刻意使用完整前缀 仅限 Jest 环境的双重约束避免误伤测试中对console.warn的 spy 断言。最佳实践1. 优先使用 Setup 助手✅推荐使用 setup 助手统一前置准备describe(QueryList, () { setupCommonMocks(); it(test, () { setupQueryListTest([createMockQuery()]); render(QueryList /); }); });❌不推荐每个用例手动重复拼装it(test, () { jest.clearAllMocks(); setupAllBrowserMocks(); mockFetchByUrl({ /v1/query: [createMockQuery()] }); render(QueryList /); });2. 优先使用测试工具函数✅推荐语义化的一行调用await clickButton(/submit/i); await typeIntoInput(/search/i, test);❌不推荐裸写 Testing Library 底层交互const button screen.getByRole(button, { name: /submit/i }); await userEvent.click(button); const input screen.getByPlaceholderText(/search/i); await userEvent.type(input, test);3. 优先使用 Fixtures✅推荐工厂函数 少量覆盖const query createRunningQuery({ queryId: test });❌不推荐手写含大量冗余字段的对象const query { queryId: test, state: RUNNING, // ... 50 more properties };4. 测试用户可见行为✅推荐断言用户看到的内容expect(screen.getByText(RUNNING)).toBeInTheDocument();❌不推荐断言组件内部实现细节expect(component.state.queries[0].state).toBe(RUNNING);5. 按需选择 sync / async 助手✅推荐不关心交互真实性的场景用同步助手提速clickButtonSync(/submit/i); setInputValue(/search/i, test); await advanceTimersAndWait(300);❌不推荐简单状态变更也滥用慢速异步助手await clickButton(/submit/i); // Slower, not needed for simple state changes await typeIntoInput(/search/i, test); // Much slower经验法则除非在专门验证用户交互行为否则优先使用同步助手clickButtonSync、setInputValue。6. 使用描述性测试命名✅推荐清楚表达意图it(displays error message when API call fails, () { // test });❌不推荐含义模糊it(works, () { // test });实战对比使用助手前 vs 使用助手后以按状态过滤查询列表这一 Presto UI 核心交互为例对比重构前后的测试代码。改造前未使用助手it(filters queries by state, async () { const queries [createRunningQuery({ queryId: q1 }), createFinishedQuery({ queryId: q2 })]; jest.clearAllMocks(); setupAllBrowserMocks(); mockFetchByUrl({ /v1/query: queries }); render(QueryList /); const finishedButton screen.getByRole(button, { name: /FINISHED/i }); await userEvent.click(finishedButton); expect(screen.getByText(q2)).toBeInTheDocument(); expect(screen.queryByText(q1)).not.toBeInTheDocument(); });改造后使用助手describe(QueryList, () { setupCommonMocks(); it(filters queries by state, async () { setupQueryListTest([createRunningQuery({ queryId: q1 }), createFinishedQuery({ queryId: q2 })]); render(QueryList /); await clickButton(/FINISHED/i); expect(screen.getByText(q2)).toBeInTheDocument(); expect(screen.queryByText(q1)).not.toBeInTheDocument(); }); });改进效果代码量减少约 30%意图更清晰模式可复用维护成本显著降低。总结与深入阅读路径Presto UI 的测试体系遵循基础设施与用例分离的组织方式__tests__/utils提供通用断言与交互助手__tests__/mocks封装外部依赖模拟__tests__/fixtures提供带默认值的数据工厂setupTests.ts完成全局环境装配jest.config.js统一定义测试发现与转换规则。理解这套体系后为 Presto UI 新增组件测试只需三步setupCommonMocks()声明前置、createMockXxx()构造数据、render 助手函数完成交互与断言。感兴趣的读者可以继续深入以下仓库文件tests/utils/testUtils.tsx — 全部公共测试助手实现tests/utils/setupHelpers.ts — 通用与组件级 setup 模式tests/mocks/apiMocks.ts — Fetch API 拦截实现tests/mocks/jqueryMock.ts — jQuery 选择性 Mock 实现tests/mocks/browserMocks.ts — 浏览器 API Mock 实现tests/fixtures/queryFixtures.js — 查询数据工厂实现jest.config.js — Jest 完整配置setupTests.ts — 全局测试初始化与告警压制package.json — 测试相关依赖与脚本声明赞分享大数据数据库后端【免费下载链接】prestoThe official home of the Presto distributed SQL query engine for big data项目地址https://gitcode.com/gh_mirrors/pre/presto点击查看免费下载相关推荐Paint-board形状绘制详解从基础图形到复杂箭头的高级技巧Paint board形状绘制详解从基础图形到复杂箭头的高级技巧 Paint board是一款功能强大的多端绘图板应用集成了丰富的创意画笔为用户带来全新的前端Material UI 测试体系全指南从单元测试到端到端测试的全链路工程实践Material UI 测试体系全指南从单元测试到端到端测试的全链路工程实践 本指南基于 Material UI 官方仓库的 test/README.md h前端UI组件设计系统Snowpack与Jest集成前端测试完整配置指南Snowpack与Jest集成前端测试完整配置指南 你是否还在为前端项目配置测试环境而烦恼本文将带你一步到位解决Snowpack与Jest的集成难题从基础前端开发工具前端构建上一篇Audacity免费多轨音频编辑器十分钟修干净一条播客下一篇深蓝词库转换终极输入法词库兼容解决方案创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考