diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 452fe72b8..57812aa82 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -793,7 +793,7 @@ jobs:
done
- name: Upload Sources
- uses: crowdin/github-action@ecd7eb0ef6f3cfa16293c79e9cbc4bc5b5fd9c49 # v1.4.9
+ uses: crowdin/github-action@965d501f160af7b1f88aed4c29154b0caf1e94b9 # v1.9.0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CROWDIN_API_TOKEN: ${{ steps.retrieve-secrets.outputs.crowdin-api-token }}
diff --git a/.github/workflows/crowdin-pull.yml b/.github/workflows/crowdin-pull.yml
index 36aaaa9ab..a2a297a19 100644
--- a/.github/workflows/crowdin-pull.yml
+++ b/.github/workflows/crowdin-pull.yml
@@ -30,7 +30,7 @@ jobs:
secrets: "crowdin-api-token, github-gpg-private-key, github-gpg-private-key-passphrase"
- name: Download translations
- uses: crowdin/github-action@ecd7eb0ef6f3cfa16293c79e9cbc4bc5b5fd9c49 # v1.4.9
+ uses: crowdin/github-action@965d501f160af7b1f88aed4c29154b0caf1e94b9 # v1.9.0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CROWDIN_API_TOKEN: ${{ steps.retrieve-secrets.outputs.crowdin-api-token }}
diff --git a/.github/workflows/enforce-labels.yml b/.github/workflows/enforce-labels.yml
index 417e34e9b..4e3127761 100644
--- a/.github/workflows/enforce-labels.yml
+++ b/.github/workflows/enforce-labels.yml
@@ -10,7 +10,7 @@ jobs:
runs-on: ubuntu-20.04
steps:
- name: Enforce Label
- uses: yogevbd/enforce-label-action@a3c219da6b8fa73f6ba62b68ff09c469b3a1c024 # v2.2.2
+ uses: yogevbd/enforce-label-action@a3c219da6b8fa73f6ba62b68ff09c469b3a1c024 # 2.2.2
with:
BANNED_LABELS: "hold,needs-qa"
BANNED_LABELS_DESCRIPTION: "PRs with the hold or needs-qa labels cannot be merged"
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index f1e57bbe9..50f4128e9 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -68,7 +68,7 @@ jobs:
- name: Download all artifacts
if: ${{ github.event.inputs.release_type != 'Dry Run' }}
- uses: dawidd6/action-download-artifact@575b1e4167df67acf7e692af784566618b23c71e # v2.17.10
+ uses: dawidd6/action-download-artifact@246dbf436b23d7c49e21a7ab8204ca9ecd1fe615 # v2.27.0
with:
workflow: build.yml
workflow_conclusion: success
@@ -76,7 +76,7 @@ jobs:
- name: Dry Run - Download all artifacts
if: ${{ github.event.inputs.release_type == 'Dry Run' }}
- uses: dawidd6/action-download-artifact@575b1e4167df67acf7e692af784566618b23c71e # v2.17.10
+ uses: dawidd6/action-download-artifact@246dbf436b23d7c49e21a7ab8204ca9ecd1fe615 # v2.27.0
with:
workflow: build.yml
workflow_conclusion: success
@@ -130,7 +130,7 @@ jobs:
- name: Download F-Droid .apk artifact
if: ${{ github.event.inputs.release_type != 'Dry Run' }}
- uses: dawidd6/action-download-artifact@575b1e4167df67acf7e692af784566618b23c71e # v2.17.10
+ uses: dawidd6/action-download-artifact@246dbf436b23d7c49e21a7ab8204ca9ecd1fe615 # v2.27.0
with:
workflow: build.yml
workflow_conclusion: success
@@ -139,7 +139,7 @@ jobs:
- name: Dry Run - Download F-Droid .apk artifact
if: ${{ github.event.inputs.release_type == 'Dry Run' }}
- uses: dawidd6/action-download-artifact@575b1e4167df67acf7e692af784566618b23c71e # v2.17.10
+ uses: dawidd6/action-download-artifact@246dbf436b23d7c49e21a7ab8204ca9ecd1fe615 # v2.27.0
with:
workflow: build.yml
workflow_conclusion: success
diff --git a/src/Android/Android.csproj b/src/Android/Android.csproj
index 4b42db250..c5f838ff8 100644
--- a/src/Android/Android.csproj
+++ b/src/Android/Android.csproj
@@ -159,6 +159,7 @@
+
diff --git a/src/Android/Autofill/FieldCollection.cs b/src/Android/Autofill/FieldCollection.cs
index a01aaad70..63d2e512b 100644
--- a/src/Android/Autofill/FieldCollection.cs
+++ b/src/Android/Autofill/FieldCollection.cs
@@ -12,7 +12,7 @@ namespace Bit.Droid.Autofill
private List _passwordFields = null;
private List _usernameFields = null;
private HashSet _ignoreSearchTerms = new HashSet { "search", "find", "recipient", "edit" };
- private HashSet _usernameTerms = new HashSet { "email", "phone", "username"};
+ private HashSet _usernameTerms = new HashSet { "email", "phone", "username" };
private HashSet _passwordTerms = new HashSet { "password", "pswd" };
public List AutofillIds { get; private set; } = new List();
@@ -54,15 +54,14 @@ namespace Bit.Droid.Autofill
if (HintToFieldsMap.ContainsKey(View.AutofillHintPassword))
{
_passwordFields.AddRange(HintToFieldsMap[View.AutofillHintPassword]);
+ return _passwordFields;
}
}
- else
+
+ _passwordFields = Fields.Where(f => FieldIsPassword(f)).ToList();
+ if (!_passwordFields.Any())
{
- _passwordFields = Fields.Where(f => FieldIsPassword(f)).ToList();
- if (!_passwordFields.Any())
- {
- _passwordFields = Fields.Where(f => FieldHasPasswordTerms(f)).ToList();
- }
+ _passwordFields = Fields.Where(f => FieldHasPasswordTerms(f)).ToList();
}
return _passwordFields;
}
@@ -87,24 +86,26 @@ namespace Bit.Droid.Autofill
{
_usernameFields.AddRange(HintToFieldsMap[View.AutofillHintUsername]);
}
+ if (_usernameFields.Any())
+ {
+ return _usernameFields;
+ }
}
- else
- {
- foreach (var passwordField in PasswordFields)
- {
- var usernameField = Fields.TakeWhile(f => f.AutofillId != passwordField.AutofillId)
- .LastOrDefault();
- if (usernameField != null)
- {
- _usernameFields.Add(usernameField);
- }
- }
- if (!_usernameFields.Any())
+ foreach (var passwordField in PasswordFields)
+ {
+ var usernameField = Fields.TakeWhile(f => f.AutofillId != passwordField.AutofillId)
+ .LastOrDefault();
+ if (usernameField != null)
{
- _usernameFields = Fields.Where(f => FieldIsUsername(f)).ToList();
+ _usernameFields.Add(usernameField);
}
}
+
+ if (!_usernameFields.Any())
+ {
+ _usernameFields = Fields.Where(f => FieldIsUsername(f)).ToList();
+ }
return _usernameFields;
}
}
diff --git a/src/Android/Renderers/CustomLabelRenderer.cs b/src/Android/Renderers/CustomLabelRenderer.cs
new file mode 100644
index 000000000..62287087d
--- /dev/null
+++ b/src/Android/Renderers/CustomLabelRenderer.cs
@@ -0,0 +1,31 @@
+using System;
+using Bit.App.Controls;
+using System.ComponentModel;
+using Xamarin.Forms.Platform.Android;
+using Android.Content;
+using Xamarin.Forms;
+using Bit.Droid.Renderers;
+
+[assembly: ExportRenderer(typeof(CustomLabel), typeof(CustomLabelRenderer))]
+namespace Bit.Droid.Renderers
+{
+ public class CustomLabelRenderer : LabelRenderer
+ {
+ public CustomLabelRenderer(Context context)
+ : base(context)
+ { }
+
+ protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
+ {
+ var label = sender as CustomLabel;
+ switch (e.PropertyName)
+ {
+ case nameof(CustomLabel.AutomationId):
+ Control.ContentDescription = label.AutomationId;
+ break;
+ }
+ base.OnElementPropertyChanged(sender, e);
+ }
+ }
+}
+
diff --git a/src/App/App.csproj b/src/App/App.csproj
index 83e1ee879..54d589ef7 100644
--- a/src/App/App.csproj
+++ b/src/App/App.csproj
@@ -145,6 +145,7 @@
+
@@ -440,5 +441,6 @@
+
diff --git a/src/App/Controls/AccountSwitchingOverlay/AccountSwitchingOverlayView.xaml b/src/App/Controls/AccountSwitchingOverlay/AccountSwitchingOverlayView.xaml
index f0c52d0d4..4dba94dd1 100644
--- a/src/App/Controls/AccountSwitchingOverlay/AccountSwitchingOverlayView.xaml
+++ b/src/App/Controls/AccountSwitchingOverlay/AccountSwitchingOverlayView.xaml
@@ -30,13 +30,15 @@
BackgroundColor="{DynamicResource BackgroundColor}"
VerticalOptions="Start"
RowHeight="{Binding AccountListRowHeight, Source={x:Reference _mainOverlay}}"
- effects:ScrollViewContentInsetAdjustmentBehaviorEffect.ContentInsetAdjustmentBehavior="Never">
+ effects:ScrollViewContentInsetAdjustmentBehaviorEffect.ContentInsetAdjustmentBehavior="Never"
+ AutomationId="AccountListView">
diff --git a/src/App/Controls/AccountViewCell/AccountViewCell.xaml b/src/App/Controls/AccountViewCell/AccountViewCell.xaml
index 3d45cf929..9a9f53831 100644
--- a/src/App/Controls/AccountViewCell/AccountViewCell.xaml
+++ b/src/App/Controls/AccountViewCell/AccountViewCell.xaml
@@ -1,4 +1,4 @@
-
+
+ LineBreakMode="TailTruncation"
+ AutomationId="AccountEmailLabel" />
+ LineBreakMode="TailTruncation"
+ AutomationId="AccountEmailLabel" />
+ LineBreakMode="TailTruncation"
+ AutomationId="AccountHostUrlLabel" />
+ LineBreakMode="TailTruncation"
+ AutomationId="AccountStatusLabel" />
+ LineBreakMode="TailTruncation"
+ AutomationId="AccountStatusLabel" />
+ LineBreakMode="TailTruncation"
+ AutomationId="AccountStatusLabel" />
+ StyleClass="list-icon, list-icon-platform"
+ AutomationId="InactiveVaultIcon" />
+ TextColor="{DynamicResource TextColor}"
+ AutomationId="ActiveVaultIcon" />
+ Grid.Column="1"
+ AutomationId="AddAccountButton" />
\ No newline at end of file
diff --git a/src/App/Controls/CipherViewCell/CipherViewCell.xaml b/src/App/Controls/CipherViewCell/CipherViewCell.xaml
index 5024ad537..e2ecba08e 100644
--- a/src/App/Controls/CipherViewCell/CipherViewCell.xaml
+++ b/src/App/Controls/CipherViewCell/CipherViewCell.xaml
@@ -9,7 +9,8 @@
StyleClass="list-row, list-row-platform"
RowSpacing="0"
ColumnSpacing="0"
- x:DataType="controls:CipherViewCellViewModel">
+ x:DataType="controls:CipherViewCellViewModel"
+ AutomationId="CipherCell">
@@ -36,7 +37,8 @@
IsVisible="{Binding ShowIconImage, Converter={StaticResource inverseBool}}"
Text="{Binding Cipher, Converter={StaticResource iconGlyphConverter}}"
ShouldUpdateFontSizeDynamicallyForAccesibility="True"
- AutomationProperties.IsInAccessibleTree="False" />
+ AutomationProperties.IsInAccessibleTree="False"
+ AutomationId="CipherTypeIcon" />
+ AutomationProperties.IsInAccessibleTree="False"
+ AutomationId="CipherWebsiteIcon" />
@@ -71,7 +74,8 @@
Grid.Column="0"
Grid.Row="0"
StyleClass="list-title, list-title-platform"
- Text="{Binding Cipher.Name}" />
+ Text="{Binding Cipher.Name}"
+ AutomationId="CipherNameLabel" />
+ Converter={StaticResource stringHasValueConverter}}"
+ AutomationId="CipherSubTitleLabel" />
+ AutomationProperties.Name="{u:I18n Shared}"
+ AutomationId="CipherInCollectionIcon" />
+ AutomationProperties.Name="{u:I18n Attachments}"
+ AutomationId="CipherWithAttachmentsIcon" />
+ AutomationProperties.Name="{u:I18n Options}"
+ AutomationId="CipherOptionsButton" />
\ No newline at end of file
diff --git a/src/App/Controls/CustomLabel.cs b/src/App/Controls/CustomLabel.cs
new file mode 100644
index 000000000..e822d3304
--- /dev/null
+++ b/src/App/Controls/CustomLabel.cs
@@ -0,0 +1,13 @@
+using System;
+using Xamarin.Forms;
+
+namespace Bit.App.Controls
+{
+ public class CustomLabel : Label
+ {
+ public CustomLabel()
+ {
+ }
+ }
+}
+
diff --git a/src/App/Controls/SendViewCell/SendViewCell.xaml b/src/App/Controls/SendViewCell/SendViewCell.xaml
index 8a9d0e2a6..30d7b8ca3 100644
--- a/src/App/Controls/SendViewCell/SendViewCell.xaml
+++ b/src/App/Controls/SendViewCell/SendViewCell.xaml
@@ -1,4 +1,4 @@
-
+
+ Text="{Binding Send.Name}"
+ AutomationId="SendNameLabel" />
+ Text="{Binding Send.DisplayDate}"
+ AutomationId="SendDateLabel" />
+ AutomationProperties.Name="{u:I18n Disabled}"
+ AutomationId="DisabledSendLabel" />
+ AutomationProperties.Name="{u:I18n Password}"
+ AutomationId="PasswordProtectedSendLabel" />
+ AutomationProperties.Name="{u:I18n MaxAccessCountReached}"
+ AutomationId="SendMaxAccessCountReachedLabel" />
+ AutomationProperties.Name="{u:I18n Expired}"
+ AutomationId="ExpiredSendLabel" />
+ AutomationProperties.Name="{u:I18n PendingDelete}"
+ AutomationId="SendWithPendingDeletionLabel" />
+ AutomationProperties.Name="{u:I18n Options}"
+ AutomationId="SendOptionsButton" />
diff --git a/src/App/Lists/ItemLayouts/CustomFields/BooleanCustomFieldItemLayout.xaml b/src/App/Lists/ItemLayouts/CustomFields/BooleanCustomFieldItemLayout.xaml
index c50cf53eb..6c7d22ed7 100644
--- a/src/App/Lists/ItemLayouts/CustomFields/BooleanCustomFieldItemLayout.xaml
+++ b/src/App/Lists/ItemLayouts/CustomFields/BooleanCustomFieldItemLayout.xaml
@@ -33,7 +33,8 @@
StyleClass="box-label"
Grid.Row="0"
Grid.Column="0"
- IsVisible="{Binding IsEditing, Mode=OneWay, Converter={StaticResource inverseBool}}" />
+ IsVisible="{Binding IsEditing, Mode=OneWay, Converter={StaticResource inverseBool}}"
+ AutomationId="BooleanCustomFieldNameLabel" />
+ IsVisible="{Binding IsEditing, Mode=OneWay, Converter={StaticResource inverseBool}}"
+ AutomationId="BooleanCustomFieldValueLabel" />
+ Grid.RowSpan="2"
+ AutomationId="BooleanCustomFieldValueToggle" />
+ Grid.Column="0"
+ AutomationId="HiddenCustomFieldNameLabel" />
+ IsVisible="{Binding ShowHiddenValue}"
+ AutomationId="HiddenCustomFieldValueLabel" />
+ AutomationProperties.Name="{Binding Field.Name}"
+ AutomationId="HiddenCustomFieldValueEntry">
@@ -74,7 +77,8 @@
Grid.Column="1"
Grid.RowSpan="2"
AutomationProperties.IsInAccessibleTree="True"
- AutomationProperties.Name="{u:I18n ToggleVisibility}" />
+ AutomationProperties.Name="{u:I18n ToggleVisibility}"
+ AutomationId="HiddenCustomFieldShowValueButton" />
+ Grid.Column="0"
+ AutomationId="LinkedCustomFieldNameLabel" />
+ IsVisible="{Binding IsEditing, Mode=OneWay, Converter={StaticResource inverseBool}}"
+ AutomationId="LinkedCustomFieldValueLabel" />
@@ -44,7 +46,8 @@
ItemsSource="{Binding LinkedFieldOptions, Mode=OneTime}"
SelectedIndex="{Binding LinkedFieldOptionSelectedIndex}"
ItemDisplayBinding="{Binding Key}"
- StyleClass="box-value" />
+ StyleClass="box-value"
+ AutomationId="LinkedCustomFieldValuePicker" />
+ AutomationProperties.Name="{u:I18n Options}"
+ AutomationId="LinkedCustomFieldOptionsButton" />
diff --git a/src/App/Lists/ItemLayouts/CustomFields/TextCustomFieldItemLayout.xaml b/src/App/Lists/ItemLayouts/CustomFields/TextCustomFieldItemLayout.xaml
index 238fbe0ab..23e243119 100644
--- a/src/App/Lists/ItemLayouts/CustomFields/TextCustomFieldItemLayout.xaml
+++ b/src/App/Lists/ItemLayouts/CustomFields/TextCustomFieldItemLayout.xaml
@@ -29,13 +29,15 @@
Text="{Binding Field.Name, Mode=OneWay}"
StyleClass="box-label"
Grid.Row="0"
- Grid.Column="0" />
+ Grid.Column="0"
+ AutomationId="TextCustomFieldNameLabel" />
+ IsVisible="{Binding IsEditing, Mode=OneWay, Converter={StaticResource inverseBool}}"
+ AutomationId="TextCustomFieldValueLabel" />
+ AutomationProperties.Name="{Binding Field.Name}"
+ AutomationId="TextCustomFieldValueEntry" />
+ AutomationProperties.Name="{u:I18n Copy}"
+ AutomationId="TextCustomFieldCopyValue" />
+ AutomationProperties.Name="{u:I18n Options}"
+ AutomationId="TextCustomFieldOptionsButton" />
diff --git a/src/App/Pages/Accounts/HomePage.xaml b/src/App/Pages/Accounts/HomePage.xaml
index a4e5f9fcd..d99b965f7 100644
--- a/src/App/Pages/Accounts/HomePage.xaml
+++ b/src/App/Pages/Accounts/HomePage.xaml
@@ -23,7 +23,8 @@
Priority="-1"
UseOriginalImage="True"
AutomationProperties.IsInAccessibleTree="True"
- AutomationProperties.Name="{u:I18n Account}" />
+ AutomationProperties.Name="{u:I18n Account}"
+ AutomationId="AccountIconButton" />
diff --git a/src/App/Pages/Accounts/LockPage.xaml b/src/App/Pages/Accounts/LockPage.xaml
index 561b051f5..f34a8b284 100644
--- a/src/App/Pages/Accounts/LockPage.xaml
+++ b/src/App/Pages/Accounts/LockPage.xaml
@@ -24,7 +24,8 @@
Priority="-1"
UseOriginalImage="True"
AutomationProperties.IsInAccessibleTree="True"
- AutomationProperties.Name="{u:I18n Account}" />
+ AutomationProperties.Name="{u:I18n Account}"
+ AutomationId="AccountIconButton" />
@@ -72,7 +73,7 @@
Grid.Column="0"
ReturnType="Go"
ReturnCommand="{Binding SubmitCommand}"
- AutomationId="PinEntry"/>
+ AutomationId="PinEntry" />
+ AutomationId="PinVisibilityToggle" />
+ AutomationId="MasterPasswordEntry" />
+ AutomationId="UnlockVaultButton" />
diff --git a/src/App/Pages/Accounts/LoginPage.xaml b/src/App/Pages/Accounts/LoginPage.xaml
index fd2bb3fbd..5f93f9b0c 100644
--- a/src/App/Pages/Accounts/LoginPage.xaml
+++ b/src/App/Pages/Accounts/LoginPage.xaml
@@ -24,7 +24,8 @@
Priority="-1"
UseOriginalImage="True"
AutomationProperties.IsInAccessibleTree="True"
- AutomationProperties.Name="{u:I18n Account}" />
+ AutomationProperties.Name="{u:I18n Account}"
+ AutomationId="AccountIconButton" />
@@ -34,7 +35,7 @@
x:Name="_moreItem" x:Key="moreItem"
AutomationProperties.IsInAccessibleTree="True"
AutomationProperties.Name="{u:I18n Options}"
- AutomationId="OptionsButton"/>
+ AutomationId="OptionsButton" />
+ Margin="0,0,0,24"
+ AutomationId="LogInAttemptByLabel" />
+ Margin="0,0,0,27"
+ AutomationId="FingerprintValueLabel" />
+ Margin="0,0,0,21"
+ AutomationId="DeviceTypeValueLabel" />
+ Margin="0,0,0,21"
+ AutomationId="IpAddressValueLabel" />
+ Margin="0,0,0,57"
+ AutomationId="TimeOfRequestValueLabel" />
@@ -75,11 +80,13 @@
Text="{u:I18n ConfirmLogIn}"
Command="{Binding AcceptRequestCommand}"
Margin="0,0,0,17"
- StyleClass="btn-primary"/>
+ StyleClass="btn-primary"
+ AutomationId="ConfirmLoginButton" />
+ StyleClass="btn-secundary"
+ AutomationId="DenyLoginButton" />
diff --git a/src/App/Pages/Accounts/LoginPasswordlessRequestPage.xaml b/src/App/Pages/Accounts/LoginPasswordlessRequestPage.xaml
index d6ea864f0..6141ade6b 100644
--- a/src/App/Pages/Accounts/LoginPasswordlessRequestPage.xaml
+++ b/src/App/Pages/Accounts/LoginPasswordlessRequestPage.xaml
@@ -24,7 +24,8 @@
Text="{u:I18n LogInInitiated}"
FontSize="Title"
FontAttributes="Bold"
- Margin="0,14,0,21"/>
+ Margin="0,14,0,21"
+ AutomationId="LogInInitiatedLabel" />
+ TextColor="{DynamicResource FingerprintPhrase}"
+ AutomationId="FingerprintPhraseValue" />
+ HorizontalTextAlignment="Center"
+ AutomationId="NoPasswordsDisplayedLabel">
+ ColumnSpacing="10"
+ AutomationId="GeneratedPasswordRow">
@@ -71,12 +74,14 @@
Grid.Column="0"
Grid.Row="0"
StyleClass="list-title, list-title-platform, text-html"
- Text="{Binding Password, Mode=OneWay, Converter={StaticResource coloredPassword}}" />
+ Text="{Binding Password, Mode=OneWay, Converter={StaticResource coloredPassword}}"
+ AutomationId="GeneratedPasswordValue" />
+ Text="{Binding Date, Mode=OneWay, Converter={StaticResource dateTime}}"
+ AutomationId="GeneratedPasswordDateLabel" />
+ AutomationProperties.Name="{u:I18n CopyPassword}"
+ AutomationId="CopyPasswordValueButton" />
diff --git a/src/App/Pages/Generator/GeneratorPage.xaml b/src/App/Pages/Generator/GeneratorPage.xaml
index 975180db8..a2f8b533b 100644
--- a/src/App/Pages/Generator/GeneratorPage.xaml
+++ b/src/App/Pages/Generator/GeneratorPage.xaml
@@ -71,7 +71,8 @@
+ HorizontalTextAlignment="Center"
+ AutomationId="PasswordGeneratorPolicyInEffectLabel" />
+ Margin="0, 20"
+ AutomationId="GeneratedPasswordLabel" />
+ AutomationProperties.Name="{u:I18n CopyPassword}"
+ AutomationId="CopyValueButton" />
+ AutomationProperties.Name="{u:I18n GeneratePassword}"
+ AutomationId="RegenerateValueButton" />
+ HorizontalOptions="Start"
+ AutomationId="GeneratedPasswordLabel" />
+ AutomationProperties.Name="{u:I18n CopyUsername}"
+ AutomationId="CopyValueButton" />
+ AutomationProperties.Name="{u:I18n GenerateUsername}"
+ AutomationId="RegenerateValueButton" />
+ StyleClass="box-value"
+ AutomationId="GeneratorTypePicker" />
+ StyleClass="box-value"
+ AutomationId="UsernameTypePicker" />
@@ -172,7 +181,8 @@
StyleClass="box-label" />
+ StyleClass="box-value"
+ AutomationId="PlusAddressedEmailEntry" />
+ StyleClass="box-value"
+ AutomationId="CatchAllEmailDomainEntry" />
-
-
+ StyleClass="box-value"
+ AutomationId="ServiceTypePicker" />
+
+ Text="{Binding ForwardedEmailApiSecret}"
+ IsPassword="{Binding ShowForwardedEmailApiSecret, Converter={StaticResource inverseBool}}"
+ Grid.Row="1"
+ AutomationId="ForwardedEmailApiSecretEntry" />
+ Grid.Column="1"
+ AutomationId="ShowForwardedEmailApiSecretButton" />
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ StyleClass="box-value"
+ AutomationId="AnonAddyDomainNameEntry" />
@@ -359,7 +288,8 @@
+ HorizontalOptions="End"
+ AutomationId="CapitalizeRandomWordUsernameToggle" />
@@ -371,7 +301,8 @@
+ HorizontalOptions="End"
+ AutomationId="IncludeNumberRandomWordUsernameToggle" />
@@ -386,7 +317,8 @@
x:Name="_passwordTypePicker"
ItemsSource="{Binding PasswordTypeOptions, Mode=OneTime}"
SelectedIndex="{Binding PasswordTypeSelectedIndex}"
- StyleClass="box-value" />
+ StyleClass="box-value"
+ AutomationId="PasswordTypePicker" />
+ VerticalTextAlignment="Center"
+ AutomationId="NumberOfWordsLabel" />
+ Increment="1"
+ AutomationId="NumberOfWordsStepper" />
@@ -419,7 +353,8 @@
Text="{Binding WordSeparator}"
IsSpellCheckEnabled="False"
IsTextPredictionEnabled="False"
- StyleClass="box-value">
+ StyleClass="box-value"
+ AutomationId="WordSeparatorEntry">
@@ -435,7 +370,8 @@
IsEnabled="{Binding EnforcedPolicyOptions.Capitalize,
Converter={StaticResource inverseBool}}"
StyleClass="box-value"
- HorizontalOptions="End" />
+ HorizontalOptions="End"
+ AutomationId="CapitalizePassphraseToggle" />
@@ -448,7 +384,8 @@
IsEnabled="{Binding EnforcedPolicyOptions.IncludeNumber,
Converter={StaticResource inverseBool}}"
StyleClass="box-value"
- HorizontalOptions="End" />
+ HorizontalOptions="End"
+ AutomationId="IncludeNumbersToggle" />
@@ -462,7 +399,8 @@
StyleClass="box-sub-label"
VerticalOptions="CenterAndExpand"
HorizontalTextAlignment="End"
- WidthRequest="50" />
+ WidthRequest="50"
+ AutomationId="PasswordLengthLabel" />
+ Minimum="5"
+ AutomationId="PasswordLengthSlider" />
@@ -488,7 +427,8 @@
StyleClass="box-value"
HorizontalOptions="End"
AutomationProperties.IsInAccessibleTree="True"
- AutomationProperties.Name="{u:I18n UppercaseAtoZ}"/>
+ AutomationProperties.Name="{u:I18n UppercaseAtoZ}"
+ AutomationId="UppercaseAtoZToggle" />
@@ -505,7 +445,8 @@
StyleClass="box-value"
HorizontalOptions="End"
AutomationProperties.IsInAccessibleTree="True"
- AutomationProperties.Name="{u:I18n LowercaseAtoZ}"/>
+ AutomationProperties.Name="{u:I18n LowercaseAtoZ}"
+ AutomationId="LowercaseAtoZToggle" />
@@ -522,7 +463,8 @@
StyleClass="box-value"
HorizontalOptions="End"
AutomationProperties.IsInAccessibleTree="True"
- AutomationProperties.Name="{u:I18n NumbersZeroToNine}"/>
+ AutomationProperties.Name="{u:I18n NumbersZeroToNine}"
+ AutomationId="NumbersZeroToNineToggle" />
@@ -539,7 +481,8 @@
StyleClass="box-value"
HorizontalOptions="End"
AutomationProperties.IsInAccessibleTree="True"
- AutomationProperties.Name="{u:I18n SpecialCharacters}"/>
+ AutomationProperties.Name="{u:I18n SpecialCharacters}"
+ AutomationId="SpecialCharactersToggle" />
@@ -554,12 +497,14 @@
HorizontalOptions="FillAndExpand"
HorizontalTextAlignment="End"
VerticalOptions="FillAndExpand"
- VerticalTextAlignment="Center" />
+ VerticalTextAlignment="Center"
+ AutomationId="MinNumberValueLabel" />
+ Increment="1"
+ AutomationId="MinNumberStepper" />
@@ -574,12 +519,14 @@
HorizontalOptions="FillAndExpand"
HorizontalTextAlignment="End"
VerticalOptions="FillAndExpand"
- VerticalTextAlignment="Center" />
+ VerticalTextAlignment="Center"
+ AutomationId="MinSpecialValueLabel" />
+ Increment="1"
+ AutomationId="MinSpecialStepper" />
@@ -590,7 +537,8 @@
+ HorizontalOptions="End"
+ AutomationId="AvoidAmbiguousCharsToggle" />
diff --git a/src/App/Pages/Generator/GeneratorPageViewModel.cs b/src/App/Pages/Generator/GeneratorPageViewModel.cs
index 78436352b..935a9f7e0 100644
--- a/src/App/Pages/Generator/GeneratorPageViewModel.cs
+++ b/src/App/Pages/Generator/GeneratorPageViewModel.cs
@@ -8,6 +8,7 @@ using Bit.App.Utilities;
using Bit.Core;
using Bit.Core.Abstractions;
using Bit.Core.Enums;
+using Bit.Core.Exceptions;
using Bit.Core.Models.Domain;
using Bit.Core.Utilities;
using Xamarin.CommunityToolkit.ObjectModel;
@@ -23,7 +24,7 @@ namespace Bit.App.Pages
private readonly IUsernameGenerationService _usernameGenerationService;
private readonly ITokenService _tokenService;
private readonly IDeviceActionService _deviceActionService;
- readonly LazyResolve _logger = new LazyResolve("logger");
+ readonly LazyResolve _logger = new LazyResolve();
private PasswordGenerationOptions _options;
private UsernameGenerationOptions _usernameOptions;
@@ -49,11 +50,7 @@ namespace Bit.App.Pages
private bool _doneIniting;
private bool _showTypePicker;
private string _emailWebsite;
- private bool _showFirefoxRelayApiAccessToken;
- private bool _showAnonAddyApiAccessToken;
- private bool _showSimpleLoginApiKey;
- private bool _showDuckDuckGoApiKey;
- private bool _showFastmailApiKey;
+ private bool _showForwardedEmailApiSecret;
private bool _editMode;
public GeneratorPageViewModel()
@@ -96,7 +93,7 @@ namespace Bit.App.Pages
UsernameTypePromptHelpCommand = new Command(UsernameTypePromptHelp);
RegenerateCommand = new AsyncCommand(RegenerateAsync, onException: ex => OnSubmitException(ex), allowsMultipleExecutions: false);
RegenerateUsernameCommand = new AsyncCommand(RegenerateUsernameAsync, onException: ex => OnSubmitException(ex), allowsMultipleExecutions: false);
- ToggleForwardedEmailHiddenValueCommand = new AsyncCommand(ToggleForwardedEmailHiddenValueAsync, onException: ex => _logger.Value.Exception(ex), allowsMultipleExecutions: false);
+ ToggleForwardedEmailHiddenValueCommand = new Command(() => ShowForwardedEmailApiSecret = !ShowForwardedEmailApiSecret);
CopyCommand = new AsyncCommand(CopyAsync, onException: ex => _logger.Value.Exception(ex), allowsMultipleExecutions: false);
CloseCommand = new AsyncCommand(CloseAsync, onException: ex => _logger.Value.Exception(ex), allowsMultipleExecutions: false);
}
@@ -415,7 +412,6 @@ namespace Bit.App.Pages
public string UsernameTypeDescriptionLabel => GetUsernameTypeLabelDescription(UsernameTypeSelected);
-
public ForwardedEmailServiceType ForwardedEmailServiceSelected
{
get => _usernameOptions.ServiceType;
@@ -425,7 +421,11 @@ namespace Bit.App.Pages
{
_usernameOptions.ServiceType = value;
Username = Constants.DefaultUsernameGenerated;
- TriggerPropertyChanged(nameof(ForwardedEmailServiceSelected));
+ TriggerPropertyChanged(nameof(ForwardedEmailServiceSelected), new string[]
+ {
+ nameof(ForwardedEmailApiSecret),
+ nameof(ForwardedEmailApiSecretLabel)
+ });
SaveUsernameOptionsAsync(false).FireAndForget();
}
}
@@ -445,27 +445,104 @@ namespace Bit.App.Pages
}
}
- public string AnonAddyApiAccessToken
+ public string ForwardedEmailApiSecret
{
- get => _usernameOptions.AnonAddyApiAccessToken;
+ get
+ {
+ switch (ForwardedEmailServiceSelected)
+ {
+ case ForwardedEmailServiceType.AnonAddy:
+ return _usernameOptions.AnonAddyApiAccessToken;
+ case ForwardedEmailServiceType.DuckDuckGo:
+ return _usernameOptions.DuckDuckGoApiKey;
+ case ForwardedEmailServiceType.Fastmail:
+ return _usernameOptions.FastMailApiKey;
+ case ForwardedEmailServiceType.FirefoxRelay:
+ return _usernameOptions.FirefoxRelayApiAccessToken;
+ case ForwardedEmailServiceType.SimpleLogin:
+ return _usernameOptions.SimpleLoginApiKey;
+ default:
+ return null;
+ }
+ }
set
{
- if (_usernameOptions.AnonAddyApiAccessToken != value)
+ bool changed = false;
+ switch (ForwardedEmailServiceSelected)
{
- _usernameOptions.AnonAddyApiAccessToken = value;
- TriggerPropertyChanged(nameof(AnonAddyApiAccessToken));
+ case ForwardedEmailServiceType.AnonAddy:
+ if (_usernameOptions.AnonAddyApiAccessToken != value)
+ {
+ _usernameOptions.AnonAddyApiAccessToken = value;
+ changed = true;
+ }
+ break;
+ case ForwardedEmailServiceType.DuckDuckGo:
+ if (_usernameOptions.DuckDuckGoApiKey != value)
+ {
+ _usernameOptions.DuckDuckGoApiKey = value;
+ changed = true;
+ }
+ break;
+ case ForwardedEmailServiceType.Fastmail:
+ if (_usernameOptions.FastMailApiKey != value)
+ {
+ _usernameOptions.FastMailApiKey = value;
+ changed = true;
+ }
+ break;
+ case ForwardedEmailServiceType.FirefoxRelay:
+ if (_usernameOptions.FirefoxRelayApiAccessToken != value)
+ {
+ _usernameOptions.FirefoxRelayApiAccessToken = value;
+ changed = true;
+ }
+ break;
+ case ForwardedEmailServiceType.SimpleLogin:
+ if (_usernameOptions.SimpleLoginApiKey != value)
+ {
+ _usernameOptions.SimpleLoginApiKey = value;
+ changed = true;
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (changed)
+ {
+ TriggerPropertyChanged(nameof(ForwardedEmailApiSecret));
SaveUsernameOptionsAsync(false).FireAndForget();
}
}
}
- public bool ShowAnonAddyApiAccessToken
+ public string ForwardedEmailApiSecretLabel
{
get
{
- return _showAnonAddyApiAccessToken;
+ switch (ForwardedEmailServiceSelected)
+ {
+ case ForwardedEmailServiceType.AnonAddy:
+ case ForwardedEmailServiceType.FirefoxRelay:
+ return AppResources.APIAccessToken;
+ case ForwardedEmailServiceType.DuckDuckGo:
+ case ForwardedEmailServiceType.Fastmail:
+ case ForwardedEmailServiceType.SimpleLogin:
+ return AppResources.APIKeyRequiredParenthesis;
+ default:
+ return null;
+ }
}
- set => SetProperty(ref _showAnonAddyApiAccessToken, value);
+ }
+
+ public bool ShowForwardedEmailApiSecret
+ {
+ get
+ {
+ return _showForwardedEmailApiSecret;
+ }
+ set => SetProperty(ref _showForwardedEmailApiSecret, value);
}
public string AnonAddyDomainName
@@ -482,99 +559,6 @@ namespace Bit.App.Pages
}
}
- public string FirefoxRelayApiAccessToken
- {
- get => _usernameOptions.FirefoxRelayApiAccessToken;
- set
- {
- if (_usernameOptions.FirefoxRelayApiAccessToken != value)
- {
- _usernameOptions.FirefoxRelayApiAccessToken = value;
- TriggerPropertyChanged(nameof(FirefoxRelayApiAccessToken));
- SaveUsernameOptionsAsync(false).FireAndForget();
- }
- }
- }
-
- public bool ShowFirefoxRelayApiAccessToken
- {
- get
- {
- return _showFirefoxRelayApiAccessToken;
- }
- set => SetProperty(ref _showFirefoxRelayApiAccessToken, value);
- }
-
- public string SimpleLoginApiKey
- {
- get => _usernameOptions.SimpleLoginApiKey;
- set
- {
- if (_usernameOptions.SimpleLoginApiKey != value)
- {
- _usernameOptions.SimpleLoginApiKey = value;
- TriggerPropertyChanged(nameof(SimpleLoginApiKey));
- SaveUsernameOptionsAsync(false).FireAndForget();
- }
- }
- }
-
- public bool ShowSimpleLoginApiKey
- {
- get
- {
- return _showSimpleLoginApiKey;
- }
- set => SetProperty(ref _showSimpleLoginApiKey, value);
- }
-
- public string DuckDuckGoApiKey
- {
- get => _usernameOptions.DuckDuckGoApiKey;
- set
- {
- if (_usernameOptions.DuckDuckGoApiKey != value)
- {
- _usernameOptions.DuckDuckGoApiKey = value;
- TriggerPropertyChanged(nameof(DuckDuckGoApiKey));
- SaveUsernameOptionsAsync(false).FireAndForget();
- }
- }
- }
-
- public bool ShowDuckDuckGoApiKey
- {
- get
- {
- return _showDuckDuckGoApiKey;
- }
- set => SetProperty(ref _showDuckDuckGoApiKey, value);
- }
-
-
- public string FastmailApiKey
- {
- get => _usernameOptions.FastMailApiKey;
- set
- {
- if (_usernameOptions.FastMailApiKey != value)
- {
- _usernameOptions.FastMailApiKey = value;
- TriggerPropertyChanged(nameof(FastmailApiKey));
- SaveUsernameOptionsAsync(false).FireAndForget();
- }
- }
- }
-
- public bool ShowFastmailApiKey
- {
- get
- {
- return _showFastmailApiKey;
- }
- set => SetProperty(ref _showFastmailApiKey, value);
- }
-
public bool CapitalizeRandomWordUsername
{
get => _usernameOptions.CapitalizeRandomWordUsername;
@@ -807,12 +791,9 @@ namespace Bit.App.Pages
TriggerPropertyChanged(nameof(PlusAddressedEmailTypeSelected));
TriggerPropertyChanged(nameof(IncludeNumberRandomWordUsername));
TriggerPropertyChanged(nameof(CapitalizeRandomWordUsername));
- TriggerPropertyChanged(nameof(SimpleLoginApiKey));
- TriggerPropertyChanged(nameof(FirefoxRelayApiAccessToken));
+ TriggerPropertyChanged(nameof(ForwardedEmailApiSecret));
+ TriggerPropertyChanged(nameof(ForwardedEmailApiSecretLabel));
TriggerPropertyChanged(nameof(AnonAddyDomainName));
- TriggerPropertyChanged(nameof(AnonAddyApiAccessToken));
- TriggerPropertyChanged(nameof(DuckDuckGoApiKey));
- TriggerPropertyChanged(nameof(FastmailApiKey));
TriggerPropertyChanged(nameof(CatchAllEmailDomain));
TriggerPropertyChanged(nameof(ForwardedEmailServiceSelected));
TriggerPropertyChanged(nameof(UsernameTypeSelected));
@@ -845,15 +826,23 @@ namespace Bit.App.Pages
{
_logger.Value.Exception(ex);
+ string message = AppResources.GenericErrorMessage;
+
if (IsUsername && UsernameTypeSelected == UsernameType.ForwardedEmailAlias)
{
- await Device.InvokeOnMainThreadAsync(() => Page.DisplayAlert(
- AppResources.AnErrorHasOccurred, string.Format(AppResources.UnknownXErrorMessage, ForwardedEmailServiceSelected), AppResources.Ok));
- }
- else
- {
- await Device.InvokeOnMainThreadAsync(() => Page.DisplayAlert(AppResources.AnErrorHasOccurred, AppResources.GenericErrorMessage, AppResources.Ok));
+ if (ex is ForwardedEmailInvalidSecretException)
+ {
+ message = ForwardedEmailServiceSelected == ForwardedEmailServiceType.AnonAddy || ForwardedEmailServiceSelected == ForwardedEmailServiceType.FirefoxRelay
+ ? AppResources.InvalidAPIToken
+ : AppResources.InvalidAPIKey;
+ }
+ else
+ {
+ message = string.Format(AppResources.UnknownXErrorMessage, ForwardedEmailServiceSelected);
+ }
}
+
+ await Device.InvokeOnMainThreadAsync(() => Page.DisplayAlert(AppResources.AnErrorHasOccurred, message, AppResources.Ok));
}
private string GetUsernameTypeLabelDescription(UsernameType value)
@@ -870,27 +859,5 @@ namespace Bit.App.Pages
return string.Empty;
}
}
-
- private async Task ToggleForwardedEmailHiddenValueAsync()
- {
- switch (ForwardedEmailServiceSelected)
- {
- case ForwardedEmailServiceType.AnonAddy:
- ShowAnonAddyApiAccessToken = !ShowAnonAddyApiAccessToken;
- break;
- case ForwardedEmailServiceType.FirefoxRelay:
- ShowFirefoxRelayApiAccessToken = !ShowFirefoxRelayApiAccessToken;
- break;
- case ForwardedEmailServiceType.SimpleLogin:
- ShowSimpleLoginApiKey = !ShowSimpleLoginApiKey;
- break;
- case ForwardedEmailServiceType.DuckDuckGo:
- ShowDuckDuckGoApiKey = !ShowDuckDuckGoApiKey;
- break;
- case ForwardedEmailServiceType.Fastmail:
- ShowFastmailApiKey = !ShowFastmailApiKey;
- break;
- }
- }
}
}
diff --git a/src/App/Pages/Send/SendAddEditPage.xaml b/src/App/Pages/Send/SendAddEditPage.xaml
index b77b5c4a4..a90ed8cd0 100644
--- a/src/App/Pages/Send/SendAddEditPage.xaml
+++ b/src/App/Pages/Send/SendAddEditPage.xaml
@@ -71,7 +71,8 @@
+ HorizontalTextAlignment="Center"
+ AutomationId="SendDisabledWarningMessageLabel" />
+ HorizontalTextAlignment="Center"
+ AutomationId="SendOptionsPolicyInEffectLabel" />
+ StyleClass="box-value"
+ AutomationId="SendNameEntry" />
+ HorizontalTextAlignment="Center"
+ AutomationId="SendNoFileChosenLabel" />
+ HorizontalTextAlignment="Center"
+ AutomationId="SendCurrentFileNameLabel" />
+ Clicked="ChooseFile_Clicked"
+ AutomationId="SendChooseFileButton" />
@@ -235,7 +246,8 @@
IsToggled="{Binding Send.Text.Hidden}"
IsEnabled="{Binding SendEnabled}"
HorizontalOptions="End"
- Margin="10,0,0,0" />
+ Margin="10,0,0,0"
+ AutomationId="SendHideTextByDefaultToggle" />
+ Margin="10,0,0,0"
+ AutomationId="SendShareSendAfterSaveToggle" />
+ AutomationProperties.IsInAccessibleTree="False"
+ AutomationId="SendShowHideOptionsButton" />
+ AutomationProperties.IsInAccessibleTree="False"
+ AutomationId="SendOptionsDisplayed" />
+ AutomationProperties.IsInAccessibleTree="False"
+ AutomationId="SendOptionsHidden" />
+ AutomationProperties.Name="{u:I18n DeletionTime}"
+ AutomationId="SendDeletionOptionsPicker" />
@@ -308,14 +325,16 @@
IsEnabled="{Binding SendEnabled}"
AutomationProperties.IsInAccessibleTree="True"
AutomationProperties.Name="{u:I18n DeletionDate}"
- Grid.Column="0" />
+ Grid.Column="0"
+ AutomationId="SendCustomDeletionDatePicker" />
+ Grid.Column="1"
+ AutomationId="SendCustomDeletionTimePicker" />
+ AutomationProperties.Name="{u:I18n ExpirationTime}"
+ AutomationId="SendExpirationOptionsPicker" />
@@ -349,7 +369,8 @@
IsEnabled="{Binding SendEnabled}"
AutomationProperties.IsInAccessibleTree="True"
AutomationProperties.Name="{u:I18n ExpirationDate}"
- Grid.Column="0" />
+ Grid.Column="0"
+ AutomationId="SendCustomExpirationDatePicker" />
+ Grid.Column="1"
+ AutomationId="SendCustomExpirationTimePicker" />
+ Clicked="ClearExpirationDate_Clicked"
+ AutomationId="SendClearExpirationDateButton" />
+ HorizontalOptions="FillAndExpand"
+ AutomationId="SendMaxAccessCountEntry" />
+ Margin="10,0,0,0"
+ AutomationId="SendMaxAccessCountStepper" />
+ VerticalTextAlignment="Center"
+ AutomationId="SendCurrentAccessCountLabel" />
+ HorizontalOptions="FillAndExpand"
+ AutomationId="SendNewPasswordEntry" />
+ AutomationProperties.HelpText="{Binding PasswordVisibilityAccessibilityText}"
+ AutomationId="SendShowHidePasswordButton" />
+ effects:ScrollEnabledEffect.IsScrollEnabled="false"
+ AutomationId="SendNotesEntry">
@@ -492,7 +521,8 @@
IsToggled="{Binding Send.HideEmail}"
IsEnabled="{Binding DisableHideEmailControl, Converter={StaticResource inverseBool}}"
HorizontalOptions="End"
- Margin="10,0,0,0" />
+ Margin="10,0,0,0"
+ AutomationId="SendHideEmailSwitch" />
+ Margin="10,0,0,0"
+ AutomationId="SendDeactivateSwitch" />
diff --git a/src/App/Pages/Send/SendAddOnlyPage.xaml b/src/App/Pages/Send/SendAddOnlyPage.xaml
index ec80b96b5..844313361 100644
--- a/src/App/Pages/Send/SendAddOnlyPage.xaml
+++ b/src/App/Pages/Send/SendAddOnlyPage.xaml
@@ -25,7 +25,8 @@
Priority="-2"
UseOriginalImage="True"
AutomationProperties.IsInAccessibleTree="True"
- AutomationProperties.Name="{u:I18n Account}" />
+ AutomationProperties.Name="{u:I18n Account}"
+ AutomationId="AccountIconButton" />
diff --git a/src/App/Pages/Send/SendGroupingsPage/SendGroupingsPage.xaml b/src/App/Pages/Send/SendGroupingsPage/SendGroupingsPage.xaml
index af2eb475d..e53e8cdeb 100644
--- a/src/App/Pages/Send/SendGroupingsPage/SendGroupingsPage.xaml
+++ b/src/App/Pages/Send/SendGroupingsPage/SendGroupingsPage.xaml
@@ -44,13 +44,15 @@
+ ShowOptions="{Binding BindingContext.SendEnabled, Source={x:Reference _page}}"
+ AutomationId="SendCell" />
+ StyleClass="list-row, list-row-platform"
+ AutomationId="{Binding AutomationId}">
+ StyleClass="list-title"
+ AutomationId="SendFilterNameLabel" />
+ StyleClass="list-sub"
+ AutomationId="SendFilterCountLabel" />
diff --git a/src/App/Pages/Send/SendGroupingsPage/SendGroupingsPageListItem.cs b/src/App/Pages/Send/SendGroupingsPage/SendGroupingsPageListItem.cs
index a89ebf18d..81a65a2be 100644
--- a/src/App/Pages/Send/SendGroupingsPage/SendGroupingsPageListItem.cs
+++ b/src/App/Pages/Send/SendGroupingsPage/SendGroupingsPageListItem.cs
@@ -66,5 +66,27 @@ namespace Bit.App.Pages
return _icon;
}
}
+
+ public string AutomationId
+ {
+ get
+ {
+ if (_name != null)
+ {
+ return "SendItem";
+ }
+ if (Type != null)
+ {
+ switch (Type.Value)
+ {
+ case SendType.Text:
+ return "SendTextFilter";
+ case SendType.File:
+ return "SendFileFilter";
+ }
+ }
+ return null;
+ }
+ }
}
}
diff --git a/src/App/Pages/Send/SendsPage.xaml b/src/App/Pages/Send/SendsPage.xaml
index fd37c5b2d..e4ceabf13 100644
--- a/src/App/Pages/Send/SendsPage.xaml
+++ b/src/App/Pages/Send/SendsPage.xaml
@@ -59,7 +59,8 @@
Margin="20, 0"
VerticalOptions="CenterAndExpand"
HorizontalOptions="CenterAndExpand"
- HorizontalTextAlignment="Center" />
+ HorizontalTextAlignment="Center"
+ AutomationId="NoSendDisplayedLabel" />
+ ExtraDataForLogging="Sends Page"
+ AutomationId="SendCellList">
+ ShowOptions="{Binding BindingContext.SendEnabled, Source={x:Reference _page}}"
+ AutomationId="SendCell" />
diff --git a/src/App/Pages/Settings/FolderAddEditPage.xaml b/src/App/Pages/Settings/FolderAddEditPage.xaml
index 2aa3efb86..97c06a820 100644
--- a/src/App/Pages/Settings/FolderAddEditPage.xaml
+++ b/src/App/Pages/Settings/FolderAddEditPage.xaml
@@ -13,13 +13,16 @@
-
-
+
+
+ x:Name="_deleteItem"
+ AutomationId="DeleteFolderButton" />
@@ -43,7 +46,8 @@
StyleClass="box-value"
x:Name="_nameEntry"
ReturnType="Go"
- ReturnCommand="{Binding SubmitCommand}" />
+ ReturnCommand="{Binding SubmitCommand}"
+ AutomationId="FolderNameEntry" />
diff --git a/src/App/Pages/Settings/FoldersPage.xaml b/src/App/Pages/Settings/FoldersPage.xaml
index 5fdd1a567..ed26436f2 100644
--- a/src/App/Pages/Settings/FoldersPage.xaml
+++ b/src/App/Pages/Settings/FoldersPage.xaml
@@ -31,7 +31,8 @@
Margin="20, 0"
VerticalOptions="CenterAndExpand"
HorizontalOptions="CenterAndExpand"
- HorizontalTextAlignment="Center">
+ HorizontalTextAlignment="Center"
+ AutomationId="NoFoldersLabel">
+ Padding="10"
+ AutomationId="FolderCell">
+ Text="{Binding Name, Mode=OneWay}"
+ AutomationId="FolderName" />
diff --git a/src/App/Pages/Settings/OptionsPage.xaml b/src/App/Pages/Settings/OptionsPage.xaml
index fb8a4966f..8a6a407b5 100644
--- a/src/App/Pages/Settings/OptionsPage.xaml
+++ b/src/App/Pages/Settings/OptionsPage.xaml
@@ -27,7 +27,8 @@
x:Name="_themePicker"
ItemsSource="{Binding ThemeOptions, Mode=OneTime}"
SelectedIndex="{Binding ThemeSelectedIndex}"
- StyleClass="box-value" />
+ StyleClass="box-value"
+ AutomationId="ThemeSelectorPicker" />
+ StyleClass="box-value"
+ AutomationId="DefaultDarkThemePicker" />
+ StyleClass="box-value"
+ AutomationId="DefaultUriMatchDetectionPicker" />
+ StyleClass="box-value"
+ AutomationId="ClearClipboardPicker" />
+ StyleClass="box-value"
+ AutomationId="LanguagePicker" />
+ HorizontalOptions="End"
+ AutomationId="CopyTotpAutomaticallyToggle" />
+ HorizontalOptions="End"
+ AutomationId="ShowWebsiteIconsToggle" />
-
-
+
+ StyleClass="list-sub"
+ AutomationId="{Binding AutomationIdSettingStatus}" />
+ BorderColor="{DynamicResource PrimaryColor}"
+ AutomationId="SettingActivePolicyTextLabel">
+ StyleClass="list-sub" Margin="-5"
+ AutomationId="SettingCustomVaultTimeoutPicker" />
diff --git a/src/App/Pages/Settings/SettingsPage/SettingsPageListItem.cs b/src/App/Pages/Settings/SettingsPage/SettingsPageListItem.cs
index b518b4cf8..e2b2b0295 100644
--- a/src/App/Pages/Settings/SettingsPage/SettingsPageListItem.cs
+++ b/src/App/Pages/Settings/SettingsPage/SettingsPageListItem.cs
@@ -1,7 +1,9 @@
using System;
+using System.Globalization;
using System.Threading.Tasks;
using Bit.App.Resources;
using Bit.App.Utilities;
+using Bit.App.Utilities.Automation;
using Xamarin.Forms;
namespace Bit.App.Pages
@@ -22,5 +24,29 @@ namespace Bit.App.Pages
public Color SubLabelColor => SubLabelTextEnabled ?
ThemeManager.GetResourceColor("SuccessColor") :
ThemeManager.GetResourceColor("MutedColor");
+
+ public string AutomationIdSettingName
+ {
+ get
+ {
+ return AutomationIdsHelper.AddSuffixFor(
+ UseFrame ? "EnabledPolicy"
+ : AutomationIdsHelper.ToEnglishTitleCase(Name)
+ , SuffixType.Cell);
+ }
+ }
+
+ public string AutomationIdSettingStatus
+ {
+ get
+ {
+ if (UseFrame)
+ {
+ return null;
+ }
+
+ return AutomationIdsHelper.AddSuffixFor(AutomationIdsHelper.ToEnglishTitleCase(Name), SuffixType.SettingValue);
+ }
+ }
}
}
diff --git a/src/App/Pages/Vault/AttachmentsPage.xaml b/src/App/Pages/Vault/AttachmentsPage.xaml
index 0b56ab9c1..4159feedf 100644
--- a/src/App/Pages/Vault/AttachmentsPage.xaml
+++ b/src/App/Pages/Vault/AttachmentsPage.xaml
@@ -33,23 +33,25 @@
-
+
-
+
-
+
+ HorizontalOptions="StartAndExpand"
+ AutomationId="AttachmentFileNameLabel" />
+ VerticalTextAlignment="Center"
+ AutomationId="AttachmentFileSizeLabel" />
+ AutomationProperties.Name="{u:I18n Delete}"
+ AutomationId="AttachmentDeleteButton" />
@@ -77,17 +80,20 @@
LineBreakMode="CharacterWrap"
StyleClass="text-sm, text-muted"
HorizontalOptions="FillAndExpand"
- HorizontalTextAlignment="Center" />
+ HorizontalTextAlignment="Center"
+ AutomationId="NoFileChosenLabel" />
+ HorizontalTextAlignment="Center"
+ AutomationId="NewAttachmentNameLabel" />
+ Clicked="ChooseFile_Clicked"
+ AutomationId="ChooseFileButton">
-
+
-
+
-
+
-
+
+ HorizontalTextAlignment="Center"
+ AutomationId="PersonalOwnershipPolicyLabel"/>
@@ -116,7 +117,8 @@
x:Name="_typePicker"
ItemsSource="{Binding TypeOptions, Mode=OneTime}"
SelectedIndex="{Binding TypeSelectedIndex}"
- StyleClass="box-value" />
+ StyleClass="box-value"
+ AutomationId="ItemTypePicker" />
+ AutomationProperties.Name="{u:I18n Name}"
+ AutomationId="ItemNameEntry" />
+ AutomationProperties.Name="{u:I18n Username}"
+ AutomationId="LoginUsernameEntry" />
+ AutomationProperties.Name="{u:I18n GenerateUsername}"
+ AutomationId="GenerateUsernameButton" />
@@ -180,7 +185,8 @@
IsTextPredictionEnabled="False"
IsEnabled="{Binding Cipher.ViewPassword}"
AutomationProperties.IsInAccessibleTree="True"
- AutomationProperties.Name="{u:I18n Password}"/>
+ AutomationProperties.Name="{u:I18n Password}"
+ AutomationId="LoginPasswordEntry" />
+ IsVisible="{Binding Cipher.ViewPassword}"
+ AutomationId="CheckPasswordButton" />
+ IsVisible="{Binding Cipher.ViewPassword}"
+ AutomationId="ViewPasswordButton" />
+ IsVisible="{Binding Cipher.ViewPassword}"
+ AutomationId="RegeneratePasswordButton" />
+ VerticalTextAlignment="Center"
+ AutomationId="SetupTotpButton" />
+ AutomationProperties.Name="{u:I18n AuthenticatorKey}"
+ AutomationId="LoginTotpEntry" />
+ AutomationProperties.Name="{u:I18n CopyTotp}"
+ AutomationId="CopyTotpValueButton" />
+ AutomationProperties.Name="{u:I18n ScanQrTitle}"
+ />
@@ -304,7 +317,8 @@
+ StyleClass="box-value"
+ AutomationId="CardholderNameEntry" />
@@ -330,7 +344,8 @@
IsSpellCheckEnabled="False"
IsTextPredictionEnabled="False"
AutomationProperties.IsInAccessibleTree="True"
- AutomationProperties.Name="{u:I18n Number}" />
+ AutomationProperties.Name="{u:I18n Number}"
+ AutomationId="CardNumberEntry" />
+ AutomationProperties.Name="{u:I18n ToggleVisibility}"
+ AutomationId="ShowCardNumberButton" />
+ StyleClass="box-value"
+ AutomationId="CardBrandPicker" />
+ StyleClass="box-value"
+ AutomationId="CardExpirationMonthPicker" />
+ AutomationProperties.Name="{u:I18n ExpirationYear}"
+ AutomationId="CardExpirationYearEntry" />
@@ -398,7 +417,8 @@
IsSpellCheckEnabled="False"
IsTextPredictionEnabled="False"
AutomationProperties.IsInAccessibleTree="True"
- AutomationProperties.Name="{u:I18n SecurityCode}" />
+ AutomationProperties.Name="{u:I18n SecurityCode}"
+ AutomationId="CardSecurityCodeEntry" />
+ AutomationProperties.Name="{u:I18n ToggleVisibility}"
+ AutomationId="CardShowSecurityCodeButton" />
@@ -419,7 +440,8 @@
x:Name="_identityTitlePicker"
ItemsSource="{Binding IdentityTitleOptions, Mode=OneTime}"
SelectedIndex="{Binding IdentityTitleSelectedIndex}"
- StyleClass="box-value" />
+ StyleClass="box-value"
+ AutomationId="IdentityTitlePicker" />
+ AutomationProperties.Name="{u:I18n FirstName}"
+ AutomationId="IdentityFirstNameEntry" />
+ AutomationProperties.Name="{u:I18n MiddleName}"
+ AutomationId="IdentityMiddleNameEntry" />
+ AutomationProperties.Name="{u:I18n LastName}"
+ AutomationId="IdentityLastNameEntry" />
+ AutomationProperties.Name="{u:I18n Username}"
+ AutomationId="IdentityUsernameEntry" />
+ AutomationProperties.Name="{u:I18n Company}"
+ AutomationId="IdentityCompanyEntry" />
+ AutomationProperties.Name="{u:I18n SSN}"
+ AutomationId="IdentitySsnEntry" />
+ AutomationProperties.Name="{u:I18n PassportNumber}"
+ AutomationId="IdentityPassportNumberEntry" />
+ AutomationProperties.Name="{u:I18n LicenseNumber}"
+ AutomationId="IdentityLicenseNumberEntry" />
+ AutomationProperties.Name="{u:I18n Email}"
+ AutomationId="IdentityEmailEntry" />
+ AutomationProperties.Name="{u:I18n Phone}"
+ AutomationId="IdentityPhoneEntry" />
+ AutomationProperties.Name="{u:I18n Address1}"
+ AutomationId="IdentityAddressOneEntry" />
+ AutomationProperties.Name="{u:I18n Address2}"
+ AutomationId="IdentityAddressTwoEntry" />
+ AutomationProperties.Name="{u:I18n Address3}"
+ AutomationId="IdentityAddressThreeEntry" />
+ AutomationProperties.Name="{u:I18n CityTown}"
+ AutomationId="IdentityCityEntry" />
+ AutomationProperties.Name="{u:I18n StateProvince}"
+ AutomationId="IdentityStateEntry" />
+ AutomationProperties.Name="{u:I18n ZipPostalCode}"
+ AutomationId="IdentityPostalCodeEntry" />
+ AutomationProperties.Name="{u:I18n Country}"
+ AutomationId="IdentityCountryEntry" />
@@ -652,7 +691,7 @@
-
+
@@ -673,7 +712,8 @@
Grid.Row="1"
Grid.Column="0"
AutomationProperties.IsInAccessibleTree="True"
- AutomationProperties.Name="{u:I18n URI}" />
+ AutomationProperties.Name="{u:I18n URI}"
+ AutomationId="LoginUriEntry" />
+ AutomationProperties.Name="{u:I18n Options}"
+ AutomationId="LoginUriOptionsButton" />
+ Clicked="NewUri_Clicked"
+ AutomationId="LoginAddNewUriButton">
@@ -704,7 +746,8 @@
x:Name="_folderPicker"
ItemsSource="{Binding FolderOptions, Mode=OneTime}"
SelectedIndex="{Binding FolderSelectedIndex}"
- StyleClass="box-value" />
+ StyleClass="box-value"
+ AutomationId="FolderPicker" />
+ HorizontalOptions="End"
+ AutomationId="ItemFavoriteToggle" />
+ HorizontalOptions="End"
+ AutomationId="MasterPasswordRepromptToggle" />
@@ -749,7 +794,8 @@
effects:ScrollEnabledEffect.IsScrollEnabled="false"
Text="{Binding Cipher.Notes}"
AutomationProperties.IsInAccessibleTree="True"
- AutomationProperties.Name="{u:I18n Notes}" >
+ AutomationProperties.Name="{u:I18n Notes}"
+ AutomationId="ItemNotesEntry">
@@ -768,9 +814,11 @@
+ BindableLayout.ItemTemplateSelector="{StaticResource CustomFieldItemTemplateSelector}"
+ AutomationId="CustomFieldsList" />
+ Clicked="NewField_Clicked"
+ AutomationId="NewCustomFieldButton">
@@ -785,7 +833,8 @@
x:Name="_ownershipPicker"
ItemsSource="{Binding OwnershipOptions, Mode=OneTime}"
SelectedIndex="{Binding OwnershipSelectedIndex}"
- StyleClass="box-value" />
+ StyleClass="box-value"
+ AutomationId="ItemOwnershipPicker" />
@@ -796,7 +845,8 @@
-
+
@@ -806,15 +856,17 @@
-
+
+ HorizontalOptions="StartAndExpand"
+ AutomationId="CollectionItemNameLabel" />
+ HorizontalOptions="End"
+ AutomationId="CollectionItemSwitch" />
@@ -824,5 +876,4 @@
-
diff --git a/src/App/Pages/Vault/CipherDetailsPage.xaml b/src/App/Pages/Vault/CipherDetailsPage.xaml
index 962ec332c..6cd9a355c 100644
--- a/src/App/Pages/Vault/CipherDetailsPage.xaml
+++ b/src/App/Pages/Vault/CipherDetailsPage.xaml
@@ -49,16 +49,16 @@
x:Name="_cloneItem" x:Key="cloneItem" />
-
+
-
+
-
+
-
+
-
+
-
+
+ StyleClass="box-label"
+ AutomationId="ItemName" />
+ StyleClass="box-value"
+ AutomationId="ItemValue" />
+ IsVisible="{Binding Cipher.Login.Username, Converter={StaticResource stringHasValue}}"
+ AutomationId="ItemRow">
@@ -98,12 +101,14 @@
Text="{u:I18n Username}"
StyleClass="box-label"
Grid.Row="0"
- Grid.Column="0" />
+ Grid.Column="0"
+ AutomationId="ItemName" />
+ Grid.Column="0"
+ AutomationId="ItemValue" />
+ AutomationProperties.Name="{u:I18n CopyUsername}"
+ AutomationId="CopyValueButton" />
+ IsVisible="{Binding Cipher.Login.Password, Converter={StaticResource stringHasValue}}"
+ AutomationId="ItemRow">
@@ -133,20 +140,23 @@
Text="{u:I18n Password}"
StyleClass="box-label"
Grid.Row="0"
- Grid.Column="0" />
+ Grid.Column="0"
+ AutomationId="ItemName" />
+ IsVisible="{Binding ShowPassword, Converter={StaticResource inverseBool}}"
+ AutomationId="ItemValue" />
+ IsVisible="{Binding ShowPassword}"
+ AutomationId="ItemValue" />
+ IsVisible="{Binding Cipher.ViewPassword}"
+ AutomationId="CheckPasswordButton" />
+ IsVisible="{Binding Cipher.ViewPassword}"
+ AutomationId="ViewValueButton" />
+ IsVisible="{Binding Cipher.ViewPassword}"
+ AutomationId="CopyValueButton" />
@@ -192,7 +205,9 @@
IsEnabled="False"
StyleClass="box-value,text-muted"
IsVisible="{Binding Cipher.Login.Fido2Key, Converter={StaticResource notNull}}" />
-
+
@@ -207,7 +222,8 @@
Text="{u:I18n VerificationCodeTotp}"
StyleClass="box-label"
Grid.Row="0"
- Grid.Column="0" />
+ Grid.Column="0"
+ AutomationId="ItemName" />
+ VerticalOptions="Start"
+ AutomationId="ItemValue" />
+ VerticalOptions="FillAndExpand"
+ AutomationId="LoginTotpProgressBar" />
+ AutomationProperties.Name="{u:I18n CopyTotp}"
+ AutomationId="CopyValueButton" />
+ HorizontalOptions="FillAndExpand"
+ AutomationId="ShowUpgradePremiumTotpLabel" />
+ IsVisible="{Binding Cipher.Card.CardholderName, Converter={StaticResource stringHasValue}}"
+ AutomationId="ItemRow">
+ StyleClass="box-label"
+ AutomationId="ItemName" />
+ StyleClass="box-value"
+ AutomationId="ItemValue" />
+ IsVisible="{Binding Cipher.Card.Number, Converter={StaticResource stringHasValue}}"
+ AutomationId="ItemRow">
@@ -283,19 +307,22 @@
Text="{u:I18n Number}"
StyleClass="box-label"
Grid.Row="0"
- Grid.Column="0" />
+ Grid.Column="0"
+ AutomationId="ItemName" />
+ IsVisible="{Binding ShowCardNumber, Converter={StaticResource inverseBool}}"
+ AutomationId="ItemValue" />
+ IsVisible="{Binding ShowCardNumber}"
+ AutomationId="ItemValue" />
+ AutomationProperties.Name="{u:I18n ToggleVisibility}"
+ AutomationId="ShowValueButton" />
+ AutomationProperties.Name="{u:I18n CopyNumber}"
+ AutomationId="CopyValueButton" />
+ IsVisible="{Binding Cipher.Card.Brand, Converter={StaticResource stringHasValue}}"
+ AutomationId="ItemRow">
+ StyleClass="box-label"
+ AutomationId="ItemName" />
+ StyleClass="box-value"
+ AutomationId="ItemValue" />
+ IsVisible="{Binding Cipher.Card.Expiration, Converter={StaticResource stringHasValue}}"
+ AutomationId="ItemRow">
+ StyleClass="box-label"
+ AutomationId="ItemName" />
+ StyleClass="box-value"
+ AutomationId="ItemValue" />
+ IsVisible="{Binding Cipher.Card.Code, Converter={StaticResource stringHasValue}}"
+ AutomationId="ItemRow">
@@ -355,19 +391,22 @@
Text="{u:I18n SecurityCode}"
StyleClass="box-label"
Grid.Row="0"
- Grid.Column="0" />
+ Grid.Column="0"
+ AutomationId="ItemName" />
+ IsVisible="{Binding ShowCardCode, Converter={StaticResource inverseBool}}"
+ AutomationId="ItemValue" />
+ IsVisible="{Binding ShowCardCode}"
+ AutomationId="ItemValue" />
+ AutomationProperties.Name="{u:I18n ToggleVisibility}"
+ AutomationId="ShowValueButton" />
+ AutomationProperties.Name="{u:I18n CopySecurityCode}"
+ AutomationId="CopyValueButton" />
+ IsVisible="{Binding Cipher.Identity.FullName, Converter={StaticResource stringHasValue}}"
+ AutomationId="ItemRow">
+ StyleClass="box-label"
+ AutomationId="ItemName" />
+ StyleClass="box-value"
+ AutomationId="ItemValue" />
+ IsVisible="{Binding Cipher.Identity.Username, Converter={StaticResource stringHasValue}}"
+ AutomationId="ItemRow">
+ StyleClass="box-label"
+ AutomationId="ItemName" />
+ StyleClass="box-value"
+ AutomationId="ItemValue" />
+ IsVisible="{Binding Cipher.Identity.Company, Converter={StaticResource stringHasValue}}"
+ AutomationId="ItemRow">
+ StyleClass="box-label"
+ AutomationId="ItemName" />
+ StyleClass="box-value"
+ AutomationId="ItemValue" />
+ IsVisible="{Binding Cipher.Identity.SSN, Converter={StaticResource stringHasValue}}"
+ AutomationId="ItemRow">
+ StyleClass="box-label"
+ AutomationId="ItemName" />
+ StyleClass="box-value"
+ AutomationId="ItemValue" />
+ IsVisible="{Binding Cipher.Identity.PassportNumber, Converter={StaticResource stringHasValue}}"
+ AutomationId="ItemRow">
+ StyleClass="box-label"
+ AutomationId="ItemName" />
+ StyleClass="box-value"
+ AutomationId="ItemValue" />
+ IsVisible="{Binding Cipher.Identity.LicenseNumber, Converter={StaticResource stringHasValue}}"
+ AutomationId="ItemRow">
+ StyleClass="box-label"
+ AutomationId="ItemName" />
+ StyleClass="box-value"
+ AutomationId="ItemValue" />
+ IsVisible="{Binding Cipher.Identity.Email, Converter={StaticResource stringHasValue}}"
+ AutomationId="ItemRow">
+ StyleClass="box-label"
+ AutomationId="ItemName" />
+ StyleClass="box-value"
+ AutomationId="ItemValue" />
+ IsVisible="{Binding Cipher.Identity.Phone, Converter={StaticResource stringHasValue}}"
+ AutomationId="ItemRow" >
+ StyleClass="box-label"
+ AutomationId="ItemName" />
+ StyleClass="box-value"
+ AutomationId="ItemValue" />
-
+
+ StyleClass="box-label"
+ AutomationId="ItemName" />
+ StyleClass="box-value"
+ AutomationId="IdentityAddressOneLabel" />
+ StyleClass="box-value"
+ AutomationId="IdentityAddressTwoLabel" />
+ StyleClass="box-value"
+ AutomationId="IdentityAddressThreeLabel" />
+ StyleClass="box-value"
+ AutomationId="IdentityFullAddressPartTwoLabel" />
+ StyleClass="box-value"
+ AutomationId="IdentityCountryLabel" />
@@ -571,11 +643,11 @@
-
+
-
+
@@ -601,7 +673,8 @@
Text="{Binding HostOrUri, Mode=OneWay}"
StyleClass="box-value"
Grid.Row="1"
- Grid.Column="0" />
+ Grid.Column="0"
+ AutomationId="UriValue" />
+ AutomationProperties.Name="{u:I18n Launch}"
+ AutomationId="LaunchUriButton" />
+ AutomationProperties.Name="{u:I18n Copy}"
+ AutomationId="CopyUriButton" />
@@ -636,14 +711,15 @@
-
+
+ StyleClass="box-value"
+ AutomationId="CipherNotesLabel" />
-
+
@@ -658,21 +734,23 @@
-
+
-
+
+ HorizontalOptions="StartAndExpand"
+ AutomationId="CipherAttachmentFileNameLabel" />
+ VerticalTextAlignment="Center"
+ AutomationId="CipherAttachmentFileSizeLabel" />
+ AutomationProperties.Name="{u:I18n Download}"
+ AutomationId="CipherAttachmentDownloadButton" />
@@ -690,17 +769,20 @@
+ StyleClass="box-footer-label"
+ AutomationId="CipherUpdatedDateLabel" />
+ IsVisible="{Binding Cipher.PasswordRevisionDisplayDate, Converter={StaticResource notNull}}"
+ AutomationId="CipherUpdatedPasswordDateLabel">
+ IsVisible="{Binding Cipher.HasPasswordHistory}"
+ AutomationId="CipherPasswordHistoryLabel">
@@ -730,6 +812,7 @@
AbsoluteLayout.LayoutBounds="1, 1, AutoSize, AutoSize"
AutomationProperties.IsInAccessibleTree="True"
AutomationProperties.Name="{u:I18n EditItem}"
+ AutomationId="CipherEditButton"
IsVisible="{Binding CanEdit}">
diff --git a/src/App/Pages/Vault/CipherSelectionPage.xaml b/src/App/Pages/Vault/CipherSelectionPage.xaml
index f5c8c0641..f71d3a2c2 100644
--- a/src/App/Pages/Vault/CipherSelectionPage.xaml
+++ b/src/App/Pages/Vault/CipherSelectionPage.xaml
@@ -19,7 +19,8 @@
Priority="-1"
UseOriginalImage="True"
AutomationProperties.IsInAccessibleTree="True"
- AutomationProperties.Name="{u:I18n Account}" />
+ AutomationProperties.Name="{u:I18n Account}"
+ AutomationId="AccountIconButton" />
diff --git a/src/App/Pages/Vault/CiphersPage.xaml b/src/App/Pages/Vault/CiphersPage.xaml
index 36b9e01c0..f35d7dc6f 100644
--- a/src/App/Pages/Vault/CiphersPage.xaml
+++ b/src/App/Pages/Vault/CiphersPage.xaml
@@ -41,7 +41,8 @@
HorizontalOptions="FillAndExpand"
TextChanged="SearchBar_TextChanged"
SearchButtonPressed="SearchBar_SearchButtonPressed"
- Placeholder="{Binding PageTitle}" />
+ Placeholder="{Binding PageTitle}"
+ AutomationId="SearchBar" />
@@ -91,7 +92,8 @@
Source="empty_items_state" />
+ HorizontalTextAlignment="Center"
+ AutomationId="NoSearchResultsLabel" />
@@ -147,7 +153,8 @@
IsVisible="{Binding ShowNoData}">
+ HorizontalTextAlignment="Center"
+ AutomationId="NoDataDisplayed">