diff --git a/lua/neotest-stenciljs/init.lua b/lua/neotest-stenciljs/init.lua index 3e37087..27514d7 100644 --- a/lua/neotest-stenciljs/init.lua +++ b/lua/neotest-stenciljs/init.lua @@ -5,7 +5,7 @@ local logger = require("neotest.logging") local util = require("neotest-stenciljs.util") ---@class neotest.StencilOptions ----@field watch? boolean Run test(s) with the `--watchAll` flag +---@field watch? boolean Run test(s) with the `--watch` flag ---@field no_build? boolean Run test(s) with the `--no-build` flag ---@field env? table|fun(): table Set environment variables ---@field cwd? string|fun(): string The current working directory for running tests @@ -76,131 +76,6 @@ local function is_spec_test_file(file_path) return string.match(file_path, "%.spec%.tsx?$") end -adapter.root = function(path) - return lib.files.match_root_pattern("package.json")(path) -end - -function adapter.filter_dir(name, relpath, root) - return not vim.tbl_contains( - { "node_modules", "dist", "hydrate", "www", ".stencil", ".storybook" }, - name - ) -end - ----@param file_path? string ----@return boolean -function adapter.is_test_file(file_path) - return file_path ~= nil - and (is_e2e_test_file(file_path) or is_spec_test_file(file_path)) - and has_stencil_dep(file_path) -end - ----@async ----@return neotest.Tree | nil -function adapter.discover_positions(path) - local query = [[ - ; -------------------------------------------------------------------------- - ; -- Namespaces -- - ; -------------------------------------------------------------------------- - ; Matches: `describe('context', () => {})` - ((call_expression - function: (identifier) @func_name (#eq? @func_name "describe") - arguments: (arguments - [(string (string_fragment) @namespace.name) (template_string (string_fragment) @namespace.name)] (arrow_function) - ) - )) @namespace.definition - ; -------------------------------------------------------------------------- - ; Matches: `describe('context', function() {})` - ((call_expression - function: (identifier) @func_name (#eq? @func_name "describe") - arguments: (arguments - [(string (string_fragment) @namespace.name) (template_string (string_fragment) @namespace.name)] (function_expression) - ) - )) @namespace.definition - ; -------------------------------------------------------------------------- - ; Matches: `describe.only('context', () => {})` - ((call_expression - function: (member_expression - object: (identifier) @func_name (#any-of? @func_name "describe") - ) - arguments: (arguments - [(string (string_fragment) @namespace.name) (template_string (string_fragment) @namespace.name)] (arrow_function) - ) - )) @namespace.definition - ; -------------------------------------------------------------------------- - ; Matches: `describe.only('context', function() {})` - ((call_expression - function: (member_expression - object: (identifier) @func_name (#any-of? @func_name "describe") - ) - arguments: (arguments - [(string (string_fragment) @namespace.name) (template_string (string_fragment) @namespace.name)] (function_expression) - ) - )) @namespace.definition - ; -------------------------------------------------------------------------- - ; Matches: `describe.each(['data'])('context', () => {})` - ((call_expression - function: (call_expression - function: (member_expression - object: (identifier) @func_name (#any-of? @func_name "describe") - ) - ) - arguments: (arguments - [(string (string_fragment) @namespace.name) (template_string (string_fragment) @namespace.name)] (arrow_function) - ) - )) @namespace.definition - ; -------------------------------------------------------------------------- - ; Matches: `describe.each(['data'])('context', function() {})` - ((call_expression - function: (call_expression - function: (member_expression - object: (identifier) @func_name (#any-of? @func_name "describe") - ) - ) - arguments: (arguments (string (string_fragment) @namespace.name) (function_expression)) - )) @namespace.definition - ; -------------------------------------------------------------------------- - ; -- Tests -- - ; -------------------------------------------------------------------------- - ; Matches: `test('test') / it('test')` - ((call_expression - function: (identifier) @func_name (#any-of? @func_name "it" "test") - arguments: (arguments - [(string (string_fragment) @test.name) (template_string (string_fragment) @test.name)] [(arrow_function) (function_expression)] - ) - )) @test.definition - ; -------------------------------------------------------------------------- - ; Matches: `test.only('test') / it.only('test')` - ((call_expression - function: (member_expression - object: (identifier) @func_name (#any-of? @func_name "test" "it") - ) - arguments: (arguments - [(string (string_fragment) @test.name) (template_string (string_fragment) @test.name)] [(arrow_function) (function_expression)] - ) - )) @test.definition - ; -------------------------------------------------------------------------- - ; Matches: `test.each(['data'])('test') / it.each(['data'])('test')` - ((call_expression - function: (call_expression - function: (member_expression - object: (identifier) @func_name (#any-of? @func_name "it" "test") - property: (property_identifier) @each_property (#eq? @each_property "each") - ) - ) - arguments: (arguments - [(string (string_fragment) @test.name) (template_string (string_fragment) @test.name)] [(arrow_function) (function_expression)] - ) - )) @test.definition - ]] - - return lib.treesitter.parse_positions( - path, - query, - { nested_tests = false, requires_namespace = false } - ) -end - ---@param path string ---@return string local function get_stencil_command(path) @@ -283,7 +158,6 @@ local function get_cwd(file_path) return nil end -local function parsed_json_to_results(data, output_file, consoleOut) local function parsed_json_to_results(data, output_file, console_out) local tests = {} @@ -342,6 +216,131 @@ local function parsed_json_to_results(data, output_file, console_out) return tests end +adapter.root = function(path) + return lib.files.match_root_pattern("package.json")(path) +end + +function adapter.filter_dir(name, relpath, root) + return not vim.tbl_contains( + { "node_modules", "dist", "hydrate", "www", ".stencil", ".storybook" }, + name + ) +end + +---@param file_path? string +---@return boolean +function adapter.is_test_file(file_path) + return file_path ~= nil + and (is_e2e_test_file(file_path) or is_spec_test_file(file_path)) + and has_stencil_dep(file_path) +end + +---@async +---@return neotest.Tree | nil +function adapter.discover_positions(path) + local query = [[ + ; -------------------------------------------------------------------------- + ; -- Namespaces -- + ; -------------------------------------------------------------------------- + ; Matches: `describe('context', () => {})` + ((call_expression + function: (identifier) @func_name (#eq? @func_name "describe") + arguments: (arguments + [(string (string_fragment) @namespace.name) (template_string (string_fragment) @namespace.name)] (arrow_function) + ) + )) @namespace.definition + ; -------------------------------------------------------------------------- + ; Matches: `describe('context', function() {})` + ((call_expression + function: (identifier) @func_name (#eq? @func_name "describe") + arguments: (arguments + [(string (string_fragment) @namespace.name) (template_string (string_fragment) @namespace.name)] (function_expression) + ) + )) @namespace.definition + ; -------------------------------------------------------------------------- + ; Matches: `describe.only('context', () => {})` + ((call_expression + function: (member_expression + object: (identifier) @func_name (#any-of? @func_name "describe") + ) + arguments: (arguments + [(string (string_fragment) @namespace.name) (template_string (string_fragment) @namespace.name)] (arrow_function) + ) + )) @namespace.definition + ; -------------------------------------------------------------------------- + ; Matches: `describe.only('context', function() {})` + ((call_expression + function: (member_expression + object: (identifier) @func_name (#any-of? @func_name "describe") + ) + arguments: (arguments + [(string (string_fragment) @namespace.name) (template_string (string_fragment) @namespace.name)] (function_expression) + ) + )) @namespace.definition + ; -------------------------------------------------------------------------- + ; Matches: `describe.each(['data'])('context', () => {})` + ((call_expression + function: (call_expression + function: (member_expression + object: (identifier) @func_name (#any-of? @func_name "describe") + ) + ) + arguments: (arguments + [(string (string_fragment) @namespace.name) (template_string (string_fragment) @namespace.name)] (arrow_function) + ) + )) @namespace.definition + ; -------------------------------------------------------------------------- + ; Matches: `describe.each(['data'])('context', function() {})` + ((call_expression + function: (call_expression + function: (member_expression + object: (identifier) @func_name (#any-of? @func_name "describe") + ) + ) + arguments: (arguments (string (string_fragment) @namespace.name) (function_expression)) + )) @namespace.definition + ; -------------------------------------------------------------------------- + ; -- Tests -- + ; -------------------------------------------------------------------------- + ; Matches: `test('test') / it('test')` + ((call_expression + function: (identifier) @func_name (#any-of? @func_name "it" "test") + arguments: (arguments + [(string (string_fragment) @test.name) (template_string (string_fragment) @test.name)] [(arrow_function) (function_expression)] + ) + )) @test.definition + ; -------------------------------------------------------------------------- + ; Matches: `test.only('test') / it.only('test')` + ((call_expression + function: (member_expression + object: (identifier) @func_name (#any-of? @func_name "test" "it") + ) + arguments: (arguments + [(string (string_fragment) @test.name) (template_string (string_fragment) @test.name)] [(arrow_function) (function_expression)] + ) + )) @test.definition + ; -------------------------------------------------------------------------- + ; Matches: `test.each(['data'])('test') / it.each(['data'])('test')` + ((call_expression + function: (call_expression + function: (member_expression + object: (identifier) @func_name (#any-of? @func_name "it" "test") + property: (property_identifier) @each_property (#eq? @each_property "each") + ) + ) + arguments: (arguments + [(string (string_fragment) @test.name) (template_string (string_fragment) @test.name)] [(arrow_function) (function_expression)] + ) + )) @test.definition + ]] + + return lib.treesitter.parse_positions( + path, + query, + { nested_tests = false, requires_namespace = false } + ) +end + ---@param args neotest.RunArgs ---@return neotest.RunSpec | nil function adapter.build_spec(args) @@ -427,7 +426,6 @@ function adapter.results(spec, b, tree) spec.context.stop_stream() local output_file = spec.context.results_path - local success, data = pcall(lib.files.read, output_file) if not success then @@ -436,14 +434,12 @@ function adapter.results(spec, b, tree) end local ok, parsed = pcall(vim.json.decode, data, { luanil = { object = true } }) - if not ok then logger.error("Failed to parse test output json ", output_file) return {} end local results = parsed_json_to_results(parsed, output_file, b.output) - return results end