KarateUI中无法使用自定义配置文件启动Firefox问题
Karate启动Firefox加载SSL证书配置文件失败:Invalid byte 58错误
环境信息
- Karate版本:1.3.0
- Firefox版本:105.0.2
- 背景:此前通过Java+Selenium成功实现启动Firefox并使用指定SSL客户端证书,现需将该UI测试集成到Karate API测试套件中
问题代码
Scenario: * def session = {'capabilities': {'alwaysMatch': {'acceptInsecureCerts':true, 'moz:firefoxOptions': {'profile': 'classpath:FFProfile/ste7rob0.zip.b64','log': {'level': 'debug'}}}}} * def driverConfig = { type: 'geckodriver', showBrowserLog: true, showProcessLog: true, showDriverLog: true, executable: './src/test/resources/driver/mozilla/win64/geckodriver.exe'} * driverConfig.webDriverSession = session * configure driver = driverConfig Given driver monitorUrl
错误日志
18:20:16.267 [main] WARN com.intuit.karate - http response code: 500, response: {"value":{"error":"unknown error","message":"Invalid byte 58, offset 9.","stacktrace":""}}, request: POST http://localhost:4444/session 18:20:16.268 [main] ERROR c.intuit.karate.driver.DriverOptions - webdriver session create status 500, {"value":{"error":"unknown error","message":"Invalid byte 58, offset 9.","stacktrace":""}} 18:20:16.269 [main] ERROR com.intuit.karate - driver config / start failed: webdriver session create status 500, {"value":{"error":"unknown error","message":"Invalid byte 58, offset 9.","stacktrace":""}}, options: {type=geckodriver, showBrowserLog=true, showProcessLog=true, showDriverLog=true, executable=./src/test/resources/driver/mozilla/win64/geckodriver.exe, webDriverSession={capabilities={alwaysMatch={acceptInsecureCerts=true, moz:firefoxOptions={profile=classpath:FFProfile/ste7rob0.zip.b64, log={level=debug}}}}}, target=null} java.lang.RuntimeException: webdriver session create status 500, {"value":{"error":"unknown error","message":"Invalid byte 58, offset 9.","stacktrace":""}} at com.intuit.karate.driver.WebDriver.<init>(WebDriver.java:67) at com.intuit.karate.driver.firefox.GeckoWebDriver.<init>(GeckoWebDriver.java:42) at com.intuit.karate.driver.firefox.GeckoWebDriver.start(GeckoWebDriver.java:48) at com.intuit.karate.driver.DriverOptions.start(DriverOptions.java:316) at com.intuit.karate.core.ScenarioEngine.driver(ScenarioEngine.java:881) at com.intuit.karate.ScenarioActions.driver(ScenarioActions.java:426) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:568) at com.intuit.karate.core.StepRuntime.execute(StepRuntime.java:296) at com.intuit.karate.core.ScenarioRuntime.execute(ScenarioRuntime.java:449) at com.intuit.karate.core.ScenarioRuntime.run(ScenarioRuntime.java:400) at com.intuit.karate.core.FeatureRuntime.processScenario(FeatureRuntime.java:199) at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:179) at com.intuit.karate.core.ScenarioIterator.tryAdvance(ScenarioIterator.java:162) at java.base/java.util.Spliterator.forEachRemaining(Spliterator.java:332) at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509) at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499) at java.base/java.util.stream.StreamSpliterators$WrappingSpliterator.forEachRemaining(StreamSpliterators.java:310) at java.base/java.util.Spliterators$1Adapter.forEachRemaining(Spliterators.java:706) at com.intuit.karate.core.FeatureRuntime.run(FeatureRuntime.java:182) at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:539) at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) at com.intuit.karate.core.SyncExecutorService.execute(SyncExecutorService.java:70) at java.base/java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:123) at com.intuit.karate.Suite.run(Suite.java:237) at com.intuit.karate.Runner$Builder.parallel(Runner.java:496) at com.intuit.karate.cli.IdeMain.main(IdeMain.java:60) at cucumber.api.cli.Main.main(Main.java:34) 18:20:16.270 [main] ERROR com.intuit.karate - src/test/java/splmonitor/TC3.acces_autorizat.feature:12 Given driver monitorUrl driver config / start failed: webdriver session create status 500, {"value":{"error":"unknown error","message":"Invalid byte 58, offset 9.","stacktrace":""}}, options: {type=geckodriver, showBrowserLog=true, showProcessLog=true, showDriverLog=true, executable=./src/test/resources/driver/mozilla/win64/geckodriver.exe, webDriverSession={capabilities={alwaysMatch={acceptInsecureCerts=true, moz:firefoxOptions={profile=classpath:FFProfile/ste7rob0.zip.b64, log={level=debug}}}}}, target=null} src/test/java/splmonitor/TC3.acces_autorizat.feature:12 18:20:16.270 [geckodriver_1674836415732] WARN com.intuit.karate.shell.Command - exit code was non-zero: 1 - [C:\QA\workspace2022\aliaspay-test-engine\.\src\test\resources\driver\mozilla\win64\geckodriver.exe, --port=4444] working dir: target\geckodriver_1674836415732
问题分析
错误信息里的Invalid byte 58对应ASCII码的冒号(:),说明Geckodriver在解析base64格式的Firefox配置文件时,遇到了非base64字符。
问题出在代码里的profile: 'classpath:FFProfile/ste7rob0.zip.b64':classpath:是Karate自身的资源路径前缀,Geckodriver并不识别这个前缀,会把整个字符串(包括classpath:)当成base64内容解析,但冒号不属于base64允许的字符集(仅允许A-Z、a-z、0-9、+、/、=),因此触发解析错误。
解决方案
用Karate的read()函数读取配置文件的纯base64内容,再传递给moz:firefoxOptions的profile参数:
Scenario: * def profileBase64 = read('classpath:FFProfile/ste7rob0.zip.b64') * def session = {'capabilities': {'alwaysMatch': {'acceptInsecureCerts':true, 'moz:firefoxOptions': {'profile': profileBase64,'log': {'level': 'debug'}}}}} * def driverConfig = { type: 'geckodriver', showBrowserLog: true, showProcessLog: true, showDriverLog: true, executable: './src/test/resources/driver/mozilla/win64/geckodriver.exe'} * driverConfig.webDriverSession = session * configure driver = driverConfig Given driver monitorUrl
说明
read('classpath:FFProfile/ste7rob0.zip.b64')会自动读取classpath下指定文件的纯文本内容(即正确的base64字符串),不会将classpath:前缀传递给Geckodriver,这样Geckodriver就能正常解析配置文件,启动带有指定SSL证书的Firefox实例。
内容的提问来源于stack exchange,提问作者Eduard Stoleru
相关产品推荐
相关产品推荐

