angular-cn/aio/src/app/embedded/code/code.component.spec.ts

185 lines
6.8 KiB
TypeScript
Raw Normal View History

/* tslint:disable:no-unused-variable */
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { Component, DebugElement } from '@angular/core';
import { CodeComponent } from './code.component';
import { CopierService } from 'app/shared//copier.service';
import { Logger } from 'app/shared/logger.service';
import { PrettyPrinter } from './pretty-printer.service';
const oneLineCode = 'const foo = "bar";';
const multiLineCode = `
<hero-details>
<h2>Bah Dah Bing</h2>
<hero-team>
<h3>NYC Team</h3>
</hero-team>
</hero-details>`;
describe('CodeComponent', () => {
let codeComponentDe: DebugElement;
let codeComponent: CodeComponent;
let hostComponent: HostComponent;
let fixture: ComponentFixture<HostComponent>;
// WARNING: Chance of cross-test pollution
// CodeComponent injects PrettyPrintService
// Once PrettyPrintService runs once _anywhere_, its ctor loads `prettify.js`
// which sets `window['prettyPrintOne']`
// That global survives these tests unless
// we take strict measures to wipe it out in the `afterAll`
// and make sure THAT runs after the tests by making component creation async
afterAll(() => {
delete window['prettyPrint'];
delete window['prettyPrintOne'];
});
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ CodeComponent, HostComponent ],
providers: [
PrettyPrinter,
{provide: CopierService, useClass: TestCopierService },
{provide: Logger, useClass: TestLogger }
]
})
.compileComponents();
}));
// Must be async because
// CodeComponent creates PrettyPrintService which async loads `prettify.js`.
// If not async, `afterAll` finishes before tests do!
beforeEach(async(() => {
fixture = TestBed.createComponent(HostComponent);
hostComponent = fixture.componentInstance;
codeComponentDe = fixture.debugElement.children[0];
codeComponent = codeComponentDe.componentInstance;
fixture.detectChanges();
}));
it('should create CodeComponent', () => {
expect(codeComponentDe.name).toBe('aio-code', 'selector');
expect(codeComponent).toBeTruthy('CodeComponent');
});
it('should format a one-line code sample', () => {
// 'pln' spans are a tell-tale for syntax highlighing
const spans = codeComponentDe.nativeElement.querySelectorAll('span.pln');
expect(spans.length).toBeGreaterThan(0, 'formatted spans');
});
it('should format a one-line code sample without linenums by default', () => {
// `<li>`s are a tell-tale for line numbers
const lis = codeComponentDe.nativeElement.querySelectorAll('li');
expect(lis.length).toBe(0, 'should be no linenums');
});
it('should add line numbers to one-line code sample when linenums set true', () => {
hostComponent.linenums = 'true';
fixture.detectChanges();
// `<li>`s are a tell-tale for line numbers
const lis = codeComponentDe.nativeElement.querySelectorAll('li');
expect(lis.length).toBe(1, 'has linenums');
});
it('should format multi-line code with linenums by default', () => {
hostComponent.code = multiLineCode;
fixture.detectChanges();
// `<li>`s are a tell-tale for line numbers
const lis = codeComponentDe.nativeElement.querySelectorAll('li');
expect(lis.length).toBeGreaterThan(0, 'has linenums');
});
it('should not format multi-line code when linenums set false', () => {
hostComponent.linenums = false;
hostComponent.code = multiLineCode;
fixture.detectChanges();
// `<li>`s are a tell-tale for line numbers
const lis = codeComponentDe.nativeElement.querySelectorAll('li');
expect(lis.length).toBe(0, 'should be no linenums');
});
it('should remove common indentation from the code before rendering', () => {
hostComponent.linenums = false;
hostComponent.code = ' abc\n let x = text.split(\'\\n\');\n ghi\n\n jkl\n';
fixture.detectChanges();
const codeContent = codeComponentDe.nativeElement.querySelector('code').innerText;
expect(codeContent).toEqual('abc\n let x = text.split(\'\\n\');\nghi\n\njkl');
});
it('should trim whitespace from the code before rendering', () => {
hostComponent.linenums = false;
hostComponent.code = '\n\n\n' + multiLineCode + '\n\n\n';
fixture.detectChanges();
const codeContent = codeComponentDe.nativeElement.querySelector('code').innerText;
expect(codeContent).toEqual(codeContent.trim());
});
it('should trim whitespace from code before computing whether to format linenums', () => {
hostComponent.code = '\n\n\n' + hostComponent.code + '\n\n\n';
fixture.detectChanges();
// `<li>`s are a tell-tale for line numbers
const lis = codeComponentDe.nativeElement.querySelectorAll('li');
expect(lis.length).toBe(0, 'should be no linenums');
});
it('should display error message when there is no code (after trimming)', () => {
hostComponent.code = ' \n ';
fixture.detectChanges();
const missing = codeComponentDe.nativeElement.querySelector('.code-missing') as HTMLElement;
expect(missing).not.toBeNull('should have element with "code-missing" class');
expect(missing.innerText).toContain('missing', 'error message');
});
it('should not display "code-missing" class when there is some code', () => {
fixture.detectChanges();
const missing = codeComponentDe.nativeElement.querySelector('.code-missing');
expect(missing).toBeNull('should not have element with "code-missing" class');
});
it('should call copier service when copy button clicked', () => {
const copierService: TestCopierService = <any> codeComponentDe.injector.get(CopierService) ;
const button = fixture.debugElement.query(By.css('button')).nativeElement as HTMLButtonElement;
expect(copierService.copyText.calls.count()).toBe(0, 'before click');
button.click();
expect(copierService.copyText.calls.count()).toBe(1, 'after click');
});
it('should copy code text when copy button clicked', () => {
const copierService: TestCopierService = <any> codeComponentDe.injector.get(CopierService) ;
const button = fixture.debugElement.query(By.css('button')).nativeElement as HTMLButtonElement;
button.click();
expect(copierService.copyText.calls.argsFor(0)[0]).toEqual(oneLineCode, 'after click');
});
});
//// Test helpers ////
// tslint:disable:member-ordering
@Component({
selector: 'aio-host-comp',
template: `
<aio-code [code]="code" [language]="language" [linenums]="linenums"></aio-code>
`
})
class HostComponent {
code = oneLineCode;
language: string;
linenums: boolean | number | string;
}
class TestCopierService {
copyText = jasmine.createSpy('copyText');
}
class TestLogger {
log = jasmine.createSpy('log');
error = jasmine.createSpy('error');
}