-
-
Notifications
You must be signed in to change notification settings - Fork 96
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
base: main
Are you sure you want to change the base?
Conversation
@@ -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 |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@@ -643,3 +643,44 @@ module Tests = | |||
/// Returns 0 if all tests passed, otherwise 1 | |||
let runTestsInAssemblyWithCLIArgs cliArgs args = | |||
runTestsInAssemblyWithCLIArgsAndCancel CancellationToken.None cliArgs args | |||
|
|||
let runTestsReturnLogs cliArgs args tests = |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe runTestsForInteractive
There was a problem hiding this comment.
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
?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
Expecto/Expecto.fs
Outdated
Seq.fold (fun s a -> foldCLIArgumentToConfig a s) | ||
ExpectoConfig.defaultConfig cliArgs | ||
|
||
match ExpectoConfig.fillFromArgs config args with |
There was a problem hiding this comment.
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
I will review this later today! |
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. | ||
|
There was a problem hiding this comment.
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"
.
One question, instead of expanding the API with a function that only changes the logging output, wouldn't it be better to add an option that tells where the output should go? |
In short, I don't think we can generally redirect output for interactive environments. So, configuration creates a more complex experience in exchange for leveraging the existing methods. It'd look something like let output = StringBuilder()
runTestsWithCLIArgs [CLIArguments.OutputWriter (fun outputSegment -> output.Append(outputSegment) |> ignore)] [||] tests
output To me, it seems unlikely we'll want any of the reflection-based runTests variants in interactive mode, but the complexity of |
Hmm, I was thinking of introducing a new case to I mean, your code looks good to me, but I'm not convinced we should have a function for something that should be a configuration option and be documented on some sort of FAQ. |
Suppose we have a call like Do you have a more concrete vision of how LogOutput would work? |
I was considering something like this: let runTestsForInteractive cliArgs args =
let cliArgs = (LogOutput <some-cool-output>)::cliArgs
runTestsWithCLIArgsAndCancel cliArgs args This way we can control how the log output is handled inside |
The In a polyglot notebook we could do something like If we accumulate in a string builder, then we're asking users to use at least 3 lines to display output, like demonstrated previously. |
Oh, I ran an interactive session like on your screenshots and now I see what you mean. The notebook expects an explicit return value to output something, this is why we need to return a string itself... Well, in this case, I think this code does what is needed! I'm still not comfortable expanding the API with this, but you perhaps found people that use this a lot. If it's useful for them, let's add it. |
I don't want to block your work here, if you feel that we should add this, let's merge it! I just feel that a third-party is a better way to deal with it, indeed. It just doesn't feel correct to introduce a new function on the library's API that is responsible to change something that should be a configuration. |
I guess I'll think about it. |
Aimed to allow an external interactive run experience
I added some configuration that would allow the interactive experience to be factored into an external library: I'm a bit concerned that this configuration looks like it's per-call but really it has to lean on As for the interactive run endpoint, I do think it still belongs in the core library. |
Motivation
Expecto is uniquely suitable for interactive environments (like FSI or Polyglot Notebooks) because it treats tests as values. Tests can be defined and executed all in the same code.
However, none of the current runTests methods print output to interactive environments like FSI.
If this PR is merged
This PR adds a new method that collects logs from the test run then returns them as a string.
This allows easily displaying test output in interactive environments.
For example, here's a polyglot notebook using
runTestsWithCLIArgs
Here's the same interactive cell using
runTestsReturnLogs
The new
runTestsReturnLogs
should obey options the same as other run methods