Add tests; tweak API; add pkg items

This commit is contained in:
Daniel J. Summers 2025-01-28 22:48:42 -05:00
parent 7e013f8225
commit eab2ced1c7
7 changed files with 175 additions and 28 deletions

View File

@ -2,7 +2,7 @@
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<TargetFrameworks>net8.0;net9.0</TargetFrameworks>
<VersionPrefix>0.2.2</VersionPrefix>
<VersionPrefix>0.5.7</VersionPrefix>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<PackageReleaseNotes>Initial version</PackageReleaseNotes>
<Authors>danieljsummers</Authors>

View File

@ -1,7 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<Description>Fixi integration for Giraffe and Giraffe View Engine</Description>
<PackageReadmeFile>README.md</PackageReadmeFile>
</PropertyGroup>
<ItemGroup>
<Compile Include="Library.fs" />
<None Include="README.md" Pack="true" PackagePath="\" />
<None Include="icon.png" Pack="true" PackagePath="\" />
</ItemGroup>
<ItemGroup>

View File

@ -6,35 +6,35 @@ open Microsoft.Extensions.Primitives
/// Module to hold extensions
[<AutoOpen>]
module Extensions =
/// Extensions to the header dictionary
type IHeaderDictionary with
/// <summary>Indicates that the request was generated from fixi</summary>
member this.FxRequest
member this.IsFixiRequest
with get () = not (this["FX-Request"] = StringValues.Empty)
/// <summary>Valid values for the <c>fx-swap</c> attribute</summary>
type FxSwap =
type FixiSwap =
/// <summary>Replace the entire target element with the response (the default)</summary>
| OuterHtml
/// <summary>Replace the inner HTML of the target element</summary>
| InnerHtml
/// <summary>Insert the response before the target element</summary>
| BeforeBegin
/// <summary>Insert the response before the first child of the target element</summary>
| AfterBegin
/// <summary>Insert the response after the last child of the target element</summary>
| BeforeEnd
/// <summary>Insert the response after the target element</summary>
| AfterEnd
override this.ToString() =
match this with
| OuterHtml -> "outerHTML"
@ -44,42 +44,42 @@ type FxSwap =
| BeforeEnd -> "beforeend"
| AfterEnd -> "afterend"
open Giraffe.ViewEngine
/// <summary>Attributes and flags for fixi</summary>
[<AutoOpen>]
module FixiAttrs =
/// <summary>Issue a request to the given URL</summary>
/// <param name="url">The URL to which the request should be issued</param>
/// <returns>A configured <c>fx-action</c> attribute</returns>
let _fxAction url =
attr "fx-action" url
/// <summary>Exclude this element (and below) from fixi's behavior</summary>
let _fxIgnore =
flag "fx-ignore"
/// <summary>Specify the HTTP method for the fixi request</summary>
/// <param name="it">The HTTP method to use for the request</param>
/// <returns>A configured <c>fx-method</c> attribute</returns>
/// <remarks>Consider <c>_fxGet</c>, <c>_fxPost</c>, etc.</remarks>
let _fxMethod (it: string) =
attr "fx-method" (it.ToUpperInvariant())
/// <summary>Specify the swap strategy</summary>
/// <param name="swap">The swap strategy to use</param>
/// <returns>A configured <c>fx-swap</c> attribute</returns>
let _fxSwap (swap: FxSwap) =
let _fxSwap (swap: FixiSwap) =
attr "fx-swap" (string swap)
/// <summary>Specify the target for the swap</summary>
/// <param name="selector">The CSS selector for the swap target</param>
/// <returns>A configured <c>fx-target</c> attribute</returns>
let _fxTarget selector =
attr "fx-target" selector
/// <summary>The event which should trigger this request</summary>
/// <param name="event">The name of the event</param>
/// <returns>A configured <c>fx-trigger</c> attribute</returns>
@ -90,27 +90,27 @@ module FixiAttrs =
/// <summary>Canned <c>fx-method</c> attributes for common HTTP methods</summary>
[<AutoOpen>]
module FixiMethods =
/// <summary>An <c>fx-method="DELETE"</c> attribute</summary>
let _fxDelete =
_fxMethod "DELETE"
/// <summary>An <c>fx-method="HEAD"</c> attribute</summary>
let _fxHead =
_fxMethod "HEAD"
/// <summary>An <c>fx-method="GET"</c> attribute</summary>
let _fxGet =
_fxMethod "GET"
/// <summary>An <c>fx-method="PATCH"</c> attribute</summary>
let _fxPatch =
_fxMethod "PATCH"
/// <summary>An <c>fx-method="POST"</c> attribute</summary>
let _fxPost =
_fxMethod "POST"
/// <summary>An <c>fx-method="PUT"</c> attribute</summary>
let _fxPut =
_fxMethod "PUT"

21
src/Library/README.md Normal file
View File

@ -0,0 +1,21 @@
# Giraffe.Fixi
[fixi](https://github.com/bigskysoftware/fixi) is a minimalist implementation of generalized hypermedia controls. It can be considered a very slimmed-down version of libraries like [htmx](https://htmx.org).
## Getting fixi and Giraffe.Fixi
fixi is designed to be vendored and served with an application. There are instructions on its page that detail how to obtain a copy. Once it is in your project, either ensure it is somewhere like `wwwroot`, or otherwise add it to your project file so that it will be included in your build.
As you are reading a NuGet package README, we will assume you know how to install this library.
## Using
On the server side, this library adds an `IsFixiRequest` property to `HttpContext`, which will return `true` if the request was generated from fixi.
In the view engine, each of fixi's six attributes have counterparts; for example, to generate an `fx-action` attribute, use `_fxAction`. Each of these take a string parameter, except for `_fxSwap`, which requires an instance of `FixiSwap`; and `_fxIgnore`, which requires no parameters at all.
Additionally, there are six attributes with the most common HTTP methods; using `_fxDelete`, `_fxHead`, `_fxGet`, `_fxPatch`, `_fxPost`, and `_fxPut` will be quicker (and less error-prone) than `_fxMethod "get"`, for example.
## Updating
This library was built in conjunction with fixi v0.5.7. Given the nature of its minimalist API, and the fact that there are no version-specific CDN links, this library will likely continue to work with future versions. (There may be more upgrades for .NET or Giraffe than will be required to change the fixi API.)

BIN
src/Library/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

View File

@ -9,4 +9,12 @@
<Compile Include="Program.fs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Library\Giraffe.Fixi.fsproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Expecto" Version="10.2.1" />
</ItemGroup>
</Project>

View File

@ -1,2 +1,112 @@
// For more information see https://aka.ms/fsharp-console-apps
printfn "Hello from F#"
/// Unit tests for Giraffe.Fixi
module FixiTests
open Expecto
open Giraffe.ViewEngine
/// Custom expectation for this test
module Expect =
/// Expect the rendered node to match the given HTML markup text
let html node markup =
Expect.equal (RenderView.AsString.htmlNode node) markup "Rendered HTML incorrect"
open Giraffe.Fixi
/// Tests for the FixiSwap type
let swap =
testList "FixiSwap" [
test "OuterHtml is correct" {
Expect.equal (string FixiSwap.OuterHtml) "outerHTML" "Outer HTML swap value incorrect"
}
test "InnerHtml is correct" {
Expect.equal (string FixiSwap.InnerHtml) "innerHTML" "Inner HTML swap value incorrect"
}
test "BeforeBegin is correct" {
Expect.equal (string FixiSwap.BeforeBegin) "beforebegin" "Before Begin swap value incorrect"
}
test "BeforeEnd is correct" {
Expect.equal (string FixiSwap.BeforeEnd) "beforeend" "Before End swap value incorrect"
}
test "AfterBegin is correct" {
Expect.equal (string FixiSwap.AfterBegin) "afterbegin" "After Begin swap value incorrect"
}
test "AfterEnd is correct" {
Expect.equal (string FixiSwap.AfterEnd) "afterend" "After End swap value incorrect"
}
]
/// Tests for the FixiAttrs module
let attributes =
testList "FixiAttrs" [
test "_fxAction succeeds" {
Expect.html (div [ _fxAction "/do-this" ] []) """<div fx-action="/do-this"></div>"""
}
test "_fxIgnore succeeds" {
Expect.html (span [ _fxIgnore ] [ rawText "this" ]) """<span fx-ignore>this</span>"""
}
test "_fxMethod succeeds" {
Expect.html (button [ _fxMethod "options" ] []) """<button fx-method="OPTIONS"></button>"""
}
test "_fxSwap succeeds" {
Expect.html (p [ _fxSwap FixiSwap.InnerHtml ] []) """<p fx-swap="innerHTML"></p>"""
}
test "_fxTarget succeeds" {
Expect.html (button [ _fxTarget "#target" ] []) """<button fx-target="#target"></button>"""
}
test "_fxTrigger succeeds" {
Expect.html (strong [ _fxTrigger "blur" ] []) """<strong fx-trigger="blur"></strong>"""
}
]
/// Tests for the FixiMethods module
let methods =
testList "FixiMethods" [
test "_fxDelete succeeds" {
match _fxDelete with
| XmlAttribute.KeyValue(attr, value) ->
Expect.equal attr "fx-method" "The attribute key is incorrect"
Expect.equal value "DELETE" "The attribute value is incorrect"
| XmlAttribute.Boolean _ -> Expect.isTrue false "The _fxDelete attribute is incorrect"
}
test "_fxHead succeeds" {
match _fxHead with
| XmlAttribute.KeyValue(attr, value) ->
Expect.equal attr "fx-method" "The attribute key is incorrect"
Expect.equal value "HEAD" "The attribute value is incorrect"
| XmlAttribute.Boolean _ -> Expect.isTrue false "The _fxHead attribute is incorrect"
}
test "_fxGet succeeds" {
match _fxGet with
| XmlAttribute.KeyValue(attr, value) ->
Expect.equal attr "fx-method" "The attribute key is incorrect"
Expect.equal value "GET" "The attribute value is incorrect"
| XmlAttribute.Boolean _ -> Expect.isTrue false "The _fxGet attribute is incorrect"
}
test "_fxPatch succeeds" {
match _fxPatch with
| XmlAttribute.KeyValue(attr, value) ->
Expect.equal attr "fx-method" "The attribute key is incorrect"
Expect.equal value "PATCH" "The attribute value is incorrect"
| XmlAttribute.Boolean _ -> Expect.isTrue false "The _fxPatch attribute is incorrect"
}
test "_fxPost succeeds" {
match _fxPost with
| XmlAttribute.KeyValue(attr, value) ->
Expect.equal attr "fx-method" "The attribute key is incorrect"
Expect.equal value "POST" "The attribute value is incorrect"
| XmlAttribute.Boolean _ -> Expect.isTrue false "The _fxPost attribute is incorrect"
}
test "_fxPut succeeds" {
match _fxPut with
| XmlAttribute.KeyValue(attr, value) ->
Expect.equal attr "fx-method" "The attribute key is incorrect"
Expect.equal value "PUT" "The attribute value is incorrect"
| XmlAttribute.Boolean _ -> Expect.isTrue false "The _fxPut attribute is incorrect"
}
]
let allTests = testList "Giraffe.Fixi" [ swap; attributes; methods ]
[<EntryPoint>]
let main args = runTestsWithCLIArgs [] args allTests