Skip to content

Commit 02fdd8d

Browse files
devversionthePunderWoman
authored andcommitted
test: add tests to verify language-service supports output() function (#54217)
Adds unit tests to verify that the language service supports the `output()` function with completions, and definition jumping. PR Close #54217
1 parent ee635f9 commit 02fdd8d

File tree

3 files changed

+95
-4
lines changed

3 files changed

+95
-4
lines changed

packages/language-service/test/completions_spec.ts

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,52 @@ describe('completions', () => {
342342
});
343343
});
344344

345+
describe('initializer-based output() API', () => {
346+
const initializerOutputDirectiveWithUnionType = {
347+
'Dir': `
348+
@Directive({
349+
selector: '[dir]',
350+
})
351+
export class Dir {
352+
bla = output<string>();
353+
}
354+
`
355+
};
356+
357+
it('should return event completion', () => {
358+
const {templateFile} =
359+
setup(`<button dir ></button>`, ``, initializerOutputDirectiveWithUnionType);
360+
templateFile.moveCursorToText(`<button dir ¦>`);
361+
const completions = templateFile.getCompletionsAtPosition();
362+
expectContain(completions, DisplayInfoKind.EVENT, ['(bla)']);
363+
});
364+
365+
it('should return property access completions', () => {
366+
const {templateFile} =
367+
setup(`<input dir (bla)="'foo'.">`, '', initializerOutputDirectiveWithUnionType);
368+
templateFile.moveCursorToText(`dir (bla)="'foo'.¦">`);
369+
370+
const completions = templateFile.getCompletionsAtPosition();
371+
expectContain(
372+
completions, ts.ScriptElementKind.memberFunctionElement,
373+
[`charAt`, 'toLowerCase', /* etc. */]);
374+
});
375+
376+
it('should return completions of string literals, number literals, `true`, ' +
377+
'`false`, `null` and `undefined`',
378+
() => {
379+
const {templateFile} =
380+
setup(`<input dir (bla)="$event.">`, '', initializerOutputDirectiveWithUnionType);
381+
templateFile.moveCursorToText('dir (bla)="$event.¦">');
382+
383+
const completions = templateFile.getCompletionsAtPosition();
384+
385+
expectContain(
386+
completions, ts.ScriptElementKind.memberFunctionElement,
387+
[`charAt`, 'toLowerCase', /* etc. */]);
388+
});
389+
});
390+
345391
describe('for blocks', () => {
346392
const completionPrefixes = ['@', '@i'];
347393

@@ -1634,7 +1680,7 @@ function setup(
16341680
const env = LanguageServiceTestEnv.setup();
16351681
const project = env.addProject('test', {
16361682
'test.ts': `
1637-
import {Component, input, Directive, NgModule, Pipe, TemplateRef} from '@angular/core';
1683+
import {Component, input, output, Directive, NgModule, Pipe, TemplateRef} from '@angular/core';
16381684
16391685
${functionDeclarations}
16401686

packages/language-service/test/definitions_spec.ts

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,13 @@ describe('definitions', () => {
171171
export class MyDir2 {
172172
@Output() someEvent = new EventEmitter<void>();
173173
}`,
174+
'dir3.ts': `
175+
import {Directive, output, EventEmitter} from '@angular/core';
176+
177+
@Directive({selector: '[dir]'})
178+
export class MyDir3 {
179+
someEvent = output();
180+
}`,
174181
'app.ts': `
175182
import {Component, NgModule} from '@angular/core';
176183
import {CommonModule} from '@angular/common';
@@ -190,13 +197,15 @@ describe('definitions', () => {
190197
expect(template.contents.slice(textSpan.start, textSpan.start + textSpan.length))
191198
.toEqual('someEvent');
192199

193-
expect(definitions.length).toEqual(2);
194-
const [def, def2] = definitions;
200+
expect(definitions.length).toEqual(3);
201+
const [def3, def2, def] = definitions;
195202
expect(def.textSpan).toContain('someEvent');
196203
expect(def2.textSpan).toContain('someEvent');
204+
expect(def3.textSpan).toContain('someEvent');
205+
expect(def3.contextSpan!).toBe('someEvent = output();');
197206
// TODO(atscott): investigate why the text span includes more than just 'someEvent'
198207
// assertTextSpans([def, def2], ['someEvent']);
199-
assertFileNames([def, def2], ['dir2.ts', 'dir.ts']);
208+
assertFileNames([def3, def2, def], ['dir3.ts', 'dir2.ts', 'dir.ts']);
200209
});
201210

202211
it('should go to the pre-compiled style sheet', () => {

packages/language-service/test/type_definitions_spec.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,42 @@ describe('type definitions', () => {
7474
});
7575
});
7676

77+
describe('initializer-based output() API', () => {
78+
it('return the definition for an output', () => {
79+
initMockFileSystem('Native');
80+
const files = {
81+
'app.ts': `
82+
import {Component, Directive, output} from '@angular/core';
83+
84+
@Directive({
85+
selector: 'my-dir',
86+
standalone: true
87+
})
88+
export class MyDir {
89+
nameChanges = output<string>();
90+
}
91+
92+
@Component({
93+
templateUrl: 'app.html',
94+
standalone: true,
95+
imports: [MyDir],
96+
})
97+
export class AppCmp {
98+
doSmth() {}
99+
}
100+
`,
101+
'app.html': `Will be overridden`,
102+
};
103+
env = LanguageServiceTestEnv.setup();
104+
const project = env.addProject('test', files);
105+
const definitions = getTypeDefinitionsAndAssertBoundSpan(
106+
project, {templateOverride: `<my-dir (name¦Changes)="doSmth()" />`});
107+
expect(definitions!.length).toEqual(1);
108+
109+
assertTextSpans(definitions, ['EventEmitter']);
110+
assertFileNames(definitions, ['index.d.ts']);
111+
});
112+
});
77113

78114
function getTypeDefinitionsAndAssertBoundSpan(
79115
project: Project, {templateOverride}: {templateOverride: string}) {

0 commit comments

Comments
 (0)