@sundaeswap/sprinkles 0.3.0 → 0.5.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/dist/cjs/Sprinkle/__tests__/encryption.test.js +20 -8
- package/dist/cjs/Sprinkle/__tests__/encryption.test.js.map +1 -1
- package/dist/cjs/Sprinkle/__tests__/enhancements.test.js +41 -16
- package/dist/cjs/Sprinkle/__tests__/enhancements.test.js.map +1 -1
- package/dist/cjs/Sprinkle/__tests__/fill-in-struct.test.js +85 -38
- package/dist/cjs/Sprinkle/__tests__/fill-in-struct.test.js.map +1 -1
- package/dist/cjs/Sprinkle/__tests__/settings-persistence.test.js +120 -0
- package/dist/cjs/Sprinkle/__tests__/settings-persistence.test.js.map +1 -1
- package/dist/cjs/Sprinkle/__tests__/show-menu.test.js +93 -7
- package/dist/cjs/Sprinkle/__tests__/show-menu.test.js.map +1 -1
- package/dist/cjs/Sprinkle/__tests__/tx-dialog.test.js +21 -0
- package/dist/cjs/Sprinkle/__tests__/tx-dialog.test.js.map +1 -1
- package/dist/cjs/Sprinkle/encryption.js +131 -0
- package/dist/cjs/Sprinkle/encryption.js.map +1 -0
- package/dist/cjs/Sprinkle/index.js +318 -352
- package/dist/cjs/Sprinkle/index.js.map +1 -1
- package/dist/cjs/Sprinkle/prompts.js +393 -0
- package/dist/cjs/Sprinkle/prompts.js.map +1 -0
- package/dist/cjs/Sprinkle/schemas.js +97 -0
- package/dist/cjs/Sprinkle/schemas.js.map +1 -0
- package/dist/cjs/Sprinkle/tx-dialog.js +101 -0
- package/dist/cjs/Sprinkle/tx-dialog.js.map +1 -0
- package/dist/cjs/Sprinkle/type-guards.js +42 -0
- package/dist/cjs/Sprinkle/type-guards.js.map +1 -0
- package/dist/cjs/Sprinkle/types.js +49 -0
- package/dist/cjs/Sprinkle/types.js.map +1 -0
- package/dist/cjs/Sprinkle/wallet.js +98 -0
- package/dist/cjs/Sprinkle/wallet.js.map +1 -0
- package/dist/esm/Sprinkle/__tests__/encryption.test.js +20 -8
- package/dist/esm/Sprinkle/__tests__/encryption.test.js.map +1 -1
- package/dist/esm/Sprinkle/__tests__/enhancements.test.js +41 -16
- package/dist/esm/Sprinkle/__tests__/enhancements.test.js.map +1 -1
- package/dist/esm/Sprinkle/__tests__/fill-in-struct.test.js +85 -38
- package/dist/esm/Sprinkle/__tests__/fill-in-struct.test.js.map +1 -1
- package/dist/esm/Sprinkle/__tests__/settings-persistence.test.js +120 -0
- package/dist/esm/Sprinkle/__tests__/settings-persistence.test.js.map +1 -1
- package/dist/esm/Sprinkle/__tests__/show-menu.test.js +94 -8
- package/dist/esm/Sprinkle/__tests__/show-menu.test.js.map +1 -1
- package/dist/esm/Sprinkle/__tests__/tx-dialog.test.js +21 -0
- package/dist/esm/Sprinkle/__tests__/tx-dialog.test.js.map +1 -1
- package/dist/esm/Sprinkle/encryption.js +117 -0
- package/dist/esm/Sprinkle/encryption.js.map +1 -0
- package/dist/esm/Sprinkle/index.js +172 -337
- package/dist/esm/Sprinkle/index.js.map +1 -1
- package/dist/esm/Sprinkle/prompts.js +385 -0
- package/dist/esm/Sprinkle/prompts.js.map +1 -0
- package/dist/esm/Sprinkle/schemas.js +91 -0
- package/dist/esm/Sprinkle/schemas.js.map +1 -0
- package/dist/esm/Sprinkle/tx-dialog.js +90 -0
- package/dist/esm/Sprinkle/tx-dialog.js.map +1 -0
- package/dist/esm/Sprinkle/type-guards.js +24 -0
- package/dist/esm/Sprinkle/type-guards.js.map +1 -0
- package/dist/esm/Sprinkle/types.js +42 -0
- package/dist/esm/Sprinkle/types.js.map +1 -0
- package/dist/esm/Sprinkle/wallet.js +90 -0
- package/dist/esm/Sprinkle/wallet.js.map +1 -0
- package/dist/types/Sprinkle/encryption.d.ts +43 -0
- package/dist/types/Sprinkle/encryption.d.ts.map +1 -0
- package/dist/types/Sprinkle/index.d.ts +13 -174
- package/dist/types/Sprinkle/index.d.ts.map +1 -1
- package/dist/types/Sprinkle/prompts.d.ts +94 -0
- package/dist/types/Sprinkle/prompts.d.ts.map +1 -0
- package/dist/types/Sprinkle/schemas.d.ts +125 -0
- package/dist/types/Sprinkle/schemas.d.ts.map +1 -0
- package/dist/types/Sprinkle/tx-dialog.d.ts +37 -0
- package/dist/types/Sprinkle/tx-dialog.d.ts.map +1 -0
- package/dist/types/Sprinkle/type-guards.d.ts +22 -0
- package/dist/types/Sprinkle/type-guards.d.ts.map +1 -0
- package/dist/types/Sprinkle/types.d.ts +62 -0
- package/dist/types/Sprinkle/types.d.ts.map +1 -0
- package/dist/types/Sprinkle/wallet.d.ts +27 -0
- package/dist/types/Sprinkle/wallet.d.ts.map +1 -0
- package/dist/types/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/Sprinkle/__tests__/encryption.test.ts +21 -8
- package/src/Sprinkle/__tests__/enhancements.test.ts +41 -15
- package/src/Sprinkle/__tests__/fill-in-struct.test.ts +104 -38
- package/src/Sprinkle/__tests__/settings-persistence.test.ts +108 -0
- package/src/Sprinkle/__tests__/show-menu.test.ts +96 -8
- package/src/Sprinkle/__tests__/tx-dialog.test.ts +21 -0
- package/src/Sprinkle/encryption.ts +130 -0
- package/src/Sprinkle/index.ts +265 -478
- package/src/Sprinkle/prompts.ts +481 -0
- package/src/Sprinkle/schemas.ts +111 -0
- package/src/Sprinkle/tx-dialog.ts +100 -0
- package/src/Sprinkle/type-guards.ts +51 -0
- package/src/Sprinkle/types.ts +73 -0
- package/src/Sprinkle/wallet.ts +133 -0
|
@@ -192,5 +192,125 @@ describe("Settings Persistence", () => {
|
|
|
192
192
|
});
|
|
193
193
|
expect(sprinkle.profileMeta.name).toBe("Default");
|
|
194
194
|
});
|
|
195
|
+
describe("currentProfile", () => {
|
|
196
|
+
test("returns null when no profile loaded", () => {
|
|
197
|
+
const schema = Type.Object({
|
|
198
|
+
name: Type.String()
|
|
199
|
+
});
|
|
200
|
+
const sprinkle = new Sprinkle(schema, tmpDir);
|
|
201
|
+
expect(sprinkle.currentProfile).toBeNull();
|
|
202
|
+
});
|
|
203
|
+
test("returns profile info when loaded", () => {
|
|
204
|
+
const schema = Type.Object({
|
|
205
|
+
name: Type.String()
|
|
206
|
+
});
|
|
207
|
+
const sprinkle = withProfile(new Sprinkle(schema, tmpDir));
|
|
208
|
+
const profile = sprinkle.currentProfile;
|
|
209
|
+
expect(profile).not.toBeNull();
|
|
210
|
+
expect(profile.id).toBe("test");
|
|
211
|
+
expect(profile.name).toBe("Test");
|
|
212
|
+
expect(profile.createdAt).toBeDefined();
|
|
213
|
+
expect(profile.updatedAt).toBeDefined();
|
|
214
|
+
});
|
|
215
|
+
test("includes description when present", () => {
|
|
216
|
+
const schema = Type.Object({
|
|
217
|
+
name: Type.String()
|
|
218
|
+
});
|
|
219
|
+
const sprinkle = withProfile(new Sprinkle(schema, tmpDir));
|
|
220
|
+
sprinkle.profileMeta.description = "Test profile description";
|
|
221
|
+
const profile = sprinkle.currentProfile;
|
|
222
|
+
expect(profile.description).toBe("Test profile description");
|
|
223
|
+
});
|
|
224
|
+
test("has undefined description when not set", () => {
|
|
225
|
+
const schema = Type.Object({
|
|
226
|
+
name: Type.String()
|
|
227
|
+
});
|
|
228
|
+
const sprinkle = withProfile(new Sprinkle(schema, tmpDir));
|
|
229
|
+
delete sprinkle.profileMeta.description;
|
|
230
|
+
const profile = sprinkle.currentProfile;
|
|
231
|
+
expect(profile.description).toBeUndefined();
|
|
232
|
+
});
|
|
233
|
+
});
|
|
234
|
+
describe("getDisplaySettings", () => {
|
|
235
|
+
test("masks sensitive fields", () => {
|
|
236
|
+
const schema = Type.Object({
|
|
237
|
+
name: Type.String(),
|
|
238
|
+
secret: Type.String({
|
|
239
|
+
sensitive: true
|
|
240
|
+
})
|
|
241
|
+
});
|
|
242
|
+
const sprinkle = withProfile(new Sprinkle(schema, tmpDir));
|
|
243
|
+
sprinkle.settings = {
|
|
244
|
+
name: "visible",
|
|
245
|
+
secret: "hidden"
|
|
246
|
+
};
|
|
247
|
+
const display = sprinkle.getDisplaySettings();
|
|
248
|
+
expect(display.name).toBe("visible");
|
|
249
|
+
expect(display.secret).toBe("********");
|
|
250
|
+
});
|
|
251
|
+
test("preserves non-sensitive fields", () => {
|
|
252
|
+
const schema = Type.Object({
|
|
253
|
+
name: Type.String(),
|
|
254
|
+
count: Type.Number()
|
|
255
|
+
});
|
|
256
|
+
const sprinkle = withProfile(new Sprinkle(schema, tmpDir));
|
|
257
|
+
sprinkle.settings = {
|
|
258
|
+
name: "test",
|
|
259
|
+
count: 42
|
|
260
|
+
};
|
|
261
|
+
const display = sprinkle.getDisplaySettings();
|
|
262
|
+
expect(display.name).toBe("test");
|
|
263
|
+
expect(display.count).toBe(42);
|
|
264
|
+
});
|
|
265
|
+
test("preserves BigInt values", () => {
|
|
266
|
+
const schema = Type.Object({
|
|
267
|
+
amount: Type.BigInt(),
|
|
268
|
+
secret: Type.String({
|
|
269
|
+
sensitive: true
|
|
270
|
+
})
|
|
271
|
+
});
|
|
272
|
+
const sprinkle = withProfile(new Sprinkle(schema, tmpDir));
|
|
273
|
+
sprinkle.settings = {
|
|
274
|
+
amount: 42n,
|
|
275
|
+
secret: "hidden"
|
|
276
|
+
};
|
|
277
|
+
const display = sprinkle.getDisplaySettings();
|
|
278
|
+
expect(display.amount).toBe(42n);
|
|
279
|
+
expect(display.secret).toBe("********");
|
|
280
|
+
});
|
|
281
|
+
test("masks nested sensitive fields", () => {
|
|
282
|
+
const schema = Type.Object({
|
|
283
|
+
wallet: Type.Object({
|
|
284
|
+
key: Type.String({
|
|
285
|
+
sensitive: true
|
|
286
|
+
}),
|
|
287
|
+
address: Type.String()
|
|
288
|
+
})
|
|
289
|
+
});
|
|
290
|
+
const sprinkle = withProfile(new Sprinkle(schema, tmpDir));
|
|
291
|
+
sprinkle.settings = {
|
|
292
|
+
wallet: {
|
|
293
|
+
key: "secret",
|
|
294
|
+
address: "addr1..."
|
|
295
|
+
}
|
|
296
|
+
};
|
|
297
|
+
const display = sprinkle.getDisplaySettings();
|
|
298
|
+
expect(display.wallet.key).toBe("********");
|
|
299
|
+
expect(display.wallet.address).toBe("addr1...");
|
|
300
|
+
});
|
|
301
|
+
test("does not mask empty sensitive fields", () => {
|
|
302
|
+
const schema = Type.Object({
|
|
303
|
+
secret: Type.String({
|
|
304
|
+
sensitive: true
|
|
305
|
+
})
|
|
306
|
+
});
|
|
307
|
+
const sprinkle = withProfile(new Sprinkle(schema, tmpDir));
|
|
308
|
+
sprinkle.settings = {
|
|
309
|
+
secret: ""
|
|
310
|
+
};
|
|
311
|
+
const display = sprinkle.getDisplaySettings();
|
|
312
|
+
expect(display.secret).toBe("");
|
|
313
|
+
});
|
|
314
|
+
});
|
|
195
315
|
});
|
|
196
316
|
//# sourceMappingURL=settings-persistence.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"settings-persistence.test.js","names":["describe","expect","test","beforeEach","afterEach","Sprinkle","Type","fs","path","os","withProfile","tmpDir","mkdtempSync","join","tmpdir","rmSync","recursive","force","result","SettingsPath","toBe","sep","nestedDir","schema","Object","name","String","sprinkle","settings","saveSettings","existsSync","content","readFileSync","parsed","JSON","parse","defaults","toEqual","meta","amount","BigInt","raw","sprinkle2","loadProfile","string","user","score","profileMeta","profiles","scanProfiles","length","id","sanitizeProfileId","mkdirSync","writeFileSync","stringify","migrateIfNeeded"],"sources":["../../../../src/Sprinkle/__tests__/settings-persistence.test.ts"],"sourcesContent":["import { describe, expect, test, beforeEach, afterEach } from \"bun:test\";\nimport { Sprinkle, Type } from \"../index.js\";\nimport * as fs from \"fs\";\nimport * as path from \"path\";\nimport * as os from \"os\";\nimport { withProfile } from \"./test-helpers.js\";\n\ndescribe(\"Settings Persistence\", () => {\n let tmpDir: string;\n\n beforeEach(() => {\n tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), \"sprinkles-test-\"));\n });\n\n afterEach(() => {\n fs.rmSync(tmpDir, { recursive: true, force: true });\n });\n\n test(\"SettingsPath returns correct path\", () => {\n const result = Sprinkle.SettingsPath(\"/some/path\");\n expect(result).toBe(`/some/path${path.sep}settings.json`);\n });\n\n test(\"saveSettings creates directory if missing\", () => {\n const nestedDir = path.join(tmpDir, \"nested\", \"deep\");\n const schema = Type.Object({ name: Type.String() });\n const sprinkle = withProfile(new Sprinkle(schema, nestedDir));\n sprinkle.settings = { name: \"test\" } as any;\n\n sprinkle.saveSettings();\n\n expect(fs.existsSync(path.join(nestedDir, \"profiles\", \"test.json\"))).toBe(\n true,\n );\n });\n\n test(\"saveSettings writes valid JSON with profile format\", () => {\n const schema = Type.Object({ name: Type.String() });\n const sprinkle = withProfile(new Sprinkle(schema, tmpDir));\n sprinkle.settings = { name: \"hello\" } as any;\n\n sprinkle.saveSettings();\n\n const content = fs.readFileSync(\n path.join(tmpDir, \"profiles\", \"test.json\"),\n \"utf-8\",\n );\n const parsed = JSON.parse(content);\n expect(parsed.settings.name).toBe(\"hello\");\n expect(parsed.defaults).toEqual({});\n expect(parsed.meta.name).toBe(\"Test\");\n });\n\n test(\"saveSettings serializes BigInt values\", () => {\n const schema = Type.Object({ amount: Type.BigInt() });\n const sprinkle = withProfile(new Sprinkle(schema, tmpDir));\n sprinkle.settings = { amount: 42n } as any;\n\n sprinkle.saveSettings();\n\n const content = fs.readFileSync(\n path.join(tmpDir, \"profiles\", \"test.json\"),\n \"utf-8\",\n );\n const raw = JSON.parse(content);\n expect(raw.settings.amount).toBe(\"42n\");\n });\n\n test(\"saveSettings and loadProfile round-trip with BigInt\", async () => {\n const schema = Type.Object({ amount: Type.BigInt() });\n const sprinkle = withProfile(new Sprinkle(schema, tmpDir));\n sprinkle.settings = { amount: 99n } as any;\n sprinkle.saveSettings();\n\n const sprinkle2 = new Sprinkle(schema, tmpDir);\n await sprinkle2.loadProfile(\"test\");\n\n expect(sprinkle2.settings).toEqual({ amount: 99n });\n });\n\n test(\"saveSettings preserves defaults\", () => {\n const schema = Type.Object({ name: Type.String() });\n const sprinkle = withProfile(new Sprinkle(schema, tmpDir));\n sprinkle.settings = { name: \"test\" } as any;\n sprinkle.defaults = { string: \"last-input\" };\n\n sprinkle.saveSettings();\n\n const content = fs.readFileSync(\n path.join(tmpDir, \"profiles\", \"test.json\"),\n \"utf-8\",\n );\n const parsed = JSON.parse(content);\n expect(parsed.defaults.string).toBe(\"last-input\");\n });\n\n test(\"loadProfile restores defaults\", async () => {\n const schema = Type.Object({ name: Type.String() });\n const sprinkle = withProfile(new Sprinkle(schema, tmpDir));\n sprinkle.settings = { name: \"test\" } as any;\n sprinkle.defaults = { string: \"remembered\" };\n sprinkle.saveSettings();\n\n const sprinkle2 = new Sprinkle(schema, tmpDir);\n await sprinkle2.loadProfile(\"test\");\n\n expect(sprinkle2.defaults).toEqual({ string: \"remembered\" });\n });\n\n test(\"round-trip with nested objects\", async () => {\n const schema = Type.Object({\n user: Type.Object({\n name: Type.String(),\n score: Type.BigInt(),\n }),\n });\n const sprinkle = withProfile(new Sprinkle(schema, tmpDir));\n sprinkle.settings = { user: { name: \"alice\", score: 100n } } as any;\n sprinkle.saveSettings();\n\n const sprinkle2 = new Sprinkle(schema, tmpDir);\n await sprinkle2.loadProfile(\"test\");\n\n expect(sprinkle2.settings).toEqual({\n user: { name: \"alice\", score: 100n },\n });\n });\n\n test(\"scanProfiles returns profile entries\", () => {\n const schema = Type.Object({ name: Type.String() });\n const sprinkle = withProfile(new Sprinkle(schema, tmpDir), \"alice\");\n sprinkle.profileMeta.name = \"Alice\";\n sprinkle.settings = { name: \"test\" } as any;\n sprinkle.saveSettings();\n\n const profiles = sprinkle.scanProfiles();\n expect(profiles.length).toBe(1);\n expect(profiles[0]!.id).toBe(\"alice\");\n expect(profiles[0]!.meta.name).toBe(\"Alice\");\n });\n\n test(\"sanitizeProfileId handles various inputs\", () => {\n expect(Sprinkle.sanitizeProfileId(\"Mainnet Alice\")).toBe(\"mainnet-alice\");\n expect(Sprinkle.sanitizeProfileId(\"test--profile\")).toBe(\"test-profile\");\n expect(Sprinkle.sanitizeProfileId(\"Hello World!@#$\")).toBe(\"hello-world\");\n expect(Sprinkle.sanitizeProfileId(\" \")).toBe(\"profile\");\n expect(Sprinkle.sanitizeProfileId(\"simple\")).toBe(\"simple\");\n });\n\n test(\"migration converts legacy settings.json to profile\", async () => {\n const schema = Type.Object({ name: Type.String() });\n\n // Write legacy settings.json\n fs.mkdirSync(tmpDir, { recursive: true });\n fs.writeFileSync(\n path.join(tmpDir, \"settings.json\"),\n JSON.stringify({\n settings: { name: \"legacy\" },\n defaults: { string: \"old\" },\n }),\n );\n\n // Create sprinkle and trigger migration\n const sprinkle = new Sprinkle(schema, tmpDir);\n await (sprinkle as any).migrateIfNeeded();\n\n // Check profile was created\n expect(fs.existsSync(path.join(tmpDir, \"profiles\", \"default.json\"))).toBe(\n true,\n );\n // Check legacy file was backed up\n expect(fs.existsSync(path.join(tmpDir, \"settings.json.bak\"))).toBe(true);\n expect(fs.existsSync(path.join(tmpDir, \"settings.json\"))).toBe(false);\n\n // Load the migrated profile\n await sprinkle.loadProfile(\"default\");\n expect(sprinkle.settings).toEqual({ name: \"legacy\" });\n expect(sprinkle.defaults).toEqual({ string: \"old\" });\n expect(sprinkle.profileMeta.name).toBe(\"Default\");\n });\n});\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"settings-persistence.test.js","names":["describe","expect","test","beforeEach","afterEach","Sprinkle","Type","fs","path","os","withProfile","tmpDir","mkdtempSync","join","tmpdir","rmSync","recursive","force","result","SettingsPath","toBe","sep","nestedDir","schema","Object","name","String","sprinkle","settings","saveSettings","existsSync","content","readFileSync","parsed","JSON","parse","defaults","toEqual","meta","amount","BigInt","raw","sprinkle2","loadProfile","string","user","score","profileMeta","profiles","scanProfiles","length","id","sanitizeProfileId","mkdirSync","writeFileSync","stringify","migrateIfNeeded","currentProfile","toBeNull","profile","not","createdAt","toBeDefined","updatedAt","description","toBeUndefined","secret","sensitive","display","getDisplaySettings","count","Number","wallet","key","address"],"sources":["../../../../src/Sprinkle/__tests__/settings-persistence.test.ts"],"sourcesContent":["import { describe, expect, test, beforeEach, afterEach } from \"bun:test\";\nimport { Sprinkle, Type } from \"../index.js\";\nimport * as fs from \"fs\";\nimport * as path from \"path\";\nimport * as os from \"os\";\nimport { withProfile } from \"./test-helpers.js\";\n\ndescribe(\"Settings Persistence\", () => {\n let tmpDir: string;\n\n beforeEach(() => {\n tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), \"sprinkles-test-\"));\n });\n\n afterEach(() => {\n fs.rmSync(tmpDir, { recursive: true, force: true });\n });\n\n test(\"SettingsPath returns correct path\", () => {\n const result = Sprinkle.SettingsPath(\"/some/path\");\n expect(result).toBe(`/some/path${path.sep}settings.json`);\n });\n\n test(\"saveSettings creates directory if missing\", () => {\n const nestedDir = path.join(tmpDir, \"nested\", \"deep\");\n const schema = Type.Object({ name: Type.String() });\n const sprinkle = withProfile(new Sprinkle(schema, nestedDir));\n sprinkle.settings = { name: \"test\" } as any;\n\n sprinkle.saveSettings();\n\n expect(fs.existsSync(path.join(nestedDir, \"profiles\", \"test.json\"))).toBe(\n true,\n );\n });\n\n test(\"saveSettings writes valid JSON with profile format\", () => {\n const schema = Type.Object({ name: Type.String() });\n const sprinkle = withProfile(new Sprinkle(schema, tmpDir));\n sprinkle.settings = { name: \"hello\" } as any;\n\n sprinkle.saveSettings();\n\n const content = fs.readFileSync(\n path.join(tmpDir, \"profiles\", \"test.json\"),\n \"utf-8\",\n );\n const parsed = JSON.parse(content);\n expect(parsed.settings.name).toBe(\"hello\");\n expect(parsed.defaults).toEqual({});\n expect(parsed.meta.name).toBe(\"Test\");\n });\n\n test(\"saveSettings serializes BigInt values\", () => {\n const schema = Type.Object({ amount: Type.BigInt() });\n const sprinkle = withProfile(new Sprinkle(schema, tmpDir));\n sprinkle.settings = { amount: 42n } as any;\n\n sprinkle.saveSettings();\n\n const content = fs.readFileSync(\n path.join(tmpDir, \"profiles\", \"test.json\"),\n \"utf-8\",\n );\n const raw = JSON.parse(content);\n expect(raw.settings.amount).toBe(\"42n\");\n });\n\n test(\"saveSettings and loadProfile round-trip with BigInt\", async () => {\n const schema = Type.Object({ amount: Type.BigInt() });\n const sprinkle = withProfile(new Sprinkle(schema, tmpDir));\n sprinkle.settings = { amount: 99n } as any;\n sprinkle.saveSettings();\n\n const sprinkle2 = new Sprinkle(schema, tmpDir);\n await sprinkle2.loadProfile(\"test\");\n\n expect(sprinkle2.settings).toEqual({ amount: 99n });\n });\n\n test(\"saveSettings preserves defaults\", () => {\n const schema = Type.Object({ name: Type.String() });\n const sprinkle = withProfile(new Sprinkle(schema, tmpDir));\n sprinkle.settings = { name: \"test\" } as any;\n sprinkle.defaults = { string: \"last-input\" };\n\n sprinkle.saveSettings();\n\n const content = fs.readFileSync(\n path.join(tmpDir, \"profiles\", \"test.json\"),\n \"utf-8\",\n );\n const parsed = JSON.parse(content);\n expect(parsed.defaults.string).toBe(\"last-input\");\n });\n\n test(\"loadProfile restores defaults\", async () => {\n const schema = Type.Object({ name: Type.String() });\n const sprinkle = withProfile(new Sprinkle(schema, tmpDir));\n sprinkle.settings = { name: \"test\" } as any;\n sprinkle.defaults = { string: \"remembered\" };\n sprinkle.saveSettings();\n\n const sprinkle2 = new Sprinkle(schema, tmpDir);\n await sprinkle2.loadProfile(\"test\");\n\n expect(sprinkle2.defaults).toEqual({ string: \"remembered\" });\n });\n\n test(\"round-trip with nested objects\", async () => {\n const schema = Type.Object({\n user: Type.Object({\n name: Type.String(),\n score: Type.BigInt(),\n }),\n });\n const sprinkle = withProfile(new Sprinkle(schema, tmpDir));\n sprinkle.settings = { user: { name: \"alice\", score: 100n } } as any;\n sprinkle.saveSettings();\n\n const sprinkle2 = new Sprinkle(schema, tmpDir);\n await sprinkle2.loadProfile(\"test\");\n\n expect(sprinkle2.settings).toEqual({\n user: { name: \"alice\", score: 100n },\n });\n });\n\n test(\"scanProfiles returns profile entries\", () => {\n const schema = Type.Object({ name: Type.String() });\n const sprinkle = withProfile(new Sprinkle(schema, tmpDir), \"alice\");\n sprinkle.profileMeta.name = \"Alice\";\n sprinkle.settings = { name: \"test\" } as any;\n sprinkle.saveSettings();\n\n const profiles = sprinkle.scanProfiles();\n expect(profiles.length).toBe(1);\n expect(profiles[0]!.id).toBe(\"alice\");\n expect(profiles[0]!.meta.name).toBe(\"Alice\");\n });\n\n test(\"sanitizeProfileId handles various inputs\", () => {\n expect(Sprinkle.sanitizeProfileId(\"Mainnet Alice\")).toBe(\"mainnet-alice\");\n expect(Sprinkle.sanitizeProfileId(\"test--profile\")).toBe(\"test-profile\");\n expect(Sprinkle.sanitizeProfileId(\"Hello World!@#$\")).toBe(\"hello-world\");\n expect(Sprinkle.sanitizeProfileId(\" \")).toBe(\"profile\");\n expect(Sprinkle.sanitizeProfileId(\"simple\")).toBe(\"simple\");\n });\n\n test(\"migration converts legacy settings.json to profile\", async () => {\n const schema = Type.Object({ name: Type.String() });\n\n // Write legacy settings.json\n fs.mkdirSync(tmpDir, { recursive: true });\n fs.writeFileSync(\n path.join(tmpDir, \"settings.json\"),\n JSON.stringify({\n settings: { name: \"legacy\" },\n defaults: { string: \"old\" },\n }),\n );\n\n // Create sprinkle and trigger migration\n const sprinkle = new Sprinkle(schema, tmpDir);\n await (sprinkle as any).migrateIfNeeded();\n\n // Check profile was created\n expect(fs.existsSync(path.join(tmpDir, \"profiles\", \"default.json\"))).toBe(\n true,\n );\n // Check legacy file was backed up\n expect(fs.existsSync(path.join(tmpDir, \"settings.json.bak\"))).toBe(true);\n expect(fs.existsSync(path.join(tmpDir, \"settings.json\"))).toBe(false);\n\n // Load the migrated profile\n await sprinkle.loadProfile(\"default\");\n expect(sprinkle.settings).toEqual({ name: \"legacy\" });\n expect(sprinkle.defaults).toEqual({ string: \"old\" });\n expect(sprinkle.profileMeta.name).toBe(\"Default\");\n });\n\n describe(\"currentProfile\", () => {\n test(\"returns null when no profile loaded\", () => {\n const schema = Type.Object({ name: Type.String() });\n const sprinkle = new Sprinkle(schema, tmpDir);\n\n expect(sprinkle.currentProfile).toBeNull();\n });\n\n test(\"returns profile info when loaded\", () => {\n const schema = Type.Object({ name: Type.String() });\n const sprinkle = withProfile(new Sprinkle(schema, tmpDir));\n\n const profile = sprinkle.currentProfile;\n expect(profile).not.toBeNull();\n expect(profile!.id).toBe(\"test\");\n expect(profile!.name).toBe(\"Test\");\n expect(profile!.createdAt).toBeDefined();\n expect(profile!.updatedAt).toBeDefined();\n });\n\n test(\"includes description when present\", () => {\n const schema = Type.Object({ name: Type.String() });\n const sprinkle = withProfile(new Sprinkle(schema, tmpDir));\n sprinkle.profileMeta.description = \"Test profile description\";\n\n const profile = sprinkle.currentProfile;\n expect(profile!.description).toBe(\"Test profile description\");\n });\n\n test(\"has undefined description when not set\", () => {\n const schema = Type.Object({ name: Type.String() });\n const sprinkle = withProfile(new Sprinkle(schema, tmpDir));\n delete sprinkle.profileMeta.description;\n\n const profile = sprinkle.currentProfile;\n expect(profile!.description).toBeUndefined();\n });\n });\n\n describe(\"getDisplaySettings\", () => {\n test(\"masks sensitive fields\", () => {\n const schema = Type.Object({\n name: Type.String(),\n secret: Type.String({ sensitive: true }),\n });\n const sprinkle = withProfile(new Sprinkle(schema, tmpDir));\n sprinkle.settings = { name: \"visible\", secret: \"hidden\" } as any;\n\n const display = sprinkle.getDisplaySettings();\n expect(display.name).toBe(\"visible\");\n expect(display.secret).toBe(\"********\");\n });\n\n test(\"preserves non-sensitive fields\", () => {\n const schema = Type.Object({\n name: Type.String(),\n count: Type.Number(),\n });\n const sprinkle = withProfile(new Sprinkle(schema, tmpDir));\n sprinkle.settings = { name: \"test\", count: 42 } as any;\n\n const display = sprinkle.getDisplaySettings();\n expect(display.name).toBe(\"test\");\n expect(display.count).toBe(42);\n });\n\n test(\"preserves BigInt values\", () => {\n const schema = Type.Object({\n amount: Type.BigInt(),\n secret: Type.String({ sensitive: true }),\n });\n const sprinkle = withProfile(new Sprinkle(schema, tmpDir));\n sprinkle.settings = { amount: 42n, secret: \"hidden\" } as any;\n\n const display = sprinkle.getDisplaySettings();\n expect(display.amount).toBe(42n);\n expect(display.secret).toBe(\"********\");\n });\n\n test(\"masks nested sensitive fields\", () => {\n const schema = Type.Object({\n wallet: Type.Object({\n key: Type.String({ sensitive: true }),\n address: Type.String(),\n }),\n });\n const sprinkle = withProfile(new Sprinkle(schema, tmpDir));\n sprinkle.settings = {\n wallet: { key: \"secret\", address: \"addr1...\" },\n } as any;\n\n const display = sprinkle.getDisplaySettings();\n expect(display.wallet.key).toBe(\"********\");\n expect(display.wallet.address).toBe(\"addr1...\");\n });\n\n test(\"does not mask empty sensitive fields\", () => {\n const schema = Type.Object({\n secret: Type.String({ sensitive: true }),\n });\n const sprinkle = withProfile(new Sprinkle(schema, tmpDir));\n sprinkle.settings = { secret: \"\" } as any;\n\n const display = sprinkle.getDisplaySettings();\n expect(display.secret).toBe(\"\");\n });\n });\n});\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -1,12 +1,20 @@
|
|
|
1
|
-
import { describe, expect, test, mock, beforeEach } from "bun:test";
|
|
1
|
+
import { describe, expect, test, mock, beforeEach, spyOn } from "bun:test";
|
|
2
2
|
import { Sprinkle, Type } from "../index.js";
|
|
3
3
|
import { withProfile } from "./test-helpers.js";
|
|
4
4
|
const mockSelect = mock();
|
|
5
5
|
const mockInput = mock();
|
|
6
|
+
const mockSelectCancellable = mock();
|
|
7
|
+
const mockInputCancellable = mock();
|
|
6
8
|
mock.module("@inquirer/prompts", () => ({
|
|
7
9
|
select: mockSelect,
|
|
8
10
|
input: mockInput
|
|
9
11
|
}));
|
|
12
|
+
mock.module("../prompts.js", () => ({
|
|
13
|
+
selectCancellable: mockSelectCancellable,
|
|
14
|
+
inputCancellable: mockInputCancellable,
|
|
15
|
+
passwordCancellable: mock(),
|
|
16
|
+
confirmCancellable: mock()
|
|
17
|
+
}));
|
|
10
18
|
describe("showMenu", () => {
|
|
11
19
|
let sprinkle;
|
|
12
20
|
beforeEach(() => {
|
|
@@ -18,10 +26,11 @@ describe("showMenu", () => {
|
|
|
18
26
|
name: "test"
|
|
19
27
|
};
|
|
20
28
|
mockSelect.mockClear();
|
|
29
|
+
mockSelectCancellable.mockClear();
|
|
21
30
|
mockInput.mockClear();
|
|
22
31
|
});
|
|
23
32
|
test("exits when Exit is selected on main menu", async () => {
|
|
24
|
-
|
|
33
|
+
mockSelectCancellable.mockResolvedValueOnce(-1);
|
|
25
34
|
const menu = {
|
|
26
35
|
title: "Test Menu",
|
|
27
36
|
items: [{
|
|
@@ -33,7 +42,7 @@ describe("showMenu", () => {
|
|
|
33
42
|
});
|
|
34
43
|
test("executes action and re-shows menu", async () => {
|
|
35
44
|
const actionFn = mock(async () => {});
|
|
36
|
-
|
|
45
|
+
mockSelectCancellable.mockResolvedValueOnce(0).mockResolvedValueOnce(-1);
|
|
37
46
|
const menu = {
|
|
38
47
|
title: "Test Menu",
|
|
39
48
|
items: [{
|
|
@@ -45,7 +54,7 @@ describe("showMenu", () => {
|
|
|
45
54
|
expect(actionFn).toHaveBeenCalledTimes(1);
|
|
46
55
|
});
|
|
47
56
|
test("main menu includes Settings & Profiles submenu and Exit", async () => {
|
|
48
|
-
|
|
57
|
+
mockSelectCancellable.mockResolvedValueOnce(-1);
|
|
49
58
|
const menu = {
|
|
50
59
|
title: "Test",
|
|
51
60
|
items: [{
|
|
@@ -54,7 +63,7 @@ describe("showMenu", () => {
|
|
|
54
63
|
}]
|
|
55
64
|
};
|
|
56
65
|
await sprinkle.showMenu(menu);
|
|
57
|
-
const choices =
|
|
66
|
+
const choices = mockSelectCancellable.mock.calls[0][0].choices;
|
|
58
67
|
const names = choices.map(c => c.name);
|
|
59
68
|
expect(names).toContain("Settings & Profiles");
|
|
60
69
|
expect(names).toContain("Exit");
|
|
@@ -63,7 +72,7 @@ describe("showMenu", () => {
|
|
|
63
72
|
expect(names).not.toContain("Edit settings");
|
|
64
73
|
});
|
|
65
74
|
test("submenu includes Back instead of Exit", async () => {
|
|
66
|
-
|
|
75
|
+
mockSelectCancellable.mockResolvedValueOnce(0).mockResolvedValueOnce(-1).mockResolvedValueOnce(-1);
|
|
67
76
|
const menu = {
|
|
68
77
|
title: "Main",
|
|
69
78
|
items: [{
|
|
@@ -75,7 +84,7 @@ describe("showMenu", () => {
|
|
|
75
84
|
}]
|
|
76
85
|
};
|
|
77
86
|
await sprinkle.showMenu(menu);
|
|
78
|
-
const subChoices =
|
|
87
|
+
const subChoices = mockSelectCancellable.mock.calls[1][0].choices;
|
|
79
88
|
const subNames = subChoices.map(c => c.name);
|
|
80
89
|
expect(subNames).toContain("Back");
|
|
81
90
|
expect(subNames).not.toContain("Exit");
|
|
@@ -84,7 +93,7 @@ describe("showMenu", () => {
|
|
|
84
93
|
sprinkle.settings = {
|
|
85
94
|
name: "original"
|
|
86
95
|
};
|
|
87
|
-
|
|
96
|
+
mockSelectCancellable.mockResolvedValueOnce(0).mockResolvedValueOnce(-1);
|
|
88
97
|
const menu = {
|
|
89
98
|
title: "Test",
|
|
90
99
|
items: [{
|
|
@@ -102,5 +111,82 @@ describe("showMenu", () => {
|
|
|
102
111
|
name: "updated"
|
|
103
112
|
});
|
|
104
113
|
});
|
|
114
|
+
test("Settings submenu includes View settings option", async () => {
|
|
115
|
+
// Select "Settings & Profiles" (-5), then "Back" (-1), then "Exit" (-1)
|
|
116
|
+
mockSelectCancellable.mockResolvedValueOnce(-5) // Settings & Profiles
|
|
117
|
+
.mockResolvedValueOnce(-1) // Back
|
|
118
|
+
.mockResolvedValueOnce(-1); // Exit
|
|
119
|
+
|
|
120
|
+
const menu = {
|
|
121
|
+
title: "Test",
|
|
122
|
+
items: [{
|
|
123
|
+
title: "Action",
|
|
124
|
+
action: async () => {}
|
|
125
|
+
}]
|
|
126
|
+
};
|
|
127
|
+
await sprinkle.showMenu(menu);
|
|
128
|
+
|
|
129
|
+
// Second call is the settings submenu
|
|
130
|
+
const settingsChoices = mockSelectCancellable.mock.calls[1][0].choices;
|
|
131
|
+
const settingsNames = settingsChoices.map(c => c.name);
|
|
132
|
+
expect(settingsNames).toContain("View settings");
|
|
133
|
+
});
|
|
134
|
+
test("View settings displays masked settings", async () => {
|
|
135
|
+
const consoleSpy = spyOn(console, "log").mockImplementation(() => {});
|
|
136
|
+
|
|
137
|
+
// Select "Settings & Profiles" (-5), then "View settings" (0), then "Back" (-1), then "Exit" (-1)
|
|
138
|
+
mockSelectCancellable.mockResolvedValueOnce(-5) // Settings & Profiles
|
|
139
|
+
.mockResolvedValueOnce(0) // View settings (first item)
|
|
140
|
+
.mockResolvedValueOnce(-1) // Back
|
|
141
|
+
.mockResolvedValueOnce(-1); // Exit
|
|
142
|
+
|
|
143
|
+
const menu = {
|
|
144
|
+
title: "Test",
|
|
145
|
+
items: [{
|
|
146
|
+
title: "Action",
|
|
147
|
+
action: async () => {}
|
|
148
|
+
}]
|
|
149
|
+
};
|
|
150
|
+
await sprinkle.showMenu(menu);
|
|
151
|
+
|
|
152
|
+
// Should have called console.log with the settings
|
|
153
|
+
expect(consoleSpy).toHaveBeenCalled();
|
|
154
|
+
const output = consoleSpy.mock.calls[0][0];
|
|
155
|
+
expect(output).toContain("name");
|
|
156
|
+
consoleSpy.mockRestore();
|
|
157
|
+
});
|
|
158
|
+
test("Create profile restores state when FillInStruct is cancelled", async () => {
|
|
159
|
+
// Capture original state
|
|
160
|
+
const originalProfileId = sprinkle.currentProfile?.id;
|
|
161
|
+
const originalSettings = {
|
|
162
|
+
...sprinkle.settings
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
// Settings menu indices: 0=View, 1=Edit, 2=Switch, 3=Create new profile
|
|
166
|
+
mockSelectCancellable.mockResolvedValueOnce(-5) // Settings & Profiles
|
|
167
|
+
.mockResolvedValueOnce(3); // Create new profile
|
|
168
|
+
|
|
169
|
+
// promptProfileMeta: name then description
|
|
170
|
+
mockInputCancellable.mockResolvedValueOnce("New Profile") // Profile name
|
|
171
|
+
.mockResolvedValueOnce("") // Profile description
|
|
172
|
+
.mockResolvedValueOnce(null); // Cancel during FillInStruct (name field)
|
|
173
|
+
|
|
174
|
+
// After cancellation, back out of menus
|
|
175
|
+
mockSelectCancellable.mockResolvedValueOnce(-1) // Back from settings
|
|
176
|
+
.mockResolvedValueOnce(-1); // Exit
|
|
177
|
+
|
|
178
|
+
const menu = {
|
|
179
|
+
title: "Test",
|
|
180
|
+
items: [{
|
|
181
|
+
title: "Action",
|
|
182
|
+
action: async () => {}
|
|
183
|
+
}]
|
|
184
|
+
};
|
|
185
|
+
await sprinkle.showMenu(menu);
|
|
186
|
+
|
|
187
|
+
// State should be restored to original
|
|
188
|
+
expect(sprinkle.currentProfile?.id).toBe(originalProfileId);
|
|
189
|
+
expect(sprinkle.settings).toEqual(originalSettings);
|
|
190
|
+
});
|
|
105
191
|
});
|
|
106
192
|
//# sourceMappingURL=show-menu.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"show-menu.test.js","names":["describe","expect","test","mock","beforeEach","Sprinkle","Type","withProfile","mockSelect","mockInput","module","select","input","sprinkle","schema","Object","name","String","settings","mockClear","mockResolvedValueOnce","menu","title","items","action","showMenu","actionFn","toHaveBeenCalledTimes","choices","calls","names","map","c","toContain","not","subChoices","subNames","s","toEqual"],"sources":["../../../../src/Sprinkle/__tests__/show-menu.test.ts"],"sourcesContent":["import { describe, expect, test, mock, beforeEach } from \"bun:test\";\nimport { Sprinkle, Type, type IMenu } from \"../index.js\";\nimport { withProfile } from \"./test-helpers.js\";\n\nconst mockSelect = mock();\nconst mockInput = mock();\n\nmock.module(\"@inquirer/prompts\", () => ({\n select: mockSelect,\n input: mockInput,\n}));\n\ndescribe(\"showMenu\", () => {\n let sprinkle: Sprinkle<any>;\n\n beforeEach(() => {\n const schema = Type.Object({ name: Type.String() });\n sprinkle = withProfile(new Sprinkle(schema, \"/tmp/test\"));\n sprinkle.settings = { name: \"test\" } as any;\n mockSelect.mockClear();\n mockInput.mockClear();\n });\n\n test(\"exits when Exit is selected on main menu\", async () => {\n mockSelect.mockResolvedValueOnce(-1);\n\n const menu: IMenu<any> = {\n title: \"Test Menu\",\n items: [\n {\n title: \"Action 1\",\n action: async () => {},\n },\n ],\n };\n\n await sprinkle.showMenu(menu);\n });\n\n test(\"executes action and re-shows menu\", async () => {\n const actionFn = mock(async () => {});\n\n mockSelect.mockResolvedValueOnce(0).mockResolvedValueOnce(-1);\n\n const menu: IMenu<any> = {\n title: \"Test Menu\",\n items: [\n {\n title: \"My Action\",\n action: actionFn,\n },\n ],\n };\n\n await sprinkle.showMenu(menu);\n expect(actionFn).toHaveBeenCalledTimes(1);\n });\n\n test(\"main menu includes Settings & Profiles submenu and Exit\", async () => {\n mockSelect.mockResolvedValueOnce(-1);\n\n const menu: IMenu<any> = {\n title: \"Test\",\n items: [{ title: \"Action\", action: async () => {} }],\n };\n\n await sprinkle.showMenu(menu);\n\n const choices = mockSelect.mock.calls[0][0].choices;\n const names = choices.map((c: any) => c.name);\n expect(names).toContain(\"Settings & Profiles\");\n expect(names).toContain(\"Exit\");\n expect(names).not.toContain(\"Switch profile\");\n expect(names).not.toContain(\"Manage profiles\");\n expect(names).not.toContain(\"Edit settings\");\n });\n\n test(\"submenu includes Back instead of Exit\", async () => {\n mockSelect\n .mockResolvedValueOnce(0)\n .mockResolvedValueOnce(-1)\n .mockResolvedValueOnce(-1);\n\n const menu: IMenu<any> = {\n title: \"Main\",\n items: [\n {\n title: \"Sub\",\n items: [{ title: \"Sub Action\", action: async () => {} }],\n },\n ],\n };\n\n await sprinkle.showMenu(menu);\n\n const subChoices = mockSelect.mock.calls[1][0].choices;\n const subNames = subChoices.map((c: any) => c.name);\n expect(subNames).toContain(\"Back\");\n expect(subNames).not.toContain(\"Exit\");\n });\n\n test(\"action returning sprinkle instance saves settings\", async () => {\n sprinkle.settings = { name: \"original\" } as any;\n\n mockSelect.mockResolvedValueOnce(0).mockResolvedValueOnce(-1);\n\n const menu: IMenu<any> = {\n title: \"Test\",\n items: [\n {\n title: \"Update\",\n action: async (s: Sprinkle<any>) => {\n s.settings = { name: \"updated\" } as any;\n return s;\n },\n },\n ],\n };\n\n await sprinkle.showMenu(menu);\n expect(sprinkle.settings).toEqual({ name: \"updated\" });\n });\n});\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"show-menu.test.js","names":["describe","expect","test","mock","beforeEach","spyOn","Sprinkle","Type","withProfile","mockSelect","mockInput","mockSelectCancellable","mockInputCancellable","module","select","input","selectCancellable","inputCancellable","passwordCancellable","confirmCancellable","sprinkle","schema","Object","name","String","settings","mockClear","mockResolvedValueOnce","menu","title","items","action","showMenu","actionFn","toHaveBeenCalledTimes","choices","calls","names","map","c","toContain","not","subChoices","subNames","s","toEqual","settingsChoices","settingsNames","consoleSpy","console","mockImplementation","toHaveBeenCalled","output","mockRestore","originalProfileId","currentProfile","id","originalSettings","toBe"],"sources":["../../../../src/Sprinkle/__tests__/show-menu.test.ts"],"sourcesContent":["import { describe, expect, test, mock, beforeEach, spyOn } from \"bun:test\";\nimport { Sprinkle, Type, type IMenu } from \"../index.js\";\nimport { withProfile } from \"./test-helpers.js\";\n\nconst mockSelect = mock();\nconst mockInput = mock();\nconst mockSelectCancellable = mock();\nconst mockInputCancellable = mock();\n\nmock.module(\"@inquirer/prompts\", () => ({\n select: mockSelect,\n input: mockInput,\n}));\n\nmock.module(\"../prompts.js\", () => ({\n selectCancellable: mockSelectCancellable,\n inputCancellable: mockInputCancellable,\n passwordCancellable: mock(),\n confirmCancellable: mock(),\n}));\n\ndescribe(\"showMenu\", () => {\n let sprinkle: Sprinkle<any>;\n\n beforeEach(() => {\n const schema = Type.Object({ name: Type.String() });\n sprinkle = withProfile(new Sprinkle(schema, \"/tmp/test\"));\n sprinkle.settings = { name: \"test\" } as any;\n mockSelect.mockClear();\n mockSelectCancellable.mockClear();\n mockInput.mockClear();\n });\n\n test(\"exits when Exit is selected on main menu\", async () => {\n mockSelectCancellable.mockResolvedValueOnce(-1);\n\n const menu: IMenu<any> = {\n title: \"Test Menu\",\n items: [\n {\n title: \"Action 1\",\n action: async () => {},\n },\n ],\n };\n\n await sprinkle.showMenu(menu);\n });\n\n test(\"executes action and re-shows menu\", async () => {\n const actionFn = mock(async () => {});\n\n mockSelectCancellable.mockResolvedValueOnce(0).mockResolvedValueOnce(-1);\n\n const menu: IMenu<any> = {\n title: \"Test Menu\",\n items: [\n {\n title: \"My Action\",\n action: actionFn,\n },\n ],\n };\n\n await sprinkle.showMenu(menu);\n expect(actionFn).toHaveBeenCalledTimes(1);\n });\n\n test(\"main menu includes Settings & Profiles submenu and Exit\", async () => {\n mockSelectCancellable.mockResolvedValueOnce(-1);\n\n const menu: IMenu<any> = {\n title: \"Test\",\n items: [{ title: \"Action\", action: async () => {} }],\n };\n\n await sprinkle.showMenu(menu);\n\n const choices = mockSelectCancellable.mock.calls[0][0].choices;\n const names = choices.map((c: any) => c.name);\n expect(names).toContain(\"Settings & Profiles\");\n expect(names).toContain(\"Exit\");\n expect(names).not.toContain(\"Switch profile\");\n expect(names).not.toContain(\"Manage profiles\");\n expect(names).not.toContain(\"Edit settings\");\n });\n\n test(\"submenu includes Back instead of Exit\", async () => {\n mockSelectCancellable\n .mockResolvedValueOnce(0)\n .mockResolvedValueOnce(-1)\n .mockResolvedValueOnce(-1);\n\n const menu: IMenu<any> = {\n title: \"Main\",\n items: [\n {\n title: \"Sub\",\n items: [{ title: \"Sub Action\", action: async () => {} }],\n },\n ],\n };\n\n await sprinkle.showMenu(menu);\n\n const subChoices = mockSelectCancellable.mock.calls[1][0].choices;\n const subNames = subChoices.map((c: any) => c.name);\n expect(subNames).toContain(\"Back\");\n expect(subNames).not.toContain(\"Exit\");\n });\n\n test(\"action returning sprinkle instance saves settings\", async () => {\n sprinkle.settings = { name: \"original\" } as any;\n\n mockSelectCancellable.mockResolvedValueOnce(0).mockResolvedValueOnce(-1);\n\n const menu: IMenu<any> = {\n title: \"Test\",\n items: [\n {\n title: \"Update\",\n action: async (s: Sprinkle<any>) => {\n s.settings = { name: \"updated\" } as any;\n return s;\n },\n },\n ],\n };\n\n await sprinkle.showMenu(menu);\n expect(sprinkle.settings).toEqual({ name: \"updated\" });\n });\n\n test(\"Settings submenu includes View settings option\", async () => {\n // Select \"Settings & Profiles\" (-5), then \"Back\" (-1), then \"Exit\" (-1)\n mockSelectCancellable\n .mockResolvedValueOnce(-5) // Settings & Profiles\n .mockResolvedValueOnce(-1) // Back\n .mockResolvedValueOnce(-1); // Exit\n\n const menu: IMenu<any> = {\n title: \"Test\",\n items: [{ title: \"Action\", action: async () => {} }],\n };\n\n await sprinkle.showMenu(menu);\n\n // Second call is the settings submenu\n const settingsChoices = mockSelectCancellable.mock.calls[1][0].choices;\n const settingsNames = settingsChoices.map((c: any) => c.name);\n expect(settingsNames).toContain(\"View settings\");\n });\n\n test(\"View settings displays masked settings\", async () => {\n const consoleSpy = spyOn(console, \"log\").mockImplementation(() => {});\n\n // Select \"Settings & Profiles\" (-5), then \"View settings\" (0), then \"Back\" (-1), then \"Exit\" (-1)\n mockSelectCancellable\n .mockResolvedValueOnce(-5) // Settings & Profiles\n .mockResolvedValueOnce(0) // View settings (first item)\n .mockResolvedValueOnce(-1) // Back\n .mockResolvedValueOnce(-1); // Exit\n\n const menu: IMenu<any> = {\n title: \"Test\",\n items: [{ title: \"Action\", action: async () => {} }],\n };\n\n await sprinkle.showMenu(menu);\n\n // Should have called console.log with the settings\n expect(consoleSpy).toHaveBeenCalled();\n const output = consoleSpy.mock.calls[0][0];\n expect(output).toContain(\"name\");\n\n consoleSpy.mockRestore();\n });\n\n test(\"Create profile restores state when FillInStruct is cancelled\", async () => {\n // Capture original state\n const originalProfileId = sprinkle.currentProfile?.id;\n const originalSettings = { ...sprinkle.settings };\n\n // Settings menu indices: 0=View, 1=Edit, 2=Switch, 3=Create new profile\n mockSelectCancellable\n .mockResolvedValueOnce(-5) // Settings & Profiles\n .mockResolvedValueOnce(3); // Create new profile\n\n // promptProfileMeta: name then description\n mockInputCancellable\n .mockResolvedValueOnce(\"New Profile\") // Profile name\n .mockResolvedValueOnce(\"\") // Profile description\n .mockResolvedValueOnce(null); // Cancel during FillInStruct (name field)\n\n // After cancellation, back out of menus\n mockSelectCancellable\n .mockResolvedValueOnce(-1) // Back from settings\n .mockResolvedValueOnce(-1); // Exit\n\n const menu: IMenu<any> = {\n title: \"Test\",\n items: [{ title: \"Action\", action: async () => {} }],\n };\n\n await sprinkle.showMenu(menu);\n\n // State should be restored to original\n expect(sprinkle.currentProfile?.id).toBe(originalProfileId);\n expect(sprinkle.settings).toEqual(originalSettings);\n });\n});\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -29,6 +29,27 @@ mock.module("@inquirer/prompts", () => ({
|
|
|
29
29
|
search: mock(async () => "result")
|
|
30
30
|
}));
|
|
31
31
|
|
|
32
|
+
// Mock cancellable prompts (used by TxDialog and other methods)
|
|
33
|
+
mock.module("../prompts.js", () => ({
|
|
34
|
+
selectCancellable: mock(async opts => {
|
|
35
|
+
selectCalls.push(opts);
|
|
36
|
+
const response = selectResponses.shift();
|
|
37
|
+
if (response === undefined) {
|
|
38
|
+
return "cancel";
|
|
39
|
+
}
|
|
40
|
+
return response;
|
|
41
|
+
}),
|
|
42
|
+
inputCancellable: mock(async () => {
|
|
43
|
+
const response = inputResponses.shift();
|
|
44
|
+
return response ?? "";
|
|
45
|
+
}),
|
|
46
|
+
passwordCancellable: mock(async () => "secret"),
|
|
47
|
+
confirmCancellable: mock(async () => {
|
|
48
|
+
const response = confirmResponses.shift();
|
|
49
|
+
return response ?? false;
|
|
50
|
+
})
|
|
51
|
+
}));
|
|
52
|
+
|
|
32
53
|
// Mock clipboardy
|
|
33
54
|
let clipboardContent = "";
|
|
34
55
|
let clipboardShouldFail = false;
|