Files
languageservices/workflow-parser/src/expressions.test.ts
T

203 lines
5.4 KiB
TypeScript
Raw Normal View History

2023-01-09 19:02:19 -05:00
import {StringToken} from "./templates/tokens";
import {isBasicExpression, isString} from "./templates/tokens/type-guards";
import {nullTrace} from "./test-utils/null-trace";
import {parseWorkflow} from "./workflows/workflow-parser";
describe("Workflow Expression Parsing", () => {
it("preserves original expressions when building format", () => {
const result = parseWorkflow(
2023-02-06 11:15:15 -05:00
{
name: "test.yaml",
content: `on: push
run-name: Test \${{ github.event_name }} \${{ github.ref }}
jobs:
build:
runs-on: ubuntu-latest
steps:
2023-01-09 19:02:19 -05:00
- run: echo 'hello'`
2023-02-06 11:15:15 -05:00
},
nullTrace
2023-01-09 19:02:19 -05:00
);
2023-01-09 19:02:19 -05:00
expect(result.context.errors.getErrors()).toHaveLength(0);
2023-01-09 19:02:19 -05:00
const run = result.value!.assertMapping("run")!;
const runNameMapping = run.get(1)!;
expect(runNameMapping?.key?.assertString("run-name key").value).toBe("run-name");
2023-01-09 19:02:19 -05:00
const v = runNameMapping.value!;
expect(v).not.toBeUndefined();
if (!isBasicExpression(v)) {
2023-01-09 19:02:19 -05:00
throw new Error("expected run-name to be a basic expression");
}
2023-01-09 19:02:19 -05:00
expect(v.originalExpressions).toHaveLength(2);
expect(v.originalExpressions!.map(x => x.toDisplayString())).toEqual([
"${{ github.event_name }}",
2023-01-09 19:02:19 -05:00
"${{ github.ref }}"
]);
});
it("preserves original expressions when building format for multi-line strings", () => {
const result = parseWorkflow(
2023-02-06 11:15:15 -05:00
{
name: "test.yaml",
content: `on: push
jobs:
build:
runs-on: ubuntu-latest
steps:
- run: |
echo \${{ github.event_name }}
echo 'hello' \${{github.ref }}`
2023-02-06 11:15:15 -05:00
},
nullTrace
2023-01-09 19:02:19 -05:00
);
2023-01-09 19:02:19 -05:00
expect(result.context.errors.getErrors()).toHaveLength(0);
2023-01-09 19:02:19 -05:00
const run = result.value!.assertMapping("run")!;
const jobsMapping = run.get(1)!;
expect(jobsMapping?.key?.assertString("jobs").value).toBe("jobs");
2023-01-09 19:02:19 -05:00
const job = jobsMapping.value!.assertMapping("jobs")!.get(0)!.value!.assertMapping("job");
const stepRun = job
.get(1)
.value!.assertSequence("steps")
.get(0)
.assertMapping("step")
.get(0)
2023-01-09 19:02:19 -05:00
.value!.assertScalar("step-run");
if (!isBasicExpression(stepRun)) {
2023-01-09 19:02:19 -05:00
throw new Error("expected run-name to be a basic expression");
}
2023-01-09 19:02:19 -05:00
expect(stepRun.originalExpressions).toHaveLength(2);
expect(stepRun.originalExpressions!.map(x => [x.toDisplayString(), x.range, x.expressionRange])).toEqual([
[
"${{ github.event_name }}",
{
2023-01-27 15:54:51 -05:00
start: {line: 7, column: 16},
end: {line: 7, column: 40}
},
{
start: {line: 7, column: 20},
end: {line: 7, column: 37}
2023-01-09 19:02:19 -05:00
}
],
[
"${{ github.ref }}",
{
2023-01-27 15:54:51 -05:00
start: {line: 8, column: 24},
end: {line: 8, column: 40}
},
{
start: {line: 8, column: 27},
end: {line: 8, column: 37}
2023-01-09 19:02:19 -05:00
}
]
]);
});
it("return errors and string token with preserved expressions for (multiple) expression errors", () => {
const result = parseWorkflow(
2023-02-06 11:15:15 -05:00
{
name: "test.yaml",
content: `on: push
jobs:
build:
runs-on: ubuntu-latest
steps:
- run: |
echo \${{ abc }}
2023-01-09 19:02:19 -05:00
echo 'hello' \${{ gith }}`
2023-02-06 11:15:15 -05:00
},
nullTrace
2023-01-09 19:02:19 -05:00
);
2023-01-09 19:02:19 -05:00
expect(result.context.errors.getErrors()).toHaveLength(2);
2023-01-09 19:02:19 -05:00
const run = result.value!.assertMapping("run")!;
const jobsMapping = run.get(1)!;
expect(jobsMapping?.key?.assertString("jobs").value).toBe("jobs");
2023-01-09 19:02:19 -05:00
const job = jobsMapping.value!.assertMapping("jobs")!.get(0)!.value!.assertMapping("job");
const stepRun = job
.get(1)
.value!.assertSequence("steps")
.get(0)
.assertMapping("step")
.get(0)
2023-01-09 19:02:19 -05:00
.value!.assertScalar("step-run");
2023-01-09 19:02:19 -05:00
expect(isString(stepRun)).toBe(true);
expect((stepRun as StringToken).value).toContain("${{");
});
it("reports all errors for multi-line expressions at the correct locations", () => {
const result = parseWorkflow(
2023-02-06 11:15:15 -05:00
{
name: "test.yaml",
content: `on: push
jobs:
build:
runs-on: ubuntu-latest
steps:
- run: |
echo \${{ fromJSON2('test') }}
2023-01-09 19:02:19 -05:00
echo 'hello' \${{ toJSON2(inputs.test) }}`
2023-02-06 11:15:15 -05:00
},
nullTrace
2023-01-09 19:02:19 -05:00
);
expect(result.context.errors.getErrors()).toEqual([
{
prefix: "test.yaml (Line: 6, Col: 14)",
range: {
2023-01-27 15:54:51 -05:00
start: {line: 7, column: 16},
end: {line: 7, column: 40}
},
2023-01-09 19:02:19 -05:00
rawMessage: "Unrecognized function: 'fromJSON2'"
},
{
prefix: "test.yaml (Line: 6, Col: 14)",
range: {
2023-01-27 15:54:51 -05:00
start: {line: 8, column: 24},
end: {line: 8, column: 51}
},
2023-01-09 19:02:19 -05:00
rawMessage: "Unrecognized function: 'toJSON2'"
}
]);
});
it("parses isExpression strings into expression tokens", () => {
const result = parseWorkflow(
2023-02-06 11:15:15 -05:00
{
name: "test.yaml",
content: `on: push
jobs:
build:
runs-on: ubuntu-latest
if: github.event_name == 'push'
steps:
2023-01-09 19:02:19 -05:00
- run: echo 'hello'`
2023-02-06 11:15:15 -05:00
},
nullTrace
2023-01-09 19:02:19 -05:00
);
2023-01-09 19:02:19 -05:00
expect(result.context.errors.getErrors()).toHaveLength(0);
2023-01-09 19:02:19 -05:00
const workflowRoot = result.value!.assertMapping("root")!;
const jobs = workflowRoot.get(1).value.assertMapping("jobs");
const build = jobs.get(0).value.assertMapping("job");
const ifToken = build.get(1).value;
expect(ifToken.toString()).toEqual("${{ github.event_name == 'push' }}");
if (!isBasicExpression(ifToken)) {
2023-01-09 19:02:19 -05:00
throw new Error("expected if to be a basic expression");
}
2023-01-09 19:02:19 -05:00
});
});