更多信息请参阅 JavaScript Modules。
如何使用
简介:
本示例展示如何通过 Tasks 接口,完整管理一次自动化任务的生命周期。
脚本依次完成任务创建(tasksCreate)、任务入库确认(tasksGet),并通过轮询方式持续查询任务状态,直到任务执行结束(RUNNING → STOPPED_*),最终输出任务执行结果与关键信息。
示例内置标准化的步骤日志(开始 / 结束 / 耗时统计),并在失败场景下自动采集前台应用、Activity、电量、设备信息及截图留证,便于问题定位与结果审计。
适用于 自动化测试调度、批量任务执行、平台集成与执行结果监控 等场景,可直接复制运行。
运行前:
sleep(10000);
print('-tasks-test-');>> sigmaLoad("TaskCreateSubmitPoll.js");
注意:
源代码
/**
* ============================================================
* [TASK] Create -> Submit -> Get results
* ============================================================
* 目标:
* 1) 创建任务 tasksCreate(...)
* 2) 确认任务已入库 tasksGet(...)
* 3) 轮询 tasksGet(...) 等待任务结束(RUNNING -> STOPPED_*)
* 4) 打印结果(status / errorMessage / execDevice / sigmaTestStatus 等)
*
* 输出要求:
* - 每一步打印「开始/结束/耗时」
* - 失败:写上下文(前台包名+activity+电量+设备信息)+ 截图 + 写日志文件(若 fs 可用)
*
* 关键注意:
* - tasksCreate() 会校验脚本路径必须存在,否则 "Script path not found"
* - tasks 的“执行器”不一定马上运行;如果 planTime 在未来会保持 SCHEDULED(-6)
* - 本示例用轮询 tasksGet 获取最终 status(-2/-3/-5 等)
*/
// ===================== 引入与注入 =====================
var { getDevices } = require("sigma/device");
var tasks = require("sigma/tasks"); // tasks 模块
// ===================== 配置区 =====================
var LOG_DIR = "C:/tc_logs";
var IMG_TYPE = tcConst.IMG_JPG || tcConst.IMG_PNG;
// 任务名必须唯一(建议带时间戳)
function pad2(n) {
return (n < 10 ? "0" : "") + n;
}
function ts() {
var d = new Date();
return (
d.getFullYear() +
pad2(d.getMonth() + 1) +
pad2(d.getDate()) +
"_" +
pad2(d.getHours()) +
pad2(d.getMinutes()) +
pad2(d.getSeconds())
);
}
var TASK_NAME = "demo_task_" + ts();
// 脚本必须存在、且扩展名必须 .js/.tst/.scp
// 例:var SCRIPT_PATH = "c:/file/test.js" 或者 test.js;
var SCRIPT_PATH = "test.js";
// 执行次数(iteration/iterCount)>=1
var ITERATION = 1;
// 执行时间策略:
// 1) 立刻创建(now):time = undefined, repeat = undefined
// 2) 指定一次性时间:time = "YYYY-MM-DD HH:mm[:ss]"
// 3) 周期:time="HH:mm[:ss]" + repeat=[0..6]
var TIME_MODE = "now"; // "now" | "runOnce" | "weekly"
// runOnce 示例(未来时间)
// var ONE_SHOT_TIME = "2026-01-14 23:50";
// weekly 示例:每周一三五 08:30
// var WEEKLY_TIME = "08:30";
// var WEEKLY_REPEAT = [1,3,5];
// 轮询等待最大时长(毫秒)
var WAIT_TIMEOUT_MS = 3 * 60 * 1000; // 3 分钟
var POLL_INTERVAL_MS = 1500;
// ===================== 小工具 =====================
function nowMs() {
return Date.now();
}
function safeFilePart(s) {
return String(s).replace(/[^\w\-.]+/g, "_");
}
function devName(d) {
return d.name || (d.getName && d.getName()) || d.SN || "UnknownDevice";
}
function safeGet(fn, fallback) {
try {
return fn();
} catch (e) {
return fallback;
}
}
// fs(有则写日志/锁)
var fs = null;
try {
fs = require("fs");
} catch (e) {
fs = null;
}
function ensureDir(path) {
if (!fs) return false;
try {
if (!fs.existsSync(path)) fs.mkdirSync(path, { recursive: true });
return true;
} catch (e) {
return false;
}
}
function appendFile(path, text) {
if (!fs) return false;
try {
fs.appendFileSync(path, text, { encoding: "utf8" });
return true;
} catch (e) {
return false;
}
}
// ===================== 日志 ctx =====================
function makeCtx() {
var canWrite = fs != null && ensureDir(LOG_DIR);
var logFile =
LOG_DIR + "/TASK__" + safeFilePart(TASK_NAME) + "__" + ts() + ".log";
return {
logFile: logFile,
canWrite: canWrite,
log: function (line) {
var msg = "[TASK] " + line;
print(msg);
if (this.canWrite) appendFile(this.logFile, msg + "\n");
},
};
}
// ===================== stepRun:开始/结束/耗时 =====================
function stepRun(ctx, stepName, fn) {
var start = nowMs();
ctx.log(">> START " + stepName);
try {
var ret = fn();
ctx.log(
"<< END " + stepName + " (cost " + (nowMs() - start) + " ms)",
);
return { ok: true, ret: ret };
} catch (e) {
ctx.log(
"<< FAIL " +
stepName +
" (cost " +
(nowMs() - start) +
" ms) err=" +
String(e && e.message ? e.message : e),
);
return { ok: false, err: String(e && e.message ? e.message : e) };
}
}
// ===================== 失败上下文 + 截图 =====================
function writeFailContext(ctx, d, stepName, errText) {
ctx.log("---- FAIL CONTEXT (" + devName(d) + ") BEGIN ----");
ctx.log("step=" + stepName);
ctx.log("error=" + (errText || ""));
ctx.log(
"foregroundApp=" +
(safeGet(function () {
return d.getForegroundApp();
}, "") || ""),
);
ctx.log(
"activity=" +
(safeGet(function () {
return d.getActivity();
}, "") || ""),
);
ctx.log(
"battery=" +
(safeGet(function () {
return d.battery;
}, "") || ""),
);
ctx.log(
"manufacturer=" +
safeGet(function () {
return d.manufacturer;
}, ""),
);
ctx.log(
"model=" +
safeGet(function () {
return d.model;
}, ""),
);
ctx.log(
"SN=" +
safeGet(function () {
return d.SN;
}, ""),
);
ctx.log(
"IP=" +
safeGet(function () {
return d.IP;
}, ""),
);
ctx.log(
"DPI=" +
safeGet(function () {
return d.DPI;
}, ""),
);
ctx.log(
"resolution=" +
safeGet(function () {
return d.width;
}, "") +
"x" +
safeGet(function () {
return d.height;
}, ""),
);
ctx.log(
"androidVersionRelease=" +
safeGet(function () {
return d.androidVersionRelease;
}, ""),
);
ctx.log(
"androidVersionSdkInt=" +
safeGet(function () {
return d.androidVersionSdkInt;
}, ""),
);
ctx.log("---- FAIL CONTEXT (" + devName(d) + ") END ----");
}
function screenshotOne(ctx, d, tag) {
var file =
LOG_DIR +
"/" +
safeFilePart(devName(d)) +
"__" +
safeFilePart(tag) +
"__" +
ts() +
".jpg";
var ret = d.screenshot(file, IMG_TYPE);
if (ret === 0) ctx.log("!! Screenshot saved: " + file);
else ctx.log("!! Screenshot failed (" + devName(d) + "): " + lastError());
}
// ===================== task status helper =====================
function statusToText(code) {
var S = tasks.STATUS || {};
// 常见值(文档里)
if (code === 0) return "FILE_NOT_FOUND(0)";
if (code === S.RUNNING || code === -1) return "RUNNING(-1)";
if (code === S.STOPPED_NORMAL || code === -2) return "STOPPED_NORMAL(-2)";
if (code === S.STOPPED_ERROR || code === -3) return "STOPPED_ERROR(-3)";
if (code === S.PAUSED || code === -4) return "PAUSED(-4)";
if (code === S.USER_TERMINATED || code === -5) return "USER_TERMINATED(-5)";
if (code === S.SCHEDULED || code === -6) return "SCHEDULED(-6)";
return String(code);
}
function isTerminalStatus(code) {
return code === -2 || code === -3 || code === -5 || code === 0;
}
// ===================== main =====================
function main() {
var ctx = makeCtx();
// 可选:拿到设备,主要用于失败时上下文/截图
var devices = getDevices();
var list = [];
if (devices && devices.length)
devices.forEach(function (d) {
list.push(d);
});
ctx.log("Selected devices: " + list.length);
// Step0:准备脚本路径存在性提示
stepRun(ctx, "Step0 Check script path string", function () {
ctx.log("TASK_NAME=" + TASK_NAME);
ctx.log("SCRIPT_PATH=" + SCRIPT_PATH);
ctx.log("ITERATION=" + ITERATION);
ctx.log("TIME_MODE=" + TIME_MODE);
});
// Step1:Create task
var s1 = stepRun(ctx, "Step1 tasksCreate()", function () {
var ret;
if (TIME_MODE === "now") {
// 立即(time/repeat 省略)
ret = tasks.tasksCreate(TASK_NAME, SCRIPT_PATH, ITERATION);
} else if (TIME_MODE === "runOnce") {
if (typeof ONE_SHOT_TIME === "undefined")
throw new Error("ONE_SHOT_TIME 未设置");
// 一次性定时(自行把 ONE_SHOT_TIME 配出来)
ret = tasks.tasksCreate(
TASK_NAME,
SCRIPT_PATH,
ITERATION,
ONE_SHOT_TIME,
);
} else if (TIME_MODE === "weekly") {
if (typeof WEEKLY_TIME === "undefined")
throw new Error("WEEKLY_TIME 未设置");
if (typeof WEEKLY_REPEAT === "undefined")
throw new Error("WEEKLY_REPEAT 未设置");
// 周期(自行把 WEEKLY_TIME/WEEKLY_REPEAT 配出来)
ret = tasks.tasksCreate(
TASK_NAME,
SCRIPT_PATH,
ITERATION,
WEEKLY_TIME,
WEEKLY_REPEAT,
);
} else {
throw new Error("Unknown TIME_MODE: " + TIME_MODE);
}
if (ret !== true && typeof ret !== "number") {
// tasksCreate 文档:成功 true;失败 false(配合 lastError)
throw new Error("tasksCreate FAIL: " + lastError());
}
ctx.log("tasksCreate OK, ret=" + ret);
return ret;
});
if (!s1.ok) {
ctx.log("[CREATE] Task create FAIL: " + TASK_NAME);
ctx.log("[CREATE] err=" + s1.err);
// 失败时:对每台设备补一份上下文+截图
for (var i = 0; i < list.length; i++) {
writeFailContext(ctx, list[i], "tasksCreate", s1.err);
screenshotOne(ctx, list[i], "FAIL__tasksCreate");
}
// 额外:打印最近任务帮助排查
var s1b = stepRun(ctx, "Step1b tasksList(recent 5)", function () {
var recent = tasks.tasksList({
limit: 5,
orderBy: "updatedAt DESC",
});
ctx.log("recent tasks:\n" + JSON.stringify(recent, null, 2));
});
return;
}
// Step2:Get task record (submit/confirm)
var taskRow = null;
var s2 = stepRun(ctx, "Step2 tasksGet(taskName)", function () {
var t = tasks.tasksGet(TASK_NAME);
if (!t) throw new Error("tasksGet returned null (not found)");
taskRow = t;
// tasksGet 可能返回 object 或 [object](不同实现),这里统一一下
if (Array.isArray(taskRow)) taskRow = taskRow[0];
ctx.log("task snapshot:\n" + JSON.stringify(taskRow, null, 2));
return taskRow;
});
if (!s2.ok) return;
// Step3:Poll until terminal
var s3 = stepRun(
ctx,
"Step3 Poll task until terminal or timeout",
function () {
var deadline = nowMs() + WAIT_TIMEOUT_MS;
var lastStatus = null;
while (nowMs() < deadline) {
var t = tasks.tasksGet(TASK_NAME);
if (Array.isArray(t)) t = t[0];
if (!t) throw new Error("tasksGet null during polling");
var st = t.status;
if (st !== lastStatus) {
ctx.log(
"poll: status=" +
statusToText(st) +
" startTime=" +
t.startTime +
" endTime=" +
t.endTime,
);
lastStatus = st;
}
if (isTerminalStatus(st)) {
taskRow = t;
return t;
}
sleep(POLL_INTERVAL_MS);
}
// 超时:可能仍是 SCHEDULED/RUNNING
throw new Error(
"Timeout waiting task finish. lastStatus=" +
statusToText(lastStatus),
);
},
);
// Step4:Print result summary
stepRun(ctx, "Step4 Print result summary", function () {
var t = taskRow;
if (Array.isArray(t)) t = t[0];
ctx.log("===== RESULT =====");
ctx.log("taskName=" + t.taskName);
ctx.log("taskID=" + t.taskID);
ctx.log("status=" + statusToText(t.status));
ctx.log("errorMessage=" + (t.errorMessage || ""));
ctx.log("execDevice=" + (t.execDevice || "-"));
ctx.log("startTime=" + t.startTime);
ctx.log("endTime=" + t.endTime);
ctx.log(
"sigmaTestStatus=" +
(t.sigmaTestStatus || t.sigma_test_status || ""),
);
// 若失败:补一份设备上下文+截图
if (t.status === -3 || t.status === 0) {
ctx.log("Task ended with error, collecting device evidence...");
for (var i = 0; i < list.length; i++) {
writeFailContext(
ctx,
list[i],
"taskResult(" + statusToText(t.status) + ")",
t.errorMessage || "",
);
screenshotOne(ctx, list[i], "FAIL__taskResult");
}
}
});
// Step5:Optional - show recent list
stepRun(ctx, "Step5 tasksList(recent 5)", function () {
var recent = tasks.tasksList({ limit: 5, orderBy: "updatedAt DESC" });
ctx.log("recent tasks:\n" + JSON.stringify(recent, null, 2));
});
ctx.log("DONE.");
}
main();
运行结果
[TASK] Selected devices: 2
[TASK] >> START Step0 Check script path string
[TASK] TASK_NAME=demo_task_20260127_184910
[TASK] SCRIPT_PATH=test.js
[TASK] ITERATION=1
[TASK] TIME_MODE=now
[TASK] << END Step0 Check script path string (cost 155 ms)
[TASK] >> START Step1 tasksCreate()
[TASK] tasksCreate OK, ret=true
[TASK] << END Step1 tasksCreate() (cost 165 ms)
[TASK] >> START Step2 tasksGet(taskName)
[TASK] task snapshot:
{
"id": 7,
"autoConnect": false,
"autoSelect": false,
"startTime": 1769510950415,
"endTime": null,
"errorMessage": "",
"execCount": 1,
"execDevice": "-",
"expiration": -31,
"iterCount": 1,
"reExec": false,
"options": [
{
"device_names": [],
"device_sn": [],
"path": "C:\\Users\xxx\\Documents\\Scripts\\test.js"
}
],
"status": -1,
"taskID": 17695109504181,
"taskName": "demo_task_20260127_184910",
"planTime": 1769510950415,
"weekJson": null,
"createdAt": 1769510950415,
"updatedAt": 1769510950452,
"timezone": "Asia/Shanghai",
"sigmaTestStatus": null
}
[TASK] << END Step2 tasksGet(taskName) (cost 67 ms)
[TASK] >> START Step3 Poll task until terminal or timeout
[TASK] poll: status=RUNNING(-1) startTime=1769510950415 endTime=null
[TASK] poll: status=STOPPED_NORMAL(-2) startTime=1769510950415 endTime=1769510960615
[TASK] << END Step3 Poll task until terminal or timeout (cost 10639 ms)
[TASK] >> START Step4 Print result summary
[TASK] ===== RESULT =====
[TASK] taskName=demo_task_20260127_184910
[TASK] taskID=17695109504181
[TASK] status=STOPPED_NORMAL(-2)
[TASK] errorMessage=
[TASK] execDevice=-
[TASK] startTime=1769510950415
[TASK] endTime=1769510960615
[TASK] sigmaTestStatus=
[TASK] << END Step4 Print result summary (cost 310 ms)
[TASK] >> START Step5 tasksList(recent 5)
[TASK] recent tasks:
[
{
"id": 7,
"autoConnect": false,
"autoSelect": false,
"startTime": 1769510950415,
"endTime": 1769510960615,
"errorMessage": "",
"execCount": 1,
"execDevice": "-",
"expiration": -10200,
"iterCount": 1,
"reExec": false,
"options": [
{
"device_names": [],
"device_sn": [],
"path": "C:\\Users\xxx\\Documents\\Scripts\\test.js"
}
],
"status": -2,
"taskID": 17695109504181,
"taskName": "demo_task_20260127_184910",
"planTime": 1769510950415,
"weekJson": null,
"createdAt": 1769510950415,
"updatedAt": 1769510960619,
"timezone": "Asia/Shanghai",
"sigmaTestStatus": null
},
{
"id": 6,
"autoConnect": false,
"autoSelect": false,
"startTime": 1769520600000,
"endTime": null,
"errorMessage": "",
"execCount": 1,
"execDevice": "-",
"expiration": 12714486,
"iterCount": 1,
"reExec": false,
"options": [
{
"device_names": [
"T110",
"TestDevice03"
],
"device_sn": [
"GDB6R19819001063",
"GDB6R19A18005229"
],
"path": "C:/Users/XXX/Documents/Scripts/TaskCreateSubmitPoll.js"
}
],
"status": -6,
"taskID": 17695078855150,
"taskName": "form_fill_demo_20260127_175805",
"planTime": 1769520600000,
"weekJson": "[\"2\",\"4\"]",
"createdAt": 1769507885514,
"updatedAt": 1769507885514,
"timezone": "Asia/Shanghai",
"sigmaTestStatus": null
},
{
"id": 5,
"autoConnect": false,
"autoSelect": false,
"startTime": 1769520600000,
"endTime": null,
"errorMessage": "",
"execCount": 1,
"execDevice": "-",
"expiration": 13809711,
"iterCount": 1,
"reExec": false,
"options": [
{
"device_names": [
"T110",
"TestDevice03"
],
"device_sn": [
"GDB6R19819001063",
"GDB6R19A18005229"
],
"path": "C:/Users/XXX/Documents/Scripts/TaskCreateSubmitPoll.js"
}
],
"status": -6,
"taskID": 17695067902980,
"taskName": "form_fill_demo_20260127_173950",
"planTime": 1769520600000,
"weekJson": "[\"2\",\"4\"]",
"createdAt": 1769506790289,
"updatedAt": 1769506790289,
"timezone": "Asia/Shanghai",
"sigmaTestStatus": null
},
{
"id": 4,
"autoConnect": false,
"autoSelect": false,
"startTime": 1769520600000,
"endTime": null,
"errorMessage": "",
"execCount": 1,
"execDevice": "-",
"expiration": 14652852,
"iterCount": 1,
"reExec": false,
"options": [
{
"device_names": [
"T110",
"TestDevice03"
],
"device_sn": [
"GDB6R19819001063",
"GDB6R19A18005229"
],
"path": "C:/Users/XXX/Documents/Scripts/TaskCreateSubmitPoll.js"
}
],
"status": -6,
"taskID": 17695059471538,
"taskName": "form_fill_demo_20260127_172547",
"planTime": 1769520600000,
"weekJson": "[\"2\",\"4\"]",
"createdAt": 1769505947148,
"updatedAt": 1769505947148,
"timezone": "Asia/Shanghai",
"sigmaTestStatus": null
},
{
"id": 3,
"autoConnect": false,
"autoSelect": false,
"startTime": 1769504982779,
"endTime": 1769504992938,
"errorMessage": "",
"execCount": 1,
"execDevice": "-",
"expiration": -10158,
"iterCount": 1,
"reExec": false,
"options": [
{
"device_names": [],
"device_sn": [],
"path": "C:\\Users\xxx\\Documents\\Scripts\\test.js"
}
],
"status": -2,
"taskID": 17695049827861,
"taskName": "demo_task_20260127_170942",
"planTime": 1769504982780,
"weekJson": null,
"createdAt": 1769504982779,
"updatedAt": 1769504992940,
"timezone": "Asia/Shanghai",
"sigmaTestStatus": null
}
]
[TASK] << END Step5 tasksList(recent 5) (cost 73 ms)
[TASK] DONE.
0