@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
JavaScript
;
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