diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index 37d690bf..54b36ffd 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -3,7 +3,7 @@ "isRoot": true, "tools": { "paket": { - "version": "5.223.0", + "version": "5.224.0", "commands": [ "paket" ] diff --git a/paket.dependencies b/paket.dependencies index dc0689d9..cdb1706b 100644 --- a/paket.dependencies +++ b/paket.dependencies @@ -29,6 +29,7 @@ nuget Selenium.WebDriver.ChromeDriver github fsprojects/FSharp.TypeProviders.SDK src/ProvidedTypes.fsi github fsprojects/FSharp.TypeProviders.SDK src/ProvidedTypes.fs nuget Nerdbank.GitVersioning copy_local: true +nuget Unquote group fake source https://api.nuget.org/v3/index.json @@ -40,4 +41,4 @@ nuget Fake.IO.FileSystem nuget Fake.DotNet.AssemblyInfoFile nuget Fake.DotNet.Cli nuget Fake.DotNet.Paket -nuget FSharp.Data ~> 3.0-beta +nuget FSharp.Data ~> 3.0-beta \ No newline at end of file diff --git a/paket.lock b/paket.lock index 625ab91c..b77e0816 100644 --- a/paket.lock +++ b/paket.lock @@ -63,7 +63,7 @@ NUGET Microsoft.AspNetCore.SpaServices.Extensions (3.0) - restriction: || (== netcoreapp3.0) (&& (== netstandard2.0) (>= netcoreapp3.0)) Microsoft.AspNetCore.SpaServices (>= 3.0) - restriction: || (== netcoreapp3.0) (&& (== netstandard2.0) (>= netcoreapp3.0)) Microsoft.Extensions.FileProviders.Physical (>= 3.0) - restriction: || (== netcoreapp3.0) (&& (== netstandard2.0) (>= netcoreapp3.0)) - Microsoft.Build.Framework (16.0.461) + Microsoft.Build.Framework (16.3) System.Runtime.Serialization.Primitives (>= 4.1.1) System.Threading.Thread (>= 4.0) Microsoft.Build.Utilities.Core (15.9.20) @@ -72,17 +72,17 @@ NUGET System.Collections.Immutable (>= 1.5) System.Runtime.InteropServices.RuntimeInformation (>= 4.3) System.Text.Encoding.CodePages (>= 4.4) - Microsoft.CodeAnalysis.Analyzers (2.9.4) - restriction: || (== netcoreapp3.0) (&& (== netstandard2.0) (>= netcoreapp3.0)) - Microsoft.CodeAnalysis.Common (3.3) - restriction: || (== netcoreapp3.0) (&& (== netstandard2.0) (>= netcoreapp3.0)) - Microsoft.CodeAnalysis.Analyzers (>= 2.9.3) + Microsoft.CodeAnalysis.Analyzers (2.9.6) - restriction: || (== netcoreapp3.0) (&& (== netstandard2.0) (>= netcoreapp3.0)) + Microsoft.CodeAnalysis.Common (3.3.1) - restriction: || (== netcoreapp3.0) (&& (== netstandard2.0) (>= netcoreapp3.0)) + Microsoft.CodeAnalysis.Analyzers (>= 2.9.4) System.Collections.Immutable (>= 1.5) System.Memory (>= 4.5.3) System.Reflection.Metadata (>= 1.6) System.Runtime.CompilerServices.Unsafe (>= 4.5.2) System.Text.Encoding.CodePages (>= 4.5.1) System.Threading.Tasks.Extensions (>= 4.5.3) - Microsoft.CodeAnalysis.CSharp (3.3) - restriction: || (== netcoreapp3.0) (&& (== netstandard2.0) (>= netcoreapp3.0)) - Microsoft.CodeAnalysis.Common (3.3) + Microsoft.CodeAnalysis.CSharp (3.3.1) - restriction: || (== netcoreapp3.0) (&& (== netstandard2.0) (>= netcoreapp3.0)) + Microsoft.CodeAnalysis.Common (3.3.1) Microsoft.CodeAnalysis.Razor (3.0) - restriction: || (== netcoreapp3.0) (&& (== netstandard2.0) (>= netcoreapp3.0)) Microsoft.AspNetCore.Razor.Language (>= 3.0) Microsoft.CodeAnalysis.Common (>= 3.3) @@ -173,11 +173,11 @@ NUGET System.Threading (>= 4.3) Mono.WebAssembly.Interop (3.0) Microsoft.JSInterop (>= 3.0) - Nerdbank.GitVersioning (3.0.25) - copy_local: true + Nerdbank.GitVersioning (3.0.26) - copy_local: true NETStandard.Library (2.0.3) Microsoft.NETCore.Platforms (>= 1.1) Newtonsoft.Json (12.0.2) - NuGet.Frameworks (5.2) - restriction: || (== netcoreapp3.0) (&& (== netstandard2.0) (>= netcoreapp1.0) (>= uap10.0)) (&& (== netstandard2.0) (>= netcoreapp2.1)) + NuGet.Frameworks (5.3) - restriction: || (== netcoreapp3.0) (&& (== netstandard2.0) (>= netcoreapp1.0) (>= uap10.0)) (&& (== netstandard2.0) (>= netcoreapp2.1)) nunit (3.12) NETStandard.Library (>= 2.0) NUnit3TestAdapter (3.15.1) @@ -633,6 +633,8 @@ NUGET FSharp.Core (>= 4.1.17) NETStandard.Library (>= 1.6.1) System.ValueTuple (>= 4.4) + Unquote (4.0) + FSharp.Core (>= 4.2.3) GITHUB remote: fsprojects/FSharp.TypeProviders.SDK src/ProvidedTypes.fs (b8727a47dd83d3e88aed8f2100f6712478c64632) diff --git a/tests/Unit/Fixture.fs b/tests/Unit/Fixture.fs index 7d4152f2..77713efc 100644 --- a/tests/Unit/Fixture.fs +++ b/tests/Unit/Fixture.fs @@ -24,12 +24,15 @@ open System open System.Threading.Tasks open Microsoft.AspNetCore open Microsoft.AspNetCore.Hosting +open FSharp.Quotations open NUnit.Framework open OpenQA.Selenium open OpenQA.Selenium.Chrome // open OpenQA.Selenium.Firefox open OpenQA.Selenium.Remote open OpenQA.Selenium.Support.UI +open Swensen.Unquote +open Bolero.Tests /// Defines the setup/teardown for all tests that use the web server and Selenium. /// These web tests must be located in the namespace Bolero.Tests.Web @@ -136,28 +139,24 @@ and NodeFixture(parent: unit -> IWebElement, by: By) = timeout |> Option.defaultWith (fun () -> TimeSpan.FromSeconds(5.))) .Until(fun _ -> cond()) - /// NUnit assertion that the given condition eventually becomes non-null non-false. - member this.AssertEventually(cond, ?message, ?timeout) = - let run() = - match this.Wait(cond, ?timeout = timeout) |> box with - | :? bool as b -> Assert.IsTrue(b) - | x -> Assert.IsNotNull(x) - match message with - | None -> Assert.DoesNotThrow(TestDelegate run) - | Some m -> Assert.DoesNotThrow(TestDelegate run, m) - - /// NUnit assertion that the actual value eventually becomes equal to the expected value. - member this.AssertAreEqualEventually(expected, getActual, ?message: string, ?timeout) = - let mutable actual = Unchecked.defaultof<_> - try this.Wait( - (fun () -> - actual <- getActual() - expected = actual), - ?timeout = timeout) |> ignore - with :? WebDriverTimeoutException -> () - match message with - | None -> Assert.AreEqual(expected, actual) - | Some m -> Assert.AreEqual(expected, actual, m) + member private this.WaitOrFalse(f: unit -> bool) = + try this.Wait(f) + with :? WebDriverTimeoutException -> false + + /// Assert that the given test eventually succeeds. + member this.Eventually(expr: Expr) = + if not (this.WaitOrFalse(fun () -> eval expr)) then + test expr + + /// Assert that the given value is eventually null. + member this.EventuallyNull<'T when 'T : null>(expr: Expr<'T>) = + if not (this.WaitOrFalse(fun () -> isNull <| eval expr)) then + testNull expr + + /// Assert that the given value is eventually non-null. + member this.EventuallyNotNull<'T when 'T : null>(expr: Expr<'T>) = + if not (this.WaitOrFalse(fun () -> isNotNull <| eval expr)) then + testNotNull expr [] module Extensions = diff --git a/tests/Unit/Tests/Elmish.fs b/tests/Unit/Tests/Elmish.fs index ea36fc18..a93155e3 100644 --- a/tests/Unit/Tests/Elmish.fs +++ b/tests/Unit/Tests/Elmish.fs @@ -2,6 +2,8 @@ namespace Bolero.Tests.Web open NUnit.Framework open OpenQA.Selenium +open Swensen.Unquote +open Bolero.Tests /// Elmish program integration. [] @@ -11,29 +13,23 @@ module Elmish = [] let ``ProgramComponent is rendered``() = - Assert.IsNotNull(elt.ByClass("container")) - Assert.AreEqual( - "constant value", - elt.ByClass("constValue-input").GetAttribute("value")) + testNotNull <@ elt.ByClass("container") @> + test <@ elt.ByClass("constValue-input").GetAttribute("value") = "constant value" @> [] let ``Input event handler dispatches message``() = let el = elt.ByClass("stringValue-input") el.SendKeys("Changed!") el.SendKeys(Keys.Backspace) - elt.AssertAreEqualEventually( - "stringValueInitChanged", - (fun () -> elt.ByClass("stringValue-repeat").Text), - "Element not updated") + elt.Eventually <@ elt.ByClass("stringValue-repeat").Text = "stringValueInitChanged" @> [] let ``ElmishComponent is rendered``() = - Assert.IsNotNull(elt.ByClass("intValue-input")) + testNotNull <@ elt.ByClass("intValue-input") @> [] let ``ElmishComponent dispatches message``() = let el = elt.ByClass("intValue-input") el.Clear() el.SendKeys("35") - elt.AssertEventually((fun () -> - elt.ByClass("intValue-repeat").Text = "35")) + elt.Eventually <@ elt.ByClass("intValue-repeat").Text = "35" @> diff --git a/tests/Unit/Tests/Html.fs b/tests/Unit/Tests/Html.fs index 353798fe..b8aeb6dd 100644 --- a/tests/Unit/Tests/Html.fs +++ b/tests/Unit/Tests/Html.fs @@ -2,6 +2,8 @@ namespace Bolero.Tests.Web open NUnit.Framework open OpenQA.Selenium +open Swensen.Unquote +open Bolero.Tests /// Basic HTML functionality: node and attribute functions, Blazor components. [] @@ -16,149 +18,144 @@ module Html = [] let ``Element with id and text content``() = - Assert.AreEqual( - "Contents of element with id", - elt.ById("element-with-id").Text) + test <@ elt.ById("element-with-id").Text = "Contents of element with id" @> [] let ``Element with content that must be escaped``() = - Assert.AreEqual( - "Escaped text & content", - elt.ById("element-with-htmlentity").Text) + test <@ elt.ById("element-with-htmlentity").Text = "Escaped text & content" @> [] let ``Element with classes``() = - Assert.IsNull(elt.ByClass("class-notset-1"), "class-notset-1") - Assert.IsNull(elt.ByClass("class-notset-2"), "class-notset-2") - Assert.IsNotNull(elt.ByClass("class-set-1"), "class-set-1") - Assert.IsNotNull(elt.ByClass("class-set-2"), "class-set-2") - Assert.IsNotNull(elt.ByClass("class-set-3"), "class-set-3") - Assert.IsNotNull(elt.ByClass("class-set-4"), "class-set-4") - Assert.IsNotNull(elt.ByClass("class-set-5"), "class-set-5") + testNull <@ elt.ByClass("class-notset-1") @> + testNull <@ elt.ByClass("class-notset-2") @> + testNotNull <@ elt.ByClass("class-set-1") @> + testNotNull <@ elt.ByClass("class-set-2") @> + testNotNull <@ elt.ByClass("class-set-3") @> + testNotNull <@ elt.ByClass("class-set-4") @> + testNotNull <@ elt.ByClass("class-set-5") @> [] let ``Raw HTML``() = - Assert.AreEqual( - "Unescape text & content", - elt.ByClass("raw-html-element").Text) + test <@ elt.ByClass("raw-html-element").Text = "Unescape text & content" @> [] let ``Blazor Component``() = let navLink = elt.ById("nav-link") - Assert.AreEqual("active", navLink.GetAttribute("class")) - Assert.AreEqual("NavLink content", navLink.Text) + test <@ navLink.GetAttribute("class") = "active" @> + test <@ navLink.Text = "NavLink content" @> [] let ``Bolero Component``() = - Assert.AreEqual("Component content", elt.ById("bolero-component").Text) + test <@ elt.ById("bolero-component").Text = "Component content" @> [] let ``Boolean cond reacts to events``() = let inp = elt.ByClass("condBoolInput") inp.Clear() + inp.SendKeys("ab") - elt.AssertEventually(fun () -> - elt.ByClass("condBoolIs2")) - Assert.IsNull(elt.ByClass("condBoolIsNot2")) + elt.EventuallyNotNull <@ elt.ByClass("condBoolIs2") @> + testNull <@ elt.ByClass("condBoolIsNot2") @> + inp.SendKeys("c") - elt.AssertEventually(fun () -> - elt.ByClass("condBoolIsNot2")) - Assert.IsNull(elt.ByClass("condBoolIs2")) + elt.EventuallyNotNull <@ elt.ByClass("condBoolIsNot2") @> + testNull <@ elt.ByClass("condBoolIs2") @> [] let ``Union cond reacts to events``() = let inp = elt.ByClass("condUnionInput") inp.Clear() - elt.AssertEventually(fun () -> - elt.ByClass("condUnionIsEmpty")) - Assert.IsNull(elt.ByClass("condUnionIsOne")) - Assert.IsNull(elt.ByClass("condUnionIsMany")) + + elt.EventuallyNotNull <@ elt.ByClass("condUnionIsEmpty") @> + testNull <@ elt.ByClass("condUnionIsOne") @> + testNull <@ elt.ByClass("condUnionIsMany") @> + inp.SendKeys("a") - elt.AssertEventually(fun () -> - elt.ByClass("condUnionIsOne")) - Assert.IsNull(elt.ByClass("condUnionIsEmpty")) - Assert.IsNull(elt.ByClass("condUnionIsMany")) + elt.EventuallyNotNull <@ elt.ByClass("condUnionIsOne") @> + testNull <@ elt.ByClass("condUnionIsEmpty") @> + testNull <@ elt.ByClass("condUnionIsMany") @> + inp.SendKeys("b") - elt.AssertEventually(fun () -> - elt.ByClass("condUnionIsMany")) - Assert.IsNull(elt.ByClass("condUnionIsOne")) - Assert.IsNull(elt.ByClass("condUnionIsEmpty")) + elt.EventuallyNotNull <@ elt.ByClass("condUnionIsMany") @> + testNull <@ elt.ByClass("condUnionIsOne") @> + testNull <@ elt.ByClass("condUnionIsEmpty") @> [] let ``Render many forEach items``() = let inp = elt.ByClass("forEachInput") inp.Clear() + inp.SendKeys("ABC") - elt.AssertEventually(fun () -> - elt.ByClass("forEachIsA")) - Assert.IsNotNull(elt.ByClass("forEachIsB")) - Assert.IsNotNull(elt.ByClass("forEachIsC")) + elt.EventuallyNotNull <@ elt.ByClass("forEachIsA") @> + testNotNull <@ elt.ByClass("forEachIsB") @> + testNotNull <@ elt.ByClass("forEachIsC") @> + inp.SendKeys(Keys.Backspace) - elt.AssertEventually(fun () -> - isNull <| elt.ByClass("forEachIsC")) - Assert.IsNotNull(elt.ByClass("forEachIsA")) - Assert.IsNotNull(elt.ByClass("forEachIsB")) + elt.EventuallyNull <@ elt.ByClass("forEachIsC") @> + testNotNull <@ elt.ByClass("forEachIsA") @> + testNotNull <@ elt.ByClass("forEachIsB") @> [] let ``bind.input``() = let inp = elt.ByClass("bind-input") inp.Clear() + inp.SendKeys("ABC") - elt.AssertEventually(fun () -> - elt.ByClass("bind-input-out").Text = "ABC") + elt.Eventually <@ elt.ByClass("bind-input-out").Text = "ABC" @> [] let ``bind.change``() = let inp = elt.ByClass("bind-change") inp.Clear() + inp.SendKeys("DEF") blur() - elt.AssertEventually(fun () -> - elt.ByClass("bind-change-out").Text = "DEF") + elt.Eventually <@ elt.ByClass("bind-change-out").Text = "DEF" @> [] let ``bind.inputInt``() = let inp = elt.ByClass("bind-input-int") inp.Clear() - inp.SendKeys("123") - elt.AssertEventually(fun () -> - elt.ByClass("bind-input-int-out").Text = "123") + inp.SendKeys("123") + elt.Eventually <@ elt.ByClass("bind-input-int-out").Text = "123" @> [] let ``bind.changeInt``() = let inp = elt.ByClass("bind-change-int") inp.Clear() + inp.SendKeys("456") blur() - elt.AssertEventually(fun () -> - elt.ByClass("bind-change-int-out").Text = "456") + elt.Eventually <@ elt.ByClass("bind-change-int-out").Text = "456" @> [] let ``bind.inputFloat``() = let inp = elt.ByClass("bind-input-float") inp.Clear() + inp.SendKeys("1234.5") - elt.AssertEventually(fun () -> - elt.ByClass("bind-input-float-out").Text.TrimEnd('0') = "1234.5") + elt.Eventually <@ elt.ByClass("bind-input-float-out").Text.TrimEnd('0') = "1234.5" @> [] let ``bind.changeFloat``() = let inp = elt.ByClass("bind-change-float") inp.Clear() + inp.SendKeys("54.321") blur() - elt.AssertEventually(fun () -> - elt.ByClass("bind-change-float-out").Text.TrimEnd('0') = "54.321") + elt.Eventually <@ elt.ByClass("bind-change-float-out").Text.TrimEnd('0') = "54.321" @> [] let ``bind.checked``() = let inp = elt.ByClass("bind-checked") let out = elt.ByClass("bind-checked-out") - Assert.AreEqual(out.Text, "false") + test <@ out.Text = "false" @> + inp.Click() - elt.AssertEventually(fun () -> out.Text = "true") + elt.Eventually <@ out.Text = "true" @> + inp.Click() - elt.AssertEventually(fun () -> out.Text = "false") + elt.Eventually <@ out.Text = "false" @> [] let ``bind.change radio``() = @@ -166,19 +163,16 @@ module Html = for v in 1..10 do let inp = elt.ByClass("bind-radio-" + string v) inp.Click() - elt.AssertEventually(fun () -> out.Text = string v) + elt.Eventually <@ out.Text = string v @> [] let ElementRefBinder() = let btn = elt.ByClass("element-ref") - Assert.IsNotNull(btn) + testNotNull <@ btn @> btn.Click() - elt.AssertEventually( - (fun () -> btn.Text = "ElementRef 1 is bound"), - "attr.ref") + elt.Eventually <@ btn.Text = "ElementRef 1 is bound" @> + let btn = elt.ByClass("element-ref-binder") - Assert.IsNotNull(btn) + testNotNull <@ btn @> btn.Click() - elt.AssertEventually( - (fun () -> btn.Text = "ElementRef 2 is bound"), - "attr.bindRef") + elt.Eventually <@ btn.Text = "ElementRef 2 is bound" @> diff --git a/tests/Unit/Tests/Json.fs b/tests/Unit/Tests/Json.fs index 26c23241..ca4147f2 100644 --- a/tests/Unit/Tests/Json.fs +++ b/tests/Unit/Tests/Json.fs @@ -5,6 +5,7 @@ open System.Collections.Generic open NUnit.Framework open FsCheck.NUnit open FsCheck +open Swensen.Unquote module J = Bolero.Json [] @@ -14,197 +15,201 @@ module Json = [] let ``Serialize bool`` (x: bool) = - J.Serialize x .=. stringLow x + test <@ J.Serialize x = stringLow x @> [] let ``Deserialize bool`` (x: bool) = - J.Deserialize (stringLow x) .=. x + test <@ J.Deserialize (stringLow x) = x @> [] let ``Serialize int8`` (x: int8) = - J.Serialize x .=. string x + test <@ J.Serialize x = string x @> [] let ``Deserialize int8`` (x: int8) = - J.Deserialize (string x) .=. x + test <@ J.Deserialize (string x) = x @> [] let ``Serialize uint8`` (x: uint8) = - J.Serialize x .=. string x + test <@ J.Serialize x = string x @> [] let ``Deserialize uint8`` (x: uint8) = - J.Deserialize (string x) .=. x + test <@ J.Deserialize (string x) = x @> [] let ``Serialize int16`` (x: int16) = - J.Serialize x .=. string x + test <@ J.Serialize x = string x @> [] let ``Deserialize int16`` (x: int16) = - J.Deserialize (string x) .=. x + test <@ J.Deserialize (string x) = x @> [] let ``Serialize uint16`` (x: uint16) = - J.Serialize x .=. string x + test <@ J.Serialize x = string x @> [] let ``Deserialize uint16`` (x: uint16) = - J.Deserialize (string x) .=. x + test <@ J.Deserialize (string x) = x @> [] let ``Serialize int32`` (x: int32) = - J.Serialize x .=. string x + test <@ J.Serialize x = string x @> [] let ``Deserialize int32`` (x: int32) = - J.Deserialize (string x) .=. x + test <@ J.Deserialize (string x) = x @> [] let ``Serialize uint32`` (x: uint32) = - J.Serialize x .=. string x + test <@ J.Serialize x = string x @> [] let ``Deserialize uint32`` (x: uint32) = - J.Deserialize (string x) .=. x + test <@ J.Deserialize (string x) = x @> [] let ``Serialize int64`` (x: int64) = - J.Serialize x .=. string x + test <@ J.Serialize x = string x @> [] let ``Deserialize int64`` (x: int64) = - J.Deserialize (string x) .=. x + test <@ J.Deserialize (string x) = x @> [] let ``Serialize uint64`` (x: uint64) = - J.Serialize x .=. string x + test <@ J.Serialize x = string x @> [] let ``Deserialize uint64`` (x: uint64) = - J.Deserialize (string x) .=. x + test <@ J.Deserialize (string x) = x @> [] let ``Serialize float`` (NormalFloat x) = - J.Serialize x .=. string x + test <@ J.Serialize x = string x @> [] let ``Deserialize float`` (NormalFloat x) = - J.Deserialize (string x) .=~. x + test <@ J.Deserialize (string x) =~ x @> [] let ``Serialize pair`` (x: int, y: string as t) = - J.Encode t .=. J.Array [|J.Encode x; J.Encode y|] + test <@ J.Encode t = J.Array [|J.Encode x; J.Encode y|] @> [] let ``Deserialize pair`` (x: int, y: string as t) = - J.Decode (J.Array [|J.Encode x; J.Encode y|]) .=. t + test <@ J.Decode (J.Array [|J.Encode x; J.Encode y|]) = t @> [] let ``Serialize triple`` (x: int, y: string, z: bool as t) = - J.Encode t .=. J.Array [|J.Encode x; J.Encode y; J.Encode z|] + test <@ J.Encode t = J.Array [|J.Encode x; J.Encode y; J.Encode z|] @> [] let ``Deserialize triple`` (x: int, y: string, z: bool as t) = - J.Decode (J.Array [|J.Encode x; J.Encode y; J.Encode z|]) .=. t + test <@ J.Decode (J.Array [|J.Encode x; J.Encode y; J.Encode z|]) = t @> [] let ``Serialize list`` (l: list) = - J.Encode l .=. J.Array [| for i in l -> J.Encode i |] + test <@ J.Encode l = J.Array [| for i in l -> J.Encode i |] @> [] let ``Deserialize list`` (l: list) = - J.Decode (J.Array [| for i in l -> J.Encode i |]) .=. l + test <@ J.Decode (J.Array [| for i in l -> J.Encode i |]) = l @> [] let ``Serialize array`` (l: int[]) = - J.Encode l .=. J.Array [| for i in l -> J.Encode i |] + test <@ J.Encode l = J.Array [| for i in l -> J.Encode i |] @> [] let ``Deserialize array`` (l: int[]) = - J.Decode (J.Array [| for i in l -> J.Encode i |]) .=. l + test <@ J.Decode (J.Array [| for i in l -> J.Encode i |]) = l @> [] let ``Serialize queue`` (l: int[]) = let q = Queue(l) - J.Encode l .=. J.Array [| for i in q -> J.Encode i |] + test <@ J.Encode l = J.Array [| for i in q -> J.Encode i |] @> [] let ``Deserialize queue`` (l: int[]) = let q = Queue(l) - J.Decode (J.Array [| for i in q -> J.Encode i |]) .=. l + test <@ J.Decode (J.Array [| for i in q -> J.Encode i |]) = l @> [] let ``Serialize stack`` (l: int[]) = let s = Stack(l) - J.Encode l .=. J.Array (Array.rev [| for i in s -> J.Encode i |]) + test <@ J.Encode l = J.Array (Array.rev [| for i in s -> J.Encode i |]) @> [] let ``Deserialize stack`` (l: int[]) = let s = Stack(l) - J.Decode (J.Array (Array.rev [| for i in s -> J.Encode i |])) .=. l + test <@ J.Decode (J.Array (Array.rev [| for i in s -> J.Encode i |])) = l @> [] let ``Serialize set`` (l: Set) = - J.Encode l .=. J.Array [| for i in l -> J.Encode i |] + test <@ J.Encode l = J.Array [| for i in l -> J.Encode i |] @> [] let ``Deserialize set`` (l: Set) = - J.Decode (J.Array [| for i in l -> J.Encode i |]) .=. l + test <@ J.Decode (J.Array [| for i in l -> J.Encode i |]) = l @> [] let ``Serialize string map`` (l: Map) = - J.Encode l .=. J.Object [| for KeyValue(k, v) in l -> k, J.Encode v |] + test <@ J.Encode l = J.Object [| for KeyValue(k, v) in l -> k, J.Encode v |] @> [] let ``Deserialize string map`` (l: Map) = - J.Decode (J.Object [| for KeyValue(k, v) in l -> k, J.Encode v |]) .=. l + test <@ J.Decode (J.Object [| for KeyValue(k, v) in l -> k, J.Encode v |]) = l @> [] let ``Serialize non-string map`` (l: Map) = - J.Encode l .=. J.Array [| for KeyValue(k, v) in l -> J.Array [| J.Encode k; J.Encode v |] |] + test <@ J.Encode l = J.Array [| for KeyValue(k, v) in l -> J.Array [| J.Encode k; J.Encode v |] |] @> [] let ``Deserialize non-string map`` (l: Map) = - J.Decode (J.Array [| for KeyValue(k, v) in l -> J.Array [| J.Encode k; J.Encode v |] |]) .=. l + test <@ J.Decode (J.Array [| for KeyValue(k, v) in l -> J.Array [| J.Encode k; J.Encode v |] |]) = l @> [] let ``Serialize string dictionary`` (l: Dictionary) = - J.Encode l .=. J.Object [| for KeyValue(k, v) in l -> k, J.Encode v |] + test <@ J.Encode l = J.Object [| for KeyValue(k, v) in l -> k, J.Encode v |] @> [] let ``Deserialize string dictionary`` (l: Dictionary) = J.Decode> (J.Object [| for KeyValue(k, v) in l -> k, J.Encode v |]) - |> Seq.forall (fun (KeyValue(k, v)) -> l.[k] = v) + |> Seq.iter (fun (KeyValue(k, v)) -> test <@ l.[k] = v @>) [] let ``Serialize non-string dictionary`` (l: Dictionary) = - J.Encode l .=. J.Array [| for KeyValue(k, v) in l -> J.Array [| J.Encode k; J.Encode v |] |] + test <@ J.Encode l = J.Array [| for KeyValue(k, v) in l -> J.Array [| J.Encode k; J.Encode v |] |] @> [] let ``Deserialize non-string dictionary`` (l: Dictionary) = J.Decode> (J.Array [| for KeyValue(k, v) in l -> J.Array [| J.Encode k; J.Encode v |] |]) - |> Seq.forall (fun (KeyValue(k, v)) -> l.[k] = v) + |> Seq.iter (fun (KeyValue(k, v)) -> test <@ l.[k] = v @>) + + // We wrap `DateTime` in `ref` because otherwise the quotation tries and fails to use a `byref`. [] let ``Serialize UTC DateTime`` (d: DateTime) = - let d = d.ToUniversalTime() - J.Encode d .=. J.String (d.ToString("o")) + let d = ref (d.ToUniversalTime()) + test <@ J.Encode !d = J.String ((!d).ToString("o")) @> [] let ``Deserialize UTC DateTime`` (d: DateTime) = - let d = d.ToUniversalTime() - J.Decode (J.String (d.ToString("o"))) .=. d + let d = ref (d.ToUniversalTime()) + test <@ J.Decode (J.String ((!d).ToString("o"))) = !d @> [] let ``Serialize DateTimeOffset`` (d: DateTimeOffset) = - J.Encode d .=. J.String (d.ToString("o")) + let d = ref d + test <@ J.Encode !d = J.String ((!d).ToString("o")) @> [] let ``Deserialize DateTimeOffset`` (d: DateTimeOffset) = - J.Decode (J.String (d.ToString("o"))) .=. d + let d = ref d + test <@ J.Decode (J.String ((!d).ToString("o"))) = !d @> type SimpleRecord = { @@ -217,11 +222,11 @@ module Json = [] let ``Serialize simple record`` (r: SimpleRecord) = - J.Encode r .=. SimpleRecord.Enc r + test <@ J.Encode r = SimpleRecord.Enc r @> [] let ``Deserialize simple record`` (r: SimpleRecord) = - J.Decode (SimpleRecord.Enc r) .=. r + test <@ J.Decode (SimpleRecord.Enc r) = r @> type RecordWithOption = { @@ -239,11 +244,11 @@ module Json = [] let ``Serialize record with option field`` (r: RecordWithOption) = - J.Encode r .=. RecordWithOption.Enc r + test <@ J.Encode r = RecordWithOption.Enc r @> [] let ``Deserialize record with option field`` (r: RecordWithOption) = - J.Decode (RecordWithOption.Enc r) .=. r + test <@ J.Decode (RecordWithOption.Enc r) = r @> type RecordWithNamedFields = { @@ -265,11 +270,11 @@ module Json = [] let ``Serialize record with named fields`` (r: RecordWithNamedFields) = - J.Encode r .=. RecordWithNamedFields.Enc r + test <@ J.Encode r = RecordWithNamedFields.Enc r @> [] let ``Deserialize record with named fields`` (r: RecordWithNamedFields) = - J.Decode (RecordWithNamedFields.Enc r) .=. r + test <@ J.Decode (RecordWithNamedFields.Enc r) = r @> type SimpleUnion = | Nullary @@ -299,11 +304,11 @@ module Json = [] let ``Serialize simple union`` (u: SimpleUnion) = - J.Encode u .=. SimpleUnion.Enc u + test <@ J.Encode u = SimpleUnion.Enc u @> [] let ``Deserialize simple union`` (u: SimpleUnion) = - J.Decode (SimpleUnion.Enc u) .=. u + test <@ J.Decode (SimpleUnion.Enc u) = u @> [] type ImplicitDiscrUnion = @@ -322,11 +327,11 @@ module Json = [] let ``Serialize union with parameterless NamedUnionCases`` (u: ImplicitDiscrUnion) = - J.Encode u .=. ImplicitDiscrUnion.Enc u + test <@ J.Encode u = ImplicitDiscrUnion.Enc u @> [] let ``Deserialize union with parameterless NamedUnionCases`` (u: ImplicitDiscrUnion) = - J.Decode (ImplicitDiscrUnion.Enc u) .=. u + test <@ J.Decode (ImplicitDiscrUnion.Enc u) = u @> [] type ExplicitDiscrUnion = @@ -341,8 +346,8 @@ module Json = [] let ``Serialize union with NamedUnionCases`` (u: ExplicitDiscrUnion) = - J.Encode u .=. ExplicitDiscrUnion.Enc u + test <@ J.Encode u = ExplicitDiscrUnion.Enc u @> [] let ``Deserialize union with NamedUnionCases`` (u: ExplicitDiscrUnion) = - J.Decode (ExplicitDiscrUnion.Enc u) .=. u + test <@ J.Decode (ExplicitDiscrUnion.Enc u) = u @> diff --git a/tests/Unit/Tests/Remoting.fs b/tests/Unit/Tests/Remoting.fs index 5c78bd3c..af63e4e0 100644 --- a/tests/Unit/Tests/Remoting.fs +++ b/tests/Unit/Tests/Remoting.fs @@ -1,10 +1,10 @@ namespace Bolero.Tests.Web -open System.Threading.Tasks open NUnit.Framework open OpenQA.Selenium open FsCheck.NUnit open FsCheck +open Swensen.Unquote open Bolero.Tests /// Server remote calls. @@ -29,13 +29,11 @@ module Remoting = sprintf "%s => %s" k v @| [ "remove" @| ( remBtn.Click() - let out = elt.Wait(fun () -> elt.ByClass("output-empty")) - not (isNull out) + testNotNull <@ elt.Wait(fun () -> elt.ByClass("output-empty")) @> ) "add" @| ( addBtn.Click() - let out = elt.Wait(fun () -> elt.ByClass("output")) - out.Text = v + test <@ elt.Wait(fun () -> elt.ByClass("output")).Text = v @> ) ] @@ -45,12 +43,12 @@ module Remoting = username.Clear() username.SendKeys("someone") elt.ByClass("signin-button").Click() - elt.AssertAreEqualEventually("someone", fun () -> elt.ByClass("is-signedin").Text) + elt.Eventually <@ elt.ByClass("is-signedin").Text = "someone" @> [] let ``Authorized remote function fails when signed out`` () = elt.ByClass("signout-button").Click() - elt.AssertAreEqualEventually("", fun () -> elt.ByClass("is-signedin").Text) + elt.Eventually <@ elt.ByClass("is-signedin").Text = "" @> [] let ``Authorized remote function fails if role is missing`` () = @@ -58,9 +56,9 @@ module Remoting = username.Clear() username.SendKeys("someone") elt.ByClass("signin-button").Click() - elt.AssertAreEqualEventually("someone", fun () -> elt.ByClass("is-signedin").Text) + elt.Eventually <@ elt.ByClass("is-signedin").Text = "someone" @> elt.ByClass("get-admin").Click() - elt.AssertAreEqualEventually("", fun () -> elt.ByClass("is-admin").Text) + elt.Eventually <@ elt.ByClass("is-admin").Text = "" @> [] let ``Authorized remote function succeeds if role is present`` () = @@ -68,6 +66,6 @@ module Remoting = username.Clear() username.SendKeys("admin") elt.ByClass("signin-button").Click() - elt.AssertAreEqualEventually("admin", fun () -> elt.ByClass("is-signedin").Text) + elt.Eventually <@ elt.ByClass("is-signedin").Text = "admin" @> elt.ByClass("get-admin").Click() - elt.AssertAreEqualEventually("admin ok", fun () -> elt.ByClass("is-admin").Text) + elt.Eventually <@ elt.ByClass("is-admin").Text = "admin ok" @> diff --git a/tests/Unit/Tests/Routing.fs b/tests/Unit/Tests/Routing.fs index b77fd31f..4c5e387f 100644 --- a/tests/Unit/Tests/Routing.fs +++ b/tests/Unit/Tests/Routing.fs @@ -1,9 +1,9 @@ namespace Bolero.Tests.Web -open System.Threading open FSharp.Reflection open NUnit.Framework open OpenQA.Selenium +open Swensen.Unquote open Bolero.Tests /// Blazor router integration. @@ -31,8 +31,8 @@ module Routing = let res = try Some <| elt.Wait(fun () -> elt.ByClass(resCls)) with :? WebDriverTimeoutException -> None - res |> Option.iter (fun res -> Assert.AreEqual(resCls, res.Text)) - Assert.AreEqual(WebFixture.Url + url, WebFixture.Driver.Url) + res |> Option.iter (fun res -> test <@ res.Text = resCls @>) + test <@ WebFixture.Driver.Url = WebFixture.Url + url @> [] let ``Set by model``(linkCls: string, url: string, page: Client.Routing.Page) = @@ -41,8 +41,8 @@ module Routing = let res = try Some <| elt.Wait(fun () -> elt.ByClass(resCls)) with :? WebDriverTimeoutException -> None - res |> Option.iter (fun res -> Assert.AreEqual(resCls, res.Text)) - Assert.AreEqual(WebFixture.Url + url, WebFixture.Driver.Url) + res |> Option.iter (fun res -> test <@ res.Text = resCls @>) + test <@ WebFixture.Driver.Url = WebFixture.Url + url @> let failingRouter<'T> (expectedError: UnionCaseInfo[] -> InvalidRouterKind) = TestCaseData( @@ -89,7 +89,5 @@ module Routing = [] let ``Invalid routers``(makeAndIgnoreRouter: unit -> unit, expectedError: InvalidRouterKind) = - Assert.AreEqual( - InvalidRouter expectedError, - Assert.Throws(fun () -> makeAndIgnoreRouter()) - ) + raisesWith <@ makeAndIgnoreRouter() @> + (fun exn -> <@ exn = InvalidRouter expectedError @>) diff --git a/tests/Unit/Tests/Templating.fs b/tests/Unit/Tests/Templating.fs index cfe2889d..28d2c33a 100644 --- a/tests/Unit/Tests/Templating.fs +++ b/tests/Unit/Tests/Templating.fs @@ -5,6 +5,8 @@ open System.Globalization open NUnit.Framework open OpenQA.Selenium open OpenQA.Selenium.Support.UI +open Swensen.Unquote +open Bolero.Tests /// HTML Templates. [] @@ -19,32 +21,31 @@ module Templating = [] let ``Inline template is instantiated``() = - Assert.IsNotNull(elt.ByClass("inline")) + testNotNull <@ elt.ByClass("inline") @> [] let ``File template is instantiated``() = - Assert.IsNotNull(elt.ByClass("file")) + testNotNull <@ elt.ByClass("file") @> [] let ``Node hole filled with string``() = - Assert.AreEqual("NodeHole1 content", - elt.ByClass("nodehole1").Text) + test <@ elt.ByClass("nodehole1").Text = "NodeHole1 content" @> [] let ``File template node hole filled``() = - Assert.IsNotNull(elt.ByClass("file").ByClass("file-hole")) + testNotNull <@ elt.ByClass("file").ByClass("file-hole") @> [] let ``Node hole filled with node``() = let filledWith = elt.ByClass("nodehole2-content") - Assert.IsNotNull(filledWith) - Assert.AreEqual("NodeHole2 content", filledWith.Text) + testNotNull <@ filledWith @> + test <@ filledWith.Text = "NodeHole2 content" @> [] [] [] let ``Node hole filled with string [multiple]``(id: string) = - Assert.AreEqual("NodeHole3 content", elt.ByClass(id).Text) + test <@ elt.ByClass(id).Text = "NodeHole3 content" @> [] [] @@ -52,40 +53,39 @@ module Templating = let ``Node hole filled with node [multiple]``(id: string) = let elt = elt.ByClass(id) let filledWith = elt.ByClass("nodehole4-content") - Assert.IsNotNull(filledWith) - Assert.AreEqual("NodeHole4 content", filledWith.Text) + testNotNull <@ filledWith @> + test <@ filledWith.Text = "NodeHole4 content" @> [] let ``Attr hole``() = - Assert.Contains("attrhole1-content", - elt.ByClass("attrhole1").GetAttribute("class").Split(' ')) + test <@ elt.ByClass("attrhole1").GetAttribute("class").Split(' ') + |> Seq.contains "attrhole1-content" @> [] [] [] let ``Attr hole [multiple]``(id: string) = - Assert.Contains("attrhole2-content", - elt.ByClass(id).GetAttribute("class").Split(' ')) + test <@ elt.ByClass(id).GetAttribute("class").Split(' ') + |> Seq.contains "attrhole2-content" @> [] let ``Attr hole mixed with node hole``() = - Assert.Contains("attrhole3-content", - elt.ByClass("attrhole3-1").GetAttribute("class").Split(' ')) - Assert.AreEqual("attrhole3-content", - elt.ByClass("attrhole3-2").Text) + test <@ elt.ByClass("attrhole3-1").GetAttribute("class").Split(' ') + |> Seq.contains "attrhole3-content" @> + test <@ elt.ByClass("attrhole3-2").Text = "attrhole3-content" @> [] let ``Full attr hole``() = let elt = elt.ByClass("fullattrhole") - Assert.AreEqual("fullattrhole-content", elt.GetAttribute("id")) - Assert.AreEqual("1234", elt.GetAttribute("data-fullattrhole")) + test <@ elt.GetAttribute("id") = "fullattrhole-content" @> + test <@ elt.GetAttribute("data-fullattrhole") = "1234" @> [] let ``Attr hole obj value``() = let elt = elt.ByClass("attrhole4") - Assert.AreEqual("5678", elt.GetAttribute("data-value")) - Assert.IsNotNull(elt.GetAttribute("data-true")) - Assert.IsNull(elt.GetAttribute("data-false")) + test <@ elt.GetAttribute("data-value") = "5678" @> + testNotNull <@ elt.GetAttribute("data-true") @> + testNull <@ elt.GetAttribute("data-false") @> [] let ``Event hole``() = @@ -94,27 +94,21 @@ module Templating = let position = elt.ByClass("position") let isNumber (s: string) = Double.TryParse(s, NumberStyles.Float, CultureInfo.InvariantCulture, ref 0.) - let isValidPosition() = - let a = position.Text.Split(',') + let isValidPosition (pos: string) = + let a = pos.Split(',') isNumber a.[0] && isNumber a.[1] elt.ByClass("btn1").Click() - elt.AssertAreEqualEventually("clicked 1", - (fun () -> state.Text), - "First click") - Assert.IsTrue(isValidPosition(), "Position: " + position.Text) + elt.Eventually <@ state.Text = "clicked 1" @> + test <@ isValidPosition position.Text @> elt.ByClass("btn2").Click() - elt.AssertAreEqualEventually("clicked 2", - (fun () -> state.Text), - "Second click") - Assert.IsTrue(isValidPosition(), "Position: " + position.Text) + elt.Eventually <@ state.Text = "clicked 2" @> + test <@ isValidPosition position.Text @> elt.ByClass("btn3").Click() - elt.AssertAreEqualEventually("clicked 1", - (fun () -> state.Text), - "Same event bound multiple times") - Assert.IsTrue(isValidPosition(), "Position: " + position.Text) + elt.Eventually <@ state.Text = "clicked 1" @> + test <@ isValidPosition position.Text @> [] [] @@ -125,18 +119,14 @@ module Templating = inp.Clear() inp.SendKeys("hello") if cls.Contains("onchange") then blur() - elt.AssertAreEqualEventually("hello", - (fun () -> elt.ByClass(sprintf "display%s1" cls).Text), - "Value propagation") - Assert.AreEqual("hello", - elt.ByClass(sprintf "input%s1-2" cls).GetAttribute("value"), - "Propagation to other input") - Assert.AreEqual("hello", - elt.ByClass(sprintf "textarea%s1" cls).GetAttribute("value"), - "Propagation to textarea") - Assert.AreEqual("hello", - elt.ByClass(sprintf "select%s1" cls).GetAttribute("value"), - "Propagation to select") + // Value propagation + elt.Eventually <@ elt.ByClass(sprintf "display%s1" cls).Text = "hello" @> + // Propagation to other input + test <@ elt.ByClass(sprintf "input%s1-2" cls).GetAttribute("value") = "hello" @> + // Propagation to textarea + test <@ elt.ByClass(sprintf "textarea%s1" cls).GetAttribute("value") = "hello" @> + // Propagation to select + test <@ elt.ByClass(sprintf "select%s1" cls).GetAttribute("value") = "hello" @> [] [] @@ -147,36 +137,28 @@ module Templating = inp.Clear() inp.SendKeys("hi textarea") if cls.Contains("onchange") then blur() - elt.AssertAreEqualEventually("hi textarea", - (fun () -> elt.ByClass(sprintf "display%s1" cls).Text), - "Value propagation") - Assert.AreEqual("hi textarea", - elt.ByClass(sprintf "input%s1-1" cls).GetAttribute("value"), - "Propagation to input") - Assert.AreEqual("hi textarea", - elt.ByClass(sprintf "input%s1-2" cls).GetAttribute("value"), - "Propagation to other input") - Assert.AreEqual("hi textarea", - elt.ByClass(sprintf "select%s1" cls).GetAttribute("value"), - "Propagation to select") + // Value propagation + elt.Eventually <@ elt.ByClass(sprintf "display%s1" cls).Text = "hi textarea" @> + // Propagation to input + test <@ elt.ByClass(sprintf "input%s1-1" cls).GetAttribute("value") = "hi textarea" @> + // Propagation to other input + test <@ elt.ByClass(sprintf "input%s1-2" cls).GetAttribute("value") = "hi textarea" @> + // Propagation to select + test <@ elt.ByClass(sprintf "select%s1" cls).GetAttribute("value") = "hi textarea" @> [] let ``Bind string to select``() = let elt = elt.Inner(By.ClassName "binds") SelectElement(elt.ByClass("select1")) .SelectByValue("hi select") - elt.AssertAreEqualEventually("hi select", - (fun () -> elt.ByClass("display1").Text), - "Value propagation") - Assert.AreEqual("hi select", - elt.ByClass("input1-1").GetAttribute("value"), - "Propagation to input") - Assert.AreEqual("hi select", - elt.ByClass("input1-2").GetAttribute("value"), - "Propagation to other input") - Assert.AreEqual("hi select", - elt.ByClass("textarea1").GetAttribute("value"), - "Propagation to textarea") + // Value propagation + elt.Eventually <@ elt.ByClass("display1").Text = "hi select" @> + // Propagation to input + test <@ elt.ByClass("input1-1").GetAttribute("value") = "hi select" @> + // Propagation to other input + test <@ elt.ByClass("input1-2").GetAttribute("value") = "hi select" @> + // Propagation to textarea + test <@ elt.ByClass("textarea1").GetAttribute("value") = "hi select" @> [] [] @@ -187,12 +169,10 @@ module Templating = inp.Clear() inp.SendKeys("1234") if cls.Contains("onchange") then blur() - elt.AssertAreEqualEventually("1234", - (fun () -> elt.ByClass(sprintf "display%s2" cls).Text), - "Value propagation") - Assert.AreEqual("1234", - elt.ByClass(sprintf "input%s2-2" cls).GetAttribute("value"), - "Propagation to other input") + // Value propagation + elt.Eventually <@ elt.ByClass(sprintf "display%s2" cls).Text = "1234" @> + // Propagation to other input + test <@ elt.ByClass(sprintf "input%s2-2" cls).GetAttribute("value") = "1234" @> [] [] @@ -203,12 +183,10 @@ module Templating = inp.Clear() inp.SendKeys("123.456") if cls.Contains("onchange") then blur() - elt.AssertAreEqualEventually("123.456", - (fun () -> elt.ByClass(sprintf "display%s3" cls).Text), - "Value propagation") - Assert.AreEqual("123.456", - elt.ByClass(sprintf "input%s3-2" cls).GetAttribute("value"), - "Propagation to other input") + // Value propagation + elt.Eventually <@ elt.ByClass(sprintf "display%s3" cls).Text = "123.456" @> + // Propagation to other input + test <@ elt.ByClass(sprintf "input%s3-2" cls).GetAttribute("value") = "123.456" @> [] let ``Bind checkbox``() = @@ -220,44 +198,38 @@ module Templating = | null -> false | s -> bool.Parse s let initial = false - Assert.AreEqual(initial, isChecked inp1) - Assert.AreEqual(initial, isChecked inp2) + test <@ isChecked inp1 = initial @> + test <@ isChecked inp2 = initial @> + inp1.Click() - elt.AssertAreEqualEventually(not initial, - (fun () -> isChecked inp1), - "Click inp1 toggles checked1") - elt.AssertAreEqualEventually(not initial, - (fun () -> isChecked inp2), - "Click inp1 toggles checked2") + elt.Eventually <@ isChecked inp1 = not initial @> + elt.Eventually <@ isChecked inp2 = not initial @> + inp2.Click() - elt.AssertAreEqualEventually(initial, - (fun () -> isChecked inp1), - "Click inp2 toggles checked1") - elt.AssertAreEqualEventually(initial, - (fun () -> isChecked inp2), - "Click inp2 toggles checked2") + elt.Eventually <@ isChecked inp1 = initial @> + elt.Eventually <@ isChecked inp2 = initial @> [] let ``Nested template is instantiated``() = - Assert.IsNotNull(elt.ByClass("nested1")) + testNotNull <@ elt.ByClass("nested1") @> [] let ``Nested template is removed from its original parent``() = - Assert.IsNull(elt.ById("Nested1")) + testNull <@ elt.ById("Nested1") @> [] let ``Nested template hole filled``() = - Assert.IsNotNull(elt.ByClass("nested1").ByClass("nested-hole")) - Assert.IsNull(elt.ByClass("nested1").ByClass("file-hole")) + testNotNull <@ elt.ByClass("nested1").ByClass("nested-hole") @> + testNull <@ elt.ByClass("nested1").ByClass("file-hole") @> [] let ``Recursively nested template is instantiated``() = - Assert.IsNotNull(elt.ByClass("nested2")) + testNotNull <@ elt.ByClass("nested2") @> [] let ``Recursively nested template is removed from its original parent``() = - Assert.IsNull(elt.ById("Nested2")) + testNull <@ elt.ById("Nested2") @> [] let ``Regression #11: common hole in attrs and children``() = - Assert.AreEqual("regression-11", elt.ByClass("regression-11").Text) + test <@ elt.ByClass("regression-11").Text = "regression-11" @> diff --git a/tests/Unit/Unit.fsproj b/tests/Unit/Unit.fsproj index cdefabb9..6cdde6f7 100644 --- a/tests/Unit/Unit.fsproj +++ b/tests/Unit/Unit.fsproj @@ -3,6 +3,7 @@ netcoreapp3.0 false + false diff --git a/tests/Unit/Utility.fs b/tests/Unit/Utility.fs index fd29b5ec..61934e41 100644 --- a/tests/Unit/Utility.fs +++ b/tests/Unit/Utility.fs @@ -22,17 +22,20 @@ namespace Bolero.Tests open System open FsCheck +open Swensen.Unquote [] module Utility = - let (.=.) left right = left = right |@ sprintf "\nActual: %A\nExpected: %A" left right - let epsilon = 0.0001 let (=~) left right = left - right < epsilon - let (.=~.) left right = left =~ right |@ sprintf "\nActual: %A\nExpected: %A" left right + let isNotNull x = not (isNull x) + + let testNull x = test <@ isNull %x @> + + let testNotNull x = test <@ isNotNull %x @> /// FsCheck-generated alphanumerical string. type Alphanum = diff --git a/tests/Unit/paket.references b/tests/Unit/paket.references index 20233c3f..55bd1dcb 100644 --- a/tests/Unit/paket.references +++ b/tests/Unit/paket.references @@ -8,3 +8,4 @@ Selenium.WebDriver.ChromeDriver Microsoft.AspNetCore.Blazor.Server Selenium.Support Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation +Unquote \ No newline at end of file