test(devtools): write tests for record formatter

This commit is contained in:
AleksanderBodurri 2020-03-15 20:31:35 -04:00 committed by Sumit Arora
parent 816974654c
commit e86ffc1d86
5 changed files with 1322 additions and 7 deletions

View file

@ -0,0 +1,140 @@
import { addFrame, AppEntry, getLabel, getValue, insertTimelineRecord, TimelineView } from './format-records';
import { ElementProfile } from 'protocol';
import {
NESTED_FORMATTED_RECORD,
NESTED_RECORD,
SIMPLE_FORMATTED_RECORD,
SIMPLE_RECORD,
} from './format-records-test-constants';
describe('getValue cases', () => {
let element;
it('calculates value with no lifecycle hooks', () => {
element = {
children: [],
directives: [{ changeDetection: 10, isElement: false, isComponent: true, lifecycle: {}, name: 'AppComponent' }],
};
expect(getValue(element)).toBe(10);
});
it('calculates value with 0 change detection and existing lifecycle hooks', () => {
element = {
children: [],
directives: [
{ isComponent: false, isElement: false, name: 'NgForOf', lifecycle: { ngDoCheck: 5 }, changeDetection: 0 },
],
};
expect(getValue(element)).toBe(5);
});
it('calculates value with non 0 change detection and one lifecycle hook', () => {
element = {
children: [],
directives: [
{ isComponent: false, isElement: false, name: 'NgForOf', lifecycle: { ngDoCheck: 5 }, changeDetection: 10 },
],
};
expect(getValue(element)).toBe(15);
});
it('calculates value with non 0 change detection and multiple lifecycle hooks', () => {
element = {
children: [],
directives: [
{
isComponent: false,
isElement: false,
name: 'NgForOf',
lifecycle: { ngDoCheck: 5, ngAfterViewInit: 100 },
changeDetection: 10,
},
],
};
expect(getValue(element)).toBe(115);
});
});
describe('getLabel cases', () => {
let element: ElementProfile;
it('has only components', () => {
element = {
children: [],
directives: [
{
changeDetection: 10,
isElement: false,
isComponent: true,
lifecycle: {},
name: 'AppComponent',
},
],
};
expect(getLabel(element)).toBe('AppComponent');
});
it('has only directives', () => {
element = {
children: [],
directives: [
{
isComponent: false,
isElement: false,
name: 'RouterOutlet',
lifecycle: {},
changeDetection: 0,
},
],
};
expect(getLabel(element)).toBe('[RouterOutlet]');
});
it('has a component and a directive', () => {
element = {
children: [],
directives: [
{ isComponent: false, isElement: false, name: 'TooltipDirective', lifecycle: {}, changeDetection: 0 },
{ changeDetection: 0, isElement: false, isComponent: true, lifecycle: {}, name: 'TodoComponent' },
],
};
expect(getLabel(element)).toBe('TodoComponent[TooltipDirective]');
});
it('has a component and multiple directives', () => {
element = {
children: [],
directives: [
{ isComponent: false, isElement: false, name: 'TooltipDirective', lifecycle: {}, changeDetection: 0 },
{ isComponent: false, isElement: false, name: 'RandomDirective', lifecycle: {}, changeDetection: 0 },
{ changeDetection: 0, isElement: false, isComponent: true, lifecycle: {}, name: 'TodoComponent' },
],
};
expect(getLabel(element)).toBe('TodoComponent[TooltipDirective, RandomDirective]');
});
});
describe('addFrame cases', () => {
let entry: AppEntry;
let timeSpent;
beforeEach(() => {
entry = {
app: [],
timeSpent: 0,
source: '',
};
});
it('add frame for simple case', () => {
timeSpent = addFrame(entry.app, SIMPLE_RECORD);
expect(timeSpent).toBe(17);
expect(entry.app).toEqual(SIMPLE_FORMATTED_RECORD);
});
it('add frame for deeply nested records', () => {
timeSpent = addFrame(entry.app, NESTED_RECORD);
expect(timeSpent).toBe(21);
expect(entry.app).toEqual(NESTED_FORMATTED_RECORD);
});
});

View file

@ -18,7 +18,7 @@ export interface FlamegraphNode {
original: ElementProfile;
}
const getLabel = (element: ElementProfile) => {
export const getLabel = (element: ElementProfile) => {
const name = element.directives
.filter(d => d.isComponent)
.map(c => c.name)
@ -27,7 +27,7 @@ const getLabel = (element: ElementProfile) => {
return attributes === '' ? name : `${name}[${attributes}]`;
};
const getValue = (element: ElementProfile, e: any) => {
export const getValue = (element: ElementProfile) => {
let result = 0;
element.directives.forEach(dir => {
result += dir.changeDetection;
@ -41,7 +41,7 @@ const getValue = (element: ElementProfile, e: any) => {
return result;
};
const addFrame = (nodes: FlamegraphNode[], elements: ElementProfile[]): number => {
export const addFrame = (nodes: FlamegraphNode[], elements: ElementProfile[]): number => {
let timeSpent = 0;
elements.forEach(element => {
// Possibly undefined because of
@ -51,7 +51,7 @@ const addFrame = (nodes: FlamegraphNode[], elements: ElementProfile[]): number =
return;
}
const node: FlamegraphNode = {
value: getValue(element, elements),
value: getValue(element),
label: getLabel(element),
children: [],
instances: 1,
@ -64,7 +64,7 @@ const addFrame = (nodes: FlamegraphNode[], elements: ElementProfile[]): number =
return timeSpent;
};
const insertTimelineRecord = (result: AppEntry[], record: ProfilerFrame) => {
export const insertTimelineRecord = (result: AppEntry[], record: ProfilerFrame) => {
const entry: AppEntry = {
app: [],
timeSpent: 0,

View file

@ -1,5 +1,5 @@
import { Component, ElementRef, Input } from '@angular/core';
import { FlamegraphNode } from '../../format-records';
import { FlamegraphNode } from '../../record-formatter/format-records';
import { RawData } from 'ngx-flamegraph/lib/utils';
@Component({

View file

@ -1,5 +1,5 @@
import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output, ViewChild } from '@angular/core';
import { AppEntry, formatFlamegraphRecords, TimelineView } from './format-records';
import { AppEntry, formatFlamegraphRecords, TimelineView } from './record-formatter/format-records';
import { MatSlider, MatSliderChange } from '@angular/material/slider';
import { ProfilerFrame } from 'protocol';