Skip to content

Commit ffdbaac

Browse files
committed
Add workaround for optional Cookie.expired field
See ChromeDevTools/devtools-protocol#317 Resolves: #494
1 parent dbeb9fc commit ffdbaac

File tree

8 files changed

+90
-13
lines changed

8 files changed

+90
-13
lines changed

api/chrome-devtools-kotlin.api

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29141,8 +29141,8 @@ public final class org/hildan/chrome/devtools/domains/network/ContinueIntercepte
2914129141

2914229142
public final class org/hildan/chrome/devtools/domains/network/Cookie {
2914329143
public static final field Companion Lorg/hildan/chrome/devtools/domains/network/Cookie$Companion;
29144-
public fun <init> (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;DIZZZLorg/hildan/chrome/devtools/domains/network/CookieSameSite;Lorg/hildan/chrome/devtools/domains/network/CookiePriority;Ljava/lang/Boolean;Lorg/hildan/chrome/devtools/domains/network/CookieSourceScheme;Ljava/lang/Integer;Lorg/hildan/chrome/devtools/domains/network/CookiePartitionKey;Ljava/lang/Boolean;)V
29145-
public synthetic fun <init> (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;DIZZZLorg/hildan/chrome/devtools/domains/network/CookieSameSite;Lorg/hildan/chrome/devtools/domains/network/CookiePriority;Ljava/lang/Boolean;Lorg/hildan/chrome/devtools/domains/network/CookieSourceScheme;Ljava/lang/Integer;Lorg/hildan/chrome/devtools/domains/network/CookiePartitionKey;Ljava/lang/Boolean;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
29144+
public fun <init> (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Double;IZZZLorg/hildan/chrome/devtools/domains/network/CookieSameSite;Lorg/hildan/chrome/devtools/domains/network/CookiePriority;Ljava/lang/Boolean;Lorg/hildan/chrome/devtools/domains/network/CookieSourceScheme;Ljava/lang/Integer;Lorg/hildan/chrome/devtools/domains/network/CookiePartitionKey;Ljava/lang/Boolean;)V
29145+
public synthetic fun <init> (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Double;IZZZLorg/hildan/chrome/devtools/domains/network/CookieSameSite;Lorg/hildan/chrome/devtools/domains/network/CookiePriority;Ljava/lang/Boolean;Lorg/hildan/chrome/devtools/domains/network/CookieSourceScheme;Ljava/lang/Integer;Lorg/hildan/chrome/devtools/domains/network/CookiePartitionKey;Ljava/lang/Boolean;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
2914629146
public final fun component1 ()Ljava/lang/String;
2914729147
public final fun component10 ()Lorg/hildan/chrome/devtools/domains/network/CookieSameSite;
2914829148
public final fun component11 ()Lorg/hildan/chrome/devtools/domains/network/CookiePriority;
@@ -29154,16 +29154,16 @@ public final class org/hildan/chrome/devtools/domains/network/Cookie {
2915429154
public final fun component2 ()Ljava/lang/String;
2915529155
public final fun component3 ()Ljava/lang/String;
2915629156
public final fun component4 ()Ljava/lang/String;
29157-
public final fun component5 ()D
29157+
public final fun component5 ()Ljava/lang/Double;
2915829158
public final fun component6 ()I
2915929159
public final fun component7 ()Z
2916029160
public final fun component8 ()Z
2916129161
public final fun component9 ()Z
29162-
public final fun copy (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;DIZZZLorg/hildan/chrome/devtools/domains/network/CookieSameSite;Lorg/hildan/chrome/devtools/domains/network/CookiePriority;Ljava/lang/Boolean;Lorg/hildan/chrome/devtools/domains/network/CookieSourceScheme;Ljava/lang/Integer;Lorg/hildan/chrome/devtools/domains/network/CookiePartitionKey;Ljava/lang/Boolean;)Lorg/hildan/chrome/devtools/domains/network/Cookie;
29163-
public static synthetic fun copy$default (Lorg/hildan/chrome/devtools/domains/network/Cookie;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;DIZZZLorg/hildan/chrome/devtools/domains/network/CookieSameSite;Lorg/hildan/chrome/devtools/domains/network/CookiePriority;Ljava/lang/Boolean;Lorg/hildan/chrome/devtools/domains/network/CookieSourceScheme;Ljava/lang/Integer;Lorg/hildan/chrome/devtools/domains/network/CookiePartitionKey;Ljava/lang/Boolean;ILjava/lang/Object;)Lorg/hildan/chrome/devtools/domains/network/Cookie;
29162+
public final fun copy (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Double;IZZZLorg/hildan/chrome/devtools/domains/network/CookieSameSite;Lorg/hildan/chrome/devtools/domains/network/CookiePriority;Ljava/lang/Boolean;Lorg/hildan/chrome/devtools/domains/network/CookieSourceScheme;Ljava/lang/Integer;Lorg/hildan/chrome/devtools/domains/network/CookiePartitionKey;Ljava/lang/Boolean;)Lorg/hildan/chrome/devtools/domains/network/Cookie;
29163+
public static synthetic fun copy$default (Lorg/hildan/chrome/devtools/domains/network/Cookie;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Double;IZZZLorg/hildan/chrome/devtools/domains/network/CookieSameSite;Lorg/hildan/chrome/devtools/domains/network/CookiePriority;Ljava/lang/Boolean;Lorg/hildan/chrome/devtools/domains/network/CookieSourceScheme;Ljava/lang/Integer;Lorg/hildan/chrome/devtools/domains/network/CookiePartitionKey;Ljava/lang/Boolean;ILjava/lang/Object;)Lorg/hildan/chrome/devtools/domains/network/Cookie;
2916429164
public fun equals (Ljava/lang/Object;)Z
2916529165
public final fun getDomain ()Ljava/lang/String;
29166-
public final fun getExpires ()D
29166+
public final fun getExpires ()Ljava/lang/Double;
2916729167
public final fun getHttpOnly ()Z
2916829168
public final fun getName ()Ljava/lang/String;
2916929169
public final fun getPartitionKey ()Lorg/hildan/chrome/devtools/domains/network/CookiePartitionKey;

build.gradle.kts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,10 @@ tasks.dokkaHtml {
145145
dependsOn(generateProtocolApi)
146146
}
147147

148+
tasks.apiDump {
149+
dependsOn(generateProtocolApi)
150+
}
151+
148152
changelog {
149153
githubUser = github.user
150154
futureVersionTag = project.version.toString()

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

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,11 @@ package org.hildan.chrome.devtools.protocol.generator
33
import com.squareup.kotlinpoet.FileSpec
44
import org.hildan.chrome.devtools.protocol.json.ChromeProtocolDescriptor
55
import org.hildan.chrome.devtools.protocol.json.TargetType
6-
import org.hildan.chrome.devtools.protocol.json.pullNestedEnumsToTopLevel
76
import org.hildan.chrome.devtools.protocol.model.ChromeDPDomain
87
import org.hildan.chrome.devtools.protocol.model.toChromeDPDomain
98
import org.hildan.chrome.devtools.protocol.names.Annotations
109
import org.hildan.chrome.devtools.protocol.names.ExtDeclarations
11-
import java.nio.file.Files
10+
import org.hildan.chrome.devtools.protocol.preprocessing.preprocessed
1211
import java.nio.file.Path
1312
import kotlin.io.path.*
1413

@@ -31,7 +30,7 @@ class Generator(
3130
generatedSourcesDir.deleteRecursively()
3231
generatedSourcesDir.createDirectories()
3332

34-
val domains = loadProtocolDomains()
33+
val domains = readProtocolDomains()
3534
domains.forEach(::generateDomainFiles)
3635

3736
val domainsByName = domains.associateBy { it.names.domainName }
@@ -52,12 +51,12 @@ class Generator(
5251
generateChildSessionsFiles(childTargets = targets.filterNot { it.kotlinName == "Browser" })
5352
}
5453

55-
private fun loadProtocolDomains(): List<ChromeDPDomain> {
54+
private fun readProtocolDomains(): List<ChromeDPDomain> {
5655
val descriptors = protocolFiles.map { ChromeProtocolDescriptor.fromJson(it.readText()) }
5756
if (descriptors.distinctBy { it.version }.size > 1) {
5857
error("Some descriptors have differing versions: ${descriptors.map { it.version }}")
5958
}
60-
return descriptors.flatMap { it.domains }.map { it.pullNestedEnumsToTopLevel().toChromeDPDomain() }
59+
return descriptors.flatMap { it.domains }.preprocessed().map { it.toChromeDPDomain() }
6160
}
6261

6362
private fun generateDomainFiles(domain: ChromeDPDomain) {
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
package org.hildan.chrome.devtools.protocol.json
1+
package org.hildan.chrome.devtools.protocol.preprocessing
22

3+
import org.hildan.chrome.devtools.protocol.json.*
34
import org.hildan.chrome.devtools.protocol.names.*
45

56
// Workaround for https://github.com/ChromeDevTools/devtools-protocol/issues/244
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package org.hildan.chrome.devtools.protocol.preprocessing
2+
3+
import org.hildan.chrome.devtools.protocol.json.JsonDomain
4+
import org.hildan.chrome.devtools.protocol.json.JsonDomainParameter
5+
import org.hildan.chrome.devtools.protocol.json.JsonDomainType
6+
7+
/**
8+
* Pre-processes the list of domains from the JSON definitions to work around some issues in the definitions themselves.
9+
*/
10+
internal fun List<JsonDomain>.preprocessed(): List<JsonDomain> = this
11+
// Workaround for https://github.com/ChromeDevTools/devtools-protocol/issues/317
12+
.transformDomainTypeProperty("Network", "Cookie", "expires") { it.copy(optional = true) }
13+
// Workaround for https://github.com/ChromeDevTools/devtools-protocol/issues/244
14+
.map { it.pullNestedEnumsToTopLevel() }
15+
16+
private fun List<JsonDomain>.transformDomainTypeProperty(
17+
domain: String,
18+
type: String,
19+
property: String,
20+
transform: (JsonDomainParameter) -> JsonDomainParameter,
21+
): List<JsonDomain> = transformDomain(domain) { d ->
22+
d.transformType(type) { t ->
23+
t.transformProperty(property, transform)
24+
}
25+
}
26+
27+
private fun List<JsonDomain>.transformDomain(
28+
name: String,
29+
transform: (JsonDomain) -> JsonDomain,
30+
): List<JsonDomain> = transformIf({ it.domain == name }) { transform(it) }
31+
32+
private fun JsonDomain.transformType(
33+
name: String,
34+
transform: (JsonDomainType) -> JsonDomainType,
35+
): JsonDomain = copy(types = types.transformIf({ it.id == name }) { transform(it) })
36+
37+
private fun JsonDomainType.transformProperty(
38+
name: String,
39+
transform: (JsonDomainParameter) -> JsonDomainParameter,
40+
): JsonDomainType = copy(properties = properties.transformIf({ it.name == name }) { transform(it) })
41+
42+
private fun <T> List<T>.transformIf(predicate: (T) -> Boolean, transform: (T) -> T): List<T> =
43+
map { if (predicate(it)) transform(it) else it }

src/commonMain/kotlin/org/hildan/chrome/devtools/extensions/CrossDomainExtensions.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@ suspend fun PageSession.clickOnElement(
2020
clickDuration: Duration = 100.milliseconds,
2121
mouseButton: MouseButton = MouseButton.left,
2222
) {
23-
val box = dom.getBoxModel(selector) ?: error("Cannot click on element, no node found using selector '$selector'")
23+
val box = dom.getBoxModel(selector)
24+
?: error("Cannot click on element, no node found using selector '$selector'. " +
25+
"If the node might appear later, use PageSession.dom.awaitNodeBySelector(...) first.")
2426
val elementCenter = box.content.center
2527

2628
input.dispatchMouseClick(

src/jvmTest/kotlin/IntegrationTestBase.kt

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
import io.ktor.client.*
22
import io.ktor.client.plugins.websocket.*
33
import kotlinx.coroutines.*
4+
import kotlinx.coroutines.flow.first
45
import kotlinx.serialization.*
56
import kotlinx.serialization.json.*
67
import org.hildan.chrome.devtools.domains.accessibility.*
78
import org.hildan.chrome.devtools.domains.backgroundservice.*
89
import org.hildan.chrome.devtools.domains.dom.*
910
import org.hildan.chrome.devtools.domains.domdebugger.*
1011
import org.hildan.chrome.devtools.domains.runtime.*
12+
import org.hildan.chrome.devtools.extensions.clickOnElement
1113
import org.hildan.chrome.devtools.protocol.*
1214
import org.hildan.chrome.devtools.protocol.json.*
1315
import org.hildan.chrome.devtools.sessions.*
@@ -291,6 +293,27 @@ abstract class IntegrationTestBase {
291293
}
292294
}
293295

296+
@OptIn(ExperimentalChromeApi::class)
297+
@Test
298+
open fun missingExpiresInCookie() {
299+
runBlockingWithTimeout {
300+
chromeWebSocket().use { browser ->
301+
browser.newPage().use { page ->
302+
page.goto("https://x.com")
303+
page.network.enable()
304+
coroutineScope {
305+
launch {
306+
// ensures we don't crash on deserialization
307+
page.network.responseReceivedExtraInfoEvents().first()
308+
}
309+
page.dom.awaitNodeBySelector("a[href=\"/login\"]")
310+
page.clickOnElement("a[href=\"/login\"]")
311+
}
312+
}
313+
}
314+
}
315+
}
316+
294317
protected fun runBlockingWithTimeout(block: suspend CoroutineScope.() -> Unit) = runBlocking {
295318
withTimeout(1.minutes, block)
296319
}

src/jvmTest/kotlin/ZenikaIntegrationTests.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import org.testcontainers.containers.*
22
import org.testcontainers.junit.jupiter.*
33
import org.testcontainers.junit.jupiter.Container
44
import org.testcontainers.utility.*
5+
import kotlin.test.Ignore
56

67
@Testcontainers
78
class ZenikaIntegrationTests : LocalIntegrationTestBase() {
@@ -23,4 +24,8 @@ class ZenikaIntegrationTests : LocalIntegrationTestBase() {
2324

2425
override val wsConnectUrl: String
2526
get() = "http://localhost:${zenikaChrome.firstMappedPort}"
27+
28+
@Ignore("The Zenika container seems out of data and still treats cookiePartitionKey as a string instead of object")
29+
override fun missingExpiresInCookie() {
30+
}
2631
}

0 commit comments

Comments
 (0)