Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .idea/modules.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions build/bazel-generated-file-list.txt
Original file line number Diff line number Diff line change
Expand Up @@ -640,6 +640,7 @@ platform/jewel/markdown/extensions/gfm-tables
platform/jewel/markdown/extensions/images
platform/jewel/markdown/ide-laf-bridge-styling
platform/jewel/markdown/int-ui-standalone-styling
platform/jewel/markdown/testing
platform/jewel/samples/showcase
platform/jewel/samples/standalone
platform/jewel/ui
Expand Down
2 changes: 2 additions & 0 deletions platform/jewel/markdown/core/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ jvm_library(
"//libraries/compose-runtime-desktop:compose-runtime-desktop_test_lib",
"//libraries/compose-foundation-desktop-junit",
"//libraries/compose-foundation-desktop-junit:compose-foundation-desktop-junit_test_lib",
"//platform/jewel/markdown/testing",
"//platform/jewel/markdown/testing:testing_test_lib",
"//libraries/jsoup",
"//libraries/jsoup:jsoup_test_lib",
],
Expand Down
1 change: 1 addition & 0 deletions platform/jewel/markdown/core/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ dependencies {

testImplementation(compose.desktop.uiTestJUnit4)
testImplementation(projects.ui)
testImplementation(projects.markdown.testing)
testImplementation(compose.desktop.currentOs)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
<orderEntry type="module" module-name="intellij.libraries.junit4" scope="TEST" />
<orderEntry type="module" module-name="intellij.libraries.compose.runtime.desktop" />
<orderEntry type="module" module-name="intellij.libraries.compose.foundation.desktop.junit" scope="TEST" />
<orderEntry type="module" module-name="intellij.platform.jewel.markdown.testing" scope="TEST" />
<orderEntry type="module" module-name="intellij.libraries.jsoup" />
</component>
</module>
Original file line number Diff line number Diff line change
Expand Up @@ -752,7 +752,7 @@ public open class DefaultMarkdownBlockRenderer(
enabled: Boolean,
onUrlClick: ((String) -> Unit)? = null,
) =
remember(block.inlineContent, styling, enabled) {
remember(block.inlineContent, styling, enabled, onUrlClick) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Core fix here :)

inlineRenderer.renderAsAnnotatedString(block.inlineContent, styling, enabled, onUrlClick)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the
// Apache 2.0 license.
package org.jetbrains.jewel.markdown.rendering

import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.test.ExperimentalTestApi
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.performClick
import androidx.compose.ui.test.runComposeUiTest
import org.jetbrains.jewel.markdown.processing.MarkdownProcessor
import org.jetbrains.jewel.markdown.testing.MarkdownTestTheme
import org.jetbrains.jewel.markdown.testing.createMarkdownTestStyling
import org.junit.Assert.assertEquals
import org.junit.Assert.assertTrue
import org.junit.Test

@OptIn(ExperimentalTestApi::class)
public class DefaultMarkdownBlockRendererTest {
@Test
public fun `onUrlClick callback updates when changed`() {
runComposeUiTest {
val processor = MarkdownProcessor()
val markdown = "[Click me](https://example.com)"
val blocks = processor.processMarkdownDocument(markdown)

var clickedUrl by mutableStateOf<String?>(null)
var onUrlClick by mutableStateOf<(String) -> Unit>({ url -> clickedUrl = "first:$url" })

setContent {
MarkdownTestTheme {
val renderer = DefaultMarkdownBlockRenderer(createMarkdownTestStyling(), emptyList())
renderer.render(
blocks,
enabled = true,
onUrlClick = onUrlClick,
onTextClick = {},
modifier = Modifier,
)
}
}

onNodeWithText("Click me").performClick()
waitForIdle()
assertEquals("first:https://example.com", clickedUrl)

// Change the callback
clickedUrl = null
onUrlClick = { url -> clickedUrl = "second:$url" }
waitForIdle()

onNodeWithText("Click me").performClick()
waitForIdle()
assertEquals("second:https://example.com", clickedUrl)
}
}

@Test
public fun `enabled change updates link rendering`() {
runComposeUiTest {
val processor = MarkdownProcessor()
val markdown = "[Click me](https://example.com)"
val blocks = processor.processMarkdownDocument(markdown)

var enabled by mutableStateOf(true)
var clickedUrl by mutableStateOf<String?>(null)

setContent {
MarkdownTestTheme {
val renderer = DefaultMarkdownBlockRenderer(createMarkdownTestStyling(), emptyList())
renderer.render(
blocks,
enabled = enabled,
onUrlClick = { url -> clickedUrl = url },
onTextClick = {},
modifier = Modifier,
)
}
}

// When enabled, clicking the link should invoke the callback
onNodeWithText("Click me").performClick()
waitForIdle()
assertEquals("https://example.com", clickedUrl)

// Disable and verify the callback is no longer invoked
clickedUrl = null
enabled = false
waitForIdle()

onNodeWithText("Click me").performClick()
waitForIdle()
// When disabled, links should not be clickable
assertTrue("Link should not be clickable when disabled", clickedUrl == null)
}
}

@Test
public fun `rendered content updates when both enabled and onUrlClick change simultaneously`() {
runComposeUiTest {
val processor = MarkdownProcessor()
val markdown = "[Click me](https://example.com)"
val blocks = processor.processMarkdownDocument(markdown)

var enabled by mutableStateOf(false)
var clickedUrl by mutableStateOf<String?>(null)
var onUrlClick by mutableStateOf<(String) -> Unit>({ url -> clickedUrl = "first:$url" })

setContent {
MarkdownTestTheme {
val renderer = DefaultMarkdownBlockRenderer(createMarkdownTestStyling(), emptyList())
renderer.render(
blocks,
enabled = enabled,
onUrlClick = onUrlClick,
onTextClick = {},
modifier = Modifier,
)
}
}

// Initially disabled - click should not work
onNodeWithText("Click me").performClick()
waitForIdle()
assertTrue("Link should not be clickable when disabled", clickedUrl == null)

// Enable and change callback simultaneously
enabled = true
onUrlClick = { url -> clickedUrl = "second:$url" }
waitForIdle()

onNodeWithText("Click me").performClick()
waitForIdle()
assertEquals("second:https://example.com", clickedUrl)
}
}
}
Loading
Loading