fix: inspections bugs (#3277)
* fix: environment add bug in inspection * chore: add 127.0.0.1 in url inspection * chore: update browserextension inspection help url * fix: team env not showing bug in selector * chore: rework inspector systems to be reactive * chore: handling tab changes gracefully * refactor: move out url interceptor from the platform * chore: add view function in inspector service to get views into the list * fix: interceptors not kicking in on initial load * fix: don't show no internet connection error unless browser deems so * chore: fix tests --------- Co-authored-by: Andrew Bastin <andrewbastin.k@gmail.com>
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
import { TestContainer } from "dioc/testing"
|
||||
import { describe, expect, it, vi } from "vitest"
|
||||
import { ExtensionInspectorService } from "../extension.inspector"
|
||||
import { InspectionService } from "~/services/inspection"
|
||||
import { getDefaultRESTRequest } from "~/helpers/rest/default"
|
||||
import { ref } from "vue"
|
||||
import { ExtensionInterceptorService } from "~/platform/std/interceptors/extension"
|
||||
|
||||
vi.mock("~/modules/i18n", () => ({
|
||||
__esModule: true,
|
||||
getI18n: () => (x: string) => x,
|
||||
}))
|
||||
|
||||
describe("ExtensionInspectorService", () => {
|
||||
it("registers with the inspection service upon initialization", () => {
|
||||
const container = new TestContainer()
|
||||
|
||||
const registerInspectorFn = vi.fn()
|
||||
|
||||
container.bindMock(InspectionService, {
|
||||
registerInspector: registerInspectorFn,
|
||||
})
|
||||
|
||||
const urlInspector = container.bind(ExtensionInspectorService)
|
||||
|
||||
expect(registerInspectorFn).toHaveBeenCalledOnce()
|
||||
expect(registerInspectorFn).toHaveBeenCalledWith(urlInspector)
|
||||
})
|
||||
|
||||
describe("getInspectorFor", () => {
|
||||
it("should return an inspector result when localhost is in URL and extension is not available", () => {
|
||||
const container = new TestContainer()
|
||||
const urlInspector = container.bind(ExtensionInspectorService)
|
||||
|
||||
const req = ref({
|
||||
...getDefaultRESTRequest(),
|
||||
endpoint: "http://localhost:8000/api/data",
|
||||
})
|
||||
|
||||
const result = urlInspector.getInspections(req)
|
||||
|
||||
expect(result.value).toContainEqual(
|
||||
expect.objectContaining({ id: "url", isApplicable: true })
|
||||
)
|
||||
})
|
||||
|
||||
it("should not return an inspector result when localhost is not in URL", () => {
|
||||
const container = new TestContainer()
|
||||
|
||||
container.bindMock(ExtensionInterceptorService, {
|
||||
extensionStatus: ref("unknown-origin" as const),
|
||||
})
|
||||
|
||||
const urlInspector = container.bind(ExtensionInspectorService)
|
||||
|
||||
const req = ref({
|
||||
...getDefaultRESTRequest(),
|
||||
endpoint: "http://example.com/api/data",
|
||||
})
|
||||
|
||||
const result = urlInspector.getInspections(req)
|
||||
|
||||
expect(result.value).toHaveLength(0)
|
||||
})
|
||||
|
||||
it("should add the correct text to the results when extension is not installed", () => {
|
||||
const container = new TestContainer()
|
||||
|
||||
container.bindMock(ExtensionInterceptorService, {
|
||||
extensionStatus: ref("waiting" as const),
|
||||
})
|
||||
|
||||
const urlInspector = container.bind(ExtensionInspectorService)
|
||||
|
||||
const req = ref({
|
||||
...getDefaultRESTRequest(),
|
||||
endpoint: "http://localhost:8000/api/data",
|
||||
})
|
||||
|
||||
const result = urlInspector.getInspections(req)
|
||||
|
||||
expect(result.value).toHaveLength(1)
|
||||
expect(result.value[0]).toMatchObject({
|
||||
text: { type: "text", text: "inspections.url.extension_not_installed" },
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,107 @@
|
||||
import { Service } from "dioc"
|
||||
import {
|
||||
InspectionService,
|
||||
Inspector,
|
||||
InspectorResult,
|
||||
} from "~/services/inspection"
|
||||
import { getI18n } from "~/modules/i18n"
|
||||
import { HoppRESTRequest } from "@hoppscotch/data"
|
||||
import { computed, markRaw } from "vue"
|
||||
import IconAlertTriangle from "~icons/lucide/alert-triangle"
|
||||
import { Ref } from "vue"
|
||||
import { InterceptorService } from "~/services/interceptor.service"
|
||||
import { ExtensionInterceptorService } from "~/platform/std/interceptors/extension"
|
||||
|
||||
/**
|
||||
* This inspector is responsible for inspecting the URL of a request.
|
||||
* It checks if the URL contains localhost and if the extension is installed.
|
||||
* It also provides an action to enable the extension.
|
||||
*
|
||||
* NOTE: Initializing this service registers it as a inspector with the Inspection Service.
|
||||
*/
|
||||
export class ExtensionInspectorService extends Service implements Inspector {
|
||||
public static readonly ID = "EXTENSION_INSPECTOR_SERVICE"
|
||||
|
||||
private t = getI18n()
|
||||
|
||||
public readonly inspectorID = "extension"
|
||||
|
||||
private readonly interceptorService = this.bind(InterceptorService)
|
||||
private readonly extensionService = this.bind(ExtensionInterceptorService)
|
||||
|
||||
private readonly inspection = this.bind(InspectionService)
|
||||
|
||||
constructor() {
|
||||
super()
|
||||
|
||||
this.inspection.registerInspector(this)
|
||||
}
|
||||
|
||||
getInspections(req: Readonly<Ref<HoppRESTRequest>>) {
|
||||
const currentExtensionStatus = this.extensionService.extensionStatus
|
||||
|
||||
const isExtensionInstalled = computed(
|
||||
() => currentExtensionStatus.value === "available"
|
||||
)
|
||||
|
||||
const EXTENSIONS_ENABLED = computed(
|
||||
() => this.interceptorService.currentInterceptorID.value === "extension"
|
||||
)
|
||||
|
||||
return computed(() => {
|
||||
const results: InspectorResult[] = []
|
||||
|
||||
const url = req.value.endpoint
|
||||
const localHostURLs = ["localhost", "127.0.0.1"]
|
||||
|
||||
const isContainLocalhost = localHostURLs.some((host) =>
|
||||
url.includes(host)
|
||||
)
|
||||
|
||||
if (
|
||||
isContainLocalhost &&
|
||||
(!EXTENSIONS_ENABLED.value || !isExtensionInstalled.value)
|
||||
) {
|
||||
let text
|
||||
|
||||
if (!isExtensionInstalled.value) {
|
||||
if (currentExtensionStatus.value === "unknown-origin") {
|
||||
text = this.t("inspections.url.extension_unknown_origin")
|
||||
} else {
|
||||
text = this.t("inspections.url.extension_not_installed")
|
||||
}
|
||||
} else if (!EXTENSIONS_ENABLED.value) {
|
||||
text = this.t("inspections.url.extention_not_enabled")
|
||||
} else {
|
||||
text = this.t("inspections.url.localhost")
|
||||
}
|
||||
|
||||
results.push({
|
||||
id: "url",
|
||||
icon: markRaw(IconAlertTriangle),
|
||||
text: {
|
||||
type: "text",
|
||||
text: text,
|
||||
},
|
||||
action: {
|
||||
text: this.t("inspections.url.extention_enable_action"),
|
||||
apply: () => {
|
||||
this.interceptorService.currentInterceptorID.value = "extension"
|
||||
},
|
||||
},
|
||||
severity: 2,
|
||||
isApplicable: true,
|
||||
locations: {
|
||||
type: "url",
|
||||
},
|
||||
doc: {
|
||||
text: this.t("action.learn_more"),
|
||||
link: "https://docs.hoppscotch.io/documentation/features/interceptor#browser-extension",
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
return results
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user