| name | create-codeql-query-unit-test-javascript |
|---|---|
| description | Create comprehensive unit tests for CodeQL queries targeting JavaScript code. Use this skill when you need to create, validate, or enhance test coverage for JavaScript CodeQL queries using the CodeQL Development MCP Server tools. |
This skill guides you through creating comprehensive unit tests for CodeQL queries that analyze JavaScript code.
- Creating new unit tests for a JavaScript CodeQL query
- Adding test cases to existing JavaScript query tests
- Validating JavaScript query behavior against known code patterns
- Testing JavaScript security queries, code quality queries, or analysis queries
Before creating tests, ensure you have:
- A CodeQL query (
.qlfile) that you want to test - Understanding of what JavaScript code patterns the query should detect
- Knowledge of JavaScript language features and frameworks relevant to your query
- Access to CodeQL Development MCP Server tools
<query-pack>/test/{QueryName}/
├── {QueryName}.qlref # Reference to the query being tested
├── Example1.js # Primary test source file
├── Example2.js # Additional test cases (optional)
├── helper.js # Helper modules if needed (optional)
├── {QueryName}.expected # Expected query results
└── {QueryName}.testproj/ # Generated test database (auto-created)
- Test source files: Use
Example1.js,Example2.js, etc. ortest.js - Helper files: Use
.jsextension (e.g.,helper.js,utils.js) - Query reference:
{QueryName}.qlref(exact match to query directory name) - Expected results:
{QueryName}.expected(exact match to query name)
Create the test directory structure:
mkdir -p <query-pack>/test/{QueryName}Create {QueryName}.qlref with the relative path to your query:
{QueryName}/{QueryName}.ql
Example (FindXssVulnerability.qlref):
FindXssVulnerability/FindXssVulnerability.ql
Important: Path is relative to your query pack's source directory.
Create Example1.js with comprehensive test cases covering:
Positive (should detect):
document.getElementById('content').innerHTML = userInput; // XSS
eval(userCode); // Code injectionNegative (should NOT detect):
const sanitized = escapeHtml(userInput);
document.getElementById('content').innerHTML = sanitized; // SafeEdge cases:
async function asyncUnsafe(userInput) {
const data = await fetch('/api/data?q=' + userInput);
}Browser: document.write(userInput), element.innerHTML = userInput, location.href = userInput
Node.js: exec('ls ' + userInput), fs.writeFileSync(userInput, data)
Express.js:
app.get('/user/:id', (req, res) => {
const query = 'SELECT * FROM users WHERE id = ' + req.params.id; // Unsafe
db.query(query, [req.params.id]); // Safe with parameterization
});React: <div dangerouslySetInnerHTML={{ __html: userInput }} /> (unsafe) vs <div>{userInput}</div> (safe)
Async patterns: Test promises, async/await, callbacks Modern JS: Arrow functions, template literals, destructuring
Include Comments: Document each test case:
// Test case 1: DOM XSS via innerHTML (should detect)
function test1(userInput) {
document.getElementById('output').innerHTML = userInput;
}Create {QueryName}.expected with the expected query output:
| file | line | col | endLine | endCol | message |
| Example1.js | 3 | 5 | 3 | 45 | DOM-based XSS vulnerability |
| Example1.js | 8 | 5 | 8 | 15 | Code injection through eval |
Column Definitions:
file: Test source file name (e.g.,Example1.js)line: Starting line number (1-indexed)col: Starting column number (1-indexed)endLine: Ending line numberendCol: Ending column numbermessage: Expected alert message from the query
Important Notes:
- Both line and column numbers are 1-indexed (starting from 1)
- Message text should match query output exactly
- Order results by file, then line, then column
Use the codeql_test_extract MCP tool to create a test database:
{
"testPath": "<query-pack>/test/{QueryName}",
"searchPath": ["<query-pack>"]
}What This Does:
- Processes your JavaScript test code
- Creates a CodeQL database at
test/{QueryName}/{QueryName}.testproj/ - Extracts AST and semantic information
- Prepares database for query execution
JavaScript Extraction Notes:
- Supports ES5, ES6+, and modern JavaScript features
- Handles both CommonJS and ES modules
- Processes JSX and TypeScript files
- Includes Node.js and browser API modeling
- Extracts framework-specific patterns (Express, React, etc.)
Before finalizing your query, use PrintAST to understand the JavaScript AST structure:
Use the codeql_query_run MCP tool:
{
"query": "<query-pack>/src/PrintAST/PrintAST.ql",
"database": "<query-pack>/test/{QueryName}/{QueryName}.testproj",
"searchPath": ["<query-pack>"],
"format": "text"
}Use codeql_bqrs_decode to view the AST:
{
"format": "text",
"bqrsFile": "<path-to-results.bqrs>",
"outputPath": "<output-file.txt>"
}Key JavaScript AST Nodes to Look For:
- Functions:
Function,ArrowFunctionExpr,MethodDefinition - Classes:
ClassDefinition,ClassExpr - Expressions:
CallExpr,VarAccess,PropAccess,DotExpr - Statements:
ExprStmt,IfStmt,ReturnStmt,ThrowStmt - Async:
AwaitExpr,PromiseExpr - DOM:
DOMElement,DOMProperty - Literals:
StringLiteral,TemplateLiteral,ObjectExpr
Execute your tests using the codeql_test_run MCP tool:
{
"testPath": "<query-pack>/test/{QueryName}",
"searchPath": ["<query-pack>"]
}Interpreting Results:
✅ Tests Pass: Output matches .expected file exactly
- All expected alerts are found
- No unexpected alerts are produced
- Line and column numbers match
❌ Tests Fail: Differences between actual and expected
- Missing alerts: Query didn't find expected patterns
- Extra alerts: Query found unexpected patterns
- Position mismatch: Line/column numbers don't match
If tests fail, analyze the differences:
- Review actual query output: Check what the query actually found
- Compare with expected results: Identify discrepancies
- Update query or expected file:
- If query is wrong: Fix the query logic
- If expected is wrong: Update
.expectedfile
- Re-run tests: Use
codeql_test_runagain - Repeat until all tests pass
If the actual results are correct and you want to update the baseline:
{
"testPath": "<query-pack>/test/{QueryName}",
"searchPath": ["<query-pack>"]
}Use codeql_test_accept tool, but only after verifying the results are correct.
Expand test coverage by adding more test files:
- Create
Example2.jswith additional scenarios - Update
{QueryName}.expectedwith new expected results - Re-extract test database with
codeql_test_extract - Run tests again with
codeql_test_run
Include tests for JavaScript features relevant to your query:
- Dynamic Types: Test type coercion and implicit conversions
- Closures: Test variable capture in nested functions
- Prototypes: Test prototype chain and constructor patterns
- Async Operations: Test promises, async/await, callbacks
- Modules: Test CommonJS and ES6 module patterns
- Template Literals: Test string interpolation vulnerabilities
Express: app.get('/route', (req, res) => res.send(req.query.param))
React: <div>{prop}</div> vs <div dangerouslySetInnerHTML={{__html: prop}} />
function source() {
return userInput;
}
function sink(data) {
eval(data);
}
sink(source()); // Test flow from source to sinkXSS: element.innerHTML = userInput or template literals
SQL Injection: "SELECT * FROM users WHERE id = " + userId
Command Injection: exec('ls ' + userPath)
Prototype Pollution: Unsafe object merging
codeql_test_extract: Extract test databases from JavaScript source codecodeql_test_run: Run query tests and compare with expected resultscodeql_test_accept: Accept actual results as new baseline (use with caution)
codeql_query_compile: Compile CodeQL queries and check for syntax errorscodeql_query_format: Format CodeQL query filescodeql_query_run: Run queries (e.g., PrintAST) against test databases
codeql_bqrs_decode: Decode binary query results to human-readable textcodeql_bqrs_interpret: Interpret results in various formats (SARIF, CSV, graph)codeql_bqrs_info: Get metadata about query results
codeql_pack_install: Install query pack dependencies before testing
❌ Don't:
- Forget to test both browser and Node.js patterns when applicable
- Skip testing asynchronous patterns (promises, async/await)
- Ignore framework-specific security patterns
- Forget to test modern JavaScript features (arrow functions, template literals)
- Use invalid JavaScript syntax
- Skip testing edge cases like prototype pollution or type coercion
✅ Do:
- Write valid, executable JavaScript code
- Include comments explaining each test case
- Test both positive and negative cases
- Cover edge cases and boundary conditions
- Use realistic JavaScript patterns from real applications
- Test relevant framework usage (Express, React, etc.)
- Include async/await and promise tests when relevant
- Test both CommonJS and ES6 module patterns
Before considering your JavaScript tests complete:
- Test directory created with correct naming
-
.qlreffile correctly references query -
Example1.jsincludes comprehensive test cases - Test code is valid JavaScript
- All JavaScript features used by query are tested
- Framework-specific patterns tested (if applicable)
- Positive cases (should detect) are included
- Negative cases (should not detect) are included
- Edge cases are covered
-
.expectedfile has correct format with proper columns - Line and column numbers in
.expectedare accurate - Test database extracted successfully with
codeql_test_extract - Tests run successfully with
codeql_test_run - All tests pass (actual matches expected)
- Additional test files added if needed (Example2.js, etc.)
<query-pack>/test/FindDomXss/
├── FindDomXss.qlref # Content: FindDomXss/FindDomXss.ql
├── Example1.js # Test cases (see below)
├── FindDomXss.expected # Expected results
└── FindDomXss.testproj/ # Auto-generated
Example1.js:
// Positive: innerHTML XSS
function test1(userInput) {
document.getElementById('output').innerHTML = userInput;
}
// Negative: textContent (safe)
function test2(userInput) {
document.getElementById('output').textContent = userInput;
}
// Positive: Template literal with innerHTML XSS
function test3(userInput) {
element.innerHTML = `<p>${userInput}</p>`;
}FindDomXss.expected:
| file | line | col | endLine | endCol | message |
| Example1.js | 3 | 5 | 3 | 56 | DOM-based XSS via innerHTML |
| Example1.js | 13 | 5 | 13 | 43 | DOM-based XSS in template |
- Verify JavaScript code is syntactically valid
- Check for missing dependencies or imports
- Ensure proper module syntax (CommonJS vs ES6)
- Review extraction error messages
- Compare actual output with
.expectedfile - Verify line and column numbers are correct (1-indexed)
- Check message text matches exactly
- Review query logic for correctness
- Ensure consistent JavaScript runtime version
- Check for platform-specific code
- Verify all dependencies are available
- Review test database extraction settings
- JavaScript Query Development Prompt
- CodeQL TDD Generic Skill
- JavaScript QSpec Reference
- JavaScript AST Documentation
- Generate QSpec for JavaScript
Your JavaScript query unit tests are successful when:
- ✅ Test structure follows conventions
- ✅ JavaScript test code is valid and executable
- ✅ Test database extracts without errors
- ✅ All tests pass consistently
- ✅ Comprehensive coverage of JavaScript features
- ✅ Framework-specific patterns tested (if applicable)
- ✅ Both positive and negative cases included
- ✅ Edge cases properly handled
- ✅ Expected results accurately reflect query behavior