Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 13 additions & 4 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,12 @@ This is a Neovim configuration managed as a Nix flake. The repository provides a

8. **Run checks:** `nix flake check`
- Validates flake structure
- Runs integration tests:
- `nvim-config-loads`: Verifies configuration loads without errors
- `nvim-health-check`: Runs `:checkhealth nobbz` to verify all systems
- `nvim-lua-tests`: Runs Lua-based integration tests for core functionality
- Checks `add-plugin` and `update-plugins` packages build successfully
- Run individual tests: `nix build .#checks.x86_64-linux.nvim-config-loads`

### Common Workflows

Expand Down Expand Up @@ -111,9 +116,13 @@ This is a Neovim configuration managed as a Nix flake. The repository provides a
**`pkgs/`** - Custom packages
- `oxide.nix` - Builds markdown-oxide LSP from pinned source

**`tests/`** - Integration tests
- `default.nix` - Flake-parts module, defines test checks
- `test-runner.lua` - Lua test framework for headless Neovim tests

**`.github/`** - GitHub configuration
- `copilot-instructions.md` - This file
- No CI workflows defined (validation is manual via `nix build`)
- No CI workflows defined (validation is manual via `nix flake check`)

### Key Configuration Files

Expand Down Expand Up @@ -160,9 +169,9 @@ Before submitting changes:

1. **Format:** `nix fmt` (REQUIRED - catches style issues)
2. **Build:** `nix build` (verifies Nix evaluation and package builds)
3. **Test run:** `nix run` (launches Neovim to verify it works)
4. **Check health:** In Neovim, run `:checkhealth nobbz` (verifies programs and LSP configs)
5. **Flake check:** `nix flake check` (validates flake structure)
3. **Run tests:** `nix flake check` (runs integration tests and validates flake structure)
4. **Test run:** `nix run` (launches Neovim to verify it works interactively)
5. **Check health:** In Neovim, run `:checkhealth nobbz` (verifies programs and LSP configs)
6. **Update instructions:** After major refactors, verify `.github/copilot-instructions.md` is still accurate

**No automated CI/CD** - all validation is manual. The maintainer runs these commands before merging.
Expand Down
28 changes: 27 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,31 @@ If you want to try it and are using `nix` already and have flakes enabled, you
can just run `nix run github:nobbz/nobbz-vim`, you might have to move/rename
existing configuration in `~/.config/nvim` temporarily.

Testing
-------

The configuration includes automated integration tests that can be run via:

```bash
nix flake check
```

This runs three test suites:

1. **nvim-config-loads**: Verifies the configuration loads without errors
2. **nvim-health-check**: Runs `:checkhealth nobbz` to verify all systems
3. **nvim-lua-tests**: Runs Lua-based integration tests for core functionality

Individual tests can be run with:

```bash
# Run specific test
nix build .#checks.x86_64-linux.nvim-config-loads

# View test output
cat result
```

Update process
--------------

Expand All @@ -15,7 +40,8 @@ Update process
3. *optional* fix build errors
4. update plugins: `nix run .#update-plugins`
5. *optional* fix build errors
6. *optional* update these instructions 😀
6. run tests: `nix flake check`
7. *optional* update these instructions 😀

Inspiration
-----------
Expand Down
2 changes: 1 addition & 1 deletion flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
parts.lib.mkFlake {inherit inputs;} {
systems = ["x86_64-linux"];

imports = [./plugins ./bin];
imports = [./plugins ./bin ./tests];

perSystem = {
self',
Expand Down
67 changes: 67 additions & 0 deletions tests/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# Neovim Integration Tests

This directory contains automated integration tests for the Neovim configuration.

## Test Structure

Tests are implemented as Nix derivations that run Neovim in headless mode. The tests are defined in `default.nix` and exposed via the flake's `checks` output.

## Available Tests

### 1. nvim-config-loads
Basic smoke test that verifies the configuration loads without errors.

```bash
nix build .#checks.x86_64-linux.nvim-config-loads
```

### 2. nvim-health-check
Runs `:checkhealth nobbz` to verify all programs and LSP configurations are correctly set up.

```bash
nix build .#checks.x86_64-linux.nvim-health-check
```

### 3. nvim-lua-tests
Runs a comprehensive Lua-based test suite that checks:
- Configuration loads completely
- Health check module is available
- LSP configurations are registered
- Lazy loading system works
- Key plugins are loaded
- Helper modules are available

```bash
nix build .#checks.x86_64-linux.nvim-lua-tests
```

## Running All Tests

```bash
nix flake check
```

## Test Implementation

Tests use `pkgs.runCommand` to create derivations that:
1. Set up a temporary HOME directory
2. Run Neovim in headless mode with specific commands
3. Capture output and verify success/failure
4. Exit with appropriate status codes

The Lua test runner (`test-runner.lua`) provides a simple test framework that:
- Runs individual test functions with `pcall` for error handling
- Tracks pass/fail status
- Prints results and summary
- Exits with status code 0 on success, 1 on failure

## Adding New Tests

To add a new test:

1. Add a new derivation in `tests/default.nix` under the `checks` attribute
2. Use the existing tests as a template
3. Ensure the test exits with status code 0 on success
4. Update this README with the new test

For Lua-based tests, add test cases in `test-runner.lua` using the `test()` function.
94 changes: 94 additions & 0 deletions tests/default.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
{
self',
pkgs,
lib,
...
}: let
# Test runner that will be available in the test environment
testRunner = pkgs.writeTextFile {
name = "test-runner.lua";
text = builtins.readFile ./test-runner.lua;
};

# Test initialization script
testInit = pkgs.writeTextFile {
name = "test.lua";
text = ''
-- Load the main configuration
require("nobbz")

-- Wait for config to fully load (250ms should be sufficient for most environments)
vim.defer_fn(function()
-- Run the test suite
local test_runner = dofile("${testRunner}")
test_runner.run()
end, 250)
'';
};
in {
perSystem = {
checks = {
nvim-config-loads = pkgs.runCommand "nvim-config-loads" {
nativeBuildInputs = [self'.packages.neovim];
} ''
# Run neovim headless and check if config loads without errors
export HOME=$(mktemp -d)
nvim --headless -c "lua vim.print('Config loaded successfully')" -c "quitall" 2>&1 | tee $out

# Check if there were any errors
if grep -qi "error" $out; then
echo "Configuration loaded with errors!"
exit 1
fi

echo "success" >> $out
'';

nvim-health-check = pkgs.runCommand "nvim-health-check" {
nativeBuildInputs = [self'.packages.neovim];
} ''
# Run neovim health check
export HOME=$(mktemp -d)
nvim --headless -c "checkhealth nobbz" -c "write! $out" -c "quitall" 2>&1

# Verify output exists
if [ ! -f "$out" ]; then
echo "Health check failed to produce output"
exit 1
fi

# Check for critical errors in health check
if grep -i "ERROR" $out; then
echo "Health check found errors:"
cat $out
exit 1
fi

echo "Health check passed"
'';

nvim-lua-tests = pkgs.runCommand "nvim-lua-tests" {
nativeBuildInputs = [self'.packages.neovim];
} ''
# Run Lua test suite
export HOME=$(mktemp -d)
nvim --headless -u ${testInit} 2>&1 | tee $out

# Check if tests passed
if grep -q "FAILED" $out; then
echo "Tests failed!"
cat $out
exit 1
fi

if ! grep -q "ALL TESTS PASSED" $out; then
echo "Tests did not complete successfully!"
cat $out
exit 1
fi

echo "success" >> $out
'';
};
};
}
99 changes: 99 additions & 0 deletions tests/test-runner.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
-- Test runner for headless neovim tests
-- This file loads the main config and runs various integration tests

local M = {}

local test_count = 0
local pass_count = 0

---Run a test and record its result
---@param name string Test name
---@param test_fn function Test function that returns boolean or throws error
local function test(name, test_fn)
test_count = test_count + 1
local success, result = pcall(test_fn)

if success and result ~= false then
pass_count = pass_count + 1
print(string.format("✓ %s", name))
else
local error_msg = result
if type(result) == "boolean" then error_msg = "Test returned false" end
print(string.format("✗ %s: %s", name, error_msg))
end
end

---Run all integration tests
M.run = function()
print("=== Running Neovim Integration Tests ===")
print("")

-- Test 1: Configuration loads without errors
test("Config loads without errors", function()
-- If we got here, config loaded successfully
return true
end)

-- Test 2: Health check module is available
test("Health check module is available", function()
local health = require("nobbz.health")
return health ~= nil and type(health.check) == "function"
end)

-- Test 3: LSP configurations are registered
test("LSP configurations are registered", function()
-- Check if vim.lsp.config table has entries
-- This validates that LSP servers were configured via the health system
local has_lsp_config = vim.lsp.config ~= nil
if not has_lsp_config then return false end

-- Verify at least one LSP is configured
local count = 0
for _ in pairs(vim.lsp.config) do
count = count + 1
end
return count > 0
end)

-- Test 4: Lazy loading system is available
test("Lazy loading system is available", function()
local lazy = require("nobbz.lazy")
return lazy ~= nil and type(lazy.add_specs) == "function"
end)

-- Test 5: Key global variables are set
test("Key global variables are set", function()
return WK ~= nil and LSP_CAPAS ~= nil
end)

-- Test 6: Core plugins are loaded
test("Core plugins are loaded", function()
local blink = require("blink.cmp")
local telescope = require("telescope")
return blink ~= nil and telescope ~= nil
end)

-- Test 7: Helpers module is available
test("Helpers module is available", function()
local helpers = require("nobbz.helpers")
return helpers ~= nil
end)

-- Print summary
print("")
print("=== Test Summary ===")
print(string.format("Total: %d", test_count))
print(string.format("Passed: %d", pass_count))
print(string.format("Failed: %d", test_count - pass_count))
print("")

if pass_count == test_count then
print("ALL TESTS PASSED")
os.exit(0)
else
print("TESTS FAILED")
os.exit(1)
end
end

return M