diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index f09160e..d49ea86 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -27,6 +27,18 @@ "description": "React Native upgrade workflow covering updated templates, dependencies, and common pitfalls. Use when migrating a React Native app to a newer release.", "source": "./", "skills": ["./skills/upgrading-react-native"] + }, + { + "name": "rn-testing-and-debugging", + "description": "E2E testing framework comparison (Detox vs Maestro) and API failure simulation using MITMProxy. Covers CI setup, test authoring, and response overriding.", + "source": "./", + "skills": ["./skills/rn-testing-and-debugging"] + }, + { + "name": "rn-native-ios-tooling", + "description": "iOS dependency manager comparison (SPM vs Carthage vs CocoaPods), OSS licensing tools for mobile apps, and Objective-C to Swift migration strategies.", + "source": "./", + "skills": ["./skills/rn-native-ios-tooling"] } ] } diff --git a/skills/rn-native-ios-tooling/SKILL.md b/skills/rn-native-ios-tooling/SKILL.md new file mode 100644 index 0000000..1636b98 --- /dev/null +++ b/skills/rn-native-ios-tooling/SKILL.md @@ -0,0 +1,34 @@ +--- +name: rn-native-ios-tooling +description: Covers Objective-C to Swift migration strategies. Use when planning an ObjC to Swift migration. +license: MIT +metadata: + author: Callstack + tags: react-native, ios, objc, swift, migration +--- + +# React Native Native iOS Tooling + +## Overview + +Practical guidance for Objective-C to Swift migration in React Native projects. + +## When to Apply + +Reference these guidelines when: +- Planning a migration from Objective-C to Swift + +## Quick Reference + +| File | Description | +|------|-------------| +| [objc-to-swift-migration.md][objc-to-swift-migration] | ObjC → Swift migration checklist | + +## Problem → Skill Mapping + +| Problem | Start With | +|---------|------------| +| Planning ObjC to Swift migration | [objc-to-swift-migration.md][objc-to-swift-migration] | +| Migrating native module to Swift | [objc-to-swift-migration.md][objc-to-swift-migration] | + +[objc-to-swift-migration]: references/objc-to-swift-migration.md diff --git a/skills/rn-native-ios-tooling/references/objc-to-swift-migration.md b/skills/rn-native-ios-tooling/references/objc-to-swift-migration.md new file mode 100644 index 0000000..835666f --- /dev/null +++ b/skills/rn-native-ios-tooling/references/objc-to-swift-migration.md @@ -0,0 +1,197 @@ +--- +title: Objective-C to Swift Migration +impact: HIGH +tags: objc, swift, migration, ios, bridging-header, refactoring, native +--- + +# Skill: Objective-C to Swift Migration + +Plan and execute an Objective-C to Swift migration for iOS native code in React Native projects. + +## Quick Reference + +| Phase | Key Actions | +|-------|------------| +| Before | Investigate code, understand flows, simplify ObjC first | +| During | Migrate by module, use bridging headers, rewrite when needed | +| After | Migrate unit tests, update docs, apply SOLID principles | + +## When to Use + +- Planning migration of native iOS modules from ObjC to Swift +- React Native native module needs Swift rewrite +- Brownfield app has legacy ObjC code +- Team wants to leverage Swift-only features (async/await, structured concurrency) + +## Prerequisites + +- Xcode 15+ with Swift 5.9+ +- Understanding of both Objective-C and Swift +- Existing unit test coverage (or willingness to add it) +- Bridging header knowledge + +## Before Migration + +### 1. Investigate the Code + +- Map all ObjC files and their dependencies +- Identify interconnected modules and isolated components +- Document threading model, queuing, and dispatch patterns +- Note any C/C++ interop (Swift's C interop is more limited) + +### 2. Understand Flows and Threading + +- Trace execution paths through ObjC code +- Document GCD/NSOperationQueue usage patterns +- Identify main thread vs background thread boundaries +- Note any `@synchronized` blocks or locking mechanisms + +### 3. Simplify First + +Before migrating, clean up the ObjC: +- Remove dead code +- Break large classes into smaller ones +- Reduce coupling between modules +- Fix existing bugs (don't carry them into Swift) + +### 4. Plan the Migration Order + +Start with the **smallest-impact, most-isolated** module: +- Utility classes with no dependencies +- Data models / value objects +- Standalone helpers + +Work outward toward more connected code. + +## During Migration + +### 5. Migrate Module by Module + +**Do not attempt a "big bang" rewrite.** Migrate one module at a time: + +1. Create Swift file(s) for the module +2. Set up bridging header for ObjC → Swift interop +3. Migrate the implementation +4. Update callers to use the Swift version +5. Remove old ObjC files +6. Verify tests pass + +### 6. Use Bridging Headers + +**ObjC calling Swift:** +```objc +// Import the auto-generated Swift header +#import "MyApp-Swift.h" + +// Use Swift class +MySwiftClass *obj = [[MySwiftClass alloc] init]; +``` + +**Swift calling ObjC:** +```swift +// In MyApp-Bridging-Header.h, add: +// #import "MyObjCClass.h" + +// Then use directly in Swift +let obj = MyObjCClass() +``` + +**Tip**: Expose only what's needed via `@objc` and `@objcMembers`. Don't make everything visible. + +### 7. Don't Hesitate to Rewrite + +- Translating ObjC patterns 1:1 into Swift often produces poor Swift code +- Use Swift idioms: optionals instead of nil checks, enums with associated values, structs for value types +- Rewrite delegate patterns as closures where appropriate +- Replace NSNotificationCenter with Combine or async/await where practical + +### 8. Leverage Swift Features + +| ObjC Pattern | Swift Replacement | +|-------------|-------------------| +| Delegate + protocol | Closure / async-await | +| NSError** | throws / Result type | +| GCD dispatch_async | Task { } / structured concurrency | +| KVO | @Published + Combine | +| NSMutableArray | [Element] (value type) | +| Category | Extension | +| typedef enum | enum with raw values | + +### 9. Migrate Unit Tests Early + +- Migrate tests for a module **alongside** the module itself +- Swift tests can call both ObjC and Swift code +- Use XCTest's Swift API directly +- Don't leave test migration for "later" — it rarely happens + +### 10. Apply SOLID Principles + +Migration is an opportunity to improve architecture: +- **Single Responsibility**: Split classes that do too much +- **Open/Closed**: Use protocols for extensibility +- **Liskov Substitution**: Ensure protocol conformances are correct +- **Interface Segregation**: Prefer small, focused protocols +- **Dependency Inversion**: Inject dependencies rather than hard-coding + +## Documentation + +Keep documentation updated throughout: +- Update API docs as interfaces change +- Document any behavior changes (even if intentional improvements) +- Note breaking changes for consumers of the migrated code +- Update README with new Swift requirements + +## React Native Specific Considerations + +### Native Modules + +When migrating a RN native module from ObjC to Swift: + +```swift +import React + +@objc(MyModule) +class MyModule: NSObject { + @objc static func requiresMainQueueSetup() -> Bool { + return false + } + + @objc func doSomething( + _ resolve: @escaping RCTPromiseResolveBlock, + reject: @escaping RCTPromiseRejectBlock + ) { + resolve(["result": "success"]) + } +} +``` + +The `RCT_EXTERN_MODULE` macro still requires an ObjC file: + +```objc +// MyModule.m +#import + +@interface RCT_EXTERN_MODULE(MyModule, NSObject) +RCT_EXTERN_METHOD(doSomething: + (RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject) +@end +``` + +### Turbo Modules + +For New Architecture Turbo Modules, prefer Swift with `@objc` annotations. The codegen bridge handles the interop layer. + +## Common Pitfalls + +- **"Big bang" migration**: Migrating everything at once introduces too many bugs simultaneously +- **1:1 translation**: Produces un-idiomatic Swift code. Rewrite to use Swift patterns. +- **Ignoring threading differences**: Swift concurrency model differs from GCD patterns +- **Skipping test migration**: Leads to untested Swift code +- **Making everything @objcMembers**: Only expose what ObjC callers actually need +- **Not simplifying ObjC first**: Migrating messy ObjC produces messy Swift + +## Related Skills + +- [ios-dependency-managers.md](./ios-dependency-managers.md) — Dependencies may change during migration +- [oss-licensing-tools.md](./oss-licensing-tools.md) — Verify license compliance after dependency changes diff --git a/skills/rn-testing-and-debugging/SKILL.md b/skills/rn-testing-and-debugging/SKILL.md new file mode 100644 index 0000000..ccc6313 --- /dev/null +++ b/skills/rn-testing-and-debugging/SKILL.md @@ -0,0 +1,35 @@ +--- +name: rn-testing-and-debugging +description: Covers API failure simulation using MITMProxy for React Native and web apps. Use when simulating API failures during development. +license: MIT +metadata: + author: Callstack + tags: react-native, testing, mitmproxy, debugging, api +--- + +# React Native Testing & Debugging + +## Overview + +Practical guidance for API failure simulation. A MITMProxy-based solution for testing API error resilience. + +## When to Apply + +Reference these guidelines when: +- Simulating API failures or error responses during development +- Debugging API error handling in React Native or web apps + +## Quick Reference + +| File | Description | +|------|-------------| +| [api-failure-simulation.md][api-failure-simulation] | MITMProxy + Redis setup for API response overriding | + +## Problem → Skill Mapping + +| Problem | Start With | +|---------|------------| +| Need to simulate API errors | [api-failure-simulation.md][api-failure-simulation] | +| Test error handling without backend changes | [api-failure-simulation.md][api-failure-simulation] | + +[api-failure-simulation]: references/api-failure-simulation.md diff --git a/skills/rn-testing-and-debugging/references/api-failure-simulation.md b/skills/rn-testing-and-debugging/references/api-failure-simulation.md new file mode 100644 index 0000000..be09956 --- /dev/null +++ b/skills/rn-testing-and-debugging/references/api-failure-simulation.md @@ -0,0 +1,197 @@ +--- +title: API Failure Simulation +impact: MEDIUM +tags: mitmproxy, redis, api, debugging, testing, proxy, error-simulation +--- + +# Skill: API Failure Simulation + +Simulate API failures and override responses using MITMProxy + Redis + a companion Next.js UI, without modifying the backend. + +## Quick Command + +```bash +# Install dependencies +brew install mitmproxy redis + +# Start Redis +brew services start redis + +# Run MITMProxy with response override addon +mitmweb --listen-port 8080 -s ./filter.py +``` + +## When to Use + +- Testing app behavior when APIs return errors (500, 404, 403) +- Verifying error handling UI without backend changes +- Simulating network failures for specific endpoints +- QA needs to reproduce API-related bugs on demand +- Testing API error resilience in React Native or web apps + +## Prerequisites + +- macOS with Homebrew +- MITMProxy (`brew install mitmproxy`) +- Redis (`brew install redis`) +- Node.js for the companion Next.js UI +- FoxyProxy browser extension (for web app testing) + +## Step-by-Step Instructions + +### 1. Install and Configure MITMProxy + +```bash +brew install mitmproxy redis +brew services start redis +``` + +Run once to generate CA certificate: +```bash +mitmweb --listen-port 8080 +# Close after startup +``` + +Install the CA cert for HTTPS interception: +```bash +sudo security add-trusted-cert -d -p ssl -p basic \ + -k /Library/Keychains/System.keychain \ + ~/.mitmproxy/mitmproxy-ca-cert.pem +``` + +### 2. Install Redis for MITMProxy's Python + +MITMProxy uses its own Homebrew-managed Python. Install the Redis client into it: + +```bash +# Find MITMProxy's Python path +brew info mitmproxy +# Look for the Cellar path, e.g., /opt/homebrew/Cellar/mitmproxy/10.0.0 + +cd /opt/homebrew/Cellar/mitmproxy/10.0.0/libexec/bin +ls -la # Find the python symlink + +# Navigate to the actual Python installation +# Follow the symlink to find pip3 +cd ../../../../../opt/python@3.12/Frameworks/Python.framework/Versions/3.12/bin + +# Install redis package +./pip3 install redis --break-system-packages +``` + +### 3. Create the Filter Addon + +Create `filter.py` — the MITMProxy addon that reads override rules from Redis: + +```python +import redis + +class MyAddon: + def __init__(self): + self.r = redis.Redis(host='localhost', port=6379, db=0) + + def response(self, flow): + urls = [url.decode('utf-8') + for url in self.r.lrange('override:urls', 0, -1)] + data = [self.r.hgetall(f'override:{url}') for url in urls] + + match = None + for node in data: + if (b'enabled' in node + and node[b'enabled'] == b'true' + and node[b'urlMatch'].decode('utf-8') + in flow.request.url): + match = node + break + + if (match is not None + and flow.request.method != 'OPTIONS' + and (b'method' not in match + or match[b'method'].decode('utf-8') + == flow.request.method)): + flow.response.status_code = int(match[b'statusCode']) + if b'body' in match: + flow.response.content = match[b'body'] + +addons = [MyAddon()] +``` + +**How it works:** +1. On each intercepted response, check if any Redis-stored `urlMatch` pattern matches the request URL (partial match) +2. If a match is found and the rule is enabled, override the response status code and body +3. Skips OPTIONS requests (CORS preflight) +4. Optionally filters by HTTP method + +### 4. Set Up the Companion UI + +Clone the companion Next.js app for managing override rules: + +```bash +git clone https://github.com/Killavus/request-tester.git +cd request-tester +yarn +yarn dev --port 3002 +``` + +Open `http://localhost:3002` to create, toggle, and manage override rules via a web UI. + +### 5. Configure Browser Proxy (Web Apps) + +Install FoxyProxy extension for Chrome or Firefox: +1. Add proxy configuration pointing to `localhost:8080` +2. Enable the proxy when testing +3. Create override rules in the companion UI +4. Toggle rules on/off as needed + +### 6. Run the Full Stack + +```bash +# Terminal 1: Redis (if not already running as service) +brew services start redis + +# Terminal 2: MITMProxy with addon +mitmweb --listen-port 8080 -s ./filter.py + +# Terminal 3: Companion UI +cd request-tester && yarn dev --port 3002 +``` + +For self-signed certificate APIs, enable "Ignore server certificates" in MITMProxy web UI options. + +## Server-Side Interception + +For Next.js or Node-based server-side requests, use `node-fetch` with `https-proxy-agent`: + +```bash +npm install node-fetch https-proxy-agent +``` + +```javascript +import fetch from 'node-fetch'; +import { HttpsProxyAgent } from 'https-proxy-agent'; + +const agent = new HttpsProxyAgent('http://localhost:8080'); + +const response = await fetch('https://api.example.com/data', { + agent, +}); +``` + +This routes server-side requests through MITMProxy, enabling the same override rules. + +## Important Caveats + +- **Side effects still execute**: Overriding a DELETE endpoint's response to 500 still deletes the resource server-side. Only the *response* is modified. +- **HTTPS requires CA cert**: Without the CA cert installed, HTTPS interception fails silently. +- **Redis must be running**: The addon crashes if Redis is unavailable. + +## Common Pitfalls + +- **Forgetting to install Redis in MITMProxy's Python**: The addon imports `redis` from MITMProxy's bundled Python, not system Python +- **Not installing CA certificate**: HTTPS interception won't work without it +- **Expecting request blocking**: This tool overrides *responses*, not requests — the original request still reaches the server +- **FoxyProxy not active**: Ensure the proxy is enabled in the browser extension before testing + +## Related Skills + +- [detox-vs-maestro.md](./detox-vs-maestro.md) — E2E testing framework comparison