@ollie-shop/cli 0.1.3 → 0.3.0
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/.turbo/turbo-build.log +2 -11
- package/CHANGELOG.md +17 -5
- package/CLAUDE_CLI.md +265 -0
- package/README.md +704 -8
- package/__tests__/mocks/console.ts +22 -0
- package/__tests__/mocks/core.ts +137 -0
- package/__tests__/mocks/index.ts +4 -0
- package/__tests__/mocks/inquirer.ts +16 -0
- package/__tests__/mocks/progress.ts +19 -0
- package/dist/__tests__/helpers/cli-test-helper.d.ts +89 -0
- package/dist/__tests__/helpers/cli-test-helper.d.ts.map +1 -0
- package/dist/__tests__/helpers/cli-test-helper.js +220 -0
- package/dist/__tests__/mocks/index.d.ts +69 -0
- package/dist/__tests__/mocks/index.d.ts.map +1 -0
- package/dist/__tests__/mocks/index.js +77 -0
- package/dist/actions/component.actions.d.ts +14 -0
- package/dist/actions/component.actions.d.ts.map +1 -0
- package/dist/actions/component.actions.js +273 -0
- package/dist/actions/function.actions.d.ts +15 -0
- package/dist/actions/function.actions.d.ts.map +1 -0
- package/dist/actions/function.actions.js +254 -0
- package/dist/actions/project.actions.d.ts +17 -0
- package/dist/actions/project.actions.d.ts.map +1 -0
- package/dist/actions/project.actions.js +97 -0
- package/dist/actions/version.actions.d.ts +19 -0
- package/dist/actions/version.actions.d.ts.map +1 -0
- package/dist/actions/version.actions.js +216 -0
- package/dist/commands/component.d.ts +3 -0
- package/dist/commands/component.d.ts.map +1 -0
- package/dist/commands/component.js +192 -0
- package/dist/commands/docs.d.ts +3 -0
- package/dist/commands/docs.d.ts.map +1 -0
- package/dist/commands/docs.js +16 -0
- package/dist/commands/function.d.ts +3 -0
- package/dist/commands/function.d.ts.map +1 -0
- package/dist/commands/function.js +243 -0
- package/dist/commands/help.d.ts +3 -0
- package/dist/commands/help.d.ts.map +1 -0
- package/dist/commands/help.js +20 -0
- package/dist/commands/index.d.ts +3 -0
- package/dist/commands/index.d.ts.map +1 -0
- package/dist/commands/index.js +26 -0
- package/dist/commands/login.d.ts +3 -0
- package/dist/commands/login.d.ts.map +1 -0
- package/dist/commands/login.js +175 -0
- package/dist/commands/project.d.ts +3 -0
- package/dist/commands/project.d.ts.map +1 -0
- package/dist/commands/project.js +78 -0
- package/dist/commands/store-version.d.ts +3 -0
- package/dist/commands/store-version.d.ts.map +1 -0
- package/dist/commands/store-version.js +241 -0
- package/dist/commands/version.d.ts +3 -0
- package/dist/commands/version.d.ts.map +1 -0
- package/dist/commands/version.js +46 -0
- package/dist/commands/whoami.d.ts +3 -0
- package/dist/commands/whoami.d.ts.map +1 -0
- package/dist/commands/whoami.js +41 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +93 -226
- package/dist/prompts/component.prompts.d.ts +14 -0
- package/dist/prompts/component.prompts.d.ts.map +1 -0
- package/dist/prompts/component.prompts.js +75 -0
- package/dist/prompts/function.prompts.d.ts +21 -0
- package/dist/prompts/function.prompts.d.ts.map +1 -0
- package/dist/prompts/function.prompts.js +127 -0
- package/dist/schemas/command.schema.d.ts +516 -0
- package/dist/schemas/command.schema.d.ts.map +1 -0
- package/dist/schemas/command.schema.js +267 -0
- package/dist/types/index.d.ts +147 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +18 -0
- package/dist/utils/auth.d.ts +4 -0
- package/dist/utils/auth.d.ts.map +1 -0
- package/dist/utils/auth.js +26 -0
- package/dist/utils/cli-progress-reporter.d.ts +12 -0
- package/dist/utils/cli-progress-reporter.d.ts.map +1 -0
- package/dist/utils/cli-progress-reporter.js +77 -0
- package/dist/utils/command-builder.d.ts +22 -0
- package/dist/utils/command-builder.d.ts.map +1 -0
- package/dist/utils/command-builder.js +268 -0
- package/dist/utils/command-helpers.d.ts +19 -0
- package/dist/utils/command-helpers.d.ts.map +1 -0
- package/dist/utils/command-helpers.js +79 -0
- package/dist/utils/command-parser.d.ts +146 -0
- package/dist/utils/command-parser.d.ts.map +1 -0
- package/dist/utils/command-parser.js +179 -0
- package/dist/utils/command-suggestions.d.ts +35 -0
- package/dist/utils/command-suggestions.d.ts.map +1 -0
- package/dist/utils/command-suggestions.js +152 -0
- package/dist/utils/console.d.ts +44 -0
- package/dist/utils/console.d.ts.map +1 -0
- package/dist/utils/console.js +233 -0
- package/dist/utils/constants.d.ts +8 -0
- package/dist/utils/constants.d.ts.map +1 -0
- package/dist/utils/constants.js +10 -0
- package/dist/utils/context-detector.d.ts +12 -0
- package/dist/utils/context-detector.d.ts.map +1 -0
- package/dist/utils/context-detector.js +155 -0
- package/dist/utils/enhanced-error-handler.d.ts +47 -0
- package/dist/utils/enhanced-error-handler.d.ts.map +1 -0
- package/dist/utils/enhanced-error-handler.js +221 -0
- package/dist/utils/error-handler.d.ts +3 -0
- package/dist/utils/error-handler.d.ts.map +1 -0
- package/dist/utils/error-handler.js +55 -0
- package/dist/utils/errors.d.ts +44 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +76 -0
- package/dist/utils/interactive-builder.d.ts +22 -0
- package/dist/utils/interactive-builder.d.ts.map +1 -0
- package/dist/utils/interactive-builder.js +246 -0
- package/dist/utils/rich-progress.d.ts +59 -0
- package/dist/utils/rich-progress.d.ts.map +1 -0
- package/dist/utils/rich-progress.js +234 -0
- package/dist/utils/store.d.ts +11 -0
- package/dist/utils/store.d.ts.map +1 -0
- package/dist/utils/store.js +19 -0
- package/dist/utils/validation-error-formatter.d.ts +25 -0
- package/dist/utils/validation-error-formatter.d.ts.map +1 -0
- package/dist/utils/validation-error-formatter.js +258 -0
- package/dist/utils/validation-helpers.d.ts +60 -0
- package/dist/utils/validation-helpers.d.ts.map +1 -0
- package/dist/utils/validation-helpers.js +152 -0
- package/package.json +44 -9
- package/src/__tests__/helpers/cli-test-helper.ts +281 -0
- package/src/__tests__/mocks/index.ts +142 -0
- package/src/actions/component.actions.ts +334 -0
- package/src/actions/function.actions.ts +313 -0
- package/src/actions/project.actions.ts +126 -0
- package/src/actions/version.actions.ts +233 -0
- package/src/commands/__tests__/component-validation.test.ts +250 -0
- package/src/commands/__tests__/component.test.ts +321 -0
- package/src/commands/__tests__/function-validation.test.ts +220 -0
- package/src/commands/__tests__/function.test.ts +286 -0
- package/src/commands/__tests__/store-version-validation.test.ts +414 -0
- package/src/commands/__tests__/store-version.test.ts +405 -0
- package/src/commands/__tests__/version.test.ts +71 -0
- package/src/commands/component.ts +188 -0
- package/src/commands/docs.ts +24 -0
- package/src/commands/function.ts +252 -0
- package/src/commands/help.ts +18 -0
- package/src/commands/index.ts +21 -7
- package/src/commands/login.ts +19 -79
- package/src/commands/project.ts +107 -0
- package/src/commands/store-version.ts +242 -0
- package/src/commands/version.ts +51 -0
- package/src/commands/whoami.ts +46 -0
- package/src/index.ts +110 -15
- package/src/prompts/component.prompts.ts +94 -0
- package/src/prompts/function.prompts.ts +168 -0
- package/src/schemas/command.schema.ts +354 -0
- package/src/types/index.ts +183 -0
- package/src/utils/__tests__/command-parser.test.ts +159 -0
- package/src/utils/__tests__/command-suggestions.test.ts +185 -0
- package/src/utils/__tests__/console.test.ts +192 -0
- package/src/utils/__tests__/context-detector.test.ts +258 -0
- package/src/utils/__tests__/enhanced-error-handler.test.ts +137 -0
- package/src/utils/__tests__/error-handler.test.ts +107 -0
- package/src/utils/__tests__/rich-progress.test.ts +170 -0
- package/src/utils/__tests__/validation-error-formatter.test.ts +175 -0
- package/src/utils/__tests__/validation-helpers.test.ts +125 -0
- package/src/utils/auth.ts +41 -0
- package/src/utils/cli-progress-reporter.ts +84 -0
- package/src/utils/command-builder.ts +390 -0
- package/src/utils/command-helpers.ts +83 -0
- package/src/utils/command-parser.ts +250 -0
- package/src/utils/command-suggestions.ts +176 -0
- package/src/utils/console.ts +291 -0
- package/src/utils/context-detector.ts +177 -0
- package/src/utils/enhanced-error-handler.ts +264 -0
- package/src/utils/error-handler.ts +60 -0
- package/src/utils/errors.ts +125 -0
- package/src/utils/interactive-builder.ts +271 -0
- package/src/utils/rich-progress.ts +320 -0
- package/src/utils/store.ts +23 -0
- package/src/utils/validation-error-formatter.ts +337 -0
- package/src/utils/validation-helpers.ts +192 -0
- package/tsconfig.json +13 -7
- package/vitest.config.ts +28 -0
- package/vitest.setup.ts +29 -0
- package/tsup.config.ts +0 -15
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import { InvalidArgumentError } from "@commander-js/extra-typings";
|
|
2
|
+
import { describe, expect, it } from "vitest";
|
|
3
|
+
import {
|
|
4
|
+
parseBooleanOption,
|
|
5
|
+
parseComponentName,
|
|
6
|
+
parseComponentSlot,
|
|
7
|
+
parseFunctionInvocation,
|
|
8
|
+
parseFunctionName,
|
|
9
|
+
parsePath,
|
|
10
|
+
} from "../command-parser";
|
|
11
|
+
|
|
12
|
+
describe("Command Parsers", () => {
|
|
13
|
+
describe("parseComponentName", () => {
|
|
14
|
+
it("should accept valid component names", () => {
|
|
15
|
+
expect(parseComponentName("header-nav")).toBe("header-nav");
|
|
16
|
+
expect(parseComponentName("shopping-cart")).toBe("shopping-cart");
|
|
17
|
+
expect(parseComponentName("product-list-2")).toBe("product-list-2");
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it("should reject invalid component names", () => {
|
|
21
|
+
expect(() => parseComponentName("")).toThrow(InvalidArgumentError);
|
|
22
|
+
expect(() => parseComponentName("Test")).toThrow(
|
|
23
|
+
/lowercase with hyphens/,
|
|
24
|
+
);
|
|
25
|
+
expect(() => parseComponentName("test component")).toThrow(
|
|
26
|
+
/lowercase with hyphens/,
|
|
27
|
+
);
|
|
28
|
+
expect(() => parseComponentName("test_component")).toThrow(
|
|
29
|
+
/lowercase with hyphens/,
|
|
30
|
+
);
|
|
31
|
+
expect(() => parseComponentName("Test-Component")).toThrow(
|
|
32
|
+
/lowercase with hyphens/,
|
|
33
|
+
);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it("should provide helpful error messages", () => {
|
|
37
|
+
try {
|
|
38
|
+
parseComponentName("TestComponent");
|
|
39
|
+
} catch (error) {
|
|
40
|
+
expect(error).toBeInstanceOf(InvalidArgumentError);
|
|
41
|
+
expect(error.message).toContain("Invalid component name");
|
|
42
|
+
expect(error.message).toContain(
|
|
43
|
+
"Component names must be lowercase with hyphens only",
|
|
44
|
+
);
|
|
45
|
+
expect(error.message).toContain("Examples:");
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
describe("parseFunctionName", () => {
|
|
51
|
+
it("should accept valid function names", () => {
|
|
52
|
+
expect(parseFunctionName("validate-order")).toBe("validate-order");
|
|
53
|
+
expect(parseFunctionName("apply-discount")).toBe("apply-discount");
|
|
54
|
+
expect(parseFunctionName("check-inventory-v2")).toBe(
|
|
55
|
+
"check-inventory-v2",
|
|
56
|
+
);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it("should reject invalid function names", () => {
|
|
60
|
+
expect(() => parseFunctionName("")).toThrow(InvalidArgumentError);
|
|
61
|
+
expect(() => parseFunctionName("ValidateOrder")).toThrow(
|
|
62
|
+
/lowercase with hyphens/,
|
|
63
|
+
);
|
|
64
|
+
expect(() => parseFunctionName("validate order")).toThrow(
|
|
65
|
+
/lowercase with hyphens/,
|
|
66
|
+
);
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
describe("parseComponentSlot", () => {
|
|
71
|
+
it("should accept valid slots", () => {
|
|
72
|
+
expect(parseComponentSlot("header")).toBe("header");
|
|
73
|
+
expect(parseComponentSlot("main")).toBe("main");
|
|
74
|
+
expect(parseComponentSlot("sidebar")).toBe("sidebar");
|
|
75
|
+
expect(parseComponentSlot("footer")).toBe("footer");
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it("should reject invalid slots", () => {
|
|
79
|
+
expect(() => parseComponentSlot("invalid")).toThrow(InvalidArgumentError);
|
|
80
|
+
expect(() => parseComponentSlot("")).toThrow(InvalidArgumentError);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it("should provide list of valid slots in error", () => {
|
|
84
|
+
try {
|
|
85
|
+
parseComponentSlot("invalid");
|
|
86
|
+
} catch (error) {
|
|
87
|
+
expect(error.message).toContain(
|
|
88
|
+
"Valid slots: header, footer, sidebar, main, checkout-summary, payment-method, shipping-method, customer-info, order-confirmation",
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
describe("parseFunctionInvocation", () => {
|
|
95
|
+
it("should accept valid invocations", () => {
|
|
96
|
+
expect(parseFunctionInvocation("request")).toBe("request");
|
|
97
|
+
expect(parseFunctionInvocation("response")).toBe("response");
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
it("should reject invalid invocations", () => {
|
|
101
|
+
expect(() => parseFunctionInvocation("invalid")).toThrow(
|
|
102
|
+
InvalidArgumentError,
|
|
103
|
+
);
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it("should provide list of valid invocations in error", () => {
|
|
107
|
+
try {
|
|
108
|
+
parseFunctionInvocation("invalid");
|
|
109
|
+
} catch (error) {
|
|
110
|
+
expect(error.message).toContain("request");
|
|
111
|
+
expect(error.message).toContain("response");
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
describe("parseBooleanOption", () => {
|
|
117
|
+
it("should parse truthy values", () => {
|
|
118
|
+
expect(parseBooleanOption("true")).toBe(true);
|
|
119
|
+
expect(parseBooleanOption("TRUE")).toBe(true);
|
|
120
|
+
expect(parseBooleanOption("yes")).toBe(true);
|
|
121
|
+
expect(parseBooleanOption("y")).toBe(true);
|
|
122
|
+
expect(parseBooleanOption("1")).toBe(true);
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
it("should parse falsy values", () => {
|
|
126
|
+
expect(parseBooleanOption("false")).toBe(false);
|
|
127
|
+
expect(parseBooleanOption("FALSE")).toBe(false);
|
|
128
|
+
expect(parseBooleanOption("no")).toBe(false);
|
|
129
|
+
expect(parseBooleanOption("n")).toBe(false);
|
|
130
|
+
expect(parseBooleanOption("0")).toBe(false);
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it("should reject invalid values", () => {
|
|
134
|
+
expect(() => parseBooleanOption("maybe")).toThrow(InvalidArgumentError);
|
|
135
|
+
expect(() => parseBooleanOption("")).toThrow(InvalidArgumentError);
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
it("should provide helpful error message", () => {
|
|
139
|
+
try {
|
|
140
|
+
parseBooleanOption("invalid");
|
|
141
|
+
} catch (error) {
|
|
142
|
+
expect(error.message).toContain("Use true/false, yes/no, or 1/0");
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
describe("parsePath", () => {
|
|
148
|
+
it("should accept valid paths", () => {
|
|
149
|
+
expect(parsePath("./components/header")).toBe("./components/header");
|
|
150
|
+
expect(parsePath("/absolute/path")).toBe("/absolute/path");
|
|
151
|
+
expect(parsePath("relative/path")).toBe("relative/path");
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
it("should reject empty paths", () => {
|
|
155
|
+
expect(() => parsePath("")).toThrow(InvalidArgumentError);
|
|
156
|
+
expect(() => parsePath("")).toThrow(/cannot be empty/);
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
});
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
3
|
+
import { CommandSuggestions } from "../command-suggestions";
|
|
4
|
+
import type { CliConsole } from "../console";
|
|
5
|
+
|
|
6
|
+
// Mock the fs module
|
|
7
|
+
vi.mock("fs");
|
|
8
|
+
|
|
9
|
+
describe("CommandSuggestions", () => {
|
|
10
|
+
let mockConsole: CliConsole;
|
|
11
|
+
let suggestions: CommandSuggestions;
|
|
12
|
+
|
|
13
|
+
beforeEach(() => {
|
|
14
|
+
// Create a mock console
|
|
15
|
+
mockConsole = {
|
|
16
|
+
log: vi.fn(),
|
|
17
|
+
error: vi.fn(),
|
|
18
|
+
warn: vi.fn(),
|
|
19
|
+
info: vi.fn(),
|
|
20
|
+
success: vi.fn(),
|
|
21
|
+
dim: vi.fn(),
|
|
22
|
+
bold: vi.fn(),
|
|
23
|
+
list: vi.fn(),
|
|
24
|
+
table: vi.fn(),
|
|
25
|
+
json: vi.fn(),
|
|
26
|
+
spinner: vi.fn(),
|
|
27
|
+
confirm: vi.fn(),
|
|
28
|
+
prompt: vi.fn(),
|
|
29
|
+
setOptions: vi.fn(),
|
|
30
|
+
group: vi.fn(),
|
|
31
|
+
groupEnd: vi.fn(),
|
|
32
|
+
separator: vi.fn(),
|
|
33
|
+
suggestions: vi.fn(),
|
|
34
|
+
debug: vi.fn(),
|
|
35
|
+
nextSteps: vi.fn(),
|
|
36
|
+
};
|
|
37
|
+
suggestions = new CommandSuggestions(mockConsole);
|
|
38
|
+
vi.clearAllMocks();
|
|
39
|
+
|
|
40
|
+
// Mock process.cwd
|
|
41
|
+
vi.spyOn(process, "cwd").mockReturnValue("/test/project");
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
describe("show", () => {
|
|
45
|
+
it("should show suggestions for component directory", () => {
|
|
46
|
+
// Mock component detection
|
|
47
|
+
vi.mocked(fs.existsSync).mockImplementation((path) => {
|
|
48
|
+
if (path.toString().includes("package.json")) return true;
|
|
49
|
+
if (path.toString().includes("meta.json")) return true;
|
|
50
|
+
if (path.toString().includes("index.tsx")) return true;
|
|
51
|
+
return false;
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
vi.mocked(fs.readFileSync).mockReturnValue(
|
|
55
|
+
JSON.stringify({ type: "component", name: "header-nav" }),
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
suggestions.show();
|
|
59
|
+
|
|
60
|
+
// Check context display
|
|
61
|
+
expect(mockConsole.log).toHaveBeenCalledWith(
|
|
62
|
+
expect.stringContaining("You're in a component directory: header-nav"),
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
// Check component commands
|
|
66
|
+
expect(mockConsole.log).toHaveBeenCalledWith(
|
|
67
|
+
expect.stringContaining("Common commands for this component:"),
|
|
68
|
+
);
|
|
69
|
+
expect(mockConsole.log).toHaveBeenCalledWith(
|
|
70
|
+
expect.stringContaining("validate"),
|
|
71
|
+
);
|
|
72
|
+
expect(mockConsole.log).toHaveBeenCalledWith(
|
|
73
|
+
expect.stringContaining("build"),
|
|
74
|
+
);
|
|
75
|
+
expect(mockConsole.log).toHaveBeenCalledWith(
|
|
76
|
+
expect.stringContaining("deploy"),
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
// Check tip
|
|
80
|
+
expect(mockConsole.log).toHaveBeenCalledWith(
|
|
81
|
+
expect.stringContaining("Run 'ollieshop dev' to start developing"),
|
|
82
|
+
);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it("should show suggestions for function directory", () => {
|
|
86
|
+
// Mock function detection - ensure we ONLY return true for function files
|
|
87
|
+
vi.mocked(fs.existsSync).mockImplementation((path) => {
|
|
88
|
+
const pathStr = path.toString();
|
|
89
|
+
// Check for function-specific files
|
|
90
|
+
const isFunctionFile =
|
|
91
|
+
pathStr.includes("package.json") ||
|
|
92
|
+
pathStr.includes("meta.json") ||
|
|
93
|
+
(pathStr.includes("index.ts") && !pathStr.includes("index.tsx"));
|
|
94
|
+
return isFunctionFile;
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
vi.mocked(fs.readFileSync).mockReturnValue(
|
|
98
|
+
JSON.stringify({ type: "function", name: "validate-order" }),
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
suggestions.show();
|
|
102
|
+
|
|
103
|
+
// Check context display
|
|
104
|
+
expect(mockConsole.log).toHaveBeenCalledWith(
|
|
105
|
+
expect.stringContaining(
|
|
106
|
+
"You're in a function directory: validate-order",
|
|
107
|
+
),
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
// Check function commands
|
|
111
|
+
expect(mockConsole.log).toHaveBeenCalledWith(
|
|
112
|
+
expect.stringContaining("Common commands for this function:"),
|
|
113
|
+
);
|
|
114
|
+
expect(mockConsole.log).toHaveBeenCalledWith(
|
|
115
|
+
expect.stringContaining("test"),
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
// Check tip
|
|
119
|
+
expect(mockConsole.log).toHaveBeenCalledWith(
|
|
120
|
+
expect.stringContaining("Run 'ollieshop test' to test this function"),
|
|
121
|
+
);
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it("should show suggestions for project root", () => {
|
|
125
|
+
// Mock project root detection
|
|
126
|
+
vi.mocked(fs.existsSync).mockImplementation((path) => {
|
|
127
|
+
if (path.toString().includes("components")) return true;
|
|
128
|
+
return false;
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
vi.mocked(fs.statSync).mockReturnValue({
|
|
132
|
+
isDirectory: () => true,
|
|
133
|
+
} as fs.Stats);
|
|
134
|
+
|
|
135
|
+
suggestions.show();
|
|
136
|
+
|
|
137
|
+
// Check context display
|
|
138
|
+
expect(mockConsole.log).toHaveBeenCalledWith(
|
|
139
|
+
expect.stringContaining("You're in the project root"),
|
|
140
|
+
);
|
|
141
|
+
|
|
142
|
+
// Check general commands
|
|
143
|
+
expect(mockConsole.log).toHaveBeenCalledWith(
|
|
144
|
+
expect.stringContaining("Common commands:"),
|
|
145
|
+
);
|
|
146
|
+
expect(mockConsole.log).toHaveBeenCalledWith(
|
|
147
|
+
expect.stringContaining("component create"),
|
|
148
|
+
);
|
|
149
|
+
expect(mockConsole.log).toHaveBeenCalledWith(
|
|
150
|
+
expect.stringContaining("function create"),
|
|
151
|
+
);
|
|
152
|
+
|
|
153
|
+
// Check tip
|
|
154
|
+
expect(mockConsole.log).toHaveBeenCalledWith(
|
|
155
|
+
expect.stringContaining(
|
|
156
|
+
"Navigate to a component with 'cd components/<name>'",
|
|
157
|
+
),
|
|
158
|
+
);
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
it("should show recent commands for component", () => {
|
|
162
|
+
// Mock component detection
|
|
163
|
+
vi.mocked(fs.existsSync).mockImplementation((path) => {
|
|
164
|
+
if (path.toString().includes("package.json")) return true;
|
|
165
|
+
if (path.toString().includes("meta.json")) return true;
|
|
166
|
+
if (path.toString().includes("index.tsx")) return true;
|
|
167
|
+
return false;
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
vi.mocked(fs.readFileSync).mockReturnValue(
|
|
171
|
+
JSON.stringify({ type: "component" }),
|
|
172
|
+
);
|
|
173
|
+
|
|
174
|
+
suggestions.show();
|
|
175
|
+
|
|
176
|
+
// Check recent commands section
|
|
177
|
+
expect(mockConsole.log).toHaveBeenCalledWith(
|
|
178
|
+
expect.stringContaining("Recent commands:"),
|
|
179
|
+
);
|
|
180
|
+
expect(mockConsole.log).toHaveBeenCalledWith(
|
|
181
|
+
expect.stringContaining("validate --fix"),
|
|
182
|
+
);
|
|
183
|
+
});
|
|
184
|
+
});
|
|
185
|
+
});
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
3
|
+
import { Console } from "../console";
|
|
4
|
+
|
|
5
|
+
// Mock chalk
|
|
6
|
+
vi.mock("chalk", () => ({
|
|
7
|
+
default: {
|
|
8
|
+
green: vi.fn((str: string) => `[GREEN]${str}[/GREEN]`),
|
|
9
|
+
red: Object.assign(
|
|
10
|
+
vi.fn((str: string) => `[RED]${str}[/RED]`),
|
|
11
|
+
{
|
|
12
|
+
bold: vi.fn((str: string) => `[RED-BOLD]${str}[/RED-BOLD]`),
|
|
13
|
+
},
|
|
14
|
+
),
|
|
15
|
+
yellow: vi.fn((str: string) => `[YELLOW]${str}[/YELLOW]`),
|
|
16
|
+
blue: Object.assign(
|
|
17
|
+
vi.fn((str: string) => `[BLUE]${str}[/BLUE]`),
|
|
18
|
+
{
|
|
19
|
+
bold: vi.fn((str: string) => `[BLUE-BOLD]${str}[/BLUE-BOLD]`),
|
|
20
|
+
},
|
|
21
|
+
),
|
|
22
|
+
gray: vi.fn((str: string) => `[GRAY]${str}[/GRAY]`),
|
|
23
|
+
cyan: vi.fn((str: string) => `[CYAN]${str}[/CYAN]`),
|
|
24
|
+
level: 0,
|
|
25
|
+
},
|
|
26
|
+
}));
|
|
27
|
+
|
|
28
|
+
// Mock ora
|
|
29
|
+
vi.mock("ora", () => ({
|
|
30
|
+
default: vi.fn(() => ({
|
|
31
|
+
start: vi.fn().mockReturnThis(),
|
|
32
|
+
succeed: vi.fn().mockReturnThis(),
|
|
33
|
+
fail: vi.fn().mockReturnThis(),
|
|
34
|
+
warn: vi.fn().mockReturnThis(),
|
|
35
|
+
stop: vi.fn().mockReturnThis(),
|
|
36
|
+
})),
|
|
37
|
+
}));
|
|
38
|
+
|
|
39
|
+
describe("Console Class", () => {
|
|
40
|
+
let consoleInstance: Console;
|
|
41
|
+
|
|
42
|
+
beforeEach(() => {
|
|
43
|
+
vi.clearAllMocks();
|
|
44
|
+
vi.spyOn(global.console, "log").mockImplementation(() => {
|
|
45
|
+
// Intentionally empty for test isolation
|
|
46
|
+
});
|
|
47
|
+
vi.spyOn(global.console, "error").mockImplementation(() => {
|
|
48
|
+
// Intentionally empty for test isolation
|
|
49
|
+
});
|
|
50
|
+
consoleInstance = new Console();
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
afterEach(() => {
|
|
54
|
+
vi.restoreAllMocks();
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
describe("setOptions", () => {
|
|
58
|
+
it("should set noColor option", () => {
|
|
59
|
+
// Act
|
|
60
|
+
consoleInstance.setOptions({ noColor: true });
|
|
61
|
+
|
|
62
|
+
// Assert
|
|
63
|
+
expect(chalk.level).toBe(0);
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
describe("success", () => {
|
|
68
|
+
it("should log success message in green", () => {
|
|
69
|
+
// Act
|
|
70
|
+
consoleInstance.success("Operation completed");
|
|
71
|
+
|
|
72
|
+
// Assert
|
|
73
|
+
expect(global.console.log).toHaveBeenCalledWith(
|
|
74
|
+
expect.stringContaining(
|
|
75
|
+
"[BLUE-BOLD][ollie][/BLUE-BOLD] [GREEN]✓[/GREEN] [GREEN]Operation completed[/GREEN]",
|
|
76
|
+
),
|
|
77
|
+
);
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
describe("error", () => {
|
|
82
|
+
it("should log error message in red", () => {
|
|
83
|
+
// Act
|
|
84
|
+
consoleInstance.error("Operation failed");
|
|
85
|
+
|
|
86
|
+
// Assert
|
|
87
|
+
expect(global.console.error).toHaveBeenCalledWith(
|
|
88
|
+
expect.stringContaining(
|
|
89
|
+
"[BLUE-BOLD][ollie][/BLUE-BOLD] [RED]✗[/RED] [RED-BOLD]Operation failed[/RED-BOLD]",
|
|
90
|
+
),
|
|
91
|
+
);
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
describe("info", () => {
|
|
96
|
+
it("should log info message", () => {
|
|
97
|
+
// Act
|
|
98
|
+
consoleInstance.info("Information message");
|
|
99
|
+
|
|
100
|
+
// Assert
|
|
101
|
+
expect(global.console.log).toHaveBeenCalledWith(
|
|
102
|
+
expect.stringContaining("Information message"),
|
|
103
|
+
);
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
describe("warn", () => {
|
|
108
|
+
it("should log warning message in yellow", () => {
|
|
109
|
+
// Act
|
|
110
|
+
consoleInstance.warn("Warning message");
|
|
111
|
+
|
|
112
|
+
// Assert
|
|
113
|
+
expect(global.console.warn).toHaveBeenCalledWith(
|
|
114
|
+
expect.stringContaining(
|
|
115
|
+
"[BLUE-BOLD][ollie][/BLUE-BOLD] [YELLOW]⚠[/YELLOW] [YELLOW]Warning message[/YELLOW]",
|
|
116
|
+
),
|
|
117
|
+
);
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
describe("hint", () => {
|
|
122
|
+
it("should log hint message in gray", () => {
|
|
123
|
+
// Act
|
|
124
|
+
consoleInstance.hint("Hint message");
|
|
125
|
+
|
|
126
|
+
// Assert
|
|
127
|
+
expect(global.console.log).toHaveBeenCalledWith(
|
|
128
|
+
expect.stringContaining("[GRAY]Hint message[/GRAY]"),
|
|
129
|
+
);
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
describe("spinner", () => {
|
|
134
|
+
it("should create and return a spinner", () => {
|
|
135
|
+
// Act
|
|
136
|
+
const spinner = consoleInstance.spinner("Loading...");
|
|
137
|
+
|
|
138
|
+
// Assert
|
|
139
|
+
expect(spinner).toBeDefined();
|
|
140
|
+
expect(spinner.start).toBeDefined();
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
describe("quiet mode", () => {
|
|
145
|
+
it("should not log messages when quiet mode is enabled", () => {
|
|
146
|
+
// Arrange
|
|
147
|
+
consoleInstance.setOptions({ quiet: true });
|
|
148
|
+
|
|
149
|
+
// Act
|
|
150
|
+
consoleInstance.info("Should not appear");
|
|
151
|
+
consoleInstance.success("Should not appear");
|
|
152
|
+
consoleInstance.warn("Should not appear");
|
|
153
|
+
|
|
154
|
+
// Assert
|
|
155
|
+
expect(global.console.log).not.toHaveBeenCalled();
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
it("should still log errors in quiet mode", () => {
|
|
159
|
+
// Arrange
|
|
160
|
+
consoleInstance.setOptions({ quiet: true });
|
|
161
|
+
|
|
162
|
+
// Act
|
|
163
|
+
consoleInstance.error("Error should appear");
|
|
164
|
+
|
|
165
|
+
// Assert
|
|
166
|
+
expect(global.console.error).toHaveBeenCalled();
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
describe("verbose mode", () => {
|
|
171
|
+
it("should log debug messages when verbose mode is enabled", () => {
|
|
172
|
+
// Arrange
|
|
173
|
+
consoleInstance.setOptions({ verbose: true });
|
|
174
|
+
|
|
175
|
+
// Act
|
|
176
|
+
consoleInstance.debug("Debug message");
|
|
177
|
+
|
|
178
|
+
// Assert
|
|
179
|
+
expect(global.console.log).toHaveBeenCalledWith(
|
|
180
|
+
expect.stringContaining("[GRAY]Debug message[/GRAY]"),
|
|
181
|
+
);
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
it("should not log debug messages when verbose mode is disabled", () => {
|
|
185
|
+
// Act
|
|
186
|
+
consoleInstance.debug("Debug message");
|
|
187
|
+
|
|
188
|
+
// Assert
|
|
189
|
+
expect(global.console.log).not.toHaveBeenCalled();
|
|
190
|
+
});
|
|
191
|
+
});
|
|
192
|
+
});
|