diff --git a/test-config-manager.js b/test-config-manager.js new file mode 100644 index 0000000..ca464ed --- /dev/null +++ b/test-config-manager.js @@ -0,0 +1,111 @@ +!function(){ + "use strict"; + variables().ADDON_TEST_CONFIG_MGR_STATE = 'ready'; + variables().ADDON_TEST_CONFIG_MGR_ERRORS = []; + Macro.add('touch', { + handler: function() { + "use strict"; + if (!Config.debug) { + return this.error("Shouldn't reach me outside of debug mode."); + } + let errs = variables().ADDON_TEST_CONFIG_MGR_ERRORS; + if (!variables().ADDON_TEST_CONFIG_MGR_STATE === 'loading') { + errs.push("Tried to {{{touch " + this.args.raw + "}}} while not loading a test config."); + return this.error("Only use me during test configuration."); + } + const realpassage = this.contextSelect((ctx) => ctx.name === 'include')?.name ?? passage(); + for(const item of this.args) { + if (Story.has(item)) { + State.create(item); + } else { + errs.push("Can't find passage {{{" + item + "}}} when {{{" + + realpassage + "}}} tried to touch it."); + } + } + } + }); + $(document).on(':passagestart', function(ev) { + "use strict"; + if (!Config.debug) { + return; + } + switch(variables().ADDON_TEST_CONFIG_MGR_STATE) { + case 'ready': + // 1. load candidate config passages + // 2. present UI + // a. "no configs" message + // b. "choose a config" selector and activation button + // notes on activation button: + // 1. silently executes chosen passage + // 2. if the tour stack is empty, done + // 3. if the tour stack is not empty: + // a. push current location + // b. reverse it + // c. set state to "touring" + // 4. reload current page without history entry + let config_passages = Story.lookup('tags', 'test-config'); + if (config_passages.length) { + let dropdown = document.createElement("select"); + dropdown.id = "addon_test_config_mgr_config_picker"; + for (const p of config_passages) { + let op = document.createElement("option"); + op.value = p.title; + op.text = p.title; + dropdown.appendChild(op); + } + let load_button = document.createElement("button"); + load_button.innerText = "Load"; + load_button.onclick = function() { + if (!Config.debug) { + // debugging got disabled, ignore it + return; + } + const orig_passage = passage(); + variables().ADDON_TEST_CONFIG_MGR_STATE="loading"; + const target = document.getElementById("addon_test_config_mgr_config_picker")?.value; + if (!target) { + return; + } + $.wiki("<>"); + variables().ADDON_TEST_CONFIG_MGR_STATE = 'done'; + Engine.play(orig_passage, passage() == orig_passage); + }; + + variables().ADDON_TEST_CONFIG_MGR_TARGETS = config_passages.map((p) => p.title); + $(ev.content).wiki("^^Test Config Manager^^\n" + + "!!!Would you like to load a test config?\n"); + $(ev.content).append(dropdown).append(load_button); + $(ev.content).wiki("\n----\n"); + } else { + $(ev.content).wiki("^^Test Config Manager^^\n" + + "!!!No test configs found.\n" + + "To create a test configuration, create a passage " + + "tagged with {{{test-config}}}, containing test setup " + + "code for a test scenario. You can use the " + + "{{{touch}}} macro inside a test configuration to " + + "add passages to the history during setup.\n" + + "----\n"); + } + variables().ADDON_TEST_CONFIG_MGR_STATE = 'done'; + return; + case 'loading': + // do nothing, we are in the middle of processing a configuration + return; + } + // state should be "done"; if not, that's an error. + if (variables().ADDON_TEST_CONFIG_MGR_STATE !== 'done') { + variables().ADDON_TEST_CONFIG_MGR_ERRORS.push( + "Invalid state: \"$ADDON_TEST_CONFIG_MGR_STATE\""); + } + let errs = variables().ADDON_TEST_CONFIG_MGR_ERRORS; + if (errs.length) { + $(ev.content).wiki("^^Test Config Manager^^\n\n" + + "!!Errors during test configuration.\n\n"); + for (const err of errs) { + $(ev.content).wiki("* " + err + "\n") + } + $(ev.content).wiki("\n----\n"); + variables().ADDON_TEST_CONFIG_MGR_ERRORS = []; + } + }); +}(); \ No newline at end of file