Skip to content

Commit

Permalink
fix: change time based config properties to use timespan, add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
egil committed Jan 27, 2024
1 parent 1387e7e commit 08bd0a4
Show file tree
Hide file tree
Showing 27 changed files with 574 additions and 119 deletions.
190 changes: 89 additions & 101 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,7 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v3
with:
dotnet-version: |
3.1.x
6.0.x
8.0.x
dotnet-version: 8.0.x

# Create the NuGet package in the folder from the environment variable NuGetDirectory
- run: dotnet pack --configuration Release --output ${{ env.NuGetDirectory }}
Expand Down Expand Up @@ -75,98 +72,92 @@ jobs:
shell: pwsh
run: meziantou.validate-nuget-package (Get-ChildItem "${{ env.NuGetDirectory }}/*.nupkg") --excluded-rules IconMustBeSet

# run-test:
# runs-on: ubuntu-latest
# timeout-minutes: 30
# strategy:
# matrix:
# framework: [ net8.0 ]
# fail-fast: false
# env:
# TestResultsDirectory: ${{ github.workspace }}/TestResults
# permissions:
# checks: write
# steps:
# - uses: actions/checkout@v3

# - name: Setup .NET
# uses: actions/setup-dotnet@v3
# with:
# dotnet-version: |
# 3.1.x
# 6.0.x
# 8.0.x

# - name: Run tests
# run: dotnet test --configuration Release --framework ${{ matrix.framework }} --logger trx --results-directory "${{ env.TestResultsDirectory }}" --collect:"XPlat Code Coverage" --blame-hang --blame-hang-timeout 5min

# - uses: actions/upload-artifact@v3
# if: always()
# with:
# name: test-results-${{ matrix.framework }}
# if-no-files-found: error
# retention-days: 3
# path: ${{ env.TestResultsDirectory }}/**/*

# - name: Test Report
# uses: dorny/test-reporter@v1
# if: github.actor != 'dependabot[bot]' && (success() || failure()) && github.repository_owner == 'egil'
# with:
# name: test-results-${{ matrix.framework }}
# path: ${{ env.TestResultsDirectory }}/**/*.trx
# path-replace-backslashes: 'true'
# reporter: dotnet-trx

# run-stryker:
# runs-on: ubuntu-latest
# if: github.event_name != 'release'
# env:
# StrykerDirectory: ${{ github.workspace }}/Stryker
# permissions:
# statuses: write
# steps:
# - uses: actions/checkout@v3

# - name: Setup .NET
# uses: actions/setup-dotnet@v3
# with:
# dotnet-version: |
# 3.1.x
# 6.0.x
# 8.0.x

# - name: Install Stryker.NET
# run: dotnet tool install -g dotnet-stryker

# - name: Run Stryker.NET
# id: stryker
# run: |
# cd test/TimeProviderExtensions.Tests
# dotnet stryker --config-file "../../stryker-config.json" --dashboard-api-key "${{ secrets.STRYKER_DASHBOARD_API_KEY }}" --version ${{ env.BRANCH_NAME }} --output ${{ env.StrykerDirectory }}

# - run: |
# cat ${{ env.StrykerDirectory }}/reports/mutation-report.md >> $GITHUB_STEP_SUMMARY
# echo "" >> $GITHUB_STEP_SUMMARY
# echo "View the [full report](https://dashboard.stryker-mutator.io/reports/github.com/egil/TimeProviderExtensions/${{ env.BRANCH_NAME }})." >> $GITHUB_STEP_SUMMARY

# - name: Stryker Report
# if: github.actor != 'dependabot[bot]' && (success() || failure()) && github.repository_owner == 'egil'
# uses: Sibz/github-status-action@v1
# with:
# authToken: ${{secrets.GITHUB_TOKEN}}
# context: stryker-report"
# description: "See report"
# state: ${{ steps.stryker.conclusion }}
# sha: ${{ github.event.pull_request.head.sha || github.sha }}
# target_url: https://dashboard.stryker-mutator.io/reports/github.com/egil/TimeProviderExtensions/${{ env.BRANCH_NAME }}

# - uses: actions/upload-artifact@v3
# if: steps.stryker.conclusion == 'success' || steps.stryker.conclusion == 'failure'
# with:
# name: stryker-reports
# if-no-files-found: error
# retention-days: 3
# path: ${{ env.StrykerDirectory }}/**/*
run-test:
runs-on: ubuntu-latest
timeout-minutes: 30
strategy:
matrix:
framework: [ net8.0 ]
fail-fast: false
env:
TestResultsDirectory: ${{ github.workspace }}/TestResults
permissions:
checks: write
steps:
- uses: actions/checkout@v3

- name: Setup .NET
uses: actions/setup-dotnet@v3
with:
dotnet-version: 8.0.x

- name: Run tests
run: dotnet test --configuration Release --framework ${{ matrix.framework }} --logger trx --results-directory "${{ env.TestResultsDirectory }}" --collect:"XPlat Code Coverage" --blame-hang --blame-hang-timeout 5min

- uses: actions/upload-artifact@v3
if: always()
with:
name: test-results-${{ matrix.framework }}
if-no-files-found: error
retention-days: 3
path: ${{ env.TestResultsDirectory }}/**/*

- name: Test Report
uses: dorny/test-reporter@v1
if: github.actor != 'dependabot[bot]' && (success() || failure()) && github.repository_owner == 'egil'
with:
name: test-results-${{ matrix.framework }}
path: ${{ env.TestResultsDirectory }}/**/*.trx
path-replace-backslashes: 'true'
reporter: dotnet-trx

run-stryker:
runs-on: ubuntu-latest
if: github.event_name != 'release'
env:
StrykerDirectory: ${{ github.workspace }}/Stryker
permissions:
statuses: write
steps:
- uses: actions/checkout@v3

- name: Setup .NET
uses: actions/setup-dotnet@v3
with:
dotnet-version: 8.0.x

- name: Install Stryker.NET
run: dotnet tool install -g dotnet-stryker

- name: Run Stryker.NET
id: stryker
run: |
cd test/TimeProviderExtensions.Tests
dotnet stryker --config-file "../../stryker-config.json" --dashboard-api-key "${{ secrets.STRYKER_DASHBOARD_API_KEY }}" --version ${{ env.BRANCH_NAME }} --output ${{ env.StrykerDirectory }}
- run: |
cat ${{ env.StrykerDirectory }}/reports/mutation-report.md >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "View the [full report](https://dashboard.stryker-mutator.io/reports/github.com/egil/TimeProviderExtensions/${{ env.BRANCH_NAME }})." >> $GITHUB_STEP_SUMMARY
- name: Stryker Report
if: github.actor != 'dependabot[bot]' && (success() || failure()) && github.repository_owner == 'egil'
uses: Sibz/github-status-action@v1
with:
authToken: ${{secrets.GITHUB_TOKEN}}
context: stryker-report"
description: "See report"
state: ${{ steps.stryker.conclusion }}
sha: ${{ github.event.pull_request.head.sha || github.sha }}
target_url: https://dashboard.stryker-mutator.io/reports/github.com/egil/TimeProviderExtensions/${{ env.BRANCH_NAME }}

- uses: actions/upload-artifact@v3
if: steps.stryker.conclusion == 'success' || steps.stryker.conclusion == 'failure'
with:
name: stryker-reports
if-no-files-found: error
retention-days: 3
path: ${{ env.StrykerDirectory }}/**/*

dependency-review:
runs-on: ubuntu-latest
Expand All @@ -192,10 +183,7 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v3
with:
dotnet-version: |
3.1.x
6.0.x
8.0.x
dotnet-version: 8.0.x

- run: dotnet build --configuration Release

Expand Down Expand Up @@ -231,7 +219,7 @@ jobs:
# You can update this logic if you want to manage releases differently
if: github.event_name == 'release'
runs-on: ubuntu-latest
needs: [ validate-nuget ]
needs: [ validate-nuget, run-test ]
steps:
- uses: actions/download-artifact@v3
with:
Expand Down
18 changes: 17 additions & 1 deletion Htmxor.sln
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,13 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HtmxBlazorSSR", "samples\Ht
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{A50FFB42-310B-45BC-BDDF-ADE3B61D61EB}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Htmxor", "src\Htmxor\Htmxor.csproj", "{8E83BAAD-08DC-4CAC-AFE7-5E82D5FCAF41}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Htmxor", "src\Htmxor\Htmxor.csproj", "{8E83BAAD-08DC-4CAC-AFE7-5E82D5FCAF41}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{BB63193F-EEC0-4EE6-B89E-9B4E1983E2FF}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Htmxor.Tests", "test\Htmxor.Tests\Htmxor.Tests.csproj", "{DBF3F19B-27E8-4971-BDCF-ECC021D55BFA}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Htmxor.TestApp", "test\Htmxor.TestApp\Htmxor.TestApp.csproj", "{0347D883-0078-4F68-BA24-DA7E3004D31D}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand All @@ -38,6 +44,14 @@ Global
{8E83BAAD-08DC-4CAC-AFE7-5E82D5FCAF41}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8E83BAAD-08DC-4CAC-AFE7-5E82D5FCAF41}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8E83BAAD-08DC-4CAC-AFE7-5E82D5FCAF41}.Release|Any CPU.Build.0 = Release|Any CPU
{DBF3F19B-27E8-4971-BDCF-ECC021D55BFA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DBF3F19B-27E8-4971-BDCF-ECC021D55BFA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DBF3F19B-27E8-4971-BDCF-ECC021D55BFA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DBF3F19B-27E8-4971-BDCF-ECC021D55BFA}.Release|Any CPU.Build.0 = Release|Any CPU
{0347D883-0078-4F68-BA24-DA7E3004D31D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0347D883-0078-4F68-BA24-DA7E3004D31D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0347D883-0078-4F68-BA24-DA7E3004D31D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0347D883-0078-4F68-BA24-DA7E3004D31D}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -46,6 +60,8 @@ Global
{7058400A-CF52-44D4-8AB1-A5D3B1248E09} = {8D4A2D7D-532C-4B68-B5D0-17873D49FB0D}
{AF1A487F-CE27-48EB-8390-04C5EC1F34F8} = {8D4A2D7D-532C-4B68-B5D0-17873D49FB0D}
{8E83BAAD-08DC-4CAC-AFE7-5E82D5FCAF41} = {A50FFB42-310B-45BC-BDDF-ADE3B61D61EB}
{DBF3F19B-27E8-4971-BDCF-ECC021D55BFA} = {BB63193F-EEC0-4EE6-B89E-9B4E1983E2FF}
{0347D883-0078-4F68-BA24-DA7E3004D31D} = {BB63193F-EEC0-4EE6-B89E-9B4E1983E2FF}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {430F7B4E-864E-44B7-84A0-A903E7386E3B}
Expand Down
25 changes: 11 additions & 14 deletions src/Htmxor/Configuration/HtmxConfig.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Text.Json.Serialization.Metadata;
using Htmxor.Antiforgery;
using Htmxor.Configuration.Serialization;

namespace Htmxor.Configuration;

Expand All @@ -9,15 +11,10 @@ namespace Htmxor.Configuration;
/// </summary>
public record class HtmxConfig
{
public readonly static JsonSerializerOptions SerializerOptions = new()
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
Converters =
{
new JsonStringEnumConverter(JsonNamingPolicy.CamelCase, allowIntegerValues: false),
},
};
/// <summary>
/// Default <see cref="JsonSerializerOptions"/> used with <see cref="HtmxConfig"/>.
/// </summary>
public readonly static JsonTypeInfo<HtmxConfig> JsonTypeInfo = HtmxConfigJsonSerializerContext.Default.HtmxConfig;

/// <summary>
/// Defaults to <see langword="true" /> if this property is null. really only useful for testing
Expand Down Expand Up @@ -48,13 +45,13 @@ public record class HtmxConfig
/// Defaults to <see langword="0"/> if this property is null.
/// </summary>
[JsonPropertyName("defaultSwapDelay")]
public int? DefaultSwapDelay { get; set; }
public TimeSpan? DefaultSwapDelay { get; set; }

/// <summary>
/// Defaults to <see langword="20"/> if this property is null.
/// </summary>
[JsonPropertyName("defaultSettleDelay")]
public int? DefaultSettleDelay { get; set; }
public TimeSpan? DefaultSettleDelay { get; set; }

/// <summary>
/// Defaults to <see langword="true" /> if this property is null.
Expand Down Expand Up @@ -160,7 +157,7 @@ public record class HtmxConfig
/// The number of milliseconds a request can take before automatically being terminated
/// </summary>
[JsonPropertyName("timeout")]
public int? Timeout { get; set; }
public TimeSpan? Timeout { get; set; }

/// <summary>
/// Defaults to <see cref="ScrollBehavior.Smooth" /> if this property is null.
Expand Down Expand Up @@ -203,7 +200,7 @@ public record class HtmxConfig
/// If set to <see langword="true" /> will only allow AJAX requests to the same domain as the current document.
/// </summary>
[JsonPropertyName("selfRequestsOnly")]
public bool? SelfRequestsOnly { get; set; }
public bool SelfRequestsOnly { get; set; } = true;

/// <summary>
/// Defaults to <see langword="false" /> if this property is null.
Expand All @@ -220,6 +217,6 @@ public record class HtmxConfig
[JsonPropertyName("scrollIntoViewOnBoost")]
public bool? ScrollIntoViewOnBoost { get; set; }

[JsonInclude]
[JsonInclude, JsonPropertyName("antiforgery")]
internal HtmxAntiforgeryOptions? Antiforgery { get; init; }
}
16 changes: 14 additions & 2 deletions src/Htmxor/Configuration/HtmxConfigHeadOutlet.cs
Original file line number Diff line number Diff line change
@@ -1,20 +1,32 @@
using Microsoft.AspNetCore.Components;
using Htmxor.Configuration.Serialization;
using Microsoft.AspNetCore.Components;
using System.Text.Json;

namespace Htmxor.Configuration;

/// <summary>
/// This component will render a meta tag with the serialized <see cref="HtmxConfig"/> object,
/// enabling customization of Htmx.
/// </summary>
/// <remarks>
/// Configure the <see cref="HtmxConfig"/> via the
/// <see cref="HtmxorApplicationBuilderExtensions.AddHtmx(Microsoft.Extensions.Hosting.IHostApplicationBuilder, Action{Htmxor.Configuration.HtmxConfig}?)"/>
/// method.
/// </remarks>
public class HtmxConfigHeadOutlet : IComponent
{
[Inject] private HtmxConfig Config { get; set; } = default!;

/// <inheritdoc/>
public void Attach(RenderHandle renderHandle)
{
var json = JsonSerializer.Serialize(Config, HtmxConfig.SerializerOptions);
var json = JsonSerializer.Serialize(Config, HtmxConfigJsonSerializerContext.Default.HtmxConfig);
renderHandle.Render(builder =>
{
builder.AddMarkupContent(0, @$"<meta name=""htmx-config"" content='{json}'>");
});
}

/// <inheritdoc/>
public Task SetParametersAsync(ParameterView parameters) => Task.CompletedTask;
}
9 changes: 9 additions & 0 deletions src/Htmxor/Configuration/ScrollBehavior.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,17 @@
namespace Htmxor.Configuration;

/// <summary>
/// The behavior for a boosted link on page transitions.
/// </summary>
public enum ScrollBehavior
{
/// <summary>
/// Smooth will smooth-scroll to the top of the page.
/// </summary>
Smooth,
/// <summary>
/// Auto will behave like a vanilla link.
/// </summary>
Auto,
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using System.Text.Json.Serialization;

namespace Htmxor.Configuration.Serialization;

[JsonSourceGenerationOptions(

Check warning on line 5 in src/Htmxor/Configuration/Serialization/HtmxConfigJsonSerializerContext.cs

View workflow job for this annotation

GitHub Actions / create-nuget

The member 'Htmxor.Configuration.Serialization.HtmxConfigJsonSerializerContext' has been annotated with 'JsonStringEnumConverter' which is not supported in native AOT. Consider using the generic 'JsonStringEnumConverter<TEnum>' instead. (https://learn.microsoft.com/dotnet/fundamentals/syslib-diagnostics/syslib1034)

Check warning on line 5 in src/Htmxor/Configuration/Serialization/HtmxConfigJsonSerializerContext.cs

View workflow job for this annotation

GitHub Actions / infer-sharp

The member 'Htmxor.Configuration.Serialization.HtmxConfigJsonSerializerContext' has been annotated with 'JsonStringEnumConverter' which is not supported in native AOT. Consider using the generic 'JsonStringEnumConverter<TEnum>' instead. (https://learn.microsoft.com/dotnet/fundamentals/syslib-diagnostics/syslib1034)

Check warning on line 5 in src/Htmxor/Configuration/Serialization/HtmxConfigJsonSerializerContext.cs

View workflow job for this annotation

GitHub Actions / run-test (net8.0)

The member 'Htmxor.Configuration.Serialization.HtmxConfigJsonSerializerContext' has been annotated with 'JsonStringEnumConverter' which is not supported in native AOT. Consider using the generic 'JsonStringEnumConverter<TEnum>' instead. (https://learn.microsoft.com/dotnet/fundamentals/syslib-diagnostics/syslib1034)
PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase,
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
Converters = [typeof(JsonCamelCaseStringEnumConverter), typeof(TimespanMillisecondJsonConverter)])]
[JsonSerializable(typeof(HtmxConfig))]
internal sealed partial class HtmxConfigJsonSerializerContext : JsonSerializerContext
{
}
Loading

0 comments on commit 08bd0a4

Please sign in to comment.