feat(config): testing subpath (createTestConfig, configTestingModule) - #9
Conversation
There was a problem hiding this comment.
Pull request overview
Adds a new ./testing subpath to the library so tests can build a fully validated, deep-frozen config (and a Nest DynamicModule) without reading process.env, by synthesizing a constraint-compliant placeholder source from a defineEnv schema and layering selective overrides.
Changes:
- Introduces a deterministic placeholder synthesizer that walks a two-level
defineEnvschema and emits a flat source record. - Adds
createTestConfig(schema, overrides?)andconfigTestingModule(schema, overrides?)as the public testing surface viasrc/testing/index.ts. - Updates dogfood smoke test expectations and marks Phase 5 docs/dashboards as complete.
Reviewed changes
Copilot reviewed 12 out of 12 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| src/testing/placeholder-synthesizer.ts | New deterministic placeholder source generator via Zod v4 internals. |
| src/testing/placeholder-synthesizer.spec.ts | Unit coverage for placeholder synthesis constraints + determinism. |
| src/testing/index.ts | Exposes the ./testing public API (two exports only). |
| src/testing/create-test-config.ts | Builds test config by synthesizing source + applying overrides + running prod validation/freeze. |
| src/testing/create-test-config.spec.ts | Unit tests for overrides, validation failure, and deep-freeze behavior. |
| src/testing/config-testing.module.ts | Wraps BymaxConfigModule.forRoot with synthesized/overridden test source. |
| src/testing/config-testing.module.spec.ts | Integration tests using Nest Test.createTestingModule. |
| scripts/dogfood-smoke-test.mjs | Asserts runtime export lists for . and ./testing subpaths. |
| docs/tasks/README.md | Updates phase dashboard progress for Phase 5. |
| docs/tasks/phase-05-testing-subpath.md | Marks Phase 5 tasks as done and appends completion log. |
| docs/development_plan.md | Updates overall progress and Phase 5 status to complete. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…nges, null-proto source (5.4)
…rom fractional bounds (5.4)
|
Automated review note: the Copilot code-review bot reviewed six prior revisions of this PR (all findings addressed and resolved) but did not submit a review of the final commit 9a90427 within the 15-minute review-bot timeout. Merging on the CI gate: Verify (typecheck, lint, test:cov 100%, build, size) and Socket Security are green, all review threads are resolved, and the final change is a focused, fully covered fix verified against the Zod validator. |
| const endpoint = required(source, 'API_ENDPOINT') | ||
| expect(endpoint.length).toBeGreaterThanOrEqual(40) | ||
| expect(z.url().safeParse(endpoint).success).toBe(true) | ||
| }) |
| return `${URL_PREFIX}${FILLER_CHARACTER.repeat(hostFill)}${URL_SUFFIX}` | ||
| } | ||
|
|
||
| /** |
| lengths.exact === undefined && | ||
| PLACEHOLDER_URL.length >= lengths.min && | ||
| PLACEHOLDER_URL.length <= lengths.max | ||
| ) { | ||
| return PLACEHOLDER_URL | ||
| } | ||
| return urlOfLength(lengths.exact ?? clampLength(PLACEHOLDER_URL.length, lengths.min, lengths.max)) | ||
| } | ||
|
|
||
| /** |
| return `${FILLER_CHARACTER.repeat(localFill)}${EMAIL_SUFFIX}` | ||
| } | ||
|
|
||
| /** |
| if ( | ||
| lengths.exact === undefined && | ||
| canonical.length >= lengths.min && | ||
| canonical.length <= lengths.max | ||
| ) { | ||
| return canonical | ||
| } | ||
| return emailOfLength(lengths.exact ?? clampLength(canonical.length, lengths.min, lengths.max)) | ||
| } | ||
|
|
||
| /** |
| // midpoint cannot land on an excluded edge (e.g. gt(0).max(1) -> [1, 1]). | ||
| const lo = bounds.lowerExclusive ? lower + 1 : lower | ||
| const hi = bounds.upperExclusive ? upper - 1 : upper | ||
| return Math.floor((lo + hi) / 2) | ||
| } | ||
| // Floats: the midpoint of any interval is strictly inside it, so it | ||
| // satisfies inclusive and exclusive bounds alike without stepping. | ||
| return (lower + upper) / 2 |
Summary
Delivers the
./testingsubpath so consumers never touchprocess.envin tests. It synthesizes a complete, constraint-compliant source from adefineEnvschema, applies selective overrides, and runs the exact production pipeline (validate then deep-freeze), plus a module-shaped counterpart for NestTestingModulegraphs.What changed
src/testing/placeholder-synthesizer.ts, internal): walks a two-level schema and emits a flat source record via Zod v4 introspection (_zod.def). Honors declared constraints (string min/max/exact lengths,url/emailformats, integer ranges, enum membership, booleans), omits defaulted and optional leaves so the schema decides their value, and unwraps nullable leaves. Fully deterministic (noMath.random, no clock); two runs are byte-for-byte identical. Placeholders are obvious filler ('a'repeats,https://placeholder.local,a@placeholder.local, first enum member) that never masks a broken schema.createTestConfig(schema, overrides?)(src/testing/create-test-config.ts): synthesizes the source, overlays selective nested partial overrides onto the targeted leaves through the shared source mapping, and delegates to the productionvalidateEnv+deepFreezepath. Returns the typed, deep-frozen config. A constraint-violating override still throws the productionBymaxConfigValidationError.configTestingModule(schema, overrides?)(src/testing/config-testing.module.ts): a thin wrapper that delegates toBymaxConfigModule.forRoot({ schema, source }), reusing the production registration path soBYMAX_CONFIGandConfigServiceare provided exactly as in production.src/testing/index.ts): exports exactlycreateTestConfigandconfigTestingModule; the synthesizer and source builder stay internal, and the root barrel does not re-export them. The subpath ships no test-runner dependency.scripts/dogfood-smoke-test.mjs):EXPECTED_EXPORTSfilled for both subpaths (.full public surface;./testing=createTestConfig,configTestingModule).dependenciesunchanged (dependencies: {});zod/@nestjs/*/reflect-metadatastay peers.Verification
All commands green on the branch:
pnpm typecheck(both tsconfigs)pnpm lint(zero warnings)pnpm buildemits.mjs/.cjs/.d.tsfor both.and./testingpnpm test:cov:all— 124 tests, 17 suites, 100% line/branch/function/statement on every file (both jest configs)pnpm build && node scripts/dogfood-smoke-test.mjs— both subpaths resolve in ESM and CJS from the packed tarball with the declared exports; tarball contains onlydist/+ meta filesInvariant greps clean: no
process.envreads in the testing subpath, no suppression comments, no@Global(), nodotenv/cryptoimports, no phase/task references in source, no em dashes, no.gitkeep.Reviews run to zero findings:
/bymax-quality:code-review(consolidated Zod introspection to a single documented_zod.defboundary; overrides applied via aMapto avoid an object-injection sink) and/security-review(no HIGH/MEDIUM findings; deterministic filler, no secrets, no I/O).P5 Definition of Done
createTestConfigoutput passes the production validator and arrives frozen — covered.configTestingModulecompiles in aTestingModuleand providesConfigService— covered../testingin both ESM and CJS — green.Follow-ups
None for this phase. End-to-end suite, README testing guide, and size-budget recalibration are P6.