RequestRunner.ts 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. import { Observable } from "rxjs"
  2. import { filter } from "rxjs/operators"
  3. import { chain, right, TaskEither } from "fp-ts/lib/TaskEither"
  4. import { pipe } from "fp-ts/function"
  5. import * as O from "fp-ts/Option"
  6. import { runTestScript, TestDescriptor } from "@hoppscotch/js-sandbox"
  7. import { isRight } from "fp-ts/Either"
  8. import {
  9. getCombinedEnvVariables,
  10. getFinalEnvsFromPreRequest,
  11. } from "./preRequest"
  12. import { getEffectiveRESTRequest } from "./utils/EffectiveURL"
  13. import { HoppRESTResponse } from "./types/HoppRESTResponse"
  14. import { createRESTNetworkRequestStream } from "./network"
  15. import { HoppTestData, HoppTestResult } from "./types/HoppTestResult"
  16. import { isJSONContentType } from "./utils/contenttypes"
  17. import { getRESTRequest, setRESTTestResults } from "~/newstore/RESTSession"
  18. const getTestableBody = (res: HoppRESTResponse & { type: "success" }) => {
  19. const contentTypeHeader = res.headers.find(
  20. (h) => h.key.toLowerCase() === "content-type"
  21. )
  22. const rawBody = new TextDecoder("utf-8")
  23. .decode(res.body)
  24. .replaceAll("\x00", "")
  25. const x = pipe(
  26. // This pipeline just decides whether JSON parses or not
  27. contentTypeHeader && isJSONContentType(contentTypeHeader.value)
  28. ? O.of(rawBody)
  29. : O.none,
  30. // Try parsing, if failed, go to the fail option
  31. O.chain((body) => O.tryCatch(() => JSON.parse(body))),
  32. // If JSON, return that (get), else return just the body string (else)
  33. O.getOrElse<any | string>(() => rawBody)
  34. )
  35. return x
  36. }
  37. export const runRESTRequest$ = (): TaskEither<
  38. string,
  39. Observable<HoppRESTResponse>
  40. > =>
  41. pipe(
  42. getFinalEnvsFromPreRequest(
  43. getRESTRequest().preRequestScript,
  44. getCombinedEnvVariables()
  45. ),
  46. chain((envs) => {
  47. const effectiveRequest = getEffectiveRESTRequest(getRESTRequest(), {
  48. name: "Env",
  49. variables: envs,
  50. })
  51. const stream = createRESTNetworkRequestStream(effectiveRequest)
  52. // Run Test Script when request ran successfully
  53. const subscription = stream
  54. .pipe(filter((res) => res.type === "success"))
  55. .subscribe(async (res) => {
  56. if (res.type === "success") {
  57. const runResult = await runTestScript(res.req.testScript, {
  58. status: res.statusCode,
  59. body: getTestableBody(res),
  60. headers: res.headers,
  61. })()
  62. // TODO: Handle script executation fails (isLeft)
  63. if (isRight(runResult)) {
  64. setRESTTestResults(translateToSandboxTestResults(runResult.right))
  65. }
  66. subscription.unsubscribe()
  67. }
  68. })
  69. return right(stream)
  70. })
  71. )
  72. function translateToSandboxTestResults(
  73. testDesc: TestDescriptor
  74. ): HoppTestResult {
  75. const translateChildTests = (child: TestDescriptor): HoppTestData => {
  76. return {
  77. description: child.descriptor,
  78. expectResults: child.expectResults,
  79. tests: child.children.map(translateChildTests),
  80. }
  81. }
  82. return {
  83. expectResults: testDesc.expectResults,
  84. tests: testDesc.children.map(translateChildTests),
  85. }
  86. }