Skip to content

Commit

Permalink
Add more testing!
Browse files Browse the repository at this point in the history
  • Loading branch information
clarkmalmgren committed Aug 15, 2017
1 parent 0b864eb commit 1786962
Show file tree
Hide file tree
Showing 15 changed files with 255 additions and 57 deletions.
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "bolingbrook-church",
"version": "1.2.7",
"version": "1.2.8",
"license": "MIT",
"angular-cli": {},
"scripts": {
Expand Down
4 changes: 1 addition & 3 deletions src/app/components/organisms/index.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import { FooterComponent } from './footer';
import { HeaderComponent } from './header';
import { SermonListComponent } from './sermon-list';
import { UStreamComponent } from './ustream';

export const ORGANISMS = [
FooterComponent,
HeaderComponent,
SermonListComponent,
UStreamComponent
SermonListComponent
];
5 changes: 0 additions & 5 deletions src/app/components/organisms/ustream.html

This file was deleted.

6 changes: 0 additions & 6 deletions src/app/components/organisms/ustream.scss

This file was deleted.

9 changes: 0 additions & 9 deletions src/app/components/organisms/ustream.ts

This file was deleted.

4 changes: 2 additions & 2 deletions src/app/components/pages/giving.scss
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ div.giving-list {
text-decoration: none;
margin: 25px;

min-width: 130px;
max-width: 130px;
min-width: 150px;
max-width: 150px;

button {
background-color: white;
Expand Down
4 changes: 1 addition & 3 deletions src/app/components/pages/sermons/sermon.html
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<bc-header></bc-header>
<main>
<section class="video">
<iframe *ngIf="showYoutube"
<iframe *ngIf="youtube_url"
id="sermonVideo"
[src]="youtube_url"
frameborder="0"
Expand All @@ -10,8 +10,6 @@
allowfullscreen="">
</iframe>

<bc-ustream *ngIf="showUstream"></bc-ustream>

<div class="data" *ngIf="sermon">
<div *ngIf="sermon.image" class="icon" [style.background-image]="icon"></div>
<div class="text">
Expand Down
132 changes: 132 additions & 0 deletions src/app/components/pages/sermons/sermon.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
import { expect, sinon, async, MockBuilder, callCount } from 'testing';
import { ActivatedRoute } from '@angular/router';
import { SermonComponent } from './sermon';
import {
Analytics,
FeatureToggles,
Observable,
SeriesImageService,
Sermon,
SermonService,
VideoState,
YoutubeService
} from 'app/services';

describe('SermonComponent', () => {

describe('ngOnInit', () => {

it('should subscribe to video state changes', async(() => {
const youtubeService = MockBuilder.of(YoutubeService)
.withStub('videoState', Observable.of(VideoState.BUFFERING))
.build();

const activatedRoute = MockBuilder.of(ActivatedRoute)
.with('params', Observable.empty())
.build();

const sermon = new SermonComponent(activatedRoute, null, null, null, null, null, youtubeService);

sermon.ngOnInit();

expect(youtubeService.videoState).to.have.been.calledOnce.and.calledWith('sermonVideo');
expect(sermon.videoState).to.equal(VideoState.BUFFERING);

sermon.ngOnDestroy();
}));

it('should register analytics events on an appropriate cadence', async(() => {
const youtubeService = MockBuilder.of(YoutubeService)
.withStub('videoState', Observable.empty())
.build();

const activatedRoute = MockBuilder.of(ActivatedRoute)
.with('params', Observable.empty())
.build();

const analytics = MockBuilder.of(Analytics)
.withSpy('event')
.build();

const sermon = new SermonComponent(activatedRoute, analytics, null, null, null, null, youtubeService);
sermon.analyticsInterval = 5;
sermon.videoState = VideoState.PLAYING;
sermon.sermon = { youtube: 'Jesus4Life' } as Sermon;

sermon.ngOnInit();

window.setTimeout(() => {
/* Giving a reasonable range to account for annoying time based testing */
expect(callCount(analytics.event)).to.be.at.least(2).and.at.most(6);
expect(analytics.event).to.have.been.calledWith('Sermon', 'Playing', 'Jesus4Life');
sermon.ngOnDestroy();
}, 25);
}));

it('should register live analytics events as appropriate', async(() => {
const youtubeService = MockBuilder.of(YoutubeService)
.withStub('videoState', Observable.empty())
.build();

const activatedRoute = MockBuilder.of(ActivatedRoute)
.with('params', Observable.empty())
.build();

const analytics = MockBuilder.of(Analytics)
.withSpy('event')
.build();

const sermon = new SermonComponent(activatedRoute, analytics, null, null, null, null, youtubeService);
sermon.analyticsInterval = 5;
sermon.videoState = VideoState.PLAYING;
sermon.live = true;
sermon.sermon = { youtube: 'Jesus4Life' } as Sermon;

sermon.ngOnInit();

window.setTimeout(() => {
expect(analytics.event).to.have.been.calledWith('Live Sermon', 'Playing', 'Jesus4Life');
sermon.ngOnDestroy();
}, 25);
}));

[
VideoState.BUFFERING,
VideoState.CUED,
VideoState.ENDED,
VideoState.PAUSED,
VideoState.UNSTARTED
].forEach(state => {
it(`should not call analytics when video state is "${state}"`, async(() => {
const youtubeService = MockBuilder.of(YoutubeService)
.withStub('videoState', Observable.empty())
.build();

const activatedRoute = MockBuilder.of(ActivatedRoute)
.with('params', Observable.empty())
.build();

const analytics = MockBuilder.of(Analytics)
.withSpy('event')
.build();

const sermon = new SermonComponent(activatedRoute, analytics, null, null, null, null, youtubeService);
sermon.analyticsInterval = 5;
sermon.videoState = state;
sermon.sermon = { youtube: 'Jesus4Life' } as Sermon;

sermon.ngOnInit();

window.setTimeout(() => {
expect(analytics.event).to.not.have.been.called;
sermon.ngOnDestroy();
}, 25);
}));
});




});

});
26 changes: 2 additions & 24 deletions src/app/components/pages/sermons/sermon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import {
SeriesImageService,
Sermon,
SermonService,
TogglesService,
VideoState,
YoutubeService
} from '../../../services';
Expand All @@ -27,13 +26,12 @@ export class SermonComponent extends Autoclean implements OnInit {
youtube_url: SafeResourceUrl;
icon: SafeStyle;

youtube_live: boolean = false;
videoState: VideoState = VideoState.UNSTARTED;
analyticsInterval: number = 60000;

constructor(
private activatedRoute: ActivatedRoute,
private analytics: Analytics,
private featureToggles: TogglesService,
private imageService: SeriesImageService,
private meta: Meta,
private sanitizer: DomSanitizer,
Expand All @@ -43,27 +41,7 @@ export class SermonComponent extends Autoclean implements OnInit {
super();
}

get showYoutube() {
if (this.live) {
return this.youtube_live;
} else {
return this.sermon && this.youtube_url;
}
}

get showUstream(): boolean {
return this.live && !this.youtube_live;
}

ngOnInit() {
/* Subscribe to Toggles */
this.autoclean(
this.featureToggles
.getToggles()
.subscribe((toggles) => {
this.youtube_live = toggles.youtube_live;
}));

/* Subscribe to Video State Change Events */
this.autoclean(
this.youtubeService
Expand All @@ -74,7 +52,7 @@ export class SermonComponent extends Autoclean implements OnInit {

/* Record Analytics when Playing */
this.autoclean(
Observable.interval(60000)
Observable.interval(this.analyticsInterval)
.subscribe(() => {
if (this.videoState === VideoState.PLAYING) {
this.analytics.event(this.live ? 'Live Sermon' : 'Sermon', 'Playing', this.sermon.youtube);
Expand Down
22 changes: 22 additions & 0 deletions src/app/components/templates/autoclean.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { expect, sinon, async, MockBuilder, Loop } from 'testing';
import { Autoclean } from './autoclean';
import { Subscription } from 'app/services';

class TestableAutoclean extends Autoclean {}

describe('Autoclean', () => {

it('should clean up registered subscriptions', () => {
const ac = new TestableAutoclean();
const subscription = MockBuilder.of(Subscription)
.withSpy('unsubscribe')
.build();

Loop.times(10).do(() => ac.autoclean(subscription));

ac.ngOnDestroy();

expect(subscription.unsubscribe).to.have.callCount(10);
});

});
2 changes: 1 addition & 1 deletion src/app/components/templates/autoclean.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { OnDestroy } from '@angular/core';
import { Subscription } from '../../services';
import { Subscription } from 'app/services';

export abstract class Autoclean implements OnDestroy {

Expand Down
71 changes: 71 additions & 0 deletions src/app/components/templates/service-group.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { expect, sinon, async, MockBuilder } from 'testing';
import { Router } from '@angular/router';
import { ServiceGroup } from './service-group';
import {
Analytics,
ConnectionRequest,
ConnectionService,
Observable
} from '../../services';

class TestableServiceGroup extends ServiceGroup {}

describe('ServiceGroup', () => {

describe('constructor', () => {
it('should work', () => {
const sg = new TestableServiceGroup(
undefined,
undefined,
undefined,
'hero',
'title',
'sub',
[ 'it does this', 'and this' ],
{
a: { name : 'Eh', description: 'Aye' },
b: { name: 'Bee', description: 'Honey' }
}
);

expect(sg).to.exist;
expect(sg.typeKeys).to.have.lengthOf(2);
expect(sg.typesArray).to.have.lengthOf(2);
});
});

describe('submit', () => {
it('should submit exactly once', async(() => {
const service = MockBuilder.of(ConnectionService)
.withStub('submit', Observable.of(''))
.build();

const analytics = MockBuilder.of(Analytics)
.withStub('event', Observable.of(''))
.build();

const router = MockBuilder.of(Router)
.withSpy('navigate')
.build();

const sg = new TestableServiceGroup(
service,
router,
analytics,
undefined,
undefined,
undefined,
undefined,
{}
);

sg.submit()
.subscribe(() => {
expect(service.submit).to.have.been.calledOnce;
expect(analytics.event).to.have.been.calledOnce;
expect(router.navigate).to.have.been.calledOnce.and.be.calledWith([ '/thank-you' ]);
});
}));
});

});
3 changes: 2 additions & 1 deletion src/app/components/templates/service-group.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ export abstract class ServiceGroup {
this.request.interests = Object.keys(this.interests).map(i => this.types[i].name);
const o = this.service.submit(this.request)
.flatMap(() => { return this.analytics.event('form', 'submit', this.title); })
.catch((err) => { return this.analytics.exception(err); });
.catch((err) => { return this.analytics.exception(err); })
.shareReplay();

o.subscribe(() => {
this.router.navigate([ '/thank-you' ]);
Expand Down

0 comments on commit 1786962

Please sign in to comment.