vendredi 2 septembre 2016

Angular2 RC5 TestBed - Use Location parameter injected into constructor

I am converting my Angular2 unit tests to the new syntax after upgrading to RC5. I have a test that uses a value (Location) that is injected into the constructor of the component under test, and I cannot figure out how to do this with the new TestBed class.

The component under test

export class RSUAppComponent implements AfterViewInit {
    constructor(private _location: Location, private _appSettingsService: AppSettingsService) {
        _appSettingsService.DeleteAppSettings();
    }

    // To maintain proper nav item highlighting
    public IndicateSelected(linkRoute: string) {
        let path = this._location.path().toLowerCase();
        if (path.length == 0 && linkRoute.toLowerCase() == 'dashboard') {
            return "mdl-navigation__link mdl-navigation__link--current";
        } else {
            if (this._location.path().toLowerCase().includes(linkRoute.toLowerCase())) {
                return "mdl-navigation__link mdl-navigation__link--current";
            } else {
                return "mdl-navigation__link";
            }
        }
    }
}

The test that worked pre-RC5

let testAppComponent: RSUAppComponent;

beforeEach(() => {
    addProviders([
        AppSettingsService,
        // injected into the constructor of RSUViewer
        provide(Location, { useClass: SpyLocation })])
});

it('#IndicateSelected should return the selected styling for the selected menu item',
    async(inject([TestComponentBuilder, Location], (tcb: TestComponentBuilder, testLocation: SpyLocation) => {
        return tcb
            .overrideTemplate(RSUAppComponent, `
                    <nav class="mdl-navigation">                           
                    </nav>
            `)
            .overrideDirective(RSUAppComponent, RSUHomeComponent, EmptyComponent)
            .overrideDirective(RSUAppComponent, RSUNotiesComponent, EmptyComponent)
            .createAsync(RSUAppComponent)
            .then((fixture: ComponentFixture<RSUAppComponent>) => {
                let selectedOutput: string;
                fixture.detectChanges();
                testAppComponent = fixture.componentInstance;

                // initial navigation by app - user has not selected any menu link
                selectedOutput = testAppComponent.IndicateSelected('Dashboard');
                expect(selectedOutput).toMatch('mdl-navigation__link--current');
                selectedOutput = testAppComponent.IndicateSelected('Noties');
                expect(selectedOutput).not.toMatch('mdl-navigation__link--current');
                selectedOutput = testAppComponent.IndicateSelected('Users');
                expect(selectedOutput).not.toMatch('mdl-navigation__link--current');

                // user has selected the Users link
                testLocation.go('/users');
                selectedOutput = testAppComponent.IndicateSelected('Dashboard');
                expect(selectedOutput).not.toMatch('mdl-navigation__link--current');
                selectedOutput = testAppComponent.IndicateSelected('Noties');
                expect(selectedOutput).not.toMatch('mdl-navigation__link--current');
                selectedOutput = testAppComponent.IndicateSelected('Users');
                expect(selectedOutput).toMatch('mdl-navigation__link--current');
            });
    }))
);

This is how I've attempted to rewrite the test. The issue is that I don't know how to get the test to use the testLocation parameter so that it can switch the location. In pre-RC5 it was injected into the test along with the TestComponentBuilder, but now we are not injecting our test component into the test.

let testAppComponent: RSUAppComponent;
let testLocation: SpyLocation;

beforeEach(() => {
    TestBed.configureTestingModule({
        declarations: [RSUAppComponent],
        providers: [
            AppSettingsService,
            // injected into the constructor of RSUViewer
            {provide: Location,  useClass: SpyLocation }
        ]
    })
});

it('#IndicateSelected should return the selected styling for the selected menu item',
    async(() => {
        TestBed.overrideComponent(RSUAppComponent, {
            set: {
                template: `
                    <nav class="mdl-navigation">                           
                    </nav>
            `

            }
        })
            .overrideDirective(RSUHomeComponent, EmptyComponent)
            .overrideDirective(RSUNotiesComponent, EmptyComponent);

        TestBed.compileComponents().then(() => {
            const fixture = TestBed.createComponent(RSUAppComponent);
            let selectedOutput: string;
            fixture.detectChanges();
            testAppComponent = fixture.componentInstance;

            // initial navigation by app - user has not selected any menu link
            selectedOutput = testAppComponent.IndicateSelected('Dashboard');
            expect(selectedOutput).toMatch('mdl-navigation__link--current');
            selectedOutput = testAppComponent.IndicateSelected('Noties');
            expect(selectedOutput).not.toMatch('mdl-navigation__link--current');
            selectedOutput = testAppComponent.IndicateSelected('Users');
            expect(selectedOutput).not.toMatch('mdl-navigation__link--current');

            // user has selected the Users link
            testLocation.go('/users');
            selectedOutput = testAppComponent.IndicateSelected('Dashboard');
            expect(selectedOutput).not.toMatch('mdl-navigation__link--current');
            selectedOutput = testAppComponent.IndicateSelected('Noties');
            expect(selectedOutput).not.toMatch('mdl-navigation__link--current');
            selectedOutput = testAppComponent.IndicateSelected('Users');
            expect(selectedOutput).toMatch('mdl-navigation__link--current');
        });


    }));

Aucun commentaire:

Enregistrer un commentaire