Trax.Api.GraphQL.Testing
Package Trax.Api.GraphQL.TestingNamespace Trax.Api.GraphQL.TestingSource CrossSchemaGuards.cs, CrossSchemaGuardFixture.cs
The GraphQL guard package: checkers for the cross-schema GraphQL pattern, and an NUnit fixture that runs them. It depends on Trax.Core.Testing and Trax.Api.GraphQL.
Signatures
namespace Trax.Api.GraphQL.Testing;
public static class CrossSchemaGuards
{
public static GuardResult EdgeManifestIsValid(IReadOnlyList<CrossSchemaEdge> edges);
public static GuardResult EdgeResolversUseLoader(ArchitectureGuardOptions options, string crossSchemaProjectSuffix = ".CrossSchema");
public static GuardResult ExtensionResolversDeclareParentRequirements(ArchitectureGuardOptions options);
}
[TestFixture]
public abstract class CrossSchemaGuardFixture
{
protected virtual ArchitectureGuardOptions Options { get; }
protected virtual IReadOnlyList<CrossSchemaEdge> Edges { get; }
protected virtual bool ExpectsCrossSchemaResolvers { get; }
protected virtual bool ExpectsParentResolvers { get; }
[Test] public void Cross_schema_edge_manifest_is_valid();
[Test] public void Cross_schema_edge_resolvers_use_the_batched_loader();
[Test] public void Extension_resolvers_declare_what_they_read_off_their_parent();
protected static void AssertInspected(GuardResult result, bool expected, string what, string optOut, ArchitectureGuardOptions options);
}Members
CrossSchemaGuards
| Checker | Checks |
|---|---|
EdgeManifestIsValid(edges) | Each CrossSchemaEdge names a real integer foreign key on its source, a target owned as a DbSet by the declared target context, and a camelCase field name |
EdgeResolversUseLoader(options, crossSchemaProjectSuffix) | Every resolver on a type extension in a project whose name ends in crossSchemaProjectSuffix routes through a CrossSchemaLoader<,>: a public method of an [ExtendObjectType] class, or of a source-generated [ObjectType<T>] extension, that is not [GraphQLIgnore] and names CrossSchemaLoader<,> in its parameters or body |
ExtensionResolversDeclareParentRequirements(options) | Every property a [Parent] resolver reads off its parent, other than the key Trax adds itself, is declared in [Parent(requires: ...)] |
CrossSchemaGuardFixture
| Member | Default | Description |
|---|---|---|
Options | new() | Scan roots and allowlists |
Edges | empty | The edge manifest; empty passes the manifest check |
ExpectsCrossSchemaResolvers | true | Whether the scan roots must hold at least one cross-schema [ExtendObjectType] resolver |
ExpectsParentResolvers | true | Whether they must hold at least one [Parent] resolver |
Cross_schema_edge_manifest_is_valid | Runs EdgeManifestIsValid(Edges); fails on any offender | |
Cross_schema_edge_resolvers_use_the_batched_loader | Runs EdgeResolversUseLoader(Options); fails when it inspected nothing and ExpectsCrossSchemaResolvers is true, then on any offender | |
Extension_resolvers_declare_what_they_read_off_their_parent | Runs ExtensionResolversDeclareParentRequirements(Options); fails when it inspected nothing and ExpectsParentResolvers is true, then on any offender | |
AssertInspected(result, expected, what, optOut, options) | The shared "inspected nothing" failure, naming the scan roots and the property that opts out. Protected, for a subclass's own guards. |
Examples
using Trax.Api.GraphQL.Testing;
using Trax.Core.Testing;
var result = CrossSchemaGuards.ExtensionResolversDeclareParentRequirements(
new ArchitectureGuardOptions { SourceScanRoots = ["src"] }
);
if (result.Inspected == 0 || !result.Passed)
throw new InvalidOperationException(result.FailureMessage);The fixture, subclassed in an NUnit test project:
[TestFixture]
public sealed class CrossSchemaGuards : CrossSchemaGuardFixture
{
protected override ArchitectureGuardOptions Options => new() { SourceScanRoots = ["libs"] };
protected override IReadOnlyList<CrossSchemaEdge> Edges => MyCrossSchemaEdges.All;
}