Skip to content

Commit

Permalink
Resolve constants for block names, refs #1
Browse files Browse the repository at this point in the history
  • Loading branch information
asvetliakov committed Oct 15, 2018
1 parent d2739b2 commit 2570e0e
Show file tree
Hide file tree
Showing 10 changed files with 225 additions and 39 deletions.
25 changes: 25 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,31 @@
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"protocol": "inspector",
"name": "Debug current test file",
"console": "internalConsole",
"internalConsoleOptions": "neverOpen",
"showAsyncStacks": true,
"cwd": "${workspaceRoot}",
"useWSL": true,
"port": 9229,
"runtimeArgs": [
"--inspect-brk=9229",
"./node_modules/jest/bin/jest.js",
"--runTestsByPath",
"--runInBand",
"${relativeFile}",
],
"skipFiles": [
"<node_internals>/**",
"node_modules/**"
],
"sourceMaps": true,
"smartStep": true
},
{
"name": "Launch Extension",
"type": "extensionHost",
Expand Down
22 changes: 15 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,20 +26,20 @@
},
"homepage": "https://github.com/asvetliakov/typescript-snapshots-plugin#readme",
"devDependencies": {
"@types/jest": "^23.3.2",
"@types/jest": "^23.3.5",
"@types/mock-fs": "^3.6.30",
"@types/node": "^10.11.3",
"@types/node": "^10.11.7",
"jest": "^23.6.0",
"mock-fs": "^4.7.0",
"ts-jest": "^23.10.2",
"typescript": "^3.1.1",
"typescript-snapshots-plugin": "^1.3.0"
"ts-jest": "^23.10.4",
"typescript": "^3.1.3",
"typescript-snapshots-plugin": "^1.4.1"
},
"jest": {
"testEnvironment": "node",
"resetMocks": true,
"transform": {
"\\.(ts|tsx)": "<rootDir>/node_modules/ts-jest/preprocessor.js"
"\\.(ts|tsx)": "ts-jest"
},
"testRegex": "(/__tests__/.*|.*\\.[Ff]?[Ss]pec)\\.(ts|tsx|js)$",
"testPathIgnorePatterns": [
Expand All @@ -54,7 +54,15 @@
],
"roots": [
"<rootDir>/src"
]
],
"globals": {
"ts-jest": {
"tsConfig": {
"sourceMap": false,
"inlineSourceMap": true
}
}
}
},
"dependencies": {}
}
30 changes: 30 additions & 0 deletions src/__tests__/__snapshots__/utils.spec.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,36 @@ exports[`getParentTestBlocks Returns last test block and all parent names 6`] =
})"
`;
exports[`getParentTestBlocks Returns last test block and all parent names 7`] = `
"it(a, () => {
expect(a).toBe(1);
})"
`;
exports[`getParentTestBlocks Returns last test block and all parent names 8`] = `
"it(\`substitution \${a}\`, () => {
expect(a).toBe(1);
})"
`;
exports[`getParentTestBlocks Returns last test block and all parent names 9`] = `
"it(\`another \${a}, \${b}, \${c}\`, () => {
expect(a).toBe(1);
})"
`;
exports[`getParentTestBlocks Returns last test block and all parent names 10`] = `
"it(Test, () => {
expect(a).toBe(1);
})"
`;
exports[`getParentTestBlocks Returns last test block and all parent names 11`] = `
"it(\`imported \${Test}\`, () => {
expect(a).toBe(1);
})"
`;
exports[`parseSnapshotFile Returns snapshot definitions 1`] = `
Array [
Object {
Expand Down
2 changes: 2 additions & 0 deletions src/__tests__/fixtures/testConstant.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@

export const Test = "exported constant";
27 changes: 27 additions & 0 deletions src/__tests__/fixtures/valid.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { Test } from "./testConstant";

const a = "via constant";
it(a, () => {
expect(a).toBe(1);
});

it(`substitution ${a}`, () => {
expect(a).toBe(1);
});

const b = 5;
const c = a;

it(`another ${a}, ${b}, ${c}`, () => {
expect(a).toBe(1);
});

it(Test, () => {
expect(a).toBe(1);
});

it(`imported ${Test}`, () => {
expect(a).toBe(1);
});

declare function it(...args: any[]): any;
46 changes: 46 additions & 0 deletions src/__tests__/utils.spec.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,29 @@
import * as ts from "typescript";
import * as path from "path";
import { findNodeAtPosition, isMatchingCallExpression, isMatchingIdentifier, getParentTestBlocks, getCountOfIdentifiersInBlock, parseSnapshotFile } from "../utils";
import { source } from "./fixtures/testsource";

const file = ts.createSourceFile("a.ts", source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
const file2path = path.join(__dirname, "./fixtures/valid.ts");
const fileConstantPath = path.join(__dirname, "./fixtures/testConstant.ts");
const program = ts.createProgram({
options: {
target: ts.ScriptTarget.Latest,
noLib: true,
module: ts.ModuleKind.ES2015,
moduleResolution: ts.ModuleResolutionKind.NodeJs,
},
host: {
...ts.createCompilerHost({
target: ts.ScriptTarget.Latest,
module: ts.ModuleKind.ES2015,
moduleResolution: ts.ModuleResolutionKind.NodeJs,
noLib: true,
}, true),
},
rootNames: [file2path, fileConstantPath],
});
const file2 = program.getSourceFile(file2path)

describe("findNodeAtPosition", () => {
it("Returns node at position", () => {
Expand Down Expand Up @@ -85,6 +106,31 @@ describe("getParentTestBlocks", () => {
expect(res).toBeDefined();
expect(res!.blockNames).toEqual(["valid", "test1"]);
expect(res!.lastNode.getText()).toMatchSnapshot();

res = getParentTestBlocks(ts as any, file2!, ["describe", "it"], ts.getPositionOfLineAndCharacter(file2!, 4, 5), program);
expect(res).toBeDefined();
expect(res!.blockNames).toEqual(["via constant"]);
expect(res!.lastNode.getText()).toMatchSnapshot();

res = getParentTestBlocks(ts as any, file2!, ["describe", "it"], ts.getPositionOfLineAndCharacter(file2!, 8, 8), program);
expect(res).toBeDefined();
expect(res!.blockNames).toEqual(["substitution via constant"]);
expect(res!.lastNode.getText()).toMatchSnapshot();

res = getParentTestBlocks(ts as any, file2!, ["describe", "it"], ts.getPositionOfLineAndCharacter(file2!, 15, 7), program);
expect(res).toBeDefined();
expect(res!.blockNames).toEqual(["another via constant, 5, via constant"]);
expect(res!.lastNode.getText()).toMatchSnapshot();

res = getParentTestBlocks(ts as any, file2!, ["describe", "it"], ts.getPositionOfLineAndCharacter(file2!, 19, 5), program);
expect(res).toBeDefined();
expect(res!.blockNames).toEqual(["exported constant"]);
expect(res!.lastNode.getText()).toMatchSnapshot();

res = getParentTestBlocks(ts as any, file2!, ["describe", "it"], ts.getPositionOfLineAndCharacter(file2!, 23, 5), program);
expect(res).toBeDefined();
expect(res!.blockNames).toEqual(["imported exported constant"]);
expect(res!.lastNode.getText()).toMatchSnapshot();
});
});

Expand Down
3 changes: 2 additions & 1 deletion src/getsnapshot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export function tryGetSnapshotForPosition(
position: number,
snapshotCache: SnapshotResolver,
config: Configuration,
program?: ts_module.Program,
): SnapshotDefinition | undefined {
if (!sourceFile) {
return;
Expand All @@ -29,7 +30,7 @@ export function tryGetSnapshotForPosition(
if (node && isMatchingIdentifier(ts, node, config.snapshotCallIdentifiers) && node.parent && node.parent.parent && ts.isCallExpression(node.parent.parent)) {

// avoid reading snapshot file until there will be real case for snapshot existing, i.e. blockInfo not undefined
const blockInfo = getParentTestBlocks(ts, sourceFile, config.testBlockIdentifiers, node.getStart(sourceFile));
const blockInfo = getParentTestBlocks(ts, sourceFile, config.testBlockIdentifiers, node.getStart(sourceFile), program);
if (blockInfo) {
const snapshotInfo = snapshotCache.getSnapshotForFile(sourceFile.fileName);
if (!snapshotInfo || !snapshotInfo.definitions.length) {
Expand Down
13 changes: 7 additions & 6 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,13 @@ function init(modules: { typescript: typeof ts_module }) {
*/
proxy.getQuickInfoAtPosition = (fileName, position) => {
const originalQuickInfo = oldLS.getQuickInfoAtPosition(fileName, position);
const program = oldLS.getProgram();
const program = info.project.getLanguageService().getProgram();
// const program = oldLS.getProgram();
if (!program) {
return originalQuickInfo;
}
const sourceFile = program.getSourceFile(fileName);
const snapshotDef = tryGetSnapshotForPosition(ts, sourceFile, position, snapshotCache, config);
const snapshotDef = tryGetSnapshotForPosition(ts, sourceFile, position, snapshotCache, config, program);
if (snapshotDef && originalQuickInfo && originalQuickInfo.displayParts) {
originalQuickInfo.displayParts.push({
kind: "method",
Expand All @@ -62,12 +63,12 @@ function init(modules: { typescript: typeof ts_module }) {
*/
proxy.getDefinitionAtPosition = (fileName, position) => {
let prior = oldLS.getDefinitionAtPosition(fileName, position);
const program = oldLS.getProgram();
const program = info.project.getLanguageService().getProgram();
if (!program) {
return prior;
}
const sourceFile = program.getSourceFile(fileName);
const snapshotDef = tryGetSnapshotForPosition(ts, sourceFile, position, snapshotCache, config);
const snapshotDef = tryGetSnapshotForPosition(ts, sourceFile, position, snapshotCache, config, program);
if (snapshotDef) {
// LS can return undefined. Also need to preserve undefined in case if snapshot is not available
if (!prior) {
Expand All @@ -91,12 +92,12 @@ function init(modules: { typescript: typeof ts_module }) {

proxy.getDefinitionAndBoundSpan = (fileName, position) => {
let prior = oldLS.getDefinitionAndBoundSpan(fileName, position);
const program = oldLS.getProgram();
const program = info.project.getLanguageService().getProgram();
if (!program) {
return prior;
}
const sourceFile = program.getSourceFile(fileName);
const snapshotDef = tryGetSnapshotForPosition(ts, sourceFile, position, snapshotCache, config);
const snapshotDef = tryGetSnapshotForPosition(ts, sourceFile, position, snapshotCache, config, program);
if (snapshotDef) {
if (!prior) {
prior = {
Expand Down
47 changes: 44 additions & 3 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,16 +75,57 @@ export interface TestBlockInfo {
* @param lookupUntil
* @returns
*/
export function getParentTestBlocks(ts: typeof ts_module, sourceFile: ts.SourceFile, testBlockIdentifiers: string[], lookupUntil: number): TestBlockInfo | undefined {
export function getParentTestBlocks(
ts: typeof ts_module,
sourceFile: ts.SourceFile,
testBlockIdentifiers: string[],
lookupUntil: number,
program?: ts_module.Program,
): TestBlockInfo | undefined {
const blocks: string[] = [];
let lastBlockNode: ts.Node | undefined;
function find(node: ts.Node): void {
if (lookupUntil >= node.getStart() && lookupUntil <= node.getEnd()) {
if (isMatchingCallExpression(ts, node, testBlockIdentifiers) && node.arguments.length >= 1) {
if (ts.isStringLiteral(node.arguments[0]) || ts.isNoSubstitutionTemplateLiteral(node.arguments[0])) {
const arg = node.arguments[0];
if (ts.isStringLiteral(arg) || ts.isNoSubstitutionTemplateLiteral(arg)) {
lastBlockNode = node;
blocks.push((node.arguments[0] as ts_module.StringLiteral).text);
blocks.push(arg.text);
ts.forEachChild(node, find);
} else if (ts.isIdentifier(arg) && program) {
const typeChecker = program.getTypeChecker();
const type = typeChecker.getTypeAtLocation(arg);
if (type && (type.getFlags() & ts.TypeFlags.StringLiteral)) {
lastBlockNode = node;
blocks.push((type as ts.StringLiteralType).value);
ts.forEachChild(node, find);
}
} else if (ts.isTemplateExpression(arg) && program) {
// try to resolve template literal
let blockName = arg.head.text;
let allResolved = true;
const typeChecker = program.getTypeChecker();
// const type = typeChecker.getTypeAtLocation(arg);
for (const span of arg.templateSpans) {
if (ts.isIdentifier(span.expression)) {
const spanType = typeChecker.getTypeAtLocation(span.expression);
if (spanType && (spanType.getFlags() & ts.TypeFlags.StringLiteral | ts.TypeFlags.NumberLiteral)) {
const literal = span.literal.text;
blockName += (spanType as ts.StringLiteralType | ts.NumberLiteralType).value + literal;
} else {
allResolved = false;
break;
}
} else {
allResolved = false;
break;
}
}
if (allResolved) {
lastBlockNode = node;
blocks.push(blockName);
ts.forEachChild(node, find);
}
}
} else {
ts.forEachChild(node, find);
Expand Down
Loading

0 comments on commit 2570e0e

Please sign in to comment.