https://github.com/theintern/example-angular
A test project to demonstrate using Intern with Angular 4+
https://github.com/theintern/example-angular
Last synced: 8 months ago
JSON representation
A test project to demonstrate using Intern with Angular 4+
- Host: GitHub
- URL: https://github.com/theintern/example-angular
- Owner: theintern
- License: other
- Created: 2017-09-12T13:21:28.000Z (almost 9 years ago)
- Default Branch: master
- Last Pushed: 2018-03-20T03:54:26.000Z (over 8 years ago)
- Last Synced: 2024-12-09T19:53:46.110Z (over 1 year ago)
- Language: TypeScript
- Size: 102 KB
- Stars: 3
- Watchers: 7
- Forks: 287
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Intern + Angular
This is a test project to demonstrate using Intern with Angular 4+. It contains [all of the specs](https://angular.io/generated/live-examples/testing/app-specs.eplnkr.html) from Angular's test guide as well as [some extras](https://angular.io/generated/live-examples/testing/bag-specs.eplnkr.html). Specs have been reformatted and converted to using Intern best practices as outlined below.
## Get started
### Clone the repo
```shell
git clone https://github.com/bryanforbes/intern-angular
cd intern-angular
```
### Install npm packages
Install the `npm` packages described in the `package.json` and verify that it works:
```shell
npm install
npm start
```
The `npm start` command builds (compiles TypeScript and copies assets) the application into `dist/`, watches for changes to the source files, and runs `lite-server` on port `3000`.
Shut it down manually with `Ctrl-C`.
#### npm scripts
These are the most useful commands defined in `package.json`:
* `npm start` - runs the TypeScript compiler, asset copier, and a server at the same time, all three in "watch mode".
* `npm run build` - runs the TypeScript compiler and asset copier once.
* `npm run build:watch` - runs the TypeScript compiler and asset copier in "watch mode"; when changes occur to source files, they will be recompiled or copied into `dist/`.
* `npm run lint` - runs `tslint` on the project files.
* `npm run serve` - runs `lite-server`.
These are the test-related scripts:
* `npm test` - builds the application and runs Intern tests (both unit and functional) one time.
* `npm run ci` - cleans, lints, and builds the application and runs Intern tests (both unit and functional) one time.
## Techniques
Because Intern seamlessly handles asynchronous testing, there is no reason to use `async`, `fakeAsync`, or `tick` from `@angular/core/testing`. Furthermore, because TypeScript introduced downlevel asynchronous function support in version 2.1, the use of `async` and `await` has been leveraged to write these tests.
### Intern `bdd` interfaces
The first change made to all spec files was to assign the `describe`, `it`, `beforeEach`, and `expect` functions from the Intern plugins:
```ts
const { describe, it, beforeEach } = intern.getPlugin('interface.bdd');
const { expect } = intern.getPlugin('chai');
```
Most of these interfaces behave similarly to jasmine or mocha with a couple of exceptions. First, `before`, `after`, `beforeEach`, `afterEach`, and `it` can all take a function that returns a promise or is defined with `async` and Intern will wait until that promise has resolved before proceeding to the next test/lifecycle function.
**It should be noted** that Intern currently (alpha.9) does not wait for a promise to resolve if there are multiple of the same lifecycle functions in one `describe` block. For instance, this is quite common to see in Angular tests:
```ts
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ DashboardHeroComponent ],
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(DashboardHeroComponent);
comp = fixture.componentInstance;
heroEl = fixture.debugElement.query(By.css('.hero'));
});
```
Using `async` and `await`, this can be easily rewritten into a single function with Intern:
```ts
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ DashboardHeroComponent ],
})
.compileComponents();
fixture = TestBed.createComponent(DashboardHeroComponent);
comp = fixture.componentInstance;
heroEl = fixture.debugElement.query(By.css('.hero'));
});
```
Since Intern comes with Chai bundled, many of the expectations had to be rewritten. Most of these were simply changing `.toBe()` to `.to.equal()` or `toMatch()` to `to.match()`.
Another change was from using jasmine's `spyOn()` to Sinon.JS's `spy()` and `stub()` as well as `sinon-chai` to add expectations for stubs and spies to `expect()`.
### Asynchronous functions
Similar to the lifecycle functions, any invocation of `it` that used Angular's `async()` or `fakeAsync()` was rewritten to use an asynchronous function. For instance:
```ts
it('should show quote after getQuote promise (async)', async(() => {
fixture.detectChanges();
fixture.whenStable().then(() => { // wait for async getQuote
fixture.detectChanges(); // update view with quote
expect(el.textContent).toBe(testQuote);
});
}));
it('should select hero on click', fakeAsync(() => {
const expectedHero = HEROES[1];
const li = page.heroRows[1];
li.dispatchEvent(newEvent('click'));
tick();
// `.toEqual` because selectedHero is clone of expectedHero; see FakeHeroService
expect(comp.selectedHero).toEqual(expectedHero);
}));
```
These can be easily rewritten to the following:
```ts
it('should show quote after getQuote promise', async () => {
fixture.detectChanges();
await fixture.whenStable(); // wait for async getQuote
fixture.detectChanges(); // update view with quote
expect(el.textContent).to.equal(testQuote);
});
it('should select hero on click', async () => {
const expectedHero = HEROES[1];
const li = page.heroRows[1];
li.dispatchEvent(newEvent('click'));
await comp.heroes; // the promise returned from the service
expect(comp.selectedHero).to.deep.equal(expectedHero);
});
```