Skip to content

feat(config): testing subpath (createTestConfig, configTestingModule) - #9

Merged
msalvatti merged 11 commits into
mainfrom
feat/phase-05-testing-subpath
Jul 16, 2026
Merged

feat(config): testing subpath (createTestConfig, configTestingModule)#9
msalvatti merged 11 commits into
mainfrom
feat/phase-05-testing-subpath

Conversation

@msalvatti

Copy link
Copy Markdown
Member

Summary

Delivers the ./testing subpath so consumers never touch process.env in tests. It synthesizes a complete, constraint-compliant source from a defineEnv schema, applies selective overrides, and runs the exact production pipeline (validate then deep-freeze), plus a module-shaped counterpart for Nest TestingModule graphs.

What changed

  • Placeholder synthesizer (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/email formats, integer ranges, enum membership, booleans), omits defaulted and optional leaves so the schema decides their value, and unwraps nullable leaves. Fully deterministic (no Math.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 production validateEnv + deepFreeze path. Returns the typed, deep-frozen config. A constraint-violating override still throws the production BymaxConfigValidationError.
  • configTestingModule(schema, overrides?) (src/testing/config-testing.module.ts): a thin wrapper that delegates to BymaxConfigModule.forRoot({ schema, source }), reusing the production registration path so BYMAX_CONFIG and ConfigService are provided exactly as in production.
  • Testing barrel (src/testing/index.ts): exports exactly createTestConfig and configTestingModule; the synthesizer and source builder stay internal, and the root barrel does not re-export them. The subpath ships no test-runner dependency.
  • Dogfood (scripts/dogfood-smoke-test.mjs): EXPECTED_EXPORTS filled for both subpaths (. full public surface; ./testing = createTestConfig, configTestingModule).
  • Zero runtime dependencies unchanged (dependencies: {}); zod/@nestjs/*/reflect-metadata stay peers.

Verification

All commands green on the branch:

  • pnpm typecheck (both tsconfigs)
  • pnpm lint (zero warnings)
  • pnpm build emits .mjs/.cjs/.d.ts for both . and ./testing
  • pnpm 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 only dist/ + meta files

Invariant greps clean: no process.env reads in the testing subpath, no suppression comments, no @Global(), no dotenv/crypto imports, 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.def boundary; overrides applied via a Map to avoid an object-injection sink) and /security-review (no HIGH/MEDIUM findings; deterministic filler, no secrets, no I/O).

P5 Definition of Done

  • createTestConfig output passes the production validator and arrives frozen — covered.
  • Overrides merge selectively without weakening constraint enforcement — covered.
  • configTestingModule compiles in a TestingModule and provides ConfigService — covered.
  • The dogfood smoke test resolves ./testing in both ESM and CJS — green.
  • Coverage stands at 100% for every file added — confirmed.

Follow-ups

None for this phase. End-to-end suite, README testing guide, and size-budget recalibration are P6.

Copilot AI review requested due to automatic review settings July 16, 2026 17:29

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 defineEnv schema and emits a flat source record.
  • Adds createTestConfig(schema, overrides?) and configTestingModule(schema, overrides?) as the public testing surface via src/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.

Comment thread src/testing/placeholder-synthesizer.ts Outdated
Comment thread src/testing/placeholder-synthesizer.ts Outdated
Comment thread src/testing/placeholder-synthesizer.ts
Copilot AI review requested due to automatic review settings July 16, 2026 17:34

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 12 out of 12 changed files in this pull request and generated 2 comments.

Comment thread src/testing/placeholder-synthesizer.ts Outdated
Comment thread src/testing/create-test-config.ts Outdated
Copilot AI review requested due to automatic review settings July 16, 2026 17:43

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 12 out of 12 changed files in this pull request and generated 1 comment.

Comment thread src/testing/placeholder-synthesizer.ts
Copilot AI review requested due to automatic review settings July 16, 2026 17:48

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 12 out of 12 changed files in this pull request and generated 2 comments.

Comment thread src/testing/placeholder-synthesizer.ts
Comment thread src/testing/placeholder-synthesizer.spec.ts
Copilot AI review requested due to automatic review settings July 16, 2026 17:55

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 12 out of 12 changed files in this pull request and generated 4 comments.

Comment thread src/testing/placeholder-synthesizer.ts
Comment thread src/testing/placeholder-synthesizer.ts
Comment thread src/testing/placeholder-synthesizer.ts
Comment thread src/testing/create-test-config.ts
Copilot AI review requested due to automatic review settings July 16, 2026 17:59
@msalvatti

Copy link
Copy Markdown
Member Author

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.

@msalvatti
msalvatti merged commit f4815ba into main Jul 16, 2026
4 checks passed
@msalvatti
msalvatti deleted the feat/phase-05-testing-subpath branch July 16, 2026 18:21
Copilot stopped reviewing on behalf of msalvatti due to an error July 16, 2026 18:25

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 12 out of 12 changed files in this pull request and generated 6 comments.

Comment on lines +233 to +236
const endpoint = required(source, 'API_ENDPOINT')
expect(endpoint.length).toBeGreaterThanOrEqual(40)
expect(z.url().safeParse(endpoint).success).toBe(true)
})
Comment thread src/testing/placeholder-synthesizer.ts Outdated
Comment on lines +153 to +156
return `${URL_PREFIX}${FILLER_CHARACTER.repeat(hostFill)}${URL_SUFFIX}`
}

/**
Comment on lines +179 to +188
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))
}

/**
Comment on lines +164 to +167
return `${FILLER_CHARACTER.repeat(localFill)}${EMAIL_SUFFIX}`
}

/**
Comment on lines +199 to +209
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))
}

/**
Comment thread src/testing/placeholder-synthesizer.ts Outdated
Comment on lines +253 to +260
// 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
Copilot AI review requested due to automatic review settings July 16, 2026 18:26

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 12 out of 12 changed files in this pull request and generated no new comments.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants