123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217 |
- import { Observable } from "rxjs"
- import { filter } from "rxjs/operators"
- import { chain, right, TaskEither } from "fp-ts/lib/TaskEither"
- import { flow, pipe } from "fp-ts/function"
- import * as O from "fp-ts/Option"
- import * as A from "fp-ts/Array"
- import { Environment } from "@hoppscotch/data"
- import {
- SandboxTestResult,
- runTestScript,
- TestDescriptor,
- } from "@hoppscotch/js-sandbox"
- import { isRight } from "fp-ts/Either"
- import cloneDeep from "lodash/cloneDeep"
- import {
- getCombinedEnvVariables,
- getFinalEnvsFromPreRequest,
- } from "./preRequest"
- import { getEffectiveRESTRequest } from "./utils/EffectiveURL"
- import { HoppRESTResponse } from "./types/HoppRESTResponse"
- import { createRESTNetworkRequestStream } from "./network"
- import { HoppTestData, HoppTestResult } from "./types/HoppTestResult"
- import { isJSONContentType } from "./utils/contenttypes"
- import { getRESTRequest, setRESTTestResults } from "~/newstore/RESTSession"
- import {
- environmentsStore,
- getCurrentEnvironment,
- getEnviroment,
- getGlobalVariables,
- setGlobalEnvVariables,
- updateEnvironment,
- } from "~/newstore/environments"
- const getTestableBody = (
- res: HoppRESTResponse & { type: "success" | "fail" }
- ) => {
- const contentTypeHeader = res.headers.find(
- (h) => h.key.toLowerCase() === "content-type"
- )
- const rawBody = new TextDecoder("utf-8")
- .decode(res.body)
- .replaceAll("\x00", "")
- const x = pipe(
- // This pipeline just decides whether JSON parses or not
- contentTypeHeader && isJSONContentType(contentTypeHeader.value)
- ? O.of(rawBody)
- : O.none,
- // Try parsing, if failed, go to the fail option
- O.chain((body) => O.tryCatch(() => JSON.parse(body))),
- // If JSON, return that (get), else return just the body string (else)
- O.getOrElse<any | string>(() => rawBody)
- )
- return x
- }
- const combineEnvVariables = (env: {
- global: Environment["variables"]
- selected: Environment["variables"]
- }) => [...env.selected, ...env.global]
- export const runRESTRequest$ = (): TaskEither<
- string | Error,
- Observable<HoppRESTResponse>
- > =>
- pipe(
- getFinalEnvsFromPreRequest(
- getRESTRequest().preRequestScript,
- getCombinedEnvVariables()
- ),
- chain((envs) => {
- const effectiveRequest = getEffectiveRESTRequest(getRESTRequest(), {
- name: "Env",
- variables: combineEnvVariables(envs),
- })
- const stream = createRESTNetworkRequestStream(effectiveRequest)
- // Run Test Script when request ran successfully
- const subscription = stream
- .pipe(filter((res) => res.type === "success" || res.type === "fail"))
- .subscribe(async (res) => {
- if (res.type === "success" || res.type === "fail") {
- const runResult = await runTestScript(res.req.testScript, envs, {
- status: res.statusCode,
- body: getTestableBody(res),
- headers: res.headers,
- })()
- if (isRight(runResult)) {
- setRESTTestResults(translateToSandboxTestResults(runResult.right))
- setGlobalEnvVariables(runResult.right.envs.global)
- if (environmentsStore.value.currentEnvironmentIndex !== -1) {
- const env = getEnviroment(
- environmentsStore.value.currentEnvironmentIndex
- )
- updateEnvironment(
- environmentsStore.value.currentEnvironmentIndex,
- {
- name: env.name,
- variables: runResult.right.envs.selected,
- }
- )
- }
- } else {
- setRESTTestResults({
- description: "",
- expectResults: [],
- tests: [],
- envDiff: {
- global: {
- additions: [],
- deletions: [],
- updations: [],
- },
- selected: {
- additions: [],
- deletions: [],
- updations: [],
- },
- },
- scriptError: true,
- })
- }
- subscription.unsubscribe()
- }
- })
- return right(stream)
- })
- )
- const getAddedEnvVariables = (
- current: Environment["variables"],
- updated: Environment["variables"]
- ) => updated.filter((x) => current.findIndex((y) => y.key === x.key) === -1)
- const getRemovedEnvVariables = (
- current: Environment["variables"],
- updated: Environment["variables"]
- ) => current.filter((x) => updated.findIndex((y) => y.key === x.key) === -1)
- const getUpdatedEnvVariables = (
- current: Environment["variables"],
- updated: Environment["variables"]
- ) =>
- pipe(
- updated,
- A.filterMap(
- flow(
- O.of,
- O.bindTo("env"),
- O.bind("index", ({ env }) =>
- pipe(
- current.findIndex((x) => x.key === env.key),
- O.fromPredicate((x) => x !== -1)
- )
- ),
- O.chain(
- O.fromPredicate(
- ({ env, index }) => env.value !== current[index].value
- )
- ),
- O.map(({ env, index }) => ({
- ...env,
- previousValue: current[index].value,
- }))
- )
- )
- )
- function translateToSandboxTestResults(
- testDesc: SandboxTestResult
- ): HoppTestResult {
- const translateChildTests = (child: TestDescriptor): HoppTestData => {
- return {
- description: child.descriptor,
- expectResults: child.expectResults,
- tests: child.children.map(translateChildTests),
- }
- }
- const globals = cloneDeep(getGlobalVariables())
- const env = cloneDeep(getCurrentEnvironment())
- return {
- description: "",
- expectResults: testDesc.tests.expectResults,
- tests: testDesc.tests.children.map(translateChildTests),
- scriptError: false,
- envDiff: {
- global: {
- additions: getAddedEnvVariables(globals, testDesc.envs.global),
- deletions: getRemovedEnvVariables(globals, testDesc.envs.global),
- updations: getUpdatedEnvVariables(globals, testDesc.envs.global),
- },
- selected: {
- additions: getAddedEnvVariables(env.variables, testDesc.envs.selected),
- deletions: getRemovedEnvVariables(
- env.variables,
- testDesc.envs.selected
- ),
- updations: getUpdatedEnvVariables(
- env.variables,
- testDesc.envs.selected
- ),
- },
- },
- }
- }
|