https://github.com/freymaurer/fable.pyxpecto
fable testing library targeting multiple languages
https://github.com/freymaurer/fable.pyxpecto
fable-dotnet fable-javascript fable-libraries fable-python fable-typescript testing unittest
Last synced: about 1 year ago
JSON representation
fable testing library targeting multiple languages
- Host: GitHub
- URL: https://github.com/freymaurer/fable.pyxpecto
- Owner: Freymaurer
- License: mit
- Created: 2023-08-07T07:41:51.000Z (almost 3 years ago)
- Default Branch: main
- Last Pushed: 2024-06-21T19:09:50.000Z (almost 2 years ago)
- Last Synced: 2025-04-08T12:51:47.144Z (about 1 year ago)
- Topics: fable-dotnet, fable-javascript, fable-libraries, fable-python, fable-typescript, testing, unittest
- Language: F#
- Homepage:
- Size: 108 KB
- Stars: 11
- Watchers: 2
- Forks: 1
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Fable.Pyxpecto
| Latest | Prerelease | Downloads |
|----------------|---------|-----------|
| |||
> This repository is heavily inspired by [Fable.Mocha](https://github.com/Zaid-Ajaj/Fable.Mocha/) by the awesome [@Zaid-Ajaj](https://github.com/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!

**Table of Contents**
- [Fable.Pyxpecto](#fablepyxpecto)
- [Features](#features)
- [Reuse Expecto/Fable.Mocha Tests](#reuse-expectofablemocha-tests)
- [Pending](#pending)
- [Focused](#focused)
- [Sequential Tests](#sequential-tests)
- [Command Line Arguments](#command-line-arguments)
- [Install](#install)
- [Running tests](#running-tests)
- [Language Agnostic](#language-agnostic)
- [With Mocha and Expecto](#with-mocha-and-expecto)
- [Development](#development)
- [Requirements](#requirements)
- [Setup](#setup)
- [Routines](#routines)
- [Tests](#tests)
## Features
### Reuse Expecto/Fable.Mocha Tests
```fsharp
/// 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".
```fsharp
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.
```fsharp
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) [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:
```fsharp
[]
let main argv =
!!Pyxpecto.runTests [|
ConfigArg.FailOnFocused
ConfigArg.Silent
|] all
```
## Install
From [Nuget](https://www.nuget.org/packages/Fable.Pyxpecto) with:
- `paket add Fable.Pyxpecto`
- ``
## 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](./tests/Multitarget.Tests) to see it fully set up!
```fsharp
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
[]
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](./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](./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:
```fsharp
#if FABLE_COMPILER_PYTHON
open Fable.Pyxpecto
#endif
#if FABLE_COMPILER_JAVASCRIPT
open Fable.Mocha
#endif
#if !FABLE_COMPILER
open Expecto
#endif
```
```fsharp
[]
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.
```xml
```
> 👀 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](https://dotnet.microsoft.com/en-us/download)
- 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`
1. `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`