> ## Documentation Index
> Fetch the complete documentation index at: https://docs.hoppscotch.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Scripts

> Write pre-request scripts and post-request tests in Hoppscotch using JavaScript to add dynamic behavior, set variables, and validate responses.

<Tabs>
  <Tab title="hopp [Experimental]">
    <Danger>
      It is not recommended to migrate or reformat your existing scripts to the new scripting APIs at this time. Upcoming updates are expected to introduce breaking changes as we continue to refine and improve the scripting experience.

      The current rollout is intentionally gradual, allowing us to gather user feedback and iterate based on real-world usage.

      All further updates to scripting will be scoped to the experimental scripting sandbox, which is the default, and the preference can be updated from `Settings → Experiments`.

      [Your feedback will be invaluable as we shape the next generation of Hoppscotch scripting.](https://github.com/hoppscotch/hoppscotch/discussions/5221)
    </Danger>

    <Note>
      This new experimental implementation provides a robust foundation for API scripting with enhanced capabilities for environment management, request manipulation, response processing, cookie handling, and comprehensive testing. The new system maintains backwards compatibility while introducing powerful new features for modern API testing workflows.
    </Note>

    ## `hopp.env` Namespace

    Environment variable management with scope-specific operations and enhanced functionality.

    ### `hopp.env.get(key: string)`

    Retrieves the value of the selected environment's variable. Accepts an environment variable as an argument.

    ```javascript theme={null}
    hopp.env.get("variable");
    hopp.env.get("baseURL");
    ```

    ### `hopp.env.getRaw(key: string)`

    Retrieves the raw value of the selected environment's variable without variable resolution.

    ```javascript theme={null}
    hopp.env.getRaw("variable");
    ```

    ### `hopp.env.set(key: string, value: string)`

    Sets the value of an environment variable in the selected environment.

    ```javascript theme={null}
    hopp.env.set("baseURL", "https://httpbin.org");
    ```

    ### `hopp.env.delete(key: string)`

    Deletes an environment variable from the selected environment.

    ```javascript theme={null}
    hopp.env.delete("baseURL");
    ```

    ### `hopp.env.reset(key: string)`

    Resets an environment variable to its initial value in the selected environment.

    ```javascript theme={null}
    hopp.env.reset("baseURL");
    ```

    ### `hopp.env.getInitialRaw(key: string)`

    Retrieves the initial raw value of an environment variable.

    ```javascript theme={null}
    hopp.env.getInitialRaw("baseURL");
    ```

    ### `hopp.env.setInitial(key: string, value: string)`

    Sets the initial value of an environment variable.

    ```javascript theme={null}
    hopp.env.setInitial("baseURL", "https://httpbin.org");
    ```

    #### Active Environment Scope

    Operations specific to the currently active environment.

    ### `hopp.env.active.get(key: string)`

    Retrieves the value of the active environment's variable.

    ```javascript theme={null}
    hopp.env.active.get("variable");
    ```

    ### `hopp.env.active.getRaw(key: string)`

    Retrieves the raw value of the active environment's variable.

    ```javascript theme={null}
    hopp.env.active.getRaw("variable");
    ```

    ### `hopp.env.active.set(key: string, value: string)`

    Sets the value of an active environment variable.

    ```javascript theme={null}
    hopp.env.active.set("baseURL", "https://httpbin.org");
    ```

    ### `hopp.env.active.delete(key: string)`

    Deletes a variable from the active environment.

    ```javascript theme={null}
    hopp.env.active.delete("baseURL");
    ```

    ### `hopp.env.active.reset(key: string)`

    Resets a variable in the active environment to its initial value.

    ```javascript theme={null}
    hopp.env.active.reset("baseURL");
    ```

    ### `hopp.env.active.getInitialRaw(key: string)`

    Retrieves the initial raw value of an active environment variable.

    ```javascript theme={null}
    hopp.env.active.getInitialRaw("baseURL");
    ```

    ### `hopp.env.active.setInitial(key: string, value: string)`

    Sets the initial value of an active environment variable.

    ```javascript theme={null}
    hopp.env.active.setInitial("baseURL", "https://httpbin.org");
    ```

    #### Global Environment Scope

    Operations specific to the global environment.

    ### `hopp.env.global.get(key: string)`

    Retrieves the value of the global environment's variable.

    ```javascript theme={null}
    hopp.env.global.get("variable");
    ```

    ### `hopp.env.global.getRaw(key: string)`

    Retrieves the raw value of the global environment's variable.

    ```javascript theme={null}
    hopp.env.global.getRaw("variable");
    ```

    ### `hopp.env.global.set(key: string, value: string)`

    Sets the value of a global environment variable.

    ```javascript theme={null}
    hopp.env.global.set("baseURL", "https://httpbin.org");
    ```

    ### `hopp.env.global.delete(key: string)`

    Deletes a variable from the global environment.

    ```javascript theme={null}
    hopp.env.global.delete("baseURL");
    ```

    ### `hopp.env.global.reset(key: string)`

    Resets a variable in the global environment to its initial value.

    ```javascript theme={null}
    hopp.env.global.reset("baseURL");
    ```

    ### `hopp.env.global.getInitialRaw(key: string)`

    Retrieves the initial raw value of a global environment variable.

    ```javascript theme={null}
    hopp.env.global.getInitialRaw("baseURL");
    ```

    ### `hopp.env.global.setInitial(key: string, value: string)`

    Sets the initial value of a global environment variable.

    ```javascript theme={null}
    hopp.env.global.setInitial("baseURL", "https://httpbin.org");
    ```

    ## `hopp.request` Namespace

    Request manipulation with immutable properties and dedicated mutation functions.

    #### Read-only Properties

    ### `hopp.request.url`

    The request URL as a string.

    ```javascript theme={null}
    const url = hopp.request.url;
    ```

    ### `hopp.request.method`

    The HTTP method of the request.

    ```javascript theme={null}
    const method = hopp.request.method;
    ```

    ### `hopp.request.params`

    The query parameters of the request.

    ```javascript theme={null}
    const params = hopp.request.params;
    ```

    ### `hopp.request.headers`

    The headers of the request.

    ```javascript theme={null}
    const headers = hopp.request.headers;
    ```

    ### `hopp.request.body`

    The body of the request.

    ```javascript theme={null}
    const body = hopp.request.body;
    ```

    ### `hopp.request.auth`

    The authentication configuration of the request.

    ```javascript theme={null}
    const auth = hopp.request.auth;
    ```

    #### Mutation Functions (Pre-request Phase Only)

    ### `hopp.request.setUrl(url: string)`

    Sets the request URL.

    ```javascript theme={null}
    hopp.request.setUrl("https://api.example.com/users");
    ```

    ### `hopp.request.setMethod(method: string)`

    Sets the HTTP method of the request.

    ```javascript theme={null}
    hopp.request.setMethod("POST");
    ```

    ### `hopp.request.setHeader(name: string, value: string)`

    Sets a header on the request.

    ```javascript theme={null}
    hopp.request.setHeader("Authorization", "Bearer token");
    ```

    ### `hopp.request.setHeaders(headers: HoppRESTHeader[])`

    Sets multiple headers on the request.

    ```javascript theme={null}
    hopp.request.setHeaders([{ key: "Content-Type", value: "application/json" }]);
    ```

    ### `hopp.request.removeHeader(name: string)`

    Removes a header from the request.

    ```javascript theme={null}
    hopp.request.removeHeader("Authorization");
    ```

    ### `hopp.request.setParam(name: string, value: string)`

    Sets a query parameter on the request.

    ```javascript theme={null}
    hopp.request.setParam("userId", "123");
    ```

    ### `hopp.request.setParams(params: HoppRESTParam[])`

    Sets multiple query parameters on the request.

    ```javascript theme={null}
    hopp.request.setParams([{ key: "userId", value: "123" }]);
    ```

    ### `hopp.request.removeParam(name: string)`

    Removes a query parameter from the request.

    ```javascript theme={null}
    hopp.request.removeParam("userId");
    ```

    ### `hopp.request.setBody(body: Partial<HoppRESTReqBody>)`

    Sets the body of the request.

    ```javascript theme={null}
    hopp.request.setBody({ body: '{"key": "value"}' });
    ```

    ### `hopp.request.setAuth(auth: Partial<HoppRESTAuth>)`

    Sets the authentication for the request.

    ```javascript theme={null}
    hopp.request.setAuth({ authType: "bearer", token: "token" });
    ```

    #### Request Variables

    ### `hopp.request.variables.get(key: string)`

    Retrieves the value of a request variable.

    ```javascript theme={null}
    const value = hopp.request.variables.get("varName");
    ```

    ### `hopp.request.variables.set(key: string, value: string)`

    Sets the value of a request variable.

    ```javascript theme={null}
    hopp.request.variables.set("varName", "value");
    ```

    > Please note that only updates to request variables get persisted and reflected in the UI while the remaining are specific to the session.

    ## `hopp.response` Namespace

    Response access with multiple data formats and comprehensive metadata.

    #### Response Metadata

    ### `hopp.response.statusCode`

    The HTTP status code of the response.

    ```javascript theme={null}
    const status = hopp.response.statusCode;
    ```

    ### `hopp.response.statusText`

    The status text of the response.

    ```javascript theme={null}
    const statusText = hopp.response.statusText;
    ```

    ### `hopp.response.headers`

    The headers of the response.

    ```javascript theme={null}
    const headers = hopp.response.headers;
    ```

    ### `hopp.response.responseTime`

    The response time in milliseconds.

    ```javascript theme={null}
    const time = hopp.response.responseTime;
    ```

    ### Response Body Access Methods

    ### `hopp.response.body.asJSON()`

    Parses the response body as JSON.

    ```javascript theme={null}
    const data = hopp.response.body.asJSON();
    ```

    ### `hopp.response.body.asText()`

    Returns the response body as text.

    ```javascript theme={null}
    const text = hopp.response.body.asText();
    ```

    ### `hopp.response.body.bytes()`

    Returns the response body as a Uint8Array.

    ```javascript theme={null}
    const bytes = hopp.response.body.bytes();
    ```

    ## `hopp.cookies` Namespace

    Domain-aware cookie management with comprehensive CRUD operations.

    ### `hopp.cookies.get(domain: string, cookieName: string)`

    Retrieves a cookie by domain and name.

    ```javascript theme={null}
    const cookie = hopp.cookies.get("example.com", "sessionId");
    ```

    ### `hopp.cookies.set(domain: string, cookie: Cookie)`

    Sets a cookie for a domain.

    ```javascript theme={null}
    hopp.cookies.set("example.com", {
      name: "session_id",
      value: "abc123",
      domain: "api.example.com",
      path: "/api",
      expires: new Date(Date.now() + 86400000).toISOString(), // 24 hours from now
      maxAge: 86400, // 24 hours in seconds
      httpOnly: true,
      secure: true,
      sameSite: "Lax",
    });
    ```

    ### `hopp.cookies.has(domain: string, cookieName: string)`

    Checks if a cookie exists for a domain.

    ```javascript theme={null}
    const exists = hopp.cookies.has("example.com", "sessionId");
    ```

    ### `hopp.cookies.getAll(domain: string)`

    Retrieves all cookies for a domain.

    ```javascript theme={null}
    const cookies = hopp.cookies.getAll("example.com");
    ```

    ### `hopp.cookies.delete(domain: string, cookieName: string)`

    Deletes a cookie for a domain.

    ```javascript theme={null}
    hopp.cookies.delete("example.com", "sessionId");
    ```

    ### `hopp.cookies.clear(domain: string)`

    Clears all cookies for a domain.

    ```javascript theme={null}
    hopp.cookies.clear("example.com");
    ```

    ## `hopp.test` and `hopp.expect` Testing Framework

    Comprehensive testing API with custom assertions and Chai.js-powered BDD assertions for advanced API testing.

    ### `hopp.test(testName: string, testFunction: () => void)`

    Creates a group of tests with a name.

    ```javascript theme={null}
    hopp.test("API Tests", () => {
      hopp.expect(1).toBe(1);
    });
    ```

    ### `hopp.expect(actual: any)`

    Returns an expectation object for assertions. Hoppscotch extends the testing framework with comprehensive Chai.js BDD assertion support, enabling advanced testing patterns with 50+ assertion methods.

    ```javascript theme={null}
    hopp.expect(value).toBe(expected);
    ```

    #### Basic Custom Assertions

    ### `hopp.expect(value).toBe(expected: any)`

    Tests for exact equality.

    ```javascript theme={null}
    hopp.expect(1).toBe(1);
    ```

    ### `hopp.expect(value).toBeType(type: string)`

    Tests for type equality.

    ```javascript theme={null}
    hopp.expect("hello").toBeType("string");
    ```

    ### `hopp.expect(value).toHaveLength(number: number)`

    Tests that a value has a specific length.

    ```javascript theme={null}
    hopp.expect([1,2,3]).toHaveLength(3);
    ```

    ### `hopp.expect(value).toInclude(item: any)`

    Tests that a value includes an item.

    ```javascript theme={null}
    hopp.expect([1,2,3]).toInclude(2);
    ```

    #### HTTP Status Code Level Assertions

    ### `hopp.expect(statusCode).toBeLevel2xx()`

    Tests that the status code is in the 2xx range.

    ```javascript theme={null}
    hopp.expect(200).toBeLevel2xx();
    ```

    ### `hopp.expect(statusCode).toBeLevel3xx()`

    Tests that the status code is in the 3xx range.

    ```javascript theme={null}
    hopp.expect(302).toBeLevel3xx();
    ```

    ### `hopp.expect(statusCode).toBeLevel4xx()`

    Tests that the status code is in the 4xx range.

    ```javascript theme={null}
    hopp.expect(404).toBeLevel4xx();
    ```

    ### `hopp.expect(statusCode).toBeLevel5xx()`

    Tests that the status code is in the 5xx range.

    ```javascript theme={null}
    hopp.expect(500).toBeLevel5xx();
    ```

    #### Negation Support

    All assertions support `.not` for negation.

    ```javascript theme={null}
    hopp.expect(1).not.toBe(2);
    hopp.expect("hello").not.toBeType("number");
    hopp.expect([1,2]).not.toHaveLength(3);
    hopp.expect([1,2]).not.toInclude(3);
    hopp.expect(200).not.toBeLevel4xx();
    ```

    ## Chai.js Assertion Support

    Hoppscotch includes comprehensive Chai.js BDD assertion support through `hopp.expect()` for native scripts and `pm.expect()` for Postman compatibility, enabling advanced testing patterns with 50+ assertion methods.

    ### Type Assertions

    Check value types and instances:

    ```javascript theme={null}
    // Basic type checking
    hopp.test("Type validation", () => {
      hopp.expect(hopp.response.statusCode).to.be.a('number')
      hopp.expect(hopp.response.body.asJSON()).to.be.an('object')
      hopp.expect([1, 2, 3]).to.be.an.instanceOf(Array)
      hopp.expect(new Date()).to.be.an.instanceOf(Date)
    })
    ```

    ### Equality Assertions

    Test for strict and deep equality:

    ```javascript theme={null}
    hopp.test("Equality checks", () => {
      hopp.expect(hopp.response.statusCode).to.equal(200)
      hopp.expect(hopp.response.body.asJSON()).to.eql({ userId: 1, name: 'John' })
      hopp.expect(hopp.response.statusCode).to.deep.equal(200)
    })
    ```

    ### Property Assertions

    Validate object properties and nested structures:

    ```javascript theme={null}
    hopp.test("Response structure", () => {
      const data = hopp.response.body.asJSON()
      hopp.expect(data).to.have.property('userId')
      hopp.expect(data).to.have.own.property('email')
      hopp.expect(data).to.have.nested.property('profile.name')
      hopp.expect(data).to.have.all.keys('id', 'name', 'email')
      hopp.expect(data).to.have.any.keys('id', 'name')
    })
    ```

    ### Collection and Array Assertions

    Validate arrays and collections:

    ```javascript theme={null}
    hopp.test("Array validation", () => {
      const tags = hopp.response.body.asJSON().tags
      hopp.expect(tags).to.have.lengthOf(3)
      hopp.expect(tags).to.include('nodejs')
      hopp.expect(tags).to.have.members(['nodejs', 'javascript', 'api'])
      hopp.expect(tags).to.have.ordered.members(['api', 'javascript', 'nodejs'])
    })
    ```

    ### Numeric Comparisons

    Perform numeric comparisons and range checks:

    ```javascript theme={null}
    hopp.test("Numeric assertions", () => {
      const responseTime = hopp.response.responseTime
      hopp.expect(responseTime).to.be.below(500)
      hopp.expect(responseTime).to.be.above(0)
      hopp.expect(responseTime).to.be.within(0, 1000)
      hopp.expect(3.14159).to.be.closeTo(3.14, 0.01)
    })
    ```

    ### String Assertions

    Validate string content and patterns:

    ```javascript theme={null}
    hopp.test("String validation", () => {
      const contentType = hopp.response.headers['content-type']
      hopp.expect(contentType).to.include('application/json')
      hopp.expect(contentType).to.match(/^application\/json/)
      hopp.expect('hello').to.have.lengthOf(5)
    })
    ```

    ### Boolean State Assertions

    Check boolean values and states:

    ```javascript theme={null}
    hopp.test("Boolean checks", () => {
      hopp.expect(true).to.be.true
      hopp.expect(false).to.be.false
      hopp.expect(1).to.be.ok
      hopp.expect(null).to.be.null
      hopp.expect(undefined).to.be.undefined
      hopp.expect({}).to.exist
      hopp.expect([]).to.not.be.empty
    })
    ```

    ### Complex Assertion Chains

    Combine multiple assertions for comprehensive validation:

    ```javascript theme={null}
    hopp.test("Complex validation", () => {
      const data = hopp.response.body.asJSON()
      hopp.expect(data)
        .to.be.an('object')
        .and.have.property('userId')
        .that.is.a('number')
        .and.is.above(0)
    })
    ```

    ### Real-World Example: API Pagination

    ```javascript theme={null}
    hopp.test("Pagination metadata validation", () => {
      const data = hopp.response.body.asJSON()
      
      // Validate pagination structure
      hopp.expect(data).to.have.all.keys('items', 'page', 'total', 'hasMore')
      hopp.expect(data.items).to.be.an.instanceOf(Array)
      hopp.expect(data.items).to.have.lengthOf.at.most(50)
      
      // Validate each item
      data.items.forEach(item => {
        hopp.expect(item).to.have.all.keys('id', 'name', 'createdAt')
        hopp.expect(item.id).to.be.a('string')
      })
      
      // Store next page cursor
      if (data.hasMore) {
        hopp.env.active.set('nextPage', String(data.page + 1))
      }
    })
    ```

    ### Complete Assertion Reference

    **Type assertions:**

    * `.a(type)` / `.an(type)` - Check value type
    * `.instanceof(constructor)` - Check instance type

    **Equality assertions:**

    * `.equal(value)` / `.eq(value)` - Strict equality (===)
    * `.eql(value)` - Deep equality

    **Property assertions:**

    * `.property(name)` - Has property
    * `.own.property(name)` - Has own property (not inherited)
    * `.nested.property(path)` - Has nested property (e.g., 'a.b.c')

    **Collection assertions:**

    * `.include(value)` / `.contain(value)` - Contains value
    * `.members(array)` - Has members (order-independent)
    * `.ordered.members(array)` - Has members in order
    * `.keys(...keys)` - Has keys
    * `.lengthOf(n)` - Length equals n
    * `.lengthOf.at.least(n)` - Minimum length
    * `.lengthOf.at.most(n)` - Maximum length

    **Comparison assertions:**

    * `.above(n)` / `.gt(n)` - Greater than
    * `.below(n)` / `.lt(n)` - Less than
    * `.at.least(n)` / `.gte(n)` - Greater than or equal
    * `.at.most(n)` / `.lte(n)` - Less than or equal
    * `.within(min, max)` - Within range
    * `.closeTo(expected, delta)` - Approximately equal

    **Boolean assertions:**

    * `.ok` - Truthy
    * `.true` - Strictly true
    * `.false` - Strictly false
    * `.null` - Strictly null
    * `.undefined` - Strictly undefined
    * `.exist` - Not null or undefined
    * `.empty` - Empty (string, array, object)

    **String assertions:**

    * `.match(regex)` - Matches regular expression
    * `.string(substring)` - Contains substring

    **Function assertions:**

    * `.throw()` / `.throw(ErrorType)` - Throws error
    * `.respondTo(method)` - Has method

    **Object state assertions:**

    * `.extensible` - Object.isExtensible()
    * `.sealed` - Object.isSealed()
    * `.frozen` - Object.isFrozen()

    **Modifiers:**

    * `.not` - Negation
    * `.deep` - Deep comparison
    * `.own` - Own properties only
    * `.ordered` - Order matters
    * `.nested` - Nested property access
    * `.all` - All items/keys
    * `.any` - Any items/keys
    * `.to` / `.be` / `.is` / `.that` / `.and` / `.have` / `.with` - Language chains for readability

    ## `pm` Namespace - Postman Compatibility Layer

    Postman API compatibility for seamless migration with experimental Postman collection import support (v2.0/v2.1). The `pm` namespace provides `pm.expect()` with full Chai.js assertion support for Postman-compatible testing.

    <Info>
      **Experimental Script Import:** When importing Postman collections, Hoppscotch can now import pre-request scripts and test scripts (experimental feature requiring user consent). This enables you to migrate your existing Postman workflows including their scripting logic.
    </Info>

    ### Core APIs

    ```javascript theme={null}
    // Environment and variable management
    pm.environment.get(key: string): string | null
    pm.environment.set(key: string, value: string): void
    pm.environment.unset(key: string): void
    pm.environment.has(key: string): boolean

    pm.globals.get(key: string): string | null
    pm.globals.set(key: string, value: string): void
    pm.globals.unset(key: string): void
    pm.globals.has(key: string): boolean

    pm.variables.get(key: string): string | null
    pm.variables.set(key: string, value: string): void
    pm.variables.has(key: string): boolean
    pm.variables.replaceIn(template: string): string

    // Request access (read-only)
    pm.request.url: URL-like (toString available; additional properties may be limited initially)
    pm.request.method: string
    pm.request.headers: HoppRESTHeader[]
    pm.request.body: HoppRESTReqBody
    pm.request.auth: HoppRESTAuth

    // Response access (post-request only)
    pm.response.code: number
    pm.response.status: string
    pm.response.responseTime: number  // ms
    pm.response.json(): Record<string, any>
    pm.response.text(): string
    pm.response.headers.get(name: string): string | null
    pm.response.headers.has(name: string): boolean
    pm.response.headers.all(): HoppRESTResponseHeader[]
    pm.response.stream: Uint8Array  // Raw response bytes

    // Testing integration
    pm.test(testName: string, testFunction: () => void): void
    pm.expect(actual: any): Expectation

    // Script context information
    pm.info.eventName: string  // "pre-request" or "post-request"
    pm.info.requestName: string
    pm.info.requestId: string

    // Asynchronous requests
    pm.sendRequest(request: string | Object, callback: (err: any, res: any) => void): void
    ```

    ### Postman Chai.js Assertions

    Use `pm.expect()` with full Chai.js BDD assertion support for Postman-compatible scripts:

    ```javascript theme={null}
    // Basic assertions
    pm.test("Status code is 200", () => {
      pm.expect(pm.response.code).to.equal(200)
      pm.expect(pm.response.responseTime).to.be.below(500)
    })

    // Response body validation
    pm.test("Response structure", () => {
      const jsonData = pm.response.json()
      pm.expect(jsonData).to.have.property('success')
      pm.expect(jsonData.success).to.be.true
      pm.expect(jsonData.data).to.be.an('array')
    })

    // Array validation
    pm.test("Array contains expected items", () => {
      const items = pm.response.json().items
      pm.expect(items).to.have.lengthOf.at.least(1)
      pm.expect(items).to.include('apple')
      pm.expect(items).to.have.members(['apple', 'banana', 'cherry'])
    })

    // Header validation
    pm.test("Headers are correct", () => {
      pm.expect(pm.response.headers.get('content-type')).to.include('application/json')
    })
    ```

    ### Postman Response Assertions

    Postman-specific response validation methods:

    ```javascript theme={null}
    pm.test("Response validation", () => {
      pm.expect(pm.response.to.have.status(200))
      pm.expect(pm.response.to.have.header('content-type'))
      pm.expect(pm.response.to.have.body())
      pm.expect(pm.response.to.have.jsonBody())
      pm.expect(pm.response.to.be.ok) // 2xx status
      pm.expect(pm.response.to.be.json)
    })

    pm.test("JSON body validation", () => {
      pm.expect(pm.response.to.have.jsonBody('userId'))
      pm.expect(pm.response.to.have.jsonBody('profile.name'))
      pm.expect(pm.response.to.have.jsonSchema({
        type: 'object',
        required: ['userId', 'email'],
        properties: {
          userId: { type: 'number' },
          email: { type: 'string' }
        }
      }))
    })
    ```

    ### OAuth Token Handling Example

    ```javascript theme={null}
    pm.test("OAuth token handling", () => {
      const response = pm.response.json()
      const expiresIn = response.expires_in // 3600 seconds
      const expiryTime = Date.now() + (expiresIn * 1000)

      // Auto-converts number to string
      pm.environment.set('token_expiry', expiryTime)
      pm.environment.set('access_token', response.access_token)

      // Verify storage
      pm.expect(pm.environment.get('access_token')).to.equal(response.access_token)
    })
    ```

    ### PM-Specific Response Assertions

    The following assertions are specific to the Postman compatibility layer:

    * `pm.response.to.have.status(code)` - Status code check
    * `pm.response.to.have.header(name)` - Header existence
    * `pm.response.to.have.body()` - Has response body
    * `pm.response.to.have.jsonBody()` - JSON body exists
    * `pm.response.to.have.jsonBody(path)` - JSON property exists
    * `pm.response.to.have.jsonSchema(schema)` - Validates JSON schema
    * `pm.response.to.be.ok` - 2xx status code
    * `pm.response.to.be.success` - Alias for ok
    * `pm.response.to.be.json` - JSON content type

    ### Sending Requests

    The `pm.sendRequest` method allows you to send HTTP requests asynchronously from your scripts. This is useful for chaining requests or fetching data from other APIs.

    ```javascript theme={null}
    pm.sendRequest("https://postman-echo.com/get", (err, res) => {
      if (err) {
        console.log(err);
      } else {
        pm.expect(res).to.have.property('code', 200);
        pm.expect(res).to.have.property('status', 'OK');
      }
    });
    ```

    <Note>
      It is recommended to use the Agent interceptor on the Web App and the Native interceptor on the Desktop App for `fetch()`, `hopp.fetch()` and `pm.sendRequest()` usages.
    </Note>

    ### Unsupported Postman Features

    The following Postman features are not currently supported:

    * `pm.visualizer`
    * `pm.collectionVariables`
    * `pm.iterationData`
    * `pm.execution.setNextRequest()`
    * Legacy patterns like global `responseBody` variable, `require()`, etc.

    <Note>
      These limitations are documented in error messages when attempting to use unsupported APIs. The supported version range for Postman collections is v2.0/v2.1.
    </Note>

    ## `pw` Namespace - Legacy Compatibility

    Maintained for backwards compatibility with existing scripts:

    ```javascript theme={null}
    // Legacy environment operations
    pw.env.get(key: string): string | null
    pw.env.getResolve(key: string): string | null
    pw.env.set(key: string, value: string): void
    pw.env.unset(key: string): void
    pw.env.resolve(template: string): string

    // Legacy response access
    pw.response.status: number
    pw.response.body: any
    pw.response.headers: HoppRESTResponseHeader[]

    // Legacy testing framework
    pw.test(testName: string, testFunction: () => void): void
    pw.expect(actual: any): Expectation
    ```

    ## Cookie Object Structure

    Cookies are represented as objects with the following properties:

    ```javascript theme={null}
    type Cookie = {
      name: string           // Cookie name
      value: string          // Cookie value
      domain: string         // Domain the cookie belongs to
      path: string           // Path scope of the cookie (default: "/")
      expires?: string       // Expiration date in ISO format, null for session cookies
      maxAge?: number        // Maximum age in seconds, null if not set
      httpOnly: boolean      // Whether cookie is HTTP-only
      secure: boolean        // Whether cookie should only be sent over HTTPS
      sameSite: 'None' | 'Lax' | 'Strict'  // SameSite attribute
    }
    ```

    ## Usage Examples

    ### Environment Management

    ```javascript theme={null}
    // Set and get environment variables
    hopp.env.set("api_token", "abc123")
    const token = hopp.env.get("api_token")

    // Scope-specific operations
    hopp.env.global.set("base_url", "https://api.example.com")
    hopp.env.active.set("user_id", "12345")

    // Reset to initial values
    hopp.env.reset("api_token")
    ```

    ### Request Manipulation

    ```javascript theme={null}
    // Modify request before sending
    hopp.request.setHeader("Authorization", "Bearer " + hopp.env.get("token"))
    hopp.request.setUrl("https://api.example.com/users/" + hopp.env.get("user_id"))
    hopp.request.setMethod("POST")
    ```

    ### Response Testing

    ```javascript theme={null}
    hopp.test("API responds successfully", () => {
      hopp.expect(hopp.response.statusCode).toBeLevel2xx()
      hopp.expect(hopp.response.responseTime).toBe(1000)

      const data = hopp.response.body.asJSON()
      hopp.expect(data).toBeType("object")
      hopp.expect(data.users).toHaveLength(10)
    })
    ```

    ### Cookie Management

    ```javascript theme={null}
    // Set authentication cookie
    hopp.cookies.set("api.example.com", {
      name: "session_id",
      value: "abc123",
      domain: "api.example.com",
      path: "/api",
      expires: new Date(Date.now() + 86400000).toISOString(), // 24 hours from now
      maxAge: 86400, // 24 hours in seconds
      httpOnly: true,
      secure: true,
      sameSite: "Lax",
    })

    // Check if cookie exists
    if (hopp.cookies.has("api.example.com", "session_id")) {
      const cookie = hopp.cookies.get("api.example.com", "session_id")
      hopp.env.set("session_token", cookie.value)
    }
    ```
  </Tab>

  <Tab title="pw [Legacy]">
    Hoppscotch provides [ECMAScript](https://tc39.es/ecma262) APIs that can be used in writing pre-request scripts and building tests. You can enter your code and run the necessary scripts.

    ## The `pw` object

    The `pw` object provides access to request and response data and variables in your Hoppscotch instance.

    The `pw` object houses the following methods:

    ## `pw.env.set("variable", "value")`

    `pw.env.set()` can be used directly for quick and convenient environment variable definition.

    ```javascript theme={null}
    pw.env.set("baseURL", "https://httpbin.org");
    ```

    Here are some practical examples that show how you can use `pw.env.set()` to encode and decode strings with Base64:

    ### 1.  `pw.env.set("variable", atob("value"))`

    Use the `atob()` function to **decode a Base64 encoded string** and set it as an environment variable.

    ```javascript theme={null}
    pw.env.set("atob", atob("SG9wcHNjb3RjaA=="));
    ```

    ### 2.  `pw.env.set("variable", btoa("value"))`

    Use the `btoa()` function to **encode a regular string into Base64** and set it as an environment variable.

    ```javascript theme={null}
    pw.env.set("btoa", btoa("Hoppscotch"));
    ```

    ## `pw.env.unset("variable")`

    `pw.env.unset()` can be used to remove the value of the variable present in the current active environment

    ```javascript theme={null}
    pw.env.unset("baseURL");
    ```

    ## `pw.env.get("variable")`

    Retrieves the value of the selected environment's variable. Accepts an environment variable as an argument.

    ```javascript theme={null}
    pw.env.get("variable");
    pw.env.get("baseURL");
    ```

    ## `pw.env.getResolve("variable")`

    Retrieves the value of the selected environment's variable recursively. Accepts an environment variable as an argument.

    ```javascript theme={null}
    pw.env.getResolve("variable");
    pw.env.getResolve("baseURL");
    ```

    ## `pw.env.resolve("variable")`

    Retrieves the value of the selected environment's variable recursively. Accepts an environment variable string as an argument.

    ```javascript theme={null}
    pw.env.resolve("<<variable_1>><<variable_2>>");
    pw.env.resolve("<<baseURL>><<basePath>>");
    ```

    ## `pw.expect(value)`

    The expect method returns an expectation object, on which you can call matcher functions.

    The example below calls the matcher function `toBe` on the expectation object that is returned by calling `pw.expect` with the response id, `pw.response.body.id` as an argument.

    Use `pw.expect` directly for quick and convenient testing. Every `pw.expect` statement will generate a line on the test report.

    ```javascript theme={null}
    // This test will pass
    pw.expect(1).toBe(1);

    // This test will fail
    pw.expect(2).not.toBe(2);
    ```

    ## `pw.test(name, function)`

    To create a group of tests, with the name as a string and fn as a callback function to write tests associated with the group. The test results will include the given name for better organization.

    Let's wrap expect statements with `pw.test` to the group and describe related statements.

    ```javascript theme={null}
    // This will return 4 lines on the test report, grouped under "Arithmetic operations"
    pw.test("Arithmetic operations", () => {
      const size = 500 + 500;
      pw.expect(size).toBe(1000);
      pw.expect(size - 500).toBe(500);
      pw.expect(size * 4).toBe(4000);
      pw.expect(size / 4).toBe(250);
    });
    ```

    If neither a `pw.expect` nor a `pw.test` statement is present, no test reports will be generated.

    ```javascript theme={null}
    // This will not generate any test reports
    (99 + 1).toBe(100);
    ```

    ## `pw.toBe(value)`

    Test for exact equality using `toBe`.

    ```javascript theme={null}
    pw.expect(pw.response.body.category).toBe("Sneakers");
    ```

    `toBe` uses strict equality and is recommended for primitive data types.

    ```javascript theme={null}
    // These tests will fail
    pw.expect("hello").toBe("Hello");
    pw.expect(5).toBe("5");
    pw.expect([]).toBe([]);
    ```

    ## `pw.not()`

    Test for negation by adding `.not` before calling the matcher function.

    ```javascript theme={null}
    // These tests will pass
    pw.expect(true).not.toBe(false);
    pw.expect(200).not.toBeLevel3xx();
    ```

    ## `pw.toBeLevelxxx()`

    There are four different matcher functions for quick and convenient testing of the http status code that is returned:

    * `toBeLevel2xx()`
    * `toBeLevel3xx()`
    * `toBeLevel4xx()`
    * `toBeLevel5xx()`

    For example, an argument passed to expect must be within `200` and `299` inclusive to pass `toBeLevel2xx()`.

    ```javascript theme={null}
    // These tests will pass
    pw.expect(204).toBeLevel2xx();
    pw.expect(308).toBeLevel3xx();
    pw.expect(404).toBeLevel4xx();
    pw.expect(503).toBeLevel5xx();
    ```

    If the argument passed to `expect()` is a non-numeric value, it is first parsed with `parseInt()`.

    ```javascript theme={null}
    // This test will pass
    pw.expect("404").toBeLevel4xx();
    ```

    ## `pw.toBeType(type)`

    Use `.toBeType(type)` for type checking. The argument for this method should be either of the following `string`, `boolean`, `number`, `object`, `undefined`, `bigint`, `symbol`, or `function`.

    ```javascript theme={null}
    // These tests will pass
    pw.expect(5).toBeType("number");
    pw.expect("Hello, world!").toBeType("string");

    pw.expect(5).not.toBeType("string");
    pw.expect("Hello, world!").not.toBeType("number");
    ```

    ## `pw.toHaveLength(number)`

    Use `.toHaveLength(number)` to check that an object has a `.length` property and it is set to a certain numeric value.

    ```javascript theme={null}
    // These expectations will pass
    pw.expect("hoppscotch").toHaveLength(10);
    pw.expect("hoppscotch").not.toHaveLength(9);

    pw.expect(["apple", "banana", "coconut"]).toHaveLength(3);
    pw.expect(["apple", "banana", "coconut"]).not.toHaveLength(4);
    ```

    ## `pw.toInclude(value)`

    Use `.toInclude(value)` to check that a string/array has a value entry.

    ```javascript theme={null}
    // These expectations will pass
    pw.expect("hoppscotch").toInclude("hopp");
    pw.expect("hoppscotch").not.toInclude("scotch");

    pw.expect(["apple", "banana", "coconut"]).toInclude("banana");
    pw.expect(["apple", "banana", "coconut"]).not.toInclude("grape");
    ```

    ## `pw.response`

    Assert response data by accessing the `pw.response` object.

    ```javascript theme={null}
    // This test will pass
    pw.test("Response is ok", () => {
      pw.expect(pw.response.status).toBe(200);
    });
    ```

    Currently supports the following response values:

    * `status`: -number- The status code as an integer.
    * `headers`: -object- The response headers.
    * `body`: -object- the data in the response. In many requests, this is the JSON sent by the server.

    ### Setting Environment Variables from API Responses

    By following these steps, you can store data from one API response and access it later using Environment Variables, making it available for use in subsequent API calls.

    Assume in this example that the payload returns `access_token` and `id_token` as part of a JSON response.

    1. Create Environment Variables without setting their values initially. For example:

    * `idToken`
    * `accessToken`

    2. In the "Tests" tab of the first API request (that returns the tokens), add the following code:

    ```javascript theme={null}
    const jsonData = pw.response.body; // Save the JSON payload response

    pw.env.set("accessToken", jsonData.access_token); // Set "accessToken" to the value of "access_token" in the response

    pw.env.set("idToken", jsonData.id_token); // Set "idToken" to the value of "id_token" in the response
    ```

    3. Use these Environment Variables in subsequent API calls within the same collection using the `<<variableName>>` syntax as usual.
  </Tab>
</Tabs>

<CardGroup cols={1}>
  <Card title="Scripts" iconType="light" icon="circle-arrow-right" href="/documentation/getting-started/rest/pre-request-scripts">
    Read about pre-request scripts.
  </Card>

  <Card title="Tests" iconType="light" icon="circle-arrow-right" href="/documentation/getting-started/rest/tests">
    Read about post-request tests.
  </Card>

  <Card title="Environments" iconType="light" icon="circle-arrow-right" href="/documentation/features/environments">
    Read about environments.
  </Card>
</CardGroup>
