Documentation
¶
Overview ¶
Package jstestprovider is an experimental IPR-08 provider slice: one JS/TS unit adapter (Vitest) and one E2E adapter (Playwright) that each produce a receipt binding test/config/app-build/environment identity to per-test execution outcomes, then feed those facts through internal/testvalidity.Project (see ../testvalidity/projection.go). This package carries no qualification authority: a receipt states what was observed, never a "valid" verdict.
Index ¶
- Constants
- func EncodeQualified(r Receipt) ([]byte, error)
- func ParsePlaywrightJSON(data []byte) ([]TestOutcome, *InfrastructureFailure, error)
- func ParseVitestJSON(data []byte) ([]TestOutcome, *InfrastructureFailure, error)
- func QualifiedApplicationRevision(r Receipt, t TestOutcome) (string, bool)
- func QualifiedReceiptBindingReady(r Receipt, t TestOutcome) bool
- func ReceiptRunProjection(r Receipt) testvalidity.Projection
- func ReceiptTestProjection(r Receipt, t TestOutcome) testvalidity.Projection
- func ToTestProjection(outcome TestOutcome) testvalidity.Projection
- type Anchor
- type AppBuildIdentity
- type ApplicationArtifactIdentity
- type ApplicationAttestation
- type ApplicationAttestationExpectation
- type ApplicationAttestationObservation
- type ApplicationAttestationProvider
- type ApplicationAttestationProviderIdentity
- type ApplicationAttestationReceipt
- type ApplicationHealth
- type ApplicationInstanceIdentity
- type ApplicationRepositoryExpectation
- type ApplicationRepositoryIdentity
- type Attempt
- type BrowserStep
- type Config
- type E2EConfig
- type ExecutionSchedule
- type ExecutionStart
- type ExecutionState
- type ExternalLifecycle
- type FailureArtifact
- type Identity
- type InfrastructureFailure
- type ProjectIdentity
- type Receipt
- type SensitiveInputFinding
- type SensitiveInputPolicy
- type SensitiveInputValidationError
- type TestOutcome
- type UnitConfig
Constants ¶
const ( AttestedExternalProfile = "corvint-playwright-external/1" ApplicationAttestationProfile = "corvint-application-attestation/0" ApplicationAttestationProviderProfile = "corvint-application-attestation-command/0" )
const ( SensitiveExternalProfile = "corvint-playwright-external/2" SensitiveInputRedactionMarker = "[REDACTED]" SensitiveInputUnredacted = "sensitive-input-unredacted" SensitiveInputDocumentInvalid = "sensitive-input-document-invalid" SensitiveInputActionSyntaxUnsupported = "sensitive-input-action-syntax-unsupported" SensitiveInputDepthExceeded = "sensitive-input-depth-exceeded" SensitiveInputStepBoundExceeded = "sensitive-input-step-bound-exceeded" SensitiveInputStringBoundExceeded = "sensitive-input-string-bound-exceeded" SensitiveInputFindingBoundExceeded = "sensitive-input-finding-bound-exceeded" )
const ExternalProfile = "corvint-playwright-external/0"
Variables ¶
This section is empty.
Functions ¶
func EncodeQualified ¶
EncodeQualified emits the frozen canonical envelope used by retention and the strict consumer. The projections are derived, never caller-supplied.
func ParsePlaywrightJSON ¶
func ParsePlaywrightJSON(data []byte) ([]TestOutcome, *InfrastructureFailure, error)
ParsePlaywrightJSON parses one Playwright `--reporter=json` output into TestOutcomes. A run that produced no suites at all (e.g. "No tests found", an unrecognized --project) is reported as a run-level InfrastructureFailure via the returned bool/failure, never as zero silently-passing tests.
func ParseVitestJSON ¶
func ParseVitestJSON(data []byte) ([]TestOutcome, *InfrastructureFailure, error)
ParseVitestJSON parses one Vitest `--reporter=json` output file into TestOutcomes. A file-level entry with status "failed" and no failed assertion (a collection error that prevented any test from running, or a file-level hook such as afterAll that threw after its tests passed) surfaces as one StateInfrastructure outcome rather than being silently dropped, per AGENTS.md invariant 2 (missing evidence must never collapse to certainty). A report with no outcome at all (Vitest found no test files) returns the run-level "no-suites-collected" failure, as ParsePlaywrightJSON does.
func QualifiedApplicationRevision ¶
func QualifiedApplicationRevision(r Receipt, t TestOutcome) (string, bool)
QualifiedApplicationRevision returns the application identity only after the complete external receipt and the selected outcome have been qualified.
func QualifiedReceiptBindingReady ¶
func QualifiedReceiptBindingReady(r Receipt, t TestOutcome) bool
QualifiedReceiptBindingReady verifies the qualified external lifecycle, identity and attempt structure independently of an observed infrastructure outcome. Classification remains the consumer's separate responsibility.
func ReceiptRunProjection ¶
func ReceiptRunProjection(r Receipt) testvalidity.Projection
ReceiptRunProjection projects the receipt's own run-level facts: a run-level InfrastructureFailure (bad command, no tests found, missing browser at collection time) and stale-app-build freshness. It is separate from per-test projections because a run-level infrastructure failure may exist with zero test outcomes, and staleness is a fact about the whole run's served build, not any one test.
func ReceiptTestProjection ¶
func ReceiptTestProjection(r Receipt, t TestOutcome) testvalidity.Projection
ReceiptTestProjection carries lifecycle and identity uncertainty into every qualified row, including retained/MCP readers that recompute projections.
func ToTestProjection ¶
func ToTestProjection(outcome TestOutcome) testvalidity.Projection
ToTestProjection projects one TestOutcome through the shared testvalidity.Project (internal/testvalidity/projection.go). Ordinary per-test states (passed/failed/skipped/flaky) carry ClaimFacts, since they are TCQ-shaped per-test report rows with a known association anchor. Harness-level incomplete states (timedOut/interrupted/infrastructure) that mean the test itself never produced a real report instead carry ExecutionFacts with an INCOMPLETE outcome, matching the LPCV/GLTP cause vocabulary Project already understands. No branch invents a "valid" verdict; every branch states exactly the fact this provider observed.
Types ¶
type Anchor ¶
Anchor is one file:line source anchor taken from a reporter's own location field (Playwright) or parsed from its failure stack trace (Vitest, which does not emit a structured location field as of 5.0.0 - see evidence/ipr-08-runner-selection.md section 4/5 and vitest_test.go).
type AppBuildIdentity ¶
type AppBuildIdentity struct {
Digest string `json:"digest"`
Unknown bool `json:"unknown"`
Reason string `json:"reason,omitempty"`
}
AppBuildIdentity is the served app's content identity: a digest of the configured build output directory, or "unknown" when no build directory was configured (Vitest unit runs, or an E2E run with no app dir bound).
func DigestAppBuildDir ¶
func DigestAppBuildDir(dir string) (AppBuildIdentity, error)
DigestAppBuildDir hashes every regular file under dir (relative path plus content), sorted for determinism, into one app-build identity digest. A missing or empty directory returns an explicit AppBuildIdentity rather than a digest of nothing, so "not built yet" is never mistaken for "built and empty." An entry that does not resolve to a regular file (a symlink to a directory, a dangling symlink) makes the identity unknown as well.
type ApplicationAttestation ¶
type ApplicationAttestation struct {
Profile string `json:"profile"`
Repository ApplicationRepositoryIdentity `json:"repository"`
Build ApplicationArtifactIdentity `json:"build"`
Configuration ApplicationArtifactIdentity `json:"configuration"`
Instance ApplicationInstanceIdentity `json:"instance"`
Health ApplicationHealth `json:"health"`
}
type ApplicationAttestationExpectation ¶
type ApplicationAttestationExpectation struct {
Repository ApplicationRepositoryExpectation `json:"repository"`
Build ApplicationArtifactIdentity `json:"build"`
Configuration ApplicationArtifactIdentity `json:"configuration"`
InstanceKind string `json:"instanceKind"`
}
type ApplicationAttestationObservation ¶
type ApplicationAttestationObservation struct {
OutputDigest string `json:"outputDigest"`
Attestation ApplicationAttestation `json:"attestation"`
}
type ApplicationAttestationProvider ¶
type ApplicationAttestationProvider struct {
Argv []string
ConfigFile string
Timeout time.Duration
}
ApplicationAttestationProvider is the typed, bounded local command used to observe an externally owned application. Corvint supplies the canonical configuration bytes on stdin and never supplies lifecycle verbs.
type ApplicationAttestationProviderIdentity ¶
type ApplicationAttestationProviderIdentity struct {
Profile string `json:"profile"`
Argv []string `json:"argv"`
ExecutablePath string `json:"executablePath"`
ExecutableDigest string `json:"executableDigest"`
ConfigPath string `json:"configPath"`
ConfigDigest string `json:"configDigest"`
Environment map[string]string `json:"environment"`
}
type ApplicationAttestationReceipt ¶
type ApplicationAttestationReceipt struct {
Provider ApplicationAttestationProviderIdentity `json:"provider"`
Expectation ApplicationAttestationExpectation `json:"expectation"`
Before *ApplicationAttestationObservation `json:"before,omitempty"`
After *ApplicationAttestationObservation `json:"after,omitempty"`
Failures []string `json:"failures"`
}
type ApplicationHealth ¶
type Attempt ¶
type Attempt struct {
State ExecutionState `json:"state"`
Retry int `json:"retry"`
FailureKind string `json:"failureKind"`
Steps []BrowserStep `json:"steps,omitempty"`
}
type BrowserStep ¶
type BrowserStep struct {
Title string `json:"title"`
Category string `json:"category,omitempty"`
Metadata map[string]string `json:"metadata,omitempty"`
Error string `json:"error,omitempty"`
Attachments []FailureArtifact `json:"attachments,omitempty"`
Steps []BrowserStep `json:"steps,omitempty"`
Redacted bool `json:"redacted,omitempty"`
}
BrowserStep is the bounded action trace retained by the redaction-capable external profile. Values entered by input actions never cross this boundary.
type Config ¶
type Config struct {
Dir string
TestFiles []string
ConfigFile string
PackageJSON string
Lockfile string
RunnerName string
RunnerVersion string
DeclaredEnvKeys []string
Timeout time.Duration
OutputLimit int
}
Config is the shared subset of binding inputs both adapters need: the files whose identity must be pinned before evidence emits (AGENTS.md invariant 1), the tool's own argv, and the env keys a caller has declared worth observing (never the full process environment).
type E2EConfig ¶
type E2EConfig struct {
Config
ObserveDescendants bool
ExternalServer bool
AppIdentity string
ServerArgv []string
ServerReadyURL string
ServerReadyLimit time.Duration
AppBuildDir string // "" => unknown app build identity.
TestArgv []string
ApplicationAttestation *ApplicationAttestationProvider
SensitiveInputPolicy *SensitiveInputPolicy
}
E2EConfig configures one Playwright E2E run. Corvint starts and owns the app server itself under procgroup rather than relying on Playwright's `webServer` teardown, per the memo's named lifecycle risk ( evidence/ipr-08-runner-selection.md section 6, item 1) and the roadmap acceptance line requiring proven descendant cleanup.
type ExecutionSchedule ¶
type ExecutionSchedule struct {
Workers int `json:"workers"`
Starts []ExecutionStart `json:"starts"`
}
ExecutionSchedule records reporter-observed starts, not the requested order.
type ExecutionStart ¶
type ExecutionState ¶
type ExecutionState string
ExecutionState is the per-test outcome vocabulary this provider maps every reporter's own status field onto. It intentionally does not reuse testvalidity.Execution* verbatim: those are the shared LPCV/GLTP axis states, while this is the finer-grained JS/TS runner vocabulary the roadmap acceptance criteria name explicitly (flaky/retried, timedOut, interrupted, infrastructure) that a caller then folds into the shared axis via ToExecutionFacts.
const ( StatePassed ExecutionState = "passed" StateFailed ExecutionState = "failed" StateSkipped ExecutionState = "skipped" StateFlaky ExecutionState = "flaky" StateTimedOut ExecutionState = "timedOut" StateInterrupted ExecutionState = "interrupted" StateInfrastructure ExecutionState = "infrastructure" )
type ExternalLifecycle ¶
type ExternalLifecycle struct {
ReadyURL string `json:"readyUrl"`
DeclaredAppIdentity string `json:"declaredAppIdentity"`
Ownership string `json:"ownership"`
CleanupResponsibility string `json:"cleanupResponsibility"`
ServerDescendants string `json:"serverDescendants"`
ReadyAtStart bool `json:"readyAtStart"`
ReadyAtPublish bool `json:"readyAtPublish"`
RunnerDescendantsGone bool `json:"runnerDescendantsGone"`
InputsUnchanged bool `json:"inputsUnchanged"`
ConfigOverride string `json:"configOverride"`
}
type FailureArtifact ¶
FailureArtifact is a bounded pointer to a failure artifact (trace, screenshot, error-context) - the path the reporter recorded, never the artifact's own content, which stays wherever the runner wrote it.
type Identity ¶
type Identity struct {
ConfigInputDigests map[string]string `json:"configInputDigests,omitempty"`
TestFileDigests map[string]string `json:"testFileDigests"`
ConfigFile string `json:"configFile"`
ConfigDigest string `json:"configDigest"`
PackageDigest string `json:"packageDigest"`
NodeVersion string `json:"nodeVersion"`
RunnerName string `json:"runnerName"`
RunnerVersion string `json:"runnerVersion"`
// Environment holds only the declared keys a caller asked to bind, never
// the full process environment (AGENTS.md invariant 4 spirit: bounded,
// explicit inputs, not incidental host state).
Environment map[string]string `json:"environment"`
Argv []string `json:"argv"`
}
Identity is every binding fact a receipt commits to before evidence emits, per AGENTS.md invariant 1 and the roadmap acceptance line "bind test/configuration/application build and environment identities."
type InfrastructureFailure ¶
InfrastructureFailure records a run-level failure that never produced a per-test result: a bad command/config, a missing browser, a run the reporter itself reports as having found no tests. It is distinct from a per-test "failed" outcome (a real assertion or workflow failure) and from StateInfrastructure applied to an individual outcome whose message pattern still matches a known infrastructure cause (e.g. a missing browser executable surfacing inside an otherwise well-formed per-test result).
type ProjectIdentity ¶
type ProjectIdentity struct {
Name string `json:"name"`
Browser string `json:"browser"`
Device string `json:"device"`
Use json.RawMessage `json:"use"`
ConfigDigest string `json:"configDigest"`
}
ProjectIdentity binds the resolved runtime configuration, not a device label inferred from the project name. Empty device labels remain explicit unknowns.
type Receipt ¶
type Receipt struct {
DescendantObservation *procgroup.DescendantObservation `json:"descendantObservation,omitempty"`
RunnerResources *procgroup.ResourceUsage `json:"runnerResources,omitempty"`
Schedule *ExecutionSchedule `json:"schedule,omitempty"`
Profile string `json:"profile,omitempty"`
SensitiveInputPolicy *SensitiveInputPolicy `json:"sensitiveInputPolicy,omitempty"`
External *ExternalLifecycle `json:"external,omitempty"`
ApplicationAttestation *ApplicationAttestationReceipt `json:"applicationAttestation,omitempty"`
TestRepositoryAtStart *ApplicationRepositoryIdentity `json:"testRepositoryAtStart,omitempty"`
TestRepositoryAtPublish *ApplicationRepositoryIdentity `json:"testRepositoryAtPublish,omitempty"`
Kind string `json:"kind"` // "unit" | "e2e"
Identity Identity `json:"identity"`
AppBuildAtStart AppBuildIdentity `json:"appBuildAtStart"`
AppBuildAtPublish AppBuildIdentity `json:"appBuildAtPublish"`
StaleAppBuild bool `json:"staleAppBuild"`
Tests []TestOutcome `json:"tests"`
Infrastructure *InfrastructureFailure `json:"infrastructure,omitempty"`
Cancelled bool `json:"cancelled"`
ServerDescendantsGone *bool `json:"serverDescendantsGone,omitempty"`
}
Receipt is the one JS/TS provider output shape: identity, app-build freshness, per-test outcomes, and an optional run-level infrastructure failure. It carries no boolean "valid" summary; ToInput below projects it through the shared testvalidity axes instead.
func RunE2E ¶
RunE2E starts the app server, waits for it to answer ServerReadyURL, runs the Playwright test command, then cancels the server's context and confirms procgroup's owned-process-group cleanup fired before returning. The app build identity is captured once before the readiness check passes and again after the test command completes; a mismatch is reported as StaleAppBuild rather than silently trusted.
func RunUnit ¶
func RunUnit(ctx context.Context, cfg UnitConfig) (Receipt, error)
RunUnit runs `vitest run --reporter=json --outputFile=<path>` under procgroup containment and returns the bound receipt. A nonzero vitest exit status is expected on real test failures and is not itself an infrastructure error when the report already names the failure (a failed assertion, or the file-level fallback in ParseVitestJSON). But an error raised outside any test's own execution window (e.g. thrown from a timer callback after its test already passed) never touches Vitest's own numFailedTests/numFailedSuites counters, so it leaves every reported outcome "passed" while the process still exits nonzero - the report carries no signal at all. unexplainedNonzeroExit below catches exactly that gap so such a run abstains instead of publishing an all-green receipt (AGENTS.md invariant 2); see docs/decisions/0182 and js-live-test-provider-v0.md §2.1.
type SensitiveInputFinding ¶
SensitiveInputFinding is a typed, value-free validation result. Path names the structural location only; it never includes the rejected value.
func ValidateSensitiveInputEvidence ¶
func ValidateSensitiveInputEvidence(receipt Receipt) []SensitiveInputFinding
type SensitiveInputPolicy ¶
type SensitiveInputPolicy struct {
AdditionalActionPatterns []string `json:"additionalActionPatterns,omitempty"`
AdditionalSensitiveFields []string `json:"additionalSensitiveFields,omitempty"`
}
SensitiveInputPolicy carries provider additions. Defaults are always applied and cannot be disabled or replaced by these declarations.
type SensitiveInputValidationError ¶
type SensitiveInputValidationError struct {
Findings []SensitiveInputFinding
}
func (*SensitiveInputValidationError) Error ¶
func (e *SensitiveInputValidationError) Error() string
type TestOutcome ¶
type TestOutcome struct {
ID string `json:"id,omitempty"`
Project *ProjectIdentity `json:"project,omitempty"`
Attempts []Attempt `json:"attempts,omitempty"`
Name string `json:"name"`
FullName string `json:"fullName"`
State ExecutionState `json:"state"`
Retries int `json:"retries"`
DurationMS float64 `json:"durationMs"`
Anchor *Anchor `json:"anchor,omitempty"`
FailureMessage string `json:"failureMessage,omitempty"`
Artifacts []FailureArtifact `json:"artifacts,omitempty"`
}
TestOutcome is one reporter test/assertion result, normalized to this package's ExecutionState vocabulary.
type UnitConfig ¶
type UnitConfig struct {
Config
OutputFile string // where --outputFile writes, removed before the run; a temp file is used if empty.
}
UnitConfig configures one Vitest unit run.