Fable.Pyxpecto 1.3.0

dotnet add package Fable.Pyxpecto --version 1.3.0
                    
NuGet\Install-Package Fable.Pyxpecto -Version 1.3.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Fable.Pyxpecto" Version="1.3.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Fable.Pyxpecto" Version="1.3.0" />
                    
Directory.Packages.props
<PackageReference Include="Fable.Pyxpecto" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Fable.Pyxpecto --version 1.3.0
                    
#r "nuget: Fable.Pyxpecto, 1.3.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#addin nuget:?package=Fable.Pyxpecto&version=1.3.0
                    
Install Fable.Pyxpecto as a Cake Addin
#tool nuget:?package=Fable.Pyxpecto&version=1.3.0
                    
Install Fable.Pyxpecto as a Cake Tool

Fable.Pyxpecto

Latest Prerelease Downloads
<a href="https://www.nuget.org/packages/Fable.Pyxpecto">Nuget</a> <a href="https://www.nuget.org/packages/Fable.Pyxpecto/absoluteLatest">Nuget (with prereleases)</a> Nuget

This repository is heavily inspired by Fable.Mocha by the awesome @Zaid-Ajaj.

Inspired by the popular Expecto library for F# and adopts the testList, testCase and testCaseAsync primitives for defining tests.

Fable.Pyxpecto can be used to run tests in Python, JavaScript, TypeScript and .NET! Or use compiler statements to switch between Pyxpecto and keep using Fable.Mocha and Expecto!

pyxpecto

Table of Contents

Features

Reuse Expecto/Fable.Mocha Tests

/// Reuse unit tests from Expecto and Fable.Mocha
let tests_basic = testList "Basic" [
    testCase "testCase works with numbers" <| fun () ->
        Expect.equal (1 + 1) 2 "Should be equal"

    testCase "isFalse works" <| fun () ->
        Expect.isFalse (1 = 2) "Should be equal"

    testCase "areEqual with msg" <| fun _ ->
        Expect.equal 2 2 "They are the same"

    testCase "isOk works correctly" <| fun _ ->
        let actual = Ok true
        Expect.isOk actual "Should be Ok"
]


Pending

Pending tests will not be run, but displayed as "skipped".

ptestCase "skipping this one" <| fun _ ->
    failwith "Shouldn't be running this test"

ptestCaseAsync "skipping this one async" <|
    async {
        failwith "Shouldn't be running this test"
    }

Focused

If there are any focused tests all other tests will not be run and are displayed as "skipped".

👀 Passing the --fail-on-focused-tests command line argument will make the runner fail if focused tests exist. This is used to avoid passing CI chains, when accidently pushing focused tests.

Example py my_focused_tests_file.py --fail-on-focused-tests will fail.

let focusedTestsCases =
    testList "Focused" [
        ftestCase "Focused sync test" <| fun _ ->
            Expect.equal (1 + 1) 2 "Should be equal"
        ftestCaseAsync "Focused async test" <|
            async {
                Expect.equal (1 + 1) 2 "Should be equal"
            }
    ]

Sequential Tests

Actually all tests run with this library will be sequential. The function is only added to comply with Expecto syntax.

💬 Help wanted. I currently have a prototype implementation for parallel tests on a branch. But it breaks collecting run-tests in .NET.

Command Line Arguments

Running any py/ts/js/net code from pyxpecto can be customized with flags:

Fable.Pyxtpecto (F#)
Author: Kevin Frey

Usage:
  (python/node/npx ts-node/dotnet run) <path_to_entrypoint> [options]

Options:
  --fail-on-focused-tests       Will exit with ExitCode 4 if run with this argument 
                                and focused tests are found.
  --silent                      Only start and result print. No print for each test.

  --do-not-exit-with-code       Will only return integer as result and not explicitly call `Environment.Exit`. 
                                This can be useful to call Pyxpecto tests from foreign test frameworks

These can also be given via:

[<EntryPoint>]
let main argv = 
    !!Pyxpecto.runTests [|
        ConfigArg.FailOnFocused
        ConfigArg.Silent
    |] all

Install

From Nuget with:

  • paket add Fable.Pyxpecto
  • <PackageReference Include="Fable.Pyxpecto" Version="0.0.0" />

Running tests

Language Agnostic

Fable.Pyxpecto does not use any dependencies and tries to support as many fable languages as possible. Check out the multitarget test project to see it fully set up!

open Fable.Pyxpecto

// This is possibly the most magic used to make this work. 
// Js and ts cannot use `Async.RunSynchronously`, instead they use `Async.StartAsPromise`.
// Here we need the transpiler not to worry about the output type.
#if !FABLE_COMPILER_JAVASCRIPT && !FABLE_COMPILER_TYPESCRIPT
let (!!) (any: 'a) = any
#endif
#if FABLE_COMPILER_JAVASCRIPT || FABLE_COMPILER_TYPESCRIPT
open Fable.Core.JsInterop
#endif

[<EntryPoint>]
let main argv = !!Pyxpecto.runTests [||] all

Then run it using:

  • .NET: dotnet run
  • JavaScript:
    • dotnet fable {rootPath} -o {rootPath}/{js_folder_name}
    • node {rootPath}/{js_folder_name}/Main.js
    • Requirements:
      • nodejs installed.
      • package.json with "type": "module".
      • init with npm init.
      • See: package.json.
  • TypeScript:
    • dotnet fable {rootPath} --lang ts -o {rootPath}/{ts_folder_name}
    • npx ts-node {rootPath}/{ts_folder_name}/Main.ts
    • Requirements:
      • possible same as JavaScript.
      • Require tsconfig file, see: tsconfig.json. (💬 Help wanted)
  • Python:
    • dotnet fable {rootPath} --lang py -o {rootPath}/{py_folder_name}
    • python {rootPath}/{py_folder_name}/main.py
    • Requirements:
      • python executable on your PATH, or replace python with path/to/python.exe.

With Mocha and Expecto

Use the following syntax to automatically switch between Expecto, Fable.Mocha and Pyxpecto:

#if FABLE_COMPILER_PYTHON
open Fable.Pyxpecto
#endif
#if FABLE_COMPILER_JAVASCRIPT
open Fable.Mocha
#endif
#if !FABLE_COMPILER
open Expecto
#endif
[<EntryPoint>]
let main argv =
    #if FABLE_COMPILER_PYTHON
    Pyxpecto.runTests [||] all
    #endif
    #if FABLE_COMPILER_JAVASCRIPT
    Mocha.runTests all
    #endif
    #if !FABLE_COMPILER
    Tests.runTestsWithCLIArgs [] [||] all
    #endif

⚠️ If you want to use Pyxpecto in combination with Fable.Mocha you need to conditionally set Fable.Mocha dependency as shown below. Without this fable will try to transpile Fable.Mocha to python, which will result in errors.


<PackageReference Condition="'$(FABLE_COMPILER_JAVASCRIPT)' == 'true'" Include="Fable.Mocha" Version="2.17.0" />

👀 Everything in curly braces are placeholders

  1. Transpile test project to python dotnet fable {path/to/tests} --lang py -o {path/to/tests}/py
  2. Run tests python {path/to/tests}/{EntryFileName.py}

Development

Requirements

  • Python
    • check with py --version (Tested with Python 3.11.1)
  • Dotnet SDK
    • check with dotnet --version (Tested with 7.0.306)
  • Node
    • check with node --version (Tested with v18.16.1)
  • npm
    • check with node --version (Tested with 9.2.0)

Setup

Run all commands in root.

  1. dotnet tool restore
  2. npm install

Routines

Tests

./build.cmd runtests

Can be specified to run tests for specific environment.

Switch test project

  • ./build.cmd runtestsdotnet
  • ./build.cmd runtestsjs
  • ./build.cmd runtestspy

Multitarget test project

  • ./build.cmd runmtpy
  • ./build.cmd runmtjs
  • ./build.cmd runmtts
  • ./build.cmd runmtnet
Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
1.3.0 179 4/14/2025
1.2.0 2,079 6/21/2024
1.1.0 536 4/12/2024
1.0.1 621 12/15/2023
1.0.0-beta.2 74 12/1/2023
0.4.0 139 11/28/2023
0.3.0 9,923 11/20/2023
0.2.0 147 11/20/2023
0.1.0 851 9/21/2023
0.0.0 901 9/13/2023

Additions:
Enhance README and Pyxpecto to support --do-not-exit-with-code flag #12
Add additional async run tests
Bugfixes:
Fix python emoji issue on windows #11