From f544307e2e2b31f5bf5c58e5bb1fb0d314cca568 Mon Sep 17 00:00:00 2001 From: Hassy Veldstra Date: Wed, 5 Jul 2023 09:42:55 +0100 Subject: [PATCH] fix(skytrace): improve handling of JSON responses (#1957) - Parse JSON responses and pass them as objects to expectation functions - Ignore JSON parsing errors unless we actually need to use the response (e.g. to pretty-print or for a JSON-specific expectation) --- packages/skytrace/src/commands/ping.ts | 49 ++++++++++++++++---------- 1 file changed, 31 insertions(+), 18 deletions(-) diff --git a/packages/skytrace/src/commands/ping.ts b/packages/skytrace/src/commands/ping.ts index 1ed7ae9ff1..ab451ad3e4 100644 --- a/packages/skytrace/src/commands/ping.ts +++ b/packages/skytrace/src/commands/ping.ts @@ -433,31 +433,44 @@ class PingCommand extends Command { const isJSON = contentType.match(/json/gi); const isXML = contentType.match(/html/gi) || contentType.match(/xml/gi); - if (flags.showBody) { - let language; - if (isJSON) { - language = 'json'; - } - if (isXML) { - language = 'html'; + let body = context.vars.body; + let isBodyValidJSON = false; + if (isJSON) { + // Try to parse the body as JSON. Errors are ignored because as a + // general purpose HTTP client we don't want to fail on invalid + // JSON by default - only if the user explicitly or implicitly + // specifies that the body needs to be valid. + try { + body = JSON.parse(context.vars.body); + isBodyValidJSON = true; + } catch (_parseErr) { } + } - if (language) { - let output = context.vars.body; - if (language === 'json' && flags.pretty) { - output = JSON.stringify(JSON.parse(context.vars.body), null, 4); - } - this.log(highlight(output, { language })); - } else { + // If -b is set without -p -- just print the body as-is. + // If -bp is set - pretty-print JSON or XML/HTML, otherwise print the body as-is. + if (flags.showBody) { + if (!flags.pretty) { this.log(context.vars.body); + } else { + if (isJSON) { + if (!isBodyValidJSON) { + this.log(chalk.red('Could not parse body is valid JSON for pretty-printing')); + } else { + this.log(highlight(JSON.stringify(body, null, 4), { language: 'json' })); + } + } else if (isXML) { + this.log(highlight(context.vars.body, { language: 'html' })); + } else { + this.log(context.vars.body); + } } } if (flags.jmespath || flags.cheerio || flags.q) { if (flags.jmespath || (isJSON && flags.q)) { try { - const json = JSON.parse(context.vars.body); - const result = jmespath.search(json, flags.jmespath || flags.query); + const result = jmespath.search(body, flags.jmespath || flags.query); // If our output is piped we want to print the JSON without highlighting: if (process.stdout.isTTY) { @@ -473,7 +486,7 @@ class PingCommand extends Command { } } else if (flags.cheerio || (isXML && flags.query)) { try { - const $ = cheerio.load(context.vars.body); + const $ = cheerio.load(body); const elts = $(flags.cheerio || flags.query).html(); // If our output is piped we want to print the without highlighting: if (process.stdout.isTTY) { @@ -503,7 +516,7 @@ class PingCommand extends Command { let result = expectations[checker].call( this, ex, - context.vars.body, + body, context.vars.req, context.vars.res, {}