Skip to content

Commit

Permalink
fix(core): do not crash for signal query that does not have any match…
Browse files Browse the repository at this point in the history
…es (#54353)

The newly introduced signal queries would error if no match exists, due to an
invalid read within the query internals.

This commit addresses the crash by allowing there to be no matches.

PR Close #54353
  • Loading branch information
JoostK authored and thePunderWoman committed Feb 9, 2024
1 parent 6c278a9 commit 62b87b4
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 3 deletions.
6 changes: 3 additions & 3 deletions packages/core/src/render3/query.ts
Expand Up @@ -354,9 +354,9 @@ function materializeViewResults<T>(
const lQuery = lView[QUERIES]!.queries![queryIndex];
if (lQuery.matches === null) {
const tViewData = tView.data;
const tQueryMatches = tQuery.matches!;
const result: T|null[] = [];
for (let i = 0; i < tQueryMatches.length; i += 2) {
const tQueryMatches = tQuery.matches;
const result: Array<T|null> = [];
for (let i = 0; tQueryMatches !== null && i < tQueryMatches.length; i += 2) {
const matchedNodeIdx = tQueryMatches[i];
if (matchedNodeIdx < 0) {
// we at the <ng-template> marker which might have results in views created based on this
Expand Down
44 changes: 44 additions & 0 deletions packages/core/test/acceptance/authoring/signal_queries_spec.ts
Expand Up @@ -183,6 +183,23 @@ describe('queries as signals', () => {
expect(result2.length).toBe(1);
expect(result2).toBe(result1);
});

it('should be empty when no query matches exist', () => {
@Component({
standalone: true,
template: ``,
})
class AppComponent {
result = viewChild('unknown');
results = viewChildren('unknown');
}

const fixture = TestBed.createComponent(AppComponent);
fixture.detectChanges();

expect(fixture.componentInstance.result()).toBeUndefined();
expect(fixture.componentInstance.results().length).toBe(0);
});
});

describe('content queries', () => {
Expand Down Expand Up @@ -319,5 +336,32 @@ describe('queries as signals', () => {

expect(queryDir.results().length).toBe(2);
});

it('should be empty when no query matches exist', () => {
@Directive({
selector: '[declare]',
standalone: true,
})
class DeclareQuery {
result = contentChild('unknown');
results = contentChildren('unknown');
}

@Component({
standalone: true,
imports: [DeclareQuery],
template: `<div declare></div>`,
})
class AppComponent {
}

const fixture = TestBed.createComponent(AppComponent);
fixture.detectChanges();
const queryDir =
fixture.debugElement.query(By.directive(DeclareQuery)).injector.get(DeclareQuery);

expect(queryDir.result()).toBeUndefined();
expect(queryDir.results().length).toBe(0);
});
});
});

0 comments on commit 62b87b4

Please sign in to comment.