UNPKG

@o3r/testing

Version:

The module provides testing (e2e, unit test) utilities to help you build your own E2E pipeline integrating visual testing.

162 lines 5.96 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.generateMockComponent = generateMockComponent; var tslib_1 = require("tslib"); var core_1 = require("@angular/core"); var forms_1 = require("@angular/forms"); var ts = require("typescript"); /** * Determine if the node in an input field * @param node Typescript AST Node * @param source Typescript source file */ function isInputNode(node, source) { return ts.isDecorator(node) && node.getText(source).startsWith('@Input'); } /** * Determine if the node in an output field * @param node Typescript AST Node * @param source Typescript source file */ function isOutputNode(node, source) { return ts.isDecorator(node) && node.getText(source).startsWith('@Output'); } /** * Get the name of the input / output * @param currentNode Typescript AST Node * @param decorator Current Input/Output decorator node * @param source Typescript source file */ function getIOName(currentNode, decorator, source) { var nameInDecorator = decorator.getText(source).match(/@(input|output) *\( *(["'](.*)["'])? *\) */i); if (nameInDecorator && nameInDecorator[3]) { return nameInDecorator[3]; } else { var name_1; currentNode.forEachChild(function (node) { if (ts.isIdentifier(node)) { name_1 = node.getText(source); } }); return name_1; } } /** * Get the list of Input and Output of a component * @param parentNode Typescript AST Node * @param source Typescript source file */ function parseIO(parentNode, source) { var outputs = []; var inputs = []; parentNode.forEachChild(function (node) { if (isInputNode(node, source)) { var name_2 = getIOName(parentNode, node, source); if (name_2) { inputs.push(name_2); } } else if (isOutputNode(node, source)) { var name_3 = getIOName(parentNode, node, source); if (name_3) { outputs.push(name_3); } } else { var childrenResult = parseIO(node, source); inputs.push.apply(inputs, childrenResult.inputs); outputs.push.apply(outputs, childrenResult.outputs); } }); return { outputs: outputs, inputs: inputs }; } /** * Get the selector of an angular class * @param parentNode Typescript AST Node * @param source Typescript source file * @param isInDecorator true if the recursive execution is in a decorator * @param isInComponentConfig true if the recursive execution is in a component decorator configuration */ function getSelector(parentNode, source, isInDecorator, isInComponentConfig) { if (isInDecorator === void 0) { isInDecorator = false; } if (isInComponentConfig === void 0) { isInComponentConfig = false; } var foundDecorator = false; var foundSelector = false; var ret; parentNode.forEachChild(function (node) { if (isInDecorator && isInComponentConfig && ts.isIdentifier(node) && node.getText(source) === 'selector') { foundSelector = true; } else if (foundSelector && ts.isStringLiteral(node)) { ret = node.getText(source).replace(/["']/gi, ''); } else if (isInDecorator && ts.isIdentifier(node) && node.getText(source) === 'Component') { foundDecorator = true; } else if (isInDecorator && foundDecorator && ts.isObjectLiteralExpression(node)) { ret = ret || getSelector(node, source, isInDecorator, true); } else { ret = ret || getSelector(node, source, isInDecorator || ts.isDecorator(node), isInComponentConfig); } }); return ret; } /** * Generate a mock class base on a component file * @param componentPath Path to the component file to mock * @param config Object containing the following configurations: * template: should be provided if the template contain `<ng-content></ng-content>` * isControlValueAccessor: should be provided if the component extends ControlValueAccessor * @param config.template * @param config.isControlValueAccessor * @example * ```typescript * // hero.component.ts * \@Component({selector: 'hero'}) * class HeroComponent { * \@Input() name: string; * \@Output() doSomething: EventEmitter<void> * } * * // mock generation * class MockComponent extends generateMockComponent('hero.component.ts') {} * ``` */ function generateMockComponent(componentPath, config) { var program = ts.createProgram([componentPath], {}); var source = program.getSourceFile(componentPath); if (!source) { throw new Error('No Source found'); } var _a = parseIO(source, source), outputs = _a.outputs, inputs = _a.inputs; var mock = /** @class */ (function () { function class_1() { var _this = this; Object.keys(outputs) .forEach(function (outputName) { return _this[outputName] = new core_1.EventEmitter(); }); if (config && config.isControlValueAccessor) { this.writeValue = function () { }; this.registerOnChange = function () { }; this.registerOnTouched = function () { }; } } return class_1; }()); return (0, core_1.Component)(tslib_1.__assign({ template: (config === null || config === void 0 ? void 0 : config.template) || '', selector: getSelector(source, source) || '', inputs: inputs, outputs: outputs }, (config && config.isControlValueAccessor) ? { providers: [ { provide: forms_1.NG_VALUE_ACCESSOR, useExisting: (0, core_1.forwardRef)(function () { return mock; }), multi: true } ] } : {}))(mock); } //# sourceMappingURL=mock-component-generator.js.map