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

Captured screenshots do not show elevation of elements #58

Open
andydelso opened this issue Nov 22, 2023 · 16 comments
Open

Captured screenshots do not show elevation of elements #58

andydelso opened this issue Nov 22, 2023 · 16 comments

Comments

@andydelso
Copy link

We are running into an issue running tests that do not seem to take element elevation into account when the shot is taken. We can visually see the elevation (example on a Compose Card element) on the running emulator, but not in the resulting screenshot.

We were wondering if anyone has run into this same issue and knows of a work around? Alternately, is there a possible issue with the emulator we setup (needs hardware acceleration or something)?

I would share screenshots of the screenshots, but it is an internal only build and I can't share at this time.

@sebastienrouif
Copy link
Contributor

Elevation is most likely drawn outside your view bounds and that's the reason why you would not see the elevation.
Try putting your component into a container and check if you see the elevation within that container.

@andydelso
Copy link
Author

@sebastienrouif I am not following that logic. The UI is rendered in the emulator, and I can visually see the elevation there when placing a breakpoint prior to the screenshot. It is not outside the view bounds of the device. Card itself is also a container if I am not mistaken, which is within a lazy column that represents the main content of the screen. There are also other elements on the screen within the same bounds that display with no issue.

@sebastienrouif
Copy link
Contributor

I assumed you were taking a screenshot of that view only, are you taking a screenshot of the whole Activity?

@rharter
Copy link
Collaborator

rharter commented Nov 22, 2023

That was my assumption based on the description, as well. Can you make a simple repro that would allow you to share a screenshot of the issue (perhaps a screenshot of the emulator in that state alongside the recorded screenshot)?

@andydelso
Copy link
Author

andydelso commented Nov 22, 2023

We are using an activity rule that loads a full fragment displaying a composable screen. It is not a component level screen shot.

Yes I said "element" but that was not meant to be one single thing. It is just a piece of the overall screen.

@rharter
Copy link
Collaborator

rharter commented Nov 23, 2023 via email

@andydelso
Copy link
Author

andydelso commented Nov 23, 2023

Here is a scenario we setup with the way we are invoking dropshots. We have a way to mock the calls to our api prior to the snapshot being shown (localApi), and also an extra rule to handle encrypted shared preferences. Neither should directly affect if something is elevated though.

@Test
    fun someScreen_LightMode() {
        localApi.enqueueSuccess(RetrieveJsonForScreen.First)

        activityScenarioRule.scenario.onActivity {
            encryptedSharedPreferences.create()
            apiManager.setDevelopmentMode(it, DevMode.STAGING)
        }

        assertSnapshot(
            createFragment = { ScreenFragment.instance() },
            lightDarkMode = AppCompatDelegate.MODE_NIGHT_NO
        )
    }


protected fun assertSnapshot(
        createFragment: () -> Fragment,
        lightDarkMode: Int = AppCompatDelegate.MODE_NIGHT_NO,
    ) {
        val testName = testName.methodName.capitalizeFirstOfEachWord()
        activityScenarioRule.launchFragment(
            createFragment,
            lightDarkMode
        ) { activity, _ ->
            dropshots.assertSnapshot(activity, "${screenName}_$testName")
        }
    }

@andydelso
Copy link
Author

The UI is something like this:

Column(
            modifier = Modifier
                .fillMaxSize()
                .padding(top = dimensions.gridS)
                .background(color = colors.backgroundNeutralMain),
            horizontalAlignment = Alignment.CenterHorizontally
        ) {
            val listScrollState = rememberLazyListState()
            val transactionList by state.transactions.observeAsState()

            LazyColumn(
                state = listScrollState,
                modifier = Modifier
                    .weight(1f),
            ) {
                state.announcementCardState?.let { announcementCardStateNotNull ->
                    item {
                        Row(Modifier.background(colors.backgroundNeutralSecondary)) {
                            AnnouncementCard(
                                state = announcementCardStateNotNull,
                                modifier = Modifier
                                    .padding(
                                        horizontal = dimensionResource(id = R.dimen.grid_s),
                                        vertical = dimensionResource(id = R.dimen.grid_s)
                                    )
                            )
                        }
                    }
                }
...

AnnoucementCard is in its simplest:

Card(
            backgroundColor = colors.backgroundNeutralSecondary,
            shape = RoundedCornerShape(size = dimensions.radiusXS),
            elevation = dimensions.defaultElevation, // 1.dp
            modifier = modifier
        ) {
            Row(
                modifier = Modifier.padding(
                    top = dimensions.gridS,
                    start = dimensions.gridS,
                    end = dimensions.gridS
                )
            ) {
                // some row content
                Column(
                    modifier = Modifier.weight(1f)
                ) {
                  // some column content
               }
           }
       }
   }

@rharter
Copy link
Collaborator

rharter commented Nov 23, 2023

Thanks for sharing. If you set a breakpoint on the assertSnapshot call can you verify that the emulator shows your layout with the elevation you expect? Since you're passing the activity Dropshots takes a screenshot of the entire window of the Activity, which should include the elevation of any included views.

Dropshots doesn't alter the way anything is rendered, it just renders the window and records that, so I'm curious if there's something with the test setup (like the theme setting) that's preventing the elevation from being drawn.

@andydelso
Copy link
Author

andydelso commented Nov 23, 2023

Thanks for sharing. If you set a breakpoint on the assertSnapshot call can you verify that the emulator shows your layout with the elevation you expect? Since you're passing the activity Dropshots takes a screenshot of the entire window of the Activity, which should include the elevation of any included views.

Dropshots doesn't alter the way anything is rendered, it just renders the window and records that, so I'm curious if there's something with the test setup (like the theme setting) that's preventing the elevation from being drawn.

As stated in the second comment: "The UI is rendered in the emulator, and I can visually see the elevation there when placing a breakpoint prior to the screenshot".

Your thought process is kinda where what we were thinking as well. Maybe something with the emulator setup for hardware acceleration or something would cause it. However, that didn't fully make sense as it was rendered to the emulator prior to the screenshot.

It is so weird 😆

@rharter
Copy link
Collaborator

rharter commented Nov 23, 2023

Hmm, that's weird. Internally, Dropshots just uses the AndroidX test screenshot class to take the screenshot. If you run this in the breakpoint evaluate expression dialog do you get the elevation? If not, I'd check the docs for that to see if they mention anything about hardware acceleration. I think I recall seeing some special handling in there for non-accepleratre surfaces, but am on mobile so can't look it up right now.

Screenshot.capture(activity).bitmap

@andydelso
Copy link
Author

Much the same here. Getting ready for the holiday. I'll check again on Friday.

@andydelso
Copy link
Author

@rharter when I add that expression I get the following:
image

At that point the emulator shows the elevation, clicking "view bitmap" next to the expression shows no elevation.

@andydelso
Copy link
Author

Also to note, the emulator we are all using has Emulated Performance > Graphics set to "Automatic".

@andydelso
Copy link
Author

@rharter I was wondering if the above gave you any other ideas?

@sergio-sastre
Copy link

sergio-sastre commented Dec 7, 2023

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants