Grist 部署测试(Deployment Tests)实战指南:面向 Docker 容器与外部服务器的端到端浏览器测试体系 📅 发布时间:2026/9/15 19:05:34 👁 浏览次数: Grist 部署测试Deployment Tests实战指南面向 Docker 容器与外部服务器的端到端浏览器测试体系【免费下载链接】grist-coreGrist is the evolution of spreadsheets.项目地址: https://gitcode.com/GitHub_Trending/gr/grist-core本文以 test/deployment/README.md 为核心线索系统讲解 Gristgrist-core中一类特殊的测试形态——部署测试Deployment Tests它们与依赖内存 TestServer 的常规浏览器测试不同必须运行在真实部署的服务如 Docker 容器或外部服务器之上。读完本文你将掌握test/deployment/目录的组织方式、test_under_docker.sh的完整启动流程与全部环境变量语义、9 个部署测试用例各自覆盖的功能点以及如何在自己的部署环境中复跑这套测试来验证配置正确性。什么是 Grist 的部署测试Grist 的测试体系非常庞大test/nbrowser/下有大量通过mocha-webdriver驱动的浏览器端到端测试但它们默认依赖仓库内置的内存版 TestServerin-memory TestServer。这种测试启动快、隔离性好却有一个天然盲区——它无法验证真实部署场景下的配置问题例如容器环境变量是否生效、会话 Cookie 是否配置正确、模板组织template org是否就绪。test/deployment/README.md用两句话给出了这一类测试的明确定位Link or import here all tests that can be run against an external server or a docker container (i.e: tests that dont rely on in-memory TestServer).翻译过来即在test/deployment/中链接或导入所有可针对外部服务器或 Docker 容器运行的测试——也就是所有不依赖内存 TestServer 的测试。这就是部署测试的定义它们是跑在真实服务上的浏览器测试用于捕获任何由部署形态引入的问题。目录组织薄封装层 真实测试实现test/deployment/目录下的 9 个.ts文件全部是**单行 re-export转导入**结构真正的测试逻辑位于test/nbrowser/下。这种薄封装设计使得同一份测试实现既能跑在内存服务器上直接跑 nbrowser又能跑在真实部署上经 deployment 层导入避免了两套重复代码deployment 文件实际导入的测试实现覆盖的核心功能test/deployment/Smoke.tstest/nbrowser/Smoke.ts最小冒烟测试文档创建、编辑、重开test/deployment/HomeIntro.tstest/nbrowser/HomeIntro.ts首页欢迎页、示例与模板页匿名/登录态test/deployment/ActionLog.tstest/nbrowser/ActionLog.ts活动日志Activity Logtest/deployment/ChoiceList.tstest/nbrowser/ChoiceList.ts选项列表Choice List列test/deployment/DuplicateDocument.tstest/nbrowser/DuplicateDocument.ts文档复制test/deployment/Fork.tstest/nbrowser/Fork.ts文档 Fork分叉test/deployment/Pages.tstest/nbrowser/Pages.ts页面Pages管理test/deployment/ReferenceColumns.tstest/nbrowser/ReferenceColumns.ts引用列Reference Columntest/deployment/ReferenceList.tstest/nbrowser/ReferenceList.ts引用列表Reference List列以 test/deployment/Smoke.ts 为例整个文件只有一行import test/nbrowser/Smoke;而真正的冒烟逻辑在 test/nbrowser/Smoke.ts 中打开主页 → 等待.test-intro-create-doc出现 → 点击创建文档 → 等待文档加载 → 在 A1 单元格输入123在 B1 单元格通过直接按键输入321→ 刷新页面后断言 A1 仍显示123。这验证了创建 → 编辑 → 持久化重开的最小闭环。为什么需要独立运行isExternalServer()分支在 test/nbrowser/testUtils.ts 中导出的server对象上有一个贯穿全部测试的关键方法isExternalServer()。从源码结构看它用于判断当前测试是否跑在外部服务器上测试代码据此裁剪行为。例如test/nbrowser/HomeIntro.ts 中检查精选模板Featured Templates下方的 CRM/Other 分类小节时明确注释External servers may have additional templates beyond the 3 above, so stop here.外部服务器可能携带额外模板因此到此为止直接返回大量测试通过if (server.isExternalServer())跳过或调整对自定义 Widget、语言设置、本地化等功能的断言因为外部部署的环境变量组合不可控。同时在 test/nbrowser/testUtils.ts 附近测试环境是否注入示例数据也取决于该判断if (process.env.TEST_ADD_SAMPLES || !server.isExternalServer())。这解释了为什么部署测试脚本中要显式设置TEST_ADD_SAMPLES1——外部服务器默认不会自动注入示例文档必须由运行脚本主动开启否则像 HomeIntro 这类依赖示例数据如 Lightweight CRM 模板的用例会直接失败。核心运行入口test/test_under_docker.sh全流程拆解部署测试的标准运行方式是 Docker 形态入口脚本为 test/test_under_docker.sh在 package.json 中注册为npm run test:docker。脚本注释点明了它的动机This runs browser tests with the server started using docker, to catch any configuration problems.——用 Docker 启动服务器再跑浏览器测试专门捕捉配置问题。整个脚本分为四个阶段阶段一健壮性与清理脚本开头启用了pipefail、nounset、errtrace、errexit四组 bash 严格模式并注册了EXIT/INT/TERM陷阱。cleanup()会执行docker rm -f grist-core-test强制删除测试容器并等待 Docker 进程结束确保测试中断后不留残留容器。阶段二日志级别控制GRIST_LOG_LEVELerror if [[ ${DEBUG:-} 1 ]]; then GRIST_LOG_LEVEL GRIST_LOG_HTTPtrue GRIST_LOG_HTTP_BODYtrue fi默认只输出 error 级别日志设置DEBUG1时则输出全量日志、HTTP 请求日志和 HTTP Body 日志用于排查服务器端问题。阶段三启动 Docker 容器docker run --name $DOCKER_CONTAINER --rm \ --env VERBOSE${DEBUG:-} \ -p $PORT:$PORT --env PORT$PORT \ --env GRIST_SESSION_COOKIEgrist_test_cookie \ --env GRIST_TEST_LOGIN1 \ --env GRIST_LOG_LEVEL$GRIST_LOG_LEVEL \ --env GRIST_LOG_HTTP${GRIST_LOG_HTTP:-false} \ --env GRIST_LOG_HTTP_BODY${GRIST_LOG_HTTP_BODY:-false} \ --env TEST_SUPPORT_API_KEYapi_key_for_support \ --env GRIST_TEMPLATE_ORGtemplates \ --env GRIST_IN_SERVICE1 \ ${TEST_DOCKER_OPTIONS:-} \ ${TEST_IMAGE:-gristlabs/grist} 各环境变量的作用如下环境变量默认值作用VERBOSE0DEBUG 为空时传给测试端控制详细输出PORT8585服务器监听端口同时映射到宿主机GRIST_SESSION_COOKIEgrist_test_cookie固定会话 Cookie 名保证测试登录状态可预测GRIST_TEST_LOGIN1启用测试登录机制跳过真实认证直接以测试用户身份登录GRIST_LOG_LEVELerror服务端日志级别DEBUG1时清空以输出全部日志GRIST_LOG_HTTPfalse是否记录 HTTP 请求日志GRIST_LOG_HTTP_BODYfalse是否记录 HTTP 请求体日志TEST_SUPPORT_API_KEYapi_key_for_support支持接口 API Key供测试调用管理类 APIGRIST_TEMPLATE_ORGtemplates模板组织名示例/模板文档所在组织GRIST_IN_SERVICE1以在服务中模式运行TEST_DOCKER_OPTIONS空透传的额外docker run参数可覆盖网络、挂载卷等TEST_IMAGEgristlabs/grist要启动的 Docker 镜像名默认官方镜像其中TEST_IMAGE支持覆盖意味着你可以用本地构建的镜像替换官方镜像来验证自定义部署产物。阶段四健康检查 Mocha 测试while true; do if curl -fs http://localhost:$PORT/status | grep -q alive; then break; fi sleep 1 done健康检查是一个值得注意的细节脚本注释指出RestartShell opens the port before the server is ready, answering /status with a 503 starting error until then, so insist on a 200 response that says alive.——Grist 的 RestartShell 机制会在服务器真正就绪前就打开端口此时/status返回 503 starting因此必须持续轮询直到返回 200 且响应体包含alive才认为服务可用。随后脚本定位 mocha优先使用 PATH 中的mocha否则回退到./node_modules/.bin/mocha并以如下环境启动测试TEST_ADD_SAMPLES1 TEST_ACCOUNT_PASSWORDnot-needed \ HOME_URLhttp://localhost:8585 \ GRIST_TEST_LOGIN1 \ GRIST_TEST_FORCE_LIGHT_MODE1 \ NODE_PATH_build:_build/ext:_build/stubs:ext/node_modules \ $MOCHA _build/test/deployment/*.js --slow 6000 -g ${GREP_TESTS:-} $TEST_ADD_SAMPLES1向服务器注入示例文档HomeIntro 等用例的前置条件HOME_URLhttp://localhost:8585指定被测服务器的首页地址GRIST_TEST_FORCE_LIGHT_MODE1强制浅色主题保证截图与元素断言稳定对应 test/nbrowser/testUtils.ts 中的--force-dark-modefalse参数注入TEST_ACCOUNT_PASSWORDnot-needed配合GRIST_TEST_LOGIN1使用测试登录无需真实密码NODE_PATH指定编译产物与扩展模块的解析路径--slow 6000超过 6 秒的用例标记为慢测试不失败仅提示-g ${GREP_TESTS:-}支持按名称过滤用例GREP_TESTS与 npm 脚本体系的-g约定保持一致$透传额外 mocha 参数如--grep外的其他选项。部署测试的用例细节Smoke最小冒烟测试test/nbrowser/Smoke.ts 是 grist-core 中最精简的浏览器测试文件头注释说明了背景Grist has a very extensive test set that has not yet been ported to the grist-core.——Grist 官方有大量测试尚未移植到社区版因此 Smoke 只保证文档可创建、可编辑、可重开这一底线。它验证了两条输入路径通过enterCell输入123以及直接按键输入321后刷新仍保留数据。HomeIntro首页与模板体系的完整回归test/nbrowser/HomeIntro.ts 是部署测试中最复杂的用例之一覆盖匿名用户 vs 登录用户 vs 团队站点三种场景下的欢迎语匿名用户看到 Welcome to Grist!登录用户看到带名字的欢迎语团队站点用户看到带组织名的欢迎语SEO meta 标签断言robots为noindex、twitter:title/og:title为 Grist, the evolution of spreadsheets、twitter:image/og:image指向opengraph-preview-image.png首页引导卡片intro cards的存在性与仅显示文档偏好切换Examples Templates 页面点击.test-intro-templates后 URL 应匹配/p/templates验证 Lightweight CRM 模板存在、缩略图能正常加载通过naturalWidth 0判断、点击模板能打开文档且数据正确模板复制将示例复制为完整副本数据保留和模板副本数据清空两种形态空工作区无文档时显示.test-dm-no-docs-message创建文档后消失删除后又恢复。它通过withEnvironmentSnapshot设置了GRIST_UI_FEATUREStemplates,tutorials、GRIST_TEMPLATE_ORGtemplates、GRIST_ONBOARDING_TUTORIAL_DOC_IDgrist-basics三个环境变量这也从测试侧印证了生产部署需要哪些环境变量来开启模板与教程功能。两种运行模式Docker 部署 vs 外部服务器虽然test_under_docker.sh是仓库提供的一键式入口但test/deployment/的定位README 原话同时覆盖external server和docker container两种目标Docker 模式运行npm run test:docker脚本负责拉取镜像、注入环境变量、健康检查、清理容器测试端通过HOME_URL指向容器暴露的端口外部服务器模式如果你已经有部署好的 Grist 实例只需把HOME_URL指向该实例、复用test_under_docker.sh后半段的环境变量与 mocha 命令即可配合MOCHA_WEBDRIVER_HEADLESS1无头运行。此时server.isExternalServer()返回真部分依赖模板数量、示例数据固定形态的断言会自动收敛避免外部部署因额外模板或定制内容导致误报。无论哪种模式测试都通过mocha-webdriver驱动真实浏览器Chrome/Firefox执行断言属于完整的端到端E2E测试而非单元或集成测试。与常规测试体系的衔接常规内存服务器浏览器测试npm run test:nbrowserpackage.json即_build/test/nbrowser/**/*.js部署测试npm run test:dockerpackage.json即_build/test/deployment/*.js公共环境变量由 test/test_env.sh 提供GRIST_IN_SERVICEtrue、GRIST_SESSION_COOKIEgrist_test_cookie、TEST_CLEAN_DATABASEtrue、TEST_SUPPORT_API_KEYapi_key_for_support等test_under_docker.sh通过source $(dirname $0)/test_env.sh引入这些默认值。从整体测试金字塔看test/common/、test/server/、test/gen-server/负责单元与集成层test/nbrowser/负责浏览器 E2E内存服务器而test/deployment/是最接近生产的一层——它用真实的 Docker 镜像、真实的配置环境变量、真实的登录流程跑完关键用户路径是发布前验证部署正确性的最后一道关卡。结语Grist 的部署测试体系用一个极简的目录约定test/deployment/薄封装 test/nbrowser/共享实现解决了同一套浏览器测试如何在真实部署上复跑的问题配合test_under_docker.sh脚本将容器启动、环境变量注入、健康检查、用例过滤、清理回收串成一条自动化流水线。无论你是想为自建 Grist 实例做发布前验证还是想理解 grist-core 测试架构的分层设计都可以从npm run test:docker出发以 test/test_under_docker.sh 为入口、以 test/deployment/README.md 为地图逐步深入到 test/nbrowser/ 中的每一个用例实现。【免费下载链接】grist-coreGrist is the evolution of spreadsheets.项目地址: https://gitcode.com/GitHub_Trending/gr/grist-core创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考