components/frontend/src/source/Sources.test.js
import { act, fireEvent, render, screen } from "@testing-library/react"
import userEvent from "@testing-library/user-event"
import * as fetch_server_api from "../api/fetch_server_api"
import { DataModel } from "../context/DataModel"
import { EDIT_REPORT_PERMISSION, Permissions } from "../context/Permissions"
import * as toast from "../widgets/toast"
import { Sources } from "./Sources"
jest.mock("../api/fetch_server_api.js")
jest.mock("../widgets/toast.js")
const dataModel = {
metrics: { metric_type: { sources: ["source_type1", "source_type2"] } },
sources: {
source_type1: {
name: "Source type 1",
parameters: { url: { type: "url", metrics: ["metric_type"] } },
},
source_type2: { name: "Source type 2", parameters: {} },
},
}
const report = {
subjects: {
subject_uuid: {
name: "Subject",
metrics: {
metric_uuid: {
name: "Metric",
type: "metric_type",
sources: {
source_uuid: {
name: "Source 1",
type: "source_type1",
parameters: { url: "https://test.nl" },
},
non_existing_source_type: {
name: "Source with non-existing source type",
type: "non-existing",
},
},
},
other_metric_uuid: {
name: "Other metric",
type: "metric_type",
sources: { other_source_uuid: { name: "Source 2", type: "source_type2" } },
},
metric_without_sources: {
name: "Metric without sources",
type: "metric_type",
sources: {},
},
},
},
},
}
function renderSources(props) {
render(
<Permissions.Provider value={[EDIT_REPORT_PERMISSION]}>
<DataModel.Provider value={dataModel}>
<Sources
report={report}
reports={[report]}
metric={report.subjects.subject_uuid.metrics.metric_uuid}
metric_uuid="metric_uuid"
measurement={{
sources: [{ source_uuid: "source_uuid", connection_error: "Oops" }],
}}
reload={() => {
/* Dummy implemention */
}}
{...props}
/>
</DataModel.Provider>
</Permissions.Provider>,
)
}
it("shows a source", () => {
renderSources()
expect(screen.getAllByPlaceholderText(/Source type 1/).length).toBe(1)
})
it("shows a message if there are no sources", () => {
renderSources({ metric: report.subjects.subject_uuid.metrics.metric_without_sources })
expect(screen.getAllByText(/No sources have been configured/).length).toBe(1)
})
it("doesn't show sources not in the data model", () => {
renderSources()
expect(screen.queryAllByDisplayValue(/Source 1/).length).toBe(1)
expect(screen.queryAllByDisplayValue(/Source with non-existing source type/).length).toBe(0)
})
it("shows errored sources", () => {
renderSources()
expect(screen.getAllByText(/Connection error/).length).toBe(1)
})
it("creates a new source", async () => {
fetch_server_api.fetch_server_api = jest.fn().mockResolvedValue({ ok: true })
renderSources()
await act(async () => {
fireEvent.click(screen.getByText(/Add source/))
})
await act(async () => {
fireEvent.click(screen.getAllByText(/Source type 2/)[1])
})
expect(fetch_server_api.fetch_server_api).toHaveBeenNthCalledWith(1, "post", "source/new/metric_uuid", {
type: "source_type2",
})
})
it("copies a source", async () => {
fetch_server_api.fetch_server_api = jest.fn().mockResolvedValue({ ok: true })
renderSources()
await act(async () => {
fireEvent.click(screen.getByText(/Copy source/))
})
await act(async () => {
fireEvent.click(screen.getByText(/Source 1/))
})
expect(fetch_server_api.fetch_server_api).toHaveBeenNthCalledWith(
1,
"post",
"source/source_uuid/copy/metric_uuid",
{},
)
})
it("moves a source", async () => {
fetch_server_api.fetch_server_api = jest.fn().mockResolvedValue({ ok: true })
renderSources()
await act(async () => {
fireEvent.click(screen.getByText(/Move source/))
})
await act(async () => {
fireEvent.click(screen.getByText(/Source 2/))
})
expect(fetch_server_api.fetch_server_api).toHaveBeenNthCalledWith(
1,
"post",
"source/other_source_uuid/move/metric_uuid",
{},
)
})
it("updates a parameter of a source", async () => {
fetch_server_api.fetch_server_api = jest.fn().mockResolvedValue({ ok: true, nr_sources_mass_edited: 0 })
renderSources()
await userEvent.type(screen.getByDisplayValue(/https:\/\/test.nl/), "https://other{Enter}", {
initialSelectionStart: 0,
initialSelectionEnd: 15,
})
await act(async () => {
fireEvent.click(screen.getByDisplayValue("Source 1"))
})
expect(screen.getAllByDisplayValue("https://other").length).toBe(1)
expect(fetch_server_api.fetch_server_api).toHaveBeenCalledWith("post", "source/source_uuid/parameter/url", {
edit_scope: "source",
url: "https://other",
})
expect(toast.showMessage).toHaveBeenCalledTimes(0)
})
it("mass updates a parameter of a source", async () => {
fetch_server_api.fetch_server_api = jest.fn().mockResolvedValue({ ok: true, nr_sources_mass_edited: 2 })
renderSources()
await act(async () => {
fireEvent.click(screen.getByText(/Apply change to subject/))
})
expect(screen.getAllByText(/Apply change to subject/).length).toBe(2)
await userEvent.type(screen.getByDisplayValue(/https:\/\/test.nl/), "https://other{Enter}", {
initialSelectionStart: 0,
initialSelectionEnd: 15,
})
await act(async () => {
fireEvent.click(screen.getByDisplayValue("Source 1"))
})
expect(screen.getAllByDisplayValue("https://other").length).toBe(1)
expect(fetch_server_api.fetch_server_api).toHaveBeenCalledWith("post", "source/source_uuid/parameter/url", {
edit_scope: "subject",
url: "https://other",
})
expect(toast.showMessage).toHaveBeenCalledTimes(1)
expect(screen.getAllByText(/Apply change to subject/).length).toBe(1)
})