1// SPDX-License-Identifier: MIT
2
3package executor
4
5import (
6 "strings"
7 "testing"
8)
9
10// Recorded on github.com (expr-runtime-errors): a fromJSON that fails in a
11// step's env or run is "The template is not valid. <file> (Line: l, Col: c):
12// <Json.NET message>"; in a step's if there is no location and the exception
13// class comes first. The line is the line of the expression in the workflow
14// file the executor was given (GitHub's Line 80 and the 90 of a current
15// recording differ only because the harness injected a shorter dump step then).
16func TestFromJSONErrorsAreTemplateErrors(t *testing.T) {
17 needTools(t, "bash")
18 const msg = "Unexpected character encountered while parsing value: n. Path '', line 0, position 0."
19 yaml := `on: push
20env:
21 NOT_JSON: not json
22jobs:
23 bad-env:
24 runs-on: ubuntu-24.04
25 steps:
26 - name: bad env expression
27 env:
28 BAD: ${{ fromJSON(env.NOT_JSON) }}
29 run: echo SHOULD-NOT-RUN
30 - name: after
31 if: always()
32 run: echo after-ran
33 bad-if:
34 runs-on: ubuntu-24.04
35 steps:
36 - name: bad if expression
37 if: fromJSON(env.NOT_JSON)
38 run: echo SHOULD-NOT-RUN
39 bad-run:
40 runs-on: ubuntu-24.04
41 steps:
42 - name: bad run expression
43 run: echo ${{ fromJSON(env.NOT_JSON) }}
44`
45 for _, tc := range []struct{ job, step, want string }{
46 {"bad-env", "bad env expression", "##[error]The template is not valid. .github/workflows/ci.yml (Line: 10, Col: 16): " + msg},
47 {"bad-if", "bad if expression", "##[error]The template is not valid. Newtonsoft.Json.JsonReaderException: " + msg},
48 {"bad-run", "bad run expression", "##[error]The template is not valid. .github/workflows/ci.yml (Line: 25, Col: 14): " + msg},
49 } {
50 t.Run(tc.job, func(t *testing.T) {
51 rec, res := runLocal(t, yaml, tc.job, nil)
52 if res.Conclusion != ConclusionFailure {
53 t.Fatalf("%+v", res)
54 }
55 s := rec.step(t, tc.step)
56 if s.Conclusion != ConclusionFailure || len(s.Log) != 1 || s.Log[0] != tc.want {
57 t.Errorf("%s: %s\nwant %s", s.Conclusion, strings.Join(s.Log, "\n"), tc.want)
58 }
59 if tc.job == "bad-env" && rec.step(t, "after").Conclusion != ConclusionSuccess {
60 t.Error("the always() step must run")
61 }
62 })
63 }
64}