diff --git a/src/core/Recipe.mjs b/src/core/Recipe.mjs index 01438e3a..0a2e217d 100755 --- a/src/core/Recipe.mjs +++ b/src/core/Recipe.mjs @@ -46,7 +46,7 @@ class Recipe { module: OperationConfig[c.op].module, ingValues: c.args, breakpoint: c.breakpoint, - disabled: c.disabled, + disabled: c.disabled || c.op === "Comment", }); }); } diff --git a/src/web/App.mjs b/src/web/App.mjs index cd736e4f..e84363f8 100644 --- a/src/web/App.mjs +++ b/src/web/App.mjs @@ -153,13 +153,6 @@ class App { // Remove all current indicators this.manager.recipe.updateBreakpointIndicator(false); - if (this.getRecipeConfig()[this.progress] && (this.getRecipeConfig()[this.progress].disabled || this.getRecipeConfig()[this.progress].op === "Comment")) { - // Skip disabled operations and comments - // This makes stepping through the recipe work correctly - this.progress++; - return this.bake(step); - } - this.manager.worker.bake( this.getRecipeConfig(), // The configuration of the recipe this.options, // Options set by the user diff --git a/src/web/waiters/WorkerWaiter.mjs b/src/web/waiters/WorkerWaiter.mjs index 296aa956..1cfa39ee 100644 --- a/src/web/waiters/WorkerWaiter.mjs +++ b/src/web/waiters/WorkerWaiter.mjs @@ -477,17 +477,24 @@ class WorkerWaiter { recipeConfig = this.recipeConfig; if (this.step) { + const stepProgress = Number.isInteger(this.app.progress) ? this.app.progress : 0, + breakpointSearchStart = Math.min(stepProgress, recipeConfig.length); + // Remove all breakpoints from the recipe up to progress - if (nextInput.progress !== false) { - for (let i = 0; i < nextInput.progress; i++) { - if ("breakpoint" in recipeConfig[i]) { - delete recipeConfig[i].breakpoint; - } + for (let i = 0; i < breakpointSearchStart; i++) { + if ("breakpoint" in recipeConfig[i]) { + delete recipeConfig[i].breakpoint; } } - // Set a breakpoint at the next operation so we stop baking there - if (recipeConfig[this.app.progress]) recipeConfig[this.app.progress].breakpoint = true; + // Set a breakpoint at the next enabled operation so disabled operations and comments do + // not cause the rest of the recipe to bake in a single step. + for (let i = breakpointSearchStart; i < recipeConfig.length; i++) { + if (!recipeConfig[i].disabled && recipeConfig[i].op !== "Comment") { + recipeConfig[i].breakpoint = true; + break; + } + } } let transferable; diff --git a/tests/browser/04_step.js b/tests/browser/04_step.js new file mode 100644 index 00000000..a0a5a8b4 --- /dev/null +++ b/tests/browser/04_step.js @@ -0,0 +1,87 @@ +/** + * Regression tests for stepping through recipes. + * + * @copyright Crown Copyright + * @license Apache-2.0 + */ + +const utils = require("./browserUtils.js"); + +module.exports = { + before: browser => { + browser + .resizeWindow(1280, 800) + .url(browser.launchUrl) + .useCss() + .waitForElementNotPresent("#preloader", 10000) + .click("#auto-bake-label"); + }, + + "Step skips comments and disabled operations when choosing the next breakpoint": browser => { + const recipeConfig = [ + { + op: "To Upper case", + args: ["All"] + }, + { + op: "Comment", + args: ["Skip while stepping"] + }, + { + op: "ROT13", + args: [true, true, false, 13], + disabled: true + }, + { + op: "To Hex", + args: ["Space", 0] + } + ]; + + utils.setInput(browser, "a", false); + + browser + .urlHash("recipe=" + JSON.stringify(recipeConfig)) + .waitUntil(async function() { + const result = await this.execute(function() { + return document.querySelectorAll("#rec-list li.operation").length; + }); + return result.value === recipeConfig.length; + }, 5000) + .waitForElementNotVisible("#output-loader", 10000) + .click("#step") + .waitForElementNotVisible("#output-loader", 10000) + .waitUntil(async function() { + const result = await this.execute(function() { + return window.app.manager.output.outputEditorView.state.doc.toString(); + }); + return result.value === "A"; + }, 5000); + + browser.execute(function() { + return document.querySelector("#rec-list li.operation.break .op-title")?.textContent; + }, [], function({value}) { + browser.expect(value).to.equal("To Hex"); + }); + + browser + .click("#step") + .waitForElementNotVisible("#output-loader", 10000) + .waitUntil(async function() { + const result = await this.execute(function() { + return window.app.manager.output.outputEditorView.state.doc.toString(); + }); + return result.value === "41"; + }, 5000); + + browser.execute(function() { + return document.querySelector("#rec-list li.operation.break .op-title")?.textContent || null; + }, [], function({value}) { + browser.expect(value).to.equal(null); + }); + }, + + after: browser => { + browser.end(); + } +}; diff --git a/tests/operations/tests/Comment.mjs b/tests/operations/tests/Comment.mjs index 06bf58f2..efee0f03 100644 --- a/tests/operations/tests/Comment.mjs +++ b/tests/operations/tests/Comment.mjs @@ -58,6 +58,25 @@ TestRegister.addTests([ } ] }, + { + name: "Comment: preserves byte array dish type", + input: "00 ff 80 41", + expectedOutput: "00 ff 80 41", + recipeConfig: [ + { + op: "From Hex", + args: ["Space"] + }, + { + op: "Comment", + args: ["Must not translate the byte array to a string"] + }, + { + op: "To Hex", + args: ["Space", 0] + } + ] + }, { name: "Label, Comment: Complex content", input: ALL_BYTES,