From 508ed36ae49964973f467e8b026f5bf732fa2d70 Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Thu, 26 Feb 2026 15:22:14 +1100 Subject: [PATCH 01/16] Remove unused build and test Rake tasks CI handles builds and tests via Fastlane; the `xcodebuild`-wrapping Rake tasks were unused. --- Generated with the help of Claude Code, https://claude.ai/code Co-Authored-By: Claude Code Opus 4.6 --- Rakefile | 51 --------------------------------------------------- 1 file changed, 51 deletions(-) diff --git a/Rakefile b/Rakefile index 71925e9cbb86..ee86adc9f01e 100644 --- a/Rakefile +++ b/Rakefile @@ -12,16 +12,12 @@ require 'zlib' RUBY_REPO_VERSION = File.read('./.ruby-version').rstrip XCODE_WORKSPACE = 'WordPress.xcworkspace' -XCODE_SCHEME = 'WordPress' -XCODE_CONFIGURATION = 'Debug' EXPECTED_XCODE_VERSION = File.read('.xcode-version').rstrip GUTENBERG_VERSION = 'v1.121.0' PROJECT_DIR = __dir__ abort('Project directory contains one or more spaces – unable to continue.') if PROJECT_DIR.include?(' ') -task default: %w[test] - desc 'Install required dependencies' task dependencies: %w[dependencies:check assets:check dependencies:gutenberg_xcframeworks] @@ -175,36 +171,6 @@ task :mocks do sh "#{File.join(PROJECT_DIR, 'API-Mocks', 'scripts', 'start.sh')} 8282" end -desc "Build #{XCODE_SCHEME}" -task build: [:dependencies] do - xcodebuild(:build) -end - -desc "Profile build #{XCODE_SCHEME}" -task buildprofile: [:dependencies] do - ENV['verbose'] = '1' - xcodebuild(:build, "OTHER_SWIFT_FLAGS='-Xfrontend -debug-time-compilation -Xfrontend -debug-time-expression-type-checking'") -end - -task timed_build: [:clean] do - require 'benchmark' - time = Benchmark.measure do - Rake::Task['build'].invoke - end - puts "CPU Time: #{time.total}" - puts "Wall Time: #{time.real}" -end - -desc 'Run test suite' -task test: [:dependencies] do - xcodebuild(:build, :test) -end - -desc 'Remove any temporary products' -task :clean do - xcodebuild(:clean) -end - desc 'Checks the source for style errors' task :lint do sh 'pushd BuildTools; export SDKROOT=$(xcrun --sdk macosx --show-sdk-path); swift package plugin --allow-writing-to-directory .. --allow-writing-to-package-directory swiftlint --working-directory .. --quiet; popd' @@ -634,23 +600,6 @@ def display_prompt_response? response == 'Y' end -def xcodebuild(*build_cmds) - cmd = 'xcodebuild' - cmd += " -destination 'platform=iOS Simulator,name=iPhone 16'" - cmd += ' -sdk iphonesimulator' - cmd += " -workspace #{XCODE_WORKSPACE}" - cmd += " -scheme #{XCODE_SCHEME}" - cmd += " -configuration #{xcode_configuration}" - cmd += ' ' - cmd += build_cmds.map(&:to_s).join(' ') - cmd += ' | bundle exec xcpretty && exit ${PIPESTATUS[0]}' unless ENV['verbose'] - sh(cmd) -end - -def xcode_configuration - ENV.fetch('XCODE_CONFIGURATION') { XCODE_CONFIGURATION } -end - def command?(command) system("which #{command} > /dev/null 2>&1") end From d2ed37dd60020ecccace278b2afc72743cd239ad Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Wed, 11 Feb 2026 09:47:35 +1100 Subject: [PATCH 02/16] Add local test Fastlane lane Skips CI prerequisites (env files, signing, toolkit checks) and reuses DerivedData for incremental builds. Supports only_testing, scheme, device, and clean options. --- Generate with the help of Claude Code, https://code.claude.com Co-Authored-By: Claude Opus 4.6 --- fastlane/Fastfile | 2 +- fastlane/lanes/build.rb | 30 ++++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/fastlane/Fastfile b/fastlane/Fastfile index aff0c757935f..c2872595ffd2 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -183,7 +183,7 @@ before_all do |lane| ENV['FASTLANE_XCODEBUILD_SETTINGS_TIMEOUT'] = '120' # Skip these checks/steps for test lane (not needed for testing) - next if lane == :test_without_building + next if %i[test test_without_building].include?(lane) # Ensure we use the latest version of the toolkit check_for_toolkit_updates unless is_ci || ENV['FASTLANE_SKIP_TOOLKIT_UPDATE_CHECK'] diff --git a/fastlane/lanes/build.rb b/fastlane/lanes/build.rb index 87fb9d5e51d8..6da191bdfc57 100644 --- a/fastlane/lanes/build.rb +++ b/fastlane/lanes/build.rb @@ -37,6 +37,36 @@ # Lanes related to Building and Testing the code # platform :ios do + # Runs tests locally without CI prerequisites (env files, signing, etc.) + # + # @option [String] scheme The scheme to test (default: WordPress) + # @option [String] device The Simulator device name (default: iPhone 16) + # @option [String] ios_version The deployment target version + # @option [String] only_testing Specific test target/class/method (e.g. WordPressUnitTests/MyClass/testFoo) + # @option [Boolean] clean Whether to clean before building (default: false for incremental builds) + # + # @example Run all WordPress tests: + # bundle exec fastlane test + # @example Run a single test class: + # bundle exec fastlane test only_testing:WordPressUnitTests/MyClass + # @example Test the Jetpack scheme: + # bundle exec fastlane test scheme:Jetpack + # @example Clean build before testing: + # bundle exec fastlane test clean:true + # + desc 'Run tests locally' + lane :test do |scheme: 'WordPress', device: 'iPhone 16', ios_version: nil, only_testing: nil, clean: false| + run_tests( + workspace: WORKSPACE_PATH, + scheme: scheme, + device: device, + derived_data_path: DERIVED_DATA_PATH, + deployment_target_version: ios_version, + only_testing: only_testing, + clean: clean + ) + end + # Builds the WordPress app for Testing # # @option [String] device the name of the Simulator device to run the tests on From d28b86d86f34ed98a1039f6d5cb1fc1407239f6b Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Wed, 11 Feb 2026 15:32:36 +1100 Subject: [PATCH 03/16] Add missing module tests to default plan --- Generate with the help of Claude Code, https://code.claude.com Co-Authored-By: Claude Opus 4.6 --- .../WordPressUnitTests.xctestplan | 61 +++++++++++++------ 1 file changed, 41 insertions(+), 20 deletions(-) diff --git a/Tests/KeystoneTests/WordPressUnitTests.xctestplan b/Tests/KeystoneTests/WordPressUnitTests.xctestplan index 107323853bad..ab9be2b1036d 100644 --- a/Tests/KeystoneTests/WordPressUnitTests.xctestplan +++ b/Tests/KeystoneTests/WordPressUnitTests.xctestplan @@ -31,18 +31,32 @@ "testRepetitionMode" : "retryOnFailure" }, "testTargets" : [ + { + "target" : { + "containerPath" : "container:WordPress.xcodeproj", + "identifier" : "4AD953BA2C21451700D0EEFA", + "name" : "WordPressAuthenticatorTests" + } + }, { "target" : { "containerPath" : "container:..\/Modules", - "identifier" : "WordPressFluxTests", - "name" : "WordPressFluxTests" + "identifier" : "DesignSystemTests", + "name" : "DesignSystemTests" } }, { "target" : { - "containerPath" : "container:WordPress.xcodeproj", - "identifier" : "E16AB92914D978240047A2E5", - "name" : "WordPressTest" + "containerPath" : "container:..\/Modules", + "identifier" : "WordPressSharedTests", + "name" : "WordPressSharedTests" + } + }, + { + "target" : { + "containerPath" : "container:..\/Modules", + "identifier" : "JetpackStatsWidgetsCoreTests", + "name" : "JetpackStatsWidgetsCoreTests" } }, { @@ -55,50 +69,57 @@ { "target" : { "containerPath" : "container:..\/Modules", - "identifier" : "WordPressSharedTests", - "name" : "WordPressSharedTests" + "identifier" : "WordPressUIUnitTests", + "name" : "WordPressUIUnitTests" } }, { "target" : { "containerPath" : "container:WordPress.xcodeproj", - "identifier" : "4A8280FC2E5FE9B60037E180", - "name" : "WordPressKitTests" + "identifier" : "E16AB92914D978240047A2E5", + "name" : "WordPressTest" } }, { "target" : { "containerPath" : "container:..\/Modules", - "identifier" : "JetpackStatsWidgetsCoreTests", - "name" : "JetpackStatsWidgetsCoreTests" + "identifier" : "JetpackStatsTests", + "name" : "JetpackStatsTests" } }, { "target" : { - "containerPath" : "container:WordPress.xcodeproj", - "identifier" : "4AD953BA2C21451700D0EEFA", - "name" : "WordPressAuthenticatorTests" + "containerPath" : "container:..\/Modules", + "identifier" : "AsyncImageKitTests", + "name" : "AsyncImageKitTests" } }, { "target" : { "containerPath" : "container:..\/Modules", - "identifier" : "WordPressUIUnitTests", - "name" : "WordPressUIUnitTests" + "identifier" : "WordPressSharedObjCTests", + "name" : "WordPressSharedObjCTests" } }, { "target" : { "containerPath" : "container:..\/Modules", - "identifier" : "WordPressSharedObjCTests", - "name" : "WordPressSharedObjCTests" + "identifier" : "WordPressFluxTests", + "name" : "WordPressFluxTests" + } + }, + { + "target" : { + "containerPath" : "container:WordPress.xcodeproj", + "identifier" : "4A8280FC2E5FE9B60037E180", + "name" : "WordPressKitTests" } }, { "target" : { "containerPath" : "container:..\/Modules", - "identifier" : "AsyncImageKitTests", - "name" : "AsyncImageKitTests" + "identifier" : "WordPressIntelligenceTests", + "name" : "WordPressIntelligenceTests" } } ], From 8a928540297cbba96fb2c80c6bfc883544ff276f Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Wed, 11 Feb 2026 16:25:22 +1100 Subject: [PATCH 04/16] Move orphan test into WordPressUIUnitTests The file was in a `WordPressUITests` directory with no matching SPM target, so it was never compiled or run. Updated its import from `WordPress` to `WordPressUI`. --- Generate with the help of Claude Code, https://code.claude.com Co-Authored-By: Claude Opus 4.6 --- .../NoResultsViewControllerTests.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename Modules/Tests/{WordPressUITests => WordPressUIUnitTests}/NoResultsViewControllerTests.swift (99%) diff --git a/Modules/Tests/WordPressUITests/NoResultsViewControllerTests.swift b/Modules/Tests/WordPressUIUnitTests/NoResultsViewControllerTests.swift similarity index 99% rename from Modules/Tests/WordPressUITests/NoResultsViewControllerTests.swift rename to Modules/Tests/WordPressUIUnitTests/NoResultsViewControllerTests.swift index 5deac3487fe4..427c2174427a 100644 --- a/Modules/Tests/WordPressUITests/NoResultsViewControllerTests.swift +++ b/Modules/Tests/WordPressUIUnitTests/NoResultsViewControllerTests.swift @@ -1,5 +1,5 @@ import XCTest -@testable import WordPress +@testable import WordPressUI class NoResultsViewControllerTests: XCTestCase { From 1fee7108b16027e5f7ef780327159a118fa4d6fa Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Wed, 11 Feb 2026 20:33:20 +1100 Subject: [PATCH 05/16] Use Bundle.wordPressUIBundle in NoResultsViewController Applies the same test-bundle workaround already used elsewhere in WordPressUI so the storyboard loads in SPM test context. --- Generate with the help of Claude Code, https://code.claude.com Co-Authored-By: Claude Opus 4.6 --- .../WordPressUI/Deprecated/NoResultsViewController.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/Sources/WordPressUI/Deprecated/NoResultsViewController.swift b/Modules/Sources/WordPressUI/Deprecated/NoResultsViewController.swift index b74bcb5062e6..095719ba14f8 100644 --- a/Modules/Sources/WordPressUI/Deprecated/NoResultsViewController.swift +++ b/Modules/Sources/WordPressUI/Deprecated/NoResultsViewController.swift @@ -132,7 +132,7 @@ import Reachability /// to set the view values before presenting the No Results View. /// @objc public class func controller() -> NoResultsViewController { - let storyBoard = UIStoryboard(name: "NoResults", bundle: Bundle.module) + let storyBoard = UIStoryboard(name: "NoResults", bundle: Bundle.wordPressUIBundle) let controller = storyBoard.instantiateViewController(withIdentifier: "NoResults") as! NoResultsViewController return controller } From 3e6ff69d4de5b7d23ab69a8cfdce168e65c5b959 Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Thu, 12 Feb 2026 20:00:57 +1100 Subject: [PATCH 06/16] Fix timezone mismatch in MockStatsServiceTests The test calendar used `.eastern` but the service used `.current`, so date interval keys never aligned. --- Generate with the help of Claude Code, https://code.claude.com Co-Authored-By: Claude Opus 4.6 --- Modules/Tests/JetpackStatsTests/MockStatsServiceTests.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Modules/Tests/JetpackStatsTests/MockStatsServiceTests.swift b/Modules/Tests/JetpackStatsTests/MockStatsServiceTests.swift index 29c5c99c0e41..4fa319eba2c5 100644 --- a/Modules/Tests/JetpackStatsTests/MockStatsServiceTests.swift +++ b/Modules/Tests/JetpackStatsTests/MockStatsServiceTests.swift @@ -9,7 +9,7 @@ struct MockStatsServiceTests { @Test("getTopListData returns valid data for posts") func testGetTopListDataPosts() async throws { // GIVEN - let service = MockStatsService(timeZone: .current) + let service = MockStatsService(timeZone: .eastern) let dateInterval = calendar.makeDateInterval(for: .today) // WHEN @@ -43,7 +43,7 @@ struct MockStatsServiceTests { @Test("Verify getChartData returns valid data for views metric with today range") func testGetChartDataViewsToday() async throws { // GIVEN - let service = MockStatsService(timeZone: .current) + let service = MockStatsService(timeZone: .eastern) let dateInterval = calendar.makeDateInterval(for: .today) let granularity = dateInterval.preferredGranularity From 84676fb95d0260b16b5abc02cdc0a92040c9b5e7 Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Thu, 12 Feb 2026 20:01:10 +1100 Subject: [PATCH 07/16] Remove DesignSystemTests from default test plan The test crashes when DesignSystem is built as a dynamic library, which happens because WordPressAuthenticator (also in the plan) depends on it transitively. --- Generate with the help of Claude Code, https://code.claude.com Co-Authored-By: Claude Opus 4.6 --- Tests/KeystoneTests/WordPressUnitTests.xctestplan | 7 ------- 1 file changed, 7 deletions(-) diff --git a/Tests/KeystoneTests/WordPressUnitTests.xctestplan b/Tests/KeystoneTests/WordPressUnitTests.xctestplan index ab9be2b1036d..b50c4258e76b 100644 --- a/Tests/KeystoneTests/WordPressUnitTests.xctestplan +++ b/Tests/KeystoneTests/WordPressUnitTests.xctestplan @@ -38,13 +38,6 @@ "name" : "WordPressAuthenticatorTests" } }, - { - "target" : { - "containerPath" : "container:..\/Modules", - "identifier" : "DesignSystemTests", - "name" : "DesignSystemTests" - } - }, { "target" : { "containerPath" : "container:..\/Modules", From 93e4c8c7d16f7536dd794e85ca6f47ce60c7ff30 Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Thu, 12 Feb 2026 20:43:33 +1100 Subject: [PATCH 08/16] Fix DesignSystem resource bundle in test runner Use `Bundle.designSystemBundle` instead of `.module` so resources resolve when Xcode builds the module as a dynamic library (same workaround as WordPressUI). --- Generate with the help of Claude Code, https://code.claude.com Co-Authored-By: Claude Opus 4.6 --- .../Foundation/Bundle+DesignSystem.swift | 14 ++++++++++++++ .../Sources/DesignSystem/Foundation/IconName.swift | 4 ++-- .../DesignSystem/Typography/FontManager.swift | 2 +- Modules/Tests/DesignSystemTests/IconTests.swift | 5 ----- Tests/KeystoneTests/WordPressUnitTests.xctestplan | 7 +++++++ 5 files changed, 24 insertions(+), 8 deletions(-) create mode 100644 Modules/Sources/DesignSystem/Foundation/Bundle+DesignSystem.swift diff --git a/Modules/Sources/DesignSystem/Foundation/Bundle+DesignSystem.swift b/Modules/Sources/DesignSystem/Foundation/Bundle+DesignSystem.swift new file mode 100644 index 000000000000..9fc8a6802baf --- /dev/null +++ b/Modules/Sources/DesignSystem/Foundation/Bundle+DesignSystem.swift @@ -0,0 +1,14 @@ +import Foundation + +extension Bundle { + public class var designSystemBundle: Bundle { +#if DEBUG + // Workaround for https://forums.swift.org/t/swift-5-3-swiftpm-resources-in-tests-uses-wrong-bundle-path/37051 + if let testBundlePath = ProcessInfo.processInfo.environment["XCTestBundlePath"], + let bundle = Bundle(path: "\(testBundlePath)/Modules_DesignSystem.bundle") { + return bundle + } +#endif + return Bundle.module + } +} diff --git a/Modules/Sources/DesignSystem/Foundation/IconName.swift b/Modules/Sources/DesignSystem/Foundation/IconName.swift index 8fca1d9258d8..f1e52829de67 100644 --- a/Modules/Sources/DesignSystem/Foundation/IconName.swift +++ b/Modules/Sources/DesignSystem/Foundation/IconName.swift @@ -22,7 +22,7 @@ public enum IconName: String, CaseIterable { public extension UIImage { enum DS { public static func icon(named name: IconName, with configuration: UIImage.Configuration? = nil) -> UIImage? { - return UIImage(named: name.rawValue, in: .module, with: configuration) + return UIImage(named: name.rawValue, in: .designSystemBundle, with: configuration) } } } @@ -30,7 +30,7 @@ public extension UIImage { public extension Image { enum DS { public static func icon(named name: IconName) -> Image { - return Image(name.rawValue, bundle: .module) + return Image(name.rawValue, bundle: .designSystemBundle) } } } diff --git a/Modules/Sources/DesignSystem/Typography/FontManager.swift b/Modules/Sources/DesignSystem/Typography/FontManager.swift index 123021e2d6fc..676e227dee03 100644 --- a/Modules/Sources/DesignSystem/Typography/FontManager.swift +++ b/Modules/Sources/DesignSystem/Typography/FontManager.swift @@ -9,7 +9,7 @@ public enum FontManager { // Makes sure it's performed only once. private static let register: Void = { - let fontURLs = Bundle.module + let fontURLs = Bundle.designSystemBundle .urls(forResourcesWithExtension: "otf", subdirectory: nil) for fontURL in (fontURLs ?? []) { if !CTFontManagerRegisterFontsForURL(fontURL as CFURL, .process, nil) { diff --git a/Modules/Tests/DesignSystemTests/IconTests.swift b/Modules/Tests/DesignSystemTests/IconTests.swift index d163469ab0c1..9d3fff211ed0 100644 --- a/Modules/Tests/DesignSystemTests/IconTests.swift +++ b/Modules/Tests/DesignSystemTests/IconTests.swift @@ -4,11 +4,6 @@ import SwiftUI final class IconTests: XCTestCase { - // This test will fail if DesignSystem is built as a dynamic library. For some reason, Xcode can't locate - // the library's resource bundle. - // - // DesignSystem will be built as a dynamic library if it's a dependency of a dynamic library, such as - // the WordPressAuthenticator target. func testCanLoadAllIconsAsUIImage() throws { for icon in IconName.allCases { let _ = try XCTUnwrap(UIImage.DS.icon(named: icon)) diff --git a/Tests/KeystoneTests/WordPressUnitTests.xctestplan b/Tests/KeystoneTests/WordPressUnitTests.xctestplan index b50c4258e76b..ab9be2b1036d 100644 --- a/Tests/KeystoneTests/WordPressUnitTests.xctestplan +++ b/Tests/KeystoneTests/WordPressUnitTests.xctestplan @@ -38,6 +38,13 @@ "name" : "WordPressAuthenticatorTests" } }, + { + "target" : { + "containerPath" : "container:..\/Modules", + "identifier" : "DesignSystemTests", + "name" : "DesignSystemTests" + } + }, { "target" : { "containerPath" : "container:..\/Modules", From 74ea8869fff6cea5e710fb44c518ee3d15d58d29 Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Thu, 19 Feb 2026 15:15:59 +1100 Subject: [PATCH 09/16] Use iPhone 17 as the default Simulator for local Fastlane tests --- fastlane/lanes/build.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fastlane/lanes/build.rb b/fastlane/lanes/build.rb index 6da191bdfc57..52f4d7101895 100644 --- a/fastlane/lanes/build.rb +++ b/fastlane/lanes/build.rb @@ -40,7 +40,7 @@ # Runs tests locally without CI prerequisites (env files, signing, etc.) # # @option [String] scheme The scheme to test (default: WordPress) - # @option [String] device The Simulator device name (default: iPhone 16) + # @option [String] device The Simulator device name # @option [String] ios_version The deployment target version # @option [String] only_testing Specific test target/class/method (e.g. WordPressUnitTests/MyClass/testFoo) # @option [Boolean] clean Whether to clean before building (default: false for incremental builds) @@ -55,7 +55,7 @@ # bundle exec fastlane test clean:true # desc 'Run tests locally' - lane :test do |scheme: 'WordPress', device: 'iPhone 16', ios_version: nil, only_testing: nil, clean: false| + lane :test do |scheme: 'WordPress', device: 'iPhone 17', ios_version: nil, only_testing: nil, clean: false| run_tests( workspace: WORKSPACE_PATH, scheme: scheme, From 5e1531590a8295f325f830b255f7a33fb3199fce Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Thu, 19 Feb 2026 16:18:02 +1100 Subject: [PATCH 10/16] Push a class back from `public` to `internal` --- .../Sources/DesignSystem/Foundation/Bundle+DesignSystem.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/Sources/DesignSystem/Foundation/Bundle+DesignSystem.swift b/Modules/Sources/DesignSystem/Foundation/Bundle+DesignSystem.swift index 9fc8a6802baf..1a5d69be629c 100644 --- a/Modules/Sources/DesignSystem/Foundation/Bundle+DesignSystem.swift +++ b/Modules/Sources/DesignSystem/Foundation/Bundle+DesignSystem.swift @@ -1,7 +1,7 @@ import Foundation extension Bundle { - public class var designSystemBundle: Bundle { + class var designSystemBundle: Bundle { #if DEBUG // Workaround for https://forums.swift.org/t/swift-5-3-swiftpm-resources-in-tests-uses-wrong-bundle-path/37051 if let testBundlePath = ProcessInfo.processInfo.environment["XCTestBundlePath"], From 08f16341337f6568790af95aebd138ad46709968 Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Thu, 26 Feb 2026 15:39:40 +1100 Subject: [PATCH 11/16] Add Build & Test section to `AGENTS.md` Prefer Xcode MCP when available, fall back to Fastlane. --- Generated with the help of Claude Code, https://claude.ai/code Co-Authored-By: Claude Code Opus 4.6 --- AGENTS.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/AGENTS.md b/AGENTS.md index 72f070989dbe..822e63263e84 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -38,6 +38,16 @@ WordPress-iOS uses a modular architecture with the main app and separate Swift p - **Accessibility**: Use proper accessibility labels and traits - **Localization**: follow best practices from @docs/localization.md +## Build & Test + +If the Xcode MCP server is connected, use it to build and test. +Otherwise, use the `test` Fastlane lane: + +```bash +bundle exec fastlane test +bundle exec fastlane test only_testing:TargetName/Class/method +``` + ## Coding Standards - Follow Swift API Design Guidelines - Use strict access control modifiers where possible From c1931f91973ac0333245246094489a307bb8771c Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Thu, 26 Feb 2026 15:41:34 +1100 Subject: [PATCH 12/16] Remove the slow WordPressIntelligenceTests from the main run --- Tests/KeystoneTests/WordPressUnitTests.xctestplan | 7 ------- 1 file changed, 7 deletions(-) diff --git a/Tests/KeystoneTests/WordPressUnitTests.xctestplan b/Tests/KeystoneTests/WordPressUnitTests.xctestplan index ab9be2b1036d..f61cbd8bffac 100644 --- a/Tests/KeystoneTests/WordPressUnitTests.xctestplan +++ b/Tests/KeystoneTests/WordPressUnitTests.xctestplan @@ -114,13 +114,6 @@ "identifier" : "4A8280FC2E5FE9B60037E180", "name" : "WordPressKitTests" } - }, - { - "target" : { - "containerPath" : "container:..\/Modules", - "identifier" : "WordPressIntelligenceTests", - "name" : "WordPressIntelligenceTests" - } } ], "version" : 1 From 2f3d323210293681a33691f6bfcccf5306efcb88 Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Thu, 26 Feb 2026 16:26:03 +1100 Subject: [PATCH 13/16] Skip package resolution in test lane When `clean:false` (the default), packages are already resolved from a previous build. Passing `-skipPackageResolving` via `skip_package_dependencies_resolution` avoids redundant resolution on incremental test runs. --- Generated with the help of Claude Code, https://claude.ai/code Co-Authored-By: Claude Code Opus 4.6 --- fastlane/lanes/build.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fastlane/lanes/build.rb b/fastlane/lanes/build.rb index 52f4d7101895..d547af1d4d68 100644 --- a/fastlane/lanes/build.rb +++ b/fastlane/lanes/build.rb @@ -63,7 +63,8 @@ derived_data_path: DERIVED_DATA_PATH, deployment_target_version: ios_version, only_testing: only_testing, - clean: clean + clean: clean, + skip_package_dependencies_resolution: !clean ) end From 918c8490ec537b1b0b45edc53c87d7e7e1bbf1b4 Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Thu, 26 Feb 2026 16:40:06 +1100 Subject: [PATCH 14/16] Make the MCP instruction stronger in `AGENTS.md` --- AGENTS.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 822e63263e84..69c609732de3 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -40,8 +40,9 @@ WordPress-iOS uses a modular architecture with the main app and separate Swift p ## Build & Test -If the Xcode MCP server is connected, use it to build and test. -Otherwise, use the `test` Fastlane lane: +**Always check for the Xcode MCP server first.** +If it is connected, use it to build and test — no exceptions. +Only fall back to the `test` Fastlane lane when the Xcode MCP is unavailable: ```bash bundle exec fastlane test From 8ed8215498ed4c4da5b5d71ac659f6f819c86d5a Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Fri, 27 Feb 2026 10:48:45 +1100 Subject: [PATCH 15/16] Track WordPressShared scheme in project folder This way, we can properly configure it and SwiftPM won't clobber it from the .swiftpm folder at its own discretion. --- .../xcschemes/WordPressShared.xcscheme | 72 +++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 WordPress/WordPress.xcodeproj/xcshareddata/xcschemes/WordPressShared.xcscheme diff --git a/WordPress/WordPress.xcodeproj/xcshareddata/xcschemes/WordPressShared.xcscheme b/WordPress/WordPress.xcodeproj/xcshareddata/xcschemes/WordPressShared.xcscheme new file mode 100644 index 000000000000..68d022cc1d87 --- /dev/null +++ b/WordPress/WordPress.xcodeproj/xcshareddata/xcschemes/WordPressShared.xcscheme @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From eb00410a506bb708d0a6078ab3c8dbd3754a240d Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Fri, 27 Feb 2026 11:12:58 +1100 Subject: [PATCH 16/16] Add instruction to fallback to `xcodebuild` if Fastlane fails --- AGENTS.md | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/AGENTS.md b/AGENTS.md index 69c609732de3..12b9fa580e1e 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -42,13 +42,28 @@ WordPress-iOS uses a modular architecture with the main app and separate Swift p **Always check for the Xcode MCP server first.** If it is connected, use it to build and test — no exceptions. -Only fall back to the `test` Fastlane lane when the Xcode MCP is unavailable: + +If the Xcode MCP fails (e.g. build errors from unrelated targets), fall back to the Fastlane `test` lane: ```bash bundle exec fastlane test bundle exec fastlane test only_testing:TargetName/Class/method ``` +If Fastlane also fails, fall back to `xcodebuild` directly: + +```bash +xcodebuild \ + -workspace WordPress.xcworkspace \ + -scheme "${SCHEME}" \ + -destination "platform=iOS Simulator,name=${DEVICE}" \ + test \ + | xcbeautify +``` + +Some test targets (e.g. `WordPressDataTests`) have their own scheme and are not part of the main `WordPress` scheme's test plan. +When the `WordPress` scheme build fails due to an unrelated target, try using the target's dedicated scheme instead. + ## Coding Standards - Follow Swift API Design Guidelines - Use strict access control modifiers where possible