Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
153 changes: 153 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
# Compliance Rules

This file contains the compliance and code quality rules for this repository.

## 1. All Swift Files Must Include Mozilla Public License Header

**Objective:** Ensure legal compliance and proper licensing by requiring all Swift source files to include the standard Mozilla Public License v2.0 header at the beginning of the file

**Success Criteria:** Every .swift file begins with the exact Mozilla Public License header comment block: '// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/'

**Failure Criteria:** Swift files are missing the Mozilla Public License header, have an incorrect or modified header text, or have the header in the wrong location (not at the top of the file)

---

## 2. Code Must Pass All Enabled SwiftLint Rules

**Objective:** Maintain consistent code quality, style, and adherence to Swift best practices by enforcing all SwiftLint rules defined in .swiftlint.yml configuration

**Success Criteria:** Code passes all SwiftLint rules specified in .swiftlint.yml without warnings or errors, including line length limits (125 characters), closure body length (34 lines), function body length (122 lines), proper spacing, naming conventions, and syntax requirements

**Failure Criteria:** SwiftLint reports warnings or errors for violations such as exceeding line length, improper spacing, incorrect naming patterns, force unwrapping, force try, legacy API usage, or any other rule violations defined in the configuration

---

## 3. Code Sections Must Be Organized with MARK Comments

**Objective:** Improve code navigation and readability by using MARK comments to clearly delineate logical sections within Swift files, making it easier for developers to locate specific functionality

**Success Criteria:** Swift files use '// MARK:' comments to separate distinct code sections such as UI Elements, Properties, Initializers, Public Methods, Private Methods, Protocol Conformance (e.g., '// MARK: - ThemeApplicable'), and other logical groupings

**Failure Criteria:** Swift files lack MARK comments for section organization, or MARK comments are inconsistently applied across similar code structures

---

## 4. UI Elements Must Have Accessibility Identifiers

**Objective:** Ensure the application is accessible and testable by requiring all interactive UI elements to have unique accessibility identifiers that can be used by UI tests and assistive technologies

**Success Criteria:** All UI elements (buttons, text fields, views, labels, etc.) that users can interact with or that are tested in UI tests have their accessibilityIdentifier property set, typically using values from ViewModels (e.g., 'viewModel.a11yIdentifier')

**Failure Criteria:** Interactive UI elements are missing accessibilityIdentifier assignments, making them difficult to test or inaccessible to automation tools

---

## 5. UI Components Must Implement ThemeApplicable Protocol

**Objective:** Ensure consistent theming across the application by requiring all custom UI components to conform to the ThemeApplicable protocol and implement the applyTheme(theme:) method, enabling dynamic theme changes

**Success Criteria:** Custom UI view classes and components that display visual content conform to the ThemeApplicable protocol and implement the 'func applyTheme(theme: Theme)' method to update colors and visual properties based on the current theme

**Failure Criteria:** UI components that should support theming do not conform to ThemeApplicable protocol, or implement the protocol but fail to properly update their visual properties in the applyTheme method

---

## 6. Test Classes Must Use XCTest Framework with Proper Structure

**Objective:** Maintain consistent and reliable test infrastructure by requiring all test classes to inherit from XCTest framework classes and follow standard setup/teardown patterns

**Success Criteria:** Test files import XCTest, test classes inherit from XCTestCase, use setUp() and tearDown() methods for test lifecycle management, test methods start with 'test' prefix, and use XCTAssert family of assertions

**Failure Criteria:** Test classes do not inherit from XCTestCase, lack proper setUp/tearDown methods when needed, test methods don't follow naming conventions, or use assertions outside the XCTest framework

---

## 7. UI Components Must Use ViewModel Structs for Configuration

**Objective:** Promote separation of concerns and testability by requiring UI components to accept configuration through dedicated ViewModel structs rather than individual parameters

**Success Criteria:** UI components (views, buttons, cells) have corresponding ViewModel structs (e.g., PrimaryRoundedButtonViewModel) that encapsulate all configuration data including titles, identifiers, and styling properties, and components provide a configure(viewModel:) method

**Failure Criteria:** UI components accept configuration through multiple individual parameters instead of a cohesive ViewModel struct, or ViewModels are missing required properties like a11yIdentifier

---

## 8. System Dependencies Must Be Abstracted Behind Protocols

**Objective:** Improve testability and maintainability by requiring system dependencies (FileManager, NotificationCenter, etc.) to be abstracted behind protocol interfaces that can be mocked in tests

**Success Criteria:** System dependencies are accessed through protocol abstractions (e.g., FileManagerProtocol, NotificationProtocol, Application protocol) rather than direct concrete type usage, enabling dependency injection and test mocking

**Failure Criteria:** Code directly instantiates or uses concrete system types (FileManager.default, NotificationCenter.default) instead of using protocol abstractions, making the code difficult to test in isolation

---

## 9. UI-Related Code Must Be Annotated with @MainActor

**Objective:** Ensure thread safety and prevent race conditions by requiring all UI-related code, including view controllers, views, and UI-manipulating methods, to be annotated with @MainActor to guarantee execution on the main thread

**Success Criteria:** Classes, structs, or methods that interact with UIKit or perform UI updates are marked with @MainActor annotation, ensuring all UI operations execute on the main thread

**Failure Criteria:** UI-related code lacks @MainActor annotation, potentially allowing UI updates from background threads and causing runtime errors or crashes

---

## 10. Test Files Must Follow Naming Convention

**Objective:** Maintain consistent test file organization and discoverability by enforcing a standardized naming pattern for test files that clearly indicates their purpose

**Success Criteria:** Test files are named with 'Tests.swift' or 'Test.swift' suffix (e.g., 'LoggerTests.swift', 'NavigationTest.swift'), clearly identifying them as test files and corresponding to the code they test

**Failure Criteria:** Test files do not follow the naming convention, making them difficult to identify as tests or unclear which code they are testing

---

## 11. Properties and Methods Must Have Appropriate Access Control

**Objective:** Enforce information hiding and prevent unintended external access by requiring explicit access control modifiers (public, internal, private, fileprivate) on all properties and methods based on their intended scope

**Success Criteria:** All properties and methods have explicit access control modifiers: 'private' for implementation details, 'public' for external API surface, 'internal' for module-level access, ensuring minimal exposure of internal implementation

**Failure Criteria:** Properties or methods lack explicit access control modifiers when they should be private, or are marked public when they are only used internally

---

## 12. Classes That Should Not Be Subclassed Must Be Marked Final

**Objective:** Improve performance through compiler optimization and prevent unintended inheritance by marking classes as final when they are not designed to be subclassed

**Success Criteria:** Classes that are not intended for inheritance are marked with the 'final' keyword (e.g., 'final class MenuCell', 'public final class SecondaryRoundedButton'), enabling compiler optimizations and making design intent explicit

**Failure Criteria:** Classes that are not designed for subclassing lack the 'final' keyword, allowing unintended inheritance and missing optimization opportunities

---

## 13. UI Constant Values Must Be Defined in Nested UX Structs

**Objective:** Organize UI-related constants and magic numbers in a centralized, discoverable location by requiring them to be defined within nested UX structs inside UI component classes

**Success Criteria:** UI components define layout constants, spacing values, corner radii, insets, and other UI measurements within a private nested struct named 'UX', keeping magic numbers organized and easily modifiable (e.g., 'private struct UX { static let buttonCornerRadius: CGFloat = 12 }')

**Failure Criteria:** UI constants and magic numbers are scattered throughout the implementation code as literals, or are not organized within a dedicated UX namespace struct

---

## 14. Public APIs Must Have Documentation Comments

**Objective:** Improve code maintainability and developer experience by requiring all public-facing APIs to include documentation comments that explain their purpose, parameters, and usage

**Success Criteria:** Public functions, methods, properties, classes, structs, and protocols include triple-slash (///) documentation comments describing their purpose, behavior, parameters, and return values

**Failure Criteria:** Public API elements lack documentation comments, making it difficult for other developers to understand their purpose and proper usage without reading implementation code

---

## 15. UIView Subclasses Must Implement Required Init With FatalError

**Objective:** Prevent accidental instantiation from Interface Builder and make design decisions explicit by requiring UIView subclasses to implement required init?(coder:) with fatalError when programmatic initialization is intended

**Success Criteria:** Custom UIView subclasses that are designed for programmatic initialization only implement 'required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }', clearly indicating Interface Builder instantiation is not supported

**Failure Criteria:** UIView subclasses designed for programmatic use are missing the required init?(coder:) implementation, or implement it without fatalError, potentially allowing unintended Interface Builder instantiation

---
10 changes: 2 additions & 8 deletions firefox-ios/Client.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -629,7 +629,6 @@
5A70EF10295DFD4900790249 /* Common in Frameworks */ = {isa = PBXBuildFile; productRef = 5A70EF0F295DFD4900790249 /* Common */; };
5A70EF16295DFD9000790249 /* Common in Frameworks */ = {isa = PBXBuildFile; productRef = 5A70EF15295DFD9000790249 /* Common */; };
5A70EF19295E2E1600790249 /* DependencyHelperMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5A70EF18295E2E1600790249 /* DependencyHelperMock.swift */; };
5A70EF1D295E3C3500790249 /* TestSetup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5A70EF1C295E3C3500790249 /* TestSetup.swift */; };
5A70EF1F295E3DFC00790249 /* UnitTestAppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5A70EF1E295E3DFC00790249 /* UnitTestAppDelegate.swift */; };
5A70EF21295E3E0B00790249 /* UnitTestSceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5A70EF20295E3E0B00790249 /* UnitTestSceneDelegate.swift */; };
5A8017E029CE15D90047120D /* TabManagerImplementation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5A8017DF29CE15D90047120D /* TabManagerImplementation.swift */; };
Expand Down Expand Up @@ -1350,8 +1349,8 @@
AAB4321B2E8187190075E47F /* RecentSearchProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAB4321A2E8187130075E47F /* RecentSearchProvider.swift */; };
AAB4321D2E8189390075E47F /* DefaultRecentSearchProviderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAB4321C2E8189310075E47F /* DefaultRecentSearchProviderTests.swift */; };
AAB434062E82F0600075E47F /* MockTrendingSearchProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAB434052E82F05C0075E47F /* MockTrendingSearchProvider.swift */; };
AAB5B7882EE077BB0051EF6E /* TranslationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAB5B7872EE077BB0051EF6E /* TranslationTests.swift */; };
AAB5AF382EDDCF600051EF6E /* MockLocaleProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAB5AF372EDDCF5A0051EF6E /* MockLocaleProvider.swift */; };
AAB5B7882EE077BB0051EF6E /* TranslationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAB5B7872EE077BB0051EF6E /* TranslationTests.swift */; };
AAD1CD872EAABA8100BEC90A /* TranslationsConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAD1CD862EAABA7C00BEC90A /* TranslationsConfiguration.swift */; };
AAD861A82E9E748700F6E0E0 /* TranslationSetting.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAD861A72E9E748100F6E0E0 /* TranslationSetting.swift */; };
AAD861AB2E9E75AB00F6E0E0 /* TranslationSettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAD861AA2E9E75A100F6E0E0 /* TranslationSettingsViewController.swift */; };
Expand Down Expand Up @@ -8314,7 +8313,6 @@
5A64225029CB506500EEC3E5 /* TabManagerDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabManagerDelegate.swift; sourceTree = "<group>"; };
5A679E4A2B239FAE004F2B0D /* TabPeekViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabPeekViewController.swift; sourceTree = "<group>"; };
5A70EF18295E2E1600790249 /* DependencyHelperMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DependencyHelperMock.swift; sourceTree = "<group>"; };
5A70EF1C295E3C3500790249 /* TestSetup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestSetup.swift; sourceTree = "<group>"; };
5A70EF1E295E3DFC00790249 /* UnitTestAppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnitTestAppDelegate.swift; sourceTree = "<group>"; };
5A70EF20295E3E0B00790249 /* UnitTestSceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnitTestSceneDelegate.swift; sourceTree = "<group>"; };
5A8017DF29CE15D90047120D /* TabManagerImplementation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabManagerImplementation.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -9567,8 +9565,8 @@
AAB4321A2E8187130075E47F /* RecentSearchProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecentSearchProvider.swift; sourceTree = "<group>"; };
AAB4321C2E8189310075E47F /* DefaultRecentSearchProviderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultRecentSearchProviderTests.swift; sourceTree = "<group>"; };
AAB434052E82F05C0075E47F /* MockTrendingSearchProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockTrendingSearchProvider.swift; sourceTree = "<group>"; };
AAB5B7872EE077BB0051EF6E /* TranslationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TranslationTests.swift; sourceTree = "<group>"; };
AAB5AF372EDDCF5A0051EF6E /* MockLocaleProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockLocaleProvider.swift; sourceTree = "<group>"; };
AAB5B7872EE077BB0051EF6E /* TranslationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TranslationTests.swift; sourceTree = "<group>"; };
AAD1CD862EAABA7C00BEC90A /* TranslationsConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TranslationsConfiguration.swift; sourceTree = "<group>"; };
AAD861A72E9E748100F6E0E0 /* TranslationSetting.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TranslationSetting.swift; sourceTree = "<group>"; };
AAD861AA2E9E75A100F6E0E0 /* TranslationSettingsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TranslationSettingsViewController.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -13747,7 +13745,6 @@
E14BF33D2950B1230039758D /* MailProvidersTests.swift */,
E1463D032982D0240074E16E /* NotificationManagerTests.swift */,
8AEE284A276A973400C7104D /* RatingPromptManagerTests.swift */,
5A70EF1C295E3C3500790249 /* TestSetup.swift */,
);
path = Helpers;
sourceTree = "<group>";
Expand Down Expand Up @@ -14847,7 +14844,6 @@
isa = PBXGroup;
children = (
21A7C44D283539170071D996 /* IntroViewModel.swift */,
81055B552BAB7CE200E166B3 /* OnboardingMultipeChoiceButtonModel.swift */,
8C51ED6F2DE0A4D700B3E58A /* OnboardingKitCardInfoModel.swift */,
8C51ED712DE0A5B500B3E58A /* OnboardingKitViewModel.swift */,
435D660423D794B90046EFA2 /* UpdateViewModel.swift */,
Expand Down Expand Up @@ -18986,7 +18982,6 @@
8A89046D2D52874600A5BB29 /* SyncedTabCell.swift in Sources */,
8A4490952BF3C42B00E7E682 /* MicrosurveyConfirmationView.swift in Sources */,
1DA6F6512B48B42900BB5AD6 /* WindowEventCoordinator.swift in Sources */,
ED07C0E62CCACD7E006C0627 /* Locale+possibilitiesForLanguageIdentifier.swift in Sources */,
437A857827E43FE100E42764 /* FxAWebViewTelemetry.swift in Sources */,
613489A32D942A020009AF01 /* ToastTelemetry.swift in Sources */,
C7F051692DB2F38000EC52C0 /* ContextMenuPreviewViewController.swift in Sources */,
Expand Down Expand Up @@ -19459,7 +19454,6 @@
ED6D46E02D3573F80045E4ED /* TitleActivityItemProviderTests.swift in Sources */,
C736C9C72E9D7C4800658045 /* StoriesFeedStateTests.swift in Sources */,
C8501F5128510DA1003B09AB /* WallpaperMigrationUtilityTests.swift in Sources */,
5A70EF1D295E3C3500790249 /* TestSetup.swift in Sources */,
E1442FDA294782F7003680B0 /* UIPasteboard+Extension.swift in Sources */,
C2D80BEB2AAF395200CDF7A9 /* CredentialAutofillCoordinatorTests.swift in Sources */,
F98CB66E2A4123F1005F38E9 /* EnhancedTrackingProtectionMenuVMTests.swift in Sources */,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ class FormAutofillHelperTests: XCTestCase {
override func setUp() async throws {
try await super.setUp()
profile = MockProfile()
DependencyHelperMock().bootstrapDependencies()
await DependencyHelperMock().bootstrapDependencies()
LegacyFeatureFlagsManager.shared.initializeDeveloperFeatures(with: profile)
tab = await Tab(profile: profile, windowUUID: windowUUID)
formAutofillHelper = FormAutofillHelper(tab: tab)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@ import XCTest
final class LaunchTypeTests: XCTestCase {
let windowUUID: WindowUUID = .XCTestDefaultUUID

override func setUp() {
super.setUp()
DependencyHelperMock().bootstrapDependencies()
override func setUp() async throws {
try await super.setUp()
await DependencyHelperMock().bootstrapDependencies()
}

override func tearDown() {
override func tearDown() async throws {
DependencyHelperMock().reset()
super.tearDown()
try await super.tearDown()
}

func testCanLaunch_surveyFromBrowserCoordinator() {
Expand Down
Loading