@intuitionrobotics/testelot
Version:
Nu-Art Sir Testelot
214 lines • 7.11 kB
JavaScript
/*
* 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