{"id":20015233,"url":"https://github.com/freymaurer/fable.pyxpecto","last_synced_at":"2025-05-04T22:31:29.007Z","repository":{"id":194528472,"uuid":"675556783","full_name":"Freymaurer/Fable.Pyxpecto","owner":"Freymaurer","description":"fable testing library targeting multiple languages","archived":false,"fork":false,"pushed_at":"2024-06-21T19:09:50.000Z","size":111,"stargazers_count":11,"open_issues_count":1,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-04-08T12:51:47.144Z","etag":null,"topics":["fable-dotnet","fable-javascript","fable-libraries","fable-python","fable-typescript","testing","unittest"],"latest_commit_sha":null,"homepage":"","language":"F#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Freymaurer.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-08-07T07:41:51.000Z","updated_at":"2025-04-04T14:46:06.000Z","dependencies_parsed_at":"2024-11-13T07:45:42.925Z","dependency_job_id":"718a77fa-5aa1-4431-8784-984e79a90e1b","html_url":"https://github.com/Freymaurer/Fable.Pyxpecto","commit_stats":null,"previous_names":["freymaurer/fable.pyxpecto"],"tags_count":9,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Freymaurer%2FFable.Pyxpecto","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Freymaurer%2FFable.Pyxpecto/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Freymaurer%2FFable.Pyxpecto/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Freymaurer%2FFable.Pyxpecto/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Freymaurer","download_url":"https://codeload.github.com/Freymaurer/Fable.Pyxpecto/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252408253,"owners_count":21743081,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["fable-dotnet","fable-javascript","fable-libraries","fable-python","fable-typescript","testing","unittest"],"created_at":"2024-11-13T07:45:25.149Z","updated_at":"2025-05-04T22:31:28.978Z","avatar_url":"https://github.com/Freymaurer.png","language":"F#","funding_links":[],"categories":[],"sub_categories":[],"readme":"﻿# Fable.Pyxpecto\n\n\n\n| Latest | Prerelease | Downloads |\n|----------------|---------|-----------|\n| \u003ca href=\"https://www.nuget.org/packages/Fable.Pyxpecto\"\u003e![Nuget](https://img.shields.io/nuget/v/Fable.Pyxpecto?logo=nuget)\u003c/a\u003e|\u003ca href=\"https://www.nuget.org/packages/Fable.Pyxpecto/absoluteLatest\"\u003e![Nuget (with prereleases)](https://img.shields.io/nuget/vpre/Fable.Pyxpecto?logo=nuget)\u003c/a\u003e|![Nuget](https://img.shields.io/nuget/dt/Fable.Pyxpecto?label=downloads)|\n\n\u003e 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).\n\nInspired by the popular Expecto library for F# and adopts the testList, testCase and testCaseAsync primitives for defining tests.\n\nFable.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!\n\n![pyxpecto](https://github.com/Freymaurer/Fable.Pyxpecto/assets/39732517/c5d09db3-8f63-4372-8655-6330c8a00af1)\n\n**Table of Contents**\n- [Fable.Pyxpecto](#fablepyxpecto)\n  - [Features](#features)\n    - [Reuse Expecto/Fable.Mocha Tests](#reuse-expectofablemocha-tests)\n    - [Pending](#pending)\n    - [Focused](#focused)\n    - [Sequential Tests](#sequential-tests)\n    - [Command Line Arguments](#command-line-arguments)\n  - [Install](#install)\n  - [Running tests](#running-tests)\n    - [Language Agnostic](#language-agnostic)\n    - [With Mocha and Expecto](#with-mocha-and-expecto)\n  - [Development](#development)\n    - [Requirements](#requirements)\n    - [Setup](#setup)\n    - [Routines](#routines)\n      - [Tests](#tests)\n\n\n## Features\n\n### Reuse Expecto/Fable.Mocha Tests\n\n```fsharp\n/// Reuse unit tests from Expecto and Fable.Mocha\nlet tests_basic = testList \"Basic\" [\n    testCase \"testCase works with numbers\" \u003c| fun () -\u003e\n        Expect.equal (1 + 1) 2 \"Should be equal\"\n\n    testCase \"isFalse works\" \u003c| fun () -\u003e\n        Expect.isFalse (1 = 2) \"Should be equal\"\n\n    testCase \"areEqual with msg\" \u003c| fun _ -\u003e\n        Expect.equal 2 2 \"They are the same\"\n\n    testCase \"isOk works correctly\" \u003c| fun _ -\u003e\n        let actual = Ok true\n        Expect.isOk actual \"Should be Ok\"\n]\n\n\n```\n### Pending\n\nPending tests will not be run, but displayed as \"skipped\".\n\n```fsharp\nptestCase \"skipping this one\" \u003c| fun _ -\u003e\n    failwith \"Shouldn't be running this test\"\n\nptestCaseAsync \"skipping this one async\" \u003c|\n    async {\n        failwith \"Shouldn't be running this test\"\n    }\n```\n\n### Focused\n\nIf there are any focused tests all other tests will not be run and are displayed as \"skipped\".\n\n\u003e 👀 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.\n\u003e\n\u003e Example `py my_focused_tests_file.py --fail-on-focused-tests` will fail.\n\n```fsharp\nlet focusedTestsCases =\n    testList \"Focused\" [\n        ftestCase \"Focused sync test\" \u003c| fun _ -\u003e\n            Expect.equal (1 + 1) 2 \"Should be equal\"\n        ftestCaseAsync \"Focused async test\" \u003c|\n            async {\n                Expect.equal (1 + 1) 2 \"Should be equal\"\n            }\n    ]\n```\n\n### Sequential Tests\n\nActually all tests run with this library will be sequential. The function is only added to comply with Expecto syntax.\n\n💬 Help wanted. I currently have a prototype implementation for parallel tests on a branch. But it breaks collecting run-tests in .NET.\n\n### Command Line Arguments\n\nRunning any py/ts/js/net code from pyxpecto can be customized with flags:\n\n```\nFable.Pyxtpecto (F#)\nAuthor: Kevin Frey\n\nUsage:\n  (python/node/npx ts-node/dotnet run) \u003cpath_to_entrypoint\u003e [options]\n\nOptions:\n  --fail-on-focused-tests       Will exit with ExitCode 4 if run with this argument \n                                and focused tests are found.\n  --silent                      Only start and result print. No print for each test.\n\n  --do-not-exit-with-code       Will only return integer as result and not explicitly call `Environment.Exit`. \n                                This can be useful to call Pyxpecto tests from foreign test frameworks\n\n```\n\nThese can also be given via: \n\n```fsharp\n[\u003cEntryPoint\u003e]\nlet main argv = \n    !!Pyxpecto.runTests [|\n        ConfigArg.FailOnFocused\n        ConfigArg.Silent\n    |] all\n```\n\n## Install\n\nFrom [Nuget](https://www.nuget.org/packages/Fable.Pyxpecto) with:\n\n- `paket add Fable.Pyxpecto`\n- `\u003cPackageReference Include=\"Fable.Pyxpecto\" Version=\"0.0.0\" /\u003e`\n\n## Running tests\n\n### Language Agnostic\n\nFable.Pyxpecto does not use any dependencies and tries to support as many fable languages as possible. \nCheck out the [multitarget test project](./tests/Multitarget.Tests) to see it fully set up!\n\n```fsharp\nopen Fable.Pyxpecto\n\n// This is possibly the most magic used to make this work. \n// Js and ts cannot use `Async.RunSynchronously`, instead they use `Async.StartAsPromise`.\n// Here we need the transpiler not to worry about the output type.\n#if !FABLE_COMPILER_JAVASCRIPT \u0026\u0026 !FABLE_COMPILER_TYPESCRIPT\nlet (!!) (any: 'a) = any\n#endif\n#if FABLE_COMPILER_JAVASCRIPT || FABLE_COMPILER_TYPESCRIPT\nopen Fable.Core.JsInterop\n#endif\n\n[\u003cEntryPoint\u003e]\nlet main argv = !!Pyxpecto.runTests [||] all\n```\n\nThen run it using:\n\n- **.NET**: `dotnet run`\n- **JavaScript**: \n  - `dotnet fable {rootPath} -o {rootPath}/{js_folder_name}`\n  - `node {rootPath}/{js_folder_name}/Main.js`\n  - *Requirements*:\n    - nodejs installed. \n    - package.json with `\"type\": \"module\"`.\n    - init with `npm init`.\n    - See: [package.json](./package.json).\n- **TypeScript**:\n  - `dotnet fable {rootPath} --lang ts -o {rootPath}/{ts_folder_name}`\n  - `npx ts-node {rootPath}/{ts_folder_name}/Main.ts`\n  - *Requirements*: \n    - possible same as JavaScript.\n    - Require tsconfig file, see: [tsconfig.json](./tsconfig.json). (💬 Help wanted)\n- **Python**:\n  - `dotnet fable {rootPath} --lang py -o {rootPath}/{py_folder_name}`\n  - `python {rootPath}/{py_folder_name}/main.py`\n  - *Requirements*: \n    - python executable on your PATH, or replace `python` with `path/to/python.exe`.\n\n### With Mocha and Expecto\n\nUse the following syntax to automatically switch between Expecto, Fable.Mocha and Pyxpecto:\n\n```fsharp\n#if FABLE_COMPILER_PYTHON\nopen Fable.Pyxpecto\n#endif\n#if FABLE_COMPILER_JAVASCRIPT\nopen Fable.Mocha\n#endif\n#if !FABLE_COMPILER\nopen Expecto\n#endif\n```\n\n```fsharp\n[\u003cEntryPoint\u003e]\nlet main argv =\n    #if FABLE_COMPILER_PYTHON\n    Pyxpecto.runTests [||] all\n    #endif\n    #if FABLE_COMPILER_JAVASCRIPT\n    Mocha.runTests all\n    #endif\n    #if !FABLE_COMPILER\n    Tests.runTestsWithCLIArgs [] [||] all\n    #endif\n```\n\n⚠️ 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.\n\n```xml\n\u003c!-- .fsproj file--\u003e\n\u003cPackageReference Condition=\"'$(FABLE_COMPILER_JAVASCRIPT)' == 'true'\" Include=\"Fable.Mocha\" Version=\"2.17.0\" /\u003e\n```\n\n\u003e 👀 Everything in curly braces are placeholders\n\n1. Transpile test project to python `dotnet fable {path/to/tests} --lang py -o {path/to/tests}/py`\n2. Run tests `python {path/to/tests}/{EntryFileName.py}`\n\n## Development\n\n### Requirements\n\n- Python\n  - check with `py --version` (Tested with `Python 3.11.1`)\n- [Dotnet SDK](https://dotnet.microsoft.com/en-us/download)\n  - check with `dotnet --version` (Tested with `7.0.306`)\n- Node\n  - check with `node --version` (Tested with `v18.16.1`)\n- npm\n  - check with `node --version` (Tested with `9.2.0`)\n\n### Setup\n\nRun all commands in root.\n\n1. `dotnet tool restore`\n1. `npm install`\n\n### Routines\n\n#### Tests\n\n`./build.cmd runtests`\n\nCan be specified to run tests for specific environment.\n\n\u003e Switch test project\n- `./build.cmd runtestsdotnet`\n- `./build.cmd runtestsjs`\n- `./build.cmd runtestspy`\n\n\u003e Multitarget test project\n- `./build.cmd runmtpy`\n- `./build.cmd runmtjs`\n- `./build.cmd runmtts`\n- `./build.cmd runmtnet`\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffreymaurer%2Ffable.pyxpecto","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffreymaurer%2Ffable.pyxpecto","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffreymaurer%2Ffable.pyxpecto/lists"}