脚本 API
请求前脚本和测试脚本能用到的一切:pm 对象、expect、JSON Schema 辅助函数和库,以及哪些功能不可用。
脚本是在发送请求之前(请求前)或响应到达之后(测试)运行的 JavaScript。它们使用 Postman 的 pm API,因此 Postman 集合中的脚本可以原样运行。本页列出了全部内容。关于如何在 App 中编写脚本并查看结果,参见脚本和测试。
脚本在哪里运行
- 请求的脚本在它的脚本标签页中,存储为请求旁边的
<slug>.pre.js和<slug>.test.js。文件夹和工作区也有脚本(_folder.pre.js、_folder.test.js);参见工作区文件。 - 对每个请求,先运行工作区的脚本,再由外向内运行各文件夹的脚本,最后是请求自己的脚本。同一事件的所有脚本共享一个沙盒。
- MCP 调用没有脚本。
- 来自 Echolot 之外(导入、Git、其他编辑器)的脚本,只有在你信任之后才会运行:用查看脚本…阅读它们之后,选择信任脚本。
- 命令行工具也会运行脚本,见
echolot run和echolot send。
沙盒
脚本在 Echolot 内部的沙盒 JavaScript 引擎(QuickJS)中运行,没有文件系统,没有自己的网络,也没有 Node.js 模块。唯一的出口是 pm.sendRequest,它通过 Echolot 发送。
| 限制 | 数值 |
|---|---|
| 一个事件的所有脚本的 JavaScript 运行时间 | 5 秒 |
| 内存 | 128 MB |
等待所有 pm.sendRequest 的应答 | 30 秒 |
| 脚本能看到的响应正文 | 前 32 MB |
抛出错误或超出限制的脚本会被报告为脚本错误,计为一次失败的测试。
pm.test
pm.test("Status is 200", () => {
pm.response.to.have.status(200);
});
pm.test("Has products", () => {
const body = pm.response.json();
pm.expect(body.items).to.be.an("array").that.is.not.empty;
});| 形式 | 含义 |
|---|---|
pm.test(name, fn) | 一个具名测试。当 fn 返回而没有抛出错误时通过。 |
pm.test(name, async () => { … }) | 返回 promise 的测试,在 promise 兑现时通过。 |
pm.test(name, done => { … }) | 带参数的测试,调用 done() 时通过,调用 done(error) 或从不调用时失败。 |
pm.test.skip(name, fn) | 跳过的测试,会列出但不计数。 |
tests[name] = condition | 旧形式:条件为真时通过。 |
请求前脚本中的测试同样计数。
pm.expect
pm.expect(value)(或 expect(value))是 Chai 风格的断言。失败信息与 Chai 的写法相同:expected 401 to equal 200。
链接词,读起来通顺但不起作用:to、be、been、is、that、which、and、has、have、with、at、of、same、but、does、still、also。
标志: not(取反)、deep(按值比较)、nested(property 中使用点分路径)、own、any、all、ordered。
| 断言 | 通过的条件 |
|---|---|
.equal(x)、.equals、.eq | 值为 x(===;配合 deep 则按值比较)。 |
.eql(x)、.eqls | 值与 x 深度相等。 |
.above(n)、.gt、.greaterThan | 值大于 n。 |
.least(n)、.gte、.greaterThanOrEqual | 值至少为 n。 |
.below(n)、.lt、.lessThan | 值小于 n。 |
.most(n)、.lte、.lessThanOrEqual | 值至多为 n。 |
.within(a, b) | 值在 a 和 b 之间,包含两端。 |
.closeTo(x, delta)、.approximately | 值与 x 的差在 delta 之内。 |
.a(type)、.an(type) | 值的类型为 type:string、number、boolean、object、array、null、undefined、regexp、date、error、function。 |
.instanceof(C)、.instanceOf | 值是 C 的实例。 |
.include(x)、.includes、.contain、.contains | 字符串包含 x,数组含有 x,对象含有 x 的键和值。 |
.ok | 值为真值。 |
.true、.false、.null、.undefined、.NaN | 值恰好是这个。 |
.exist、.exists | 值既不是 null 也不是 undefined。 |
.empty | 字符串或数组没有元素,对象没有键,Map 或 Set 没有条目。 |
.finite | 值是有限的数字。 |
.property(name)、.property(name, value) | 对象有该属性,若给出则值也相同。之后继续针对该属性的值。也可用 .ownProperty、.haveOwnProperty。 |
.lengthOf(n)、.length(n) | 值的 length(或 Map、Set 的大小)为 n。 |
.match(regex)、.matches | 字符串匹配该正则表达式。 |
.string(s) | 字符串包含 s。 |
.keys(…)、.key | 对象恰好有这些键(配合 any 时为其中之一;在 include 之后则至少有这些)。 |
.members(array) | 数组有相同的成员(配合 include 时至少有这些;配合 ordered 时顺序也相同)。 |
.oneOf(array) | 值是数组中的某一项。 |
.satisfy(fn)、.satisfies | fn(value) 返回 true。 |
.throw()、.throws、.Throw | 函数抛出错误(若给出,则消息包含某个字符串或匹配某个正则,或属于某个类)。 |
.jsonSchema(schema) | 值符合该 JSON Schema。参见 JSON Schema。 |
对响应而言,expect 还接受 Postman 的响应断言:pm.expect(pm.response).to.have.status(200)、.header(name)、.jsonBody(…)、.body(…)、.responseTime(…),以及 pm.expect(pm.response).to.be.ok、.success、.json 和下面列出的其他断言。
pm.response
在测试脚本中,即响应。
| 成员 | 含义 |
|---|---|
code | 状态码:200。 |
status | 原因短语:"OK"。也可用 reason()。 |
headers | 标头,是一个列表。pm.response.headers.get("Content-Type")。 |
responseTime | 以毫秒计的时间。 |
responseSize | 正文的大小,以字节计。也可用 size(),它返回 { body, header, total }。 |
text() | 作为文本的正文。 |
json(reviver) | 解析为 JSON 的正文;不是 JSON 时抛出错误。 |
响应断言: pm.response.to.have.… 和 pm.response.to.not.have.…:
| 断言 | 通过的条件 |
|---|---|
status(200)、status("OK") | 状态码是 200,或原因是 OK。也可用 statusCode(n)、statusReason(text)。 |
header(name)、header(name, value) | 有该标头,若给出则值也相同。 |
body()、body(text)、body(regex)、body(object) | 正文不为空、等于该文本、匹配该正则,或等于该 JSON。 |
jsonBody()、jsonBody(path)、jsonBody(path, value)、jsonBody(object) | 正文是 JSON、有该点分路径、值相同,或等于该对象。 |
responseTime(ms) | 响应用时不超过 ms。 |
pm.response.to.be.…:
| 属性 | 在状态码为以下值时通过 |
|---|---|
info | 100 到 199 |
success | 200 到 299 |
ok | 200 |
accepted | 202 |
redirection | 300 到 399 |
clientError | 400 到 499 |
serverError | 500 或更大 |
error | 400 或更大 |
badRequest、unauthorized(或 unauthorised)、forbidden、notFound、rateLimited | 400、401、403、404、429 |
json、html、xml、text | (Content-Type 包含该词) |
withBody | (正文不为空) |
pm.request
请求。在请求前脚本中,对它所做的更改就是实际发送的内容。
| 成员 | 含义 |
|---|---|
url | URL,是一个对象;见下文。String(pm.request.url) 是文本。 |
method | 方法;可以更改。 |
headers | 标头,是一个列表。 |
body | 正文:{ mode: "raw", raw: "…" },或 undefined。 |
name、id | 请求的名称,以及它在工作区中的路径。 |
addHeader(item)、removeHeader(name)、upsertHeader(item) | 更改标头。项是 { key, value } 或 "Name: value"。 |
addQueryParams(params)、removeQueryParams(names) | 更改查询:"a=1&b=2"、{ key, value } 或它们的数组。 |
to.have.header(name, value) | 针对请求标头的断言。 |
pm.request.headers.upsert({ key: "X-Request-Id", value: pm.variables.replaceIn("{{$guid}}") });
pm.request.url.addQueryParams("per_page=50");url 对象有 protocol、host(标签数组)、port、path(路径段数组)、query(列表)、hash,以及 getHost()、getPath()、getQueryString()、getPathWithQuery()、getRemote()、update(text)、addQueryParams(…)、removeQueryParams(…)、toString()。你没有更改的 URL 会保持其原文,包括 {{variables}};Echolot 在脚本之后才解析它们。
变量
| 作用域 | 含义 |
|---|---|
pm.environment | 当前环境的变量。pm.environment.name 是它的名称。 |
pm.collectionVariables | 工作区的变量。 |
pm.globals | 全局变量。 |
pm.iterationData | 数据驱动运行的当前行。只读。 |
pm.variables | 同时涵盖所有作用域,由近及远。set 和 unset 只更改本地值。 |
每个作用域都有 get(name)、has(name)、set(name, value)、unset(name)、clear()、toObject() 和 replaceIn(text)。set 会把对象转换为 JSON 文本。
pm.variables.get 按以下顺序查找:本地值、数据行、文件夹和请求变量、环境、工作区、全局变量。
// Pre-request: sign the body
const signature = CryptoJS.HmacSHA256(pm.request.body.raw, pm.environment.get("apiSecret")).toString();
pm.request.headers.upsert({ key: "X-Signature", value: signature });
// Test: keep the new order's ID for the next requests
pm.collectionVariables.set("orderId", pm.response.json().id);set 会保留什么。脚本设置的值是 Postman 所说的“当前值”:它们在 App 中持续到窗口关闭,在命令行中持续到命令结束,并且在请求解析时优先于其作用域中已存储的值。它们绝不会写入工作区文件。要保存响应中的值,请使用响应捕获。pm.variables.set 设置的本地值在运行开始时会被丢弃。
replaceIn(text) 从上述作用域填入 {{variables}}。动态值中,它认识 {{$guid}}、{{$randomUUID}}、{{$timestamp}}、{{$isoTimestamp}} 和 {{$randomInt}};其他所有 {{$…}} 都保持原样,由 Echolot 在发送请求时解析。
pm.info
| 成员 | 含义 |
|---|---|
eventName | "prerequest" 或 "test"。 |
iteration | 运行的迭代序号,从 0 起。 |
iterationCount | 运行共有多少次迭代。 |
requestName | 请求的名称。 |
requestId | 请求在工作区中的路径。 |
pm.sendRequest
在脚本中通过 Echolot 发送另一个请求:代理、证书和 Cookie 与任何请求一样生效。
pm.sendRequest("https://demo.echolot.dev/v1/categories", (error, response) => {
if (error) { console.error(error); return; }
pm.collectionVariables.set("firstCategory", response.json().items[0].id);
});
// or with a promise
pm.sendRequest({
url: pm.variables.replaceIn("{{baseURL}}/auth/token"),
method: "POST",
header: { "Content-Type": "application/json" },
body: { mode: "raw", raw: JSON.stringify({ email: "heidi@alpenglow.ch", password: pm.environment.get("password") }) }
}).then(response => {
pm.environment.set("token", response.json().access_token);
});- 第一个参数是 URL,或带有
url、method(默认GET)、header({ key, value }数组、对象或列表)和body的对象。 body是字符串、{ mode: "raw", raw }、{ mode: "urlencoded", urlencoded: [{ key, value }] }或{ mode: "graphql", graphql: { query, variables } }。后两者在你没有设置时会自动设置Content-Type。- URL 中的
{{variables}}会按请求的环境填入。 - 回调接收
(error, response);response与pm.response类似。没有回调时返回 promise。 - 该请求没有自己的认证(工作区的认证不适用),也不运行脚本。
- 智能体的
pm.sendRequest与它的其他发送一样,要经过智能体的批准。
控制运行
| 调用 | 作用 |
|---|---|
pm.execution.setNextRequest(name) | 在运行中,接下来继续该请求。null 结束运行。也可用 pm.setNextRequest、postman.setNextRequest。 |
pm.execution.skipRequest() | 在请求前脚本中:不发送这个请求。 |
pm.cookies
此次交换的 Cookie:请求发送的和响应设置的。是一个列表,带有 pm.cookies.get(name)、has(name)、toObject(),以及返回 { name, key, value } 的 one(name)。
列表
标头、查询参数和 Cookie 都是 Postman 的属性列表:
| 方法 | 作用 |
|---|---|
get(key) | 值;键不区分大小写。 |
one(key) | 整个项,{ key, value, disabled }。 |
has(key)、has(key, value) | 是否存在(且值相同)。 |
add(item)、append(item)、upsert(item) | 添加项,或添加或替换项。 |
remove(key)、remove(fn)、clear() | 移除项。 |
toObject()、all()、count()、idx(i) | 以对象形式、以数组形式返回项,项的数量,以及指定索引处的项。 |
each(fn)、map(fn)、filter(fn)、find(fn) | 遍历各项。 |
toString() | Name: value 的各行。 |
console
console.log、info、warn、error、debug 和 trace 会写入请求的控制台,在命令行中则写在 ── console ── 之下。对象以 JSON 形式写出。
计时器
setTimeout、setInterval 和 setImmediate 会在脚本结束后,按延迟的先后顺序运行其函数,并不真正等待。setInterval 只运行一次。clearTimeout 等函数用于取消。
JSON Schema
有三种方式,都基于 Echolot 自己的 JSON Schema 验证器:
const schema = {
type: "object",
required: ["sku", "price"],
properties: { sku: { type: "string" }, price: { type: "object" } }
};
// Chai
pm.expect(pm.response.json()).to.have.jsonSchema(schema);
// ajv
const Ajv = require("ajv");
const validate = new Ajv().compile(schema);
pm.test("Matches the schema", () => pm.expect(validate(pm.response.json()), JSON.stringify(validate.errors)).to.be.true);
// tv4
pm.test("Matches the schema", () => pm.expect(tv4.validate(pm.response.json(), schema)).to.be.true);| 辅助函数 | 包含 |
|---|---|
require("ajv") | 一个类:new Ajv(options)、validate(schema, data)、compile(schema)(带 .errors 的函数)、addSchema(schema, key)、getSchema(key)、errorsText(errors) 和 errors。addFormat 和 addKeyword 可以调用,但不起作用。 |
tv4(也可用 require("tv4")) | validate(data, schema)(带 tv4.error)、validateResult(data, schema)、validateMultiple(data, schema)。 |
.jsonSchema(schema) | 上面的 Chai 断言。 |
JSON Schema 检查也可以不用脚本:使用测试标签页中的 JSON Schema 检查。
库
| 名称 | 包含 |
|---|---|
CryptoJS(也可用 require("crypto-js")) | MD5、SHA1、SHA256、SHA384、SHA512、HmacMD5、HmacSHA1、HmacSHA256、HmacSHA384、HmacSHA512;enc.Hex、enc.Utf8、enc.Base64、enc.Latin1;lib.WordArray.create(bytes) 和 lib.WordArray.random(n)。结果带有 toString(encoder)。 |
_(也可用 require("lodash")) | 集合常用的 lodash 函数:each/forEach、map、filter、reject、find、findIndex、some、every、reduce、includes/contains、get、has、set、keys、values、size,is… 系列测试(isArray、isString、isEmpty、isEqual 等),startsWith、endsWith、trim、toLower、toUpper、capitalize、parseInt、toNumber、toString、first/head、last、tail、initial、uniq、flatten、compact、concat、range、times、sortBy、groupBy、keyBy、countBy、pick、omit、assign/extend、clone、cloneDeep、merge、random、sample、sum、max、min、noop、identity、now、uniqueId。 |
require("uuid") | v4(),一个随机 UUID。 |
btoa、atob(也可用 require("btoa")、require("atob")) | Latin-1 文本的 Base64 编码,以及解码。 |
旧版 Postman 全局变量
旧集合中的脚本会用到这些,它们都可以使用:
| 全局变量 | 含义 |
|---|---|
tests["name"] = condition | 一个测试。 |
responseBody、responseCode(code、name、detail)、responseHeaders、responseTime | 响应。 |
request(url、method、headers、data、name、description) | 请求。 |
environment、globals、data、iteration | 作为对象的变量、数据行、迭代。 |
postman.setEnvironmentVariable、getEnvironmentVariable、clearEnvironmentVariable、clearEnvironmentVariables | 环境。 |
postman.setGlobalVariable、getGlobalVariable、clearGlobalVariable、clearGlobalVariables | 全局变量。 |
postman.getResponseHeader(name)、postman.getResponseCookie(name)、postman.setNextRequest(name) | 响应和运行。 |
"text".has("x") | 字符串是否包含另一个字符串。 |
不可用的功能
- 其他模块:对上面未列出的任何内容使用
require(cheerio、xml2js、moment、Node 自带的模块)都会抛出 “The module … is not available in Echolot scripts.”。 - 真正的等待:计时器不会延迟运行,也没有
fetch或XMLHttpRequest。请使用pm.sendRequest。 - 文件和进程:脚本不能读写文件,也不能启动程序。
pm.visualizer.set可以调用,因此使用它的脚本能运行,但 Echolot 不显示可视化内容。xml2Json、pm.require和 Postman 的包库,以及pm.vault。- 文件中的机密:脚本可以像读取其他变量一样读取机密变量,但它们
set的内容绝不会进入工作区文件。