ohayolibs
Version:
Ohayo is a set of essential modules for ohayojp.
464 lines (431 loc) • 15 kB
text/typescript
import { APP_BASE_HREF } from '@angular/common';
import { Component, DebugElement, ViewChild } from '@angular/core';
import { ComponentFixture, fakeAsync, flush, TestBed, tick } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { Router } from '@angular/router';
import { RouterTestingModule } from '@angular/router/testing';
import { createTestContext } from '@ohayo/testing';
import { OhayoI18NService, OhayoI18NServiceFake, OHAYO_I18N_TOKEN, MenuService, SettingsService, TitleService } from '@ohayo/theme';
import { NzAffixComponent } from 'ng-zorro-antd/affix';
import { ReuseTabService } from '../reuse-tab/reuse-tab.service';
import { PageHeaderComponent } from './page-header.component';
import { PageHeaderModule } from './page-header.module';
class MockI18NServiceFake extends OhayoI18NServiceFake {
fanyi(key: string): string {
return key;
}
}
describe('components: page-header', () => {
let fixture: ComponentFixture<TestComponent>;
let dl: DebugElement;
let menuSrv: MenuService;
let context: TestComponent;
let router: Router;
function genModule(other: { template?: string; providers?: any[]; created?: boolean }): void {
const imports = [RouterTestingModule.withRoutes([{ path: '1-1/:name', component: TestComponent }]), PageHeaderModule];
const providers = [{ provide: APP_BASE_HREF, useValue: '/' }, SettingsService];
if (other.providers && other.providers.length) {
providers.push(...other.providers);
}
TestBed.configureTestingModule({
imports,
declarations: [TestComponent],
providers,
});
if (other.template) TestBed.overrideTemplate(TestComponent, other.template);
fixture = TestBed.createComponent(TestComponent);
dl = fixture.debugElement;
context = fixture.componentInstance;
if (other.created !== false) fixture.detectChanges();
menuSrv = TestBed.inject<MenuService>(MenuService);
router = TestBed.inject<Router>(Router);
}
function isExists(cls: string, stauts: boolean = true): void {
if (stauts) {
expect(dl.query(By.css(cls))).not.toBeNull();
} else {
expect(dl.query(By.css(cls))).toBeNull();
}
}
function checkValue(cls: string, value: any): void {
const el = dl.query(By.css(cls)).nativeElement as HTMLElement;
expect(el.textContent!.trim()).toBe(value);
}
afterEach(() => context.comp.ngOnDestroy());
describe('', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [RouterTestingModule.withRoutes([{ path: '1-1/:name', component: TestComponent }]), PageHeaderModule],
providers: [{ provide: APP_BASE_HREF, useValue: '/' }, SettingsService],
declarations: [TestComponent, TestAutoBreadcrumbComponent, TestI18nComponent],
});
});
describe('[property]', () => {
beforeEach(() => {
({ fixture, dl, context } = createTestContext(TestComponent));
menuSrv = TestBed.inject<MenuService>(MenuService);
router = TestBed.inject<Router>(Router);
fixture.detectChanges();
});
describe('#title', () => {
it('with string', () => {
isExists('.page-header__title');
});
it('with null', () => {
context.title = null;
fixture.detectChanges();
isExists('.page-header__title', false);
});
});
['breadcrumb', 'logo', 'action', 'content', 'extra', 'tab'].forEach(type => {
it('#' + type, () => isExists('.' + type));
});
describe('#fixed', () => {
beforeEach(() => {
context.fixed = true;
fixture.detectChanges();
});
it('should working', () => {
isExists('nz-affix', true);
});
it('should be update position when switch collapsed', () => {
const srv = TestBed.inject(SettingsService);
const affixComp = dl.query(By.directive(NzAffixComponent)).injector.get<NzAffixComponent>(NzAffixComponent, undefined);
spyOn(affixComp, 'updatePosition');
srv.setLayout('collapsed', true);
expect(affixComp.updatePosition).toHaveBeenCalled();
});
});
it('#wide', () => {
context.wide = true;
fixture.detectChanges();
isExists('.page-header__wide');
});
it('#loading', () => {
context.loading = true;
fixture.detectChanges();
isExists('.ant-skeleton');
});
});
describe('[generation breadcrumb]', () => {
beforeEach(() => {
({ fixture, dl, context } = createTestContext(TestAutoBreadcrumbComponent));
menuSrv = TestBed.inject<MenuService>(MenuService);
router = TestBed.inject<Router>(Router);
fixture.detectChanges();
menuSrv.add([
{
text: 'root',
children: [
{
text: '1-1',
link: '/1-1',
children: [
{ text: '1-1-1', link: '/1-1/1-1-1' },
{ text: '1-1-2', link: '/1-1/1-1-2' },
],
},
],
},
]);
});
it('should be', () => {
spyOnProperty(router, 'url').and.returnValue('/1-1/1-1-2');
context.home = '';
context.autoBreadcrumb = true;
fixture.detectChanges();
expect(dl.queryAll(By.css('nz-breadcrumb-item')).length).toBe(3);
});
it('should be no breadcrumb when invalid url', () => {
spyOnProperty(router, 'url').and.returnValue('/1-1/a-1-1-2');
context.autoBreadcrumb = true;
fixture.detectChanges();
expect(dl.queryAll(By.css('nz-breadcrumb-item')).length).toBe(0);
});
it('should be hide breadcrumb', () => {
menuSrv.add([
{
text: 'root',
hideInBreadcrumb: true,
children: [
{
text: '1-1',
link: '/1-1',
children: [
{ text: '1-1-1', link: '/1-1/1-1-1' },
{ text: '1-1-2', link: '/1-1/1-1-2' },
],
},
],
},
]);
spyOnProperty(router, 'url').and.returnValue('/1-1/1-1-2');
context.autoBreadcrumb = true;
fixture.detectChanges();
expect(dl.queryAll(By.css('nz-breadcrumb-item')).length).toBe(2);
});
describe('#home', () => {
it('shoule be hide home', () => {
spyOnProperty(router, 'url').and.returnValue('/1-1/1-1-2');
context.home = '';
context.autoBreadcrumb = true;
fixture.detectChanges();
expect(dl.queryAll(By.css('nz-breadcrumb-item')).length).toBe(3);
});
});
it('shoule be different breadcrumb by paths', fakeAsync(() => {
context.home = '';
context.autoBreadcrumb = true;
const urlSpy = spyOnProperty(router, 'url');
urlSpy.and.returnValue('/1-1/1-1-2');
fixture.detectChanges();
const firstPath: HTMLElement = dl.query(By.css('nz-breadcrumb-item:nth-child(3)')).nativeElement;
urlSpy.and.returnValue('/1-1/1-1-1');
fixture.ngZone!.run(() => {
router.navigateByUrl('/1-1/1-1-1');
fixture.whenStable().then(() => {
fixture.detectChanges();
const secondPath: HTMLElement = dl.query(By.css('nz-breadcrumb-item:nth-child(3)')).nativeElement;
expect(firstPath.innerText).not.toBe(secondPath.innerText);
});
});
flush();
}));
});
describe('[i18n]', () => {
let i18n: OhayoI18NService;
beforeEach(() => {
TestBed.overrideProvider(OHAYO_I18N_TOKEN, {
useFactory: () => new MockI18NServiceFake(),
});
({ fixture, dl, context } = createTestContext(TestI18nComponent));
i18n = TestBed.inject(OHAYO_I18N_TOKEN);
menuSrv = TestBed.inject<MenuService>(MenuService);
router = TestBed.inject<Router>(Router);
fixture.detectChanges();
});
it('should be refresh when i18n changed', () => {
spyOn(context.comp, 'refresh');
expect(context.comp.refresh).not.toHaveBeenCalled();
i18n.use('en');
expect(context.comp.refresh).toHaveBeenCalled();
});
it('in text', () => {
menuSrv.add([
{
text: 'root',
i18n: 'root-i18n',
children: [
{
text: '1-1',
link: '/1-1',
children: [
{ text: '1-1-1', link: '/1-1/1-1-1' },
{ text: '1-1-2', link: '/1-1/1-1-2' },
],
},
],
},
]);
spyOnProperty(router, 'url').and.returnValue('/1-1/1-1-2');
spyOn(i18n, 'fanyi');
expect(i18n.fanyi).not.toHaveBeenCalled();
context.autoBreadcrumb = true;
fixture.detectChanges();
expect(i18n.fanyi).toHaveBeenCalled();
});
it('in title', () => {
const text = 'asdf';
// tslint:disable-next-line:no-shadowed-variable
const i18n = 'i18n';
context.title = null;
context.autoTitle = true;
context.autoBreadcrumb = true;
spyOn(menuSrv, 'getPathByUrl').and.returnValue([{ text, i18n }]);
fixture.detectChanges();
checkValue('.page-header__title', i18n);
});
it('in home', () => {
menuSrv.add([
{
text: 'root',
children: [
{
text: '1-1',
link: '/1-1',
children: [
{ text: '1-1-1', link: '/1-1/1-1-1' },
{ text: '1-1-2', link: '/1-1/1-1-2' },
],
},
],
},
]);
context.autoBreadcrumb = true;
spyOnProperty(router, 'url').and.returnValue('/1-1/1-1-2');
spyOn(i18n, 'fanyi');
context.home = 'home';
context.homeI18n = 'homeI18n';
context.autoBreadcrumb = true;
fixture.detectChanges();
expect(i18n.fanyi).toHaveBeenCalled();
});
});
});
describe('#title', () => {
it('should be custom title template', () => {
genModule({
template: `<page-header #comp [title]="titleTpl">
<ng-template #titleTpl>
<div class="custom-title">title</div>
</ng-template>
</page-header>`,
});
expect(dl.queryAll(By.css('.custom-title')).length).toBe(1);
});
it('should be refresh title when route changed of auto generate title', fakeAsync(() => {
genModule({ created: false });
context.title = null;
context.autoTitle = true;
menuSrv.add([
{ text: '1', link: '/1-1/p1' },
{ text: '2', link: '/1-1/p2' },
]);
const urlSpy = spyOnProperty(router, 'url');
urlSpy.and.returnValue('/1-1/p1');
tick();
fixture.detectChanges();
checkValue('.page-header__title', '1');
urlSpy.and.returnValue('/1-1/p2');
router.navigateByUrl('/1-1/p2');
tick();
fixture.detectChanges();
checkValue('.page-header__title', '2');
}));
describe('[generateion title]', () => {
beforeEach(() => {
genModule({
providers: [
{
provide: TitleService,
useFactory: () => null,
},
{
provide: ReuseTabService,
useFactory: () => null,
},
],
});
context.title = null;
context.autoTitle = true;
context.syncTitle = true;
});
it('should be auto generate title via menu data', () => {
const text = 'asdf';
spyOn(menuSrv, 'getPathByUrl').and.returnValue([{ text }]);
fixture.detectChanges();
checkValue('.page-header__title', text);
});
});
describe('[auto sync title]', () => {
class MockTitle {
setTitle = jasmine.createSpy();
}
class MockReuse {
set title(_val: string) { }
get title(): string {
return '';
}
}
let titleSrv: TitleService;
let reuseSrv: ReuseTabService;
beforeEach(() => {
genModule({
providers: [
{
provide: TitleService,
useClass: MockTitle,
},
{
provide: ReuseTabService,
useClass: MockReuse,
},
],
});
titleSrv = TestBed.inject<TitleService>(TitleService);
reuseSrv = TestBed.inject<ReuseTabService>(ReuseTabService);
context.syncTitle = true;
});
it('should be auto sync title of document and result-tab', () => {
const spyReuseTitle = spyOnProperty(reuseSrv, 'title', 'set').and.callThrough();
fixture.detectChanges();
context.comp.inited = false;
context.comp.refresh();
expect(titleSrv.setTitle).toHaveBeenCalled();
expect(spyReuseTitle).toHaveBeenCalled();
});
});
});
});
class TestBaseComponent {
@ViewChild('comp', { static: true })
comp: PageHeaderComponent;
title: string | null = '所属类目';
autoBreadcrumb: boolean;
autoTitle: boolean;
syncTitle: boolean;
home: string;
homeLink: string;
homeI18n: string;
fixed: boolean;
loading = false;
wide = false;
}
@Component({
template: `
<page-header
#comp
[title]="title"
[autoTitle]="autoTitle"
[syncTitle]="syncTitle"
[autoBreadcrumb]="autoBreadcrumb"
[home]="home"
[homeI18n]="homeI18n"
[homeLink]="homeLink"
[fixed]="fixed"
[loading]="loading"
[wide]="wide"
[breadcrumb]="breadcrumb"
[logo]="logo"
[action]="action"
[extra]="extra"
[content]="content"
[tab]="tab"
>
<ng-template #breadcrumb><div class="breadcrumb">面包屑</div></ng-template>
<ng-template #logo><div class="logo">logo</div></ng-template>
<ng-template #action><div class="action">action</div></ng-template>
<ng-template #content><div class="content">content</div></ng-template>
<ng-template #extra><div class="extra">extra</div></ng-template>
<ng-template #tab><div class="tab">tab</div></ng-template>
</page-header>
`,
})
class TestComponent extends TestBaseComponent { }
@Component({
template: ` <page-header #comp [title]="title" [home]="home" [homeI18n]="homeI18n" [autoBreadcrumb]="autoBreadcrumb"></page-header> `,
})
class TestAutoBreadcrumbComponent extends TestBaseComponent { }
@Component({
template: `
<page-header
#comp
[title]="title"
[home]="home"
[homeI18n]="homeI18n"
[homeLink]="homeLink"
[autoBreadcrumb]="autoBreadcrumb"
></page-header>
`,
})
class TestI18nComponent extends TestBaseComponent { }