From 31dccab2da741d6ba612a9e333d25a305f2fc3bd Mon Sep 17 00:00:00 2001 From: Keen Yee Liau Date: Tue, 29 Oct 2019 16:32:18 -0700 Subject: [PATCH] test(language-service): Completions test should reuse existing host and services (#33478) Reusing the single instance of MockHost and language services makes the tests run much faster. PR Close #33478 --- .../language-service/test/completions_spec.ts | 346 +++++++++--------- 1 file changed, 169 insertions(+), 177 deletions(-) diff --git a/packages/language-service/test/completions_spec.ts b/packages/language-service/test/completions_spec.ts index 6795b97a50..b6ec2ac2a7 100644 --- a/packages/language-service/test/completions_spec.ts +++ b/packages/language-service/test/completions_spec.ts @@ -9,7 +9,7 @@ import * as ts from 'typescript'; import {createLanguageService} from '../src/language_service'; -import {CompletionKind, LanguageService} from '../src/types'; +import {CompletionKind} from '../src/types'; import {TypeScriptServiceHost} from '../src/typescript_host'; import {MockTypescriptHost} from './test_utils'; @@ -25,6 +25,8 @@ describe('completions', () => { const ngHost = new TypeScriptServiceHost(mockHost, tsLS); const ngLS = createLanguageService(ngHost); + beforeEach(() => { mockHost.reset(); }); + it('should be able to get entity completions', () => { const marker = mockHost.getLocationMarkerFor(APP_COMPONENT, 'entity-amp'); const completions = ngLS.getCompletionsAt(APP_COMPONENT, marker.start); @@ -370,192 +372,182 @@ describe('completions', () => { // expectContain(completions, CompletionKind.PROPERTY, ['innerText']); // }); }); -}); -describe('replace completions correctly', () => { - const mockHost = new MockTypescriptHost(['/app/main.ts']); - let ngLS: LanguageService; + describe('replacement span', () => { + it('should not generate replacement entries for zero-length replacements', () => { + const fileName = mockHost.addCode(` + @Component({ + selector: 'foo-component', + template: \` +
{{obj.~{key}}}
+ \`, + }) + export class FooComponent { + obj: {key: 'value'}; + } + `); + const location = mockHost.getLocationMarkerFor(fileName, 'key'); + const completions = ngLS.getCompletionsAt(fileName, location.start) !; + expect(completions).toBeDefined(); + const completion = completions.entries.find(entry => entry.name === 'key') !; + expect(completion).toBeDefined(); + expect(completion.kind).toBe('property'); + expect(completion.replacementSpan).toBeUndefined(); + }); - beforeEach(() => { - mockHost.reset(); - const tsLS = ts.createLanguageService(mockHost); - const ngHost = new TypeScriptServiceHost(mockHost, tsLS); - ngLS = createLanguageService(ngHost); - }); + it('should work for start of template', () => { + const fileName = mockHost.addCode(` + @Component({ + selector: 'foo-component', + template: \`~{start}abc\`, + }) + export class FooComponent {} + `); + const location = mockHost.getLocationMarkerFor(fileName, 'start'); + const completions = ngLS.getCompletionsAt(fileName, location.start) !; + expect(completions).toBeDefined(); + const completion = completions.entries.find(entry => entry.name === 'acronym') !; + expect(completion).toBeDefined(); + expect(completion.kind).toBe('html element'); + expect(completion.replacementSpan).toEqual({start: location.start, length: 3}); + }); - it('should not generate replacement entries for zero-length replacements', () => { - const fileName = mockHost.addCode(` - @Component({ - selector: 'foo-component', - template: \` -
{{obj.~{key}}}
- \`, - }) - export class FooComponent { - obj: {key: 'value'}; - } - `); - const location = mockHost.getLocationMarkerFor(fileName, 'key'); - const completions = ngLS.getCompletionsAt(fileName, location.start) !; - expect(completions).toBeDefined(); - const completion = completions.entries.find(entry => entry.name === 'key') !; - expect(completion).toBeDefined(); - expect(completion.kind).toBe('property'); - expect(completion.replacementSpan).toBeUndefined(); - }); + it('should work for end of template', () => { + const fileName = mockHost.addCode(` + @Component({ + selector: 'foo-component', + template: \`acro~{end}\`, + }) + export class FooComponent {} + `); + const location = mockHost.getLocationMarkerFor(fileName, 'end'); + const completions = ngLS.getCompletionsAt(fileName, location.start) !; + expect(completions).toBeDefined(); + const completion = completions.entries.find(entry => entry.name === 'acronym') !; + expect(completion).toBeDefined(); + expect(completion.kind).toBe('html element'); + expect(completion.replacementSpan).toEqual({start: location.start - 4, length: 4}); + }); - it('should work for start of template', () => { - const fileName = mockHost.addCode(` - @Component({ - selector: 'foo-component', - template: \`~{start}abc\`, - }) - export class FooComponent {} - `); - const location = mockHost.getLocationMarkerFor(fileName, 'start'); - const completions = ngLS.getCompletionsAt(fileName, location.start) !; - expect(completions).toBeDefined(); - const completion = completions.entries.find(entry => entry.name === 'acronym') !; - expect(completion).toBeDefined(); - expect(completion.kind).toBe('html element'); - expect(completion.replacementSpan).toEqual({start: location.start, length: 3}); - }); + it('should work for middle-word replacements', () => { + const fileName = mockHost.addCode(` + @Component({ + selector: 'foo-component', + template: \` +
{{obj.ke~{key}key}}
+ \`, + }) + export class FooComponent { + obj: {key: 'value'}; + } + `); + const location = mockHost.getLocationMarkerFor(fileName, 'key'); + const completions = ngLS.getCompletionsAt(fileName, location.start) !; + expect(completions).toBeDefined(); + const completion = completions.entries.find(entry => entry.name === 'key') !; + expect(completion).toBeDefined(); + expect(completion.kind).toBe('property'); + expect(completion.replacementSpan).toEqual({start: location.start - 2, length: 5}); + }); - it('should work for end of template', () => { - const fileName = mockHost.addCode(` - @Component({ - selector: 'foo-component', - template: \`acro~{end}\`, - }) - export class FooComponent {} - `); - const location = mockHost.getLocationMarkerFor(fileName, 'end'); - const completions = ngLS.getCompletionsAt(fileName, location.start) !; - expect(completions).toBeDefined(); - const completion = completions.entries.find(entry => entry.name === 'acronym') !; - expect(completion).toBeDefined(); - expect(completion.kind).toBe('html element'); - expect(completion.replacementSpan).toEqual({start: location.start - 4, length: 4}); - }); + it('should work for all kinds of identifier characters', () => { + const fileName = mockHost.addCode(` + @Component({ + selector: 'foo-component', + template: \` +
{{~{field}$title_1}}
+ \`, + }) + export class FooComponent { + $title_1: string; + } + `); + const location = mockHost.getLocationMarkerFor(fileName, 'field'); + const completions = ngLS.getCompletionsAt(fileName, location.start) !; + expect(completions).toBeDefined(); + const completion = completions.entries.find(entry => entry.name === '$title_1') !; + expect(completion).toBeDefined(); + expect(completion.kind).toBe('property'); + expect(completion.replacementSpan).toEqual({start: location.start, length: 8}); + }); - it('should work for middle-word replacements', () => { - const fileName = mockHost.addCode(` - @Component({ - selector: 'foo-component', - template: \` -
{{obj.ke~{key}key}}
- \`, - }) - export class FooComponent { - obj: {key: 'value'}; - } - `); - const location = mockHost.getLocationMarkerFor(fileName, 'key'); - const completions = ngLS.getCompletionsAt(fileName, location.start) !; - expect(completions).toBeDefined(); - const completion = completions.entries.find(entry => entry.name === 'key') !; - expect(completion).toBeDefined(); - expect(completion.kind).toBe('property'); - expect(completion.replacementSpan).toEqual({start: location.start - 2, length: 5}); - }); + it('should work for attributes', () => { + const fileName = mockHost.addCode(` + @Component({ + selector: 'foo-component', + template: \` +
+ \`, + }) + export class FooComponent {} + `); + const location = mockHost.getLocationMarkerFor(fileName, 'click'); + const completions = ngLS.getCompletionsAt(fileName, location.start) !; + expect(completions).toBeDefined(); + const completion = completions.entries.find(entry => entry.name === '(click)') !; + expect(completion).toBeDefined(); + expect(completion.kind).toBe('attribute'); + expect(completion.replacementSpan).toEqual({start: location.start - 2, length: 2}); + }); - it('should work for all kinds of identifier characters', () => { - const fileName = mockHost.addCode(` - @Component({ - selector: 'foo-component', - template: \` -
{{~{field}$title_1}}
- \`, - }) - export class FooComponent { - $title_1: string; - } - `); - const location = mockHost.getLocationMarkerFor(fileName, 'field'); - const completions = ngLS.getCompletionsAt(fileName, location.start) !; - expect(completions).toBeDefined(); - const completion = completions.entries.find(entry => entry.name === '$title_1') !; - expect(completion).toBeDefined(); - expect(completion.kind).toBe('property'); - expect(completion.replacementSpan).toEqual({start: location.start, length: 8}); - }); + it('should work for events', () => { + const fileName = mockHost.addCode(` + @Component({ + selector: 'foo-component', + template: \` +
+ \`, + }) + export class FooComponent { + handleClick() {} + } + `); + const location = mockHost.getLocationMarkerFor(fileName, 'handleClick'); + const completions = ngLS.getCompletionsAt(fileName, location.start) !; + expect(completions).toBeDefined(); + const completion = completions.entries.find(entry => entry.name === 'handleClick') !; + expect(completion).toBeDefined(); + expect(completion.kind).toBe('method'); + expect(completion.replacementSpan).toEqual({start: location.start - 3, length: 3}); + }); - it('should work for attributes', () => { - const fileName = mockHost.addCode(` - @Component({ - selector: 'foo-component', - template: \` -
- \`, - }) - export class FooComponent {} - `); - const location = mockHost.getLocationMarkerFor(fileName, 'click'); - const completions = ngLS.getCompletionsAt(fileName, location.start) !; - expect(completions).toBeDefined(); - const completion = completions.entries.find(entry => entry.name === '(click)') !; - expect(completion).toBeDefined(); - expect(completion.kind).toBe('attribute'); - expect(completion.replacementSpan).toEqual({start: location.start - 2, length: 2}); - }); + it('should work for element names', () => { + const fileName = mockHost.addCode(` + @Component({ + selector: 'foo-component', + template: \` + + \`, + }) + export class FooComponent {} + `); + const location = mockHost.getLocationMarkerFor(fileName, 'div'); + const completions = ngLS.getCompletionsAt(fileName, location.start) !; + expect(completions).toBeDefined(); + const completion = completions.entries.find(entry => entry.name === 'div') !; + expect(completion).toBeDefined(); + expect(completion.kind).toBe('html element'); + expect(completion.replacementSpan).toEqual({start: location.start - 2, length: 2}); + }); - it('should work for events', () => { - const fileName = mockHost.addCode(` - @Component({ - selector: 'foo-component', - template: \` -
- \`, - }) - export class FooComponent { - handleClick() {} - } - `); - const location = mockHost.getLocationMarkerFor(fileName, 'handleClick'); - const completions = ngLS.getCompletionsAt(fileName, location.start) !; - expect(completions).toBeDefined(); - const completion = completions.entries.find(entry => entry.name === 'handleClick') !; - expect(completion).toBeDefined(); - expect(completion.kind).toBe('method'); - expect(completion.replacementSpan).toEqual({start: location.start - 3, length: 3}); - }); - - it('should work for element names', () => { - const fileName = mockHost.addCode(` - @Component({ - selector: 'foo-component', - template: \` - - \`, - }) - export class FooComponent {} - `); - const location = mockHost.getLocationMarkerFor(fileName, 'div'); - const completions = ngLS.getCompletionsAt(fileName, location.start) !; - expect(completions).toBeDefined(); - const completion = completions.entries.find(entry => entry.name === 'div') !; - expect(completion).toBeDefined(); - expect(completion.kind).toBe('html element'); - expect(completion.replacementSpan).toEqual({start: location.start - 2, length: 2}); - }); - - it('should work for bindings', () => { - const fileName = mockHost.addCode(` - @Component({ - selector: 'foo-component', - template: \` + it('should work for bindings', () => { + const fileName = mockHost.addCode(` + @Component({ + selector: 'foo-component', + template: \` - \`, - }) - export class FooComponent {} - `); - const location = mockHost.getLocationMarkerFor(fileName, 'model'); - const completions = ngLS.getCompletionsAt(fileName, location.start) !; - expect(completions).toBeDefined(); - const completion = completions.entries.find(entry => entry.name === '[(ngModel)]') !; - expect(completion).toBeDefined(); - expect(completion.kind).toBe('attribute'); - expect(completion.replacementSpan).toEqual({start: location.start - 5, length: 5}); + \`, + }) + export class FooComponent {} + `); + const location = mockHost.getLocationMarkerFor(fileName, 'model'); + const completions = ngLS.getCompletionsAt(fileName, location.start) !; + expect(completions).toBeDefined(); + const completion = completions.entries.find(entry => entry.name === '[(ngModel)]') !; + expect(completion).toBeDefined(); + expect(completion.kind).toBe('attribute'); + expect(completion.replacementSpan).toEqual({start: location.start - 5, length: 5}); + }); }); });