UNPKG

@intuitionrobotics/testelot

Version:
214 lines 7.11 kB
/* * Testelot is a typescript scenario composing framework * * Copyright (C) 2020 Intuition Robotics * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Created by IR on 3/18/17. */ import { currentTimeMillies, generateUUID, Logger, timeout, Void, isErrorOfType, __stringify } from "@intuitionrobotics/ts-common"; import { ContextKey } from "./ContainerContext.js"; import { Reporter } from "./Reporter.js"; import { TestException } from "./TestException.js"; export var Status; (function (Status) { Status["Ready"] = "Ready"; Status["Running"] = "Running"; Status["Skipped"] = "Skipped"; Status["Success"] = "Success"; Status["Error"] = "Error"; })(Status || (Status = {})); export var ErrorPolicy; (function (ErrorPolicy) { ErrorPolicy[ErrorPolicy["ContinueOnError"] = 0] = "ContinueOnError"; ErrorPolicy[ErrorPolicy["SkipOnError"] = 1] = "SkipOnError"; ErrorPolicy[ErrorPolicy["HaltOnError"] = 2] = "HaltOnError"; })(ErrorPolicy || (ErrorPolicy = {})); export class Action extends Logger { static testsToRun = []; actionType; uuid = generateUUID(); writeKey; readKey; parent; reporter; label = "Unnamed Action"; policy = ErrorPolicy.SkipOnError; _started; _ended; postExecutionDelay = 0; status = Status.Ready; shouldFailCondition; assertFailCondition; constructor(actionType, tag) { super(tag || "Testelot"); this.actionType = actionType.name; } static resolveTestsToRun() { const strings = process.argv.filter((arg) => arg.includes("--test=")); console.log(`raw: ${__stringify(strings)}`); this.testsToRun = strings.map(arg => arg.replace("--test=", "")); console.log(`Tests to run: ${__stringify(this.testsToRun)}`); } expectToFail(_exceptionType, assertFailCondition) { this.shouldFailCondition = (e) => { const err = isErrorOfType(e, _exceptionType); if (!err) throw new TestException(`Test should have failed with an: ${_exceptionType.name}`); return !assertFailCondition ? true : assertFailCondition(err); }; return this; } processReturnValue(returnValueProcessor) { this.assertFailCondition = returnValueProcessor; return this; } isContainer() { return false; } hasParent() { return !!this.parent; } setErrorPolicy(policy) { this.policy = policy; return this; } setParent(parent) { this.parent = parent; } setReporter(reporter) { this.reporter = reporter; } setWriteKey(writeKey) { this.writeKey = writeKey; return this; } setReadKey(readKey) { this.readKey = readKey; return this; } setPostExecutionDelay(postExecutionDelay) { this.postExecutionDelay = postExecutionDelay; return this; } setLabel(label) { this.label = label; return this; } getStarted() { return this._started; } getEnded() { return this._ended; } async _executeSubAction(action) { action.setParent(this); action.setReporter(this.reporter); await action._execute(); } resolveLabel(param) { if (!this.label) return; return typeof this.label === "string" ? this.label : this.label(param); } async _execute() { this._started = currentTimeMillies(); let label; let err; let retValue = undefined; try { let param; if (this.readKey) param = this.get(this.readKey); label = this.resolveLabel(param); if (Action.testsToRun.length > 0 && !Action.testsToRun.find(testToRun => (label || "").includes(testToRun))) this.setStatus(Status.Skipped); else this.setStatus(Status.Ready); if (this.status === Status.Skipped) { if (this.isContainer()) // @ts-expect-error TS struggles with this dynamic typing await this.execute(); if (label) this.reporter.logVerbose(`skipped: ${label}`); this.reporter.onActionEnded(this); this._ended = currentTimeMillies(); return; } if (this.isContainer()) { if (label) this.reporter.logVerbose(`+ ${label}`); } else { if (label) this.reporter.logVerbose(`Running: ${label}`); if (this.readKey) this.reporter.logDebug(`Using context: ${this.readKey.key}`); } this.reporter.onActionStarted(this); this.setStatus(Status.Running); retValue = await this.execute((param || Void)); } catch (e) { err = this.shouldFailCondition?.(e) ? undefined : e; } finally { if (this.status !== Status.Skipped) { this.setStatus(err ? Status.Error : Status.Success); this.reporter.onActionEnded(this); if (err) { if (label) this.reporter.logError(`Error in Action: ${label}`); this.reporter.logError(err); } else { // only set the ret value if we expect a success... if (this.writeKey && !this.shouldFailCondition) { this.set(this.writeKey, retValue); } this.assertFailCondition?.(retValue); // label && this.reporter.logVerbose(`ended: ${label}`); if (this.isContainer() && label) this.reporter.logVerbose(`- ${label}`); } } } if (this.postExecutionDelay > 0) await timeout(this.postExecutionDelay); this._ended = currentTimeMillies(); } setStatus(status) { this.status = status; } get(key) { if (!this.parent) return key.defaultValue; return this.parent.get(key); } remove(key) { if (!this.parent) return false; return this.parent.remove(key); } set(key, value) { if (!this.parent) return; return this.parent.set(key, value); } reset() { // } } //# sourceMappingURL=Action.js.map