Hacktoberfest 2026: những issue maintainer đã đánh dấu cho tháng Mười, đang mở và phù hợp người mới. Xem issue Hacktoberfest

Plugin test kits: an every-plugin "test" slot + layered consumer regression — plugins own their test-data fabrication

Đang mở
#593 0 bình luận 0 reaction 0 người được giao Xem trên GitHub

Maintainer thường phản hồi trong vòng 1 ngày

Chưa có ai nhận issue này.

Đánh giá

Độ khó
5/5
Thời gian dự kiến
Hơn một tuần
Mức phù hợp với người mới
30/100
Loại issue
Tính năng
Độ rõ ràng
Đặc tả rõ ràng
Mức độ hoạt động
Sôi nổi
Công nghệ
typescript
Lĩnh vực
backend, testing-qa

Hướng nghiên cứu

Start with definePlugin and the auth plugin’s service and test files, then read the consumer regression runner described in #368. Trace how plugin procedures are registered and how runtime route ownership selects specs. Done means the gated auth factories use real services and the acceptance criteria are met, including a citynode end-to-end regression and derived spec selection.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Mô tả

Problem

Consumers with browser-regression suites have no way to fabricate a remote plugin's state except by re-implementing the plugin's internals: vendor-copying its schema + migrations, building a parallel Better Auth instance with a fraction of its plugin list, and hand-inserting rows that bypass its invariants. The drift is structural — citynode's fixtures still carry a new_member column and pre-rc.7 stats semantics and produce deterministic red specs (NEARBuilders/citynode.app#426), while its parallel instance is why an approve-test-organizations script must undo what the real plugin's approval flow does. Meanwhile, children re-testing plugin behavior deeply is the only net catching upstream regressions today — late, duplicated in every child.

Precedents

  • better-auth's testUtils() — a plugin exposing test endpoints when mounted. The auth plugin's kit will use it internally (behind this seam) to implement mintSession; this ask generalizes the pattern to every plugin with the host owning the gate.
  • Package-owned factories (Rails engine fixtures, Laravel HasFactory, WordPress factories) — the domain ships its fixtures; consumers never re-implement invariants.
  • Env-gated dev surfaces inert in production (devtools NoOp builds) — inert by registration, not authorization.
  • Derived test selection (Nx "affected") — spec applicability computed from an ownership graph, not hand-curated.

Proposal

One word at every layer of the seam — the slot, the RPC namespace, and the manifest key are the same word, so they cannot drift apart:

Layer Name
definePlugin slot test
Consumption apiClient.<plugin>.test.<factory>
Manifest "test": true
Env gate BOS_TEST_MODE=1
Harness adapter (host side) everything-dev/test-kit

Ownership split (mirrors how migrations already split): slot + gating + plumbing → every-plugin; factories → each plugin (ordinary plugin code, like db/migrate.ts adapters); harness/runner → everything-dev/test-kit.

The slot — factories return Effects, call the plugin's real services with a time seam, and are state-named (the name promises the aggregate state, not the transition — the previous drift was exactly a transition/state mismatch):

test: ({ services, db, config }) => ({
  mintSession: (i: { role?; organizationId? }) => Effect<Session, KitError>,
  approvedOrganization: (i: { name }) => Effect<Organization, KitError>,
  verifiedEmail: (userId) => Effect<void, KitError>,
  createOnboardingCode: (i: { organizationId; expiresAt: Date; maxUses?: number }) =>
    Effect<{ code; codeId }, KitError>,
  joinsThisMonth: (i: { organizationId; redeemed: number; newMembers: number }) =>
    Effect<Stats, KitError>,
})

Cookie mechanics stay behind the seam: the RPC adapter sets the session cookie on the response (as better-auth does); the in-process adapter returns the session handle. Consumers never learn what a cookie is — which also deletes the child's cookie-artifact pipeline rather than relocating it.

Seeded state is valid by construction — there is no parallel re-implementation to drift.

Gating: the host registers test/* plugin procedures only under BOS_TEST_MODE=1; they never enter the production router (registration-gated, devtools-style).

The layers

  • L0 — plugin tests (upstream): kit consumed in-process.
  • L1 — the framework browser suite gates the release train: upstream accidents die here, before publish.
  • L1.5 — consumer-regression.yml (#368): re-runs a runtime-map-derived selection of framework specs against a child's composition. Route ownership (from the manifest/composed route tree) decides applicability — a child that shadows /login replaces the framework's /login specs with its own. Derived, not curated, so the selection can't drift.
  • L2 — children shrink to: thin contract smoke, child behavior (their overrides), child flows (kit-fabricated data). The parallel instance, vendored fixtures, raw inserts, and cookie-artifact pipelines are deleted.

First implementation

The auth plugin ships the starter surface above. A consumer's spec becomes:

const { code } = await apiClient.auth.test.createOnboardingCode({ organizationId, expiresAt });

…and tests/regression/fixtures/auth/, auth-test-instance.ts, approve-test-organizations.ts, verify-test-emails.ts, and the migrate-runner mirror in citynode all become unnecessary.

Acceptance criteria

  • definePlugin accepts a test slot; procedures are registered only under BOS_TEST_MODE=1; a boot warning fires if the gate is set in a production-shaped environment.
  • The manifest advertises "test": true; bos can list a runtime's available test surfaces.
  • Auth plugin implements the starter surface with factories calling its real services.
  • A consumer (citynode) seeds auth state end-to-end via gated RPC with no vendored schema/migrations, no parallel instance, and no raw auth-DB inserts.
  • Session fabrication sets cookies on the response — no cookie-artifact interchange in the child.
  • consumer-regression (#368) derives its spec selection from route ownership.
  • Documented convention so each new plugin ships its test surface by default.

Cross-refs

#368 (consumer-regression runner), #531 (session wall — related non-gating cause), NEARBuilders/citynode.app#426 (motivating failure), #582/#583 (child UX asks this doesn't cover).

Ngôn ngữ chính
TypeScript
Star
5
Fork
3
Merge trung bình
9 giờ 35 phút
Pull request đã merge (30 ngày)
151

Chuẩn bị môi trường

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Issue khác của NEARBuilders/everything-dev

Tất cả issue của NEARBuilders/everything-dev

Issue tương tự

Thêm issue về TypeScript

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.