Skip to content

Commit 17eb20c

Browse files
committed
fix(@angular-devkit/schematics): throw more relevant error when Rule returns invalid null value
A `null` value is not considered a valid return value for a schematics Rule. While the Rule type should prevent this, casting could allow this to potentially occur. Previously, this would accidentally be treated the same as a void return due to incomplete result checking. However, recent refactoring caused the `null` case to fail with a non-obvious error message when it should have failed with the existing `InvalidRuleResultException`. Non-tree result objects including `null` will now fail with `InvalidRuleResultException`. (cherry picked from commit 8eb58bd)
1 parent a4f4b33 commit 17eb20c

File tree

2 files changed

+12
-26
lines changed

2 files changed

+12
-26
lines changed

packages/angular_devkit/schematics/src/rules/call.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ async function callRuleAsync(rule: Rule, tree: Tree, context: SchematicContext):
9191
result = await result.pipe(defaultIfEmpty(tree)).toPromise();
9292
}
9393

94-
if (TreeSymbol in result) {
94+
if (result && TreeSymbol in result) {
9595
return result as Tree;
9696
}
9797

packages/angular_devkit/schematics/src/rules/call_spec.ts

Lines changed: 11 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,11 @@ import {
2020
callSource,
2121
} from './call';
2222

23-
const context: SchematicContext = ({
23+
const context: SchematicContext = {
2424
engine: null,
2525
debug: false,
2626
strategy: MergeStrategy.Default,
27-
} as {}) as SchematicContext;
27+
} as {} as SchematicContext;
2828

2929
describe('callSource', () => {
3030
it('errors if undefined source', (done) => {
@@ -95,34 +95,20 @@ describe('callSource', () => {
9595
});
9696

9797
describe('callRule', () => {
98-
it('errors if invalid source object', (done) => {
99-
const tree0 = observableOf(empty());
98+
it('should throw InvalidRuleResultException when rule result is non-Tree object', async () => {
10099
const rule0: Rule = () => ({} as Tree);
101100

102-
callRule(rule0, tree0, context)
103-
.toPromise()
104-
.then(
105-
() => done.fail(),
106-
(err) => {
107-
expect(err).toEqual(new InvalidRuleResultException({}));
108-
},
109-
)
110-
.then(done, done.fail);
101+
await expectAsync(callRule(rule0, empty(), context).toPromise()).toBeRejectedWithError(
102+
InvalidRuleResultException,
103+
);
111104
});
112105

113-
it('errors if Observable of invalid source object', (done) => {
114-
const tree0 = observableOf(empty());
115-
const rule0: Rule = () => observableOf({} as Tree);
106+
it('should throw InvalidRuleResultException when rule result is null', async () => {
107+
const rule0: Rule = () => null as unknown as Tree;
116108

117-
callRule(rule0, tree0, context)
118-
.toPromise()
119-
.then(
120-
() => done.fail(),
121-
(err) => {
122-
expect(err).toEqual(new InvalidRuleResultException({}));
123-
},
124-
)
125-
.then(done, done.fail);
109+
await expectAsync(callRule(rule0, empty(), context).toPromise()).toBeRejectedWithError(
110+
InvalidRuleResultException,
111+
);
126112
});
127113

128114
it('works with undefined result', (done) => {

0 commit comments

Comments
 (0)