@aigne/doc-smith 0.8.12-beta.8 → 0.8.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +15 -0
- package/agents/publish/index.yaml +4 -0
- package/agents/publish/publish-docs.mjs +77 -5
- package/agents/publish/translate-meta.mjs +103 -0
- package/agents/update/generate-document.yaml +30 -28
- package/agents/update/update-document-detail.yaml +3 -1
- package/agents/utils/update-branding.mjs +69 -0
- package/package.json +16 -2
- package/prompts/common/document/role-and-personality.md +3 -1
- package/prompts/detail/d2-diagram/guide.md +7 -1
- package/prompts/detail/d2-diagram/user-prompt.md +3 -0
- package/prompts/detail/generate/system-prompt.md +6 -7
- package/prompts/detail/generate/user-prompt.md +12 -3
- package/prompts/detail/update/user-prompt.md +0 -2
- package/prompts/structure/update/user-prompt.md +0 -4
- package/utils/file-utils.mjs +69 -24
- package/utils/markdown-checker.mjs +0 -20
- package/utils/request.mjs +7 -0
- package/utils/upload-files.mjs +231 -0
- package/utils/utils.mjs +11 -1
- package/.aigne/doc-smith/config.yaml +0 -77
- package/.aigne/doc-smith/history.yaml +0 -37
- package/.aigne/doc-smith/media-description.yaml +0 -91
- package/.aigne/doc-smith/output/structure-plan.json +0 -162
- package/.aigne/doc-smith/preferences.yml +0 -97
- package/.aigne/doc-smith/upload-cache.yaml +0 -1830
- package/.github/PULL_REQUEST_TEMPLATE.md +0 -28
- package/.github/workflows/ci.yml +0 -54
- package/.github/workflows/create-release-pr.yaml +0 -21
- package/.github/workflows/publish-docs.yml +0 -65
- package/.github/workflows/release.yml +0 -49
- package/.github/workflows/reviewer.yml +0 -54
- package/.release-please-manifest.json +0 -3
- package/RELEASE.md +0 -9
- package/assets/screenshots/doc-complete-setup.png +0 -0
- package/assets/screenshots/doc-generate-docs.png +0 -0
- package/assets/screenshots/doc-generate.png +0 -0
- package/assets/screenshots/doc-generated-successfully.png +0 -0
- package/assets/screenshots/doc-publish.png +0 -0
- package/assets/screenshots/doc-regenerate.png +0 -0
- package/assets/screenshots/doc-translate-langs.png +0 -0
- package/assets/screenshots/doc-translate.png +0 -0
- package/assets/screenshots/doc-update.png +0 -0
- package/biome.json +0 -73
- package/codecov.yml +0 -15
- package/docs/_sidebar.md +0 -15
- package/docs/configuration-initial-setup.ja.md +0 -179
- package/docs/configuration-initial-setup.md +0 -198
- package/docs/configuration-initial-setup.zh-TW.md +0 -179
- package/docs/configuration-initial-setup.zh.md +0 -179
- package/docs/configuration-managing-preferences.ja.md +0 -100
- package/docs/configuration-managing-preferences.md +0 -100
- package/docs/configuration-managing-preferences.zh-TW.md +0 -100
- package/docs/configuration-managing-preferences.zh.md +0 -100
- package/docs/configuration.ja.md +0 -69
- package/docs/configuration.md +0 -69
- package/docs/configuration.zh-TW.md +0 -69
- package/docs/configuration.zh.md +0 -69
- package/docs/getting-started.ja.md +0 -107
- package/docs/getting-started.md +0 -107
- package/docs/getting-started.zh-TW.md +0 -107
- package/docs/getting-started.zh.md +0 -107
- package/docs/guides-cleaning-up.ja.md +0 -51
- package/docs/guides-cleaning-up.md +0 -52
- package/docs/guides-cleaning-up.zh-TW.md +0 -51
- package/docs/guides-cleaning-up.zh.md +0 -51
- package/docs/guides-evaluating-documents.ja.md +0 -66
- package/docs/guides-evaluating-documents.md +0 -107
- package/docs/guides-evaluating-documents.zh-TW.md +0 -66
- package/docs/guides-evaluating-documents.zh.md +0 -66
- package/docs/guides-generating-documentation.ja.md +0 -151
- package/docs/guides-generating-documentation.md +0 -89
- package/docs/guides-generating-documentation.zh-TW.md +0 -151
- package/docs/guides-generating-documentation.zh.md +0 -151
- package/docs/guides-interactive-chat.ja.md +0 -85
- package/docs/guides-interactive-chat.md +0 -93
- package/docs/guides-interactive-chat.zh-TW.md +0 -85
- package/docs/guides-interactive-chat.zh.md +0 -85
- package/docs/guides-managing-history.ja.md +0 -48
- package/docs/guides-managing-history.md +0 -53
- package/docs/guides-managing-history.zh-TW.md +0 -48
- package/docs/guides-managing-history.zh.md +0 -48
- package/docs/guides-publishing-your-docs.ja.md +0 -78
- package/docs/guides-publishing-your-docs.md +0 -83
- package/docs/guides-publishing-your-docs.zh-TW.md +0 -78
- package/docs/guides-publishing-your-docs.zh.md +0 -78
- package/docs/guides-translating-documentation.ja.md +0 -95
- package/docs/guides-translating-documentation.md +0 -100
- package/docs/guides-translating-documentation.zh-TW.md +0 -95
- package/docs/guides-translating-documentation.zh.md +0 -95
- package/docs/guides-updating-documentation.ja.md +0 -77
- package/docs/guides-updating-documentation.md +0 -79
- package/docs/guides-updating-documentation.zh-TW.md +0 -77
- package/docs/guides-updating-documentation.zh.md +0 -77
- package/docs/guides.ja.md +0 -32
- package/docs/guides.md +0 -32
- package/docs/guides.zh-TW.md +0 -32
- package/docs/guides.zh.md +0 -32
- package/docs/overview.ja.md +0 -61
- package/docs/overview.md +0 -61
- package/docs/overview.zh-TW.md +0 -61
- package/docs/overview.zh.md +0 -61
- package/docs/release-notes.ja.md +0 -255
- package/docs/release-notes.md +0 -288
- package/docs/release-notes.zh-TW.md +0 -255
- package/docs/release-notes.zh.md +0 -255
- package/prompts/common/afs/afs-tools-usage.md +0 -5
- package/prompts/common/afs/use-afs-instruction.md +0 -1
- package/release-please-config.json +0 -14
- package/tests/agents/chat/chat.test.mjs +0 -46
- package/tests/agents/clear/choose-contents.test.mjs +0 -284
- package/tests/agents/clear/clear-auth-tokens.test.mjs +0 -268
- package/tests/agents/clear/clear-document-config.test.mjs +0 -167
- package/tests/agents/clear/clear-document-structure.test.mjs +0 -380
- package/tests/agents/clear/clear-generated-docs.test.mjs +0 -222
- package/tests/agents/evaluate/code-snippet.test.mjs +0 -163
- package/tests/agents/evaluate/fixtures/api-services.md +0 -87
- package/tests/agents/evaluate/fixtures/js-sdk.md +0 -94
- package/tests/agents/evaluate/generate-report.test.mjs +0 -312
- package/tests/agents/generate/check-document-structure.test.mjs +0 -45
- package/tests/agents/generate/check-need-generate-structure.test.mjs +0 -279
- package/tests/agents/generate/document-structure-tools/add-document.test.mjs +0 -449
- package/tests/agents/generate/document-structure-tools/delete-document.test.mjs +0 -410
- package/tests/agents/generate/document-structure-tools/generate-sub-structure.test.mjs +0 -277
- package/tests/agents/generate/document-structure-tools/move-document.test.mjs +0 -476
- package/tests/agents/generate/document-structure-tools/update-document.test.mjs +0 -548
- package/tests/agents/generate/generate-structure.test.mjs +0 -45
- package/tests/agents/generate/user-review-document-structure.test.mjs +0 -319
- package/tests/agents/history/view.test.mjs +0 -97
- package/tests/agents/init/init.test.mjs +0 -1657
- package/tests/agents/prefs/prefs.test.mjs +0 -431
- package/tests/agents/publish/publish-docs.test.mjs +0 -787
- package/tests/agents/translate/choose-language.test.mjs +0 -311
- package/tests/agents/translate/translate-document.test.mjs +0 -51
- package/tests/agents/update/check-document.test.mjs +0 -463
- package/tests/agents/update/check-update-is-single.test.mjs +0 -300
- package/tests/agents/update/document-tools/update-document-content.test.mjs +0 -329
- package/tests/agents/update/generate-document.test.mjs +0 -51
- package/tests/agents/update/save-and-translate-document.test.mjs +0 -369
- package/tests/agents/update/user-review-document.test.mjs +0 -582
- package/tests/agents/utils/action-success.test.mjs +0 -54
- package/tests/agents/utils/check-detail-result.test.mjs +0 -743
- package/tests/agents/utils/check-feedback-refiner.test.mjs +0 -478
- package/tests/agents/utils/choose-docs.test.mjs +0 -406
- package/tests/agents/utils/exit.test.mjs +0 -70
- package/tests/agents/utils/feedback-refiner.test.mjs +0 -51
- package/tests/agents/utils/find-item-by-path.test.mjs +0 -517
- package/tests/agents/utils/find-user-preferences-by-path.test.mjs +0 -382
- package/tests/agents/utils/format-document-structure.test.mjs +0 -364
- package/tests/agents/utils/fs.test.mjs +0 -267
- package/tests/agents/utils/load-sources.test.mjs +0 -1470
- package/tests/agents/utils/save-docs.test.mjs +0 -109
- package/tests/agents/utils/save-output.test.mjs +0 -315
- package/tests/agents/utils/save-single-doc.test.mjs +0 -364
- package/tests/agents/utils/transform-detail-datasources.test.mjs +0 -320
- package/tests/utils/auth-utils.test.mjs +0 -596
- package/tests/utils/blocklet.test.mjs +0 -336
- package/tests/utils/conflict-detector.test.mjs +0 -355
- package/tests/utils/constants.test.mjs +0 -295
- package/tests/utils/d2-utils.test.mjs +0 -437
- package/tests/utils/deploy.test.mjs +0 -399
- package/tests/utils/docs-finder-utils.test.mjs +0 -650
- package/tests/utils/file-utils.test.mjs +0 -521
- package/tests/utils/history-utils.test.mjs +0 -206
- package/tests/utils/kroki-utils.test.mjs +0 -646
- package/tests/utils/linter/fixtures/css/keyword-error.css +0 -1
- package/tests/utils/linter/fixtures/css/missing-semicolon.css +0 -1
- package/tests/utils/linter/fixtures/css/syntax-error.css +0 -1
- package/tests/utils/linter/fixtures/css/undeclare-variable.css +0 -1
- package/tests/utils/linter/fixtures/css/unused-variable.css +0 -2
- package/tests/utils/linter/fixtures/css/valid-code.css +0 -1
- package/tests/utils/linter/fixtures/dockerfile/keyword-error.dockerfile +0 -1
- package/tests/utils/linter/fixtures/dockerfile/missing-semicolon.dockerfile +0 -2
- package/tests/utils/linter/fixtures/dockerfile/syntax-error.dockerfile +0 -2
- package/tests/utils/linter/fixtures/dockerfile/undeclare-variable.dockerfile +0 -1
- package/tests/utils/linter/fixtures/dockerfile/unused-variable.dockerfile +0 -1
- package/tests/utils/linter/fixtures/dockerfile/valid-code.dockerfile +0 -2
- package/tests/utils/linter/fixtures/go/keyword-error.go +0 -5
- package/tests/utils/linter/fixtures/go/missing-semicolon.go +0 -5
- package/tests/utils/linter/fixtures/go/syntax-error.go +0 -6
- package/tests/utils/linter/fixtures/go/undeclare-variable.go +0 -5
- package/tests/utils/linter/fixtures/go/unused-variable.go +0 -5
- package/tests/utils/linter/fixtures/go/valid-code.go +0 -7
- package/tests/utils/linter/fixtures/js/keyword-error.js +0 -3
- package/tests/utils/linter/fixtures/js/missing-semicolon.js +0 -6
- package/tests/utils/linter/fixtures/js/syntax-error.js +0 -4
- package/tests/utils/linter/fixtures/js/undeclare-variable.js +0 -3
- package/tests/utils/linter/fixtures/js/unused-variable.js +0 -7
- package/tests/utils/linter/fixtures/js/valid-code.js +0 -15
- package/tests/utils/linter/fixtures/json/keyword-error.json +0 -1
- package/tests/utils/linter/fixtures/json/missing-semicolon.json +0 -1
- package/tests/utils/linter/fixtures/json/syntax-error.json +0 -1
- package/tests/utils/linter/fixtures/json/undeclare-variable.json +0 -1
- package/tests/utils/linter/fixtures/json/unused-variable.json +0 -1
- package/tests/utils/linter/fixtures/json/valid-code.json +0 -1
- package/tests/utils/linter/fixtures/jsx/keyword-error.jsx +0 -5
- package/tests/utils/linter/fixtures/jsx/missing-semicolon.jsx +0 -5
- package/tests/utils/linter/fixtures/jsx/syntax-error.jsx +0 -5
- package/tests/utils/linter/fixtures/jsx/undeclare-variable.jsx +0 -5
- package/tests/utils/linter/fixtures/jsx/unused-variable.jsx +0 -4
- package/tests/utils/linter/fixtures/jsx/valid-code.jsx +0 -5
- package/tests/utils/linter/fixtures/python/keyword-error.py +0 -3
- package/tests/utils/linter/fixtures/python/missing-semicolon.py +0 -2
- package/tests/utils/linter/fixtures/python/syntax-error.py +0 -3
- package/tests/utils/linter/fixtures/python/undeclare-variable.py +0 -3
- package/tests/utils/linter/fixtures/python/unused-variable.py +0 -6
- package/tests/utils/linter/fixtures/python/valid-code.py +0 -12
- package/tests/utils/linter/fixtures/ruby/keyword-error.rb +0 -2
- package/tests/utils/linter/fixtures/ruby/missing-semicolon.rb +0 -1
- package/tests/utils/linter/fixtures/ruby/syntax-error.rb +0 -2
- package/tests/utils/linter/fixtures/ruby/undeclare-variable.rb +0 -1
- package/tests/utils/linter/fixtures/ruby/unused-variable.rb +0 -2
- package/tests/utils/linter/fixtures/ruby/valid-code.rb +0 -1
- package/tests/utils/linter/fixtures/sass/keyword-error.sass +0 -2
- package/tests/utils/linter/fixtures/sass/missing-semicolon.sass +0 -3
- package/tests/utils/linter/fixtures/sass/syntax-error.sass +0 -3
- package/tests/utils/linter/fixtures/sass/undeclare-variable.sass +0 -2
- package/tests/utils/linter/fixtures/sass/unused-variable.sass +0 -4
- package/tests/utils/linter/fixtures/sass/valid-code.sass +0 -2
- package/tests/utils/linter/fixtures/scss/keyword-error.scss +0 -1
- package/tests/utils/linter/fixtures/scss/missing-semicolon.scss +0 -1
- package/tests/utils/linter/fixtures/scss/syntax-error.scss +0 -1
- package/tests/utils/linter/fixtures/scss/undeclare-variable.scss +0 -1
- package/tests/utils/linter/fixtures/scss/unused-variable.scss +0 -2
- package/tests/utils/linter/fixtures/scss/valid-code.scss +0 -1
- package/tests/utils/linter/fixtures/shell/keyword-error.sh +0 -5
- package/tests/utils/linter/fixtures/shell/missing-semicolon.sh +0 -3
- package/tests/utils/linter/fixtures/shell/syntax-error.sh +0 -4
- package/tests/utils/linter/fixtures/shell/undeclare-variable.sh +0 -3
- package/tests/utils/linter/fixtures/shell/unused-variable.sh +0 -4
- package/tests/utils/linter/fixtures/shell/valid-code.sh +0 -3
- package/tests/utils/linter/fixtures/ts/keyword-error.ts +0 -1
- package/tests/utils/linter/fixtures/ts/missing-semicolon.ts +0 -1
- package/tests/utils/linter/fixtures/ts/syntax-error.ts +0 -1
- package/tests/utils/linter/fixtures/ts/undeclare-variable.ts +0 -1
- package/tests/utils/linter/fixtures/ts/unused-variable.ts +0 -3
- package/tests/utils/linter/fixtures/ts/valid-code.ts +0 -3
- package/tests/utils/linter/fixtures/tsx/keyword-error.tsx +0 -5
- package/tests/utils/linter/fixtures/tsx/missing-semicolon.tsx +0 -5
- package/tests/utils/linter/fixtures/tsx/syntax-error.tsx +0 -5
- package/tests/utils/linter/fixtures/tsx/undeclare-variable.tsx +0 -6
- package/tests/utils/linter/fixtures/tsx/unused-variable.tsx +0 -6
- package/tests/utils/linter/fixtures/tsx/valid-code.tsx +0 -5
- package/tests/utils/linter/fixtures/vue/keyword-error.vue +0 -6
- package/tests/utils/linter/fixtures/vue/missing-semicolon.vue +0 -6
- package/tests/utils/linter/fixtures/vue/syntax-error.vue +0 -6
- package/tests/utils/linter/fixtures/vue/undeclare-variable.vue +0 -6
- package/tests/utils/linter/fixtures/vue/unused-variable.vue +0 -7
- package/tests/utils/linter/fixtures/vue/valid-code.vue +0 -6
- package/tests/utils/linter/fixtures/yaml/keyword-error.yml +0 -1
- package/tests/utils/linter/fixtures/yaml/missing-semicolon.yml +0 -2
- package/tests/utils/linter/fixtures/yaml/syntax-error.yml +0 -1
- package/tests/utils/linter/fixtures/yaml/undeclare-variable.yml +0 -1
- package/tests/utils/linter/fixtures/yaml/unused-variable.yml +0 -2
- package/tests/utils/linter/fixtures/yaml/valid-code.yml +0 -3
- package/tests/utils/linter/index.test.mjs +0 -440
- package/tests/utils/linter/scan-results.mjs +0 -42
- package/tests/utils/load-config.test.mjs +0 -141
- package/tests/utils/markdown/index.test.mjs +0 -478
- package/tests/utils/mermaid-validator.test.mjs +0 -541
- package/tests/utils/mock-chat-model.mjs +0 -12
- package/tests/utils/preferences-utils.test.mjs +0 -465
- package/tests/utils/save-value-to-config.test.mjs +0 -483
- package/tests/utils/utils.test.mjs +0 -941
|
@@ -1,582 +0,0 @@
|
|
|
1
|
-
import { afterEach, beforeEach, describe, expect, mock, spyOn, test } from "bun:test";
|
|
2
|
-
import * as markedModule from "marked";
|
|
3
|
-
import userReviewDocument from "../../../agents/update/user-review-document.mjs";
|
|
4
|
-
import * as preferencesUtils from "../../../utils/preferences-utils.mjs";
|
|
5
|
-
|
|
6
|
-
describe("user-review-document", () => {
|
|
7
|
-
let mockOptions;
|
|
8
|
-
let mockContent;
|
|
9
|
-
|
|
10
|
-
// Spies for internal utils
|
|
11
|
-
let getActiveRulesForScopeSpy;
|
|
12
|
-
let consoleSpy;
|
|
13
|
-
let consoleErrorSpy;
|
|
14
|
-
let consoleWarnSpy;
|
|
15
|
-
let markedLexerSpy;
|
|
16
|
-
let markedSpy;
|
|
17
|
-
|
|
18
|
-
beforeEach(() => {
|
|
19
|
-
// Reset all mocks
|
|
20
|
-
mock.restore();
|
|
21
|
-
|
|
22
|
-
mockContent =
|
|
23
|
-
"# Getting Started\n\n## Installation\n\nThis is a test document.\n\n### Prerequisites\n\nSome prerequisites here.";
|
|
24
|
-
|
|
25
|
-
mockOptions = {
|
|
26
|
-
prompts: {
|
|
27
|
-
select: mock(async () => "finish"),
|
|
28
|
-
input: mock(async () => ""),
|
|
29
|
-
},
|
|
30
|
-
context: {
|
|
31
|
-
agents: {
|
|
32
|
-
updateDocumentDetail: {},
|
|
33
|
-
checkFeedbackRefiner: {},
|
|
34
|
-
},
|
|
35
|
-
invoke: mock(async () => ({
|
|
36
|
-
updatedContent: "# Updated Content\n\nThis is updated content.",
|
|
37
|
-
operationSummary: "Document updated successfully",
|
|
38
|
-
})),
|
|
39
|
-
userContext: {
|
|
40
|
-
currentContent: "",
|
|
41
|
-
},
|
|
42
|
-
},
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
// Set up spies for internal utils
|
|
46
|
-
getActiveRulesForScopeSpy = spyOn(preferencesUtils, "getActiveRulesForScope").mockReturnValue(
|
|
47
|
-
[],
|
|
48
|
-
);
|
|
49
|
-
consoleSpy = spyOn(console, "log").mockImplementation(() => {});
|
|
50
|
-
consoleErrorSpy = spyOn(console, "error").mockImplementation(() => {});
|
|
51
|
-
consoleWarnSpy = spyOn(console, "warn").mockImplementation(() => {});
|
|
52
|
-
|
|
53
|
-
// Mock marked library
|
|
54
|
-
markedLexerSpy = spyOn(markedModule.marked, "lexer").mockImplementation(() => [
|
|
55
|
-
{ type: "heading", depth: 1, text: "Getting Started" },
|
|
56
|
-
{ type: "heading", depth: 2, text: "Installation" },
|
|
57
|
-
{ type: "heading", depth: 3, text: "Prerequisites" },
|
|
58
|
-
]);
|
|
59
|
-
markedSpy = spyOn(markedModule.marked, "setOptions").mockImplementation(() => {});
|
|
60
|
-
|
|
61
|
-
// Clear context mock call history
|
|
62
|
-
mockOptions.prompts.select.mockClear();
|
|
63
|
-
mockOptions.prompts.input.mockClear();
|
|
64
|
-
mockOptions.context.invoke.mockClear();
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
afterEach(() => {
|
|
68
|
-
// Restore all spies
|
|
69
|
-
getActiveRulesForScopeSpy?.mockRestore();
|
|
70
|
-
consoleSpy?.mockRestore();
|
|
71
|
-
consoleErrorSpy?.mockRestore();
|
|
72
|
-
consoleWarnSpy?.mockRestore();
|
|
73
|
-
markedLexerSpy?.mockRestore();
|
|
74
|
-
markedSpy?.mockRestore();
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
// CONTENT VALIDATION TESTS
|
|
78
|
-
test("should return original content when no content provided", async () => {
|
|
79
|
-
const result = await userReviewDocument({}, mockOptions);
|
|
80
|
-
|
|
81
|
-
expect(result).toBeDefined();
|
|
82
|
-
expect(result.content).toBeUndefined();
|
|
83
|
-
expect(mockOptions.prompts.select).not.toHaveBeenCalled();
|
|
84
|
-
expect(consoleSpy).toHaveBeenCalledWith("Please provide document content to review.");
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
test("should return original content when empty content provided", async () => {
|
|
88
|
-
const result = await userReviewDocument({ content: "" }, mockOptions);
|
|
89
|
-
|
|
90
|
-
expect(result).toBeDefined();
|
|
91
|
-
expect(result.content).toBe("");
|
|
92
|
-
expect(mockOptions.prompts.select).not.toHaveBeenCalled();
|
|
93
|
-
expect(consoleSpy).toHaveBeenCalledWith("Please provide document content to review.");
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
test("should return original content when only whitespace provided", async () => {
|
|
97
|
-
const result = await userReviewDocument({ content: " \n\t " }, mockOptions);
|
|
98
|
-
|
|
99
|
-
expect(result).toBeDefined();
|
|
100
|
-
expect(result.content).toBe(" \n\t ");
|
|
101
|
-
expect(mockOptions.prompts.select).not.toHaveBeenCalled();
|
|
102
|
-
expect(consoleSpy).toHaveBeenCalledWith("Please provide document content to review.");
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
// HEADING EXTRACTION TESTS
|
|
106
|
-
test("should extract markdown headings correctly", async () => {
|
|
107
|
-
mockOptions.prompts.select.mockImplementation(async () => "finish");
|
|
108
|
-
|
|
109
|
-
const result = await userReviewDocument(
|
|
110
|
-
{ content: mockContent, title: "Test Doc" },
|
|
111
|
-
mockOptions,
|
|
112
|
-
);
|
|
113
|
-
|
|
114
|
-
expect(result).toBeDefined();
|
|
115
|
-
expect(result.content).toBe(mockContent);
|
|
116
|
-
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Current Document: Test Doc"));
|
|
117
|
-
expect(markedLexerSpy).toHaveBeenCalledWith(mockContent);
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
test("should handle markdown parsing errors with fallback", async () => {
|
|
121
|
-
markedLexerSpy.mockImplementation(() => {
|
|
122
|
-
throw new Error("Parsing error");
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
mockOptions.prompts.select.mockImplementation(async () => "finish");
|
|
126
|
-
|
|
127
|
-
const result = await userReviewDocument({ content: mockContent }, mockOptions);
|
|
128
|
-
|
|
129
|
-
expect(result).toBeDefined();
|
|
130
|
-
expect(result.content).toBe(mockContent);
|
|
131
|
-
expect(consoleWarnSpy).toHaveBeenCalledWith(
|
|
132
|
-
"Failed to parse markdown with marked library, falling back to regex:",
|
|
133
|
-
"Parsing error",
|
|
134
|
-
);
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
test("should handle empty content in heading extraction", async () => {
|
|
138
|
-
const emptyContent = "";
|
|
139
|
-
mockOptions.prompts.select.mockImplementation(async () => "finish");
|
|
140
|
-
|
|
141
|
-
markedLexerSpy.mockReturnValue([]);
|
|
142
|
-
|
|
143
|
-
const result = await userReviewDocument({ content: emptyContent }, mockOptions);
|
|
144
|
-
|
|
145
|
-
expect(result.content).toBe(emptyContent);
|
|
146
|
-
expect(consoleSpy).toHaveBeenCalledWith("Please provide document content to review.");
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
// USER INTERACTION TESTS
|
|
150
|
-
test("should finish immediately when user selects finish", async () => {
|
|
151
|
-
mockOptions.prompts.select.mockImplementation(async () => "finish");
|
|
152
|
-
|
|
153
|
-
const result = await userReviewDocument({ content: mockContent }, mockOptions);
|
|
154
|
-
|
|
155
|
-
expect(result.content).toBe(mockContent);
|
|
156
|
-
expect(mockOptions.prompts.select).toHaveBeenCalledTimes(1);
|
|
157
|
-
expect(mockOptions.prompts.input).not.toHaveBeenCalled();
|
|
158
|
-
expect(mockOptions.context.invoke).not.toHaveBeenCalled();
|
|
159
|
-
});
|
|
160
|
-
|
|
161
|
-
test("should show document details when user selects view", async () => {
|
|
162
|
-
mockOptions.prompts.select.mockImplementation(async () => "view");
|
|
163
|
-
mockOptions.prompts.input.mockImplementation(async () => ""); // Empty feedback after view
|
|
164
|
-
|
|
165
|
-
// Mock the marked function directly
|
|
166
|
-
const markedFunctionSpy = spyOn(markedModule, "marked").mockReturnValue(
|
|
167
|
-
"Rendered markdown content",
|
|
168
|
-
);
|
|
169
|
-
|
|
170
|
-
const result = await userReviewDocument(
|
|
171
|
-
{ content: mockContent, title: "Test Doc" },
|
|
172
|
-
mockOptions,
|
|
173
|
-
);
|
|
174
|
-
|
|
175
|
-
expect(result.content).toBe(mockContent);
|
|
176
|
-
expect(mockOptions.prompts.select).toHaveBeenCalledTimes(1);
|
|
177
|
-
expect(mockOptions.prompts.input).toHaveBeenCalledTimes(1);
|
|
178
|
-
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Document: Test Doc"));
|
|
179
|
-
|
|
180
|
-
markedFunctionSpy?.mockRestore();
|
|
181
|
-
});
|
|
182
|
-
|
|
183
|
-
test("should handle marked-terminal rendering errors gracefully", async () => {
|
|
184
|
-
mockOptions.prompts.select.mockImplementation(async () => "view");
|
|
185
|
-
mockOptions.prompts.input.mockImplementation(async () => ""); // Empty feedback after view
|
|
186
|
-
|
|
187
|
-
// Mock the marked function to throw error
|
|
188
|
-
const markedFunctionSpy = spyOn(markedModule, "marked").mockImplementation(() => {
|
|
189
|
-
throw new Error("Rendering error");
|
|
190
|
-
});
|
|
191
|
-
|
|
192
|
-
const result = await userReviewDocument(
|
|
193
|
-
{ content: mockContent, title: "Test Doc" },
|
|
194
|
-
mockOptions,
|
|
195
|
-
);
|
|
196
|
-
|
|
197
|
-
expect(result.content).toBe(mockContent);
|
|
198
|
-
expect(consoleSpy).toHaveBeenCalledWith(
|
|
199
|
-
expect.stringContaining("Falling back to plain text display"),
|
|
200
|
-
);
|
|
201
|
-
|
|
202
|
-
markedFunctionSpy?.mockRestore();
|
|
203
|
-
});
|
|
204
|
-
|
|
205
|
-
// FEEDBACK PROCESSING TESTS
|
|
206
|
-
test("should process user feedback and update content", async () => {
|
|
207
|
-
const feedback = "Please add more examples";
|
|
208
|
-
const updatedContent = "# Updated Content\n\nThis has more examples.";
|
|
209
|
-
|
|
210
|
-
mockOptions.prompts.select.mockImplementation(async () => "feedback");
|
|
211
|
-
mockOptions.prompts.input
|
|
212
|
-
.mockImplementationOnce(async () => feedback)
|
|
213
|
-
.mockImplementationOnce(async () => ""); // Exit loop
|
|
214
|
-
|
|
215
|
-
mockOptions.context.invoke.mockImplementation(async () => {
|
|
216
|
-
// Simulate the agent updating the shared context
|
|
217
|
-
mockOptions.context.userContext.currentContent = updatedContent;
|
|
218
|
-
return {
|
|
219
|
-
updatedContent,
|
|
220
|
-
operationSummary: "Added examples successfully",
|
|
221
|
-
};
|
|
222
|
-
});
|
|
223
|
-
|
|
224
|
-
const result = await userReviewDocument({ content: mockContent }, mockOptions);
|
|
225
|
-
|
|
226
|
-
expect(mockOptions.context.invoke).toHaveBeenCalledWith(
|
|
227
|
-
mockOptions.context.agents.updateDocumentDetail,
|
|
228
|
-
expect.objectContaining({
|
|
229
|
-
originalContent: mockContent,
|
|
230
|
-
feedback: feedback,
|
|
231
|
-
userPreferences: "",
|
|
232
|
-
}),
|
|
233
|
-
);
|
|
234
|
-
expect(result.content).toBe(updatedContent);
|
|
235
|
-
});
|
|
236
|
-
|
|
237
|
-
test("should handle empty feedback by exiting loop", async () => {
|
|
238
|
-
mockOptions.prompts.select.mockImplementation(async () => "feedback");
|
|
239
|
-
mockOptions.prompts.input.mockImplementation(async () => "");
|
|
240
|
-
|
|
241
|
-
const result = await userReviewDocument({ content: mockContent }, mockOptions);
|
|
242
|
-
|
|
243
|
-
expect(result.content).toBe(mockContent);
|
|
244
|
-
expect(mockOptions.context.invoke).not.toHaveBeenCalled();
|
|
245
|
-
});
|
|
246
|
-
|
|
247
|
-
test("should handle whitespace-only feedback by exiting loop", async () => {
|
|
248
|
-
mockOptions.prompts.select.mockImplementation(async () => "feedback");
|
|
249
|
-
mockOptions.prompts.input.mockImplementation(async () => " \n\t ");
|
|
250
|
-
|
|
251
|
-
const result = await userReviewDocument({ content: mockContent }, mockOptions);
|
|
252
|
-
|
|
253
|
-
expect(result.content).toBe(mockContent);
|
|
254
|
-
expect(mockOptions.context.invoke).not.toHaveBeenCalled();
|
|
255
|
-
});
|
|
256
|
-
|
|
257
|
-
// USER PREFERENCES TESTS
|
|
258
|
-
test("should include user preferences in update call", async () => {
|
|
259
|
-
const feedback = "Improve clarity";
|
|
260
|
-
const mockRules = [{ rule: "Keep sections concise" }, { rule: "Use clear headings" }];
|
|
261
|
-
const expectedPreferences = "Keep sections concise\n\nUse clear headings";
|
|
262
|
-
|
|
263
|
-
getActiveRulesForScopeSpy
|
|
264
|
-
.mockImplementationOnce(() => mockRules) // document rules
|
|
265
|
-
.mockImplementationOnce(() => []); // global rules
|
|
266
|
-
|
|
267
|
-
mockOptions.prompts.select.mockImplementation(async () => "feedback");
|
|
268
|
-
mockOptions.prompts.input
|
|
269
|
-
.mockImplementationOnce(async () => feedback)
|
|
270
|
-
.mockImplementationOnce(async () => "");
|
|
271
|
-
|
|
272
|
-
await userReviewDocument({ content: mockContent, path: "/test-doc" }, mockOptions);
|
|
273
|
-
|
|
274
|
-
expect(getActiveRulesForScopeSpy).toHaveBeenCalledWith("document", ["/test-doc"]);
|
|
275
|
-
expect(getActiveRulesForScopeSpy).toHaveBeenCalledWith("global");
|
|
276
|
-
expect(mockOptions.context.invoke).toHaveBeenCalledWith(
|
|
277
|
-
mockOptions.context.agents.updateDocumentDetail,
|
|
278
|
-
expect.objectContaining({
|
|
279
|
-
userPreferences: expectedPreferences,
|
|
280
|
-
}),
|
|
281
|
-
);
|
|
282
|
-
});
|
|
283
|
-
|
|
284
|
-
test("should combine document and global rules correctly", async () => {
|
|
285
|
-
const feedback = "Add examples";
|
|
286
|
-
const documentRules = [{ rule: "Document rule 1" }];
|
|
287
|
-
const globalRules = [{ rule: "Global rule 1" }, { rule: "Global rule 2" }];
|
|
288
|
-
const expectedPreferences = "Document rule 1\n\nGlobal rule 1\n\nGlobal rule 2";
|
|
289
|
-
|
|
290
|
-
getActiveRulesForScopeSpy
|
|
291
|
-
.mockImplementationOnce(() => documentRules)
|
|
292
|
-
.mockImplementationOnce(() => globalRules);
|
|
293
|
-
|
|
294
|
-
mockOptions.prompts.select.mockImplementation(async () => "feedback");
|
|
295
|
-
mockOptions.prompts.input
|
|
296
|
-
.mockImplementationOnce(async () => feedback)
|
|
297
|
-
.mockImplementationOnce(async () => "");
|
|
298
|
-
|
|
299
|
-
await userReviewDocument({ content: mockContent, path: "/test-doc" }, mockOptions);
|
|
300
|
-
|
|
301
|
-
expect(mockOptions.context.invoke).toHaveBeenCalledWith(
|
|
302
|
-
mockOptions.context.agents.updateDocumentDetail,
|
|
303
|
-
expect.objectContaining({
|
|
304
|
-
userPreferences: expectedPreferences,
|
|
305
|
-
}),
|
|
306
|
-
);
|
|
307
|
-
});
|
|
308
|
-
|
|
309
|
-
// AGENT ERROR HANDLING TESTS
|
|
310
|
-
test("should handle missing updateDocumentDetail agent", async () => {
|
|
311
|
-
const feedback = "Some feedback";
|
|
312
|
-
mockOptions.context.agents = {}; // No updateDocumentDetail agent
|
|
313
|
-
|
|
314
|
-
mockOptions.prompts.select.mockImplementation(async () => "feedback");
|
|
315
|
-
mockOptions.prompts.input.mockImplementation(async () => feedback);
|
|
316
|
-
|
|
317
|
-
const result = await userReviewDocument({ content: mockContent }, mockOptions);
|
|
318
|
-
|
|
319
|
-
expect(result.content).toBe(mockContent);
|
|
320
|
-
expect(consoleSpy).toHaveBeenCalledWith(
|
|
321
|
-
"We can't process your feedback right now. The document update feature is temporarily unavailable.",
|
|
322
|
-
);
|
|
323
|
-
expect(consoleSpy).toHaveBeenCalledWith(
|
|
324
|
-
"Please try again later or contact support if this continues.",
|
|
325
|
-
);
|
|
326
|
-
});
|
|
327
|
-
|
|
328
|
-
test("should handle updateDocumentDetail agent errors", async () => {
|
|
329
|
-
const feedback = "Some feedback";
|
|
330
|
-
mockOptions.prompts.select.mockImplementation(async () => "feedback");
|
|
331
|
-
mockOptions.prompts.input
|
|
332
|
-
.mockImplementationOnce(async () => feedback)
|
|
333
|
-
.mockImplementationOnce(async () => "");
|
|
334
|
-
|
|
335
|
-
mockOptions.context.invoke.mockImplementation(async () => {
|
|
336
|
-
const error = new Error("Agent failed");
|
|
337
|
-
error.name = "AgentError";
|
|
338
|
-
error.stack = "Stack trace here";
|
|
339
|
-
throw error;
|
|
340
|
-
});
|
|
341
|
-
|
|
342
|
-
const result = await userReviewDocument({ content: mockContent }, mockOptions);
|
|
343
|
-
|
|
344
|
-
expect(result.content).toBe(mockContent);
|
|
345
|
-
expect(consoleErrorSpy).toHaveBeenCalledWith("Error processing your feedback:");
|
|
346
|
-
expect(consoleErrorSpy).toHaveBeenCalledWith("Type: AgentError");
|
|
347
|
-
expect(consoleErrorSpy).toHaveBeenCalledWith("Message: Agent failed");
|
|
348
|
-
expect(consoleErrorSpy).toHaveBeenCalledWith("Stack: Stack trace here");
|
|
349
|
-
});
|
|
350
|
-
|
|
351
|
-
test("should handle updateDocumentDetail agent returning no content", async () => {
|
|
352
|
-
const feedback = "Some feedback";
|
|
353
|
-
mockOptions.prompts.select.mockImplementation(async () => "feedback");
|
|
354
|
-
mockOptions.prompts.input
|
|
355
|
-
.mockImplementationOnce(async () => feedback)
|
|
356
|
-
.mockImplementationOnce(async () => "");
|
|
357
|
-
|
|
358
|
-
// Agent doesn't update the shared context (simulating failure)
|
|
359
|
-
mockOptions.context.invoke.mockImplementation(async () => ({})); // No updatedContent
|
|
360
|
-
|
|
361
|
-
const result = await userReviewDocument({ content: mockContent }, mockOptions);
|
|
362
|
-
|
|
363
|
-
// Content should remain unchanged since agent didn't update it
|
|
364
|
-
expect(result.content).toBe(mockContent);
|
|
365
|
-
});
|
|
366
|
-
|
|
367
|
-
// FEEDBACK REFINER TESTS
|
|
368
|
-
test("should call checkFeedbackRefiner agent when available", async () => {
|
|
369
|
-
const feedback = "Improve examples";
|
|
370
|
-
mockOptions.prompts.select.mockImplementation(async () => "feedback");
|
|
371
|
-
mockOptions.prompts.input
|
|
372
|
-
.mockImplementationOnce(async () => feedback)
|
|
373
|
-
.mockImplementationOnce(async () => "");
|
|
374
|
-
|
|
375
|
-
mockOptions.context.invoke
|
|
376
|
-
.mockImplementationOnce(async () => ({
|
|
377
|
-
updatedContent: "Updated content",
|
|
378
|
-
operationSummary: "Updated successfully",
|
|
379
|
-
})) // updateDocumentDetail
|
|
380
|
-
.mockImplementationOnce(async () => ({})); // checkFeedbackRefiner
|
|
381
|
-
|
|
382
|
-
await userReviewDocument({ content: mockContent }, mockOptions);
|
|
383
|
-
|
|
384
|
-
expect(mockOptions.context.invoke).toHaveBeenCalledWith(
|
|
385
|
-
mockOptions.context.agents.checkFeedbackRefiner,
|
|
386
|
-
expect.objectContaining({
|
|
387
|
-
documentContentFeedback: feedback,
|
|
388
|
-
stage: "document_refine",
|
|
389
|
-
}),
|
|
390
|
-
);
|
|
391
|
-
});
|
|
392
|
-
|
|
393
|
-
test("should handle missing checkFeedbackRefiner agent gracefully", async () => {
|
|
394
|
-
const feedback = "Some feedback";
|
|
395
|
-
const updatedContent = "# Updated Content\n\nThis is updated content.";
|
|
396
|
-
mockOptions.context.agents = { updateDocumentDetail: {} }; // No checkFeedbackRefiner
|
|
397
|
-
|
|
398
|
-
mockOptions.prompts.select.mockImplementation(async () => "feedback");
|
|
399
|
-
mockOptions.prompts.input
|
|
400
|
-
.mockImplementationOnce(async () => feedback)
|
|
401
|
-
.mockImplementationOnce(async () => "");
|
|
402
|
-
|
|
403
|
-
mockOptions.context.invoke.mockImplementation(async () => {
|
|
404
|
-
mockOptions.context.userContext.currentContent = updatedContent;
|
|
405
|
-
return { updatedContent, operationSummary: "Updated" };
|
|
406
|
-
});
|
|
407
|
-
|
|
408
|
-
const result = await userReviewDocument({ content: mockContent }, mockOptions);
|
|
409
|
-
|
|
410
|
-
expect(mockOptions.context.invoke).toHaveBeenCalledTimes(1); // Only updateDocumentDetail called
|
|
411
|
-
expect(result.content).toBe(updatedContent);
|
|
412
|
-
});
|
|
413
|
-
|
|
414
|
-
test("should handle checkFeedbackRefiner errors gracefully", async () => {
|
|
415
|
-
const feedback = "Some feedback";
|
|
416
|
-
const updatedContent = "Updated content";
|
|
417
|
-
mockOptions.prompts.select.mockImplementation(async () => "feedback");
|
|
418
|
-
mockOptions.prompts.input
|
|
419
|
-
.mockImplementationOnce(async () => feedback)
|
|
420
|
-
.mockImplementationOnce(async () => "");
|
|
421
|
-
|
|
422
|
-
mockOptions.context.invoke
|
|
423
|
-
.mockImplementationOnce(async () => {
|
|
424
|
-
mockOptions.context.userContext.currentContent = updatedContent;
|
|
425
|
-
return {
|
|
426
|
-
updatedContent,
|
|
427
|
-
operationSummary: "Updated successfully",
|
|
428
|
-
};
|
|
429
|
-
}) // updateDocumentDetail
|
|
430
|
-
.mockImplementationOnce(async () => {
|
|
431
|
-
throw new Error("Refiner failed");
|
|
432
|
-
}); // checkFeedbackRefiner
|
|
433
|
-
|
|
434
|
-
const result = await userReviewDocument({ content: mockContent }, mockOptions);
|
|
435
|
-
|
|
436
|
-
expect(result.content).toBe(updatedContent);
|
|
437
|
-
expect(consoleWarnSpy).toHaveBeenCalledWith(
|
|
438
|
-
"We couldn't save your feedback as a preference:",
|
|
439
|
-
"Refiner failed",
|
|
440
|
-
);
|
|
441
|
-
expect(consoleWarnSpy).toHaveBeenCalledWith(
|
|
442
|
-
"Your feedback was applied, but we couldn't save it as a preference.",
|
|
443
|
-
);
|
|
444
|
-
});
|
|
445
|
-
|
|
446
|
-
// MULTIPLE ROUNDS TESTS
|
|
447
|
-
test("should handle multiple feedback rounds", async () => {
|
|
448
|
-
const firstFeedback = "Add more examples";
|
|
449
|
-
const secondFeedback = "Improve clarity";
|
|
450
|
-
const firstUpdate = "# Content with examples";
|
|
451
|
-
const secondUpdate = "# Clear content with examples";
|
|
452
|
-
|
|
453
|
-
mockOptions.prompts.select.mockImplementation(async () => "feedback");
|
|
454
|
-
mockOptions.prompts.input
|
|
455
|
-
.mockImplementationOnce(async () => firstFeedback)
|
|
456
|
-
.mockImplementationOnce(async () => secondFeedback)
|
|
457
|
-
.mockImplementationOnce(async () => ""); // Exit loop
|
|
458
|
-
|
|
459
|
-
let invokeCount = 0;
|
|
460
|
-
mockOptions.context.invoke.mockImplementation(async () => {
|
|
461
|
-
invokeCount++;
|
|
462
|
-
if (invokeCount === 1) {
|
|
463
|
-
// First update
|
|
464
|
-
mockOptions.context.userContext.currentContent = firstUpdate;
|
|
465
|
-
return { updatedContent: firstUpdate, operationSummary: "Added examples" };
|
|
466
|
-
} else if (invokeCount === 2) {
|
|
467
|
-
// First refiner
|
|
468
|
-
return {};
|
|
469
|
-
} else if (invokeCount === 3) {
|
|
470
|
-
// Second update
|
|
471
|
-
mockOptions.context.userContext.currentContent = secondUpdate;
|
|
472
|
-
return { updatedContent: secondUpdate, operationSummary: "Improved clarity" };
|
|
473
|
-
} else {
|
|
474
|
-
// Second refiner
|
|
475
|
-
return {};
|
|
476
|
-
}
|
|
477
|
-
});
|
|
478
|
-
|
|
479
|
-
const result = await userReviewDocument({ content: mockContent }, mockOptions);
|
|
480
|
-
|
|
481
|
-
expect(mockOptions.context.invoke).toHaveBeenCalledTimes(4);
|
|
482
|
-
expect(result.content).toBe(secondUpdate);
|
|
483
|
-
});
|
|
484
|
-
|
|
485
|
-
test("should stop at maximum iterations to prevent infinite loops", async () => {
|
|
486
|
-
mockOptions.prompts.select.mockImplementation(async () => "feedback");
|
|
487
|
-
mockOptions.prompts.input.mockImplementation(async () => "Keep giving feedback");
|
|
488
|
-
|
|
489
|
-
// Mock a long running process
|
|
490
|
-
let callCount = 0;
|
|
491
|
-
mockOptions.context.invoke.mockImplementation(async () => {
|
|
492
|
-
callCount++;
|
|
493
|
-
return {
|
|
494
|
-
updatedContent: `Updated content ${callCount}`,
|
|
495
|
-
operationSummary: `Update ${callCount}`,
|
|
496
|
-
};
|
|
497
|
-
});
|
|
498
|
-
|
|
499
|
-
const result = await userReviewDocument({ content: mockContent }, mockOptions);
|
|
500
|
-
|
|
501
|
-
// Should have stopped due to MAX_ITERATIONS (100)
|
|
502
|
-
expect(mockOptions.prompts.input).toHaveBeenCalledTimes(100);
|
|
503
|
-
expect(result.content).toBeDefined();
|
|
504
|
-
});
|
|
505
|
-
|
|
506
|
-
// EDGE CASES
|
|
507
|
-
test("should handle document with no title", async () => {
|
|
508
|
-
mockOptions.prompts.select.mockImplementation(async () => "finish");
|
|
509
|
-
|
|
510
|
-
const result = await userReviewDocument({ content: mockContent }, mockOptions);
|
|
511
|
-
|
|
512
|
-
expect(result.content).toBe(mockContent);
|
|
513
|
-
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Untitled Document"));
|
|
514
|
-
});
|
|
515
|
-
|
|
516
|
-
test("should handle nested tokens in marked parsing", async () => {
|
|
517
|
-
const tokensWithNested = [
|
|
518
|
-
{
|
|
519
|
-
type: "heading",
|
|
520
|
-
depth: 1,
|
|
521
|
-
text: "Main Heading",
|
|
522
|
-
},
|
|
523
|
-
{
|
|
524
|
-
type: "list",
|
|
525
|
-
items: [],
|
|
526
|
-
tokens: [
|
|
527
|
-
{
|
|
528
|
-
type: "heading",
|
|
529
|
-
depth: 2,
|
|
530
|
-
text: "Nested Heading",
|
|
531
|
-
},
|
|
532
|
-
],
|
|
533
|
-
},
|
|
534
|
-
];
|
|
535
|
-
|
|
536
|
-
markedLexerSpy.mockReturnValue(tokensWithNested);
|
|
537
|
-
mockOptions.prompts.select.mockImplementation(async () => "finish");
|
|
538
|
-
|
|
539
|
-
const result = await userReviewDocument({ content: mockContent }, mockOptions);
|
|
540
|
-
|
|
541
|
-
expect(result.content).toBe(mockContent);
|
|
542
|
-
// Should process both the main heading and nested heading
|
|
543
|
-
expect(markedLexerSpy).toHaveBeenCalledWith(mockContent);
|
|
544
|
-
});
|
|
545
|
-
|
|
546
|
-
test("should handle non-string content gracefully", async () => {
|
|
547
|
-
const result = await userReviewDocument({ content: null }, mockOptions);
|
|
548
|
-
|
|
549
|
-
expect(result.content).toBeNull();
|
|
550
|
-
expect(consoleSpy).toHaveBeenCalledWith("Please provide document content to review.");
|
|
551
|
-
});
|
|
552
|
-
|
|
553
|
-
// FALLBACK HEADING EXTRACTION TESTS
|
|
554
|
-
test("should use fallback regex extraction when marked fails", async () => {
|
|
555
|
-
const contentWithHeadings = "# Title\n## Section\n### Subsection\nContent here.";
|
|
556
|
-
markedLexerSpy.mockImplementation(() => {
|
|
557
|
-
throw new Error("Marked failed");
|
|
558
|
-
});
|
|
559
|
-
|
|
560
|
-
mockOptions.prompts.select.mockImplementation(async () => "finish");
|
|
561
|
-
|
|
562
|
-
const result = await userReviewDocument({ content: contentWithHeadings }, mockOptions);
|
|
563
|
-
|
|
564
|
-
expect(result.content).toBe(contentWithHeadings);
|
|
565
|
-
expect(consoleWarnSpy).toHaveBeenCalledWith(
|
|
566
|
-
"Failed to parse markdown with marked library, falling back to regex:",
|
|
567
|
-
"Marked failed",
|
|
568
|
-
);
|
|
569
|
-
});
|
|
570
|
-
|
|
571
|
-
test("should handle content with no headings", async () => {
|
|
572
|
-
const contentNoHeadings = "Just some plain text content without any headings.";
|
|
573
|
-
markedLexerSpy.mockReturnValue([]);
|
|
574
|
-
|
|
575
|
-
mockOptions.prompts.select.mockImplementation(async () => "finish");
|
|
576
|
-
|
|
577
|
-
const result = await userReviewDocument({ content: contentNoHeadings }, mockOptions);
|
|
578
|
-
|
|
579
|
-
expect(result.content).toBe(contentNoHeadings);
|
|
580
|
-
expect(consoleSpy).toHaveBeenCalledWith(" This document has no headings.");
|
|
581
|
-
});
|
|
582
|
-
});
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import { describe, expect, test } from "bun:test";
|
|
2
|
-
import actionSuccess from "../../../agents/utils/action-success.mjs";
|
|
3
|
-
|
|
4
|
-
describe("action-success", () => {
|
|
5
|
-
test("should return success message with action name", async () => {
|
|
6
|
-
const result = await actionSuccess({ action: "✅ Document generation successfully" });
|
|
7
|
-
|
|
8
|
-
expect(result).toBeDefined();
|
|
9
|
-
expect(result).toHaveProperty("message");
|
|
10
|
-
expect(result.message).toBe("✅ Document generation successfully");
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
test("should handle different action names", async () => {
|
|
14
|
-
const actions = [
|
|
15
|
-
"Configuration setup",
|
|
16
|
-
"File processing",
|
|
17
|
-
"Translation generation",
|
|
18
|
-
"Markdown validation",
|
|
19
|
-
];
|
|
20
|
-
|
|
21
|
-
for (const action of actions) {
|
|
22
|
-
const result = await actionSuccess({ action });
|
|
23
|
-
|
|
24
|
-
expect(result).toBeDefined();
|
|
25
|
-
expect(result.message).toBe(`${action}`);
|
|
26
|
-
}
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
test("should handle empty action name", async () => {
|
|
30
|
-
const result = await actionSuccess({ action: "" });
|
|
31
|
-
|
|
32
|
-
expect(result).toBeDefined();
|
|
33
|
-
expect(result.message).toBe("");
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
test("should handle undefined action", async () => {
|
|
37
|
-
const result = await actionSuccess({ action: undefined });
|
|
38
|
-
|
|
39
|
-
expect(result).toBeDefined();
|
|
40
|
-
expect(result.message).toBe("undefined");
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
test("should have task_render_mode property", () => {
|
|
44
|
-
expect(actionSuccess.task_render_mode).toBe("hide");
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
test("should handle mermaid worker pool shutdown gracefully", async () => {
|
|
48
|
-
// This test ensures the function doesn't throw even if worker pool fails
|
|
49
|
-
const result = await actionSuccess({ action: "Test action" });
|
|
50
|
-
|
|
51
|
-
expect(result).toBeDefined();
|
|
52
|
-
expect(result.message).toBe("Test action");
|
|
53
|
-
});
|
|
54
|
-
});
|