xiaohongshu
xiaohongshu
fosmvvm-viewmodel-test-generator
Generate comprehensive ViewModel tests with multi-locale translation verification. Use when creating test coverage for ViewModels, especially those with localization.
Full skill instructions
Generate test files for ViewModels following FOSMVVM testing patterns.
For full architecture context, see FOSMVVMArchitecture.md
ViewModel testing in FOSMVVM verifies three critical aspects:
@LocalizedString properties have values in all supported localesThe LocalizableTestCase protocol provides infrastructure that tests all three in a single call.
@LocalizedSubs substitution behavior| File | Location | Purpose |
|---|---|---|
{Name}ViewModelTests.swift | Tests/{Target}Tests/Localization/ | Test suite conforming to LocalizableTestCase |
{Name}ViewModel.yml | Tests/{Target}Tests/TestYAML/ | YAML translations for test (if needed) |
For most ViewModels, a single line provides complete coverage:
@Test func dashboardViewModel() throws {
try expectFullViewModelTests(DashboardViewModel.self)
}
This verifies:
This is sufficient for the vast majority of ViewModel tests.
When testing specific formatting behavior (substitutions, compound strings), add locale-specific assertions:
@Test func greetingWithSubstitution() throws {
try expectFullViewModelTests(GreetingViewModel.self)
// Verify specific substitution behavior
let vm: GreetingViewModel = try .stub()
.toJSON(encoder: encoder(locale: en))
.fromJSON()
#expect(try vm.welcomeMessage.localizedString == "Welcome, John!")
}
This is optional - use only when verifying specific formatting techniques.
Test suites conform to LocalizableTestCase to access testing infrastructure:
import FOSFoundation
@testable import FOSMVVM
import FOSTesting
import Foundation
import Testing
@testable import {ViewModelsTarget}
@Suite("My ViewModel Tests")
struct MyViewModelTests: LocalizableTestCase {
let locStore: LocalizationStore
init() throws {
self.locStore = try Self.loadLocalizationStore(
bundle: {ViewModelsTarget}.resourceAccess,
resourceDirectoryName: ""
)
}
}
The {ViewModelsTarget}.resourceAccess is the resource accessor defined when creating the ViewModels SPM target (via FOSResourceAccessor build tool plugin).
| Property/Method | Purpose |
|---|---|
locStore | Required - the localization store |
locales | Optional - locales to test (default: en, es) |
encoder(locale:) | Creates a localizing JSONEncoder |
en, es, enGB, enUS | Locale constants |
| Method | Use When |
|---|---|
expectFullViewModelTests(_:) | Primary - complete ViewModel testing |
expectTranslations(_:) | Translation-only verification |
expectFullFieldValidationModelTests(_:) | Testing FieldValidationModel types |
expectFullFormFieldTests(_:) | Testing FormField instances |
expectCodable(_:encoder:) | Codable round-trip only |
expectVersionedViewModel(_:encoder:) | Versioning stability only |
Every ViewModel with @LocalizedString properties needs YAML entries:
@ViewModel
public struct DashboardViewModel: RequestableViewModel {
@LocalizedString public var pageTitle // Needs YAML entry
@LocalizedString public var emptyMessage // Needs YAML entry
public let itemCount: Int // No YAML needed
}
# DashboardViewModel.yml
en:
DashboardViewModel:
pageTitle: "Dashboard"
emptyMessage: "No items yet"
es:
DashboardViewModel:
pageTitle: "Tablero"
emptyMessage: "No hay elementos todavía"
When a ViewModel contains child ViewModels, all types in the hierarchy need YAML entries:
@ViewModel
public struct BoardViewModel: RequestableViewModel {
@LocalizedString public var title
public let cards: [CardViewModel] // Child ViewModel
}
@ViewModel
public struct CardViewModel {
@LocalizedString public var cardTitle
}
Both BoardViewModel and CardViewModel need YAML entries (can be in same or separate files).
When tests define private ViewModel structs for testing specific scenarios, those also need YAML:
// In test file
private struct TestParentViewModel: ViewModel {
@LocalizedString var title
let children: [TestChildViewModel]
}
private struct TestChildViewModel: ViewModel {
@LocalizedString var label
}
Add entries to a test YAML file for these private types.
Invocation: /fosmvvm-viewmodel-test-generator
Prerequisites:
Workflow integration: This skill is used when adding test coverage for ViewModels. The skill references conversation context automatically—no file paths or Q&A needed. Typically follows fosmvvm-viewmodel-generator.
This skill references conversation context to determine test structure:
From conversation context, the skill identifies:
Verifies completeness:
Creates test suite with:
Skill references information from:
See reference.md for complete file templates.
@Test func dashboardViewModel() throws {
try expectFullViewModelTests(DashboardViewModel.self)
}
@Test func boardViewModels() throws {
try expectFullViewModelTests(BoardViewModel.self)
try expectFullViewModelTests(ColumnViewModel.self)
try expectFullViewModelTests(CardViewModel.self)
}
var locales: Set<Locale> { [en, es, enGB] } // Override default
@Test func multiLocaleViewModel() throws {
try expectFullViewModelTests(MyViewModel.self)
// Tests en, es, AND en-GB
}
@Test func greetingSubstitutions() throws {
try expectFullViewModelTests(GreetingViewModel.self)
let vm: GreetingViewModel = try .stub(userName: "Alice")
.toJSON(encoder: encoder(locale: en))
.fromJSON()
#expect(try vm.welcomeMessage.localizedString == "Welcome, Alice!")
}
@Test func parentWithChildren() throws {
// Tests parent AND verifies children can be encoded/decoded
try expectFullViewModelTests(ParentViewModel.self)
// Optionally verify specific child values
let vm: ParentViewModel = try .stub()
.toJSON(encoder: encoder(locale: en))
.fromJSON()
#expect(try vm.children[0].label.localizedString == "Child 1")
}
FOSLocalizableError: _pageTitle -- Missing Translation -- en
Cause: YAML entry missing for a @LocalizedString property.
Fix: Add the property to the YAML file:
en:
MyViewModel:
pageTitle: "Page Title" # Add this
Cause: The ViewModel wasn't encoded with a localizing encoder.
Fix: Ensure using encoder(locale:) or expectFullViewModelTests().
Cause: YAML values exist but may have typos or wrong content.
Fix: Add specific assertions to verify exact values:
let vm = try .stub().toJSON(encoder: encoder(locale: en)).fromJSON()
#expect(try vm.title.localizedString == "Expected Value")
| Concept | Convention | Example |
|---|---|---|
| Test suite | {Feature}ViewModelTests | DashboardViewModelTests |
| Test file | {Feature}ViewModelTests.swift | DashboardViewModelTests.swift |
| YAML file | {ViewModelName}.yml | DashboardViewModel.yml |
| Test method | {viewModelName}() or descriptive | dashboardViewModel() |
| Version | Date | Changes |
|---|---|---|
| 1.0 | 2025-01-02 | Initial skill |
| 1.1 | 2026-01-19 | Updated LocalizableTestCase example to use {ViewModelsTarget}.resourceAccess pattern. |
| 1.2 | 2026-01-24 | Update to context-aware approach (remove file-parsing/Q&A). Skill references conversation context instead of asking questions or accepting file paths. |
xiaohongshu
technical spec
product ux expert
database patterns
Conduct multi-agent task orchestration and workflow coordination.
Initialize project with Conductor artifacts (product definition,
Expert in web animations, transitions, and motion design using Framer Motion and CSS
Creates Mermaid and ASCII diagrams for flowcharts, architecture, ERDs, state machines, mindmaps, and more. Use when user mentions diagram, flowchart, mermaid, ASCII diagram, text diagram, terminal diagram, visualize, C4, mindmap, architecture diagram, sequence diagram, ERD, or needs visual docume...
PostgreSQL bindings for H3 hexagonal grid system. Use when working with H3 cells in Postgres, including spatial indexing, geometry/geography integration, and raster analysis.
Context-Driven Development skill for projects using Conductor. Use this skill when you detect a `conductor/` directory in the project, when working on tasks defined in a `plan.md` file, or when the user asks about tracks, specs, or plans. Automatically applies TDD workflow, tracks task completion...
Display project status, active tracks, and next actions
Official Stakpak application containerization standard operating procedure, a step-by-step guidline to properly dockerize applications. This is a rule book curated by the Stakpak Team.
Generate, edit, and beat-sync AI video with leading models in one workspace.
The world's fastest calendar for remote work
Transform Your Design with AI Designer by ImgCreator.ai
Revolutionizing Video Production with AI-Powered Creativity
Extend an image past the frame and let AI fill the new aspect ratio.
Discover your celebrity doppelgänger with StarByFace!
ChainClarity explains 700+ crypto whitepapers in plain English, with layered summaries, comparisons, research tools, alerts, and a $4.99 Pro plan.
Opus.ai: Revolutionize Your Web Experience