How to run a Canopy test suite with xUnit? - f#

I decided to use canopy framework to test my UI.
Most of the examples include either built-in assertion framework or Expecto. Which are both good choices yet I use xUnit everywhere else in the project and want to be uniform for now.
For xUnit I have found only this example but it contains just two very basic tests whereas I need to things like common code to run prior to all the tests. What would be an idiomatic way for canopy + xUnit?

xUnit has class fixtures and here is an example how to bring it to F# code.
Combining that with canopy scenarios, here is an example of what it can look like:
open canopy.classic
open canopy.types
open System
open Xunit
let private openApp() =
...
type Fixture() =
do
start ChromeHeadless
interface IDisposable with
member _.Dispose() =
quit()
type Tests() =
interface IClassFixture<Fixture>
[<Fact>]
member _.``Soundcheck - Server is online``() =
openApp()
[<Fact>]
member _.``Button1 is enabled``() =
openApp()
let button = element "#button1"
Assert.True button.Enabled
[<Fact>]
member _.``Button2 is disabled``() =
openApp()
let button = element "#button2"
Assert.False button.Enabled

Related

In F#, how does one access the TestContext for .runsettings?

I'm writing an integration test for a third party C# library in an F# code base. There are some constraints to this integration test.
For regulatory reasons I must test with MsTest
The library only works with a valid license
We cannot commit the license into our repository
I don't want to hardcode the location of the valid license into the test
I've got the failing test passing, but can't figure out how to write the test with a valid license. The function Initialize is just a wrapper for the third party library to initialize the library with the license and returns the Result.
[<TestClass>]
type ``Test Local Initialize`` () =
[<TestMethod>]
member this.``When loading an invalid INI file`` () =
let actual =
$#"{AppDomain.CurrentDomain.BaseDirectory}Resources\DummyLicense.INI"
|> Initialize
match actual with
| Ok _ -> Assert.Fail("Should not initialize with an invalid configuration.")
| Error e -> Assert.IsNotNull(e, "Should error with an invalid configuration")
The test I want to write is "given a valid license file, initializing the library should return a Result of OK."
In C#, I would use the .runsettings to point to a license folder, but I'm pretty new to F# and I'm not really sure how I would add the TestContext to the test. Since the tests are defined as a type, I'm guessing they don't hold state or fields.
So my questions are:
Is there a way to load the TextContext in F#?
Is there a more idiomatic way to achieve this in F#?
It works much the same as in C#. In your test class, mark a static member with the ClassInitialize or AssemblyInitialize attribute and specify a context parameter:
[<TestClass>]
type TestClass () =
static let mutable myValue = ""
[<ClassInitialize>]
static member Setup(context : TestContext) =
myValue <- string context.Properties.["MyValue"]
[<TestMethod>]
member this.TestMyValue() =
Assert.AreEqual("xyzzy", myValue)

Is there a way to use let statements in classes with inline methods?

A simplified example that gives an error because let str is private:
let launch = printfn "%s"
type Test() =
let str = "Hello"
member inline t.A() =
launch str
I've discovered statically resolved type parameters in F# and after a rewrite have a neural net library where 95% of the functions are inlined as a result, including class methods. I wrote it as a F# script at first, forgetting that there is a difference between script mode and compiled mode in their treatment of inlined methods.
let test = // Is this the only choice?
let str = "Hello"
fun () ->
launch str
Is there any way to use body initializers in F# classes or should I rewrite the classes to be higher order functions like the above? Thankfully, that would not be a problem here.
This question is related to this one, but I thought I'd ask again since it has been 5 years.
Actually I was wrong. It is true that the higher order function example does work in the simplified case above, but I've realized that lambda arguments cannot be statically resolved. I thought of using records for a bit and then tried this:
type Test() =
let str = "Hello"
member t.Str = str
member inline t.A() =
launch t.Str
Private member can be exposed and this will compile. Doing it like the above would be satisfactory.

F# How to use an interface in a separate module

So I have been doing research on interfaces on F#. I have found these 2 articles on it. The MSDN and F# for fun and profit But unfortunately they are only skin deep.
UPDATED
here is my module with my interfaces
//open statements omitted for brevity
module DrawingInterfaces =
///gets a string representation of the SVG code representation of the object
type IRepresentable_SVG =
abstract member getSVGRepresenation : unit -> string
//other interfaces omitted for brevity
Now within the same namespace and physical folder also I have this:
type lineSet (x1off,x2off,y1off,y2off,x1,x2,y1,y2,rot,rotOff,count) =
//tons of member vals omitted for brevity
member val x1Start = x1 with get, set
interface DrawingInterfaces.IRepresentable_SVG with
member __.getSVGRepresenation() =
let mutable svg = ""
let mutable currentx1 = x1Start
svg
This used to give me 2 errors, before I was using the __. notation for the member. The first error was on the interface line. And a second on the member line.
The errors were respectively:
The type 'IRepresentable_SVG' is not defined
This instance member needs a parameter to represent the object being invoked.
I was able to fix the first one by changing the file order. Thanks to John Palmer.
The second one is nearly fixed./
After using the __ . notation I was able to get rid of the second error. However, now a new error pops up when I try to use type members in my interface implementation.
let mutable currentx1 = x1Start
x1Start shows as not being defined. I need to be able to use values stored in my other members within my implementation.
Let's first make it work and then point to your problems. I define below 2 separate modules in 2 separate .fs files within the same namespace Example for interface definition in module Example.DrawingInterfacesand interface implementation in module Example.UseInterface and also a console app that will use the interface from third (implicit) module Program. In my project correspondent code files are in the following order: DefInterface.fs, UseInterface,fs, Program.fs (I also made few idiomatic styling changes and more brevity omissions)
File: DefInterface.fs
namespace Example
module DrawingInterfaces =
type IRepresentable_SVG =
abstract member GetSVGRepresenation : unit -> string
File: UseInterface.fs
namespace Example
module UseInterface =
type LineSet (x1) =
member val X1Start = x1 with get, set
interface DrawingInterfaces.IRepresentable_SVG with
member __.GetSVGRepresenation() = "test" + " " + __.X1Start.ToString()
File: Program.fs
open Example
open System
[<EntryPoint>]
let main argv =
let lineSet = UseInterface.LineSet(5)
let example : DrawingInterfaces.IRepresentable_SVG = lineSet :> _
example.GetSVGRepresenation() |> printfn "%A"
lineSet.X1Start <- 10
example.GetSVGRepresenation() |> printfn "%A"
0
Compile, run and make sure it works.
Now to problems in your code:
first error message stems from the need to refer to the full implemented interface name in UseInterface.fs, which is Example.DrawingInterfaces.IRepresentable_SVG although as both modules belong to the same namespace the Example prefix may be omitted
second error message points to the need of using instance method in implementation class UseInterface.LineSet, which is achieved by prepending self-identifier __. to the method signature
Finally, notice the usage of your interface in Program.fs that imports namespace, provides module names for definition and implementation respectively, and also explicitly casts implementation LineSet to IRepresentable_SVG.
EDIT: I've added X1Start property to the original LineSet to show how it can be used from interface implementation per question author's request. Now self-id __. is more involved and probably using self. or even this. instead would make more sense.

Is there any way to use JavaScript attribute by default?

I just want somehow to say "I want all methods in this project use [JavaScript]"
Manually annotation every method is annoying
F# 3 lets you mark a module with the ReflectedDefinition attribute (aka [JavaScript] in WebSharper) which marks all the methods underneath.
See More About F# 3.0 Language Features:
(Speaking of uncommon attributes, in F# 3.0, the
[< ReflectedDefinition >] attribute can now be placed on modules and
type definitions, as a shorthand way to apply it to each individual
member of the module/type.)
I think Phil's answer is the way to go - when you can mark an entire module or type, it does not add too much noise and it also allows you to distinguish between server-side and client-side code in WebSharper.
Just for the record, the F# compiler is open-source and so someone (who finds this issue important) could easily create branch that would add an additional command line attribute to override the setting. I think this is just a matter of adding the parameter and then setting the default value of the reflect flag in check.fs (here is the source on GitHub).
At the moment, the main F# repository does not accept contributions that add new features (see the discussion here), but it is certainly a good way to send a feature request to the F# team :-)
If you annotate all your code with the JavaScript attribute, the WebSharper compiler will try to translate everything to JavaScript. A rule of thumb in WebSharper development is to separate server-side and client-side code, so you can simply annotate the module/class containing client-side code instead of every function/member if you're targeting .NET 4.5.
namespace Website
open IntelliFactory.WebSharper
module HelloWorld =
module private Server =
[<Rpc>]
let main() = async { return "World" }
[<JavaScript>] // or [<ReflectedDefinition>]
module Client =
open IntelliFactory.WebSharper.Html
let sayHello() =
async {
let! world = Server.main()
JavaScript.Alert <| "Hello " + world
}
let btn =
Button [Text "Click Me"]
|>! OnClick (fun _ _ ->
async {
do! sayHello()
} |> Async.Start)
let main() = Div [btn]
type Control() =
inherit Web.Control()
[<JavaScript>]
override __.Body = Client.main() :> _

Making F# Test case methods public for unit testing with Nunit

I'm using F# to write my test methods but Nunit complains that the methods are non public.
namespace Test
open NUnit.Framework
type public Test() =
[<Test>]
let testIt () =
Assert.AreEqual(10,10)
what do I need to change?
Since let bindings are private to the parent type, you have to use member instead:
namespace Test
open NUnit.Framework
[<TestFixture>]
type public Test() =
[<Test>]
member x.testIt() =
Assert.AreEqual(10, 10)
If you don't need complicated setups, using module-level let bindings directly should be preferable:
module Test
open NUnit.Framework
[<Test>]
let testIt() = Assert.AreEqual(10, 10)
You can put F# test cases in a module to make them public and visible to NUnit:
module Tests
open NUnit.Framework
let [<Test>] ``10 should equal 10`` () = Assert.AreEqual(10,10)

Resources