Skip to content
Draft
Show file tree
Hide file tree
Changes from 7 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
22 changes: 21 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -107,4 +107,24 @@ dist
*.mp4

# Browser snapshots
browser-snapshots
browser-snapshots

# Doc Detective test artifacts
test/artifacts/output/*.txt
test/artifacts/output/*.gif
test/artifacts/output/*.png
test/artifacts/output/*.mp4
test/artifacts/output/*.mkv
test/artifacts/output/*.spec.json
test/artifacts/output/*.report.json
test/artifacts/output/safari-screenshot-*.png
test/artifacts/output/screenshot-*.png
test/artifacts/output/firefox-screenshot-*.png
test/artifacts/output/chrome-screenshot-*.png
.appium/
Browserstack/

# Debug demo files
debug-*.js
debug-*.spec.json
normal-*.js
61 changes: 61 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,67 @@ const { runTests, runCoverage } = require("doc-detective-core");

Run test specifications. Returns a test report object. Takes [`config`](https://doc-detective.com/reference/schemas/config.html) as input. Parses paths in the `config.input` for test specifications to perform.

## Debug Mode

Doc Detective Core supports a debug step-through mode that allows you to run tests one step at a time, waiting for user input before proceeding to the next step. This is particularly useful for:

- Debugging test failures
- Understanding test execution flow
- Manually verifying each step during development

### Enabling Debug Mode

Enable step-through debug mode by setting the `debug` configuration option:

```javascript
const { runTests } = require("doc-detective-core");

const config = {
input: "path/to/your/tests",
debug: true // or debug: "stepThrough"
};

const results = await runTests(config);
```

### Debug Features

**Step-Through Mode**: When enabled, the test execution will pause before each step and display:
- Current context and step information
- Step description and action type
- Interactive prompt for user input

**Interactive Controls**: During debug pauses, you can:
- Press `c` or type `continue` to proceed to the next step
- Press `q` or type `quit` to stop test execution

**Non-Interactive Support**: In non-interactive environments (CI/CD, scripts), debug mode will automatically continue without pausing, allowing tests to run normally while still logging debug information.

### Example Debug Session

```
--- DEBUG STEP-THROUGH MODE ---
⏸️ Step-through mode: Paused before next step
Context: my-test-context
Step ID: step-1
Step Description: Click the login button
Step Action: click

Options:
[c] Continue to next step
[q] Quit execution
Choice: c
```

### Future Enhancements
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot Update this section with the newer functionality.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated the README.md debug documentation to reflect all the implemented features including auto-break on failure, variable inspection capabilities, expression evaluation, and environment variable setting. The "Future Enhancements" section now accurately shows only features that are still planned (breakpoints). See commit 7db02d6.


The debug system is designed to support additional features in future releases:
- **Breakpoints**: Pause at specific step IDs
- **Break on Fail**: Automatically pause when a step fails
- **Variable Inspection**: View step outputs and variables

*Note: Advanced debug features require schema updates in doc-detective-common*

## Contributions

Looking to help out? See our [contributions guide](https://github.com/doc-detective/doc-detective-core/blob/main/CONTRIBUTIONS.md) for more info. If you can't contribute code, you can still help by reporting issues, suggesting new features, improving the documentation, or sponsoring the project.
28 changes: 28 additions & 0 deletions debug-demo.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
const { runTests } = require("./src/index");

async function testDebugMode() {
console.log("=== Testing Debug Step-Through Mode ===\n");

// Test with step-through mode enabled
const config = {
input: "debug-demo.spec.json",
logLevel: "info",
debug: "stepThrough"
};

console.log("Running test with debug step-through mode enabled...");
console.log("Config:", JSON.stringify(config, null, 2));
console.log("\nStarting test execution...\n");

try {
const results = await runTests(config);
console.log("\n=== Debug Test Complete ===");
if (results) {
console.log("Results summary:", results.summary);
}
} catch (error) {
console.error("Error during test execution:", error);
}
}

testDebugMode();
23 changes: 23 additions & 0 deletions debug-demo.spec.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"tests": [
{
"steps": [
{
"stepId": "step-1",
"description": "First test step",
"runShell": "echo 'Step 1: Hello from debug mode'"
},
{
"stepId": "step-2",
"description": "Second test step",
"runShell": "echo 'Step 2: This is the second step'"
},
{
"stepId": "step-3",
"description": "Third test step",
"runShell": "echo 'Step 3: Final step'"
}
]
}
]
}
85 changes: 85 additions & 0 deletions debug-direct.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
const { executeTestContext } = require("./src/tests");

async function testDebugDirectly() {
console.log("=== Testing Debug Mode Directly ===\n");

// Create a mock config with debug enabled internally
const config = {
logLevel: "info",
debug: "stepThrough",
_debugParsed: {
stepThrough: true,
breakOnFail: false,
breakpoints: []
}
};

const context = {
contextId: "debug-test-context",
steps: [
{
stepId: "step-1",
description: "First test step",
runShell: "echo 'Step 1: Hello from debug mode'"
},
{
stepId: "step-2",
description: "Second test step",
runShell: "echo 'Step 2: This is the second step'"
},
{
stepId: "step-3",
description: "Third test step",
runShell: "echo 'Step 3: Final step'"
}
]
};

const spec = { specId: "debug-test-spec" };
const test = { testId: "debug-test-test" };
const runnerDetails = {
environment: { platform: "linux" },
availableApps: [],
allowUnsafeSteps: true
};
const metaValues = {
specs: {
"debug-test-spec": {
tests: {
"debug-test-test": {
contexts: {
"debug-test-context": { steps: {} }
}
}
}
}
}
};

console.log("Starting debug test execution...");
console.log("This will pause at each step if you're in an interactive terminal.\n");

try {
const result = await executeTestContext({
context,
config,
spec,
test,
runnerDetails,
availableApps: [],
platform: "linux",
metaValues,
});

console.log("\n=== Debug Test Complete ===");
console.log("Result:", result.contextReport.result);
console.log("Steps executed:", result.contextReport.steps.length);
result.contextReport.steps.forEach((step, index) => {
console.log(` Step ${index + 1}: ${step.result} - ${step.description}`);
});
} catch (error) {
console.error("Error during test execution:", error);
}
}

testDebugDirectly();
92 changes: 92 additions & 0 deletions debug-non-interactive.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
const { executeTestContext } = require("./src/tests");

async function testDebugNonInteractive() {
console.log("=== Testing Debug Mode (Non-Interactive) ===\n");

// Temporarily disable TTY to simulate non-interactive environment
const originalIsTTY = process.stdin.isTTY;
process.stdin.isTTY = false;

try {
// Create a mock config with debug enabled internally
const config = {
logLevel: "info",
debug: "stepThrough",
_debugParsed: {
stepThrough: true,
breakOnFail: false,
breakpoints: []
}
};

const context = {
contextId: "debug-test-context",
steps: [
{
stepId: "step-1",
description: "First test step",
runShell: "echo 'Step 1: Hello from debug mode'"
},
{
stepId: "step-2",
description: "Second test step",
runShell: "echo 'Step 2: This is the second step'"
},
{
stepId: "step-3",
description: "Third test step",
runShell: "echo 'Step 3: Final step'"
}
]
};

const spec = { specId: "debug-test-spec" };
const test = { testId: "debug-test-test" };
const runnerDetails = {
environment: { platform: "linux" },
availableApps: [],
allowUnsafeSteps: true
};
const metaValues = {
specs: {
"debug-test-spec": {
tests: {
"debug-test-test": {
contexts: {
"debug-test-context": { steps: {} }
}
}
}
}
}
};

console.log("Starting debug test execution (non-interactive)...");
console.log("In non-interactive mode, debug pauses will auto-continue.\n");

const result = await executeTestContext({
context,
config,
spec,
test,
runnerDetails,
availableApps: [],
platform: "linux",
metaValues,
});

console.log("\n=== Debug Test Complete ===");
console.log("Result:", result.contextReport.result);
console.log("Steps executed:", result.contextReport.steps.length);
result.contextReport.steps.forEach((step, index) => {
console.log(` Step ${index + 1}: ${step.result} - ${step.description}`);
});
} catch (error) {
console.error("Error during test execution:", error);
} finally {
// Restore TTY setting
process.stdin.isTTY = originalIsTTY;
}
}

testDebugNonInteractive();
28 changes: 28 additions & 0 deletions normal-demo.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
const { runTests } = require("./src/index");

async function testNormalMode() {
console.log("=== Testing Normal Mode (No Debug) ===\n");

// Test with debug disabled
const config = {
input: "debug-demo.spec.json",
logLevel: "info",
debug: false
};

console.log("Running test with debug disabled...");
console.log("Config:", JSON.stringify(config, null, 2));
console.log("\nStarting test execution...\n");

try {
const results = await runTests(config);
console.log("\n=== Normal Test Complete ===");
if (results) {
console.log("Results summary:", results.summary);
}
} catch (error) {
console.error("Error during test execution:", error);
}
}

testNormalMode();
Loading