Current section

Files

Jump to
dream_test src dream_test@unit_context.erl
Raw

src/dream_test@unit_context.erl

-module(dream_test@unit_context).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/dream_test/unit_context.gleam").
-export([describe/3, group/2, it/2, before_all/1, before_each/1, after_each/1, after_all/1, with_tags/2, skip/2]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
?MODULEDOC(
" Context-aware unit DSL (`unit_context`).\n"
"\n"
" Use this module when you want hooks and tests to operate on a shared,\n"
" strongly-typed context value (your own record/union).\n"
"\n"
" - You provide an initial context value to `describe`.\n"
" - `before_all` / `before_each` can transform the context.\n"
" - `it` receives the current context.\n"
"\n"
" This builds a `dream_test/types.TestSuite(context)` under the hood.\n"
"\n"
" ## When should I use this?\n"
"\n"
" - Use `dream_test/unit` for most tests (no explicit context).\n"
" - Use `dream_test/unit_context` when you want an explicit context value\n"
" passed into every test (database handles, fixtures, counters, etc.).\n"
"\n"
" ## Example\n"
"\n"
" ```gleam\n"
" import dream_test/matchers.{be_equal, or_fail_with, should}\n"
" import dream_test/reporters/bdd\n"
" import dream_test/reporters/progress\n"
" import dream_test/runner\n"
" import dream_test/unit_context.{before_each, describe, it}\n"
"\n"
" pub type Context {\n"
" Context(counter: Int)\n"
" }\n"
"\n"
" fn increment_counter(context: Context) {\n"
" Ok(Context(counter: context.counter + 1))\n"
" }\n"
"\n"
" pub fn suite() {\n"
" describe(\"Context-aware suite\", Context(counter: 0), [\n"
" before_each(increment_counter),\n"
" it(\"receives the updated context\", fn(context: Context) {\n"
" context.counter\n"
" |> should\n"
" |> be_equal(1)\n"
" |> or_fail_with(\"expected counter to be 1 after before_each\")\n"
" }),\n"
" ])\n"
" }\n"
"\n"
" pub fn main() {\n"
" runner.new([suite()])\n"
" |> runner.progress_reporter(progress.new())\n"
" |> runner.results_reporters([bdd.new()])\n"
" |> runner.exit_on_failure()\n"
" |> runner.run()\n"
" }\n"
" ```\n"
).
-file("src/dream_test/unit_context.gleam", 115).
?DOC(
" Create a top-level context-aware suite with an explicit initial context.\n"
"\n"
" ## Parameters\n"
"\n"
" - `name`: Display name for the suite (shown in reports)\n"
" - `seed`: Initial context value passed into hooks and tests\n"
" - `children`: Tests, groups, and hooks that make up the suite\n"
"\n"
" ## Returns\n"
"\n"
" A `TestSuite(context)` you can run with `dream_test/runner`.\n"
"\n"
" ## Example\n"
"\n"
" ```gleam\n"
" import dream_test/matchers.{be_equal, or_fail_with, should}\n"
" import dream_test/reporters/bdd\n"
" import dream_test/reporters/progress\n"
" import dream_test/runner\n"
" import dream_test/unit_context.{before_each, describe, it}\n"
"\n"
" pub type Context {\n"
" Context(counter: Int)\n"
" }\n"
"\n"
" fn increment_counter(context: Context) {\n"
" Ok(Context(counter: context.counter + 1))\n"
" }\n"
"\n"
" pub fn suite() {\n"
" describe(\"Context-aware suite\", Context(counter: 0), [\n"
" before_each(increment_counter),\n"
" it(\"receives the updated context\", fn(context: Context) {\n"
" context.counter\n"
" |> should\n"
" |> be_equal(1)\n"
" |> or_fail_with(\"expected counter to be 1 after before_each\")\n"
" }),\n"
" ])\n"
" }\n"
"\n"
" pub fn main() {\n"
" runner.new([suite()])\n"
" |> runner.progress_reporter(progress.new())\n"
" |> runner.results_reporters([bdd.new()])\n"
" |> runner.exit_on_failure()\n"
" |> runner.run()\n"
" }\n"
" ```\n"
).
-spec describe(binary(), KIR, list(dream_test@types:node_(KIR))) -> dream_test@types:root(KIR).
describe(Name, Seed, Children) ->
{root, Seed, {group, Name, [], Children}}.
-file("src/dream_test/unit_context.gleam", 183).
?DOC(
" Create a nested group inside a context-aware suite.\n"
"\n"
" ## Parameters\n"
"\n"
" - `name`: Display name for the group (shown in reports)\n"
" - `children`: Tests and hooks that belong to this group\n"
"\n"
" ## Returns\n"
"\n"
" A `ContextNode(context)` you can include in `describe`/`group`.\n"
"\n"
" ## Example\n"
"\n"
" ```gleam\n"
" import dream_test/matchers.{be_equal, or_fail_with, should}\n"
" import dream_test/reporters/bdd\n"
" import dream_test/reporters/progress\n"
" import dream_test/runner\n"
" import dream_test/unit_context.{before_each, describe, group, it}\n"
" import gleam/io\n"
"\n"
" pub type Context {\n"
" Context(counter: Int)\n"
" }\n"
"\n"
" fn increment_counter(context: Context) {\n"
" Ok(Context(counter: context.counter + 1))\n"
" }\n"
"\n"
" pub fn suite() {\n"
" describe(\"Context-aware grouping\", Context(counter: 0), [\n"
" // This outer hook applies everywhere under this describe, including groups.\n"
" before_each(increment_counter),\n"
" group(\"inner group\", [\n"
" // This hook only applies to tests inside this group.\n"
" before_each(increment_counter),\n"
" it(\"sees both outer + inner hooks\", fn(context: Context) {\n"
" context.counter\n"
" |> should\n"
" |> be_equal(2)\n"
" |> or_fail_with(\"expected counter to be 2 (outer + inner before_each)\")\n"
" }),\n"
" ]),\n"
" it(\"sees only outer hook\", fn(context: Context) {\n"
" context.counter\n"
" |> should\n"
" |> be_equal(1)\n"
" |> or_fail_with(\"expected counter to be 1 (outer before_each only)\")\n"
" }),\n"
" ])\n"
" }\n"
"\n"
" pub fn main() {\n"
" runner.new([suite()])\n"
" |> runner.progress_reporter(progress.new())\n"
" |> runner.results_reporters([bdd.new()])\n"
" |> runner.exit_on_failure()\n"
" |> runner.run()\n"
" }\n"
" ```\n"
).
-spec group(binary(), list(dream_test@types:node_(KIV))) -> dream_test@types:node_(KIV).
group(Name, Children) ->
{group, Name, [], Children}.
-file("src/dream_test/unit_context.gleam", 242).
?DOC(
" Define a context-aware test case.\n"
"\n"
" The test body receives the current context and returns:\n"
" `Result(AssertionResult, String)`.\n"
"\n"
" ## Parameters\n"
"\n"
" - `name`: Display name for the test (shown in reports)\n"
" - `run`: Test body function that receives the current context\n"
"\n"
" ## Returns\n"
"\n"
" A `ContextNode(context)` you can include in `describe`/`group`.\n"
"\n"
" ## Example\n"
"\n"
" ```gleam\n"
" import dream_test/matchers.{be_equal, or_fail_with, should}\n"
" import dream_test/reporters/bdd\n"
" import dream_test/reporters/progress\n"
" import dream_test/runner\n"
" import dream_test/unit_context.{before_each, describe, it}\n"
" import gleam/io\n"
"\n"
" pub type Context {\n"
" Context(counter: Int)\n"
" }\n"
"\n"
" fn increment_counter(context: Context) {\n"
" Ok(Context(counter: context.counter + 1))\n"
" }\n"
"\n"
" pub fn suite() {\n"
" describe(\"Context-aware suite\", Context(counter: 0), [\n"
" before_each(increment_counter),\n"
" it(\"receives the updated context\", fn(context: Context) {\n"
" context.counter\n"
" |> should\n"
" |> be_equal(1)\n"
" |> or_fail_with(\"expected counter to be 1 after before_each\")\n"
" }),\n"
" ])\n"
" }\n"
"\n"
" pub fn main() {\n"
" runner.new([suite()])\n"
" |> runner.progress_reporter(progress.new())\n"
" |> runner.results_reporters([bdd.new()])\n"
" |> runner.exit_on_failure()\n"
" |> runner.run()\n"
" }\n"
" ```\n"
).
-spec it(
binary(),
fun((KIZ) -> {ok, dream_test@types:assertion_result()} | {error, binary()})
) -> dream_test@types:node_(KIZ).
it(Name, Run) ->
{test, Name, [], unit, Run, none}.
-file("src/dream_test/unit_context.gleam", 317).
?DOC(" Run once before any tests and produce/transform the context.\n").
-spec before_all(fun((KJH) -> {ok, KJH} | {error, binary()})) -> dream_test@types:node_(KJH).
before_all(Setup) ->
{before_all, Setup}.
-file("src/dream_test/unit_context.gleam", 324).
?DOC(" Run before each test and transform the context for that test.\n").
-spec before_each(fun((KJL) -> {ok, KJL} | {error, binary()})) -> dream_test@types:node_(KJL).
before_each(Setup) ->
{before_each, Setup}.
-file("src/dream_test/unit_context.gleam", 331).
?DOC(" Run after each test for cleanup.\n").
-spec after_each(fun((KJP) -> {ok, nil} | {error, binary()})) -> dream_test@types:node_(KJP).
after_each(Teardown) ->
{after_each, Teardown}.
-file("src/dream_test/unit_context.gleam", 338).
?DOC(" Run once after all tests for cleanup.\n").
-spec after_all(fun((KJT) -> {ok, nil} | {error, binary()})) -> dream_test@types:node_(KJT).
after_all(Teardown) ->
{after_all, Teardown}.
-file("src/dream_test/unit_context.gleam", 392).
?DOC(
" Attach tags to a node.\n"
"\n"
" Tags can be used by runners and reporters for filtering and display.\n"
" Prefer piping: `node |> with_tags([\"tag\"])`.\n"
"\n"
" ## Parameters\n"
"\n"
" - `node`: A group or test node to tag\n"
" - `tags`: Tags to attach (replaces any existing tags on that node)\n"
"\n"
" ## Returns\n"
"\n"
" A new node with the provided tags.\n"
"\n"
" ## Example\n"
"\n"
" ```gleam\n"
" import dream_test/matchers.{succeed}\n"
" import dream_test/reporters/bdd\n"
" import dream_test/reporters/progress\n"
" import dream_test/runner\n"
" import dream_test/unit_context.{describe, group, it, with_tags}\n"
" import gleam/io\n"
"\n"
" pub type Context {\n"
" Context(counter: Int)\n"
" }\n"
"\n"
" pub fn suite() {\n"
" describe(\"Tagging context-aware tests\", Context(counter: 0), [\n"
" group(\"group tagged slow\", [\n"
" it(\"inherits the group tag\", fn(_context: Context) { Ok(succeed()) }),\n"
" ])\n"
" |> with_tags([\"slow\"]),\n"
" it(\"can tag an individual test\", fn(_context: Context) { Ok(succeed()) })\n"
" |> with_tags([\"unit_context\", \"fast\"]),\n"
" it(\"untagged tests still work\", fn(_context: Context) { Ok(succeed()) }),\n"
" ])\n"
" }\n"
"\n"
" pub fn main() {\n"
" runner.new([suite()])\n"
" |> runner.progress_reporter(progress.new())\n"
" |> runner.results_reporters([bdd.new()])\n"
" |> runner.exit_on_failure()\n"
" |> runner.run()\n"
" }\n"
" ```\n"
).
-spec with_tags(dream_test@types:node_(KJX), list(binary())) -> dream_test@types:node_(KJX).
with_tags(Node, Tags) ->
case Node of
{group, Name, _, Children} ->
{group, Name, Tags, Children};
{test, Name@1, _, Kind, Run, Timeout_ms} ->
{test, Name@1, Tags, Kind, Run, Timeout_ms};
Other ->
Other
end.
-file("src/dream_test/unit_context.gleam", 405).
-spec skipped_test_run(any()) -> {ok, dream_test@types:assertion_result()} |
{error, binary()}.
skipped_test_run(_) ->
{ok, assertion_skipped}.
-file("src/dream_test/unit_context.gleam", 303).
?DOC(
" Define a skipped context-aware test.\n"
"\n"
" `skip` has the same shape as `it` so you can easily switch a test between\n"
" running and skipped without rewriting the test body.\n"
"\n"
" The provided test body is preserved for that purpose, but it is **not\n"
" executed** while the test is skipped.\n"
"\n"
" ## Parameters\n"
"\n"
" - `name`: Display name for the skipped test (shown in reports)\n"
" - `run`: Unused; kept so you can switch between `it` and `skip` easily\n"
"\n"
" ## Returns\n"
"\n"
" A `ContextNode(context)` that always results in `AssertionSkipped`.\n"
"\n"
" ## Example\n"
"\n"
" ```gleam\n"
" import dream_test/matchers.{be_equal, or_fail_with, should, succeed}\n"
" import dream_test/reporters/bdd\n"
" import dream_test/reporters/progress\n"
" import dream_test/runner\n"
" import dream_test/unit_context.{describe, it, skip}\n"
" import gleam/io\n"
"\n"
" pub type Context {\n"
" Context(counter: Int)\n"
" }\n"
"\n"
" pub fn suite() {\n"
" describe(\"Skipping context-aware tests\", Context(counter: 0), [\n"
" skip(\"this test is skipped\", fn(_context: Context) {\n"
" // This would pass if it ran, but Dream Test will mark it skipped.\n"
" Ok(succeed())\n"
" }),\n"
" it(\"normal tests still run\", fn(context: Context) {\n"
" context.counter\n"
" |> should\n"
" |> be_equal(0)\n"
" |> or_fail_with(\"expected counter to start at 0\")\n"
" }),\n"
" ])\n"
" }\n"
"\n"
" pub fn main() {\n"
" runner.new([suite()])\n"
" |> runner.progress_reporter(progress.new())\n"
" |> runner.results_reporters([bdd.new()])\n"
" |> runner.exit_on_failure()\n"
" |> runner.run()\n"
" }\n"
" ```\n"
).
-spec skip(
binary(),
fun((KJD) -> {ok, dream_test@types:assertion_result()} | {error, binary()})
) -> dream_test@types:node_(KJD).
skip(Name, _) ->
{test, Name, [], unit, fun skipped_test_run/1, none}.