techygarg/confit
Agent skills for ConfIT — set up a declarative API test suite, write component tests from your controller and its mocks, and write black-box API tests from an OpenAPI spec.
Changelog
All notable changes to ConfIT are documented here. Format follows Keep a Changelog. ConfIT uses Semantic Versioning.
[3.2.0]
Added
-
mock.enableLogs— WireMock request logging is now switchable fromsuite.config.yamlinstead of only from fixture code. Beyond debugging a stub that will not match, it turns an unknown dependency surface into a listing: run a component test with nomock:block and every outbound call is logged as an unmatched request, which is enough to write the interactions from. Works whatever language the service under test is written in, since it observes HTTP rather than code. See Mock Interactions. -
Agent skills — three Agent Skills in
skills/, distributed as agent plugins:confit-suite-setup(wire a suite),confit-component-tests(developer, mid-implementation — works from the controller plus the mocks behind it) andconfit-integration-tests(QA, post-deployment — black box, works from a spec, collection or live endpoint and assumes no access to the service source). See AI Agent Skills. -
Plugin manifests — the repository is its own Claude Code marketplace (
/plugin marketplace add techygarg/ConfIT, then/plugin install confit@confit), and carries a Codex manifest. Further agents are onboarded by adding one manifest directory each. -
example/README.md— maps the three startup modes to their example projects, states what every suite structurally needs, and lists what is demo-specific so none of it is copied into a consuming project. -
Validation tooling in
tools/—check-testcases.pystatically validates test definitions (missing expected bodies, invaliddepends:, unresolvable{{variables}},mock:blocks in an integration suite, unregistered files, and matcher problems such as an unknown name, a missing closing parenthesis, or a wildcard in asemanticpath).verify-suite.shchecks project wiring. Both exit non-zero on error and run in CI via the newmake skillstarget, and both read ground truth fromsrc/ConfIT/— supported frameworks, built-in matcher names — rather than hardcoding it.
Changed
- Skills read ConfIT's own
example/anddoc/instead of shipping templates. Embedded copies of the fixture,suite.config.yamland.csprojdrifted from the real projects, so they were removed; each skill now resolves the repository it ships inside and reads the suites CI verifies.
Fixed
example/User.IntegrationTests—TestReader.GetTestsForAFilewas called with its arguments reversed; removedAuthTokenProvider.cs, which implementedIAuthTokenProviderbut was never referenced, since noSuiteBootstrapperoverload accepts a custom provider (auth is configured declaratively). Theqaenvironment now reads its URL from${QA_API_URL}instead of a hardcoded host.example/User.ComponentTests—appsettings.Tests.jsoncarried anenvironmentVariableskey that nothing reads;UserDbInitializer.Seed()had a commented-out body and now seeds real reference data, demonstrating theonStartedhook.example/User.ComponentTests.AppLauncher— configuration comments referred to aStartup.SeedDatabasemethod that does not exist, and now describe the actualIsLocalComponentTests/UserDbContextmechanism; the namespace was aligned with the project folder.
Other than mock.enableLogs, the library is unchanged — the skills are distributed as agent plugins, not as package content.
[3.1.0]
Added
-
GraphQL request support — a
graphqlblock (query/queryFromFile/variables/operationName) onapi.requestor on a mock interaction'srequestcompiles into the standard{ query, variables, operationName }JSON body at test-load time.methoddefaults toPOSTonly if unset, andContent-Type: application/jsonis added only if not already present — the rest of the pipeline (matchers,extract,{{inject}}, mocking) behaves exactly as it does for any other request. See GraphQL Support. -
Array-wildcard matcher segments —
ignoreandpatternpaths accept a literal*segment (e.g.errors__*__path) to target a field across every element of an array regardless of length, so a variable-length array — such as a GraphQLerrorslist — can be matched without listing an index per entry.
Changed
ResultMatcherwildcard matching — parent-path template construction is hoisted to once per matcher rule instead of once per JSON property visited during tree traversal, and array-index regex normalization is skipped entirely when neither the template nor the path contains an array index.
Documentation
- GraphQL Support — new reference for the
graphqlblock: structure,queryvsqueryFromFile, and how it composes into the request body. - Test File Format and Matchers and Patterns — updated with the
graphqlblock and array-wildcard matcher segment documentation. - NuGet package README —
doc/Package.Readme.mdadded as the package description shown on nuget.org.
[3.0.0]
Added
-
YAML test files —
.yaml/.ymltest definitions alongside JSON. Full DSL parity: all matchers, extract/inject, mock interactions, and tags work identically in YAML. YAML anchors and comments supported. -
Variable extraction and injection —
extractcaptures response field values;{{varName}}injects them into subsequent requests and paths.${ENV_VAR}references pull environment values directly into test definitions. Covers the majority ofITestProcessoruse cases declaratively. -
Semantic matcher library — Type-aware named assertions:
isUuid,isIsoDate,isIsoDateTime,isEmail,isUrl,greaterThan(n),lessThan(n),hasLength(n),isNull,isNotNull,isNotEmpty. Custom matchers registered as acustomMatchersparameter toSuiteBootstrapperor viaSuiteConfig.CustomMatchersin the manual wiring path. -
Field-level failure output — Test failures report per-field diffs (expected vs actual,
<missing>,<absent>) rather than raw JSON dumps. Semantic and pattern matcher results are reported separately before the body diff. -
Suite summary table —
TestResultCollectorprints a grouped pass/fail table at the end of every suite run, organised by source file with colour-coded results and timing per test. -
AppLauncher — Out-of-process service startup via any shell command. Polls HTTP or TCP readiness before running tests. Enables language-agnostic testing: test Go, Node.js, Python, Java, or any HTTP API using the same test definitions. The application manages its own test environment; the test project holds no reference to application internals.
-
Declarative suite configuration —
suite.config.yamlwithSuiteConfiguration.LoadComponent/LoadIntegrationreplaces manual fixture wiring. One file declares API URL, mock URL, folder paths, filter strategy, and startup mode. Integration suites support named environments (local,qa,staging) selected at runtime viaTEST_ENVIRONMENT.${ENV_VAR}interpolation in config values keeps secrets out of committed files. -
Test Dependency Graph —
depends:field on test definitions declares prerequisites within the same file. When a prerequisite fails or is skipped, all dependents are skipped rather than producing cascading errors or misleadingUndefinedVariableExceptionfailures. The skip reason is shown in the suite summary beneath each skipped test (└─ prerequisite 'CreateUser' failed). Dependencies are validated at load time — forward references and references to tests in other files are rejected with a clear message naming the test and the file. -
Declarative Auth Profiles —
auth:block insuite.config.yamlreplacesIAuthTokenProviderC# boilerplate for the common auth cases. Three types are supported:type: bearer— static token or${ENV_VAR}reference; every request carriesAuthorization: Bearer {token}type: oauth2-client-credentials— posts totokenUrlat suite startup usinggrant_type=client_credentials; caches theaccess_tokenfor the entire run; throws with endpoint URL and HTTP status if the token endpoint failstype: api-key— injects a value into any named request header;headerKey:(required) names the header,value:supplies the key- All types accept an optional
headerKey:override; bearer and OAuth2 default toAuthorization cfg.ToAuthTokenProvider()extension method onComponentConfigandIntegrationConfigconstructs the configured provider; returnsnullwhen noauth:block is declared, preserving existing no-auth behaviour
-
net10.0 support — Library targets both
net9.0andnet10.0. -
SuiteBootstrapper— single-call fixture factory that replaces the manual adapter chain. Three methods cover every suite type:SuiteBootstrapper.ForComponent<TStartup>(configFile, configureServices?, onStarted?, customMatchers?)— in-process component suite;onStartedcallback receivesIServiceProviderfor DB seeding and project-specific initSuiteBootstrapper.ForCommand(configFile, customMatchers?)— command/AppLauncher suite; starts the external process, builds auth provider, manages full lifecycleSuiteBootstrapper.ForIntegration(configFile, environment?, customMatchers?)— integration suite; selects environment via parameter,TEST_ENVIRONMENTenv var, or YAML default
-
BootstrappedSuite— disposable wrapper returned by allSuiteBootstrappermethods. HoldsTestSuiteContext ContextandIServiceProvider? Services(in-process suites only).Dispose()prints the suite summary then shuts down infrastructure in the correct order. Reduces fixture boilerplate from 15–28 lines to 5–10 lines. -
TestSuiteContext— record that bundles the five objectsBaseTestneeds (HttpClient,Config,ProcessorFactory,Filter,ResultCollector). Passed as a single parameter to the primaryBaseTestconstructor. Supports thewithexpression for augmenting a bootstrapped context (e.g. adding aProcessorFactoryon top of a bootstrapped suite). -
TestCaseResolver— static class inConfIT.Readerthat owns file I/O forbodyFromFileloading andoverridemerging. Replaces the self-mutatingInitialize()pattern on model types. -
MatchResult— record inConfIT.Matchingthat decouples diff computation from assertion.ResultMatcher.MatchResponseBodyreturnsMatchResultinstead of calling FluentAssertions directly;BaseTest.Verifyowns the single assertion boundary.
Changed
-
TestSuiteInitializermodernised — Replaced legacyWebHost.CreateDefaultBuilder()and manualTestServerconstruction withWebApplicationFactory<TProgram>. Generic parameter is the app's entry point class (typicallyStartup); theTestServerStartupsubclass pattern is eliminated. Service overrides via an optionalAction<IServiceCollection>callback.Services(IServiceProvider) replaces the deprecatedTestServerproperty. -
IAuthTokenProvidergains aHeaderKey()method with a default implementation of"Authorization". Existing custom providers that only implementToken()continue to work unchanged — the default covers the standard bearer case.TestHttpClientnow callsHeaderKey()to determine the header name, making API key auth expressible through the same interface without a separate injection point. -
BaseTestconstructor — primary constructor is nowprotected BaseTest(TestSuiteContext context, ITestOutputLogger? logger = null). The previous 6-parameter constructor is kept as a delegating overload for backward compatibility; existing subclasses continue to compile without changes. -
BaseTest.Config— changed fromprotected static SuiteConfig Configtoprotected SuiteConfig Config(instance property). Eliminates a race condition where parallel test classes with different configurations could overwrite each other's static field. -
TestFilter.TagsandTestFilter.TestNames— changed fromList<string> { get; set; }toIReadOnlyList<string> { get; init; }. Filters are immutable after construction; the factory methods (CreateForTags,CreateForTagsFromEnvVariable, etc.) are the intended construction path. -
SemanticMatcher.Apply— now returnsstring?(a failure description, ornullon success) instead of throwing via FluentAssertions. FluentAssertions is invoked only at theBaseTest.Verifyboundary, decoupling matcher logic from the assertion framework. -
TestHttpClient— builds a freshHttpRequestMessageperExecute()call instead of clearing and repopulatingDefaultRequestHeaders. Eliminates a thread-safety issue under concurrent request execution. -
AuthConfig— validation logic moved fromAuthConfig.ValidateAuth()intoSuiteConfiguration.ValidateComponent/ValidateIntegrationEnv.AuthConfigis now a pure data class with no methods. -
BaseTest.Executeaccepts rawJToken— new overloadExecute(string testName, JToken test, string? sourceFile)resolves the token to aTestCaseinternally using the folder paths already present in_config. Test classes no longer need to calltest.ToTestCase(Config.RequestBodyFolder, Config.ResponseBodyFolder)ortest.ToTestCase(null, null)explicitly —await Execute(testName, test, sourceFile)works identically for both component and integration suites. The existingExecute(string, TestCase, string?)overload is unchanged. -
Filter env var naming — example env var names renamed from
RUN_POOLS/RUN_TESTStoTEST_TAGS/TEST_NAMESfor clarity. These are project-level conventions set insuite.config.yamlvia theenvVariable:field, not library constants; any name is valid. -
Namespace restructure — types reorganised into purpose-specific namespaces. Consumers using
SuiteBootstrapper,BaseTest, and extension methods are unaffected. Code with explicitusingdirectives for the old namespaces must update:Old namespace New namespace Types affected ConfIT.Server.DtoConfIT.ModelTestCase,TestApi,MockInteraction,HttpTestRequest,HttpTestResponse,Matcher,TestMockConfIT.Server.HttpConfIT.Runner.HttpTestHttpClient,TestSuiteInitializerConfIT.Server.BootConfIT.Runner.BootAppLauncher,AppLauncherConfig,AppLauncherException,ReadinessConfigConfIT.Server.MockConfIT.Runner.MockHttpMockServerConfIT.UtilConfIT.MatchingResultMatcher,SemanticMatcher,DeltaFormatterConfIT.UtilConfIT.ReaderTestReader,YamlConverterConfIT.UtilConfIT.ReportingTestColor,TestResultCollector -
IntegrationEnvironmentConfigrenamed toIntegrationConfig— the type returned bySuiteConfiguration.LoadIntegrationand used by theToSuiteConfig(),ToTestFilter(), andToAuthTokenProvider()extension methods. -
BaseRequestResponserenamed toHttpPayload— the base class forHttpTestRequestandHttpTestResponse. Direct references must be updated; types accessed through normal test wiring are unaffected. -
BuilderExtensionmadeinternal— the WireMock extension methods inConfIT.Runner.Mockare no longer part of the public API.
Deprecated
TestSuiteInitializer.TestServer— useTestSuiteInitializer.Services(IServiceProvider) instead.ITestProcessor/ITestProcessorFactory— theextract+{{inject}}DSL covers the majority of use cases without C#. These interfaces remain for genuinely imperative cases such as request signing or external side effects.
Removed
-
net8.0 support — The library now targets
net9.0andnet10.0only. Projects still on .NET 8 must upgrade before adopting this release. -
BaseRequestResponse.Initialize(string folder)andApplyOverride(JToken)— file I/O is now handled byTestCaseResolver. Model types are pure data carriers.JToken.ToTestCase(requestFolder, responseFolder)callsTestCaseResolverinternally; consumer call sites are unchanged. -
ApiInteraction.Initialize(string, string)andTestCase.Initialize(string, string)— same as above. -
EnvironmentKeysclass — theEnvironmentKeys.TestEnvironmentconstant is inlined intoSuiteConfiguration. Remove anyusing ConfIT.Constant;directives.
Documentation
- Suite Setup — full rewrite:
SuiteBootstrapperis the primary path; adapter chain and manual wiring documented as advanced/custom alternatives. - Test Filtering — full rewrite: leads with the YAML
filter:block; documents both strategies (tags/tests), theenvVariablefield, and the untagged-test skip rule. - Auth Profiles — fixture code examples updated to reflect
SuiteBootstrapperand bootstrapped path. - AppLauncher — fixture code examples updated to
SuiteBootstrapper.ForCommand(). - Extending ConfIT — constructor snippets,
ITestProcessorFactorywiring withwithexpression, andCustomMatchersparameter updated. - Test Execution Flow — startup diagrams updated to show
SuiteBootstrapperas entry point. - Test Dependency Graph — full reference for the
depends:field: skip-not-fail semantics, cascading skip propagation, load-time validation rules, and interaction with variable extraction.