|
1 |
| -# @angular-extensions/testing-library |
| 1 | +<div align="center"> |
| 2 | +<h1>@angular-extensions/testing-library</h1> |
2 | 3 |
|
3 |
| -Lightweight utility functions to test Angular components. |
| 4 | +<a href="https://www.emojione.com/emoji/1f994"> |
| 5 | + <img |
| 6 | + height="80" |
| 7 | + width="80" |
| 8 | + alt="hedgehog" |
| 9 | + src="https://raw.githubusercontent.com/angular-extensions/testing-library/master/other/hedgehog.png" |
| 10 | + /> |
| 11 | +</a> |
4 | 12 |
|
5 |
| -[**Read The Docs**](https://testing-library.com/angular) | [Edit the docs](https://github.com/alexkrolick/testing-library-docs) |
| 13 | +<p>Simple and complete Angular testing utilities that encourage good testing |
| 14 | +practices.</p> |
6 | 15 |
|
7 |
| -<hr /> |
8 |
| - |
9 |
| -[![Build status][build-badge]][build] |
| 16 | +<br /> |
10 | 17 |
|
11 |
| -[![npm][npm-badge]][npm] |
| 18 | +[**Read The Docs**](https://testing-library.com/angular) | |
| 19 | +[Edit the docs](https://github.com/alexkrolick/testing-library-docs) |
12 | 20 |
|
13 |
| -[![Semantically released][sr-badge]][sr] |
| 21 | +<br /> |
| 22 | +</div> |
14 | 23 |
|
15 |
| -[![Styled with prettier][prettier-badge]][prettier] |
| 24 | +<hr /> |
16 | 25 |
|
| 26 | +<!-- prettier-ignore-start --> |
| 27 | +[![Build Status][build-badge]][build] |
| 28 | +[![version][version-badge]][package] [![downloads][downloads-badge]][npmtrends] |
17 | 29 | [![MIT License][license-badge]][license]
|
18 | 30 |
|
19 |
| -[![Code of Conduct][coc-badge]][coc] |
20 |
| - |
21 |
| -## Table of Contents |
| 31 | +[![PRs Welcome][prs-badge]][prs] [![Code of Conduct][coc-badge]][coc] |
| 32 | +[![Join the community on Spectrum][spectrum-badge]][spectrum] |
22 | 33 |
|
23 |
| -- [Installation](#installation) |
24 |
| -- [Why](#why) |
25 |
| -- [What](#what) |
26 |
| -- [How](#how) |
27 |
| - - [`render`](#render) |
28 |
| - - [`container: HTMLElement`](#container-htmlelement) |
29 |
| - - [`debug(element: HTMLElement) => void`](#debug--void) |
30 |
| - - [`fixture: any`](#fixture-any) |
31 |
| -- [Usage](#usage) |
32 |
| -- [LICENSE](#license) |
| 34 | +[![Watch on GitHub][github-watch-badge]][github-watch] |
| 35 | +[![Star on GitHub][github-star-badge]][github-star] |
| 36 | +[![Tweet][twitter-badge]][twitter] |
| 37 | +<!-- prettier-ignore-end --> |
33 | 38 |
|
34 |
| -## Installation |
| 39 | +<div align="center"> |
| 40 | + <a href="https://testingjavascript.com"> |
| 41 | + <img |
| 42 | + width="500" |
| 43 | + alt="TestingJavaScript.com Learn the smart, efficient way to test any JavaScript application." |
| 44 | + src="https://raw.githubusercontent.com/testing-library/react-testing-library/master/other/testingjavascript.jpg" |
| 45 | + /> |
| 46 | + </a> |
| 47 | +</div> |
35 | 48 |
|
36 |
| -Install `@angular-extensions/testing-library` from [npm] and add it your `devDependencies`: |
| 49 | +## Table of Contents |
37 | 50 |
|
38 |
| -`npm install @angular-extensions/testing-library --save-dev` |
| 51 | +<!-- START doctoc generated TOC please keep comment here to allow auto update --> |
| 52 | +<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --> |
39 | 53 |
|
40 |
| -## Why |
| 54 | +- [The problem](#the-problem) |
| 55 | +- [This solution](#this-solution) |
| 56 | +- [Example](#example) |
| 57 | +- [Installation](#installation) |
| 58 | +- [Guiding Principles](#guiding-principles) |
| 59 | +- [Docs](#docs) |
| 60 | +- [Issues](#issues) |
| 61 | + - [🐛 Bugs](#-bugs) |
| 62 | + - [💡 Feature Requests](#-feature-requests) |
| 63 | + - [❓ Questions](#-questions) |
| 64 | +- [LICENSE](#license) |
41 | 65 |
|
42 |
| -- test your UI components the way your users are using it |
43 |
| -- making your tests resilient to implementation changes |
| 66 | +<!-- END doctoc generated TOC please keep comment here to allow auto update --> |
44 | 67 |
|
45 |
| -## What |
| 68 | +## The problem |
46 | 69 |
|
47 |
| -`@angular-extensions/testing-library` is an Angular adapter around [dom-testing-library][dom-testing-library], |
48 |
| -which provides lightweight utility functions to test UI components. Your tests will work with actual DOM nodes. |
| 70 | +You want to write maintainable tests for your Angular components. As a part of |
| 71 | +this goal, you want your tests to avoid including implementation details of your |
| 72 | +components and rather focus on making your tests give you the confidence for |
| 73 | +which they are intended. As part of this, you want your testbase to be |
| 74 | +maintainable in the long run so refactors of your components (changes to |
| 75 | +implementation but not functionality) don't break your tests and slow you and |
| 76 | +your team down. |
49 | 77 |
|
50 |
| -## How |
| 78 | +## This solution |
51 | 79 |
|
52 |
| -### `render` |
| 80 | +The `@angular-extensions/testing-library` is a very lightweight solution for testing Angular |
| 81 | +components. It provides light utility functions on top of `Angular` and |
| 82 | +`dom-testing-library`, in a way that encourages better testing practices. Its |
| 83 | +primary guiding principle is: |
53 | 84 |
|
54 |
| -This library only consists of one function, `render` which is used to setup the Angular `TestBed` and creates the component fixture. |
| 85 | +> [The more your tests resemble the way your software is used, the more |
| 86 | +> confidence they can give you.][guiding-principle] |
55 | 87 |
|
56 |
| -This method can be used in two ways: |
| 88 | +## Example |
57 | 89 |
|
58 |
| -Based on a template: |
| 90 | +counter.component.ts |
59 | 91 |
|
60 | 92 | ```ts
|
61 |
| -import { render } from '@angular-extensions/testing-library'; |
62 |
| - |
63 |
| -render('<my-component [prop]="1"></my-component>', options); |
| 93 | +@Component({ |
| 94 | + selector: 'counter', |
| 95 | + template: ` |
| 96 | + <button (click)="decrement()">-</button> |
| 97 | + <span data-testid="count">Current Count: {{ counter }}</span> |
| 98 | + <button (click)="increment()">+</button> |
| 99 | + `, |
| 100 | +}) |
| 101 | +export class CounterComponent { |
| 102 | + @Input() counter = 0; |
| 103 | + |
| 104 | + increment() { |
| 105 | + this.counter += 1; |
| 106 | + } |
| 107 | + |
| 108 | + decrement() { |
| 109 | + this.counter -= 1; |
| 110 | + } |
| 111 | +} |
64 | 112 | ```
|
65 | 113 |
|
66 |
| -Based on a component type: |
| 114 | +counter.component.spec.ts |
67 | 115 |
|
68 |
| -```ts |
| 116 | +```javascript |
69 | 117 | import { render } from '@angular-extensions/testing-library';
|
| 118 | +import CounterComponent from './counter.component.ts'; |
70 | 119 |
|
71 |
| -render( |
72 |
| - { |
73 |
| - component: MyComponent, |
74 |
| - parameters: { |
75 |
| - prop: 1, |
76 |
| - }, |
77 |
| - }, |
78 |
| - options, |
79 |
| -); |
80 |
| -``` |
| 120 | +describe('Counter', () => { |
| 121 | + test('should render counter', async () => { |
| 122 | + const { getByText } = await render(CounterComponent, { componentProperties: { counter: 5 } }); |
81 | 123 |
|
82 |
| -The second parameter in `render` is the `options` parameter, which looks like this: |
| 124 | + expect(getByText('Current Count: 5')); |
| 125 | + }); |
83 | 126 |
|
84 |
| -```ts |
85 |
| -{ |
86 |
| - detectChanges?: boolean = true; |
87 |
| - declarations: any[] = []; |
88 |
| - providers?: any[] = []; |
89 |
| - imports?: any[] = []; |
90 |
| - schemas?: any[] = []; |
91 |
| -} |
| 127 | + test('should increment the counter on click', async () => { |
| 128 | + const { getByText, click } = await render(CounterComponent, { componentProperties: { counter: 5 } }); |
| 129 | + |
| 130 | + click(getByText('+')); |
| 131 | + |
| 132 | + expect(getByText('Current Count: 6')); |
| 133 | + }); |
| 134 | +}); |
92 | 135 | ```
|
93 | 136 |
|
94 |
| -`detectChanges`: runs `detectChanges` on the fixture |
| 137 | +## Installation |
95 | 138 |
|
96 |
| -`declarations`: passed to the `TestBed` |
| 139 | +This module is distributed via [npm][npm] which is bundled with [node][node] and |
| 140 | +should be installed as one of your project's `devDependencies`: |
97 | 141 |
|
98 |
| -`providers`: passed to the `TestBed` |
| 142 | +```bash |
| 143 | +npm install @angular-extensions/testing-library --save-dev |
| 144 | +``` |
99 | 145 |
|
100 |
| -`imports`: passed to the `TestBed` |
| 146 | +You may also be interested in installing `jest-dom` so you can use |
| 147 | +[the custom jest matchers](https://github.com/gnapse/jest-dom#readme). |
101 | 148 |
|
102 |
| -`schemas`: passed to the `TestBed` |
| 149 | +> [**Docs**](https://testing-library.com/angular) |
103 | 150 |
|
104 |
| -The `render` function returns an object consisting all of the query functions from [dom-testing-library][dom-testing-library], all the event functions exposed from `fireEvent`, and adds the following properties: |
| 151 | +## Guiding Principles |
105 | 152 |
|
106 |
| -> Every event runs `detectChanges` on the fixture. |
| 153 | +> [The more your tests resemble the way your software is used, the more |
| 154 | +> confidence they can give you.][guiding-principle] |
107 | 155 |
|
108 |
| -#### `container: HTMLElement` |
| 156 | +We try to only expose methods and utilities that encourage you to write tests |
| 157 | +that closely resemble how your Angular components are used. |
109 | 158 |
|
110 |
| -The DOM node containing the Angular component. |
| 159 | +Utilities are included in this project based on the following guiding |
| 160 | +principles: |
111 | 161 |
|
112 |
| -All of the [dom-testing-library][dom-testing-library] query functions are binded to this container. |
| 162 | +1. If it relates to rendering components, it deals with DOM nodes rather than |
| 163 | + component instances, nor should it encourage dealing with component |
| 164 | + instances. |
| 165 | +2. It should be generally useful for testing individual Angular components or |
| 166 | + full Angular applications. |
| 167 | +3. Utility implementations and APIs should be simple and flexible. |
113 | 168 |
|
114 |
| -#### `debug(element: HTMLElement) => void` |
| 169 | +At the end of the day, what we want is for this library to be pretty |
| 170 | +light-weight, simple, and understandable. |
115 | 171 |
|
116 |
| -Prints out the container. |
| 172 | +## Docs |
117 | 173 |
|
118 |
| -#### `fixture: any` |
| 174 | +[**Read The Docs**](https://testing-library.com/angular) | |
| 175 | +[Edit the docs](https://github.com/alexkrolick/testing-library-docs) |
119 | 176 |
|
120 |
| -The Angular fixture. |
| 177 | +## Issues |
121 | 178 |
|
122 |
| -## Usage |
| 179 | +_Looking to contribute? Look for the [Good First Issue][good-first-issue] |
| 180 | +label._ |
123 | 181 |
|
124 |
| -You can find some examples in the [tests folder](https://github.com/angular-extensions/testing-library/tree/master/projects/testing-library/tests). |
| 182 | +### 🐛 Bugs |
125 | 183 |
|
126 |
| -Here is how the "default" specifications can be written with `@angular-extensions/testing-library`. |
| 184 | +Please file an issue for bugs, missing documentation, or unexpected behavior. |
127 | 185 |
|
128 |
| -Before: |
| 186 | +[**See Bugs**][bugs] |
129 | 187 |
|
130 |
| -```ts |
131 |
| -import { TestBed, async } from '@angular/core/testing'; |
132 |
| -import { AppComponent } from './app.component'; |
133 |
| - |
134 |
| -describe('AppComponent', () => { |
135 |
| - beforeEach(async(() => { |
136 |
| - TestBed.configureTestingModule({ |
137 |
| - declarations: [AppComponent], |
138 |
| - }).compileComponents(); |
139 |
| - })); |
140 |
| - |
141 |
| - it(`should have as title 'my-awesome-app'`, async(() => { |
142 |
| - const fixture = TestBed.render(AppComponent); |
143 |
| - const app = fixture.debugElement.componentInstance; |
144 |
| - expect(app.title).toEqual('my-awesome-app'); |
145 |
| - })); |
146 |
| - |
147 |
| - it(`should render title in a h1 tag`, async(() => { |
148 |
| - const fixture = TestBed.render(AppComponent); |
149 |
| - fixture.detectChanges(); |
150 |
| - const compiled = fixture.debugElement.nativeElement; |
151 |
| - expect(compiled.querySelector('h1').textContent).toContain('Welcome to my-awesome-app!'); |
152 |
| - })); |
153 |
| -}); |
154 |
| -``` |
| 188 | +### 💡 Feature Requests |
155 | 189 |
|
156 |
| -After: |
| 190 | +Please file an issue to suggest new features. Vote on feature requests by adding |
| 191 | +a 👍. This helps maintainers prioritize what to work on. |
157 | 192 |
|
158 |
| -```ts |
159 |
| -import { render } from '@angular-extensions/testing-library'; |
160 |
| -import { AppComponent } from './app.component'; |
| 193 | +[**See Feature Requests**][requests] |
161 | 194 |
|
162 |
| -it(`should have as title 'my-awesome-app'`, async () => { |
163 |
| - const { getByText } = await render('<app-root></app-root>', { |
164 |
| - declarations: [AppComponent], |
165 |
| - }); |
166 |
| - expect(getByText('Welcome to my-awesome-app!')).toBeDefined(); |
167 |
| -}); |
| 195 | +### ❓ Questions |
168 | 196 |
|
169 |
| -it(`should render title in a h1 tag`, async () => { |
170 |
| - const { container } = await render( |
171 |
| - { |
172 |
| - component: AppComponent, |
173 |
| - }, |
174 |
| - { |
175 |
| - declarations: [AppComponent], |
176 |
| - }, |
177 |
| - ); |
178 |
| - expect(container.querySelector('h1').textContent).toContain('Welcome to my-awesome-app!'); |
179 |
| -}); |
180 |
| -``` |
| 197 | +For questions related to using the library, please visit a support community |
| 198 | +instead of filing an issue on GitHub. |
| 199 | + |
| 200 | +- [Spectrum][spectrum] |
| 201 | +- [Stack Overflow][stackoverflow] |
181 | 202 |
|
182 | 203 | ## LICENSE
|
183 | 204 |
|
184 | 205 | MIT
|
185 | 206 |
|
| 207 | +<!-- |
| 208 | +Links: |
| 209 | +--> |
| 210 | + |
| 211 | +<!-- prettier-ignore-start --> |
| 212 | + |
| 213 | +[npm]: https://www.npmjs.com/ |
| 214 | +[node]: https://nodejs.org |
186 | 215 | [build-badge]: https://circleci.com/gh/angular-extensions/testing-library/tree/master.svg?style=shield
|
187 | 216 | [build]: https://circleci.com/gh/angular-extensions/testing-library/tree/master
|
188 |
| -[sr-badge]: https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg |
189 |
| -[sr]: https://github.com/semantic-release/semantic-release |
190 |
| -[prettier-badge]: https://img.shields.io/badge/styled_with-prettier-ff69b4.svg |
191 |
| -[prettier]: https://github.com/prettier/prettier |
192 |
| -[npm-badge]: https://img.shields.io/npm/v/@angular-extensions/testing-library.svg |
193 |
| -[npm]: https://www.npmjs.com/package/@angular-extensions/testing-library |
| 217 | +[version-badge]: https://img.shields.io/npm/v/@angular-extensions/testing-library.svg?style=flat-square |
| 218 | +[package]: https://www.npmjs.com/package/@angular-extensions/testing-library |
| 219 | +[downloads-badge]: https://img.shields.io/npm/dm/@angular-extensions/testing-library.svg?style=flat-square |
| 220 | +[npmtrends]: http://www.npmtrends.com/@angular-extensions/testing-library |
| 221 | +[spectrum-badge]: https://withspectrum.github.io/badge/badge.svg |
| 222 | +[spectrum]: https://spectrum.chat/testing-library |
194 | 223 | [license-badge]: https://img.shields.io/npm/l/@angular-extensions/testing-library.svg?style=flat-square
|
195 | 224 | [license]: https://github.com/angular-extensions/testing-library/blob/master/LICENSE
|
| 225 | +[prs-badge]: https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square |
| 226 | +[prs]: http://makeapullrequest.com |
| 227 | +[donate-badge]: https://img.shields.io/badge/$-support-green.svg?style=flat-square |
196 | 228 | [coc-badge]: https://img.shields.io/badge/code%20of-conduct-ff69b4.svg?style=flat-square
|
197 | 229 | [coc]: https://github.com/angular-extensions/testing-library/blob/master/CODE_OF_CONDUCT.md
|
198 |
| -[dom-testing-library]: https://testing-library.com/ |
| 230 | +[github-watch-badge]: https://img.shields.io/github/watchers/angular-extensions/testing-library.svg?style=social |
| 231 | +[github-watch]: https://github.com/angular-extensions/testing-library/watchers |
| 232 | +[github-star-badge]: https://img.shields.io/github/stars/angular-extensions/testing-library.svg?style=social |
| 233 | +[github-star]: https://github.com/angular-extensions/testing-library/stargazers |
| 234 | +[twitter]: https://twitter.com/intent/tweet?text=Check%20out%20🦔%20@angular-extensions/testing-library%20by%20%40tim_deschryver%20https%3A%2F%2Fgithub.com%2F@angular-extensions/testing-library |
| 235 | +[twitter-badge]: https://img.shields.io/twitter/url/https/github.com/angular-extensions/testing-library.svg?style=social |
| 236 | +[emojis]: https://github.com/all-contributors/all-contributors#emoji-key |
| 237 | +[all-contributors]: https://github.com/all-contributors/all-contributors |
| 238 | +[set-immediate]: https://developer.mozilla.org/en-US/docs/Web/API/Window/setImmediate |
| 239 | +[guiding-principle]: https://twitter.com/kentcdodds/status/977018512689455106 |
| 240 | +[bugs]: https://github.com/angular-extensions/testing-library/issues?q=is%3Aissue+is%3Aopen+label%3Abug+sort%3Acreated-desc |
| 241 | +[requests]: https://github.com/angular-extensions/testing-library/issues?q=is%3Aissue+sort%3Areactions-%2B1-desc+label%3Aenhancement+is%3Aopen |
| 242 | +[good-first-issue]: https://github.com/angular-extensions/testing-library/issues?utf8=✓&q=is%3Aissue+is%3Aopen+sort%3Areactions-%2B1-desc+label%3A"good+first+issue"+ |
| 243 | +[stackoverflow]: https://stackoverflow.com/questions/tagged/angular-testing-library |
| 244 | + |
| 245 | +<!-- prettier-ignore-end --> |
0 commit comments