ng-flex-layout
Version:
Angular Flex-Layout =======
411 lines (403 loc) • 15.1 kB
JavaScript
import { extendObject, applyCssPrefixes } from 'ng-flex-layout/_private-utils';
import { expect } from 'vitest';
import { CommonModule } from '@angular/common';
import { getDebugNode, Component, EnvironmentInjector, createEnvironmentInjector, createComponent } from '@angular/core';
import { TestBed } from '@angular/core/testing';
import { FlexLayoutModule } from 'ng-flex-layout';
import { BreakPointRegistry, MediaMarshaller, MediaObserver } from 'ng-flex-layout/core';
/**
* @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.io/license
*/
/**
* Exported DOM accessor utility functions
*/
const _dom = {
hasStyle,
getDistributedNodes,
getShadowRoot,
getText,
getStyle,
childNodes,
childNodesAsList,
hasClass,
hasAttribute,
getAttribute,
hasShadowRoot,
isCommentNode,
isElementNode,
isPresent,
isShadowRoot,
tagName,
lastElementChild
};
// ******************************************************************************************
// These functions are cloned from
// * @angular/platform-browser/src/browser/GenericBrowserDomAdapter
// and are to be used ONLY internally in custom-matchers.ts and Unit Tests
// ******************************************************************************************
function getStyle(element, stylename) {
return element.style[stylename];
}
function hasStyle(element, styleName, styleValue = '', inlineOnly = true) {
let value = getStyle(element, styleName) || '';
if (!value && !inlineOnly) {
// Search stylesheets
value = typeof getComputedStyle === 'function' &&
getComputedStyle(element).getPropertyValue(styleName) || '';
}
return styleValue ? value == styleValue : value.length > 0;
}
function getDistributedNodes(el) {
return el.getDistributedNodes();
}
function getShadowRoot(el) {
return el.shadowRoot;
}
function getText(el) {
return el.textContent || '';
}
function childNodesAsList(el) {
const list = el.childNodes;
const res = new Array(list.length);
for (let i = 0; i < list.length; i++) {
res[i] = list[i];
}
return res;
}
function hasClass(element, className) {
return element.classList.contains(className);
}
function hasAttribute(element, attributeName) {
return element.hasAttribute(attributeName);
}
function getAttribute(element, attributeName) {
return element.getAttribute(attributeName);
}
function childNodes(el) {
return el.childNodes;
}
function hasShadowRoot(node) {
return isPresent(node.shadowRoot) && node instanceof HTMLElement;
}
function isCommentNode(node) {
return node.nodeType === Node.COMMENT_NODE;
}
function isElementNode(node) {
return node.nodeType === Node.ELEMENT_NODE;
}
function isShadowRoot(node) {
return node instanceof DocumentFragment;
}
function isPresent(obj) {
return obj != null;
}
function tagName(element) {
return element.tagName;
}
// ******************************************************************************************
// These functions are part of the DOM API
// and are to be used ONLY internally in custom-matchers.ts and Unit Tests
// ******************************************************************************************
function lastElementChild(element) {
return element.lastElementChild;
}
const _global = (typeof window === 'undefined' ? global : window);
expect.extend({
toHaveText(received, expectedText) {
const actualText = elementText(received);
const pass = actualText === expectedText;
return {
pass,
message: () => `Expected element text ${actualText} to ${pass ? 'not ' : ''}equal ${expectedText}`,
};
},
toHaveCssClass(received, className) {
const pass = _dom.hasClass(received, className);
return {
pass,
message: () => `Expected element ${received.outerHTML} ${pass ? 'not ' : ''}to have class "${className}"`,
};
},
toHaveMap(received, expected) {
const allPassed = Object.entries(expected).every(([k, v]) => received[k] === v);
return {
pass: allPassed,
message: () => `Expected map ${JSON.stringify(received)} ${allPassed ? 'not ' : ''}to match ${JSON.stringify(expected)}`,
};
},
toHaveAttributes(received, expected) {
const allPassed = Object.entries(expected).every(([name, value]) => _dom.hasAttribute(received, name) && _dom.getAttribute(received, name) === value);
return {
pass: allPassed,
message: () => `Expected element ${received.outerHTML} ${allPassed ? 'not ' : ''}to have attributes ${JSON.stringify(expected)}`,
};
},
toHaveStyle(received, styles, styler) {
return buildCompareStyleFunction(true)(received, styles, styler);
},
toHaveCSS(received, styles, styler) {
return buildCompareStyleFunction(false)(received, styles, styler);
},
});
function buildCompareStyleFunction(inlineOnly = true) {
return function (actual, styles, styler) {
const found = {};
const styleMap = {};
if (typeof styles === 'string') {
styleMap[styles] = '';
}
else {
Object.assign(styleMap, styles);
}
let allPassed = Object.keys(styleMap).length !== 0;
Object.keys(styleMap).forEach(prop => {
const { elHasStyle, current } = hasPrefixedStyles(actual, prop, styleMap[prop], inlineOnly, styler);
allPassed = allPassed && elHasStyle;
if (!elHasStyle) {
extendObject(found, current);
}
});
return {
pass: allPassed,
message: () => {
const expectedValueStr = typeof styles === 'string'
? styleMap
: JSON.stringify(styleMap, null, 2);
const foundValueStr = inlineOnly
? actual.outerHTML
: JSON.stringify(found);
return `Expected ${foundValueStr}${!allPassed ? '' : ' not'} to contain the CSS ${typeof styles === 'string' ? 'property' : 'styles'} '${expectedValueStr}'`;
}
};
};
}
/**
* Validate presence of requested style or use fallback
* to possible `prefixed` styles. Useful when some browsers
* (Safari, IE, etc) will use prefixed style instead of defaults.
*/
function hasPrefixedStyles(actual, key, value, inlineOnly, styler) {
const current = {};
if (value === '*') {
return { elHasStyle: styler.lookupStyle(actual, key, inlineOnly) !== '', current };
}
value = value.trim();
let elHasStyle = styler.lookupStyle(actual, key, inlineOnly) === value;
if (!elHasStyle) {
let prefixedStyles = applyCssPrefixes({ [key]: value });
Object.keys(prefixedStyles).forEach(prop => {
// Search for optional prefixed values
elHasStyle = elHasStyle ||
styler.lookupStyle(actual, prop, inlineOnly) === prefixedStyles[prop];
});
}
// Return BOTH confirmation and current computed key values (if confirmation == false)
return { elHasStyle, current };
}
function elementText(n) {
const hasNodes = (m) => {
const children = _dom.childNodes(m);
return children && children['length'];
};
if (n instanceof Array) {
return n.map(elementText).join('');
}
if (_dom.isCommentNode(n)) {
return '';
}
if (_dom.isElementNode(n) && _dom.tagName(n) == 'CONTENT') {
return elementText(Array.prototype.slice.apply(_dom.getDistributedNodes(n)));
}
if (_dom.hasShadowRoot(n)) {
return elementText(_dom.childNodesAsList(_dom.getShadowRoot(n)));
}
if (hasNodes(n)) {
return elementText(_dom.childNodesAsList(n));
}
return _dom.getText(n);
}
function unwrapNativeElement(value) {
return (value && typeof value === 'object' && 'nativeElement' in value) ? value.nativeElement : value;
}
expect.extend({
toHaveMap(received, expected) {
const pass = Object.entries(expected).every(([k, v]) => received[k] === v);
return {
pass,
message: () => `Expected map ${JSON.stringify(received)} ${pass ? 'not ' : ''}to match ${JSON.stringify(expected)}`,
};
},
toHaveCssClass(received, className) {
const el = unwrapNativeElement(received);
const hasClass = el.classList.contains(className);
return {
pass: hasClass,
message: () => `Expected element ${el.outerHTML} ${hasClass ? 'not ' : ''}to have class '${className}'`
};
},
toHaveAttributes(received, expected) {
const el = unwrapNativeElement(received);
const allMatch = Object.entries(expected).every(([key, value]) => el.getAttribute(key) === value);
return {
pass: allMatch,
message: () => `Expected element ${el.outerHTML} ${allMatch ? 'not ' : ''}to have attributes ${JSON.stringify(expected)}`
};
}
});
function getHostElement(fixture) {
return fixture?.location?.nativeElement ?? fixture?.nativeElement ?? fixture?.componentRef?.location?.nativeElement;
}
function getInstance(fixture) {
return fixture?.componentInstance ?? fixture?.instance ?? fixture?.componentRef?.instance;
}
function detectChanges(fixture) {
const hostEl = fixture?.location?.nativeElement ?? fixture?.nativeElement ?? fixture?.componentRef?.location?.nativeElement;
if (hostEl) {
const wrapper = hostEl.querySelector('#testing-wrapper-node');
if (wrapper) {
wrapper.dispatchEvent(new CustomEvent('change'));
}
}
if (typeof fixture?.detectChanges === 'function') {
fixture.detectChanges();
return;
}
if (fixture?.changeDetectorRef?.detectChanges) {
fixture.changeDetectorRef.detectChanges();
return;
}
if (fixture?.componentRef?.changeDetectorRef?.detectChanges) {
fixture.componentRef.changeDetectorRef.detectChanges();
}
}
function asFixtureLike(ref) {
const fixture = ref;
fixture.componentInstance ??= ref.instance;
fixture.location ??= ref.location;
fixture.injector ??= ref.injector;
fixture.changeDetectorRef ??= ref.changeDetectorRef;
fixture.nativeElement ??= ref.location.nativeElement;
fixture.detectChanges ??= () => {
const hostEl = fixture.nativeElement ?? fixture.location?.nativeElement;
if (hostEl) {
const wrapper = hostEl.querySelector('#testing-wrapper-node');
if (wrapper) {
wrapper.dispatchEvent(new CustomEvent('change'));
}
}
ref.changeDetectorRef.detectChanges();
};
const debugNode = getDebugNode(ref.location.nativeElement);
if (debugNode && debugNode.children) {
const wrapper = debugNode.children.find((c) => c.nativeElement?.id === 'testing-wrapper-node');
if (wrapper) {
Object.defineProperty(debugNode, 'children', {
get: () => wrapper.children
});
Object.defineProperty(debugNode, 'childNodes', {
get: () => wrapper.childNodes
});
}
fixture.debugElement ??= debugNode;
}
return fixture;
}
const TRACKED_REFS = [];
let cleanupRegistered = false;
function registerCleanup() {
if (cleanupRegistered) {
return;
}
cleanupRegistered = true;
const afterEachHook = globalThis.afterEach;
if (typeof afterEachHook !== 'function') {
return;
}
afterEachHook(() => {
while (TRACKED_REFS.length) {
const tracked = TRACKED_REFS.pop();
try {
tracked.componentRef.destroy();
}
catch {
// ignore
}
if (tracked.envInjector && tracked.envInjector !== tracked.componentRef.injector) {
try {
tracked.envInjector.destroy();
}
catch {
// ignore
}
}
}
});
}
function makeCreateTestComponent(baseOrProviders = [], defaultProviders = []) {
const hasBase = typeof baseOrProviders === 'function';
const BaseComponent = hasBase ? baseOrProviders() : class {
};
const providers = [
...(hasBase ? [] : baseOrProviders),
...defaultProviders
];
return function createTestComponent(templateStr, styles = [], additionalProviders = [], additionalImports = []) {
registerCleanup();
const DynamicTestComponent = Component({
selector: 'test-wrapper',
standalone: true,
template: `<div (change)="0" id="testing-wrapper-node" style="display:contents">${templateStr}</div>`,
styles,
imports: [CommonModule, FlexLayoutModule, ...additionalImports]
})(class extends BaseComponent {
});
const parentInjector = TestBed.inject(EnvironmentInjector);
const isolatedFlexProviders = [
{ provide: BreakPointRegistry, useClass: BreakPointRegistry },
{ provide: MediaMarshaller, useClass: MediaMarshaller },
{ provide: MediaObserver, useClass: MediaObserver },
];
const finalProviders = [...isolatedFlexProviders, ...providers, ...additionalProviders];
const envInjector = createEnvironmentInjector(finalProviders, parentInjector);
const componentRef = createComponent(DynamicTestComponent, { environmentInjector: envInjector });
TRACKED_REFS.push({ componentRef, envInjector });
const fixture = asFixtureLike(componentRef);
fixture.detectChanges?.();
return fixture;
};
}
function expectNativeEl(fixture, instanceOptions) {
Object.assign(getInstance(fixture) ?? {}, instanceOptions || {});
detectChanges(fixture);
const host = getHostElement(fixture);
const wrapper = host.querySelector('#testing-wrapper-node');
const target = wrapper ? wrapper.children[0] : host.children[0];
return expect(target);
}
function expectEl(el) {
const native = el?.nativeElement ?? el;
return expect(native);
}
function queryFor(fixture, selector) {
const host = getHostElement(fixture);
const wrapper = host.querySelector('#testing-wrapper-node');
const target = wrapper ? wrapper : host;
const nodes = Array.from(target.querySelectorAll(selector));
return nodes.map((node) => getDebugNode(node) ?? node);
}
/**
* @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.io/license
*/
/**
* Generated bundle index. Do not edit.
*/
export { _dom, expectEl, expectNativeEl, makeCreateTestComponent, queryFor };
//# sourceMappingURL=ng-flex-layout-_private-utils-testing.mjs.map