Open catfireparty opened 4 years ago
Hi, I think the problem here is that the destination folder (libs) doesn't exist.
@alan-agius4 If you check the linked repo, running the schematic fully succeeds. The problem is in the missing context when using callRule
. It's not clear what that missing context should be in the case of a unit test.
Having hit the same issue with a rule I'm working on and from digging in, it looks like it is due to the fact that the callRule
method in the test runner doesn't create a real Schematic, but just passes in an empty object:
Eventually that empty schematic
wends its way here:
Finally, when the file system engine tries to get the path from the schematic, it blows up, as description
is not defined:
I think the callRule
method would need to provide a way to override or extend that empty schematic object to make this work.
We had the same problem described below and the only solution that we found was to create a CustomSchematicTestRunner that extends the angular-devkit SchematicTestRunner. This custom class exposes a new method that allows to pass a test schematic and context as parameters :
/**
* Custom Schematic Test Runner
*/
import { Observable, of as observableOf } from 'rxjs';
import {SchematicTestRunner} from "@angular-devkit/schematics/testing";
import {callRule, Rule, Schematic, SchematicContext, Tree} from "@angular-devkit/schematics";
export class CustomSchematicTestRunner extends SchematicTestRunner{
constructor(collectionName: string, collectionPath: string) {
super(collectionName, collectionPath);
}
/**
* Calls a schematics Rule using an isolated context and the schematics passed in as parameter
* @param rule
* @param tree
* @param schematic
* @param parentContext
*/
callSchematicsRule(rule: Rule, tree: Tree, schematic: Schematic<{}, {}>, parentContext?: Partial<SchematicContext>): Observable<Tree> {
const context = this.engine.createContext(schematic, parentContext);
return callRule(rule, observableOf(tree), context);
}
}
And in the Rule's unit test the schematic and the context were setted in a beforeEach function as follows :
schematicTest = {
description : {
name: "Test schematic",
path: "src/init"
}
};
testContext = {
debug: true,
engine: this,
logger:
new logging.NullLogger(),
schematicTest,
strategy: MergeStrategy.Default,
};
And the final test looks like :
it('should create a jenkinsfile', async () => {
const tree = await schematicRunner
.callSchematicsRule(createJenkinsfile(), appTree, schematicTest as Schematic<{}, {}>, testContext)
.toPromise();
expect(tree.exists("Jenkinsfile")).toBeTrue();
});
Hope this technique helps and let you unit test your schematic's Rules waiting for an official fix.
Addendum
In creating the test case I've realised that I'm not passing a
partialContext
tocallRule
, so it is definitely missing context, however, it is not at all clear what context is necessary formergeWith
to succeed and the error does not indicate that context is actually missing.Happy for this to be marked as a question instead. Guidance on how to provide the context and what context to provide would be amazingly useful.
🐞 Bug report
Description
Using
callRule
to unit test rules within a schematic fails when it comes to rules which returnmergeWith
🔬 Minimal Reproduction
See: https://github.com/jdpearce/schematics-apply-problem
Given a rule which applies template files to the tree, this unit test will fail with
TypeError: Cannot read property 'path' of undefined
:🔥 Exception or Error
🌍 Your Environment