{"id":14978856,"url":"https://github.com/japgolly/test-state","last_synced_at":"2025-04-07T13:08:00.410Z","repository":{"id":8359136,"uuid":"58114707","full_name":"japgolly/test-state","owner":"japgolly","description":"Scala Test-State. ","archived":false,"fork":false,"pushed_at":"2024-08-12T21:41:18.000Z","size":1614,"stargazers_count":142,"open_issues_count":30,"forks_count":12,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-03-31T11:04:48.307Z","etag":null,"topics":["cats","dom","fp","functional-programming","react","scala","scalajs","scalajs-react","scalaz","script","selenium","state","testing"],"latest_commit_sha":null,"homepage":"","language":"Scala","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/japgolly.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":null,"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},"funding":{"patreon":"japgolly"}},"created_at":"2016-05-05T08:04:33.000Z","updated_at":"2024-11-22T01:05:16.000Z","dependencies_parsed_at":"2023-12-22T13:06:15.048Z","dependency_job_id":"1adc55eb-ef56-4230-8e28-2976dd3a1539","html_url":"https://github.com/japgolly/test-state","commit_stats":{"total_commits":775,"total_committers":6,"mean_commits":"129.16666666666666","dds":0.06580645161290322,"last_synced_commit":"d62bd0a1bc13c97bd5a88c6a7964aab4f23bd453"},"previous_names":[],"tags_count":21,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/japgolly%2Ftest-state","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/japgolly%2Ftest-state/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/japgolly%2Ftest-state/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/japgolly%2Ftest-state/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/japgolly","download_url":"https://codeload.github.com/japgolly/test-state/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247657281,"owners_count":20974345,"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":["cats","dom","fp","functional-programming","react","scala","scalajs","scalajs-react","scalaz","script","selenium","state","testing"],"created_at":"2024-09-24T13:58:32.241Z","updated_at":"2025-04-07T13:08:00.390Z","avatar_url":"https://github.com/japgolly.png","language":"Scala","readme":"# Scala Test-State\n\nTest **stateful** stuff **statelessly**, and reasonably.\n\n[![Build Status](https://travis-ci.org/japgolly/test-state.svg?branch=master)](https://travis-ci.org/japgolly/test-state)\n\n# Contents\n\n- [What is this?](#what-is-this)\n- [How does this work?](#how-does-this-work)\n- How do I use this?\n  - [Usage](doc/USAGE.md)\n  - [Types](doc/TYPES.md)\n  - [DSL](doc/DSL.md)\n  - [Composability](doc/COMPOSE.md)\n- [Modules](#modules)\n- [Examples](#examples)\n- [Changelogs](doc/changelog)\n- [Support](#supportexamples)\n\n\n# What is this?\n\nFirstly, a quick mention of what this *is not*:\n\n1. This is not a test *framework*.\n   \u003cbr\u003eUse it conjunction with ScalaTest, Specs2, μTest, etc.\n\n1. This is not a property testing library.\n   \u003cbr\u003eUse it conjunction with ScalaCheck, Nyaya, ScalaProps, etc.\n\nOk, so what *is* this?\nThis is a library that:\n\n1. Lets you write pure, immutable, referentially-transparent tests\n   that verify stateful, effectful code or data.\n\n1. Encourages composability of test concepts such as invariants/properties, pre/post conditions,\n   dynamic actions/assertions, and more.\n\n1. Makes test failure and inspection easy to comprehend.\n\n### Uses\n\n* Unit-test a webapp with Scala.JS.\n* Integration testing.\n* UAT automation.\n* Random-test (fuzz-test) like Android's `monkeyrunner` or ScalaCheck's `Command` API.\n* Data migration.\n\n\n### Features\n\n* Compiled for Scala \u0026 Scala.JS.\n* Can run synchronously, asynchronously (`Future`) or in your own context-type (eg `IO`). Is stack-safe.\n* Everything is immutable and composable.\n* Everything can be transformed into (reused in) different contexts.\n* Combines property and imperative testing.\n* Actions and assertions can be non-deterministic and/or dependent on runtime state.\n* Transparent and informative about test execution.\n* Includes an abstract `DomZipper` which greatly simplifies the task of HTML/SVG observation.\n* Comes with various `DomZipper` implementations and backends.\n* Lots of platform-specific utilities for web testing.\n* Configurable error handling. Be impure and throw exceptions or be pure and use a custom ADT to precisely maintain all forms of failure and error in your domain; it's up to you.\n* Extension modules for various 3rd-party libraries. (Cats, more.)\n\n\n# How does this work?\n\nThe key is to take **observations** of anything relevant in the stateful test subject.\nObservations are like immutable snapshots.\nThey capture what the state was at a particular point in time.\nOnce an observation is captured, assertions are performed on it.\n\nOptionally, you can specify some kind of test-only state that you modify as you test,\nand use to ensure the real-world observations are what you expect.\n\u003cbr\u003eFor example, if you're testing a bank account app, you could maintain your own expected balance such that\nwhen you instruct the app to make a deposit, you add the same amount to your state.\nYou could then add an invariant that whenever the balance is shown in the app, it matches the expected state balance.\n\nThis is a (simplified) model of how tests are executed:\n\n![concept](doc/concept.uml.png)\n\nWhen retries are enabled, then test execution is\n[like this](https://rawgit.com/japgolly/test-state/master/doc/retries.gv.svg).\n\n# How do I use this?\n  - [Usage](doc/USAGE.md)\n  - [Types](doc/TYPES.md)\n  - [DSL](doc/DSL.md)\n  - [Composability](doc/COMPOSE.md)\n\n# Modules\n\n| Module                | Description | JVM | JS |\n|-----------------------|-------------|-----|-----|\n| `core`                | The core module. | JVM | JS |\n| `dom-zipper`          | Standalone utility for observing web DOM with precision with conciseness.\u003cbr\u003eThis is the base API; concrete implementations below. | JVM | JS |\n| `dom-zipper-jsoup`    | DOM zipper built on [Jsoup](https://jsoup.org). | JVM | |\n| `dom-zipper-selenium` | DOM zipper built on [Selenium](https://www.seleniumhq.org).\u003cbr\u003eAlso comes with a fast version with uses Jsoup for nearly all operations which is 5-50x faster.\u003cbr\u003eSee [doc/SELENIUM.md](doc/SELENIUM.md). | JVM | |\n| `dom-zipper-sizzle`   | DOM zipper built on [Sizzle](https://sizzlejs.com/). | | JS |\n| `ext-cats`            | Extensions for [Cats](https://github.com/typelevel/cats). | JVM | JS |\n| `ext-nyaya`           | Extensions for [Nyaya](https://github.com/japgolly/nyaya). | JVM | JS |\n| `ext-scalajs-react`   | Extensions for [scalajs-react](https://github.com/japgolly/scalajs-react). | | JS |\n| `ext-selenium`        | Extensions for [Selenium](https://www.seleniumhq.org). | JVM | |\n\n\n# Examples\n\n* [Scala.Js + React](example-react) - Demonstrates DomZipper, invariants, actions, basics.\n* [Selenium](example-selenium) - Demonstrates Selenium testing of external web content, using retry scheduling (instead of `Thread.sleep`), parallelism and concurrency.\n* [TODO] DB triggers.    - real external state, ref.\n* [TODO] Mutable sample. - fuzz, invariants.\n\n\n# Support\nIf you like what I do\n—my OSS libraries, my contributions to other OSS libs, [my programming blog](https://japgolly.blogspot.com)—\nand you'd like to support me, more content, more lib maintenance, [please become a patron](https://www.patreon.com/japgolly)!\nI do all my OSS work unpaid so showing your support will make a big difference.\n","funding_links":["https://patreon.com/japgolly","https://www.patreon.com/japgolly)!"],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjapgolly%2Ftest-state","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjapgolly%2Ftest-state","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjapgolly%2Ftest-state/lists"}