diff --git a/src/tagged-union.test.ts b/src/tagged-union.test.ts index 03b3cdf..2027f71 100644 --- a/src/tagged-union.test.ts +++ b/src/tagged-union.test.ts @@ -398,3 +398,55 @@ test("autocomplete: a fallback makes the remaining tags optional", () => { assert.deepEqual([...result], ["a?", "b?", "c?"]); }); }); + +// `Mixed` has two common keys, but `id`'s value is not a tag, so only `kind` +// may serve as the discriminant. +const MIXED_SOURCE = `type Mixed = { id: Date; kind: "a"; a: number } | { id: Date; kind: "b"; b: number };`; + +const discriminantLabelsFor = ({ + name, + factory, + typeName, + typeSource, +}: { + readonly name: string; + readonly factory: "getTaggedUnionMatcher" | "getTaggedUnionMatcherW"; + readonly typeName: string; + readonly typeSource: string; +}): Promise => { + const session = new LspSession(REPO_ROOT); + const target: CompletionTarget = { + file: `src/__autocomplete_${name}.ts`, + source: [ + `import { ${factory} } from "./index.ts";`, + typeSource, + `const m = ${factory}<${typeName}>()(/*COMPLETE*/);`, + "", + ].join("\n"), + }; + return session + .completionLabelsAt(target) + .then((result) => result.labels) + .finally(() => session.close()); +}; + +test("autocomplete: the discriminant key is offered at the key argument", () => { + // Arrange + const name = "tagged_union_discriminant"; + + // Act + const labels = discriminantLabelsFor({ + name, + factory: "getTaggedUnionMatcher", + typeName: "Mixed", + typeSource: MIXED_SOURCE, + }); + + // Assert + return labels.then((result) => { + // The argument position also offers every global identifier, so assert + // inclusion of the discriminant and exclusion of the non-tag key. + assert.ok(result.includes('"kind"')); + assert.ok(!result.includes('"id"')); + }); +});