Skip to content

Commit

Permalink
Load target law data
Browse files Browse the repository at this point in the history
RISDEV-3463
  • Loading branch information
malte-laukoetter committed Mar 6, 2024
1 parent e0227ba commit dcd63ac
Show file tree
Hide file tree
Showing 7 changed files with 295 additions and 2 deletions.
80 changes: 80 additions & 0 deletions frontend/src/composables/useTargetLaw.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { defineStore } from "pinia"
import { beforeEach, describe, expect, test, vi } from "vitest"
import { nextTick, ref } from "vue"
import { createTestingPinia } from "@pinia/testing"

describe("useTargetLaw", () => {
beforeEach(() => {
vi.resetModules()
vi.resetAllMocks()
})

test("should provide the target law", async () => {
createTestingPinia({
stubActions: false,
})

vi.doMock("@/store/targetLawStore", () => ({
useTargetLawStore: vi.fn().mockReturnValue(
defineStore("target-law", () => {
return {
targetLaw: ref({
eli: "eli/bund/bgbl-1/1990/s2954/2022-12-19/1/deu/regelungstext-1",
title:
"Gesetz über die Zusammenarbeit des Bundes und der Länder in Angelegenheiten des Verfassungsschutzes und über das Bundesamt für Verfassungsschutz",
}),
loadTargetLawByEli: vi.fn(),
}
})(),
),
}))

const { useTargetLaw } = await import("./useTargetLaw")

const eli = ref(
"eli/bund/bgbl-1/1990/s2954/2022-12-19/1/deu/regelungstext-1",
)
const targetLaw = useTargetLaw(eli)

expect(targetLaw.value?.eli).toBe(
"eli/bund/bgbl-1/1990/s2954/2022-12-19/1/deu/regelungstext-1",
)
expect(targetLaw.value?.title).toBe(
"Gesetz über die Zusammenarbeit des Bundes und der Länder in Angelegenheiten des Verfassungsschutzes und über das Bundesamt für Verfassungsschutz",
)
})

test("should load the target law when the eli changes", async () => {
const loadTargetLawByEli = vi.fn()

createTestingPinia({
stubActions: false,
})

vi.doMock("@/store/targetLawStore", () => ({
useTargetLawStore: vi.fn().mockReturnValue(
defineStore("target-law", () => {
return {
targetLaw: ref(),
loadTargetLawByEli,
}
})(),
),
}))

const { useTargetLaw } = await import("./useTargetLaw")

const eli = ref(
"eli/bund/bgbl-1/1990/s2954/2022-12-19/1/deu/regelungstext-1",
)
useTargetLaw(eli)

eli.value = "eli/bund/bgbl-1/1964/s593/1964-08-05/1/deu/regelungstext-1"
await nextTick()

eli.value = "eli/bund/bgbl-1/1964/s593/1964-08-05/1/deu/regelungstext-1"
await nextTick()

expect(loadTargetLawByEli).toBeCalledTimes(2)
})
})
33 changes: 33 additions & 0 deletions frontend/src/composables/useTargetLaw.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { storeToRefs } from "pinia"
import {
readonly,
watch,
MaybeRefOrGetter,
toValue,
Ref,
DeepReadonly,
} from "vue"
import { useTargetLawStore } from "@/store/targetLawStore"
import { TargetLaw } from "@/services/targetLawsService"

/**
* Get the data of a target law.
* @param eli a reference to the eli for which the law data will be returned. Changing the value of the reference will load the data for the new eli.
* @returns A reference to the target law or undefined if it is not available (or still loading).
*/
export function useTargetLaw(
eli: MaybeRefOrGetter<string>,
): DeepReadonly<Ref<TargetLaw | undefined>> {
const targetLawStore = useTargetLawStore()
const { targetLaw } = storeToRefs(targetLawStore)

watch(
() => toValue(eli),
(newEli) => {
targetLawStore.loadTargetLawByEli(newEli)
},
{ immediate: true },
)

return readonly(targetLaw)
}
66 changes: 66 additions & 0 deletions frontend/src/services/targetLawsService.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { describe, it, expect, vi, beforeEach } from "vitest"

describe("targetLawsService", () => {
beforeEach(() => {
vi.resetModules()
vi.resetAllMocks()
})

describe("getTargetLawByEli(eli)", () => {
it("provides the data from the api", async () => {
const fetchMock = vi.fn().mockResolvedValueOnce({
eli: "eli/bund/bgbl-1/1990/s2954/2022-12-19/1/deu/regelungstext-1",
title:
"Gesetz über die Zusammenarbeit des Bundes und der Länder in Angelegenheiten des Verfassungsschutzes und über das Bundesamt für Verfassungsschutz",
})

vi.doMock("./apiService.ts", () => ({
apiFetch: fetchMock,
}))

const { getTargetLawByEli } = await import("./targetLawsService")

const result = await getTargetLawByEli(
"eli/bund/bgbl-1/1990/s2954/2022-12-19/1/deu/regelungstext-1",
)
expect(result.eli).toBe(
"eli/bund/bgbl-1/1990/s2954/2022-12-19/1/deu/regelungstext-1",
)
expect(result.title).toBe(
"Gesetz über die Zusammenarbeit des Bundes und der Länder in Angelegenheiten des Verfassungsschutzes und über das Bundesamt für Verfassungsschutz",
)

expect(fetchMock).toHaveBeenCalledWith(
"/target-laws/eli/bund/bgbl-1/1990/s2954/2022-12-19/1/deu/regelungstext-1",
)
})
})

describe("getTargetLawXmlByEli(eli)", () => {
it("provides the data from the api", async () => {
const fetchMock = vi
.fn()
.mockResolvedValueOnce(`<?xml version="1.0" encoding="UTF-8"?></xml>`)

vi.doMock("./apiService.ts", () => ({
apiFetch: fetchMock,
}))

const { getTargetLawXmlByEli } = await import("./targetLawsService")

const result = await getTargetLawXmlByEli(
"eli/bund/bgbl-1/1990/s2954/2022-12-19/1/deu/regelungstext-1",
)
expect(result).toBe('<?xml version="1.0" encoding="UTF-8"?></xml>')

expect(fetchMock).toHaveBeenCalledWith(
"/target-laws/eli/bund/bgbl-1/1990/s2954/2022-12-19/1/deu/regelungstext-1",
expect.objectContaining({
headers: expect.objectContaining({
Accept: "application/xml",
}),
}),
)
})
})
})
28 changes: 28 additions & 0 deletions frontend/src/services/targetLawsService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { apiFetch } from "@/services/apiService"

export interface TargetLaw {
eli: string
title: string
}

/**
* Load a target law from the api
*
* @param eli Eli of the target law
*/
export async function getTargetLawByEli(eli: string): Promise<TargetLaw> {
return await apiFetch(`/target-laws/${eli}`)
}

/**
* Load the xml version of a target law from the api
*
* @param eli Eli of the target law
*/
export async function getTargetLawXmlByEli(eli: string): Promise<string> {
return await apiFetch(`/target-laws/${eli}`, {
headers: {
Accept: "application/xml",
},
})
}
48 changes: 48 additions & 0 deletions frontend/src/store/targetLawStore.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { describe, it, expect, beforeEach, vi } from "vitest"
import { setActivePinia, createPinia } from "pinia"
import { nextTick } from "vue"

describe("useTargetLawsStore", () => {
beforeEach(() => {
vi.resetModules()
vi.resetAllMocks()
})

beforeEach(() => {
setActivePinia(createPinia())
})

it("loads amending laws correctly", async () => {
const getTargetLawByEli = vi.fn().mockResolvedValue({
eli: "eli/bund/bgbl-1/1990/s2954/2022-12-19/1/deu/regelungstext-1",
title:
"Gesetz über die Zusammenarbeit des Bundes und der Länder in Angelegenheiten des Verfassungsschutzes und über das Bundesamt für Verfassungsschutz",
})

vi.doMock("@/services/targetLawsService", () => ({
getTargetLawByEli,
}))

const { useTargetLawStore } = await import("./targetLawStore")

const store = useTargetLawStore()

store.loadTargetLawByEli(
"eli/bund/bgbl-1/1990/s2954/2022-12-19/1/deu/regelungstext-1",
)
await nextTick()

expect(store.loading).toBe(true)
expect(getTargetLawByEli).toHaveBeenCalledOnce()

await vi.waitUntil(() => !store.loading)

expect(store.loading).toBe(false)
expect(store.targetLaw?.eli).toEqual(
"eli/bund/bgbl-1/1990/s2954/2022-12-19/1/deu/regelungstext-1",
)
expect(store.targetLaw?.title).toEqual(
"Gesetz über die Zusammenarbeit des Bundes und der Länder in Angelegenheiten des Verfassungsschutzes und über das Bundesamt für Verfassungsschutz",
)
})
})
35 changes: 35 additions & 0 deletions frontend/src/store/targetLawStore.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { defineStore } from "pinia"
import { ref, watch } from "vue"
import { getTargetLawByEli, TargetLaw } from "@/services/targetLawsService"

export const useTargetLawStore = defineStore("target-law", () => {
const targetLaw = ref<TargetLaw | undefined>(undefined)
const eli = ref<string | undefined>(undefined)
const loading = ref<boolean>(false)

function loadTargetLawByEli(newEli: string): void {
eli.value = newEli
}

watch(eli, async (newEli) => {
if (newEli) {
if (loading.value) {
// todo (Malte Laukötter, 2024-03-06): We should cancel a possibly still running call of getTargetLawByEli here. The AbortController-API should allow us to do this.
console.warn(
"There is already an unfinished call to getTargetLawByEli, we are still creating a new one but this could have created a race condition.",
)
}
loading.value = true
targetLaw.value = undefined
targetLaw.value = await getTargetLawByEli(newEli)
loading.value = false
}
})

return {
targetLaw,
eli,
loading,
loadTargetLawByEli,
}
})
7 changes: 5 additions & 2 deletions frontend/src/views/AmendingLawArticleEditor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import IconArrowBack from "~icons/ic/baseline-arrow-back"
import { useAmendingLaw } from "@/composables/useAmendingLaw"
import RisAmendingLawInfoHeader from "@/components/amendingLaws/RisAmendingLawInfoHeader.vue"
import { getAmendingLawXmlByEli } from "@/services/amendingLawsService"
import { useTargetLaw } from "@/composables/useTargetLaw"
const TARGET_LAW_TITLE = "Bundesverfassungsschutzgesetz"
const TARGET_LAW_XML = `<akn:activeModifications eId="meta-1_analysis-1_activemod-1"
GUID="cd241744-ace4-436c-a0e3-dc1ee8caf3ac">
<akn:textualMod eId="meta-1_analysis-1_activemod-1_textualmod-1"
Expand Down Expand Up @@ -42,6 +42,9 @@ function handleArticleXMLChange({ content }: { content: string }) {
const eli = useEliPathParameter()
const amendingLaw = useAmendingLaw(eli)
const article = computed(() => amendingLaw.value?.articles?.[0])
const targetLaw = useTargetLaw(
"eli/bund/bgbl-1/1990/s2954/2022-12-19/1/deu/regelungstext-1",
)
const articleXml = ref<string>("")
/**
Expand Down Expand Up @@ -93,7 +96,7 @@ watch(

<div class="gap grid min-h-0 flex-grow grid-cols-2 grid-rows-2 gap-32">
<div class="flex flex-col gap-8">
<h3 class="ds-label-02-bold">{{ TARGET_LAW_TITLE }}</h3>
<h3 class="ds-label-02-bold">{{ targetLaw?.title }}</h3>
<RisCodeEditor
class="flex-grow border border-black"
:readonly="true"
Expand Down

0 comments on commit dcd63ac

Please sign in to comment.