{"id":32111633,"url":"https://github.com/samth/recspecs","last_synced_at":"2026-02-20T00:30:47.990Z","repository":{"id":299517939,"uuid":"997614648","full_name":"samth/recspecs","owner":"samth","description":"Expect testing for Racket","archived":false,"fork":false,"pushed_at":"2026-01-13T05:31:20.000Z","size":131,"stargazers_count":3,"open_issues_count":3,"forks_count":1,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-01-13T08:35:30.095Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Racket","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/samth.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,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2025-06-06T20:41:59.000Z","updated_at":"2026-01-13T05:31:23.000Z","dependencies_parsed_at":"2025-06-17T00:40:08.332Z","dependency_job_id":null,"html_url":"https://github.com/samth/recspecs","commit_stats":null,"previous_names":["samth/recspecs"],"tags_count":0,"template":false,"template_full_name":"racket-templates/package","purl":"pkg:github/samth/recspecs","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/samth%2Frecspecs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/samth%2Frecspecs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/samth%2Frecspecs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/samth%2Frecspecs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/samth","download_url":"https://codeload.github.com/samth/recspecs/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/samth%2Frecspecs/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29637407,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-19T22:32:43.237Z","status":"ssl_error","status_checked_at":"2026-02-19T22:32:38.330Z","response_time":117,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":[],"created_at":"2025-10-20T14:43:02.906Z","updated_at":"2026-02-20T00:30:47.978Z","avatar_url":"https://github.com/samth.png","language":"Racket","funding_links":[],"categories":[],"sub_categories":[],"readme":"# recspecs\n\n`recspecs` provides a lightweight expect testing facility for Racket. It is\ninspired by [Jane Street's `expect_test` for OCaml](https://github.com/janestreet/ppx_expect)\nand the [`expect-test` crate](https://github.com/rust-analyzer/expect-test) for Rust.\n\nExpect tests record the output of expressions directly in the source file.\nEach `expect` form expands to a small RackUnit test that compares the\ncaptured output against the recorded expectation. When the environment\nvariable `RECSPECS_UPDATE` is set, failing expectations are automatically\nupdated in the file instead of causing a failure.\n\nAdditional forms mirror features from the OCaml and Rust libraries:\n\n* `expect-file` compares the output against the contents of a separate file\n  and rewrites that file when updating.\n* `expect-exn` checks that an expression raises an exception with a given\n  message.\n* `expect-unreachable` fails if the wrapped expression is evaluated.\n* `expect/print` runs `expr`, prints the result with `print`, and compares\n  the printed output.\n* `expect/pretty` is like `expect/print` but uses `pretty-print`, so the\n  expectation includes a trailing newline.\n* `expect/shell` from `recspecs/shell` runs an external command and compares\n  the session against a transcript. Lines beginning with `\u003e` are sent to the\n  command's input.\n* All expectation forms accept multiple string arguments which are\n  concatenated together. This is handy when using\n  `#lang at-exp` for multi-line expectations.\n* Setting the `RECSPECS_UPDATE_TEST` environment variable to a test case\n  name limits updates to only that expectation.\n* Set `RECSPECS_VERBOSE` or parameterize `recspecs-verbose?` to print\n  captured output while tests run.\n* Pass `#:port 'stderr` to capture output from `current-error-port` in\n  `expect`, `expect-file`, `expect-exn`, or `capture-output`. Use `'both`\n  to capture from both output ports at once.\n* Use `capture-output` to run a thunk and return its printed output.\n\n## Example\n\n```racket\n#lang racket\n(require recspecs)\n\n(expect\n  (begin\n    (displayln \"hello\")\n    (displayln (+ 1 2)))\n  \"hello\\n3\\n\")\n\n(expect (display \"oops\" (current-error-port))\n        \"oops\"\n        #:port 'stderr)\n\n(expect (begin\n          (display \"warn\" (current-error-port))\n          (display \"out\"))\n        \"warnout\"\n        #:port 'both)\n```\n\nUsing @ expressions from `#lang at-exp` can make multi-line output\neasier to write:\n\n```racket\n#lang at-exp racket\n(require recspecs)\n\n@expect[(begin (displayln \"hello\") (displayln (+ 1 2)))]{\nhello\n3}\n```\n\nMark code that should not run with `expect-unreachable`:\n\n```racket\n(when #f\n  (expect-unreachable (displayln \"never\")))\n```\n\nYou can also capture output directly without an expectation:\n\n```racket\n(capture-output (lambda () (display \"hi\"))) ; =\u003e \"hi\"\n(capture-output (lambda () (display \"err\" (current-error-port)))\n               #:port 'stderr) ; =\u003e \"err\"\n(capture-output (lambda ()\n                  (display \"warn\" (current-error-port))\n                  (display \"out\"))\n               #:port 'both) ; =\u003e \"warnout\"\n```\n\n### Additional examples\n\nStore expectations in a separate file with `expect-file`:\n\n```racket\n(expect-file\n  (begin\n    (displayln \"hello\")\n    (displayln \"world\"))\n  \"expected.txt\")\n```\n\nCheck exception messages using `expect-exn`:\n\n```racket\n(expect-exn (raise-user-error \"bad\") \"bad\")\n```\n\nAutomatically print a value before comparing:\n\n```racket\n(expect/print (+ 1 2) \"3\")\n(expect/pretty '(1 2 3) \"(1 2 3)\\n\")\n@expect/shell[\"cat\"]{\n\u003e hi\nhi\n\u003e there\nthere\n}\n```\n\nTransform output before comparison with `recspecs-output-filter`:\n\n```racket\n(parameterize ([recspecs-output-filter string-upcase])\n  (expect (display \"ok\") \"OK\"))\n```\n\nTrim whitespace before checking the result:\n\n```racket\n(parameterize ([recspecs-output-filter string-trim])\n  (expect (display \"  hi  \") \"hi\"))\n```\n\nRemove digits entirely:\n\n```racket\n(parameterize ([recspecs-output-filter\n                (lambda (s) (regexp-replace* #px\"[0-9]+\" s \"\"))])\n  (expect (display \"v1.2\") \"v.\"))\n```\n\nThe library also exposes a mutable `expectation` value for recording\noutput programmatically. Use `with-expectation` to capture output into the\nstruct and call `commit-expectation!` or `skip-expectation!` to mark the\nresult:\n\n```racket\n(define e (make-expectation))\n(with-expectation e (display \"ok\"))\n(commit-expectation! e)\n```\n\n`with-expectation` can also wrap other recspecs forms. The recorded output is\navailable via @racket[expectation-out]:\n\n```racket\n(define log (make-expectation))\n(with-expectation log\n  (expect (display \"hi\") \"hi\"))\n(commit-expectation! log)\n(displayln (expectation-out log)) ; prints \"\"\n```\n\nRun the file with `raco test` (or any RackUnit runner) to execute the\nexpectations. If they fail and you want to update the saved output, set\n`RECSPECS_UPDATE`:\n\n```console\n$ RECSPECS_UPDATE=1 raco test my-test.rkt\n```\nTo update just one expectation, set `RECSPECS_UPDATE_TEST` to the name\nshown for that test case:\n\n```console\n$ RECSPECS_UPDATE=1 RECSPECS_UPDATE_TEST=my-test.rkt:42 raco test my-test.rkt\n```\n\nEnable verbose output with:\n\n```console\n$ RECSPECS_VERBOSE=1 raco test my-test.rkt\n```\n\n### Emacs integration\n\nThe file `emacs/recspecs.el` defines a helper command\n`recspecs-update-at-point`.  When called from a buffer visiting a Racket\nfile under `racket-mode`, it reruns that file with\n`RECSPECS_UPDATE` enabled and sets `RECSPECS_UPDATE_TEST` to the\nexpectation at point so only that one is updated.  After the test\nfinishes, the buffer is automatically reverted to load any updated\nexpectations from disk.\n\nTo enable this, add `(load \"\u003cpath-to-this-code\u003e/emacs/recspecs.el\")`\nto your `.emacs` file.\n\n## Status\n\nThis library is new but relatively-feature complete. However, it hasn't\nbeen used in anger, so lots of things might change.\n\nAlmost all the code here was written by the OpenAI Codex tool\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsamth%2Frecspecs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsamth%2Frecspecs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsamth%2Frecspecs/lists"}