extends "res://addons/gut/test.gd" const SCENE := "res://scenes/shell/NarrationBook.tscn" const FakeTransport = preload("res://tests/doubles/fake_transport.gd") const DmResponse = preload("res://scripts/net/dm_response.gd") func _book_with(response) -> NarrationBook: var transport = FakeTransport.new() transport.set_response(response) var service := DmService.new(transport, FallbackLibrary.new()) var book = load(SCENE).instantiate() add_child_autofree(book) # _ready() builds nodes + the considering indicator book.setup(service, CanonLog.new(), ShellState.seed()) return book func test_narrate_shows_prose_and_harvests_facts(): var book := _book_with(DmResponse.ok(200, {"prose": "The rain runs black into the gutter. [FACT: the eastern bridge is out]"})) var log := CanonLog.new() var transport = FakeTransport.new() transport.set_response(DmResponse.ok(200, {"prose": "The rain runs black into the gutter. [FACT: the eastern bridge is out]"})) book.setup(DmService.new(transport, FallbackLibrary.new()), log, ShellState.seed()) await book.narrate() assert_string_contains(book._prose.text, "The rain runs black into the gutter.") assert_false(book._prose.text.contains("[FACT"), "tags are stripped from displayed prose") assert_true("the eastern bridge is out" in log.established_facts, "fact harvested to the log") assert_false(book.last_degraded) func test_degraded_response_shows_fallback_and_sets_flag(): var book := _book_with(DmResponse.failed("proxy down")) await book.narrate() assert_true(book.last_degraded, "a failed call degrades") assert_ne(book._prose.text, "", "the fallback line is still shown (ยง13)")