/
githubmirror
/
angular
Обзор
Документация
Войти
/
githubmirror
/
angular
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
devtools/projects/ng-devtools-backend/src/lib/directive-forest/component-tree/component-tree.spec.ts
186 строк
5 KB
hawkgs
refactor(devtools): reorganize backend code
20 июл 2026, 12:15
20 июл 2026, 12:15
a7ebf1c
Код
Авторство
О чём код?
/** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.dev/license */ import { Injector, ɵExternalCoreGlobalUtils, ɵProviderRecord as ProviderRecord, InjectionToken, } from '@angular/core'; import { getInjectorFromElementNode, getRootElements, serializeProviderRecord, } from './component-tree'; type Ng = ɵExternalCoreGlobalUtils; const NG_VERSION = 'ng-version'; const VERSION = '0.0.0-PLACEHOLDER'; function setNgVersion(element: Element) { element.setAttribute(NG_VERSION, VERSION); } function createRoot() { const root = document.createElement('div'); setNgVersion(root); return root; } describe('component-tree', () => { afterEach(() => { delete (globalThis as any).ng; }); describe('getInjectorFromElementNode', () => { it('returns injector', () => { const injector = Injector.create({ providers: [], }); const ng: Partial<Ng> = { getInjector: jasmine.createSpy('getInjector').and.returnValue(injector), }; (globalThis as any).ng = ng; const el = document.createElement('div'); expect(getInjectorFromElementNode(el)).toBe(injector); expect(ng.getInjector).toHaveBeenCalledOnceWith(el); }); it('returns `null` when `getInjector` is not supported', () => { (globalThis as any).ng = {}; const el = document.createElement('div'); expect(getInjectorFromElementNode(el)).toBeNull(); }); }); describe('getRootElements', () => { beforeEach(() => { const ng: Partial<Ng> = { getComponent: jasmine.createSpy('getComponent').and.callFake((element: HTMLElement) => { // Will treat only `ng-*` elements as Angular components. if (element.tagName.toLowerCase().startsWith('ng-')) { return element; } return null; }), }; (window as any).ng = ng; }); afterEach(() => { document.body.replaceChildren(); document.body.removeAttribute(NG_VERSION); delete (window as any).ng; }); it('should return root element', () => { const rootElement = createRoot(); const childElement = createRoot(); rootElement.appendChild(childElement); document.body.appendChild(rootElement); const roots = getRootElements(); expect(roots.length).toEqual(1); expect(roots.pop()).toEqual(rootElement); }); it('should return multiple sibling roots', () => { const firstRoot = createRoot(); const secondRoot = createRoot(); document.body.appendChild(firstRoot); document.body.appendChild(secondRoot); const roots = getRootElements(); expect(roots.length).toEqual(2); expect(roots).toContain(firstRoot); expect(roots).toContain(secondRoot); }); it('should only return document.body when document.body is the root', () => { setNgVersion(document.body); const child1 = createRoot(); document.body.appendChild(child1); const roots = getRootElements(); expect(roots.length).toEqual(1); expect(roots).toContain(document.body); }); it('should return all root elements with all non-application root components', () => { const rootElement = createRoot(); const childElement = createRoot(); const nonAppRootCmp = document.createElement('ng-cmp'); rootElement.appendChild(childElement); document.body.appendChild(rootElement); document.body.appendChild(nonAppRootCmp); const roots = getRootElements(); expect(roots.length).toEqual(2); expect(roots).toEqual([rootElement, nonAppRootCmp]); }); }); describe('serializeProviderRecord', () => { it('should return "internal" type for internal tokens', () => { const internalTokenNames = [ 'ElementRef', 'Renderer2', 'ViewContainerRef', 'DestroyRef', 'ChangeDetectorRef', 'Injector', ]; internalTokenNames.forEach((tokenName, index) => { const token = () => {}; Object.defineProperty(token, 'name', {value: tokenName}); const providerRecord: any = { provider: () => {}, token, isViewProvider: false, }; const result = serializeProviderRecord(providerRecord, index); expect(result.type).toBe('internal'); expect(result.token).toBe(tokenName); }); }); it('should return "type" for non-internal function providers', () => { const token = () => {}; Object.defineProperty(token, 'name', {value: 'MyCustomService'}); const providerRecord: any = { provider: () => {}, token, isViewProvider: false, }; const result = serializeProviderRecord(providerRecord, 0); expect(result.type).toBe('type'); expect(result.token).toBe('MyCustomService'); }); it('should handle injection tokens', () => { const result = serializeProviderRecord( { token: new InjectionToken('FOO'), isViewProvider: false, } as ProviderRecord, 0, ); expect(result.token).toBe('InjectionToken (FOO)'); }); }); });