Repository navigation
test(ui): live e2e signs in a read-not-write member and asserts the Console refuses coherently (#27552) - #27768
Merged
Conversation
…onsole refuses coherently (#27552) The live suite signed in only as the seeded admin, who passes every access check, so the Console⇄server access class (#27138 and siblings) was invisible to it. `ui/e2e/live/member.ts` gives the harness a second identity: the admin creates a member holding one of the showcase's own permission sets through `POST /auth/admin/create-user` (self sign-up is closed on the dev server), and the member's storageState is handed to the spec. The new spec, as a `showcase_manager` member on an admin-owned inquiry, asserts the server's read/refuse premise, the read-only edit form with its notice and no submit, no Edit and no inline pencils on the record page, and no write sent; then the admin control edits the same record and the save persists. It runs in `test:e2e:live:nightly` until the promotion rule admits it to the CI lane. Claude-Session: https://claude.ai/code/session_01Utp6CbDmdfNUqBtfbQtu5T Co-authored-by: Claude <noreply@anthropic.com>
…-l13hln Claude-Session: https://claude.ai/code/session_01Utp6CbDmdfNUqBtfbQtu5T Co-authored-by: Claude <noreply@anthropic.com>
Contributor
Author
|
domain:ui#3 · os-bill · session_01Utp6CaJoinvGQSbHeDaWBe 席位核对ACCEPT · head
Generated by Claude Code |
github-merge-queue
Bot
removed this pull request from the merge queue due to a conflict with the base branch
Oct 29, 2026
…-l13hln Resolves the ui/package.json conflict with #27770: its live:ci and nightly lines kept, plus read-only-member-record.spec.ts in the nightly list. Claude-Session: https://claude.ai/code/session_01Utp6CbDmdfNUqBtfbQtu5T Co-authored-by: Claude <noreply@anthropic.com>
Contributor
Author
|
domain:ui#3 · os-bill · session_01Utp6CaJoinvGQSbHeDaWBe 席位核对 · deltaACCEPT · head
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.
Requested by Bill · project thread
维护者速读
when) still disables the field on every row — the detail page does not ask the record projection the edit dialog now asks #27146、Record form field-access scope: the record projection is asked once and not again when the form re-reads the record, so a field a save just locked is drawn enabled until remount #27147)是 Console 和服务端之间最常见的合并后才发现的问题,管理员什么都能过,所以原来的实时测试看不到这一类。ui/e2e/live/read-only-member-record.spec.ts(三步断言)、ui/e2e/live/member.ts(管理员建成员并登录)、ui/package.json的test:e2e:live:nightly一行。ui/跑pnpm exec playwright test --config=playwright.live.config.ts read-only-member-record.spec.ts,预期 1 passed(本地约 38 秒)。Fixes #27552
Clause-②: no
Metadata-protocol: none
What changes
ui/e2e/live/member.ts).signInMember(adminRequest, permissionSet)has the admin create a member holding one of the showcase's own permission sets throughPOST /api/v1/auth/admin/create-user(password,mustChangePassword: false,permissionSet), signs it in, and returns a storageState with the same two halvesglobal-setup.tswrites for the admin (the API-origin cookie and the APP-originauth-session-token). One member per set at a fixed address, so a re-run against a long-lived backend reuses it (USER_ALREADY_EXISTS_USE_ANOTHER_EMAILis accepted). The state is returned, not written to disk, so no path needs rooting.ui/e2e/live/read-only-member-record.spec.ts). The member holdsshowcase_manager: onshowcase_inquiry(OWDprivate) it reads org-wide and writes only its own rows. The admin creates an inquiry, so the member may read it and may not write it: a row verdict, the shape Record edit dialog: on a row the caller may read but not write (sharing / RLS / ownership), the fields are offered as editable and the save is refused whole — the dialog never asks whether the row is writable #27138 had. In order:PERMISSION_DENIED;?form=IDopens the edit dialog withclosed-affordance-noticevisible,name/email/company/messagedisabled and no submit button inmodal-form-footer; the record page under it has no Edit button and no inline-edit pencils; the member's browser sent no non-GET request to the object;ui/package.json): the spec joinstest:e2e:live:nightly. Per the card's promotion rule it moves totest:e2e:live:cionly after 3/3 consecutive green on the live pair plus 5/5 of the enlarged allowlist, inside [devx] Live E2E UI skips every server-only PR: widen its gate to the server packages the Console runs against, and pin the spec-time budget #27550's 2-minute budget.Tests
Live stack in this container: this tree's built CLI serving
examples/app-showcasethroughui/e2e/live/ci/start-backend.sh(objectstack dev --seed-admin --fresh, port 4127), the Console fromui/apps/consoleon vite (port 5327) proxying to it.Spec runs: green 3/3 consecutive, about 38 s each on the vite dev server
Runs 2 and 3 took the member-already-exists path.
The spec can fail: the row write verdict removed, the spec goes red
Mutation through
scripts/ablation-replace.mjsonui/packages/permissions/src/RecordFieldAccessScope.tsx(vite serves source, so no build was needed): the anchoranswer?.writable === false ? 'record-not-writable'replaced so the projection'swritable: falseis ignored, which is the #27138 shape (the dialog offers editable fields on a row the server will refuse).What was measured before writing the spec
POST /api/v1/auth/sign-up/emailon the dev server answers 403SELF_REGISTRATION_CLOSED(audience postureinvite_only), so a sign-up step in the global setup cannot make the member; the admin's create-user door can.showcase_managermember: GET of an admin-owned inquiry 200, PATCH 403PERMISSION_DENIED("You do not have access to this record…"); PATCH of a project 403 (object-level, from theeveryonebaseline's read-only grant).More actionsandTimelineonly (no Edit), the⋯menu holds Refresh / Add to favorites / Share (no Delete), no inline-edit pencils;?form=IDdraws the dialog read-only with "You don't have permission to edit this record. The fields are read-only." and Cancel / Close only. As the admin: Edit, six pencils, Delete in the menu, the dialog editable with Update.pnpm --dir ui run type-check:e2eexit 0;tsc --listFilesincludes both new files.pnpm --dir ui exec vitest run scripts/__tests__/live-e2e-storage-state-roots-9519.test.ts scripts/__tests__/check-test-path-roots.test.ts scripts/__tests__/e2e-type-check.test.ts: 3 files, 43 tests passed.pnpm --dir ui exec eslint e2e/live/member.ts e2e/live/read-only-member-record.spec.tsexit 0;node ui/scripts/check-test-path-roots.mjsOK.Derived gates on head 3937f50: 31 derived, 31 run, all exit 0, plus check-sdui-manifest exit 0
node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --ran FILE: 31 derived, 31 run, 0 NOT-MEASURED, 0 UNRUN.Acceptance notes
examples/app-showcase, or a sign-up step inglobal-setup.tswith a second storageState. Sign-up is closed on the dev server (measured above), and a seed change is not needed: the admin create-user door with the showcase's existingshowcase_managerset gives the member and the read-not-write row. So neitherglobal-setup.tsnor the showcase changed. The member is made by the one spec that needs it rather than by the global setup, so the requiredLive E2E UIlane, which shares the global setup, pays nothing for it while the spec is nightly-only. It also keeps this PR offglobal-setup.ts, which sibling [ui] Live E2E UI master-detail.spec asserts only that the batch request was SENT, never that the server stored it: assert the persisted parent and child #27551 may touch. When the spec is promoted, movingsignInMemberinto the global setup is a one-call change if a second spec wants the identity.ui/e2e/live/member.tsis a new file beside the spec, under the claimedui/e2e/live/surface; it is the "second identity" half of the card's Task 1 kept reusable for the next access scenario (Record detail page inline edit: a row-conditioned field lock (when) still disables the field on every row — the detail page does not ask the record projection the edit dialog now asks #27146 / Record form field-access scope: the record projection is asked once and not again when the form re-reads the record, so a field a save just locked is drawn enabled until remount #27147 shapes).showcase_project) was measured and left out of the spec; the existing unit suites already pin the object-level form lock (objectui#11000).vite previewbuild.ui/package.jsonis the private workspace root), so no changeset.Generated by Claude Code