Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,9 @@ var PdfViewer.outlineStatus: PdfViewModel.OutlineStatus
set(value) {
viewModel.setOutlineForTest(value)
}

var PdfViewer.zoomRatio: Float
get() = viewModel.zoomRatio.value
set(value) {
viewModel.setZoomRatio(value)
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,34 +3,40 @@ package app.grapheneos.pdfviewer.test
import android.app.Activity
import android.app.Instrumentation
import android.content.Intent
import androidx.compose.ui.test.assertTextContains
import androidx.compose.ui.test.assertTextEquals
import androidx.compose.ui.test.onNodeWithTag
import androidx.test.core.app.ActivityScenario
import androidx.test.espresso.intent.Intents
import androidx.test.espresso.intent.Intents.intending
import androidx.test.espresso.intent.matcher.IntentMatchers.hasAction
import androidx.test.ext.junit.runners.AndroidJUnit4
import app.grapheneos.pdfviewer.PdfJsChannel.Companion.MAX_ZOOM_RATIO
import app.grapheneos.pdfviewer.PdfJsChannel.Companion.MIN_ZOOM_RATIO
import app.grapheneos.pdfviewer.PdfViewer
import app.grapheneos.pdfviewer.testrules.RetryRules
import app.grapheneos.pdfviewer.RetryableComposeRule
import app.grapheneos.pdfviewer.TestTags
import app.grapheneos.pdfviewer.currentPage
import app.grapheneos.pdfviewer.documentName
import app.grapheneos.pdfviewer.testrules.OrientationRules
import app.grapheneos.pdfviewer.testrules.RetryRules
import app.grapheneos.pdfviewer.totalPages
import app.grapheneos.pdfviewer.util.PdfViewerLauncher
import app.grapheneos.pdfviewer.util.PdfViewerRobot
import app.grapheneos.pdfviewer.util.PdfViewerTestUtils
import app.grapheneos.pdfviewer.zoomRatio
import org.junit.Assert.assertEquals
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.rules.RuleChain
import org.junit.runner.RunWith
import kotlin.math.abs
import kotlin.math.roundToInt

/**
* Page navigation and JumpToPage dialog.
* Page navigation, JumpToPage dialog and CustomZoomDialog.
*/
@RunWith(AndroidJUnit4::class)
class PdfViewerNavigationTest {
Expand Down Expand Up @@ -320,4 +326,140 @@ class PdfViewerNavigationTest {
robot.assertMenuItemVisible(PdfViewerRobot.AppMenuItem.Outline, expected = true)
}
}

@Test
fun zoomButtons_menuStaysOpenAfterClick() {
PdfViewerLauncher.launchWithTestAsset("test-simple.pdf").use { scenario ->
PdfViewerTestUtils.waitForDocumentFullyLoaded(scenario)
PdfViewerTestUtils.waitForCanvasRendered(scenario)

robot.clickMenuZoomIn()
robot.assertZoomRowVisible()
}
}

@Test
fun zoomInButton_disabledAtMaxZoom() {
PdfViewerLauncher.launchWithTestAsset("test-simple.pdf").use { scenario ->
PdfViewerTestUtils.waitForDocumentFullyLoaded(scenario)
PdfViewerTestUtils.waitForCanvasRendered(scenario)

scenario.onActivity {
it.zoomRatio = MAX_ZOOM_RATIO
}
composeRule.waitForIdle()

robot.assertZoomInEnabled(false)
robot.assertZoomOutEnabled(true)
}
}

@Test
fun zoomOutButton_disabledAtMinZoom() {
PdfViewerLauncher.launchWithTestAsset("test-simple.pdf").use { scenario ->
PdfViewerTestUtils.waitForDocumentFullyLoaded(scenario)
PdfViewerTestUtils.waitForCanvasRendered(scenario)

scenario.onActivity {
it.zoomRatio = MIN_ZOOM_RATIO
}
composeRule.waitForIdle()

robot.assertZoomOutEnabled(false)
robot.assertZoomInEnabled(true)
}
}

@Test
fun customZoomDialog_opensWithCurrentZoom() {
PdfViewerLauncher.launchWithTestAsset("test-simple.pdf").use { scenario ->
PdfViewerTestUtils.waitForDocumentFullyLoaded(scenario)
PdfViewerTestUtils.waitForCanvasRendered(scenario)

val currentZoom = robot.getZoomRatio(scenario)
val expectedPercent = (currentZoom * 100).roundToInt()

robot.clickZoomPercentage()
robot.assertCustomZoomDialogText(expectedPercent)
}
}

@Test
fun customZoomDialog_okAppliesZoom() {
PdfViewerLauncher.launchWithTestAsset("test-simple.pdf").use { scenario ->
PdfViewerTestUtils.waitForDocumentFullyLoaded(scenario)
PdfViewerTestUtils.waitForCanvasRendered(scenario)

robot.clickZoomPercentage()
robot.setCustomZoomValue(200)
robot.clickDialogOk()

PdfViewerTestUtils.pollUntil(
description = {
"Zoom ratio should be 2.0 after custom zoom " +
"(was ${robot.getZoomRatio(scenario)})"
}
) {
abs(robot.getZoomRatio(scenario) - 2.0f) < 0.01f
}
}
}

@Test
fun customZoomDialog_cancelDoesNotChangeZoom() {
PdfViewerLauncher.launchWithTestAsset("test-simple.pdf").use { scenario ->
PdfViewerTestUtils.waitForDocumentFullyLoaded(scenario)
PdfViewerTestUtils.waitForCanvasRendered(scenario)

val initialZoom = robot.getZoomRatio(scenario)

robot.clickZoomPercentage()
robot.setCustomZoomValue(200)
robot.clickDialogCancel()
composeRule.waitForIdle()

val afterZoom = robot.getZoomRatio(scenario)
assertEquals(
"Zoom should not change after dialog cancel",
initialZoom, afterZoom, 0.001f
)
}
}

@Test
fun customZoomDialog_prefilledValueIsSelected_typingReplaces() {
PdfViewerLauncher.launchWithTestAsset("test-simple.pdf").use { scenario ->
PdfViewerTestUtils.waitForDocumentFullyLoaded(scenario)
PdfViewerTestUtils.waitForCanvasRendered(scenario)

robot.clickZoomPercentage()
robot.typeCustomZoom(200)

composeRule.onNodeWithTag(TestTags.CUSTOM_ZOOM_FIELD)
.assertTextContains("200")

robot.clickDialogOk()

PdfViewerTestUtils.pollUntil(
description = {
"Zoom ratio should be 2.0 after typing replacement " +
"(was ${robot.getZoomRatio(scenario)})"
}
) {
abs(robot.getZoomRatio(scenario) - 2.0f) < 0.01f
}
}
}

@Test
fun customZoomDialog_rejectsInvalidInput() {
PdfViewerLauncher.launchWithTestAsset("test-simple.pdf").use { scenario ->
PdfViewerTestUtils.waitForDocumentFullyLoaded(scenario)
PdfViewerTestUtils.waitForCanvasRendered(scenario)

robot.clickZoomPercentage()
robot.setCustomZoomValue(0)
robot.assertDialogOkEnabled(false)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ package app.grapheneos.pdfviewer.test

import androidx.test.ext.junit.runners.AndroidJUnit4
import app.grapheneos.pdfviewer.PdfJsChannel.Companion.MIN_ZOOM_RATIO
import app.grapheneos.pdfviewer.testrules.RetryRules
import app.grapheneos.pdfviewer.RetryableComposeRule
import app.grapheneos.pdfviewer.currentPage
import app.grapheneos.pdfviewer.documentProperties
import app.grapheneos.pdfviewer.testrules.OrientationRules
import app.grapheneos.pdfviewer.testrules.RetryRules
import app.grapheneos.pdfviewer.totalPages
import app.grapheneos.pdfviewer.util.PdfViewerLauncher
import app.grapheneos.pdfviewer.util.PdfViewerRobot
Expand Down Expand Up @@ -275,6 +275,79 @@ class PdfViewerRenderTest {
}
}

@Test
fun buttonZoomIn_increasesDimensionsAndPreservesTextLayer() {
PdfViewerLauncher.launchWithTestAsset("test-simple.pdf").use { scenario ->
PdfViewerTestUtils.waitForDocumentFullyLoaded(scenario)
PdfViewerTestUtils.waitForCanvasRendered(scenario)

val initialWidth = robot.getCanvasCssWidth(scenario)
val initialHeight = robot.getCanvasCssHeight(scenario)

robot.clickMenuZoomIn()

PdfViewerTestUtils.waitForCanvasCssDimensionsChanged(
scenario, initialWidth, initialHeight
)

val zoomedWidth = robot.getCanvasCssWidth(scenario)
val zoomedHeight = robot.getCanvasCssHeight(scenario)
assertTrue(
"Canvas CSS width should increase after menu button zoom in " +
"($initialWidth → $zoomedWidth)",
zoomedWidth > initialWidth
)
assertTrue(
"Canvas CSS height should increase after menu button zoom in " +
"($initialHeight → $zoomedHeight)",
zoomedHeight > initialHeight
)

PdfViewerTestUtils.assertTextLayerContent(scenario, "Test Text")
robot.assertTextLayerAligned(scenario)
}
}

@Test
fun buttonZoomOut_decreasesDimensionsAndPreservesTextLayer() {
PdfViewerLauncher.launchWithTestAsset("test-simple.pdf").use { scenario ->
PdfViewerTestUtils.waitForDocumentFullyLoaded(scenario)
PdfViewerTestUtils.waitForCanvasRendered(scenario)

val defaultWidth = robot.getCanvasCssWidth(scenario)
val defaultHeight = robot.getCanvasCssHeight(scenario)

robot.clickMenuZoomIn()
PdfViewerTestUtils.waitForCanvasCssDimensionsChanged(
scenario, defaultWidth, defaultHeight
)

val zoomedInWidth = robot.getCanvasCssWidth(scenario)
val zoomedInHeight = robot.getCanvasCssHeight(scenario)

robot.clickMenuZoomOut()
PdfViewerTestUtils.waitForCanvasCssDimensionsChanged(
scenario, zoomedInWidth, zoomedInHeight
)

val zoomedOutWidth = robot.getCanvasCssWidth(scenario)
val zoomedOutHeight = robot.getCanvasCssHeight(scenario)
assertTrue(
"Canvas CSS width should decrease after menu button zoom out " +
"($zoomedInWidth → $zoomedOutWidth)",
zoomedOutWidth < zoomedInWidth
)
assertTrue(
"Canvas CSS height should decrease after menu button zoom out " +
"($zoomedInHeight → $zoomedOutHeight)",
zoomedOutHeight < zoomedInHeight
)

PdfViewerTestUtils.assertTextLayerContent(scenario, "Test Text")
robot.assertTextLayerAligned(scenario)
}
}

@Test
fun documentPropertiesDialog_showsExpectedRows() {
PdfViewerLauncher.launchWithTestAsset("test-simple.pdf").use { scenario ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import androidx.compose.ui.test.assertIsNotEnabled
import androidx.compose.ui.test.assertTextContains
import androidx.compose.ui.test.hasText
import androidx.compose.ui.test.junit4.ComposeTestRule
import androidx.compose.ui.test.onAllNodesWithContentDescription
import androidx.compose.ui.test.onAllNodesWithTag
import androidx.compose.ui.test.onNodeWithContentDescription
import androidx.compose.ui.test.onNodeWithTag
Expand Down Expand Up @@ -559,6 +560,75 @@ class PdfViewerRobot(private val composeRule: ComposeTestRule) {
return result.toFloat()
}

private fun ensureOverflowMenuOpen() {
val zoomInDesc = getTargetContext().getString(R.string.zoom_in)
val nodes = composeRule.onAllNodesWithContentDescription(zoomInDesc)
.fetchSemanticsNodes()
if (nodes.isEmpty()) {
composeRule.onNodeWithContentDescription(TestTags.OVERFLOW_MENU).performClick()
composeRule.waitForIdle()
}
}

fun clickMenuZoomIn() {
ensureOverflowMenuOpen()
val desc = getTargetContext().getString(R.string.zoom_in)
composeRule.onNodeWithContentDescription(desc).performClick()
composeRule.waitForIdle()
}

fun clickMenuZoomOut() {
ensureOverflowMenuOpen()
val desc = getTargetContext().getString(R.string.zoom_out)
composeRule.onNodeWithContentDescription(desc).performClick()
composeRule.waitForIdle()
}

fun clickZoomPercentage() {
ensureOverflowMenuOpen()
composeRule.onNodeWithTag(TestTags.ZOOM_PERCENTAGE).performClick()
composeRule.waitForIdle()
}

fun assertZoomInEnabled(enabled: Boolean) {
ensureOverflowMenuOpen()
val desc = getTargetContext().getString(R.string.zoom_in)
val node = composeRule.onNodeWithContentDescription(desc)
if (enabled) node.assertIsEnabled() else node.assertIsNotEnabled()
}

fun assertZoomOutEnabled(enabled: Boolean) {
ensureOverflowMenuOpen()
val desc = getTargetContext().getString(R.string.zoom_out)
val node = composeRule.onNodeWithContentDescription(desc)
if (enabled) node.assertIsEnabled() else node.assertIsNotEnabled()
}

fun assertZoomRowVisible() {
val desc = getTargetContext().getString(R.string.zoom_in)
composeRule.onNodeWithContentDescription(desc).assertIsDisplayed()
}

fun assertCustomZoomDialogText(currentPercent: Int) {
composeRule.onNodeWithTag(TestTags.CUSTOM_ZOOM_FIELD)
.assertTextContains(currentPercent.toString())
}

fun setCustomZoomValue(value: Int) {
composeRule.onNodeWithTag(TestTags.CUSTOM_ZOOM_FIELD).performTextClearance()
composeRule.onNodeWithTag(TestTags.CUSTOM_ZOOM_FIELD).performTextInput(value.toString())
}

fun typeCustomZoom(value: Int) {
composeRule.onNodeWithTag(TestTags.CUSTOM_ZOOM_FIELD).performTextInput(value.toString())
}

fun assertDialogOkEnabled(enabled: Boolean) {
val text = getTargetContext().getString(android.R.string.ok)
val node = composeRule.onNodeWithText(text)
if (enabled) node.assertIsEnabled() else node.assertIsNotEnabled()
}

// Text layer alignment

fun assertTextLayerAligned(scenario: ActivityScenario<PdfViewer>) {
Expand Down
4 changes: 2 additions & 2 deletions app/src/main/java/app/grapheneos/pdfviewer/PdfJsChannel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,11 @@ class PdfJsChannel(private val viewModel: PdfViewModel) {
fun getPage(): Int = viewModel.page.value

@JavascriptInterface
fun getZoomRatio(): Float = viewModel.zoomRatio
fun getZoomRatio(): Float = viewModel.zoomRatio.value

@JavascriptInterface
fun setZoomRatio(ratio: Float) {
viewModel.zoomRatio = ratio.coerceIn(MIN_ZOOM_RATIO, MAX_ZOOM_RATIO)
viewModel.setZoomRatio(ratio.coerceIn(MIN_ZOOM_RATIO, MAX_ZOOM_RATIO))
}

@JavascriptInterface
Expand Down
Loading