Unable to visualize response after update latest update

After updating to the latest version of Postman, I am encountering an issue with the Visualizer feature in the “post-response” in the Scripts tab. Specifically, the pm object, which is essential for Postman-specific scripting, is throwing a ReferenceError: pm is not defined. This error occurs when trying to execute a script for a custom visualization of API responses.

My response has a unique structure, so I can’t directly use post-bot to generate visualization.

This is my script for the visualization, which worked for the older version:

var template = `
<style>
    .fill,
    body,
    html {
        height: 100%;
    }

    table,
    td,
    th {
        border: 1px solid gray;
    }

    /* Additions for table cell and header styling */
    .my-table th,
    .my-table td {
        max-width: 120px;
        padding: 5px;
        border: 1px solid #ddd;
        text-align: left; 
        vertical-align: top; 
    }

    /* Specific styling for table headers */
    .my-table th,
    .my-table td {
        white-space: normal; 
        word-wrap: break-word;
    }

    /* Reduce the font size for all table content */
    .my-table,
    .my-table th,
    .my-table td {
        font-size: 0.8em; 
    }

    .my-table th {
        position: sticky;
        top: 0;
        background-color: #f0f0f0; 
        z-index: 1;
    }

    table {
        table-layout: fixed; 
        width: 100%;
    }

    /* Alternate row coloring */
    .my-table tr:nth-child(odd) {
        background-color: #f9f9f9; /* Light grey for odd rows */
    }
    .my-table tr:nth-child(even) {
        background-color: #ffffff; /* White for even rows */
    }

    *,
    html {
        font-family: Verdana, Arial, Helvetica, sans-serif;
    }

    form,
    h1,
    h2,
    h3,
    h4,
    h5,
    li,
    p,
    ul {
        margin: 0;
        padding: 0;
    }

    .container {
        width: 100%;
        max-width: none !important;
    }

    /* Additional CSS for key-value pairs */
    .key-value-pair {
        background-color: #e8e8e8; /* Light gray background */
        border: 1px solid #ccc; /* Light border for distinction */
        border-radius: 4px; /* Rounded corners */
        padding: 5px; /* Some padding around the text */
        margin: 5px 0; /* Margin for spacing between pairs */
        font-family: monospace; /* Monospaced font for better readability */
    }

    /* Style adjustments for better spacing and alignment */
    .key-value-pair::before {
        display: inline-block;
        margin-right: 5px;
        color: #333;
    }
</style>
<div id="html">
    <input type="text" id="json" hidden />
    <div id="container"></div>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <script>
        $(function () {
            pm.getData((err, data) => {
                if (err) {
                    console.error("Error getting data:", err);
                    $("#container").text("Error getting data.");
                    return;
                }

                // Clear previous contents
                $("#container").empty();

                // Check if the outputs array is present
                if (Array.isArray(data.json.outputs)) {
                    data.json.outputs.forEach((item) => {
                        // Check for items with a structure applicable for table rendering
                        if (
                            item.value &&
                            Array.isArray(item.value) &&
                            item.value.some((val) => val.metadata || val.data)
                        ) {
                            const tableData = transformDatagridData(item.value);
                            $("#container").append($("<h4>").text(item.name)); // Add a header for each table
                            $("#container").append(buildTable(tableData));
                        } else {
                            // For other items, display them as key-value pairs
                            $("#container").append(
                                $('<div class="key-value-pair">').append($("<span>").text(item.name)).append(": " + item.value)
                                
                            );
                        }
                    });
                } else {
                    $("#container").text(
                        "The data is not an array as expected."
                    );
                }
            });
        });

        function transformDatagridData(value) {
            // Assume value is an array with one item that has metadata and one that has data
            const metadataItem = value.find((item) => item.metadata);
            const dataItem = value.find((item) => item.data);
            if (!metadataItem || !dataItem) {
                return { headers: [], rows: [] };
            }

            const metadata = metadataItem.metadata;
            const data = dataItem.data;

            // Create headers array from metadata
            const headers = metadata.map((col) => Object.keys(col)[0]);

            // Transform data array into array of objects
            const dataRows = data.map((row) => {
                return row.reduce((acc, val, index) => {
                    // acc is the accumulator object
                    // val is the current value in the row
                    // index is the current index of val in the row to find the corresponding header name in headers
                    acc[headers[index]] = val;
                    return acc;
                }, {});
            });

            return { headers, rows: dataRows };
        }

        function buildTable(data) {
            const table = $("<table/>").addClass("my-table");

            // Build the header
            const thead = $("<thead/>");
            const headerRow = $("<tr/>");
            data.headers.forEach((header) => {
                headerRow.append($("<th/>").text(header));
            });
            thead.append(headerRow);
            table.append(thead);

            // Build the body
            const tbody = $("<tbody/>");
            data.rows.forEach((row) => {
                const tr = $("<tr/>");
                data.headers.forEach((header) => {
                    tr.append($("<td/>").text(row[header]));
                });
                tbody.append(tr);
            });
            table.append(tbody);

            return table;
        }
    </script>
</div>
`;

// Change to use the entire JSON response
let tableProps = {
    json: pm.response.json(),
};

pm.visualizer.set(template, tableProps);

Could you confirm if there have been changes in the latest Postman update that affect the pm object or the Visualizer feature? If so, could you provide guidance on how to adapt the script for compatibility with the updated version?

Thank you for your assistance!

Hey @lli-1und1 :wave:

I’ve raised this with the team to investigate - Thank you for also creating the GH Issue for this. :pray:

Are you able to see the expected visualized response, when using the web platform?

https://go.postman.co

Hi @danny-dainton,

I cannot use the web app because our domain is not public. Currently I can only use the old version V11.23.3 to ensure that the script works

You can download and use the Postman Agent with the web app for non public usage.

Thank you, now I can confirm that the script works, when using the web platform.

1 Like

Hi! Any news?

I’m also severely affected by this issue.

I can’t find a way to disable automatic updates to use the old version, from before this bug, and the visualization from the web platform is not working on my browser of choice (Microsoft Edge on MacOS; see log below), even ensuring usage of the desktop agent.

Hey @garrucho

What’s the script that you’re using? I’m sure it’s not the same as @lli-1und1 so it would be useful to share that information.

Hi! Thanks in advance.

My script is extremely similar regarding the usage of a pm.getData() inside a script from pm.visualizer.set(template, pm.response.json()).

If it’s really useful for you, I can organize a simplified version of it. Just let me know.

Having something that can reproduce the issue each time is very useful for debugging the problem.

Sure! Here it goes:

This implements a filter via JQ, presenting the results in a simple ACE Editor.

let template = `
  <html>
    <head>
      <script src="https://cdn.jsdelivr.net/npm/jquery"></script>
      <script src="https://cdn.jsdelivr.net/npm/ace-builds/src-min-noconflict/ace.js"></script>
      <link  href="https://cdn.jsdelivr.net/npm/ace-builds/css/ace.min.css" rel="stylesheet">
      <script src="https://cdn.jsdelivr.net/npm/[email protected]"></script>

      <style>
        #parent {width: 100%; height: 100%; display: inline-block; position: relative;}
        #editor {position: absolute; top: 0; right: 0; bottom: 0; left: 0;}
      </style>
    </head>
    <body style="background-color:#272822;">
      <div id="parent"><div id="editor"></div></div>
    </body>
  </html>

  <script>
    var editor = ace.edit("editor", {
      theme: "ace/theme/monokai",
      mode: "ace/mode/javascript"
    });
    
    let jqQuery = "."

    pm.getData((error, value) => {
      let jqOutput = jq.json(value, jqQuery);
      editor.setValue(JSON.stringify(jqOutput));
    });
  </script>
`

pm.visualizer.set(template, pm.response.json())

It can be used with any request, such as GET https://postman-echo.com/get.

In the last stable version, the ACE Editor from the Visualization will be blank. If you inspect, you’ll be able to see in the console:

Uncaught ReferenceError: pm is not defined
    at 3uHSKtSMs.html:57:5

The mentioned file/line leads straight to pm.getData((error, value) => { from my script.

1 Like

In the very latest version of the desktop app, I can see this working now.

Uhhhhh, what a relief! Now it’s working fine for me too. :raised_hands:

Many thanks, Danny. =)

1 Like

It is working now, thank you.

1 Like

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.