{"id":19859392,"url":"https://github.com/dmitry-stepanenko/ngx-cva-test-suite","last_synced_at":"2025-07-08T05:16:08.536Z","repository":{"id":54330163,"uuid":"407227758","full_name":"dmitry-stepanenko/ngx-cva-test-suite","owner":"dmitry-stepanenko","description":null,"archived":false,"fork":false,"pushed_at":"2023-04-07T18:09:10.000Z","size":689,"stargazers_count":7,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-18T17:50:33.283Z","etag":null,"topics":["angular","cva","typescript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","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/dmitry-stepanenko.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}},"created_at":"2021-09-16T15:58:57.000Z","updated_at":"2024-10-20T01:35:31.000Z","dependencies_parsed_at":"2024-11-12T14:39:19.639Z","dependency_job_id":null,"html_url":"https://github.com/dmitry-stepanenko/ngx-cva-test-suite","commit_stats":{"total_commits":7,"total_committers":2,"mean_commits":3.5,"dds":0.1428571428571429,"last_synced_commit":"50f3cbe16f23158f1d7e467b61daa1e43967bb3c"},"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dmitry-stepanenko%2Fngx-cva-test-suite","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dmitry-stepanenko%2Fngx-cva-test-suite/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dmitry-stepanenko%2Fngx-cva-test-suite/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dmitry-stepanenko%2Fngx-cva-test-suite/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dmitry-stepanenko","download_url":"https://codeload.github.com/dmitry-stepanenko/ngx-cva-test-suite/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251972505,"owners_count":21673616,"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","cva","typescript"],"created_at":"2024-11-12T14:26:56.530Z","updated_at":"2025-05-02T02:31:22.138Z","avatar_url":"https://github.com/dmitry-stepanenko.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ngx-cva-test-suite\n\n## Standardise your custom UI form components with ControlValueAccessor Test Suite\n\n\u003ca href=\"https://www.npmjs.com/ngx-cva-test-suite\"\u003e\n    \u003cimg src=\"https://img.shields.io/npm/v/ngx-cva-test-suite.svg?logo=npm\u0026logoColor=fff\u0026label=NPM+package\u0026color=limegreen\" alt=\"NPM package\" /\u003e\n\u003c/a\u003e\n\n`ngx-cva-test-suite` provides an extensive set of test cases, ensuring your custom controls behave as intended. Package is designed and tested to work properly with both **Jest** and **Jasmine** test runners.\n\nIt provides various configurations, that allows even the most non-standard components to be properly tested.\n\nAmong the main features:\n\n-   ensures the correct amount of calls for the `onChange` function _(incorrect usage may result in extra emissions of `valueChanges` of formControl)_\n-   ensures correct triggering of `onTouched` function _(is needed for `touched` state of the control and `updateOn: 'blur'` [strategy](https://angular.io/api/forms/AbstractControl#updateOn) to function properly)_\n-   ensures that no extra emissions are present when control is disabled\n-   checks for control to be resettable using `AbstractControl.reset()`\n\nIn the repository you can also [find few simple CVA components](apps/integration/src/app/controls), that are configured properly along with `ngx-cva-test-suite` setup for them.\n\n## Installation\n\n```\nnpm i ngx-cva-test-suite --save-dev\n```\n\n## Simple Usage\n\nSee [config](#config) below for the details on each property.\n\n```typescript\nimport { runValueAccessorTests } from `ngx-cva-test-suite`;\nimport { ComboboxComponent } from './combobox.component';\n\nrunValueAccessorTests({\n    /** Component, that is being tested */\n    component: ComboboxComponent,\n    /**\n     * All the metadata required for this test to run.\n     * Under the hood calls TestBed.configureTestingModule with provided config.\n     */\n    testModuleMetadata: {\n        declarations: [ComboboxComponent],\n    },\n    /** Whether component is able to track \"onBlur\" events separately */\n    supportsOnBlur: true,\n    /**\n     * CSS selector for the element, that should dispatch `blur` event.\n     * Required and used only if `supportsOnBlur` is set to true.\n     */\n    nativeControlSelector: 'input.combobox-input',\n    /**\n     * Tests the correctness of an approach that is used to set value in the component,\n     * when the change is internal. It's optional and can be omitted by passing \"null\"\n     */\n    internalValueChangeSetter: (fixture, value) =\u003e {\n        fixture.componentInstance.setValue(value, true);\n    },\n    /** Function to get the value of a component in a runtime. */\n    getComponentValue: (fixture) =\u003e fixture.componentInstance.value,\n});\n```\n\n## Using host template\n\nThis type of configuration might become handy, if your CVA component relies on projected content or specific layout to function correctly. A good example of such would be a select component, that gets it's options as projected content.\n\n```typescript\nimport { runValueAccessorTests } from 'ngx-cva-test-suite';\nimport { Component, ViewChild } from '@angular/core';\n\nimport { CustomCheckboxControlValueAccessor } from './support/standard-value-accessors-directives';\n\n@Component({\n    template: `\n        \u003capp-select\u003e\n            \u003capp-select-option [value]=\"1\"\u003eOpt 1\u003c/app-select-option\u003e\n            \u003capp-select-option [value]=\"2\"\u003eOpt 2\u003c/app-select-option\u003e\n            \u003capp-select-option [value]=\"3\"\u003eOpt 3\u003c/app-select-option\u003e\n        \u003c/app-select\u003e\n    `,\n})\nexport class SelectWrapperComponent {\n    @ViewChild(AppSelectComponent) ctrl: AppSelectComponent;\n}\n\nrunValueAccessorTests\u003cAppSelectComponent, SelectWrapperComponent\u003e({\n    // \u003c= if host template is used, it should be marked explicitly as a type\n    component: AppSelectComponent, // \u003c= using actual AppSelectComponent as a test target\n    testModuleMetadata: {\n        declarations: [SelectWrapperComponent],\n        imports: [AppSelectModule], // \u003c= importing the module for app-select\n    },\n    hostTemplate: {\n        // specify that \"AppSelectComponent\" should not be tested directly\n        hostComponent: SelectWrapperComponent,\n        // specify the way to access \"AppSelectComponent\" from the host template\n        getTestingComponent: (fixture) =\u003e fixture.componentInstance.ctrl,\n    },\n    supportsOnBlur: false,\n    internalValueChangeSetter: (fixture, value) =\u003e {\n        // \"setValue\" is a function that is being called\n        // when user selects any \"app-select-option\"\n        fixture.componentInstance.ctrl.setValue(value, true);\n    },\n    getComponentValue: (fixture) =\u003e fixture.componentInstance.ctrl.value,\n    getValues: () =\u003e [1, 2, 3], // \u003c= setting the same values as select options in host template\n});\n```\n\n## Config\n\n### interface CVATestConfig\u003cT extends CVAComponentType, H = T\u003e\n\n#### testModuleMetadata: TestModuleMetadata\n\nAll the metadata required for this test to run. Under the hood calls `TestBed.configureTestingModule` with provided config\n\n#### name?: string\n\nIs used in a root `describe` statement of the test suite.\n\nShould be the name of the component, that is being tested. By default will use the name of testing component.\n\n#### hostTemplate?: HostTemplate\u003cT, H\u003e\n\nAllows to define custom wrapper template for this set of tests. Is useful if CVA cannot be tested in complete isolation.\n\nSee details [below](#interface-hosttemplatet-h)\n\n#### component: Type\u003cT\u003e\n\nComponent, that is being tested\n\n#### getComponentValue: (fixture: ComponentFixture\u003cH\u003e) =\u003e any\n\nFunction to get the value of a component in a runtime. Is used to ensure component applies provided value correctly.\nSet to `null` if you want to skip this check.\n\nExample usage:\n\n```typescript\n// supposed your component has \"getValue()\" method\ngetComponentValue: (fixture) =\u003e fixture.componentInstance.getValue();\n```\n\n#### supportsOnBlur: boolean\n\nThis is related to the ability to track blur events in order to set `emitOn: 'blur'` when used in reactive form.\n\nIf set to true, component will be tested to not call `onTouched` event when value changed.\nInstead of this, it will be expected to trigger this function\nby html blur event using native control (see `nativeControlSelector`in this config).\n\n#### nativeControlSelector?: string\n\nCSS selector for the element, that should dispatch `blur` event. Required and used only if `supportsOnBlur` is set to true.\nProvided selected will be used to programmatically dispatch `blur` event.\n\nExample:\n\n```html\n\u003cinput class=\"combobox-input\" /\u003e\n```\n\nFor the CVA with HTML as above the following should be provided:\n\n```typescript\nnativeControlSelector: 'input.combobox-input';\n```\n\n#### internalValueChangeSetter: (fixture: ComponentFixture\u003cH\u003e, value: any) =\u003e void\n\nTests the approach that is used to set value in the component, when the change is internal\n(e.g. by clicking on an option of the select or typing in the input field).\nWhen value is set, \"onChange\" (and \"onTouched\" depending on the \"blur\" behavior) methods are expected to be invoked\n\nSet to `null` if you want to skip this check.\n\nExample:\nif in your component you have something like this in html\n\n```html\n\u003cinput (input)=\"onSearchChange($event.target.value) /\u003e\n```\n\nthen provide here\n\n```typescript\ninternalValueChangeSetter: (fixture, value) =\u003e {\n    fixture.componentInstance.onSearchChange(value);\n};\n```\n\n#### additionalSetup?: (fixture: ComponentFixture\u003cH\u003e, done: () =\u003e void) =\u003e void\n\nGives an ability to add any additional logic for the setup process.\nIt will be called before running each test.\n\nMake sure you are calling `done` callback after setup is finished.\n\n#### customDelay?: number\n\nAfter setting the value, each test waits for the given amount of time before going further with checks. Defaults to 100ms\n\n#### getValues?: () =\u003e [any, any, any]\n\nCustomizer for plain values. By default will use ['a', 'b', 'c']\n\nThis test suite applies up to 3 different values on the component. If strings are not supported in your component,\nreplace it with whatever is needed. It's recommended to **NOT** use consecutive same values (like ~`[1, 1, 1]`~)\n\nExample:\n\n```\ngetValues: () =\u003e [1, 2, 3]\n// or\ngetValues: () =\u003e [true, false, true]\n```\n\n#### resetCustomValue?: { value: any }\n\nComponent will be tested for correct behavior, when `FormControl`'s `reset()` method is called.\nAfter simulating this call, it will check if value of the component is reset internally.\n\nIf your component is not supposed to work with `null` as a value, specify what you're expecting to have as a value internally\n\n#### disabledStateNotSupported?: boolean\n\nSet this to true, if component cannot be disabled.\n\nIf set to true, `ControlValueAccessor.setDisabledState()` function will not be checked for existance and correct behavior.\n\n#### testRunnerType?: TestRunnerType\n\nTest suite will automatically detect whether it's Jest or Jasmine environment. If needed, this can be overriden\n\n#### excludeSteps?: CVATestSteps[];\n\nList of steps to be excluded from execution. Cannot be specified along with `includeSteps`\n\n#### includeSteps?: CVATestSteps[];\n\nList of steps to be included in execution. Cannot be specified along with `excludeSteps`\n\n### interface HostTemplate\u003cT, H\u003e\n\n#### hostComponent: Type\u003cany\u003e\n\nWrapper, that hosts testing component. For example, to test `app-select-component` the following wrapper is used\n\n```typescript\n@Component({\n    selector: 'app-test-component-wrapper',\n    template: `\n        \u003capp-select label=\"Label Value\" #ctrl\u003e\n            \u003capp-select-option [value]=\"1\" label=\"Opt 1\"\u003e\u003c/app-select-option\u003e\n            \u003capp-select-option [value]=\"2\" label=\"Opt 2\"\u003e\u003c/app-select-option\u003e\n            \u003capp-select-option [value]=\"3\" label=\"Opt 3\"\u003e\u003c/app-select-option\u003e\n        \u003c/app-select\u003e\n    `,\n})\nclass TestWrapperComponent {\n    @ViewChild('ctrl') ctrl: AppSelectComponent;\n}\n```\n\n#### getTestingComponent: (fixture: ComponentFixture\u003cH\u003e) =\u003e T\n\nGetter for the actual component that is being tested\n\nUsing the hostComponent above, the following function should be used:\n`(fixture) =\u003e fixture.componentInstance.ctrl;`\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdmitry-stepanenko%2Fngx-cva-test-suite","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdmitry-stepanenko%2Fngx-cva-test-suite","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdmitry-stepanenko%2Fngx-cva-test-suite/lists"}