155 lines
5.7 KiB
TypeScript
155 lines
5.7 KiB
TypeScript
/**
|
|
* @license
|
|
* Copyright Google LLC All Rights Reserved.
|
|
*
|
|
* Use of this source code is governed by an MIT-style license that can be
|
|
* found in the LICENSE file at https://angular.io/license
|
|
*/
|
|
|
|
import * as ts from 'typescript/lib/tsserverlibrary';
|
|
|
|
import {APP_COMPONENT, APP_MAIN, setup, TEST_SRCDIR} from './mock_host';
|
|
|
|
describe('mock host', () => {
|
|
const {project, service, tsLS} = setup();
|
|
|
|
beforeEach(() => {
|
|
service.reset();
|
|
});
|
|
|
|
it('can load test project from Bazel runfiles', () => {
|
|
expect(project).toBeInstanceOf(ts.server.ConfiguredProject);
|
|
const configPath = (project as ts.server.ConfiguredProject).getConfigFilePath();
|
|
expect(configPath.substring(TEST_SRCDIR.length))
|
|
.toBe('/angular/packages/language-service/test/project/tsconfig.json');
|
|
const program = tsLS.getProgram();
|
|
expect(program).toBeDefined();
|
|
const sourceFiles = program!.getSourceFiles().map(sf => {
|
|
const {fileName} = sf;
|
|
if (fileName.startsWith(TEST_SRCDIR)) {
|
|
return fileName.substring(TEST_SRCDIR.length);
|
|
}
|
|
return fileName;
|
|
});
|
|
expect(sourceFiles).toEqual(jasmine.arrayContaining([
|
|
// This shows that module resolution works
|
|
'/angular/packages/common/src/common.d.ts',
|
|
'/angular/packages/core/src/core.d.ts',
|
|
'/angular/packages/forms/src/forms.d.ts',
|
|
// This shows that project files are present
|
|
'/angular/packages/language-service/test/project/app/app.component.ts',
|
|
'/angular/packages/language-service/test/project/app/main.ts',
|
|
'/angular/packages/language-service/test/project/app/parsing-cases.ts',
|
|
]));
|
|
});
|
|
|
|
it('produces no TS error for test project', () => {
|
|
const errors = project.getAllProjectErrors();
|
|
expect(errors).toEqual([]);
|
|
const globalErrors = project.getGlobalProjectErrors();
|
|
expect(globalErrors).toEqual([]);
|
|
const diags = tsLS.getSemanticDiagnostics(APP_MAIN);
|
|
expect(diags).toEqual([]);
|
|
});
|
|
|
|
it('can overwrite test file', () => {
|
|
service.overwrite(APP_MAIN, `const x: string = 0`);
|
|
const scriptInfo = service.getScriptInfo(APP_MAIN);
|
|
expect(getText(scriptInfo)).toBe('const x: string = 0');
|
|
});
|
|
|
|
describe('overwrite()', () => {
|
|
it('will return the cursor position', () => {
|
|
const {position} = service.overwrite(APP_MAIN, `const fo¦o = 'hello world';`);
|
|
expect(position).toBe(8);
|
|
});
|
|
|
|
it('will remove the cursor in overwritten text', () => {
|
|
const {text} = service.overwrite(APP_MAIN, `const fo¦o = 'hello world';`);
|
|
expect(text).toBe(`const foo = 'hello world';`);
|
|
});
|
|
|
|
it('will update script info without cursor', () => {
|
|
const {text} = service.overwrite(APP_MAIN, `const fo¦o = 'hello world';`);
|
|
const scriptInfo = service.getScriptInfo(APP_MAIN);
|
|
const snapshot = getText(scriptInfo);
|
|
expect(snapshot).toBe(`const foo = 'hello world';`);
|
|
expect(snapshot).toBe(text);
|
|
});
|
|
|
|
it('will throw if there is more than one cursor', () => {
|
|
expect(() => service.overwrite(APP_MAIN, `const f¦oo = 'hello wo¦rld';`))
|
|
.toThrowError(/matches more than one occurrence in text/);
|
|
});
|
|
|
|
it('will return -1 if cursor is not present', () => {
|
|
const {position} = service.overwrite(APP_MAIN, `const foo = 'hello world';`);
|
|
expect(position).toBe(-1);
|
|
});
|
|
});
|
|
|
|
describe('overwriteInlineTemplate()', () => {
|
|
it('will return the cursor position', () => {
|
|
const {position, text} = service.overwriteInlineTemplate(APP_COMPONENT, `{{ fo¦o }}`);
|
|
// The position returned should be relative to the start of the source
|
|
// file, not the start of the template.
|
|
expect(position).not.toBe(5);
|
|
expect(text.substring(position, position + 4)).toBe('o }}');
|
|
});
|
|
|
|
it('will remove the cursor in overwritten text', () => {
|
|
const {text} = service.overwriteInlineTemplate(APP_COMPONENT, `{{ fo¦o }}`);
|
|
expect(text).toContain(`{{ foo }}`);
|
|
});
|
|
|
|
it('will return the entire content of the source file', () => {
|
|
const {text} = service.overwriteInlineTemplate(APP_COMPONENT, `{{ foo }}`);
|
|
expect(text).toContain(`@Component`);
|
|
});
|
|
|
|
it('will update script info without cursor', () => {
|
|
service.overwriteInlineTemplate(APP_COMPONENT, `{{ fo¦o }}`);
|
|
const scriptInfo = service.getScriptInfo(APP_COMPONENT);
|
|
expect(getText(scriptInfo)).toContain(`{{ foo }}`);
|
|
});
|
|
|
|
it('will throw if there is no template in file', () => {
|
|
expect(() => service.overwriteInlineTemplate(APP_MAIN, `{{ foo }}`))
|
|
.toThrowError(/does not contain a component with template/);
|
|
});
|
|
|
|
it('will throw if there is more than one cursor', () => {
|
|
expect(() => service.overwriteInlineTemplate(APP_COMPONENT, `{{ f¦o¦o }}`))
|
|
.toThrowError(/matches more than one occurrence in text/);
|
|
});
|
|
|
|
it('will return -1 if cursor is not present', () => {
|
|
const {position} = service.overwriteInlineTemplate(APP_COMPONENT, `{{ foo }}`);
|
|
expect(position).toBe(-1);
|
|
});
|
|
|
|
it('will throw if there is more than one component with template', () => {
|
|
service.overwrite(APP_COMPONENT, `
|
|
import {Component} from '@angular/core';
|
|
|
|
@Component({
|
|
template: \`<h1></h1>\`,
|
|
})
|
|
export class ComponentA {}
|
|
|
|
@Component({
|
|
template: \`<h2></h2>\`,
|
|
})
|
|
export class ComponentB {}
|
|
`);
|
|
expect(() => service.overwriteInlineTemplate(APP_COMPONENT, `<p></p>`))
|
|
.toThrowError(/matches more than one occurrence in text/);
|
|
});
|
|
});
|
|
});
|
|
|
|
function getText(scriptInfo: ts.server.ScriptInfo): string {
|
|
const snapshot = scriptInfo.getSnapshot();
|
|
return snapshot.getText(0, snapshot.getLength());
|
|
}
|