{"id":15677906,"url":"https://github.com/mradionov/tleaf","last_synced_at":"2025-06-12T14:32:23.724Z","repository":{"id":34278667,"uuid":"38166520","full_name":"mradionov/tleaf","owner":"mradionov","description":"AngularJS unit test generator","archived":false,"fork":false,"pushed_at":"2022-02-11T09:41:52.000Z","size":909,"stargazers_count":12,"open_issues_count":14,"forks_count":9,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-05-07T01:51:42.619Z","etag":null,"topics":["angular","generator","unit-testing"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/tleaf","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mradionov.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}},"created_at":"2015-06-27T16:18:46.000Z","updated_at":"2020-03-10T14:03:24.000Z","dependencies_parsed_at":"2022-09-14T02:31:36.630Z","dependency_job_id":null,"html_url":"https://github.com/mradionov/tleaf","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/mradionov/tleaf","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mradionov%2Ftleaf","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mradionov%2Ftleaf/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mradionov%2Ftleaf/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mradionov%2Ftleaf/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mradionov","download_url":"https://codeload.github.com/mradionov/tleaf/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mradionov%2Ftleaf/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":259482626,"owners_count":22864783,"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":["angular","generator","unit-testing"],"created_at":"2024-10-03T16:13:53.651Z","updated_at":"2025-06-12T14:32:23.708Z","avatar_url":"https://github.com/mradionov.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"tleaf\n===\n\n\u003e AngularJS unit test generator\n\nCommand line [npm](https://www.npmjs.com/) utility tool built on [Node.js](https://nodejs.org/) to generate [AngularJS](https://angularjs.org/) unit tests based on existing code or create them from scratch.\n\n![screencast](screencast.gif)\n\n#### Contents:\n\n  * [How does it work?](#how-does-it-work)\n  * [Installation](#installation)\n  * [Usage](#usage)\n  * [Configuration](#configuration)\n  * [Custom templates](#custom-templates)\n    * [Data available in templates](#data-available-in-templates)\n    * [Examples](#examples)\n    * [Extra helpers](#extra-helpers)\n\n## How does it work?\n\nIt takes your AngularJS source file and parses it with the help of [esprima](http://esprima.org/) - standard-compliant ECMAScript parser, which results into a code syntax tree. The tree is being analyzed for AngularJS units and based on that information it generates a test file from pre-defined templates, setting up the collected data for unit tests.\n\n*Note: source code can be very different and complex from project to project (and from person to person), so it's really difficult to cover all cases and styles of writing AngularJS applications to be able to extract required information. If your AngularJS source code is not getting parsed as expected, feel free to create an issue with an example of the source code causing the problem or PR a test reproducing it.*\n\n## Installation\n\nInstall module globally:\n\n```bash\n$ npm i tleaf -g\n```\n\n## Usage\n\n***\n\n```bash\n$ tleaf SOURCE DEST\n```\n\n* `SOURCE` - path to AngularJS source code with a unit to test\n* `DEST` - path to output test file\n\nThe command parses your source file and extracts all AngularJS units. After that you will be asked which one you'd want to test and also to identify the dependencies. The result will be a test file generated based on a template for this unit type.\n\n***\n\n```bash\n$ tleaf create DEST\n```\n\n* `DEST` - path to output test file\n\nThe command creates a test file based on answers you provide for a number of questions: *What is a name of the unit?* *What is a type of the unit?* *What are unit's dependencies?* The result will be a test file generated based on a template for this unit type.\n\n***\n\n```bash\n$ tleaf init [DIRECTORY]\n```\n\n* `[DIRECTORY]` - *(optional)* path to output folder\n\nThe command copies a configuration file to a directory you've provided. If directory is not specified, the configuration file will be copied to a current directory.\n\n***\n\n```bash\n$ tleaf clone [DIRECTORY]\n```\n\n* `[DIRECTORY]` - *(optional)* path to output folder\n\nThe command copies default templates to a directory you've provided. If directory is not specified, the folder will be created in a current directory. As a result you'll be able to modify copied templates for your needs and requirements and use them instead of default templates to generate test files (see more in [Custom templates](#custom-templates)). This folder can be initialized anywhere on your machine, you can use the same configuration and set of templates for multiple projects (see commands below to switch between configurations). It can be included under version control system, but it is not required at all, it's up to you.\n\n***\n\n```bash\n$ tleaf use CONFIG\n```\n\n* `CONFIG` - path to configuration file\n\nThe command sets current configuration which will be used to generate test files. It accepts a path to a configuration file created by executing a command `tleaf init [DIRECTORY]` or a configuration file inside a folder, which was created by executing a command `tleaf clone [DIRECTORY]`. It assumes that custom templates are in the same folder with the configuration file, following the same structure when you cloned them with `tleaf clone [DIRECTORY]`. The command allows you to switch between different configurations and set of templates.\n\n***\n\n```bash\n$ tleaf default\n```\n\n  The command allows to switch back to the default configuration and set of templates.\n\n***\n\n```bash\n$ tleaf current\n```\n\n  The command shows what configuration is used at the moment.\n\n***\n\n## Configuration\n\n[Default configuration file](src/defaults/tleaf.conf.js) contains only a few commonly used options ([see the complete configuration](src/config/default.js)). Your configuration will be merged with the default complete configuration, arrays will be overriden by your values (not merged). Available options:\n\n* `template.indent: [string|integer]` - sets indentation for templates. Tabs by default (`'\\t'`). A string will replace one tab. An integer will be a number of spaces to replace one tab.\n\n  ```js\n  module.exports = function (config) {\n    config.set({\n      template: {\n        indent: '  '    // 1 tab = 2 spaces,\n        indent: '\\t'    // 1 tab = 1 tab\n        indent: 4       // 1 tab = 4 spaces\n        indent: '--'    // 1 tab = '--'\n      }\n    });\n  };\n  ```\n* `template.useStrict: [bool]` - include `'use strict';` to the top of a generated test file.\n\n  ```js\n  module.exports = function (config) {\n    config.set({\n      template: {\n        useStrict: true     // include\n        useStrict: false    // don't include\n      }\n    });\n  };\n  ```\n\n* `template.includeSamples: [bool]` - add commented examples of basic specs to a generated test file.\n\n  ```js\n  module.exports = function (config) {\n    config.set({\n      template: {\n        includeSamples: true  // include\n        includeSamples: false // don't include\n      }\n    });\n  };\n  ```\n\n* `units.process: [array]` - array of unit types which should be parsed and processed. To reorder the appearance of unit types change their order in this array. See the [complete configuration](src/config/default.js#L22) for all possible options.\n\n  ```js\n  module.exports = function (config) {\n    config.set({\n      units: {\n        // process only controllers, directives and providers\n        // these types will appear in the exact same order\n        process: ['controller', 'directive', 'provider']\n      }\n    });\n  };\n  ```\n\n* `dependencies.process: [array]` - array of dependency types which should be parsed and processed. To reorder the appearance of dependency types change their order in this array. See the [complete configuration](src/config/default.js#L34) for all possible options.\n\n  ```js\n  module.exports = function (config) {\n    config.set({\n      dependencies: {\n        // process only services and values, others will be ignored\n        // these types will appear in the exact same order, which means that\n        // all services will be rendered first, then all the values, etc.\n        process: ['service', 'value']\n      }\n    });\n  };\n  ```\n\n* `dependencies.filter: [array]` - array of dependency names, which should be ignored, by default only `$scope` is excluded. If you override this value make sure to include `$scope` too (if you need it to be exluded).\n\n  ```js\n  module.exports = function (config) {\n    config.set({\n      dependencies: {\n        // ignore dependencies with these names\n        filter: ['$scope', 'GlobalService', 'SECRET_CONST']\n      }\n    });\n  };\n  ```\n\n* `dependencies.templateMap: [object]` - object, which maps dependency types with templates they should use. May be useful, for example, when you want to render *factories* or *services* using *value* template. See the [complete configuration](src/config/default.js#L42) for all possible options.\n\n  ```js\n  module.exports = function (config) {\n    config.set({\n      dependencies: {\n        templateMap: {\n          'provider': 'provider', // use default provider template\n          'service': 'value',     // use value template for service\n          'factory': 'service'    // use service template for factory\n        }\n      }\n    });\n  };\n  ```\n\n## Custom templates\n\nTest files are generated from the templates, which are kinda JavaScript files, but they get processed like templates to be able to fill it with the gathered data.\nWhen you run the command `tleaf clone [DIRECTORY]`, all default templates and a configuration file are copied to the location you've provided.\nMost of the templates are based on [yeoman/angular-generator](https://github.com/yeoman/generator-angular) and [daniellmb/angular-test-patterns](https://github.com/daniellmb/angular-test-patterns), the rest of the templates are made by taking already existing ones as an example. You can take a look at the [default templates](src/defaults/templates), they have pretty simple base setup, which might be enough for general use.\nTemplates are processed by the templating engine [Handlebars](http://handlebarsjs.com/), so you can use any of it's features.\n\n### Data available in templates\n\nInformation, which is being collected by a parser or from your answers, gets passed to the templates. Here is a structure of the data available in the templates, consider it a global object in your templates (taking some controller as an example):\n\n```js\n\n{\n  // top level\n\n  unit: {\n\n    name: 'UserController',\n\n    type: 'controller',\n\n    module: {\n      name: 'admin'\n    },\n\n    deps: [\n      {\n        name: '$http',\n        type: 'provider'\n      },\n      {\n        name: 'UserService',\n        type: 'service'\n      },\n      {\n        name: 'API_KEY',\n        type: 'constant'\n      }\n    ]\n  },\n\n  // top level\n\n  // shortcut for: unit.name\n  name: 'UserController',\n\n  // shortcut for: \"_\" + unit.name + \"_\"; useful in provide() section\n  _name_: '_UserController_',\n\n  // shortcut for: unit.module.name\n  module: 'admin',\n\n  // shortcut for: unit.deps; plus some additions\n  deps: [\n    {\n      name: '$http',\n      _name_: '_$http_',\n      type: 'provider'\n    },\n    {\n      name: 'UserService',\n      _name_: '_UserService_',\n      type: 'service'\n    },\n    {\n      name: 'API_KEY',\n      _name_: '_API_KEY_',\n      type: 'constant'\n    }\n  ],\n\n  // top level\n\n  // args are usually used to render variables or arguments\n  arg: {\n\n    // shortcut for unit names\n    deps: ['$http', 'UserService', 'API_KEY'],\n\n    // shortcut for unit names; useful in provide() section\n    _deps_: ['_$http_', '_UserService_', '_API_KEY_']\n\n  },\n\n  // top level\n\n  // references to config values\n  opts: {\n\n    useStrict: true,\n\n    includeTemplates: true\n\n  }\n\n}\n```\n\n### Examples\n\nHere you can find some examples of composing the templates. You can discover more use-cases by looking at the [default templates](src/defaults/templates).\n\n1. Load module:\n\n  Template:\n\n  ```js\n  module('{{module}}');\n  module('{{unit.module.name}}')\n  ```\n\n  After render:\n\n  ```js\n  module('admin');\n  module('admin');\n  ```\n\n2. Initialize variables:\n\n  Template:\n\n  ```js\n  var {{name}}{{and arg.deps}};\n  var {{only arg.deps}};\n  ```\n\n  After render:\n\n  ```js\n  var UserController, $http, UserService, API_KEY;\n  var $http, UserService, API_KEY;\n  ```\n\n3. Provide dependencies:\n\n  Template:\n\n  ```js\n  module(function ($provide) {\n    {{#each deps}}\n    {{\u003e (this.partial) this}} // renders a partial for a current dependency\n    {{/each}}\n  });\n  ```\n\n  After render:\n\n  ```js\n  module(function ($provide) {\n    $provide.provider('$http', function () {\n      this.$get = function () {\n        return {};\n      };\n    });\n    $provide.service('UserService', function () {\n    });\n    $provide.constant('API_KEY', '');\n  });\n  ```\n\n### Extra helpers\n\nHandlerbars allows to create custom helpers to help render the data. Here are the ones built-in in the module:\n\n* `{{only array}}` - joins array of strings with `\", \"`:\n\n  ```js\n  $http, UserService, API_KEY\n  ```\n\n* `{{and array}}` - joins array of strings with `\", \"`, but also adds extra `\", \"` in front:\n\n  ```js\n  , $http, UserService, API_KEY\n  ```\n\n* `{{dashCase string}}` - converts string to dash-case, useful when working with directives:\n\n  ```\n  \"ngBindHtml\" =\u003e \"ng-bind-html\"\n  ```\n\n* `{{defaults value defaultValue}}` - renders *value* if it is not *undefined*, *defaultValue* otherwise.\n\n## Changelog\n\n- 0.2.0 - Support for Angular 1.5 components\n- 0.1.0 - Initial","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmradionov%2Ftleaf","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmradionov%2Ftleaf","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmradionov%2Ftleaf/lists"}