Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Snapshots are not generated for Android Views that are annotated with Dagger's @AndroidEntryPoint #1249

Open
Tinder-FroWarner opened this issue Jan 22, 2024 · 4 comments
Labels
bug Something isn't working

Comments

@Tinder-FroWarner
Copy link

Tinder-FroWarner commented Jan 22, 2024

Description

We are working on creating a snapshot test for an Android View with injected dependencies via Dagger/Hilt, but are running into an issue when generating the snapshot if a view is annotated with @AndroidEntryPoint.

Steps to Reproduce

The following gives an example of the error and setup.

Exception

java.lang.IllegalStateException: Could not find an Application in the given context: com.android.layoutlib.bridge.android.BridgeContext@6425422c 
at dagger.hilt.android.internal.Contexts.getApplication(Contexts.java:42)
at dagger.hilt.android.internal.managers.ViewComponentManager.getParentContext(ViewComponentManager.java:146)
at dagger.hilt.android.internal.managers.ViewComponentManager.getParentComponentManager(ViewComponentManager.java:128)
at dagger.hilt.android.internal.managers.ViewComponentManager.createComponent(ViewComponentManager.java:86) 
at dagger.hilt.android.internal.managers.ViewComponentManager.generatedComponent(ViewComponentManager.java:77)
...

Example Code

Example of View:

@AndroidEntryPoint
class CustomView(
    context: Context,
    attrs: AttributeSet? = null,
) : CustomComponentView<CustomModel>(context, attrs) {

    private val binding = CustomViewBinding.inflate(LayoutInflater.from(context), this)

    @Inject
    lateinit var injectedLinkLauncher: InjectedLinkLauncher

    override fun bind(uiModel: CustomModel) {
        // ...
    }
// ... 

Example of Test:

class CustomViewSnapshotTest {
    @get:Rule
    val paparazzi = Paparazzi(
        deviceConfig = PIXEL_5,
        maxPercentDifference = 0.01
    )

    @Test
    fun `CustomView - content`() {
        val view = CustomView(paparazzi.context)
        view.bind(
            uiModel = CustomComponentUiModel.CustomModel(
                text = "Content",
                 // ...
            )
        )
        paparazzi.snapshot(view)
    }
}

Expected behavior

Snapshots generate and tests pass.

Actual Behavior

Snapshots only generate and tests pass when commenting out the injected vals and @AndroidEntryPoint i.e.

// @AndroidEntryPoint
class CustomView(
    context: Context,
    attrs: AttributeSet? = null,
) : CustomComponentView<CustomModel>(context, attrs) {

    private val binding = CustomViewBinding.inflate(LayoutInflater.from(context), this)

   // @Inject
   // lateinit var injectedLinkLauncher: InjectedLinkLauncher

    override fun bind(uiModel: CustomModel) {
        // ...
    }
// commented out injectedLinkLauncher usage as well

Additional information:

  • Paparazzi Version: 1.3.2
  • OS: Mac OS ver. 12.6 (M1 Max)
  • Gradle Version: 17.0.9
  • Android Gradle Plugin Version: 8.1.0
@Tinder-FroWarner Tinder-FroWarner added the bug Something isn't working label Jan 22, 2024
@jrodbx
Copy link
Collaborator

jrodbx commented Jan 22, 2024

@Tinder-FroWarner

Is the view located in the main source set or in a test source set? If the latter, you likely need to add a "testKapt" or "kspTest" configuration.

If not, mind providing a sample project? This is very specific to your setup and I'm inclined to consider this a Hilt configuration issue without something to help easily repro.

@jrodbx
Copy link
Collaborator

jrodbx commented May 24, 2024

Took another look at this. The issue is that BridgeContext inherits from Context, not ContextWrapper, therefore dagger.hilt.android.internal.Contexts is unable to find the application context here: https://github.com/google/dagger/blob/a8581e0a62b7cb3d1f5a13da26a8f40e22aad3d0/java/dagger/hilt/android/internal/Contexts.java

One option might be to file an issue with the Dagger team to special case layoutlib's BridgeContext, but I could understand that request being turned down. I'll file this as a feature request with the LayoutLib team and see where that goes.

@jrodbx
Copy link
Collaborator

jrodbx commented May 24, 2024

@drinkthestars
Copy link

Thanks for creating the issue with the LayoutLib team @jrodbx! 🙏🏼

Ran into a similar issue when trying to create a snapshot test for a View that uses Hilt's EntryPointAccessors.fromApplication to inject something from applicationContext. I assume it's for a similar reason?

Any thoughts on a possible workaround for the time being? Is it possible to somehow make snapshot tests to mock/"give" them an "application context" or otherwise mock the injected dependency itself? Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants