From ff763fab967405dfeb8e2f06f7155f5e7f88cfa8 Mon Sep 17 00:00:00 2001 From: Pokey Rule Date: Wed, 1 Dec 2021 12:26:04 +0000 Subject: [PATCH 1/2] Avoid multiple calls to done during a failed test --- src/test/suite/asyncSafety.ts | 34 +++++++++++++++++++++++++++++++++ src/test/suite/recorded.test.ts | 8 +++++++- 2 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 src/test/suite/asyncSafety.ts diff --git a/src/test/suite/asyncSafety.ts b/src/test/suite/asyncSafety.ts new file mode 100644 index 0000000000..1f6295adb0 --- /dev/null +++ b/src/test/suite/asyncSafety.ts @@ -0,0 +1,34 @@ +import { AsyncFunc, Context, Done } from "mocha"; + +/** + * if an async returns after the method times out, + * it will cause a "done() called multiple times" error. + * In the context of a running webdriver, this is potentially very bad. + * We need to be able to quit the driver gracefully under any circumstances. + * This allows methods to time out while an async is pending, + * and will avoid calling done twice in this case. + * + * From https://github.com/mochajs/mocha/issues/967#issuecomment-810484206 + * @param fn The test function to run + * @returns A safely wrapped test function + */ +export default function asyncSafety(fn: AsyncFunc) { + return function (this: Context, done: Done) { + let runnable = this.runnable(); + + fn.bind(this)() + .then((res) => { + // for successful I think we only need timedOut? not sure though, might have side effects + // when the duration check is added it will get stuck and never complete on a second runthrough + if (!runnable.timedOut) { + done(res); + } + }) + // @ts-ignore + .catch((err) => { + if (!runnable.timedOut && !runnable.duration) { + done(err); + } + }); + }; +} diff --git a/src/test/suite/recorded.test.ts b/src/test/suite/recorded.test.ts index 2b1e6a6de4..b9844dbc09 100644 --- a/src/test/suite/recorded.test.ts +++ b/src/test/suite/recorded.test.ts @@ -24,6 +24,7 @@ import { } from "../../util/getExtensionApi"; import { enableDebugLog } from "../../util/debug"; import { extractTargetedMarks } from "../../testUtil/extractTargetedMarks"; +import asyncSafety from "./asyncSafety"; function createPosition(position: PositionPlainObject) { return new vscode.Position(position.line, position.character); @@ -49,7 +50,12 @@ suite("recorded test cases", async function () { sinon.restore(); }); - files.forEach((file) => test(file.split(".")[0], () => runTest(file))); + files.forEach((file) => + test( + file.split(".")[0], + asyncSafety(() => runTest(file)) + ) + ); }); async function runTest(file: string) { From 552cec276e385d39c20618c40fb504bf9492ce66 Mon Sep 17 00:00:00 2001 From: Pokey Rule Date: Wed, 1 Dec 2021 12:57:18 +0000 Subject: [PATCH 2/2] Remove problematic test cases --- .../parseTree/typescript/clearMatching12.yml | 23 ------------------- .../parseTree/typescript/clearMatching13.yml | 23 ------------------- .../parseTree/typescript/clearPair4.yml | 23 +++++++++++++++++++ .../parseTree/typescript/clearPair5.yml | 23 +++++++++++++++++++ .../parseTree/typescript/clearPair6.yml | 23 +++++++++++++++++++ .../parseTree/typescript/clearPair7.yml | 23 +++++++++++++++++++ 6 files changed, 92 insertions(+), 46 deletions(-) delete mode 100644 src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearMatching12.yml delete mode 100644 src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearMatching13.yml create mode 100644 src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearPair4.yml create mode 100644 src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearPair5.yml create mode 100644 src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearPair6.yml create mode 100644 src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearPair7.yml diff --git a/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearMatching12.yml b/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearMatching12.yml deleted file mode 100644 index acba16c7fa..0000000000 --- a/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearMatching12.yml +++ /dev/null @@ -1,23 +0,0 @@ -spokenForm: clear matching -languageId: typescript -command: - actionName: clearAndSetSelection - partialTargets: - - type: primitive - modifier: {type: surroundingPair, delimiter: any, delimiterInclusion: interiorOnly} - extraArgs: [] -initialState: - documentContents: import { Point, SyntaxNode } from "web-tree-sitter"; - selections: - - anchor: {line: 0, character: 19} - active: {line: 0, character: 19} - marks: {} -finalState: - documentContents: import {} from "web-tree-sitter"; - selections: - - anchor: {line: 0, character: 8} - active: {line: 0, character: 8} - thatMark: - - anchor: {line: 0, character: 8} - active: {line: 0, character: 8} -fullTargets: [{type: primitive, mark: {type: cursor}, selectionType: token, position: contents, modifier: {type: surroundingPair, delimiter: null, delimitersOnly: false}, insideOutsideType: inside}] diff --git a/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearMatching13.yml b/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearMatching13.yml deleted file mode 100644 index 716b6cb498..0000000000 --- a/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearMatching13.yml +++ /dev/null @@ -1,23 +0,0 @@ -spokenForm: clear matching -languageId: typescript -command: - actionName: clearAndSetSelection - partialTargets: - - type: primitive - modifier: {type: surroundingPair, delimiter: any, delimiterInclusion: interiorOnly} - extraArgs: [] -initialState: - documentContents: import { Point, SyntaxNode } from "web-tree-sitter"; - selections: - - anchor: {line: 0, character: 40} - active: {line: 0, character: 40} - marks: {} -finalState: - documentContents: import { Point, SyntaxNode } from ""; - selections: - - anchor: {line: 0, character: 35} - active: {line: 0, character: 35} - thatMark: - - anchor: {line: 0, character: 35} - active: {line: 0, character: 35} -fullTargets: [{type: primitive, mark: {type: cursor}, selectionType: token, position: contents, modifier: {type: surroundingPair, delimiter: null, delimitersOnly: false}, insideOutsideType: inside}] diff --git a/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearPair4.yml b/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearPair4.yml new file mode 100644 index 0000000000..b05de070fd --- /dev/null +++ b/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearPair4.yml @@ -0,0 +1,23 @@ +spokenForm: clear pair +languageId: typescript +command: + actionName: clearAndSetSelection + partialTargets: + - type: primitive + modifier: {type: surroundingPair, delimiter: any} + extraArgs: [] +initialState: + documentContents: "const {hello} = {hello: \"world\"}" + selections: + - anchor: {line: 0, character: 23} + active: {line: 0, character: 23} + marks: {} +finalState: + documentContents: "const {hello} = " + selections: + - anchor: {line: 0, character: 16} + active: {line: 0, character: 16} + thatMark: + - anchor: {line: 0, character: 16} + active: {line: 0, character: 16} +fullTargets: [{type: primitive, mark: {type: cursor}, selectionType: token, position: contents, insideOutsideType: inside, modifier: {type: surroundingPair, delimiter: any}}] diff --git a/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearPair5.yml b/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearPair5.yml new file mode 100644 index 0000000000..c681de463d --- /dev/null +++ b/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearPair5.yml @@ -0,0 +1,23 @@ +spokenForm: clear pair +languageId: typescript +command: + actionName: clearAndSetSelection + partialTargets: + - type: primitive + modifier: {type: surroundingPair, delimiter: any} + extraArgs: [] +initialState: + documentContents: "const {hello} = {hello: \"world\"}" + selections: + - anchor: {line: 0, character: 28} + active: {line: 0, character: 28} + marks: {} +finalState: + documentContents: "const {hello} = {hello: }" + selections: + - anchor: {line: 0, character: 24} + active: {line: 0, character: 24} + thatMark: + - anchor: {line: 0, character: 24} + active: {line: 0, character: 24} +fullTargets: [{type: primitive, mark: {type: cursor}, selectionType: token, position: contents, insideOutsideType: inside, modifier: {type: surroundingPair, delimiter: any}}] diff --git a/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearPair6.yml b/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearPair6.yml new file mode 100644 index 0000000000..6de20d54ed --- /dev/null +++ b/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearPair6.yml @@ -0,0 +1,23 @@ +spokenForm: clear pair +languageId: typescript +command: + actionName: clearAndSetSelection + partialTargets: + - type: primitive + modifier: {type: surroundingPair, delimiter: any} + extraArgs: [] +initialState: + documentContents: "const {hello} = {hello: \"world\"}" + selections: + - anchor: {line: 0, character: 10} + active: {line: 0, character: 10} + marks: {} +finalState: + documentContents: "const = {hello: \"world\"}" + selections: + - anchor: {line: 0, character: 6} + active: {line: 0, character: 6} + thatMark: + - anchor: {line: 0, character: 6} + active: {line: 0, character: 6} +fullTargets: [{type: primitive, mark: {type: cursor}, selectionType: token, position: contents, insideOutsideType: inside, modifier: {type: surroundingPair, delimiter: any}}] diff --git a/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearPair7.yml b/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearPair7.yml new file mode 100644 index 0000000000..9d739d40a2 --- /dev/null +++ b/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearPair7.yml @@ -0,0 +1,23 @@ +spokenForm: clear pair +languageId: typescript +command: + actionName: clearAndSetSelection + partialTargets: + - type: primitive + modifier: {type: surroundingPair, delimiter: any} + extraArgs: [] +initialState: + documentContents: () => {return 0;} + selections: + - anchor: {line: 0, character: 12} + active: {line: 0, character: 12} + marks: {} +finalState: + documentContents: "() => " + selections: + - anchor: {line: 0, character: 6} + active: {line: 0, character: 6} + thatMark: + - anchor: {line: 0, character: 6} + active: {line: 0, character: 6} +fullTargets: [{type: primitive, mark: {type: cursor}, selectionType: token, position: contents, insideOutsideType: inside, modifier: {type: surroundingPair, delimiter: any}}]