From cad301a93cffe7f935cdca72e00571909b9a758b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A1s=20B=20Nagy?= <20251272+BNAndras@users.noreply.github.com> Date: Sun, 11 Oct 2026 10:12:41 -0700 Subject: [PATCH 1/6] Existing v2 fixtures to v3 --- tests/example-all-fail/expected_results.json | 2 +- tests/example-empty-file/expected_results.json | 2 +- tests/example-multiline-test-name/expected_results.json | 2 +- tests/example-partial-fail/expected_results.json | 2 +- tests/example-success/expected_results.json | 2 +- tests/example-syntax-error/expected_results.json | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/example-all-fail/expected_results.json b/tests/example-all-fail/expected_results.json index 63dee40..654744f 100644 --- a/tests/example-all-fail/expected_results.json +++ b/tests/example-all-fail/expected_results.json @@ -1,5 +1,5 @@ { - "version": 2, + "version": 3, "status": "fail", "tests": [ { diff --git a/tests/example-empty-file/expected_results.json b/tests/example-empty-file/expected_results.json index eba1229..d862f79 100644 --- a/tests/example-empty-file/expected_results.json +++ b/tests/example-empty-file/expected_results.json @@ -1,5 +1,5 @@ { - "version": 2, + "version": 3, "status": "error", "tests": [], "message": "\u001b[31mF\u001b[0m\n\nFailures:\n\n 1) Bob encountered a declaration exception\n Message:\n \u001b[31mTypeError: Bob is not a constructor\u001b[0m\n Stacktrace:\n TypeError: Bob is not a constructor\n at jasmine.Suite. (/solution/example-empty-file.spec.coffee:3:9)\n at Object. (/solution/example-empty-file.spec.coffee:2:1)\n at Object. (/solution/example-empty-file.spec.coffee:1:1)\n at Module._compile (node:internal/modules/cjs/loader:1956:14)\n at Object.loadFile (/opt/test-runner/node_modules/jasmine-node/node_modules/coffeescript/lib/coffee-script/register.js:16:19)\n at Module.load (/opt/test-runner/node_modules/jasmine-node/node_modules/coffeescript/lib/coffee-script/register.js:45:36)\n at Module._load (node:internal/modules/cjs/loader:1470:12)\n at wrapModuleLoad (node:internal/modules/cjs/loader:261:19)\n at Module.require (node:internal/modules/cjs/loader:1701:12)\n at require (node:internal/modules/helpers:318:16)\n at Object.jasmine.executeSpecsInFolder (/opt/test-runner/node_modules/jasmine-node/lib/jasmine-node/index.js:160:9)\n at Object. (/opt/test-runner/node_modules/jasmine-node/lib/jasmine-node/cli.js:247:9)\n at Module._compile (node:internal/modules/cjs/loader:1956:14)\n at Object..js (node:internal/modules/cjs/loader:2096:10)\n at Module. (node:internal/modules/cjs/loader:1678:32)\n at Module._load (node:internal/modules/cjs/loader:1470:12)\n at wrapModuleLoad (node:internal/modules/cjs/loader:261:19)\n at Module.require (node:internal/modules/cjs/loader:1701:12)\n at require (node:internal/modules/helpers:318:16)\n at Object. (/opt/test-runner/node_modules/jasmine-node/bin/jasmine-node:6:1)\n at Module._compile (node:internal/modules/cjs/loader:1956:14)\n at Object..js (node:internal/modules/cjs/loader:2096:10)\n at Module. (node:internal/modules/cjs/loader:1678:32)\n at Module._load (node:internal/modules/cjs/loader:1470:12)\n at wrapModuleLoad (node:internal/modules/cjs/loader:261:19)\n at Module.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:171:5)\n at node:internal/main/run_main_module:33:47\n\n\n\n\u001b[31m1 test, 1 assertion, 1 failure, 0 skipped\n\u001b[0m\n\n" diff --git a/tests/example-multiline-test-name/expected_results.json b/tests/example-multiline-test-name/expected_results.json index e12a691..8c22199 100644 --- a/tests/example-multiline-test-name/expected_results.json +++ b/tests/example-multiline-test-name/expected_results.json @@ -1,5 +1,5 @@ { - "version": 2, + "version": 3, "status": "pass", "tests": [ { diff --git a/tests/example-partial-fail/expected_results.json b/tests/example-partial-fail/expected_results.json index 009fa4d..27fbcf8 100644 --- a/tests/example-partial-fail/expected_results.json +++ b/tests/example-partial-fail/expected_results.json @@ -1,5 +1,5 @@ { - "version": 2, + "version": 3, "status": "fail", "tests": [ { diff --git a/tests/example-success/expected_results.json b/tests/example-success/expected_results.json index d016fff..1dfe514 100644 --- a/tests/example-success/expected_results.json +++ b/tests/example-success/expected_results.json @@ -1,5 +1,5 @@ { - "version": 2, + "version": 3, "status": "pass", "tests": [ { diff --git a/tests/example-syntax-error/expected_results.json b/tests/example-syntax-error/expected_results.json index c3e629b..0d85a87 100644 --- a/tests/example-syntax-error/expected_results.json +++ b/tests/example-syntax-error/expected_results.json @@ -1,5 +1,5 @@ { - "version": 2, + "version": 3, "status": "error", "tests": [], "message": "Exception loading: /solution/example-syntax-error.spec.coffee\n[/solution/example-syntax-error.coffee:1:13: error: unexpected @\nclasSSY Bo%b@\n ^] {\n location: { first_line: 0, first_column: 12, last_line: 0, last_column: 12 },\n toString: [Function: syntaxErrorToString],\n code: 'clasSSY Bo%b@',\n filename: '/solution/example-syntax-error.coffee'\n}\n" From 1f6d4cd217ddf0a8b29503c56685f1c041ecb666 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A1s=20B=20Nagy?= <20251272+BNAndras@users.noreply.github.com> Date: Sun, 11 Oct 2026 10:25:01 -0700 Subject: [PATCH 2/6] Add v3 task id fixture --- tests/example-task-ids/.meta/config.json | 5 ++++ .../example-task-ids/example-task-ids.coffee | 3 +++ .../example-task-ids.spec.coffee | 13 +++++++++ tests/example-task-ids/expected_results.json | 27 +++++++++++++++++++ 4 files changed, 48 insertions(+) create mode 100644 tests/example-task-ids/.meta/config.json create mode 100644 tests/example-task-ids/example-task-ids.coffee create mode 100644 tests/example-task-ids/example-task-ids.spec.coffee create mode 100644 tests/example-task-ids/expected_results.json diff --git a/tests/example-task-ids/.meta/config.json b/tests/example-task-ids/.meta/config.json new file mode 100644 index 0000000..1978cf3 --- /dev/null +++ b/tests/example-task-ids/.meta/config.json @@ -0,0 +1,5 @@ +{ + "custom": { + "flag.tests.task-per-describe": true + } +} diff --git a/tests/example-task-ids/example-task-ids.coffee b/tests/example-task-ids/example-task-ids.coffee new file mode 100644 index 0000000..e34bdf1 --- /dev/null +++ b/tests/example-task-ids/example-task-ids.coffee @@ -0,0 +1,3 @@ +answer = -> 42 + +module.exports = answer diff --git a/tests/example-task-ids/example-task-ids.spec.coffee b/tests/example-task-ids/example-task-ids.spec.coffee new file mode 100644 index 0000000..596ef40 --- /dev/null +++ b/tests/example-task-ids/example-task-ids.spec.coffee @@ -0,0 +1,13 @@ +answer = require './example-task-ids' + +# First task by order of appearance, not label, in the file +describe 'second task', -> + it 'Should appear first', -> + expect(answer()).toEqual 42 + + xit 'Should appear second', -> + expect(answer()).toEqual 42 + +describe 'first task', -> + xit 'Should appear third', -> + expect(answer()).toEqual 42 diff --git a/tests/example-task-ids/expected_results.json b/tests/example-task-ids/expected_results.json new file mode 100644 index 0000000..8c09401 --- /dev/null +++ b/tests/example-task-ids/expected_results.json @@ -0,0 +1,27 @@ +{ + "version": 3, + "status": "pass", + "tests": [ + { + "name": "Should appear first", + "test_code": "expect(answer()).toEqual 42", + "task_id": 1, + "status": "pass", + "message": null + }, + { + "name": "Should appear second", + "test_code": "expect(answer()).toEqual 42", + "task_id": 1, + "status": "pass", + "message": null + }, + { + "name": "Should appear third", + "test_code": "expect(answer()).toEqual 42", + "task_id": 2, + "status": "pass", + "message": null + } + ] +} From e8f7d1e4d20f9dcdb2f04288394b389b86da9577 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A1s=20B=20Nagy?= <20251272+BNAndras@users.noreply.github.com> Date: Sun, 11 Oct 2026 10:26:36 -0700 Subject: [PATCH 3/6] Read track config for task-ids flag --- bin/run.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bin/run.sh b/bin/run.sh index b68dc12..c040b2f 100755 --- a/bin/run.sh +++ b/bin/run.sh @@ -35,6 +35,7 @@ input_dir="${2%/}" output_dir="${3%/}" tests_file="${input_dir}/${slug}.spec.coffee" original_tests_file="${input_dir}/${slug}.spec.coffee.original" +config_file="${input_dir}/.meta/config.json" capture_file="${output_dir}/capture" ast_file="${output_dir}/ast.json" results_file="${output_dir}/results.json" @@ -57,6 +58,6 @@ file=$(find ${output_dir} -type f -name "*.xml") if test -f "$file"; then sed_sub_in_place "&apos;" "\\'" "${file}" fi -node bin/results.js "${file}" "${output_dir}" "${capture_file}" "${ast_file}" ${tests_file} +node bin/results.js "${file}" "${output_dir}" "${capture_file}" "${ast_file}" "${tests_file}" "${config_file}" mv -f "${original_tests_file}" "${tests_file}" From 35deb608afabdc75abbdb118009e22e4540130a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A1s=20B=20Nagy?= <20251272+BNAndras@users.noreply.github.com> Date: Mon, 12 Oct 2026 21:16:06 -0700 Subject: [PATCH 4/6] Nest the describes in `example-task-ids` --- .../example-task-ids.spec.coffee | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/tests/example-task-ids/example-task-ids.spec.coffee b/tests/example-task-ids/example-task-ids.spec.coffee index 596ef40..2403981 100644 --- a/tests/example-task-ids/example-task-ids.spec.coffee +++ b/tests/example-task-ids/example-task-ids.spec.coffee @@ -1,13 +1,14 @@ answer = require './example-task-ids' # First task by order of appearance, not label, in the file -describe 'second task', -> - it 'Should appear first', -> - expect(answer()).toEqual 42 +describe 'task IDs', -> + describe 'second task', -> + it 'Should appear first', -> + expect(answer()).toEqual 42 - xit 'Should appear second', -> - expect(answer()).toEqual 42 + xit 'Should appear second', -> + expect(answer()).toEqual 42 -describe 'first task', -> - xit 'Should appear third', -> - expect(answer()).toEqual 42 + describe 'first task', -> + xit 'Should appear third', -> + expect(answer()).toEqual 42 From 8f73317c0a1265d7c854117a6e2b7206ca9ee9a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A1s=20B=20Nagy?= <20251272+BNAndras@users.noreply.github.com> Date: Mon, 12 Oct 2026 21:29:48 -0700 Subject: [PATCH 5/6] Track task ids if `tests.task-per-describe` enabled --- bin/results.coffee | 55 ++++++++++++++++++++++++++++------------------ 1 file changed, 34 insertions(+), 21 deletions(-) diff --git a/bin/results.coffee b/bin/results.coffee index 30cbb5a..93cd65c 100755 --- a/bin/results.coffee +++ b/bin/results.coffee @@ -5,17 +5,21 @@ he = require 'he' class TestRunner constructor: () -> @astData = [] + @taskIdsEnabled = false + + configFile = process.argv[7] + if configFile? and fs.existsSync(configFile) + config = JSON.parse(fs.readFileSync(configFile, 'utf8')) + @taskIdsEnabled = config.custom?['flag.tests.task-per-describe'] is true read_test_cases: (results) => fs.readFile process.argv[2], 'utf8', (err, data) => if err - @error_handeling() + @error_handling() else @read_ast_tree() .then(() => - options = - ignoreAttributes: false - parser = new XMLParser(options) + parser = new XMLParser(ignoreAttributes: false) @get_test_cases(parser.parse(data)) ) .catch((err) => console.log(err)) @@ -31,7 +35,7 @@ class TestRunner if typeof obj[key] is 'object' search_keys(obj[key]) search_keys(result) - + test_cases = [] fs.readFile process.argv[6], 'utf8', (err, data) => @@ -42,13 +46,16 @@ class TestRunner for test_case in matchingKeys name = he.decode(test_case['@_name'].replace(/'/g, "\'")); testInfo = @astData.find (element) => he.decode(element.name) is name - return @error_handeling() if testInfo is undefined + return @error_handling() if testInfo is undefined testCode = file.slice(testInfo["loc"]["start"]["line"], testInfo["loc"]["end"]["line"]) length = testCode[0].match(/^\s*/)[0].length testCode = (testCode.map (line) => (line.slice(length))).join("\n") data = name: test_case['@_name'] test_code: testCode + + if @taskIdsEnabled and testInfo.task_id? + data['task_id'] = testInfo.task_id if test_case.hasOwnProperty('failure') data['status'] = 'fail' @@ -59,7 +66,7 @@ class TestRunner test_cases.push(data) @write_result((if test_cases.some (item) -> item.status is "fail" then "fail" else "pass"), test_cases) - error_handeling: () => + error_handling: () => fs.readFile process.argv[4], 'utf8', (err, data) => if err console.log err @@ -78,21 +85,27 @@ class TestRunner ) get_ast_tree: (ast) => - search_keys = (obj) => + nextTaskId = 0 + search_keys = (obj, taskId) => for key in Object.keys(obj) - if typeof obj[key] is 'object' and obj[key] isnt null - if obj[key]["type"]? and obj[key]["expression"]?["callee"]?["name"]? - if obj[key]["type"] is "ExpressionStatement" and obj[key]["expression"]["callee"]["name"] is "it" - name = @read_test_name(obj[key]["expression"]?["arguments"]?[0]) - if name? and obj[key]["expression"]?["arguments"]?[1]?["loc"]? - @astData.push({name: name, loc: obj[key]["expression"]["arguments"][1]["loc"]}) - else - console.log("incorrect") - else - search_keys(obj[key]) + child = obj[key] + continue unless typeof child is 'object' and child? + + calleeName = child["expression"]?["callee"]?["name"] + if child["type"] is "ExpressionStatement" and calleeName is "it" + name = @read_test_name(child["expression"]?["arguments"]?[0]) + if name? and child["expression"]?["arguments"]?[1]?["loc"]? + @astData.push({name: name, loc: child["expression"]["arguments"][1]["loc"], task_id: taskId}) else - search_keys(obj[key]) - search_keys(ast) + console.log("incorrect") + else if child["type"] is "ExpressionStatement" and calleeName is "describe" + nextTaskId += 1 + search_keys(child, nextTaskId) + else + search_keys(child, taskId) + + for statement in ast.program?.body ? [] + search_keys(statement) read_test_name: (node) => return unless node? @@ -107,7 +120,7 @@ class TestRunner write_result: (status, test_cases = [], message = "") -> result = - version: 2 + version: 3 status: status tests: test_cases message: message if message isnt "" From 61b38dd90f739aaf858bcd8f6ba8b12a19b4dde1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A1s=20B=20Nagy?= <20251272+BNAndras@users.noreply.github.com> Date: Mon, 12 Oct 2026 21:44:09 -0700 Subject: [PATCH 6/6] End results.json with a newline --- bin/results.coffee | 2 +- tests/example-all-fail/expected_results.json | 2 +- tests/example-empty-file/expected_results.json | 2 +- tests/example-multiline-test-name/expected_results.json | 2 +- tests/example-partial-fail/expected_results.json | 2 +- tests/example-success/expected_results.json | 2 +- tests/example-syntax-error/expected_results.json | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/bin/results.coffee b/bin/results.coffee index 93cd65c..92576d2 100755 --- a/bin/results.coffee +++ b/bin/results.coffee @@ -127,7 +127,7 @@ class TestRunner - fs.writeFile "#{process.argv[3]}/results.json", JSON.stringify(result, null, "\t"), (err) -> + fs.writeFile "#{process.argv[3]}/results.json", "#{JSON.stringify(result, null, "\t")}\n", (err) -> if err console.log err else diff --git a/tests/example-all-fail/expected_results.json b/tests/example-all-fail/expected_results.json index 654744f..8f43b54 100644 --- a/tests/example-all-fail/expected_results.json +++ b/tests/example-all-fail/expected_results.json @@ -87,4 +87,4 @@ "message": "Expected 'I don't know.' to equal 'Fine. Be that way!'." } ] -} \ No newline at end of file +} diff --git a/tests/example-empty-file/expected_results.json b/tests/example-empty-file/expected_results.json index d862f79..642bab3 100644 --- a/tests/example-empty-file/expected_results.json +++ b/tests/example-empty-file/expected_results.json @@ -3,4 +3,4 @@ "status": "error", "tests": [], "message": "\u001b[31mF\u001b[0m\n\nFailures:\n\n 1) Bob encountered a declaration exception\n Message:\n \u001b[31mTypeError: Bob is not a constructor\u001b[0m\n Stacktrace:\n TypeError: Bob is not a constructor\n at jasmine.Suite. (/solution/example-empty-file.spec.coffee:3:9)\n at Object. (/solution/example-empty-file.spec.coffee:2:1)\n at Object. (/solution/example-empty-file.spec.coffee:1:1)\n at Module._compile (node:internal/modules/cjs/loader:1956:14)\n at Object.loadFile (/opt/test-runner/node_modules/jasmine-node/node_modules/coffeescript/lib/coffee-script/register.js:16:19)\n at Module.load (/opt/test-runner/node_modules/jasmine-node/node_modules/coffeescript/lib/coffee-script/register.js:45:36)\n at Module._load (node:internal/modules/cjs/loader:1470:12)\n at wrapModuleLoad (node:internal/modules/cjs/loader:261:19)\n at Module.require (node:internal/modules/cjs/loader:1701:12)\n at require (node:internal/modules/helpers:318:16)\n at Object.jasmine.executeSpecsInFolder (/opt/test-runner/node_modules/jasmine-node/lib/jasmine-node/index.js:160:9)\n at Object. (/opt/test-runner/node_modules/jasmine-node/lib/jasmine-node/cli.js:247:9)\n at Module._compile (node:internal/modules/cjs/loader:1956:14)\n at Object..js (node:internal/modules/cjs/loader:2096:10)\n at Module. (node:internal/modules/cjs/loader:1678:32)\n at Module._load (node:internal/modules/cjs/loader:1470:12)\n at wrapModuleLoad (node:internal/modules/cjs/loader:261:19)\n at Module.require (node:internal/modules/cjs/loader:1701:12)\n at require (node:internal/modules/helpers:318:16)\n at Object. (/opt/test-runner/node_modules/jasmine-node/bin/jasmine-node:6:1)\n at Module._compile (node:internal/modules/cjs/loader:1956:14)\n at Object..js (node:internal/modules/cjs/loader:2096:10)\n at Module. (node:internal/modules/cjs/loader:1678:32)\n at Module._load (node:internal/modules/cjs/loader:1470:12)\n at wrapModuleLoad (node:internal/modules/cjs/loader:261:19)\n at Module.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:171:5)\n at node:internal/main/run_main_module:33:47\n\n\n\n\u001b[31m1 test, 1 assertion, 1 failure, 0 skipped\n\u001b[0m\n\n" -} \ No newline at end of file +} diff --git a/tests/example-multiline-test-name/expected_results.json b/tests/example-multiline-test-name/expected_results.json index 8c22199..5ac84f8 100644 --- a/tests/example-multiline-test-name/expected_results.json +++ b/tests/example-multiline-test-name/expected_results.json @@ -9,4 +9,4 @@ "message": null } ] -} \ No newline at end of file +} diff --git a/tests/example-partial-fail/expected_results.json b/tests/example-partial-fail/expected_results.json index 27fbcf8..ba702dc 100644 --- a/tests/example-partial-fail/expected_results.json +++ b/tests/example-partial-fail/expected_results.json @@ -87,4 +87,4 @@ "message": "Expected 'Okay. Be that way!' to equal 'Fine. Be that way!'." } ] -} \ No newline at end of file +} diff --git a/tests/example-success/expected_results.json b/tests/example-success/expected_results.json index 1dfe514..2237f45 100644 --- a/tests/example-success/expected_results.json +++ b/tests/example-success/expected_results.json @@ -87,4 +87,4 @@ "message": null } ] -} \ No newline at end of file +} diff --git a/tests/example-syntax-error/expected_results.json b/tests/example-syntax-error/expected_results.json index 0d85a87..29e7440 100644 --- a/tests/example-syntax-error/expected_results.json +++ b/tests/example-syntax-error/expected_results.json @@ -3,4 +3,4 @@ "status": "error", "tests": [], "message": "Exception loading: /solution/example-syntax-error.spec.coffee\n[/solution/example-syntax-error.coffee:1:13: error: unexpected @\nclasSSY Bo%b@\n ^] {\n location: { first_line: 0, first_column: 12, last_line: 0, last_column: 12 },\n toString: [Function: syntaxErrorToString],\n code: 'clasSSY Bo%b@',\n filename: '/solution/example-syntax-error.coffee'\n}\n" -} \ No newline at end of file +}