Files
languageservices/actions-languageservice/src/complete.test.ts
T

277 lines
7.6 KiB
TypeScript
Raw Normal View History

2022-11-15 14:08:12 -05:00
import {complete} from "./complete";
2022-11-23 15:35:34 -08:00
import {WorkflowContext} from "./context/workflow-context";
2022-11-15 14:08:12 -05:00
import {getPositionFromCursor} from "./test-utils/cursor-position";
2022-11-28 15:47:05 -08:00
import {ValueProviderConfig} from "./value-providers/config";
2022-11-08 17:00:59 -08:00
describe("completion", () => {
it("runs-on", async () => {
const input = "on: push\njobs:\n build:\n runs-on: |";
const result = await complete(...getPositionFromCursor(input));
expect(result).not.toBeUndefined();
expect(result.length).toEqual(11);
expect(result[0].label).toEqual("macos-10.13");
});
2022-11-23 10:54:15 -08:00
it("needs", async () => {
const input = `on: push
jobs:
build:
runs-on: ubuntu-latest
build2:
runs-on: ubuntu-latest
needs: bu|`;
const result = await complete(...getPositionFromCursor(input));
expect(result).not.toBeUndefined();
expect(result.length).toEqual(1);
expect(result[0].label).toEqual("build");
});
2022-11-08 17:00:59 -08:00
it("empty workflow", async () => {
const input = "|";
const result = await complete(...getPositionFromCursor(input));
expect(result).not.toBeUndefined();
expect(result.length).toEqual(8);
expect(result[0].label).toEqual("concurrency");
});
it("completion within a sequence", async () => {
const input = `on: push
jobs:
build:
2022-11-18 08:16:31 -08:00
runs-on: [self-hosted, u|]`;
2022-11-08 17:00:59 -08:00
const result = await complete(...getPositionFromCursor(input));
expect(result).not.toBeUndefined();
expect(result.length).toEqual(10);
expect(result[0].label).toEqual("macos-10.13");
});
it("sequence filters out existing values", async () => {
const input = `on: push
jobs:
build:
runs-on: [ubuntu-latest, u|]`;
const result = await complete(...getPositionFromCursor(input));
expect(result).not.toBeUndefined();
expect(result.length).toEqual(10);
expect(result[0].label).toEqual("macos-10.13");
});
it("one-of definition completion", async () => {
const input = `on: push
jobs:
build:
|`;
const result = await complete(...getPositionFromCursor(input));
expect(result).not.toBeUndefined();
expect(result.length).toEqual(20);
});
2022-11-18 08:16:31 -08:00
it("string definition completion in sequence", async () => {
const input = `on:
release:
types:
- |`;
const result = await complete(...getPositionFromCursor(input));
expect(result.map(x => x.label)).toEqual([
"created",
"deleted",
"edited",
"prereleased",
"published",
"released",
"unpublished"
]);
});
it("string definition completion", async () => {
const input = `on:
release:
types: |`;
const result = await complete(...getPositionFromCursor(input));
expect(result.map(x => x.label)).toEqual([
"created",
"deleted",
"edited",
"prereleased",
"published",
"released",
"unpublished"
]);
});
2022-11-08 17:00:59 -08:00
it("map keys filter out existing values", async () => {
const input = `on: push
jobs:
build:
runs-on: ubuntu-latest
|`;
const result = await complete(...getPositionFromCursor(input));
expect(result).not.toBeUndefined();
2022-11-15 14:08:12 -05:00
expect(result.map(x => x.label)).not.toContain("runs-on");
2022-11-08 17:00:59 -08:00
});
it("one-of narrows down to a specific type", async () => {
// A job could be a job-factory or a workflow-job (callable workflow with uses)
// If we have `runs-on`, we should be able to identify that we're in a job-factory
const jobFactory = `on: push
jobs:
build:
runs-on: ubuntu-latest
|`;
2022-11-15 14:08:12 -05:00
const jobFactoryResult = await complete(...getPositionFromCursor(jobFactory));
2022-11-08 17:00:59 -08:00
expect(jobFactoryResult).not.toBeUndefined();
2022-11-15 14:08:12 -05:00
expect(jobFactoryResult.map(x => x.label)).not.toContain("uses");
2022-11-08 17:00:59 -08:00
const workflowJob = `on: push
jobs:
build:
uses: octo-org/this-repo/.github/workflows/workflow-1.yml@172239021f7ba04fe7327647b213799853a9eb89
|`;
2022-11-15 14:08:12 -05:00
const workflowJobResult = await complete(...getPositionFromCursor(workflowJob));
2022-11-08 17:00:59 -08:00
expect(workflowJobResult).not.toBeUndefined();
2022-11-15 14:08:12 -05:00
expect(workflowJobResult.map(x => x.label)).not.toContain("runs-on");
2022-11-08 17:00:59 -08:00
});
it("completes boolean values", async () => {
const input = `on: push
jobs:
build:
continue-on-error: t|`;
const result = await complete(...getPositionFromCursor(input));
expect(result).not.toBeUndefined();
expect(result.length).toEqual(2);
2022-11-15 14:08:12 -05:00
expect(result.map(x => x.label).sort()).toEqual(["false", "true"]);
2022-11-08 17:00:59 -08:00
});
it("completes for empty map values", async () => {
const input = `on: push
jobs:
build:
continue-on-error: |`;
const result = await complete(...getPositionFromCursor(input));
expect(result).not.toBeUndefined();
expect(result.length).toEqual(2);
2022-11-15 14:08:12 -05:00
expect(result.map(x => x.label).sort()).toEqual(["false", "true"]);
2022-11-08 17:00:59 -08:00
});
it("does not complete empty map values when cursor is immediately after the position", async () => {
const input = `on: push
jobs:
build:
continue-on-error:|`;
const result = await complete(...getPositionFromCursor(input));
expect(result).not.toBeUndefined();
2022-11-23 07:08:50 -08:00
expect(result.length).toEqual(0);
2022-11-08 17:00:59 -08:00
});
it("custom value providers override defaults", async () => {
const input = "on: push\njobs:\n build:\n runs-on: |";
2022-11-28 15:47:05 -08:00
const config: ValueProviderConfig = {
"runs-on": async (_: WorkflowContext) => {
2022-11-15 14:08:12 -05:00
return [{label: "my-custom-label"}];
2022-11-08 17:00:59 -08:00
}
};
const result = await complete(...getPositionFromCursor(input), config);
expect(result).not.toBeUndefined();
expect(result.length).toEqual(1);
expect(result[0].label).toEqual("my-custom-label");
});
it("does not show parent mapping sibling keys", async () => {
const input = `on: push
jobs:
build:
container: |
runs-on: ubuntu-latest`;
const result = await complete(...getPositionFromCursor(input));
expect(result).not.toBeUndefined();
expect(result.length).toEqual(6);
// Should not contain other top-level job keys like `if` and `runs-on`
expect(result.map(x => x.label)).not.toContain("if");
expect(result.map(x => x.label)).not.toContain("runs-on");
});
it("shows mapping keys within a new map ", async () => {
const input = `on: push
jobs:
build:
concurrency: |`;
const result = await complete(...getPositionFromCursor(input));
expect(result).not.toBeUndefined();
expect(result.map(x => x.label).sort()).toEqual(["cancel-in-progress", "group"]);
});
2022-11-23 06:26:44 -08:00
it("job key", async () => {
const input = `on: push
jobs:
build:
runs-|`;
const result = await complete(...getPositionFromCursor(input));
expect(result).not.toBeUndefined();
expect(result).toHaveLength(20);
});
it("job key with comment afterwards", async () => {
const input = `on: push
jobs:
build:
runs-|
#`;
const result = await complete(...getPositionFromCursor(input));
expect(result).not.toBeUndefined();
expect(result).toHaveLength(20);
});
2022-11-23 07:35:43 -08:00
it("job key with other values afterwards", async () => {
const input = `on: push
jobs:
build:
runs-|
concurrency: 'group-name'`;
const result = await complete(...getPositionFromCursor(input));
expect(result).not.toBeUndefined();
expect(result).toHaveLength(19);
});
2022-11-23 08:11:59 -08:00
it("step key without space after colon", async () => {
const input = `on: push
jobs:
build:
runs-on: ubuntu-latest
steps:
- env:|
run: echo`;
const result = await complete(...getPositionFromCursor(input));
expect(result).toHaveLength(0);
});
2022-11-28 12:52:06 -05:00
it("loose mapping keys have no completion suggestions", async () => {
const input = `
on:
workflow_dispatch:
inputs:
name:
type: string
description: "hello"
|
`;
const result = await complete(...getPositionFromCursor(input));
expect(result).toHaveLength(0);
});
2022-11-08 17:00:59 -08:00
});