diff --git a/tests/test_gemini_config.mjs b/tests/test_gemini_config.mjs new file mode 100644 index 0000000..6609e0a --- /dev/null +++ b/tests/test_gemini_config.mjs @@ -0,0 +1,54 @@ +import test from "node:test"; +import assert from "node:assert/strict"; +import { readFile } from "node:fs/promises"; +import vm from "node:vm"; + +const source = await readFile(new URL("../web/gemini_config.js", import.meta.url), "utf8"); +let extension; +vm.runInNewContext(source.replace(/^import .*;\r?$/m, ""), { + app: { registerExtension(value) { extension = value; } }, +}); + +function nodeType() { + return class { + constructor() { + this.widgets = [ + { name: "cache_seed", value: 42, linkedWidgets: [{ value: "randomize" }] }, + { name: "use_cache", value: false }, + { name: "seed", value: 7, linkedWidgets: [{ value: "randomize" }] }, + ]; + } + onNodeCreated() { this.created = true; return "original result"; } + configure(savedControl) { this.widgets[0].linkedWidgets[0].value = savedControl; } + }; +} + +test("new API config nodes default only cache_seed control to fixed", () => { + const Node = nodeType(); + extension.beforeRegisterNodeDef(Node, { name: "SSL_GeminiAPIKeyConfig" }); + const node = new Node(); + assert.equal(node.onNodeCreated(), "original result"); + assert.equal(node.created, true); + assert.equal(node.widgets[0].linkedWidgets[0].value, "fixed"); + assert.equal(node.widgets[0].value, 42); + assert.equal(node.widgets[1].value, false); + assert.equal(node.widgets[2].linkedWidgets[0].value, "randomize"); + // Workflow configuration restores serialized choices after node creation. + node.configure("increment"); + assert.equal(node.widgets[0].linkedWidgets[0].value, "increment"); + node.configure("randomize"); + assert.equal(node.widgets[0].linkedWidgets[0].value, "randomize"); +}); + +test("other node classes and missing seed controls are untouched", () => { + const Other = nodeType(); + extension.beforeRegisterNodeDef(Other, { name: "SSL_GeminiTextPrompt" }); + const other = new Other(); + other.onNodeCreated(); + assert.equal(other.widgets[0].linkedWidgets[0].value, "randomize"); + const Config = nodeType(); + extension.beforeRegisterNodeDef(Config, { name: "SSL_GeminiAPIKeyConfig" }); + const config = new Config(); + config.widgets = []; + assert.doesNotThrow(() => config.onNodeCreated()); +}); diff --git a/tests/test_groups.toml b/tests/test_groups.toml index 62803d1..74344a2 100644 --- a/tests/test_groups.toml +++ b/tests/test_groups.toml @@ -16,3 +16,8 @@ frontend_tests = [ paths = ["__init__.py", "response_schema.py", "web/response_schema.js", "web/response_schema_model.js", "web/response_schema_widgets.js", "web/response_schema_style.js", "package.json", "package-lock.json"] python_tests = ["tests/test_response_schema.py"] frontend_tests = ["tests/test_response_schema_model.mjs", "tests/test_response_schema_widgets.mjs"] + +[groups.gemini_config_frontend] +paths = ["web/gemini_config.js", "tests/test_gemini_config.mjs"] +python_tests = [] +frontend_tests = ["tests/test_gemini_config.mjs"] diff --git a/web/gemini_config.js b/web/gemini_config.js new file mode 100644 index 0000000..d27c647 --- /dev/null +++ b/web/gemini_config.js @@ -0,0 +1,16 @@ +import { app } from "../../scripts/app.js"; + +app.registerExtension({ + name: "GeminiExpandedAPI.ConfigSeedDefault", + beforeRegisterNodeDef(nodeType, nodeData) { + if (nodeData.name !== "SSL_GeminiAPIKeyConfig") return; + const onNodeCreated = nodeType.prototype.onNodeCreated; + nodeType.prototype.onNodeCreated = function () { + const result = onNodeCreated?.apply(this, arguments); + const seed = this.widgets?.find((widget) => widget.name === "cache_seed"); + const control = seed?.linkedWidgets?.[0]; + if (control) control.value = "fixed"; + return result; + }; + }, +});