# 스크립트와 테스트 (/ko/docs/requests/scripts-and-tests)

테스트는 응답이 기대한 대로인지 알려 줍니다. Echolot에서는 두 가지 방법으로 작성할 수 있습니다. 요청의 **테스트** 탭에서 코드 없이 설정하는 검사와, 요청을 보내기 전과
응답을 받은 후에 실행되는 JavaScript 스크립트입니다. 둘 다 보낼 때마다, [실행](/docs/requests/runner)과 명령줄에서도 실행됩니다.

## 테스트 탭의 검사 [#checks-in-the-tests-tab]

<Shot id="requests-tests-tab" alt="List products의 테스트 탭: 초록색 체크가 붙은 검사 네 개 — 상태 같음 200, JSON 값 $.items.length 초과 0, 헤더 Content-Type 포함 json, 응답 시간 미만 1000" />

1. 요청을 엽니다. 예를 들어 Alpenglow 작업 공간의 **Catalog › List products**입니다.
2. **테스트** 탭을 선택합니다.
3. **테스트 추가**를 선택하고 검사할 대상을 고릅니다.
4. 옆의 메뉴에서 비교 방식을 고르고 기대하는 값을 입력합니다.
5. 요청을 보냅니다. 각 검사에 초록색 체크 표시 또는 빨간색 가위표가 나타나며, 실패한 검사는 그 아래에 이유가 표시됩니다.

검사는 요청과 함께 저장되며 그때부터 모든 응답에서 실행됩니다. 행 앞의 체크 상자는 검사를 제거하지 않고 끕니다. 빼기 버튼은 검사를 제거합니다. 테스트 탭의 배지는 검사
개수를 보여 주고, 탭 아래쪽에는 **4개 통과** 또는 **4개 중 1개 실패**처럼 몇 개가 통과했는지 표시됩니다.

기대하는 값은 템플릿이므로 `{{variables}}`를 쓸 수 있습니다. **Catalog › Get product**는 `$.sku`가 `{{productId}}`와 같은지 검사합니다.

### 검사할 수 있는 것 [#what-you-can-check]

| 검사 | 읽는 대상 | 비교 방식 |
| --- | --- | --- |
| **상태** | 상태 코드 | 같음, 같지 않음, 미만, 초과, 다음 중 하나 |
| **헤더** | 이름으로 지정하는 응답 헤더 | 있음, 없음, 같음, 같지 않음, 포함, 포함 안 함, 정규 표현식 일치 |
| **JSON 값** | JSON 본문에서 JSONPath 위치의 값 | 있음, 없음, 같음, 같지 않음, 포함, 포함 안 함, 미만, 이하, 초과, 이상, 정규 표현식 일치, 유형 일치, 다음 중 하나 |
| **본문** | 텍스트로 읽은 본문 전체 | 포함, 포함 안 함, 같음, 정규 표현식 일치 |
| **응답 시간(ms)** | 밀리초 단위의 교환 총 소요 시간 | 미만, 이하, 초과, 이상 |
| **크기(바이트)** | 바이트 단위의 본문 크기 | 미만, 이하, 초과, 이상 |
| **JSON Schema** | 붙여넣은 JSON Schema에 대한 본문 | 일치 |
| **GraphQL 오류** | GraphQL 응답의 `errors` 배열 | 같음, 미만, 초과(개수), 포함, 포함 안 함(메시지) |
| **MCP 오류** | MCP 호출의 실패 여부: `true` 또는 `false` | 같음 |
| **도구 출력 스키마** | MCP 도구 결과의 `structuredContent`를 도구 자체의 `outputSchema`에 대해 | 일치 |
| **OpenAPI 명세** | 응답 상태에 대해 연결된 OpenAPI 명세의 스키마에 대한 본문 | 일치 |
| **gRPC 상태** | 이름 또는 코드로 지정하는 gRPC 호출의 상태 | 같음, 같지 않음, 다음 중 하나 |

새 검사는 적절한 값으로 시작합니다. <strong>상태</strong>는 `200`과 같음, <strong>응답 시간(ms)</strong>은 `1000` 미만, <strong>GraphQL 오류</strong>는 `0`과 같음, <strong>MCP 오류</strong>는 `false`와 같음,
**gRPC 상태**는 `OK`와 같음, **JSON Schema**는 `{"type": "object"}`입니다.

### 값을 비교하는 방식 [#how-values-compare]

- **같음**은 숫자를 숫자로 비교하므로 `200`은 `200.0`과 같으며, 값 앞뒤의 공백은 무시합니다.
- **다음 중 하나**는 쉼표로 구분한 목록을 받습니다: `200, 201, 204`.
- **정규 표현식 일치**는 정규 표현식이 값의 어느 부분에서든 일치하면 통과합니다.
- **유형 일치**는 `object`, `array`, `string`, `number`, `integer`, `boolean`, `null` 중 하나를 받습니다.
- 숫자 비교는 양쪽이 숫자여야 하며, 아니면 그렇다는 메시지와 함께 실패합니다.

### JSON 값 [#json-values]

경로는 `$`로 시작하는 키와 인덱스의 JSONPath입니다. `$.items[0].sku`, `$.data.search.totalCount`처럼 씁니다. 음수 인덱스는 끝에서부터 셉니다: `$.items[-1]`.
`.length`를 붙이면 배열의 항목 수나 객체의 키 수를 셉니다. `$.items.length`가 `0` 초과인 식입니다. Echolot은 값에 이르는 길목의 본문 일부만 읽으므로 JSON 검사는 어떤
크기의 본문에서도 동작합니다.

**본문**의 **포함** 또는 **포함 안 함**도 어떤 크기의 본문에서나 동작합니다. 그 밖의 본문 비교와 **JSON Schema**, **GraphQL 오류**는 본문 전체를 읽으며 50 MB에서 멈춥니다.

### 다른 종류의 요청에 대한 검사 [#checks-for-other-kinds-of-request]

- **GraphQL**: 서버는 오류를 상태 200으로 응답하므로 **GraphQL 오류**가 `0`과 같음 검사를 추가해 오류를 잡으십시오. 특정 메시지가 돌아오는지 확인하려면 **포함**을
  사용하십시오.
- **MCP 호출**: **MCP 오류**가 `false`와 같음은 호출이 성공했을 때 통과합니다. 오류로 표시된 결과와 JSON-RPC 오류에서는 실패하며, 메시지에 서버가 한 말이 표시됩니다.
  **도구 출력 스키마**는 도구 결과를 도구가 선언한 스키마와 대조하며, 도구가 선언하지 않았으면 실패합니다. [MCP 요청](/docs/requests/mcp-requests)을 참고하십시오.
- **gRPC**: **gRPC 상태**는 `OK`, `NOT_FOUND` 같은 이름 또는 0에서 16까지의 코드를 받습니다. `5`, `not_found`, `NOT_FOUND`는 같은 상태입니다. 실패한 검사에는
  상태 메시지가 표시됩니다. [gRPC](/docs/requests/grpc)를 참고하십시오.
- **OpenAPI 명세**: 요청의 폴더(또는 그 위의 폴더)가 명세에 연결되어 있어야 하고, 요청이 명세의 작업 중 하나를 따라야 합니다. 그러면 검사는 돌아온 상태에 대해 명세가
  문서화한 스키마로 본문을 검증합니다. 명세가 JSON 본문 없이 문서화한 상태는 통과하고, 문서화되지 않은 상태는 실패합니다. [명세](/docs/specs)를 참고하십시오.

### 응답에서 검사 추가 [#add-checks-from-a-response]

모든 검사를 직접 입력할 필요는 없습니다.

- 테스트 탭의 <strong>응답에서 생성…</strong>은 최신 응답에서 검사를 제안합니다. 상태, 콘텐츠 유형, JSON Schema로 표현한 본문의 형태처럼 정상적인 응답이면 항상 성립하는 검사는 이미
  체크되어 있습니다. 호출마다 달라지는 값과 시간은 제안되지만 체크되어 있지 않습니다. **추론된 스키마**를 선택하면 제안된 스키마를 읽을 수 있습니다. **테스트 1개 추가**
  (또는 **테스트 N개 추가**)를 선택하면 체크된 항목이 보관됩니다. 먼저 요청을 보내십시오. 이 버튼에는 응답이 필요합니다.
- 응답의 **본문**에서 JSON 트리 보기로 값을 오른쪽 클릭하고 **검사 추가**를 선택하면 해당 경로가 그 값과 같다는 **JSON 값** 검사가 추가됩니다.
- 응답의 **헤더**에서 헤더를 오른쪽 클릭하고 **검사 추가**를 선택하면 해당 헤더가 그 값과 같다는 **헤더** 검사가 추가됩니다.

<Shot id="requests-tests-generate" alt="List products의 응답에서 테스트 생성 시트: 상태, 콘텐츠 유형, 추론된 스키마가 체크되어 있고 값 검사가 제안되었지만 체크되지 않음" />

### 결과 [#results]

응답 패널의 **테스트** 탭에는 각 검사가 결과와 찾은 값(`실제: 200`)과 함께 나열되고, 이어서 스크립트의 각 테스트가 나열됩니다. 사이드바의 **테스트** 페이지(**보기 › 테스트**,
<kbd>⌥</kbd><kbd>⌘</kbd><kbd>T</kbd>)에는 검사가 있는 모든 요청이 최신 응답에서의 상태와 함께 나열되며, 하나를 클릭하면 요청이 열립니다.

## 스크립트 [#scripts]

스크립트는 Postman의 `pm.*` API를 쓰는 JavaScript이므로 대부분의 Postman 스크립트가 그대로 실행됩니다. 요청에는 두 가지가 있을 수 있습니다.

- **사전 요청** 스크립트는 요청을 보내기 전에 실행됩니다. 요청을 바꾸거나, 변수를 설정하거나, 요청을 건너뛸 수 있습니다.
- **테스트** 스크립트는 응답이 도착한 뒤에 실행됩니다. `pm.test`로 응답을 검사하고 이후 요청에서 쓸 값을 저장할 수 있습니다.

<Shot id="requests-scripts-tab" alt="테스트 탭의 List products 스크립트 탭: 상태와 항목 수를 검사하는 pm.test와 열린 스니펫 메뉴" />

1. 요청을 열고 **스크립트** 탭을 선택합니다.
2. 맨 위에서 <strong>사전 요청</strong> 또는 <strong>테스트</strong>를 선택합니다. <strong>테스트 •</strong>처럼 이름 뒤에 점이 있으면 코드가 있는 스크립트입니다.
3. 스크립트를 작성합니다. 편집기는 JavaScript에 색을 입히고 입력하는 동안 `pm.` 경로를 자동 완성합니다. **스니펫**은 자주 쓰는 경우를 위한 완성된 스크립트를 추가합니다.
4. 요청을 보냅니다.

예를 들어 **Catalog › List products**의 테스트 스크립트는 다음과 같습니다.

```js
pm.test("Status code is 200", () => {
  pm.response.to.have.status(200);
});

pm.test("Returns tents", () => {
  const body = pm.response.json();
  pm.expect(body.items.length).to.be.above(0);
});
```

다음은 실행되는 모든 요청에 헤더를 추가하는 사전 요청 스크립트입니다.

```js
pm.request.headers.add({ key: "X-Request-Id", value: pm.variables.replaceIn("{{$guid}}") });
```

각 `pm.test`는 응답의 **테스트** 탭에서 테스트 탭의 검사 뒤에 **스크립트** 아래로 나타납니다. 예외가 발생한 스크립트는 메시지와 함께 **스크립트 오류**로 표시됩니다.
스크립트가 `console.log`, `console.info`, `console.warn`, `console.error`로 쓴 내용은 응답의 **콘솔** 탭에 `pre` 또는 `test`로 표시되어 나타납니다. 이 탭은
스크립트가 실행된 뒤에 생깁니다.

### 스니펫 [#snippets]

| 스니펫 | 용도 |
| --- | --- |
| **상태 코드가 200**, **응답 시간이 500 ms 미만**, **JSON 값이 있음**, **헤더가 있음**, **본문에 텍스트 포함** | 테스트 |
| **이후 요청에서 쓸 값 저장** | 테스트: `pm.environment.set("token", pm.response.json().token)` |
| **다음에 다른 요청 실행** | 테스트: `pm.execution.setNextRequest("Request name")` |
| **변수 설정**, **헤더 추가**, **HMAC-SHA256으로 요청 서명**, **먼저 토큰 받기**, **이 요청 건너뛰기** | 사전 요청 |

### 폴더와 작업 공간의 스크립트 [#scripts-on-folders-and-the-workspace]

폴더와 작업 공간에도 그 안의 모든 요청에 적용되는 스크립트를 둘 수 있습니다. 사이드바의 폴더 컨텍스트 메뉴(<strong>폴더 설정…</strong>) 또는 <strong>작업 공간 설정…</strong>의 <strong>스크립트</strong> 탭에서
엽니다.

각 요청에 대해 Echolot은 작업 공간의 스크립트를 먼저, 이어서 바깥쪽 폴더부터 안쪽 순으로 각 폴더의 스크립트를, 마지막으로 요청 자체의 스크립트를 실행합니다. 사전 요청 스크립트와
테스트 스크립트 모두 같은 순서입니다. 저장된 요청만 스크립트를 실행합니다.

MCP 호출에는 스크립트 탭이 없으며 스크립트를 실행하지 않습니다. 다른 모든 종류의 요청에는 있습니다.

### `pm` API 한눈에 보기 [#the-pm-api-at-a-glance]

전체 목록은 [스크립트 API 레퍼런스](/docs/reference/scripting-api)에 있습니다.

| 객체 | 동작 |
| --- | --- |
| `pm.test(name, fn)`, `pm.expect(value)` | 이름이 있는 테스트와 Chai 스타일 단언: `pm.expect(x).to.equal(1)` |
| `pm.response` | 테스트 스크립트의 응답: `code`, `status`, `headers`, `responseTime`, `responseSize`, `json()`, `text()`, 그리고 `pm.response.to.have.status(200)`, `.header()`, `.body()`, `.jsonBody()`, `pm.response.to.be.ok`, `.success`, `.json`, `.clientError`, `.serverError`, `.notFound` |
| `pm.request` | 요청: `url`, `method`, `headers`, `body`. 사전 요청 스크립트는 헤더와 쿼리 매개변수를 추가, 교체, 제거할 수 있음 |
| `pm.variables` | 가장 가까운 범위부터 모든 범위: `get`, `set`, `has`, `unset`, `replaceIn`, `toObject` |
| `pm.environment`, `pm.collectionVariables`, `pm.globals` | 활성 환경, 작업 공간의 변수, 전역 변수 |
| `pm.iterationData` | 실행의 데이터 행: `get`, `has`, `toObject` |
| `pm.info` | `requestName`, `requestId`, `iteration`(0부터), `iterationCount`, `eventName` |
| `pm.execution` | `setNextRequest(name)`(`null`이면 실행 종료)과 `skipRequest()` |
| `pm.cookies` | 응답의 쿠키 |
| `pm.sendRequest` | 다른 요청을 보냄 |
| `console` | `log`, `info`, `warn`, `error` |
| `CryptoJS` | `MD5`, `SHA1`, `SHA256`, `SHA512`, `HmacSHA1`, `HmacSHA256`, `HmacSHA512`, 그리고 `CryptoJS.enc`(`Hex`, `Base64`, `Utf8`, `Latin1`) |

`require`로 `lodash`, `ajv`, `tv4`, `crypto-js`, `uuid`, `atob`, `btoa`를 가져옵니다. `_`(lodash), `tv4`, `btoa`, `atob`, `setTimeout`은 가져오지 않고도
사용할 수 있습니다. Postman의 예전 전역 객체(`postman.setEnvironmentVariable`, `tests[...]`, `environment`, `globals`, `data`, `iteration`)도 여전히
동작합니다. 다른 모듈은 "The module … is not available in Echolot scripts."라는 오류와 함께 실패합니다.

### 스크립트가 설정하는 변수 [#variables-that-scripts-set]

`pm.environment.set`, `pm.collectionVariables.set`, `pm.globals.set`이 쓰는 것은 현재 값입니다. 윈도우가 열려 있는 동안만 유지되고, 요청이 해석될 때 해당 범위의 저장된
값을 덮어쓰며, 작업 공간 파일에는 절대 기록되지 않습니다. 따라서 스크립트가 저장한 토큰은 Git에 남지 않고 이후 요청에 전달됩니다. 응답의 값을 작업 공간에 보관하려면 대신
[캡처](/docs/requests/captures)를 사용하십시오.

`pm.variables.set`은 현재 실행에서만 쓰는 값을 설정합니다. 실행은 이런 식으로 스크립트가 설정한 값 없이 시작합니다.

### 다른 요청 보내기 [#sending-another-request]

`pm.sendRequest`는 토큰을 먼저 가져오는 경우처럼 스크립트에서 요청을 보냅니다. URL 또는 `url`, `method`, `header`, `body`가 있는 객체를 받으며, 콜백이나 반환되는
프라미스를 사용합니다.

```js
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: "alpenglow" }) },
}, (error, response) => {
  if (!error) pm.environment.set("token", response.json().access_token);
});
```

요청은 Echolot이 보내는 다른 요청과 같은 프록시와 인증서로 나가지만, 작업 공간이나 폴더의 인증은 적용되지 않습니다. 스크립트는 응답을 최대 30초 기다립니다.

### 요청 건너뛰기와 다음 요청 선택 [#skipping-requests-and-choosing-the-next-one]

사전 요청 스크립트의 `pm.execution.skipRequest()`는 요청이 전송되지 않게 하며, 응답 패널과 실행에 건너뛰었다고 표시됩니다. 실행 중의 `pm.execution.setNextRequest("Get order")`는
다음에 그 요청으로 이동하고, `setNextRequest(null)`은 실행을 끝냅니다. [실행](/docs/requests/runner)을 참고하십시오.

## Echolot 외부에서 온 스크립트 [#scripts-from-outside-echolot]

스크립트는 코드이므로 Echolot은 이 Mac에서 신뢰한 것만 실행합니다. Echolot에서 작성한 스크립트는 저장하는 순간 신뢰됩니다. 가져오기, Git, 다른 편집기에서의 편집처럼 다른
경로로 들어온 스크립트는 대기합니다.

- 스크립트 탭에 **Echolot 외부에서 온 스크립트입니다**와 **스크립트 신뢰**가 표시됩니다.
- 요청을 보내면 <strong>스크립트 검토…</strong>와 함께 중단됩니다. 이는 <strong>이 스크립트를 실행하겠습니까?</strong>를 열며, 아직 실행되지 않은 각 스크립트와 그 출처(요청, 폴더, 작업 공간)가
  표시됩니다. 내용을 읽은 다음 **신뢰하고 보내기** 또는 **취소**를 선택합니다.

신뢰는 이 Mac에서 작업 공간별로, 정확히 그 코드에 대해 유지됩니다. Echolot 밖에서 스크립트가 바뀌면 다시 묻습니다. 신뢰는 작업 공간과 함께 이동하지 않으므로 공유된
작업 공간이 스스로 자신의 스크립트를 신뢰할 수는 없습니다.

명령줄 도구는 지정한 작업 공간의 모든 스크립트를 실행합니다. `echolot mcp serve`는 시작 시점에 작업 공간이 가지고 있던 스크립트만 실행합니다.

## 샌드박스와 제한 [#the-sandbox-and-its-limits]

스크립트는 Echolot 안의 JavaScript 샌드박스에서 실행됩니다. 파일 시스템도, 자체 네트워크도, Mac에 대한 접근도 없습니다. 밖으로 나가는 길은 `pm.sendRequest`, `console`,
변수뿐입니다. 보낼 때마다 새 샌드박스로 시작합니다.

| 제한 | 값 |
| --- | --- |
| 한 이벤트(사전 요청 또는 테스트)의 모든 스크립트에 대한 JavaScript 실행 시간 | 5초 |
| 메모리 | 128 MB |
| `pm.sendRequest` 응답 대기 | 30초 |
| 스크립트가 볼 수 있는 응답 본문 | 처음 32 MB |

너무 오래 실행되는 스크립트는 "the script took longer than 5 s"로, 메모리를 너무 많이 쓰는 스크립트는 "the script used more memory than allowed"로 실패합니다.
스크립트는 비밀 값을 포함한 작업 공간의 변수를 읽어 `pm.sendRequest`로 보낼 수 있으며, 외부에서 온 스크립트가 신뢰를 기다리는 이유가 이것입니다.

## 문제 해결 [#troubleshooting]

- **응답에서 생성…이 회색으로 표시됨**: 먼저 요청을 보내십시오. HTTP와 GraphQL 요청에서 동작합니다.
- **"no OpenAPI spec is linked to this request's folder"**: 폴더를 명세에 연결하거나 **OpenAPI 명세** 검사를 제거하십시오.
- **"“…” is not a JSONPath this version understands"**: `$.items[0].sku`처럼 키와 인덱스만 사용하십시오.
- **스크립트가 실행되지 않음**: 요청이 저장되어 있는지, MCP 호출이 아닌지, 스크립트가 신뢰를 기다리고 있지 않은지 확인하십시오.
