{"id":13428268,"url":"https://github.com/AdevintaSpain/Barista","last_synced_at":"2025-03-16T01:32:15.303Z","repository":{"id":40680498,"uuid":"79541183","full_name":"AdevintaSpain/Barista","owner":"AdevintaSpain","description":":coffee: The one who serves a great Espresso","archived":false,"fork":false,"pushed_at":"2024-01-15T01:27:01.000Z","size":1458,"stargazers_count":1697,"open_issues_count":56,"forks_count":123,"subscribers_count":35,"default_branch":"master","last_synced_at":"2024-05-18T19:33:34.111Z","etag":null,"topics":["android","espresso","flaky-tests","instrumentation-tests","testing"],"latest_commit_sha":null,"homepage":"","language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/AdevintaSpain.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE.md","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null},"funding":{"custom":"https://github.com/AdevintaSpain/Barista/issues/344"}},"created_at":"2017-01-20T08:34:07.000Z","updated_at":"2024-05-17T11:54:24.000Z","dependencies_parsed_at":"2023-02-09T11:32:36.357Z","dependency_job_id":"cee672a2-f91c-474e-8b19-a93b7a0cde8d","html_url":"https://github.com/AdevintaSpain/Barista","commit_stats":{"total_commits":399,"total_committers":51,"mean_commits":7.823529411764706,"dds":0.6140350877192983,"last_synced_commit":"9f355b42123da91a5431e340a10bbfbec5ba1c7e"},"previous_names":[],"tags_count":51,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AdevintaSpain%2FBarista","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AdevintaSpain%2FBarista/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AdevintaSpain%2FBarista/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AdevintaSpain%2FBarista/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/AdevintaSpain","download_url":"https://codeload.github.com/AdevintaSpain/Barista/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":221631897,"owners_count":16855020,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["android","espresso","flaky-tests","instrumentation-tests","testing"],"created_at":"2024-07-31T01:00:50.806Z","updated_at":"2024-10-27T05:30:52.077Z","avatar_url":"https://github.com/AdevintaSpain.png","language":"Kotlin","funding_links":["https://github.com/AdevintaSpain/Barista/issues/344"],"categories":["Libraries","android","Kotlin"],"sub_categories":[],"readme":"# Barista\n**The one who serves a great Espresso**\n\n[![Hex.pm](https://img.shields.io/hexpm/l/plug.svg)](LICENSE.md)\n\n\u003cimg src=\"art/barista-logo.svg\" width=\"30%\"/\u003e\n\nBarista makes developing UI tests faster, easier, and more predictable. Built on top of Espresso, it provides a simple and discoverable API, removing most of the boilerplate and verbosity of common Espresso tasks. You and your Android team will write tests with no effort.\n\n - [Download](#download)\n - [API Overview](#api-overview)\n    - [Interactions](#baristas-interactions-api)\n    - [Assertions](#baristas-assertions-api)\n    - [Intents](#baristas-intents-api)\n    - [Runtime Permissions](#runtime-permissions)\n    - [Useful test rules](#useful-test-rules)\n      - [Resetting app data](#resetting-app-data)\n      - [Dealing with Flaky tests](#dealing-with-flaky-tests)\n      - [One rule to rule them all](#one-rule-to-rule-them-all)\n  - [Magic that Barista does for you](#magic-that-barista-does-for-you)\n  - [Contributing](#contributing)\n  - [License](#license)\n\n# Download\n\nImport Barista as a testing dependency:\n```gradle\nandroidTestImplementation('com.adevinta.android:barista:4.2.0') {\n  exclude group: 'org.jetbrains.kotlin' // Only if you already use Kotlin in your project\n}\n```\n\nYou might need to include the Google Maven repository, required by Espresso 3:\n```gradle\nrepositories {\n    google()\n}\n```\n\nBarista already includes `espresso-core` and `espresso-contrib`. If you need [any other Espresso package](https://developer.android.com/topic/libraries/testing-support-library/packages.html#atsl-dependencies) you can add them yourself.\n\n# API Overview\n\n## Barista’s Interactions API\n\n#### Click widgets\n```java\nclickOn(R.id.button);\nclickOn(R.string.button_text);\nclickOn(\"Next\");\nclickBack();\n```\n\n#### Long click widgets\n```java\nlongClickOn(R.id.button);\nlongClickOn(R.string.button_text);\nlongClickOn(\"Next\");\n```\n\n#### Click menu items, with or without overflow\n```java\nclickMenu(R.id.menu_item);\n```\n\n#### Open the overflow menu without clicking any item\n```java\nopenMenu();\n```\n\n#### Writing into widgets\n```java\nwriteTo(R.id.edittext, \"A great text\"); // Ignores the EditText restrictions like maxLength and textFilter. It's blazing fast.\ntypeTo(R.id.edittext, \"A great text\"); // Honors the EditText restrictions like maxLength and textFilter. It slows down the test.\nwriteToAutoComplete(R.id.autocomplete, \"Another great text\");\nclearText(R.id.edittext)\n```\n\n#### Operate on ListViews and RecyclerViews indistinctly by position\n```java\nclickListItem(R.id.list, 4);\nclickListItemChild(R.id.list, 3, R.id.row_button);\nscrollListToPosition(R.id.list, 4);\n\nclickSpinnerItem(R.id.spinner, 1);\n```\n\n#### Select items on RadioButtons\n```java\nclickRadioButtonItem(R.id.radiogroup, R.id.radio_item);\nclickRadioButtonItem(R.id.radiogroup, \"The radio text\");\nclickRadioButtonPosition(R.id.radiogroup, 42);\n```\n\n#### Check/Uncheck a Checkbox\n```java\ncheck(R.id.check_box_item_1);\nuncheck(R.id.check_box_item_2);\n```\n\n#### Pick data on pickers\n```java\nsetDateOnPicker(1986, 3, 23);\nsetTimeOnPicker(17, 2);\n```\n\n#### Interact with dialogs\n```java\nclickDialogPositiveButton();\nclickDialogNeutralButton();\nclickDialogNegativeButton();\n```\n\n#### Scroll on scrolls and pagers\n```java\nscrollTo(R.id.far_away_widget);\nscrollTo(R.string.text);\nscrollTo(\"A widget with this text\");\nscrollTo(withTagValue(is(\"tagName\"))) // using custom matchers\nswipeViewPagerForward();\nswipeViewPagerBack();\n```\n\n#### Interact with the navigation drawer\n```java\nopenDrawer();\nopenDrawerWithGravity(Gravity.RIGHT);\ncloseDrawer();\ncloseDrawerWithGravity(Gravity.RIGHT);\n```\n\n#### Interact with SeekBars\n```java\nsetProgressTo(R.id.seek_bar, 5);\nsetProgressToMin(R.id.seek_bar);\nsetProgressToMax(R.id.seek_bar);\n```\n\n#### Pull to refresh in SwipeRefreshLayout\n```java\nrefresh(R.id.swipe_refresh);\nrefresh(); // Id is optional. Barista will find it for you.\n```\n\n#### Close or press ime actions on the Keyboard\n```java\ncloseKeyboard()\npressImeActionButton()\n```\n\n#### And another tricky feature, but try not to use it\n```java\nsleep(2000);\nsleep(2, SECONDS);\n```\n\n## Barista’s Assertions API\n\n#### Is this view displayed?\n```java\nassertDisplayed(\"Hello world\");\nassertDisplayed(R.string.hello_world);\nassertDisplayed(R.id.button);\nassertDisplayed(R.id.button, \"Hello world\")\nassertDisplayed(R.id.button, R.string.hello_world)\n\n// on ListViews and RecyclerViews by position\nassertDisplayedAtPosition(R.id.list, 0, \"text\");\nassertDisplayedAtPosition(R.id.list, 0, R.id.text_field, \"text\");\nassertDisplayedAtPosition(R.id.list, 0, R.string.hello_world);\nassertDisplayedAtPosition(R.id.list, 0, R.id.text_field, R.string.hello_world);\nassertDrawableDisplayedAtPosition(R.id.recycler, 0, R.id.imageview, R.drawable.ic_barista);\n\n// you can also pass custom matchers\nassertDisplayed(withTagValue(is(\"tagName\")))\n\n// ...or not?\nassertNotDisplayed(\"Hello world\");\nassertNotDisplayed(R.string.hello_world);\nassertNotDisplayed(R.id.button);\nassertNotDisplayed(R.id.button, \"Hello world\")\nassertNotDisplayed(R.id.button, R.string.hello_world)\n// you can also pass custom matchers\nassertNotDisplayed(withTagValue(is(\"tagName\")))\n```\n\n#### Is this view enabled?\n```java\nassertEnabled(\"Hello world\");\nassertEnabled(R.string.hello_world);\nassertEnabled(R.id.button);\n\n// ...or not?\nassertDisabled(\"Hello world\");\nassertDisabled(R.string.hello_world);\nassertDisabled(R.id.button);\n```\n\n#### Hope this view doesn't exist!\n\n```java\nassertNotExist(\"Hello world\");\nassertNotExist(R.string.hello_world);\nassertNotExist(R.id.button);\nassertNotExist(allOf(withId(R.id.recycler),isDisplayed()));\n```\n\n#### Hope this view does exist!\n\n```java\nassertExist(\"Hello world\");\nassertExist(R.string.hello_world);\nassertExist(R.id.button);\nassertExist(allOf(withId(R.id.recycler),isDisplayed()));\n```\n\n#### Is the expected checkbox checked?\n\n```java\nassertChecked(\"Checked checkbox\");\nassertChecked(R.string.checked_checkbox);\nassertChecked(R.id.checkbox);\n\n// ...or not?\nassertUnchecked(\"Unchecked checkbox\");\nassertUnchecked(R.string.unchecked_checkbox);\nassertUnchecked(R.id.checkbox);\n```\n\n#### Is this view clickable?\n```java\nassertClickable(\"Hello world\")\nassertClickable(R.string.hello_world)\nassertClickable(R.id.button)\n\n// ...or not?\nassertNotClickable(\"Hello world\")\nassertNotClickable(R.string.hello_world)\nassertNotClickable(R.id.button)\n```\n\n#### Does this view have the focus?\n```java\nassertFocused(R.id.focused_view)\nassertFocused(\"Button\")\n\n// ...or not?\nassertNotFocused(R.id.focused_view)\nassertNotFocused(\"Button\")\n```\n\n#### Is this ImageView showing a drawable?\n```java\nassertHasAnyDrawable(R.id.image_view);\nassertHasDrawable(R.id.image_view, R.drawable.ic_barista);\n\n// ...or not?\nassertHasNoDrawable(R.id.image_view);\n```\n\n#### Does this View have a background?\n```java\nassertHasAnyBackground(R.id.view);\nassertHasBackground(R.id.view, R.drawable.ic_barista);\n\n// ...or not?\nassertHasNoBackground(R.id.view);\n```\n\n#### Does this View have content description?\n```java\nassertHasContentDescription(R.id.anyView);\nassertContentDescription(R.id.anyView, R.string.content_description);\nassertContentDescription(R.id.anyView, \"Some text\");\n```\n\n#### Is this List empty? How many items does it have?\n````java\n// Works with both ListView and RecyclerView\nassertListNotEmpty(R.id.list)\nassertListItemCount(R.id.list, 5)\n\n// You can also pass custom assertions\nassertCustomAssertionAtPosition(R.id.list, 0, customViewAssertion);\n````\n\n#### What's the state of the Drawer?\n```java\nassertDrawerIsOpen();\nassertDrawerIsOpenWithGravity(Gravity.RIGHT);\nassertDrawerIsClosed();\nassertDrawerIsClosedWithGravity(Gravity.RIGHT);\n```\n\n#### Check TextInputLayout and EditText's hints\n```java\nassertHint(R.id.edittext, R.string.hint);\nassertHint(R.id.edittext, \"Hint\");\n```\n\n#### Check TextInputLayout and EditText's errors\n```java\nassertErrorDisplayed(R.id.edittext, R.string.error);\nassertErrorDisplayed(R.id.edittext, \"Error message\");\n\nassertNoErrorDisplayed(R.id.edittext, R.string.error);\nassertNoErrorDisplayed(R.id.edittext, \"Error message\");\n```\n\n#### Check TextInputLayout's assistive helper text\n```java\nassertAssistiveText(R.id.textinputlayout, R.string.helper_text);\nassertAssistiveText(R.id.textinputlayout, \"Helper text\");\n```\n\n#### Check if the text on screen contains the given text\n```java\nassertContains(\"text\");\nassertContains(R.string.text);\nassertContains(R.id.textview, \"text\");\nassertContains(R.id.textview, R.string.text);\n\n// ...or not?\nassertNotContains(\"text\");\nassertNotContains(R.string.text);\nassertNotContains(R.id.textview, \"text\");\nassertNotContains(R.id.textview, R.string.text);\n```\n\n#### Check text is given color\n```java\nassertTextColorIs(R.id.some_red_text, R.color.red);\nassertTextColorIs(R.id.some_color_list_text, R.color.state_list);\n\n// ...or not?\nassertTextColorIsNot(R.id.some_red_text, R.color.blue);\nassertTextColorIsNot(R.id.some_color_list_text, R.color.another_state_list);\n```\n\n`assertTextColorIs` and its variant `assertTextColorIsNot` work with:\n\n- *Color int*: `Color.parse(\"#ff00ff\")`\n- *Color resource*: `R.color.green`\n- *Color attribute*: `R.attr.colorPrimary`\n\nAlso Barista can check colors parsed from `declarable-style` custom attribute:\n```java\nassertTextColorIs(R.id.customTextView, R.styleable.SampleCustomView, R.style.SampleCustomStyle, R.styleable.SampleCustomView_customColor);\n\n// ...or not?\nassertTextColorIsNot(R.id.customTextView, R.styleable.SampleCustomView, R.style.SampleCustomStyle_Green, R.styleable.SampleCustomView_customColor);\n```\n\n#### Check recyclerView item count against expected item count\n```java\nassertRecyclerViewItemCount(R.id.recycler, 10);\n```\n\n#### Is this ProgressBar/SeekBar progress?\n```java\nassertProgress(R.id.seek_bar, 5)\nassertProgressIsMin(R.id.seek_bar)\nassertProgressIsMax(R.id.seek_bar)\n```\n\n#### And another tricky feature\n```java\nassertThatBackButtonClosesTheApp();\n```\n\n### Custom assertions\n\nIf you have a special case not covered by the given assertions API, we encourage you to assert these special cases with our custom assertions API. It's a convenient way to replace plain `Matcher`s with complex assertions. With Barista, you can match any kind of view by knowing its type and passing its `viewId`, `text`, or a `Matcher\u003cView\u003e`. Once you matched it, you will be able to assert all its properties without adding any complex `Matcher` to your project.\n\n```kotlin\n\n// Matching a Button by text\nassertAny\u003cButton\u003e(\"Save\") {\n    it.enabled == true\n}\n\n// Matching a RadioGroup by id\nassertAny\u003cRadioGroup\u003e(R.id.radioGroup) {\n    it.checkedRadioButtonId == R.id.option1\n}\n\n// Matching a Progressbar by a Matcher\nassertAny\u003cProgressbar\u003e(withId(R.id.progressBar)) {\n    it.progress == 42\n}\n\n// You can also define the assertion description that will be shown if the assertion fails\nassertAny\u003cRadioGroup\u003e(R.id.radioGroup, \"selected option is the second one\") {\n    it.checkedRadioButtonId == R.id.option1\n}\n```\n\n## Mocking the Intent results\n\nMocking the Android Camera Intent is a tricky thing to do. To accomplish it in no time, Barista gives a way to do it in one line: the method `mockAndroidCamera()`. This method does all the magic to mock the result of the camera. One more thing to do: you have to call `Intents.init()` before calling `mockAndroidCamera()`, and `Intents.release()` after doing the action that launches the camera. You could also use `IntentsTestRule` instead of the common `ActivityTestRule` to skip it, but as we recommend the use of `BaristaRule`, it's easier to just call both methods manually when needed.\n\nHere's an example to copy paste:\n\n```java\ntry {\n  Intents.init();\n  BaristaIntents.mockAndroidCamera();\n  clickOn(R.id.launch_camera);\n} finally {\n  Intents.release();\n}\n```\n\n## Runtime Permissions\nThe new Marshmallow permissions system requires checking for permissions at runtime. As Espresso can't interact with the system dialog, Barista offers a way to allow permissions when needed.\n\n```java\nPermissionGranter.allowPermissionsIfNeeded(Manifest.permission.GET_ACCOUNTS);\n```\n```java\nPermissionGranter.allowPermissionOneTime(Manifest.permission.GET_ACCOUNTS);\n```\n\n## Useful test rules\nBarista includes a set of useful test rules to help you:\n\n### Resetting app data\n\nAs tests should be isolated, they need to set the environment before running. Espresso doesn't help achieving it but Barista offers a set of rules to clear the app's data before running each test.\n\n```java\n// Clear all app's SharedPreferences\n@Rule public ClearPreferencesRule clearPreferencesRule = new ClearPreferencesRule();\n\n// Delete all tables from all the app's SQLite Databases\n@Rule public ClearDatabaseRule clearDatabaseRule = new ClearDatabaseRule();\n\n// Delete all files in getFilesDir() and getCacheDir()\n@Rule public ClearFilesRule clearFilesRule = new ClearFilesRule();\n```\n\n\n### Dealing with Flaky tests\n\nWe should try to write deterministic tests, but when everything else fails Barista helps you deal with flaky tests using a specific ActivityTestRule and a couple of annotations that repeat your tests multiple times.\n\n```java\n// Use a RuleChain to wrap your ActivityTestRule with a FlakyTestRule\nprivate ActivityTestRule\u003cFlakyActivity\u003e activityRule = new ActivityTestRule\u003c\u003e(FlakyActivity.class);\nprivate FlakyTestRule flakyRule = new FlakyTestRule();\n\n@Rule\npublic RuleChain chain = RuleChain.outerRule(flakyRule)\n    .around(activityRule);\n\n\n// Use @AllowFlaky to let flaky tests pass if they pass any time.\n@Test\n@AllowFlaky(attempts = 5)\npublic void some_flaky_test() throws Exception {\n  // ...\n}\n\n// Use @Repeat to avoid flaky tests from passing if any repetition fails.\n@Test\n@Repeat(times = 5)\npublic void some_important_test() throws Exception {\n  // ...\n}\n```\n\n### One rule to rule them all\n\nAll previous rules can be added at the same time by just adding the BaristaRule.\n```java\n@Rule\npublic BaristaRule\u003cMyActivity\u003e baristaRule = BaristaRule.create(MyActivity.class);\n\n//...\n\nbaristaRule.launchActivity();\n```\n\nThe rule assumes some sane defaults:\n- Retry flaky tests: 10 attempts\n- Launch activity automatically: false\n- Initial touch mode enabled: true\n- Clear preferences\n- Clear databases\n- Clear files\n\n### Writing tests in Kotlin?\n[Check this link](https://github.com/AdevintaSpain/Barista/issues/219) to know how to use `@Rule` in Kotlin.\n\n# Magic that Barista does for you\n\nIn order to speed up testing, Barista keeps in mind some considerations.\n- **Scrolls when needed**: Interacting with Espresso in a `ScrollView` requires you to scroll to each view, which sometimes doesn't work the first time. Also trying to scroll outside a `ScrollView` produces an `Exception`, forcing you to change the test depending on the layout. To keep tests simpler, Barista scrolls automatically before interacting with any `View`, and only does it if needed.\n- **Scrolls on all views**: Barista scrolls on all scrollable views, including `NestedScrollView`. Espresso only handles `ScrollView` and `HorizontalScrollView`, so people need to open questions on [StackOverflow like this](https://stackoverflow.com/questions/35272953/espresso-scrolling-not-working-when-nestedscrollview-or-recyclerview-is-in-coor). Or... just use **Barista**.\n- **Just interacts with displayed Views**: Interacting with `View`s inside a `ViewPager` throws `AmbiguousViewMatcherException`, because the views you interact with will be potentially repeated on different pages. Barista only interacts with displayed widgets, so you can focus on the behavior instead of wasting time on details.\n\n# Contributing\n\nWe welcome contributions! If you found a bug or have a feature request, feel free to [open an issue](https://github.com/AdevintaSpain/Barista/issues/new) to discuss it. Remember that bugs reported with a reproducible test are more likely to be investigated and fixed. You can also submit a Pull Request.\n\n## Formatting\nWe use our company's IntelliJ code style for the project, which is very similar to the official Kotlin Android code style. When submitting code please make sure you use the proper format. You can install the code style into Android Studio by running the script in `./config/androidstudio/install-codestyle.sh`. Then restart Android Studio and pick the \"BaristaAndroid\" schema in preferences.\n\n## Prefer Java-written test classes\nAs most parts of Barista are Java-compatible, please do write Java tests when possible. Writing them in Kotlin might lead to using Kotlin-only shortcuts, breaking the Java compatibility Barista aims for.\n\n# License\n**[Apache License, Version 2.0 (the \"License\")](LICENSE.md)**\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FAdevintaSpain%2FBarista","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FAdevintaSpain%2FBarista","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FAdevintaSpain%2FBarista/lists"}