├── resources
├── custom_scalar_mapping.txt
├── icon.ico
├── icon.jpg
├── custom_scalar_mapping.json
├── configuration.json
└── blog.graphql
├── MAINTAINERS.md
├── src
├── GraphQLToKarate.CommandLine
│ ├── Program.cs
│ ├── icon.ico
│ ├── InternalsVisibleTo.cs
│ ├── Settings
│ │ ├── LogCommandSettings.cs
│ │ ├── IConvertCommandSettingsLoader.cs
│ │ ├── GraphQLToKarateUserConfiguration.cs
│ │ ├── LoadedConvertCommandSettings.cs
│ │ └── ConvertCommandSettingsLoader.cs
│ ├── Infrastructure
│ │ ├── TypeResolver.cs
│ │ ├── TypeRegistrarConfigurator.cs
│ │ ├── CompositionRoot.cs
│ │ ├── StringToSetConverter.cs
│ │ ├── CommandAppConfigurator.cs
│ │ ├── LogCommandSettingsInterceptor.cs
│ │ ├── TypeRegistrar.cs
│ │ ├── LogLevelVerbosityConverter.cs
│ │ └── HostConfigurator.cs
│ ├── Exceptions
│ │ └── GraphQLToKarateConfigurationException.cs
│ ├── Mappers
│ │ ├── IGraphQLToKarateUserConfigurationMapper.cs
│ │ └── GraphQLToKarateUserConfigurationMapper.cs
│ ├── Prompts
│ │ └── IConvertCommandSettingsPrompt.cs
│ ├── Commands
│ │ └── ConvertCommand.cs
│ └── GraphQLToKarate.CommandLine.csproj
├── GraphQLToKarate.Library
│ ├── InternalsVisibleTo.cs
│ ├── Enums
│ │ └── GraphQLOperationType.cs
│ ├── Tokens
│ │ ├── Indent.cs
│ │ ├── GraphQLToken.cs
│ │ ├── KarateToken.cs
│ │ └── SchemaToken.cs
│ ├── Types
│ │ ├── KarateTypeBase.cs
│ │ ├── GraphQLArgumentTypeBase.cs
│ │ ├── KarateType.cs
│ │ ├── KarateListType.cs
│ │ ├── KarateNullType.cs
│ │ ├── KarateNonNullType.cs
│ │ ├── GraphQLArgumentType.cs
│ │ ├── GraphQLNonNullArgumentType.cs
│ │ ├── GraphQLListArgumentType.cs
│ │ ├── GraphQLOperation.cs
│ │ └── KarateObject.cs
│ ├── Settings
│ │ ├── KarateFeatureBuilderSettings.cs
│ │ └── GraphQLToKarateSettings.cs
│ ├── Parsers
│ │ ├── GraphQLSchemaParser.cs
│ │ └── IGraphQLSchemaParser.cs
│ ├── Converters
│ │ ├── IGraphQLToKarateConverter.cs
│ │ ├── IGraphQLInputValueDefinitionConverterFactory.cs
│ │ ├── GraphQLInputValueDefinitionConverterFactory.cs
│ │ ├── IGraphQLTypeConverterFactory.cs
│ │ ├── IGraphQLCyclicToAcyclicConverter.cs
│ │ ├── IGraphQLInputValueToExampleValueConverter.cs
│ │ ├── GraphQLCustomScalarTypeConverter.cs
│ │ ├── IGraphQLScalarToExampleValueConverter.cs
│ │ ├── IGraphQLTypeDefinitionConverter.cs
│ │ ├── GraphQLNullTypeConverter.cs
│ │ ├── IGraphQLTypeConverter.cs
│ │ ├── GraphQLTypeConverterFactory.cs
│ │ ├── IGraphQLFieldDefinitionConverter.cs
│ │ ├── GraphQLNonNullTypeConverter.cs
│ │ ├── IGraphQLInputValueDefinitionConverter.cs
│ │ ├── GraphQLTypeDefinitionConverter.cs
│ │ ├── GraphQLListTypeConverter.cs
│ │ ├── GraphQLTypeConverter.cs
│ │ ├── GraphQLScalarToExampleValueConverter.cs
│ │ └── GraphQLInputValueToExampleValueConverter.cs
│ ├── Builders
│ │ ├── IConfiguredGraphQLToKarateConverterBuilder.cs
│ │ └── IGraphQLToKarateConverterBuilder.cs
│ ├── Apollo
│ │ └── Directives.cs
│ ├── Extensions
│ │ ├── HasArgumentsDefinitionNodeExtensions.cs
│ │ ├── StringBuilderExtensions.cs
│ │ ├── CollectionExtensions.cs
│ │ ├── AdjacencyGraphExtensions.cs
│ │ ├── EnumExtensions.cs
│ │ ├── GraphQLDirectiveExtensions.cs
│ │ ├── GraphQLFieldDefinitionExtensions.cs
│ │ ├── GraphQLEnumValueDefinitionExtensions.cs
│ │ ├── GraphQLInputValueDefinitionExtensions.cs
│ │ ├── GraphQLTypeExtensions.cs
│ │ └── StringExtensions.cs
│ ├── Mappings
│ │ ├── ICustomScalarMappingValidator.cs
│ │ ├── ICustomScalarMappingLoader.cs
│ │ ├── ICustomScalarMapping.cs
│ │ ├── CustomScalarMapping.cs
│ │ └── CustomScalarMappingLoader.cs
│ ├── Exceptions
│ │ └── InvalidGraphQLTypeException.cs
│ ├── Features
│ │ ├── IKarateScenarioBuilder.cs
│ │ ├── IKarateFeatureBuilder.cs
│ │ └── KarateFeatureBuilder.cs
│ ├── GraphQLToKarate.Library.csproj
│ └── Adapters
│ │ └── IGraphQLDocumentAdapter.cs
└── GraphQLToKarate.sln
├── renovate.json
├── tests
├── GraphQLToKarate.Integration.Api
│ ├── Types
│ │ ├── ISearchResult.cs
│ │ ├── UserRole.cs
│ │ ├── PageInfoInput.cs
│ │ ├── UserConnection.cs
│ │ ├── CommentConnection.cs
│ │ ├── BlogPostConnection.cs
│ │ ├── Node.cs
│ │ ├── BlogPostExtensions.cs
│ │ ├── PageInfo.cs
│ │ ├── UpdateUserInput.cs
│ │ ├── CreateBlogPostInput.cs
│ │ ├── CreateUserInput.cs
│ │ ├── Comment.cs
│ │ ├── User.cs
│ │ ├── BlogPost.cs
│ │ └── Mutation.cs
│ ├── appsettings.json
│ ├── Program.cs
│ ├── Properties
│ │ └── launchSettings.json
│ └── GraphQLToKarate.Integration.Api.csproj
├── GraphQLToKarate.Tests
│ ├── Mocks
│ │ └── UnsupportedGraphQLType.cs
│ ├── Enums
│ │ └── GraphQLOperationTypeTests.cs
│ ├── Extensions
│ │ ├── CollectionExtensionTests.cs
│ │ ├── GraphQLDirectiveExtensionsTests.cs
│ │ ├── StringExtensionsTests.cs
│ │ ├── AdjacencyGraphExtensionsTests.cs
│ │ ├── GraphQLInputValueDefinitionExtensionsTests.cs
│ │ ├── GraphQLFieldDefinitionExtensionsTests.cs
│ │ ├── GraphQLEnumValueDefinitionExtensionsTests.cs
│ │ └── GraphQLTypeExtensionsTests.cs
│ ├── Converters
│ │ ├── GraphQLTypeConverterFactoryTests.cs
│ │ └── GraphQLCustomScalarTypeConverterTests.cs
│ ├── Types
│ │ ├── GraphQLVariableTypeTests.cs
│ │ └── KarateObjectTests.cs
│ ├── GraphQLToKarate.Tests.csproj
│ ├── Builders
│ │ └── GraphQLToKarateConverterBuilderTests.cs
│ └── Mappings
│ │ └── CustomScalarMappingTest.cs
└── GraphQLToKarate.CommandLine.Tests
│ ├── Infrastructure
│ ├── TypeRegistrarConfiguratorTests.cs
│ ├── TypeRegistrarTests.cs
│ ├── TypeResolverTests.cs
│ ├── LogCommandSettingsInterceptorTests.cs
│ ├── LogLevelVerbosityConverterTests.cs
│ └── StringToSetConverterTests.cs
│ ├── GraphQLToKarate.CommandLine.Tests.csproj
│ ├── Mappers
│ └── GraphQLToKarateUserConfigurationMapperTests.cs
│ └── Settings
│ └── ConvertCommandSettingsTests.cs
├── .markdownlint.json
├── stylecop.json
├── .github
├── workflows
│ ├── approve.yml
│ ├── stale.yml
│ ├── lint.yml
│ ├── integration-test.yml
│ ├── test.yml
│ └── codeql.yml
├── ISSUE_TEMPLATE
│ ├── FEATURE_REQUEST.md
│ └── BUG_REPORT.md
└── PULL_REQUEST_TEMPLATE.md
├── scripts
└── extract_changelog.py
├── LICENSE
├── SECURITY.md
├── CHANGELOG.md
├── .editorconfig
├── CONTRIBUTING.md
└── configuration
└── schema
└── v1
└── schema.json
/resources/custom_scalar_mapping.txt:
--------------------------------------------------------------------------------
1 | Date:string,Long:number,URL:string
--------------------------------------------------------------------------------
/MAINTAINERS.md:
--------------------------------------------------------------------------------
1 | # Maintainers
2 |
3 | - [@wbaldoumas](https://github.com/wbaldoumas)
4 |
--------------------------------------------------------------------------------
/resources/icon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wbaldoumas/graphql-to-karate/HEAD/resources/icon.ico
--------------------------------------------------------------------------------
/resources/icon.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wbaldoumas/graphql-to-karate/HEAD/resources/icon.jpg
--------------------------------------------------------------------------------
/resources/custom_scalar_mapping.json:
--------------------------------------------------------------------------------
1 | {
2 | "Date": "string",
3 | "Long": "number",
4 | "URL": "string"
5 | }
--------------------------------------------------------------------------------
/src/GraphQLToKarate.CommandLine/Program.cs:
--------------------------------------------------------------------------------
1 | await CompositionRoot.Build(args).RunAsync(args).ConfigureAwait(false);
--------------------------------------------------------------------------------
/src/GraphQLToKarate.CommandLine/icon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wbaldoumas/graphql-to-karate/HEAD/src/GraphQLToKarate.CommandLine/icon.ico
--------------------------------------------------------------------------------
/src/GraphQLToKarate.Library/InternalsVisibleTo.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.CompilerServices;
2 |
3 | [assembly: InternalsVisibleTo("GraphQLToKarate.Tests")]
4 |
--------------------------------------------------------------------------------
/renovate.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json",
3 | "extends": [
4 | "github>wbaldoumas/renovate-config"
5 | ]
6 | }
7 |
--------------------------------------------------------------------------------
/src/GraphQLToKarate.Library/Enums/GraphQLOperationType.cs:
--------------------------------------------------------------------------------
1 | namespace GraphQLToKarate.Library.Enums;
2 |
3 | public enum GraphQLOperationType
4 | {
5 | Query,
6 | Mutation
7 | }
--------------------------------------------------------------------------------
/tests/GraphQLToKarate.Integration.Api/Types/ISearchResult.cs:
--------------------------------------------------------------------------------
1 | namespace GraphQLToKarate.Integration.Api.Types;
2 |
3 | [UnionType("SearchResult")]
4 | public interface ISearchResult { }
--------------------------------------------------------------------------------
/tests/GraphQLToKarate.Integration.Api/Types/UserRole.cs:
--------------------------------------------------------------------------------
1 | namespace GraphQLToKarate.Integration.Api.Types;
2 |
3 | public enum UserRole
4 | {
5 | Guest,
6 | Standard,
7 | Administrator
8 | }
--------------------------------------------------------------------------------
/src/GraphQLToKarate.CommandLine/InternalsVisibleTo.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.CompilerServices;
2 |
3 | [assembly: InternalsVisibleTo("GraphQLToKarate.CommandLine.Tests")]
4 | [assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]
5 |
--------------------------------------------------------------------------------
/tests/GraphQLToKarate.Integration.Api/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft.AspNetCore": "Warning"
6 | }
7 | },
8 | "AllowedHosts": "*"
9 | }
10 |
--------------------------------------------------------------------------------
/tests/GraphQLToKarate.Integration.Api/Types/PageInfoInput.cs:
--------------------------------------------------------------------------------
1 | namespace GraphQLToKarate.Integration.Api.Types;
2 |
3 | public sealed class PageInfoInput
4 | {
5 | public int? Limit { get; set; }
6 |
7 | public int? Offset { get; set; }
8 | }
--------------------------------------------------------------------------------
/tests/GraphQLToKarate.Integration.Api/Types/UserConnection.cs:
--------------------------------------------------------------------------------
1 | namespace GraphQLToKarate.Integration.Api.Types;
2 |
3 | public sealed class UserConnection
4 | {
5 | public required User[] Nodes { get; init; }
6 |
7 | public required PageInfo PageInfo { get; init; }
8 | }
--------------------------------------------------------------------------------
/tests/GraphQLToKarate.Integration.Api/Types/CommentConnection.cs:
--------------------------------------------------------------------------------
1 | namespace GraphQLToKarate.Integration.Api.Types;
2 |
3 | public sealed class CommentConnection
4 | {
5 | public required Comment[] Nodes { get; init; }
6 |
7 | public required PageInfo PageInfo { get; init; }
8 | }
--------------------------------------------------------------------------------
/tests/GraphQLToKarate.Integration.Api/Types/BlogPostConnection.cs:
--------------------------------------------------------------------------------
1 | namespace GraphQLToKarate.Integration.Api.Types;
2 |
3 | public sealed class BlogPostConnection
4 | {
5 | public required BlogPost[] Nodes { get; init; }
6 |
7 | public required PageInfo PageInfo { get; init; }
8 | }
--------------------------------------------------------------------------------
/tests/GraphQLToKarate.Integration.Api/Types/Node.cs:
--------------------------------------------------------------------------------
1 | namespace GraphQLToKarate.Integration.Api.Types;
2 |
3 | [InterfaceType("Node")]
4 | public abstract class Node
5 | {
6 | [GraphQLType(typeof(IdType))]
7 | [GraphQLNonNullType]
8 | public required string Id { get; init; }
9 | }
--------------------------------------------------------------------------------
/tests/GraphQLToKarate.Integration.Api/Types/BlogPostExtensions.cs:
--------------------------------------------------------------------------------
1 | namespace GraphQLToKarate.Integration.Api.Types;
2 |
3 | [ExtendObjectType(typeof(BlogPost))]
4 | public sealed class BlogPostExtensions
5 | {
6 | public required Uri Uri { get; set; } = new ("https://my-awesome-api.com");
7 | }
--------------------------------------------------------------------------------
/tests/GraphQLToKarate.Integration.Api/Types/PageInfo.cs:
--------------------------------------------------------------------------------
1 | namespace GraphQLToKarate.Integration.Api.Types;
2 |
3 | public sealed class PageInfo
4 | {
5 | public bool HasNextPage { get; set; }
6 |
7 | public bool HasPreviousPage { get; set; }
8 |
9 | public int TotalCount { get; set; }
10 | }
--------------------------------------------------------------------------------
/.markdownlint.json:
--------------------------------------------------------------------------------
1 | {
2 | "default": true,
3 | "MD013": {
4 | "line_length": 10000,
5 | "headings": false,
6 | "code_blocks": false,
7 | "tables": false
8 | },
9 | "MD024": {
10 | "siblings_only": true
11 | },
12 | "MD041": false,
13 | "MD034": false
14 | }
15 |
--------------------------------------------------------------------------------
/src/GraphQLToKarate.Library/Tokens/Indent.cs:
--------------------------------------------------------------------------------
1 | namespace GraphQLToKarate.Library.Tokens;
2 |
3 | internal static class Indent
4 | {
5 | public const int Single = 2;
6 |
7 | public const int Double = Single * 2;
8 |
9 | public const int Triple = Single * 3;
10 |
11 | public const int Quadruple = Single * 4;
12 | }
--------------------------------------------------------------------------------
/tests/GraphQLToKarate.Integration.Api/Types/UpdateUserInput.cs:
--------------------------------------------------------------------------------
1 | namespace GraphQLToKarate.Integration.Api.Types;
2 |
3 | public sealed class UpdateUserInput
4 | {
5 | public required string Id { get; init; }
6 |
7 | public required string Name { get; init; }
8 |
9 | public required UserRole Role { get; init; }
10 | }
--------------------------------------------------------------------------------
/src/GraphQLToKarate.Library/Types/KarateTypeBase.cs:
--------------------------------------------------------------------------------
1 | namespace GraphQLToKarate.Library.Types;
2 |
3 | ///
4 | /// Represents an abstract Karate schema type.
5 | ///
6 | public abstract class KarateTypeBase
7 | {
8 | public abstract string Name { get; }
9 |
10 | public abstract string Schema { get; }
11 | }
12 |
--------------------------------------------------------------------------------
/tests/GraphQLToKarate.Integration.Api/Types/CreateBlogPostInput.cs:
--------------------------------------------------------------------------------
1 | namespace GraphQLToKarate.Integration.Api.Types;
2 |
3 | public class CreateBlogPostInput
4 | {
5 | public required string Title { get; init; }
6 |
7 | public required string Content { get; init; }
8 |
9 | public required CreateUserInput? Author { get; init; }
10 | }
--------------------------------------------------------------------------------
/tests/GraphQLToKarate.Tests/Mocks/UnsupportedGraphQLType.cs:
--------------------------------------------------------------------------------
1 | using GraphQLParser.AST;
2 | using System.Diagnostics.CodeAnalysis;
3 |
4 | namespace GraphQLToKarate.Tests.Mocks;
5 |
6 | [ExcludeFromCodeCoverage]
7 | internal sealed class UnsupportedGraphQLType : GraphQLType
8 | {
9 | public override ASTNodeKind Kind => ASTNodeKind.Alias;
10 | }
--------------------------------------------------------------------------------
/stylecop.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json",
3 | "settings": {
4 | "orderingRules": {
5 | "systemUsingDirectivesFirst": false,
6 | "usingDirectivesPlacement": "outsideNamespace"
7 | }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/GraphQLToKarate.Library/Types/GraphQLArgumentTypeBase.cs:
--------------------------------------------------------------------------------
1 | namespace GraphQLToKarate.Library.Types;
2 |
3 | public abstract class GraphQLArgumentTypeBase
4 | {
5 | public abstract string ArgumentName { get; }
6 |
7 | public abstract string VariableName { get; }
8 |
9 | public abstract string VariableTypeName { get; }
10 |
11 | public abstract string ExampleValue { get; }
12 | }
--------------------------------------------------------------------------------
/tests/GraphQLToKarate.Integration.Api/Types/CreateUserInput.cs:
--------------------------------------------------------------------------------
1 | namespace GraphQLToKarate.Integration.Api.Types;
2 |
3 | public sealed class CreateUserInput
4 | {
5 | public required string Name { get; init; }
6 |
7 | public required string Password { get; init; }
8 |
9 | public required UserRole Role { get; init; }
10 |
11 | public required CreateBlogPostInput BlogPost { get; init; }
12 | }
--------------------------------------------------------------------------------
/src/GraphQLToKarate.Library/Settings/KarateFeatureBuilderSettings.cs:
--------------------------------------------------------------------------------
1 | using System.Diagnostics.CodeAnalysis;
2 |
3 | namespace GraphQLToKarate.Library.Settings;
4 |
5 | [ExcludeFromCodeCoverage]
6 | public sealed class KarateFeatureBuilderSettings
7 | {
8 | public bool ExcludeQueries { get; init; } = false;
9 |
10 | public string BaseUrl { get; init; } = "\"https://www.my-awesome-api.com/graphql\"";
11 | }
--------------------------------------------------------------------------------
/src/GraphQLToKarate.Library/Types/KarateType.cs:
--------------------------------------------------------------------------------
1 | namespace GraphQLToKarate.Library.Types;
2 |
3 | ///
4 | /// Represents a Karate schema type with on information about nullability, non-nullability, or list-ness.
5 | ///
6 | internal sealed class KarateType(string schema, string name) : KarateTypeBase
7 | {
8 | public override string Name { get; } = name;
9 |
10 | public override string Schema { get; } = schema;
11 | }
12 |
--------------------------------------------------------------------------------
/tests/GraphQLToKarate.Integration.Api/Types/Comment.cs:
--------------------------------------------------------------------------------
1 | namespace GraphQLToKarate.Integration.Api.Types;
2 |
3 | public sealed class Comment : Node, ISearchResult
4 | {
5 | public required string Content { get; init; }
6 |
7 | public required User Author { get; init; }
8 |
9 | public required BlogPost BlogPost { get; init; }
10 |
11 | public required DateTime CreatedAt { get; init; }
12 |
13 | public required DateTime UpdatedAt { get; init; }
14 | }
--------------------------------------------------------------------------------
/src/GraphQLToKarate.Library/Types/KarateListType.cs:
--------------------------------------------------------------------------------
1 | using GraphQLToKarate.Library.Tokens;
2 |
3 | namespace GraphQLToKarate.Library.Types;
4 |
5 | ///
6 | /// Represents a list Karate schema type.
7 | ///
8 | internal sealed class KarateListType(KarateTypeBase innerType) : KarateTypeBase
9 | {
10 | public override string Name => innerType.Name;
11 |
12 | public override string Schema => $"{KarateToken.Array} {innerType.Schema}";
13 | }
14 |
--------------------------------------------------------------------------------
/src/GraphQLToKarate.Library/Types/KarateNullType.cs:
--------------------------------------------------------------------------------
1 | using GraphQLToKarate.Library.Tokens;
2 |
3 | namespace GraphQLToKarate.Library.Types;
4 |
5 | ///
6 | /// Represents a nullable Karate schema type.
7 | ///
8 | internal sealed class KarateNullType(KarateTypeBase innerType) : KarateTypeBase
9 | {
10 | public override string Name => innerType.Name;
11 |
12 | public override string Schema => $"{KarateToken.Null}{innerType.Schema}";
13 | }
14 |
--------------------------------------------------------------------------------
/tests/GraphQLToKarate.Integration.Api/Types/User.cs:
--------------------------------------------------------------------------------
1 | namespace GraphQLToKarate.Integration.Api.Types;
2 |
3 | public sealed class User : Node, ISearchResult
4 | {
5 | public required string Name { get; init; }
6 |
7 | public required UserRole Role { get; init; }
8 |
9 | public required IEnumerable BlogPosts { get; init; }
10 |
11 | public required DateTime CreatedAt { get; init; }
12 |
13 | public required DateTime UpdatedAt { get; init; }
14 | }
--------------------------------------------------------------------------------
/src/GraphQLToKarate.Library/Types/KarateNonNullType.cs:
--------------------------------------------------------------------------------
1 | using GraphQLToKarate.Library.Tokens;
2 |
3 | namespace GraphQLToKarate.Library.Types;
4 |
5 | ///
6 | /// Represents a non-nullable Karate schema type.
7 | ///
8 | internal sealed class KarateNonNullType(KarateTypeBase innerType) : KarateTypeBase
9 | {
10 | public override string Name => innerType.Name;
11 |
12 | public override string Schema => $"{KarateToken.NonNull}{innerType.Schema}";
13 | }
14 |
--------------------------------------------------------------------------------
/src/GraphQLToKarate.Library/Parsers/GraphQLSchemaParser.cs:
--------------------------------------------------------------------------------
1 | using GraphQLParser;
2 | using GraphQLParser.AST;
3 | using System.Diagnostics.CodeAnalysis;
4 |
5 | namespace GraphQLToKarate.Library.Parsers;
6 |
7 | ///
8 | [ExcludeFromCodeCoverage(Justification = "Just a wrapper to enable dependency injection.")]
9 | public sealed class GraphQLSchemaParser : IGraphQLSchemaParser
10 | {
11 | public GraphQLDocument Parse(string source) => Parser.Parse(source);
12 | }
--------------------------------------------------------------------------------
/src/GraphQLToKarate.CommandLine/Settings/LogCommandSettings.cs:
--------------------------------------------------------------------------------
1 | using Serilog.Events;
2 | using Spectre.Console.Cli;
3 | using System.ComponentModel;
4 |
5 | namespace GraphQLToKarate.CommandLine.Settings;
6 |
7 | internal class LogCommandSettings : CommandSettings
8 | {
9 | [CommandOption("--log-level")]
10 | [Description("Minimum level for logging")]
11 | [TypeConverter(typeof(LogLevelVerbosityConverter))]
12 | [DefaultValue(LogEventLevel.Information)]
13 | public LogEventLevel LogLevel { get; set; }
14 | }
--------------------------------------------------------------------------------
/tests/GraphQLToKarate.Integration.Api/Types/BlogPost.cs:
--------------------------------------------------------------------------------
1 | namespace GraphQLToKarate.Integration.Api.Types;
2 |
3 | public sealed class BlogPost : Node, ISearchResult
4 | {
5 | public required string Title { get; init; }
6 |
7 | public required string Content { get; init; }
8 |
9 | public required User Author { get; init; }
10 |
11 | public required IEnumerable Comments { get; init; }
12 |
13 | public required DateTime CreatedAt { get; init; }
14 |
15 | public required DateTime UpdatedAt { get; init; }
16 | }
--------------------------------------------------------------------------------
/.github/workflows/approve.yml:
--------------------------------------------------------------------------------
1 | name: Auto-Approve Renovate
2 | on:
3 | pull_request:
4 | branches: [ main ]
5 |
6 | permissions:
7 | pull-requests: write
8 |
9 | jobs:
10 | approve:
11 | runs-on: ubuntu-latest
12 |
13 | if: ${{ github.actor == 'renovate[bot]' }}
14 | steps:
15 | - name: ✅ Approve Renovate Pull Request
16 | run: gh pr review --approve "$PR_URL"
17 | env:
18 | PR_URL: ${{ github.event.pull_request.html_url }}
19 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
20 |
--------------------------------------------------------------------------------
/src/GraphQLToKarate.Library/Converters/IGraphQLToKarateConverter.cs:
--------------------------------------------------------------------------------
1 | namespace GraphQLToKarate.Library.Converters;
2 |
3 | ///
4 | /// Converts GraphQL schemas to Karate features.
5 | ///
6 | public interface IGraphQLToKarateConverter
7 | {
8 | ///
9 | /// Converts the given GraphQL to a Karate feature.
10 | ///
11 | /// The source GraphQL schema to convert.
12 | /// The converted Karate feature.
13 | string Convert(string schema);
14 | }
--------------------------------------------------------------------------------
/resources/configuration.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://raw.githubusercontent.com/wbaldoumas/graphql-to-karate/main/configuration/schema/v1/schema.json",
3 | "outputFile": "blog.feature",
4 | "baseUrl": "\"http://localhost:9001\"",
5 | "excludeQueries": false,
6 | "includeMutations": true,
7 | "queryName": "Query",
8 | "mutationName": "Mutation",
9 | "typeFilter": [],
10 | "queryOperationFilter": [],
11 | "mutationOperationFilter": [],
12 | "customScalarMapping": {
13 | "DateTime": "string",
14 | "URL": "string"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/GraphQLToKarate.CommandLine/Infrastructure/TypeResolver.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.Hosting;
2 | using Spectre.Console.Cli;
3 |
4 | namespace GraphQLToKarate.CommandLine.Infrastructure;
5 |
6 | ///
7 | internal sealed class TypeResolver(IHost? host) : ITypeResolver, IDisposable
8 | {
9 | private readonly IHost _host = host ?? throw new ArgumentNullException(nameof(host));
10 |
11 | public object? Resolve(Type? serviceType) => serviceType is not null ? _host.Services.GetService(serviceType) : null;
12 |
13 | public void Dispose() => _host.Dispose();
14 | }
--------------------------------------------------------------------------------
/src/GraphQLToKarate.Library/Types/GraphQLArgumentType.cs:
--------------------------------------------------------------------------------
1 | namespace GraphQLToKarate.Library.Types;
2 |
3 | public sealed class GraphQLArgumentType(
4 | string argumentName,
5 | string variableName,
6 | string variableTypeName,
7 | string exampleValue)
8 | : GraphQLArgumentTypeBase
9 | {
10 | public override string ArgumentName { get; } = argumentName;
11 |
12 | public override string VariableName { get; } = variableName;
13 |
14 | public override string VariableTypeName { get; } = variableTypeName;
15 |
16 | public override string ExampleValue { get; } = exampleValue;
17 | }
--------------------------------------------------------------------------------
/src/GraphQLToKarate.Library/Types/GraphQLNonNullArgumentType.cs:
--------------------------------------------------------------------------------
1 | using GraphQLToKarate.Library.Tokens;
2 |
3 | namespace GraphQLToKarate.Library.Types;
4 |
5 | internal sealed class GraphQLNonNullArgumentType(GraphQLArgumentTypeBase innerType) : GraphQLArgumentTypeBase
6 | {
7 | public override string ArgumentName => innerType.ArgumentName;
8 |
9 | public override string VariableName => innerType.VariableName;
10 |
11 | public override string VariableTypeName => $"{innerType.VariableTypeName}{GraphQLToken.NonNull}";
12 |
13 | public override string ExampleValue => innerType.ExampleValue;
14 | }
--------------------------------------------------------------------------------
/src/GraphQLToKarate.Library/Builders/IConfiguredGraphQLToKarateConverterBuilder.cs:
--------------------------------------------------------------------------------
1 | using GraphQLToKarate.Library.Converters;
2 |
3 | namespace GraphQLToKarate.Library.Builders;
4 |
5 | ///
6 | /// A fully configured .
7 | ///
8 | public interface IConfiguredGraphQLToKarateConverterBuilder
9 | {
10 | ///
11 | /// Build the configured .
12 | ///
13 | /// The configured .
14 | IGraphQLToKarateConverter Build();
15 | }
--------------------------------------------------------------------------------
/src/GraphQLToKarate.Library/Converters/IGraphQLInputValueDefinitionConverterFactory.cs:
--------------------------------------------------------------------------------
1 | namespace GraphQLToKarate.Library.Converters;
2 |
3 | ///
4 | /// A factory for creating instances of .
5 | ///
6 | public interface IGraphQLInputValueDefinitionConverterFactory
7 | {
8 | ///
9 | /// Creates a new .
10 | ///
11 | /// The newly created .
12 | IGraphQLInputValueDefinitionConverter Create();
13 | }
--------------------------------------------------------------------------------
/src/GraphQLToKarate.Library/Types/GraphQLListArgumentType.cs:
--------------------------------------------------------------------------------
1 | using GraphQLToKarate.Library.Tokens;
2 |
3 | namespace GraphQLToKarate.Library.Types;
4 |
5 | internal sealed class GraphQLListArgumentType(GraphQLArgumentTypeBase innerType) : GraphQLArgumentTypeBase
6 | {
7 | public override string ArgumentName => innerType.ArgumentName;
8 |
9 | public override string VariableName => innerType.VariableName;
10 |
11 | public override string VariableTypeName => $"{SchemaToken.OpenBracket}{innerType.VariableTypeName}{SchemaToken.CloseBracket}";
12 |
13 | public override string ExampleValue => innerType.ExampleValue;
14 | }
--------------------------------------------------------------------------------
/src/GraphQLToKarate.Library/Converters/GraphQLInputValueDefinitionConverterFactory.cs:
--------------------------------------------------------------------------------
1 | using System.Diagnostics.CodeAnalysis;
2 |
3 | namespace GraphQLToKarate.Library.Converters;
4 |
5 | ///
6 | [ExcludeFromCodeCoverage]
7 | public sealed class GraphQLInputValueDefinitionConverterFactory(IGraphQLInputValueToExampleValueConverter graphQLInputValueToExampleValue) : IGraphQLInputValueDefinitionConverterFactory
8 | {
9 | public IGraphQLInputValueDefinitionConverter Create() => new GraphQLInputValueDefinitionConverter(
10 | graphQLInputValueToExampleValue
11 | );
12 | }
--------------------------------------------------------------------------------
/src/GraphQLToKarate.Library/Apollo/Directives.cs:
--------------------------------------------------------------------------------
1 | using System.Diagnostics.CodeAnalysis;
2 |
3 | namespace GraphQLToKarate.Library.Apollo;
4 |
5 | ///
6 | /// Directives used by the Apollo Federation specification. Currently, the only ones that
7 | /// matter within the context of this library are and ,
8 | /// since they should be ignored when generating Karate tests.
9 | ///
10 | [ExcludeFromCodeCoverage]
11 | internal static class Directives
12 | {
13 | public const string External = "external";
14 | public const string Inaccessible = "inaccessible";
15 | }
--------------------------------------------------------------------------------
/src/GraphQLToKarate.Library/Parsers/IGraphQLSchemaParser.cs:
--------------------------------------------------------------------------------
1 | using GraphQLParser.AST;
2 |
3 | namespace GraphQLToKarate.Library.Parsers;
4 |
5 | ///
6 | /// Parses a GraphQL schema source string into a .
7 | ///
8 | public interface IGraphQLSchemaParser
9 | {
10 | ///
11 | /// Generates an AST based on the schema.
12 | ///
13 | /// Input data as a sequence of characters.
14 | /// An AST (Abstract Syntax Tree) for GraphQL document.
15 | GraphQLDocument Parse(string source);
16 | }
--------------------------------------------------------------------------------
/src/GraphQLToKarate.Library/Extensions/HasArgumentsDefinitionNodeExtensions.cs:
--------------------------------------------------------------------------------
1 | using GraphQLParser.AST;
2 |
3 | namespace GraphQLToKarate.Library.Extensions;
4 |
5 | internal static class HasArgumentsDefinitionNodeExtensions
6 | {
7 | ///
8 | /// Returns whether the has arguments or not.
9 | ///
10 | /// The source node to check.
11 | /// Whether the actually has arguments.
12 | public static bool HasArguments(this IHasArgumentsDefinitionNode source) => source.Arguments?.Any() ?? false;
13 | }
--------------------------------------------------------------------------------
/src/GraphQLToKarate.Library/Extensions/StringBuilderExtensions.cs:
--------------------------------------------------------------------------------
1 | using System.Text;
2 |
3 | namespace GraphQLToKarate.Library.Extensions;
4 |
5 | internal static class StringBuilderExtensions
6 | {
7 | ///
8 | /// Trims the last characters from the end of the .
9 | ///
10 | /// The to manipulate.
11 | /// The count of characters to trim from the end of the .
12 | public static void TrimEnd(this StringBuilder source, int count) => source.Remove(source.Length - count, count);
13 | }
--------------------------------------------------------------------------------
/src/GraphQLToKarate.Library/Converters/IGraphQLTypeConverterFactory.cs:
--------------------------------------------------------------------------------
1 | using GraphQLParser.AST;
2 |
3 | namespace GraphQLToKarate.Library.Converters;
4 |
5 | ///
6 | /// Used to create various implementations.
7 | ///
8 | public interface IGraphQLTypeConverterFactory
9 | {
10 | IGraphQLTypeConverter CreateGraphQLTypeConverter();
11 |
12 | IGraphQLTypeConverter CreateGraphQLListTypeConverter();
13 |
14 | IGraphQLTypeConverter CreateGraphQLNonNullTypeConverter();
15 |
16 | IGraphQLTypeConverter CreateGraphQLNullTypeConverter();
17 |
18 | IGraphQLTypeConverter CreateGraphQLTypeConverter(GraphQLType graphQLType);
19 | }
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/FEATURE_REQUEST.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature Request
3 | about: Suggest a feature for this project
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | ## Problem Statement
11 |
12 | Please describe the problem to be addressed by the proposed feature.
13 |
14 | ## Proposed Solution
15 |
16 | Please describe what you envision the solution to this problem would look like.
17 |
18 | ## Alternatives Considered
19 |
20 | Please briefly describe which alternatives, if any, have been considered, including merits of alternate approaches and
21 | tradeoffs being made.
22 |
23 | ## Additional Context
24 |
25 | Please provide any other information that may be relevant.
26 |
--------------------------------------------------------------------------------
/src/GraphQLToKarate.Library/Builders/IGraphQLToKarateConverterBuilder.cs:
--------------------------------------------------------------------------------
1 | using GraphQLToKarate.Library.Converters;
2 |
3 | namespace GraphQLToKarate.Library.Builders;
4 |
5 | ///
6 | /// A builder which can create a configured .
7 | ///
8 | public interface IGraphQLToKarateConverterBuilder
9 | {
10 | ///
11 | /// Begin configuring a new .
12 | ///
13 | /// A to configure the with.
14 | IConfigurableGraphQLToKarateConverterBuilder Configure();
15 | }
--------------------------------------------------------------------------------
/src/GraphQLToKarate.Library/Tokens/GraphQLToken.cs:
--------------------------------------------------------------------------------
1 | using System.Diagnostics.CodeAnalysis;
2 |
3 | namespace GraphQLToKarate.Library.Tokens;
4 |
5 | ///
6 | /// Contains tokens for each of the available GraphQL types.
7 | ///
8 | [ExcludeFromCodeCoverage]
9 | public static class GraphQLToken
10 | {
11 | public const string Id = "ID";
12 |
13 | public const string String = "String";
14 |
15 | public const string Int = "Int";
16 |
17 | public const string Float = "Float";
18 |
19 | public const string Boolean = "Boolean";
20 |
21 | public const string Query = "Query";
22 |
23 | public const string Mutation = "Mutation";
24 |
25 | public const char NonNull = '!';
26 | }
--------------------------------------------------------------------------------
/src/GraphQLToKarate.CommandLine/Exceptions/GraphQLToKarateConfigurationException.cs:
--------------------------------------------------------------------------------
1 | using System.Diagnostics.CodeAnalysis;
2 |
3 | namespace GraphQLToKarate.CommandLine.Exceptions;
4 |
5 | [Serializable]
6 | [ExcludeFromCodeCoverage]
7 | internal sealed class GraphQLToKarateConfigurationException : Exception
8 | {
9 | public const string DefaultMessage = "Failed to load configuration from file!";
10 |
11 | public GraphQLToKarateConfigurationException() { }
12 |
13 | public GraphQLToKarateConfigurationException(string? message)
14 | : base(message) { }
15 |
16 | public GraphQLToKarateConfigurationException(string? message, Exception? innerException)
17 | : base(message, innerException) { }
18 | }
--------------------------------------------------------------------------------
/src/GraphQLToKarate.Library/Tokens/KarateToken.cs:
--------------------------------------------------------------------------------
1 | using System.Diagnostics.CodeAnalysis;
2 |
3 | namespace GraphQLToKarate.Library.Tokens;
4 |
5 | ///
6 | /// Contains tokens for each of the available Karate types.
7 | ///
8 | [ExcludeFromCodeCoverage]
9 | internal static class KarateToken
10 | {
11 | public const string String = "string";
12 |
13 | public const string Number = "number";
14 |
15 | public const string Boolean = "boolean";
16 |
17 | public const string Object = "object";
18 |
19 | public const string Present = "present";
20 |
21 | public const string Null = "##";
22 |
23 | public const string NonNull = "#";
24 |
25 | public const string Array = "[]";
26 | }
--------------------------------------------------------------------------------
/src/GraphQLToKarate.CommandLine/Settings/IConvertCommandSettingsLoader.cs:
--------------------------------------------------------------------------------
1 | namespace GraphQLToKarate.CommandLine.Settings;
2 |
3 | ///
4 | /// Loads GraphQL-to-Karate data from a given .
5 | ///
6 | internal interface IConvertCommandSettingsLoader
7 | {
8 | ///
9 | /// Load the GraphQL-to-Karate data to convert from the given .
10 | ///
11 | /// The settings to load data into the application with.
12 | /// The loaded settings data.
13 | Task LoadAsync(ConvertCommandSettings convertCommandSettings);
14 | }
--------------------------------------------------------------------------------
/src/GraphQLToKarate.Library/Mappings/ICustomScalarMappingValidator.cs:
--------------------------------------------------------------------------------
1 | namespace GraphQLToKarate.Library.Mappings;
2 |
3 | ///
4 | /// Can validate whether a custom scalar mapping is loadable from a file or text.
5 | ///
6 | public interface ICustomScalarMappingValidator
7 | {
8 | ///
9 | /// Returns whether the custom scalar mapping source (file path or raw text) is valid.
10 | ///
11 | /// The custom scalar mapping source (file path or raw text) to check.
12 | /// Whether or not the custom scalar mapping source (file path or raw text) is valid.
13 | bool IsValid(string? customScalarMappingSource);
14 | }
--------------------------------------------------------------------------------
/tests/GraphQLToKarate.Integration.Api/Program.cs:
--------------------------------------------------------------------------------
1 | using GraphQLToKarate.Integration.Api.Types;
2 |
3 | var builder = WebApplication.CreateBuilder(args);
4 |
5 | builder.Services
6 | .AddGraphQLServer()
7 | .AddType()
8 | .AddQueryType()
9 | .AddMutationType()
10 | .AddType()
11 | .AddType()
12 | .AddType()
13 | .AddType()
14 | .AddType()
15 | .AddType()
16 | .AddType()
17 | .AddType()
18 | .AddType()
19 | .AddTypeExtension();
20 |
21 | var app = builder.Build();
22 |
23 | app.UseHttpsRedirection();
24 |
25 | app.MapGraphQL();
26 |
27 | app.Run();
--------------------------------------------------------------------------------
/src/GraphQLToKarate.CommandLine/Infrastructure/TypeRegistrarConfigurator.cs:
--------------------------------------------------------------------------------
1 | using Spectre.Console.Cli;
2 |
3 | namespace GraphQLToKarate.CommandLine.Infrastructure;
4 |
5 | ///
6 | /// Configures the type registrar with the configured host builder.
7 | ///
8 | internal static class TypeRegistrarConfigurator
9 | {
10 | ///
11 | /// Configures the type registrar with the configured host builder.
12 | ///
13 | /// The command line arguments.
14 | /// The configured type registrar.
15 | public static ITypeRegistrar ConfigureTypeRegistrar(string[]? args) => new TypeRegistrar(
16 | HostConfigurator.ConfigureHostBuilder(args)
17 | );
18 | }
--------------------------------------------------------------------------------
/src/GraphQLToKarate.Library/Tokens/SchemaToken.cs:
--------------------------------------------------------------------------------
1 | namespace GraphQLToKarate.Library.Tokens;
2 |
3 | ///
4 | /// Tokens for use with schema generation.
5 | ///
6 | internal static class SchemaToken
7 | {
8 | public const char OpenBrace = '{';
9 |
10 | public const char CloseBrace = '}';
11 |
12 | public const char Space = ' ';
13 |
14 | public const char Comma = ',';
15 |
16 | public const string Indent = " ";
17 |
18 | public const char OpenBracket = '[';
19 |
20 | public const char CloseBracket = ']';
21 |
22 | public const char OpenParen = '(';
23 |
24 | public const char CloseParen = ')';
25 |
26 | public const string TripleQuote = "\"\"\"";
27 |
28 | public const char Colon = ':';
29 | }
--------------------------------------------------------------------------------
/src/GraphQLToKarate.Library/Exceptions/InvalidGraphQLTypeException.cs:
--------------------------------------------------------------------------------
1 | using System.Diagnostics.CodeAnalysis;
2 |
3 | namespace GraphQLToKarate.Library.Exceptions;
4 |
5 | ///
6 | /// An exception to be thrown when an invalid GraphQL type is encountered.
7 | ///
8 | [ExcludeFromCodeCoverage(Justification = $"This is just a simple exception inheriting from the base {nameof(Exception)} class.")]
9 | public sealed class InvalidGraphQLTypeException : Exception
10 | {
11 | public InvalidGraphQLTypeException() { }
12 |
13 | public InvalidGraphQLTypeException(string? message)
14 | : base(message) { }
15 |
16 | public InvalidGraphQLTypeException(string? message, Exception? innerException)
17 | : base(message, innerException) { }
18 | }
--------------------------------------------------------------------------------
/src/GraphQLToKarate.Library/Mappings/ICustomScalarMappingLoader.cs:
--------------------------------------------------------------------------------
1 | namespace GraphQLToKarate.Library.Mappings;
2 |
3 | ///
4 | /// A class which can load custom scalar mappings, mapping custom scalar
5 | /// GraphQL types to their Karate equivalents.
6 | ///
7 | public interface ICustomScalarMappingLoader : ICustomScalarMappingValidator
8 | {
9 | ///
10 | /// Load the custom scalar mapping from the given source (file path or raw text).
11 | ///
12 | /// The custom scalar mapping source (file path or raw text) to load the custom scalar mapping from.
13 | /// The custom scalar mapping.
14 | Task LoadAsync(string? customScalarMappingSource);
15 | }
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/BUG_REPORT.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug Report
3 | about: Report a bug to help us improve
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | ## Description
11 |
12 | Please provide a description of the problem.
13 |
14 | ## Expected Behaviour
15 |
16 | Please describe what you expected would happen.
17 |
18 | ## Actual Behaviour
19 |
20 | Please describe what happened instead.
21 |
22 | ## Affected Version
23 |
24 | Please provide the version number where this issue was encountered.
25 |
26 | ## Steps to Reproduce
27 |
28 | 1. First step
29 | 1. Second step
30 | 1. etc.
31 |
32 | ## Checklist
33 |
34 | - [ ] I have read the [contributing guidelines](https://github.com/wbaldoumas/graphql-to-karate/blob/main/CONTRIBUTING.md)
35 | - [ ] I have verified this does not duplicate an existing issue
36 |
--------------------------------------------------------------------------------
/tests/GraphQLToKarate.Integration.Api/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://json.schemastore.org/launchsettings.json",
3 | "profiles": {
4 | "http": {
5 | "commandName": "Project",
6 | "launchBrowser": true,
7 | "launchUrl": "graphql",
8 | "environmentVariables": {
9 | "ASPNETCORE_ENVIRONMENT": "Development"
10 | },
11 | "dotnetRunMessages": true,
12 | "applicationUrl": "http://localhost:9001"
13 | },
14 | "https": {
15 | "commandName": "Project",
16 | "launchBrowser": true,
17 | "launchUrl": "graphql",
18 | "environmentVariables": {
19 | "ASPNETCORE_ENVIRONMENT": "Development"
20 | },
21 | "dotnetRunMessages": true,
22 | "applicationUrl": "https://localhost:7134;http://localhost:9001"
23 | }
24 | }
25 | }
--------------------------------------------------------------------------------
/scripts/extract_changelog.py:
--------------------------------------------------------------------------------
1 | import sys
2 |
3 | def main(changelog_file, output_file):
4 | with open(changelog_file, "r") as file:
5 | content = file.read()
6 |
7 | # Split the content by release sections
8 | sections = content.split("\n## ")
9 | latest_release = sections[1].strip()
10 |
11 | # Add the correct header values to the first line
12 | first_line, rest = latest_release.split("\n", 1)
13 | formatted_first_line = f"## {first_line}\n"
14 |
15 | # Combine the formatted first line and the rest of the release notes
16 | formatted_latest_release = formatted_first_line + rest
17 |
18 | # Write the latest release to a markdown file
19 | with open(output_file, "w") as file:
20 | file.write(formatted_latest_release)
21 |
22 | if __name__ == "__main__":
23 | main(sys.argv[1], sys.argv[2])
24 |
--------------------------------------------------------------------------------
/src/GraphQLToKarate.Library/Features/IKarateScenarioBuilder.cs:
--------------------------------------------------------------------------------
1 | using GraphQLToKarate.Library.Adapters;
2 | using GraphQLToKarate.Library.Types;
3 |
4 | namespace GraphQLToKarate.Library.Features;
5 |
6 | ///
7 | /// Builds a Karate API testing scenario in string format.
8 | ///
9 | public interface IKarateScenarioBuilder
10 | {
11 | ///
12 | /// Build a Karate API testing scenario in string format.
13 | ///
14 | /// The GraphQL query field type to build a Karate scenario for.
15 | /// The GraphQL document adapter to use.
16 | /// A Karate API testing scenario in string format.
17 | string Build(GraphQLOperation graphQLOperation, IGraphQLDocumentAdapter graphQLDocumentAdapter);
18 | }
--------------------------------------------------------------------------------
/src/GraphQLToKarate.CommandLine/Infrastructure/CompositionRoot.cs:
--------------------------------------------------------------------------------
1 | global using GraphQLToKarate.CommandLine.Infrastructure;
2 | using Spectre.Console.Cli;
3 | using System.Diagnostics.CodeAnalysis;
4 |
5 | namespace GraphQLToKarate.CommandLine.Infrastructure;
6 |
7 | ///
8 | /// Configures the command app.
9 | ///
10 | [ExcludeFromCodeCoverage(Justification = "Just abstraction and orchestration of app bootstrapping...")]
11 | internal static class CompositionRoot
12 | {
13 | ///
14 | /// Builds the command app.
15 | ///
16 | /// The command line arguments.
17 | /// The command app.
18 | public static CommandApp Build(string[]? args) => CommandAppConfigurator.ConfigureCommandApp(
19 | TypeRegistrarConfigurator.ConfigureTypeRegistrar(args)
20 | );
21 | }
--------------------------------------------------------------------------------
/tests/GraphQLToKarate.Integration.Api/Types/Mutation.cs:
--------------------------------------------------------------------------------
1 | namespace GraphQLToKarate.Integration.Api.Types;
2 |
3 | public sealed class Mutation
4 | {
5 | public User CreateUser(CreateUserInput input) => new()
6 | {
7 | Id = Guid.NewGuid().ToString(),
8 | Name = input.Name,
9 | Role = input.Role,
10 | BlogPosts = new List(),
11 | CreatedAt = DateTime.UtcNow,
12 | UpdatedAt = DateTime.UtcNow,
13 | };
14 |
15 | public User UpdateUser(UpdateUserInput input) => new()
16 | {
17 | Id = input.Id,
18 | Name = input.Name,
19 | Role = input.Role,
20 | BlogPosts = new List(),
21 | CreatedAt = DateTime.UtcNow,
22 | UpdatedAt = DateTime.UtcNow,
23 | };
24 |
25 | public bool DeleteUser([GraphQLType(typeof(IdType))][GraphQLNonNullType] string id) => true;
26 | }
--------------------------------------------------------------------------------
/src/GraphQLToKarate.CommandLine/Mappers/IGraphQLToKarateUserConfigurationMapper.cs:
--------------------------------------------------------------------------------
1 | using GraphQLToKarate.CommandLine.Settings;
2 |
3 | namespace GraphQLToKarate.CommandLine.Mappers;
4 |
5 | ///
6 | /// A mapper that maps a to a .
7 | ///
8 | internal interface IGraphQLToKarateUserConfigurationMapper
9 | {
10 | ///
11 | /// Maps a to a .
12 | ///
13 | /// The to map.
14 | /// A .
15 | LoadedConvertCommandSettings Map(GraphQLToKarateUserConfiguration graphQLToKarateUserConfiguration);
16 | }
--------------------------------------------------------------------------------
/.github/workflows/stale.yml:
--------------------------------------------------------------------------------
1 | name: Identify and close stale issues and pull requests
2 |
3 | on:
4 | schedule:
5 | - cron: "0 0 * * 0"
6 |
7 | jobs:
8 | stale:
9 | runs-on: ubuntu-latest
10 | permissions:
11 | issues: write
12 | pull-requests: write
13 |
14 | steps:
15 | - uses: actions/stale@v10
16 | with:
17 | repo-token: ${{ secrets.GITHUB_TOKEN }}
18 | days-before-stale: 30
19 | stale-issue-label: 'stale'
20 | stale-pr-label: 'stale'
21 | stale-issue-message: 'Automatically marking issue as stale due to lack of activity'
22 | stale-pr-message: 'Automatically marking pull request as stale due to lack of activity'
23 | days-before-close: 10
24 | close-issue-message: 'Automatically closing this issue as stale'
25 | close-pr-message: 'Automatically closing this pull request as stale'
26 |
--------------------------------------------------------------------------------
/src/GraphQLToKarate.Library/Converters/IGraphQLCyclicToAcyclicConverter.cs:
--------------------------------------------------------------------------------
1 | using GraphQLParser.AST;
2 | using GraphQLToKarate.Library.Adapters;
3 |
4 | namespace GraphQLToKarate.Library.Converters;
5 |
6 | ///
7 | /// Removes cycles from GraphQL field definitions.
8 | ///
9 | public interface IGraphQLCyclicToAcyclicConverter
10 | {
11 | ///
12 | /// Removes cycles from the given .
13 | ///
14 | /// The field definition to remove cycles from.
15 | /// The GraphQL document adapter, providing access to user-defined types within the GraphQL document.
16 | void Convert(
17 | GraphQLFieldDefinition graphQLFieldDefinition,
18 | IGraphQLDocumentAdapter graphQLDocumentAdapter
19 | );
20 | }
--------------------------------------------------------------------------------
/.github/workflows/lint.yml:
--------------------------------------------------------------------------------
1 | name: Lint
2 |
3 | on:
4 | push:
5 | branches: [main]
6 | pull_request:
7 | branches: [main]
8 |
9 | jobs:
10 | markdown:
11 | runs-on: ubuntu-latest
12 | steps:
13 | - uses: actions/checkout@v6
14 | - name: 🧼 lint markdown files
15 | uses: avto-dev/markdown-lint@v1
16 | with:
17 | config: ".markdownlint.json"
18 | args: "**/*.md .github/**/*.md"
19 |
20 | json:
21 | runs-on: ubuntu-latest
22 | steps:
23 | - uses: actions/checkout@v6
24 | - name: 🧼 lint json files
25 | uses: ocular-d/json-linter@0.0.2
26 |
27 | renovate:
28 | runs-on: ubuntu-latest
29 | steps:
30 | - uses: actions/checkout@v6
31 | - name: 🧼 lint renovate config
32 | uses: suzuki-shunsuke/github-action-renovate-config-validator@v1.1.1
33 | with:
34 | config_file_path: "renovate.json"
35 |
--------------------------------------------------------------------------------
/src/GraphQLToKarate.Library/Settings/GraphQLToKarateSettings.cs:
--------------------------------------------------------------------------------
1 | using GraphQLToKarate.Library.Tokens;
2 | using System.Diagnostics.CodeAnalysis;
3 |
4 | namespace GraphQLToKarate.Library.Settings;
5 |
6 | [ExcludeFromCodeCoverage]
7 | public sealed class GraphQLToKarateSettings
8 | {
9 | public bool ExcludeQueries { get; init; } = false;
10 |
11 | public bool IncludeMutations { get; init; } = false;
12 |
13 | public string QueryName { get; init; } = GraphQLToken.Query;
14 |
15 | public string MutationName { get; init; } = GraphQLToken.Mutation;
16 |
17 | public ISet TypeFilter { get; init; } = new HashSet(StringComparer.OrdinalIgnoreCase);
18 |
19 | public ISet QueryOperationFilter { get; init; } = new HashSet(StringComparer.OrdinalIgnoreCase);
20 |
21 | public ISet MutationOperationFilter { get; init; } = new HashSet(StringComparer.OrdinalIgnoreCase);
22 | }
--------------------------------------------------------------------------------
/src/GraphQLToKarate.CommandLine/Infrastructure/StringToSetConverter.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel;
2 | using System.Globalization;
3 |
4 | namespace GraphQLToKarate.CommandLine.Infrastructure;
5 |
6 | ///
7 | /// Converts a comma-separated string into an ISet of strings, trimming whitespace.
8 | ///
9 | internal sealed class StringToSetConverter : TypeConverter
10 | {
11 | public override object ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object value)
12 | {
13 | if (value is not string stringValue)
14 | {
15 | throw new NotSupportedException("Can't convert type filter value to type filter.");
16 | }
17 |
18 | return stringValue
19 | .Split(',')
20 | .Select(item => item.Trim())
21 | .Where(item => !string.IsNullOrEmpty(item))
22 | .ToHashSet(StringComparer.OrdinalIgnoreCase);
23 | }
24 | }
--------------------------------------------------------------------------------
/src/GraphQLToKarate.CommandLine/Prompts/IConvertCommandSettingsPrompt.cs:
--------------------------------------------------------------------------------
1 | using GraphQLToKarate.CommandLine.Settings;
2 |
3 | namespace GraphQLToKarate.CommandLine.Prompts;
4 |
5 | ///
6 | /// Prompt the user for settings in an interactive way.
7 | ///
8 | internal interface IConvertCommandSettingsPrompt
9 | {
10 | ///
11 | /// Prompt the user for settings in an interactive way.
12 | ///
13 | ///
14 | /// The initial settings to use as a starting point. This lets the user pass some initial options in the
15 | /// up-front command, which are then used as defaults when they are prompted interactively.
16 | ///
17 | /// The settings that the user has chosen.
18 | Task PromptAsync(LoadedConvertCommandSettings initialLoadedConvertCommandSettings);
19 | }
--------------------------------------------------------------------------------
/src/GraphQLToKarate.Library/Types/GraphQLOperation.cs:
--------------------------------------------------------------------------------
1 | using GraphQLParser.AST;
2 | using GraphQLToKarate.Library.Enums;
3 | using GraphQLToKarate.Library.Extensions;
4 |
5 | namespace GraphQLToKarate.Library.Types;
6 |
7 | public sealed class GraphQLOperation(GraphQLFieldDefinition graphQLFieldDefinition)
8 | {
9 | public string Name => graphQLFieldDefinition.NameValue();
10 |
11 | public string OperationName => $"{Name.FirstCharToUpper()}Test";
12 |
13 | public GraphQLType ReturnType => graphQLFieldDefinition.Type;
14 |
15 | public string ReturnTypeName => graphQLFieldDefinition.Type.GetUnwrappedTypeName();
16 |
17 | public bool IsListReturnType => graphQLFieldDefinition.Type.IsListType();
18 |
19 | public required string OperationString { get; init; }
20 |
21 | public required GraphQLOperationType Type { get; init; }
22 |
23 | public required ICollection Arguments { get; init; }
24 | }
25 |
--------------------------------------------------------------------------------
/tests/GraphQLToKarate.CommandLine.Tests/Infrastructure/TypeRegistrarConfiguratorTests.cs:
--------------------------------------------------------------------------------
1 | using FluentAssertions;
2 | using GraphQLToKarate.CommandLine.Infrastructure;
3 | using GraphQLToKarate.CommandLine.Settings;
4 | using NUnit.Framework;
5 |
6 | namespace GraphQLToKarate.CommandLine.Tests.Infrastructure;
7 |
8 | [TestFixture]
9 | internal sealed class TypeRegistrarConfiguratorTests
10 | {
11 | [Test]
12 | public void TypeRegistrarConfigurator_configures_expected_TypeRegistrar()
13 | {
14 | // arrange + act
15 | var typeRegistrar = TypeRegistrarConfigurator.ConfigureTypeRegistrar(Array.Empty());
16 | var typeResolver = typeRegistrar.Build();
17 |
18 | // assert
19 | typeResolver
20 | .Should()
21 | .NotBeNull();
22 |
23 | typeResolver
24 | .Resolve(typeof(ConvertCommandSettings))
25 | .Should()
26 | .BeOfType();
27 | }
28 | }
--------------------------------------------------------------------------------
/src/GraphQLToKarate.Library/Features/IKarateFeatureBuilder.cs:
--------------------------------------------------------------------------------
1 | using GraphQLToKarate.Library.Adapters;
2 | using GraphQLToKarate.Library.Types;
3 |
4 | namespace GraphQLToKarate.Library.Features;
5 |
6 | ///
7 | /// Builds a Karate API testing feature in string format.
8 | ///
9 | public interface IKarateFeatureBuilder
10 | {
11 | ///
12 | /// Builds a Karate API testing feature in string format.
13 | ///
14 | /// The Karate schema objects.
15 | /// The GraphQL query objects.
16 | /// The GraphQL document adapter to use.
17 | /// The Karate feature as a string.
18 | string Build(
19 | IEnumerable karateObjects,
20 | IEnumerable graphQLOperations,
21 | IGraphQLDocumentAdapter graphQLDocumentAdapter
22 | );
23 | }
--------------------------------------------------------------------------------
/tests/GraphQLToKarate.Tests/Enums/GraphQLOperationTypeTests.cs:
--------------------------------------------------------------------------------
1 | using FluentAssertions;
2 | using GraphQLToKarate.Library.Enums;
3 | using GraphQLToKarate.Library.Extensions;
4 | using NUnit.Framework;
5 | using System.ComponentModel;
6 |
7 | namespace GraphQLToKarate.Tests.Enums;
8 |
9 | [TestFixture]
10 | internal sealed class GraphQLOperationTypeTests
11 | {
12 | [Test]
13 | [TestCase(GraphQLOperationType.Query, "query")]
14 | [TestCase(GraphQLOperationType.Mutation, "mutation")]
15 | public void Name_returns_expected_value(
16 | GraphQLOperationType graphQLOperationType,
17 | string expectedValue
18 | ) => graphQLOperationType.Name().Should().Be(expectedValue);
19 |
20 | [Test]
21 | public void Name_throws_exception_for_invalid_value()
22 | {
23 | // arrange
24 | var act = () => ((GraphQLOperationType)5).Name();
25 |
26 | // assert
27 | act.Should().Throw();
28 | }
29 | }
--------------------------------------------------------------------------------
/src/GraphQLToKarate.Library/Converters/IGraphQLInputValueToExampleValueConverter.cs:
--------------------------------------------------------------------------------
1 | using GraphQLParser.AST;
2 | using GraphQLToKarate.Library.Adapters;
3 |
4 | namespace GraphQLToKarate.Library.Converters;
5 |
6 | ///
7 | /// Converts a to an example value.
8 | ///
9 | public interface IGraphQLInputValueToExampleValueConverter
10 | {
11 | ///
12 | /// Converts a to an example value.
13 | ///
14 | /// The to convert.
15 | /// The to use.
16 | /// The converted example value.
17 | string Convert(
18 | GraphQLInputValueDefinition graphQLInputValueDefinition,
19 | IGraphQLDocumentAdapter graphQLDocumentAdapter
20 | );
21 | }
--------------------------------------------------------------------------------
/src/GraphQLToKarate.Library/Converters/GraphQLCustomScalarTypeConverter.cs:
--------------------------------------------------------------------------------
1 | using GraphQLParser.AST;
2 | using GraphQLToKarate.Library.Adapters;
3 | using GraphQLToKarate.Library.Extensions;
4 | using GraphQLToKarate.Library.Mappings;
5 | using GraphQLToKarate.Library.Types;
6 |
7 | namespace GraphQLToKarate.Library.Converters;
8 |
9 | ///
10 | public sealed class GraphQLCustomScalarTypeConverter(
11 | ICustomScalarMapping customScalarMapping,
12 | IGraphQLTypeConverter graphQLTypeConverter) : IGraphQLTypeConverter
13 | {
14 | public KarateTypeBase Convert(
15 | string graphQLFieldName,
16 | GraphQLType graphQLType,
17 | IGraphQLDocumentAdapter graphQLDocumentAdapter
18 | ) => customScalarMapping.TryGetKarateType(graphQLType.GetUnwrappedTypeName(), out var karateType)
19 | ? new KarateType(karateType, graphQLFieldName)
20 | : graphQLTypeConverter.Convert(graphQLFieldName, graphQLType, graphQLDocumentAdapter);
21 | }
--------------------------------------------------------------------------------
/src/GraphQLToKarate.Library/Extensions/CollectionExtensions.cs:
--------------------------------------------------------------------------------
1 | namespace GraphQLToKarate.Library.Extensions;
2 |
3 | ///
4 | /// A home for extension methods on .
5 | ///
6 | internal static class CollectionExtensions
7 | {
8 | ///
9 | /// Returns true if the collection is empty or contains the given item. This method is useful
10 | /// for optional "filter" type operations, where collection to filter with would be empty if
11 | /// the user didn't specify any filters.
12 | ///
13 | /// The type of the collection.
14 | /// The collection to check.
15 | /// The item to check for.
16 | /// Whether the collection is empty or contains the given item.
17 | public static bool NoneOrContains(this ICollection collection, T item) =>
18 | !collection.Any() || collection.Contains(item);
19 | }
--------------------------------------------------------------------------------
/src/GraphQLToKarate.CommandLine/Infrastructure/CommandAppConfigurator.cs:
--------------------------------------------------------------------------------
1 | using GraphQLToKarate.CommandLine.Commands;
2 | using Spectre.Console.Cli;
3 |
4 | namespace GraphQLToKarate.CommandLine.Infrastructure;
5 |
6 | ///
7 | /// Configures the command app.
8 | ///
9 | internal static class CommandAppConfigurator
10 | {
11 | ///
12 | /// Configures the command app.
13 | ///
14 | /// The type registrar to use with the command app.
15 | /// The configured command app.
16 | public static CommandApp ConfigureCommandApp(ITypeRegistrar typeRegistrar)
17 | {
18 | var commandApp = new CommandApp(typeRegistrar);
19 |
20 | commandApp.Configure(configurator =>
21 | {
22 | configurator.SetInterceptor(new LogCommandSettingsInterceptor());
23 | configurator.AddCommand("convert");
24 | });
25 |
26 | return commandApp;
27 | }
28 | }
--------------------------------------------------------------------------------
/src/GraphQLToKarate.Library/Extensions/AdjacencyGraphExtensions.cs:
--------------------------------------------------------------------------------
1 | using QuikGraph;
2 | using QuikGraph.Algorithms;
3 |
4 | namespace GraphQLToKarate.Library.Extensions;
5 |
6 | ///
7 | /// Extension methods for .
8 | ///
9 | internal static class AdjacencyGraphExtensions
10 | {
11 | ///
12 | /// Determines whether the given is cyclic.
13 | ///
14 | /// The vertex type.
15 | /// The edge type.
16 | /// The to check.
17 | /// true if the given is cyclic; otherwise, false.
18 | public static bool IsCyclicGraph(this AdjacencyGraph adjacencyGraph)
19 | where TEdge : IEdge => !adjacencyGraph.IsDirectedAcyclicGraph();
20 | }
--------------------------------------------------------------------------------
/src/GraphQLToKarate.Library/Converters/IGraphQLScalarToExampleValueConverter.cs:
--------------------------------------------------------------------------------
1 | using GraphQLParser.AST;
2 | using GraphQLToKarate.Library.Adapters;
3 |
4 | namespace GraphQLToKarate.Library.Converters;
5 |
6 | ///
7 | /// Converts a GraphQL type into its associated example value.
8 | ///
9 | public interface IGraphQLScalarToExampleValueConverter
10 | {
11 | ///
12 | /// Converts a GraphQL type into its associated example value. For example, a GraphQL type of "String" would
13 | /// be converted to "\"exampleString\"", a GraphQL type of "Int" would be converted to "1", etc.
14 | ///
15 | /// The GraphQL type to convert.
16 | ///
17 | /// The to use to retrieve additional information about the GraphQL type.
18 | ///
19 | /// The converted GraphQL type.
20 | string Convert(GraphQLType graphQLType, IGraphQLDocumentAdapter graphQLDocumentAdapter);
21 | }
22 |
--------------------------------------------------------------------------------
/src/GraphQLToKarate.Library/Extensions/EnumExtensions.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel;
2 |
3 | namespace GraphQLToKarate.Library.Extensions;
4 |
5 | ///
6 | /// A home for extensions on the type.
7 | ///
8 | public static class EnumExtensions
9 | {
10 | ///
11 | /// Retrieve the string representation of the enum.
12 | ///
13 | /// The enum type.
14 | /// The enum value.
15 | /// The string representation of the enum.
16 | /// Thrown when the enum name is unidentifiable.
17 | public static string Name(this TEnum value)
18 | where TEnum : struct, Enum
19 | {
20 | var enumName = Enum.GetName(value);
21 |
22 | if (enumName is null)
23 | {
24 | throw new InvalidEnumArgumentException($"Unable to identify enum name for {value}!");
25 | }
26 |
27 | return enumName.FirstCharToLower();
28 | }
29 | }
--------------------------------------------------------------------------------
/src/GraphQLToKarate.Library/Mappings/ICustomScalarMapping.cs:
--------------------------------------------------------------------------------
1 | using System.Diagnostics.CodeAnalysis;
2 |
3 | namespace GraphQLToKarate.Library.Mappings;
4 |
5 | ///
6 | /// Represents a mapping of GraphQL custom scalar types to Karate data types.
7 | ///
8 | public interface ICustomScalarMapping
9 | {
10 | ///
11 | /// Gets the Karate data type for the specified GraphQL custom scalar type.
12 | ///
13 | /// The GraphQL custom scalar type.
14 | /// The Karate data type to retrieve.
15 | /// true if the mapping was found; otherwise, false.
16 | bool TryGetKarateType(
17 | string graphQLType,
18 | [MaybeNullWhen(false)] out string karateType
19 | );
20 |
21 | ///
22 | /// Determines whether the mapping contains any custom scalar types.
23 | ///
24 | /// true if the mapping contains any custom scalar types; otherwise, false.
25 | bool Any();
26 | }
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | ## Description
2 |
3 | Please provide a meaningful description of what this change will do, or is for. Bonus points for including links to related issues, other PRs, or technical references.
4 |
5 | Note that by _not_ including a description, you are asking reviewers to do extra work to understand the context of this change, which may lead to your PR taking much longer to review, or result in it not being reviewed at all.
6 |
7 | ## Type of Change
8 |
9 | - [ ] Bug Fix
10 | - [ ] New Feature
11 | - [ ] Breaking Change
12 | - [ ] Refactor
13 | - [ ] Documentation
14 | - [ ] Other (please describe)
15 |
16 | ## Checklist
17 |
18 | - [ ] I have read the [contributing guidelines](https://github.com/wbaldoumas/graphql-to-karate/blob/main/CONTRIBUTING.md)
19 | - [ ] Existing issues have been referenced (where applicable)
20 | - [ ] I have verified this change is not present in other open pull requests
21 | - [ ] Functionality is documented
22 | - [ ] All code style checks pass
23 | - [ ] New code contribution is covered by automated tests
24 | - [ ] All new and existing tests pass
25 |
--------------------------------------------------------------------------------
/tests/GraphQLToKarate.Tests/Extensions/CollectionExtensionTests.cs:
--------------------------------------------------------------------------------
1 | using FluentAssertions;
2 | using GraphQLToKarate.Library.Extensions;
3 | using NUnit.Framework;
4 |
5 | namespace GraphQLToKarate.Tests.Extensions;
6 |
7 | [TestFixture]
8 | public class CollectionExtensionsTests
9 | {
10 | [Test]
11 | [TestCaseSource(nameof(TestCases))]
12 | public void NoneOrContains_should_return_expected_result(
13 | ICollection collection,
14 | int item,
15 | bool expected)
16 | {
17 | // Act
18 | var actual = collection.NoneOrContains(item);
19 |
20 | // Assert
21 | actual.Should().Be(expected);
22 | }
23 |
24 | private static IEnumerable TestCases
25 | {
26 | get
27 | {
28 | yield return new TestCaseData(Array.Empty(), 1, true).SetName("Empty Collection");
29 | yield return new TestCaseData(new[] { 1, 2, 3 }, 1, true).SetName("Contains Item");
30 | yield return new TestCaseData(new[] { 1, 2, 3 }, 4, false).SetName("Does Not ContainItem");
31 | }
32 | }
33 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 Will Baldoumas
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/src/GraphQLToKarate.Library/Mappings/CustomScalarMapping.cs:
--------------------------------------------------------------------------------
1 | namespace GraphQLToKarate.Library.Mappings;
2 |
3 | ///
4 | public sealed class CustomScalarMapping(IDictionary mappings) : ICustomScalarMapping
5 | {
6 | public IDictionary Mappings { get; } = mappings;
7 |
8 | public CustomScalarMapping()
9 | : this(new Dictionary(StringComparer.OrdinalIgnoreCase))
10 | {
11 | }
12 |
13 | public bool TryGetKarateType(string graphQLType, out string karateType) =>
14 | Mappings.TryGetValue(graphQLType, out karateType!);
15 |
16 | public bool Any() => Mappings.Any();
17 |
18 | ///
19 | /// Returns the custom scalar mapping as a string, formatted in a way that is acceptable as a command-line argument.
20 | ///
21 | /// An example response would be "DateTime:string,URL:string,Long:int".
22 | ///
23 | /// The custom scalar mapping as a string.
24 | public override string ToString() => string.Join(',', Mappings.Select(mapping => $"{mapping.Key}:{mapping.Value}"));
25 | }
--------------------------------------------------------------------------------
/src/GraphQLToKarate.CommandLine/Infrastructure/LogCommandSettingsInterceptor.cs:
--------------------------------------------------------------------------------
1 | using GraphQLToKarate.CommandLine.Settings;
2 | using Serilog.Core;
3 | using Spectre.Console.Cli;
4 |
5 | namespace GraphQLToKarate.CommandLine.Infrastructure;
6 |
7 | ///
8 | /// Intercepts the and sets the accordingly.
9 | ///
10 | internal sealed class LogCommandSettingsInterceptor : ICommandInterceptor
11 | {
12 | public static readonly LoggingLevelSwitch LoggingLevelSwitch = new();
13 |
14 | ///
15 | /// Intercepts the and sets the accordingly.
16 | ///
17 | /// The command context.
18 | /// The command settings.
19 | public void Intercept(CommandContext context, CommandSettings settings)
20 | {
21 | if (settings is LogCommandSettings logCommandSettings)
22 | {
23 | LoggingLevelSwitch.MinimumLevel = logCommandSettings.LogLevel;
24 | }
25 | }
26 | }
--------------------------------------------------------------------------------
/src/GraphQLToKarate.Library/Converters/IGraphQLTypeDefinitionConverter.cs:
--------------------------------------------------------------------------------
1 | using GraphQLParser.AST;
2 | using GraphQLToKarate.Library.Adapters;
3 | using GraphQLToKarate.Library.Types;
4 |
5 | namespace GraphQLToKarate.Library.Converters;
6 |
7 | ///
8 | /// Converts instances to instances.
9 | ///
10 | public interface IGraphQLTypeDefinitionConverter
11 | {
12 | ///
13 | /// Convert the given to a .
14 | ///
15 | /// The GraphQL object to convert.
16 | ///
17 | /// The GraphQL document adapter, providing access to user-defined types within the GraphQL document.
18 | ///
19 | /// The type of the GraphQL object to convert.
20 | /// The converted .
21 | KarateObject Convert(
22 | T graphQLTypeDefinition,
23 | IGraphQLDocumentAdapter graphQLDocumentAdapter)
24 | where T : GraphQLTypeDefinition, IHasFieldsDefinitionNode;
25 | }
--------------------------------------------------------------------------------
/src/GraphQLToKarate.Library/Converters/GraphQLNullTypeConverter.cs:
--------------------------------------------------------------------------------
1 | using GraphQLParser.AST;
2 | using GraphQLToKarate.Library.Adapters;
3 | using GraphQLToKarate.Library.Exceptions;
4 | using GraphQLToKarate.Library.Types;
5 |
6 | namespace GraphQLToKarate.Library.Converters;
7 |
8 | ///
9 | internal sealed class GraphQLNullTypeConverter(IGraphQLTypeConverterFactory graphQLTypeConverterFactory) : IGraphQLTypeConverter
10 | {
11 | public KarateTypeBase Convert(
12 | string graphQLFieldName,
13 | GraphQLType graphQLType,
14 | IGraphQLDocumentAdapter graphQLDocumentAdapter)
15 | {
16 | var graphQLTypeConverter = graphQLType switch
17 | {
18 | GraphQLNamedType => graphQLTypeConverterFactory.CreateGraphQLTypeConverter(),
19 | GraphQLListType => graphQLTypeConverterFactory.CreateGraphQLListTypeConverter(),
20 | _ => throw new InvalidGraphQLTypeException()
21 | };
22 |
23 | var karateType = graphQLTypeConverter.Convert(
24 | graphQLFieldName,
25 | graphQLType,
26 | graphQLDocumentAdapter
27 | );
28 |
29 | return new KarateNullType(karateType);
30 | }
31 | }
--------------------------------------------------------------------------------
/tests/GraphQLToKarate.Integration.Api/GraphQLToKarate.Integration.Api.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net8.0
5 | enable
6 | enable
7 | true
8 | true
9 | 5fca7578-a673-4a41-bcd3-06db3b52cc6a
10 |
11 |
12 |
13 |
14 |
15 | all
16 | runtime; build; native; contentfiles; analyzers; buildtransitive
17 |
18 |
19 | all
20 | runtime; build; native; contentfiles; analyzers; buildtransitive
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/src/GraphQLToKarate.Library/Converters/IGraphQLTypeConverter.cs:
--------------------------------------------------------------------------------
1 | using GraphQLParser.AST;
2 | using GraphQLToKarate.Library.Adapters;
3 | using GraphQLToKarate.Library.Types;
4 |
5 | namespace GraphQLToKarate.Library.Converters;
6 |
7 | ///
8 | /// Converts a to a . The actual Karate type
9 | /// will differ based on things like nullability, non-nullability, and list-ness.
10 | ///
11 | public interface IGraphQLTypeConverter
12 | {
13 | ///
14 | /// Convert the given to an instance of .
15 | ///
16 | /// The name of the GraphQL field associated with the type.
17 | /// The GraphQL type to convert.
18 | ///
19 | /// The GraphQL document adapter, providing access to user-defined types within the GraphQL document.
20 | ///
21 | /// The converted .
22 | KarateTypeBase Convert(
23 | string graphQLFieldName,
24 | GraphQLType graphQLType,
25 | IGraphQLDocumentAdapter graphQLDocumentAdapter
26 | );
27 | }
28 |
--------------------------------------------------------------------------------
/tests/GraphQLToKarate.Tests/Extensions/GraphQLDirectiveExtensionsTests.cs:
--------------------------------------------------------------------------------
1 | using FluentAssertions;
2 | using GraphQLParser.AST;
3 | using GraphQLToKarate.Library.Apollo;
4 | using GraphQLToKarate.Library.Extensions;
5 | using NUnit.Framework;
6 |
7 | namespace GraphQLToKarate.Tests.Extensions;
8 |
9 | [TestFixture]
10 | internal sealed class GraphQLDirectiveExtensionsTests
11 | {
12 | [TestCase(Directives.Inaccessible, true)]
13 | [TestCase(Directives.External, false)]
14 | [TestCase("otherDirective", false)]
15 | public void IsInaccessible_returns_expected_result(string directiveName, bool expectedResult)
16 | {
17 | var directive = new GraphQLDirective(new GraphQLName(directiveName));
18 |
19 | var result = directive.IsInaccessible();
20 |
21 | result.Should().Be(expectedResult);
22 | }
23 |
24 | [TestCase(Directives.Inaccessible, false)]
25 | [TestCase(Directives.External, true)]
26 | [TestCase("otherDirective", false)]
27 | public void IsExternal_returns_expected_result(string directiveName, bool expectedResult)
28 | {
29 | var directive = new GraphQLDirective(new GraphQLName(directiveName));
30 |
31 | var result = directive.IsExternal();
32 |
33 | result.Should().Be(expectedResult);
34 | }
35 | }
--------------------------------------------------------------------------------
/src/GraphQLToKarate.CommandLine/Infrastructure/TypeRegistrar.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.DependencyInjection;
2 | using Microsoft.Extensions.Hosting;
3 | using Spectre.Console.Cli;
4 |
5 | namespace GraphQLToKarate.CommandLine.Infrastructure;
6 |
7 | ///
8 | internal sealed class TypeRegistrar(IHostBuilder hostBuilder) : ITypeRegistrar
9 | {
10 | public ITypeResolver Build() => new TypeResolver(hostBuilder.Build());
11 |
12 | public void Register(Type serviceType, Type implementationType) => hostBuilder.ConfigureServices(
13 | (_, serviceCollection) => serviceCollection.AddSingleton(serviceType, implementationType)
14 | );
15 |
16 | public void RegisterInstance(Type serviceType, object implementation) => hostBuilder.ConfigureServices(
17 | (_, serviceCollection) => serviceCollection.AddSingleton(serviceType, implementation)
18 | );
19 |
20 | public void RegisterLazy(Type serviceType, Func