Test infra: shared accessibility IDs + PageObjects + AAA_SeedTests

Ports iOS HoneyDueUITests AccessibilityIdentifiers + PageObjects pattern
to Android Compose UI Test. Kotlin AccessibilityIds object mirrors Swift
verbatim so scripts/verify_test_tag_parity.sh can gate on divergence.

AAA_SeedTests bracketed first alphanumerically; SuiteZZ cleanup to follow.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Trey T
2026-04-18 14:19:37 -05:00
parent 42c21bfca1
commit 2d80ade6bc
12 changed files with 1076 additions and 0 deletions

View File

@@ -0,0 +1,289 @@
package com.tt.honeyDue.testing
/**
* Centralized accessibility identifiers for UI testing.
*
* 1:1 port of iOS `AccessibilityIdentifiers.swift` — string values MUST
* remain verbatim matches so `scripts/verify_test_tag_parity.sh` can gate
* cross-platform divergence. Production screens reference these via
* `Modifier.testTag(AccessibilityIds.Authentication.usernameField)` so the
* same test harness works identically across iOS and Android.
*/
object AccessibilityIds {
// MARK: - Authentication
object Authentication {
const val usernameField = "Login.UsernameField"
const val passwordField = "Login.PasswordField"
const val loginButton = "Login.LoginButton"
const val signUpButton = "Login.SignUpButton"
const val forgotPasswordButton = "Login.ForgotPasswordButton"
const val passwordVisibilityToggle = "Login.PasswordVisibilityToggle"
const val appleSignInButton = "Login.AppleSignInButton"
const val googleSignInButton = "Login.GoogleSignInButton"
// Registration
const val registerUsernameField = "Register.UsernameField"
const val registerEmailField = "Register.EmailField"
const val registerPasswordField = "Register.PasswordField"
const val registerConfirmPasswordField = "Register.ConfirmPasswordField"
const val registerButton = "Register.RegisterButton"
const val registerCancelButton = "Register.CancelButton"
// Verification
const val verificationCodeField = "Verification.CodeField"
const val verifyButton = "Verification.VerifyButton"
const val resendCodeButton = "Verification.ResendButton"
}
// MARK: - Navigation
object Navigation {
const val residencesTab = "TabBar.Residences"
const val tasksTab = "TabBar.Tasks"
const val contractorsTab = "TabBar.Contractors"
const val documentsTab = "TabBar.Documents"
const val profileTab = "TabBar.Profile"
const val settingsButton = "Navigation.SettingsButton"
const val backButton = "Navigation.BackButton"
}
// MARK: - Residence
object Residence {
// List
const val addButton = "Residence.AddButton"
const val residencesList = "Residence.List"
const val residenceCard = "Residence.Card"
const val emptyStateView = "Residence.EmptyState"
const val emptyStateButton = "Residence.EmptyState.AddButton"
// Form
const val nameField = "ResidenceForm.NameField"
const val propertyTypePicker = "ResidenceForm.PropertyTypePicker"
const val streetAddressField = "ResidenceForm.StreetAddressField"
const val apartmentUnitField = "ResidenceForm.ApartmentUnitField"
const val cityField = "ResidenceForm.CityField"
const val stateProvinceField = "ResidenceForm.StateProvinceField"
const val postalCodeField = "ResidenceForm.PostalCodeField"
const val countryField = "ResidenceForm.CountryField"
const val bedroomsField = "ResidenceForm.BedroomsField"
const val bathroomsField = "ResidenceForm.BathroomsField"
const val squareFootageField = "ResidenceForm.SquareFootageField"
const val lotSizeField = "ResidenceForm.LotSizeField"
const val yearBuiltField = "ResidenceForm.YearBuiltField"
const val descriptionField = "ResidenceForm.DescriptionField"
const val isPrimaryToggle = "ResidenceForm.IsPrimaryToggle"
const val saveButton = "ResidenceForm.SaveButton"
const val formCancelButton = "ResidenceForm.CancelButton"
// Detail
const val detailView = "ResidenceDetail.View"
const val editButton = "ResidenceDetail.EditButton"
const val deleteButton = "ResidenceDetail.DeleteButton"
const val shareButton = "ResidenceDetail.ShareButton"
const val manageUsersButton = "ResidenceDetail.ManageUsersButton"
const val tasksSection = "ResidenceDetail.TasksSection"
const val addTaskButton = "ResidenceDetail.AddTaskButton"
}
// MARK: - Task
object Task {
// List/Kanban
const val addButton = "Task.AddButton"
const val refreshButton = "Task.RefreshButton"
const val tasksList = "Task.List"
const val taskCard = "Task.Card"
const val emptyStateView = "Task.EmptyState"
const val kanbanView = "Task.KanbanView"
const val overdueColumn = "Task.Column.Overdue"
const val upcomingColumn = "Task.Column.Upcoming"
const val inProgressColumn = "Task.Column.InProgress"
const val completedColumn = "Task.Column.Completed"
// Form
const val titleField = "TaskForm.TitleField"
const val descriptionField = "TaskForm.DescriptionField"
const val categoryPicker = "TaskForm.CategoryPicker"
const val frequencyPicker = "TaskForm.FrequencyPicker"
const val priorityPicker = "TaskForm.PriorityPicker"
const val statusPicker = "TaskForm.StatusPicker"
const val dueDatePicker = "TaskForm.DueDatePicker"
const val intervalDaysField = "TaskForm.IntervalDaysField"
const val estimatedCostField = "TaskForm.EstimatedCostField"
const val residencePicker = "TaskForm.ResidencePicker"
const val saveButton = "TaskForm.SaveButton"
const val formCancelButton = "TaskForm.CancelButton"
// Detail
const val detailView = "TaskDetail.View"
const val editButton = "TaskDetail.EditButton"
const val deleteButton = "TaskDetail.DeleteButton"
const val markInProgressButton = "TaskDetail.MarkInProgressButton"
const val completeButton = "TaskDetail.CompleteButton"
const val detailCancelButton = "TaskDetail.CancelButton"
// Completion
const val completionDatePicker = "TaskCompletion.CompletionDatePicker"
const val actualCostField = "TaskCompletion.ActualCostField"
const val ratingView = "TaskCompletion.RatingView"
const val notesField = "TaskCompletion.NotesField"
const val photosPicker = "TaskCompletion.PhotosPicker"
const val submitButton = "TaskCompletion.SubmitButton"
}
// MARK: - Contractor
object Contractor {
const val addButton = "Contractor.AddButton"
const val contractorsList = "Contractor.List"
const val contractorCard = "Contractor.Card"
const val emptyStateView = "Contractor.EmptyState"
// Form
const val nameField = "ContractorForm.NameField"
const val companyField = "ContractorForm.CompanyField"
const val emailField = "ContractorForm.EmailField"
const val phoneField = "ContractorForm.PhoneField"
const val specialtyPicker = "ContractorForm.SpecialtyPicker"
const val ratingView = "ContractorForm.RatingView"
const val notesField = "ContractorForm.NotesField"
const val saveButton = "ContractorForm.SaveButton"
const val formCancelButton = "ContractorForm.CancelButton"
// Detail
const val detailView = "ContractorDetail.View"
const val menuButton = "ContractorDetail.MenuButton"
const val editButton = "ContractorDetail.EditButton"
const val deleteButton = "ContractorDetail.DeleteButton"
const val callButton = "ContractorDetail.CallButton"
const val emailButton = "ContractorDetail.EmailButton"
}
// MARK: - Document
object Document {
const val addButton = "Document.AddButton"
const val documentsList = "Document.List"
const val documentCard = "Document.Card"
const val emptyStateView = "Document.EmptyState"
// Form
const val titleField = "DocumentForm.TitleField"
const val typePicker = "DocumentForm.TypePicker"
const val categoryPicker = "DocumentForm.CategoryPicker"
const val residencePicker = "DocumentForm.ResidencePicker"
const val filePicker = "DocumentForm.FilePicker"
const val notesField = "DocumentForm.NotesField"
const val expirationDatePicker = "DocumentForm.ExpirationDatePicker"
const val itemNameField = "DocumentForm.ItemNameField"
const val modelNumberField = "DocumentForm.ModelNumberField"
const val serialNumberField = "DocumentForm.SerialNumberField"
const val providerField = "DocumentForm.ProviderField"
const val providerContactField = "DocumentForm.ProviderContactField"
const val tagsField = "DocumentForm.TagsField"
const val locationField = "DocumentForm.LocationField"
const val saveButton = "DocumentForm.SaveButton"
const val formCancelButton = "DocumentForm.CancelButton"
// Detail
const val detailView = "DocumentDetail.View"
const val menuButton = "DocumentDetail.MenuButton"
const val editButton = "DocumentDetail.EditButton"
const val deleteButton = "DocumentDetail.DeleteButton"
const val shareButton = "DocumentDetail.ShareButton"
const val downloadButton = "DocumentDetail.DownloadButton"
}
// MARK: - Onboarding
object Onboarding {
// Welcome Screen
const val welcomeTitle = "Onboarding.WelcomeTitle"
const val startFreshButton = "Onboarding.StartFreshButton"
const val joinExistingButton = "Onboarding.JoinExistingButton"
const val loginButton = "Onboarding.LoginButton"
// Value Props Screen
const val valuePropsTitle = "Onboarding.ValuePropsTitle"
const val valuePropsNextButton = "Onboarding.ValuePropsNextButton"
// Name Residence Screen
const val nameResidenceTitle = "Onboarding.NameResidenceTitle"
const val residenceNameField = "Onboarding.ResidenceNameField"
const val nameResidenceContinueButton = "Onboarding.NameResidenceContinueButton"
// Create Account Screen
const val createAccountTitle = "Onboarding.CreateAccountTitle"
const val appleSignInButton = "Onboarding.AppleSignInButton"
const val emailSignUpExpandButton = "Onboarding.EmailSignUpExpandButton"
const val usernameField = "Onboarding.UsernameField"
const val emailField = "Onboarding.EmailField"
const val passwordField = "Onboarding.PasswordField"
const val confirmPasswordField = "Onboarding.ConfirmPasswordField"
const val createAccountButton = "Onboarding.CreateAccountButton"
const val loginLinkButton = "Onboarding.LoginLinkButton"
// Verify Email Screen
const val verifyEmailTitle = "Onboarding.VerifyEmailTitle"
const val verificationCodeField = "Onboarding.VerificationCodeField"
const val verifyButton = "Onboarding.VerifyButton"
// Join Residence Screen
const val joinResidenceTitle = "Onboarding.JoinResidenceTitle"
const val shareCodeField = "Onboarding.ShareCodeField"
const val joinResidenceButton = "Onboarding.JoinResidenceButton"
// First Task Screen
const val firstTaskTitle = "Onboarding.FirstTaskTitle"
const val taskSelectionCounter = "Onboarding.TaskSelectionCounter"
const val addPopularTasksButton = "Onboarding.AddPopularTasksButton"
const val addTasksContinueButton = "Onboarding.AddTasksContinueButton"
const val taskCategorySection = "Onboarding.TaskCategorySection"
const val taskTemplateRow = "Onboarding.TaskTemplateRow"
// Subscription Screen
const val subscriptionTitle = "Onboarding.SubscriptionTitle"
const val yearlyPlanCard = "Onboarding.YearlyPlanCard"
const val monthlyPlanCard = "Onboarding.MonthlyPlanCard"
const val startTrialButton = "Onboarding.StartTrialButton"
const val continueWithFreeButton = "Onboarding.ContinueWithFreeButton"
// Navigation
const val backButton = "Onboarding.BackButton"
const val skipButton = "Onboarding.SkipButton"
const val progressIndicator = "Onboarding.ProgressIndicator"
}
// MARK: - Profile
object Profile {
const val logoutButton = "Profile.LogoutButton"
const val editProfileButton = "Profile.EditProfileButton"
const val settingsButton = "Profile.SettingsButton"
const val notificationsToggle = "Profile.NotificationsToggle"
const val darkModeToggle = "Profile.DarkModeToggle"
const val aboutButton = "Profile.AboutButton"
const val helpButton = "Profile.HelpButton"
}
// MARK: - Alerts & Modals
object Alert {
const val confirmButton = "Alert.ConfirmButton"
const val cancelButton = "Alert.CancelButton"
const val deleteButton = "Alert.DeleteButton"
const val okButton = "Alert.OKButton"
}
// MARK: - Common
object Common {
const val loadingIndicator = "Common.LoadingIndicator"
const val errorView = "Common.ErrorView"
const val retryButton = "Common.RetryButton"
const val searchField = "Common.SearchField"
const val filterButton = "Common.FilterButton"
const val sortButton = "Common.SortButton"
const val refreshControl = "Common.RefreshControl"
}
/**
* Convenience helper to generate dynamic identifiers.
* Example: withId(Residence.residenceCard, residenceId) yields
* Residence.Card.{residenceId}.
*/
fun withId(base: String, id: Any): String = "$base.$id"
}