Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve support for interactive experiences #482

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
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
14 changes: 14 additions & 0 deletions Expecto.Tests/Bug_RepeatedColourSetting.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
module Bug_RepeatedColourSetting

open Expecto
open Expecto.Logging


[<Tests>]
let tests =
ftest "Colour can be set repeatedly" {
let colours = [|Colour0; Colour256|]
colours |> Array.iter ANSIOutputWriter.setColourLevel

Expect.equal (ANSIOutputWriter.getColour ()) (Array.last colours) "Colour should be the last set value"
}
1 change: 1 addition & 0 deletions Expecto.Tests/Expecto.Tests.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
<Compile Include="FsCheckTests.fs" />
<Compile Include="PerformanceTests.fs" />
<Compile Include="Bug341.fs" />
<Compile Include="Bug_RepeatedColourSetting.fs" />
<Compile Include="Main.fs" />
<None Include="paket.references" />
<ProjectReference Include="..\Expecto.Hopac\Expecto.Hopac.fsproj" />
Expand Down
44 changes: 44 additions & 0 deletions Expecto/Expecto.fs
Original file line number Diff line number Diff line change
Expand Up @@ -643,3 +643,47 @@ module Tests =
/// Returns 0 if all tests passed, otherwise 1
let runTestsInAssemblyWithCLIArgs cliArgs args =
runTestsInAssemblyWithCLIArgsAndCancel CancellationToken.None cliArgs args

/// Runs all given tests with the supplied typed command-line options.
/// Returns the console output as a string (with ANSI coloring by default)
/// Useful for interactive environments like F# interactive or notebooks
let runTestsReturnLogs cliArgs args tests =
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I could use feedback on this method name.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Maybe runTestsForInteractive

Copy link
Collaborator

Choose a reason for hiding this comment

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

What do you think about runTestsInteractively?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I thought of a similar name, but I feel like it denotes the test run itself is interactive, as in there will be decision points for the user during the test run.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Well, runTestsForInteractive seems reasonable to me, then.

let tryBuildConfig cliArgs args =
let config =
Seq.fold (fun s a -> foldCLIArgumentToConfig a s)
ExpectoConfig.defaultConfig cliArgs

match ExpectoConfig.fillFromArgs config args with
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I believe this results in double args parsing, but it seemed like the least complex option (and easiest to follow) and we're not doing that much parsing generally. It also only applies to this interactive run method

| ArgsUsage (usage, errors) ->
None
| ArgsList config
| ArgsRun config
| ArgsVersion config ->
Some config

let literateOutputWriter (outputBuilder: Text.StringBuilder) (text: (string*ConsoleColor) list) : unit =
let colorizeLine (text, color) = ColourText.colouriseText color text
let sbAppend (builder: Text.StringBuilder) (text: string) =
builder.Append(text)

text
|> List.iter (colorizeLine >> (sbAppend outputBuilder) >> ignore)

let outputBuilder = System.Text.StringBuilder("")

let verbosity =
tryBuildConfig cliArgs args
|> Option.defaultValue ExpectoConfig.defaultConfig
|> (fun config -> config.verbosity)

Global.initialise
{ Global.defaultConfig with
getLogger = fun name ->
Expecto.Logging.LiterateConsoleTarget(
name,
minLevel = verbosity,
outputWriter = (literateOutputWriter outputBuilder)) :> Expecto.Logging.Logger
}

runTestsWithCLIArgs cliArgs args tests |> ignore
outputBuilder.ToString()
2 changes: 1 addition & 1 deletion Expecto/Logging.fs
Original file line number Diff line number Diff line change
Expand Up @@ -879,7 +879,7 @@ module internal ANSIOutputWriter =
override __.WriteLine() = write "\n"

let mutable internal colours = None
let internal setColourLevel c = if colours.IsNone then colours <- Some c
let internal setColourLevel c = colours <- Some c
Copy link
Collaborator Author

@farlee2121 farlee2121 Nov 6, 2023

Choose a reason for hiding this comment

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

I couldn't discern a reason this needed to be settable only once, and it prevents the colour setting from working as expected in interactive environments

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

let internal getColour() = Option.defaultValue Colour8 colours

let colourReset = "\u001b[0m"
Expand Down
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ What follows is the Table of Contents for this README, which also serves as the
- [`runTestsWithCLIArgsAndCancel`](#runtestswithcliargsandcancel)
- [`runTestsInAssemblyWithCLIArgs`](#runtestsinassemblywithcliargs)
- [`runTestsInAssemblyWithCLIArgsAndCancel`](#runtestsinassemblywithcliargsandcancel)
- [`runTestsReturnLogs`](#runtestsreturnlogs)
- [Filtering with `filter`](#filtering-with-filter)
- [Shuffling with `shuffle`](#shuffling-with-shuffle)
- [Stress testing](#stress-testing)
Expand Down Expand Up @@ -250,6 +251,22 @@ Signature `CancellationToken -> CLIArguments seq -> string[] -> int`. Runs the t
assembly and also overrides the passed `CLIArguments` with the command line
parameters. All tests need to be marked with the `[<Tests>]` attribute.

### `runTestsReturnLogs`

Signature `CLIArguments seq -> string[] -> Test -> string`.
Accepts the same arguments as `runTestsWithCLIArgs`, but returns the console output as a string.

This is useful for interactive environments like [F# interactive](https://learn.microsoft.com/en-us/dotnet/fsharp/tools/fsharp-interactive/) and [Polyglot Notebooks](https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.dotnet-interactive-vscode), where console output is not available but the returned string can be displayed instead.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I plan to add a screen shot once I can show the proper package reference.
Something like #r "nuget: Expecto, 10.2.0".

Note that ANSI colors are used by default, but can be turned off using `--colours 0`.
```fsharp
runTestsReturnLogs [] [|"--colours";"0"|] tests
```

Any valid CLI arguments work, including `--help` and `--list-tests`.



### Filtering with `filter`

You can single out tests by filtering them by name (e.g. in the
Expand Down
Loading