You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jmeter.apache.org by pm...@apache.org on 2019/09/25 14:30:52 UTC

[jmeter] branch master updated: Add JMESPath Tester to View Results Tree (#500)

This is an automated email from the ASF dual-hosted git repository.

pmouawad pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/jmeter.git


The following commit(s) were added to refs/heads/master by this push:
     new b8aac25  Add JMESPath Tester to View Results Tree (#500)
b8aac25 is described below

commit b8aac252c343e301bec32630cc6357d834501f5f
Author: UBIK LOAD PACK <su...@ubikloadpack.com>
AuthorDate: Wed Sep 25 16:30:47 2019 +0200

    Add JMESPath Tester to View Results Tree (#500)
    
    * Add JMESPath Tester
    * Add documentation and update release notes
    * Update test RenderAsJsonRendererSpec following refactoring of
    RenderAsJsonRenderer
    Add test for RenderAsJmesPathRenferer
    * Improve javadocs
    
    This resolves https://bz.apache.org/bugzilla/show_bug.cgi?id=63770
---
 ...erer.java => AbstractRenderAsJsonRenderer.java} | 171 +++++++++--------
 .../json/render/RenderAsJmesPathRenderer.java      |  93 +++++++++
 .../json/render/RenderAsJsonRenderer.java          | 208 ++-------------------
 ....groovy => RenderAsJmesPathRendererSpec.groovy} |  28 +--
 .../json/render/RenderAsJsonRendererSpec.groovy    |  16 +-
 .../apache/jmeter/resources/messages.properties    |   6 +-
 .../apache/jmeter/resources/messages_fr.properties |   6 +-
 xdocs/changes.xml                                  |   1 +
 xdocs/usermanual/component_reference.xml           |   3 +
 9 files changed, 235 insertions(+), 297 deletions(-)

diff --git a/src/components/src/main/java/org/apache/jmeter/extractor/json/render/RenderAsJsonRenderer.java b/src/components/src/main/java/org/apache/jmeter/extractor/json/render/AbstractRenderAsJsonRenderer.java
similarity index 56%
copy from src/components/src/main/java/org/apache/jmeter/extractor/json/render/RenderAsJsonRenderer.java
copy to src/components/src/main/java/org/apache/jmeter/extractor/json/render/AbstractRenderAsJsonRenderer.java
index 5205d41..c7de2d5 100644
--- a/src/components/src/main/java/org/apache/jmeter/extractor/json/render/RenderAsJsonRenderer.java
+++ b/src/components/src/main/java/org/apache/jmeter/extractor/json/render/AbstractRenderAsJsonRenderer.java
@@ -23,8 +23,6 @@ import java.awt.Color;
 import java.awt.Dimension;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
-import java.text.ParseException;
-import java.util.List;
 
 import javax.swing.BoxLayout;
 import javax.swing.JButton;
@@ -36,7 +34,6 @@ import javax.swing.JTextArea;
 import javax.swing.border.Border;
 import javax.swing.border.EmptyBorder;
 
-import org.apache.jmeter.extractor.json.jsonpath.JSONManager;
 import org.apache.jmeter.gui.util.JSyntaxTextArea;
 import org.apache.jmeter.gui.util.JTextScrollPane;
 import org.apache.jmeter.samplers.SampleResult;
@@ -47,29 +44,26 @@ import org.apache.jmeter.visualizers.ViewResultsFullVisualizer;
 import org.apache.jorphan.gui.GuiUtils;
 import org.apache.jorphan.gui.JLabeledTextField;
 import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 
 /**
- * Implement ResultsRender for JSON Path tester
- * @since 3.0
+ * Abstract base class for implementation of a ResultsRenderer for a JSON tester
+ * @since 5.2
  */
-public class RenderAsJsonRenderer implements ResultRenderer, ActionListener {
+abstract class AbstractRenderAsJsonRenderer implements ResultRenderer, ActionListener {
 
-    private static final Logger log = LoggerFactory.getLogger(RenderAsJsonRenderer.class);
-    private static final String NO_MATCH = "NO MATCH"; //$NON-NLS-1$
+    protected static final String NO_MATCH = "NO MATCH"; //$NON-NLS-1$
     private static final String TAB_SEPARATOR = "    "; //$NON-NLS-1$
 
-    private static final String JSONPATH_TESTER_COMMAND = "jsonpath_tester"; // $NON-NLS-1$
+    private static final String TESTER_COMMAND = "TESTER_COMMAND"; // $NON-NLS-1$
 
-    private JPanel jsonWithJSonPathPanel;
+    private JPanel jsonWithExtractorPanel;
 
     private JSyntaxTextArea jsonDataField;
 
-    private JLabeledTextField jsonPathExpressionField;
+    private JLabeledTextField expressionField;
 
-    private JTextArea jsonPathResultField;
+    private JTextArea resultField;
 
     private JTabbedPane rightSide;
 
@@ -80,14 +74,14 @@ public class RenderAsJsonRenderer implements ResultRenderer, ActionListener {
     public void clearData() {
         this.jsonDataField.setText(""); // $NON-NLS-1$
         // don't set empty to keep json path
-        this.jsonPathResultField.setText(""); // $NON-NLS-1$
+        this.resultField.setText(""); // $NON-NLS-1$
     }
 
     /** {@inheritDoc} */
     @Override
     public void init() {
         // Create the panels for the json tab
-        jsonWithJSonPathPanel = createJSonPathExtractorPanel();
+        jsonWithExtractorPanel = createExtractorPanel();
     }
 
     /**
@@ -99,9 +93,9 @@ public class RenderAsJsonRenderer implements ResultRenderer, ActionListener {
     @Override
     public void actionPerformed(ActionEvent e) {
         String command = e.getActionCommand();
-        if ((sampleResult != null) && (JSONPATH_TESTER_COMMAND.equals(command))) {
+        if ((sampleResult != null) && (TESTER_COMMAND.equals(command))) {
             String response = jsonDataField.getText();
-            executeAndJSonPathTester(response);
+            executeTester(response);
         }
     }
 
@@ -109,40 +103,16 @@ public class RenderAsJsonRenderer implements ResultRenderer, ActionListener {
      * Launch json path engine to parse a input text
      * @param textToParse
      */
-    private void executeAndJSonPathTester(String textToParse) {
+    protected void executeTester(String textToParse) {
         if (textToParse != null && textToParse.length() > 0
-                && this.jsonPathExpressionField.getText().length() > 0) {
-            this.jsonPathResultField.setText(process(textToParse));
-            this.jsonPathResultField.setCaretPosition(0); // go to first line
+                && this.expressionField.getText().length() > 0) {
+            this.resultField.setText(process(textToParse));
+            this.resultField.setCaretPosition(0); // go to first line
         }
     }
 
-    private String process(String textToParse) {
-        String jsonPathExpression = jsonPathExpressionField.getText();
-        try {
-            List<Object> matchStrings = extractWithJSonPath(textToParse, jsonPathExpression);
-            if (matchStrings.isEmpty()) {
-                return NO_MATCH; //$NON-NLS-1$
-            } else {
-                StringBuilder builder = new StringBuilder();
-                int i = 0;
-                for (Object obj : matchStrings) {
-                    String objAsString =
-                            obj != null ? obj.toString() : ""; //$NON-NLS-1$
-                    builder.append("Result[").append(i++).append("]=").append(objAsString).append("\n"); //$NON-NLS-1$ $NON-NLS-2$ $NON-NLS-3$
-                }
-
-                return builder.toString();
-            }
-        } catch (Exception e) { // NOSONAR We handle it through return message
-            log.debug("Exception extracting from '{}' with JSON Path expression '{}'", textToParse, jsonPathExpression);
-            return "Exception: " + e.getMessage(); //$NON-NLS-1$
-        }
-    }
-
-    private List<Object> extractWithJSonPath(String textToParse, String expression) throws ParseException {
-        JSONManager jsonManager = new JSONManager();
-        return jsonManager.extractWithJsonPath(textToParse, expression);
+    protected String getExpression() {
+        return expressionField.getText();
     }
 
     /*================= internal business =================*/
@@ -155,28 +125,20 @@ public class RenderAsJsonRenderer implements ResultRenderer, ActionListener {
         jsonDataField.setCaretPosition(0);
     }
 
-
-    /** {@inheritDoc} */
-    @Override
-    public String toString() {
-        return JMeterUtils.getResString("jsonpath_renderer"); // $NON-NLS-1$
-    }
-
-
     /** {@inheritDoc} */
     @Override
     public void setupTabPane() {
          // Add json-path tester pane
-        if (rightSide.indexOfTab(JMeterUtils.getResString("jsonpath_tester_title")) < 0) { // $NON-NLS-1$
-            rightSide.addTab(JMeterUtils.getResString("jsonpath_tester_title"), jsonWithJSonPathPanel); // $NON-NLS-1$
+        if (rightSide.indexOfTab(getTabLabel()) < 0) { // $NON-NLS-1$
+            rightSide.addTab(getTabLabel(), jsonWithExtractorPanel); // $NON-NLS-1$
         }
         clearData();
     }
 
     /**
-     * @return JSON PATH Tester panel
+     * @return Extractor panel
      */
-    private JPanel createJSonPathExtractorPanel() {
+    private JPanel createExtractorPanel() {
         jsonDataField = JSyntaxTextArea.getInstance(50, 80, true);
         jsonDataField.setCodeFoldingEnabled(true);
         jsonDataField.setEditable(false);
@@ -193,7 +155,7 @@ public class RenderAsJsonRenderer implements ResultRenderer, ActionListener {
         JPanel panel = new JPanel(new BorderLayout(0, 5));
 
         JSplitPane mainSplit = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
-                jsonDataPane, createJSonPathExtractorTasksPanel());
+                jsonDataPane, createTechnologyExtractorTasksPanel());
         mainSplit.setDividerLocation(0.6d);
         mainSplit.setOneTouchExpandable(true);
         panel.add(mainSplit, BorderLayout.CENTER);
@@ -201,32 +163,32 @@ public class RenderAsJsonRenderer implements ResultRenderer, ActionListener {
     }
 
     /**
-     * Create the JSON PATH task pane
+     * Create the extractor task pane
      *
-     * @return JSON PATH task pane
+     * @return extractor task pane
      */
-    private JPanel createJSonPathExtractorTasksPanel() {
+    private JPanel createTechnologyExtractorTasksPanel() {
         JPanel jsonPathActionPanel = new JPanel();
         jsonPathActionPanel.setLayout(new BoxLayout(jsonPathActionPanel, BoxLayout.X_AXIS));
         Border margin = new EmptyBorder(5, 5, 0, 5);
         jsonPathActionPanel.setBorder(margin);
-        jsonPathExpressionField = new JLabeledTextField(JMeterUtils.getResString("jsonpath_tester_field")); // $NON-NLS-1$
-        jsonPathActionPanel.add(jsonPathExpressionField, BorderLayout.WEST);
+        expressionField = new JLabeledTextField(getExpressionLabel()); // $NON-NLS-1$
+        jsonPathActionPanel.add(expressionField, BorderLayout.WEST);
 
-        JButton jsonPathTester = new JButton(JMeterUtils.getResString("jsonpath_tester_button_test")); // $NON-NLS-1$
-        jsonPathTester.setActionCommand(JSONPATH_TESTER_COMMAND);
-        jsonPathTester.addActionListener(this);
-        jsonPathActionPanel.add(jsonPathTester, BorderLayout.EAST);
+        JButton testerButton = new JButton(getTestButtonLabel()); // $NON-NLS-1$
+        testerButton.setActionCommand(TESTER_COMMAND);
+        testerButton.addActionListener(this);
+        jsonPathActionPanel.add(testerButton, BorderLayout.EAST);
 
-        jsonPathResultField = new JTextArea();
-        jsonPathResultField.setEditable(false);
-        jsonPathResultField.setLineWrap(true);
-        jsonPathResultField.setWrapStyleWord(true);
-        jsonPathResultField.setMinimumSize(new Dimension(100, 150));
+        resultField = new JTextArea();
+        resultField.setEditable(false);
+        resultField.setLineWrap(true);
+        resultField.setWrapStyleWord(true);
+        resultField.setMinimumSize(new Dimension(100, 150));
 
         JPanel jsonPathTasksPanel = new JPanel(new BorderLayout(0, 5));
         jsonPathTasksPanel.add(jsonPathActionPanel, BorderLayout.NORTH);
-        jsonPathTasksPanel.add(GuiUtils.makeScrollPane(jsonPathResultField), BorderLayout.CENTER);
+        jsonPathTasksPanel.add(GuiUtils.makeScrollPane(resultField), BorderLayout.CENTER);
 
         return jsonPathTasksPanel;
     }
@@ -255,7 +217,7 @@ public class RenderAsJsonRenderer implements ResultRenderer, ActionListener {
     @Override
     public void renderImage(SampleResult sampleResult) {
         clearData();
-        jsonDataField.setText(JMeterUtils.getResString("jsonpath_render_no_text")); // $NON-NLS-1$
+        jsonDataField.setText(JMeterUtils.getResString("render_no_text")); // $NON-NLS-1$
     }
 
     /** {@inheritDoc} */
@@ -264,4 +226,59 @@ public class RenderAsJsonRenderer implements ResultRenderer, ActionListener {
         // NOOP
     }
 
+    /**
+     * @return Tab label
+     */
+    protected abstract String getTabLabel();
+
+    /**
+     * @return Test button label
+     */
+    protected abstract String getTestButtonLabel();
+
+    /**
+     * @return The label for the technology expression
+     */
+    protected abstract String getExpressionLabel();
+
+    /**
+     * @param textToParse String of the response to process
+     * @return the extracted values using the technology
+     */
+    protected abstract String process(String textToParse);
+
+    /**
+     * @return the rightSide
+     */
+    protected JTabbedPane getRightSide() {
+        return rightSide;
+    }
+
+    /**
+     * @return the jsonWithExtractorPanel
+     */
+    protected JPanel getJsonWithExtractorPanel() {
+        return jsonWithExtractorPanel;
+    }
+
+    /**
+     * @return the jsonDataField
+     */
+    protected JSyntaxTextArea getJsonDataField() {
+        return jsonDataField;
+    }
+
+    /**
+     * @return the expressionField
+     */
+    protected JLabeledTextField getExpressionField() {
+        return expressionField;
+    }
+
+    /**
+     * @return the resultField
+     */
+    protected JTextArea getResultField() {
+        return resultField;
+    }
 }
diff --git a/src/components/src/main/java/org/apache/jmeter/extractor/json/render/RenderAsJmesPathRenderer.java b/src/components/src/main/java/org/apache/jmeter/extractor/json/render/RenderAsJmesPathRenderer.java
new file mode 100644
index 0000000..e4a9004
--- /dev/null
+++ b/src/components/src/main/java/org/apache/jmeter/extractor/json/render/RenderAsJmesPathRenderer.java
@@ -0,0 +1,93 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.jmeter.extractor.json.render;
+
+import org.apache.jmeter.extractor.json.jmespath.JMESPathCache;
+import org.apache.jmeter.util.JMeterUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+
+/**
+ * Implement ResultsRender for JMES Path tester
+ * @since 5.2
+ */
+public class RenderAsJmesPathRenderer extends AbstractRenderAsJsonRenderer {
+    private static final Logger log = LoggerFactory.getLogger(RenderAsJmesPathRenderer.class);
+    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
+
+    @Override
+    protected String getTabLabel() {
+        return JMeterUtils.getResString("jmespath_tester_title");
+    }
+
+    @Override
+    protected String getTestButtonLabel() {
+        return JMeterUtils.getResString("jmespath_tester_button_test");
+    }
+
+    @Override
+    protected String getExpressionLabel() {
+        return JMeterUtils.getResString("jmespath_tester_field");
+    }
+
+    @Override
+    protected String process(String textToParse) {
+        String expression = getExpression();
+        try {
+            JsonNode actualObj = OBJECT_MAPPER.readValue(textToParse, JsonNode.class);
+            JsonNode result = JMESPathCache.getInstance().get(expression).search(actualObj);
+            if (result.isNull()) {
+                return NO_MATCH; //$NON-NLS-1$
+            } else {
+                StringBuilder builder = new StringBuilder();
+                int i = 0;
+                if (result.isArray()) {
+                    for (JsonNode element : (ArrayNode) result) {
+                        builder.append("Result[").append(i++).append("]=").append(writeJsonNode(OBJECT_MAPPER, element)).append("\n");
+                    }
+                } else {
+                    builder.append("Result[").append(i++).append("]=").append(writeJsonNode(OBJECT_MAPPER, result)).append("\n");
+                }
+                return builder.toString();
+            }
+        } catch (Exception e) { // NOSONAR We handle it through return message
+            log.debug("Exception extracting from '{}' with expression '{}'", textToParse, expression);
+            return "Exception: " + e.getMessage(); //$NON-NLS-1$
+        }
+    }
+
+    private static String writeJsonNode(ObjectMapper mapper, JsonNode element) throws JsonProcessingException {
+        if (element.isTextual()) {
+            return element.asText();
+        } else {
+            return mapper.writeValueAsString(element);
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        return JMeterUtils.getResString("jmespath_renderer"); // $NON-NLS-1$
+    }
+}
diff --git a/src/components/src/main/java/org/apache/jmeter/extractor/json/render/RenderAsJsonRenderer.java b/src/components/src/main/java/org/apache/jmeter/extractor/json/render/RenderAsJsonRenderer.java
index 5205d41..95960fb 100644
--- a/src/components/src/main/java/org/apache/jmeter/extractor/json/render/RenderAsJsonRenderer.java
+++ b/src/components/src/main/java/org/apache/jmeter/extractor/json/render/RenderAsJsonRenderer.java
@@ -18,109 +18,39 @@
 
 package org.apache.jmeter.extractor.json.render;
 
-import java.awt.BorderLayout;
-import java.awt.Color;
-import java.awt.Dimension;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.text.ParseException;
 import java.util.List;
 
-import javax.swing.BoxLayout;
-import javax.swing.JButton;
-import javax.swing.JPanel;
-import javax.swing.JScrollPane;
-import javax.swing.JSplitPane;
-import javax.swing.JTabbedPane;
-import javax.swing.JTextArea;
-import javax.swing.border.Border;
-import javax.swing.border.EmptyBorder;
-
 import org.apache.jmeter.extractor.json.jsonpath.JSONManager;
-import org.apache.jmeter.gui.util.JSyntaxTextArea;
-import org.apache.jmeter.gui.util.JTextScrollPane;
-import org.apache.jmeter.samplers.SampleResult;
 import org.apache.jmeter.util.JMeterUtils;
-import org.apache.jmeter.visualizers.RenderAsJSON;
-import org.apache.jmeter.visualizers.ResultRenderer;
-import org.apache.jmeter.visualizers.ViewResultsFullVisualizer;
-import org.apache.jorphan.gui.GuiUtils;
-import org.apache.jorphan.gui.JLabeledTextField;
-import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-
 /**
  * Implement ResultsRender for JSON Path tester
  * @since 3.0
  */
-public class RenderAsJsonRenderer implements ResultRenderer, ActionListener {
-
+public class RenderAsJsonRenderer extends AbstractRenderAsJsonRenderer {
     private static final Logger log = LoggerFactory.getLogger(RenderAsJsonRenderer.class);
-    private static final String NO_MATCH = "NO MATCH"; //$NON-NLS-1$
-    private static final String TAB_SEPARATOR = "    "; //$NON-NLS-1$
-
-    private static final String JSONPATH_TESTER_COMMAND = "jsonpath_tester"; // $NON-NLS-1$
-
-    private JPanel jsonWithJSonPathPanel;
-
-    private JSyntaxTextArea jsonDataField;
-
-    private JLabeledTextField jsonPathExpressionField;
-
-    private JTextArea jsonPathResultField;
 
-    private JTabbedPane rightSide;
-
-    private SampleResult sampleResult;
-
-    /** {@inheritDoc} */
     @Override
-    public void clearData() {
-        this.jsonDataField.setText(""); // $NON-NLS-1$
-        // don't set empty to keep json path
-        this.jsonPathResultField.setText(""); // $NON-NLS-1$
+    protected String getTabLabel() {
+        return JMeterUtils.getResString("jsonpath_tester_title");
     }
 
-    /** {@inheritDoc} */
     @Override
-    public void init() {
-        // Create the panels for the json tab
-        jsonWithJSonPathPanel = createJSonPathExtractorPanel();
+    protected String getTestButtonLabel() {
+        return JMeterUtils.getResString("jsonpath_tester_button_test");
     }
 
-    /**
-     * Display the response as text or as rendered HTML. Change the text on the
-     * button appropriate to the current display.
-     *
-     * @param e the ActionEvent being processed
-     */
     @Override
-    public void actionPerformed(ActionEvent e) {
-        String command = e.getActionCommand();
-        if ((sampleResult != null) && (JSONPATH_TESTER_COMMAND.equals(command))) {
-            String response = jsonDataField.getText();
-            executeAndJSonPathTester(response);
-        }
-    }
-
-    /**
-     * Launch json path engine to parse a input text
-     * @param textToParse
-     */
-    private void executeAndJSonPathTester(String textToParse) {
-        if (textToParse != null && textToParse.length() > 0
-                && this.jsonPathExpressionField.getText().length() > 0) {
-            this.jsonPathResultField.setText(process(textToParse));
-            this.jsonPathResultField.setCaretPosition(0); // go to first line
-        }
+    protected String getExpressionLabel() {
+        return JMeterUtils.getResString("jsonpath_tester_field");
     }
 
-    private String process(String textToParse) {
-        String jsonPathExpression = jsonPathExpressionField.getText();
+    protected String process(String textToParse) {
+        String expression = getExpression();
         try {
-            List<Object> matchStrings = extractWithJSonPath(textToParse, jsonPathExpression);
+            List<Object> matchStrings = extractWithTechnology(textToParse, expression);
             if (matchStrings.isEmpty()) {
                 return NO_MATCH; //$NON-NLS-1$
             } else {
@@ -135,133 +65,19 @@ public class RenderAsJsonRenderer implements ResultRenderer, ActionListener {
                 return builder.toString();
             }
         } catch (Exception e) { // NOSONAR We handle it through return message
-            log.debug("Exception extracting from '{}' with JSON Path expression '{}'", textToParse, jsonPathExpression);
+            log.debug("Exception extracting from '{}' with expression '{}'", textToParse, expression);
             return "Exception: " + e.getMessage(); //$NON-NLS-1$
         }
     }
 
-    private List<Object> extractWithJSonPath(String textToParse, String expression) throws ParseException {
+    private List<Object> extractWithTechnology(String textToParse, String expression) throws Exception {
         JSONManager jsonManager = new JSONManager();
         return jsonManager.extractWithJsonPath(textToParse, expression);
     }
 
-    /*================= internal business =================*/
-
-    /** {@inheritDoc} */
-    @Override
-    public void renderResult(SampleResult sampleResult) {
-        String response = ViewResultsFullVisualizer.getResponseAsString(sampleResult);
-        jsonDataField.setText(response == null ? "" : RenderAsJSON.prettyJSON(response, TAB_SEPARATOR));  //$NON-NLS-1$
-        jsonDataField.setCaretPosition(0);
-    }
-
-
     /** {@inheritDoc} */
     @Override
     public String toString() {
         return JMeterUtils.getResString("jsonpath_renderer"); // $NON-NLS-1$
     }
-
-
-    /** {@inheritDoc} */
-    @Override
-    public void setupTabPane() {
-         // Add json-path tester pane
-        if (rightSide.indexOfTab(JMeterUtils.getResString("jsonpath_tester_title")) < 0) { // $NON-NLS-1$
-            rightSide.addTab(JMeterUtils.getResString("jsonpath_tester_title"), jsonWithJSonPathPanel); // $NON-NLS-1$
-        }
-        clearData();
-    }
-
-    /**
-     * @return JSON PATH Tester panel
-     */
-    private JPanel createJSonPathExtractorPanel() {
-        jsonDataField = JSyntaxTextArea.getInstance(50, 80, true);
-        jsonDataField.setCodeFoldingEnabled(true);
-        jsonDataField.setEditable(false);
-        jsonDataField.setBracketMatchingEnabled(false);
-        jsonDataField.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JSON);
-        jsonDataField.setLanguage(SyntaxConstants.SYNTAX_STYLE_JSON);
-        jsonDataField.setLineWrap(true);
-        jsonDataField.setWrapStyleWord(true);
-
-
-        JScrollPane jsonDataPane = JTextScrollPane.getInstance(jsonDataField, true);
-        jsonDataPane.setPreferredSize(new Dimension(100, 200));
-
-        JPanel panel = new JPanel(new BorderLayout(0, 5));
-
-        JSplitPane mainSplit = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
-                jsonDataPane, createJSonPathExtractorTasksPanel());
-        mainSplit.setDividerLocation(0.6d);
-        mainSplit.setOneTouchExpandable(true);
-        panel.add(mainSplit, BorderLayout.CENTER);
-        return panel;
-    }
-
-    /**
-     * Create the JSON PATH task pane
-     *
-     * @return JSON PATH task pane
-     */
-    private JPanel createJSonPathExtractorTasksPanel() {
-        JPanel jsonPathActionPanel = new JPanel();
-        jsonPathActionPanel.setLayout(new BoxLayout(jsonPathActionPanel, BoxLayout.X_AXIS));
-        Border margin = new EmptyBorder(5, 5, 0, 5);
-        jsonPathActionPanel.setBorder(margin);
-        jsonPathExpressionField = new JLabeledTextField(JMeterUtils.getResString("jsonpath_tester_field")); // $NON-NLS-1$
-        jsonPathActionPanel.add(jsonPathExpressionField, BorderLayout.WEST);
-
-        JButton jsonPathTester = new JButton(JMeterUtils.getResString("jsonpath_tester_button_test")); // $NON-NLS-1$
-        jsonPathTester.setActionCommand(JSONPATH_TESTER_COMMAND);
-        jsonPathTester.addActionListener(this);
-        jsonPathActionPanel.add(jsonPathTester, BorderLayout.EAST);
-
-        jsonPathResultField = new JTextArea();
-        jsonPathResultField.setEditable(false);
-        jsonPathResultField.setLineWrap(true);
-        jsonPathResultField.setWrapStyleWord(true);
-        jsonPathResultField.setMinimumSize(new Dimension(100, 150));
-
-        JPanel jsonPathTasksPanel = new JPanel(new BorderLayout(0, 5));
-        jsonPathTasksPanel.add(jsonPathActionPanel, BorderLayout.NORTH);
-        jsonPathTasksPanel.add(GuiUtils.makeScrollPane(jsonPathResultField), BorderLayout.CENTER);
-
-        return jsonPathTasksPanel;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public synchronized void setRightSide(JTabbedPane side) {
-        rightSide = side;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public synchronized void setSamplerResult(Object userObject) {
-        if (userObject instanceof SampleResult) {
-            sampleResult = (SampleResult) userObject;
-        }
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public void setLastSelectedTab(int index) {
-        // nothing to do
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public void renderImage(SampleResult sampleResult) {
-        clearData();
-        jsonDataField.setText(JMeterUtils.getResString("jsonpath_render_no_text")); // $NON-NLS-1$
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public void setBackgroundColor(Color backGround) {
-        // NOOP
-    }
-
 }
diff --git a/src/components/src/test/groovy/org/apache/jmeter/extractor/json/render/RenderAsJsonRendererSpec.groovy b/src/components/src/test/groovy/org/apache/jmeter/extractor/json/render/RenderAsJmesPathRendererSpec.groovy
similarity index 82%
copy from src/components/src/test/groovy/org/apache/jmeter/extractor/json/render/RenderAsJsonRendererSpec.groovy
copy to src/components/src/test/groovy/org/apache/jmeter/extractor/json/render/RenderAsJmesPathRendererSpec.groovy
index fa252f9..a522141 100644
--- a/src/components/src/test/groovy/org/apache/jmeter/extractor/json/render/RenderAsJsonRendererSpec.groovy
+++ b/src/components/src/test/groovy/org/apache/jmeter/extractor/json/render/RenderAsJmesPathRendererSpec.groovy
@@ -18,7 +18,7 @@
 package org.apache.jmeter.extractor.json.render
 
 import org.apache.jmeter.samplers.SampleResult
-import org.apache.jmeter.extractor.json.render.RenderAsJsonRenderer
+import org.apache.jmeter.extractor.json.render.RenderAsJmesPathRenderer
 import org.apache.jmeter.junit.spock.JMeterSpec
 import org.apache.jmeter.util.JMeterUtils
 import javax.swing.JTabbedPane
@@ -26,15 +26,15 @@ import org.apache.jmeter.junit.categories.NeedGuiTests
 import org.junit.experimental.categories.Category
 import spock.lang.IgnoreIf
 
-class RenderAsJsonRendererSpec extends JMeterSpec {
-    def sut = new RenderAsJsonRenderer()
+class RenderAsJmesPathRendererSpec extends JMeterSpec {
+    def sut = new RenderAsJmesPathRenderer()
 
     def "init of component doesn't fail"() {
         when:
             sut.init()
         then:
             noExceptionThrown()
-            sut.jsonWithJSonPathPanel != null;
+            sut.jsonWithExtractorPanel != null;
     }
 
     @IgnoreIf({ JMeterSpec.isHeadless() })
@@ -45,7 +45,7 @@ class RenderAsJsonRendererSpec extends JMeterSpec {
         when:
             sut.renderImage(sampleResult)
         then:
-            sut.jsonDataField.getText() == JMeterUtils.getResString("jsonpath_render_no_text")
+            sut.jsonDataField.getText() == JMeterUtils.getResString("render_no_text")
     }
 
     def "render null Response"() {
@@ -81,29 +81,29 @@ class RenderAsJsonRendererSpec extends JMeterSpec {
     def "execute '#expression' on '#input' results into '#output'"() {
         given:
             sut.init();
-            sut.jsonPathExpressionField.setText(expression);
+            sut.expressionField.setText(expression);
             def sampleResult = new SampleResult();
         when:
-            sut.executeAndJSonPathTester(input);
+            sut.executeTester(input);
         then:
-            output == sut.jsonPathResultField.getText()
+            output == sut.resultField.getText()
         where:
             input               | expression          | output
-            "{name:\"Ludwig\",age: 23,city: \"Bonn\"}"   | "\$..name"           | "Result[0]=Ludwig\n"
-            "This is not json"  | "\$..name" | "NO MATCH"
-            "{name:\"Ludwig\",age: 23,city: \"Bonn\"}" | "\$.." | "Exception: Path must not end with a '.' or '..'"
+            "{\"name\":\"Ludwig\",\"age\": 23,\"city\": \"Bonn\"}"   | "name"           | "Result[0]=Ludwig\n"
+            "{\"name\":\"Ludwig\",\"age\": 23,\"city\": \"Bonn\"}"   | "age"           | "Result[0]=23\n"
+            "{\"name\":\"Ludwig\",\"age\": 23,\"city\": \"Bonn\"}" | "name1" | "NO MATCH"
     }
 
     def "clearData clears expected fields"() {
         given:
             sut.init()
             sut.jsonDataField.setText("blabla")
-            sut.jsonPathResultField.setText("blabla")
+            sut.resultField.setText("blabla")
         when:
             sut.clearData()
         then:
             sut.jsonDataField.getText() == ""
-            sut.jsonPathResultField.getText() == ""
+            sut.resultField.getText() == ""
     }
 
     def "setupTabPane adds the tab to rightSide"() {
@@ -116,7 +116,7 @@ class RenderAsJsonRendererSpec extends JMeterSpec {
         then:
             sut.rightSide.getTabCount() == 1
             // Investigate why it's failing
-            // sut.rightSide.getTabComponentAt(0) == sut.jsonWithJSonPathPanel
+            // sut.rightSide.getTabComponentAt(0) == sut.jsonWithExtractorPanel
     }
 
     def "setupTabPane called twice does not add twice the tab"() {
diff --git a/src/components/src/test/groovy/org/apache/jmeter/extractor/json/render/RenderAsJsonRendererSpec.groovy b/src/components/src/test/groovy/org/apache/jmeter/extractor/json/render/RenderAsJsonRendererSpec.groovy
index fa252f9..5774388 100644
--- a/src/components/src/test/groovy/org/apache/jmeter/extractor/json/render/RenderAsJsonRendererSpec.groovy
+++ b/src/components/src/test/groovy/org/apache/jmeter/extractor/json/render/RenderAsJsonRendererSpec.groovy
@@ -34,7 +34,7 @@ class RenderAsJsonRendererSpec extends JMeterSpec {
             sut.init()
         then:
             noExceptionThrown()
-            sut.jsonWithJSonPathPanel != null;
+            sut.jsonWithExtractorPanel != null;
     }
 
     @IgnoreIf({ JMeterSpec.isHeadless() })
@@ -45,7 +45,7 @@ class RenderAsJsonRendererSpec extends JMeterSpec {
         when:
             sut.renderImage(sampleResult)
         then:
-            sut.jsonDataField.getText() == JMeterUtils.getResString("jsonpath_render_no_text")
+            sut.jsonDataField.getText() == JMeterUtils.getResString("render_no_text")
     }
 
     def "render null Response"() {
@@ -81,12 +81,12 @@ class RenderAsJsonRendererSpec extends JMeterSpec {
     def "execute '#expression' on '#input' results into '#output'"() {
         given:
             sut.init();
-            sut.jsonPathExpressionField.setText(expression);
+            sut.expressionField.setText(expression);
             def sampleResult = new SampleResult();
         when:
-            sut.executeAndJSonPathTester(input);
+            sut.executeTester(input);
         then:
-            output == sut.jsonPathResultField.getText()
+            output == sut.resultField.getText()
         where:
             input               | expression          | output
             "{name:\"Ludwig\",age: 23,city: \"Bonn\"}"   | "\$..name"           | "Result[0]=Ludwig\n"
@@ -98,12 +98,12 @@ class RenderAsJsonRendererSpec extends JMeterSpec {
         given:
             sut.init()
             sut.jsonDataField.setText("blabla")
-            sut.jsonPathResultField.setText("blabla")
+            sut.resultField.setText("blabla")
         when:
             sut.clearData()
         then:
             sut.jsonDataField.getText() == ""
-            sut.jsonPathResultField.getText() == ""
+            sut.resultField.getText() == ""
     }
 
     def "setupTabPane adds the tab to rightSide"() {
@@ -116,7 +116,7 @@ class RenderAsJsonRendererSpec extends JMeterSpec {
         then:
             sut.rightSide.getTabCount() == 1
             // Investigate why it's failing
-            // sut.rightSide.getTabComponentAt(0) == sut.jsonWithJSonPathPanel
+            // sut.rightSide.getTabComponentAt(0) == sut.jsonWithExtractorPanel
     }
 
     def "setupTabPane called twice does not add twice the tab"() {
diff --git a/src/core/src/main/resources/org/apache/jmeter/resources/messages.properties b/src/core/src/main/resources/org/apache/jmeter/resources/messages.properties
index 97c0120..1bc0b75 100644
--- a/src/core/src/main/resources/org/apache/jmeter/resources/messages.properties
+++ b/src/core/src/main/resources/org/apache/jmeter/resources/messages.properties
@@ -586,6 +586,10 @@ jmespath_assertion_regex=Match as regular expression
 jmespath_assertion_expected_value=Expected Value\:
 jmespath_assertion_null=Expect null
 jmespath_assertion_invert=Invert assertion (will fail if above conditions met)
+jmespath_renderer=JMESPath Tester
+jmespath_tester_button_test=Test
+jmespath_tester_field=JMESPath expression
+jmespath_tester_title=JMESPath Tester
 jndi_config_title=JNDI Configuration
 jndi_lookup_name=Remote Interface
 jndi_lookup_title=JNDI Lookup Configuration
@@ -604,7 +608,7 @@ jsonpath_renderer=JSON Path Tester
 jsonpath_tester_title=JSON Path Tester
 jsonpath_tester_field=JSON Path Expression
 jsonpath_tester_button_test=Test
-jsonpath_render_no_text=No Text
+render_no_text=No Text
 json_post_processor_title=JSON Extractor
 json_assertion_title=JSON Assertion
 json_assertion_path=Assert JSON Path exists\:
diff --git a/src/core/src/main/resources/org/apache/jmeter/resources/messages_fr.properties b/src/core/src/main/resources/org/apache/jmeter/resources/messages_fr.properties
index 16de466..d431697 100644
--- a/src/core/src/main/resources/org/apache/jmeter/resources/messages_fr.properties
+++ b/src/core/src/main/resources/org/apache/jmeter/resources/messages_fr.properties
@@ -580,6 +580,10 @@ jmespath_assertion_regex=Correspondance selon expression régulière
 jmespath_assertion_expected_value==Valeur attendue\:
 jmespath_assertion_null=Valeur nulle attendue
 jmespath_assertion_invert=Inverser l'assertion (échouera si les conditions ci-dessus sont remplies)
+jmespath_renderer=Testeur JMESPath
+jmespath_tester_button_test=Tester
+jmespath_tester_field=Expression JMESPath
+jmespath_tester_title=Testeur JMESPath
 jndi_config_title=Configuration JNDI
 jndi_lookup_name=Interface remote
 jndi_lookup_title=Configuration Lookup JNDI
@@ -602,7 +606,7 @@ json_assertion_regex=Correspondance selon expression régulière
 json_assertion_title=Assertion JSON
 json_assertion_validation=Vérification supplémentaire
 json_post_processor_title=Extracteur JSON
-jsonpath_render_no_text=Pas de Texte
+render_no_text=Pas de Texte
 jsonpath_renderer=Testeur JSON Path
 jsonpath_tester_button_test=Tester
 jsonpath_tester_field=Expression JSON Path
diff --git a/xdocs/changes.xml b/xdocs/changes.xml
index ff876c3..9758ff2 100644
--- a/xdocs/changes.xml
+++ b/xdocs/changes.xml
@@ -100,6 +100,7 @@ to view the last release notes of version 5.1.1.
 <h3>Listeners</h3>
 <ul>
     <li><bug>63720</bug>BackendListener: InfluxDBBackendListenerClient Add support for InfluxDB 2. Contributed by Jakub Bednář (https://github.com/bednar)</li>
+    <li><bug>63770</bug>View Results Tree: Add JMESPath Tester. Contributed by Ubik Load Pack (support at ubikloadpack.com)</li>
 </ul>
 
 <h3>Timers, Assertions, Config, Pre- &amp; Post-Processors</h3>
diff --git a/xdocs/usermanual/component_reference.xml b/xdocs/usermanual/component_reference.xml
index 0ea60f2..031351a 100644
--- a/xdocs/usermanual/component_reference.xml
+++ b/xdocs/usermanual/component_reference.xml
@@ -2804,6 +2804,9 @@ may download images, style-sheets, etc. referenced by the HTML code.
 <tr><td><code>JSON Path Tester</code></td>
 <td>The <i>JSON Path Tester view</i> will let you test your JSON-PATH expressions and see the extracted data from a particular response.
 <br/></td></tr>
+<tr><td><code>JMESPath Tester</code></td>
+<td>The <i>JMESPath Tester view</i> will let you test your <a href="http://jmespath.org/">JMESPath</a> expressions and see the extracted data from a particular response.
+<br/></td></tr>
 <tr><td><code>Regexp Tester</code></td>
 <td>The <i>Regexp Tester view</i> only works for text responses. It shows the plain text in the upper panel.
 The "<code>Test</code>" button allows the user to apply the Regular Expression to the upper panel and the results