Skip to content

Commit

Permalink
Merge pull request #1062 from atmire/w2p-77643_fix-trail-not-showing-…
Browse files Browse the repository at this point in the history
…on-item-pages

Fix trail not showing on item pages
  • Loading branch information
tdonohue authored Mar 22, 2021
2 parents a9f553a + 2e7e041 commit a5bc6c1
Show file tree
Hide file tree
Showing 12 changed files with 371 additions and 189 deletions.
80 changes: 47 additions & 33 deletions src/app/app.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import { provideMockStore } from '@ngrx/store/testing';
import { GoogleAnalyticsService } from './statistics/google-analytics.service';
import { ThemeService } from './shared/theme-support/theme.service';
import { getMockThemeService } from './shared/mocks/theme-service.mock';
import { BreadcrumbsService } from './breadcrumbs/breadcrumbs.service';

let comp: AppComponent;
let fixture: ComponentFixture<AppComponent>;
Expand All @@ -45,47 +46,54 @@ const initialState = {

describe('App component', () => {

let breadcrumbsServiceSpy;

function getMockLocaleService(): LocaleService {
return jasmine.createSpyObj('LocaleService', {
setCurrentLanguageCode: jasmine.createSpy('setCurrentLanguageCode')
});
}

const defaultTestBedConf = {
imports: [
CommonModule,
StoreModule.forRoot(authReducer, storeModuleConfig),
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useClass: TranslateLoaderMock
}
}),
],
declarations: [AppComponent], // declare the test component
providers: [
{ provide: NativeWindowService, useValue: new NativeWindowRef() },
{ provide: MetadataService, useValue: new MetadataServiceMock() },
{ provide: Angulartics2GoogleAnalytics, useValue: new AngularticsProviderMock() },
{ provide: Angulartics2DSpace, useValue: new AngularticsProviderMock() },
{ provide: AuthService, useValue: new AuthServiceMock() },
{ provide: Router, useValue: new RouterMock() },
{ provide: ActivatedRoute, useValue: new MockActivatedRoute() },
{ provide: MenuService, useValue: menuService },
{ provide: CSSVariableService, useClass: CSSVariableServiceStub },
{ provide: HostWindowService, useValue: new HostWindowServiceStub(800) },
{ provide: LocaleService, useValue: getMockLocaleService() },
{ provide: ThemeService, useValue: getMockThemeService() },
provideMockStore({ initialState }),
AppComponent,
RouteService
],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
const getDefaultTestBedConf = () => {
breadcrumbsServiceSpy = jasmine.createSpyObj(['listenForRouteChanges']);

return {
imports: [
CommonModule,
StoreModule.forRoot(authReducer, storeModuleConfig),
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useClass: TranslateLoaderMock
}
}),
],
declarations: [AppComponent], // declare the test component
providers: [
{ provide: NativeWindowService, useValue: new NativeWindowRef() },
{ provide: MetadataService, useValue: new MetadataServiceMock() },
{ provide: Angulartics2GoogleAnalytics, useValue: new AngularticsProviderMock() },
{ provide: Angulartics2DSpace, useValue: new AngularticsProviderMock() },
{ provide: AuthService, useValue: new AuthServiceMock() },
{ provide: Router, useValue: new RouterMock() },
{ provide: ActivatedRoute, useValue: new MockActivatedRoute() },
{ provide: MenuService, useValue: menuService },
{ provide: CSSVariableService, useClass: CSSVariableServiceStub },
{ provide: HostWindowService, useValue: new HostWindowServiceStub(800) },
{ provide: LocaleService, useValue: getMockLocaleService() },
{ provide: ThemeService, useValue: getMockThemeService() },
{ provide: BreadcrumbsService, useValue: breadcrumbsServiceSpy },
provideMockStore({ initialState }),
AppComponent,
RouteService
],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
};
};

// waitForAsync beforeEach
beforeEach(waitForAsync(() => {
return TestBed.configureTestingModule(defaultTestBedConf);
return TestBed.configureTestingModule(getDefaultTestBedConf());
}));

// synchronous beforeEach
Expand Down Expand Up @@ -120,13 +128,19 @@ describe('App component', () => {

});

describe('the constructor', () => {
it('should call breadcrumbsService.listenForRouteChanges', () => {
expect(breadcrumbsServiceSpy.listenForRouteChanges).toHaveBeenCalledTimes(1);
});
});

describe('when GoogleAnalyticsService is provided', () => {
let googleAnalyticsSpy;

beforeEach(() => {
// NOTE: Cannot override providers once components have been compiled, so TestBed needs to be reset
TestBed.resetTestingModule();
TestBed.configureTestingModule(defaultTestBedConf);
TestBed.configureTestingModule(getDefaultTestBedConf());
googleAnalyticsSpy = jasmine.createSpyObj('googleAnalyticsService', [
'addTrackingIdToPage',
]);
Expand Down Expand Up @@ -154,7 +168,7 @@ describe('App component', () => {
beforeEach(() => {
// NOTE: Cannot override providers once components have been compiled, so TestBed needs to be reset
TestBed.resetTestingModule();
TestBed.configureTestingModule(defaultTestBedConf);
TestBed.configureTestingModule(getDefaultTestBedConf());
TestBed.overrideProvider(ThemeService, {useValue: getMockThemeService('custom')});
document = TestBed.inject(DOCUMENT);
headSpy = jasmine.createSpyObj('head', ['appendChild']);
Expand Down
3 changes: 3 additions & 0 deletions src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import { DOCUMENT } from '@angular/common';
import { ThemeService } from './shared/theme-support/theme.service';
import { BASE_THEME_NAME } from './shared/theme-support/theme.constants';
import { DEFAULT_THEME_CONFIG } from './shared/theme-support/theme.effects';
import { BreadcrumbsService } from './breadcrumbs/breadcrumbs.service';

@Component({
selector: 'ds-app',
Expand Down Expand Up @@ -73,6 +74,7 @@ export class AppComponent implements OnInit, AfterViewInit {
private menuService: MenuService,
private windowService: HostWindowService,
private localeService: LocaleService,
private breadcrumbsService: BreadcrumbsService,
@Optional() private cookiesService: KlaroService,
@Optional() private googleAnalyticsService: GoogleAnalyticsService,
) {
Expand Down Expand Up @@ -106,6 +108,7 @@ export class AppComponent implements OnInit, AfterViewInit {
angulartics2DSpace.startTracking();

metadata.listenForRouteChange();
breadcrumbsService.listenForRouteChanges();

if (environment.debug) {
console.info(environment);
Expand Down
4 changes: 2 additions & 2 deletions src/app/breadcrumbs/breadcrumb/breadcrumb-config.model.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { BreadcrumbsService } from '../../core/breadcrumbs/breadcrumbs.service';
import { BreadcrumbsProviderService } from '../../core/breadcrumbs/breadcrumbsProviderService';

/**
* Interface for breadcrumb configuration objects
Expand All @@ -7,7 +7,7 @@ export interface BreadcrumbConfig<T> {
/**
* The service used to calculate the breadcrumb object
*/
provider: BreadcrumbsService<T>;
provider: BreadcrumbsProviderService<T>;

/**
* The key that is used to calculate the breadcrumb display value
Expand Down
2 changes: 1 addition & 1 deletion src/app/breadcrumbs/breadcrumbs.component.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<ng-container *ngVar="(breadcrumbs$ | async) as breadcrumbs">
<nav *ngIf="showBreadcrumbs" aria-label="breadcrumb">
<nav *ngIf="(showBreadcrumbs$ | async)" aria-label="breadcrumb">
<ol class="breadcrumb">
<ng-container
*ngTemplateOutlet="breadcrumbs?.length > 0 ? breadcrumb : activeBreadcrumb; context: {text: 'home.breadcrumbs', url: '/'}"></ng-container>
Expand Down
139 changes: 51 additions & 88 deletions src/app/breadcrumbs/breadcrumbs.component.spec.ts
Original file line number Diff line number Diff line change
@@ -1,115 +1,78 @@
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';

import { BreadcrumbsComponent } from './breadcrumbs.component';
import { ActivatedRoute, NavigationEnd, Router } from '@angular/router';
import { Observable, of as observableOf } from 'rxjs';
import { RouterTestingModule } from '@angular/router/testing';
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
import { TranslateLoaderMock } from '../shared/testing/translate-loader.mock';
import { BreadcrumbConfig } from './breadcrumb/breadcrumb-config.model';
import { BreadcrumbsService } from '../core/breadcrumbs/breadcrumbs.service';
import { BreadcrumbsService } from './breadcrumbs.service';
import { Breadcrumb } from './breadcrumb/breadcrumb.model';
import { NO_ERRORS_SCHEMA } from '@angular/core';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { VarDirective } from '../shared/utils/var.directive';
import { getTestScheduler } from 'jasmine-marbles';

class TestBreadcrumbsService implements BreadcrumbsService<string> {
getBreadcrumbs(key: string, url: string): Observable<Breadcrumb[]> {
return observableOf([new Breadcrumb(key, url)]);
}
}
import { By } from '@angular/platform-browser';
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
import { TranslateLoaderMock } from '../shared/testing/translate-loader.mock';
import { RouterTestingModule } from '@angular/router/testing';
import { of as observableOf } from 'rxjs/internal/observable/of';
import { DebugElement } from '@angular/core';

describe('BreadcrumbsComponent', () => {
let component: BreadcrumbsComponent;
let fixture: ComponentFixture<BreadcrumbsComponent>;
let router: any;
let route: any;
let breadcrumbProvider;
let breadcrumbConfigA: BreadcrumbConfig<string>;
let breadcrumbConfigB: BreadcrumbConfig<string>;
let expectedBreadcrumbs;

function init() {
breadcrumbProvider = new TestBreadcrumbsService();
let breadcrumbsServiceMock: BreadcrumbsService;

breadcrumbConfigA = { provider: breadcrumbProvider, key: 'example.path', url: 'example.com' };
breadcrumbConfigB = { provider: breadcrumbProvider, key: 'another.path', url: 'another.com' };

route = {
root: {
snapshot: {
data: { breadcrumb: breadcrumbConfigA },
routeConfig: { resolve: { breadcrumb: {} } }
},
firstChild: {
snapshot: {
// Example without resolver should be ignored
data: { breadcrumb: breadcrumbConfigA },
},
firstChild: {
snapshot: {
data: { breadcrumb: breadcrumbConfigB },
routeConfig: { resolve: { breadcrumb: {} } }
}
}
}
}
};
const expectBreadcrumb = (listItem: DebugElement, text: string, url: string) => {
const anchor = listItem.query(By.css('a'));

expectedBreadcrumbs = [
new Breadcrumb(breadcrumbConfigA.key, breadcrumbConfigA.url),
new Breadcrumb(breadcrumbConfigB.key, breadcrumbConfigB.url)
];

}
if (url == null) {
expect(anchor).toBeNull();
expect(listItem.nativeElement.innerHTML).toEqual(text);
} else {
expect(anchor).toBeInstanceOf(DebugElement);
expect(anchor.attributes.href).toEqual(url);
expect(anchor.nativeElement.innerHTML).toEqual(text);
}
};

beforeEach(waitForAsync(() => {
init();
breadcrumbsServiceMock = {
breadcrumbs$: observableOf([
// NOTE: a root breadcrumb is automatically rendered
new Breadcrumb('bc 1', 'example.com'),
new Breadcrumb('bc 2', 'another.com'),
]),
showBreadcrumbs$: observableOf(true),
} as BreadcrumbsService;

TestBed.configureTestingModule({
declarations: [BreadcrumbsComponent, VarDirective],
imports: [RouterTestingModule.withRoutes([]), TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useClass: TranslateLoaderMock
}
}), NgbModule],
declarations: [
BreadcrumbsComponent,
VarDirective,
],
imports: [
RouterTestingModule.withRoutes([]),
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useClass: TranslateLoaderMock,
}
}),
],
providers: [
{provide: ActivatedRoute, useValue: route}
], schemas: [NO_ERRORS_SCHEMA]
})
.compileComponents();
}));
{ provide: BreadcrumbsService, useValue: breadcrumbsServiceMock },
],
}).compileComponents();

beforeEach(() => {
fixture = TestBed.createComponent(BreadcrumbsComponent);
component = fixture.componentInstance;
router = TestBed.inject(Router);
fixture.detectChanges();
});
}));

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

describe('ngOnInit', () => {
beforeEach(() => {
spyOn(component, 'resolveBreadcrumbs').and.returnValue(observableOf([]));
});

it('should call resolveBreadcrumb on init', () => {
router.events = observableOf(new NavigationEnd(0, '', ''));
component.ngOnInit();
fixture.detectChanges();

expect(component.resolveBreadcrumbs).toHaveBeenCalledWith(route.root);
});
it('should render the breadcrumbs', () => {
const breadcrumbs = fixture.debugElement.queryAll(By.css('.breadcrumb-item'));
expect(breadcrumbs.length).toBe(3);
expectBreadcrumb(breadcrumbs[0], 'home.breadcrumbs', '/');
expectBreadcrumb(breadcrumbs[1], 'bc 1', '/example.com');
expectBreadcrumb(breadcrumbs[2], 'bc 2', null);
});

describe('resolveBreadcrumbs', () => {
it('should return the correct breadcrumbs', () => {
const breadcrumbs = component.resolveBreadcrumbs(route.root);
getTestScheduler().expectObservable(breadcrumbs).toBe('(a|)', { a: expectedBreadcrumbs });
});
});
});
Loading

0 comments on commit a5bc6c1

Please sign in to comment.