P1: Shared FixtureDataManager (empty + populated) for cross-platform snapshots
InMemoryDataManager + Fixtures with deterministic data (fixed clock 2026-04-15,
2 residences, 8 tasks, 3 contractors, 5 documents). FixtureDataManager.empty()
and .populated() factories. Exposed to Swift via SKIE.
Expanded IDataManager surface (5 -> 22 members) so fixtures cover every
StateFlow and lookup helper screens read: myResidences, allTasks,
tasksByResidence, documents, documentsByResidence, contractors, residenceTypes,
taskFrequencies, taskPriorities, taskCategories, contractorSpecialties,
taskTemplates, taskTemplatesGrouped, residenceSummaries, upgradeTriggers,
promotions, plus get{ResidenceType,TaskFrequency,TaskPriority,TaskCategory,
ContractorSpecialty}(id) lookup helpers. DataManager implementation is a pure
override-keyword addition — no behavior change.
Enables P2 (Android gallery) + P3 (iOS gallery) to render real screens against
identical inputs.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
package com.tt.honeyDue.testing
|
||||
|
||||
import com.tt.honeyDue.data.IDataManager
|
||||
|
||||
/**
|
||||
* Factories that produce deterministic [IDataManager] instances for the
|
||||
* parity-gallery (Android Roborazzi + iOS swift-snapshot-testing) and any
|
||||
* other snapshot/preview harness. Both platforms consume the same fixture
|
||||
* graph (via SKIE bridging on iOS), so any layout divergence between iOS
|
||||
* and Android renders of the same screen is a real parity bug — not a test
|
||||
* data mismatch.
|
||||
*
|
||||
* Use:
|
||||
* ```kotlin
|
||||
* // Android Compose preview or Roborazzi test
|
||||
* CompositionLocalProvider(LocalDataManager provides FixtureDataManager.empty()) {
|
||||
* MyScreen()
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* ```swift
|
||||
* // iOS SwiftUI preview or snapshot test
|
||||
* MyView().environment(\.dataManager,
|
||||
* DataManagerObservable(kotlin: FixtureDataManager.shared.populated()))
|
||||
* ```
|
||||
*/
|
||||
object FixtureDataManager {
|
||||
|
||||
/**
|
||||
* Data-free fixture — represents a freshly-signed-in user with no
|
||||
* residences, no tasks, no contractors, no documents. Lookups
|
||||
* (priorities, categories, frequencies) are still populated because
|
||||
* empty-state form pickers render them even before the user has any
|
||||
* entities of their own.
|
||||
*/
|
||||
fun empty(): IDataManager = InMemoryDataManager(
|
||||
currentUser = null,
|
||||
residences = emptyList(),
|
||||
myResidencesResponse = null,
|
||||
totalSummary = null,
|
||||
residenceSummaries = emptyMap(),
|
||||
allTasks = null,
|
||||
tasksByResidence = emptyMap(),
|
||||
documents = emptyList(),
|
||||
documentsByResidence = emptyMap(),
|
||||
contractors = emptyList(),
|
||||
subscription = Fixtures.freeSubscription,
|
||||
upgradeTriggers = emptyMap(),
|
||||
featureBenefits = Fixtures.featureBenefits,
|
||||
promotions = emptyList(),
|
||||
residenceTypes = Fixtures.residenceTypes,
|
||||
taskFrequencies = Fixtures.taskFrequencies,
|
||||
taskPriorities = Fixtures.taskPriorities,
|
||||
taskCategories = Fixtures.taskCategories,
|
||||
contractorSpecialties = Fixtures.contractorSpecialties,
|
||||
taskTemplates = Fixtures.taskTemplates,
|
||||
taskTemplatesGrouped = Fixtures.taskTemplatesGrouped,
|
||||
)
|
||||
|
||||
/**
|
||||
* Fully-populated fixture with realistic content for every screen:
|
||||
* 2 residences · 8 tasks (mix of overdue/due-soon/upcoming/completed)
|
||||
* · 3 contractors · 5 documents (2 warranties — one expired —
|
||||
* + 3 manuals). The user is premium-tier so gated surfaces render
|
||||
* their "pro" appearance.
|
||||
*/
|
||||
fun populated(): IDataManager = InMemoryDataManager(
|
||||
currentUser = Fixtures.user,
|
||||
residences = Fixtures.residences,
|
||||
myResidencesResponse = Fixtures.myResidencesResponse,
|
||||
totalSummary = Fixtures.totalSummary,
|
||||
residenceSummaries = Fixtures.residenceSummaries,
|
||||
allTasks = Fixtures.taskColumnsResponse,
|
||||
tasksByResidence = Fixtures.residences.associate { residence ->
|
||||
residence.id to Fixtures.taskColumnsResponse.copy(
|
||||
columns = Fixtures.taskColumnsResponse.columns.map { column ->
|
||||
val filtered = column.tasks.filter { it.residenceId == residence.id }
|
||||
column.copy(tasks = filtered, count = filtered.size)
|
||||
},
|
||||
residenceId = residence.id.toString(),
|
||||
)
|
||||
},
|
||||
documents = Fixtures.documents,
|
||||
documentsByResidence = Fixtures.documentsByResidence,
|
||||
contractors = Fixtures.contractorSummaries,
|
||||
subscription = Fixtures.premiumSubscription,
|
||||
upgradeTriggers = emptyMap(),
|
||||
featureBenefits = Fixtures.featureBenefits,
|
||||
promotions = emptyList(),
|
||||
residenceTypes = Fixtures.residenceTypes,
|
||||
taskFrequencies = Fixtures.taskFrequencies,
|
||||
taskPriorities = Fixtures.taskPriorities,
|
||||
taskCategories = Fixtures.taskCategories,
|
||||
contractorSpecialties = Fixtures.contractorSpecialties,
|
||||
taskTemplates = Fixtures.taskTemplates,
|
||||
taskTemplatesGrouped = Fixtures.taskTemplatesGrouped,
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user