<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Luca Nicoletti</title>
    <description>The latest articles on DEV Community by Luca Nicoletti (@luca_nicoletti).</description>
    <link>https://dev.to/luca_nicoletti</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F236260%2Fc7169f36-4edf-4ba7-8612-7e7d37c19c50.jpg</url>
      <title>DEV Community: Luca Nicoletti</title>
      <link>https://dev.to/luca_nicoletti</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/luca_nicoletti"/>
    <language>en</language>
    <item>
      <title>Be careful with package names</title>
      <dc:creator>Luca Nicoletti</dc:creator>
      <pubDate>Wed, 28 Feb 2024 16:21:45 +0000</pubDate>
      <link>https://dev.to/luca_nicoletti/be-careful-with-package-names-4mn8</link>
      <guid>https://dev.to/luca_nicoletti/be-careful-with-package-names-4mn8</guid>
      <description>&lt;p&gt;A few days ago, while working on a side project, I got the point that I needed to create a feature that would allow the user to &lt;code&gt;Add&lt;/code&gt; something to my app.&lt;/p&gt;

&lt;p&gt;The package showing the already existing objects of the app was declared as follows: &lt;code&gt;appName.objectName.list&lt;/code&gt; so I decided to add an &lt;code&gt;appName.objectName.add&lt;/code&gt; package to include all the components needed to build that specific part of my app: screens (I'm building this app using Jetpack Compose), composable functions, view models, models, view state definition etc.&lt;/p&gt;

&lt;p&gt;Little did I know, I was making my future self-life as hard as I could.&lt;/p&gt;

&lt;p&gt;So I went ahead and used the right-click of my mouse to show the pop-up menu to create a new package:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe7g193ksygv37fhcd2ac.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe7g193ksygv37fhcd2ac.png" alt="pop-up window to add a new package" width="800" height="269"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I then proceeded to insert the &lt;code&gt;new&lt;/code&gt; keyword for my new package:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F84f0flp8fw9vh0oiq35r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F84f0flp8fw9vh0oiq35r.png" alt="Image description" width="800" height="159"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Unfortunately, I completely missed the warning you can see above, as I simply typed new and pressed &lt;code&gt;Enter&lt;/code&gt; as soon as I was done. &lt;/p&gt;

&lt;p&gt;I missed the hint of the Android Studio editor:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2milzabkwnp6w5rbbqqv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2milzabkwnp6w5rbbqqv.png" alt="differences between a valid package and an invalid one in Android Studio" width="198" height="176"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That shows something was different with that folder (yep, not a package!).&lt;/p&gt;

&lt;p&gt;I went ahead and created my screen, my various composable, and my ViewModel class inside of that package, and ran the app on my device. Initially, the ViewModel had no dependencies so there were no problems.&lt;/p&gt;

&lt;p&gt;Kept coding for a while and started adding external dependencies to the ViewModel, to perform the action of adding my objects to the app, with all that it comes with: defined a view state that the screen observes and updates accordingly, created various functions to update that state, from the screen to the view model, etc...&lt;/p&gt;

&lt;p&gt;I'd say I spent an hour coding the entire screen, something like that. &lt;/p&gt;

&lt;p&gt;And so, as we all do, after finishing coding I re-ran the app to check that everything was working as expected. The app crashed as soon as I tried to reach that screen.&lt;/p&gt;

&lt;p&gt;As I was using &lt;code&gt;Room&lt;/code&gt; for local storage, and did a few updates on the classes, I thought I'd forgotten about bumping the Database version - so the first thing I did, without looking at the crash log, was to go to the definition of the database and update the version. But that had already been increased by past-me, what a surprise! For once I did the right thing.&lt;/p&gt;

&lt;p&gt;So I re-ran the app and looked at the Logcat output to check what was causing my app to crash.&lt;/p&gt;

&lt;p&gt;The crash was:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FATAL EXCEPTION: main
   Process: com.lucanicoletti.app, PID: 31649
   java.lang.RuntimeException: Cannot create an instance of class com.lucanicoletti.app.screens.intervals.new.ViewModel
[...]
Caused by: java.lang.NoSuchMethodException: com.lucanicoletti.app.screens.intervals.new.ViewModel.&amp;lt;init&amp;gt; []
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That felt weird. I was sure I had set up the ViewModel correctly as the first time I tried reaching that screen, the instance (despite missing external dependencies) was created without problems. I double-checked that the ViewModel had the correct &lt;code&gt;@HiltViewModel&lt;/code&gt; annotation, that the (only) activity it was contained within had the correct &lt;code&gt;@AndroidEntryPoint&lt;/code&gt; annotation, and that the dependencies it relied upon were set up correctly with either &lt;code&gt;@Bind&lt;/code&gt; or &lt;code&gt;@Provide&lt;/code&gt; annotation from a &lt;code&gt;@Module&lt;/code&gt;. Everything was set up accurately, or so it looked like so. &lt;/p&gt;

&lt;p&gt;So, what was I doing wrong?&lt;/p&gt;

&lt;p&gt;I started searching for possible solutions on the web, checking StackOverflow for questions with similar errors and crashes, asking ChatGPT for a possible solution, and reaching out to groups of developers I belong to.&lt;br&gt;
All I was able to find were solutions that didn't apply to my case: missing annotations on the ViewModel (or wrong, outdated one), dependencies not set up the correct way, missing annotation in the activity hosting the ViewModel, or other things I already checked in my app or that upon checking, were made precisely. &lt;/p&gt;

&lt;p&gt;My app at that point had 3 screens (counting the new one I was creating) and the only difference between those three screens was how they were added and reached from the Navigation component in Jetpack Compose. I had two nested graphs: one containing the two main screens (the two reachable from a bottom bar in my app) and a nested one (the one I just created and was causing trouble). So I thought it was due to the nested-ness of the newest screen, perhaps Hilt (dependency injection) wasn't able to retrieve an instance of the ViewModel due to that. Perhaps there was a specific configuration to set up to have nested graphs and ViewModels injectable. So I went ahead and created &lt;a href="https://stackoverflow.com/questions/78056656/jetpack-compose-navigation-with-hiltviewmodel-cannot-find-constructor"&gt;this question&lt;/a&gt; on StackOverflow.&lt;/p&gt;

&lt;p&gt;I got a few comments and an answer, but none was pointing me in the right direction - they couldn't know, since they didn't know the noobie mistake I started with.&lt;/p&gt;

&lt;p&gt;After a few days of doing extensive Google searches every search query had only purple results on the first two pages (yes, I spent around 2 days looking at every possible link Google gave me with different queries pointing at my problem).&lt;/p&gt;

&lt;p&gt;I was close to giving up: I tried replicating the problem in a smaller (smaller than 3 screens and 3 dependencies, can you imagine?!?) project, but since for time-seek I didn't create the same package structure, the problem was not happening in the replica project. I didn't know what to do, and then a friend asked me for a complete stack trace of the crash (I only posted parts of it, removing namespaces, and so, to hide my app name, screen name etc..). &lt;/p&gt;

&lt;p&gt;While copy-pasting the errors in the chat with him, I don't know for what reason, my eyes took a peak at the package structure in AndroidStudio &lt;code&gt;Project Structure&lt;/code&gt; and noticed (image above) that the package I was in was missing a small circle on the folder's icon. I wondered why. So I moved the files outside of that package and re-ran the app. It didn't crash.&lt;/p&gt;

&lt;p&gt;I deleted the package and re-created it, giving it the same name it had from the beginning: &lt;code&gt;new&lt;/code&gt;. The app crashed again. So I renamed the package once more, with &lt;code&gt;add&lt;/code&gt; instead of &lt;code&gt;new&lt;/code&gt; and the app was running smoothly without crashing. &lt;/p&gt;

&lt;p&gt;I was astonished by this situation, it was surely one that no one would have been able to debug for me without having access to the project file(s). But even with that at hand, it might not have been so easy to spot the problem. The warning (second image) is only &lt;strong&gt;momentary&lt;/strong&gt; and doesn't stop you from creating a package with a reserved name my simply hitting &lt;code&gt;Enter&lt;/code&gt; on your keyboard. &lt;/p&gt;

&lt;p&gt;I would love to get a dialog prompt warning me about the mistake I am making in this scenario, perhaps it would be worth raising a ticket on Android Studio? What do you think? Should I create one? Would it be helpful to everyone in the future to prevent being in my same situation?&lt;/p&gt;

</description>
      <category>android</category>
      <category>androiddev</category>
      <category>programming</category>
      <category>learning</category>
    </item>
    <item>
      <title>Keep your UI test working when migrating from native Auth0 to WebAuth0 login</title>
      <dc:creator>Luca Nicoletti</dc:creator>
      <pubDate>Sun, 16 Apr 2023 15:15:53 +0000</pubDate>
      <link>https://dev.to/luca_nicoletti/keep-your-ui-test-working-when-migrating-from-native-auth0-to-webauth0-login-3g70</link>
      <guid>https://dev.to/luca_nicoletti/keep-your-ui-test-working-when-migrating-from-native-auth0-to-webauth0-login-3g70</guid>
      <description>&lt;h2&gt;
  
  
  Introductions
&lt;/h2&gt;

&lt;p&gt;Auth0 is a popular identity and access management platform that provides developers with an easy-to-use solution for securing their applications and APIs. With Auth0, developers can quickly add authentication and authorization to their applications without having to worry about the underlying infrastructure. Auth0 supports a wide range of authentication protocols and provides a customizable login page, multi-factor authentication, and social identity providers. In this blog post, I will show the two possible solutions offered from the Auth0 SDK to login the user, and how migrating from one another could break your UI E2E automated tests, and how to "crack" a working solution to maintain your test checks all green ✅.&lt;/p&gt;

&lt;h3&gt;
  
  
  Auth0 SDK
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Auth0 makes authentication and authorization easy&lt;br&gt;
Because you have better things to be worrying about.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And I couldn't agree more, us developer have better things to spend our time on, login should always be an effortless implementation in an application, from all points.&lt;br&gt;
In the specifics, the &lt;a href="https://github.com/auth0/Auth0.Android"&gt;Android Auth0 SDK&lt;/a&gt; provides 2 ways of logging the user into your application:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Native login&lt;/li&gt;
&lt;li&gt;WebAuth login&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;
  
  
  Native login
&lt;/h4&gt;

&lt;p&gt;The SDK provides a method to invoke to login the user using username and password. There are variants of this method, one accepting a callback, and one using coroutines, suspending the current thread.&lt;br&gt;
Our app had already in place the native login, using callbacks (a bit of legacy code).&lt;br&gt;
The method, inside the callback, provides you a &lt;code&gt;Credentials&lt;/code&gt; object, containing both &lt;code&gt;authToken&lt;/code&gt; and &lt;code&gt;refreshToken&lt;/code&gt;, which you can then save using the &lt;code&gt;CredentialManager&lt;/code&gt; class (from the Auth0 SDK), and re-access whenever you need them to perform any authorised-only API call to your backend.&lt;br&gt;
This method is pure Java/Kotlin and requires you to setup your own UI (however you want) in your app.&lt;br&gt;
Our app looked like this:&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkdwxho0tgxmyromf292t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkdwxho0tgxmyromf292t.png" width="601" height="1198"&gt;&lt;/a&gt;&lt;br&gt;
We had two fields: username and password, and a checkbox to keep the user logged in. The login button is disabled until both the fields are filled with valid inputs.&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7gei2awfaisun17cdj1v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7gei2awfaisun17cdj1v.png" width="601" height="1198"&gt;&lt;/a&gt; &lt;br&gt;
Once the user clicks on the login button, we perform the login with Auth0 native authentication, and then navigate the user accordingly to the correct page (either the dashboard or the account setup page).&lt;/p&gt;
&lt;h4&gt;
  
  
  WebAuth login
&lt;/h4&gt;

&lt;p&gt;The WebAuth login instead, gives you a login-page (that is customisable through the Auth0 dashboard), so you don't have to think about the UI inside your app, not entirely, at least.&lt;br&gt;
You just need to tell the SDK to start the web-flow.&lt;br&gt;
We changed our login page to look like this&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flupuzzlpyx7vm48myd6h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flupuzzlpyx7vm48myd6h.png" width="534" height="1053"&gt;&lt;/a&gt;&lt;br&gt;
It is much simpler, it just has a login button and a checkbox to keep the user signed in. Once the user clicks on the login button, the web-flow is started, and the webpage is shown:&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqaquacta77ud5odatuak.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqaquacta77ud5odatuak.png" width="534" height="1053"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  SDK setup
&lt;/h3&gt;

&lt;p&gt;To use the Auth0 SDK, some setup is required, and by some I mean "very little".&lt;br&gt;
The shared setup between the &lt;code&gt;WebAuth&lt;/code&gt; and &lt;code&gt;Native&lt;/code&gt; is this simple line of code:&lt;br&gt;
&lt;code&gt;val account = Auth0("{YOUR_CLIENT_ID}", "{YOUR_DOMAIN}")&lt;/code&gt;&lt;br&gt;
With this, you will be able to login the user with the &lt;code&gt;WebAuth&lt;/code&gt; without anything else.&lt;/p&gt;
&lt;h4&gt;
  
  
  Native
&lt;/h4&gt;

&lt;p&gt;For the &lt;code&gt;Native&lt;/code&gt; login, some more configuration is needed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;val authentication = AuthenticationAPIClient(account)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this &lt;code&gt;authentication&lt;/code&gt; object, you can then login the user using the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;authentication.login(username, password)
   .setScope(authScope)
   .setAudience(authAudience)
   .start(callback)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;authScope&lt;/code&gt; being the scope (configured on the Auth0's dashboard)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;authAudience&lt;/code&gt; being the audience  (configured on the Auth0's dashboard)&lt;/li&gt;
&lt;li&gt;and &lt;code&gt;callback&lt;/code&gt; being a &lt;code&gt;Callback&amp;lt;Credentials, AuthenticationException&amp;gt;&lt;/code&gt; used to proceed after the login is successful (gives back a &lt;code&gt;Credentials&lt;/code&gt; object), or to show what went wrong from the &lt;code&gt;AuthenticationException&lt;/code&gt; received)&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  WebAuth
&lt;/h4&gt;

&lt;p&gt;For the WebAuth instead, once you have the &lt;code&gt;account&lt;/code&gt; object, you can directly call:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;WebAuthProvider.login(account)
    .withScope(authScope)
    .withAudience(authAudience)
    .start(activity, callback)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The parameters are the same as the ones above, with the addition of the &lt;code&gt;activity&lt;/code&gt; (used to launch the new web activity with &lt;code&gt;ACTION_VIEW&lt;/code&gt; from inside the SDK).&lt;br&gt;
Some more configuration need to be done, as you have to specify the &lt;code&gt;callback URLs&lt;/code&gt; (for login and logout) on the Auth0 dashboard, and inside your app. This can be done in the manifest as explained &lt;a href="https://auth0.com/docs/quickstart/native/android/interactive"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h4&gt;
  
  
  Both
&lt;/h4&gt;

&lt;p&gt;The code shown above allows you only to login the user, and gives you back the &lt;code&gt;Credentials&lt;/code&gt;. But if you don't store and save them, you won't be able to keep your user logged in, or re-use them at will when needed.&lt;br&gt;
To achieve this, some more code is needed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;val auth0Storage: SharedPreferencesStorage = SharedPreferencesStorage(context)
val credentialsManager: CredentialsManager = CredentialsManager(authentication, auth0Storage) 
// authentication is already defined above
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now with the &lt;code&gt;credentialManager&lt;/code&gt; instance, you can save the credentials, using the &lt;code&gt;fun saveCredentials(credentials: Credentials)&lt;/code&gt; function, and also retrieve them, using the function &lt;code&gt;suspend fun awaitCredentials(): Credentials&lt;/code&gt;. You can also check, beforehand that the manager has valid credentials, using &lt;code&gt;fun hasValidCredentials(): Boolean&lt;/code&gt;.&lt;br&gt;
With these three function, you will be able to login the user, save his/her credentials, and retrieve them at will, whenever you need them.&lt;/p&gt;
&lt;h2&gt;
  
  
  Why migrating to WebAuth?
&lt;/h2&gt;

&lt;p&gt;Since we started targeting a broader audience (we're a B2B), some of our clients asked for - or suggested it would be nice to have - an universal login that allowed them to login using existing accounts from other platforms (e.g.: Google, Microsoft, Apple, etc...). I won't talk about all the UX process that we went through, but in the end it made sense, not requiring a personalised account on our side, and allowing a user to authenticate throughout another existing account would make ours - and their - lifes easier. &lt;/p&gt;
&lt;h3&gt;
  
  
  Migration
&lt;/h3&gt;

&lt;p&gt;As you might have already seen from the code above, the migration from one to the other is pretty easy and straight forward. There aren't many differences, and both requires a minimum effort to implement, even if starting from scratch.&lt;/p&gt;

&lt;p&gt;In fact, it took relatively a short amount of time to do the migration, even using a TDD approach, refactoring all the tests first, and then applying the changes in the code to get back on a full passing test (I'm talking about Unit tests here).&lt;br&gt;
I left UI tests as the last thing to check and update, and boy that was a mistake.&lt;br&gt;
The changes on the clicks to be performed were easy, as it was removing all the "fill this field with X".&lt;br&gt;
The problem was now that, after tapping on the login button, we were outside of our codebase, outside of our application, in a WebView opened from an SDK of which we have no control.&lt;br&gt;
We tried using &lt;code&gt;Espresso Web&lt;/code&gt; with &lt;code&gt;androidTestImplementation 'androidx.test.espresso:espresso-web:3.4.0'&lt;/code&gt; but unfortunately the framework was not able to find the webview, probably because it was not inside any of our view hierarchies. &lt;br&gt;
I &lt;a href="https://stackoverflow.com/questions/75758009/android-espresso-testing-webview-opened-from-an-sdk-using-action-view"&gt;asked the community on StackOverflow&lt;/a&gt; if anyone else faced the same problem before, hoping for an easy solution on how to interact with the WebView launched.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No luck.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;So we tried checking if it was possible to configure, only for the test-folder, the object &lt;code&gt;WebAuthProvider&lt;/code&gt; to automatically perform the login for us, sending to it a username and password. I also opened a feature-request on the &lt;code&gt;Auth0 Android SDK&lt;/code&gt; &lt;a href="https://github.com/auth0/Auth0.Android/issues/636"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No luck. Again&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We had to find another solution to keep our UI E2E tests running. &lt;/p&gt;
&lt;h3&gt;
  
  
  Interface to the rescue!
&lt;/h3&gt;

&lt;p&gt;After struggling for a bit, we thought about using an interface to solve all our problems: the initial idea was WebAuthProvider required, and perform the login for us. This way, we could have two different implementations: one for our "real" codebase, the one that would run in production and allow the user to login, and one that would be specific for testing, overriding the default implementation, and logging in the user without opening any webview or using the &lt;code&gt;WebAuthProvider&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;After considering what to provide this interface and what not, we came up with this solution:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;interface WebAuthLogin {
    fun login(
        activity: Activity,
        event: OpenUniversalLogin,
        onSuccess: ((result: Credentials) -&amp;gt; Unit),
        onFailure: ((error: AuthenticationException) -&amp;gt; Unit)
    )
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;where the &lt;code&gt;OpenUniversalLogin&lt;/code&gt; event contains the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;data class OpenUniversalLogin(
    val auth0: Auth0,
    val scheme: String,
    val scope: String,
    val audience: String,
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Modules and test-substitution
&lt;/h4&gt;

&lt;p&gt;With &lt;a href="https://developer.android.com/training/dependency-injection/hilt-android"&gt;Hilt&lt;/a&gt; we were able to use dependency injection to configure correctly the scenarios listed above: 1 implementation for our production code, and one for testing purposes. &lt;br&gt;
We used a &lt;code&gt;Module&lt;/code&gt; to &lt;code&gt;Binds&lt;/code&gt; the implementation of our interface. The "official" implementation, as you might have guessed by combining the code I provided, simply would do this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;WebAuthProvider.login(event.auth0)
    .withParameters(mapOf(PROMPT_KEY to LOGIN_KEY))
    .withScheme(event.scheme)
    .withScope(event.scope)
    .withAudience(event.audience)
    .start(
        activity,
        object : Callback&amp;lt;Credentials, AuthenticationException&amp;gt; {
            override fun onFailure(error: AuthenticationException) {
                onFailure(error)
            }

            override fun onSuccess(result: Credentials) {
                onSuccess(result)
            }
        }
    )
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Scheme is another parameter that can be configured in the &lt;code&gt;Auth0&lt;/code&gt; dashboard, and since we're using a custom-defined one, we need to provide it to the &lt;code&gt;WebAuthProvider&lt;/code&gt; object before performing the login.&lt;br&gt;
The &lt;code&gt;.withParameters(mapOf(PROMPT_KEY to LOGIN_KEY))&lt;/code&gt; line, instead, turned out to be quite useful and required - as well - for us: it was not documented in their repository, but it forced the webview to show the login every time, even if a log out action is not performed. This was a requirement for us, since if the user logs in without the &lt;code&gt;remember me&lt;/code&gt; functionality, upon closing the app, we would want him to login again. But without that parameter, since the cookies of the webview were not cleared, when the user clicked the &lt;code&gt;login&lt;/code&gt; button, the webview would immediately return to our app, with a logged user, without asking for any credentials. &lt;/p&gt;

&lt;p&gt;Whereas for testing, we used &lt;code&gt;TestInstallIn&lt;/code&gt; as follow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@TestInstallIn(
    components = [SingletonComponent::class],
    replaces = [RealLoginBinds::class]
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;replacing the "official implementation with a "fake" one that used the "old"-native method to login the user and store its data in the application's cache.&lt;br&gt;
Paired with &lt;code&gt;@UninstallModules()&lt;/code&gt; in the tests where we needed the fake implementation.&lt;/p&gt;
&lt;h4&gt;
  
  
  One additional problem
&lt;/h4&gt;

&lt;p&gt;As you might have noticed, the &lt;code&gt;login&lt;/code&gt; function doesn't accept any username or password, so our tests were at the moment blind and wouldn't know which user to login (we need different account as we're testing different scenarios and interactions between accounts - invites, etc...).&lt;br&gt;
To solve this "problem", I had a light-bulb 💡 moment, and came up with&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;object LoginThingy {
    lateinit var username: String
    lateinit var password: String
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Kotlin allows you to define an object with lazily initialised variables. With this, our implementation of the &lt;code&gt;login&lt;/code&gt; function in the test folder would access the parameters as &lt;code&gt;LoginThingy.username&lt;/code&gt; and &lt;code&gt;LoginThingy.password&lt;/code&gt;, which we would define, in a case-by-case scenario in our test as&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;LoginThingy.username = email
LoginThingy.password = password
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusions
&lt;/h2&gt;

&lt;p&gt;What we thought was an easy to implement change, turned out to be one of the most challenging task of the last month: not much for the code implementation, but for all the tests we had to do in order to check and re-check that everything was working fine as it was.&lt;br&gt;
Last but not least, after doing the login migration, we had to implement the log-out functionality as well, but that was an easy walk compared to the long, exhausting sprint of the login, given we walked that path already. &lt;/p&gt;

&lt;p&gt;The new login is now live in our app, and since it's completely configured from the &lt;code&gt;Auth0&lt;/code&gt; dashboard, we will be able to add Google/Facebook/Apple or other universal login way for our user base to authenticate.&lt;/p&gt;

&lt;p&gt;It was a nice challenge overall, that kept me busy with researching online for possible solutions already in place for a while, and I really enjoyed it. Hopefully the next migration will be easier and quicker, without too many headache to follow! &lt;/p&gt;

</description>
      <category>android</category>
      <category>auth</category>
      <category>mobile</category>
    </item>
  </channel>
</rss>
