shallow-render
Version:
Shallow rendering test utility for Angular
228 lines • 10.9 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.Rendering = void 0;
const testing_1 = require("@angular/core/testing");
const platform_browser_1 = require("@angular/platform-browser");
const output_proxy_1 = require("../tools/output-proxy");
const query_match_1 = require("./query-match");
/**
* Contains all information about a rendered test component including
* utilities for querying and toggling rendered states of directives
*
* This is not intended for direct instantion. These are created via the `render` method on an instance of `Shallow`
*
* @link https://getsaf.github.io/shallow-render/#rendering
*/
class Rendering {
constructor(fixture, element, instance, bindings, _setup) {
this.fixture = fixture;
this.element = element;
this.instance = instance;
this.bindings = bindings;
this._setup = _setup;
this.outputs = (0, output_proxy_1.outputProxy)(this.instance);
/////////////////////////////////////////////////////////////////////////////
// The following methods MUST be arrow functions so they can be deconstructured
// off of the class
/////////////////////////////////////////////////////////////////////////////
/**
* Search for a component with a CSS celector
*
* The result is either a `DebugElement` OR an Array of `DebugElement`. Your test
* must give proper treatment to the result based on the expected results.
*
* For example, if your test expects a single result, you may treat the result as a `DebugElement` or an array of `DebugElement`s with one entry.
*
* @example
* expect(find('h1.large').nativeElement.textContent).toBe('Foo');
*
* // If your query results in multiple matches, you may iterate over the matches but if you attempt
* // to treat the collection of matches as a single match, the test will fail due to a mismatched
* // usage of the query results in the test.
*
* // This would throw an error if the query resulted in multiple matches
* expect(find('h1.large').nativeElement.textContent).toBe('Foo');
*
* const results = find('h1.large');
* expect(results.length).toBe(3);
* expect(results.map(result => result.nativeElement.textContent)).toEqual([
* 'Foo',
* 'Bar',
* 'Baz'
* ])
*
* @link https://getsaf.github.io/shallow-render/#querying
*/
this.find = (cssOrDirective, options) => {
const query = typeof cssOrDirective === 'string'
? platform_browser_1.By.css(cssOrDirective)
: platform_browser_1.By.directive(this._setup.mockCache.find(cssOrDirective) || cssOrDirective);
const mainQuery = this.fixture.debugElement.queryAll(query);
const found = options && options.query
? this.fixture.debugElement.queryAll(platform_browser_1.By.css(options.query)).filter(item => mainQuery.includes(item))
: mainQuery;
if (found.includes(this.element)) {
throw new Error(`Don't search for your test component, it is automatically returned by the shallow renderer`);
}
return (0, query_match_1.createQueryMatch)(found);
};
/**
* Search for a component by it's class
*
* The result is either an instance of the component OR an Array of component instances. Your test
* must give proper treatment to the result based on the expected results.
*
* For example, if your test expects a single result, you may treat the result as a single component instance or an array of instances with one entry.
*
* @example
* expect(find(ItemComponent).label).toBe('Foo');
*
* // If your query results in multiple matches, you may iterate over the matches but if you attempt
* // to treat the collection of matches as a single match, the test will fail due to a mismatched
* // usage of the query results in the test.
*
* // This would throw an error if the query resulted in multiple matches
* expect(findComponent(ItemComponent).label).toBe('Foo');
*
* const results = findComponent(ItemComponent);
* expect(results.length).toBe(3);
* expect(results.map(result => result.label)).toEqual([
* 'Foo',
* 'Bar',
* 'Baz'
* ])
*
* @link https://getsaf.github.io/shallow-render/#querying
*/
this.findComponent = (component, options) => this.findDirective(component, options);
/**
* Search for a directive by it's class
*
* Note: For structural directives, @see Rendering#findStructuralDirective
*
* The result is either an instance of the directive OR an Array of directive instances. Your test
* must give proper treatment to the result based on the expected results.
*
* For example, if your test expects a single result, you may treat the result as a single directive instance or an array of instances with one entry.
*
* @example
* expect(findDirective(MyDirective).label).toBe('Foo');
*
* // If your query results in multiple matches, you may iterate over the matches but if you attempt
* // to treat the collection of matches as a single match, the test will fail due to a mismatched
* // usage of the query results in the test.
*
* // This would throw an error if the query resulted in multiple matches
* expect(findDirective(MyDirective).label).toBe('Foo');
*
* const results = findDirective(MyDirective);
* expect(results.length).toBe(3);
* expect(results.map(result => result.label)).toEqual([
* 'Foo',
* 'Bar',
* 'Baz'
* ])
*
* @link https://getsaf.github.io/shallow-render/#querying
*/
this.findDirective = (directive, options) => {
const directiveOrMock = this._setup.mockCache.find(directive) || directive;
const foundElements = options && options.query
? this.fixture.debugElement.queryAll(platform_browser_1.By.css(options.query))
: this.find(directive, options);
const foundDirectives = foundElements
.map(result => {
try {
return result.injector.get(directiveOrMock);
}
catch (e) {
return undefined;
}
})
.filter(i => i);
if (foundDirectives.some(i => i === this.instance)) {
throw new Error(`Don't search for your test component, it is automatically returned by the shallow renderer`);
}
return (0, query_match_1.createQueryMatch)(foundDirectives);
};
/**
* @deprecated Use inject instead
*/
this.get = (queryClass) => testing_1.TestBed.inject(queryClass);
/**
* Get the instance of a provider via Angular's injection system.
*
* This is identical to `TestBed.inject`
*/
this.inject = testing_1.TestBed.inject.bind(testing_1.TestBed);
/**
* Search for a structural directive by it's class
*
* The result is either an instance of the directive OR an Array of directive instances. Your test
* must give proper treatment to the result based on the expected results.
*
* For example, if your test expects a single result, you may treat the result as a single directive instance or an array of directives with one entry.
*
* @example
* expect(find(MyDirective).label).toBe('Foo');
*
* // If your query results in multiple matches, you may iterate over the matches but if you attempt
* // to treat the collection of matches as a single match, the test will fail due to a mismatched
* // usage of the query results in the test.
*
* // This would throw an error if the query resulted in multiple matches
* expect(findStructuralDirective(MyDirective).label).toBe('Foo');
*
* const results = findStructuralDirective(MyDirective);
* expect(results.length).toBe(3);
* expect(results.map(result => result.label)).toEqual([
* 'Foo',
* 'Bar',
* 'Baz'
* ])
*
* @link https://getsaf.github.io/shallow-render/#querying
*/
this.findStructuralDirective = (directiveClass, options) => (0, query_match_1.createQueryMatch)(this.fixture.debugElement
.queryAllNodes(node => {
try {
const instance = node.injector.get(directiveClass);
if (instance) {
return options && options.query ? options.query(instance) : true;
}
}
catch (e) { }
return false;
})
.map(node => node.injector.get(directiveClass)));
/**
* Toggle on and off the rendering of child templates into a structural directive
*
* @link https://getsaf.github.io/shallow-render/#structural-directives
*/
this.renderStructuralDirective = (directiveClassOrObject, renderContents = true) => {
const directives = typeof directiveClassOrObject === 'function'
? this.findStructuralDirective(directiveClassOrObject)
: directiveClassOrObject.length
? directiveClassOrObject
: [directiveClassOrObject];
if (!directives.length) {
throw new Error(`Tried to render a structural directive but none were found.`);
}
directives.forEach(foundDirective => {
if (!('renderContents' in foundDirective)) {
const directiveName = Object.getPrototypeOf(foundDirective).constructor.name;
throw new Error(`You may only manually render mocked directives with "renderStructuralDirective". Tried to render a structural directive (${directiveName}) but the directive is not mocked.`);
}
if (renderContents) {
foundDirective.renderContents();
}
else {
foundDirective.clearContents();
}
});
};
}
}
exports.Rendering = Rendering;
//# sourceMappingURL=rendering.js.map