test(e2e): state the seed-visibility precondition instead of depending on it (#665) - #668
Merged
Merged
Conversation
…g on it (#665) `pnpm test:e2e` against a dev server that had been up for more than ten minutes failed 11 of 16 specs on "no seeded accounts returned" and "no seeded crm_account — the demo seed did not load". The seed had loaded. `global-setup.ts` signs UP `e2e-admin@hotcrm.test`, which lands as a plain org member owning nothing and holding no sharing grant; every seeded row starts out ownerless, which under `sharingModel: 'private'` is the only reason the suite could read it. Once `demo_bootstrap` (or `pnpm demo:staff`) claims those rows for the first user, the suite reads zero — and blamed the seed loader. Global setup now asserts the precondition. Two `?limit=1` reads separate the two states that both look like zero rows: `crm_account` is `private` and swept by `demo_bootstrap`, so it goes dark the moment the seeds are claimed; `crm_product` is `public_read` and in no sweep, so no ownership state can hide it. Products but no accounts means the seeds are there and claimed, and the run aborts with that sentence plus the remedy; neither means nothing was seeded, and says so. The guard cannot turn a passing run red: it returns on the first readable row without issuing the second probe, and waits out a seed that is still loading rather than calling it absent. Measured on both server modes — `objectstack start` (CI's webServer) seeds no dev admin, so the e2e account is the org's first user and the sweep claims the seeds FOR it; `objectstack dev` seeds admin@objectos.ai and the sweep claims them away. What the suite proves is unchanged: no sharing grant, no permission set, no switch to the seeded dev admin. `test/e2e-seed-precondition.test.ts` pins the guard's metadata premises against the real objects and flow, so adding `crm_product` to `CLAIMED_OBJECTS` fails rather than silently degrading the diagnosis back to the misleading one.
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
Contributor
Author
|
补一条本地实测,补齐 PR 正文里「守卫不会把 CI 变红」的最后一格——在 CI 那条路径上, 同一台 原因就是正文第 3 点的机制,这里是它的直接读数(以套件账号
对照组是 Generated by Claude Code Generated by Claude Code |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #665
按 PM 裁定实现方案 3:把 e2e 套件一直隐式依赖、却从未声明的前置条件——「种子记录此刻对套件登录的账号可见」——在
e2e/global-setup.ts里显式断言。不满足时整轮 run 以一条说明真实成因和可执行补救的错误中止,而不是让 11 个 spec 带着no seeded accounts returned/the demo seed did not load级联失败(那句话描述的是一个加载得好好的种子)。套件证明的东西没有任何变化:不加共享授权、不加权限集、不改用 seeded dev admin。方案 1 / 2 明确不在本 PR 范围,方案 2 已单独立案(见文末)。
两个探针,而不是一个
只读一次
crm_account无法区分「种子被别人认领了」和「种子根本没播种」——两者都返回 0 行,而补救方式相反。所以多花一个请求,读一个可见性与 ownership 无关的对象:demo_bootstrap扫描crm_accountprivatecrm_productpublic_read两者都在
CrmSeedData里。于是「有 product、没有 account」只能是种子在、但属于别人;「两者都没有」只能是根本没播种。这两条前提不是注释,test/e2e-seed-precondition.test.ts直接对元数据断言:把crm_product加进demo_bootstrap的CLAIMED_OBJECTS,或改掉任一sharingModel,测试就红——否则守卫会悄悄退化成把「被认领」误报成「没播种」,正是 #665 要消灭的那种误诊。为什么这条守卫不可能把 CI 变红
三层保证,前两层是结构性的:
smoke.spec.ts的records.length > 0,就意味着这个探针在 CI 上恒 > 0。waitForQuiet用 health 延迟推断「播种风暴过去了」,那是代理指标不是事实。守卫最多轮询 30s,行一出现立即返回。webServer跑objectstack start,它不播种 dev admin:套件注册的账号就是组织里的第一个用户(sys_user恰好 1 行),demo_bootstrap于是把种子认领给它自己——冷库上实测每条crm_account的owner_id都等于该账号 id。CI 一直绿是因为这个,不是因为运气。而pnpm dev播种admin@objectos.ai,第一个用户变成那个 admin,下一个整十分钟边界一到,种子就被从套件手里认领走。验证(全部在本机对真实 booted server 跑出来,不是推理)
A.
objectstack dev+ 已被认领的种子 → 守卫按预期响亮失败(即 #665 的复现态)。用真实的e2e/global-setup.ts(sign-up/sign-in + 守卫)打一台pnpm demo:reset后启动的 dev server:以 dev admin 身份核对成因:9 条
crm_account的owner_id全是 dev admin 的 id(server 于 :49 启动,:50 的 sweep 已认领完毕)。B.
objectstack start冷库(CI 路径)→ 守卫不触发:同一台 server 上以套件账号读:
sys_user只有 1 行(e2e-admin@hotcrm.test),sweep 跑过之后crm_account.owner_id全部等于该账号 id——即 CI 上 sweep 前后都可读。C. 真正的
playwright test走一遍(复用同一台 server,含真实 global setup + 守卫):容器里没有 chromium,
page驱动的那几个 spec 只能交给 CI 跑;它们不读种子行,与本改动无关。D. 单元与静态检查:
新测试用结构化的请求上下文接口对着 stub 跑,所以「绝不能在 CI 触发的那条分支」有测试覆盖,却不需要浏览器、server 或数据库。
仍会被跑到的两处措辞
守卫只在 global setup 跑一次,而
demo_bootstrap每十分钟一次,所以 sweep 可能在一轮 run 中途认领种子——e2e/smoke.spec.ts和seededAccountId()因此仍可达。这两处现在带上同一句成因(SEEDS_UNREADABLE_MID_RUN),而不再指控种子加载器。后续
方案 2(给 e2e 账号显式授权,或让 spec 自持数据,从而彻底摆脱对种子 ownership 的依赖)已作为未指派的独立 issue 立案,引用 #665 与本 PR。
Generated by Claude Code