code: def test_plot_forecasts_by_step(valid_bm):
      bm = valid_bm
  
      # default value
      fig = bm.plot_forecasts_by_step(forecast_step=1)
      assert fig.layout.showlegend
      assert fig.layout.xaxis.title.text == TIME_COL
      assert fig.layout.yaxis.title.text == VALUE_COL
      assert fig.layout.title.text == "1-step ahead rolling forecasts"
      assert fig.layout.title.x == 0.5
  
      # len(fig.data) = 1 + len(config_keys)
      assert len(fig.data) == 1 + len(bm.configs)
  
      assert fig.data[0].name == ACTUAL_COL
      assert fig.data[1].name == "valid_prophet_forecast"
      assert fig.data[2].name == "valid_silverkite_forecast"
  
      # custom value
      fig = bm.plot_forecasts_by_step(
          forecast_step=5,
          config_names=["valid_silverkite"],
          xlabel="xlab",
          ylabel="ylab",
          title="title",
          showlegend=False,
      )
      assert not fig.layout.showlegend
      assert fig.layout.xaxis.title.text == "xlab"
      assert fig.layout.yaxis.title.text == "ylab"
      assert fig.layout.title.text == "title"
      assert fig.layout.title.x == 0.5
  
      # len(fig.data) = 1 + len(config_names)
      assert len(fig.data) == 1 + 1
      assert fig.data[0].name == ACTUAL_COL
      assert fig.data[1].name == "valid_silverkite_forecast"
      # # error due to wrong config key
      # # error due to wrong forecast step is checked in test_plot_multivariate_grouped
      missing_keys = {"missing_config"}
      with pytest.raises(
          ValueError,
          match=f"The following config keys are missing: {missing_keys}",
      ):
          bm.plot_forecasts_by_step(
              forecast_step=1, config_names=["missing_config"]
          )
  
      # Error due to forecast_step > forecast_horizon
      forecast_step = 20
      with pytest.raises(
          ValueError,
          match=rf"`forecast_step` \({forecast_step}\) must be less than or equal "
          rf"to forecast horizon \({bm.tscv.forecast_horizon}\).",
      ):
          bm.plot_forecasts_by_step(forecast_step=forecast_step)
  
imports: import pickle
  import sys
  import numpy
  import pandas
  import pytest
  from plotly.colors import DEFAULT_PLOTLY_COLORS
  from greykite.algo.forecast.silverkite.constants.silverkite_holiday import SilverkiteHoliday
  from greykite.common.constants import ACTUAL_COL
  from greykite.common.constants import PREDICTED_COL
  from greykite.common.constants import PREDICTED_LOWER_COL
  from greykite.common.constants import PREDICTED_UPPER_COL
  from greykite.common.constants import TIME_COL
  from greykite.common.constants import VALUE_COL
  from greykite.common.evaluation import EvaluationMetricEnum
  from greykite.common.evaluation import root_mean_squared_error
  from greykite.common.python_utils import assert_equal
  from greykite.common.testing_utils import generate_df_with_reg_for_tests
  from greykite.framework.benchmark.benchmark_class import BenchmarkForecastConfig
  from greykite.framework.constants import FORECAST_STEP_COL
  from greykite.framework.templates.autogen.forecast_config import ComputationParam
  from greykite.framework.templates.autogen.forecast_config import EvaluationMetricParam
  from greykite.framework.templates.autogen.forecast_config import EvaluationPeriodParam
  from greykite.framework.templates.autogen.forecast_config import ForecastConfig
  from greykite.framework.templates.autogen.forecast_config import MetadataParam
  from greykite.framework.templates.autogen.forecast_config import ModelComponentsParam
  from greykite.framework.templates.forecaster import Forecaster
  from greykite.framework.templates.model_templates import ModelTemplateEnum
  from greykite.sklearn.cross_validation import RollingTimeSeriesSplit
label_desc: Use image node_id 10 for calling a global function with example usage: test_plot_forecasts_by_step(valid_bm) without return types