Complete guide to testing OpenCode WordPress components and examples.
Testing ensures OpenCode WordPress components work correctly and follow standards. This guide covers:
- Skill testing
- Agent testing
- Hook testing
- Command testing
- Example testing
- Integration testing
- WordPress testing
- PHPUnit: For PHP unit testing
- Jest: For JavaScript testing (hooks)
- WP-CLI: For WordPress testing
- Node.js: 14+ for hook testing
- PHP: 7.4+ for example testing
# Install PHPUnit globally
composer global require phpunit/phpunit
# Install Jest for hook tests
npm install --global jest
# Install WP-CLI
curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar
chmod +x wp-cli.phar
sudo mv wp-cli.phar /usr/local/bin/wp
# Verify installations
phpunit --version
jest --version
wp --versionTest skill invocation manually:
# Navigate to test WordPress project
cd test-wordpress-project
# Start OpenCode
opencode
# Invoke skill
opencode skill wordpress-theme-development
# Verify:
# - Skill loads correctly
# - Guidance is accurate
# - Examples are relevant
# - References are valid
# - No errors in outputFor each skill, verify:
- SKILL.md exists and is valid markdown
- Skill invokes correctly
- Guidance is WordPress-specific
- Examples are accurate
- Code examples follow WordPress standards
- References are valid URLs
- Version compatibility is documented
- No broken links
- No outdated information
Create automated skill test:
#!/bin/bash
# test-skills.sh
SKILLS_DIR="skills"
ERRORS=0
for skill_dir in "$SKILLS_DIR"/*; do
skill_name=$(basename "$skill_dir")
skill_file="$skill_dir/SKILL.md"
echo "Testing skill: $skill_name"
# Check SKILL.md exists
if [ ! -f "$skill_file" ]; then
echo "ERROR: SKILL.md not found for $skill_name"
ERRORS=$((ERRORS + 1))
continue
fi
# Validate markdown
if ! markdown-validator "$skill_file"; then
echo "ERROR: Invalid markdown in $skill_name"
ERRORS=$((ERRORS + 1))
fi
# Check required sections
sections=("Overview" "Capabilities" "Instructions" "Examples" "References")
for section in "${sections[@]}"; do
if ! grep -q "## $section" "$skill_file"; then
echo "ERROR: Missing section '$section' in $skill_name"
ERRORS=$((ERRORS + 1))
fi
done
# Test skill invocation (mock)
if ! opencode-test skill "$skill_name"; then
echo "ERROR: Skill invocation failed for $skill_name"
ERRORS=$((ERRORS + 1))
fi
done
echo "Skill tests completed with $ERRORS errors"
exit $ERRORSTest agent activates correctly:
# Create test WordPress file
echo "<?php wp_enqueue_script('test', 'url'); ?>" > test-file.php
# Invoke agent
opencode agent wordpress-reviewer --file=test-file.php
# Verify agent:
# - Activates for WordPress files
# - Detects issues
# - Reports in correct format
# - Provides actionable suggestionsCreate test cases for agents:
// test-cases/theme-reviewer/bad-enqueue.php
<?php
// This should trigger warning
wp_enqueue_style('style', get_stylesheet_uri());
// Missing: version parameter, proper handle name// test-cases/plugin-reviewer/no-nonce.php
<?php
function save_data() {
// This should trigger error
update_option('my_option', $_POST['data']);
// Missing: nonce verification, capability check, sanitization
}// test-cases/security-check/sql-injection.php
<?php
global $wpdb;
// This should trigger error
$results = $wpdb->get_results("SELECT * FROM table WHERE id = " . $_GET['id']);
// Missing: $wpdb->prepare()#!/bin/bash
# test-agents.sh
AGENTS_DIR="agents"
TEST_CASES_DIR="test-cases"
ERRORS=0
for agent_file in "$AGENTS_DIR"/*.md; do
agent_name=$(basename "$agent_file" .md)
echo "Testing agent: $agent_name"
# Check agent file exists
if [ ! -f "$agent_file" ]; then
echo "ERROR: Agent file not found"
ERRORS=$((ERRORS + 1))
continue
fi
# Test with test cases
if [ -d "$TEST_CASES_DIR/$agent_name" ]; then
for test_file in "$TEST_CASES_DIR/$agent_name"/*.php; do
echo "Testing with: $test_file"
# Run agent on test file
result=$(opencode agent "$agent_name" --file="$test_file" 2>&1)
# Check agent detected expected issues
if [[ $result != *"ERROR"* ]] && [[ $result != *"WARNING"* ]]; then
echo "ERROR: Agent did not detect issues in $test_file"
ERRORS=$((ERRORS + 1))
fi
done
fi
done
echo "Agent tests completed with $ERRORS errors"
exit $ERRORSTest hooks manually:
# Test PHP lint hook
node hooks/php-lint.js test-files/valid.php
# Should pass
node hooks/php-lint.js test-files/syntax-error.php
# Should fail with error
# Test WordPress debug check
node hooks/wp-debug-check.js test-files/no-debug.php
# Should pass
node hooks/wp-debug-check.js test-files/with-debug.php
# Should fail with var_dump detected
# Test security check
node hooks/security-check.js test-files/secure.php
# Should pass
node hooks/security-check.js test-files/sql-injection.php
# Should fail with SQL injection riskCreate test files for hooks:
// test-files/valid.php
<?php
/**
* Valid PHP file
*/
function valid_function() {
return 'valid';
}// test-files/syntax-error.php
<?php
function broken_function() {
echo "missing semicolon"
return // syntax error
}// test-files/with-debug.php
<?php
function debug_function() {
var_dump($variable); // Should trigger error
print_r($array); // Should trigger error
error_log('test'); // Allowed
}// test-files/sql-injection.php
<?php
function insecure_query() {
global $wpdb;
$id = $_GET['id'];
$results = $wpdb->get_results("SELECT * FROM table WHERE id = $id");
// Should trigger error
}Create Jest tests for hooks:
// hooks/__tests__/php-lint.test.js
const phpLint = require('../php-lint.js');
const fs = require('fs');
describe('PHP Lint Hook', () => {
test('should pass valid PHP file', async () => {
const files = [
{ path: 'test-files/valid.php', content: fs.readFileSync('test-files/valid.php', 'utf8') }
];
const result = await phpLint.validate(files, {});
expect(result.valid).toBe(true);
expect(result.errors).toHaveLength(0);
});
test('should fail PHP file with syntax error', async () => {
const files = [
{ path: 'test-files/syntax-error.php', content: fs.readFileSync('test-files/syntax-error.php', 'utf8') }
];
const result = await phpLint.validate(files, {});
expect(result.valid).toBe(false);
expect(result.errors.length).toBeGreaterThan(0);
});
test('should skip excluded files', async () => {
const files = [
{ path: 'vendor/package/file.php', content: 'invalid' }
];
const config = { exclude: ['vendor/'] };
const result = await phpLint.validate(files, config);
expect(result.valid).toBe(true);
});
});
// hooks/__tests__/wp-debug-check.test.js
const wpDebugCheck = require('../wp-debug-check.js');
describe('WordPress Debug Check Hook', () => {
test('should detect var_dump', async () => {
const files = [
{ path: 'test.php', content: 'var_dump($var);' }
];
const result = await wpDebugCheck.validate(files, {});
expect(result.valid).toBe(false);
expect(result.errors[0].message).toContain('var_dump');
});
test('should detect print_r', async () => {
const files = [
{ path: 'test.php', content: 'print_r($array);' }
];
const result = await wpDebugCheck.validate(files, {});
expect(result.valid).toBe(false);
expect(result.errors[0].message).toContain('print_r');
});
test('should allow error_log', async () => {
const files = [
{ path: 'test.php', content: 'error_log("message");' }
];
const result = await wpDebugCheck.validate(files, {});
expect(result.valid).toBe(true);
});
});
// hooks/__tests__/security-check.test.js
const securityCheck = require('../security-check.js');
describe('Security Check Hook', () => {
test('should detect SQL injection', async () => {
const files = [
{ path: 'test.php', content: '$wpdb->get_results("SELECT * FROM table WHERE id = $id");' }
];
const result = await securityCheck.validate(files, {});
expect(result.valid).toBe(false);
expect(result.errors[0].message).toContain('SQL injection');
});
test('should detect missing nonce verification', async () => {
const files = [
{ path: 'test.php', content: 'update_option("key", $_POST["value"]);' }
];
const result = await securityCheck.validate(files, {});
expect(result.valid).toBe(false);
expect(result.errors[0].message).toContain('nonce');
});
test('should pass secure code', async () => {
const files = [
{
path: 'test.php',
content: `
if (!wp_verify_nonce($_POST['nonce'], 'action')) wp_die();
if (!current_user_can('manage_options')) wp_die();
$value = sanitize_text_field($_POST['value']);
update_option('key', $value);
`
}
];
const result = await securityCheck.validate(files, {});
expect(result.valid).toBe(true);
});
});Run Jest tests:
cd hooks
npm testTest commands work correctly:
# Test theme command
/wp-theme create test-theme
# Verify theme created
/wp-theme validate test-theme
# Verify validation runs
# Test plugin command
/wp-plugin create test-plugin
# Verify plugin created
/wp-plugin validate test-plugin
# Verify validation runs
# Test review command
/wp-review path/to/file.php
# Verify review executes#!/bin/bash
# test-commands.sh
COMMANDS_DIR=".opencode/commands"
ERRORS=0
for command_file in "$COMMANDS_DIR"/*.md; do
command_name=$(basename "$command_file" .md)
echo "Testing command: $command_name"
# Check command file exists
if [ ! -f "$command_file" ]; then
echo "ERROR: Command file not found"
ERRORS=$((ERRORS + 1))
continue
fi
# Validate markdown
if ! markdown-validator "$command_file"; then
echo "ERROR: Invalid markdown"
ERRORS=$((ERRORS + 1))
fi
# Check frontmatter
if ! grep -q "^---" "$command_file"; then
echo "ERROR: Missing frontmatter"
ERRORS=$((ERRORS + 1))
fi
# Test command (mock)
if ! opencode-test command "$command_name"; then
echo "ERROR: Command invocation failed"
ERRORS=$((ERRORS + 1))
fi
done
echo "Command tests completed with $ERRORS errors"
exit $ERRORSTest theme example works:
# Navigate to theme example
cd examples/theme-example
# Check theme structure
ls -la
# Required files: style.css, index.php, functions.php
# Validate theme
wp theme validate opencode-theme-example
# Theme Check plugin
wp plugin install theme-check --activate
wp theme-check opencode-theme-example
# Test theme functionality
wp theme activate opencode-theme-example
# Visit site, verify templates workTest plugin example:
# Navigate to plugin example
cd examples/plugin-example
# Check plugin structure
ls -la
# Required file: my-plugin.php
# Validate plugin
wp plugin validate opencode-plugin-example
# Test plugin activation
wp plugin activate opencode-plugin-example
# Test plugin functionality
wp opencode-plugin test-command
# PHPUnit tests (if provided)
phpunitTest WooCommerce example:
# Ensure WooCommerce active
wp plugin install woocommerce --activate
# Navigate to WooCommerce example
cd examples/woocommerce-example
# Activate extension
wp plugin activate opencode-wc-extension
# Test WooCommerce integration
wc --extension=opencode-wc-extension test
# Create test product
wc product create --type=opencode_custom --name="Test Product"
# Test custom product type
wc product list --type=opencode_custom
# PHPUnit tests
phpunitTest complete workflow:
# 1. Create test WordPress installation
wp core download
wp config create --dbname=test --dbuser=root
wp db create
wp core install --url=test.local --title=Test
# 2. Start OpenCode in test installation
cd test-wordpress
opencode
# 3. Invoke skill
opencode skill wordpress-theme-development
# 4. Create theme following skill guidance
opencode: "Create theme following skill guidance"
# 5. Use command for validation
/wp-theme validate
# 6. Let agent review
opencode agent theme-reviewer
# 7. Fix issues
/wp-build-fix
# 8. Commit with hooks
git add .
git commit -m "Test workflow"
# 9. Verify hooks ran
git log --show-notes=hooks
# 10. Verify everything works
wp theme list
wp theme activate test-themeTest in CI pipeline:
# .github/workflows/test.yml
name: OpenCode WordPress Tests
on: [push, pull_request]
jobs:
test-skills:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Test Skills
run: ./test-skills.sh
test-agents:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Test Agents
run: ./test-agents.sh
test-hooks:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
- name: Install dependencies
run: cd hooks && npm install
- name: Test Hooks
run: cd hooks && npm test
test-examples:
runs-on: ubuntu-latest
services:
mysql:
image: mysql:5.7
wordpress:
image: wordpress:latest
steps:
- uses: actions/checkout@v2
- name: Test Theme Example
run: wp theme validate examples/theme-example
- name: Test Plugin Example
run: wp plugin validate examples/plugin-exampleSet up WordPress test environment:
# Install WordPress test library
bash <(curl -s https://raw.githubusercontent.com/kurpass/wp-test-lib/master/install.sh)
# Or use wp-cli scaffold
wp scaffold plugin-tests examples/plugin-example
# Run WordPress tests
phpunit -c wordpress-tests/phpunit.xmlCreate WordPress unit tests:
// examples/plugin-example/tests/test-main.php
<?php
class Plugin_Test extends WP_UnitTestCase {
public function test_plugin_activated() {
$this->assertTrue(class_exists('OpenCode_Plugin_Example\Plugin'));
}
public function test_custom_post_type_registered() {
$this->assertTrue(post_type_exists('opencode_item'));
}
public function test_option_saved() {
$value = 'test_value';
update_option('opencode_plugin_test', $value);
$this->assertEquals($value, get_option('opencode_plugin_test'));
}
public function test_shortcode_registered() {
global $shortcode_tags;
$this->assertArrayHasKey('opencode_shortcode', $shortcode_tags);
}
}Run WordPress unit tests:
cd examples/plugin-example
phpunitCreate theme unit tests:
// examples/theme-example/tests/test-theme.php
<?php
class Theme_Test extends WP_UnitTestCase {
public function test_theme_activated() {
$this->assertEquals('opencode-theme-example', get_stylesheet());
}
public function test_theme_supports_title_tag() {
$this->assertTrue(current_theme_supports('title-tag'));
}
public function test_theme_supports_post_thumbnails() {
$this->assertTrue(current_theme_supports('post-thumbnails'));
}
public function test_nav_menu_registered() {
$locations = get_nav_menu_locations();
$this->assertArrayHasKey('primary', $locations);
}
public function test_sidebar_registered() {
$this->assertTrue(is_active_sidebar('sidebar-1'));
}
}Test skill performance:
# Time skill invocation
time opencode skill wordpress-theme-development
# Should be < 5 secondsTest agent performance:
# Time agent review on large file
time opencode agent wordpress-reviewer --file=large-plugin.php
# Should be < 10 seconds for 100KB fileTest hook performance:
# Time hook validation on 100 files
time node hooks/php-lint.js $(find . -name "*.php" | head -100)
# Should be < 30 secondsMinimum test coverage:
- Skills: All skills tested
- Agents: All agents tested
- Hooks: 80% code coverage
- Examples: Core functionality tested
Generate coverage reports:
# Jest coverage
cd hooks
npm test -- --coverage
# PHPUnit coverage
cd examples/plugin-example
phpunit --coverage-html coverage/
# View reports
open hooks/coverage/lcov-report/index.html
open examples/plugin-example/coverage/index.htmlAutomated testing before commit:
# .git/hooks/pre-commit
#!/bin/bash
# Run all tests
./test-skills.sh
./test-agents.sh
cd hooks && npm test
# If any test fails, abort commitAutomated test pipeline:
# test-all.sh
#!/bin/bash
echo "Running all tests..."
# Skills
./test-skills.sh || exit 1
# Agents
./test-agents.sh || exit 1
# Commands
./test-commands.sh || exit 1
# Hooks
cd hooks && npm test || exit 1
# Examples
cd examples/plugin-example && phpunit || exit 1
cd examples/theme-example && phpunit || exit 1
echo "All tests passed!"Run all tests:
chmod +x test-all.sh
./test-all.shUpdate tests when:
- Adding new skills
- Adding new agents
- Adding new hooks
- Adding new examples
- WordPress version changes
- OpenCode version changes
Review tests regularly:
- Weekly: Check all tests pass
- Monthly: Review test coverage
- Quarterly: Update test cases
- Annually: Full test audit
# Check SKILL.md
cat skills/skill-name/SKILL.md
# Validate markdown
markdown-validator skills/skill-name/SKILL.md
# Check skill invocation
opencode skill skill-name --debug# Check agent file
cat agents/agent-name.md
# Check test cases
ls test-cases/agent-name/
# Run agent manually
opencode agent agent-name --file=test-file.php --debug# Check hook file
cat hooks/hook-name.js
# Run hook manually
node hooks/hook-name.js test-file.php
# Check Node.js version
node --version
# Reinstall dependencies
cd hooks && rm -rf node_modules && npm install# Check WordPress test library
ls wordpress-tests/
# Check phpunit.xml
cat phpunit.xml
# Run with debug
phpunit --debug
# Check PHP version
php --versionWrite tests before or alongside code:
- Test-driven development
- Examples need tests
- Hooks need tests
- Agents need test cases
Update tests when:
- Code changes
- WordPress updates
- Standards change
- Bugs found
Test all aspects:
- Functionality
- Security
- Performance
- Compatibility
- Edge cases
Document test requirements:
- How to run tests
- What tests cover
- How to fix test failures
- Test maintenance schedule
For testing questions:
- GitHub Issues: https://github.com/promoweb/opencode-wordpress/issues
- Testing Discussions: https://github.com/promoweb/opencode-wordpress/discussions/categories/testing
GPL v2 or later