Skip to content

Commit 57db09c

Browse files
committed
Make new experimental properties optional if they are not in the current stable Chrome
When new properties are added to experimental types in the most recent protocol versions, the stable Chrome doesn't have them yet, and serialization fails because of these missing properties. This also affects tests which are using Docker containers with the latest-ish stable Chrome version.
1 parent d9779f5 commit 57db09c

File tree

3 files changed

+61
-25
lines changed

3 files changed

+61
-25
lines changed

protocol-generator/cdp-kotlin-generator/src/main/kotlin/org/hildan/chrome/devtools/protocol/preprocessing/JsonPreProcessor.kt

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,33 @@
11
package org.hildan.chrome.devtools.protocol.preprocessing
22

33
import org.hildan.chrome.devtools.protocol.json.JsonDomain
4+
import org.hildan.chrome.devtools.protocol.json.JsonDomainCommand
45
import org.hildan.chrome.devtools.protocol.json.JsonDomainParameter
56
import org.hildan.chrome.devtools.protocol.json.JsonDomainType
67

78
/**
89
* Pre-processes the list of domains from the JSON definitions to work around some issues in the definitions themselves.
910
*/
1011
internal fun List<JsonDomain>.preprocessed(): List<JsonDomain> = this
12+
.makeNewExperimentalPropsOptional()
1113
// Workaround for https://github.com/ChromeDevTools/devtools-protocol/issues/317
1214
.transformDomainTypeProperty("Network", "Cookie", "expires") { it.copy(optional = true) }
1315
// Workaround for https://github.com/ChromeDevTools/devtools-protocol/issues/244
1416
.map { it.pullNestedEnumsToTopLevel() }
1517

18+
/**
19+
* Modifies some new experimental properties to make them optional, so that serialization doesn't fail on stable Chrome
20+
* versions.
21+
*
22+
* When new properties are added to experimental types in the most recent protocol versions, the stable Chrome doesn't
23+
* have them yet, and serialization fails because of these missing properties. This also affects tests which are using
24+
* Docker containers with the latest-ish stable Chrome version.
25+
*/
26+
// NOTE: only add properties that are not already in the latest stable. We don't want to make everything nullable.
27+
private fun List<JsonDomain>.makeNewExperimentalPropsOptional(): List<JsonDomain> =
28+
transformDomainCommandReturnProp("Runtime", "getHeapUsage", "embedderHeapUsedSize") { it.copy(optional = true) }
29+
.transformDomainCommandReturnProp("Runtime", "getHeapUsage", "backingStorageSize") { it.copy(optional = true) }
30+
1631
private fun List<JsonDomain>.transformDomainTypeProperty(
1732
domain: String,
1833
type: String,
@@ -24,6 +39,17 @@ private fun List<JsonDomain>.transformDomainTypeProperty(
2439
}
2540
}
2641

42+
private fun List<JsonDomain>.transformDomainCommandReturnProp(
43+
domain: String,
44+
command: String,
45+
property: String,
46+
transform: (JsonDomainParameter) -> JsonDomainParameter,
47+
): List<JsonDomain> = transformDomain(domain) { d ->
48+
d.transformCommand(command) { t ->
49+
t.transformReturnProperty(property, transform)
50+
}
51+
}
52+
2753
private fun List<JsonDomain>.transformDomain(
2854
name: String,
2955
transform: (JsonDomain) -> JsonDomain,
@@ -39,5 +65,15 @@ private fun JsonDomainType.transformProperty(
3965
transform: (JsonDomainParameter) -> JsonDomainParameter,
4066
): JsonDomainType = copy(properties = properties.transformIf({ it.name == name }) { transform(it) })
4167

68+
private fun JsonDomain.transformCommand(
69+
name: String,
70+
transform: (JsonDomainCommand) -> JsonDomainCommand,
71+
): JsonDomain = copy(commands = commands.transformIf({ it.name == name }) { transform(it) })
72+
73+
private fun JsonDomainCommand.transformReturnProperty(
74+
name: String,
75+
transform: (JsonDomainParameter) -> JsonDomainParameter,
76+
): JsonDomainCommand = copy(returns = returns.transformIf({ it.name == name }) { transform(it) })
77+
4278
private fun <T> List<T>.transformIf(predicate: (T) -> Boolean, transform: (T) -> T): List<T> =
4379
map { if (predicate(it)) transform(it) else it }

src/jvmTest/kotlin/LocalIntegrationTestBase.kt

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1+
import kotlinx.coroutines.Dispatchers
12
import kotlinx.coroutines.launch
3+
import kotlinx.coroutines.withContext
24
import kotlinx.coroutines.withTimeoutOrNull
35
import org.hildan.chrome.devtools.domains.accessibility.AXProperty
46
import org.hildan.chrome.devtools.domains.accessibility.AXPropertyName
@@ -108,6 +110,29 @@ abstract class LocalIntegrationTestBase : IntegrationTestBase() {
108110
}
109111
}
110112

113+
@OptIn(ExperimentalChromeApi::class)
114+
@Test
115+
fun parallelPages() = runTestWithRealTime {
116+
withResourceServerForTestcontainers { baseUrl ->
117+
chromeWebSocket().use { browser ->
118+
// we want all coroutines to finish before we close the browser session
119+
withContext(Dispatchers.IO) {
120+
repeat(20) {
121+
launch {
122+
browser.newPage().use { page ->
123+
page.goto("$baseUrl/test-server-pages/basic.html")
124+
page.runtime.getHeapUsage()
125+
val docRoot = page.dom.getDocumentRootNodeId()
126+
page.dom.describeNode(DescribeNodeRequest(docRoot, depth = 2))
127+
page.storage.getCookies()
128+
}
129+
}
130+
}
131+
}
132+
}
133+
}
134+
}
135+
111136
@OptIn(ExperimentalChromeApi::class)
112137
@Test
113138
fun sessionThrowsIOExceptionIfAlreadyClosed() = runTestWithRealTime {

src/jvmTest/kotlin/ZenikaIntegrationTests.kt

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
import kotlinx.coroutines.*
22
import org.hildan.chrome.devtools.*
3-
import org.hildan.chrome.devtools.domains.dom.*
43
import org.hildan.chrome.devtools.protocol.*
5-
import org.hildan.chrome.devtools.sessions.*
64
import org.junit.jupiter.api.Test
75
import org.testcontainers.containers.*
86
import org.testcontainers.junit.jupiter.*
@@ -62,27 +60,4 @@ class ZenikaIntegrationTests : LocalIntegrationTestBase() {
6260
message = "the google.com page target should be closed, got:\n${targetsAfterClose.joinToString("\n")}",
6361
)
6462
}
65-
66-
@OptIn(ExperimentalChromeApi::class)
67-
@Test
68-
fun parallelPages() = runTestWithRealTime {
69-
withResourceServerForTestcontainers { baseUrl ->
70-
chromeWebSocket().use { browser ->
71-
// we want all coroutines to finish before we close the browser session
72-
withContext(Dispatchers.IO) {
73-
repeat(20) {
74-
launch {
75-
browser.newPage().use { page ->
76-
page.goto("$baseUrl/test-server-pages/basic.html")
77-
page.runtime.getHeapUsage()
78-
val docRoot = page.dom.getDocumentRootNodeId()
79-
page.dom.describeNode(DescribeNodeRequest(docRoot, depth = 2))
80-
page.storage.getCookies()
81-
}
82-
}
83-
}
84-
}
85-
}
86-
}
87-
}
8863
}

0 commit comments

Comments
 (0)