{"id":25661843,"url":"https://github.com/nyub/expekt-test","last_synced_at":"2026-05-09T07:41:14.805Z","repository":{"id":277436164,"uuid":"932428573","full_name":"NyuB/expekt-test","owner":"NyuB","description":"Inline snapshot tests for Kotlin/Java","archived":false,"fork":false,"pushed_at":"2025-02-21T06:00:39.000Z","size":1283,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-02-21T06:24:41.609Z","etag":null,"topics":["acceptance-testing","jvm"],"latest_commit_sha":null,"homepage":"","language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/NyuB.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"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}},"created_at":"2025-02-13T22:33:13.000Z","updated_at":"2025-02-21T06:00:43.000Z","dependencies_parsed_at":"2025-02-21T06:22:20.108Z","dependency_job_id":null,"html_url":"https://github.com/NyuB/expekt-test","commit_stats":null,"previous_names":["nyub/expekt-test"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NyuB%2Fexpekt-test","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NyuB%2Fexpekt-test/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NyuB%2Fexpekt-test/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NyuB%2Fexpekt-test/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/NyuB","download_url":"https://codeload.github.com/NyuB/expekt-test/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":240410953,"owners_count":19797000,"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":["acceptance-testing","jvm"],"created_at":"2025-02-24T03:23:57.829Z","updated_at":"2026-05-09T07:41:14.800Z","avatar_url":"https://github.com/NyuB.png","language":"Kotlin","funding_links":[],"categories":[],"sub_categories":[],"readme":"![ci-badge](https://github.com/NyuB/expekt-test/actions/workflows/ci.yml/badge.svg?branch=main)\n![latest release](https://img.shields.io/github/release/NyuB/expekt-test)\n![latest release date](https://img.shields.io/github/release-date/NyuB/expekt-test)\n\n# Expekt tests\n\nInline snapshot testing for Kotlin and Java, inspired by JaneStreet's [expect-tests framework for OCaml](https://blog.janestreet.com/the-joy-of-expect-tests/)\n\n![waveforms demo](doc/waveforms.gif)\n\n- [Principles](#principles)\n- [Alternatives and external resources on snapshot testing](#alternatives-and-external-resources-on-snapshot-testing)\n- [Setup](#setup)\n  + [Maven](#from-maven)\n  + [From Source](#from-source)\n- [Usage](#usage)\n  + [Kotlin](#kotlin)\n  + [Java](#java)\n  + [Examples](#examples)\n  + [Constraints on expected string blocks](#constraints-on-expected-string-blocks)\n- [Customizing promotion review](#customizing-promotion-review)\n\n## Principles\n\nExpekt is a lightweight **inline** **snapshot testing** tool:\n- targeted toward to the assert/then part of a typical arrange-act-assert/given-when-then test setup\n- compare textual representation of expected (**snapshot**ed) outputs and actual ones. With Expekt, the expected outputs are expressed as raw string blocks in source code (the **inline** part).\n- offers a 'promotion' mechanism to replace the expected outputs with the actual ones when the user (developer) decides the change is suitable. The promotion is done directly in the source code, altering the string blocks. \n\nThis means that efforts to represent your objects as readable strings, (such as ascii art, tables, graphs ...) can be directly exploited as readable assertions.\nIt also makes updating these assertions effortless, should their representation change.\n\n## Alternatives and external resources on snapshot testing\n\nSnapshot testing (also called approval, acceptance, golden-master, ...) is a popular technique in many ecosystems. \n\nA few resources on this topic:\n- [The JaneStreet article on the expect-test library that inspired Expekt](https://blog.janestreet.com/the-joy-of-expect-tests/)\n- [An article describing the advantages of inline snapshot testing](https://ianthehenry.com/posts/my-kind-of-repl/)\n- [An article from TigerBeetle describing their Zig library for inline snapshot testing](https://tigerbeetle.com/blog/2024-05-14-snapshot-testing-for-the-masses/)\n\nSome alternatives or equivalents in other ecosystems:\n- [Selfie (Java/Python/JavaScript)](https://selfie.dev/jvm)\n- [ApprovalTests (Java and many others)](https://github.com/approvals/approvaltests.java)\n- [expect-test (OCaml)](https://github.com/janestreet/ppx_expect)\n- [Jest (JavaScript)](https://jestjs.io/fr/docs/snapshot-testing)\n- [Insta (Rust)](https://insta.rs/)\n- [Verify (C#)](https://github.com/VerifyTests/Verify)\n\nHere is a quick comparison table if you want to choose between Expekt and another JVM tool, or come from another language and want an idea of the corresponding features in Expekt:\n\n| Tool          | JVM | Inline snapshot | File snapshot | Update control                                                                         | Interactive snapshot review | Extensible diff/review |\n|---------------|:---:|----------------:|---------------|----------------------------------------------------------------------------------------|-----------------------------|------------------------|\n| Expekt        |  ✅  |               ✅ | ❌             | user-configurable flag, per test class, test method, or `promote@` label on a snapshot | ✅                           | ✅                      | \n| Selfie        |  ✅  |               ✅ | ✅             | global flag, `toBe_TODO()` or `//selfieonce` comment                                   | ❌                           | ❌                      |\n| ApprovalTests |  ✅  |               ❌ | ✅             | interactive, global flag                                                               | ✅                           | ✅                      |\n| expect-test   |  ❌  |               ✅ | ❌             | promotion command to update differing snapshots                                        | ❌                           | ❌                      |\n| Jest          |  ❌  |               ✅ | ✅             | interactive, promotion command to update differing snapshots                           | ✅                           | ❌                      |\n| Insta         |  ❌  |               ✅ | ✅             | interactive, global flag                                                               | ✅                           | ❌                      |\n| Verify        |  ❌  |               ❌ | ✅             | interactive, global flag                                                               | ✅                           | ✅                      |\n\n## Setup\n\n### From Maven\n\nAdd expekt dependency to your `pom.xml`:\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003eio.github.nyub\u003c/groupId\u003e\n    \u003cartifactId\u003eexpekt-test\u003c/artifactId\u003e\n    \u003cversion\u003e1.1.0\u003c/version\u003e\n    \u003cscope\u003etest\u003c/scope\u003e\n\u003c/dependency\u003e\n```\n\n### From source\n\nThe source code is only comprised of 2 files (and even 1 if you don't use the JUnit extension).\nFeel free to download [ExpectTests.kt](src/main/kotlin/nyub/expekt/ExpectTests.kt) and [ExpectTestExtension.kt](src/main/kotlin/nyub/expekt/junit/ExpectTestExtension.kt) directly into your sources and experiment.\n\n## Usage\n\n### Kotlin\n\nThe recommended usage for Kotlin is to define an ExpectTests shared configuration and write your test with the `expectTest { }` scope function. See [the kotlin tests](src/test/kotlin/nyub/expekt/KotlinUsageTest.kt) for setup examples.\n\nPromotion is triggered:\n- By returning `true` from the [ExpectTests](src/main/kotlin/nyub/expekt/ExpectTests.kt) `promote` parameter\n  + See [PromotionTrigger](src/main/kotlin/nyub/expekt/ExpectTests.kt)\n- By adding a `promote@` label before the [expected string block](#constraints-on-expected-string-blocks). This overrides the above-mentioned `promote` parameter\n```kotlin\n\"\u003cCONTENT\u003e\".expect(promote@\"\"\"\n\u003cCONTENT\u003e\n\"\"\")\n```\n\nThe JUnit 5 extension is also usable from the Kotlin side, even if it brings fewer improvements than for [Java users](#java).\n\n### Java\n\nThe recommended usage for Java is to use the provided JUnit 5 extension. See [the java tests](src/test/kotlin/nyub/expekt/JavaUsageTest.java) for examples.\n\nPromotion is triggered:\n- By setting the system property `nyub.expekt.promote` to `\"true\"`\n- At class level by using `@Promote(true/false)` annotation\n- At method (test) level by using `@Promote(true/false)` annotation\n\nFor non-junit codebases, the Kotlin scope functions are usable on the Java side, with slightly degraded ergonomics.\n\n### Examples\n\nMore examples are available in [the demo folder](src/test/kotlin/nyub/expekt/demos)\n\n### Constraints on expected string blocks\n\nExpekt detects string blocks to check and promote based on a few heuristics.\n\nThis imposes some formatting rule regarding the `expect(` call.\n\n1) the `expect(` call should be written in place, not aliased\n2) the expected content\n   - should be in a triple-quoted-string block\n   - should not use [Kotlin string interpolation](https://kotlinlang.org/docs/strings.html#string-templates)\n3) the opening triple-quotes should be the next token after the `expect(` call (not nested in parentheses or aliased)\n4) the closing triple-quotes\n    - should be on a different line than the opening triple-quotes\n    - should be on a different line than the expected content\n\n#### OK:\n\n```kotlin\nexpect(\"\"\"\n\u003cCONTENT\u003e\n\"\"\")\n```\n\n```kotlin\nexpect(\n\"\"\"\n\u003cCONTENT\u003e\n\"\"\")\n```\n\n```kotlin\nexpect(\n\"\"\"\n\u003cCONTENT\u003e\n\"\"\"\n)\n```\n\n#### Not OK:\n\n```kotlin\nexpect(\"\u003cCONTENT\u003e\")\n```\n\n- (because the expected content is not within a triple-quoted block)\n\n```kotlin\nexpect(\"\"\"\u003cCONTENT\u003e\"\"\")\n```\n- (because the closing quotes are on the same line as the opening quotes)\n\n```kotlin\nexpect(\"\"\"\n\u003cCONTENT\u003e\"\"\")\n```\n- (because the closing quotes are on the same line as the expected content)\n\n```kotlin\nexpect(f(\"\"\"\n\u003cCONTENT\u003e\n\"\"\"))\n```\n\n- (because the opening quotes are not the next token after the `expect(` call)\n\n\u003c!-- snippet-start constraint-error-alias --\u003e\n\u003ca id='snippet-constraint-error-alias'\u003e\u003c/a\u003e\n```kotlin\n        fun alias(s: String) = expect(s)\n        alias(\n        \"\"\"\n           \u003cCONTENT\u003e\n           \"\"\"\n        )\n```\n\u003csup\u003e\u003ca href='/src\\test\\kotlin\\nyub\\expekt\\ExpectCallConstraintsTest.kt#L39-L46' title='Snippet source file'\u003esnippet source\u003c/a\u003e | \u003ca href='#snippet-constraint-error-alias' title='Start of snippet'\u003eanchor\u003c/a\u003e\u003c/sup\u003e\n\u003c!-- snippet-end --\u003e\n\n- (because expect is aliased, so the search starts from the actual call site on the first line)\n\n```kotlin\nval content = \"\u003cCONTENT\u003e\"\nexpect(\"\"\"\n$content\n\"\"\")\n```\n\n- (because the expected string block uses string interpolation)\n\nSee [ExpectTestsTest.ExpectCallConstraintsTest](src/test/kotlin/nyub/expekt/ExpectCallConstraintsTest.kt) for more invalid examples\n\n## Customizing promotion review\n\nWhen comparing actual and expected contents, ExpectTests.promote() is called to choose between updating the expected content or perform equality assertion, where `promote` is an implementation of `PromotionTrigger`.\nInjecting an implementation of PromotionTrigger to ExpectTests configuration allows to define any custom review mechanism, for example interactive prompting or reports.\n\nThe builtin [PromptWithDiffPanel](src/main/kotlin/nyub/expekt/diff/PromptWithDiffPanel.kt) pops up a git-like diff view asking user to accept or not each differing snapshot along the test suite.\n\n![Interactive review gif](doc/diff.gif)","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnyub%2Fexpekt-test","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnyub%2Fexpekt-test","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnyub%2Fexpekt-test/lists"}