Skip to content

Commit 0489a9f

Browse files
committed
enhance markdown generation with new formatting functions and documentation
1 parent 26d03c6 commit 0489a9f

16 files changed

Lines changed: 274 additions & 216 deletions

dist/index.js

Lines changed: 50 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -27444,12 +27444,9 @@ class LinkGenerator {
2744427444
else if (markdownRelativePath.endsWith('.spec.ts')) {
2744527445
markdownRelativePath = markdownRelativePath.replace(/\.spec\.ts$/, '.md');
2744627446
}
27447-
else if (markdownRelativePath.startsWith('test_') && markdownRelativePath.endsWith('.py')) {
27448-
// Handle pytest files: test_example.py -> test_example.md
27449-
markdownRelativePath = markdownRelativePath.replace(/\.py$/, '.md');
27450-
}
27451-
else if (markdownRelativePath.endsWith('_test.py')) {
27452-
// Handle pytest files: example_test.py -> example_test.md
27447+
else if (markdownRelativePath.endsWith('.py')) {
27448+
// Handle all Python test files: convert .py extension to .md
27449+
// This fixes the issue with files in subfolders not getting .md extension
2745327450
markdownRelativePath = markdownRelativePath.replace(/\.py$/, '.md');
2745427451
}
2745527452
return markdownRelativePath;
@@ -27987,7 +27984,6 @@ class PytestExtractor {
2798727984
const testMatch = trimmedLine.match(/^def\s+(test_\w+)\s*\([^)]*\)\s*:/);
2798827985
if (testMatch) {
2798927986
const testName = testMatch[1];
27990-
const fullTestName = currentClass ? `${currentClass}::${testName}` : testName;
2799127987
const describeName = currentClass || path.basename(filePath, '.py');
2799227988
// Look ahead for docstring after the function definition
2799327989
let functionDocstring = [];
@@ -28042,9 +28038,14 @@ class PytestExtractor {
2804228038
const link = this.linkGenerator.generateTestLink(filePath, lineNumber, describeName, testName);
2804328039
// Extract tags from markers and description
2804428040
const tags = [...currentMarkers, ...this.tagProcessor.extractTags(describeName, description)];
28041+
// Format test names: remove "test_" prefix and replace underscores with spaces
28042+
const formattedTestName = this.formatTestName(testName);
28043+
const formattedFullTestName = currentClass
28044+
? `${currentClass}::${formattedTestName}`
28045+
: formattedTestName;
2804528046
tests.push({
28046-
testName: fullTestName,
28047-
shortName: testName,
28047+
testName: formattedFullTestName,
28048+
shortName: formattedTestName,
2804828049
describeName,
2804928050
link,
2805028051
description,
@@ -28054,7 +28055,7 @@ class PytestExtractor {
2805428055
framework: 'pytest'
2805528056
});
2805628057
if (this.verbose) {
28057-
console.log(` Found test: ${fullTestName} with markers: [${currentMarkers.join(', ')}]`);
28058+
console.log(` Found test: ${formattedFullTestName} with markers: [${currentMarkers.join(', ')}]`);
2805828059
}
2805928060
// Reset markers and docstring after processing
2806028061
currentMarkers = [];
@@ -28068,6 +28069,19 @@ class PytestExtractor {
2806828069
}
2806928070
return tests;
2807028071
}
28072+
/**
28073+
* Format test name: remove "test_" prefix and replace underscores with spaces
28074+
*/
28075+
formatTestName(testName) {
28076+
let formatted = testName;
28077+
// Remove "test_" prefix if present
28078+
if (formatted.startsWith('test_')) {
28079+
formatted = formatted.substring(5);
28080+
}
28081+
// Replace underscores with spaces
28082+
formatted = formatted.replace(/_/g, ' ');
28083+
return formatted;
28084+
}
2807128085
/**
2807228086
* Generate a summary for the file including test type counts
2807328087
*/
@@ -28092,25 +28106,30 @@ class PytestExtractor {
2809228106
};
2809328107
}
2809428108
/**
28095-
* Parse docstring content for test description and steps
28109+
* Parse docstring content for test description and steps - preserving original line breaks
2809628110
*/
2809728111
parseTestDescription(docstringLines) {
2809828112
if (docstringLines.length === 0) {
2809928113
return '';
2810028114
}
2810128115
const parsed = {
28102-
description: [],
2810328116
given: '',
2810428117
when: '',
2810528118
then: '',
2810628119
and: [],
2810728120
steps: []
2810828121
};
2810928122
let currentSection = 'description';
28123+
const descriptionLines = [];
2811028124
for (const line of docstringLines) {
2811128125
const trimmed = line.trim();
28112-
if (!trimmed)
28126+
if (!trimmed) {
28127+
// Preserve empty lines in description
28128+
if (currentSection === 'description') {
28129+
descriptionLines.push('');
28130+
}
2811328131
continue;
28132+
}
2811428133
// Check for bullet points (steps)
2811528134
if (trimmed.startsWith('* ')) {
2811628135
parsed.steps.push(trimmed.substring(2).trim());
@@ -28138,11 +28157,11 @@ class PytestExtractor {
2813828157
}
2813928158
// Add to current section
2814028159
if (currentSection === 'description') {
28141-
parsed.description.push(trimmed);
28160+
descriptionLines.push(trimmed);
2814228161
}
2814328162
}
28144-
// Format the description
28145-
let result = parsed.description.join(' ').trim();
28163+
// Format the description - preserve line breaks from original docstring
28164+
let result = descriptionLines.join('\n').trim();
2814628165
// Add BDD sections if present
2814728166
if (parsed.given)
2814828167
result += `\n\n**Given:** ${parsed.given}`;
@@ -28271,9 +28290,9 @@ class MarkdownGenerator {
2827128290
content += '|------|------|-----------|-------------|\n';
2827228291
for (const test of tests) {
2827328292
const typeEmoji = this.getTestTypeEmoji(test.testType);
28274-
const testName = this.escapeMarkdown(test.testName);
28293+
const testName = this.escapeMarkdownForTable(test.testName);
2827528294
const link = `[L${test.lineNumber}](${test.link})`;
28276-
const description = this.escapeMarkdown(test.description || 'No description available');
28295+
const description = this.escapeMarkdownForTable(test.description || 'No description available');
2827728296
content += `| ${typeEmoji} | ${link} | ${testName} | ${description} |\n`;
2827828297
}
2827928298
content += '\n---\n';
@@ -28373,12 +28392,12 @@ class MarkdownGenerator {
2837328392
content += '| Category | File | Link | Test Name | Description |\n';
2837428393
content += '|----------|------|------|-----------|-------------|\n';
2837528394
for (const test of allTests) {
28376-
const category = this.escapeMarkdown(test.category);
28395+
const category = this.escapeMarkdownForTable(test.category);
2837728396
const markdownRelativePath = this.linkGenerator.getMarkdownPath(test.filePath);
2837828397
const fileName = `[${test.fileName}](${markdownRelativePath})`;
28379-
const testName = this.escapeMarkdown(test.testName);
28398+
const testName = this.escapeMarkdownForTable(test.testName);
2838028399
const link = `[L${test.lineNumber}](${test.link})`;
28381-
const description = this.escapeMarkdown(test.description || 'No description available');
28400+
const description = this.escapeMarkdownForTable(test.description || 'No description available');
2838228401
content += `| ${category} | ${fileName} | ${link} | ${testName} | ${description} |\n`;
2838328402
}
2838428403
// Add tag-based index
@@ -28396,7 +28415,7 @@ class MarkdownGenerator {
2839628415
for (const test of testsWithTag) {
2839728416
const markdownRelativePath = this.linkGenerator.getMarkdownPath(test.filePath);
2839828417
const fileName = `[${test.fileName}](${markdownRelativePath})`;
28399-
const testName = this.escapeMarkdown(test.testName);
28418+
const testName = this.escapeMarkdownForTable(test.testName);
2840028419
const link = `[L${test.lineNumber}](${test.link})`;
2840128420
content += `| ${fileName} | ${link} | ${testName} |\n`;
2840228421
}
@@ -28484,6 +28503,15 @@ class MarkdownGenerator {
2848428503
default: return '❓';
2848528504
}
2848628505
}
28506+
/**
28507+
* Escape markdown special characters for table cells - preserves line breaks as <br>
28508+
*/
28509+
escapeMarkdownForTable(text) {
28510+
return text
28511+
.replace(/\|/g, '\\|')
28512+
.replace(/\n/g, '<br>')
28513+
.trim();
28514+
}
2848728515
/**
2848828516
* Escape markdown special characters
2848928517
*/

dist/index.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/markdown-generator.d.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ export declare class MarkdownGenerator {
1919
* Get test type emoji for display
2020
*/
2121
private getTestTypeEmoji;
22+
/**
23+
* Escape markdown special characters for table cells - preserves line breaks as <br>
24+
*/
25+
private escapeMarkdownForTable;
2226
/**
2327
* Escape markdown special characters
2428
*/

dist/pytest-extractor.d.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,16 @@ export declare class PytestExtractor {
99
* Extract tests from Python pytest file content
1010
*/
1111
extractTests(content: string, filePath: string): TestCase[];
12+
/**
13+
* Format test name: remove "test_" prefix and replace underscores with spaces
14+
*/
15+
private formatTestName;
1216
/**
1317
* Generate a summary for the file including test type counts
1418
*/
1519
generateFileSummary(tests: TestCase[]): FileSummary;
1620
/**
17-
* Parse docstring content for test description and steps
21+
* Parse docstring content for test description and steps - preserving original line breaks
1822
*/
1923
private parseTestDescription;
2024
/**

doc/pytest-tests/ALL_TESTS.md

Lines changed: 0 additions & 74 deletions
This file was deleted.

doc/pytest-tests/README.md

Lines changed: 0 additions & 29 deletions
This file was deleted.

doc/pytest-tests/test_example_pytest.py

Lines changed: 0 additions & 32 deletions
This file was deleted.

0 commit comments

Comments
 (0)