Module: Karst::Spec

Defined in:
lib/karst/spec/catalog.rb,
lib/karst/spec/observer.rb,
lib/karst/spec/reporter.rb,
lib/karst/spec/scenario.rb,
lib/karst/spec/principal.rb,
lib/karst/spec/example_observation.rb,
lib/karst/spec/request_observation.rb

Defined Under Namespace

Modules: Observer Classes: Catalog, InvalidMetadataError, Reporter

Constant Summary collapse

Scenario =

One RSpec example exercising one specific browser-facing controller/action request, built entirely from evidence already present in the JSON artifact Karst::Spec::Observer writes.

observed_status/observed_redirect describe what this spec execution observed while it ran, never what the example asserted -- a failing or pending example still produces a Scenario, and example_outcome is how a consumer tells "verified" apart from "merely observed."

An example that issues several browser-facing requests (a denied attempt followed by an allowed retry, a sign-in followed by the page it unlocks) legitimately produces one Scenario per such request: Karst never collapses an example down to "its last request," and never labels any request as authentication setup versus the subject under test.

principal_before/principal_after are both kept, not collapsed to whichever was active when the request began: a signup or checkout scenario that establishes a session is exactly the case where the identity a request produces matters as much as the identity it started with, and either side alone would discard real evidence.

Value.define(
  :example_id,
  :file_path,
  :line_number,
  :description_parts,
  :full_description,
  :karst_explicit,
  :karst_name,
  :example_outcome,
  :controller,
  :action,
  :http_method,
  :route_pattern,
  :observed_path,
  :observed_status,
  :observed_redirect,
  :principal_before,
  :principal_after,
  :principal_changed,
  :sequence
) do
  # The most specific zero-config name available without repeating the
  # whole describe chain: RSpec's own nesting already puts the most
  # specific description last. Never invents a persona the spec itself
  # did not name.
  def name
    karst_name || description_parts.last || full_description
  end

  def passed?
    example_outcome == :passed
  end

  def explicit?
    karst_explicit
  end
end
Principal =

Minimal principal evidence observed via Warden's public hooks during an RSpec example: class name and primary key only, never a serialized user object, mirroring Karst's runtime-evidence principal model.

Value.define(:type, :id, :scope)
ExampleObservation =

One RSpec example's complete observed request history: every request it issued, in order, plus enough of RSpec's own metadata (file/line, nested description, stable example id, pass/fail outcome) to present and re-locate the example without re-parsing spec source.

Value.define(
  :example_id,
  :file_path,
  :line_number,
  :spec_type,
  :description_parts,
  :full_description,
  :karst_explicit,
  :karst_name,
  :outcome,
  :requests
) do
  # An example is part of Karst's route/page catalog only if at least one
  # of its requests rendered HTML -- an examples whose only requests are
  # JSON API calls has nothing to show a person exercising a page.
  def browser_facing?
    requests.any? { |request| request.format == "html" }
  end
end
RequestObservation =

One HTTP request observed during a single RSpec example.

principal_before/principal_after are the active Warden principal immediately before and immediately after this request was processed; principal_changed is true when they differ -- a login, a logout, or a switch from one principal to another. This is raw observed evidence, not an interpretation of what the request was FOR. Karst does not classify a request as "setup" or "the subject under test": a signup route, an invitation-acceptance route, or a checkout-completion route that happens to establish a session is a legitimate subject request, not authentication plumbing, and a single request carries no reliable signal for telling those apart. That classification, if Karst ever offers one, belongs to catalog-building logic downstream of this observer, informed by more context than one request can supply.

Named http_method, not method, so it never shadows Object#method.

Value.define(
  :sequence,
  :http_method,
  :path,
  :route_pattern,
  :controller,
  :action,
  :format,
  :status,
  :redirect_location,
  :principal_before,
  :principal_after,
  :principal_changed
)