{"id":19441691,"url":"https://github.com/rhyskeepence/clairvoyance","last_synced_at":"2025-10-28T06:18:42.406Z","repository":{"id":2768404,"uuid":"3766983","full_name":"rhyskeepence/clairvoyance","owner":"rhyskeepence","description":"A Scala Specs2 extension, producing human readable documentation à la Yatspec.","archived":false,"fork":false,"pushed_at":"2019-10-15T22:04:21.000Z","size":728,"stargazers_count":14,"open_issues_count":5,"forks_count":2,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-09-23T17:06:25.003Z","etag":null,"topics":["scala","testing"],"latest_commit_sha":null,"homepage":"","language":"Scala","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/rhyskeepence.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}},"created_at":"2012-03-19T18:16:20.000Z","updated_at":"2022-07-20T06:52:47.000Z","dependencies_parsed_at":"2022-08-06T12:31:20.767Z","dependency_job_id":null,"html_url":"https://github.com/rhyskeepence/clairvoyance","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/rhyskeepence/clairvoyance","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rhyskeepence%2Fclairvoyance","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rhyskeepence%2Fclairvoyance/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rhyskeepence%2Fclairvoyance/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rhyskeepence%2Fclairvoyance/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rhyskeepence","download_url":"https://codeload.github.com/rhyskeepence/clairvoyance/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rhyskeepence%2Fclairvoyance/sbom","scorecard":{"id":774628,"data":{"date":"2025-08-11","repo":{"name":"github.com/rhyskeepence/clairvoyance","commit":"a929a4b63364b99af3ace3e6333bd96ae21d41fb"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":2.6,"checks":[{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Code-Review","score":0,"reason":"Found 1/29 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":0,"reason":"license file not detected","details":["Warn: project does not have a license file"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 2 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}}]},"last_synced_at":"2025-08-23T03:12:29.023Z","repository_id":2768404,"created_at":"2025-08-23T03:12:29.023Z","updated_at":"2025-08-23T03:12:29.023Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":278379548,"owners_count":25977214,"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","status":"online","status_checked_at":"2025-10-04T02:00:05.491Z","response_time":63,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":["scala","testing"],"created_at":"2024-11-10T15:36:37.941Z","updated_at":"2025-10-04T21:33:49.562Z","avatar_url":"https://github.com/rhyskeepence.png","language":"Scala","funding_links":[],"categories":[],"sub_categories":[],"readme":"Clairvoyance\n============\n\nClairvoyance is an extension to Specs2, a Scala test library. Clairvoyance provides a few extensions to capture what is\nhappening in your tests, and then produce business and tester friendly documentation.\n\nIt's a pastiche of [Yatspec](http://code.google.com/p/yatspec), a Java testing library written by my colleague Dan\nBodart. It addresses the deficiencies we experienced with Fit and Concordion.\n\n[![Build Status](https://secure.travis-ci.org/rhyskeepence/clairvoyance.svg)](http://travis-ci.org/rhyskeepence/clairvoyance) [![Coverage Status](https://coveralls.io/repos/rhyskeepence/clairvoyance/badge.svg?branch=master\u0026service=github)](https://coveralls.io/github/rhyskeepence/clairvoyance?branch=master) [![codecov.io](https://codecov.io/github/rhyskeepence/clairvoyance/coverage.svg?branch=master)](https://codecov.io/github/rhyskeepence/clairvoyance?branch=master\u0026view=all) [![Join the chat at https://gitter.im/rhyskeepence/clairvoyance](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/rhyskeepence/clairvoyance?utm_source=badge\u0026utm_medium=badge\u0026utm_campaign=pr-badge\u0026utm_content=badge)\n\nExample\n-------\n\n```scala\nclass LoggingExample extends ClairvoyantSpec {\n  \"The coordinator\" should {\n    \"invoke the Doomsday Device on the 21st of December 2012\" in new context {\n      givenTheDateIs(\"21/12/2012\")\n      whenTheCoordinatorRuns\n      theDoomsdayDevice should beUnleashed\n    }\n  }\n\n  trait context extends ClairvoyantContext {\n    // test set up and fixtures\n  }\n}\n```\n\nIt breaks down like this:\n\n* Create a Spec which extends `ClairvoyantSpec`\n* Write the spec in the mutable spec style (for various historical reasons)\n* Create a context which extends `ClairvoyantContext`\n* `InterestingGivens` can be added with statements such as `interestingGivens += (\"Current date\" -\u003e \"21/12/2012\")`\n* The Scala code within the spec method is interpreted into a text specification, to encourage readability.\n\nThe full source to this example is [here](https://github.com/rhyskeepence/clairvoyance/blob/master/specs2/src/test/scala/clairvoyance/specs2/examples/LoggingExample.scala).\n\nHere is the output of this spec.\n![Example output](http://github.com/rhyskeepence/clairvoyance/raw/master/doc/example-output.jpg)\n\nGet This Party Started\n----------------------\n\nAdd this to your SBT build:\n\n```scala\n// for Scala 2.10 and above:\nlibraryDependencies += \"com.github.rhyskeepence\" %% \"clairvoyance-specs2\" % \u003clatest-version\u003e\n\n// for scala 2.9.x:\nlibraryDependencies += \"com.github.rhyskeepence\" %% \"clairvoyance\" % \"27\"\n\nresolvers += \"releases\" at \"http://oss.sonatype.org/content/repositories/releases\"\n```\n\n[\u003cimg src=\"https://img.shields.io/maven-central/v/com.github.rhyskeepence/clairvoyance-core_2.10*.svg?label=latest%20version%20for%202.10\"/\u003e](http://search.maven.org/#search%7Cga%7C1%7Cg%3Acom.github.rhyskeepence%20a%3Aclairvoyance-core_2.10) [\u003cimg src=\"https://img.shields.io/maven-central/v/com.github.rhyskeepence/clairvoyance-core_2.11*.svg?label=latest%20version%20for%202.11\"/\u003e](http://search.maven.org/#search%7Cga%7C1%7Cg%3Acom.github.rhyskeepence%20a%3Aclairvoyance-core_2.11)\n\nOr in Maven:\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003ecom.github.rhyskeepence\u003c/groupId\u003e\n    \u003cartifactId\u003eclairvoyance-specs2_2.10\u003c/artifactId\u003e\n    \u003cversion\u003e${latest-version}\u003c/version\u003e\n    \u003cscope\u003etest\u003c/scope\u003e\n\u003c/dependency\u003e\n...\n\u003crepository\u003e\n    \u003cid\u003esonatype-releases\u003c/id\u003e\n    \u003cname\u003esonatype releases\u003c/name\u003e\n    \u003csnapshots\u003e\n        \u003cenabled\u003efalse\u003c/enabled\u003e\n    \u003c/snapshots\u003e\n    \u003curl\u003ehttp://oss.sonatype.org/content/repositories/releases\u003c/url\u003e\n\u003c/repository\u003e\n```\n\nInteresting Givens\n------------------\n\nThese are inputs into your test, which may not be specified in the spec, but should be logged to the output:\n\n```scala\n  interestingGivens += (\"Current date\" -\u003e \"21/12/2012\")\n```\n\nor\n\n```scala\n  (\"Current date\" -\u003e \"21/12/2012\").isInteresting\n```\n\n\nCaptured Inputs And Outputs\n---------------------------\n\nThese are the inputs or outputs to your system, which may not be practical to assert upon, but should be logged.\n\nPerhaps you are using a stub rather than communicating with a third party in your spec:\n\n```scala\nclass StubGizmometer extends Gizmometer {\n}\n```\n\nTo capture inputs and outputs, just add the `ProducesCapturedInputsAndOutputs` trait and call `captureValue`:\n\n```scala\nclass StubGizmometer extends Gizmometer with ProducesCapturedInputsAndOutputs {\n  def scan(brain: Brain) {\n    captureValue(\"Brain\" -\u003e brain)\n  }\n}\n```\n\nand in your context, register the stub so that clairvoyant knows about it:\n\n```scala\ntrait context extends ClairvoyantContext {\n    val gizmometer = new StubGizmometer\n    override def capturedInputsAndOutputs = Seq(gizmometer)\n}\n```\n\nThe value that is captured can be of any type. XML is formatted nicely, and HTML can be inlined into the output\nby capturing a value in a Html type:\n\n```scala\ncaptureValue(\"Inline HTML\" -\u003e Html(\u003cem\u003eHello!\u003c/em\u003e))\n```\n\nAll other values are displayed as their String representation, unless a custom renderer has been defined.\n\nCustom Rendering of Interesting Givens \u0026 Captured Inputs And Outputs\n--------------------------------------------------------------------\n\nWhen you capture a value or an interesting given, it will be rendered to the screen. XML and Strings are formatted\nnicely by default, but you may wish to capture your own domain objects and have them presented in readable format.\n\nA full example is here: [clairvoyance/specs2/examples/CustomRenderingExample.scala]\n(https://github.com/rhyskeepence/clairvoyance/blob/master/specs2/src/test/scala/clairvoyance/specs2/examples/CustomRenderingExample.scala)\n\nThe juicy bits are shown below:\n\n```scala\nclass CustomRenderingExample extends ClairvoyantSpec with CustomRendering {\n\n  def customRendering = {\n    case Brain(iq) =\u003e \"a Brain with an IQ of %d\".format(iq)\n  }\n}\n```\n\n`customRendering` is a partial function, which will be run before the default rendering.\n\nAnd behold, custom rendering of Brains:\n\n![Custom Rendering of Brains](http://github.com/rhyskeepence/clairvoyance/raw/master/doc/custom-rendering.jpg)\n\nSequence Diagrams\n-----------------\n\nIf your spec describes interactions between many systems, it can be nice to generate a sequence diagram automatically\nfrom CapturedInputsAndOutputs. Just add the `SequenceDiagram` trait to your context, ie:\n\n```scala\ntrait context extends ClairvoyantContext with SequenceDiagram {\n  override def capturedInputsAndOutputs = Seq(system_x, system_y)\n}\n```\n\nThe name of the captured values should be in the following formats in order to appear on the diagram:\n\n`captureValue(\"SOMETHING from X to Y\" -\u003e ...)` or\n\n`captureValue(\"SOMETHING from X\" -\u003e ...)` or\n\n`captureValue(\"SOMETHING to Y\" -\u003e ...)`\n\nIn the last two cases, the default actor will be used, which can be set using this statement in the context:\n`override def defaultSequenceDiagramActor = \"Name of my component\"`\n\nAn example can be found [here](https://github.com/rhyskeepence/clairvoyance/blob/master/specs2/src/test/scala/clairvoyance/specs2/examples/SequenceDiagramExample.scala),\nwhich produces the following output:\n\n![Sequence Diagram](http://github.com/rhyskeepence/clairvoyance/raw/master/doc/sequence.jpg)\n\nAlternatively, a graph can be produced:\n\n```scala\ntrait context extends ClairvoyantContext with Graph\n```\n\nMarkdown\n--------\n\n[Markdown](http://en.wikipedia.org/wiki/Markdown) is supported in specification descriptions, to whet your appetite\n[see this example](https://github.com/rhyskeepence/clairvoyance/blob/master/specs2/src/test/scala/clairvoyance/specs2/examples/MarkdownExample.scala).\n\nOTHER COOL STUFF!!!\n-------------------\n\n* [ScalaCheck](https://github.com/rhyskeepence/clairvoyance/blob/master/specs2/src/test/scala/clairvoyance/specs2/examples/ScalaCheckExample.scala)\n* [Graphs](https://github.com/rhyskeepence/clairvoyance/blob/master/specs2/src/test/scala/clairvoyance/specs2/examples/GraphExample.scala)\n* [G/W/T](https://github.com/rhyskeepence/clairvoyance/blob/master/specs2/src/test/scala/clairvoyance/specs2/examples/GivenWhenThenExample.scala)\n\nTODO\n----\n\n* Scenario tables\n\nContributing\n------------\n\n* Browse [existing issues](https://github.com/rhyskeepence/clairvoyance/issues)\n* [![Join the chat at https://gitter.im/rhyskeepence/clairvoyance](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/rhyskeepence/clairvoyance?utm_source=badge\u0026utm_medium=badge\u0026utm_campaign=pr-badge\u0026utm_content=badge)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frhyskeepence%2Fclairvoyance","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frhyskeepence%2Fclairvoyance","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frhyskeepence%2Fclairvoyance/lists"}