mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-11 19:27:35 -06:00
Sym links into single test
This commit is contained in:
parent
5234b8b18e
commit
9e17a66151
@ -93,6 +93,7 @@
|
||||
"unittests/tsserverProjectLoadingEvents.ts",
|
||||
"unittests/tsserverProjectSystem.ts",
|
||||
"unittests/tsserverProjectUpdatedInBackgroundEvent.ts",
|
||||
"unittests/tsserverSymLinks.ts",
|
||||
"unittests/typingsInstaller.ts",
|
||||
"unittests/versionCache.ts",
|
||||
"unittests/watchEnvironment.ts",
|
||||
|
||||
@ -482,14 +482,15 @@ namespace ts.projectSystem {
|
||||
const toLocation = protocolToLocation(str);
|
||||
return { start: toLocation(span.start), end: toLocation(textSpanEnd(span)) };
|
||||
}
|
||||
//function protocolRenameSpanFromSubstring(
|
||||
// str: string,
|
||||
// substring: string,
|
||||
// options?: SpanFromSubstringOptions,
|
||||
// prefixSuffixText?: { readonly prefixText?: string, readonly suffixText?: string },
|
||||
//): protocol.RenameTextSpan {
|
||||
// return { ...protocolTextSpanFromSubstring(str, substring, options), ...prefixSuffixText };
|
||||
//}
|
||||
|
||||
export function protocolRenameSpanFromSubstring(
|
||||
str: string,
|
||||
substring: string,
|
||||
options?: SpanFromSubstringOptions,
|
||||
prefixSuffixText?: { readonly prefixText?: string, readonly suffixText?: string },
|
||||
): protocol.RenameTextSpan {
|
||||
return { ...protocolTextSpanFromSubstring(str, substring, options), ...prefixSuffixText };
|
||||
}
|
||||
|
||||
export function textSpanFromSubstring(str: string, substring: string, options?: SpanFromSubstringOptions): TextSpan {
|
||||
const start = nthIndexOf(str, substring, options ? options.index : 0);
|
||||
|
||||
@ -7,14 +7,6 @@ namespace ts.projectSystem {
|
||||
checkArray("ScriptInfos files", arrayFrom(projectService.filenameToScriptInfo.values(), info => info.fileName), expectedFiles);
|
||||
}
|
||||
|
||||
function protocolRenameSpanFromSubstring(
|
||||
str: string,
|
||||
substring: string,
|
||||
options?: SpanFromSubstringOptions,
|
||||
prefixSuffixText?: { readonly prefixText?: string, readonly suffixText?: string },
|
||||
): protocol.RenameTextSpan {
|
||||
return { ...protocolTextSpanFromSubstring(str, substring, options), ...prefixSuffixText };
|
||||
}
|
||||
function protocolFileLocationFromSubstring(file: File, substring: string): protocol.FileLocationRequestArgs {
|
||||
return { file: file.path, ...protocolLocationFromSubstring(file.content, substring) };
|
||||
}
|
||||
@ -5144,287 +5136,6 @@ var x = 10;`
|
||||
});
|
||||
});
|
||||
|
||||
describe("tsserverProjectSystem with symLinks", () => {
|
||||
it("rename in common file renames all project", () => {
|
||||
const projects = "/users/username/projects";
|
||||
const folderA = `${projects}/a`;
|
||||
const aFile: File = {
|
||||
path: `${folderA}/a.ts`,
|
||||
content: `import {C} from "./c/fc"; console.log(C)`
|
||||
};
|
||||
const aTsconfig: File = {
|
||||
path: `${folderA}/tsconfig.json`,
|
||||
content: JSON.stringify({ compilerOptions: { module: "commonjs" } })
|
||||
};
|
||||
const aC: SymLink = {
|
||||
path: `${folderA}/c`,
|
||||
symLink: "../c"
|
||||
};
|
||||
const aFc = `${folderA}/c/fc.ts`;
|
||||
|
||||
const folderB = `${projects}/b`;
|
||||
const bFile: File = {
|
||||
path: `${folderB}/b.ts`,
|
||||
content: `import {C} from "./c/fc"; console.log(C)`
|
||||
};
|
||||
const bTsconfig: File = {
|
||||
path: `${folderB}/tsconfig.json`,
|
||||
content: JSON.stringify({ compilerOptions: { module: "commonjs" } })
|
||||
};
|
||||
const bC: SymLink = {
|
||||
path: `${folderB}/c`,
|
||||
symLink: "../c"
|
||||
};
|
||||
const bFc = `${folderB}/c/fc.ts`;
|
||||
|
||||
const folderC = `${projects}/c`;
|
||||
const cFile: File = {
|
||||
path: `${folderC}/fc.ts`,
|
||||
content: `export const C = 8`
|
||||
};
|
||||
|
||||
const files = [cFile, libFile, aFile, aTsconfig, aC, bFile, bTsconfig, bC];
|
||||
const host = createServerHost(files);
|
||||
const session = createSession(host);
|
||||
const projectService = session.getProjectService();
|
||||
openFilesForSession(
|
||||
[
|
||||
{ file: aFile, projectRootPath: folderA },
|
||||
{ file: bFile, projectRootPath: folderB },
|
||||
{ file: aFc, projectRootPath: folderA },
|
||||
{ file: bFc, projectRootPath: folderB },
|
||||
],
|
||||
session);
|
||||
checkNumberOfProjects(projectService, { configuredProjects: 2 });
|
||||
assert.isDefined(projectService.configuredProjects.get(aTsconfig.path));
|
||||
assert.isDefined(projectService.configuredProjects.get(bTsconfig.path));
|
||||
|
||||
const response = executeSessionRequest<protocol.RenameRequest, protocol.RenameResponse>(session, protocol.CommandTypes.Rename, { file: aFc, ...protocolLocationFromSubstring(cFile.content, "C") });
|
||||
|
||||
assert.equal(aFile.content, bFile.content);
|
||||
const abLocs: protocol.RenameTextSpan[] = [
|
||||
protocolRenameSpanFromSubstring(aFile.content, "C"),
|
||||
protocolRenameSpanFromSubstring(aFile.content, "C", { index: 1 }),
|
||||
];
|
||||
const span = protocolRenameSpanFromSubstring(cFile.content, "C");
|
||||
const cLocs: protocol.RenameTextSpan[] = [span];
|
||||
assert.deepEqual<protocol.RenameResponseBody | undefined>(response, {
|
||||
info: {
|
||||
canRename: true,
|
||||
displayName: "C",
|
||||
fileToRename: undefined,
|
||||
fullDisplayName: '"/users/username/projects/a/c/fc".C',
|
||||
kind: ScriptElementKind.constElement,
|
||||
kindModifiers: ScriptElementKindModifier.exportedModifier,
|
||||
triggerSpan: protocolTextSpanFromSubstring(cFile.content, "C"),
|
||||
},
|
||||
locs: [
|
||||
{ file: aFc, locs: cLocs },
|
||||
{ file: aFile.path, locs: abLocs },
|
||||
{ file: bFc, locs: cLocs },
|
||||
{ file: bFile.path, locs: abLocs },
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
describe("module resolution when symlinked folder contents change and resolve modules", () => {
|
||||
const projectRootPath = "/users/username/projects/myproject";
|
||||
const packages = `${projectRootPath}/javascript/packages`;
|
||||
const recognizersDateTime = `${packages}/recognizers-date-time`;
|
||||
const recognizersText = `${packages}/recognizers-text`;
|
||||
const recognizersTextDist = `${recognizersText}/dist`;
|
||||
const moduleName = "@microsoft/recognizers-text";
|
||||
const moduleNameInFile = `"${moduleName}"`;
|
||||
const recognizersDateTimeSrcFile: File = {
|
||||
path: `${recognizersDateTime}/src/datetime/baseDate.ts`,
|
||||
content: `import {C} from ${moduleNameInFile};
|
||||
new C();`
|
||||
};
|
||||
const recognizerDateTimeTsconfigPath = `${recognizersDateTime}/tsconfig.json`;
|
||||
const recognizerDateTimeTsconfigWithoutPathMapping: File = {
|
||||
path: recognizerDateTimeTsconfigPath,
|
||||
content: JSON.stringify({
|
||||
include: ["src"]
|
||||
})
|
||||
};
|
||||
const recognizerDateTimeTsconfigWithPathMapping: File = {
|
||||
path: recognizerDateTimeTsconfigPath,
|
||||
content: JSON.stringify({
|
||||
compilerOptions: {
|
||||
rootDir: "src",
|
||||
baseUrl: "./",
|
||||
paths: {
|
||||
"@microsoft/*": ["../*"]
|
||||
}
|
||||
},
|
||||
include: ["src"]
|
||||
})
|
||||
};
|
||||
const nodeModulesRecorgnizersText: SymLink = {
|
||||
path: `${recognizersDateTime}/node_modules/@microsoft/recognizers-text`,
|
||||
symLink: recognizersText
|
||||
};
|
||||
const recognizerTextSrcFile: File = {
|
||||
path: `${recognizersText}/src/recognizers-text.ts`,
|
||||
content: `export class C { method () { return 10; } }`
|
||||
};
|
||||
const recongnizerTextDistTypingFile: File = {
|
||||
path: `${recognizersTextDist}/types/recognizers-text.d.ts`,
|
||||
content: `export class C { method(): number; }`
|
||||
};
|
||||
const recongnizerTextPackageJson: File = {
|
||||
path: `${recognizersText}/package.json`,
|
||||
content: JSON.stringify({
|
||||
typings: "dist/types/recognizers-text.d.ts"
|
||||
})
|
||||
};
|
||||
const filesInProjectWithUnresolvedModule = [recognizerDateTimeTsconfigPath, libFile.path, recognizersDateTimeSrcFile.path];
|
||||
const filesInProjectWithResolvedModule = [...filesInProjectWithUnresolvedModule, recongnizerTextDistTypingFile.path];
|
||||
|
||||
function verifyErrors(session: TestSession, semanticErrors: protocol.Diagnostic[]) {
|
||||
session.clearMessages();
|
||||
const expectedSequenceId = session.getNextSeq();
|
||||
session.executeCommandSeq<protocol.GeterrRequest>({
|
||||
command: server.CommandNames.Geterr,
|
||||
arguments: {
|
||||
delay: 0,
|
||||
files: [recognizersDateTimeSrcFile.path],
|
||||
}
|
||||
});
|
||||
|
||||
const host = session.host;
|
||||
host.checkTimeoutQueueLengthAndRun(1);
|
||||
|
||||
checkErrorMessage(session, "syntaxDiag", { file: recognizersDateTimeSrcFile.path, diagnostics: [] });
|
||||
session.clearMessages();
|
||||
|
||||
host.runQueuedImmediateCallbacks(1);
|
||||
|
||||
checkErrorMessage(session, "semanticDiag", { file: recognizersDateTimeSrcFile.path, diagnostics: semanticErrors });
|
||||
session.clearMessages();
|
||||
|
||||
host.runQueuedImmediateCallbacks(1);
|
||||
|
||||
checkErrorMessage(session, "suggestionDiag", {
|
||||
file: recognizersDateTimeSrcFile.path,
|
||||
diagnostics: [],
|
||||
});
|
||||
checkCompleteEvent(session, 2, expectedSequenceId);
|
||||
}
|
||||
|
||||
function verifyWatchedFilesAndDirectories(host: TestServerHost, files: string[], recursiveDirectories: ReadonlyMap<number>, nonRecursiveDirectories: string[]) {
|
||||
checkWatchedFilesDetailed(host, files.filter(f => f !== recognizersDateTimeSrcFile.path), 1);
|
||||
checkWatchedDirectoriesDetailed(host, nonRecursiveDirectories, 1, /*recursive*/ false);
|
||||
checkWatchedDirectoriesDetailed(host, recursiveDirectories, /*recursive*/ true);
|
||||
}
|
||||
|
||||
function createSessionAndOpenFile(host: TestServerHost) {
|
||||
const session = createSession(host, { canUseEvents: true });
|
||||
session.executeCommandSeq<protocol.OpenRequest>({
|
||||
command: protocol.CommandTypes.Open,
|
||||
arguments: {
|
||||
file: recognizersDateTimeSrcFile.path,
|
||||
projectRootPath
|
||||
}
|
||||
});
|
||||
return session;
|
||||
}
|
||||
|
||||
function verifyModuleResolution(withPathMapping: boolean) {
|
||||
describe(withPathMapping ? "when tsconfig file contains path mapping" : "when tsconfig does not contain path mapping", () => {
|
||||
const filesWithSources = [libFile, recognizersDateTimeSrcFile, withPathMapping ? recognizerDateTimeTsconfigWithPathMapping : recognizerDateTimeTsconfigWithoutPathMapping, recognizerTextSrcFile, recongnizerTextPackageJson];
|
||||
const filesWithNodeModulesSetup = [...filesWithSources, nodeModulesRecorgnizersText];
|
||||
const filesAfterCompilation = [...filesWithNodeModulesSetup, recongnizerTextDistTypingFile];
|
||||
|
||||
const watchedDirectoriesWithResolvedModule = arrayToMap(getTypeRootsFromLocation(recognizersDateTime), k => k, () => 1);
|
||||
watchedDirectoriesWithResolvedModule.set(`${recognizersDateTime}/src`, withPathMapping ? 1 : 2); // wild card + failed lookups
|
||||
if (!withPathMapping) {
|
||||
watchedDirectoriesWithResolvedModule.set(`${recognizersDateTime}/node_modules`, 1); // failed lookups
|
||||
}
|
||||
const watchedDirectoriesWithUnresolvedModule = cloneMap(watchedDirectoriesWithResolvedModule);
|
||||
watchedDirectoriesWithUnresolvedModule.set(`${recognizersDateTime}/src`, 2); // wild card + failed lookups
|
||||
[`${recognizersDateTime}/node_modules`, ...(withPathMapping ? [recognizersText] : emptyArray), ...getNodeModuleDirectories(packages)].forEach(d => {
|
||||
watchedDirectoriesWithUnresolvedModule.set(d, 1);
|
||||
});
|
||||
const nonRecursiveWatchedDirectories = withPathMapping ? [packages] : emptyArray;
|
||||
|
||||
function verifyProjectWithResolvedModule(session: TestSession) {
|
||||
const projectService = session.getProjectService();
|
||||
const project = projectService.configuredProjects.get(recognizerDateTimeTsconfigPath)!;
|
||||
checkProjectActualFiles(project, filesInProjectWithResolvedModule);
|
||||
verifyWatchedFilesAndDirectories(session.host, filesInProjectWithResolvedModule, watchedDirectoriesWithResolvedModule, nonRecursiveWatchedDirectories);
|
||||
verifyErrors(session, []);
|
||||
}
|
||||
|
||||
function verifyProjectWithUnresolvedModule(session: TestSession) {
|
||||
const projectService = session.getProjectService();
|
||||
const project = projectService.configuredProjects.get(recognizerDateTimeTsconfigPath)!;
|
||||
checkProjectActualFiles(project, filesInProjectWithUnresolvedModule);
|
||||
verifyWatchedFilesAndDirectories(session.host, filesInProjectWithUnresolvedModule, watchedDirectoriesWithUnresolvedModule, nonRecursiveWatchedDirectories);
|
||||
const startOffset = recognizersDateTimeSrcFile.content.indexOf('"') + 1;
|
||||
verifyErrors(session, [
|
||||
createDiagnostic({ line: 1, offset: startOffset }, { line: 1, offset: startOffset + moduleNameInFile.length }, Diagnostics.Cannot_find_module_0, [moduleName])
|
||||
]);
|
||||
}
|
||||
|
||||
it("when project compiles from sources", () => {
|
||||
const host = createServerHost(filesWithSources);
|
||||
const session = createSessionAndOpenFile(host);
|
||||
verifyProjectWithUnresolvedModule(session);
|
||||
|
||||
host.reloadFS(filesAfterCompilation);
|
||||
host.runQueuedTimeoutCallbacks();
|
||||
|
||||
verifyProjectWithResolvedModule(session);
|
||||
});
|
||||
|
||||
it("when project has node_modules setup but doesnt have modules in typings folder and then recompiles", () => {
|
||||
const host = createServerHost(filesWithNodeModulesSetup);
|
||||
const session = createSessionAndOpenFile(host);
|
||||
verifyProjectWithUnresolvedModule(session);
|
||||
|
||||
host.reloadFS(filesAfterCompilation);
|
||||
host.runQueuedTimeoutCallbacks();
|
||||
|
||||
if (withPathMapping) {
|
||||
verifyProjectWithResolvedModule(session);
|
||||
}
|
||||
else {
|
||||
// Cannot handle the resolution update
|
||||
verifyProjectWithUnresolvedModule(session);
|
||||
}
|
||||
});
|
||||
|
||||
it("when project recompiles after deleting generated folders", () => {
|
||||
const host = createServerHost(filesAfterCompilation);
|
||||
const session = createSessionAndOpenFile(host);
|
||||
|
||||
verifyProjectWithResolvedModule(session);
|
||||
|
||||
host.deleteFolder(recognizersTextDist, /*recursive*/ true);
|
||||
host.runQueuedTimeoutCallbacks();
|
||||
|
||||
verifyProjectWithUnresolvedModule(session);
|
||||
|
||||
host.ensureFileOrFolder(recongnizerTextDistTypingFile);
|
||||
host.runQueuedTimeoutCallbacks();
|
||||
|
||||
if (withPathMapping) {
|
||||
verifyProjectWithResolvedModule(session);
|
||||
}
|
||||
else {
|
||||
// Cannot handle the resolution update
|
||||
verifyProjectWithUnresolvedModule(session);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
verifyModuleResolution(/*withPathMapping*/ false);
|
||||
verifyModuleResolution(/*withPathMapping*/ true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("tsserverProjectSystem forceConsistentCasingInFileNames", () => {
|
||||
it("works when extends is specified with a case insensitive file system", () => {
|
||||
const rootPath = "/Users/username/dev/project";
|
||||
|
||||
282
src/testRunner/unittests/tsserverSymLinks.ts
Normal file
282
src/testRunner/unittests/tsserverSymLinks.ts
Normal file
@ -0,0 +1,282 @@
|
||||
namespace ts.projectSystem {
|
||||
describe("tsserverProjectSystem with symLinks", () => {
|
||||
it("rename in common file renames all project", () => {
|
||||
const projects = "/users/username/projects";
|
||||
const folderA = `${projects}/a`;
|
||||
const aFile: File = {
|
||||
path: `${folderA}/a.ts`,
|
||||
content: `import {C} from "./c/fc"; console.log(C)`
|
||||
};
|
||||
const aTsconfig: File = {
|
||||
path: `${folderA}/tsconfig.json`,
|
||||
content: JSON.stringify({ compilerOptions: { module: "commonjs" } })
|
||||
};
|
||||
const aC: SymLink = {
|
||||
path: `${folderA}/c`,
|
||||
symLink: "../c"
|
||||
};
|
||||
const aFc = `${folderA}/c/fc.ts`;
|
||||
|
||||
const folderB = `${projects}/b`;
|
||||
const bFile: File = {
|
||||
path: `${folderB}/b.ts`,
|
||||
content: `import {C} from "./c/fc"; console.log(C)`
|
||||
};
|
||||
const bTsconfig: File = {
|
||||
path: `${folderB}/tsconfig.json`,
|
||||
content: JSON.stringify({ compilerOptions: { module: "commonjs" } })
|
||||
};
|
||||
const bC: SymLink = {
|
||||
path: `${folderB}/c`,
|
||||
symLink: "../c"
|
||||
};
|
||||
const bFc = `${folderB}/c/fc.ts`;
|
||||
|
||||
const folderC = `${projects}/c`;
|
||||
const cFile: File = {
|
||||
path: `${folderC}/fc.ts`,
|
||||
content: `export const C = 8`
|
||||
};
|
||||
|
||||
const files = [cFile, libFile, aFile, aTsconfig, aC, bFile, bTsconfig, bC];
|
||||
const host = createServerHost(files);
|
||||
const session = createSession(host);
|
||||
const projectService = session.getProjectService();
|
||||
openFilesForSession(
|
||||
[
|
||||
{ file: aFile, projectRootPath: folderA },
|
||||
{ file: bFile, projectRootPath: folderB },
|
||||
{ file: aFc, projectRootPath: folderA },
|
||||
{ file: bFc, projectRootPath: folderB },
|
||||
],
|
||||
session);
|
||||
checkNumberOfProjects(projectService, { configuredProjects: 2 });
|
||||
assert.isDefined(projectService.configuredProjects.get(aTsconfig.path));
|
||||
assert.isDefined(projectService.configuredProjects.get(bTsconfig.path));
|
||||
|
||||
const response = executeSessionRequest<protocol.RenameRequest, protocol.RenameResponse>(session, protocol.CommandTypes.Rename, { file: aFc, ...protocolLocationFromSubstring(cFile.content, "C") });
|
||||
|
||||
assert.equal(aFile.content, bFile.content);
|
||||
const abLocs: protocol.RenameTextSpan[] = [
|
||||
protocolRenameSpanFromSubstring(aFile.content, "C"),
|
||||
protocolRenameSpanFromSubstring(aFile.content, "C", { index: 1 }),
|
||||
];
|
||||
const span = protocolRenameSpanFromSubstring(cFile.content, "C");
|
||||
const cLocs: protocol.RenameTextSpan[] = [span];
|
||||
assert.deepEqual<protocol.RenameResponseBody | undefined>(response, {
|
||||
info: {
|
||||
canRename: true,
|
||||
displayName: "C",
|
||||
fileToRename: undefined,
|
||||
fullDisplayName: '"/users/username/projects/a/c/fc".C',
|
||||
kind: ScriptElementKind.constElement,
|
||||
kindModifiers: ScriptElementKindModifier.exportedModifier,
|
||||
triggerSpan: protocolTextSpanFromSubstring(cFile.content, "C"),
|
||||
},
|
||||
locs: [
|
||||
{ file: aFc, locs: cLocs },
|
||||
{ file: aFile.path, locs: abLocs },
|
||||
{ file: bFc, locs: cLocs },
|
||||
{ file: bFile.path, locs: abLocs },
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
describe("module resolution when symlinked folder contents change and resolve modules", () => {
|
||||
const projectRootPath = "/users/username/projects/myproject";
|
||||
const packages = `${projectRootPath}/javascript/packages`;
|
||||
const recognizersDateTime = `${packages}/recognizers-date-time`;
|
||||
const recognizersText = `${packages}/recognizers-text`;
|
||||
const recognizersTextDist = `${recognizersText}/dist`;
|
||||
const moduleName = "@microsoft/recognizers-text";
|
||||
const moduleNameInFile = `"${moduleName}"`;
|
||||
const recognizersDateTimeSrcFile: File = {
|
||||
path: `${recognizersDateTime}/src/datetime/baseDate.ts`,
|
||||
content: `import {C} from ${moduleNameInFile};
|
||||
new C();`
|
||||
};
|
||||
const recognizerDateTimeTsconfigPath = `${recognizersDateTime}/tsconfig.json`;
|
||||
const recognizerDateTimeTsconfigWithoutPathMapping: File = {
|
||||
path: recognizerDateTimeTsconfigPath,
|
||||
content: JSON.stringify({
|
||||
include: ["src"]
|
||||
})
|
||||
};
|
||||
const recognizerDateTimeTsconfigWithPathMapping: File = {
|
||||
path: recognizerDateTimeTsconfigPath,
|
||||
content: JSON.stringify({
|
||||
compilerOptions: {
|
||||
rootDir: "src",
|
||||
baseUrl: "./",
|
||||
paths: {
|
||||
"@microsoft/*": ["../*"]
|
||||
}
|
||||
},
|
||||
include: ["src"]
|
||||
})
|
||||
};
|
||||
const nodeModulesRecorgnizersText: SymLink = {
|
||||
path: `${recognizersDateTime}/node_modules/@microsoft/recognizers-text`,
|
||||
symLink: recognizersText
|
||||
};
|
||||
const recognizerTextSrcFile: File = {
|
||||
path: `${recognizersText}/src/recognizers-text.ts`,
|
||||
content: `export class C { method () { return 10; } }`
|
||||
};
|
||||
const recongnizerTextDistTypingFile: File = {
|
||||
path: `${recognizersTextDist}/types/recognizers-text.d.ts`,
|
||||
content: `export class C { method(): number; }`
|
||||
};
|
||||
const recongnizerTextPackageJson: File = {
|
||||
path: `${recognizersText}/package.json`,
|
||||
content: JSON.stringify({
|
||||
typings: "dist/types/recognizers-text.d.ts"
|
||||
})
|
||||
};
|
||||
const filesInProjectWithUnresolvedModule = [recognizerDateTimeTsconfigPath, libFile.path, recognizersDateTimeSrcFile.path];
|
||||
const filesInProjectWithResolvedModule = [...filesInProjectWithUnresolvedModule, recongnizerTextDistTypingFile.path];
|
||||
|
||||
function verifyErrors(session: TestSession, semanticErrors: protocol.Diagnostic[]) {
|
||||
session.clearMessages();
|
||||
const expectedSequenceId = session.getNextSeq();
|
||||
session.executeCommandSeq<protocol.GeterrRequest>({
|
||||
command: server.CommandNames.Geterr,
|
||||
arguments: {
|
||||
delay: 0,
|
||||
files: [recognizersDateTimeSrcFile.path],
|
||||
}
|
||||
});
|
||||
|
||||
const host = session.host;
|
||||
host.checkTimeoutQueueLengthAndRun(1);
|
||||
|
||||
checkErrorMessage(session, "syntaxDiag", { file: recognizersDateTimeSrcFile.path, diagnostics: [] });
|
||||
session.clearMessages();
|
||||
|
||||
host.runQueuedImmediateCallbacks(1);
|
||||
|
||||
checkErrorMessage(session, "semanticDiag", { file: recognizersDateTimeSrcFile.path, diagnostics: semanticErrors });
|
||||
session.clearMessages();
|
||||
|
||||
host.runQueuedImmediateCallbacks(1);
|
||||
|
||||
checkErrorMessage(session, "suggestionDiag", {
|
||||
file: recognizersDateTimeSrcFile.path,
|
||||
diagnostics: [],
|
||||
});
|
||||
checkCompleteEvent(session, 2, expectedSequenceId);
|
||||
}
|
||||
|
||||
function verifyWatchedFilesAndDirectories(host: TestServerHost, files: string[], recursiveDirectories: ReadonlyMap<number>, nonRecursiveDirectories: string[]) {
|
||||
checkWatchedFilesDetailed(host, files.filter(f => f !== recognizersDateTimeSrcFile.path), 1);
|
||||
checkWatchedDirectoriesDetailed(host, nonRecursiveDirectories, 1, /*recursive*/ false);
|
||||
checkWatchedDirectoriesDetailed(host, recursiveDirectories, /*recursive*/ true);
|
||||
}
|
||||
|
||||
function createSessionAndOpenFile(host: TestServerHost) {
|
||||
const session = createSession(host, { canUseEvents: true });
|
||||
session.executeCommandSeq<protocol.OpenRequest>({
|
||||
command: protocol.CommandTypes.Open,
|
||||
arguments: {
|
||||
file: recognizersDateTimeSrcFile.path,
|
||||
projectRootPath
|
||||
}
|
||||
});
|
||||
return session;
|
||||
}
|
||||
|
||||
function verifyModuleResolution(withPathMapping: boolean) {
|
||||
describe(withPathMapping ? "when tsconfig file contains path mapping" : "when tsconfig does not contain path mapping", () => {
|
||||
const filesWithSources = [libFile, recognizersDateTimeSrcFile, withPathMapping ? recognizerDateTimeTsconfigWithPathMapping : recognizerDateTimeTsconfigWithoutPathMapping, recognizerTextSrcFile, recongnizerTextPackageJson];
|
||||
const filesWithNodeModulesSetup = [...filesWithSources, nodeModulesRecorgnizersText];
|
||||
const filesAfterCompilation = [...filesWithNodeModulesSetup, recongnizerTextDistTypingFile];
|
||||
|
||||
const watchedDirectoriesWithResolvedModule = arrayToMap(getTypeRootsFromLocation(recognizersDateTime), k => k, () => 1);
|
||||
watchedDirectoriesWithResolvedModule.set(`${recognizersDateTime}/src`, withPathMapping ? 1 : 2); // wild card + failed lookups
|
||||
if (!withPathMapping) {
|
||||
watchedDirectoriesWithResolvedModule.set(`${recognizersDateTime}/node_modules`, 1); // failed lookups
|
||||
}
|
||||
const watchedDirectoriesWithUnresolvedModule = cloneMap(watchedDirectoriesWithResolvedModule);
|
||||
watchedDirectoriesWithUnresolvedModule.set(`${recognizersDateTime}/src`, 2); // wild card + failed lookups
|
||||
[`${recognizersDateTime}/node_modules`, ...(withPathMapping ? [recognizersText] : emptyArray), ...getNodeModuleDirectories(packages)].forEach(d => {
|
||||
watchedDirectoriesWithUnresolvedModule.set(d, 1);
|
||||
});
|
||||
const nonRecursiveWatchedDirectories = withPathMapping ? [packages] : emptyArray;
|
||||
|
||||
function verifyProjectWithResolvedModule(session: TestSession) {
|
||||
const projectService = session.getProjectService();
|
||||
const project = projectService.configuredProjects.get(recognizerDateTimeTsconfigPath)!;
|
||||
checkProjectActualFiles(project, filesInProjectWithResolvedModule);
|
||||
verifyWatchedFilesAndDirectories(session.host, filesInProjectWithResolvedModule, watchedDirectoriesWithResolvedModule, nonRecursiveWatchedDirectories);
|
||||
verifyErrors(session, []);
|
||||
}
|
||||
|
||||
function verifyProjectWithUnresolvedModule(session: TestSession) {
|
||||
const projectService = session.getProjectService();
|
||||
const project = projectService.configuredProjects.get(recognizerDateTimeTsconfigPath)!;
|
||||
checkProjectActualFiles(project, filesInProjectWithUnresolvedModule);
|
||||
verifyWatchedFilesAndDirectories(session.host, filesInProjectWithUnresolvedModule, watchedDirectoriesWithUnresolvedModule, nonRecursiveWatchedDirectories);
|
||||
const startOffset = recognizersDateTimeSrcFile.content.indexOf('"') + 1;
|
||||
verifyErrors(session, [
|
||||
createDiagnostic({ line: 1, offset: startOffset }, { line: 1, offset: startOffset + moduleNameInFile.length }, Diagnostics.Cannot_find_module_0, [moduleName])
|
||||
]);
|
||||
}
|
||||
|
||||
it("when project compiles from sources", () => {
|
||||
const host = createServerHost(filesWithSources);
|
||||
const session = createSessionAndOpenFile(host);
|
||||
verifyProjectWithUnresolvedModule(session);
|
||||
|
||||
host.reloadFS(filesAfterCompilation);
|
||||
host.runQueuedTimeoutCallbacks();
|
||||
|
||||
verifyProjectWithResolvedModule(session);
|
||||
});
|
||||
|
||||
it("when project has node_modules setup but doesnt have modules in typings folder and then recompiles", () => {
|
||||
const host = createServerHost(filesWithNodeModulesSetup);
|
||||
const session = createSessionAndOpenFile(host);
|
||||
verifyProjectWithUnresolvedModule(session);
|
||||
|
||||
host.reloadFS(filesAfterCompilation);
|
||||
host.runQueuedTimeoutCallbacks();
|
||||
|
||||
if (withPathMapping) {
|
||||
verifyProjectWithResolvedModule(session);
|
||||
}
|
||||
else {
|
||||
// Cannot handle the resolution update
|
||||
verifyProjectWithUnresolvedModule(session);
|
||||
}
|
||||
});
|
||||
|
||||
it("when project recompiles after deleting generated folders", () => {
|
||||
const host = createServerHost(filesAfterCompilation);
|
||||
const session = createSessionAndOpenFile(host);
|
||||
|
||||
verifyProjectWithResolvedModule(session);
|
||||
|
||||
host.deleteFolder(recognizersTextDist, /*recursive*/ true);
|
||||
host.runQueuedTimeoutCallbacks();
|
||||
|
||||
verifyProjectWithUnresolvedModule(session);
|
||||
|
||||
host.ensureFileOrFolder(recongnizerTextDistTypingFile);
|
||||
host.runQueuedTimeoutCallbacks();
|
||||
|
||||
if (withPathMapping) {
|
||||
verifyProjectWithResolvedModule(session);
|
||||
}
|
||||
else {
|
||||
// Cannot handle the resolution update
|
||||
verifyProjectWithUnresolvedModule(session);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
verifyModuleResolution(/*withPathMapping*/ false);
|
||||
verifyModuleResolution(/*withPathMapping*/ true);
|
||||
});
|
||||
});
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user