How to use runInstance method in storybook-root

Best JavaScript code snippet using storybook-root

runinstance.js

Source:runinstance.js Github

copy

Full Screen

1const chai = require('chai');2const chaiAsPromised = require("chai-as-promised");3const expect = chai.expect;4const assert = chai.assert;5const util = require('util');6const Step = require('../../src/step.js');7const Branch = require('../../src/branch.js');8const Tree = require('../../src/tree.js');9const Runner = require('../../src/runner.js');10const RunInstance = require('../../src/runinstance.js');11chai.use(chaiAsPromised);12describe("RunInstance", () => {13 describe("run()", () => {14 context("generic tests", () => {15 it("runs a branch it pulls from the tree", async () => {16 let tree = new Tree();17 tree.parseIn(`18A -19 B {20 runInstance.ranStepB = true;21 }22 C {23 runInstance.ranStepC = true;24 }25 `, "file.txt");26 let runner = new Runner();27 runner.init(tree, true);28 let runInstance = new RunInstance(runner);29 await runInstance.run();30 expect(runInstance.ranStepB).to.be.true;31 expect(runInstance.ranStepC).to.be.true;32 });33 it("runs multiple branches it pulls from the tree", async () => {34 let tree = new Tree();35 tree.parseIn(`36A -37 B {38 runInstance.ranStepB = true;39 }40 C {41 runInstance.ranStepC = true;42 }43 D {44 runInstance.ranStepD = true;45 }46 E {47 runInstance.ranStepE = true;48 }49 `, "file.txt");50 let runner = new Runner();51 runner.init(tree, true);52 let runInstance = new RunInstance(runner);53 await runInstance.run();54 expect(runInstance.ranStepB).to.be.true;55 expect(runInstance.ranStepC).to.be.true;56 expect(runInstance.ranStepD).to.be.true;57 expect(runInstance.ranStepE).to.be.true;58 });59 it("clears local and global variables between different branches", async () => {60 let tree = new Tree();61 tree.parseIn(`62First branch -63 {var1}='foo'64 {{var2}}='bar'65Second branch -66 Check the vars {67 runInstance.var1 = getGlobal("var1");68 runInstance.var2 = getLocal("var2");69 }70 `, "file.txt");71 let runner = new Runner();72 runner.init(tree, true);73 let runInstance = new RunInstance(runner);74 await runInstance.run();75 expect(runInstance.var1).to.be.undefined;76 expect(runInstance.var2).to.be.undefined;77 });78 it("resets global vars to their inits from the Runner", async () => {79 let tree = new Tree();80 tree.parseIn(`81Run one at a time - !82 Branch 1 -83 Verify vars84 {x}='33'85 {y}='44'86 Branch 2 -87 Verify vars88* Verify vars {89 if(x == '11' && y == '22' && getGlobal('x') == '11' && getGlobal('y') == '22') {90 runInstance.signOffs.push(true);91 }92}93 `, "file.txt");94 let runner = new Runner();95 runner.init(tree, true);96 runner.globalInit = {97 x: '11',98 y: '22'99 }100 let runInstance = new RunInstance(runner);101 runInstance.signOffs = [];102 await runInstance.run();103 expect(runInstance.signOffs).to.have.lengthOf(2);104 expect(runInstance.signOffs[0]).to.be.true;105 expect(runInstance.signOffs[1]).to.be.true;106 });107 });108 context("failures", () => {109 it("handles a step that fails but doesn't end the branch", async () => {110 let tree = new Tree();111 tree.parseIn(`112A -113 B {114 runInstance.ranStepB = true;115 let e = new Error("oops");116 e.continue = true;117 throw e;118 }119 C {120 runInstance.ranStepC = true;121 }122 `, "file.txt");123 let runner = new Runner();124 runner.init(tree, true);125 let runInstance = new RunInstance(runner);126 await runInstance.run();127 expect(runInstance.ranStepB).to.be.true;128 expect(runInstance.ranStepC).to.be.true;129 expect(tree.branches[0].isFailed).to.be.true;130 });131 it("handles a step that fails and ends the branch", async () => {132 let tree = new Tree();133 tree.parseIn(`134A -135 B {136 runInstance.ranStepB = true;137 throw new Error("oops");138 }139 C {140 runInstance.ranStepC = true;141 }142 `, "file.txt");143 let runner = new Runner();144 runner.init(tree, true);145 let runInstance = new RunInstance(runner);146 await runInstance.run();147 expect(runInstance.ranStepB).to.be.true;148 expect(runInstance.ranStepC).to.be.undefined;149 expect(tree.branches[0].isFailed).to.be.true;150 });151 it("handles one branch that fails and one that passes", async () => {152 let tree = new Tree();153 tree.parseIn(`154A -155 B {156 throw new Error("oops");157 }158 C -159 D -160 E -161 `, "file.txt");162 let runner = new Runner();163 runner.init(tree, true);164 let runInstance = new RunInstance(runner);165 await runInstance.run();166 expect(tree.branches[0].isPassed).to.be.undefined;167 expect(tree.branches[0].isFailed).to.be.true;168 expect(tree.branches[1].isPassed).to.be.true;169 expect(tree.branches[1].isFailed).to.be.undefined;170 });171 });172 context("pause and resume", () => {173 it("handles a ~ step that pauses execution before the step", async () => {174 let tree = new Tree();175 tree.parseIn(`176A -177 B {178 runInstance.ranStepB = true;179 }180 ~ C {181 runInstance.ranStepC = true;182 }183 D {184 runInstance.ranStepD = true;185 }186 `, "file.txt");187 let runner = new Runner();188 runner.init(tree, true);189 let runInstance = new RunInstance(runner);190 await runInstance.run();191 expect(runInstance.ranStepB).to.be.true;192 expect(runInstance.ranStepC).to.be.undefined;193 expect(runInstance.ranStepD).to.be.undefined;194 expect(runInstance.isPaused).to.be.true;195 expect(tree.stepNodeIndex[runInstance.currStep.id].text).to.equal("C");196 expect(tree.branches[0].isPassed).to.be.undefined;197 expect(tree.branches[0].isFailed).to.be.undefined;198 });199 it("handles a ~ step that pauses execution after the step", async () => {200 let tree = new Tree();201 tree.parseIn(`202A -203 B {204 runInstance.ranStepB = true;205 }206 C ~ {207 runInstance.ranStepC = true;208 }209 D {210 runInstance.ranStepD = true;211 }212 `, "file.txt");213 let runner = new Runner();214 runner.init(tree, true);215 let runInstance = new RunInstance(runner);216 await runInstance.run();217 expect(runInstance.ranStepB).to.be.true;218 expect(runInstance.ranStepC).to.be.true;219 expect(runInstance.ranStepD).to.be.undefined;220 expect(runInstance.isPaused).to.be.true;221 expect(tree.stepNodeIndex[runInstance.currStep.id].text).to.equal("C");222 expect(tree.branches[0].isPassed).to.be.undefined;223 expect(tree.branches[0].isFailed).to.be.undefined;224 });225 it("handles a failed step that pauses execution via pauseOnFail", async () => {226 let tree = new Tree();227 tree.parseIn(`228A -229 B {230 runInstance.ranStepB = true;231 }232 C {233 runInstance.ranStepC = true;234 throw new Error("oops");235 }236 D {237 runInstance.ranStepD = true;238 }239 `, "file.txt");240 let runner = new Runner();241 runner.init(tree, true);242 runner.pauseOnFail = true;243 let runInstance = new RunInstance(runner);244 await runInstance.run();245 expect(runInstance.ranStepB).to.be.true;246 expect(runInstance.ranStepC).to.be.true;247 expect(runInstance.ranStepD).to.be.undefined;248 expect(tree.branches[0].isPassed).to.be.undefined;249 expect(tree.branches[0].isFailed).to.be.undefined;250 });251 it("handles a resume from a previous pause, where the current step never ran", async () => {252 let tree = new Tree();253 tree.parseIn(`254A -255 B {256 runInstance.ranStepB = true;257 }258 ~ C {259 runInstance.ranStepC = true;260 }261 D {262 runInstance.ranStepD = true;263 }264 `, "file.txt");265 let runner = new Runner();266 runner.init(tree, true);267 let runInstance = new RunInstance(runner);268 await runInstance.run();269 expect(runInstance.ranStepB).to.be.true;270 expect(runInstance.ranStepC).to.be.undefined;271 expect(runInstance.ranStepD).to.be.undefined;272 expect(tree.branches[0].isPassed).to.be.undefined;273 expect(tree.branches[0].isFailed).to.be.undefined;274 await runInstance.run();275 expect(runInstance.ranStepB).to.be.true;276 expect(runInstance.ranStepC).to.be.true;277 expect(runInstance.ranStepD).to.be.true;278 expect(tree.branches[0].isPassed).to.be.true;279 expect(tree.branches[0].isFailed).to.be.undefined;280 });281 it("handles a resume from a previous pause, where the current step completed", async () => {282 let tree = new Tree();283 tree.parseIn(`284A -285 B {286 runInstance.ranStepB = true;287 }288 C ~ {289 runInstance.doubleRanStepC = (runInstance.ranStepC === true);290 runInstance.ranStepC = true;291 }292 D {293 runInstance.ranStepD = true;294 }295 `, "file.txt");296 let runner = new Runner();297 runner.init(tree, true);298 runner.pauseOnFail = true;299 let runInstance = new RunInstance(runner);300 await runInstance.run();301 expect(runInstance.ranStepB).to.be.true;302 expect(runInstance.ranStepC).to.be.true;303 expect(runInstance.doubleRanStepC).to.be.false;304 expect(runInstance.ranStepD).to.be.undefined;305 await runInstance.run();306 expect(runInstance.ranStepB).to.be.true;307 expect(runInstance.ranStepC).to.be.true;308 expect(runInstance.doubleRanStepC).to.be.false;309 expect(runInstance.ranStepD).to.be.true;310 });311 it("handles a resume from a previous pause, where the current step has ~ before and after itself", async () => {312 let tree = new Tree();313 tree.parseIn(`314A -315 B {316 runInstance.ranStepB = true;317 }318 ~ C ~ {319 runInstance.doubleRanStepC = (runInstance.ranStepC === true);320 runInstance.ranStepC = true;321 }322 D {323 runInstance.ranStepD = true;324 }325 `, "file.txt");326 let runner = new Runner();327 runner.init(tree, true);328 runner.pauseOnFail = true;329 let runInstance = new RunInstance(runner);330 await runInstance.run();331 expect(runInstance.ranStepB).to.be.true;332 expect(runInstance.ranStepC).to.be.undefined;333 expect(runInstance.doubleRanStepC).to.be.undefined;334 expect(runInstance.ranStepD).to.be.undefined;335 await runInstance.run();336 expect(runInstance.ranStepB).to.be.true;337 expect(runInstance.ranStepC).to.be.true;338 expect(runInstance.doubleRanStepC).to.be.false;339 expect(runInstance.ranStepD).to.be.true;340 });341 it("handles a resume from a previous pause, where the current step never ran and is the last step", async () => {342 let tree = new Tree();343 tree.parseIn(`344A {345 runInstance.ranStepA = !runInstance.ranStepA;346}347 B {348 runInstance.ranStepB = !runInstance.ranStepB;349 }350 ~ C {351 runInstance.ranStepC = !runInstance.ranStepC;352 }353*** Before Every Branch {354 runInstance.beforeEveryBranchRan = !runInstance.beforeEveryBranchRan;355}356*** After Every Branch {357 runInstance.afterEveryBranchRan = !runInstance.afterEveryBranchRan;358}359 `, "file.txt");360 let runner = new Runner();361 runner.init(tree, true);362 let runInstance = new RunInstance(runner);363 await runInstance.run();364 expect(runInstance.isPaused).to.be.true;365 expect(runInstance.ranStepA).to.be.true;366 expect(runInstance.ranStepB).to.be.true;367 expect(runInstance.ranStepC).to.be.undefined;368 expect(tree.branches[0].isPassed).to.be.undefined;369 expect(runInstance.afterEveryBranchRan).to.be.undefined;370 expect(runInstance.beforeEveryBranchRan).to.be.true;371 await runInstance.run();372 expect(runInstance.isPaused).to.be.false;373 expect(runInstance.ranStepA).to.be.true;374 expect(runInstance.ranStepB).to.be.true;375 expect(runInstance.ranStepC).to.be.true;376 expect(tree.branches[0].isPassed).to.be.true;377 expect(runInstance.afterEveryBranchRan).to.be.true;378 expect(runInstance.beforeEveryBranchRan).to.be.true;379 });380 it("handles a resume from a previous pause, where the current step completed and is the last step", async () => {381 let tree = new Tree();382 tree.parseIn(`383A {384 runInstance.ranStepA = !runInstance.ranStepA;385}386 B {387 runInstance.ranStepB = !runInstance.ranStepB;388 }389 C ~ {390 runInstance.ranStepC = !runInstance.ranStepC;391 }392*** Before Every Branch {393 runInstance.beforeEveryBranchRan = !runInstance.beforeEveryBranchRan;394}395*** After Every Branch {396 runInstance.afterEveryBranchRan = !runInstance.afterEveryBranchRan;397}398 `, "file.txt");399 let runner = new Runner();400 runner.init(tree, true);401 runner.pauseOnFail = true;402 let runInstance = new RunInstance(runner);403 await runInstance.run();404 expect(runInstance.isPaused).to.be.true;405 expect(runInstance.ranStepA).to.be.true;406 expect(runInstance.ranStepB).to.be.true;407 expect(runInstance.ranStepC).to.be.true;408 expect(runInstance.afterEveryBranchRan).to.be.undefined; // doesn't run After Every Branch until one more runOneStep() call409 expect(runInstance.beforeEveryBranchRan).to.be.true;410 await runInstance.run();411 expect(runInstance.isPaused).to.be.false;412 expect(runInstance.ranStepA).to.be.true;413 expect(runInstance.ranStepB).to.be.true;414 expect(runInstance.ranStepC).to.be.true;415 expect(runInstance.afterEveryBranchRan).to.be.true;416 expect(runInstance.beforeEveryBranchRan).to.be.true;417 });418 it("handles a resume from a previous pause, where the current step completed in error, and is the last step", async () => {419 let tree = new Tree();420 tree.parseIn(`421A {422 runInstance.ranStepA = !runInstance.ranStepA;423}424 B {425 runInstance.ranStepB = !runInstance.ranStepB;426 }427 C {428 runInstance.ranStepC = !runInstance.ranStepC;429 let e = new Error();430 e.continue = true;431 throw e;432 }433*** Before Every Branch {434 runInstance.beforeEveryBranchRan = !runInstance.beforeEveryBranchRan;435}436*** After Every Branch {437 runInstance.afterEveryBranchRan = !runInstance.afterEveryBranchRan;438}439 `, "file.txt");440 let runner = new Runner();441 runner.init(tree, true);442 runner.pauseOnFail = true;443 let runInstance = new RunInstance(runner);444 await runInstance.run();445 expect(runInstance.isPaused).to.be.true;446 expect(runInstance.ranStepA).to.be.true;447 expect(runInstance.ranStepB).to.be.true;448 expect(runInstance.ranStepC).to.be.true;449 expect(tree.branches[0].isFailed).to.be.true;450 expect(runInstance.afterEveryBranchRan).to.be.undefined; // doesn't run After Every Branch until one more runOneStep() call451 expect(runInstance.beforeEveryBranchRan).to.be.true;452 await runInstance.run();453 expect(runInstance.isPaused).to.be.false;454 expect(runInstance.ranStepA).to.be.true;455 expect(runInstance.ranStepB).to.be.true;456 expect(runInstance.ranStepC).to.be.true;457 expect(tree.branches[0].isFailed).to.be.true;458 expect(runInstance.afterEveryBranchRan).to.be.true;459 expect(runInstance.beforeEveryBranchRan).to.be.true;460 });461 it("handles a ~~ step, but doesn't pause", async () => {462 let tree = new Tree();463 tree.parseIn(`464A -465 B {466 runInstance.ranStepB = true;467 }468 ~~ C {469 runInstance.ranStepC = true;470 }471 D {472 runInstance.ranStepD = true;473 }474 `, "file.txt");475 let runner = new Runner();476 runner.init(tree, true);477 let runInstance = new RunInstance(runner);478 await runInstance.run();479 expect(runInstance.ranStepB).to.be.true;480 expect(runInstance.ranStepC).to.be.true;481 expect(runInstance.ranStepD).to.be.true;482 expect(tree.branches[0].isPassed).to.be.true;483 expect(tree.branches[0].isFailed).to.be.undefined;484 });485 it("handles a ~ and ~~ on the same branch, but doesn't pause", async () => {486 let tree = new Tree();487 tree.parseIn(`488A -489 ~ B {490 runInstance.ranStepB = true;491 }492 ~~ C {493 runInstance.ranStepC = true;494 }495 D {496 runInstance.ranStepD = true;497 }498 `, "file.txt");499 let runner = new Runner();500 runner.init(tree, true);501 let runInstance = new RunInstance(runner);502 await runInstance.run();503 expect(runInstance.ranStepB).to.be.true;504 expect(runInstance.ranStepC).to.be.true;505 expect(runInstance.ranStepD).to.be.true;506 expect(tree.branches[0].isPassed).to.be.true;507 expect(tree.branches[0].isFailed).to.be.undefined;508 });509 it("handles a ~ and ~~ on the same step, but doesn't pause", async () => {510 let tree = new Tree();511 tree.parseIn(`512A -513 B {514 runInstance.ranStepB = true;515 }516 ~ ~~ C {517 runInstance.ranStepC = true;518 }519 D {520 runInstance.ranStepD = true;521 }522 `, "file.txt");523 let runner = new Runner();524 runner.init(tree, true);525 let runInstance = new RunInstance(runner);526 await runInstance.run();527 expect(runInstance.ranStepB).to.be.true;528 expect(runInstance.ranStepC).to.be.true;529 expect(runInstance.ranStepD).to.be.true;530 expect(tree.branches[0].isPassed).to.be.true;531 expect(tree.branches[0].isFailed).to.be.undefined;532 });533 });534 context("stops", () => {535 it("handles a stop during a step", async () => {536 let tree = new Tree();537 tree.parseIn(`538Wait 10ms, cause a stop, then wait 10 ms more {539 async function wait10() {540 await new Promise((resolve, reject) => {541 setTimeout(() => {542 resolve();543 }, 10);544 });545 }546 await wait10();547 runInstance.isStopped = true;548 await wait10();549}550 A {551 runInstance.ranStepA = true;552 }553Second branch -554 B {555 runInstance.ranStepB = true;556 }557 `, "file.txt");558 let runner = new Runner();559 runner.init(tree, true);560 let runInstance = new RunInstance(runner);561 await runInstance.run();562 expect(runInstance.isStopped).to.be.true;563 expect(runInstance.ranStepA).to.be.undefined;564 expect(runInstance.ranStepB).to.be.undefined;565 });566 it("throws an error when trying to start a previously stopped RunInstance", async () => {567 let tree = new Tree();568 tree.parseIn(`569Cause a stop {570 runInstance.isStopped = true;571}572 `, "file.txt");573 let runner = new Runner();574 runner.init(tree, true);575 let runInstance = new RunInstance(runner);576 await runInstance.run();577 await expect(runInstance.run()).to.be.rejectedWith("Cannot run a stopped runner");578 });579 });580 context("hooks", () => {581 it("runs a Before Every Branch hook", async () => {582 let tree = new Tree();583 tree.parseIn(`584A -585 B {586 runInstance.ranStepB = true;587 }588 C {589 runInstance.ranStepC = true;590 }591*** Before Every Branch {592 runInstance.beforeEveryBranchRan = true;593 runInstance.nothingElseRanYet = (runInstance.ranStepB !== true);594}595 `, "file.txt");596 let runner = new Runner();597 runner.init(tree, true);598 let runInstance = new RunInstance(runner);599 await runInstance.run();600 expect(runInstance.beforeEveryBranchRan).to.be.true;601 expect(runInstance.nothingElseRanYet).to.be.true;602 expect(runInstance.ranStepB).to.be.true;603 expect(runInstance.ranStepC).to.be.true;604 expect(tree.branches[0].isPassed).to.be.true;605 expect(tree.branches[0].isFailed).to.be.undefined;606 });607 it("runs an After Every Branch hook", async () => {608 let tree = new Tree();609 tree.parseIn(`610A -611 B {612 runInstance.ranStepB = true;613 }614 C {615 runInstance.ranStepC = true;616 }617*** After Every Branch {618 runInstance.afterEveryBranchRan = true;619 runInstance.everythingElseRanAlready = (runInstance.ranStepB === true && runInstance.ranStepC === true);620}621 `, "file.txt");622 let runner = new Runner();623 runner.init(tree, true);624 let runInstance = new RunInstance(runner);625 await runInstance.run();626 expect(runInstance.afterEveryBranchRan).to.be.true;627 expect(runInstance.everythingElseRanAlready).to.be.true;628 expect(runInstance.ranStepB).to.be.true;629 expect(runInstance.ranStepC).to.be.true;630 expect(tree.branches[0].isPassed).to.be.true;631 expect(tree.branches[0].isFailed).to.be.undefined;632 });633 it("runs multiple Before Every Branch and After Every Branch hooks, with multiple branches", async () => {634 let tree = new Tree();635 tree.parseIn(`636A -637 B -638 C -639 D -640 E -641*** Before Every Branch {642 runInstance.count += 1;643}644*** Before Every Branch {645 runInstance.count *= 2;646}647*** After Every Branch {648 runInstance.count += 3;649}650*** After Every Branch {651 runInstance.count *= 4;652}653 `, "file.txt");654 let runner = new Runner();655 runner.init(tree, true);656 let runInstance = new RunInstance(runner);657 runInstance.count = 1;658 await runInstance.run();659 expect(runInstance.count).to.equal(208);660 });661 it("runs After Every Branch hooks even if a branch fails", async () => {662 let tree = new Tree();663 tree.parseIn(`664A -665 B {666 throw new Error("oops");667 }668 C -669 D -670 E -671*** After Every Branch {672 runInstance.count++;673}674*** After Every Branch {675 runInstance.count *= 2;676}677 `, "file.txt");678 let runner = new Runner();679 runner.init(tree, true);680 let runInstance = new RunInstance(runner);681 runInstance.count = 1;682 await runInstance.run();683 expect(runInstance.count).to.equal(10);684 });685 it("handles an error inside a Before Every Branch hook", async () => {686 let tree = new Tree();687 tree.parseIn(`688A -689 B {690 runInstance.ranStepB = true;691 }692 C {693 runInstance.ranStepC = true;694 }695*** Before Every Branch {696 throw new Error("oops");697}698*** After Every Branch {699 runInstance.afterCount++;700}701 `, "file.txt");702 let runner = new Runner();703 runner.init(tree, true);704 let runInstance = new RunInstance(runner);705 runInstance.afterCount = 0;706 await runInstance.run();707 expect(tree.branches[0].error.message).to.equal("oops");708 expect(tree.branches[0].error.filename).to.equal("file.txt");709 expect(tree.branches[0].error.lineNumber).to.equal(12);710 expect(tree.branches[0].isPassed).to.be.undefined;711 expect(tree.branches[0].isFailed).to.be.true;712 expect(tree.branches[1].error.message).to.equal("oops");713 expect(tree.branches[1].error.filename).to.equal("file.txt");714 expect(tree.branches[1].error.lineNumber).to.equal(12);715 expect(tree.branches[1].isPassed).to.be.undefined;716 expect(tree.branches[1].isFailed).to.be.true;717 expect(runInstance.ranStepB).to.be.undefined;718 expect(runInstance.ranStepC).to.be.undefined;719 expect(runInstance.afterCount).to.equal(2); // remaining After Every Branch hooks are still run720 });721 it("handles an error inside an After Every Branch hook", async () => {722 let tree = new Tree();723 tree.parseIn(`724A -725 B {726 runInstance.ranStepB = true;727 }728 C {729 runInstance.ranStepC = true;730 }731*** Before Every Branch {732 runInstance.beforeCount++;733}734*** After Every Branch {735 throw new Error("oops");736}737*** After Every Branch {738 runInstance.afterCount++;739}740 `, "file.txt");741 let runner = new Runner();742 runner.init(tree, true);743 let runInstance = new RunInstance(runner);744 runInstance.afterCount = 0;745 runInstance.beforeCount = 0;746 await runInstance.run();747 expect(tree.branches[0].error.message).to.equal("oops");748 expect(tree.branches[0].error.filename).to.equal("file.txt");749 expect(tree.branches[0].error.lineNumber).to.equal(16);750 expect(tree.branches[0].isPassed).to.be.undefined;751 expect(tree.branches[0].isFailed).to.be.true;752 expect(tree.branches[1].error.message).to.equal("oops");753 expect(tree.branches[1].error.filename).to.equal("file.txt");754 expect(tree.branches[1].error.lineNumber).to.equal(16);755 expect(tree.branches[1].isPassed).to.be.undefined;756 expect(tree.branches[1].isFailed).to.be.true;757 expect(runInstance.ranStepB).to.be.true;758 expect(runInstance.ranStepC).to.be.true;759 expect(runInstance.afterCount).to.equal(2); // remaining After Every Branch hooks are still run760 expect(runInstance.beforeCount).to.equal(2);761 });762 it("handles a stop during a Before Every Branch hook execution", async () => {763 let tree = new Tree();764 tree.parseIn(`765A {766 runInstance.ranStepA = true;767}768B {769 runInstance.ranStepB = true;770}771*** Before Every Branch {772 runInstance.isStopped = true;773 runInstance.beforeCount++;774 // Wait 20 ms775 await new Promise((resolve, reject) => {776 setTimeout(() => {777 resolve();778 }, 20);779 });780}781 `, "file.txt");782 let runner = new Runner();783 runner.init(tree, true);784 let runInstance = new RunInstance(runner);785 runInstance.beforeCount = 0;786 await runInstance.run();787 expect(runInstance.isStopped).to.be.true;788 expect(runInstance.ranStepA).to.be.undefined;789 expect(runInstance.ranStepB).to.be.undefined;790 expect(runInstance.beforeCount).to.equal(1);791 });792 it("handles a stop during an After Every Branch hook execution", async () => {793 let tree = new Tree();794 tree.parseIn(`795A {796 runInstance.ranStepA = true;797}798B {799 runInstance.ranStepB = true;800}801*** After Every Branch {802 runInstance.isStopped = true;803 runInstance.afterCount++;804}805*** After Every Branch {806 runInstance.afterCount++;807}808 `, "file.txt");809 let runner = new Runner();810 runner.init(tree, true);811 let runInstance = new RunInstance(runner);812 runInstance.afterCount = 0;813 await runInstance.run();814 expect(runInstance.isStopped).to.be.true;815 expect(runInstance.ranStepA).to.be.true;816 expect(runInstance.ranStepB).to.be.undefined;817 expect(runInstance.afterCount).to.be.equal(1);818 });819 it("a {var} and {{var}} declared in a branch is accessible in an After Every Branch hook", async () => {820 let tree = new Tree();821 tree.parseIn(`822{var1}='foo'823 {{var2}}='bar'824*** After Every Branch {825 runInstance.var1 = var1;826 runInstance.var2 = var2;827}828 `, "file.txt");829 let runner = new Runner();830 runner.init(tree, true);831 let runInstance = new RunInstance(runner);832 await runInstance.run();833 expect(runInstance.var1).to.equal("foo");834 expect(runInstance.var2).to.equal("bar");835 });836 });837 context("elapsed time", () => {838 it("sets branch.elapsed to how long it took the branch to execute", async () => {839 let tree = new Tree();840 tree.parseIn(`841Wait 20ms {842 await new Promise((resolve, reject) => {843 setTimeout(() => {844 resolve();845 }, 20);846 });847}848 `, "file.txt");849 let runner = new Runner();850 runner.init(tree, true);851 let runInstance = new RunInstance(runner);852 await runInstance.run();853 expect(tree.branches[0].elapsed).to.be.above(15);854 expect(tree.branches[0].elapsed).to.be.below(50);855 expect(tree.branches[0].timeStarted instanceof Date).to.equal(true);856 });857 it("sets branch.elapsed to how long it took the branch to execute when a stop ocurred", async () => {858 let tree = new Tree();859 tree.parseIn(`860Wait '20' ms861 Cause a stop {862 this.isStopped = true;863 }864 Wait '100' ms // we never get here865* Wait {{N}} ms {866 await new Promise((resolve, reject) => {867 setTimeout(() => {868 resolve();869 }, N);870 });871}872 `, "file.txt");873 let runner = new Runner();874 runner.init(tree, true);875 let runInstance = new RunInstance(runner);876 await runInstance.run();877 expect(tree.branches[0].elapsed).to.be.above(15);878 expect(tree.branches[0].elapsed).to.be.below(50);879 expect(tree.branches[0].timeStarted instanceof Date).to.equal(true);880 });881 it("sets branch.elapsed to -1 when a pause and when a resume occurred", async () => {882 let tree = new Tree();883 tree.parseIn(`884First step -885 Cause a pause {886 throw new Error("oops");887 }888 Third step -889 `, "file.txt");890 let runner = new Runner();891 runner.init(tree, true);892 runner.pauseOnFail = true;893 let runInstance = new RunInstance(runner);894 await runInstance.run();895 expect(tree.branches[0].elapsed).to.equal(-1);896 expect(tree.branches[0].timeStarted instanceof Date).to.equal(true);897 await runInstance.run();898 expect(tree.branches[0].elapsed).to.equal(-1);899 expect(tree.branches[0].timeStarted instanceof Date).to.equal(true);900 });901 });902 });903 describe("runStep()", () => {904 context("generic tests", () => {905 it("executes a textual step", async () => {906 let tree = new Tree();907 tree.parseIn(`908A -909 `, "file.txt");910 let runner = new Runner();911 runner.init(tree, true);912 let runInstance = new RunInstance(runner);913 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);914 expect(tree.branches[0].error).to.equal(undefined);915 expect(tree.branches[0].steps[0].error).to.equal(undefined);916 });917 it("executes a step with a code block", async () => {918 let tree = new Tree();919 tree.parseIn(`920A {921 runInstance.flag = true;922}923 `, "file.txt");924 let runner = new Runner();925 runner.init(tree, true);926 let runInstance = new RunInstance(runner);927 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);928 expect(runInstance.flag).to.equal(true);929 expect(tree.branches[0].error).to.equal(undefined);930 expect(tree.branches[0].steps[0].error).to.equal(undefined);931 });932 it("sets step.elapsed to how long it took step to execute", async () => {933 let tree = new Tree();934 tree.stepDataMode = 'all';935 tree.parseIn(`936Wait 20ms {937 await new Promise((resolve, reject) => {938 setTimeout(() => {939 resolve();940 }, 20);941 });942}943 `, "file.txt");944 let runner = new Runner();945 runner.init(tree, true);946 let runInstance = new RunInstance(runner);947 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);948 expect(tree.branches[0].steps[0].elapsed).to.be.above(15);949 expect(tree.branches[0].steps[0].elapsed).to.be.below(50);950 expect(tree.branches[0].steps[0].timeStarted instanceof Date).to.equal(true);951 });952 it("a persistent variable set in one RunInstance is accessible in another RunInstance", async () => {953 let tree = new Tree();954 let runner = new Runner();955 runner.init(tree, true);956 let runInstance1 = new RunInstance(runner);957 let runInstance2 = new RunInstance(runner);958 runInstance1.setPersistent("foo", "bar");959 expect(runInstance2.getPersistent("foo")).to.equal("bar");960 });961 it("throws an error when a non-object is thrown inside a step", async () => {962 let tree = new Tree();963 tree.stepDataMode = 'all';964 tree.parseIn(`965Step {966 throw 5;967}968 `, "file.txt");969 let runner = new Runner();970 runner.init(tree, true);971 let runInstance = new RunInstance(runner);972 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);973 expect(tree.branches[0].steps[0].error.message).to.equal(`A non-object was thrown inside this step. Only objects can be thrown.`);974 });975 it("handles a step timeout", async () => {976 let tree = new Tree();977 tree.parseIn(`978Set step timeout to 10 ms {979 setStepTimeout(0.01);980}981 This step times out {982 await new Promise(res => setTimeout(res, 20)); // wait 20 ms983 }984 `, "file.txt");985 let runner = new Runner();986 runner.init(tree, true);987 let runInstance = new RunInstance(runner);988 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);989 await runInstance.runStep(tree.branches[0].steps[1], tree.branches[0], false);990 expect(tree.branches[0].error).to.equal(undefined);991 expect(tree.branches[0].steps[0].error).to.equal(undefined);992 expect(tree.branches[0].steps[1].error.message).to.equal("Timeout of 0.01s exceeded");993 expect(tree.branches[0].steps[1].error.filename).to.equal("file.txt");994 expect(tree.branches[0].steps[1].error.lineNumber).to.equal(5);995 });996 });997 context("functions", () => {998 it("executes a function call with no {{variables}} in its function declaration", async () => {999 let tree = new Tree();1000 tree.parseIn(`1001F1002* F {1003 runInstance.flag = true;1004}1005 `, "file.txt");1006 let runner = new Runner();1007 runner.init(tree, true);1008 let runInstance = new RunInstance(runner);1009 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);1010 expect(runInstance.flag).to.equal(true);1011 expect(tree.branches[0].error).to.equal(undefined);1012 expect(tree.branches[0].steps[0].error).to.equal(undefined);1013 });1014 it("executes a function call with {{variables}} in its function declaration, passing in 'strings'", async () => {1015 let tree = new Tree();1016 tree.stepDataMode = 'all';1017 tree.parseIn(`1018My 'foo' Function 'bar'1019* My {{one}} Function {{two}} {1020 runInstance.one = one;1021 runInstance.two = two;1022}1023 `, "file.txt");1024 let runner = new Runner();1025 runner.init(tree, true);1026 let runInstance = new RunInstance(runner);1027 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);1028 expect(runInstance.one).to.equal("foo");1029 expect(runInstance.two).to.equal("bar");1030 expect(tree.branches[0].error).to.equal(undefined);1031 expect(tree.branches[0].steps[0].error).to.equal(undefined);1032 expect(tree.branches[0].steps[0].log).to.eql([1033 {text: "Function parameter {{one}} is `foo`"},1034 {text: "Function parameter {{two}} is `bar`"}1035 ]);1036 });1037 it("executes a function call with {{variables}} in its function declaration, passing in \"strings\"", async () => {1038 let tree = new Tree();1039 tree.stepDataMode = 'all';1040 tree.parseIn(`1041"foo" My "bar" Function 'blah\\n'1042* {{first}} My {{second}} Function {{third}} {1043 runInstance.first = first;1044 runInstance.second = second;1045 runInstance.third = third;1046}1047 `, "file.txt");1048 let runner = new Runner();1049 runner.init(tree, true);1050 let runInstance = new RunInstance(runner);1051 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);1052 expect(runInstance.first).to.equal("foo");1053 expect(runInstance.second).to.equal("bar");1054 expect(runInstance.third).to.equal("blah\n");1055 expect(tree.branches[0].error).to.equal(undefined);1056 expect(tree.branches[0].steps[0].error).to.equal(undefined);1057 expect(tree.branches[0].steps[0].log).to.eql([1058 {text: "Function parameter {{first}} is `foo`"},1059 {text: "Function parameter {{second}} is `bar`"},1060 {text: "Function parameter {{third}} is `blah\n`"}1061 ]);1062 });1063 it("executes a function call with {{variables}} in its function declaration, passing in {variables}", async () => {1064 let tree = new Tree();1065 tree.parseIn(`1066My {A} Function { b }1067* My {{one}} Function {{two}} {1068 runInstance.one = one;1069 runInstance.two = two;1070}1071 `, "file.txt");1072 let runner = new Runner();1073 runner.init(tree, true);1074 let runInstance = new RunInstance(runner);1075 runInstance.global.A = "foo";1076 runInstance.global.b = "bar";1077 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);1078 expect(runInstance.one).to.equal("foo");1079 expect(runInstance.two).to.equal("bar");1080 expect(tree.branches[0].error).to.equal(undefined);1081 expect(tree.branches[0].steps[0].error).to.equal(undefined);1082 });1083 it("executes a function call with {{variables}} in its function declaration, passing in {variables} set to js objects", async () => {1084 let tree = new Tree();1085 tree.stepDataMode = 'all';1086 tree.parseIn(`1087Set vars {1088 setGlobal("A", {foo:"bar"});1089}1090 My Function { A }1091* My Function {{X}} {1092 runInstance.one = X;1093}1094 `, "file.txt");1095 let runner = new Runner();1096 runner.init(tree, true);1097 let runInstance = new RunInstance(runner);1098 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);1099 await runInstance.runStep(tree.branches[0].steps[1], tree.branches[0], false);1100 expect(runInstance.one).to.eql({foo:"bar"});1101 expect(tree.branches[0].steps[1].log[0]).to.eql( {text: "Function parameter {{X}} is [object Object]"} );1102 });1103 it("executes a function call with {{variables}} in its function declaration, passing in {{variables}}", async () => {1104 let tree = new Tree();1105 tree.parseIn(`1106My {{A}} Function {{ b }} { a B c }1107* My {{one}} Function {{two}} {{three}} {1108 runInstance.one = one;1109 runInstance.two = two;1110 runInstance.three = three;1111}1112 `, "file.txt");1113 let runner = new Runner();1114 runner.init(tree, true);1115 let runInstance = new RunInstance(runner);1116 runInstance.local.A = "foo";1117 runInstance.local.b = "bar";1118 runInstance.global["a B c"] = "blah";1119 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);1120 expect(runInstance.one).to.equal("foo");1121 expect(runInstance.two).to.equal("bar");1122 expect(runInstance.three).to.equal("blah");1123 expect(tree.branches[0].error).to.equal(undefined);1124 expect(tree.branches[0].steps[0].error).to.equal(undefined);1125 });1126 it("executes a function call with {{variables}} in its function declaration, passing in 'strings containing {variables}'", async () => {1127 let tree = new Tree();1128 tree.parseIn(`1129My '{A} and { b }' Function '{b}'1130* My {{one}} Function {{two}} {1131 runInstance.one = one;1132 runInstance.two = two;1133}1134 `, "file.txt");1135 let runner = new Runner();1136 runner.init(tree, true);1137 let runInstance = new RunInstance(runner);1138 runInstance.global.A = "foo";1139 runInstance.global.b = "b\"a'r";1140 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);1141 expect(runInstance.one).to.equal("foo and b\"a'r");1142 expect(runInstance.two).to.equal("b\"a'r");1143 expect(tree.branches[0].error).to.equal(undefined);1144 expect(tree.branches[0].steps[0].error).to.equal(undefined);1145 });1146 it("executes a function call with {{variables}} in its function declaration, passing in \"strings containing {{variables}}\"", async () => {1147 let tree = new Tree();1148 tree.parseIn(`1149My "{A} and { b }" Function "{b}"1150* My {{one}} Function {{two}} {1151 runInstance.one = one;1152 runInstance.two = two;1153}1154 `, "file.txt");1155 let runner = new Runner();1156 runner.init(tree, true);1157 let runInstance = new RunInstance(runner);1158 runInstance.global.A = "foo";1159 runInstance.global.b = "b\"a'r";1160 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);1161 expect(runInstance.one).to.equal("foo and b\"a'r");1162 expect(runInstance.two).to.equal("b\"a'r");1163 expect(tree.branches[0].error).to.equal(undefined);1164 expect(tree.branches[0].steps[0].error).to.equal(undefined);1165 });1166 it("executes a function call with {{variables}} in its function declaration, passing in [strings]", async () => {1167 let tree = new Tree();1168 tree.parseIn(`1169My [4th 'Login' button next to 'something'] Function [ big link ]1170* My {{one}} Function {{two}} {1171 runInstance.one = one;1172 runInstance.two = two;1173}1174 `, "file.txt");1175 let runner = new Runner();1176 runner.init(tree, true);1177 let runInstance = new RunInstance(runner);1178 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);1179 expect(runInstance.one).to.equal("4th 'Login' button next to 'something'");1180 expect(runInstance.two).to.equal(" big link ");1181 expect(tree.branches[0].error).to.equal(undefined);1182 expect(tree.branches[0].steps[0].error).to.equal(undefined);1183 });1184 it("executes a function call with {{variables}} in its function declaration, passing in [strings containing {variables}]", async () => {1185 let tree = new Tree();1186 tree.parseIn(`1187My [{{N}}th 'Login {{A}}' {b} next to '{{ C }}'] Function [ big { d d } ]1188* My {{one}} Function {{two}} {1189 runInstance.one = one;1190 runInstance.two = two;1191}1192 `, "file.txt");1193 let runner = new Runner();1194 runner.init(tree, true);1195 let runInstance = new RunInstance(runner);1196 runInstance.local.A = "sign";1197 runInstance.global.b = "small button";1198 runInstance.local.C = "lots of CATS!";1199 runInstance.local.N = 14;1200 runInstance.global["d d"] = "link";1201 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);1202 expect(runInstance.one).to.equal("14th 'Login sign' small button next to 'lots of CATS!'");1203 expect(runInstance.two).to.equal(" big link ");1204 expect(tree.branches[0].error).to.equal(undefined);1205 expect(tree.branches[0].steps[0].error).to.equal(undefined);1206 });1207 it("executes a function call with {{variables}} in its function declaration, passing in 'strings', \"strings\", [strings], {variables}, {{variables}}, including strings with variables inside", async () => {1208 let tree = new Tree();1209 tree.parseIn(`1210My 'first' Function "second" [third] { four th} Is {{fifth}} Here! "{sixth} six '6' \\\"66\\\"" [{{seventh}} seven 'th']1211* My {{one}} Function {{two}} {{three}} {{fo ur}} Is {{five}} Here! {{six}} {{seven}} {1212 runInstance.one = one;1213 runInstance.two = two;1214 runInstance.three = three;1215 runInstance.four = getLocal("fo ur");1216 runInstance.five = five;1217 runInstance.six = six;1218 runInstance.seven = seven;1219}1220 `, "file.txt");1221 let runner = new Runner();1222 runner.init(tree, true);1223 let runInstance = new RunInstance(runner);1224 runInstance.global["four th"] = "4";1225 runInstance.local["fifth"] = "5";1226 runInstance.global["sixth"] = "6";1227 runInstance.local["seventh"] = "7";1228 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);1229 expect(runInstance.one).to.equal("first");1230 expect(runInstance.two).to.equal("second");1231 expect(runInstance.three).to.equal("third");1232 expect(runInstance.four).to.equal("4");1233 expect(runInstance.five).to.equal("5");1234 expect(runInstance.six).to.equal("6 six '6' \"66\"");1235 expect(runInstance.seven).to.equal("7 seven 'th'");1236 expect(tree.branches[0].error).to.equal(undefined);1237 expect(tree.branches[0].steps[0].error).to.equal(undefined);1238 });1239 it("executes a function call with {{variables}} in its function declaration, that has no code block, passing in 'strings', \"strings\", [strings], {variables}, {{variables}}, including strings with variables inside", async () => {1240 let tree = new Tree();1241 tree.parseIn(`1242My 'first' Function "second" [third] { four th} Is {{fifth}} Here! "{sixth} six '6' \\\"66\\\"" [{{seventh}} seven 'th']1243* My {{one}} Function {{two}} {{three}} {{fo ur}} Is {{five}} Here! {{six}} {{seven}}1244 {A}='{{one}}', {B}='{{two}}'1245 {C}='{{three}}'1246 { D } = '{{ fo ur }}', {E}='{{five}}'1247 ..1248 {F}='{{six}}'1249 {G}='{{seven}}'1250 Final step {1251 runInstance.one = getLocal("one");1252 runInstance.two = two;1253 runInstance.three = three;1254 runInstance.four = getLocal("fo ur");1255 runInstance.five = five;1256 runInstance.six = six;1257 runInstance.seven = seven;1258 }1259 `, "file.txt");1260 let runner = new Runner();1261 runner.init(tree, true);1262 let runInstance = new RunInstance(runner);1263 runInstance.global["four th"] = "4";1264 runInstance.local["fifth"] = "5";1265 runInstance.global["sixth"] = "6";1266 runInstance.local["seventh"] = "7";1267 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);1268 expect(runInstance.getLocal("one")).to.equal("first");1269 expect(runInstance.getLocal("two")).to.equal("second");1270 expect(runInstance.getLocal("three")).to.equal("third");1271 expect(runInstance.getLocal("fo ur")).to.equal("4");1272 expect(runInstance.getLocal("five")).to.equal("5");1273 expect(runInstance.getLocal("six")).to.equal("6 six '6' \"66\"");1274 expect(runInstance.getLocal("seven")).to.equal("7 seven 'th'");1275 await runInstance.runStep(tree.branches[0].steps[1], tree.branches[0], false);1276 expect(runInstance.getLocal("one")).to.equal("first");1277 expect(runInstance.getLocal("two")).to.equal("second");1278 expect(runInstance.getLocal("three")).to.equal("third");1279 expect(runInstance.getLocal("fo ur")).to.equal("4");1280 expect(runInstance.getLocal("five")).to.equal("5");1281 expect(runInstance.getLocal("six")).to.equal("6 six '6' \"66\"");1282 expect(runInstance.getLocal("seven")).to.equal("7 seven 'th'");1283 await runInstance.runStep(tree.branches[0].steps[2], tree.branches[0], false);1284 expect(runInstance.getLocal("one")).to.equal("first");1285 expect(runInstance.getLocal("two")).to.equal("second");1286 expect(runInstance.getLocal("three")).to.equal("third");1287 expect(runInstance.getLocal("fo ur")).to.equal("4");1288 expect(runInstance.getLocal("five")).to.equal("5");1289 expect(runInstance.getLocal("six")).to.equal("6 six '6' \"66\"");1290 expect(runInstance.getLocal("seven")).to.equal("7 seven 'th'");1291 await runInstance.runStep(tree.branches[0].steps[3], tree.branches[0], false);1292 expect(runInstance.getLocal("one")).to.equal("first");1293 expect(runInstance.getLocal("two")).to.equal("second");1294 expect(runInstance.getLocal("three")).to.equal("third");1295 expect(runInstance.getLocal("fo ur")).to.equal("4");1296 expect(runInstance.getLocal("five")).to.equal("5");1297 expect(runInstance.getLocal("six")).to.equal("6 six '6' \"66\"");1298 expect(runInstance.getLocal("seven")).to.equal("7 seven 'th'");1299 await runInstance.runStep(tree.branches[0].steps[4], tree.branches[0], false);1300 expect(runInstance.getLocal("one")).to.equal("first");1301 expect(runInstance.getLocal("two")).to.equal("second");1302 expect(runInstance.getLocal("three")).to.equal("third");1303 expect(runInstance.getLocal("fo ur")).to.equal("4");1304 expect(runInstance.getLocal("five")).to.equal("5");1305 expect(runInstance.getLocal("six")).to.equal("6 six '6' \"66\"");1306 expect(runInstance.getLocal("seven")).to.equal("7 seven 'th'");1307 await runInstance.runStep(tree.branches[0].steps[5], tree.branches[0], false);1308 expect(runInstance.getGlobal("A")).to.equal("first");1309 expect(runInstance.getGlobal("B")).to.equal("second");1310 expect(runInstance.getGlobal("C")).to.equal("third");1311 expect(runInstance.getGlobal("D")).to.equal("4");1312 expect(runInstance.getGlobal("E")).to.equal("5");1313 expect(runInstance.getGlobal("F")).to.equal("6 six '6' \"66\"");1314 expect(runInstance.getGlobal("G")).to.equal("7 seven 'th'");1315 await runInstance.runStep(tree.branches[0].steps[6], tree.branches[0], false);1316 expect(runInstance.getGlobal("A")).to.equal("first");1317 expect(runInstance.getGlobal("B")).to.equal("second");1318 expect(runInstance.getGlobal("C")).to.equal("third");1319 expect(runInstance.getGlobal("D")).to.equal("4");1320 expect(runInstance.getGlobal("E")).to.equal("5");1321 expect(runInstance.getGlobal("F")).to.equal("6 six '6' \"66\"");1322 expect(runInstance.getGlobal("G")).to.equal("7 seven 'th'");1323 expect(runInstance.one).to.equal("first");1324 expect(runInstance.two).to.equal("second");1325 expect(runInstance.three).to.equal("third");1326 expect(runInstance.four).to.equal("4");1327 expect(runInstance.five).to.equal("5");1328 expect(runInstance.six).to.equal("6 six '6' \"66\"");1329 expect(runInstance.seven).to.equal("7 seven 'th'");1330 expect(tree.branches[0].error).to.equal(undefined);1331 expect(tree.branches[0].steps[0].error).to.equal(undefined);1332 });1333 it("executes a function call where {variables} are passed in and are only set in a later step, which is in format {var}='string'", async () => {1334 let tree = new Tree();1335 tree.parseIn(`1336My {var:} Function1337 {var} = 'foobar'1338* My {{one}} Function {1339 runInstance.one = one;1340}1341 `, "file.txt");1342 let runner = new Runner();1343 runner.init(tree, true);1344 let runInstance = new RunInstance(runner);1345 runInstance.currBranch = tree.branches[0];1346 runInstance.currStep = tree.branches[0].steps[0];1347 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);1348 expect(runInstance.one).to.equal("foobar");1349 expect(tree.branches[0].error).to.equal(undefined);1350 expect(tree.branches[0].steps[0].error).to.equal(undefined);1351 });1352 it("executes a function call where {variables} are passed in and are only set in a later step, which is a synchronous code block", async () => {1353 let tree = new Tree();1354 tree.parseIn(`1355My {var:} Function1356 {var} = Set that var {1357 return 'foobar';1358 }1359* My {{one}} Function {1360 runInstance.one = one;1361}1362 `, "file.txt");1363 let runner = new Runner();1364 runner.init(tree, true);1365 let runInstance = new RunInstance(runner);1366 runInstance.currBranch = tree.branches[0];1367 runInstance.currStep = tree.branches[0].steps[0];1368 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);1369 expect(runInstance.one).to.equal("foobar");1370 expect(tree.branches[0].error).to.equal(undefined);1371 expect(tree.branches[0].steps[0].error).to.equal(undefined);1372 });1373 it("executes a function call has a {variable} passed in and it is only set in a later step, which is an asynchronous code block", async () => {1374 let tree = new Tree();1375 tree.parseIn(`1376My {var:} Function1377 {var} = Set that var {1378 return new Promise((resolve, reject) => {});1379 }1380* My {{one}} Function {1381 runInstance.one = one;1382}1383 `, "file.txt");1384 let runner = new Runner();1385 runner.init(tree, true);1386 let runInstance = new RunInstance(runner);1387 runInstance.currBranch = tree.branches[0];1388 runInstance.currStep = tree.branches[0].steps[0];1389 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);1390 expect(runInstance.one instanceof Promise).to.equal(true);1391 expect(tree.branches[0].error).to.equal(undefined);1392 expect(tree.branches[0].steps[0].error).to.equal(undefined);1393 });1394 it("fails step if a function call has a {variable} passed in and it is never set", async () => {1395 let tree = new Tree();1396 tree.parseIn(`1397My {var} Function1398* My {{one}} Function {1399 runInstance.one = one;1400}1401 `, "file.txt");1402 let runner = new Runner();1403 runner.init(tree, true);1404 let runInstance = new RunInstance(runner);1405 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);1406 expect(tree.branches[0].steps[0].error.message).to.contain("The variable {var} wasn't set, but is needed for this step");1407 expect(tree.branches[0].steps[0].error.filename).to.equal("file.txt");1408 expect(tree.branches[0].steps[0].error.lineNumber).to.equal(2);1409 expect(tree.branches[0].error).to.equal(undefined);1410 });1411 it("executes a function call where 'strings' containing vars are passed in and those vars are only set in a later step, which is in format {var}='string'", async () => {1412 let tree = new Tree();1413 tree.parseIn(`1414My 'so called {var:}' Function1415 {var} = 'foobar'1416* My {{one}} Function {1417 runInstance.one = one;1418}1419 `, "file.txt");1420 let runner = new Runner();1421 runner.init(tree, true);1422 let runInstance = new RunInstance(runner);1423 runInstance.currBranch = tree.branches[0];1424 runInstance.currStep = tree.branches[0].steps[0];1425 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);1426 expect(runInstance.one).to.equal("so called foobar");1427 expect(tree.branches[0].error).to.equal(undefined);1428 expect(tree.branches[0].steps[0].error).to.equal(undefined);1429 });1430 it("executes a function call where 'strings' containing vars are passed in and those vars are only set in a later step, which is a synchronous code block", async () => {1431 let tree = new Tree();1432 tree.parseIn(`1433My 'so called {var :}' Function1434 {var} = Set that var {1435 return 'foobar';1436 }1437* My {{one}} Function {1438 runInstance.one = one;1439}1440 `, "file.txt");1441 let runner = new Runner();1442 runner.init(tree, true);1443 let runInstance = new RunInstance(runner);1444 runInstance.currBranch = tree.branches[0];1445 runInstance.currStep = tree.branches[0].steps[0];1446 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);1447 expect(runInstance.one).to.equal("so called foobar");1448 expect(tree.branches[0].error).to.equal(undefined);1449 expect(tree.branches[0].steps[0].error).to.equal(undefined);1450 });1451 it("fails step if a function call has a 'string' containing a let passed in and that let is only set in a later step, which is an asynchronous code block", async () => {1452 let tree = new Tree();1453 tree.parseIn(`1454My 'so called {var :}' Function1455 {var} = Set that var {1456 return new Promise((resolve, reject) => { resolve('foobar'); });1457 }1458* My {{one}} Function {1459 runInstance.one = one;1460}1461 `, "file.txt");1462 let runner = new Runner();1463 runner.init(tree, true);1464 let runInstance = new RunInstance(runner);1465 runInstance.currBranch = tree.branches[0];1466 runInstance.currStep = tree.branches[0].steps[0];1467 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);1468 expect(tree.branches[0].steps[0].error.message).to.contain("The variable {var :} must be set to a string");1469 expect(tree.branches[0].steps[0].error.filename).to.equal("file.txt");1470 expect(tree.branches[0].steps[0].error.lineNumber).to.equal(2);1471 expect(tree.branches[0].error).to.equal(undefined);1472 });1473 it("fails step if a function call has a 'string' containing a let that is never set", async () => {1474 let tree = new Tree();1475 tree.parseIn(`1476My 'so called {var}' Function1477* My {{one}} Function {1478 runInstance.one = one;1479}1480 `, "file.txt");1481 let runner = new Runner();1482 runner.init(tree, true);1483 let runInstance = new RunInstance(runner);1484 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);1485 expect(tree.branches[0].steps[0].error.message).to.contain("The variable {var} wasn't set, but is needed for this step");1486 expect(tree.branches[0].steps[0].error.filename).to.equal("file.txt");1487 expect(tree.branches[0].steps[0].error.lineNumber).to.equal(2);1488 expect(tree.branches[0].error).to.equal(undefined);1489 });1490 it("executes a function call where the function has no steps inside of it", async () => {1491 let tree = new Tree();1492 tree.parseIn(`1493My Function1494* My Function1495 `, "file.txt");1496 let runner = new Runner();1497 runner.init(tree, true);1498 let runInstance = new RunInstance(runner);1499 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);1500 expect(tree.branches[0].error).to.equal(undefined);1501 expect(tree.branches[0].steps[0].error).to.equal(undefined);1502 });1503 it("executes a function call with only a {{variable}} in its function declaration", async () => {1504 let tree = new Tree();1505 tree.parseIn(`1506'foobar'1507* {{input}} {1508 runInstance.one = input;1509}1510 `, "file.txt");1511 let runner = new Runner();1512 runner.init(tree, true);1513 let runInstance = new RunInstance(runner);1514 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);1515 expect(runInstance.one).to.equal('foobar');1516 expect(tree.branches[0].error).to.equal(undefined);1517 expect(tree.branches[0].steps[0].error).to.equal(undefined);1518 });1519 it("executes a function call with only two {{variables}} in its function declaration", async () => {1520 let tree = new Tree();1521 tree.parseIn(`1522'foo' 'bar'1523* {{A}} {{B}} {1524 runInstance.one = A;1525 runInstance.two = B;1526}1527 `, "file.txt");1528 let runner = new Runner();1529 runner.init(tree, true);1530 let runInstance = new RunInstance(runner);1531 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);1532 expect(runInstance.one).to.equal('foo');1533 expect(runInstance.two).to.equal('bar');1534 expect(tree.branches[0].error).to.equal(undefined);1535 expect(tree.branches[0].steps[0].error).to.equal(undefined);1536 });1537 it("executes a multi-level step block", async () => {1538 let tree = new Tree();1539 tree.parseIn(`1540[1541 F {1542 runInstance.one = true;1543 }1544]1545 `, "file.txt");1546 let runner = new Runner();1547 runner.init(tree, true);1548 let runInstance = new RunInstance(runner);1549 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);1550 await runInstance.runStep(tree.branches[0].steps[1], tree.branches[0], false);1551 expect(runInstance.one).to.equal(true);1552 expect(tree.branches[0].error).to.equal(undefined);1553 expect(tree.branches[0].steps[0].error).to.equal(undefined);1554 expect(tree.branches[0].steps[1].error).to.equal(undefined);1555 });1556 it("doesn't clear out a {{local var}} after a function is called", async () => {1557 let tree = new Tree();1558 tree.parseIn(`1559{{v}}='foobar'1560 F '1'1561 V '{{v}}'1562* F {{n}}1563 G {{n}}1564* G {{n}} {1565}1566* V {{n}} {1567 runInstance.one = n;1568}1569 `, "file.txt");1570 let runner = new Runner();1571 runner.init(tree, true);1572 let runInstance = new RunInstance(runner);1573 runInstance.currBranch = tree.branches[0];1574 runInstance.currStep = tree.branches[0].steps[0];1575 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);1576 runInstance.currStep = tree.branches[0].steps[1];1577 await runInstance.runStep(tree.branches[0].steps[1], tree.branches[0], false);1578 runInstance.currStep = tree.branches[0].steps[2];1579 await runInstance.runStep(tree.branches[0].steps[2], tree.branches[0], false);1580 runInstance.currStep = tree.branches[0].steps[3];1581 await runInstance.runStep(tree.branches[0].steps[3], tree.branches[0], false);1582 expect(runInstance.one).to.equal("foobar");1583 expect(tree.branches[0].error).to.equal(undefined);1584 expect(tree.branches[0].steps[0].error).to.equal(undefined);1585 expect(tree.branches[0].steps[1].error).to.equal(undefined);1586 expect(tree.branches[0].steps[2].error).to.equal(undefined);1587 expect(tree.branches[0].steps[3].error).to.equal(undefined);1588 });1589 });1590 context("passing in {vars}", () => {1591 it("allows {{variables}} passed in through a function call to be accessed by steps inside the function", async () => {1592 let tree = new Tree();1593 tree.parseIn(`1594My {var:} Function1595 {var} = 'foobar'1596* My {{one}} Function1597 Another step {1598 runInstance.one = one;1599 }1600 `, "file.txt");1601 let runner = new Runner();1602 runner.init(tree, true);1603 let runInstance = new RunInstance(runner);1604 runInstance.currBranch = tree.branches[0];1605 runInstance.currStep = tree.branches[0].steps[0];1606 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);1607 runInstance.currStep = tree.branches[0].steps[1];1608 await runInstance.runStep(tree.branches[0].steps[1], tree.branches[0], false);1609 expect(runInstance.one).to.equal("foobar");1610 expect(tree.branches[0].error).to.equal(undefined);1611 expect(tree.branches[0].steps[0].error).to.equal(undefined);1612 expect(tree.branches[0].steps[1].error).to.equal(undefined);1613 });1614 it("allows {{variables}} passed in through a function call to be accessed by the function's code block", async () => {1615 let tree = new Tree();1616 tree.parseIn(`1617My {var:} Function1618 {var} = 'foobar'1619* My {{one}} Function {1620 runInstance.one = one;1621}1622 `, "file.txt");1623 let runner = new Runner();1624 runner.init(tree, true);1625 let runInstance = new RunInstance(runner);1626 runInstance.currBranch = tree.branches[0];1627 runInstance.currStep = tree.branches[0].steps[0];1628 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);1629 expect(runInstance.one).to.equal("foobar");1630 expect(tree.branches[0].error).to.equal(undefined);1631 expect(tree.branches[0].steps[0].error).to.equal(undefined);1632 });1633 it("allows {{variables}} to be accessed through a non-function-call code block", async () => {1634 let tree = new Tree();1635 tree.parseIn(`1636{{var1}} = 'foobar'1637 Another step {1638 runInstance.one = var1;1639 }1640 `, "file.txt");1641 let runner = new Runner();1642 runner.init(tree, true);1643 let runInstance = new RunInstance(runner);1644 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);1645 await runInstance.runStep(tree.branches[0].steps[1], tree.branches[0], false);1646 expect(runInstance.one).to.equal("foobar");1647 expect(tree.branches[0].error).to.equal(undefined);1648 expect(tree.branches[0].steps[0].error).to.equal(undefined);1649 expect(tree.branches[0].steps[1].error).to.equal(undefined);1650 });1651 it("{global} variables passed in retain their value after the end of the function", async () => {1652 let tree = new Tree();1653 tree.parseIn(`1654My 'foo' and 'bar' and 'FU' and 'ba arr' Function1655 Save var values {1656 runInstance.globalOne = g("one");1657 runInstance.globalTwo = g("two");1658 runInstance.globalThree = g("three");1659 runInstance.globalFour = g("four");1660 runInstance.localOne = l("one");1661 runInstance.localTwo = l("two");1662 runInstance.localThree = l("three");1663 runInstance.localFour = l("four");1664 }1665* My {{one}} and {two} and {three} and {{four}} Function {1666 // something1667}1668 `, "file.txt");1669 let runner = new Runner();1670 runner.init(tree, true);1671 let runInstance = new RunInstance(runner);1672 runInstance.currBranch = tree.branches[0];1673 runInstance.currStep = tree.branches[0].steps[0];1674 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);1675 runInstance.currStep = tree.branches[0].steps[1];1676 await runInstance.runStep(tree.branches[0].steps[1], tree.branches[0], false);1677 expect(runInstance.globalOne).to.equal(undefined);1678 expect(runInstance.globalTwo).to.equal("bar");1679 expect(runInstance.globalThree).to.equal("FU");1680 expect(runInstance.globalFour).to.equal(undefined);1681 expect(runInstance.localOne).to.equal(undefined);1682 expect(runInstance.localTwo).to.equal(undefined);1683 expect(runInstance.localThree).to.equal(undefined);1684 expect(runInstance.localFour).to.equal(undefined);1685 expect(tree.branches[0].error).to.equal(undefined);1686 expect(tree.branches[0].steps[0].error).to.equal(undefined);1687 expect(tree.branches[0].steps[1].error).to.equal(undefined);1688 });1689 it("allows {{variables}} passed in through a function call where there is no whitespace between them", async () => {1690 let tree = new Tree();1691 tree.parseIn(`1692GET /api/something?param1='foo'&param2='bar'&param3=blah1693* GET /api/something?param1={{one}}&param2={{two}}&param3=blah {1694 runInstance.one = one;1695 runInstance.two = two;1696}1697 `, "file.txt");1698 let runner = new Runner();1699 runner.init(tree, true);1700 let runInstance = new RunInstance(runner);1701 runInstance.currBranch = tree.branches[0];1702 runInstance.currStep = tree.branches[0].steps[0];1703 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);1704 expect(runInstance.one).to.equal("foo");1705 expect(runInstance.two).to.equal("bar");1706 expect(tree.branches[0].error).to.equal(undefined);1707 expect(tree.branches[0].steps[0].error).to.equal(undefined);1708 });1709 it("allows a {global} variable passed into a function to be accessible by functions declared within, when called in context", async () => {1710 let tree = new Tree();1711 tree.parseIn(`1712Request '6'1713 Verify1714* Request {num} {1715 // do the request1716}1717 * Verify {1718 runInstance.one = num;1719 }1720 `, "file.txt");1721 let runner = new Runner();1722 runner.init(tree, true);1723 let runInstance = new RunInstance(runner);1724 runInstance.currBranch = tree.branches[0];1725 runInstance.currStep = tree.branches[0].steps[0];1726 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);1727 runInstance.currStep = tree.branches[0].steps[1];1728 await runInstance.runStep(tree.branches[0].steps[1], tree.branches[0], false);1729 expect(runInstance.one).to.equal('6');1730 expect(tree.branches[0].error).to.equal(undefined);1731 expect(tree.branches[0].steps[0].error).to.equal(undefined);1732 expect(tree.branches[0].steps[1].error).to.equal(undefined);1733 });1734 it("allows a {global} variable to be accessed within a multi-level step block", async () => {1735 let tree = new Tree();1736 tree.parseIn(`1737{var1}='foobar'1738 [1739 F {1740 runInstance.one = var1;1741 }1742 ]1743 `, "file.txt");1744 let runner = new Runner();1745 runner.init(tree, true);1746 let runInstance = new RunInstance(runner);1747 runInstance.currBranch = tree.branches[0];1748 runInstance.currStep = tree.branches[0].steps[0];1749 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);1750 runInstance.currStep = tree.branches[0].steps[1];1751 await runInstance.runStep(tree.branches[0].steps[1], tree.branches[0], false);1752 runInstance.currStep = tree.branches[0].steps[2];1753 await runInstance.runStep(tree.branches[0].steps[2], tree.branches[0], false);1754 expect(runInstance.one).to.equal('foobar');1755 expect(tree.branches[0].error).to.equal(undefined);1756 expect(tree.branches[0].steps[0].error).to.equal(undefined);1757 expect(tree.branches[0].steps[1].error).to.equal(undefined);1758 expect(tree.branches[0].steps[2].error).to.equal(undefined);1759 });1760 it("ignores {{variables}} inside the text of a textual step", async () => {1761 let tree = new Tree();1762 tree.parseIn(`1763A textual step {{var1}} -1764 {{var1}} = 'foobar'1765 Another textual step {{var2}} -1766 `, "file.txt");1767 let runner = new Runner();1768 runner.init(tree, true);1769 let runInstance = new RunInstance(runner);1770 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);1771 await runInstance.runStep(tree.branches[0].steps[1], tree.branches[0], false);1772 await runInstance.runStep(tree.branches[0].steps[2], tree.branches[0], false);1773 expect(tree.branches[0].error).to.equal(undefined);1774 expect(tree.branches[0].steps[0].error).to.equal(undefined);1775 expect(tree.branches[0].steps[1].error).to.equal(undefined);1776 expect(tree.branches[0].steps[2].error).to.equal(undefined);1777 });1778 it("ignores {{variables}} inside the text of a textual step with a code block, but those {{variables}} are still accessible inside the code block nonetheless", async () => {1779 let tree = new Tree();1780 tree.parseIn(`1781{{var1}} = 'foobar'1782 Another step {{var1}} {1783 runInstance.one = var1;1784 }1785 `, "file.txt");1786 let runner = new Runner();1787 runner.init(tree, true);1788 let runInstance = new RunInstance(runner);1789 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);1790 await runInstance.runStep(tree.branches[0].steps[1], tree.branches[0], false);1791 expect(runInstance.one).to.equal("foobar");1792 expect(tree.branches[0].error).to.equal(undefined);1793 expect(tree.branches[0].steps[0].error).to.equal(undefined);1794 expect(tree.branches[0].steps[1].error).to.equal(undefined);1795 });1796 it("executes a function call where 'string with {var}' is passed in, with another step being {var}='string with apos \' '", async () => {1797 let tree = new Tree();1798 tree.parseIn(`1799My 'string with {var:}' Function1800 {var} = 'string with apos \\\' '1801* My {{one}} Function {1802 runInstance.one = one;1803}1804 `, "file.txt");1805 let runner = new Runner();1806 runner.init(tree, true);1807 let runInstance = new RunInstance(runner);1808 runInstance.currBranch = tree.branches[0];1809 runInstance.currStep = tree.branches[0].steps[0];1810 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);1811 expect(runInstance.one).to.equal("string with string with apos ' ");1812 expect(tree.branches[0].error).to.equal(undefined);1813 expect(tree.branches[0].steps[0].error).to.equal(undefined);1814 });1815 it("executes a function call where 'string with {var}' is passed in, with another step being {var}=\"string with apos ' \"", async () => {1816 let tree = new Tree();1817 tree.parseIn(`1818My 'string with {var :}' Function1819 {var} = "string with apos ' "1820* My {{one}} Function {1821 runInstance.one = one;1822}1823 `, "file.txt");1824 let runner = new Runner();1825 runner.init(tree, true);1826 let runInstance = new RunInstance(runner);1827 runInstance.currBranch = tree.branches[0];1828 runInstance.currStep = tree.branches[0].steps[0];1829 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);1830 expect(runInstance.one).to.equal("string with string with apos ' ");1831 expect(tree.branches[0].error).to.equal(undefined);1832 expect(tree.branches[0].steps[0].error).to.equal(undefined);1833 });1834 it("executes a function call with nothing in its body", async () => {1835 let tree = new Tree();1836 tree.parseIn(`1837My 'foobar' Function1838* My {{one}} Function {1839}1840 `, "file.txt");1841 let runner = new Runner();1842 runner.init(tree, true);1843 let runInstance = new RunInstance(runner);1844 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);1845 expect(runInstance.getLocal("one")).to.equal("foobar");1846 expect(tree.branches[0].error).to.equal(undefined);1847 expect(tree.branches[0].steps[0].error).to.equal(undefined);1848 });1849 it("handles a function declaration where multiple {{variables}} have the same name", async () => {1850 let tree = new Tree();1851 tree.parseIn(`1852My 'foo' Function 'bar'1853* My {{one}} Function {{one}} {1854 runInstance.one = one;1855 runInstance.two = getLocal("one");1856}1857 `, "file.txt");1858 let runner = new Runner();1859 runner.init(tree, true);1860 let runInstance = new RunInstance(runner);1861 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);1862 expect(runInstance.one).to.equal("bar");1863 expect(runInstance.two).to.equal("bar");1864 expect(tree.branches[0].error).to.equal(undefined);1865 expect(tree.branches[0].steps[0].error).to.equal(undefined);1866 });1867 it('step text is accessible via getCurrStepNode()', async () => {1868 let tree = new Tree();1869 tree.parseIn(`1870My 'foo' Function 'bar' other text1871* My {{one}} Function {{two}} other text {1872 runInstance.one = one;1873 runInstance.two = two;1874 runInstance.three = getCurrStepNode().text;1875}1876 `, "file.txt");1877 let runner = new Runner();1878 runner.init(tree, true);1879 let runInstance = new RunInstance(runner);1880 runInstance.currStep = tree.branches[0].steps[0];1881 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);1882 expect(runInstance.one).to.equal("foo");1883 expect(runInstance.two).to.equal("bar");1884 expect(runInstance.three).to.equal("My 'foo' Function 'bar' other text");1885 expect(tree.branches[0].error).to.equal(undefined);1886 expect(tree.branches[0].steps[0].error).to.equal(undefined);1887 });1888 });1889 context("{var}='string'", () => {1890 it("executes a {var} = 'string' step", async () => {1891 let tree = new Tree();1892 tree.parseIn(`1893{var1} = 'foobar'1894 `, "file.txt");1895 let runner = new Runner();1896 runner.init(tree, true);1897 let runInstance = new RunInstance(runner);1898 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);1899 expect(runInstance.getLocal("var1")).to.equal(undefined);1900 expect(runInstance.getGlobal("var1")).to.equal("foobar");1901 expect(runInstance.getPersistent("var1")).to.equal(undefined);1902 expect(tree.branches[0].error).to.equal(undefined);1903 expect(tree.branches[0].steps[0].error).to.equal(undefined);1904 });1905 it("executes a {var} is 'string' step", async () => {1906 let tree = new Tree();1907 tree.parseIn(`1908{var1} is 'foobar'1909 `, "file.txt");1910 let runner = new Runner();1911 runner.init(tree, true);1912 let runInstance = new RunInstance(runner);1913 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);1914 expect(runInstance.getLocal("var1")).to.equal(undefined);1915 expect(runInstance.getGlobal("var1")).to.equal("foobar");1916 expect(runInstance.getPersistent("var1")).to.equal(undefined);1917 expect(tree.branches[0].error).to.equal(undefined);1918 expect(tree.branches[0].steps[0].error).to.equal(undefined);1919 });1920 it("executes a {var} = 'string' step where the string has escaped special chars", async () => {1921 let tree = new Tree();1922 tree.parseIn(`1923{var1} = 'escaped single quote: \\' escaped backslash: \\\\ newline: \\n backslash-n: \\\\n'1924 {var2} = '\\n\\0{var1}\\\\\\b'1925 `, "file.txt");1926 let runner = new Runner();1927 runner.init(tree, true);1928 let runInstance = new RunInstance(runner);1929 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);1930 expect(runInstance.g("var1")).to.equal("escaped single quote: ' escaped backslash: \\ newline: \n backslash-n: \\n");1931 await runInstance.runStep(tree.branches[0].steps[1], tree.branches[0], false);1932 expect(runInstance.g("var2")).to.equal("\n\0escaped single quote: ' escaped backslash: \\ newline: \n backslash-n: \\n\\\b");1933 expect(tree.branches[0].error).to.equal(undefined);1934 expect(tree.branches[0].steps[0].error).to.equal(undefined);1935 expect(tree.branches[0].steps[1].error).to.equal(undefined);1936 });1937 it("executes a {{var}} = 'string' step", async () => {1938 let tree = new Tree();1939 tree.stepDataMode = 'all';1940 tree.parseIn(`1941{{var1}} = 'foobar'1942 `, "file.txt");1943 let runner = new Runner();1944 runner.init(tree, true);1945 let runInstance = new RunInstance(runner);1946 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);1947 expect(runInstance.getLocal("var1")).to.equal("foobar");1948 expect(runInstance.getGlobal("var1")).to.equal(undefined);1949 expect(runInstance.getPersistent("var1")).to.equal(undefined);1950 expect(tree.branches[0].error).to.equal(undefined);1951 expect(tree.branches[0].steps[0].error).to.equal(undefined);1952 expect(tree.branches[0].steps[0].log).to.eql([1953 {text: "Setting {{var1}} to `foobar`"},1954 ]);1955 });1956 it("executes a {var} = \"string\" step", async () => {1957 let tree = new Tree();1958 tree.parseIn(`1959{var1} = "foobar"1960 `, "file.txt");1961 let runner = new Runner();1962 runner.init(tree, true);1963 let runInstance = new RunInstance(runner);1964 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);1965 expect(runInstance.getLocal("var1")).to.equal(undefined);1966 expect(runInstance.getGlobal("var1")).to.equal("foobar");1967 expect(runInstance.getPersistent("var1")).to.equal(undefined);1968 expect(tree.branches[0].error).to.equal(undefined);1969 expect(tree.branches[0].steps[0].error).to.equal(undefined);1970 });1971 it("executes a {var} = [string] step", async () => {1972 let tree = new Tree();1973 tree.parseIn(`1974{var1} = [foobar]1975 `, "file.txt");1976 let runner = new Runner();1977 runner.init(tree, true);1978 let runInstance = new RunInstance(runner);1979 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);1980 expect(runInstance.getLocal("var1")).to.equal(undefined);1981 expect(runInstance.getGlobal("var1")).to.equal("foobar");1982 expect(runInstance.getPersistent("var1")).to.equal(undefined);1983 expect(tree.branches[0].error).to.equal(undefined);1984 expect(tree.branches[0].steps[0].error).to.equal(undefined);1985 });1986 it("executes a {var} = '{other var}' step", async () => {1987 let tree = new Tree();1988 tree.parseIn(`1989..1990{var1} = 'foobar'1991{var2} = '{var1} blah {var3:}'1992{var3} = "bleh"1993 `, "file.txt");1994 let runner = new Runner();1995 runner.init(tree, true);1996 let runInstance = new RunInstance(runner);1997 runInstance.currBranch = tree.branches[0];1998 runInstance.currStep = tree.branches[0].steps[0];1999 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);2000 runInstance.currStep = tree.branches[0].steps[1];2001 await runInstance.runStep(tree.branches[0].steps[1], tree.branches[0], false);2002 runInstance.currStep = tree.branches[0].steps[2];2003 await runInstance.runStep(tree.branches[0].steps[2], tree.branches[0], false);2004 expect(runInstance.getGlobal("var1")).to.equal("foobar");2005 expect(runInstance.getGlobal("var2")).to.equal("foobar blah bleh");2006 expect(runInstance.getGlobal("var3")).to.equal("bleh");2007 expect(tree.branches[0].error).to.equal(undefined);2008 expect(tree.branches[0].steps[0].error).to.equal(undefined);2009 expect(tree.branches[0].steps[1].error).to.equal(undefined);2010 expect(tree.branches[0].steps[2].error).to.equal(undefined);2011 });2012 it("executes a {var1} = '{var2} {{var2}} [something]' step", async () => {2013 let tree = new Tree();2014 tree.stepDataMode = 'all';2015 tree.parseIn(`2016..2017{var1} = 'foobar'2018{var2} = '{var1} blah {{ var2 : }} [something]'2019{{var2}} = "bleh"2020 `, "file.txt");2021 let runner = new Runner();2022 runner.init(tree, true);2023 let runInstance = new RunInstance(runner);2024 runInstance.currBranch = tree.branches[0];2025 runInstance.currStep = tree.branches[0].steps[0];2026 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);2027 runInstance.currStep = tree.branches[0].steps[1];2028 await runInstance.runStep(tree.branches[0].steps[1], tree.branches[0], false);2029 runInstance.currStep = tree.branches[0].steps[2];2030 await runInstance.runStep(tree.branches[0].steps[2], tree.branches[0], false);2031 expect(runInstance.getGlobal("var1")).to.equal("foobar");2032 expect(runInstance.getGlobal("var2")).to.equal("foobar blah bleh [something]");2033 expect(runInstance.getLocal("var2")).to.equal("bleh");2034 expect(tree.branches[0].error).to.equal(undefined);2035 expect(tree.branches[0].steps[0].error).to.equal(undefined);2036 expect(tree.branches[0].steps[1].error).to.equal(undefined);2037 expect(tree.branches[0].steps[2].error).to.equal(undefined);2038 expect(tree.branches[0].steps[1].log[1]).to.eql( {text: "Setting {var2} to `foobar blah bleh [something]`"} );2039 });2040 it("executes a {var1} = [ 'string {var2}' {{var3}} ] step", async () => {2041 let tree = new Tree();2042 tree.parseIn(`2043..2044{ var1 } = 'foobar'2045{var2} = [ 'string { var1 }' {{var2:}} ]2046{{var2}} = "bleh"2047 `, "file.txt");2048 let runner = new Runner();2049 runner.init(tree, true);2050 let runInstance = new RunInstance(runner);2051 runInstance.currBranch = tree.branches[0];2052 runInstance.currStep = tree.branches[0].steps[0];2053 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);2054 runInstance.currStep = tree.branches[0].steps[1];2055 await runInstance.runStep(tree.branches[0].steps[1], tree.branches[0], false);2056 runInstance.currStep = tree.branches[0].steps[2];2057 await runInstance.runStep(tree.branches[0].steps[2], tree.branches[0], false);2058 expect(runInstance.getGlobal("var1")).to.equal("foobar");2059 expect(runInstance.getGlobal("var2")).to.equal(" 'string foobar' bleh ");2060 expect(runInstance.getLocal("var2")).to.equal("bleh");2061 expect(tree.branches[0].error).to.equal(undefined);2062 expect(tree.branches[0].steps[0].error).to.equal(undefined);2063 expect(tree.branches[0].steps[1].error).to.equal(undefined);2064 expect(tree.branches[0].steps[2].error).to.equal(undefined);2065 });2066 it("executes a {var1} = 'string1', {{var2}} = 'string2', {{var3}} = [string3] etc. step", async () => {2067 let tree = new Tree();2068 tree.parseIn(`2069{var1} = 'one', {{var2}} = "two", {{ var 3 }}=[three]2070 `, "file.txt");2071 let runner = new Runner();2072 runner.init(tree, true);2073 let runInstance = new RunInstance(runner);2074 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);2075 expect(runInstance.getGlobal("var1")).to.equal("one");2076 expect(runInstance.getLocal("var2")).to.equal("two");2077 expect(runInstance.getLocal("var 3")).to.equal("three");2078 expect(tree.branches[0].error).to.equal(undefined);2079 expect(tree.branches[0].steps[0].error).to.equal(undefined);2080 });2081 it("executes a {var1} is 'string1', {{var2}} is 'string2', {{var3}} is [string3] etc. step", async () => {2082 let tree = new Tree();2083 tree.parseIn(`2084{var1} is 'one', {{var2}} is "two", {{ var 3 }}is[three]2085 `, "file.txt");2086 let runner = new Runner();2087 runner.init(tree, true);2088 let runInstance = new RunInstance(runner);2089 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);2090 expect(runInstance.getGlobal("var1")).to.equal("one");2091 expect(runInstance.getLocal("var2")).to.equal("two");2092 expect(runInstance.getLocal("var 3")).to.equal("three");2093 expect(tree.branches[0].error).to.equal(undefined);2094 expect(tree.branches[0].steps[0].error).to.equal(undefined);2095 });2096 });2097 context("{var}=Function", () => {2098 it("executes a {var} = Text { code block } step", async () => {2099 let tree = new Tree();2100 tree.parseIn(`2101{var1} = Text {2102 return "foobar";2103}2104 `, "file.txt");2105 let runner = new Runner();2106 runner.init(tree, true);2107 let runInstance = new RunInstance(runner);2108 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);2109 expect(runInstance.getGlobal("var1")).to.equal("foobar");2110 expect(tree.branches[0].error).to.equal(undefined);2111 expect(tree.branches[0].steps[0].error).to.equal(undefined);2112 });2113 it("executes a {{var}} = Text { code block } step", async () => {2114 let tree = new Tree();2115 tree.parseIn(`2116{{var1}} = Text {2117 return "foobar";2118}2119 `, "file.txt");2120 let runner = new Runner();2121 runner.init(tree, true);2122 let runInstance = new RunInstance(runner);2123 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);2124 expect(runInstance.getLocal("var1")).to.equal("foobar");2125 expect(tree.branches[0].error).to.equal(undefined);2126 expect(tree.branches[0].steps[0].error).to.equal(undefined);2127 });2128 it("executes a {var} = Function step, where the function declaration has a code block that returns a value", async () => {2129 let tree = new Tree();2130 tree.parseIn(`2131{var1} = My function2132* My function {2133 return "foobar";2134}2135 `, "file.txt");2136 let runner = new Runner();2137 runner.init(tree, true);2138 let runInstance = new RunInstance(runner);2139 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);2140 expect(runInstance.getGlobal("var1")).to.equal("foobar");2141 expect(tree.branches[0].error).to.equal(undefined);2142 expect(tree.branches[0].steps[0].error).to.equal(undefined);2143 });2144 it("executes a {{var}} = Function step, where the function declaration has a code block that returns a value", async () => {2145 let tree = new Tree();2146 tree.parseIn(`2147{{var1}} = My function2148 {{var2}} = '{{var1}}'2149* My function {2150 return "foobar";2151}2152 `, "file.txt");2153 let runner = new Runner();2154 runner.init(tree, true);2155 let runInstance = new RunInstance(runner);2156 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);2157 await runInstance.runStep(tree.branches[0].steps[1], tree.branches[0], false);2158 expect(runInstance.getLocal("var2")).to.equal("foobar");2159 expect(tree.branches[0].error).to.equal(undefined);2160 expect(tree.branches[0].steps[0].error).to.equal(undefined);2161 expect(tree.branches[0].steps[1].error).to.equal(undefined);2162 });2163 it("executes a Function step, without {var}=, where the function declaration has a code block that returns a value", async () => {2164 let tree = new Tree();2165 tree.parseIn(`2166My function2167* My function {2168 return "foobar";2169}2170 `, "file.txt");2171 let runner = new Runner();2172 runner.init(tree, true);2173 let runInstance = new RunInstance(runner);2174 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);2175 expect(tree.branches[0].error).to.equal(undefined);2176 expect(tree.branches[0].steps[0].error).to.equal(undefined);2177 });2178 it("executes a {var} = Function step, where the function declaration has a code block that returns a value asynchonously", async () => {2179 let tree = new Tree();2180 tree.parseIn(`2181{var} = Set that var {2182 return await new Promise((resolve, reject) => {2183 setTimeout(() => {2184 resolve("foobar");2185 }, 1);2186 });2187}2188 My {var} Function2189* My {{one}} Function {2190 runInstance.one = one;2191}2192 `, "file.txt");2193 let runner = new Runner();2194 runner.init(tree, true);2195 let runInstance = new RunInstance(runner);2196 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);2197 await runInstance.runStep(tree.branches[0].steps[1], tree.branches[0], false);2198 expect(runInstance.one).to.equal("foobar");2199 expect(tree.branches[0].error).to.equal(undefined);2200 expect(tree.branches[0].steps[0].error).to.equal(undefined);2201 expect(tree.branches[0].steps[1].error).to.equal(undefined);2202 });2203 it("executes a {var} = Function step, where the function declaration has {{variables}} and has a code block that returns a value", async () => {2204 let tree = new Tree();2205 tree.parseIn(`2206{var1} = My "foobar" function2207* My {{one}} function {2208 return one + ' blah!';2209}2210 `, "file.txt");2211 let runner = new Runner();2212 runner.init(tree, true);2213 let runInstance = new RunInstance(runner);2214 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);2215 expect(runInstance.getGlobal("var1")).to.equal("foobar blah!");2216 expect(tree.branches[0].error).to.equal(undefined);2217 expect(tree.branches[0].steps[0].error).to.equal(undefined);2218 });2219 it("executes a {var} = Function with {vars passed in} step, where the function declaration has {{variables}} and has a code block that returns a value", async () => {2220 let tree = new Tree();2221 tree.parseIn(`2222{var1} = My {var2:} function2223 {var2}='foobar'2224* My {{one}} function {2225 return one + ' blah!';2226}2227 `, "file.txt");2228 let runner = new Runner();2229 runner.init(tree, true);2230 let runInstance = new RunInstance(runner);2231 runInstance.currBranch = tree.branches[0];2232 runInstance.currStep = tree.branches[0].steps[0];2233 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);2234 expect(runInstance.getGlobal("var1")).to.equal("foobar blah!");2235 expect(tree.branches[0].error).to.equal(undefined);2236 expect(tree.branches[0].steps[0].error).to.equal(undefined);2237 });2238 it("executes a {var} = Function step, where the function declaration is in {x}='value' format", async () => {2239 let tree = new Tree();2240 tree.parseIn(`2241{var1} = My function2242* My function2243 {x}='foobar'2244 `, "file.txt");2245 let runner = new Runner();2246 runner.init(tree, true);2247 let runInstance = new RunInstance(runner);2248 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);2249 expect(runInstance.getGlobal("var1")).to.equal(undefined); // not set yet, as {var1} will be set on the next step ({x}='foobar')2250 await runInstance.runStep(tree.branches[0].steps[1], tree.branches[0], false);2251 expect(runInstance.getGlobal("var1")).to.equal("foobar");2252 expect(tree.branches[0].error).to.equal(undefined);2253 expect(tree.branches[0].steps[0].error).to.equal(undefined);2254 expect(tree.branches[0].steps[1].error).to.equal(undefined);2255 });2256 it("executes a {var} = Function step, where the function declaration is in {x}='value' and {x}=Func format", async () => {2257 let tree = new Tree();2258 tree.parseIn(`2259{var1} = My function2260* My function2261 {x} = My function 22262* My function 22263 {y}='foobar'2264 `, "file.txt");2265 let runner = new Runner();2266 runner.init(tree, true);2267 let runInstance = new RunInstance(runner);2268 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);2269 expect(runInstance.getGlobal("var1")).to.equal(undefined);2270 await runInstance.runStep(tree.branches[0].steps[1], tree.branches[0], false);2271 expect(runInstance.getGlobal("var1")).to.equal(undefined);2272 await runInstance.runStep(tree.branches[0].steps[2], tree.branches[0], false);2273 expect(runInstance.getGlobal("var1")).to.equal("foobar");2274 expect(tree.branches[0].error).to.equal(undefined);2275 expect(tree.branches[0].steps[0].error).to.equal(undefined);2276 expect(tree.branches[0].steps[1].error).to.equal(undefined);2277 expect(tree.branches[0].steps[2].error).to.equal(undefined);2278 });2279 });2280 context("code blocks", () => {2281 it("allows a code block to get local, global, and persistent variables via getter functions", async () => {2282 let tree = new Tree();2283 tree.parseIn(`2284Text {2285 runInstance.one = p("one");2286 runInstance.two = g("two");2287 runInstance.three = l("three");2288}2289 `, "file.txt");2290 let runner = new Runner();2291 runner.init(tree, true);2292 let runInstance = new RunInstance(runner);2293 runInstance.p("one", "first");2294 runInstance.g("two", "second");2295 runInstance.l("three", "third");2296 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);2297 expect(runInstance.one).to.equal("first");2298 expect(runInstance.two).to.equal("second");2299 expect(runInstance.three).to.equal("third");2300 expect(tree.branches[0].error).to.equal(undefined);2301 expect(tree.branches[0].steps[0].error).to.equal(undefined);2302 });2303 it("allows a code block to set local, global, and persistent variables via setter functions", async () => {2304 let tree = new Tree();2305 tree.parseIn(`2306Text {2307 p("one", "first");2308 g("two", "second");2309 l("three", "third");2310}2311 `, "file.txt");2312 let runner = new Runner();2313 runner.init(tree, true);2314 let runInstance = new RunInstance(runner);2315 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);2316 expect(runInstance.p("one")).to.equal("first");2317 expect(runInstance.g("two")).to.equal("second");2318 expect(runInstance.l("three")).to.equal("third");2319 expect(tree.branches[0].error).to.equal(undefined);2320 expect(tree.branches[0].steps[0].error).to.equal(undefined);2321 });2322 it("makes a passed-in {{variable}} accessible as a plain js variable inside a code block", async () => {2323 let tree = new Tree();2324 tree.parseIn(`2325My 'foo' "bar" function2326* My {{$One_two_123$}} {{three}} function {2327 runInstance.one = $One_two_123$;2328 runInstance.three = three;2329 runInstance.four = getLocal("$One_two_123$");2330 runInstance.five = getLocal("three");2331}2332 `, "file.txt");2333 let runner = new Runner();2334 runner.init(tree, true);2335 let runInstance = new RunInstance(runner);2336 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);2337 expect(runInstance.one).to.equal("foo");2338 expect(runInstance.three).to.equal("bar");2339 expect(runInstance.four).to.equal("foo");2340 expect(runInstance.five).to.equal("bar");2341 expect(tree.branches[0].error).to.equal(undefined);2342 expect(tree.branches[0].steps[0].error).to.equal(undefined);2343 });2344 it("does not make a passed-in {{variable}} accessible as a plain js variable inside a code block if it has non-whitelisted chars in its name", async () => {2345 let tree = new Tree();2346 tree.parseIn(`2347My 'foobar' function2348* My {{one%}} function {2349 runInstance.one = one%;2350}2351 `, "file.txt");2352 let runner = new Runner();2353 runner.init(tree, true);2354 let runInstance = new RunInstance(runner);2355 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);2356 expect(tree.branches[0].steps[0].error.message).to.contain("Unexpected token ';'");2357 expect(tree.branches[0].steps[0].error.filename).to.equal("file.txt");2358 expect(tree.branches[0].steps[0].error.lineNumber).to.equal(4);2359 expect(tree.branches[0].error).to.equal(undefined);2360 });2361 it("does not make a passed-in {{variable}} accessible as a plain js variable inside a code block if its name is blacklisted", async () => {2362 let tree = new Tree();2363 tree.parseIn(`2364My 'foobar' function2365* My {{for}} function {2366 runInstance.one = for;2367}2368 `, "file.txt");2369 let runner = new Runner();2370 runner.init(tree, true);2371 let runInstance = new RunInstance(runner);2372 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);2373 expect(tree.branches[0].steps[0].error.message).to.contain("Unexpected token 'for'");2374 expect(tree.branches[0].steps[0].error.filename).to.equal("file.txt");2375 expect(tree.branches[0].steps[0].error.lineNumber).to.equal(4);2376 expect(tree.branches[0].error).to.equal(undefined);2377 });2378 it("makes a {variable} accessible as a plain js variable inside a code block", async () => {2379 let tree = new Tree();2380 tree.parseIn(`2381{one}='foobar'2382 My function2383 Other {2384 runInstance.two = one;2385 }2386* My function {2387 runInstance.one = one;2388}2389 `, "file.txt");2390 let runner = new Runner();2391 runner.init(tree, true);2392 let runInstance = new RunInstance(runner);2393 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);2394 await runInstance.runStep(tree.branches[0].steps[1], tree.branches[0], false);2395 await runInstance.runStep(tree.branches[0].steps[2], tree.branches[0], false);2396 expect(runInstance.one).to.equal("foobar");2397 expect(runInstance.two).to.equal("foobar");2398 expect(tree.branches[0].error).to.equal(undefined);2399 expect(tree.branches[0].steps[0].error).to.equal(undefined);2400 expect(tree.branches[0].steps[1].error).to.equal(undefined);2401 expect(tree.branches[0].steps[2].error).to.equal(undefined);2402 });2403 it("does not make a {{variable}} accessible as a plain js variable inside a function's code block", async () => {2404 let tree = new Tree();2405 tree.parseIn(`2406{{one}}='foobar'2407 My function2408* My function {2409 runInstance.one = one;2410}2411 `, "file.txt");2412 let runner = new Runner();2413 runner.init(tree, true);2414 let runInstance = new RunInstance(runner);2415 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);2416 await runInstance.runStep(tree.branches[0].steps[1], tree.branches[0], false);2417 expect(tree.branches[0].steps[1].error.message).to.contain("one is not defined");2418 expect(tree.branches[0].steps[1].error.filename).to.equal("file.txt");2419 expect(tree.branches[0].steps[1].error.lineNumber).to.equal(6);2420 expect(tree.branches[0].error).to.equal(undefined);2421 expect(tree.branches[0].steps[0].error).to.equal(undefined);2422 });2423 it("makes a {{variable}} accessible as a plain js variable inside a non-function code block", async () => {2424 let tree = new Tree();2425 tree.parseIn(`2426{{one}}='foobar'2427 Other {2428 runInstance.one = one;2429 }2430 Other {2431 runInstance.two = one;2432 }2433 `, "file.txt");2434 let runner = new Runner();2435 runner.init(tree, true);2436 let runInstance = new RunInstance(runner);2437 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);2438 await runInstance.runStep(tree.branches[0].steps[1], tree.branches[0], false);2439 expect(runInstance.one).to.equal("foobar");2440 await runInstance.runStep(tree.branches[0].steps[2], tree.branches[0], false);2441 expect(runInstance.two).to.equal("foobar");2442 expect(tree.branches[0].error).to.equal(undefined);2443 expect(tree.branches[0].steps[0].error).to.equal(undefined);2444 expect(tree.branches[0].steps[1].error).to.equal(undefined);2445 expect(tree.branches[0].steps[2].error).to.equal(undefined);2446 });2447 it("sets the plain js variable inside a code block to a passed-in {{variable}} when an existing {{variable}} of the same name is defined", async () => {2448 let tree = new Tree();2449 tree.parseIn(`2450{{one}}='foo'2451 Check that the original value is here {2452 runInstance.one = one;2453 }2454 My 'bar' function2455 Check that the original value is here {2456 runInstance.three = one;2457 }2458* My {{one}} function {2459 runInstance.two = one;2460}2461 `, "file.txt");2462 let runner = new Runner();2463 runner.init(tree, true);2464 let runInstance = new RunInstance(runner);2465 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);2466 await runInstance.runStep(tree.branches[0].steps[1], tree.branches[0], false);2467 await runInstance.runStep(tree.branches[0].steps[2], tree.branches[0], false);2468 await runInstance.runStep(tree.branches[0].steps[3], tree.branches[0], false);2469 expect(runInstance.one).to.equal("foo");2470 expect(runInstance.two).to.equal("bar");2471 expect(runInstance.three).to.equal("foo");2472 expect(tree.branches[0].error).to.equal(undefined);2473 expect(tree.branches[0].steps[0].error).to.equal(undefined);2474 expect(tree.branches[0].steps[1].error).to.equal(undefined);2475 expect(tree.branches[0].steps[2].error).to.equal(undefined);2476 expect(tree.branches[0].steps[3].error).to.equal(undefined);2477 });2478 it("does not make a {{variable}} accessible as a plain js variable inside a code block if it has non-whitelisted chars in its name", async () => {2479 let tree = new Tree();2480 tree.parseIn(`2481{{one%}}='foobar'2482 My function2483* My function {2484 runInstance.one = one%;2485}2486 `, "file.txt");2487 let runner = new Runner();2488 runner.init(tree, true);2489 let runInstance = new RunInstance(runner);2490 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);2491 await runInstance.runStep(tree.branches[0].steps[1], tree.branches[0], false);2492 expect(tree.branches[0].steps[1].error.message).to.contain("Unexpected token ';'");2493 expect(tree.branches[0].steps[1].error.filename).to.equal("file.txt");2494 expect(tree.branches[0].steps[1].error.lineNumber).to.equal(5);2495 expect(tree.branches[0].error).to.equal(undefined);2496 expect(tree.branches[0].steps[0].error).to.equal(undefined);2497 });2498 it("does not make a {{variable}} accessible as a plain js variable inside a code block if its name is blacklisted", async () => {2499 let tree = new Tree();2500 tree.parseIn(`2501{{for}}='foobar'2502 My function2503* My function {2504 runInstance.one = for;2505}2506 `, "file.txt");2507 let runner = new Runner();2508 runner.init(tree, true);2509 let runInstance = new RunInstance(runner);2510 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);2511 await runInstance.runStep(tree.branches[0].steps[1], tree.branches[0], false);2512 expect(tree.branches[0].steps[1].error.message).to.contain("Unexpected token 'for'");2513 expect(tree.branches[0].steps[1].error.filename).to.equal("file.txt");2514 expect(tree.branches[0].steps[1].error.lineNumber).to.equal(5);2515 expect(tree.branches[0].error).to.equal(undefined);2516 expect(tree.branches[0].steps[0].error).to.equal(undefined);2517 });2518 it("when a {{var}} and {var} of the same name both exist and both get passed into a code block, the js variable is set to the local version", async () => {2519 let tree = new Tree();2520 tree.parseIn(`2521{{var1}}='foo'2522 {var1}='bar'2523 Text {2524 runInstance.one = var1;2525 runInstance.two = getLocal("var1");2526 runInstance.three = getGlobal("var1");2527 runInstance.four = getPersistent("var1");2528 }2529 `, "file.txt");2530 let runner = new Runner();2531 runner.init(tree, true);2532 let runInstance = new RunInstance(runner);2533 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);2534 await runInstance.runStep(tree.branches[0].steps[1], tree.branches[0], false);2535 await runInstance.runStep(tree.branches[0].steps[2], tree.branches[0], false);2536 expect(runInstance.one).to.equal("foo");2537 expect(runInstance.two).to.equal("foo");2538 expect(runInstance.three).to.equal("bar");2539 expect(runInstance.four).to.equal(undefined);2540 expect(tree.branches[0].error).to.equal(undefined);2541 expect(tree.branches[0].steps[0].error).to.equal(undefined);2542 expect(tree.branches[0].steps[1].error).to.equal(undefined);2543 expect(tree.branches[0].steps[2].error).to.equal(undefined);2544 });2545 it("when a {{var}} and a persistent let of the same name both exist, the js variable for let is set to the local version", async () => {2546 let tree = new Tree();2547 tree.parseIn(`2548{{var1}}='foo'2549 Text {2550 runInstance.one = var1;2551 runInstance.two = l("var1");2552 runInstance.three = g("var1");2553 runInstance.four = p("var1");2554 }2555 `, "file.txt");2556 let runner = new Runner();2557 runner.init(tree, true);2558 let runInstance = new RunInstance(runner);2559 runInstance.setPersistent("var1", "bar");2560 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);2561 await runInstance.runStep(tree.branches[0].steps[1], tree.branches[0], false);2562 expect(runInstance.one).to.equal("foo");2563 expect(runInstance.two).to.equal("foo");2564 expect(runInstance.three).to.equal(undefined);2565 expect(runInstance.four).to.equal("bar");2566 expect(tree.branches[0].error).to.equal(undefined);2567 expect(tree.branches[0].steps[0].error).to.equal(undefined);2568 expect(tree.branches[0].steps[1].error).to.equal(undefined);2569 });2570 it("when a {var} and a persistent let of the same name both exist, the js variable for let is set to the global version", async () => {2571 let tree = new Tree();2572 tree.parseIn(`2573{var1}='foo'2574 Text {2575 runInstance.one = var1;2576 runInstance.two = getLocal("var1");2577 runInstance.three = getGlobal("var1");2578 runInstance.four = getPersistent("var1");2579 }2580 `, "file.txt");2581 let runner = new Runner();2582 runner.init(tree, true);2583 let runInstance = new RunInstance(runner);2584 runInstance.setPersistent("var1", "bar");2585 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);2586 await runInstance.runStep(tree.branches[0].steps[1], tree.branches[0], false);2587 expect(runInstance.one).to.equal("foo");2588 expect(runInstance.two).to.equal(undefined);2589 expect(runInstance.three).to.equal("foo");2590 expect(runInstance.four).to.equal("bar");2591 expect(tree.branches[0].error).to.equal(undefined);2592 expect(tree.branches[0].steps[0].error).to.equal(undefined);2593 expect(tree.branches[0].steps[1].error).to.equal(undefined);2594 });2595 it("makes the return value of the last code block available in {prev}", async () => {2596 let tree = new Tree();2597 tree.parseIn(`2598One {2599 return 7;2600}2601 Two {2602 runInstance.one = prev;2603 }2604 `, "file.txt");2605 let runner = new Runner();2606 runner.init(tree, true);2607 let runInstance = new RunInstance(runner);2608 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);2609 await runInstance.runStep(tree.branches[0].steps[1], tree.branches[0], false);2610 expect(runInstance.one).to.equal(7);2611 expect(tree.branches[0].error).to.equal(undefined);2612 expect(tree.branches[0].steps[0].error).to.equal(undefined);2613 expect(tree.branches[0].steps[1].error).to.equal(undefined);2614 });2615 });2616 context("{var} accessibility", () => {2617 it("a {{var}} is accessible in a later step", async () => {2618 let tree = new Tree();2619 tree.parseIn(`2620{{var1}}='foo'2621 {{var2}}='{{var1}}bar'2622 `, "file.txt");2623 let runner = new Runner();2624 runner.init(tree, true);2625 let runInstance = new RunInstance(runner);2626 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);2627 await runInstance.runStep(tree.branches[0].steps[1], tree.branches[0], false);2628 expect(runInstance.getLocal("var2")).to.equal("foobar");2629 expect(tree.branches[0].error).to.equal(undefined);2630 expect(tree.branches[0].steps[0].error).to.equal(undefined);2631 expect(tree.branches[0].steps[1].error).to.equal(undefined);2632 });2633 it("a {{var}} is accessible in a later step, with a function call without code block in between", async () => {2634 let tree = new Tree();2635 tree.parseIn(`2636{{var1}}='foo'2637 My function2638 {{var2}}='{{var1}}bar'2639* My function2640 {{var1}}='blah'2641 `, "file.txt");2642 let runner = new Runner();2643 runner.init(tree, true);2644 let runInstance = new RunInstance(runner);2645 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);2646 await runInstance.runStep(tree.branches[0].steps[1], tree.branches[0], false);2647 await runInstance.runStep(tree.branches[0].steps[2], tree.branches[0], false);2648 await runInstance.runStep(tree.branches[0].steps[3], tree.branches[0], false);2649 expect(runInstance.one).to.equal(undefined);2650 expect(runInstance.getLocal("var2")).to.equal("foobar");2651 expect(tree.branches[0].error).to.equal(undefined);2652 expect(tree.branches[0].steps[0].error).to.equal(undefined);2653 expect(tree.branches[0].steps[1].error).to.equal(undefined);2654 expect(tree.branches[0].steps[2].error).to.equal(undefined);2655 expect(tree.branches[0].steps[3].error).to.equal(undefined);2656 });2657 it("a {{var}} is accessible in a later step, with a function call with code block in between", async () => {2658 let tree = new Tree();2659 tree.parseIn(`2660{{var1}}='foo'2661 My function2662 {{var2}}='{{var1}}bar'2663* My function {2664 runInstance.one = getLocal("var1");2665}2666 `, "file.txt");2667 let runner = new Runner();2668 runner.init(tree, true);2669 let runInstance = new RunInstance(runner);2670 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);2671 await runInstance.runStep(tree.branches[0].steps[1], tree.branches[0], false);2672 await runInstance.runStep(tree.branches[0].steps[2], tree.branches[0], false);2673 expect(runInstance.one).to.equal(undefined);2674 expect(runInstance.getLocal("var2")).to.equal("foobar");2675 expect(tree.branches[0].error).to.equal(undefined);2676 expect(tree.branches[0].steps[0].error).to.equal(undefined);2677 expect(tree.branches[0].steps[1].error).to.equal(undefined);2678 expect(tree.branches[0].steps[2].error).to.equal(undefined);2679 });2680 it("a {{var}} is accessible in a later step, with a non-function code block in between", async () => {2681 let tree = new Tree();2682 tree.parseIn(`2683{{var1}}='foo'2684 Something {2685 runInstance.one = getLocal("var1");2686 }2687 {{var2}}='{{var1}}bar'2688 `, "file.txt");2689 let runner = new Runner();2690 runner.init(tree, true);2691 let runInstance = new RunInstance(runner);2692 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);2693 await runInstance.runStep(tree.branches[0].steps[1], tree.branches[0], false);2694 await runInstance.runStep(tree.branches[0].steps[2], tree.branches[0], false);2695 expect(runInstance.one).to.equal("foo");2696 expect(runInstance.getLocal("var2")).to.equal("foobar");2697 expect(tree.branches[0].error).to.equal(undefined);2698 expect(tree.branches[0].steps[0].error).to.equal(undefined);2699 expect(tree.branches[0].steps[1].error).to.equal(undefined);2700 expect(tree.branches[0].steps[2].error).to.equal(undefined);2701 });2702 it("does not make a {{var}} declared outside and before a function call accessible to steps inside the function call", async () => {2703 let tree = new Tree();2704 tree.parseIn(`2705{{var1}}='foo'2706 My function2707* My function2708 {var2}='{{var1}}'2709 `, "file.txt");2710 let runner = new Runner();2711 runner.init(tree, true);2712 let runInstance = new RunInstance(runner);2713 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);2714 await runInstance.runStep(tree.branches[0].steps[1], tree.branches[0], false);2715 await runInstance.runStep(tree.branches[0].steps[2], tree.branches[0], false);2716 expect(tree.branches[0].steps[2].error.message).to.equal("The variable {{var1}} wasn't set, but is needed for this step. If it's set later in the branch, try using {{var1:}}.");2717 expect(tree.branches[0].steps[2].error.filename).to.equal("file.txt");2718 expect(tree.branches[0].steps[2].error.lineNumber).to.equal(6);2719 expect(tree.branches[0].error).to.equal(undefined);2720 expect(tree.branches[0].steps[0].error).to.equal(undefined);2721 expect(tree.branches[0].steps[1].error).to.equal(undefined);2722 });2723 it("does not make a {{var}} declared outside and after a function call accessible to steps inside the function call", async () => {2724 let tree = new Tree();2725 tree.parseIn(`2726My function2727 {{var1}}='bar'2728* My function2729 {var2}='{{var1:}}'2730 `, "file.txt");2731 let runner = new Runner();2732 runner.init(tree, true);2733 let runInstance = new RunInstance(runner);2734 runInstance.currBranch = tree.branches[0];2735 runInstance.currStep = tree.branches[0].steps[0];2736 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);2737 runInstance.currStep = tree.branches[0].steps[1];2738 await runInstance.runStep(tree.branches[0].steps[1], tree.branches[0], false);2739 expect(tree.branches[0].steps[1].error.message).to.equal("The variable {{var1:}} is never set, but is needed for this step");2740 expect(tree.branches[0].steps[1].error.filename).to.equal("file.txt");2741 expect(tree.branches[0].steps[1].error.lineNumber).to.equal(6);2742 expect(tree.branches[0].error).to.equal(undefined);2743 expect(tree.branches[0].steps[0].error).to.equal(undefined);2744 });2745 it("does not make a {{var}} declared outside a function call accessible inside the function call's code block", async () => {2746 let tree = new Tree();2747 tree.parseIn(`2748{{var1}}='foo'2749 My function2750* My function {2751 runInstance.one = getLocal("var1");2752}2753 `, "file.txt");2754 let runner = new Runner();2755 runner.init(tree, true);2756 let runInstance = new RunInstance(runner);2757 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);2758 await runInstance.runStep(tree.branches[0].steps[1], tree.branches[0], false);2759 expect(runInstance.one).to.equal(undefined);2760 expect(tree.branches[0].error).to.equal(undefined);2761 expect(tree.branches[0].steps[0].error).to.equal(undefined);2762 expect(tree.branches[0].steps[1].error).to.equal(undefined);2763 });2764 it("makes a {{var}} declared outside a function call accessible after the function call, where the function has steps inside it", async () => {2765 let tree = new Tree();2766 tree.parseIn(`2767{{var1}}='foo'2768 My function2769 {{var2}}='{{var1}}bar'2770* My function2771 {{var1}}='blah'2772 `, "file.txt");2773 let runner = new Runner();2774 runner.init(tree, true);2775 let runInstance = new RunInstance(runner);2776 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);2777 await runInstance.runStep(tree.branches[0].steps[1], tree.branches[0], false);2778 await runInstance.runStep(tree.branches[0].steps[2], tree.branches[0], false);2779 expect(runInstance.getLocal("var1")).to.equal("blah");2780 await runInstance.runStep(tree.branches[0].steps[3], tree.branches[0], false);2781 expect(runInstance.getLocal("var1")).to.equal("foo");2782 expect(runInstance.getLocal("var2")).to.equal("foobar");2783 expect(tree.branches[0].error).to.equal(undefined);2784 expect(tree.branches[0].steps[0].error).to.equal(undefined);2785 expect(tree.branches[0].steps[1].error).to.equal(undefined);2786 expect(tree.branches[0].steps[2].error).to.equal(undefined);2787 expect(tree.branches[0].steps[3].error).to.equal(undefined);2788 });2789 it("makes a {{var}} declared outside a function call accessible after the function call, where the function has a code block only", async () => {2790 let tree = new Tree();2791 tree.parseIn(`2792{{var1}}='foo'2793 My function2794 {{var2}}='{{var1}}bar'2795* My function {2796 setLocal("var1", "blah");2797}2798 `, "file.txt");2799 let runner = new Runner();2800 runner.init(tree, true);2801 let runInstance = new RunInstance(runner);2802 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);2803 await runInstance.runStep(tree.branches[0].steps[1], tree.branches[0], false);2804 expect(runInstance.getLocal("var1")).to.equal("blah");2805 await runInstance.runStep(tree.branches[0].steps[2], tree.branches[0], false);2806 expect(runInstance.getLocal("var1")).to.equal("foo");2807 expect(runInstance.getLocal("var2")).to.equal("foobar");2808 expect(tree.branches[0].error).to.equal(undefined);2809 expect(tree.branches[0].steps[0].error).to.equal(undefined);2810 expect(tree.branches[0].steps[1].error).to.equal(undefined);2811 expect(tree.branches[0].steps[2].error).to.equal(undefined);2812 });2813 it("makes a {{var}} declared outside a function call accessible after the function call, where the function has a code block and has steps inside it", async () => {2814 let tree = new Tree();2815 tree.parseIn(`2816{{var1}}='foo'2817 My function2818 {{var2}}='{{var1}}bar'2819* My function {2820 setLocal("var1", "blah");2821}2822 {{var1}}="blah2"2823 `, "file.txt");2824 let runner = new Runner();2825 runner.init(tree, true);2826 let runInstance = new RunInstance(runner);2827 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);2828 await runInstance.runStep(tree.branches[0].steps[1], tree.branches[0], false);2829 expect(runInstance.getLocal("var1")).to.equal("blah");2830 await runInstance.runStep(tree.branches[0].steps[2], tree.branches[0], false);2831 expect(runInstance.getLocal("var1")).to.equal("blah2");2832 await runInstance.runStep(tree.branches[0].steps[3], tree.branches[0], false);2833 expect(runInstance.getLocal("var1")).to.equal("foo");2834 expect(runInstance.getLocal("var2")).to.equal("foobar");2835 expect(tree.branches[0].error).to.equal(undefined);2836 expect(tree.branches[0].steps[0].error).to.equal(undefined);2837 expect(tree.branches[0].steps[1].error).to.equal(undefined);2838 expect(tree.branches[0].steps[2].error).to.equal(undefined);2839 expect(tree.branches[0].steps[3].error).to.equal(undefined);2840 });2841 it("does not make a {{var}} declared inside a function accessible outside of it", async () => {2842 let tree = new Tree();2843 tree.parseIn(`2844My function2845 {var2}='{{var1}}'2846* My function2847 {{var1}}='bar'2848 `, "file.txt");2849 let runner = new Runner();2850 runner.init(tree, true);2851 let runInstance = new RunInstance(runner);2852 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);2853 await runInstance.runStep(tree.branches[0].steps[1], tree.branches[0], false);2854 await runInstance.runStep(tree.branches[0].steps[2], tree.branches[0], false);2855 expect(tree.branches[0].steps[2].error.message).to.equal("The variable {{var1}} wasn't set, but is needed for this step. If it's set later in the branch, try using {{var1:}}.");2856 expect(tree.branches[0].steps[2].error.filename).to.equal("file.txt");2857 expect(tree.branches[0].steps[2].error.lineNumber).to.equal(3);2858 expect(tree.branches[0].error).to.equal(undefined);2859 expect(tree.branches[0].steps[0].error).to.equal(undefined);2860 expect(tree.branches[0].steps[1].error).to.equal(undefined);2861 });2862 it("clears {{local vars}} and reinstates previous {{local vars}} when exiting multiple levels of function calls", async () => {2863 let tree = new Tree();2864 tree.parseIn(`2865{{var1}}='foo'2866 My function2867 E -2868 Something {2869 runInstance.one = getLocal("var1");2870 runInstance.two = var1;2871 setLocal("var1", "hehe");2872 runInstance.three = getLocal("var1");2873 runInstance.four = var1;2874 }2875 F -2876 My function2877 Silly function2878 G -2879 {{var1}}='foo2'2880* My function2881 A -2882 {{var1}}='bar'2883 Other function2884 D -2885 * Other function2886 B -2887 {{var1}}='bar2'2888 C -2889* Silly function {2890 runInstance.five = getLocal("var1");2891 setLocal("var1", "blah");2892 runInstance.six = getLocal("var1");2893}2894 {{var1}} = "blah2"2895 `, "file.txt");2896 let runner = new Runner();2897 runner.init(tree, true);2898 let runInstance = new RunInstance(runner);2899 /*2900 0) {{var1}}='foo'2901 1) My function2902 2) A -2903 3) {{var1}}='bar'2904 4) Other function2905 5) B -2906 6) {{var1}}='bar2'2907 7) C -2908 8) D -2909 9) E -2910 10) Something { code block }2911 11) F -2912 12) My function2913 13) A -2914 14) {{var1}}='bar'2915 15) Other function2916 16) B -2917 17) {{var1}}='bar2'2918 18) C -2919 19) D -2920 20) Silly function { code block }2921 21) {{var1}} = "blah2"2922 22) G -2923 23) {{var1}}='foo2'2924 */2925 expect(runInstance.getLocal("var1")).to.equal(undefined);2926 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);2927 expect(runInstance.getLocal("var1")).to.equal("foo");2928 await runInstance.runStep(tree.branches[0].steps[1], tree.branches[0], false);2929 expect(runInstance.getLocal("var1")).to.equal("foo");2930 await runInstance.runStep(tree.branches[0].steps[2], tree.branches[0], false);2931 expect(runInstance.getLocal("var1")).to.equal(undefined);2932 await runInstance.runStep(tree.branches[0].steps[3], tree.branches[0], false);2933 expect(runInstance.getLocal("var1")).to.equal("bar");2934 await runInstance.runStep(tree.branches[0].steps[4], tree.branches[0], false);2935 expect(runInstance.getLocal("var1")).to.equal("bar");2936 await runInstance.runStep(tree.branches[0].steps[5], tree.branches[0], false);2937 expect(runInstance.getLocal("var1")).to.equal(undefined);2938 await runInstance.runStep(tree.branches[0].steps[6], tree.branches[0], false);2939 expect(runInstance.getLocal("var1")).to.equal("bar2");2940 await runInstance.runStep(tree.branches[0].steps[7], tree.branches[0], false);2941 expect(runInstance.getLocal("var1")).to.equal("bar2");2942 await runInstance.runStep(tree.branches[0].steps[8], tree.branches[0], false);2943 expect(runInstance.getLocal("var1")).to.equal("bar");2944 await runInstance.runStep(tree.branches[0].steps[9], tree.branches[0], false);2945 expect(runInstance.getLocal("var1")).to.equal("foo");2946 await runInstance.runStep(tree.branches[0].steps[10], tree.branches[0], false);2947 expect(runInstance.one).to.equal("foo");2948 expect(runInstance.two).to.equal("foo");2949 expect(runInstance.getLocal("var1")).to.equal("hehe");2950 expect(runInstance.three).to.equal("hehe");2951 expect(runInstance.four).to.equal("foo");2952 await runInstance.runStep(tree.branches[0].steps[11], tree.branches[0], false);2953 expect(runInstance.getLocal("var1")).to.equal("hehe");2954 await runInstance.runStep(tree.branches[0].steps[12], tree.branches[0], false);2955 expect(runInstance.getLocal("var1")).to.equal("hehe");2956 await runInstance.runStep(tree.branches[0].steps[13], tree.branches[0], false);2957 expect(runInstance.getLocal("var1")).to.equal(undefined);2958 await runInstance.runStep(tree.branches[0].steps[14], tree.branches[0], false);2959 expect(runInstance.getLocal("var1")).to.equal("bar");2960 await runInstance.runStep(tree.branches[0].steps[15], tree.branches[0], false);2961 expect(runInstance.getLocal("var1")).to.equal("bar");2962 await runInstance.runStep(tree.branches[0].steps[16], tree.branches[0], false);2963 expect(runInstance.getLocal("var1")).to.equal(undefined);2964 await runInstance.runStep(tree.branches[0].steps[17], tree.branches[0], false);2965 expect(runInstance.getLocal("var1")).to.equal("bar2");2966 await runInstance.runStep(tree.branches[0].steps[18], tree.branches[0], false);2967 expect(runInstance.getLocal("var1")).to.equal("bar2");2968 await runInstance.runStep(tree.branches[0].steps[19], tree.branches[0], false);2969 expect(runInstance.getLocal("var1")).to.equal("bar");2970 await runInstance.runStep(tree.branches[0].steps[20], tree.branches[0], false);2971 expect(runInstance.five).to.equal(undefined);2972 expect(runInstance.getLocal("var1")).to.equal("blah");2973 expect(runInstance.six).to.equal("blah");2974 await runInstance.runStep(tree.branches[0].steps[21], tree.branches[0], false);2975 expect(runInstance.getLocal("var1")).to.equal("blah2");2976 await runInstance.runStep(tree.branches[0].steps[22], tree.branches[0], false);2977 expect(runInstance.getLocal("var1")).to.equal("hehe");2978 await runInstance.runStep(tree.branches[0].steps[23], tree.branches[0], false);2979 expect(runInstance.getLocal("var1")).to.equal("foo2");2980 expect(tree.branches[0].error).to.equal(undefined);2981 expect(tree.branches[0].steps[0].error).to.equal(undefined);2982 expect(tree.branches[0].steps[1].error).to.equal(undefined);2983 expect(tree.branches[0].steps[2].error).to.equal(undefined);2984 expect(tree.branches[0].steps[3].error).to.equal(undefined);2985 expect(tree.branches[0].steps[4].error).to.equal(undefined);2986 expect(tree.branches[0].steps[5].error).to.equal(undefined);2987 expect(tree.branches[0].steps[6].error).to.equal(undefined);2988 expect(tree.branches[0].steps[7].error).to.equal(undefined);2989 expect(tree.branches[0].steps[8].error).to.equal(undefined);2990 expect(tree.branches[0].steps[9].error).to.equal(undefined);2991 expect(tree.branches[0].steps[10].error).to.equal(undefined);2992 expect(tree.branches[0].steps[11].error).to.equal(undefined);2993 expect(tree.branches[0].steps[12].error).to.equal(undefined);2994 expect(tree.branches[0].steps[13].error).to.equal(undefined);2995 expect(tree.branches[0].steps[14].error).to.equal(undefined);2996 expect(tree.branches[0].steps[15].error).to.equal(undefined);2997 expect(tree.branches[0].steps[16].error).to.equal(undefined);2998 expect(tree.branches[0].steps[17].error).to.equal(undefined);2999 expect(tree.branches[0].steps[18].error).to.equal(undefined);3000 expect(tree.branches[0].steps[19].error).to.equal(undefined);3001 expect(tree.branches[0].steps[20].error).to.equal(undefined);3002 expect(tree.branches[0].steps[21].error).to.equal(undefined);3003 expect(tree.branches[0].steps[22].error).to.equal(undefined);3004 expect(tree.branches[0].steps[23].error).to.equal(undefined);3005 });3006 it("a {var} is accessible in a later step", async () => {3007 let tree = new Tree();3008 tree.parseIn(`3009{var1}='foo'3010 {var2}='{var1}bar'3011 `, "file.txt");3012 let runner = new Runner();3013 runner.init(tree, true);3014 let runInstance = new RunInstance(runner);3015 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);3016 await runInstance.runStep(tree.branches[0].steps[1], tree.branches[0], false);3017 expect(runInstance.getGlobal("var2")).to.equal("foobar");3018 expect(tree.branches[0].error).to.equal(undefined);3019 expect(tree.branches[0].steps[0].error).to.equal(undefined);3020 expect(tree.branches[0].steps[1].error).to.equal(undefined);3021 });3022 it("a {var} is accessible in a later step, with a function call without code block in between", async () => {3023 let tree = new Tree();3024 tree.parseIn(`3025{var1}='foo'3026 My function3027 {var2}='{var1}bar'3028* My function3029 {var1}='blah'3030 `, "file.txt");3031 let runner = new Runner();3032 runner.init(tree, true);3033 let runInstance = new RunInstance(runner);3034 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);3035 await runInstance.runStep(tree.branches[0].steps[1], tree.branches[0], false);3036 await runInstance.runStep(tree.branches[0].steps[2], tree.branches[0], false);3037 await runInstance.runStep(tree.branches[0].steps[3], tree.branches[0], false);3038 expect(runInstance.one).to.equal(undefined);3039 expect(runInstance.getGlobal("var2")).to.equal("blahbar");3040 expect(tree.branches[0].error).to.equal(undefined);3041 expect(tree.branches[0].steps[0].error).to.equal(undefined);3042 expect(tree.branches[0].steps[1].error).to.equal(undefined);3043 expect(tree.branches[0].steps[2].error).to.equal(undefined);3044 expect(tree.branches[0].steps[3].error).to.equal(undefined);3045 });3046 it("a {var} is accessible in a later step, with a function call with code block in between", async () => {3047 let tree = new Tree();3048 tree.parseIn(`3049{var1}='foo'3050 My function3051 {var2}='{var1}bar'3052* My function {3053 runInstance.one = getGlobal("var1");3054 setGlobal("var1", "blah");3055}3056 `, "file.txt");3057 let runner = new Runner();3058 runner.init(tree, true);3059 let runInstance = new RunInstance(runner);3060 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);3061 await runInstance.runStep(tree.branches[0].steps[1], tree.branches[0], false);3062 await runInstance.runStep(tree.branches[0].steps[2], tree.branches[0], false);3063 expect(runInstance.one).to.equal("foo");3064 expect(runInstance.getGlobal("var2")).to.equal("blahbar");3065 expect(tree.branches[0].error).to.equal(undefined);3066 expect(tree.branches[0].steps[0].error).to.equal(undefined);3067 expect(tree.branches[0].steps[1].error).to.equal(undefined);3068 expect(tree.branches[0].steps[2].error).to.equal(undefined);3069 });3070 it("a {var} is accessible in a later step, with a non-function code block in between", async () => {3071 let tree = new Tree();3072 tree.parseIn(`3073{var1}='foo'3074 Something {3075 runInstance.one = getGlobal("var1");3076 }3077 {var2}='{var1}bar'3078 `, "file.txt");3079 let runner = new Runner();3080 runner.init(tree, true);3081 let runInstance = new RunInstance(runner);3082 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);3083 await runInstance.runStep(tree.branches[0].steps[1], tree.branches[0], false);3084 await runInstance.runStep(tree.branches[0].steps[2], tree.branches[0], false);3085 expect(runInstance.one).to.equal("foo");3086 expect(runInstance.getGlobal("var2")).to.equal("foobar");3087 expect(tree.branches[0].error).to.equal(undefined);3088 expect(tree.branches[0].steps[0].error).to.equal(undefined);3089 expect(tree.branches[0].steps[1].error).to.equal(undefined);3090 expect(tree.branches[0].steps[2].error).to.equal(undefined);3091 });3092 it("a {var} is accessible inside a function call's code block", async () => {3093 let tree = new Tree();3094 tree.parseIn(`3095{var1}='foo'3096 My function3097* My function {3098 runInstance.one = getGlobal("var1");3099 runInstance.two = var1;3100}3101 `, "file.txt");3102 let runner = new Runner();3103 runner.init(tree, true);3104 let runInstance = new RunInstance(runner);3105 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);3106 await runInstance.runStep(tree.branches[0].steps[1], tree.branches[0], false);3107 expect(runInstance.one).to.equal("foo");3108 expect(runInstance.two).to.equal("foo");3109 expect(tree.branches[0].error).to.equal(undefined);3110 expect(tree.branches[0].steps[0].error).to.equal(undefined);3111 expect(tree.branches[0].steps[1].error).to.equal(undefined);3112 });3113 it("a {var} is accessible to steps inside a function call", async () => {3114 let tree = new Tree();3115 tree.parseIn(`3116{var1}='foo'3117 My function3118 A -3119* My function3120 {var2}='{var1}bar'3121 `, "file.txt");3122 let runner = new Runner();3123 runner.init(tree, true);3124 let runInstance = new RunInstance(runner);3125 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);3126 await runInstance.runStep(tree.branches[0].steps[1], tree.branches[0], false);3127 await runInstance.runStep(tree.branches[0].steps[2], tree.branches[0], false);3128 await runInstance.runStep(tree.branches[0].steps[3], tree.branches[0], false);3129 expect(runInstance.getGlobal("var2")).to.equal("foobar");3130 expect(tree.branches[0].error).to.equal(undefined);3131 expect(tree.branches[0].steps[0].error).to.equal(undefined);3132 expect(tree.branches[0].steps[1].error).to.equal(undefined);3133 expect(tree.branches[0].steps[2].error).to.equal(undefined);3134 expect(tree.branches[0].steps[3].error).to.equal(undefined);3135 });3136 it("a {var} is accessible to code blocks of steps inside a function call", async () => {3137 let tree = new Tree();3138 tree.parseIn(`3139{var1}='foo'3140 My function3141 A -3142* My function3143 Something {3144 runInstance.one = getGlobal("var1");3145 runInstance.two = var1;3146 setGlobal("var1", "bar");3147 }3148 `, "file.txt");3149 let runner = new Runner();3150 runner.init(tree, true);3151 let runInstance = new RunInstance(runner);3152 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);3153 await runInstance.runStep(tree.branches[0].steps[1], tree.branches[0], false);3154 await runInstance.runStep(tree.branches[0].steps[2], tree.branches[0], false);3155 await runInstance.runStep(tree.branches[0].steps[3], tree.branches[0], false);3156 expect(runInstance.one).to.equal("foo");3157 expect(runInstance.two).to.equal("foo");3158 expect(runInstance.getGlobal("var1")).to.equal("bar");3159 expect(tree.branches[0].error).to.equal(undefined);3160 expect(tree.branches[0].steps[0].error).to.equal(undefined);3161 expect(tree.branches[0].steps[1].error).to.equal(undefined);3162 expect(tree.branches[0].steps[2].error).to.equal(undefined);3163 expect(tree.branches[0].steps[3].error).to.equal(undefined);3164 });3165 it("a {var} declared inside a function call is accessible in steps after the function call", async () => {3166 let tree = new Tree();3167 tree.parseIn(`3168My function3169 {var2}='{var1}bar'3170* My function3171 {var1}='foo'3172 `, "file.txt");3173 let runner = new Runner();3174 runner.init(tree, true);3175 let runInstance = new RunInstance(runner);3176 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);3177 await runInstance.runStep(tree.branches[0].steps[1], tree.branches[0], false);3178 await runInstance.runStep(tree.branches[0].steps[2], tree.branches[0], false);3179 expect(runInstance.getGlobal("var1")).to.equal("foo");3180 expect(runInstance.getGlobal("var2")).to.equal("foobar");3181 expect(tree.branches[0].error).to.equal(undefined);3182 expect(tree.branches[0].steps[0].error).to.equal(undefined);3183 expect(tree.branches[0].steps[1].error).to.equal(undefined);3184 expect(tree.branches[0].steps[2].error).to.equal(undefined);3185 });3186 it("a {var} declared in a branch is accessible in an After Every Step hook", async () => {3187 let tree = new Tree();3188 tree.parseIn(`3189{var1}='foo'3190*** After Every Step {3191 runInstance.one = getGlobal('var1');3192 runInstance.two = var1;3193}3194 `, "file.txt");3195 let runner = new Runner();3196 runner.init(tree, true);3197 let runInstance = new RunInstance(runner);3198 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);3199 expect(runInstance.one).to.equal("foo");3200 expect(runInstance.two).to.equal("foo");3201 expect(tree.branches[0].error).to.equal(undefined);3202 expect(tree.branches[0].steps[0].error).to.equal(undefined);3203 });3204 it("a {{var}} declared in a branch is accessible in an After Every Step hook, so long as it didn't go out of scope", async () => {3205 let tree = new Tree();3206 tree.parseIn(`3207{{var1}}='foo'3208*** After Every Step {3209 runInstance.one = getLocal('var1');3210 runInstance.two = var1;3211}3212 `, "file.txt");3213 let runner = new Runner();3214 runner.init(tree, true);3215 let runInstance = new RunInstance(runner);3216 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);3217 expect(runInstance.one).to.equal("foo");3218 expect(runInstance.two).to.equal("foo");3219 expect(tree.branches[0].error).to.equal(undefined);3220 expect(tree.branches[0].steps[0].error).to.equal(undefined);3221 });3222 });3223 context("errors and logs", () => {3224 it("executes a step that logs", async () => {3225 let tree = new Tree();3226 tree.stepDataMode = 'all';3227 tree.parseIn(`3228My function3229 Something else {3230 log("C");3231 log("D");3232 }3233* My function {3234 log("A");3235 log("B");3236}3237 `, "file.txt");3238 let runner = new Runner();3239 runner.init(tree, true);3240 let runInstance = new RunInstance(runner);3241 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);3242 await runInstance.runStep(tree.branches[0].steps[1], tree.branches[0], false);3243 expect(tree.branches[0].steps[0].log).to.eql([3244 {text: "A"},3245 {text: "B"}3246 ]);3247 expect(tree.branches[0].steps[1].log).to.eql([3248 {text: "C"},3249 {text: "D"}3250 ]);3251 expect(tree.branches[0].error).to.equal(undefined);3252 expect(tree.branches[0].steps[0].error).to.equal(undefined);3253 expect(tree.branches[0].steps[1].error).to.equal(undefined);3254 });3255 it("sets the error's filename and lineNumber correctly when an error occurs inside a code block", async () => {3256 let tree = new Tree();3257 tree.parseIn(`3258Something {3259 let a = "a";3260 let b = "b";3261 cc; // will throw an exception3262 let d = "d";3263}3264 `, "file.txt");3265 let runner = new Runner();3266 runner.init(tree, true);3267 let runInstance = new RunInstance(runner);3268 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);3269 expect(tree.branches[0].steps[0].error.message).to.contain("cc is not defined");3270 expect(tree.branches[0].steps[0].error.filename).to.equal("file.txt");3271 expect(tree.branches[0].steps[0].error.lineNumber).to.equal(5);3272 expect(tree.branches[0].error).to.equal(undefined);3273 });3274 it("sets the error's filename and lineNumber correctly when an error occurs inside a function used inside a code block", async () => {3275 let tree = new Tree();3276 tree.parseIn(`3277Something {3278 let a = "a";3279 let b = "b";3280 runInstance.badFunc(); // will throw an exception3281 let d = "d";3282}3283 `, "file.txt");3284 let runner = new Runner();3285 runner.init(tree, true);3286 let runInstance = new RunInstance(runner);3287 runInstance.badFunc = () => {3288 let a = "a";3289 let b = "b";3290 cc;3291 let d = "d";3292 };3293 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);3294 expect(tree.branches[0].steps[0].error.message).to.contain("cc is not defined");3295 expect(tree.branches[0].steps[0].error.filename).to.equal("file.txt");3296 expect(tree.branches[0].steps[0].error.lineNumber).to.equal(5);3297 expect(!!tree.branches[0].steps[0].error.stack.match(/at runInstance\.badFunc/)).to.equal(true);3298 expect(!!tree.branches[0].steps[0].error.stack.match(/at CodeBlock_for_Something[^\n]+<anonymous>:5:17\)/)).to.equal(true);3299 expect(tree.branches[0].error).to.equal(undefined);3300 });3301 it("sets the error's filename and lineNumber correctly when an error occurs inside a function from one code block that's used inside another code block", async () => {3302 let tree = new Tree();3303 tree.parseIn(`3304First {3305 runInstance.badFunc = () => {3306 let a = "a";3307 let b = "b";3308 cc;3309 let d = "d";3310 };3311}3312 Second {3313 let a = "a";3314 let b = "b";3315 runInstance.badFunc(); // will throw an exception3316 let d = "d";3317 }3318 `, "file.txt");3319 let runner = new Runner();3320 runner.init(tree, true);3321 let runInstance = new RunInstance(runner);3322 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);3323 await runInstance.runStep(tree.branches[0].steps[1], tree.branches[0], false);3324 expect(tree.branches[0].steps[1].error.message).to.contain("cc is not defined");3325 expect(tree.branches[0].steps[1].error.filename).to.equal("file.txt");3326 expect(tree.branches[0].steps[1].error.lineNumber).to.equal(14);3327 expect(!!tree.branches[0].steps[1].error.stack.match(/at runInstance\.badFunc[^\n]+<anonymous>:6:9\)/)).to.equal(true);3328 expect(!!tree.branches[0].steps[1].error.stack.match(/at CodeBlock_for_Second[^\n]+<anonymous>:14:21\)/)).to.equal(true);3329 expect(tree.branches[0].error).to.equal(undefined);3330 });3331 it("sets the error's filename and lineNumber correctly when an error occurs inside a js function implemented inside a code block", async () => {3332 let tree = new Tree();3333 tree.parseIn(`3334Something {3335 function func() {3336 let a = "a";3337 let b = "b";3338 badFunc(); // will throw an exception3339 let d = "d";3340 }3341 func();3342}3343 `, "file.txt");3344 let runner = new Runner();3345 runner.init(tree, true);3346 let runInstance = new RunInstance(runner);3347 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);3348 expect(tree.branches[0].steps[0].error.message).to.contain("badFunc is not defined");3349 expect(tree.branches[0].steps[0].error.filename).to.equal("file.txt");3350 expect(tree.branches[0].steps[0].error.lineNumber).to.equal(10);3351 expect(!!tree.branches[0].steps[0].error.stack.match(/at func[^\n]+<anonymous>:6:9\)/)).to.equal(true);3352 expect(!!tree.branches[0].steps[0].error.stack.match(/at CodeBlock_for_Something[^\n]+<anonymous>:10:5\)/)).to.equal(true);3353 expect(tree.branches[0].error).to.equal(undefined);3354 });3355 it("sets the error's filename and lineNumber to the function call when an error occurs inside a packaged code block", async () => {3356 let tree = new Tree();3357 tree.parseIn(`3358Packaged function3359`, "file.txt");3360tree.parseIn(`3361* Packaged function {3362 let a = "a";3363 let b = "b";3364 cc; // will throw an exception3365 let d = "d";3366}3367 `, "package.txt", true);3368 let runner = new Runner();3369 runner.init(tree, true);3370 let runInstance = new RunInstance(runner);3371 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);3372 expect(tree.branches[0].steps[0].error.message).to.contain("cc is not defined");3373 expect(tree.branches[0].steps[0].error.filename).to.equal("file.txt");3374 expect(tree.branches[0].steps[0].error.lineNumber).to.equal(2);3375 expect(!!tree.branches[0].steps[0].error.stack.match(/at CodeBlock_for_Packaged_function[^\n]+<anonymous>:5:5\)/)).to.equal(true);3376 expect(tree.branches[0].error).to.equal(undefined);3377 });3378 // NOTE: This test skipped because it fails when running nyc code coverage3379 // The test right after this one is almost identical but nyc-friendly3380 it.skip("sets the error's filename and lineNumber correctly when an error occurs inside a required function", async () => {3381 let tree = new Tree();3382 tree.parseIn(`3383Something {3384 let BF = require(process.cwd().replace(/smashtest.*/, 'smashtest/tests/core/badfunc.js')); // using process.cwd() because the relative path varies depending on if you run the tests with mocha vs. nyc3385 BF.badFunc();3386}3387 `, "file.txt");3388 let runner = new Runner();3389 runner.init(tree, true);3390 let runInstance = new RunInstance(runner);3391 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);3392 expect(tree.branches[0].steps[0].error.message).to.contain("cc is not defined");3393 expect(tree.branches[0].steps[0].error.filename).to.equal("file.txt");3394 expect(tree.branches[0].steps[0].error.lineNumber).to.equal(4);3395 expect(!!tree.branches[0].steps[0].error.stack.match(/at Object\.exports\.badFunc[^\n]+badfunc\.js:4:5\)/)).to.equal(true);3396 expect(!!tree.branches[0].steps[0].error.stack.match(/at CodeBlock_for_Something[^\n]+<anonymous>:4:8\)/)).to.equal(true);3397 expect(tree.branches[0].error).to.equal(undefined);3398 });3399 it("sets the error's filename and lineNumber correctly when an error occurs inside a required function (code coverage tool friendly)", async () => {3400 let tree = new Tree();3401 tree.parseIn(`3402Something {3403 let BF = require(process.cwd().replace(/smashtest.*/, 'smashtest/tests/core/badfunc.js')); // using process.cwd() because the relative path varies depending on if you run the tests with mocha vs. nyc3404 BF.badFunc();3405}3406 `, "file.txt");3407 let runner = new Runner();3408 runner.init(tree, true);3409 let runInstance = new RunInstance(runner);3410 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);3411 expect(tree.branches[0].steps[0].error.message).to.contain("c is not defined");3412 expect(tree.branches[0].steps[0].error.filename).to.equal("file.txt");3413 expect(tree.branches[0].steps[0].error.lineNumber).to.equal(4);3414 // NOTE: commented out because nyc code coverage tool minifies the js, breaking the line number reference3415 //expect(!!tree.branches[0].steps[0].error.stack.match(/at Object\.exports\.badFunc[^\n]+badfunc\.js:4:5\)/)).to.equal(true);3416 expect(!!tree.branches[0].steps[0].error.stack.match(/at CodeBlock_for_Something[^\n]+<anonymous>:4:8\)/)).to.equal(true);3417 expect(tree.branches[0].error).to.equal(undefined);3418 });3419 it("marks a step as failed when it fails", async () => {3420 let tree = new Tree();3421 tree.parseIn(`3422My function3423* My function {3424 let a = 1 + 1;3425 throw new Error("oops");3426}3427 `, "file.txt");3428 let runner = new Runner();3429 runner.init(tree, true);3430 let runInstance = new RunInstance(runner);3431 tree.nextStep(tree.branches[0], true);3432 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);3433 tree.nextStep(tree.branches[0], true);3434 expect(tree.branches[0].steps[0].error.message).to.equal("oops");3435 expect(tree.branches[0].steps[0].error.filename).to.equal("file.txt");3436 expect(tree.branches[0].steps[0].error.lineNumber).to.equal(6);3437 expect(tree.branches[0].steps[0].isPassed).to.equal(undefined);3438 expect(tree.branches[0].steps[0].isFailed).to.equal(true);3439 expect(tree.branches[0].steps[0].isSkipped).to.equal(undefined);3440 expect(tree.branches[0].error).to.equal(undefined);3441 expect(tree.branches[0].isPassed).to.equal(undefined);3442 expect(tree.branches[0].isFailed).to.equal(true);3443 expect(tree.branches[0].isSkipped).to.equal(undefined);3444 });3445 it("marks a step as passed when it passes", async () => {3446 let tree = new Tree();3447 tree.stepDataMode = 'all';3448 tree.parseIn(`3449My function3450* My function {3451 let a = 1 + 1;3452}3453 `, "file.txt");3454 let runner = new Runner();3455 runner.init(tree, true);3456 let runInstance = new RunInstance(runner);3457 tree.nextStep(tree.branches[0], true);3458 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);3459 tree.nextStep(tree.branches[0], true);3460 expect(tree.branches[0].steps[0].error).to.equal(undefined);3461 expect(tree.branches[0].steps[0].isPassed).to.equal(true);3462 expect(tree.branches[0].steps[0].isFailed).to.equal(undefined);3463 expect(tree.branches[0].steps[0].isSkipped).to.equal(undefined);3464 expect(tree.branches[0].error).to.equal(undefined);3465 expect(tree.branches[0].isPassed).to.equal(true);3466 expect(tree.branches[0].isFailed).to.equal(undefined);3467 expect(tree.branches[0].isSkipped).to.equal(undefined);3468 });3469 it("handles bad syntax in a code block step", async () => {3470 let tree = new Tree();3471 tree.parseIn(`3472A -3473 Something {3474 let a = "A";3475 let b = "B";3476 cc;3477 let d = "D";3478 }3479 My function3480* My function {3481 let a = "A";3482 let b = "B";3483 let c = "C";3484 d;3485}3486 `, "file.txt");3487 let runner = new Runner();3488 runner.init(tree, true);3489 let runInstance = new RunInstance(runner);3490 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);3491 await runInstance.runStep(tree.branches[0].steps[1], tree.branches[0], false);3492 await runInstance.runStep(tree.branches[0].steps[2], tree.branches[0], false);3493 expect(tree.branches[0].steps[1].error.message).to.contain("cc is not defined");3494 expect(tree.branches[0].steps[1].error.filename).to.equal("file.txt");3495 expect(tree.branches[0].steps[1].error.lineNumber).to.equal(6);3496 expect(tree.branches[0].steps[2].error.message).to.contain("d is not defined");3497 expect(tree.branches[0].steps[2].error.filename).to.equal("file.txt");3498 expect(tree.branches[0].steps[2].error.lineNumber).to.equal(15);3499 expect(tree.branches[0].error).to.equal(undefined);3500 expect(tree.branches[0].steps[0].error).to.equal(undefined);3501 });3502 it("doesn't finish off the branch if a step has an error and the error's continue flag is set", async () => {3503 let tree = new Tree();3504 tree.parseIn(`3505My function3506 A -3507* My function {3508 let e = new Error("oops");3509 e.continue = true;3510 throw e;3511}3512 `, "file.txt");3513 let runner = new Runner();3514 runner.init(tree, true);3515 let runInstance = new RunInstance(runner);3516 tree.nextStep(tree.branches[0], true);3517 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);3518 tree.nextStep(tree.branches[0], true);3519 expect(tree.branches[0].steps[0].error.message).to.equal("oops");3520 expect(tree.branches[0].steps[0].error.filename).to.equal("file.txt");3521 expect(tree.branches[0].steps[0].error.lineNumber).to.equal(6);3522 expect(tree.branches[0].steps[0].isPassed).to.equal(undefined);3523 expect(tree.branches[0].steps[0].isFailed).to.equal(true);3524 expect(tree.branches[0].steps[0].isSkipped).to.equal(undefined);3525 expect(tree.branches[0].error).to.equal(undefined);3526 expect(tree.branches[0].isPassed).to.equal(undefined);3527 expect(tree.branches[0].isFailed).to.equal(undefined);3528 expect(tree.branches[0].isSkipped).to.equal(undefined);3529 });3530 it("doesn't finish off the branch if a step has an error and pauseOnFail is set", async () => {3531 let tree = new Tree();3532 tree.parseIn(`3533My function3534 A -3535* My function {3536 let e = new Error("oops");3537 throw e;3538}3539 `, "file.txt");3540 let runner = new Runner();3541 runner.init(tree, true);3542 runner.pauseOnFail = true;3543 let runInstance = new RunInstance(runner);3544 tree.nextStep(tree.branches[0], true);3545 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);3546 tree.nextStep(tree.branches[0], true);3547 expect(tree.branches[0].steps[0].error.message).to.equal("oops");3548 expect(tree.branches[0].steps[0].error.filename).to.equal("file.txt");3549 expect(tree.branches[0].steps[0].error.lineNumber).to.equal(6);3550 expect(tree.branches[0].steps[0].isPassed).to.equal(undefined);3551 expect(tree.branches[0].steps[0].isFailed).to.equal(true);3552 expect(tree.branches[0].steps[0].isSkipped).to.equal(undefined);3553 expect(tree.branches[0].error).to.equal(undefined);3554 expect(tree.branches[0].isPassed).to.equal(undefined);3555 expect(tree.branches[0].isFailed).to.equal(undefined);3556 expect(tree.branches[0].isSkipped).to.equal(undefined);3557 });3558 });3559 context("pause and resume", () => {3560 it("pauses when a ~ step is encountered before the step", async () => {3561 let tree = new Tree();3562 tree.parseIn(`3563A -3564 ~ B -3565 C -3566 `, "file.txt");3567 let runner = new Runner();3568 runner.init(tree, true);3569 let runInstance = new RunInstance(runner);3570 expect(runInstance.isPaused).to.equal(false);3571 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);3572 expect(runInstance.isPaused).to.equal(false);3573 await runInstance.runStep(tree.branches[0].steps[1], tree.branches[0], false);3574 expect(runInstance.isPaused).to.equal(true);3575 });3576 it("pauses when a ~ step is encountered after the step", async () => {3577 let tree = new Tree();3578 tree.parseIn(`3579A -3580 B ~ -3581 C -3582 `, "file.txt");3583 let runner = new Runner();3584 runner.init(tree, true);3585 let runInstance = new RunInstance(runner);3586 expect(runInstance.isPaused).to.equal(false);3587 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);3588 expect(runInstance.isPaused).to.equal(false);3589 await runInstance.runStep(tree.branches[0].steps[1], tree.branches[0], false);3590 expect(runInstance.isPaused).to.equal(true);3591 });3592 it("when resuming from a pause on a ~, doesn't pause on the same ~ again, when the ~ is before the step", async () => {3593 let tree = new Tree();3594 tree.parseIn(`3595A -3596 ~ B -3597 {var1}='foo'3598 `, "file.txt");3599 let runner = new Runner();3600 runner.init(tree, true);3601 let runInstance = new RunInstance(runner);3602 expect(runInstance.isPaused).to.equal(false);3603 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);3604 expect(runInstance.isPaused).to.equal(false);3605 await runInstance.runStep(tree.branches[0].steps[1], tree.branches[0], false);3606 expect(runInstance.isPaused).to.equal(true);3607 runInstance.isPaused = false;3608 await runInstance.runStep(tree.branches[0].steps[2], tree.branches[0], false);3609 expect(runInstance.isPaused).to.equal(false);3610 expect(runInstance.getGlobal("var1")).to.equal("foo");3611 });3612 it("when resuming from a pause on a ~, doesn't pause on the same ~ again, when the ~ is after the step", async () => {3613 let tree = new Tree();3614 tree.parseIn(`3615A -3616 B - ~3617 {var1}='foo'3618 `, "file.txt");3619 let runner = new Runner();3620 runner.init(tree, true);3621 let runInstance = new RunInstance(runner);3622 expect(runInstance.isPaused).to.equal(false);3623 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);3624 expect(runInstance.isPaused).to.equal(false);3625 await runInstance.runStep(tree.branches[0].steps[1], tree.branches[0], false);3626 expect(runInstance.isPaused).to.equal(true);3627 runInstance.isPaused = false;3628 await runInstance.runStep(tree.branches[0].steps[2], tree.branches[0], false);3629 expect(runInstance.isPaused).to.equal(false);3630 expect(runInstance.getGlobal("var1")).to.equal("foo");3631 });3632 it("when resuming from a pause on a ~, doesn't pause on the same ~ again, when ~ is before and after the step", async () => {3633 let tree = new Tree();3634 tree.parseIn(`3635A -3636 ~ B ~ -3637 {var1}='foo'3638 `, "file.txt");3639 let runner = new Runner();3640 runner.init(tree, true);3641 let runInstance = new RunInstance(runner);3642 expect(runInstance.isPaused).to.equal(false);3643 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);3644 expect(runInstance.isPaused).to.equal(false);3645 await runInstance.runStep(tree.branches[0].steps[1], tree.branches[0], false);3646 expect(runInstance.isPaused).to.equal(true);3647 runInstance.isPaused = false;3648 await runInstance.runStep(tree.branches[0].steps[2], tree.branches[0], false);3649 expect(runInstance.isPaused).to.equal(false);3650 expect(runInstance.getGlobal("var1")).to.equal("foo");3651 });3652 it("pauses when pauseOnFail is set and a step fails", async () => {3653 let tree = new Tree();3654 tree.parseIn(`3655A -3656 B {3657 throw new Error("oops");3658 }3659 C -3660 `, "file.txt");3661 let runner = new Runner();3662 runner.init(tree, true);3663 runner.pauseOnFail = true;3664 let runInstance = new RunInstance(runner);3665 expect(runInstance.isPaused).to.equal(false);3666 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);3667 expect(runInstance.isPaused).to.equal(false);3668 await runInstance.runStep(tree.branches[0].steps[1], tree.branches[0], false);3669 expect(runInstance.isPaused).to.equal(true);3670 });3671 it("doesn't pause when pauseOnFail is set and a step passes", async () => {3672 let tree = new Tree();3673 tree.parseIn(`3674A -3675 B -3676 C -3677 `, "file.txt");3678 let runner = new Runner();3679 runner.init(tree, true);3680 runner.pauseOnFail = true;3681 let runInstance = new RunInstance(runner);3682 expect(runInstance.isPaused).to.equal(false);3683 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);3684 expect(runInstance.isPaused).to.equal(false);3685 await runInstance.runStep(tree.branches[0].steps[1], tree.branches[0], false);3686 expect(runInstance.isPaused).to.equal(false);3687 });3688 it("doesn't pause when pauseOnFail is not set and a step fails", async () => {3689 let tree = new Tree();3690 tree.parseIn(`3691A -3692 B {3693 throw new Error("oops");3694 }3695 C -3696 `, "file.txt");3697 let runner = new Runner();3698 runner.init(tree, true);3699 let runInstance = new RunInstance(runner);3700 expect(runInstance.isPaused).to.equal(false);3701 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);3702 expect(runInstance.isPaused).to.equal(false);3703 await runInstance.runStep(tree.branches[0].steps[1], tree.branches[0], false);3704 expect(runInstance.isPaused).to.equal(false);3705 });3706 });3707 context("hooks", () => {3708 it("runs a Before Every Step hook", async () => {3709 let tree = new Tree();3710 tree.parseIn(`3711A -3712*** Before Every Step {3713 runInstance.one = "foo";3714}3715 `, "file.txt");3716 let runner = new Runner();3717 runner.init(tree, true);3718 let runInstance = new RunInstance(runner);3719 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);3720 expect(runInstance.one).to.equal("foo");3721 });3722 it("runs multiple Before Every Step and After Every Step hooks", async () => {3723 let tree = new Tree();3724 tree.parseIn(`3725A {3726 runInstance.one += "THREE";3727 runInstance.two += "FOUR";3728}3729 B {3730 runInstance.one += "SEVEN";3731 runInstance.two += "EIGHT";3732 }3733*** Before Every Step {3734 runInstance.one = "one";3735}3736*** Before Every Step {3737 runInstance.two = "two";3738}3739*** After Every Step {3740 runInstance.one += "five";3741}3742*** After Every Step {3743 runInstance.two += "six";3744}3745 `, "file.txt");3746 let runner = new Runner();3747 runner.init(tree, true);3748 let runInstance = new RunInstance(runner);3749 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);3750 expect(runInstance.one).to.equal("oneTHREEfive");3751 expect(runInstance.two).to.equal("twoFOURsix");3752 await runInstance.runStep(tree.branches[0].steps[1], tree.branches[0], false);3753 expect(runInstance.one).to.equal("oneSEVENfive");3754 expect(runInstance.two).to.equal("twoEIGHTsix");3755 });3756 it("handles an error inside a Before Every Step hook", async () => {3757 let tree = new Tree();3758 tree.parseIn(`3759A -3760*** Before Every Step {3761 var a = 2 + 2;3762 throw new Error("oops");3763}3764 `, "file.txt");3765 let runner = new Runner();3766 runner.init(tree, true);3767 let runInstance = new RunInstance(runner);3768 tree.nextStep(tree.branches[0], true);3769 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);3770 tree.nextStep(tree.branches[0], true);3771 expect(tree.branches[0].steps[0].error.message).to.equal("oops");3772 expect(tree.branches[0].steps[0].error.filename).to.equal("file.txt");3773 expect(tree.branches[0].steps[0].error.lineNumber).to.equal(6);3774 expect(!!tree.branches[0].steps[0].error.stack.match(/at CodeBlock_for_Before_Every_Step[^\n]+<anonymous>:6:11\)/)).to.equal(true);3775 expect(tree.branches[0].steps[0].isPassed).to.equal(undefined);3776 expect(tree.branches[0].steps[0].isFailed).to.equal(true);3777 expect(tree.branches[0].steps[0].isSkipped).to.equal(undefined);3778 expect(tree.branches[0].error).to.equal(undefined);3779 expect(tree.branches[0].isPassed).to.equal(undefined);3780 expect(tree.branches[0].isFailed).to.equal(true);3781 expect(tree.branches[0].isSkipped).to.equal(undefined);3782 });3783 it("handles an error inside an After Every Step hook", async () => {3784 let tree = new Tree();3785 tree.parseIn(`3786A -3787*** After Every Step {3788 var a = 2 + 2;3789 throw new Error("oops");3790}3791 `, "file.txt");3792 let runner = new Runner();3793 runner.init(tree, true);3794 let runInstance = new RunInstance(runner);3795 tree.nextStep(tree.branches[0], true);3796 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);3797 tree.nextStep(tree.branches[0], true);3798 expect(tree.branches[0].steps[0].error.message).to.equal("oops");3799 expect(tree.branches[0].steps[0].error.filename).to.equal("file.txt");3800 expect(tree.branches[0].steps[0].error.lineNumber).to.equal(6);3801 expect(!!tree.branches[0].steps[0].error.stack.match(/at CodeBlock_for_After_Every_Step[^\n]+<anonymous>:6:11\)/)).to.equal(true);3802 expect(tree.branches[0].steps[0].isPassed).to.equal(undefined);3803 expect(tree.branches[0].steps[0].isFailed).to.equal(true);3804 expect(tree.branches[0].steps[0].isSkipped).to.equal(undefined);3805 expect(tree.branches[0].error).to.equal(undefined);3806 expect(tree.branches[0].isPassed).to.equal(undefined);3807 expect(tree.branches[0].isFailed).to.equal(true);3808 expect(tree.branches[0].isSkipped).to.equal(undefined);3809 });3810 it("stops running Before Every Step hooks when an error occurs inside a Before Every Step hook, doesn't run actual step, but runs all After Every Step hooks and doesn't override the existing error", async () => {3811 let tree = new Tree();3812 tree.parseIn(`3813A {3814 runInstance.one += "THREE"; // this step will be skipped3815}3816*** Before Every Step {3817 runInstance.one += "TWO"; // this hook will be skipped3818}3819*** Before Every Step {3820 throw new Error("oops1"); // this will run second3821}3822*** Before Every Step {3823 runInstance.one = "one"; // this will run first3824}3825*** After Every Step {3826 throw new Error("oops2"); // this will run third, but this error won't override the existing one3827}3828*** After Every Step {3829 runInstance.one += "four"; // this will run fourth3830}3831 `, "file.txt");3832 let runner = new Runner();3833 runner.init(tree, true);3834 let runInstance = new RunInstance(runner);3835 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);3836 expect(runInstance.one).to.equal("onefour");3837 expect(tree.branches[0].steps[0].error.message).to.equal("oops1");3838 expect(tree.branches[0].steps[0].error.filename).to.equal("file.txt");3839 expect(tree.branches[0].steps[0].error.lineNumber).to.equal(11);3840 });3841 it("pauses when an error occurs inside a Before Every Step hook and pauseOnFail is set", async () => {3842 let tree = new Tree();3843 tree.parseIn(`3844A -3845 B -3846*** Before Every Step {3847 var a = 2 + 2;3848 throw new Error("oops");3849}3850 `, "file.txt");3851 let runner = new Runner();3852 runner.init(tree, true);3853 runner.pauseOnFail = true;3854 let runInstance = new RunInstance(runner);3855 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);3856 expect(runInstance.isPaused).to.equal(true);3857 });3858 it("pauses when an error occurs inside an After Every Step hook and pauseOnFail is set", async () => {3859 let tree = new Tree();3860 tree.parseIn(`3861A -3862 B -3863*** After Every Step {3864 var a = 2 + 2;3865 throw new Error("oops");3866}3867 `, "file.txt");3868 let runner = new Runner();3869 runner.init(tree, true);3870 runner.pauseOnFail = true;3871 let runInstance = new RunInstance(runner);3872 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);3873 expect(runInstance.isPaused).to.equal(true);3874 });3875 it("pauses when an error occurs inside a Before Every Step hook, pauseOnFail is set, and we we're at the last step of the branch", async () => {3876 let tree = new Tree();3877 tree.parseIn(`3878A -3879*** Before Every Step {3880 var a = 2 + 2;3881 throw new Error("oops");3882}3883*** After Every Branch {3884 runInstance.afterEveryBranchRan = true;3885}3886 `, "file.txt");3887 let runner = new Runner();3888 runner.init(tree, true);3889 runner.pauseOnFail = true;3890 let runInstance = new RunInstance(runner);3891 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);3892 expect(runInstance.isPaused).to.equal(true);3893 expect(runInstance.afterEveryBranchRan).to.equal(undefined);3894 });3895 it("pauses when an error occurs inside an After Every Step hook, pauseOnFail is set, and we we're at the last step of the branch", async () => {3896 let tree = new Tree();3897 tree.parseIn(`3898A -3899*** After Every Step {3900 var a = 2 + 2;3901 throw new Error("oops");3902}3903*** After Every Branch {3904 runInstance.afterEveryBranchRan = true;3905}3906 `, "file.txt");3907 let runner = new Runner();3908 runner.init(tree, true);3909 runner.pauseOnFail = true;3910 let runInstance = new RunInstance(runner);3911 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);3912 expect(runInstance.isPaused).to.equal(true);3913 expect(runInstance.afterEveryBranchRan).to.equal(undefined);3914 });3915 it("exits after running After Every Step hooks if an error occurs during a step", async () => {3916 let tree = new Tree();3917 tree.parseIn(`3918First step {3919 runInstance.firstStepRan = true;3920 throw new Error("oops");3921}3922 Second step {3923 runInstance.secondStepRan = true;3924 }3925*** Before Every Step {3926 runInstance.beforeEveryStep2Ran = true;3927}3928*** Before Every Step {3929 runInstance.beforeEveryStep1Ran = true;3930}3931*** After Every Step {3932 runInstance.afterEveryStep1Ran = true;3933}3934*** After Every Step {3935 runInstance.afterEveryStep2Ran = true;3936}3937 `, "file.txt");3938 let runner = new Runner();3939 runner.init(tree, true);3940 let runInstance = new RunInstance(runner);3941 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);3942 expect(runInstance.beforeEveryStep1Ran).to.equal(true);3943 expect(runInstance.beforeEveryStep2Ran).to.equal(true);3944 expect(runInstance.firstStepRan).to.equal(true);3945 expect(runInstance.secondStepRan).to.equal(undefined);3946 expect(runInstance.afterEveryStep1Ran).to.equal(true);3947 expect(runInstance.afterEveryStep2Ran).to.equal(true);3948 });3949 it("exits after running After Every Step hooks if an error occurs during a Before Every Step hook", async () => {3950 let tree = new Tree();3951 tree.parseIn(`3952First step {3953 runInstance.firstStepRan = true;3954}3955 Second step {3956 runInstance.secondStepRan = true;3957 }3958*** Before Every Step {3959 runInstance.beforeEveryStep2Ran = true;3960}3961*** Before Every Step {3962 runInstance.beforeEveryStep1Ran = true;3963 throw new Error("oops");3964}3965*** After Every Step {3966 runInstance.afterEveryStep1Ran = true;3967}3968*** After Every Step {3969 runInstance.afterEveryStep2Ran = true;3970}3971 `, "file.txt");3972 let runner = new Runner();3973 runner.init(tree, true);3974 let runInstance = new RunInstance(runner);3975 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);3976 expect(runInstance.beforeEveryStep1Ran).to.equal(true);3977 expect(runInstance.beforeEveryStep2Ran).to.equal(undefined);3978 expect(runInstance.firstStepRan).to.equal(undefined);3979 expect(runInstance.secondStepRan).to.equal(undefined);3980 expect(runInstance.afterEveryStep1Ran).to.equal(true);3981 expect(runInstance.afterEveryStep2Ran).to.equal(true);3982 });3983 it("exits after running After Every Step hooks if an error occurs during an After Every Step hook", async () => {3984 let tree = new Tree();3985 tree.parseIn(`3986First step {3987 runInstance.firstStepRan = true;3988}3989 Second step {3990 runInstance.secondStepRan = true;3991 }3992*** Before Every Step {3993 runInstance.beforeEveryStep2Ran = true;3994}3995*** Before Every Step {3996 runInstance.beforeEveryStep1Ran = true;3997}3998*** After Every Step {3999 runInstance.afterEveryStep1Ran = true;4000 throw new Error("oops");4001}4002*** After Every Step {4003 runInstance.afterEveryStep2Ran = true;4004}4005 `, "file.txt");4006 let runner = new Runner();4007 runner.init(tree, true);4008 let runInstance = new RunInstance(runner);4009 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);4010 expect(runInstance.beforeEveryStep1Ran).to.equal(true);4011 expect(runInstance.beforeEveryStep2Ran).to.equal(true);4012 expect(runInstance.firstStepRan).to.equal(true);4013 expect(runInstance.secondStepRan).to.equal(undefined);4014 expect(runInstance.afterEveryStep1Ran).to.equal(true);4015 expect(runInstance.afterEveryStep2Ran).to.equal(true);4016 });4017 });4018 context("stops", () => {4019 it("exits immediately if a stop occurs during a step", async () => {4020 let tree = new Tree();4021 tree.parseIn(`4022First step {4023 await new Promise((resolve, reject) => {4024 setTimeout(() => {4025 runInstance.firstStepRan = true;4026 resolve();4027 }, 20);4028 runInstance.isStopped = true; // stop the RunInstance mid-step4029 });4030}4031 Second step {4032 runInstance.secondStepRan = true;4033 }4034*** Before Every Step {4035 runInstance.beforeEveryStep2Ran = true;4036}4037*** Before Every Step {4038 runInstance.beforeEveryStep1Ran = true;4039}4040*** After Every Step {4041 runInstance.afterEveryStep1Ran = true;4042}4043*** After Every Step {4044 runInstance.afterEveryStep2Ran = true;4045}4046 `, "file.txt");4047 let runner = new Runner();4048 runner.init(tree, true);4049 let runInstance = new RunInstance(runner);4050 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);4051 expect(tree.branches[0].steps[0].elapsed).to.equal(undefined);4052 expect(runInstance.beforeEveryStep1Ran).to.equal(true);4053 expect(runInstance.beforeEveryStep2Ran).to.equal(true);4054 expect(runInstance.firstStepRan).to.equal(true);4055 expect(runInstance.secondStepRan).to.equal(undefined);4056 expect(runInstance.afterEveryStep1Ran).to.equal(undefined);4057 expect(runInstance.afterEveryStep2Ran).to.equal(undefined);4058 });4059 it("exits immediately if a stop occurs during a Before Every Step hook", async () => {4060 let tree = new Tree();4061 tree.parseIn(`4062First step {4063 runInstance.firstStepRan = true;4064}4065 Second step {4066 runInstance.secondStepRan = true;4067 }4068*** Before Every Step {4069 runInstance.beforeEveryStep2Ran = true;4070}4071*** Before Every Step {4072 await new Promise((resolve, reject) => {4073 setTimeout(() => {4074 runInstance.beforeEveryStep1Ran = true;4075 resolve();4076 }, 20);4077 runInstance.isStopped = true; // stop the RunInstance mid-step4078 });4079}4080*** After Every Step {4081 runInstance.afterEveryStep1Ran = true;4082}4083*** After Every Step {4084 runInstance.afterEveryStep2Ran = true;4085}4086 `, "file.txt");4087 let runner = new Runner();4088 runner.init(tree, true);4089 let runInstance = new RunInstance(runner);4090 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);4091 expect(tree.branches[0].steps[0].elapsed).to.equal(undefined);4092 expect(runInstance.beforeEveryStep1Ran).to.equal(true);4093 expect(runInstance.beforeEveryStep2Ran).to.equal(undefined);4094 expect(runInstance.firstStepRan).to.equal(undefined);4095 expect(runInstance.secondStepRan).to.equal(undefined);4096 expect(runInstance.afterEveryStep1Ran).to.equal(undefined);4097 expect(runInstance.afterEveryStep2Ran).to.equal(undefined);4098 });4099 it("exits immediately if a stop occurs during an After Every Step hook", async () => {4100 let tree = new Tree();4101 tree.parseIn(`4102First step {4103 runInstance.firstStepRan = true;4104}4105 Second step {4106 runInstance.secondStepRan = true;4107 }4108*** Before Every Step {4109 runInstance.beforeEveryStep2Ran = true;4110}4111*** Before Every Step {4112 runInstance.beforeEveryStep1Ran = true;4113}4114*** After Every Step {4115 await new Promise((resolve, reject) => {4116 setTimeout(() => {4117 runInstance.afterEveryStep1Ran = true;4118 resolve();4119 }, 20);4120 runInstance.isStopped = true; // stop the RunInstance mid-step4121 });4122}4123*** After Every Step {4124 runInstance.afterEveryStep2Ran = true;4125}4126 `, "file.txt");4127 let runner = new Runner();4128 runner.init(tree, true);4129 let runInstance = new RunInstance(runner);4130 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);4131 expect(tree.branches[0].steps[0].elapsed).to.be.at.least(0);4132 expect(runInstance.beforeEveryStep1Ran).to.equal(true);4133 expect(runInstance.beforeEveryStep2Ran).to.equal(true);4134 expect(runInstance.firstStepRan).to.equal(true);4135 expect(runInstance.secondStepRan).to.equal(undefined);4136 expect(runInstance.afterEveryStep1Ran).to.equal(true);4137 expect(runInstance.afterEveryStep2Ran).to.equal(undefined);4138 });4139 });4140 });4141 describe("runHookStep()", () => {4142 it("runs a passing hook step", async () => {4143 let tree = new Tree();4144 let sn = tree.newStepNode();4145 sn.codeBlock = ``;4146 let runner = new Runner();4147 runner.init(tree, true);4148 let runInstance = new RunInstance(runner);4149 let retVal = await runInstance.runHookStep(new Step(sn.id));4150 expect(retVal).to.equal(true);4151 });4152 it("runs a failing hook step with only a stepToGetError", async () => {4153 let tree = new Tree();4154 let sn = tree.newStepNode();4155 sn.filename = "file1.txt";4156 sn.lineNumber = 10;4157 sn.codeBlock = `4158 throw new Error("foobar");4159 `;4160 let stepToGetError = new Step(999);4161 let runner = new Runner();4162 runner.init(tree, true);4163 let runInstance = new RunInstance(runner);4164 let retVal = await runInstance.runHookStep(new Step(sn.id), stepToGetError);4165 expect(retVal).to.equal(false);4166 expect(stepToGetError.error.message).to.equal("foobar");4167 expect(stepToGetError.error.filename).to.equal("file1.txt");4168 expect(stepToGetError.error.lineNumber).to.equal(11);4169 });4170 it("runs a failing hook step with only a branchToGetError", async () => {4171 let tree = new Tree();4172 let sn = tree.newStepNode();4173 sn.filename = "file1.txt";4174 sn.lineNumber = 10;4175 sn.codeBlock = `4176 throw new Error("foobar");4177 `;4178 let branchToGetError = new Branch();4179 let runner = new Runner();4180 runner.init(tree, true);4181 let runInstance = new RunInstance(runner);4182 let retVal = await runInstance.runHookStep(new Step(sn.id), null, branchToGetError);4183 expect(retVal).to.equal(false);4184 expect(branchToGetError.error.message).to.equal("foobar");4185 expect(branchToGetError.error.filename).to.equal("file1.txt");4186 expect(branchToGetError.error.lineNumber).to.equal(11);4187 });4188 it("runs a failing hook step with only a branchToGetError, but branchToGetError already has an error set", async () => {4189 let tree = new Tree();4190 let sn = tree.newStepNode();4191 sn.filename = "file1.txt";4192 sn.lineNumber = 10;4193 sn.codeBlock = `4194 throw new Error("foobar");4195 `;4196 let branchToGetError = new Branch();4197 branchToGetError.error = new Error("existing error");4198 let runner = new Runner();4199 runner.init(tree, true);4200 let runInstance = new RunInstance(runner);4201 let retVal = await runInstance.runHookStep(new Step(sn.id), null, branchToGetError);4202 expect(retVal).to.equal(false);4203 expect(branchToGetError.error.message).to.equal("existing error");4204 });4205 it("runs a failing hook step with both a stepToGetError and a branchToGetError", async () => {4206 let tree = new Tree();4207 let sn = tree.newStepNode();4208 sn.filename = "file1.txt";4209 sn.lineNumber = 10;4210 sn.codeBlock = `4211 throw new Error("foobar");4212 `;4213 let stepToGetError = new Step();4214 stepToGetError.filename = "file2.txt";4215 stepToGetError.lineNumber = 20;4216 let branchToGetError = new Branch();4217 let runner = new Runner();4218 runner.init(tree, true);4219 let runInstance = new RunInstance(runner);4220 let retVal = await runInstance.runHookStep(new Step(sn.id), stepToGetError, branchToGetError);4221 expect(retVal).to.equal(false);4222 expect(stepToGetError.isFailed).to.equal(true);4223 expect(stepToGetError.error.message).to.equal("foobar");4224 expect(stepToGetError.error.filename).to.equal("file1.txt");4225 expect(stepToGetError.error.lineNumber).to.equal(11);4226 expect(branchToGetError.isFailed).to.equal(true);4227 expect(branchToGetError.error).to.equal(undefined);4228 });4229 it("runs a failing hook step with no stepToGetError and no branchToGetError", async () => {4230 let tree = new Tree();4231 let sn = tree.newStepNode();4232 sn.filename = "file1.txt";4233 sn.lineNumber = 10;4234 sn.codeBlock = `4235 throw new Error("foobar");4236 `;4237 let runner = new Runner();4238 runner.init(tree, true);4239 let runInstance = new RunInstance(runner);4240 let retVal = await runInstance.runHookStep(new Step(sn.id));4241 expect(retVal).to.equal(false);4242 });4243 });4244 describe("evalCodeBlock()", () => {4245 it("evals a code and returns a value asynchonously", async () => {4246 let runner = new Runner(new Tree());4247 let runInstance = new RunInstance(runner);4248 await expect(runInstance.evalCodeBlock("return 5;")).to.eventually.equal(5);4249 });4250 it("evals a code and returns a value synchronously", () => {4251 let runner = new Runner(new Tree());4252 let runInstance = new RunInstance(runner);4253 expect(runInstance.evalCodeBlock("return 5;", undefined, undefined, 0, undefined, true)).to.equal(5);4254 });4255 it("returns undefined when executing code that has no return value synchronously", () => {4256 let runner = new Runner(new Tree());4257 let runInstance = new RunInstance(runner);4258 expect(runInstance.evalCodeBlock("5;", undefined, undefined, 0, undefined, true)).to.equal(undefined);4259 });4260 it("makes the persistent, global, and local objects available", async () => {4261 let runner = new Runner(new Tree());4262 let runInstance = new RunInstance(runner);4263 runInstance.setPersistent("a", "A");4264 runInstance.setGlobal("b", "B");4265 runInstance.setLocal("c", "C");4266 await expect(runInstance.evalCodeBlock("return getPersistent('a');")).to.eventually.equal("A");4267 await expect(runInstance.evalCodeBlock("return getGlobal('b');")).to.eventually.equal("B");4268 await expect(runInstance.evalCodeBlock("return getLocal('c');")).to.eventually.equal("C");4269 await runInstance.evalCodeBlock("setPersistent('a', 'AA'); setGlobal('b', 'BB'); setLocal('c', 'CC');");4270 expect(runInstance.getPersistent("a")).to.equal("AA");4271 expect(runInstance.getGlobal("b")).to.equal("BB");4272 expect(runInstance.getLocal("c")).to.equal("CC");4273 });4274 it("makes persistent, global, and local variables available as js variables", async () => {4275 let runner = new Runner(new Tree());4276 let runInstance = new RunInstance(runner);4277 runInstance.setPersistent('a', "A");4278 runInstance.setGlobal('b', "B");4279 runInstance.setLocal('c', "C");4280 await expect(runInstance.evalCodeBlock("return a;")).to.eventually.equal("A");4281 await expect(runInstance.evalCodeBlock("return b;")).to.eventually.equal("B");4282 await expect(runInstance.evalCodeBlock("return c;")).to.eventually.equal("C");4283 });4284 it("makes a local variable accessible as a js variable if both a local and global variable share the same name", async () => {4285 let runner = new Runner(new Tree());4286 let runInstance = new RunInstance(runner);4287 runInstance.setGlobal('b', "B");4288 runInstance.setLocal('b', "C");4289 await expect(runInstance.evalCodeBlock("return b;")).to.eventually.equal("C");4290 });4291 it("makes a global variable accessible as a js variable if both a global and persistent variable share the same name", async () => {4292 let runner = new Runner(new Tree());4293 let runInstance = new RunInstance(runner);4294 runInstance.setPersistent('b', "B");4295 runInstance.setGlobal('b', "C");4296 await expect(runInstance.evalCodeBlock("return b;")).to.eventually.equal("C");4297 });4298 it("makes a local variable accessible as a js variable if both a local and persistent variable share the same name", async () => {4299 let runner = new Runner(new Tree());4300 let runInstance = new RunInstance(runner);4301 runInstance.setPersistent('b', "B");4302 runInstance.setLocal('b', "C");4303 await expect(runInstance.evalCodeBlock("return b;")).to.eventually.equal("C");4304 });4305 it("does not make a variable available as js variable if its name contains non-whitelisted characters", async () => {4306 let runner = new Runner(new Tree());4307 let runInstance = new RunInstance(runner);4308 runInstance.setPersistent(" one two ", "A");4309 runInstance.setGlobal("three four", "B");4310 runInstance.setLocal("five>six", "C");4311 runInstance.setLocal("seven", "D");4312 await expect(runInstance.evalCodeBlock("return seven;")).to.eventually.equal("D");4313 });4314 it("does not make a variable available as js variable if its name is blacklisted", async () => {4315 let runner = new Runner(new Tree());4316 let runInstance = new RunInstance(runner);4317 runInstance.setPersistent(" for ", "A");4318 runInstance.setGlobal("await", "B");4319 runInstance.setLocal("switch ", "C");4320 runInstance.setLocal("seven", "D");4321 await expect(runInstance.evalCodeBlock("return seven;")).to.eventually.equal("D");4322 });4323 it("allows for logging inside the code", async () => {4324 let runner = new Runner(new Tree());4325 let runInstance = new RunInstance(runner);4326 let step = new Step();4327 await runInstance.evalCodeBlock("log('foobar');", undefined, undefined, 0, step);4328 expect(step.log).to.eql([4329 {text: "foobar"}4330 ]);4331 });4332 it("handles an error inside the code, with a function name and line number", async () => {4333 let runner = new Runner(new Tree());4334 let runInstance = new RunInstance(runner);4335 let step = new Step();4336 let errorThrown = false;4337 try {4338 await runInstance.evalCodeBlock(`4339 let a = 1;4340 let b = 2;4341 throw new Error('oops');`, "Oops function!", undefined, 10, step);4342 }4343 catch(e) {4344 errorThrown = true;4345 expect(e.message).to.equal("oops");4346 expect(!!e.stack.match(/at CodeBlock_for_Oops_function[^\n]+<anonymous>:13:27\)/)).to.equal(true);4347 }4348 expect(errorThrown).to.be.true;4349 });4350 it("handles an error inside the code, with a function name and no filename or line number", async () => {4351 let runner = new Runner(new Tree());4352 let runInstance = new RunInstance(runner);4353 let step = new Step();4354 let errorThrown = false;4355 try {4356 await runInstance.evalCodeBlock(`4357 let a = 1;4358 let b = 2;4359 throw new Error('oops');`, "Oops function!", undefined, undefined, step);4360 }4361 catch(e) {4362 errorThrown = true;4363 expect(e.message).to.equal("oops");4364 expect(!!e.stack.match(/at CodeBlock_for_Oops_function[^\n]+<anonymous>:4:27\)/)).to.equal(true);4365 }4366 expect(errorThrown).to.be.true;4367 });4368 it("handles an error inside the code, with a function name with all invalid chars", async () => {4369 let runner = new Runner(new Tree());4370 let runInstance = new RunInstance(runner);4371 let step = new Step();4372 let errorThrown = false;4373 try {4374 await runInstance.evalCodeBlock(`4375 let a = 1;4376 let b = 2;4377 throw new Error('oops');`, "@!#!!", undefined, 10, step);4378 }4379 catch(e) {4380 errorThrown = true;4381 expect(e.message).to.equal("oops");4382 expect(!!e.stack.match(/at CodeBlock \([^\n]+<anonymous>:13:27\)/)).to.equal(true);4383 }4384 expect(errorThrown).to.be.true;4385 });4386 it("handles an error inside the code, with no function name", async () => {4387 let runner = new Runner(new Tree());4388 let runInstance = new RunInstance(runner);4389 let step = new Step();4390 let errorThrown = false;4391 try {4392 await runInstance.evalCodeBlock(`4393 let a = 1;4394 let b = 2;4395 throw new Error('oops');`, undefined, undefined, 20, step);4396 }4397 catch(e) {4398 errorThrown = true;4399 expect(e.message).to.equal("oops");4400 expect(!!e.stack.match(/at CodeBlock \([^\n]+<anonymous>:23:27\)/)).to.equal(true);4401 }4402 expect(errorThrown).to.be.true;4403 });4404 it("can import packages", async () => {4405 let runner = new Runner(new Tree());4406 let runInstance = new RunInstance(runner);4407 await expect(runInstance.evalCodeBlock(`4408 let chai = i('chai');4409 chai.expect(2+3).to.equal(2);4410 `)).to.be.rejectedWith("expected 5 to equal 2");4411 await expect(runInstance.evalCodeBlock(`4412 i('chai');4413 i('chai-as-promised');4414 getPersistent('chai').expect(!!getPersistent('chaiAsPromised')).to.be.true;4415 getPersistent('chai').expect(2+3).to.equal(2);4416 `)).to.be.rejectedWith("expected 5 to equal 2");4417 await expect(runInstance.evalCodeBlock(`4418 i('chai', 'chai');4419 i('chaiAsPromised', 'chai-as-promised');4420 getPersistent('chai').expect(!!getPersistent('chaiAsPromised')).to.be.true;4421 getPersistent('chai').expect(2+3).to.equal(2);4422 `)).to.be.rejectedWith("expected 5 to equal 2");4423 });4424 });4425 describe("i()", () => {4426 it("includes a file with just a package name", async () => {4427 let tree = new Tree();4428 tree.parseIn(`4429Step {4430 i('chalk');4431 runInstance.one = p('chalk');4432}4433 `, "file.txt");4434 let runner = new Runner(tree);4435 runner.init(tree, true);4436 let runInstance = new RunInstance(runner);4437 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);4438 expect(typeof runInstance.one).to.equal("function");4439 expect(tree.branches[0].isFailed).to.equal(undefined);4440 expect(tree.branches[0].steps[0].isFailed).to.equal(undefined);4441 });4442 it("includes a file with a package name and variable name", async () => {4443 let tree = new Tree();4444 tree.parseIn(`4445Step {4446 i('colorful', 'chalk');4447 runInstance.one = p('colorful');4448}4449 `, "file.txt");4450 let runner = new Runner(tree);4451 runner.init(tree, true);4452 let runInstance = new RunInstance(runner);4453 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);4454 expect(typeof runInstance.one).to.equal("function");4455 expect(tree.branches[0].isFailed).to.equal(undefined);4456 expect(tree.branches[0].steps[0].isFailed).to.equal(undefined);4457 });4458 it("includes a file that has already been included", async () => {4459 let tree = new Tree();4460 tree.parseIn(`4461Step {4462 i('chalk');4463 i('chalk');4464 runInstance.one = p('chalk');4465}4466 `, "file.txt");4467 let runner = new Runner(tree);4468 runner.init(tree, true);4469 let runInstance = new RunInstance(runner);4470 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);4471 expect(typeof runInstance.one).to.equal("function");4472 expect(tree.branches[0].isFailed).to.equal(undefined);4473 expect(tree.branches[0].steps[0].isFailed).to.equal(undefined);4474 });4475 it("returns the object being included", async () => {4476 let tree = new Tree();4477 tree.parseIn(`4478Step {4479 runInstance.one = i('chalk');4480}4481 `, "file.txt");4482 let runner = new Runner(tree);4483 runner.init(tree, true);4484 let runInstance = new RunInstance(runner);4485 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);4486 expect(typeof runInstance.one).to.equal("function");4487 expect(tree.branches[0].isFailed).to.equal(undefined);4488 expect(tree.branches[0].steps[0].isFailed).to.equal(undefined);4489 });4490 // Skipped because the absolute path changes4491 it.skip("includes a file with an absolute path", async () => {4492 let tree = new Tree();4493 tree.parseIn(`4494Step {4495 runInstance.one = i('/ABSOLUTE-PATH-HERE/smashtest/node_modules/chalk');4496}4497 `, "file.txt");4498 let runner = new Runner(tree);4499 runner.init(tree, true);4500 let runInstance = new RunInstance(runner);4501 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);4502 expect(typeof runInstance.one).to.equal("function");4503 expect(tree.branches[0].isFailed).to.equal(undefined);4504 expect(tree.branches[0].steps[0].isFailed).to.equal(undefined);4505 });4506 it("includes a file with a relative path that starts with .", async () => {4507 let tree = new Tree();4508 tree.parseIn(`4509Step {4510 runInstance.one = i('./branch.js');4511}4512 `, "file.txt");4513 let runner = new Runner(tree);4514 runner.init(tree, true);4515 let runInstance = new RunInstance(runner);4516 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);4517 expect(typeof runInstance.one).to.equal("function");4518 expect(tree.branches[0].isFailed).to.equal(undefined);4519 expect(tree.branches[0].steps[0].isFailed).to.equal(undefined);4520 });4521 it("includes a file with a relative path that starts with ..", async () => {4522 let tree = new Tree();4523 tree.parseIn(`4524Step {4525 runInstance.one = i('../../smashtest/node_modules/chalk');4526}4527 `, "file.txt");4528 let runner = new Runner(tree);4529 runner.init(tree, true);4530 let runInstance = new RunInstance(runner);4531 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);4532 expect(typeof runInstance.one).to.equal("function");4533 expect(tree.branches[0].isFailed).to.equal(undefined);4534 expect(tree.branches[0].steps[0].isFailed).to.equal(undefined);4535 });4536 it("includes a file using a module name, where the file resides in the executable's node_modules", async () => {4537 let tree = new Tree();4538 tree.parseIn(`4539Step {4540 runInstance.one = i('chalk');4541}4542 `, "file.txt");4543 let runner = new Runner(tree);4544 runner.init(tree, true);4545 let runInstance = new RunInstance(runner);4546 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);4547 expect(typeof runInstance.one).to.equal("function");4548 expect(tree.branches[0].isFailed).to.equal(undefined);4549 expect(tree.branches[0].steps[0].isFailed).to.equal(undefined);4550 });4551 // Skipped because the absolute path changes4552 it.skip("includes a file using a module name, where the file resides in the node_modules of the file of the current step", async () => {4553 let tree = new Tree();4554 tree.parseIn(`4555Step {4556 runInstance.one = i('chalk');4557}4558 `, "/ABSOLUTE-PATH-HERE/file.txt");4559 let runner = new Runner(tree);4560 runner.init(tree, true);4561 let runInstance = new RunInstance(runner);4562 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);4563 expect(typeof runInstance.one).to.equal("function");4564 expect(tree.branches[0].isFailed).to.equal(undefined);4565 expect(tree.branches[0].steps[0].isFailed).to.equal(undefined);4566 });4567 it("rejects a file with an absolute path that cannot be found", async () => {4568 let tree = new Tree();4569 tree.parseIn(`4570Step {4571 i('/bad/path/chalk');4572}4573 `, "file.txt");4574 let runner = new Runner(tree);4575 runner.init(tree, true);4576 let runInstance = new RunInstance(runner);4577 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);4578 expect(tree.branches[0].isFailed).to.be.true;4579 expect(tree.branches[0].steps[0].isFailed).to.be.true;4580 expect(tree.branches[0].steps[0].error.message).to.contain(`Cannot find module '/bad/path/chalk'`);4581 });4582 it("rejects a file with a relative path that cannot be found", async () => {4583 let tree = new Tree();4584 tree.parseIn(`4585Step {4586 i('../bad/path/chalk');4587}4588 `, "file.txt");4589 let runner = new Runner(tree);4590 runner.init(tree, true);4591 let runInstance = new RunInstance(runner);4592 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);4593 expect(tree.branches[0].isFailed).to.be.true;4594 expect(tree.branches[0].steps[0].isFailed).to.be.true;4595 expect(tree.branches[0].steps[0].error.message).to.contain(`Cannot find module './../bad/path/chalk'`);4596 });4597 it("rejects a file with a module name that cannot be found", async () => {4598 let tree = new Tree();4599 tree.parseIn(`4600Step {4601 i('bad-module');4602}4603 `, "file.txt");4604 let runner = new Runner(tree);4605 runner.init(tree, true);4606 let runInstance = new RunInstance(runner);4607 await runInstance.runStep(tree.branches[0].steps[0], tree.branches[0], false);4608 expect(tree.branches[0].isFailed).to.be.true;4609 expect(tree.branches[0].steps[0].isFailed).to.be.true;4610 expect(tree.branches[0].steps[0].error.message).to.contain(`Cannot find module 'node_modules/bad-module'`);4611 });4612 });4613 describe("replaceVars()", () => {4614 it("replaces {vars} and {{vars}} with their values", () => {4615 let tree = new Tree();4616 tree.parseIn(`4617A -4618 {var1}='value1'4619 {{var2}} = 'value2'4620 {var 3}= "value 3", {{var5}} ='value5',{var6}=[value6]4621 {{ var 4 }}=" value 4 "4622`, "file.txt");4623 let runner = new Runner();4624 runner.init(tree, true);4625 let runInstance = new RunInstance(runner);4626 runInstance.currBranch = tree.branches[0];4627 runInstance.currStep = tree.branches[0].steps[0];4628 runInstance.setGlobal("var0", "value0");4629 expect(runInstance.replaceVars("{var0} {var1:} - {{var2:}}{var 3:}-{{var 4:}} {{var5:}} {var6:}")).to.equal("value0 value1 - value2value 3- value 4 value5 value6");4630 });4631 it("handles a branch of null", () => {4632 let tree = new Tree();4633 tree.parseIn(`4634{var1}='value1'4635`, "file.txt");4636 let runner = new Runner();4637 runner.init(tree, true);4638 let runInstance = new RunInstance(runner);4639 runInstance.currBranch = null;4640 runInstance.currStep = tree.branches[0].steps[0];4641 runInstance.setGlobal("var0", "value0");4642 expect(runInstance.replaceVars("{var0} {var1:}")).to.equal("value0 value1");4643 });4644 it("doesn't affect a string that doesn't contain variables", () => {4645 let tree = new Tree();4646 tree.parseIn(`4647A -4648`, "file.txt");4649 let runner = new Runner();4650 runner.init(tree, true);4651 let runInstance = new RunInstance(runner);4652 runInstance.currBranch = tree.branches[0];4653 runInstance.currStep = tree.branches[0].steps[0];4654 expect(runInstance.replaceVars("foo bar")).to.equal("foo bar");4655 });4656 // Skipped because it runs slow and we don't need to run it each time4657 it.skip("throws an error when vars reference each other in an infinite loop", () => {4658 let tree = new Tree();4659 tree.parseIn(`4660A -4661 {var1}='{var1}'4662`, "file.txt");4663 let runner = new Runner();4664 runner.init(tree, true);4665 let runInstance = new RunInstance(runner);4666 runInstance.currBranch = tree.branches[0];4667 runInstance.currStep = tree.branches[0].steps[0];4668 assert.throws(() => {4669 runInstance.replaceVars("{var1:}");4670 }, "Infinite loop detected amongst variable references");4671 tree = new Tree();4672 tree.parseIn(`4673A -4674 {var1}='{var2:} {var3:}'4675 {var2}='foo'4676 {var3}='bar{var1}'4677`, "file.txt");4678 runner = new Runner();4679 runner.init(tree, true);4680 runInstance = new RunInstance(runner);4681 runInstance.currBranch = tree.branches[0];4682 runInstance.currStep = tree.branches[0].steps[0];4683 assert.throws(() => {4684 expect(runInstance.replaceVars("{var1:}"));4685 }, "Infinite loop detected amongst variable references");4686 });4687 it("replaces vars by looking above and below when lookAnywhere is set to true", () => {4688 let tree = new Tree();4689 tree.parseIn(`4690A -4691 {var1}='value1'4692`, "file.txt");4693 let runner = new Runner();4694 runner.init(tree, true);4695 let runInstance = new RunInstance(runner);4696 runInstance.currBranch = tree.branches[0];4697 runInstance.currStep = tree.branches[0].steps[0];4698 runInstance.setGlobal("var0", "value0");4699 expect(runInstance.replaceVars("{var0} {var1}", true)).to.equal("value0 value1");4700 });4701 it("throws an error when a var isn't set above or below and when lookAnywhere is set to true", () => {4702 let tree = new Tree();4703 tree.parseIn(`4704A -4705 {var1}='value1'4706`, "file.txt");4707 let runner = new Runner();4708 runner.init(tree, true);4709 let runInstance = new RunInstance(runner);4710 runInstance.currBranch = tree.branches[0];4711 runInstance.currStep = tree.branches[0].steps[0];4712 assert.throws(() => {4713 runInstance.replaceVars("{var2}", true);4714 }, "The variable {var2} is never set, but is needed for this step");4715 assert.throws(() => {4716 runInstance.replaceVars("{var2 :}", true);4717 }, "The variable {var2 :} is never set, but is needed for this step");4718 });4719 });4720 describe("findVarValue()", () => {4721 it("returns the value of a local variable that's already set", () => {4722 let tree = new Tree();4723 tree.parseIn(`4724A -4725`, "file.txt");4726 let runner = new Runner();4727 runner.init(tree, true);4728 let runInstance = new RunInstance(runner);4729 runInstance.setLocal("var0", "value0");4730 runInstance.currBranch = tree.branches[0];4731 runInstance.currStep = tree.branches[0].steps[0];4732 expect(runInstance.findVarValue("var0", true)).to.equal("value0");4733 });4734 it("returns the value of a global variable that's already set", () => {4735 let tree = new Tree();4736 tree.parseIn(`4737A -4738`, "file.txt");4739 let runner = new Runner();4740 runner.init(tree, true);4741 let runInstance = new RunInstance(runner);4742 runInstance.setGlobal("var0", "value0");4743 runInstance.currBranch = tree.branches[0];4744 runInstance.currStep = tree.branches[0].steps[0];4745 expect(runInstance.findVarValue("var0", false)).to.equal("value0");4746 });4747 it("returns the value of a variable with a branch of null", () => {4748 let tree = new Tree();4749 tree.parseIn(`4750{var1}='value1'4751`, "file.txt");4752 let runner = new Runner();4753 runner.init(tree, true);4754 let runInstance = new RunInstance(runner);4755 runInstance.currBranch = null;4756 runInstance.currStep = tree.branches[0].steps[0];4757 expect(runInstance.findVarValue("var1:", false)).to.equal("value1");4758 });4759 it("can find variables defined later on the same line", () => {4760 let tree = new Tree();4761 tree.parseIn(`4762{var1}='foo {var2:}', {var2}='bar'4763`, "file.txt");4764 let runner = new Runner();4765 runner.init(tree, true);4766 let runInstance = new RunInstance(runner);4767 runInstance.currBranch = null;4768 runInstance.currStep = tree.branches[0].steps[0];4769 expect(runInstance.findVarValue("var1:", false)).to.equal("foo bar");4770 });4771 it("returns the value of a variable that's not set yet and whose eventual value is a plain string", () => {4772 let tree = new Tree();4773 tree.parseIn(`4774A -4775 {var1}="value1"4776`, "file.txt");4777 let runner = new Runner();4778 runner.init(tree, true);4779 let runInstance = new RunInstance(runner);4780 runInstance.currBranch = tree.branches[0];4781 runInstance.currStep = tree.branches[0].steps[0];4782 expect(runInstance.findVarValue("var1:", false)).to.equal("value1");4783 expect(tree.branches[0].steps[0].log).to.eql([4784 {text: "The value of variable {var1:} is being set by a later step at file.txt:3"}4785 ]);4786 });4787 it("throws an error if a local variable is not yet set but is set outside the scope of the current function", () => {4788 let tree = new Tree();4789 tree.parseIn(`4790My function4791 {{var1}}="value1"4792* My function4793 A -4794`, "file.txt");4795 let runner = new Runner();4796 runner.init(tree, true);4797 let runInstance = new RunInstance(runner);4798 runInstance.currBranch = tree.branches[0];4799 runInstance.currStep = tree.branches[0].steps[1];4800 assert.throws(() => {4801 runInstance.findVarValue("var1:", true);4802 }, "The variable {{var1:}} is never set, but is needed for this step");4803 });4804 it("returns the value of a variable given the same variable name in a different case", () => {4805 let tree = new Tree();4806 tree.parseIn(`4807A -4808 {var one}="value1"4809`, "file.txt");4810 let runner = new Runner();4811 runner.init(tree, true);4812 let runInstance = new RunInstance(runner);4813 runInstance.currBranch = tree.branches[0];4814 runInstance.currStep = tree.branches[0].steps[0];4815 expect(runInstance.findVarValue("var ONE:", false)).to.equal("value1");4816 expect(tree.branches[0].steps[0].log).to.eql([4817 {text: "The value of variable {var ONE:} is being set by a later step at file.txt:3"}4818 ]);4819 });4820 it("returns the value of a variable given the same variable name but with varying amounts of whitespace", () => {4821 let tree = new Tree();4822 tree.parseIn(`4823A -4824 { var one }="value1"4825`, "file.txt");4826 let runner = new Runner();4827 runner.init(tree, true);4828 let runInstance = new RunInstance(runner);4829 runInstance.currBranch = tree.branches[0];4830 runInstance.currStep = tree.branches[0].steps[0];4831 expect(runInstance.findVarValue("var one:", false)).to.equal("value1");4832 expect(tree.branches[0].steps[0].log).to.eql([4833 { text: "The value of variable {var one:} is being set by a later step at file.txt:3" }4834 ]);4835 tree = new Tree();4836 tree.parseIn(`4837A -4838 {var one}="value1"4839`, "file.txt");4840 runner = new Runner();4841 runner.init(tree, true);4842 runInstance = new RunInstance(runner);4843 runInstance.currBranch = tree.branches[0];4844 runInstance.currStep = tree.branches[0].steps[0];4845 expect(runInstance.findVarValue(" var ONE : ", false)).to.equal("value1");4846 expect(tree.branches[0].steps[0].log).to.eql([4847 { text: "The value of variable { var ONE : } is being set by a later step at file.txt:3" }4848 ]);4849 });4850 it("returns the value of a variable that's not set yet and whose eventual value contains more variables", () => {4851 // If the original step is A, and its vars are defined in B, then's B's vars are defined 1) before A, 2) between A and B, and 3) after B4852 let tree = new Tree();4853 tree.parseIn(`4854A -4855 {{var2}} = 'value2'4856 {var1}='{{var2}} {var 3 :} . {var0} {{var5:}}'4857 {var 3}= "-{{var 4 :}}-", {{var5}}='value5'4858 B -4859 {{ var 4 }}=[ value 4 ]4860`, "file.txt");4861 let runner = new Runner();4862 runner.init(tree, true);4863 let runInstance = new RunInstance(runner);4864 runInstance.currBranch = tree.branches[0];4865 runInstance.currStep = tree.branches[0].steps[0];4866 runInstance.setGlobal("var0", "value0");4867 expect(runInstance.findVarValue("var1 :", false)).to.equal("value2 - value 4 - . value0 value5");4868 expect(tree.branches[0].steps[0].log).to.eql([4869 { text: "The value of variable {{var2}} is being set by a later step at file.txt:3" },4870 { text: "The value of variable {{var 4 :}} is being set by a later step at file.txt:7" },4871 { text: "The value of variable {var 3 :} is being set by a later step at file.txt:5" },4872 { text: "The value of variable {{var5:}} is being set by a later step at file.txt:5" },4873 { text: "The value of variable {var1 :} is being set by a later step at file.txt:4" }4874 ]);4875 });4876 it("returns the value of a variable that's not set yet and whose eventual value is generated from a sync code block function", () => {4877 let tree = new Tree();4878 tree.parseIn(`4879A -4880 {var1} = F {4881 return "foobar";4882 }4883 {var2} = F24884 * F2 {4885 return "blah";4886 }4887`, "file.txt");4888 let runner = new Runner();4889 runner.init(tree, true);4890 let runInstance = new RunInstance(runner);4891 runInstance.currBranch = tree.branches[0];4892 runInstance.currStep = tree.branches[0].steps[0];4893 expect(runInstance.findVarValue("var1 :", false)).to.equal("foobar");4894 expect(tree.branches[0].steps[0].log).to.eql([4895 { text: "The value of variable {var1 :} is being set by a later step at file.txt:3" }4896 ]);4897 expect(runInstance.findVarValue("var2:", false)).to.equal("blah");4898 expect(tree.branches[0].steps[0].log).to.eql([4899 { text: "The value of variable {var1 :} is being set by a later step at file.txt:3" },4900 { text: "The value of variable {var2:} is being set by a later step at file.txt:7" }4901 ]);4902 });4903 it("throws an error if the variable's value is not set", () => {4904 let tree = new Tree();4905 tree.parseIn(`4906A -4907 {var1}="value1"4908`, "file.txt");4909 let runner = new Runner();4910 runner.init(tree, true);4911 let runInstance = new RunInstance(runner);4912 runInstance.currBranch = tree.branches[0];4913 runInstance.currStep = tree.branches[0].steps[0];4914 assert.throws(() => {4915 runInstance.findVarValue("var2", false);4916 }, "The variable {var2} wasn't set, but is needed for this step");4917 });4918 it("throws an error if the variable's value is set ahead, but the variable is not a lookahead", () => {4919 let tree = new Tree();4920 tree.parseIn(`4921A -4922 {var1}="value1"4923`, "file.txt");4924 let runner = new Runner();4925 runner.init(tree, true);4926 let runInstance = new RunInstance(runner);4927 runInstance.currBranch = tree.branches[0];4928 runInstance.currStep = tree.branches[0].steps[0];4929 assert.throws(() => {4930 runInstance.findVarValue("var1", false);4931 }, "The variable {var1} wasn't set, but is needed for this step");4932 });4933 it("throws an error if the lookahead variable's value is never set", () => {4934 let tree = new Tree();4935 tree.parseIn(`4936A -4937 {var1}="value1"4938`, "file.txt");4939 let runner = new Runner();4940 runner.init(tree, true);4941 let runInstance = new RunInstance(runner);4942 runInstance.currBranch = tree.branches[0];4943 runInstance.currStep = tree.branches[0].steps[0];4944 assert.throws(() => {4945 runInstance.findVarValue("var2:", false);4946 }, "The variable {var2:} is never set, but is needed for this step");4947 });4948 it("throws an error if the lookahead variable's value is set, but the * isn't used", () => {4949 let tree = new Tree();4950 tree.parseIn(`4951A -4952 {var1}="value1"4953`, "file.txt");4954 let runner = new Runner();4955 runner.init(tree, true);4956 let runInstance = new RunInstance(runner);4957 runInstance.currBranch = tree.branches[0];4958 runInstance.currStep = tree.branches[0].steps[0];4959 assert.throws(() => {4960 runInstance.findVarValue("var1", false);4961 }, "The variable {var1} wasn't set, but is needed for this step");4962 });4963 it("uses the existing value if : isn't used", () => {4964 let tree = new Tree();4965 tree.parseIn(`4966A -4967 {var1}="bar"4968`, "file.txt");4969 let runner = new Runner();4970 runner.init(tree, true);4971 let runInstance = new RunInstance(runner);4972 runInstance.g('var1', 'foo');4973 runInstance.currBranch = tree.branches[0];4974 runInstance.currStep = tree.branches[0].steps[0];4975 expect(runInstance.findVarValue("var1", false)).to.equal("foo");4976 });4977 it("uses the value ahead if : is used", () => {4978 let tree = new Tree();4979 tree.parseIn(`4980A -4981 {var1}="bar"4982`, "file.txt");4983 let runner = new Runner();4984 runner.init(tree, true);4985 let runInstance = new RunInstance(runner);4986 runInstance.g('var1', 'foo');4987 runInstance.currBranch = tree.branches[0];4988 runInstance.currStep = tree.branches[0].steps[0];4989 expect(runInstance.findVarValue("var1:", false)).to.equal("bar");4990 });4991 it("throws an error if the variable's value contains more variables, but one of those variables is never set", () => {4992 let tree = new Tree();4993 tree.parseIn(`4994A -4995 {var1}="-{{var2:}}-"4996 {{var3}}="-{var4}-"4997`, "file.txt");4998 let runner = new Runner();4999 runner.init(tree, true);5000 let runInstance = new RunInstance(runner);5001 runInstance.currBranch = tree.branches[0];5002 runInstance.currStep = tree.branches[0].steps[0];5003 assert.throws(() => {5004 runInstance.findVarValue("var1:", false);5005 }, "The variable {{var2:}} is never set, but is needed for this step");5006 assert.throws(() => {5007 runInstance.findVarValue("var3:", true);5008 }, "The variable {var4} is never set, but is needed for this step");5009 });5010 it("finds var values by looking above and below when lookAnywhere is set to true", () => {5011 let tree = new Tree();5012 tree.parseIn(`5013A -5014 {var1}='value1'5015`, "file.txt");5016 let runner = new Runner();5017 runner.init(tree, true);5018 let runInstance = new RunInstance(runner);5019 runInstance.currBranch = tree.branches[0];5020 runInstance.currStep = tree.branches[0].steps[0];5021 runInstance.setGlobal("var0", "value0");5022 expect(runInstance.findVarValue("var0", false, true)).to.equal("value0");5023 expect(runInstance.findVarValue("var1", false, true)).to.equal("value1");5024 });5025 it("throws an error when a var isn't set above or below and when lookAnywhere is set to true", () => {5026 let tree = new Tree();5027 tree.parseIn(`5028A -5029 {var1}='value1'5030`, "file.txt");5031 let runner = new Runner();5032 runner.init(tree, true);5033 let runInstance = new RunInstance(runner);5034 runInstance.currBranch = tree.branches[0];5035 runInstance.currStep = tree.branches[0].steps[0];5036 assert.throws(() => {5037 runInstance.findVarValue("var2", false, true);5038 }, "The variable {var2} is never set, but is needed for this step");5039 assert.throws(() => {5040 runInstance.findVarValue("var2 :", false, true);5041 }, "The variable {var2 :} is never set, but is needed for this step");5042 });5043 });5044 describe("appendToLog()", () => {5045 it("logs a string to a step, where no other logs exist", () => {5046 let step = new Step();5047 let runner = new Runner(new Tree());5048 let runInstance = new RunInstance(runner);5049 runInstance.appendToLog("foobar", step);5050 expect(step.log).to.eql([5051 { text: "foobar" }5052 ]);5053 });5054 it("logs a string to a step, where other logs exist", () => {5055 let step = new Step();5056 let branch = new Branch();5057 let runner = new Runner(new Tree());5058 let runInstance = new RunInstance(runner);5059 branch.log = [5060 { text: "foo" }5061 ];5062 runInstance.appendToLog("bar", step || branch);5063 expect(step.log).to.eql([5064 { text: "bar" }5065 ]);5066 });5067 it("logs a string to a branch, where no other logs exist and where there is no step", () => {5068 let branch = new Branch();5069 let runner = new Runner(new Tree());5070 let runInstance = new RunInstance(runner);5071 runInstance.appendToLog("foobar", null || branch);5072 expect(branch.log).to.eql([5073 { text: "foobar" }5074 ]);5075 });5076 it("logs a string to a branch, where other logs exist and where there is no step", () => {5077 let branch = new Branch();5078 let runner = new Runner(new Tree());5079 let runInstance = new RunInstance(runner);5080 branch.log = [5081 { text: "foo" }5082 ];5083 runInstance.appendToLog("bar", null || branch);5084 expect(branch.log).to.eql([5085 { text: "foo" },5086 { text: "bar" }5087 ]);5088 });5089 it("fails silently when there is no step or branch", () => {5090 let step = new Step();5091 let runner = new Runner(new Tree());5092 let runInstance = new RunInstance(runner);5093 assert.doesNotThrow(() => {5094 runInstance.appendToLog("foobar", null || null);5095 });5096 });5097 });5098 describe("stop()", () => {5099 it("stops the RunInstance, time elapsed for the branches are properly measured, and no more steps are running", () => {5100 let tree = new Tree();5101 tree.parseIn(`5102Wait 20ms {5103 await new Promise((resolve, reject) => {5104 setTimeout(() => {5105 resolve();5106 }, 20);5107 });5108}5109 A {5110 runInstance.ranStepA = true;5111 }5112Second branch -5113 B {5114 runInstance.ranStepB = true;5115 }5116`, "file.txt");5117 let runner = new Runner();5118 runner.init(tree, true);5119 let runInstance = new RunInstance(runner);5120 // The branches take 20 ms to run, but will be stopped 10ms in5121 var runInstancePromise = runInstance.run();5122 // 10 ms in5123 setTimeout(() => {5124 runInstance.stop();5125 expect(runInstance.isStopped).to.be.true;5126 expect(runInstance.ranStepA).to.be.undefined;5127 expect(runInstance.ranStepB).to.be.undefined;5128 expect(tree.branches[0].steps[0].isRunning).to.be.undefined;5129 expect(tree.branches[0].steps[1].isRunning).to.be.undefined;5130 expect(tree.branches[1].steps[0].isRunning).to.be.undefined;5131 expect(tree.branches[1].steps[1].isRunning).to.be.undefined;5132 }, 10);5133 // 20 ms in, RunInstance is done and ends itself5134 return runInstancePromise.then(() => {5135 expect(runInstance.isStopped).to.be.true;5136 expect(runInstance.ranStepA).to.be.undefined;5137 expect(runInstance.ranStepB).to.be.undefined;5138 expect(tree.branches[0].steps[0].isRunning).to.be.undefined;5139 expect(tree.branches[0].steps[1].isRunning).to.be.undefined;5140 expect(tree.branches[1].steps[0].isRunning).to.be.undefined;5141 expect(tree.branches[1].steps[1].isRunning).to.be.undefined;5142 expect(tree.branches[0].elapsed).to.be.above(15);5143 expect(tree.branches[1].elapsed).to.be.undefined;5144 });5145 });5146 it("doesn't log or error to branches or steps once a stop is made", () => {5147 let tree = new Tree();5148 tree.parseIn(`5149Big step {5150 await new Promise((resolve, reject) => {5151 setTimeout(() => {5152 resolve();5153 }, 20);5154 });5155 // log and error happen after a stop occurred mid-step5156 log("log from A");5157 throw new Error("error from A");5158}5159`, "file.txt");5160 let runner = new Runner();5161 runner.init(tree, true);5162 let runInstance = new RunInstance(runner);5163 // The branches take 20 ms to run, but will be stopped 10ms in5164 var runInstancePromise = runInstance.run();5165 // 10 ms in5166 setTimeout(() => {5167 runInstance.stop();5168 }, 10);5169 // 20 ms in, RunInstance is done and ends itself5170 return runInstancePromise.then(() => {5171 expect(runInstance.isStopped).to.be.true;5172 expect(tree.branches[0].steps[0].log).to.be.undefined;5173 expect(tree.branches[0].steps[0].error).to.be.undefined;5174 });5175 });5176 });5177 describe("runOneStep()", async () => {5178 it("runs the step currently paused on if it's not completed yet and then pauses again", async () => {5179 let tree = new Tree();5180 tree.parseIn(`5181~ A {5182 runInstance.ranStepA = !runInstance.ranStepA;5183}5184 B {5185 runInstance.ranStepB = !runInstance.ranStepB;5186 }5187 C {5188 runInstance.ranStepC = !runInstance.ranStepC;5189 }5190*** Before Every Branch {5191 runInstance.beforeEveryBranchRan = !runInstance.beforeEveryBranchRan;5192}5193*** After Every Branch {5194 runInstance.afterEveryBranchRan = !runInstance.afterEveryBranchRan;5195}5196`, "file.txt");5197 let runner = new Runner();5198 runner.init(tree, true);5199 let runInstance = new RunInstance(runner);5200 await runInstance.run();5201 expect(runInstance.isPaused).to.be.true;5202 expect(runInstance.ranStepA).to.be.undefined;5203 expect(runInstance.ranStepB).to.be.undefined;5204 expect(runInstance.ranStepC).to.be.undefined;5205 expect(tree.branches[0].isPassed).to.be.undefined;5206 expect(runInstance.afterEveryBranchRan).to.be.undefined;5207 expect(runInstance.beforeEveryBranchRan).to.be.true;5208 let isBranchComplete = await runInstance.runOneStep();5209 expect(runInstance.isPaused).to.be.true;5210 expect(runInstance.ranStepA).to.be.true;5211 expect(runInstance.ranStepB).to.be.undefined;5212 expect(runInstance.ranStepC).to.be.undefined;5213 expect(tree.branches[0].isPassed).to.be.undefined;5214 expect(runInstance.afterEveryBranchRan).to.be.undefined;5215 expect(runInstance.beforeEveryBranchRan).to.be.true;5216 expect(isBranchComplete).to.be.false;5217 isBranchComplete = await runInstance.runOneStep();5218 expect(runInstance.isPaused).to.be.true;5219 expect(runInstance.ranStepA).to.be.true;5220 expect(runInstance.ranStepB).to.be.true;5221 expect(runInstance.ranStepC).to.be.undefined;5222 expect(tree.branches[0].isPassed).to.be.undefined;5223 expect(runInstance.afterEveryBranchRan).to.be.undefined;5224 expect(runInstance.beforeEveryBranchRan).to.be.true;5225 expect(isBranchComplete).to.be.false;5226 isBranchComplete = await runInstance.runOneStep();5227 expect(runInstance.isPaused).to.be.true;5228 expect(runInstance.ranStepA).to.be.true;5229 expect(runInstance.ranStepB).to.be.true;5230 expect(runInstance.ranStepC).to.be.true;5231 expect(tree.branches[0].isPassed).to.be.true;5232 expect(runInstance.afterEveryBranchRan).to.be.undefined; // doesn't run After Every Branch until one more runOneStep() call5233 expect(runInstance.beforeEveryBranchRan).to.be.true;5234 expect(isBranchComplete).to.be.false;5235 isBranchComplete = await runInstance.runOneStep();5236 expect(runInstance.isPaused).to.be.true;5237 expect(runInstance.ranStepA).to.be.true;5238 expect(runInstance.ranStepB).to.be.true;5239 expect(runInstance.ranStepC).to.be.true;5240 expect(tree.branches[0].isPassed).to.be.true;5241 expect(runInstance.afterEveryBranchRan).to.be.true;5242 expect(runInstance.beforeEveryBranchRan).to.be.true;5243 expect(isBranchComplete).to.be.true;5244 });5245 it("doesn't run the step currently paused on if it's completed already, runs the step after that, then pauses again", async () => {5246 let tree = new Tree();5247 tree.parseIn(`5248A {5249 runInstance.ranStepA = !runInstance.ranStepA;5250 let e = new Error();5251 e.continue = true;5252 throw e;5253}5254 B {5255 runInstance.ranStepB = !runInstance.ranStepB;5256 }5257 C {5258 runInstance.ranStepC = !runInstance.ranStepC;5259 }5260*** Before Every Branch {5261 runInstance.beforeEveryBranchRan = !runInstance.beforeEveryBranchRan;5262}5263*** After Every Branch {5264 runInstance.afterEveryBranchRan = !runInstance.afterEveryBranchRan;5265}5266`, "file.txt");5267 let runner = new Runner();5268 runner.init(tree, true);5269 runner.pauseOnFail = true;5270 let runInstance = new RunInstance(runner);5271 await runInstance.run();5272 expect(runInstance.isPaused).to.be.true;5273 expect(runInstance.ranStepA).to.be.true;5274 expect(runInstance.ranStepB).to.be.undefined;5275 expect(runInstance.ranStepC).to.be.undefined;5276 expect(tree.branches[0].isFailed).to.be.undefined;5277 expect(runInstance.afterEveryBranchRan).to.be.undefined;5278 expect(runInstance.beforeEveryBranchRan).to.be.true;5279 let isBranchComplete = await runInstance.runOneStep();5280 expect(runInstance.isPaused).to.be.true;5281 expect(runInstance.ranStepA).to.be.true;5282 expect(runInstance.ranStepB).to.be.true;5283 expect(runInstance.ranStepC).to.be.undefined;5284 expect(tree.branches[0].isFailed).to.be.undefined;5285 expect(runInstance.afterEveryBranchRan).to.be.undefined;5286 expect(runInstance.beforeEveryBranchRan).to.be.true;5287 expect(isBranchComplete).to.be.false;5288 isBranchComplete = await runInstance.runOneStep();5289 expect(runInstance.isPaused).to.be.true;5290 expect(runInstance.ranStepA).to.be.true;5291 expect(runInstance.ranStepB).to.be.true;5292 expect(runInstance.ranStepC).to.be.true;5293 expect(tree.branches[0].isFailed).to.be.true;5294 expect(runInstance.afterEveryBranchRan).to.be.undefined; // doesn't run After Every Branch until one more runOneStep() call5295 expect(runInstance.beforeEveryBranchRan).to.be.true;5296 expect(isBranchComplete).to.be.false;5297 isBranchComplete = await runInstance.runOneStep();5298 expect(runInstance.isPaused).to.be.true;5299 expect(runInstance.ranStepA).to.be.true;5300 expect(runInstance.ranStepB).to.be.true;5301 expect(runInstance.ranStepC).to.be.true;5302 expect(tree.branches[0].isFailed).to.be.true;5303 expect(runInstance.afterEveryBranchRan).to.be.true;5304 expect(runInstance.beforeEveryBranchRan).to.be.true;5305 expect(isBranchComplete).to.be.true;5306 });5307 it("works when currently paused on the last step, which has not completed yet", async () => {5308 let tree = new Tree();5309 tree.parseIn(`5310A {5311 runInstance.ranStepA = !runInstance.ranStepA;5312}5313 B {5314 runInstance.ranStepB = !runInstance.ranStepB;5315 }5316 ~ C {5317 runInstance.ranStepC = !runInstance.ranStepC;5318 }5319*** Before Every Branch {5320 runInstance.beforeEveryBranchRan = !runInstance.beforeEveryBranchRan;5321}5322*** After Every Branch {5323 runInstance.afterEveryBranchRan = !runInstance.afterEveryBranchRan;5324}5325`, "file.txt");5326 let runner = new Runner();5327 runner.init(tree, true);5328 let runInstance = new RunInstance(runner);5329 await runInstance.run();5330 expect(runInstance.isPaused).to.be.true;5331 expect(runInstance.ranStepA).to.be.true;5332 expect(runInstance.ranStepB).to.be.true;5333 expect(runInstance.ranStepC).to.be.undefined;5334 expect(tree.branches[0].isPassed).to.be.undefined;5335 expect(runInstance.afterEveryBranchRan).to.be.undefined;5336 expect(runInstance.beforeEveryBranchRan).to.be.true;5337 let isBranchComplete = await runInstance.runOneStep();5338 expect(runInstance.isPaused).to.be.true;5339 expect(runInstance.ranStepA).to.be.true;5340 expect(runInstance.ranStepB).to.be.true;5341 expect(runInstance.ranStepC).to.be.true;5342 expect(tree.branches[0].isPassed).to.be.true;5343 expect(runInstance.afterEveryBranchRan).to.be.undefined; // doesn't run After Every Branch until one more runOneStep() call5344 expect(runInstance.beforeEveryBranchRan).to.be.true;5345 expect(isBranchComplete).to.be.false;5346 isBranchComplete = await runInstance.runOneStep();5347 expect(runInstance.isPaused).to.be.true;5348 expect(runInstance.ranStepA).to.be.true;5349 expect(runInstance.ranStepB).to.be.true;5350 expect(runInstance.ranStepC).to.be.true;5351 expect(tree.branches[0].isPassed).to.be.true;5352 expect(runInstance.afterEveryBranchRan).to.be.true;5353 expect(runInstance.beforeEveryBranchRan).to.be.true;5354 expect(isBranchComplete).to.be.true;5355 });5356 it("works when currently paused on the last step, which has completed already", async () => {5357 let tree = new Tree();5358 tree.parseIn(`5359A {5360 runInstance.ranStepA = !runInstance.ranStepA;5361}5362 B {5363 runInstance.ranStepB = !runInstance.ranStepB;5364 }5365 C {5366 runInstance.ranStepC = !runInstance.ranStepC;5367 let e = new Error();5368 e.continue = true;5369 throw e;5370 }5371*** Before Every Branch {5372 runInstance.beforeEveryBranchRan = !runInstance.beforeEveryBranchRan;5373}5374*** After Every Branch {5375 runInstance.afterEveryBranchRan = !runInstance.afterEveryBranchRan;5376}5377`, "file.txt");5378 let runner = new Runner();5379 runner.init(tree, true);5380 runner.pauseOnFail = true;5381 let runInstance = new RunInstance(runner);5382 await runInstance.run();5383 expect(runInstance.isPaused).to.be.true;5384 expect(runInstance.ranStepA).to.be.true;5385 expect(runInstance.ranStepB).to.be.true;5386 expect(runInstance.ranStepC).to.be.true;5387 expect(tree.branches[0].isFailed).to.be.true;5388 expect(runInstance.afterEveryBranchRan).to.be.undefined; // doesn't run After Every Branch until one more runOneStep() call5389 expect(runInstance.beforeEveryBranchRan).to.be.true;5390 let isBranchComplete = await runInstance.runOneStep();5391 expect(runInstance.isPaused).to.be.true;5392 expect(runInstance.ranStepA).to.be.true;5393 expect(runInstance.ranStepB).to.be.true;5394 expect(runInstance.ranStepC).to.be.true;5395 expect(tree.branches[0].isFailed).to.be.true;5396 expect(runInstance.afterEveryBranchRan).to.be.true;5397 expect(runInstance.beforeEveryBranchRan).to.be.true;5398 expect(isBranchComplete).to.be.true;5399 });5400 });5401 describe("runLastStep()", () => {5402 it("fails gracefully when the branch hasn't started yet", async () => {5403 let tree = new Tree();5404 tree.parseIn(`5405~ A {5406 runInstance.ranStepA = !runInstance.ranStepA;5407}5408 B {5409 runInstance.ranStepB = !runInstance.ranStepB;5410 }5411 C {5412 runInstance.ranStepC = !runInstance.ranStepC;5413 }5414*** Before Every Branch {5415 runInstance.beforeEveryBranchRan = !runInstance.beforeEveryBranchRan;5416}5417*** After Every Branch {5418 runInstance.afterEveryBranchRan = !runInstance.afterEveryBranchRan;5419}5420`, "file.txt");5421 let runner = new Runner();5422 runner.init(tree, true);5423 let runInstance = new RunInstance(runner);5424 expect(runInstance.isPaused).to.be.false;5425 expect(runInstance.ranStepA).to.be.undefined;5426 expect(runInstance.ranStepB).to.be.undefined;5427 expect(runInstance.ranStepC).to.be.undefined;5428 expect(runInstance.afterEveryBranchRan).to.be.undefined;5429 expect(runInstance.beforeEveryBranchRan).to.be.undefined;5430 await runInstance.runLastStep();5431 expect(runInstance.isPaused).to.be.false;5432 expect(runInstance.ranStepA).to.be.undefined;5433 expect(runInstance.ranStepB).to.be.undefined;5434 expect(runInstance.ranStepC).to.be.undefined;5435 expect(runInstance.afterEveryBranchRan).to.be.undefined;5436 expect(runInstance.beforeEveryBranchRan).to.be.undefined;5437 });5438 it("fails gracefully when currently on the first step", async () => {5439 let tree = new Tree();5440 tree.parseIn(`5441~ A {5442 runInstance.ranStepA = !runInstance.ranStepA;5443}5444 B {5445 runInstance.ranStepB = !runInstance.ranStepB;5446 }5447 C {5448 runInstance.ranStepC = !runInstance.ranStepC;5449 }5450*** Before Every Branch {5451 runInstance.beforeEveryBranchRan = !runInstance.beforeEveryBranchRan;5452}5453*** After Every Branch {5454 runInstance.afterEveryBranchRan = !runInstance.afterEveryBranchRan;5455}5456`, "file.txt");5457 let runner = new Runner();5458 runner.init(tree, true);5459 let runInstance = new RunInstance(runner);5460 await runInstance.run();5461 expect(runInstance.isPaused).to.be.true;5462 expect(runInstance.ranStepA).to.be.undefined;5463 expect(runInstance.ranStepB).to.be.undefined;5464 expect(runInstance.ranStepC).to.be.undefined;5465 expect(runInstance.afterEveryBranchRan).to.be.undefined;5466 expect(runInstance.beforeEveryBranchRan).to.be.true;5467 await runInstance.runLastStep();5468 expect(runInstance.isPaused).to.be.true;5469 expect(runInstance.ranStepA).to.be.undefined;5470 expect(runInstance.ranStepB).to.be.undefined;5471 expect(runInstance.ranStepC).to.be.undefined;5472 expect(runInstance.afterEveryBranchRan).to.be.undefined;5473 expect(runInstance.beforeEveryBranchRan).to.be.true;5474 });5475 it("runs the last step when currently in the middle of the branch, paused by a ~", async () => {5476 let tree = new Tree();5477 tree.parseIn(`5478A {5479 runInstance.ranStepA = !runInstance.ranStepA;5480}5481 B {5482 runInstance.ranStepB = !runInstance.ranStepB;5483 }5484 ~ C {5485 runInstance.ranStepC = !runInstance.ranStepC;5486 }5487*** Before Every Branch {5488 runInstance.beforeEveryBranchRan = !runInstance.beforeEveryBranchRan;5489}5490*** After Every Branch {5491 runInstance.afterEveryBranchRan = !runInstance.afterEveryBranchRan;5492}5493`, "file.txt");5494 let runner = new Runner();5495 runner.init(tree, true);5496 runner.pauseOnFail = true;5497 let runInstance = new RunInstance(runner);5498 await runInstance.run();5499 expect(runInstance.isPaused).to.be.true;5500 expect(runInstance.ranStepA).to.be.true;5501 expect(runInstance.ranStepB).to.be.true;5502 expect(runInstance.ranStepC).to.be.undefined;5503 expect(runInstance.afterEveryBranchRan).to.be.undefined;5504 expect(runInstance.beforeEveryBranchRan).to.be.true;5505 await runInstance.runLastStep();5506 expect(runInstance.isPaused).to.be.true;5507 expect(runInstance.ranStepA).to.be.true;5508 expect(runInstance.ranStepB).to.be.false;5509 expect(runInstance.ranStepC).to.be.undefined;5510 expect(runInstance.afterEveryBranchRan).to.be.undefined;5511 expect(runInstance.beforeEveryBranchRan).to.be.true;5512 await runInstance.runLastStep();5513 expect(runInstance.isPaused).to.be.true;5514 expect(runInstance.ranStepA).to.be.true;5515 expect(runInstance.ranStepB).to.be.true;5516 expect(runInstance.ranStepC).to.be.undefined;5517 expect(runInstance.afterEveryBranchRan).to.be.undefined;5518 expect(runInstance.beforeEveryBranchRan).to.be.true;5519 });5520 it("runs the last step when currently in the middle of the branch, paused by an error", async () => {5521 let tree = new Tree();5522 tree.parseIn(`5523A {5524 runInstance.ranStepA = !runInstance.ranStepA;5525}5526 B {5527 runInstance.ranStepB = !runInstance.ranStepB;5528 throw new Error("oops");5529 }5530 C {5531 runInstance.ranStepC = !runInstance.ranStepC;5532 }5533*** Before Every Branch {5534 runInstance.beforeEveryBranchRan = !runInstance.beforeEveryBranchRan;5535}5536*** After Every Branch {5537 runInstance.afterEveryBranchRan = !runInstance.afterEveryBranchRan;5538}5539`, "file.txt");5540 let runner = new Runner();5541 runner.init(tree, true);5542 runner.pauseOnFail = true;5543 let runInstance = new RunInstance(runner);5544 await runInstance.run();5545 expect(runInstance.isPaused).to.be.true;5546 expect(runInstance.ranStepA).to.be.true;5547 expect(runInstance.ranStepB).to.be.true;5548 expect(runInstance.ranStepC).to.be.undefined;5549 expect(runInstance.afterEveryBranchRan).to.be.undefined;5550 expect(runInstance.beforeEveryBranchRan).to.be.true;5551 await runInstance.runLastStep();5552 expect(runInstance.isPaused).to.be.true;5553 expect(runInstance.ranStepA).to.be.true;5554 expect(runInstance.ranStepB).to.be.false;5555 expect(runInstance.ranStepC).to.be.undefined;5556 expect(runInstance.afterEveryBranchRan).to.be.undefined;5557 expect(runInstance.beforeEveryBranchRan).to.be.true;5558 await runInstance.runLastStep();5559 expect(runInstance.isPaused).to.be.true;5560 expect(runInstance.ranStepA).to.be.true;5561 expect(runInstance.ranStepB).to.be.true;5562 expect(runInstance.ranStepC).to.be.undefined;5563 expect(runInstance.afterEveryBranchRan).to.be.undefined;5564 expect(runInstance.beforeEveryBranchRan).to.be.true;5565 });5566 it("runs the last step when currently beyond the last step", async () => {5567 let tree = new Tree();5568 tree.parseIn(`5569A {5570 runInstance.ranStepA = !runInstance.ranStepA;5571}5572 B {5573 runInstance.ranStepB = !runInstance.ranStepB;5574 }5575 C {5576 runInstance.ranStepC = !runInstance.ranStepC;5577 throw new Error("oops");5578 }5579*** Before Every Branch {5580 runInstance.beforeEveryBranchRan = !runInstance.beforeEveryBranchRan;5581}5582*** After Every Branch {5583 runInstance.afterEveryBranchRan = !runInstance.afterEveryBranchRan;5584}5585`, "file.txt");5586 let runner = new Runner();5587 runner.init(tree, true);5588 runner.pauseOnFail = true;5589 let runInstance = new RunInstance(runner);5590 await runInstance.run();5591 expect(runInstance.isPaused).to.be.true;5592 expect(runInstance.ranStepA).to.be.true;5593 expect(runInstance.ranStepB).to.be.true;5594 expect(runInstance.ranStepC).to.be.true;5595 expect(runInstance.afterEveryBranchRan).to.be.undefined;5596 expect(runInstance.beforeEveryBranchRan).to.be.true;5597 await runInstance.runLastStep();5598 expect(runInstance.isPaused).to.be.true;5599 expect(runInstance.ranStepA).to.be.true;5600 expect(runInstance.ranStepB).to.be.true;5601 expect(runInstance.ranStepC).to.be.false;5602 expect(runInstance.afterEveryBranchRan).to.be.undefined;5603 expect(runInstance.beforeEveryBranchRan).to.be.true;5604 await runInstance.runLastStep();5605 expect(runInstance.isPaused).to.be.true;5606 expect(runInstance.ranStepA).to.be.true;5607 expect(runInstance.ranStepB).to.be.true;5608 expect(runInstance.ranStepC).to.be.true;5609 expect(runInstance.afterEveryBranchRan).to.be.undefined;5610 expect(runInstance.beforeEveryBranchRan).to.be.true;5611 });5612 it("fails silently when the branch completed already", async () => {5613 let tree = new Tree();5614 tree.parseIn(`5615A {5616 runInstance.ranStepA = !runInstance.ranStepA;5617}5618 B {5619 runInstance.ranStepB = !runInstance.ranStepB;5620 }5621 C {5622 runInstance.ranStepC = !runInstance.ranStepC;5623 }5624*** Before Every Branch {5625 runInstance.beforeEveryBranchRan = !runInstance.beforeEveryBranchRan;5626}5627*** After Every Branch {5628 runInstance.afterEveryBranchRan = !runInstance.afterEveryBranchRan;5629}5630`, "file.txt");5631 let runner = new Runner();5632 runner.init(tree, true);5633 runner.pauseOnFail = true;5634 let runInstance = new RunInstance(runner);5635 await runInstance.run();5636 expect(runInstance.isPaused).to.be.false;5637 expect(runInstance.ranStepA).to.be.true;5638 expect(runInstance.ranStepB).to.be.true;5639 expect(runInstance.ranStepC).to.be.true;5640 expect(runInstance.afterEveryBranchRan).to.be.true;5641 expect(runInstance.beforeEveryBranchRan).to.be.true;5642 await runInstance.runLastStep();5643 expect(runInstance.isPaused).to.be.false;5644 expect(runInstance.ranStepA).to.be.true;5645 expect(runInstance.ranStepB).to.be.true;5646 expect(runInstance.ranStepC).to.be.true;5647 expect(runInstance.afterEveryBranchRan).to.be.true;5648 expect(runInstance.beforeEveryBranchRan).to.be.true;5649 });5650 });5651 describe("skipOneStep()", () => {5652 it("skips the step currently paused on if it's not completed yet then pauses again", async () => {5653 let tree = new Tree();5654 tree.parseIn(`5655~ A {5656 runInstance.ranStepA = !runInstance.ranStepA;5657}5658 B {5659 runInstance.ranStepB = !runInstance.ranStepB;5660 }5661 C {5662 runInstance.ranStepC = !runInstance.ranStepC;5663 }5664*** Before Every Branch {5665 runInstance.beforeEveryBranchRan = !runInstance.beforeEveryBranchRan;5666}5667*** After Every Branch {5668 runInstance.afterEveryBranchRan = !runInstance.afterEveryBranchRan;5669}5670`, "file.txt");5671 let runner = new Runner();5672 runner.init(tree, true);5673 let runInstance = new RunInstance(runner);5674 await runInstance.run();5675 expect(runInstance.isPaused).to.be.true;5676 expect(runInstance.ranStepA).to.be.undefined;5677 expect(runInstance.ranStepB).to.be.undefined;5678 expect(runInstance.ranStepC).to.be.undefined;5679 expect(tree.branches[0].steps[0].isSkipped).to.be.undefined;5680 expect(tree.branches[0].steps[1].isSkipped).to.be.undefined;5681 expect(tree.branches[0].steps[2].isSkipped).to.be.undefined;5682 expect(tree.branches[0].isPassed).to.be.undefined;5683 expect(runInstance.afterEveryBranchRan).to.be.undefined;5684 expect(runInstance.beforeEveryBranchRan).to.be.true;5685 let isBranchComplete = await runInstance.skipOneStep();5686 expect(runInstance.isPaused).to.be.true;5687 expect(runInstance.ranStepA).to.be.undefined;5688 expect(runInstance.ranStepB).to.be.undefined;5689 expect(runInstance.ranStepC).to.be.undefined;5690 expect(tree.branches[0].steps[0].isSkipped).to.be.true;5691 expect(tree.branches[0].steps[1].isSkipped).to.be.undefined;5692 expect(tree.branches[0].steps[2].isSkipped).to.be.undefined;5693 expect(tree.branches[0].isPassed).to.be.undefined;5694 expect(runInstance.afterEveryBranchRan).to.be.undefined;5695 expect(runInstance.beforeEveryBranchRan).to.be.true;5696 expect(isBranchComplete).to.be.false;5697 isBranchComplete = await runInstance.skipOneStep();5698 expect(runInstance.isPaused).to.be.true;5699 expect(runInstance.ranStepA).to.be.undefined;5700 expect(runInstance.ranStepB).to.be.undefined;5701 expect(runInstance.ranStepC).to.be.undefined;5702 expect(tree.branches[0].steps[0].isSkipped).to.be.true;5703 expect(tree.branches[0].steps[1].isSkipped).to.be.true;5704 expect(tree.branches[0].steps[2].isSkipped).to.be.undefined;5705 expect(tree.branches[0].isPassed).to.be.undefined;5706 expect(runInstance.afterEveryBranchRan).to.be.undefined;5707 expect(runInstance.beforeEveryBranchRan).to.be.true;5708 expect(isBranchComplete).to.be.false;5709 isBranchComplete = await runInstance.skipOneStep();5710 expect(runInstance.isPaused).to.be.true;5711 expect(runInstance.ranStepA).to.be.undefined;5712 expect(runInstance.ranStepB).to.be.undefined;5713 expect(runInstance.ranStepC).to.be.undefined;5714 expect(tree.branches[0].steps[0].isSkipped).to.be.true;5715 expect(tree.branches[0].steps[1].isSkipped).to.be.true;5716 expect(tree.branches[0].steps[2].isSkipped).to.be.true;5717 expect(tree.branches[0].isPassed).to.be.true;5718 expect(runInstance.afterEveryBranchRan).to.be.undefined; // doesn't run After Every Branch until one more runOneStep() call5719 expect(runInstance.beforeEveryBranchRan).to.be.true;5720 expect(isBranchComplete).to.be.false;5721 isBranchComplete = await runInstance.skipOneStep();5722 expect(runInstance.isPaused).to.be.true;5723 expect(runInstance.ranStepA).to.be.undefined;5724 expect(runInstance.ranStepB).to.be.undefined;5725 expect(runInstance.ranStepC).to.be.undefined;5726 expect(tree.branches[0].steps[0].isSkipped).to.be.true;5727 expect(tree.branches[0].steps[1].isSkipped).to.be.true;5728 expect(tree.branches[0].steps[2].isSkipped).to.be.true;5729 expect(tree.branches[0].isPassed).to.be.true;5730 expect(runInstance.afterEveryBranchRan).to.be.true;5731 expect(runInstance.beforeEveryBranchRan).to.be.true;5732 expect(isBranchComplete).to.be.true;5733 });5734 it("skips the step currently paused on if it's completed already, skips the step after than, runs the step after that, then pauses again", async () => {5735 let tree = new Tree();5736 tree.parseIn(`5737A {5738 runInstance.ranStepA = !runInstance.ranStepA;5739 let e = new Error();5740 e.continue = true;5741 throw e;5742}5743 B {5744 runInstance.ranStepB = !runInstance.ranStepB;5745 }5746 C {5747 runInstance.ranStepC = !runInstance.ranStepC;5748 }5749*** Before Every Branch {5750 runInstance.beforeEveryBranchRan = !runInstance.beforeEveryBranchRan;5751}5752*** After Every Branch {5753 runInstance.afterEveryBranchRan = !runInstance.afterEveryBranchRan;5754}5755`, "file.txt");5756 let runner = new Runner();5757 runner.init(tree, true);5758 runner.pauseOnFail = true;5759 let runInstance = new RunInstance(runner);5760 await runInstance.run();5761 expect(runInstance.isPaused).to.be.true;5762 expect(runInstance.ranStepA).to.be.true;5763 expect(runInstance.ranStepB).to.be.undefined;5764 expect(runInstance.ranStepC).to.be.undefined;5765 expect(tree.branches[0].steps[0].isSkipped).to.be.undefined;5766 expect(tree.branches[0].steps[1].isSkipped).to.be.undefined;5767 expect(tree.branches[0].steps[2].isSkipped).to.be.undefined;5768 expect(tree.branches[0].isFailed).to.be.undefined;5769 expect(runInstance.afterEveryBranchRan).to.be.undefined;5770 expect(runInstance.beforeEveryBranchRan).to.be.true;5771 let isBranchComplete = await runInstance.skipOneStep();5772 expect(runInstance.isPaused).to.be.true;5773 expect(runInstance.ranStepA).to.be.true;5774 expect(runInstance.ranStepB).to.be.undefined;5775 expect(runInstance.ranStepC).to.be.undefined;5776 expect(tree.branches[0].steps[0].isSkipped).to.be.undefined;5777 expect(tree.branches[0].steps[1].isSkipped).to.be.true;5778 expect(tree.branches[0].steps[2].isSkipped).to.be.undefined;5779 expect(tree.branches[0].isFailed).to.be.undefined;5780 expect(runInstance.afterEveryBranchRan).to.be.undefined;5781 expect(runInstance.beforeEveryBranchRan).to.be.true;5782 expect(isBranchComplete).to.be.false;5783 isBranchComplete = await runInstance.skipOneStep();5784 expect(runInstance.isPaused).to.be.true;5785 expect(runInstance.ranStepA).to.be.true;5786 expect(runInstance.ranStepB).to.be.undefined;5787 expect(runInstance.ranStepC).to.be.undefined;5788 expect(tree.branches[0].steps[0].isSkipped).to.be.undefined;5789 expect(tree.branches[0].steps[1].isSkipped).to.be.true;5790 expect(tree.branches[0].steps[2].isSkipped).to.be.true;5791 expect(tree.branches[0].isFailed).to.be.true;5792 expect(runInstance.afterEveryBranchRan).to.be.undefined; // doesn't run After Every Branch until one more runOneStep() call5793 expect(runInstance.beforeEveryBranchRan).to.be.true;5794 expect(isBranchComplete).to.be.false;5795 isBranchComplete = await runInstance.skipOneStep();5796 expect(runInstance.isPaused).to.be.true;5797 expect(runInstance.ranStepA).to.be.true;5798 expect(runInstance.ranStepB).to.be.undefined;5799 expect(runInstance.ranStepC).to.be.undefined;5800 expect(tree.branches[0].steps[0].isSkipped).to.be.undefined;5801 expect(tree.branches[0].steps[1].isSkipped).to.be.true;5802 expect(tree.branches[0].steps[2].isSkipped).to.be.true;5803 expect(tree.branches[0].isFailed).to.be.true;5804 expect(runInstance.afterEveryBranchRan).to.be.true;5805 expect(runInstance.beforeEveryBranchRan).to.be.true;5806 expect(isBranchComplete).to.be.true;5807 });5808 it("works when currently paused on the second-to-last step, which has not completed yet", async () => {5809 let tree = new Tree();5810 tree.parseIn(`5811A {5812 runInstance.ranStepA = !runInstance.ranStepA;5813}5814 ~ B {5815 runInstance.ranStepB = !runInstance.ranStepB;5816 }5817 C {5818 runInstance.ranStepC = !runInstance.ranStepC;5819 }5820*** Before Every Branch {5821 runInstance.beforeEveryBranchRan = !runInstance.beforeEveryBranchRan;5822}5823*** After Every Branch {5824 runInstance.afterEveryBranchRan = !runInstance.afterEveryBranchRan;5825}5826`, "file.txt");5827 let runner = new Runner();5828 runner.init(tree, true);5829 let runInstance = new RunInstance(runner);5830 await runInstance.run();5831 expect(runInstance.isPaused).to.be.true;5832 expect(runInstance.ranStepA).to.be.true;5833 expect(runInstance.ranStepB).to.be.undefined;5834 expect(runInstance.ranStepC).to.be.undefined;5835 expect(tree.branches[0].steps[0].isSkipped).to.be.undefined;5836 expect(tree.branches[0].steps[1].isSkipped).to.be.undefined;5837 expect(tree.branches[0].steps[2].isSkipped).to.be.undefined;5838 expect(tree.branches[0].isPassed).to.be.undefined;5839 expect(runInstance.afterEveryBranchRan).to.be.undefined;5840 expect(runInstance.beforeEveryBranchRan).to.be.true;5841 let isBranchComplete = await runInstance.skipOneStep();5842 expect(runInstance.isPaused).to.be.true;5843 expect(runInstance.ranStepA).to.be.true;5844 expect(runInstance.ranStepB).to.be.undefined;5845 expect(runInstance.ranStepC).to.be.undefined;5846 expect(tree.branches[0].steps[0].isSkipped).to.be.undefined;5847 expect(tree.branches[0].steps[1].isSkipped).to.be.true;5848 expect(tree.branches[0].steps[2].isSkipped).to.be.undefined;5849 expect(tree.branches[0].isPassed).to.be.undefined;5850 expect(runInstance.afterEveryBranchRan).to.be.undefined;5851 expect(runInstance.beforeEveryBranchRan).to.be.true;5852 expect(isBranchComplete).to.be.false;5853 isBranchComplete = await runInstance.skipOneStep();5854 expect(runInstance.isPaused).to.be.true;5855 expect(runInstance.ranStepA).to.be.true;5856 expect(runInstance.ranStepB).to.be.undefined;5857 expect(runInstance.ranStepC).to.be.undefined;5858 expect(tree.branches[0].steps[0].isSkipped).to.be.undefined;5859 expect(tree.branches[0].steps[1].isSkipped).to.be.true;5860 expect(tree.branches[0].steps[2].isSkipped).to.be.true;5861 expect(tree.branches[0].isPassed).to.be.true;5862 expect(runInstance.afterEveryBranchRan).to.be.undefined; // doesn't run After Every Branch until one more runOneStep() call5863 expect(runInstance.beforeEveryBranchRan).to.be.true;5864 expect(isBranchComplete).to.be.false;5865 isBranchComplete = await runInstance.skipOneStep();5866 expect(runInstance.isPaused).to.be.true;5867 expect(runInstance.ranStepA).to.be.true;5868 expect(runInstance.ranStepB).to.be.undefined;5869 expect(runInstance.ranStepC).to.be.undefined;5870 expect(tree.branches[0].steps[0].isSkipped).to.be.undefined;5871 expect(tree.branches[0].steps[1].isSkipped).to.be.true;5872 expect(tree.branches[0].steps[2].isSkipped).to.be.true;5873 expect(tree.branches[0].isPassed).to.be.true;5874 expect(runInstance.afterEveryBranchRan).to.be.true;5875 expect(runInstance.beforeEveryBranchRan).to.be.true;5876 expect(isBranchComplete).to.be.true;5877 });5878 it("works when currently paused on the last step, which has not completed yet", async () => {5879 let tree = new Tree();5880 tree.parseIn(`5881A {5882 runInstance.ranStepA = !runInstance.ranStepA;5883}5884 B {5885 runInstance.ranStepB = !runInstance.ranStepB;5886 }5887 ~ C {5888 runInstance.ranStepC = !runInstance.ranStepC;5889 }5890*** Before Every Branch {5891 runInstance.beforeEveryBranchRan = !runInstance.beforeEveryBranchRan;5892}5893*** After Every Branch {5894 runInstance.afterEveryBranchRan = !runInstance.afterEveryBranchRan;5895}5896`, "file.txt");5897 let runner = new Runner();5898 runner.init(tree, true);5899 let runInstance = new RunInstance(runner);5900 await runInstance.run();5901 expect(runInstance.isPaused).to.be.true;5902 expect(runInstance.ranStepA).to.be.true;5903 expect(runInstance.ranStepB).to.be.true;5904 expect(runInstance.ranStepC).to.be.undefined;5905 expect(tree.branches[0].steps[0].isSkipped).to.be.undefined;5906 expect(tree.branches[0].steps[1].isSkipped).to.be.undefined;5907 expect(tree.branches[0].steps[2].isSkipped).to.be.undefined;5908 expect(tree.branches[0].isPassed).to.be.undefined;5909 expect(runInstance.afterEveryBranchRan).to.be.undefined;5910 expect(runInstance.beforeEveryBranchRan).to.be.true;5911 let isBranchComplete = await runInstance.skipOneStep();5912 expect(runInstance.isPaused).to.be.true;5913 expect(runInstance.ranStepA).to.be.true;5914 expect(runInstance.ranStepB).to.be.true;5915 expect(runInstance.ranStepC).to.be.undefined;5916 expect(tree.branches[0].steps[0].isSkipped).to.be.undefined;5917 expect(tree.branches[0].steps[1].isSkipped).to.be.undefined;5918 expect(tree.branches[0].steps[2].isSkipped).to.be.true;5919 expect(tree.branches[0].isPassed).to.be.true;5920 expect(runInstance.afterEveryBranchRan).to.be.undefined; // doesn't run After Every Branch until one more runOneStep() call5921 expect(runInstance.beforeEveryBranchRan).to.be.true;5922 expect(isBranchComplete).to.be.false;5923 isBranchComplete = await runInstance.skipOneStep();5924 expect(runInstance.isPaused).to.be.true;5925 expect(runInstance.ranStepA).to.be.true;5926 expect(runInstance.ranStepB).to.be.true;5927 expect(runInstance.ranStepC).to.be.undefined;5928 expect(tree.branches[0].steps[0].isSkipped).to.be.undefined;5929 expect(tree.branches[0].steps[1].isSkipped).to.be.undefined;5930 expect(tree.branches[0].steps[2].isSkipped).to.be.true;5931 expect(tree.branches[0].isPassed).to.be.true;5932 expect(runInstance.afterEveryBranchRan).to.be.true;5933 expect(runInstance.beforeEveryBranchRan).to.be.true;5934 expect(isBranchComplete).to.be.true;5935 });5936 it("works when currently paused on the second-to-last step, which has completed already", async () => {5937 let tree = new Tree();5938 tree.parseIn(`5939A {5940 runInstance.ranStepA = !runInstance.ranStepA;5941}5942 B {5943 runInstance.ranStepB = !runInstance.ranStepB;5944 let e = new Error();5945 e.continue = true;5946 throw e;5947 }5948 C {5949 runInstance.ranStepC = !runInstance.ranStepC;5950 }5951*** Before Every Branch {5952 runInstance.beforeEveryBranchRan = !runInstance.beforeEveryBranchRan;5953}5954*** After Every Branch {5955 runInstance.afterEveryBranchRan = !runInstance.afterEveryBranchRan;5956}5957`, "file.txt");5958 let runner = new Runner();5959 runner.init(tree, true);5960 runner.pauseOnFail = true;5961 let runInstance = new RunInstance(runner);5962 await runInstance.run();5963 expect(runInstance.isPaused).to.be.true;5964 expect(runInstance.ranStepA).to.be.true;5965 expect(runInstance.ranStepB).to.be.true;5966 expect(runInstance.ranStepC).to.be.undefined;5967 expect(tree.branches[0].steps[0].isSkipped).to.be.undefined;5968 expect(tree.branches[0].steps[1].isSkipped).to.be.undefined;5969 expect(tree.branches[0].steps[2].isSkipped).to.be.undefined;5970 expect(tree.branches[0].isFailed).to.be.undefined;5971 expect(runInstance.afterEveryBranchRan).to.be.undefined;5972 expect(runInstance.beforeEveryBranchRan).to.be.true;5973 let isBranchComplete = await runInstance.skipOneStep();5974 expect(runInstance.isPaused).to.be.true;5975 expect(runInstance.ranStepA).to.be.true;5976 expect(runInstance.ranStepB).to.be.true;5977 expect(runInstance.ranStepC).to.be.undefined;5978 expect(tree.branches[0].steps[0].isSkipped).to.be.undefined;5979 expect(tree.branches[0].steps[1].isSkipped).to.be.undefined;5980 expect(tree.branches[0].steps[2].isSkipped).to.be.true;5981 expect(tree.branches[0].isFailed).to.be.true;5982 expect(runInstance.afterEveryBranchRan).to.be.undefined; // doesn't run After Every Branch until one more runOneStep() call5983 expect(runInstance.beforeEveryBranchRan).to.be.true;5984 isBranchComplete = await runInstance.skipOneStep();5985 expect(runInstance.isPaused).to.be.true;5986 expect(runInstance.ranStepA).to.be.true;5987 expect(runInstance.ranStepB).to.be.true;5988 expect(runInstance.ranStepC).to.be.undefined;5989 expect(tree.branches[0].steps[0].isSkipped).to.be.undefined;5990 expect(tree.branches[0].steps[1].isSkipped).to.be.undefined;5991 expect(tree.branches[0].steps[2].isSkipped).to.be.true;5992 expect(tree.branches[0].isFailed).to.be.true;5993 expect(runInstance.afterEveryBranchRan).to.be.true;5994 expect(runInstance.beforeEveryBranchRan).to.be.true;5995 expect(isBranchComplete).to.be.true;5996 });5997 it("works when currently paused on the last step, which has completed already", async () => {5998 let tree = new Tree();5999 tree.parseIn(`6000A {6001 runInstance.ranStepA = !runInstance.ranStepA;6002}6003 B {6004 runInstance.ranStepB = !runInstance.ranStepB;6005 }6006 C {6007 runInstance.ranStepC = !runInstance.ranStepC;6008 let e = new Error();6009 e.continue = true;6010 throw e;6011 }6012*** Before Every Branch {6013 runInstance.beforeEveryBranchRan = !runInstance.beforeEveryBranchRan;6014}6015*** After Every Branch {6016 runInstance.afterEveryBranchRan = !runInstance.afterEveryBranchRan;6017}6018`, "file.txt");6019 let runner = new Runner();6020 runner.init(tree, true);6021 runner.pauseOnFail = true;6022 let runInstance = new RunInstance(runner);6023 await runInstance.run();6024 expect(runInstance.isPaused).to.be.true;6025 expect(runInstance.ranStepA).to.be.true;6026 expect(runInstance.ranStepB).to.be.true;6027 expect(runInstance.ranStepC).to.be.true;6028 expect(tree.branches[0].steps[0].isSkipped).to.be.undefined;6029 expect(tree.branches[0].steps[1].isSkipped).to.be.undefined;6030 expect(tree.branches[0].steps[2].isSkipped).to.be.undefined;6031 expect(tree.branches[0].isFailed).to.be.true;6032 expect(runInstance.afterEveryBranchRan).to.be.undefined; // doesn't run After Every Branch until one more runOneStep() call6033 expect(runInstance.beforeEveryBranchRan).to.be.true;6034 let isBranchComplete = await runInstance.skipOneStep();6035 expect(runInstance.isPaused).to.be.true;6036 expect(runInstance.ranStepA).to.be.true;6037 expect(runInstance.ranStepB).to.be.true;6038 expect(runInstance.ranStepC).to.be.true;6039 expect(tree.branches[0].steps[0].isSkipped).to.be.undefined;6040 expect(tree.branches[0].steps[1].isSkipped).to.be.undefined;6041 expect(tree.branches[0].steps[2].isSkipped).to.be.undefined;6042 expect(tree.branches[0].isFailed).to.be.true;6043 expect(runInstance.afterEveryBranchRan).to.be.true;6044 expect(runInstance.beforeEveryBranchRan).to.be.true;6045 expect(isBranchComplete).to.be.true;6046 });6047 });6048 describe("inject()", () => {6049 it("runs a step, then pauses again", async () => {6050 let tree = new Tree();6051 tree.parseIn(`6052A {6053 runInstance.ranStepA = !runInstance.ranStepA;6054}6055 ~ B {6056 runInstance.ranStepB = !runInstance.ranStepB;6057 }6058 C {6059 runInstance.ranStepC = !runInstance.ranStepC;6060 }6061`, "file.txt");6062 let runner = new Runner();6063 runner.init(tree, true);6064 let runInstance = new RunInstance(runner);6065 await runInstance.run();6066 expect(runInstance.isPaused).to.be.true;6067 expect(runInstance.ranStepA).to.be.true;6068 expect(runInstance.ranStepB).to.be.undefined;6069 expect(runInstance.ranStepC).to.be.undefined;6070 expect(runInstance.ranInjectedStep).to.be.undefined;6071 await runInstance.inject(`6072Step to Inject {6073 runInstance.ranInjectedStep = true;6074}`);6075 expect(runInstance.isPaused).to.be.true;6076 expect(runInstance.ranStepA).to.be.true;6077 expect(runInstance.ranStepB).to.be.undefined;6078 expect(runInstance.ranStepC).to.be.undefined;6079 expect(runInstance.ranInjectedStep).to.be.true;6080 });6081 it("works when there is no current step or branch", async () => {6082 let runner = new Runner(new Tree());6083 runner.tree = new Tree();6084 let runInstance = new RunInstance(runner);6085 await runInstance.inject(`6086Step to Inject {6087 runInstance.ranInjectedStep = true;6088}`);6089 expect(runInstance.ranInjectedStep).to.be.true;6090 });6091 it("step has access to {{vars}} and {vars} that were defined at the time of the pause", async () => {6092 let tree = new Tree();6093 tree.parseIn(`6094{var1}='foo'6095 {{var2}}='bar'6096 ~ B -6097 C -6098`, "file.txt");6099 let runner = new Runner();6100 runner.init(tree, true);6101 let runInstance = new RunInstance(runner);6102 await runInstance.run();6103 await runInstance.inject(`6104Step to Inject {6105 runInstance.var1 = var1;6106 runInstance.var2 = var2;6107 runInstance.var3 = getGlobal("var1");6108 runInstance.var4 = getLocal("var2");6109}`);6110 expect(runInstance.var1).to.equal("foo");6111 expect(runInstance.var2).to.equal("bar");6112 expect(runInstance.var3).to.equal("foo");6113 expect(runInstance.var4).to.equal("bar");6114 });6115 it("step can be a function call for a function that was defined at the time of the pause", async () => {6116 let tree = new Tree();6117 tree.parseIn(`6118~ A -6119* My function6120 {var1}='foo'6121`, "file.txt");6122 let runner = new Runner();6123 runner.init(tree, true);6124 let runInstance = new RunInstance(runner);6125 await runInstance.run();6126 let stepsRan = await runInstance.inject(`6127My function6128`);6129 expect(runInstance.getGlobal("var1")).to.equal("foo");6130 expect(stepsRan.steps).to.have.lengthOf(2);6131 expect(tree.stepNodeIndex[stepsRan.steps[0].id].text).to.equal("My function");6132 expect(stepsRan.steps[0].isPassed).to.be.true;6133 expect(stepsRan.steps[0].isFailed).to.be.undefined;6134 expect(tree.stepNodeIndex[stepsRan.steps[1].id].text).to.equal("{var1}='foo'");6135 expect(stepsRan.steps[1].isPassed).to.be.true;6136 expect(stepsRan.steps[1].isFailed).to.be.undefined;6137 });6138 it("step can be a function call for a function that was defined in context at the time of the pause", async () => {6139 let tree = new Tree();6140 tree.parseIn(`6141B6142 ~ A -6143* B6144 * My function6145 {var1}='foo'6146`, "file.txt");6147 let runner = new Runner();6148 runner.init(tree, true);6149 let runInstance = new RunInstance(runner);6150 await runInstance.run();6151 let stepsRan = await runInstance.inject(`6152My function6153`);6154 expect(runInstance.getGlobal("var1")).to.equal("foo");6155 expect(stepsRan.steps).to.have.lengthOf(2);6156 expect(tree.stepNodeIndex[stepsRan.steps[0].id].text).to.equal("My function");6157 expect(stepsRan.steps[0].isPassed).to.be.true;6158 expect(stepsRan.steps[0].isFailed).to.be.undefined;6159 expect(tree.stepNodeIndex[stepsRan.steps[1].id].text).to.equal("{var1}='foo'");6160 expect(stepsRan.steps[1].isPassed).to.be.true;6161 expect(stepsRan.steps[1].isFailed).to.be.undefined;6162 });6163 it("can call a function that exposes another function in context, which can subsequently be called", async () => {6164 let tree = new Tree();6165 tree.parseIn(`6166~ A -6167* B6168 * My function6169 {var1}='foo'6170`, "file.txt");6171 let runner = new Runner();6172 runner.init(tree, true);6173 let runInstance = new RunInstance(runner);6174 await runInstance.run();6175 let stepsRan = await runInstance.inject(`B`);6176 expect(runInstance.getGlobal("var1")).to.be.undefined;6177 expect(stepsRan.steps).to.have.lengthOf(1);6178 stepsRan = await runInstance.inject(`My function`);6179 expect(runInstance.getGlobal("var1")).to.equal("foo");6180 expect(stepsRan.steps).to.have.lengthOf(2);6181 expect(tree.stepNodeIndex[stepsRan.steps[0].id].text).to.equal("My function");6182 expect(stepsRan.steps[0].isPassed).to.be.true;6183 expect(stepsRan.steps[0].isFailed).to.be.undefined;6184 expect(tree.stepNodeIndex[stepsRan.steps[1].id].text).to.equal("{var1}='foo'");6185 expect(stepsRan.steps[1].isPassed).to.be.true;6186 expect(stepsRan.steps[1].isFailed).to.be.undefined;6187 });6188 it("step can be a function call for a function that was defined at the time of the pause, and if we're currently beyond the last step", async () => {6189 let tree = new Tree();6190 tree.parseIn(`6191~ A -6192* My function6193 {var1}='foo'6194`, "file.txt");6195 let runner = new Runner();6196 runner.init(tree, true);6197 let runInstance = new RunInstance(runner);6198 await runInstance.run();6199 await runInstance.runOneStep(); // now we're right after A6200 let stepsRan = await runInstance.inject(`6201My function6202`);6203 expect(runInstance.getGlobal("var1")).to.equal("foo");6204 expect(stepsRan.steps).to.have.lengthOf(2);6205 expect(tree.stepNodeIndex[stepsRan.steps[0].id].text).to.equal("My function");6206 expect(stepsRan.steps[0].isPassed).to.be.true;6207 expect(stepsRan.steps[0].isFailed).to.be.undefined;6208 expect(tree.stepNodeIndex[stepsRan.steps[1].id].text).to.equal("{var1}='foo'");6209 expect(stepsRan.steps[1].isPassed).to.be.true;6210 expect(stepsRan.steps[1].isFailed).to.be.undefined;6211 });6212 it("step can be a function call that's in the tree, but if there is no current branch", async () => {6213 let tree = new Tree();6214 tree.stepDataMode = 'all';6215 tree.parseIn(`6216* My function6217 {var1}='foo'6218`, "file.txt");6219 let runner = new Runner();6220 runner.init(tree, true);6221 let runInstance = new RunInstance(runner);6222 let stepsRan = await runInstance.inject(`6223My function6224`);6225 expect(runInstance.getGlobal("var1")).to.equal("foo");6226 expect(stepsRan.steps).to.have.lengthOf(2);6227 expect(tree.stepNodeIndex[stepsRan.steps[0].id].text).to.equal("My function");6228 expect(stepsRan.steps[0].isPassed).to.be.true;6229 expect(stepsRan.steps[0].isFailed).to.be.undefined;6230 expect(tree.stepNodeIndex[stepsRan.steps[1].id].text).to.equal("{var1}='foo'");6231 expect(stepsRan.steps[1].isPassed).to.be.true;6232 expect(stepsRan.steps[1].isFailed).to.be.undefined;6233 });6234 it("attaches an error to the step returned if it fails", async () => {6235 let tree = new Tree();6236 tree.parseIn(`6237~ A -6238* My function {6239 throw new Error("oops");6240}6241`, "file.txt");6242 let runner = new Runner();6243 runner.init(tree, true);6244 let runInstance = new RunInstance(runner);6245 await runInstance.run();6246 let stepsRan = await runInstance.inject(`6247My function6248`);6249 expect(stepsRan.steps).to.have.lengthOf(1);6250 expect(tree.stepNodeIndex[stepsRan.steps[0].id].text).to.equal("My function");6251 expect(stepsRan.steps[0].isPassed).to.be.undefined;6252 expect(stepsRan.steps[0].isFailed).to.be.true;6253 expect(stepsRan.steps[0].error.message).to.equal("oops");6254 expect(stepsRan.steps[0].error.filename).to.equal("file.txt");6255 expect(stepsRan.steps[0].error.lineNumber).to.equal(5);6256 expect(runInstance.currStep.error).to.equal(undefined);6257 expect(runInstance.currBranch.error).to.equal(undefined);6258 });6259 it("throws an error for a function call that cannot be found", async () => {6260 let tree = new Tree();6261 tree.parseIn(`6262~ A -6263`, "file.txt");6264 let runner = new Runner();6265 runner.init(tree, true);6266 let runInstance = new RunInstance(runner);6267 await runInstance.run();6268 await expect(runInstance.inject(`Some unknown function`)).to.be.rejectedWith("The function \`Some unknown function\` cannot be found.");6269 });6270 it("can handle two function calls that cannot be found", async () => {6271 let tree = new Tree();6272 tree.parseIn(`6273A -6274 ~ B -6275`, "file.txt");6276 let runner = new Runner();6277 runner.init(tree, true);6278 let runInstance = new RunInstance(runner);6279 await runInstance.run();6280 await expect(runInstance.inject(`Some unknown function`)).to.be.rejectedWith("The function \`Some unknown function\` cannot be found.");6281 await expect(runInstance.inject(`Some unknown function`)).to.be.rejectedWith("The function \`Some unknown function\` cannot be found.");6282 });6283 it("the RunInstance can flawlessly resume from a pause, after an injected step has run", async () => {6284 let tree = new Tree();6285 tree.parseIn(`6286A {6287 runInstance.ranStepA = !runInstance.ranStepA;6288}6289 ~ B {6290 runInstance.ranStepB = !runInstance.ranStepB;6291 }6292 C {6293 runInstance.ranStepC = !runInstance.ranStepC;6294 }6295*** Before Every Branch {6296 runInstance.beforeEveryBranchRan = !runInstance.beforeEveryBranchRan;6297}6298*** After Every Branch {6299 runInstance.afterEveryBranchRan = !runInstance.afterEveryBranchRan;6300}6301`, "file.txt");6302 let runner = new Runner();6303 runner.init(tree, true);6304 let runInstance = new RunInstance(runner);6305 await runInstance.run();6306 expect(runInstance.beforeEveryBranchRan).to.be.true;6307 expect(runInstance.ranStepA).to.be.true;6308 expect(runInstance.ranInjectedStep).to.be.undefined;6309 expect(runInstance.ranStepB).to.be.undefined;6310 expect(runInstance.ranStepC).to.be.undefined;6311 expect(runInstance.afterEveryBranchRan).to.be.undefined;6312 await runInstance.inject(`6313Step to Inject {6314 runInstance.ranInjectedStep = !runInstance.ranInjectedStep;6315}`);6316 expect(runInstance.beforeEveryBranchRan).to.be.true;6317 expect(runInstance.ranStepA).to.be.true;6318 expect(runInstance.ranInjectedStep).to.be.true;6319 expect(runInstance.ranStepB).to.be.undefined;6320 expect(runInstance.ranStepC).to.be.undefined;6321 expect(runInstance.afterEveryBranchRan).to.be.undefined;6322 await runInstance.run();6323 expect(runInstance.beforeEveryBranchRan).to.be.true;6324 expect(runInstance.ranStepA).to.be.true;6325 expect(runInstance.ranInjectedStep).to.be.true;6326 expect(runInstance.ranStepB).to.be.true;6327 expect(runInstance.ranStepC).to.be.true;6328 expect(runInstance.afterEveryBranchRan).to.be.true;6329 });6330 it("the RunInstance can flawlessly run single steps, after an injected step has run", async () => {6331 let tree = new Tree();6332 tree.parseIn(`6333A {6334 runInstance.ranStepA = !runInstance.ranStepA;6335}6336 ~ B {6337 runInstance.ranStepB = !runInstance.ranStepB;6338 }6339 C {6340 runInstance.ranStepC = !runInstance.ranStepC;6341 }6342*** Before Every Branch {6343 runInstance.beforeEveryBranchRan = !runInstance.beforeEveryBranchRan;6344}6345*** After Every Branch {6346 runInstance.afterEveryBranchRan = !runInstance.afterEveryBranchRan;6347}6348`, "file.txt");6349 let runner = new Runner();6350 runner.init(tree, true);6351 let runInstance = new RunInstance(runner);6352 await runInstance.run();6353 expect(runInstance.beforeEveryBranchRan).to.be.true;6354 expect(runInstance.ranStepA).to.be.true;6355 expect(runInstance.ranInjectedStep).to.be.undefined;6356 expect(runInstance.ranStepB).to.be.undefined;6357 expect(runInstance.ranStepC).to.be.undefined;6358 expect(runInstance.afterEveryBranchRan).to.be.undefined;6359 await runInstance.inject(`6360Step to Inject {6361 runInstance.ranInjectedStep = !runInstance.ranInjectedStep;6362}`);6363 expect(runInstance.beforeEveryBranchRan).to.be.true;6364 expect(runInstance.ranStepA).to.be.true;6365 expect(runInstance.ranInjectedStep).to.be.true;6366 expect(runInstance.ranStepB).to.be.undefined;6367 expect(runInstance.ranStepC).to.be.undefined;6368 expect(runInstance.afterEveryBranchRan).to.be.undefined;6369 await runInstance.runOneStep();6370 expect(runInstance.beforeEveryBranchRan).to.be.true;6371 expect(runInstance.ranStepA).to.be.true;6372 expect(runInstance.ranInjectedStep).to.be.true;6373 expect(runInstance.ranStepB).to.be.true;6374 expect(runInstance.ranStepC).to.be.undefined;6375 expect(runInstance.afterEveryBranchRan).to.be.undefined;6376 await runInstance.runOneStep();6377 expect(runInstance.beforeEveryBranchRan).to.be.true;6378 expect(runInstance.ranStepA).to.be.true;6379 expect(runInstance.ranInjectedStep).to.be.true;6380 expect(runInstance.ranStepB).to.be.true;6381 expect(runInstance.ranStepC).to.be.true;6382 expect(runInstance.afterEveryBranchRan).to.be.undefined;6383 await runInstance.runOneStep();6384 expect(runInstance.beforeEveryBranchRan).to.be.true;6385 expect(runInstance.ranStepA).to.be.true;6386 expect(runInstance.ranInjectedStep).to.be.true;6387 expect(runInstance.ranStepB).to.be.true;6388 expect(runInstance.ranStepC).to.be.true;6389 expect(runInstance.afterEveryBranchRan).to.be.true;6390 });6391 it("the RunInstance can flawlessly skip steps, after an injected step has run", async () => {6392 let tree = new Tree();6393 tree.parseIn(`6394A {6395 runInstance.ranStepA = !runInstance.ranStepA;6396}6397 ~ B {6398 runInstance.ranStepB = !runInstance.ranStepB;6399 }6400 C {6401 runInstance.ranStepC = !runInstance.ranStepC;6402 }6403*** Before Every Branch {6404 runInstance.beforeEveryBranchRan = !runInstance.beforeEveryBranchRan;6405}6406*** After Every Branch {6407 runInstance.afterEveryBranchRan = !runInstance.afterEveryBranchRan;6408}6409`, "file.txt");6410 let runner = new Runner();6411 runner.init(tree, true);6412 let runInstance = new RunInstance(runner);6413 await runInstance.run();6414 expect(runInstance.beforeEveryBranchRan).to.be.true;6415 expect(runInstance.ranStepA).to.be.true;6416 expect(runInstance.ranInjectedStep).to.be.undefined;6417 expect(runInstance.ranStepB).to.be.undefined;6418 expect(runInstance.ranStepC).to.be.undefined;6419 expect(runInstance.afterEveryBranchRan).to.be.undefined;6420 await runInstance.inject(`6421Step to Inject {6422 runInstance.ranInjectedStep = !runInstance.ranInjectedStep;6423}`);6424 expect(runInstance.beforeEveryBranchRan).to.be.true;6425 expect(runInstance.ranStepA).to.be.true;6426 expect(runInstance.ranInjectedStep).to.be.true;6427 expect(runInstance.ranStepB).to.be.undefined;6428 expect(runInstance.ranStepC).to.be.undefined;6429 expect(runInstance.afterEveryBranchRan).to.be.undefined;6430 await runInstance.skipOneStep();6431 await runInstance.runOneStep();6432 expect(runInstance.beforeEveryBranchRan).to.be.true;6433 expect(runInstance.ranStepA).to.be.true;6434 expect(runInstance.ranInjectedStep).to.be.true;6435 expect(runInstance.ranStepB).to.be.undefined;6436 expect(runInstance.ranStepC).to.be.true;6437 expect(runInstance.afterEveryBranchRan).to.be.undefined;6438 await runInstance.skipOneStep();6439 expect(runInstance.beforeEveryBranchRan).to.be.true;6440 expect(runInstance.ranStepA).to.be.true;6441 expect(runInstance.ranInjectedStep).to.be.true;6442 expect(runInstance.ranStepB).to.be.undefined;6443 expect(runInstance.ranStepC).to.be.true;6444 expect(runInstance.afterEveryBranchRan).to.be.true;6445 });6446 it("allows an indented step", async () => {6447 let runner = new Runner(new Tree());6448 runner.tree = new Tree();6449 let runInstance = new RunInstance(runner);6450 await runInstance.inject(`6451 Step to Inject {6452 runInstance.ranInjectedStep = true;6453 }`);6454 expect(runInstance.ranInjectedStep).to.be.true;6455 });6456 });...

Full Screen

Full Screen

runner.js

Source:runner.js Github

copy

Full Screen

1const chai = require('chai');2const chaiAsPromised = require("chai-as-promised");3const expect = chai.expect;4const assert = chai.assert;5const util = require('util');6const Tree = require('../../src/tree.js');7const Runner = require('../../src/runner.js');8const Comparer = require('../../packages/js/comparer.js');9const utils = require('../../src/utils.js');10chai.use(chaiAsPromised);11describe("Runner", () => {12 describe("run()", () => {13 it("runs an empty tree", async () => {14 let tree = new Tree();15 let runner = new Runner();16 runner.init(tree, true);17 await runner.run();18 });19 it("can spawn a single run instance that completes", async () => {20 let tree = new Tree();21 tree.parseIn(`22A -23 B -24 C {25 runInstance.runner.ranStepC = true;26 }27`, "file.txt");28 let runner = new Runner();29 runner.init(tree, true);30 let isComplete = await runner.run();31 expect(runner.ranStepC).to.be.true;32 expect(isComplete).to.be.true;33 });34 it("can spawn a single run instance that pauses and resumes", async () => {35 let tree = new Tree();36 tree.parseIn(`37A {38 runInstance.runner.ranStepA = true;39}40 ~ B {41 runInstance.runner.ranStepB = true;42 }43 C {44 runInstance.runner.ranStepC = true;45 }46`, "file.txt");47 let runner = new Runner();48 runner.init(tree, true);49 let isComplete = await runner.run();50 expect(runner.isPaused).to.be.true;51 expect(runner.ranStepA).to.be.true;52 expect(runner.ranStepB).to.be.undefined;53 expect(runner.ranStepC).to.be.undefined;54 expect(isComplete).to.be.false;55 isComplete = await runner.run();56 expect(runner.isPaused).to.be.false;57 expect(runner.ranStepA).to.be.true;58 expect(runner.ranStepB).to.be.true;59 expect(runner.ranStepC).to.be.true;60 expect(isComplete).to.be.true;61 });62 it("can spawn a multiple run instances, all of which complete", async () => {63 let tree = new Tree();64 tree.parseIn(`65A -66 B -67 C {68 runInstance.runner.ranStepC = true;69 }70 D -71 E {72 runInstance.runner.ranStepE = true;73 }74F {75 runInstance.runner.ranStepF = true;76}77`, "file.txt");78 let runner = new Runner();79 runner.init(tree, true);80 await runner.run();81 expect(runner.ranStepC).to.be.true;82 expect(runner.ranStepE).to.be.true;83 expect(runner.ranStepF).to.be.true;84 });85 it("runs multiple run instances in parallel", async () => {86 let tree = new Tree();87 tree.parseIn(`88Branch 1 -89 Wait '20' ms90Branch 2 -91 Wait '20' ms92Branch 3 -93 Wait '20' ms94Branch 4 -95 Wait '20' ms96Branch 5 -97 Wait '20' ms98Branch 6 -99 Wait '20' ms100* Wait {{N}} ms {101 await new Promise((resolve, reject) => {102 setTimeout(() => {103 resolve();104 }, N);105 });106}107`, "file.txt");108 let runner = new Runner();109 runner.init(tree, true);110 runner.maxParallel = 6;111 await runner.run();112 expect(tree.elapsed).to.be.above(15);113 expect(tree.elapsed).to.be.below(35);114 });115 it("runs multiple run instances in parallel where maxParallel limits the number of simultaneous run instances", async () => {116 let tree = new Tree();117 tree.parseIn(`118Branch 1 -119 Wait '20' ms120Branch 2 -121 Wait '20' ms122Branch 3 -123 Wait '20' ms124Branch 4 -125 Wait '20' ms126Branch 5 -127 Wait '20' ms128Branch 6 -129 Wait '20' ms130* Wait {{N}} ms {131 await new Promise((resolve, reject) => {132 setTimeout(() => {133 resolve();134 }, N);135 });136}137`, "file.txt");138 let runner = new Runner();139 runner.init(tree, true);140 runner.maxParallel = 2;141 await runner.run();142 expect(tree.elapsed).to.be.above(55);143 expect(tree.elapsed).to.be.below(90);144 });145 it("runs multiple run instances in parallel where maxParallel is 1", async () => {146 let tree = new Tree();147 tree.parseIn(`148Branch 1 -149 Wait '20' ms150Branch 2 -151 Wait '20' ms152Branch 3 -153 Wait '20' ms154* Wait {{N}} ms {155 await new Promise((resolve, reject) => {156 setTimeout(() => {157 resolve();158 }, N);159 });160}161`, "file.txt");162 let runner = new Runner();163 runner.init(tree, true);164 runner.maxParallel = 1;165 await runner.run();166 expect(tree.elapsed).to.be.above(55);167 expect(tree.elapsed).to.be.below(90);168 });169 it("can spawn a multiple run instances, but due to ! only a subset of them run at a time", async () => {170 let tree = new Tree();171 tree.parseIn(`172Branch Group 1 - !173 Branch 1 -174 Wait '20' ms175 Log '1'176 Branch 2 -177 Wait '20' ms178 Log '2'179 Branch 3 -180 Wait '20' ms181 Log '3'182Branch Group 2 - !183 Branch 4 -184 Wait '20' ms185 Log '4'186 Branch 5 -187 Wait '20' ms188 Log '5'189 Branch 6 -190 Wait '20' ms191 Log '6'192* Wait {{N}} ms {193 await new Promise((resolve, reject) => {194 setTimeout(() => {195 resolve();196 }, N);197 });198}199* Log {{N}} {200 runInstance.runner.numArr.push(N);201}202`, "file.txt");203 let runner = new Runner();204 runner.init(tree, true);205 runner.maxParallel = 2;206 runner.numArr = [];207 await runner.run();208 expect(tree.elapsed).to.be.above(55);209 expect(tree.elapsed).to.be.below(100);210 expect(runner.numArr).to.eql([ '1', '4', '2', '5', '3', '6' ]);211 });212 it("runs multiple run instances for multiple branches, where one branch fails and one branch passes", async () => {213 let tree = new Tree();214 tree.parseIn(`215Passing branch -216 A -217Failing branch -218 {var1}='{var2}'219`, "file.txt");220 let runner = new Runner();221 runner.init(tree, true);222 runner.maxParallel = 1;223 await runner.run();224 expect(tree.branches[0].isPassed).to.be.true;225 expect(tree.branches[1].isFailed).to.be.true;226 expect(tree.branches[1].steps[1].isFailed).to.be.true;227 expect(tree.branches[1].steps[1].error.message).to.equal("The variable {var2} wasn't set, but is needed for this step. If it's set later in the branch, try using {var2:}.");228 });229 it("pauses before a ~ step is executed, doesn't pause on the same step when resumed", async () => {230 let tree = new Tree();231 tree.parseIn(`232A {233 runInstance.runner.ranStepA = true;234}235 ~ B {236 runInstance.runner.ranStepB = true;237 }238 C {239 runInstance.runner.ranStepC = true;240 }241`, "file.txt");242 let runner = new Runner();243 runner.init(tree, true);244 let isComplete = await runner.run();245 expect(runner.isPaused).to.be.true;246 expect(runner.ranStepA).to.be.true;247 expect(runner.ranStepB).to.be.undefined;248 expect(runner.ranStepC).to.be.undefined;249 expect(isComplete).to.be.false;250 isComplete = await runner.run();251 expect(runner.isPaused).to.be.false;252 expect(runner.ranStepA).to.be.true;253 expect(runner.ranStepB).to.be.true;254 expect(runner.ranStepC).to.be.true;255 expect(isComplete).to.be.true;256 });257 it("pauses after a fail occurs on a step that's inside a branch with ~ anywhere", async () => {258 let tree = new Tree();259 tree.parseIn(`260A {261 runInstance.runner.ranStepA = true;262 throw new Error();263}264 B {265 runInstance.runner.ranStepB = true;266 }267 C {268 runInstance.runner.ranStepC = true;269 }270 ~ D {271 runInstance.runner.ranStepD = true;272 }273`, "file.txt");274 let runner = new Runner();275 runner.init(tree, true);276 let isComplete = await runner.run();277 expect(runner.isPaused).to.be.true;278 expect(runner.ranStepA).to.be.true;279 expect(runner.ranStepB).to.be.undefined;280 expect(runner.ranStepC).to.be.undefined;281 expect(runner.ranStepD).to.be.undefined;282 expect(isComplete).to.be.false;283 isComplete = await runner.run();284 expect(runner.isPaused).to.be.true;285 expect(runner.ranStepA).to.be.true;286 expect(runner.ranStepB).to.be.true;287 expect(runner.ranStepC).to.be.true;288 expect(runner.ranStepD).to.be.undefined;289 expect(isComplete).to.be.false;290 isComplete = await runner.run();291 expect(runner.isPaused).to.be.false;292 expect(runner.ranStepA).to.be.true;293 expect(runner.ranStepB).to.be.true;294 expect(runner.ranStepC).to.be.true;295 expect(runner.ranStepD).to.be.true;296 expect(isComplete).to.be.true;297 });298 it("runs all Before Everything and After Everything steps", async () => {299 let tree = new Tree();300 tree.parseIn(`301A302 B303C304* A {305 runInstance.runner.count++;306}307* B {308 runInstance.runner.count++;309}310* C {311 runInstance.runner.count++;312}313*** Before Everything {314 runInstance.runner.count *= 3;315}316*** Before Everything {317 runInstance.runner.count *= 2;318}319*** After Everything {320 runInstance.runner.count *= 4;321}322*** After Everything {323 runInstance.runner.count *= 5;324}325`, "file.txt");326 let runner = new Runner();327 runner.init(tree, true);328 runner.count = 1;329 await runner.run();330 expect(runner.count).to.equal(180);331 });332 it("runs all After Everything steps but not the Before Everything steps on resume", async () => {333 let tree = new Tree();334 tree.parseIn(`335A336 B337C338* A {339 runInstance.runner.count++;340}341~ * B {342 runInstance.runner.count++;343}344* C {345 runInstance.runner.count++;346}347*** Before Everything {348 runInstance.runner.count *= 3;349}350*** Before Everything {351 runInstance.runner.count *= 2;352}353*** After Everything {354 runInstance.runner.count *= 4;355}356*** After Everything {357 runInstance.runner.count *= 5;358}359`, "file.txt");360 let runner = new Runner();361 runner.init(tree, true);362 runner.count = 1;363 await runner.run();364 expect(runner.count).to.equal(7);365 await runner.run();366 expect(runner.count).to.equal(160);367 });368 it("stores errors from Before Everything steps and stops execution", async () => {369 let tree = new Tree();370 tree.parseIn(`371A372* A {373 runInstance.runner.ranStepA = true;374}375*** Before Everything {376 runInstance.runner.ranBeforeEverything2 = true;377}378*** Before Everything {379 runInstance.runner.ranBeforeEverything1 = true;380 throw new Error("oops");381}382*** After Everything {383 runInstance.runner.ranAfterEverything1 = true;384}385*** After Everything {386 runInstance.runner.ranAfterEverything2 = true;387}388`, "file.txt");389 let runner = new Runner();390 runner.init(tree, true);391 await runner.run();392 expect(runner.ranBeforeEverything1).to.be.true;393 expect(runner.ranBeforeEverything2).to.be.undefined;394 expect(runner.ranStepA).to.be.undefined;395 expect(runner.ranAfterEverything1).to.be.true;396 expect(runner.ranAfterEverything2).to.be.true;397 expect(tree.beforeEverything[0].error.message).to.equal("oops");398 expect(tree.beforeEverything[0].error.filename).to.equal("file.txt");399 expect(tree.beforeEverything[0].error.lineNumber).to.equal(14);400 });401 it("stores errors from After Everything steps", async () => {402 let tree = new Tree();403 tree.parseIn(`404A405* A {406 runInstance.runner.ranStepA = true;407}408*** Before Everything {409 runInstance.runner.ranBeforeEverything2 = true;410}411*** Before Everything {412 runInstance.runner.ranBeforeEverything1 = true;413}414*** After Everything {415 runInstance.runner.ranAfterEverything1 = true;416 throw new Error("oops");417}418*** After Everything {419 runInstance.runner.ranAfterEverything2 = true;420}421`, "file.txt");422 let runner = new Runner();423 runner.init(tree, true);424 await runner.run();425 expect(runner.ranBeforeEverything1).to.be.true;426 expect(runner.ranBeforeEverything2).to.be.true;427 expect(runner.ranStepA).to.be.true;428 expect(runner.ranAfterEverything1).to.be.true;429 expect(runner.ranAfterEverything2).to.be.true;430 expect(tree.afterEverything[0].error.message).to.equal("oops");431 expect(tree.afterEverything[0].error.filename).to.equal("file.txt");432 expect(tree.afterEverything[0].error.lineNumber).to.equal(18);433 });434 it("when a stop occurs while in a Before Everything hook, stops executing Before Everything hooks and executes all After Everything hooks", async () => {435 let tree = new Tree();436 tree.parseIn(`437A438* A {439 runInstance.runner.ranStepA = true;440}441*** Before Everything {442 runInstance.runner.ranBeforeEverything2 = true;443}444*** Before Everything {445 runInstance.runner.ranBeforeEverything1 = true;446 await runInstance.runner.stop();447}448*** After Everything {449 runInstance.runner.ranAfterEverything1 = true;450}451*** After Everything {452 runInstance.runner.ranAfterEverything2 = true;453}454`, "file.txt");455 let runner = new Runner();456 runner.init(tree, true);457 await runner.run();458 expect(runner.ranBeforeEverything1).to.be.true;459 expect(runner.ranBeforeEverything2).to.be.undefined;460 expect(runner.ranStepA).to.be.undefined;461 expect(runner.ranAfterEverything1).to.be.true;462 expect(runner.ranAfterEverything2).to.be.true;463 });464 it("when a stop occurs while in an After Everything hook, finishes executing the rest of the After Everything hooks", async () => {465 let tree = new Tree();466 tree.parseIn(`467A468* A {469 runInstance.runner.ranStepA = true;470}471*** Before Everything {472 runInstance.runner.ranBeforeEverything2 = true;473}474*** Before Everything {475 runInstance.runner.ranBeforeEverything1 = true;476}477*** After Everything {478 runInstance.runner.ranAfterEverything1 = true;479 await runInstance.runner.stop();480}481*** After Everything {482 runInstance.runner.ranAfterEverything2 = true;483}484`, "file.txt");485 let runner = new Runner();486 runner.init(tree, true);487 await runner.run();488 expect(runner.ranBeforeEverything1).to.be.true;489 expect(runner.ranBeforeEverything2).to.be.true;490 expect(runner.ranStepA).to.be.true;491 expect(runner.ranAfterEverything1).to.be.true;492 expect(runner.ranAfterEverything2).to.be.true;493 });494 it("when a stop occurs while executing branches, stops executing branches and executes all After Everything hooks", async () => {495 let tree = new Tree();496 tree.parseIn(`497A498* A {499 runInstance.runner.ranStepA = true;500 await runInstance.runner.stop();501}502*** Before Everything {503 runInstance.runner.ranBeforeEverything2 = true;504}505*** Before Everything {506 runInstance.runner.ranBeforeEverything1 = true;507}508*** After Everything {509 runInstance.runner.ranAfterEverything1 = true;510}511*** After Everything {512 runInstance.runner.ranAfterEverything2 = true;513}514`, "file.txt");515 let runner = new Runner();516 runner.init(tree, true);517 await runner.run();518 expect(runner.ranBeforeEverything1).to.be.true;519 expect(runner.ranBeforeEverything2).to.be.true;520 expect(runner.ranStepA).to.be.true;521 expect(runner.ranAfterEverything1).to.be.true;522 expect(runner.ranAfterEverything2).to.be.true;523 });524 it("sets tree.elapsed to how long it took the tree to execute", async () => {525 let tree = new Tree();526 tree.parseIn(`527Wait 20 ms {528 await new Promise((resolve, reject) => {529 setTimeout(() => {530 resolve();531 }, 20);532 });533}534`, "file.txt");535 let runner = new Runner();536 runner.init(tree, true);537 await runner.run();538 expect(tree.elapsed).to.be.above(15);539 expect(tree.elapsed).to.be.below(35);540 });541 it("sets tree.elapsed to how long it took the tree to execute when a stop ocurred", async () => {542 let tree = new Tree();543 tree.parseIn(`544Wait 20 ms {545 await new Promise((resolve, reject) => {546 setTimeout(() => {547 resolve();548 }, 20);549 });550}551 Stop me {552 await runInstance.runner.stop();553 }554 Wait 100 ms {555 await new Promise((resolve, reject) => {556 setTimeout(() => {557 resolve();558 }, 100);559 });560 }561`, "file.txt");562 let runner = new Runner();563 runner.init(tree, true);564 await runner.run();565 expect(tree.elapsed).to.be.above(15);566 expect(tree.elapsed).to.be.below(35);567 });568 it("sets tree.elapsed to -1 when a pause and resume occurred", async () => {569 let tree = new Tree();570 tree.parseIn(`571A -572 ~ B -573 C -574`, "file.txt");575 let runner = new Runner();576 runner.init(tree, true);577 await runner.run();578 expect(tree.elapsed).to.equal(-1);579 await runner.run();580 expect(tree.elapsed).to.equal(-1);581 });582 it("throws an error if the Runner was already stopped before", async () => {583 let tree = new Tree();584 tree.parseIn(`585A -586 B {587 await runInstance.runner.stop();588 }589 C -590`, "file.txt");591 let runner = new Runner();592 runner.init(tree, true);593 await runner.run();594 await expect(runner.run()).to.be.rejectedWith("Cannot run a stopped runner");595 });596 });597 describe("stop()", () => {598 it("stops all running run instances, time elapsed for the Tree is properly measured", function(done) {599 let tree = new Tree();600 tree.parseIn(`601Branch 1 -602 Wait '20' ms603Branch 2 -604 Wait '20' ms605Branch 3 -606 Wait '20' ms607* Wait {{N}} ms {608 await new Promise((resolve, reject) => {609 setTimeout(() => {610 resolve();611 }, N);612 });613}614`, "file.txt");615 let runner = new Runner();616 runner.init(tree, true);617 let promise = runner.run();618 // do a stop() after 10 ms619 setTimeout(async() => {620 await runner.stop();621 expect(tree.elapsed).to.be.above(8);622 expect(tree.elapsed).to.be.below(20);623 await promise;624 done();625 }, 10);626 });627 it("runs all After Everything steps asynchronously after a stop occurs", function(done) {628 let tree = new Tree();629 tree.parseIn(`630Branch 1 -631 Wait '20' ms632Branch 2 -633 Wait '20' ms634Branch 3 -635 Wait '20' ms636*** After Everything {637 await new Promise((resolve, reject) => {638 setTimeout(() => {639 runInstance.runner.afterEverythingRan = true;640 resolve();641 }, 1);642 });643}644* Wait {{N}} ms {645 await new Promise((resolve, reject) => {646 setTimeout(() => {647 resolve();648 }, N);649 });650}651`, "file.txt");652 let runner = new Runner();653 runner.init(tree, true);654 let promise = runner.run();655 // do a stop() after 10 ms656 setTimeout(async() => {657 await runner.stop();658 expect(tree.elapsed).to.be.above(8);659 expect(tree.elapsed).to.be.below(20);660 expect(runner.afterEverythingRan).to.be.true;661 await promise;662 done();663 }, 10);664 });665 });666 describe("runOneStep()", () => {667 it("runs the next step, then pauses again", async () => {668 let tree = new Tree();669 tree.parseIn(`670A {671 runInstance.runner.ranStepA = true;672}673 ~ B {674 runInstance.runner.ranStepB = true;675 }676 C {677 runInstance.runner.ranStepC = true;678 }679*** After Everything {680 runInstance.runner.afterEverythingRan = true;681}682`, "file.txt");683 let runner = new Runner();684 runner.init(tree, true);685 await runner.run();686 expect(runner.isPaused).to.be.true;687 expect(runner.ranStepA).to.be.true;688 expect(runner.ranStepB).to.be.undefined;689 expect(runner.ranStepC).to.be.undefined;690 expect(runner.afterEverythingRan).to.be.undefined;691 let isBranchComplete = await runner.runOneStep();692 expect(runner.isPaused).to.be.true;693 expect(runner.ranStepA).to.be.true;694 expect(runner.ranStepB).to.be.true;695 expect(runner.ranStepC).to.be.undefined;696 expect(runner.afterEverythingRan).to.be.undefined;697 expect(isBranchComplete).to.be.false;698 isBranchComplete = await runner.runOneStep();699 expect(runner.isPaused).to.be.true;700 expect(runner.ranStepA).to.be.true;701 expect(runner.ranStepB).to.be.true;702 expect(runner.ranStepC).to.be.true;703 expect(runner.afterEverythingRan).to.be.undefined;704 expect(isBranchComplete).to.be.false;705 isBranchComplete = await runner.runOneStep();706 expect(runner.isPaused).to.be.true;707 expect(runner.ranStepA).to.be.true;708 expect(runner.ranStepB).to.be.true;709 expect(runner.ranStepC).to.be.true;710 expect(runner.afterEverythingRan).to.be.true;711 expect(isBranchComplete).to.be.true;712 });713 it("the Runner is able to resume after pausing and running one step", async () => {714 let tree = new Tree();715 tree.parseIn(`716A {717 runInstance.runner.ranStepA = true;718}719 ~ B {720 runInstance.runner.ranStepB = true;721 }722 C {723 runInstance.runner.ranStepC = true;724 }725*** After Everything {726 runInstance.runner.afterEverythingRan = true;727}728`, "file.txt");729 let runner = new Runner();730 runner.init(tree, true);731 await runner.run();732 expect(runner.isPaused).to.be.true;733 expect(runner.ranStepA).to.be.true;734 expect(runner.ranStepB).to.be.undefined;735 expect(runner.ranStepC).to.be.undefined;736 expect(runner.afterEverythingRan).to.be.undefined;737 let isBranchComplete = await runner.runOneStep();738 expect(runner.isPaused).to.be.true;739 expect(runner.ranStepA).to.be.true;740 expect(runner.ranStepB).to.be.true;741 expect(runner.ranStepC).to.be.undefined;742 expect(runner.afterEverythingRan).to.be.undefined;743 expect(isBranchComplete).to.be.false;744 await runner.run();745 expect(runner.ranStepA).to.be.true;746 expect(runner.ranStepB).to.be.true;747 expect(runner.ranStepC).to.be.true;748 expect(runner.afterEverythingRan).to.be.true;749 });750 it("the Runner is able to resume after pausing, running one step, and ending up beyond the last step", async () => {751 let tree = new Tree();752 tree.parseIn(`753A {754 runInstance.runner.ranStepA = true;755}756 ~ B {757 runInstance.runner.ranStepB = true;758 }759 C {760 runInstance.runner.ranStepC = true;761 }762*** After Everything {763 runInstance.runner.afterEverythingRan = true;764}765`, "file.txt");766 let runner = new Runner();767 runner.init(tree, true);768 await runner.run();769 expect(runner.isPaused).to.be.true;770 expect(runner.ranStepA).to.be.true;771 expect(runner.ranStepB).to.be.undefined;772 expect(runner.ranStepC).to.be.undefined;773 expect(runner.afterEverythingRan).to.be.undefined;774 let isBranchComplete = await runner.runOneStep();775 expect(runner.isPaused).to.be.true;776 expect(runner.ranStepA).to.be.true;777 expect(runner.ranStepB).to.be.true;778 expect(runner.ranStepC).to.be.undefined;779 expect(runner.afterEverythingRan).to.be.undefined;780 expect(isBranchComplete).to.be.false;781 isBranchComplete = await runner.runOneStep();782 expect(runner.isPaused).to.be.true;783 expect(runner.ranStepA).to.be.true;784 expect(runner.ranStepB).to.be.true;785 expect(runner.ranStepC).to.be.true;786 expect(runner.afterEverythingRan).to.be.undefined;787 expect(isBranchComplete).to.be.false;788 await runner.run();789 expect(runner.ranStepA).to.be.true;790 expect(runner.ranStepB).to.be.true;791 expect(runner.ranStepC).to.be.true;792 expect(runner.afterEverythingRan).to.be.true;793 });794 it("throws error if not paused", async () => {795 let tree = new Tree();796 let runner = new Runner();797 runner.init(tree, true);798 await expect(runner.runOneStep()).to.be.rejectedWith("Must be paused to run a step");799 });800 });801 describe("skipOneStep()", () => {802 it("skips the next step, then pauses again", async () => {803 let tree = new Tree();804 tree.parseIn(`805A {806 runInstance.runner.ranStepA = true;807}808 ~ B {809 runInstance.runner.ranStepB = true;810 }811 C {812 runInstance.runner.ranStepC = true;813 }814*** After Everything {815 runInstance.runner.afterEverythingRan = true;816}817`, "file.txt");818 let runner = new Runner();819 runner.init(tree, true);820 await runner.run();821 expect(runner.isPaused).to.be.true;822 expect(runner.ranStepA).to.be.true;823 expect(runner.ranStepB).to.be.undefined;824 expect(runner.ranStepC).to.be.undefined;825 expect(runner.afterEverythingRan).to.be.undefined;826 let isBranchComplete = await runner.skipOneStep();827 // We are at the start of C828 expect(runner.isPaused).to.be.true;829 expect(runner.ranStepA).to.be.true;830 expect(runner.ranStepB).to.be.undefined;831 expect(runner.ranStepC).to.be.undefined;832 expect(runner.afterEverythingRan).to.be.undefined;833 expect(isBranchComplete).to.be.false;834 isBranchComplete = await runner.skipOneStep();835 // We are at the start of After Everythings836 expect(runner.isPaused).to.be.true;837 expect(runner.ranStepA).to.be.true;838 expect(runner.ranStepB).to.be.undefined;839 expect(runner.ranStepC).to.be.undefined;840 expect(runner.afterEverythingRan).to.be.undefined;841 expect(isBranchComplete).to.be.false;842 isBranchComplete = await runner.skipOneStep();843 // We finished the branch844 expect(runner.isPaused).to.be.true;845 expect(runner.ranStepA).to.be.true;846 expect(runner.ranStepB).to.be.undefined;847 expect(runner.ranStepC).to.be.undefined;848 expect(runner.afterEverythingRan).to.be.true;849 expect(isBranchComplete).to.be.true;850 });851 it("the Runner is able to resume after pausing and skipping steps", async () => {852 let tree = new Tree();853 tree.parseIn(`854A {855 runInstance.runner.ranStepA = true;856}857 ~ B {858 runInstance.runner.ranStepB = true;859 }860 C {861 runInstance.runner.ranStepC = true;862 }863*** After Everything {864 runInstance.runner.afterEverythingRan = true;865}866`, "file.txt");867 let runner = new Runner();868 runner.init(tree, true);869 await runner.run();870 expect(runner.isPaused).to.be.true;871 expect(runner.ranStepA).to.be.true;872 expect(runner.ranStepB).to.be.undefined;873 expect(runner.ranStepC).to.be.undefined;874 expect(runner.afterEverythingRan).to.be.undefined;875 let isBranchComplete = await runner.skipOneStep();876 // We are at the start of C877 expect(runner.isPaused).to.be.true;878 expect(runner.ranStepA).to.be.true;879 expect(runner.ranStepB).to.be.undefined;880 expect(runner.ranStepC).to.be.undefined;881 expect(runner.afterEverythingRan).to.be.undefined;882 expect(isBranchComplete).to.be.false;883 await runner.run();884 expect(runner.ranStepA).to.be.true;885 expect(runner.ranStepB).to.be.undefined;886 expect(runner.ranStepC).to.be.true;887 expect(runner.afterEverythingRan).to.be.true;888 });889 it("the Runner is able to resume after pausing, skipping steps, and ending up beyond the last step", async () => {890 let tree = new Tree();891 tree.parseIn(`892A {893 runInstance.runner.ranStepA = true;894}895 ~ B {896 runInstance.runner.ranStepB = true;897 }898 C {899 runInstance.runner.ranStepC = true;900 }901*** After Everything {902 runInstance.runner.afterEverythingRan = true;903}904`, "file.txt");905 let runner = new Runner();906 runner.init(tree, true);907 await runner.run();908 expect(runner.isPaused).to.be.true;909 expect(runner.ranStepA).to.be.true;910 expect(runner.ranStepB).to.be.undefined;911 expect(runner.ranStepC).to.be.undefined;912 expect(runner.afterEverythingRan).to.be.undefined;913 let isBranchComplete = await runner.skipOneStep();914 // We are at the start of C915 expect(runner.isPaused).to.be.true;916 expect(runner.ranStepA).to.be.true;917 expect(runner.ranStepB).to.be.undefined;918 expect(runner.ranStepC).to.be.undefined;919 expect(runner.afterEverythingRan).to.be.undefined;920 expect(isBranchComplete).to.be.false;921 isBranchComplete = await runner.skipOneStep();922 // We are at the start of After Everythings923 expect(runner.isPaused).to.be.true;924 expect(runner.ranStepA).to.be.true;925 expect(runner.ranStepB).to.be.undefined;926 expect(runner.ranStepC).to.be.undefined;927 expect(runner.afterEverythingRan).to.be.undefined;928 expect(isBranchComplete).to.be.false;929 await runner.run();930 expect(runner.ranStepA).to.be.true;931 expect(runner.ranStepB).to.be.undefined;932 expect(runner.ranStepC).to.be.undefined;933 expect(runner.afterEverythingRan).to.be.true;934 });935 it("throws error if not paused", async () => {936 let tree = new Tree();937 let runner = new Runner();938 runner.init(tree, true);939 await expect(runner.skipOneStep()).to.be.rejectedWith("Must be paused to skip a step");940 });941 });942 describe("inject()", () => {943 it("throws error if not paused", async () => {944 let tree = new Tree();945 let runner = new Runner();946 runner.init(tree, true);947 await expect(runner.inject(``)).to.be.rejectedWith("Must be paused to run a step");948 });949 it("injects a step and runs it, then pauses again", async () => {950 let tree = new Tree();951 tree.parseIn(`952A {953 runInstance.runner.ranStepA = !runInstance.runner.ranStepA;954}955 ~ B {956 runInstance.runner.ranStepB = !runInstance.runner.ranStepB;957 }958 C {959 runInstance.runner.ranStepC = !runInstance.runner.ranStepC;960 }961`, "file.txt");962 let runner = new Runner();963 runner.init(tree, true);964 await runner.run();965 expect(runner.isPaused).to.be.true;966 expect(runner.ranStepA).to.be.true;967 expect(runner.ranStepB).to.be.undefined;968 expect(runner.ranStepC).to.be.undefined;969 expect(runner.ranInjectedStep).to.be.undefined;970 await runner.inject(`971Step to Inject {972 runInstance.runner.ranInjectedStep = !runInstance.runner.ranInjectedStep;973}`);974 expect(runner.isPaused).to.be.true;975 expect(runner.ranStepA).to.be.true;976 expect(runner.ranStepB).to.be.undefined;977 expect(runner.ranStepC).to.be.undefined;978 expect(runner.ranInjectedStep).to.be.true;979 });980 });981 describe("serialize()", () => {982 it("returns a serialized object", async () => {983 let tree = new Tree();984 let runner = new Runner();985 runner.init(tree, true);986 runner.persistent = { a: 1, b: 2 };987 runner.isComplete = true;988 let obj = runner.serialize();989 Comparer.expect(obj).to.match({990 isComplete: true,991 persistent: undefined992 });993 });994 });...

Full Screen

Full Screen

gameServer.js

Source:gameServer.js Github

copy

Full Screen

1const { getRunInstanceServer } = require("./main.js");2const { CodeRepo, InvitationRequest, Joystick, Turn, Game, Pawn, Hero, Prize} = require("./jigs.js");3let codeRepoLocation = '4d7417796d72bffc3c128e85eddea6e44bdf90a36913c3aa622007cb4d623e43_o1';4const CLASES = [InvitationRequest, Joystick, Turn, Game, Pawn, Hero, Prize];5async function deployGameClasses(run, codeRepo) {6 const deployedClasses = await Promise.all(CLASES.map(c => {7 const promise = run.deploy(c)8 console.log(`Deploya3 clase: ${c.name}`)9 return promise;10 }))11 await run.sync();12 const classesLocations = {};13 deployedClasses.forEach(c => { classesLocations[c.name] = c.location; });14 codeRepo.mergeLocations(classesLocations);15 await codeRepo.sync();16 return codeRepo.locations;17}18class GameServer {19 constructor() {20 this.runInstance = getRunInstanceServer();21 }22 async loadClasses() {23 this.classesLocations = {}24 await this.runInstance.inventory.sync();25 this.runInstance.inventory.code.forEach(c => {26 this.classesLocations[c.name] = c;27 })28 }29 async resetearYEmpezarDeNuevo() {30 await this.destroyAll()31 await this.deployClasses()32 await this.beginGame()33 }34 async deployClasses() {35 let CodeRepoDeployed;36 if (codeRepoLocation === null) {37 CodeRepoDeployed = await this.runInstance.deploy(CodeRepo);38 await this.runInstance.sync();39 codeRepoLocation = CodeRepoDeployed.location;40 } else {41 CodeRepoDeployed = await this.runInstance.load(codeRepoLocation);42 await CodeRepoDeployed.sync();43 await this.runInstance.sync();44 }45 await deployGameClasses(this.runInstance, CodeRepoDeployed);46 await this.loadClasses();47 }48 async beginGame() {49 const Game = this.classesLocations.Game;50 await Game.sync()51 const pepitaGame = Game.createGame();52 pepitaGame.begin(`pepita ${new Date().toString()}`, 1);53 await pepitaGame.sync();54 this.gameLocation = pepitaGame.location;55 }56 async approveInvitations() {57 await this.runInstance.inventory.sync();58 const I = this.classesLocations.InvitationRequest;59 const game = await this.currentGame();60 await game.sync();61 for(const i of this.runInstance.inventory.jigs.filter(jig => jig instanceof I)) {62 await i.sync();63 if(!i.used) {64 const j = i.sendJoystick();65 await j.sync();66 await i.sync();67 await game.sync();68 }69 }70 }71 async destroyInstances() {72 await this.runInstance.inventory.sync();73 this.classesLocations.Game.removeAllGames();74 await Promise.all(this.runInstance.inventory.jigs.map(j => j.destroy()));75 }76 async destroyAll() {77 await this.runInstance.inventory.sync();78 await Promise.all(this.runInstance.inventory.jigs.map(j => j.destroy()));79 await Promise.all(this.runInstance.inventory.code.filter(c => c.name !== 'CodeRepo').map(j => j.destroy()));80 }81 async currentGame() {82 const currentGame = await this.runInstance.load(this.gameLocation);83 return await currentGame.sync();84 }85 async tickGame() {86 const game = await this.currentGame();87 game.tick();88 await game.sync();89 }90}...

Full Screen

Full Screen

Using AI Code Generation

copy

Full Screen

1import { runInstance } from 'storybook-root-decorator';2import { storiesOf } from '@storybook/react';3import { withKnobs, text } from '@storybook/addon-knobs';4import { withInfo } from '@storybook/addon-info';5import { withA11y } from '@storybook/addon-a11y';6import { withTests } from '@storybook/addon-jest';7import results from '../.jest-test-results.json';8import MyComponent from '../src';9const stories = storiesOf('MyComponent', module);10stories.addDecorator(withKnobs);11stories.addDecorator(withInfo);12stories.addDecorator(withA11y);13stories.addDecorator(withTests({ results }));14stories.add('Default', () => {15 const name = text('Name', 'John Doe');16 return runInstance(MyComponent, { name });17});18import { configure } from '@storybook/react';19import { addDecorator } from '@storybook/react';20import { withA11y } from '@storybook/addon-a11y';21import { withTests } from '@storybook/addon-jest';22import results from '../.jest-test-results.json';23addDecorator(withA11y);24addDecorator(withTests({ results }));25configure(() => {26 require('../test.js');27}, module);28module.exports = async ({ config }) => {29 {30 test: /\.(js|jsx)$/,31 use: {32 },33 },34 {35 test: /\.(ts|tsx)$/,36 use: {37 },38 },39 {40 },41 {42 {43 options: {44 },45 },46 },47 {48 test: /\.(png|jpg|gif|svg)$/,49 use: {50 options: {51 },52 },53 },54 ];55 config.resolve.extensions.push('.ts', '.tsx', '.js', '.jsx');56 return config;57};

Full Screen

Using AI Code Generation

copy

Full Screen

1import { runInstance } from 'storybook-root-decorator';2import { storiesOf } from '@storybook/react';3const stories = storiesOf('MyComponent', module);4stories.add('default', () => {5 return runInstance(<MyComponent />, {6 });7});8import { configure } from '@storybook/react';9import 'storybook-root-decorator/register';10configure(require.context('../src', true, /\.stories\.js$/), module);11import 'storybook-root-decorator/preview';

Full Screen

Using AI Code Generation

copy

Full Screen

1import { runInstance } from 'storybook-root-decorator'2runInstance({3 props: {4 },5})6import { configure } from '@storybook/react'7import 'storybook-root-decorator'8configure(() => {9 require('./test.js')10}, module)

Full Screen

Using AI Code Generation

copy

Full Screen

1import { runInstance } from 'storybook-root-decorator';2import YourComponent from '../src/components/YourComponent';3runInstance(YourComponent);4import '../test.js';5import { addDecorator } from '@storybook/react';6import { withRootDecorator } from 'storybook-root-decorator';7addDecorator(withRootDecorator);8const path = require('path');9module.exports = ({ config }) => {10 config.resolve.alias['storybook-root-decorator'] = path.resolve(11 );12 return config;13};14import React from 'react';15import { storiesOf } from '@storybook/react';16import Button from '../src/components/Button';17storiesOf('Button', module).add('with text', () => <Button>Hello Button</Button>);18import React from 'react';19import { storiesOf } from '@storybook/react';20import { action } from '@storybook/addon-actions';21import Button from '../src/components/Button';22const stories = storiesOf('Button', module);23stories.add('with text', () => (24 <Button onClick={action('clicked')}>Hello Button</Button>25));26stories.add('with some emoji', () => (27 <Button onClick={action('clicked')}>28));29import React from 'react';30import { storiesOf } from '@storybook/react';31import { action } from '@storybook/addon-actions';32import Button from '../src/components/Button';33export default {34};35export const Text = () => <Button onClick={action('clicked')}>Hello Button</Button>;36export const Emoji = () => (37 <Button onClick={action('clicked')}>

Full Screen

Using AI Code Generation

copy

Full Screen

1import { runInstance } from 'storybook-root-decorator';2runInstance({3 props: {4 },5 options: {6 },7});8import { runInstance } from 'storybook-root-decorator';9runInstance({10 props: {11 },12 options: {13 },14});15import { runInstance } from 'storybook-root-decorator';16runInstance({17 props: {18 },19 options: {20 },21});22import { runInstance } from 'storybook-root-decorator';23runInstance({24 props: {25 },26 options: {27 },28});29import { runInstance } from 'storybook-root-decorator';30runInstance({31 props: {32 },33 options: {34 },35});36import { runInstance } from 'storybook-root-decorator';37runInstance({38 props: {39 },40 options: {41 },42});43import { runInstance } from 'storybook-root-decorator';44runInstance({45 props: {

Full Screen

Automation Testing Tutorials

Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.

LambdaTest Learning Hubs:

YouTube

You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.

Run storybook-root automation tests on LambdaTest cloud grid

Perform automation testing on 3000+ real desktop and mobile devices online.

Try LambdaTest Now !!

Get 100 minutes of automation test minutes FREE!!

Next-Gen App & Browser Testing Cloud

Was this article helpful?

Helpful

NotHelpful