{"id":32305418,"url":"https://github.com/polyhedra-studio/cake-dart","last_synced_at":"2026-03-05T02:04:25.177Z","repository":{"id":207057176,"uuid":"717948562","full_name":"Polyhedra-Studio/Cake-Dart","owner":"Polyhedra-Studio","description":"The lightweight, explicit testing framework - built for Dart.","archived":false,"fork":false,"pushed_at":"2024-12-04T16:01:04.000Z","size":259,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-10-23T06:51:31.870Z","etag":null,"topics":["dart","testing","testing-framework"],"latest_commit_sha":null,"homepage":"https://pub.dev/packages/cake","language":"Dart","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Polyhedra-Studio.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","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":null,"dco":null,"cla":null}},"created_at":"2023-11-13T03:02:34.000Z","updated_at":"2024-12-04T16:02:26.000Z","dependencies_parsed_at":"2023-11-13T22:27:10.594Z","dependency_job_id":"e31d9150-392d-4c63-ba1e-e3de43f557d1","html_url":"https://github.com/Polyhedra-Studio/Cake-Dart","commit_stats":{"total_commits":82,"total_committers":1,"mean_commits":82.0,"dds":0.0,"last_synced_commit":"9b1038454b5333034230b6ef310678c5ccabd5c8"},"previous_names":["polyhedra-studio/cake","polyhedra-studio/cake-dart"],"tags_count":34,"template":false,"template_full_name":null,"purl":"pkg:github/Polyhedra-Studio/Cake-Dart","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Polyhedra-Studio%2FCake-Dart","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Polyhedra-Studio%2FCake-Dart/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Polyhedra-Studio%2FCake-Dart/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Polyhedra-Studio%2FCake-Dart/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Polyhedra-Studio","download_url":"https://codeload.github.com/Polyhedra-Studio/Cake-Dart/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Polyhedra-Studio%2FCake-Dart/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30106175,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-05T01:39:18.192Z","status":"online","status_checked_at":"2026-03-05T02:00:06.710Z","response_time":93,"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":["dart","testing","testing-framework"],"created_at":"2025-10-23T06:50:59.762Z","updated_at":"2026-03-05T02:04:25.159Z","avatar_url":"https://github.com/Polyhedra-Studio.png","language":"Dart","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n    \u003cimg src=\"https://github.com/Polyhedra-Studio/Cake-Dart-VS/blob/main/images/cake_logo.png?raw=true\" alt=\"Cake Tester Logo\" width=\"128\" /\u003e\n    \u003ch1\u003eCake Test Runner for Dart \u0026 Flutter\u003c/h1\u003e\n    \u003ca href=\"https://pub.dev/packages/cake\"\u003e\u003cimg alt=\"Pub Version\" src=\"https://img.shields.io/pub/v/cake\" /\u003e\u003c/a\u003e\n    \u003ca href=\"https://opensource.org/license/mpl-2-0/\"\u003e\u003cimg src=\"https://img.shields.io/badge/License-MPL%202.0-brightgreen.svg\" alt=\"License: MPL 2.0\" /\u003e\u003c/a\u003e\n    \u003cp\u003eThe tiniest unit tester, built for Dart. Now supports Flutter! Grab the additional \u003ca href=\"https://pub.dev/packages/cake_flutter\"\u003eCake_Flutter\u003c/a\u003e package.\u003c/p\u003e\n    \u003cp\u003eRunning this in VS Code? Install the \u003ca href=\"https://marketplace.visualstudio.com/items?itemName=Polyhedra.cake-dart-vs\"\u003eCake VS-Code extension\u003c/a\u003e to run tests inside your IDE, snippets, and more.\u003c/p\u003e\n\u003c/div\u003e\n\n# Features\n  - **Lightweight \u0026 Flexible**: Easy to set up, fast to run, and works seamlessly with Dart and Flutter.\n  - **Clear Test Organization**: Group and structure tests for better readability. Share reusable data across multiple levels with flexible context options.\n  - **Built-in Mocking**: Includes an optional lightweight mocking framework with call tracking, argument history, and flexible matchers.\n  - **Structured Test Flow**: Write clean, atomic tests by defining setup, action, assertion, and teardown stages for focused, maintainable testing.\n  - **IDE Integration**: Native support for the [Cake VSCode extension](https://marketplace.visualstudio.com/items?itemName=Polyhedra.cake-dart-vs), enabling in-editor test execution, debugging, test coverage visualization, and an enhanced developer experience.\n\n# Getting started\n## Installing\n\n### Dart\n\n1. Install Cake test runner globally.\n\n```\ndart pub global activate cake\n```\n\n2. (Optional) Install the [VSCode Extension](https://marketplace.visualstudio.com/items?itemName=Polyhedra.cake-dart-vs)\n\n3. Add the `cake` package to your [dev dependencies](https://pub.dev/packages/cake/install).\n```\ndart pub add dev:cake\n```\n\n### Flutter\n\n1. Install Cake test runner globally.\n\n```\ndart pub global activate cake\n```\n\n2. (Optional) Install the [VSCode Extension](https://marketplace.visualstudio.com/items?itemName=Polyhedra.cake-dart-vs)\n\n3. Add the `cake_flutter` package to your [dev dependencies](https://pub.dev/packages/cake_flutter/install). (This also includes the `cake` package.)\n```\nflutter pub add dev:cake_flutter\n```\n\n## Running\n- Cake will search for anything that has .cake.dart for the file name in the directory that it's run in.\n\n### Command Line\nIn the CLI in the directory that you want to run your tests in:\n```\ndart run cake\n```\n\nYou can also [add flags](#flags) to run specific tests or view output from specific tests.\n\n### VS Code\n- Run or debug tests in the Test Explorer or directly in the files themselves. (See [Marketplace](https://marketplace.visualstudio.com/items?itemName=Polyhedra.cake-dart-vs) page for more details.)\n\n## Writing unit tests\n\nLet's start off with a quick example:\n\n```dart\nTestRunnerOf\u003cString\u003e('API Service Test', [\n  Group('Get Hello World', [\n    Test(\n      'Response payload should return \"Hello world\" if successful',\n      action: (test) async =\u003e APIService.getHelloWorld(),\n      assertions: (test) =\u003e [\n        Expect.equals(actual: test.actual, expected: 'Hello world'),\n      ],\n    ),\n  ]),\n]);\n```\n\n**For an expanded version, check out the example in `examples/test/api.cake.dart`.**\n\n### Organization\nCake relies on a hierarchy to organize tests. All tests _must_ be wrapped in a TestRunner. From there, you can list Tests directly or further nest them into groups. It's recommended to have one TestRunner per file.\n\n```dart\nimport 'package:cake/cake.dart';\n\nvoid main() {\n  TestRunnerDefault('Example Test Runner', [\n    Group('Example Group', [\n      Test(\n        'Test inside a group',\n        assertions: (test) =\u003e [Expect.isTrue(true)],\n      ),\n      Group('Nested Group', []),\n    ]),\n    Test(\n        'Test directly under TestRunner',\n        assertions: (test) =\u003e [Expect.isTrue(true)],\n      ),\n  ]);\n}\n```\n\n### Stages\nCake encourages developers to write clean, simple, atomic tests by defining separate stages for each test. You might recognize this from the \"Arrange-Act-Assert\" or \"Given-When-Then\" style of writing unit tests. Here, you could analogue this to \"Setup-Action-Assertions\" (with additional teardown if needed).\n\nAll stages can be written as asynchronous, if needed.\n\n```dart\nTest(\n  'Stages Example',\n  setup: (test) {\n    // Generally the Setup stage is used to create any mocks, preparing the environment,\n    // or in general, anything that isn't the action step.\n    test.value = 'setup';\n  },\n  action: (test) {\n    // The action stage should include the part of the test that changes in order\n    // to test against the assertions.\n    // This function allows for returning a value, which will assign to the test's \"actual\"\n    // value, although this is not required.\n    return test.value == 'setup';\n  },\n  assertions: (test) =\u003e [\n    // Assertions must return a collection of Expects.\n    Expect\u003cString\u003e.isType(test.value),\n    Expect.isTrue(test.actual),\n  ],\n  teardown: (test) =\u003e test.value = 'teardown',\n),\n```\n\n#### Setup \u0026 Teardown\nSetup and teardown is inherited from parents to children tests and groups. So you can write your initial setup logic in the root TestRunner, and then run any specific set up later in a group or test to specifically arrange for that functionality being tested on. All setup is run before any action. All teardown is run after all assertions have completed, and will run regardless if any issues occurred during testing.\n\n```dart\nString outsideValue = 'Tests not run';\n\nTestRunnerDefault(\n  'Test Runner with setup and teardown',\n  [\n    Test(\n      'This test should have the parent context included',\n      assertions: (test) =\u003e [\n        Expect.equals(actual: test.value, expected: 'Test Runner Setup'),\n      ],\n    ),\n    Group(\n      'Can override and pass down context',\n      [\n        Test(\n          'Child has parent context',\n          assertions: (test) =\u003e [\n            Expect.equals(actual: test.value, expected: 'Group Setup'),\n          ],\n        ),\n      ],\n      setup: (test) {\n        test.value = 'Group Setup';\n      },\n      teardown: (test) {\n        test.value = 'Test Runner Setup';\n      }\n    ),\n  ],\n  setup: (test) {\n    outsideValue = 'Tests are running';\n    test.value = 'Test Runner Setup';\n  },\n  teardown: (test) {\n    outsideValue = 'Tests have run';\n  }\n);\n\nprint(outsideValue); // Should output \"Tests have run\"\n```\n\n#### Action\nThe action stage is meant to highlight the action being taken to test the outcome. This would be something like clicking a button, sending an API call, or running a function. Just remember that only _one_ action can be run during a test. If you find that your action function is large or encompassing a lot of code, that is usually a sign that it needs to broken into multiple tests or into the setup function.\n\nWhile often need, the action stage is not required. Often unit tests that validate the initial state will skip the action stage.\n\nAction can return a value to be set to the \"actual\" value that can be later used in assertions.\n\n#### Assertions\nAssertions run after the action stage and return a list of [Expects](#expect-matches). That, when applicable, take an expected output and matches it against an actual outcome. There's no limitations on how many assertions you can run. By default, Cake will ignore the rest of the assertions after the first one fails. This can be turned off in [Options](#options).\n\n### Context\nContext is how information can be passed from stage to stage and is an inheritable object that is passed from parent to children. This is passed as an argument on each stage. By default, test has an `actual` value, an `expected` value, and an additional map to pass information through ad-hoc. The default Context is called by using the `TestRunnerDefault` constructor.\n\n```dart\nTestRunnerDefault('Simple Test with Default Context', [\n    Test('True is true', assertions: (test) =\u003e [Expect.isTrue(true)]),\n    Test('Foo is bar', action: (test) =\u003e test['foo'] = 'bar', assertions: (test) =\u003e [\n      Expect.equals(actual: test['foo'], expected: 'bar')\n    ]),\n  ],\n);\n```\n\n#### Context Typing\nThe Context class allows for a generic parameter to be passed in order to have `actual` and `expected` be a specific type. This can be very handy for quickly protecting against bad refactors on code. You can define the generic value by using `TestRunnerOf`, `GroupOf`, and `TestOf` constructors.\n\n```dart\nTestRunnerOf\u003cString\u003e('Foo tests', [\n    // This test inherits Context\u003cString\u003e\n    Test('actual should be foo', action: (test) =\u003e test.actual = 'foo', assertions: (test) =\u003e [\n      Expect.equals(actual: test.actual, expected: 'foo')\n    ]),\n    // This test should error because actual is trying to be set\n    // to something that is not a String.\n    Test(\n      'actual should be true',\n      action: (test) =\u003e test.actual = true, // This line should error in the Dart complier\n      assertions: (test) =\u003e\n          [Expect.equals(actual: test.actual, expected: true)],\n    ),\n  ],\n);\n```\n\n#### Extending Context\nIt's encouraged to create a custom context to avoid losing typing information on mapped items and avoiding magic strings. On TestRunners, Groups, and Tests, a `contextBuilder` parameter is must be set when it's declared. Remember to also override `copyExtraParams` to set the extra parameters if passing information from parent to children.\n\n```dart\nTestRunner\u003cExtraContext\u003e('Test Suite with Extra Context', [\n  // Group has ExtraContext set as Context\n  Group('Foo', \n    [\n      // Test has ExtraContext set as Context\n      Test('Foo is True', assertions: (test) =\u003e [\n        Expect.isTrue(test.foo),\n        Expect.isNull(test.bar),\n      ]),\n    ],\n    setup: (test) {\n      test.foo = true;\n    },\n  ),\n  Group('Bar', \n    [\n      Test('Bar is set', assertions: (test) =\u003e [\n        Expect.isFalse(test.foo),\n        Expect.isNotNull(test.bar),\n      ]),\n    ],\n    setup: (test) {\n      test.bar = Bar();\n    },\n  ),\n  setup: (test) {\n    test.bar = null;\n  },\n  contextBuilder: ExtraContext.new,\n]);\n\n// ....\nclass ExtraContext extends Context {\n  bool foo = false;\n  Bar? bar;\n\n  @override\n  void copyExtraParams(Context contextToCopyFrom) {\n    if (contextToCopyFrom is ExtraContext) {\n      bar = contextToCopyFrom.bar;\n      foo = contextToCopyFrom.foo;\n    }\n  }\n}\n\n```\n\n## Expect Matches\n  - equals\n  - isEqual **\n  - isNotEqual\n  - isNull\n  - isNotNull\n  - isType ***\n  - isTrue\n  - isFalse\n\n** equals and isEqual can be used interchangeably.\n\n*** isType will need a generic defined or else it will always pass as true as it thinks the type is `dynamic`.\n\n## Mocking\nCake includes an optional, basic mocking library. You can, of course, use any mocking library of choice. In fact, you can extend the MockBase to wrap around a 3rd party library and still get all the benefits included with Cake's library. See `mock_base.dart` and `mockable_function.dart` for examples on how to do this. `MockableFunction` is \n\n### Mock Functionality\n\n### `call()`\nMocks can be called directly with `call()`, which will increase the `callCount` by 1. If using `MockableFunction` (the default mocking library in Cake), you can provide call arguments to be tracked with `history`.\n\n### `value`\nMocks can be set to return a specific default value when called. If using `MockableFunction`, this can be set on the constructor.\n\n### `returnNextCall()`\nOverrides the default `value` for a provided one only for the next time the mock is called. Will reset back to the default value after the next call. Calling `reset()` will also clear this override regardless if the mock has been called or not.\n\n### `throwNextCall()`\nOverrides the default `value` to throw a given error for only the next time the mock is called. Will reset back to the default value without errors after the next call. Calling `reset()` will also clear this override regardless if the mock has been called or not.\n\n### `pause()` and `resume()`\nPause will stop incrementing the call count and call arguments will not be recorded. The default value of a mock will be used on call unless `pausedValue` is provided. This will also pause `returnNextCall` and `throwNextCall` values unless `respectNextCall` flag is turned on.\n\nUse `resume` to revert back to normal behavior.\n\n### Example usage\n\n- Mocking a function\n```dart\nimport 'package:cake/cake.dart';\n\nvoid main() async {\n  TestRunnerDefault('Mocks', [\n    Group('Mocking Functions', [\n      Test(\n        'Can create a mockable function',\n        action: (test) =\u003e MockableFunction(),\n        assertions: (test) =\u003e [\n          Expect.isTrue(true),\n        ],\n      ),\n      Test(\n        'Mocks can be called and will return their value',\n        action: (test) {\n          final MockableFunction mock = MockableFunction(true);\n          return mock.call([1, 2, 3], {'a': 'b'});\n        },\n        assertions: (test) =\u003e [\n          Expect.isTrue(test.actual),\n        ],\n      ),\n      Test(\n        'Mocks can be called multiple times',\n        action: (test) {\n          final MockableFunction mock = MockableFunction(true);\n          mock.call([1, 2, 3], {'a': 'b'});\n          mock.call([1, 2, 3], {'a': 'b'});\n          return mock;\n        },\n        assertions: (test) =\u003e [\n          MockExpect.calledN(test.actual, n: 2),\n          MockExpect.calledWith(\n            test.actual,\n            args: [1, 2, 3],\n            namedArgs: {'a': 'b'},\n          ),\n        ],\n      ),\n      Test(\n        'Mocks can be reset',\n        action: (test) {\n          final MockableFunction mock = MockableFunction(true);\n          mock.call([1, 2, 3], {'a': 'b'});\n          mock.reset();\n          return mock;\n        },\n        assertions: (test) =\u003e [\n          MockExpect.notCalled(test.actual),\n        ],\n      ),\n    ]),\n  ]);\n}\n```\n\n- Mocking a function inside a class\n\n```dart\nclass MockClass extends ClassToMock {\n  final MockableFunctionOf\u003cString\u003e mock = MockableFunctionOf\u003cString\u003e('foobar');\n  ///\n  @override\n  String mockedFunction(String foo, {String? bar}) {\n    return mock.call(args: [foo], namedArgs: {'bar': bar});\n  }\n}\n```\n\n\n### Mock Expects\n  - called\n\n    Checks if the mock has been called.\n  - calledOnce\n\n    Checks if the mock has been called exactly one time.\n  - calledN\n\n    Checks if the mock has been called exactly N times.\n  - notCalled\n\n    Checks if the mock has not been called.\n  - calledWith\n\n    Checks if any of the calls has the given arguments.\n  - calledWithLast\n\n    Checks if the last call made had the given arguments.\n  - calledInOrder\n\n    Checks if the call history has the given sequence in order. Turning on `allowExtraCalls` will ignore any calls between the sequence.\n  - calledHistory\n\n    Checks if the entire call history matches exactly the given sequence.\n\n\n## Options\nOptions are an inheritable object that can be set on a TestRunner, Group, or Test. Any child settings will override parent settings, if set.\n\n- `failOnFirstExpect` - Default: `true`\n  - Set the flag to false to have Cake run all assertions regardless if one of them fails or not.\n\n```dart\nTestRunnerDefault('Test Options', [\n  Test(\n    'Should report only one failure by default',\n    assertions: (test) =\u003e [\n      Expect.equals(actual: true, expected: false), // This test will fail and Cake will bail on the rest of the asserts.\n      Expect.isTrue(true), // This one is meant to pass, but will be skipped\n    ],\n  ),\n  Test(\n    'Should report only one failure when failOnFirstExpect is true',\n    assertions: (test) =\u003e [\n      Expect.equals(actual: true, expected: false), // This test will fail, but Cake is set to continue\n      Expect.isTrue(true), // This one is meant to pass and will show as passed in results.\n    ],\n    options: const TestOptions(failOnFirstExpect: true),\n  ),\n  options: const TestOptions(failOnFirstExpect: false),\n);\n```\n\n## Flags\n\n### File name filter\n- `-f [fileName]`\n  - Filters tests based off of file name\n  - EX: `dart run cake -f foo` will test 'test-foo.cake.dart'\n\n### Verbose mode\n- `-v` or `--verbose`\n  - Displays full output of summary and tests run\n\n### Test Filter\n- `-t [testFilter]`, `--tt [testFilter]`, `--tte [testName]`,  `--tg [groupFilter]`, `--tge [groupName]`, `--tr [testRunnerFilter]`, `--tre [testRunnerName]`\n  - All of these do similar things, which filters based off of title of the item. You can also use certain tags to run only a group, test runner, or a specific test.\n  - Note - search is case-sensitive.\n  - Examples: \n    - `-t` **General search:** `dart run cake -t foo` - Run all tests, groups, and runners with \"foo\" in the title\n    - `--tt` **Test search** `dart run cake --tt \"cool test\"` - Run all tests with the phrase \"cool test\" in the title\n    - `--tte` **Test search, exact:** `dart run cake --tte \"should only run when this one specific thing happens\"` - Runs only the test that matches the phrase exactly.\n    - `--tg` **Group search** `dart run cake --tg bar` - Run all groups matching \"bar\" in the title\n    - `--tge` **Group search, exact:** `dart run cake --tge \"API Endpoints\" - Runs all groups _exactly_ matching the phrase \"API Endpoints\"\n    - `--tr` **Test Runner search:** `dart run cake --tr \"Models\" - Runs all test runners with \"Models\" in the title\n    - `--tre` **Test Runner search, exact:** `dart run cake --tre \"Models - User\"` - Runs test runners that _exactly_ match the phrase \"Models - User\" \n\n### Interactive mode\n- `-i`\n  - Allows for repeatedly running tests. You can also use the test filters similar to non-interactive mode's syntax.\n\n### Flutter mode\n- `--flutter`\n  - Forces Cake to run in Flutter mode regardless of imports. Cake otherwise will automatically try to detect if the [cake_flutter](https://pub.dev/packages/cake_flutter) package has been imported.\n\n# Feedback\nIf you discover a bug or have a suggestion, please check [Issues](https://github.com/Polyhedra-Studio/Cake-Dart/issues) page. If someone has already submitted your bug/suggestion, please upvote so it can get better visibility.\n\n# License\nThis extension is licensed under Mozilla Public License, 2.0.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpolyhedra-studio%2Fcake-dart","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpolyhedra-studio%2Fcake-dart","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpolyhedra-studio%2Fcake-dart/lists"}