mirror of
https://github.com/pnx/neotest-phpunit
synced 2026-06-16 03:54:55 +02:00
phpunit
This commit is contained in:
parent
1429445746
commit
8cbe882c2f
5 changed files with 89 additions and 124 deletions
4
.phpactor.json
Normal file
4
.phpactor.json
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"$schema": "/phpactor.schema.json",
|
||||
"language_server_phpstan.enabled": false
|
||||
}
|
||||
33
README.md
33
README.md
|
|
@ -1,15 +1,14 @@
|
|||
# neotest-pest
|
||||
# neotest-phpunit
|
||||
|
||||
This plugin provides a [Pest](https://pestphp.com) adapter for the [Neotest](https://github.com/nvim-neotest/neotest) framework.
|
||||
This plugin provides a [PHPUnit](https://phpunit.de) adapter for the [Neotest](https://github.com/nvim-neotest/neotest) framework.
|
||||
|
||||
This is a fork of `neotest-pest` originally by [@theutz](https://github.com/theutz/neotest-pest), with some fixes and updates:
|
||||
This is a fork of `neotest-pest` originally by [@V13Axel](https://github.com/V13Axel/neotest-pest) modified for phpunit
|
||||
|
||||
- Updated to work with [Pest](https://pestphp.com) 2.0
|
||||
- Support for (and automatic detection of) Laravel Sail
|
||||
- Note: This also moves junit output files into `storage/app/`
|
||||
- Note: This also moves phpunit output files into `storage/app/`
|
||||
- Parallel testing support
|
||||
|
||||
:warning: _Ive only focused on making this work for me. Please test against your Pest tests_ :warning:
|
||||
:warning: _Ive only focused on making this work for me. Please test against your phpunit tests_ :warning:
|
||||
|
||||
## :package: Installation
|
||||
|
||||
|
|
@ -22,13 +21,13 @@ Here's an example using lazy.nvim:
|
|||
'nvim-neotest/neotest',
|
||||
dependencies = {
|
||||
...,
|
||||
'V13Axel/neotest-pest',
|
||||
'pnx/neotest-phpunit',
|
||||
},
|
||||
config = function()
|
||||
require('neotest').setup({
|
||||
...,
|
||||
adapters = {
|
||||
require('neotest-pest'),
|
||||
require('neotest-phpunit'),
|
||||
}
|
||||
})
|
||||
end
|
||||
|
|
@ -48,13 +47,13 @@ adapters = {
|
|||
-- -- Default: { "vendor", "node_modules" }
|
||||
ignore_dirs = { "vendor", "node_modules" }
|
||||
|
||||
-- Ignore any projects containing "phpunit-only.tests"
|
||||
-- Ignore any projects containing "no_phpunit"
|
||||
-- -- Default: {}
|
||||
root_ignore_files = { "phpunit-only.tests" },
|
||||
root_ignore_files = { "no_phpunit" },
|
||||
|
||||
-- Specify suffixes for files that should be considered tests
|
||||
-- -- Default: { "Test.php" }
|
||||
test_file_suffixes = { "Test.php", "_test.php", "PestTest.php" },
|
||||
test_file_suffixes = { "Test.php", "_test.php" },
|
||||
|
||||
-- Sail not properly detected? Explicitly enable it.
|
||||
-- -- Default: function() that checks for sail presence
|
||||
|
|
@ -71,16 +70,12 @@ adapters = {
|
|||
|
||||
-- Custom pest binary.
|
||||
-- -- Default: function that checks for sail presence
|
||||
pest_cmd = "vendor/bin/pest",
|
||||
phpunit_cmd = "vendor/bin/phpunit",
|
||||
|
||||
-- Run N tests in parallel, <=1 doesn't pass --parallel to pest at all
|
||||
-- Run N tests in parallel, <=1 doesn't pass --parallel to phpunit at all
|
||||
-- -- Default: 0
|
||||
parallel = 16
|
||||
|
||||
-- Enable ["compact" output printer](https://pestphp.com/docs/optimizing-tests#content-compact-printer)
|
||||
-- -- Default: false
|
||||
compact = false,
|
||||
|
||||
-- Set a custom path for the results XML file, parsed by this adapter
|
||||
--
|
||||
------------------------------------------------------------------------------------
|
||||
|
|
@ -127,7 +122,7 @@ To test the full test suite run `lua require('neotest').run.run({ suite = true }
|
|||
|
||||
## :gift: Contributing
|
||||
|
||||
I'm just one guy, maintaining this in my spare time and when I can get to it. Please raise a PR if you are interested in adding new functionality or fixing any bugs. When submitting a bug, please include an example test that I can test against.
|
||||
Please raise a PR if you are interested in adding new functionality or fixing any bugs. When submitting a bug, please include an example test that I can test against.
|
||||
|
||||
To trigger the tests for the adapter, run:
|
||||
|
||||
|
|
@ -137,4 +132,4 @@ To trigger the tests for the adapter, run:
|
|||
|
||||
## :clap: Prior Art
|
||||
|
||||
This package is a fork of [neotest-pest](https://github.com/theutz/neotest-pest) by [@theutz](https://github.com/olimorris), which relied _heavily_ on [olimorris/neotest-phpunit](https://github.com/olimorris/neotest-phpunit) by [@olimorris](https://github.com/olimorris).
|
||||
This package is a fork of [neotest-pest](https://github.com/V13Axel/neotest-pest) by [@V13Axel](https://github.com/V13Axel) which is a fork of [neotest-pest](https://github.com/theutz/neotest-pest) by [@theutz](https://github.com/olimorris), which relied _heavily_ on [olimorris/neotest-phpunit](https://github.com/olimorris/neotest-phpunit) by [@olimorris](https://github.com/olimorris).
|
||||
|
|
|
|||
|
|
@ -11,13 +11,12 @@ end
|
|||
local M = {
|
||||
env = {
|
||||
root_ignore_files = {},
|
||||
root_files = { "tests/Pest.php" },
|
||||
root_files = { "tests/" },
|
||||
ignore_dirs = { "vendor", "node_modules" },
|
||||
test_file_suffixes = { "Test.php" },
|
||||
sail_executable = "vendor/bin/sail",
|
||||
sail_project_path = "/var/www/html",
|
||||
parallel = 0,
|
||||
compact = false,
|
||||
},
|
||||
|
||||
_sail_error = false,
|
||||
|
|
@ -39,17 +38,17 @@ function M.env.is_parallel()
|
|||
return M('parallel') > 0
|
||||
end
|
||||
|
||||
function M.env.pest_cmd()
|
||||
function M.env.phpunit_cmd()
|
||||
if M('sail_enabled') then
|
||||
return { "vendor/bin/sail", "bin", "pest" }
|
||||
return { M('sail_executable'), "phpunit" }
|
||||
end
|
||||
|
||||
return { "vendor/bin/pest" }
|
||||
return { "vendor/bin/phpunit" }
|
||||
end
|
||||
|
||||
function M.env.results_path()
|
||||
if M('sail_enabled') then
|
||||
return "storage/app/" .. os.date("pest-%Y%m%d-%H%M%S")
|
||||
return "storage/app/" .. os.date("phpunit-%Y%m%d-%H%M%S")
|
||||
end
|
||||
|
||||
return async.fn.tempname()
|
||||
|
|
@ -1,12 +1,12 @@
|
|||
local lib = require('neotest.lib')
|
||||
local logger = require('neotest.logging')
|
||||
local utils = require('neotest-pest.utils')
|
||||
local config = require('neotest-pest.config')
|
||||
local utils = require('neotest-phpunit.utils')
|
||||
local config = require('neotest-phpunit.config')
|
||||
local debug = logger.debug
|
||||
|
||||
---@class neotest.Adapter
|
||||
---@field name string
|
||||
local NeotestAdapter = { name = "neotest-pest" }
|
||||
local NeotestAdapter = { name = "neotest-phpunit" }
|
||||
|
||||
---Find the project root directory given a current directory to work from.
|
||||
---Should no root be found, the adapter can still be use dina non-project context
|
||||
|
|
@ -73,29 +73,35 @@ end
|
|||
|
||||
function NeotestAdapter.discover_positions(path)
|
||||
local query = [[
|
||||
((expression_statement
|
||||
(member_call_expression
|
||||
name: (name) @member_name (#eq? @member_name "group")
|
||||
arguments: (arguments . (argument (string (string_content) @namespace.name)))
|
||||
) @member
|
||||
((class_declaration
|
||||
name: (name) @namespace.name (#match? @namespace.name "Test")
|
||||
)) @namespace.definition
|
||||
|
||||
((function_call_expression
|
||||
function: (name) @func_name (#match? @func_name "^(test|it)$")
|
||||
arguments: (arguments . (argument (_ (string_content) @test.name)))
|
||||
((method_declaration
|
||||
(attribute_list
|
||||
(attribute_group
|
||||
(attribute) @test_attribute (#match? @test_attribute "Test")
|
||||
)
|
||||
)
|
||||
(
|
||||
(visibility_modifier)
|
||||
(name) @test.name
|
||||
) @test.definition
|
||||
))
|
||||
|
||||
((method_declaration
|
||||
(name) @test.name (#match? @test.name "test")
|
||||
)) @test.definition
|
||||
|
||||
((expression_statement
|
||||
(member_call_expression
|
||||
object: (#eq? @test.definition)
|
||||
name: (name) @member_call_name (#match? @member_call_name "^(with)$")
|
||||
arguments: (arguments . (argument (array_creation_expression (array_element_initializer (array_creation_expression (array_element_initializer (_) @test.parameter .) )))))
|
||||
)
|
||||
(((comment) @test_comment (#match? @test_comment "\\@test") .
|
||||
(method_declaration
|
||||
(name) @test.name
|
||||
) @test.definition
|
||||
))
|
||||
]]
|
||||
|
||||
return lib.treesitter.parse_positions(path, query, {
|
||||
position_id = "require('neotest-pest.utils').make_test_id",
|
||||
position_id = "require('neotest-phpunit.utils').make_test_id",
|
||||
})
|
||||
end
|
||||
|
||||
|
|
@ -108,7 +114,7 @@ function NeotestAdapter.build_spec(args)
|
|||
debug("Building spec for:", position)
|
||||
debug("Results path:", results_path)
|
||||
|
||||
local path = position.path;
|
||||
local path = position.path
|
||||
|
||||
if config('sail_enabled') then
|
||||
debug("Sail enabled, adjusting path")
|
||||
|
|
@ -120,7 +126,7 @@ function NeotestAdapter.build_spec(args)
|
|||
end
|
||||
|
||||
local command = vim.tbl_flatten({
|
||||
config('pest_cmd'),
|
||||
config('phpunit_cmd'),
|
||||
path,
|
||||
"--log-junit=" .. results_path,
|
||||
})
|
||||
|
|
@ -129,24 +135,7 @@ function NeotestAdapter.build_spec(args)
|
|||
command = vim.tbl_flatten({
|
||||
command,
|
||||
"--filter",
|
||||
position.name,
|
||||
})
|
||||
else
|
||||
if config('is_parallel') then
|
||||
command = vim.tbl_flatten({
|
||||
command,
|
||||
"--parallel",
|
||||
"--processes=" .. config('parallel'),
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
if config('compact') == true then
|
||||
info("Using compact output")
|
||||
command = vim.tbl_flatten({
|
||||
command,
|
||||
"--compact",
|
||||
"::" .. position.name .. "( with data set .*)?$",
|
||||
})
|
||||
end
|
||||
|
||||
|
|
@ -1,21 +1,22 @@
|
|||
local logger = require("neotest.logging")
|
||||
local config = require('neotest-phpunit.config')
|
||||
|
||||
local M = {}
|
||||
local separator = "::"
|
||||
|
||||
---Generate an id which we can use to match Treesitter queries and Pest tests
|
||||
---Generate an id which we can use to match Treesitter queries and PHPUnit tests
|
||||
---@param position neotest.Position The position to return an ID for
|
||||
---@param namespace neotest.Position[] Any namespaces the position is within
|
||||
---@return string
|
||||
M.make_test_id = function(position)
|
||||
-- Treesitter ID needs to look like 'tests/Unit/ColsHelperTest.php::it returns the proper format'
|
||||
-- which means it should include position.path. However, as of PHPUnit 10, position.path
|
||||
-- includes the root directory of the project, which breaks the ID matching.
|
||||
-- As such, we need to remove the root directory from the path.
|
||||
-- Treesitter starts line numbers from 0 so we add 1
|
||||
local path = string.sub(position.path, string.len(vim.loop.cwd()) + 2)
|
||||
-- local id = position.path .. separator .. (tonumber(position.range[1]) + 1)
|
||||
local id = path .. separator .. (tonumber(position.range[1]) + 1)
|
||||
|
||||
local id = path .. separator .. position.name
|
||||
logger.debug("Path to test file:", { position.path })
|
||||
logger.debug("Treesitter id:", { id })
|
||||
logger.info("New path:", { path })
|
||||
logger.info("Path to test file:", { position.path })
|
||||
logger.info("Treesitter id:", { id })
|
||||
|
||||
return id
|
||||
end
|
||||
|
|
@ -39,77 +40,54 @@ end
|
|||
|
||||
---Extract the failure messages from the tests
|
||||
---@param tests table,
|
||||
---@return boolean,table,table
|
||||
---@return boolean|table
|
||||
local function errors_or_fails(tests)
|
||||
local failed = false
|
||||
local errors = {}
|
||||
local fails = {}
|
||||
local errors_fails = {}
|
||||
|
||||
iterate_key(tests, "error", errors)
|
||||
iterate_key(tests, "failure", fails)
|
||||
iterate_key(tests, "error", errors_fails)
|
||||
iterate_key(tests, "failure", errors_fails)
|
||||
|
||||
if #errors > 0 or #fails > 0 then
|
||||
failed = true
|
||||
if #errors_fails == 0 then
|
||||
return false
|
||||
end
|
||||
|
||||
return failed, errors, fails
|
||||
end
|
||||
|
||||
local function make_short_output(test_attr, status)
|
||||
return string.upper(status) .. " | " .. test_attr.name
|
||||
return errors_fails
|
||||
end
|
||||
|
||||
---Make the outputs for a given test
|
||||
---@param test table
|
||||
---@param output_file string
|
||||
---@return string, table
|
||||
---@return table
|
||||
local function make_outputs(test, output_file)
|
||||
logger.debug("Pre-output test:", test)
|
||||
local test_attr = test["_attr"] or test[1]["_attr"]
|
||||
local name = string.gsub(test_attr.name, "^it (.*)", "%1")
|
||||
local root_dir = vim.loop.cwd()
|
||||
|
||||
-- Difference to neotest-phpunit as of PHPUnit 10:
|
||||
-- Pest's test IDs are in the format "path/to/test/file::test name"
|
||||
local test_id = string.gsub(test_attr.file, "(.*)::(.*)", "%1") .. separator .. name
|
||||
logger.debug("Pest id:", { test_id })
|
||||
if config('sail_enabled') then
|
||||
root_dir = config('sail_project_path')
|
||||
end
|
||||
|
||||
local relfile = string.sub(test_attr.file, string.len(root_dir) + 2)
|
||||
|
||||
local test_id = relfile .. separator .. test_attr.line
|
||||
logger.info("PHPUnit id:", { test_id })
|
||||
|
||||
local classname = test_attr.classname or test_attr.class
|
||||
local test_output = {
|
||||
status = "passed",
|
||||
short = make_short_output(test_attr, "passed"),
|
||||
short = string.upper(classname) .. "\n-> " .. "PASSED" .. " - " .. test_attr.name,
|
||||
output_file = output_file,
|
||||
}
|
||||
|
||||
local test_failed, errors, fails = errors_or_fails(test)
|
||||
|
||||
local test_failed = errors_or_fails(test)
|
||||
if test_failed then
|
||||
logger.debug("test_failed:", { test_failed, errors, fails })
|
||||
test_output.status = "failed"
|
||||
|
||||
if #errors > 0 then
|
||||
local message = errors[1][1]
|
||||
test_output.short = make_short_output(test_attr, "error") .. "\n\n" .. message
|
||||
test_output.short = test_failed[1]["failure"] or test_failed[1]["errors"]
|
||||
test_output.errors = {
|
||||
{
|
||||
message = message
|
||||
line = test_attr.line,
|
||||
},
|
||||
}
|
||||
elseif #fails > 0 then
|
||||
local message = fails[1][1]
|
||||
test_output.short = make_short_output(test_attr, "failed") .. "\n\n" .. message
|
||||
test_output.errors = {
|
||||
{
|
||||
message = message
|
||||
}
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
if test['skipped'] then
|
||||
test_output.status = "skipped"
|
||||
test_output.short = make_short_output(test_attr, "skipped")
|
||||
end
|
||||
|
||||
logger.debug("test_output:", test_output)
|
||||
|
||||
return test_id, test_output
|
||||
end
|
||||
Loading…
Add table
Add a link
Reference in a new issue