Skip to content

Commit beb7e89

Browse files
committed
PRSD-1546: Clean up destinations and add tests
1 parent 245b628 commit beb7e89

File tree

7 files changed

+175
-25
lines changed

7 files changed

+175
-25
lines changed

src/main/kotlin/uk/gov/communities/prsdb/webapp/journeys/JourneyStep.kt

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -93,12 +93,12 @@ open class JourneyStep<out TEnum : Enum<out TEnum>, TFormModel : FormModel, in T
9393
}
9494

9595
fun determineNextDestination(): Destination =
96-
stepConfig.mode(state)?.let { nextDestination(it).withParam("journeyId", state.journeyId) }
97-
?: Destination.Step(this).withParam("journeyId", state.journeyId)
96+
stepConfig.mode(state)?.let { nextDestination(it) }
97+
?: Destination(this)
9898

9999
private lateinit var unreachableStepDestination: () -> Destination
100100

101-
fun getUnreachableStepDestination() = unreachableStepDestination().withParam("journeyId", state.journeyId)
101+
fun getUnreachableStepDestination() = unreachableStepDestination()
102102

103103
val formModel: TFormModel?
104104
get() = stepConfig.getFormModelFromState(state)
@@ -157,7 +157,8 @@ open class JourneyStep<out TEnum : Enum<out TEnum>, TFormModel : FormModel, in T
157157
this.unreachableStepDestination = unreachableStepDestinationProvider
158158
}
159159

160-
private fun journeyUrl(path: String): String = JourneyStateService.urlWithJourneyState(path, state.journeyId)
160+
val currentJourneyId: String
161+
get() = state.journeyId
161162
}
162163

163164
enum class StepInitialisationStage {

src/main/kotlin/uk/gov/communities/prsdb/webapp/journeys/builders/JourneyBuilder.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ class JourneyBuilder<TState : JourneyState>(
4444
if (unreachableStepDestination != null) {
4545
throw JourneyInitialisationException("unreachableStepRedirect has already been set")
4646
}
47-
unreachableStepDestination = { Destination.Step(getStep()) }
47+
unreachableStepDestination = { Destination(getStep()) }
4848
}
4949

5050
private fun checkForUninitialisedParents(stepInitialiser: StepInitialiser<*, *, *>) {

src/main/kotlin/uk/gov/communities/prsdb/webapp/journeys/builders/StepInitialiser.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ class StepInitialiser<TStep : AbstractStepConfig<TMode, *, TState>, TState : Jou
2929
if (nextDestinationProvider != null) {
3030
throw JourneyInitialisationException("Step $segment already has a next destination defined")
3131
}
32-
nextDestinationProvider = { mode -> Destination.Step(nextStepProvider(mode)) }
32+
nextDestinationProvider = { mode -> Destination(nextStepProvider(mode)) }
3333
return this
3434
}
3535

src/main/kotlin/uk/gov/communities/prsdb/webapp/journeys/example/Destination.kt

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import uk.gov.communities.prsdb.webapp.journeys.JourneyStep
66
sealed class Destination {
77
fun toModelAndView(): ModelAndView =
88
when (this) {
9-
is Step -> ModelAndView("redirect:${step.routeSegment}", params)
9+
is Step -> ModelAndView("redirect:${step.routeSegment}", mapOf("journeyId" to journeyId))
1010
is ExternalUrl -> ModelAndView("redirect:$externalUrl", params)
1111
is Template -> ModelAndView(templateName, content)
1212
}
@@ -17,19 +17,9 @@ sealed class Destination {
1717
else -> this
1818
}
1919

20-
fun withParam(
21-
key: String,
22-
value: String,
23-
): Destination =
24-
when (this) {
25-
is Step -> Step(step, params + (key to value))
26-
is ExternalUrl -> ExternalUrl(externalUrl, params + (key to value))
27-
is Template -> this
28-
}
29-
3020
class Step(
3121
val step: JourneyStep<*, *, *>,
32-
val params: Map<String, String> = mapOf(),
22+
val journeyId: String,
3323
) : Destination()
3424

3525
class ExternalUrl(
@@ -41,4 +31,8 @@ sealed class Destination {
4131
val templateName: String,
4232
val content: Map<String, Any?> = mapOf(),
4333
) : Destination()
34+
35+
companion object {
36+
operator fun invoke(step: JourneyStep<*, *, *>): Destination = Step(step, step.currentJourneyId)
37+
}
4438
}

src/test/kotlin/uk/gov/communities/prsdb/webapp/journeys/JourneyStepTest.kt

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -286,21 +286,20 @@ class JourneyStepTest {
286286
assertTrue(redirectDestination is Destination.ExternalUrl)
287287
with(redirectDestination as Destination.ExternalUrl) {
288288
assertEquals("redirect", externalUrl)
289-
assertEquals("jid123", params["journeyId"])
290289
}
291290
}
292291

293292
@Test
294293
fun `determine redirect returns the route segment if the step config's mode is null`() {
295294
// Arrange
296-
val step = JourneyStep<TestEnum, TestFormModel, JourneyState>(mock())
297-
whenever(step.stepConfig.mode(any())).thenReturn(null)
298-
whenever(step.stepConfig.routeSegment).thenReturn("stepId")
295+
val journeyStep = JourneyStep<TestEnum, TestFormModel, JourneyState>(mock())
296+
whenever(journeyStep.stepConfig.mode(any())).thenReturn(null)
297+
whenever(journeyStep.stepConfig.routeSegment).thenReturn("stepId")
299298

300299
val state: JourneyState = mock()
301300
whenever(state.journeyId).thenReturn("jid123")
302301

303-
step.initialize(
302+
journeyStep.initialize(
304303
"stepId",
305304
state,
306305
mock(),
@@ -310,13 +309,13 @@ class JourneyStepTest {
310309
)
311310

312311
// Act
313-
val redirectDestination = step.determineNextDestination()
312+
val redirectDestination = journeyStep.determineNextDestination()
314313

315314
// Assert
316315
assertTrue(redirectDestination is Destination.Step)
317316
with(redirectDestination as Destination.Step) {
318317
assertEquals("stepId", step.routeSegment)
319-
assertEquals("jid123", params["journeyId"])
318+
assertEquals("jid123", journeyId)
320319
}
321320
}
322321

src/test/kotlin/uk/gov/communities/prsdb/webapp/journeys/builders/StepInitialiserTests.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ class StepInitialiserTests {
151151
val nextStepSegment = "nextStepSegment"
152152
val nextStepMock = mock<JourneyStep<TestEnum, *, JourneyState>>()
153153
whenever(nextStepMock.routeSegment).thenReturn(nextStepSegment)
154+
whenever(nextStepMock.currentJourneyId).thenReturn("journeyId")
154155

155156
val builder = StepInitialiser("test", stepMock)
156157
builder.nextStep { _: TestEnum -> nextStepMock }
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
package uk.gov.communities.prsdb.webapp.journeys.example
2+
3+
import org.junit.jupiter.api.Assertions.assertEquals
4+
import org.junit.jupiter.api.Assertions.assertNull
5+
import org.junit.jupiter.api.Assertions.assertSame
6+
import org.junit.jupiter.api.Assertions.assertTrue
7+
import org.junit.jupiter.api.Test
8+
import org.mockito.kotlin.mock
9+
import org.mockito.kotlin.whenever
10+
import uk.gov.communities.prsdb.webapp.journeys.JourneyStep
11+
12+
class DestinationTests {
13+
@Test
14+
fun `Step Destination with just a step returns a redirect for the current step and journey`() {
15+
// Arrange
16+
val mockStep = mock<JourneyStep<*, *, *>>()
17+
val journeyId = "test-journey-id"
18+
val routeSegment = "test-segment"
19+
20+
whenever(mockStep.currentJourneyId).thenReturn(journeyId)
21+
whenever(mockStep.routeSegment).thenReturn(routeSegment)
22+
23+
// Act
24+
val destination = Destination(mockStep)
25+
val modelAndView = destination.toModelAndView()
26+
27+
// Assert
28+
assertEquals("redirect:$routeSegment", modelAndView.viewName)
29+
assertEquals(journeyId, modelAndView.model["journeyId"])
30+
}
31+
32+
@Test
33+
fun `Step Destination with explicit journeyId returns a redirect for the specified step and journey`() {
34+
// Arrange
35+
val mockStep = mock<JourneyStep<*, *, *>>()
36+
val journeyId = "explicit-journey-id"
37+
val routeSegment = "explicit-segment"
38+
39+
whenever(mockStep.routeSegment).thenReturn(routeSegment)
40+
41+
// Act
42+
val destination = Destination.Step(mockStep, journeyId)
43+
val modelAndView = destination.toModelAndView()
44+
45+
// Assert
46+
assertEquals("redirect:$routeSegment", modelAndView.viewName)
47+
assertEquals(journeyId, modelAndView.model["journeyId"])
48+
}
49+
50+
@Test
51+
fun `ExternalUrl Destination returns a redirect to the specified URL with parameters`() {
52+
// Arrange
53+
val externalUrl = "http://example.com"
54+
val params = mapOf("param1" to "value1", "param2" to "value2")
55+
56+
// Act
57+
val destination = Destination.ExternalUrl(externalUrl, params)
58+
val modelAndView = destination.toModelAndView()
59+
60+
// Assert
61+
assertEquals("redirect:$externalUrl", modelAndView.viewName)
62+
assertEquals("value1", modelAndView.model["param1"])
63+
assertEquals("value2", modelAndView.model["param2"])
64+
}
65+
66+
@Test
67+
fun `ExternalUrl Destination without parameters returns a redirect to the specified URL`() {
68+
// Arrange
69+
val externalUrl = "http://example.com"
70+
71+
// Act
72+
val destination = Destination.ExternalUrl(externalUrl)
73+
val modelAndView = destination.toModelAndView()
74+
75+
// Assert
76+
assertEquals("redirect:$externalUrl", modelAndView.viewName)
77+
assertTrue(modelAndView.model.isEmpty())
78+
}
79+
80+
@Test
81+
fun `Template Destination returns the correct template name and content`() {
82+
// Arrange
83+
val templateName = "test-template"
84+
val content = mapOf("key1" to "value1", "key2" to "value2")
85+
86+
// Act
87+
val destination = Destination.Template(templateName, content)
88+
val modelAndView = destination.toModelAndView()
89+
90+
// Assert
91+
assertEquals(templateName, modelAndView.viewName)
92+
assertEquals("value1", modelAndView.model["key1"])
93+
assertEquals("value2", modelAndView.model["key2"])
94+
}
95+
96+
@Test
97+
fun `Template Destination with empty content returns the correct template name`() {
98+
// Arrange
99+
val templateName = "test-template"
100+
101+
// Act
102+
val destination = Destination.Template(templateName)
103+
val modelAndView = destination.toModelAndView()
104+
105+
// Assert
106+
assertEquals(templateName, modelAndView.viewName)
107+
assertTrue(modelAndView.model.isEmpty())
108+
}
109+
110+
@Test
111+
fun `Template Destination withContent creates a new Destination with that content`() {
112+
// Arrange
113+
val templateName = "test-template"
114+
val initialContent = mapOf("key1" to "value1")
115+
val additionalContent = mapOf("key2" to "value2")
116+
117+
// Act
118+
val destination = Destination.Template(templateName, initialContent)
119+
val updatedDestination = destination.withContent(additionalContent)
120+
val updatedModelAndView = updatedDestination.toModelAndView()
121+
val oldModelAndView = destination.toModelAndView()
122+
123+
// Assert
124+
assertEquals(templateName, updatedModelAndView.viewName)
125+
assertEquals("value1", updatedModelAndView.model["key1"])
126+
assertEquals("value2", updatedModelAndView.model["key2"])
127+
128+
assertEquals(templateName, oldModelAndView.viewName)
129+
assertEquals("value1", oldModelAndView.model["key1"])
130+
assertNull(oldModelAndView.model["key2"])
131+
}
132+
133+
@Test
134+
fun `withContent on non-Template Destination returns the same Destination`() {
135+
// Arrange
136+
val mockStep = mock<JourneyStep<*, *, *>>()
137+
val journeyId = "test-journey-id"
138+
val routeSegment = "test-segment"
139+
140+
whenever(mockStep.currentJourneyId).thenReturn(journeyId)
141+
whenever(mockStep.routeSegment).thenReturn(routeSegment)
142+
143+
val stepDestination = Destination(mockStep)
144+
val externalUrlDestination = Destination.ExternalUrl("http://example.com")
145+
val contentToAdd = mapOf("key" to "value")
146+
147+
// Act
148+
val updatedStepDestination = stepDestination.withContent(contentToAdd)
149+
val updatedExternalUrlDestination = externalUrlDestination.withContent(contentToAdd)
150+
151+
// Assert
152+
assertSame(stepDestination, updatedStepDestination)
153+
assertSame(externalUrlDestination, updatedExternalUrlDestination)
154+
}
155+
}

0 commit comments

Comments
 (0)