mirror of
https://github.com/angular/angular
synced 2026-05-24 09:28:37 +00:00
test(devtools): write tests for record formatter
This commit is contained in:
parent
816974654c
commit
e86ffc1d86
5 changed files with 1322 additions and 7 deletions
File diff suppressed because it is too large
Load diff
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
|
|
@ -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,
|
||||
|
|
@ -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({
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue