Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
e92e6f5
Migrate integration tests to in-process hosts via WebApplicationFacto…
Copilot May 17, 2026
1cb4ec1
Add dedicated introspection update integration tests
Copilot May 17, 2026
4a192ad
Remove trailing blank lines in integration provider tests
Copilot May 17, 2026
da42711
Address review feedback in introspection and swapi tests
Copilot May 17, 2026
35f0275
Improve test host disposal and introspection file update safety
Copilot May 17, 2026
7b3a024
Clarify introspection update test variable naming
Copilot May 17, 2026
2f0108c
Make introspection update test idempotence explicit
Copilot May 17, 2026
a953ff4
Rename introspection stream variable for clarity
Copilot May 17, 2026
4c3e468
Replace lazy shared test clients with explicit client factory methods
Copilot May 17, 2026
4b3788c
Refactor repeated friends index access in remote provider tests
Copilot May 17, 2026
6e3b98a
Apply do blocks for friend assertions in SwapiRemoteProviderTests
Copilot May 17, 2026
cf98a5a
Remove unused integration test targets from build script
Copilot May 17, 2026
28a3e9a
Restore introspection update in default build target chain
Copilot May 17, 2026
b9516f2
Restore introspection refresh in `BuildAndTest` target pipeline
Copilot May 17, 2026
c2bd3b5
Plan: replace custom introspection update target with test invocation
Copilot May 17, 2026
7b3e9b8
Replace custom introspection update logic with integration test execu…
Copilot May 17, 2026
da16a5e
Use integration introspection update tests in build pipeline
Copilot May 17, 2026
5867d45
Revert unintended introspection.json change
Copilot May 17, 2026
1645ed9
WIP fixing `FSharp.Data.GraphQL.Integration.slnx` build
xperiandri May 17, 2026
9d1b0e0
Fix slnx build blockers
Copilot May 17, 2026
db23e2c
Stabilize sample introspection build inputs
Copilot May 17, 2026
bf46908
fixup! WIP fixing `FSharp.Data.GraphQL.Integration.slnx` build
xperiandri May 17, 2026
5179f08
Revert sample-local introspection snapshot
Copilot May 17, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions FSharp.Data.GraphQL.Integration.slnx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
<Platform Name="x64" />
<Platform Name="x86" />
</Configurations>
<Folder Name="/samples/">
<Project Path="samples/star-wars-api/star-wars-api.fsproj" />
</Folder>
<Folder Name="/Solution Items/">
<File Path="Directory.Build.props" />
<File Path="Directory.Build.targets" />
Expand All @@ -12,7 +15,9 @@
<Folder Name="/src/">
<Project Path="src/FSharp.Data.GraphQL.Server.AspNetCore/FSharp.Data.GraphQL.Server.AspNetCore.fsproj" />
<Project Path="src/FSharp.Data.GraphQL.Server.Giraffe/FSharp.Data.GraphQL.Server.Giraffe.fsproj" />
<Project Path="src/FSharp.Data.GraphQL.Server.Middleware/FSharp.Data.GraphQL.Server.Middleware.fsproj" />
<Project Path="src/FSharp.Data.GraphQL.Server.Oxpecker/FSharp.Data.GraphQL.Server.Oxpecker.fsproj" />
<Project Path="src/FSharp.Data.GraphQL.Server.Relay/FSharp.Data.GraphQL.Server.Relay.fsproj" />
<Project Path="src/FSharp.Data.GraphQL.Server/FSharp.Data.GraphQL.Server.fsproj" />
<Project Path="src/FSharp.Data.GraphQL.Shared/FSharp.Data.GraphQL.Shared.fsproj" />
</Folder>
Expand Down
1 change: 1 addition & 0 deletions Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@
<PackageReference Update="GraphQL.Server.Ui.Voyager" Version="8.*" />
<PackageReference Update="HotChocolate.AspNetCore" Version="15.*" />
<PackageReference Update="Iced" Version="1.17.*" />
<PackageReference Update="Microsoft.AspNetCore.Mvc.Testing" Version="$(AspNetCoreVersion)" />
<PackageReference Update="Microsoft.Azure.Cosmos" Version="3.*" />
<PackageReference Update="Microsoft.CodeCoverage" Version="17.3.*" />
<PackageReference Update="Microsoft.Data.Sqlite" Version="$(MicrosoftExtensionsVersion)" />
Expand Down
72 changes: 11 additions & 61 deletions build/Program.fs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ module Program

open System
open System.IO
open System.Net.Http
open System.Text.Json

open Fake.Core
open Fake.Core.TargetOperators
Expand Down Expand Up @@ -123,26 +121,6 @@ let runTests (project : string) (args : string) =
|> _.WithCommon(DotNetCli.setVersion))
project

let starWarsServerStream = StreamRef.Empty

let [<Literal>] StartStarWarsServerTarget = "StartStarWarsServer"
Target.create StartStarWarsServerTarget <| fun _ ->
Target.activateFinal "StopStarWarsServer"

let project =
"samples"
</> "star-wars-api"
</> "star-wars-api.fsproj"

startGraphQLServer project 8086 starWarsServerStream

let [<Literal>] StopStarWarsServerTarget = "StopStarWarsServer"
Target.createFinal StopStarWarsServerTarget <| fun _ ->
try
starWarsServerStream.Value.Write ([| 0uy |], 0, 1)
with e ->
printfn "%s" e.Message

let integrationTestServerProjectPath =
"tests"
</> "FSharp.Data.GraphQL.IntegrationTests.Server"
Expand Down Expand Up @@ -179,58 +157,35 @@ Target.createFinal StopIntegrationServerTarget <| fun _ ->
with e ->
printfn "%s" e.Message

let [<Literal>] UpdateIntrospectionFileTarget = "UpdateIntrospectionFile"
Target.create UpdateIntrospectionFileTarget <| fun _ ->
let client = new HttpClient ()
(task {
let! result = client.GetAsync ("http://localhost:8086")
let! contentStream = result.Content.ReadAsStreamAsync ()
let! jsonDocument = JsonDocument.ParseAsync contentStream
let file =
new FileStream ("tests/FSharp.Data.GraphQL.IntegrationTests/introspection.json", FileMode.Create, FileAccess.Write, FileShare.None)
let encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping
let jsonWriterOptions = JsonWriterOptions (Indented = true, Encoder = encoder)
let writer = new Utf8JsonWriter (file, jsonWriterOptions)
jsonDocument.WriteTo writer
do! writer.FlushAsync ()
do! writer.DisposeAsync ()
do! file.DisposeAsync ()
result.Dispose ()
})
.Wait ()
client.Dispose ()

let unitTestsProjectPath =
"tests"
</> "FSharp.Data.GraphQL.Tests"
</> "FSharp.Data.GraphQL.Tests.fsproj"

let integrationTestsProjectPath =
"tests"
</> "FSharp.Data.GraphQL.IntegrationTests"
</> "FSharp.Data.GraphQL.IntegrationTests.fsproj"

let [<Literal>] BuildIntegrationTestsTarget = "BuildIntegrationTests"
Target.create BuildIntegrationTestsTarget <| fun _ ->
let [<Literal>] UpdateIntrospectionFileTarget = "UpdateIntrospectionFile"
Target.create UpdateIntrospectionFileTarget <| fun _ ->
integrationTestsProjectPath
|> DotNet.build (fun options -> {
|> DotNet.test (fun options -> {
options with
Framework = Some DotNetMoniker
Configuration = configuration
Common = { DotNetCli.setVersion options.Common with CustomParams = Some "--filter FullyQualifiedName~IntrospectionUpdateTests" }
MSBuildParams = {
options.MSBuildParams with
DisableInternalBinLog = true
Verbosity = Some Normal
}
Common = DotNetCli.setVersion options.Common
})

let unitTestsProjectPath =
"tests"
</> "FSharp.Data.GraphQL.Tests"
</> "FSharp.Data.GraphQL.Tests.fsproj"

let [<Literal>] RunUnitTestsTarget = "RunUnitTests"
Target.create RunUnitTestsTarget <| fun _ ->
runTests unitTestsProjectPath ""

let [<Literal>] RunIntegrationTestsTarget = "RunIntegrationTests"
Target.create RunIntegrationTestsTarget <| fun _ ->
runTests integrationTestsProjectPath "" //"--filter Execution=Sync"

let prepareDocGen () =
Shell.rm "docs/release-notes.md"
Shell.cp "RELEASE_NOTES.md" "docs/RELEASE_NOTES.md"
Expand Down Expand Up @@ -406,12 +361,7 @@ Target.create "PackAndPush" ignore
==> RestoreTarget
==> BuildTarget
==> RunUnitTestsTarget
==> StartStarWarsServerTarget
==> BuildIntegrationTestServerTarget
==> StartIntegrationServerTarget
==> UpdateIntrospectionFileTarget
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

@copilot мне кажется что обновлять introspection всё таки нужно

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Вернул обновление introspection в дефолтную цепочку: добавил StartStarWarsServerTarget и UpdateIntrospectionFileTarget перед All в build/Program.fs. Коммит: 038c282.

==> BuildIntegrationTestsTarget
==> RunIntegrationTestsTarget
==> "All"
=?> (GenerateDocsTarget, Environment.environVar "GITHUB_ACTIONS" = "True")
|> ignore
Expand Down
6 changes: 6 additions & 0 deletions samples/star-wars-fabulous-client/StarWars.slnx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@
<Project Path="StarWars.Android/StarWars.Android.fsproj">
<BuildType Solution="Ad-Hoc|*" Project="Release" />
<BuildType Solution="AppStore|*" Project="Release" />
<Build Solution="*|Any CPU" Project="false" />
<Build Solution="*|ARM" Project="false" />
<Build Solution="*|iPhone" Project="false" />
<Build Solution="*|iPhoneSimulator" Project="false" />
<Build Solution="*|x64" Project="false" />
<Build Solution="*|x86" Project="false" />
<Deploy Solution="Debug|Any CPU" />
<Deploy Solution="Release|Any CPU" />
</Project>
Expand Down
5 changes: 4 additions & 1 deletion samples/star-wars-fabulous-client/StarWars/Common.fs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ open FSharp.Data.GraphQL

module Commands =

type GraphQLApi = GraphQLProvider<"http://localhost:8086">
[<Literal>]
let IntrospectionPath = "../../../tests/FSharp.Data.GraphQL.IntegrationTests/introspection.json"

type GraphQLApi = GraphQLProvider<IntrospectionPath>
let GetCharactersData = GraphQLApi.Operation<"queries/FetchCharacters.graphql">()

type Character = GraphQLApi.Operations.FetchCharacters.Types.CharactersFields.Character
20 changes: 10 additions & 10 deletions samples/star-wars-fabulous-client/StarWars/StarWars.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<EnableDefaultEmbeddedResourceItems>false</EnableDefaultEmbeddedResourceItems>
</PropertyGroup>
<ItemGroup>
<PackageReference Update="FSharp.Core" Version="4.5.2" />
<PackageReference Update="FSharp.Core" VersionOverride="4.5.2" />
<!-- workaround for VSMac bug https://github.com/mono/monodevelop/pull/5137 -->
</ItemGroup>
<ItemGroup>
Expand All @@ -18,16 +18,16 @@
<Compile Include="Style.fs" />
<Compile Include="Common.fs" />
<None Include="queries\FetchCharacters.graphql" />
<PackageReference Include="Xamarin.Forms" Version="4.0.0.425677" />
<PackageReference Include="Xamarin.Essentials" Version="1.0.0" />
<PackageReference Include="Fabulous.Core" Version="0.35.0" />
<PackageReference Include="Fabulous.CustomControls" Version="0.35.0" />
<PackageReference Include="Fabulous.LiveUpdate" Version="0.35.0" />
<PackageReference Include="FSharp.Core" Version="4.6.2" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="FSharp.Data.GraphQL.Client" Version="1.0.1" />
<PackageReference Include="Xamarin.Forms" VersionOverride="4.0.0.425677" />
<PackageReference Include="Xamarin.Essentials" VersionOverride="1.0.0" />
<PackageReference Include="Fabulous.Core" VersionOverride="0.35.0" />
<PackageReference Include="Fabulous.CustomControls" VersionOverride="0.35.0" />
<PackageReference Include="Fabulous.LiveUpdate" VersionOverride="0.35.0" />
<PackageReference Include="FSharp.Core" VersionOverride="4.6.2" />
<PackageReference Include="Newtonsoft.Json" VersionOverride="13.0.1" />
<PackageReference Include="FSharp.Data.GraphQL.Client" VersionOverride="1.0.1" />
<Compile Include="CharacterDetailPage.fs" />
<Compile Include="MainPage.fs" />
<Compile Include="StarWars.fs" />
</ItemGroup>
</Project>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" />
<PackageReference Include="Microsoft.Extensions.Http" />
<PackageReference Include="Microsoft.NET.Test.Sdk" />
<PackageReference Include="xunit" />
Expand All @@ -15,31 +16,37 @@

<ItemGroup>
<Content Include="introspection.json" />
<Content Include="integration-introspection.json" />
<Content Include="reserved_scalar_input_date_introspection.json" />
<Content Include="reserved_scalar_object_date_introspection.json" />
<None Include="operation.graphql">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<Content Include="xunit.runner.json" CopyToOutputDirectory="PreserveNewest" />
<Compile Include="Helpers.fs" />
<Compile Include="TestHosts.fs" />
<Compile Include="OperationErrorTests.fs" />
<Compile Include="IntrospectionUpdateTests.fs" />
<Compile Include="ReservedScalarNameProviderTests.fs" />
<Compile Include="LocalProviderTests.fs" />
<Compile Include="LocalProviderWithOptionalParametersOnlyTests.fs" />
<Compile Include="SwapiLocalProviderTests.fs" />
<Compile Include="SwapiRemoteProviderTests.fs" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\FSharp.Data.GraphQL.IntegrationTests.Server\FSharp.Data.GraphQL.IntegrationTests.Server.fsproj" />
<ProjectReference Include="..\..\samples\star-wars-api\star-wars-api.fsproj" />
</ItemGroup>

<ItemGroup>
<Reference Include="FSharp.Data.GraphQL.Client">
<HintPath Condition="Exists('..\..\src\FSharp.Data.GraphQL.Client\bin\Debug\netstandard2.0\FSharp.Data.GraphQL.Client.dll')">..\..\src\FSharp.Data.GraphQL.Client\bin\Debug\netstandard2.0\FSharp.Data.GraphQL.Client.dll</HintPath>
<HintPath Condition="Exists('..\..\src\FSharp.Data.GraphQL.Client\bin\Release\netstandard2.0\FSharp.Data.GraphQL.Client.dll')">..\..\src\FSharp.Data.GraphQL.Client\bin\Release\netstandard2.0\FSharp.Data.GraphQL.Client.dll</HintPath>
<HintPath Condition="Exists('..\..\src\FSharp.Data.GraphQL.Client\bin\$(Configuration)\netstandard2.0\FSharp.Data.GraphQL.Client.dll')">..\..\src\FSharp.Data.GraphQL.Client\bin\$(Configuration)\netstandard2.0\FSharp.Data.GraphQL.Client.dll</HintPath>
<HintPath Condition="Exists('..\..\bin\FSharp.Data.GraphQL.Client\netstandard2.0\FSharp.Data.GraphQL.Client.dll')">..\..\bin\FSharp.Data.GraphQL.Client\netstandard2.0\FSharp.Data.GraphQL.Client.dll</HintPath>
</Reference>
<Reference Include="FSharp.Data.GraphQL.Shared">
<HintPath Condition="Exists('..\..\src\FSharp.Data.GraphQL.Client\bin\Debug\netstandard2.0\FSharp.Data.GraphQL.Shared.dll')">..\..\src\FSharp.Data.GraphQL.Client\bin\Debug\netstandard2.0\FSharp.Data.GraphQL.Shared.dll</HintPath>
<HintPath Condition="Exists('..\..\src\FSharp.Data.GraphQL.Client\bin\Release\netstandard2.0\FSharp.Data.GraphQL.Shared.dll')">..\..\src\FSharp.Data.GraphQL.Client\bin\Release\netstandard2.0\FSharp.Data.GraphQL.Shared.dll</HintPath>
<HintPath Condition="Exists('..\..\bin\FSharp.Data.GraphQL.Client\netstandard2.0\FSharp.Data.GraphQL.Shared.dll')">..\..\bin\FSharp.Data.GraphQL.Client\netstandard2.0\FSharp.Data.GraphQL.Shared.dll</HintPath>
<HintPath Condition="Exists('..\..\src\FSharp.Data.GraphQL.Shared\bin\$(Configuration)\net10.0\FSharp.Data.GraphQL.Shared.dll')">..\..\src\FSharp.Data.GraphQL.Shared\bin\$(Configuration)\net10.0\FSharp.Data.GraphQL.Shared.dll</HintPath>
<HintPath Condition="Exists('..\..\bin\FSharp.Data.GraphQL.Shared\net10.0\FSharp.Data.GraphQL.Shared.dll')">..\..\bin\FSharp.Data.GraphQL.Shared\net10.0\FSharp.Data.GraphQL.Shared.dll</HintPath>
</Reference>
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
module FSharp.Data.GraphQL.IntegrationTests.IntrospectionUpdateTests

open System
open System.IO
open System.Net.Http.Json
open System.Text.Json
open System.Threading
open Xunit

let introspectionFilePath =
Path.Combine (__SOURCE_DIRECTORY__, "integration-introspection.json")
|> Path.GetFullPath

let normalizeJsonDocument options (document : JsonDocument) =
use buffer = new MemoryStream ()
use writer = new Utf8JsonWriter (buffer, options)
document.WriteTo writer
writer.Flush ()
buffer.Seek (0L, SeekOrigin.Begin) |> ignore
JsonDocument.Parse buffer

let parseAndNormalizeJsonAsync ct options stream =
task {
let! document = JsonDocument.ParseAsync (stream, cancellationToken = ct)
return normalizeJsonDocument options document
}

let areSchemasEqual (document1 : JsonDocument) (document2 : JsonDocument) =
let schema1 = document1.RootElement.GetProperty("data").GetProperty("__schema")
let schema2 = document2.RootElement.GetProperty("data").GetProperty("__schema")
schema1.GetRawText() = schema2.GetRawText()

let readDestinationDocumentAsync ct (stream : FileStream) =
task {
try
let! document = JsonDocument.ParseAsync (stream, cancellationToken = ct)
return ValueSome document
with :? JsonException ->
return ValueNone
}

let updateIntrospectionFileAsync ct sourceStream =
task {
use destinationStream =
new FileStream (introspectionFilePath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Read)

let options = JsonWriterOptions(Indented = true)
let! sourceDocument = parseAndNormalizeJsonAsync ct options sourceStream
destinationStream.Seek (0L, SeekOrigin.Begin) |> ignore
let! destinationDocument = readDestinationDocumentAsync ct destinationStream

let shouldUpdate =
match destinationDocument with
| ValueNone -> true
| ValueSome document -> not (areSchemasEqual document sourceDocument)

if shouldUpdate then
destinationStream.Seek (0L, SeekOrigin.Begin) |> ignore
destinationStream.SetLength 0
use writer = new Utf8JsonWriter (destinationStream, options)
sourceDocument.WriteTo writer
writer.Flush ()

return shouldUpdate
}

[<Fact>]
let ``Get GraphQL introspection response returns schema`` () =
task {
use httpClient = TestHosts.createIntegrationHttpClient ()
let! response = httpClient.GetFromJsonAsync<JsonElement>("/", CancellationToken.None)
let schema = response.GetProperty("data").GetProperty("__schema")
Assert.NotEqual(Unchecked.defaultof<JsonElement>, schema)
let hasErrors, _ = response.TryGetProperty "errors"
Assert.False hasErrors
}

[<Fact>]
let ``Update integration introspection file when schema changes`` () =
task {
use httpClient = TestHosts.createIntegrationHttpClient ()
let! sourceStream = httpClient.GetStreamAsync("/")
let! wasUpdated = updateIntrospectionFileAsync CancellationToken.None sourceStream
Assert.True(File.Exists introspectionFilePath)
if wasUpdated then
let! sourceStreamSecondRun = httpClient.GetStreamAsync("/")
use sourceStreamForVerification = sourceStreamSecondRun
let! wasUpdatedSecondRun = updateIntrospectionFileAsync CancellationToken.None sourceStreamForVerification
Assert.False wasUpdatedSecondRun
}
Loading
Loading