From 0e10b59dcfbdbb2adb39dd9c6d7f1ffbde0fcde0 Mon Sep 17 00:00:00 2001 From: Kieran Osgood Date: Tue, 15 Jul 2025 11:03:17 +0100 Subject: [PATCH 1/4] feat: add cursor rules for improving usage on swift --- .cursor/rules/swift-development.mdc | 75 +++++++++++++++++++++++++++++ .cursor/rules/swift-test.mdc | 71 +++++++++++++++++++++++++++ 2 files changed, 146 insertions(+) create mode 100644 .cursor/rules/swift-development.mdc create mode 100644 .cursor/rules/swift-test.mdc diff --git a/.cursor/rules/swift-development.mdc b/.cursor/rules/swift-development.mdc new file mode 100644 index 00000000..ff5761e8 --- /dev/null +++ b/.cursor/rules/swift-development.mdc @@ -0,0 +1,75 @@ +--- +description: Swift development workflow and language server workarounds +globs: ["**/*.swift"] +alwaysApply: true +--- + +# SWIFT DEVELOPMENT WORKFLOW + +## ⚠️ IMPORTANT: Language Server Issues + +**IGNORE ALL LANGUAGE SERVER ERRORS IN SWIFT FILES** +- The language server reports errors erroneously while code compiles fine +- Do NOT trust red squiggles or inline error messages +- Always verify issues using the commands below instead + +## Verification Commands + +### Check your work systematically: +1. **Lint & Format** → `dev lint` (or `dev style`) +2. **Build Issues** → `dev build` +3. **Test Issues** → `dev test` +4. **All Checks** → `dev check` (runs everything) + +### Available dev commands: +```bash +# Code Quality +dev lint # Check format & lint issues (alias: dev style) +dev fix # Auto-fix format & lint issues + +# Building +dev build packages # Build ShopifyCheckoutSheetKit & ShopifyAcceleratedCheckouts +dev build samples # Build sample apps + +# Testing +dev test packages # Test the packages +dev test samples # Test sample apps + +# Apollo/GraphQL +dev apollo download_schema # Download GraphQL schema +dev apollo codegen # Generate Apollo client code +``` + +## Workflow Best Practices + +### Before committing: +1. Run `dev lint` to ensure code style compliance +2. Run `dev build` to verify compilation +3. Run `dev test` if you've modified functionality +4. Or just run `dev check` to do all of the above + +### When you see errors: +❌ DON'T: Trust language server errors in Xcode/editor +✅ DO: Run the appropriate dev command to verify + +### After making changes: +- ALWAYS run `dev lint` before considering your work complete +- This ensures consistency with CI checks + +## Example Workflow + +```bash +# Make your Swift changes... + +# Verify it compiles +dev build + +# Fix any style issues +dev fix + +# Run tests if needed +dev test packages + +# Final check before commit +dev check +``` diff --git a/.cursor/rules/swift-test.mdc b/.cursor/rules/swift-test.mdc new file mode 100644 index 00000000..1b011af1 --- /dev/null +++ b/.cursor/rules/swift-test.mdc @@ -0,0 +1,71 @@ +--- +description: Swift testing best practices and requirements +globs: ["Tests/**/*.swift"] +alwaysApply: true +--- + +# SWIFT TESTING RULES + +## Test Structure Requirements + +### DO: +- Create separate test methods for each test case +- Use `guard` statements with `XCTFail` for unwrapping optionals +- Write focused tests that test one thing at a time +- Use descriptive test method names that explain what is being tested +- catch only one error type per test + +### DON'T: +- Write conditional logic (if/else) inside tests - create separate test methods instead +- Use typed catches when testing throwing expressions +- Delete and recreate test files when debugging +- Add boilerplate comments like "// Given", "// When", "// Then" + +## Code Examples + +### ✅ CORRECT: Unwrapping optionals +```swift +func testSomething() { + guard let result = someOptionalValue else { + XCTFail("Expected non-nil value") + return + } + XCTAssertEqual(result, expectedValue) +} +``` + +### ❌ INCORRECT: Conditional test logic +```swift +// DON'T DO THIS +func testSomething() { + if condition { + XCTAssertTrue(something) + } else { + XCTAssertFalse(something) + } +} +``` + +### ✅ CORRECT: Separate test methods +```swift +func testSomething_whenConditionTrue() { + // Test for true condition +} + +func testSomething_whenConditionFalse() { + // Test for false condition +} +``` + +## Error Testing + +When testing throwing functions: +- Test only ONE error type per test method +- Avoid typed catch blocks that check for specific error types +- Let unhandled errors fail the test naturally + +## Comments + +- Use comments ONLY to explain non-obvious side effects or complex reasoning +- Keep comments minimal and purposeful +- Focus on WHY something is done, not WHAT is being done From 07cf33440fd8d6b55dcc8e6c99b04d4003a6e779 Mon Sep 17 00:00:00 2001 From: Kieran Osgood Date: Tue, 15 Jul 2025 15:18:33 +0100 Subject: [PATCH 2/4] Apply suggestions from code review Co-authored-by: Mark Murray <2034704+markmur@users.noreply.github.com> --- .cursor/rules/swift-development.mdc | 3 +-- .cursor/rules/swift-test.mdc | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/.cursor/rules/swift-development.mdc b/.cursor/rules/swift-development.mdc index ff5761e8..080f855b 100644 --- a/.cursor/rules/swift-development.mdc +++ b/.cursor/rules/swift-development.mdc @@ -53,8 +53,7 @@ dev apollo codegen # Generate Apollo client code ✅ DO: Run the appropriate dev command to verify ### After making changes: -- ALWAYS run `dev lint` before considering your work complete -- This ensures consistency with CI checks +- ALWAYS run `dev lint` before considering your work complete. This ensures consistency with CI checks. ## Example Workflow diff --git a/.cursor/rules/swift-test.mdc b/.cursor/rules/swift-test.mdc index 1b011af1..38780355 100644 --- a/.cursor/rules/swift-test.mdc +++ b/.cursor/rules/swift-test.mdc @@ -13,7 +13,7 @@ alwaysApply: true - Use `guard` statements with `XCTFail` for unwrapping optionals - Write focused tests that test one thing at a time - Use descriptive test method names that explain what is being tested -- catch only one error type per test +- Catch only one error type per test ### DON'T: - Write conditional logic (if/else) inside tests - create separate test methods instead From 5536a813b3a772c3e9f635d7e0b34b533f33d330 Mon Sep 17 00:00:00 2001 From: Kieran Osgood Date: Tue, 22 Jul 2025 16:01:57 +0100 Subject: [PATCH 3/4] fix: update mdc files to add more context and refactor wording --- .cursor/rules/swift-development.mdc | 29 +++++++++++------------------ .cursor/rules/swift-test.mdc | 2 +- 2 files changed, 12 insertions(+), 19 deletions(-) diff --git a/.cursor/rules/swift-development.mdc b/.cursor/rules/swift-development.mdc index 080f855b..127060a0 100644 --- a/.cursor/rules/swift-development.mdc +++ b/.cursor/rules/swift-development.mdc @@ -16,16 +16,15 @@ alwaysApply: true ## Verification Commands ### Check your work systematically: -1. **Lint & Format** → `dev lint` (or `dev style`) -2. **Build Issues** → `dev build` -3. **Test Issues** → `dev test` -4. **All Checks** → `dev check` (runs everything) +1. **Lint & Format** → `dev lint` (or `dev style`) - Checks for linting and stylistic errors +2. **Build Issues** → `dev build` - Checks for compilation issues +3. **Test Issues** → `dev test` - Checks for failing tests ### Available dev commands: ```bash # Code Quality dev lint # Check format & lint issues (alias: dev style) -dev fix # Auto-fix format & lint issues +dev fix # auto fixes formatting and linting issues # Building dev build packages # Build ShopifyCheckoutSheetKit & ShopifyAcceleratedCheckouts @@ -42,33 +41,27 @@ dev apollo codegen # Generate Apollo client code ## Workflow Best Practices -### Before committing: -1. Run `dev lint` to ensure code style compliance -2. Run `dev build` to verify compilation -3. Run `dev test` if you've modified functionality -4. Or just run `dev check` to do all of the above - ### When you see errors: ❌ DON'T: Trust language server errors in Xcode/editor ✅ DO: Run the appropriate dev command to verify ### After making changes: -- ALWAYS run `dev lint` before considering your work complete. This ensures consistency with CI checks. +- ALWAYS run `dev fix && dev lint` to check your code is formatted and written in our style. ## Example Workflow ```bash # Make your Swift changes... +# Fix any auto-fixable issues +dev fix + +# Check for any remaining lint issues +dev lint + # Verify it compiles dev build -# Fix any style issues -dev fix - # Run tests if needed dev test packages - -# Final check before commit -dev check ``` diff --git a/.cursor/rules/swift-test.mdc b/.cursor/rules/swift-test.mdc index 38780355..2e6f5f65 100644 --- a/.cursor/rules/swift-test.mdc +++ b/.cursor/rules/swift-test.mdc @@ -14,9 +14,9 @@ alwaysApply: true - Write focused tests that test one thing at a time - Use descriptive test method names that explain what is being tested - Catch only one error type per test +- Create separate test methods instead of conditional logic ### DON'T: -- Write conditional logic (if/else) inside tests - create separate test methods instead - Use typed catches when testing throwing expressions - Delete and recreate test files when debugging - Add boilerplate comments like "// Given", "// When", "// Then" From 37b64d2077d2d97682f13cca7bbe82cf452d5b33 Mon Sep 17 00:00:00 2001 From: Kieran Osgood Date: Thu, 24 Jul 2025 11:19:52 +0100 Subject: [PATCH 4/4] refactor: add more examples for cursor rules and move dev descriptions to dev.yml --- .cursor/rules/swift-development.mdc | 36 +++++++------ .cursor/rules/swift-test.mdc | 82 +++++++++++++++++------------ dev.yml | 14 ++--- 3 files changed, 74 insertions(+), 58 deletions(-) diff --git a/.cursor/rules/swift-development.mdc b/.cursor/rules/swift-development.mdc index 127060a0..58ebdaca 100644 --- a/.cursor/rules/swift-development.mdc +++ b/.cursor/rules/swift-development.mdc @@ -21,22 +21,26 @@ alwaysApply: true 3. **Test Issues** → `dev test` - Checks for failing tests ### Available dev commands: -```bash -# Code Quality -dev lint # Check format & lint issues (alias: dev style) -dev fix # auto fixes formatting and linting issues - -# Building -dev build packages # Build ShopifyCheckoutSheetKit & ShopifyAcceleratedCheckouts -dev build samples # Build sample apps - -# Testing -dev test packages # Test the packages -dev test samples # Test sample apps - -# Apollo/GraphQL -dev apollo download_schema # Download GraphQL schema -dev apollo codegen # Generate Apollo client code +**See `dev.yml` in project root for complete list of commands and descriptions.** + +Key commands for verification: +- `dev lint` (alias: `dev style`) - Check format & lint issues +- `dev fix` - Auto-fix formatting and linting issues +- `dev build packages` - Build both packages +- `dev test packages` - Run all tests + +## Concurrency Best Practices + +### DO: Use actors for thread-safe shared state +```swift +actor QueryCache { + private var cache: [String: Any] = [:] + private var inflightRequests: [String: Any] = [:] + + func loadCached(...) async throws -> T { + // Safe concurrent access to shared state + } +} ``` ## Workflow Best Practices diff --git a/.cursor/rules/swift-test.mdc b/.cursor/rules/swift-test.mdc index 2e6f5f65..11ce94e1 100644 --- a/.cursor/rules/swift-test.mdc +++ b/.cursor/rules/swift-test.mdc @@ -11,19 +11,6 @@ alwaysApply: true ### DO: - Create separate test methods for each test case - Use `guard` statements with `XCTFail` for unwrapping optionals -- Write focused tests that test one thing at a time -- Use descriptive test method names that explain what is being tested -- Catch only one error type per test -- Create separate test methods instead of conditional logic - -### DON'T: -- Use typed catches when testing throwing expressions -- Delete and recreate test files when debugging -- Add boilerplate comments like "// Given", "// When", "// Then" - -## Code Examples - -### ✅ CORRECT: Unwrapping optionals ```swift func testSomething() { guard let result = someOptionalValue else { @@ -33,36 +20,61 @@ func testSomething() { XCTAssertEqual(result, expectedValue) } ``` +- Write focused tests that test one thing at a time +- Use descriptive test method names in the format `test___` +``` + func test_canTransition_fromAppleSheetPresentedState_shouldAllowPaymentAuthorizationAndInterruptAndCompleted() + func test_ensureCurrencyNotChanged_withNoInitialCurrency_shouldNotThrow() +``` -### ❌ INCORRECT: Conditional test logic -```swift -// DON'T DO THIS -func testSomething() { - if condition { - XCTAssertTrue(something) - } else { - XCTAssertFalse(something) +- If a function may throw multiple types of errors, write multiple tests to capture them in isolation +``` +func throwingFunction() { + if someCondition { + throw Error.foo + } else + throw Error.bar + } + + func test_throwingFunction_whenSomeConditionTrue_shouldThrowFoo() { + do { + _ = try await storefront.createCart() + XCTFail("Expected error to be thrown") + } catch { + guard case let error = Error.foo else { + XCTFail("Expected .foo") + } } -} + } + func test_throwingFunction_whenSomeConditionTrue_shouldThrowBar(){ + do { + _ = try await storefront.createCart() + XCTFail("Expected error to be thrown") + } catch { + guard case let error = Error.foo else { + XCTFail("Expected .foo") + } + } + } ``` -### ✅ CORRECT: Separate test methods -```swift -func testSomething_whenConditionTrue() { - // Test for true condition -} +## Code Examples -func testSomething_whenConditionFalse() { - // Test for false condition +### ✅ CORRECT: Unwrapping optionals +```swift +func testSomething() { + guard let result = someOptionalValue else { + XCTFail("Expected non-nil value") + return + } + XCTAssertEqual(result, expectedValue) } ``` -## Error Testing - -When testing throwing functions: -- Test only ONE error type per test method -- Avoid typed catch blocks that check for specific error types -- Let unhandled errors fail the test naturally +### DON'T: +- Use typed catches when testing throwing expressions +- Delete and recreate test files when debugging +- Add boilerplate comments like "// Given", "// When", "// Then" ## Comments diff --git a/dev.yml b/dev.yml index dc68b42a..82873cad 100644 --- a/dev.yml +++ b/dev.yml @@ -30,29 +30,29 @@ check: commands: lint: aliases: [style] - desc: Check Format & Lint issues + desc: Check format and lint issues across all Swift files using SwiftLint and SwiftFormat run: scripts/lint fix: - desc: Autofix Format & Lint issues + desc: Automatically fix format and lint issues where possible run: scripts/lint fix build: subcommands: packages: - desc: Build the Package + desc: Build both ShopifyCheckoutSheetKit and ShopifyAcceleratedCheckouts packages run: | ./scripts/xcode_run build ShopifyCheckoutSheetKit ./scripts/xcode_run build ShopifyAcceleratedCheckouts samples: - desc: Build the Samples + desc: Build all sample applications to verify integration run: ./scripts/build_samples test: subcommands: packages: - desc: Test the Packages + desc: Run all unit and integration tests for the packages run: | ./scripts/xcode_run test ShopifyCheckoutSheetKit-Package samples: - desc: Test the Samples + desc: Run tests for sample applications run: ./scripts/test_samples apollo: @@ -68,7 +68,7 @@ commands: rover graph introspect https://$DOMAIN/api/$API_VERSION/graphql --header="X-Shopify-Storefront-Access-Token: $TOKEN" --output schema.$API_VERSION.graphqls codegen: - desc: Generate Apollo Client + desc: Generate Apollo Client models and request functions for sample app run: | cd ./Samples/ShopifyAcceleratedCheckoutsApp/ ./apollo-ios-cli generate