Skip to content

Instantly share code, notes, and snippets.

@ratbeard
Created February 9, 2018 16:15
Show Gist options
  • Select an option

  • Save ratbeard/4dc5bd675b25e0540df74aa49ec44c4b to your computer and use it in GitHub Desktop.

Select an option

Save ratbeard/4dc5bd675b25e0540df74aa49ec44c4b to your computer and use it in GitHub Desktop.
import { SearchInputModule } from './../search-input/search-input.module';
import { GetRecordsServiceMock } from './../get-records.service.mock';
import { AppConfigServiceMock } from './../app-config-service/app-config-service.mock';
import { AppConfigService } from './../app-config-service/app-config.service';
import { MaterialModule } from '@angular/material';
import { SorterComponent } from './../sorter/sorter.component';
import { ScormDisclaimerComponent } from './../scorm-disclaimer/scorm-disclaimer.component';
import { GetRecordsService } from './../get-records.service';
import { FilterBySystemComponent } from './../filter-by-system/filter-by-system.component';
import { LearningContentTableComponent } from './../learning-content-table/learning-content-table.component';
import { TitleBarComponent } from './../title-bar/title-bar.component';
import { PaginatorComponent } from './../paginator/paginator.component';
import { MainNavigationComponent } from './../main-navigation/main-navigation.component';
/* tslint:disable:no-unused-variable */
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { DebugElement } from '@angular/core';
import { LocalforageService } from './../local-forage/local-forage.service';
import { LearningPlanComponent } from './learning-plan.component';
describe('LearningPlanComponent', () => {
let component: LearningPlanComponent;
let fixture: ComponentFixture<LearningPlanComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [ MaterialModule, SearchInputModule ],
declarations: [
LearningPlanComponent,
MainNavigationComponent,
PaginatorComponent,
TitleBarComponent,
LearningContentTableComponent,
FilterBySystemComponent,
ScormDisclaimerComponent,
SorterComponent],
providers: [
{ provide: AppConfigService, useClass: AppConfigServiceMock },
{ provide: GetRecordsService, useClass: GetRecordsServiceMock },
{ provide: LocalforageService, useClass: LocalforageService },
]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(LearningPlanComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
@justinmchase
Copy link

justinmchase commented Feb 9, 2018

You could probably pull a ton of that out and just put it in a different module and then reduce it to:

import { TestConfiguration } from './test/configuration';
import { LearningPlanComponent } from './learning-plan.component';

describe('LearningPlanComponent', () => {
  let component: LearningPlanComponent;
  let fixture: ComponentFixture<LearningPlanComponent>;

  beforeEach(async(() => {
    TestBed.configureTestingModule(TestConfiguration).compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(LearningPlanComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

  it('should create', () => {
    expect(component).toBeTruthy();
  });
});

@justinmchase
Copy link

justinmchase commented Feb 9, 2018

Here's one of ours for comparison:

import { BrowserModule, By } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { FlexLayoutModule } from '@angular/flex-layout';
import { HttpClientModule } from '@angular/common/http';
import { NgModule, CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA, DebugElement } from '@angular/core';
import { TestBed, async, ComponentFixture, ComponentFixtureAutoDetect, tick } from '@angular/core/testing';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/of';

import { AppComponent } from './app.component';
import { MaterialModule } from './material.module';
import { AnalyticsService, ListService, TrackingService, WindowRef } from './services';
import { IItem, IResponse, Client } from './models';

import * as URI from 'urijs';
import { } from 'jasmine';
import 'jest-preset-angular';

const AUTH = require('../assets/data/auth.json');
const TRACKERS = require('../assets/data/trackers.json');
const EMPTY_TRACKERS = require('../assets/data/empty_trackers.json');
const ANALYTICS = require('../assets/data/analytics.json');
const RESPONSE = require('../assets/data/response.json');
const URL = 'http://manage.myalerts.com/acme/fakeauthkey/somepath/?utm_campaign=test&utm_medium=email&utm_source=price_drop';

describe('AppComponent', () => {
    let fixture: ComponentFixture<AppComponent>;
    let de: DebugElement;
    let comp: AppComponent;
    let el: HTMLElement;
    let trackingService: TrackingService;
    let authSpy: any;
    let getTrackersSpy: any;
    let analyticsService: AnalyticsService;
    let recordEventSpy: any;

    // Asynchronous, so external component templates load
    beforeEach(async(() => {
        // Create an Angular testing module
        TestBed.configureTestingModule({
            declarations: [
                AppComponent // declare the test component
            ],
            imports: [
                BrowserModule,
                MaterialModule,
                FlexLayoutModule,
                BrowserAnimationsModule,
                HttpClientModule
            ],
            providers: [
                AnalyticsService,
                ListService,
                TrackingService,
                WindowRef,
                { provide: ComponentFixtureAutoDetect, useValue: true }
            ]
        }).compileComponents(); // compile template and css
    }));

    // Synchronous. Waits for async to complete first.
    beforeEach(() => {
        fixture = TestBed.createComponent(AppComponent); // Gain access to Testbed features
        de = fixture.debugElement; // test helper
        comp = de.componentInstance; // access properties and methods
        el = de.nativeElement; // access DOM

        // Get injected services for spies
        trackingService = de.injector.get(TrackingService);
        analyticsService = de.injector.get(AnalyticsService);

        // Setup spies
        authSpy = jest.spyOn(trackingService, 'auth');
        getTrackersSpy = jest.spyOn(trackingService, 'getTrackers');
        recordEventSpy = jest.spyOn(analyticsService, 'recordEvent');

        // Mock response data for every test
        authSpy.mockReturnValue(Observable.of(AUTH));
        recordEventSpy.mockReturnValue(Observable.of(ANALYTICS));

        // Mock url
        comp.uri = new URI(URL);
    });

    afterEach(() => {
        jest.resetAllMocks();
        jest.restoreAllMocks();
    });

    function init() {
        comp.ngOnInit();
        fixture.detectChanges();
    }

    it(`should create the app`, () => {
        expect(comp).toBeTruthy();
    });

    describe('Static', () => {
        it(`should render page title`, () => {
            expect(comp.title).toEqual('Manage Alerts');
        });

        it(`should render subtitle `, () => {
            expect(el.querySelector('header .subtitle').textContent).toBe('Manage Alerts');
        });

        it(`should render copyright in footer`, () => {
            expect(el.querySelector('mat-toolbar p').textContent).toBe('© 2017 MyAlerts LLC. All rights reserved.');
        });
    });

    describe('Theme', () => {

        it(`should set correct theme if theme not set in url`, () => {
            getTrackersSpy.mockReturnValue(Observable.of(TRACKERS));
            init();
            expect(comp.theme).toBe('theme-light');
        });

        it(`should set correct theme if theme set incorrectly`, () => {
            getTrackersSpy.mockReturnValue(Observable.of(TRACKERS));
            comp.uri = new URI('http://manage.myalerts.com/?theme=random');
            init();
            expect(comp.theme).toBe('theme-light');
        });

        it(`should set correct theme if 'theme=light'`, () => {
            getTrackersSpy.mockReturnValue(Observable.of(TRACKERS));
            comp.uri = new URI('http://manage.myalerts.com/?theme=light');
            init();
            expect(comp.theme).toBe('theme-light');
        });

        it(`should correct theme if 'theme=dark'`, () => {
            getTrackersSpy.mockReturnValue(Observable.of(TRACKERS));
            comp.uri = new URI('http://manage.myalerts.com/?theme=dark');
            init();
            expect(comp.theme).toBe('theme-dark');
        });

    });

    describe('Auth', () => {
        it(`should read an auth key from the 2nd url path segment`, () => {
            getTrackersSpy.mockReturnValue(Observable.of(TRACKERS));
            init();
            expect(comp.authKey).toBe('fakeauthkey');
        });

        it(`should not read an auth key from the 1st url path segment`, () => {
            comp.uri = new URI('http://manage.myalerts.com/fakeauthkey/');
            init();
            expect(comp.authKey).not.toBe('fakeauthkey');
        });

        it(`should set the client name from auth data`, () => {
            getTrackersSpy.mockReturnValue(Observable.of(TRACKERS));
            init();
            expect(el.querySelector('h1.title').textContent).toBe('Acme');
        });

        it(`should set logo src from auth data`, () => {
            getTrackersSpy.mockReturnValue(Observable.of(TRACKERS));
            init();
            expect(el.querySelector('.logo img').attributes.getNamedItem('src').value).toBe('https://logo.clearbit.com/myalerts.com');
        });

        it(`should not display logo if client domain missing from auth data`, () => {
            AUTH.data.client_website_url = null;
            authSpy.mockReturnValue(Observable.of(AUTH));
            getTrackersSpy.mockReturnValue(Observable.of(TRACKERS));
            init();
            expect(el.querySelector('.logo')).toBe(null);
        });
    });

    describe('Message', () => {
        it(`should render default message`, () => {
            expect(el.querySelector('article.message h2').textContent).toBe('Sorry, there was an error processing your request.');
        });

        it(`should show message if user has no trackers`, () => {
            getTrackersSpy.mockReturnValue(Observable.of(EMPTY_TRACKERS));
            init();
            expect(el.querySelector('article.message h2').textContent).toBe('You currently have no alerts to manage.');
        });

        it(`should not show message if user has trackers`, () => {
            getTrackersSpy.mockReturnValue(Observable.of(TRACKERS));
            init();
            expect(el.querySelector('article.message h2')).toBeNull();
        });
    });

    describe('Cards', () => {
        it(`should not show cards if user has no trackers`, () => {
            getTrackersSpy.mockReturnValue(Observable.of(EMPTY_TRACKERS));
            init();
            expect(el.querySelector('mat-card')).toBeNull();
        });

        it(`should show cards if user has trackers`, () => {
            getTrackersSpy.mockReturnValue(Observable.of(TRACKERS));
            init();
            expect(el.querySelectorAll('mat-card')).not.toBeNull();
        });

        it(`should show the same number of cards as trackers`, () => {
            getTrackersSpy.mockReturnValue(Observable.of(TRACKERS));
            init();
            expect(el.querySelectorAll('mat-card').length).toBe(TRACKERS.trackers.length);
        });

        it(`should display correct titles on cards`, () => {
            getTrackersSpy.mockReturnValue(Observable.of(TRACKERS));
            init();
            de.queryAll(By.css('mat-card-title')).forEach((item, i) => {
                expect(item.nativeElement.textContent.trim()).toBe(TRACKERS.trackers[i].item.current_record.title);
            });
        });
    });

    describe('Card Actions', () => {
        it(`should go to url if card image clicked`, () => {
            const spy = jest.spyOn(comp, 'goTo');
            getTrackersSpy.mockReturnValue(Observable.of(TRACKERS));
            init();
            de.queryAll(By.css('mat-card-content img')).forEach((element) => {
                element.triggerEventHandler('click', null);
            });
            fixture.detectChanges();
            expect(spy).toHaveBeenCalledTimes(TRACKERS.trackers.length);
        });

        it(`should go to url if jump icon clicked`, () => {
            const spy = jest.spyOn(comp, 'goTo');
            getTrackersSpy.mockReturnValue(Observable.of(TRACKERS));
            init();
            de.queryAll(By.css('.mat-icon-button')).forEach((element) => {
                element.triggerEventHandler('click', null);
            });
            fixture.detectChanges();
            expect(spy).toHaveBeenCalledTimes(TRACKERS.trackers.length);
        });

        it(`should unsubscribe if toggled OFF`, () => {
            const spy = jest.spyOn(trackingService, 'removeItem').mockReturnValue(Observable.of(RESPONSE));
            getTrackersSpy.mockReturnValue(Observable.of(TRACKERS));
            init();
            de.queryAll(By.css('.mat-slide-toggle')).forEach((element, i) => {
                const item = de.injector.get(ListService).marshalItem(TRACKERS.trackers[i]);
                const e = {
                    checked: false,
                    item: item
                };
                element.triggerEventHandler('change', e);
            });
            fixture.detectChanges();
            expect(spy).toHaveBeenCalledTimes(3);
        });

        it(`should subscribe if toggled ON`, () => {
            const spy = jest.spyOn(trackingService, 'createItem').mockReturnValue(Observable.of(RESPONSE));
            getTrackersSpy.mockReturnValue(Observable.of(TRACKERS));
            init();
            de.queryAll(By.css('.mat-slide-toggle')).forEach((element, i) => {
                const item = de.injector.get(ListService).marshalItem(TRACKERS.trackers[i]);
                const e = {
                    checked: true,
                    item: item
                };
                element.triggerEventHandler('change', e);
            });
            fixture.detectChanges();
            expect(spy).toHaveBeenCalledTimes(3);
        });
    });

});

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment