Add unit tests for Auto Bullet plugin

This commit is contained in:
Hiroo Takizawa 2025-03-17 21:55:04 +09:00
parent 9d4bf71704
commit a66ad2f812
4 changed files with 4381 additions and 43 deletions

View file

@ -0,0 +1,209 @@
// Obsidianの環境をモックする代わりに、必要なインターフェースだけをインポート
import { Editor } from 'obsidian';
// モックの作成
class MockEditor implements Partial<Editor> {
private lines: string[] = [''];
private cursorPosition = { line: 0, ch: 0 };
constructor(initialContent: string[] = ['']) {
this.lines = initialContent;
}
getLine(lineNumber: number): string {
return this.lines[lineNumber] || '';
}
getCursor(): { line: number; ch: number } {
return this.cursorPosition;
}
setCursor(position: { line: number; ch: number }): void {
this.cursorPosition = position;
}
replaceRange(
replacement: string,
from: { line: number; ch: number },
to: { line: number; ch: number }
): void {
const line = this.lines[from.line] || '';
const beforeCursor = line.substring(0, from.ch);
const afterCursor = line.substring(to.ch);
this.lines[from.line] = beforeCursor + replacement + afterCursor;
}
// テスト用のヘルパーメソッド
simulateTyping(text: string): void {
for (const char of text) {
const line = this.lines[this.cursorPosition.line] || '';
const beforeCursor = line.substring(0, this.cursorPosition.ch);
const afterCursor = line.substring(this.cursorPosition.ch);
this.lines[this.cursorPosition.line] = beforeCursor + char + afterCursor;
this.cursorPosition.ch += 1;
}
}
getCurrentContent(): string[] {
return [...this.lines];
}
}
// 直接ハンドラー関数をテスト
describe('AutoBullet機能のテスト', () => {
let mockEditor: MockEditor;
// handleEditorChangeの実装main.tsから抽出
function handleEditorChange(editor: Editor, settings: any) {
const cursor = editor.getCursor();
const line = editor.getLine(cursor.line);
const lastChar = line.charAt(cursor.ch - 1);
// Check if the last character typed was a space (half-width or full-width) or tab
// and if the corresponding setting is enabled
if ((lastChar === ' ' && settings.enableHalfWidthSpace) ||
(lastChar === '\t' && settings.enableTab) ||
(lastChar === ' ' && settings.enableFullWidthSpace)) {
const textBeforeCursor = line.slice(0, cursor.ch);
// Check if we're at the beginning of a line (only whitespace before cursor)
if (textBeforeCursor.trim() === '') {
// Check if the line already has a bullet point
const lineWithoutWhitespace = line.trim();
if (!lineWithoutWhitespace.startsWith('- ')) {
// Insert a bullet point
const bulletPoint = "- ";
editor.replaceRange(bulletPoint,
{ line: cursor.line, ch: 0 },
{ line: cursor.line, ch: textBeforeCursor.length }
);
// Move cursor after the bullet point
editor.setCursor({ line: cursor.line, ch: bulletPoint.length });
}
}
}
}
beforeEach(() => {
// エディタの準備
mockEditor = new MockEditor();
});
test('半角スペースで箇条書きが挿入される', () => {
// 設定
const settings = {
enableHalfWidthSpace: true,
enableFullWidthSpace: true,
enableTab: true
};
// 行の先頭で半角スペースを入力
mockEditor.simulateTyping(' ');
// ハンドラーを実行
handleEditorChange(mockEditor as unknown as Editor, settings);
// 箇条書きが挿入されたことを確認
expect(mockEditor.getCurrentContent()[0]).toBe('- ');
expect(mockEditor.getCursor()).toEqual({ line: 0, ch: 2 });
});
test('全角スペースで箇条書きが挿入される', () => {
// 設定
const settings = {
enableHalfWidthSpace: true,
enableFullWidthSpace: true,
enableTab: true
};
// 行の先頭で全角スペースを入力
mockEditor.simulateTyping(' ');
// ハンドラーを実行
handleEditorChange(mockEditor as unknown as Editor, settings);
// 箇条書きが挿入されたことを確認
expect(mockEditor.getCurrentContent()[0]).toBe('- ');
expect(mockEditor.getCursor()).toEqual({ line: 0, ch: 2 });
});
test('タブで箇条書きが挿入される', () => {
// 設定
const settings = {
enableHalfWidthSpace: true,
enableFullWidthSpace: true,
enableTab: true
};
// 行の先頭でタブを入力
mockEditor.simulateTyping('\t');
// ハンドラーを実行
handleEditorChange(mockEditor as unknown as Editor, settings);
// 箇条書きが挿入されたことを確認
expect(mockEditor.getCurrentContent()[0]).toBe('- ');
expect(mockEditor.getCursor()).toEqual({ line: 0, ch: 2 });
});
test('行の先頭でない場合は箇条書きが挿入されない', () => {
// 設定
const settings = {
enableHalfWidthSpace: true,
enableFullWidthSpace: true,
enableTab: true
};
// 先頭に文字がある状態でスペースを入力
mockEditor.simulateTyping('テキスト ');
// ハンドラーを実行
handleEditorChange(mockEditor as unknown as Editor, settings);
// 箇条書きが挿入されないことを確認
expect(mockEditor.getCurrentContent()[0]).toBe('テキスト ');
});
test('設定が無効の場合は箇条書きが挿入されない', () => {
// 設定を無効化
const settings = {
enableHalfWidthSpace: false,
enableFullWidthSpace: false,
enableTab: false
};
// 行の先頭でスペースを入力
mockEditor.simulateTyping(' ');
// ハンドラーを実行
handleEditorChange(mockEditor as unknown as Editor, settings);
// 箇条書きが挿入されないことを確認
expect(mockEditor.getCurrentContent()[0]).toBe(' ');
});
test('既に箇条書きがある場合は重複して挿入されない', () => {
// 設定
const settings = {
enableHalfWidthSpace: true,
enableFullWidthSpace: true,
enableTab: true
};
// 既に箇条書きがある状態を作成
mockEditor = new MockEditor(['- ']);
mockEditor.setCursor({ line: 0, ch: 2 });
// スペースを入力
mockEditor.simulateTyping(' ');
// ハンドラーを実行
handleEditorChange(mockEditor as unknown as Editor, settings);
// 箇条書きが重複して挿入されないことを確認
// スペースが入力されるので「- 」になる
expect(mockEditor.getCurrentContent()[0]).toBe('- ');
});
});

11
jest.config.js Normal file
View file

@ -0,0 +1,11 @@
// 標準のJest設定を使用
module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
testMatch: ['**/__tests__/**/*.test.ts'],
transform: {
'^.+\\.tsx?$': ['ts-jest', {
tsconfig: 'tsconfig.json',
}],
},
};

4196
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -6,7 +6,8 @@
"scripts": { "scripts": {
"dev": "node esbuild.config.mjs", "dev": "node esbuild.config.mjs",
"build": "tsc -noEmit -skipLibCheck && node esbuild.config.mjs production", "build": "tsc -noEmit -skipLibCheck && node esbuild.config.mjs production",
"version": "node version-bump.mjs && git add manifest.json versions.json" "version": "node version-bump.mjs && git add manifest.json versions.json",
"test": "jest --passWithNoTests"
}, },
"keywords": [ "keywords": [
"obsidian", "obsidian",
@ -18,12 +19,17 @@
"author": "", "author": "",
"license": "MIT", "license": "MIT",
"devDependencies": { "devDependencies": {
"@types/jest": "^29.5.14",
"@types/node": "^16.11.6", "@types/node": "^16.11.6",
"@typescript-eslint/eslint-plugin": "5.29.0", "@typescript-eslint/eslint-plugin": "5.29.0",
"@typescript-eslint/parser": "5.29.0", "@typescript-eslint/parser": "5.29.0",
"builtin-modules": "3.3.0", "builtin-modules": "3.3.0",
"esbuild": "0.25.0", "esbuild": "0.25.0",
"jest": "^29.7.0",
"jest-environment-obsidian": "^0.0.1",
"jest-message-util": "^29.7.0",
"obsidian": "latest", "obsidian": "latest",
"ts-jest": "^29.2.6",
"tslib": "2.4.0", "tslib": "2.4.0",
"typescript": "4.7.4" "typescript": "4.7.4"
} }