4f1fce367e
- The edit form's "Parent Wildcard" option stayed greyed out even when a valid wildcard existed, since hostEditOpen() never ran the eligibility check (only the host field's keyup handler did, which setting .val() programmatically doesn't fire) -- and the check itself, GET /host/lookup/:item, had the same self-match bug as the recently-fixed Host.prototype.update() case: it resolves an already-existing host to its own record instead of a sibling wildcard. Added a dedicated /host/wildcard-parent/:item route combining lookUp() (handles a brand-new subdomain) with lookUpWildcardParent() (handles an already-existing host), and hostEditOpen() now actually runs it. - Migrated ops/nginx_conf/autossl.conf's deprecated "listen ... http2" directive to the standalone "http2 on;" directive (nginx 1.25.1+). Bumps to v1.1.12. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KDEx8ghuZR61pqPXc6da9C
Test Suite
This project uses Node.js built-in test runner (requires Node 18+). No external testing dependencies required.
Running Tests
# Run all tests
npm test
# Run only unit tests
npm run test:unit
# Run only integration tests
npm run test:integration
# Run tests in watch mode (auto-rerun on file changes)
npm run test:watch
Test Structure
test/
├── unit/ # Unit tests for isolated components
│ ├── basicauth.test.js
│ ├── callback_queue.test.js
│ ├── dynamic_record.test.js
│ ├── host_features.test.js
│ ├── host_lookup.test.js
│ ├── hostname_validate.test.js
│ ├── host_sso.test.js
│ ├── oidc.test.js
│ ├── password_policy.test.js
│ ├── roles.test.js
│ ├── safe_redirect.test.js
│ ├── unix_socket.test.js
│ └── wildcard_matchany.test.js
├── integration/ # Integration tests for complex interactions
│ └── dns_provider.test.js
└── helpers/ # Test utilities and contracts
└── dns_provider_contract.js
What We Test
Unit Tests
callback_queue.test.js
- Callback registration and invocation
- Multiple callbacks with arguments
- Error handling
host_lookup.test.js
- Host lookup tree algorithm
- Wildcard matching (single and double)
- Exact match priority
- Edge cases (no match, empty input, etc.)
unix_socket.test.js
- Unix socket server creation
- JSON message parsing
- Partial data buffering
- Multiple connections
- Error handling
Integration Tests
dns_provider.test.js
- DNS provider contract compliance
- All existing providers (Cloudflare, DigitalOcean, PorkBun, DuckDNS)
- Method signatures
- Key mapping
- Type validation
Adding a New DNS Provider
When you add a new DNS provider, you MUST add tests to ensure it meets the contract:
-
Create your provider class extending
DnsApiinmodels/dns_provider/yourprovider.js -
Add a test block in
test/integration/dns_provider.test.js:
describe('YourProvider Provider', () => {
const YourProvider = require('../../models/dns_provider/yourprovider');
test('should meet DNS provider contract', () => {
const mockCredentials = {api_key: 'mock-key'};
const instance = validateDnsProviderContract(YourProvider, mockCredentials);
assert.ok(instance, 'YourProvider should be instantiated');
});
test('should have correct _keyMap structure', () => {
// Test your specific credential requirements
assert.ok(YourProvider._keyMap.api_key);
assert.strictEqual(YourProvider._keyMap.api_key.type, 'string');
assert.strictEqual(YourProvider._keyMap.api_key.isRequired, true);
});
test('should have valid method signatures', () => {
const instance = new YourProvider({api_key: 'mock'});
validateMethodSignatures(instance);
});
test('should validate key mapping', () => {
const instance = new YourProvider({api_key: 'mock'});
validateKeyMapping(instance);
});
test('should validate type checking', () => {
const instance = new YourProvider({api_key: 'mock'});
validateTypeChecking(instance);
});
});
- Run tests to verify compliance:
npm run test:integration
DNS Provider Contract
All DNS providers must:
- Extend
DnsApibase class - Define static
_keyMapwith required credentials - Define static display properties:
displayName,displayIconHtml,displayIconUni - Implement required methods:
listDomains()- Returns array of{domain, zoneId}getRecords(domain, options)- Returns array of DNS recordscreateRecord(domain, options)- Creates a recorddeleteRecords(domain, options)- Deletes matching records
- Define
__apiKeyMapto translate between class keys and API keys - Implement or inherit
__typeCheck()for record type validation - Throw appropriate errors from
this.errorsobject
CI/CD Integration
Tests can be run in GitHub Actions, GitLab CI, or any CI/CD system:
# Example GitHub Actions workflow
- name: Run tests
run: npm test
Philosophy
We test custom logic, not third-party code:
- YES: Test our host lookup algorithm
- YES: Test our socket buffering logic
- YES: Test DNS provider contracts
- NO: Don't test Express.js routing
- NO: Don't test the Redis ORM
- NO: Don't test external DNS APIs (use mocks)
Notes
- Tests use Node's built-in
node:testandnode:assertmodules - No external testing framework needed
- Tests are fast and run in parallel by default
- Mock external services (Redis, DNS APIs) to avoid network calls
- Focus on testing business logic, not infrastructure