@@ -29,6 +29,13 @@ case class CucumberOptions(
2929 * Mix this trait into your test class and define the `cucumberOptions` value
3030 * to configure the Cucumber runtime.
3131 *
32+ * Options can be configured via:
33+ * - The `cucumberOptions` value (programmatic configuration, takes
34+ * precedence)
35+ * - cucumber.properties file on the classpath
36+ * - Environment variables starting with CUCUMBER_
37+ * - System properties starting with cucumber.
38+ *
3239 * Example:
3340 * {{{
3441 * import io.cucumber.scalatest.{CucumberOptions, CucumberSuite}
@@ -50,6 +57,8 @@ trait CucumberSuite extends Suite {
5057 */
5158 def cucumberOptions : CucumberOptions = CucumberOptions ()
5259
60+ private lazy val classLoader : ClassLoader = getClass.getClassLoader
61+
5362 /** Runs the Cucumber scenarios.
5463 *
5564 * @param testName
@@ -98,7 +107,44 @@ trait CucumberSuite extends Suite {
98107 val packageName = getClass.getPackage.getName
99108 val builder = new RuntimeOptionsBuilder ()
100109
101- // Add features
110+ // Parse options from cucumber.properties file on classpath
111+ scala.util.Try {
112+ val propertiesUrl = classLoader.getResource(" cucumber.properties" )
113+ if (propertiesUrl != null ) {
114+ val props = new java.util.Properties ()
115+ val is = propertiesUrl.openStream()
116+ try {
117+ props.load(is)
118+ } finally {
119+ is.close()
120+ }
121+ import scala .jdk .CollectionConverters ._
122+ props.asScala.foreach { case (key, value) =>
123+ applyProperty(builder, key.toString, value.toString)
124+ }
125+ }
126+ }
127+
128+ // Parse options from environment variables (CUCUMBER_*)
129+ scala.util.Try {
130+ sys.env.foreach { case (key, value) =>
131+ if (key.startsWith(" CUCUMBER_" )) {
132+ val propertyName = key.substring(9 ).toLowerCase.replace('_' , '.' )
133+ applyProperty(builder, " cucumber." + propertyName, value)
134+ }
135+ }
136+ }
137+
138+ // Parse options from system properties (cucumber.*)
139+ scala.util.Try {
140+ sys.props.foreach { case (key, value) =>
141+ if (key.startsWith(" cucumber." )) {
142+ applyProperty(builder, key, value)
143+ }
144+ }
145+ }
146+
147+ // Add features (programmatic options take precedence)
102148 val features =
103149 if (cucumberOptions.features.nonEmpty) cucumberOptions.features
104150 else List (" classpath:" + packageName.replace('.' , '/' ))
@@ -132,4 +178,33 @@ trait CucumberSuite extends Suite {
132178
133179 builder.build()
134180 }
181+
182+ private def applyProperty (
183+ builder : RuntimeOptionsBuilder ,
184+ key : String ,
185+ value : String
186+ ): Unit = {
187+ // Map property keys to builder methods
188+ key match {
189+ case " cucumber.glue" =>
190+ value.split(" ," ).foreach { g =>
191+ builder.addGlue(java.net.URI .create(" classpath:" + g.trim))
192+ }
193+ case " cucumber.plugin" =>
194+ value.split(" ," ).foreach { p =>
195+ builder.addPluginName(p.trim)
196+ }
197+ case " cucumber.tags" | " cucumber.filter.tags" =>
198+ builder.addTagFilter(
199+ io.cucumber.tagexpressions.TagExpressionParser .parse(value)
200+ )
201+ case " cucumber.features" =>
202+ value.split(" ," ).foreach { f =>
203+ builder.addFeature(
204+ io.cucumber.core.feature.FeatureWithLines .parse(f.trim)
205+ )
206+ }
207+ case _ => // Ignore unknown properties
208+ }
209+ }
135210}
0 commit comments