{"record":{"id":"944ec612532830bd","repo":"microsoft/TypeScript","slug":"exactly-one-refactor-range-is-allowed-per-test","errorCode":null,"errorMessage":"Exactly one refactor range is allowed per test.","messagePattern":"Exactly one refactor range is allowed per test\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/harness/fourslashImpl.ts","lineNumber":4084,"sourceCode":"                this.raiseError(`${refactors.length} available refactors both have name ${name} and action ${actionName}`);\r\n            }\r\n        }\r\n    }\r\n\r\n    public verifyRefactorKindsAvailable(kind: string, expected: string[], preferences: {} = ts.emptyOptions): void {\r\n        const refactors = this.getApplicableRefactorsAtSelection(\"invoked\", kind, preferences);\r\n        const availableKinds = ts.flatMap(refactors, refactor => refactor.actions).map(action => action.kind);\r\n        assert.deepEqual(availableKinds.slice().sort(), expected.slice().sort(), `Expected kinds to be equal`);\r\n    }\r\n\r\n    public verifyRefactorsAvailable(names: readonly string[]): void {\r\n        assert.deepEqual(unique(this.getApplicableRefactorsAtSelection(), r => r.name), names);\r\n    }\r\n\r\n    public verifyApplicableRefactorAvailableForRange(negative: boolean): void {\r\n        const ranges = this.getRanges();\r\n        if (!(ranges && ranges.length === 1)) {\r\n            throw new Error(\"Exactly one refactor range is allowed per test.\");\r\n        }\r\n\r\n        const isAvailable = this.getApplicableRefactors(ts.first(ranges)).length > 0;\r\n        if (negative && isAvailable) {\r\n            this.raiseError(`verifyApplicableRefactorAvailableForRange failed - expected no refactor but found some.`);\r\n        }\r\n        if (!negative && !isAvailable) {\r\n            this.raiseError(`verifyApplicableRefactorAvailableForRange failed - expected a refactor but found none.`);\r\n        }\r\n    }\r\n\r\n    public applyRefactor({ refactorName, actionName, actionDescription, newContent: newContentWithRenameMarker, triggerReason }: FourSlashInterface.ApplyRefactorOptions): void {\r\n        const range = this.getSelection();\r\n        const refactors = this.getApplicableRefactorsAtSelection(triggerReason);\r\n        const refactorsWithName = refactors.filter(r => r.name === refactorName);\r\n        if (refactorsWithName.length === 0) {\r\n            this.raiseError(`The expected refactor: ${refactorName} is not available at the marker location.\\nAvailable refactors: ${refactors.map(r => r.name)}`);\r\n        }\r","sourceCodeStart":4066,"sourceCodeEnd":4102,"githubUrl":"https://github.com/microsoft/TypeScript/blob/b465fdbfe175304d9b977da137b2c178ae1091d3/src/harness/fourslashImpl.ts#L4066-L4102","documentation":"Thrown by verifyApplicableRefactorAvailableForRange when the test data does not contain exactly one defined range (via [range ... ] markers). Range-based refactor verification requires a single range to evaluate applicable refactors against; zero or multiple ranges make the check ambiguous, so the harness refuses to proceed.","triggerScenarios":"Calling verify.applicableRefactorAvailableForRange or verify.noApplicableRefactorAvailableForRange in a fourslash test whose .ts source has zero [range markers] or more than one [range ... ...] region. getRanges() returns undefined or a multi-element array.","commonSituations":"Test author copies a server-based refactor test and forgets to bracket the target code with [| ... |] range markers, or leaves an extra range from a previous test variant. The negative/positive overload both require the single range.","solutions":["Add exactly one range to the fourslash file using [| ... |] (or the equivalent range marker syntax) around the code region to check.","Remove any extra range markers so getRanges().length === 1.","If you need multiple ranges, restructure into separate test functions or use a different verification method per range."],"exampleFix":"// before — no range markers\nverify.applicableRefactorAvailableForRange();\n// after\n// in test file: [|export function foo() {}|]\nverify.applicableRefactorAvailableForRange();","handlingStrategy":"validation","validationCode":"const ranges = state.getRanges();\nif (ranges && ranges.length === 1) {\n    verify.applicableRefactorAvailableForRange();\n} else {\n    throw new Error(`Test needs exactly one range, found ${ranges ? ranges.length : 0}`);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Define exactly one [| ... |] region before using range-based refactor verification.","When copying refactor tests, carry over the range markers together with the verification call."],"tags":["fourslash","refactor","test-configuration","range-markers"],"backgroundTag":null,"analyzedSha":"b465fdbfe175304d9b977da137b2c178ae1091d3","analyzedAt":"2026-08-12T05:38:42.698Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}