Skip to content

Commit b50641b

Browse files
committed
add UI DOCX editing test
1 parent 9161079 commit b50641b

File tree

1 file changed

+139
-1
lines changed

1 file changed

+139
-1
lines changed

app/src/androidTest/java/at/tomtasche/reader/test/MainActivityTests.java

Lines changed: 139 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import android.content.Intent;
2323
import android.content.res.AssetManager;
2424
import android.net.Uri;
25+
import android.os.SystemClock;
2526
import android.util.ArrayMap;
2627
import android.util.Log;
2728

@@ -49,9 +50,15 @@
4950
import java.io.InputStream;
5051
import java.io.OutputStream;
5152
import java.util.Map;
53+
import java.util.concurrent.CountDownLatch;
54+
import java.util.concurrent.TimeUnit;
55+
import java.util.concurrent.atomic.AtomicReference;
5256

5357
import at.tomtasche.reader.R;
58+
import at.tomtasche.reader.ui.EditActionModeCallback;
5459
import at.tomtasche.reader.ui.activity.MainActivity;
60+
import at.tomtasche.reader.ui.activity.DocumentFragment;
61+
import at.tomtasche.reader.ui.widget.PageView;
5562

5663
@LargeTest
5764
@RunWith(AndroidJUnit4.class)
@@ -126,7 +133,7 @@ public static void extractTestFiles() throws IOException {
126133

127134
AssetManager testAssetManager = instrumentation.getContext().getAssets();
128135

129-
for (String filename: new String[] {"test.odt", "dummy.pdf", "password-test.odt"}) {
136+
for (String filename: new String[] {"test.odt", "dummy.pdf", "password-test.odt", "style-various-1.docx"}) {
130137
File targetFile = new File(testDocumentsDir, filename);
131138
try (InputStream inputStream = testAssetManager.open(filename)) {
132139
copy(inputStream, targetFile);
@@ -277,4 +284,135 @@ public void testPasswordProtectedODT() {
277284
.perform(click());
278285
});
279286
}
287+
288+
@Test
289+
public void testODTEditMode() throws InterruptedException {
290+
File testFile = s_testFiles.get("test.odt");
291+
Assert.assertNotNull(testFile);
292+
MainActivity activity = mainActivityActivityTestRule.getActivity();
293+
DocumentFragment documentFragment = loadDocument(activity, testFile);
294+
enterEditMode(activity, documentFragment);
295+
296+
PageView pageView = documentFragment.getPageView();
297+
Assert.assertNotNull(pageView);
298+
Assert.assertTrue(
299+
"ODT should become editable after entering edit mode",
300+
waitForEditableState(pageView, true, 10000)
301+
);
302+
}
303+
304+
@Test
305+
public void testDOCXEditMode() throws InterruptedException {
306+
File testFile = s_testFiles.get("style-various-1.docx");
307+
Assert.assertNotNull(testFile);
308+
MainActivity activity = mainActivityActivityTestRule.getActivity();
309+
DocumentFragment documentFragment = loadDocument(activity, testFile);
310+
enterEditMode(activity, documentFragment);
311+
312+
PageView pageView = documentFragment.getPageView();
313+
Assert.assertNotNull(pageView);
314+
315+
Assert.assertTrue(
316+
"DOCX should become editable after entering edit mode",
317+
waitForEditableState(pageView, true, 10000)
318+
);
319+
}
320+
321+
private DocumentFragment loadDocument(MainActivity activity, File testFile) throws InterruptedException {
322+
Context appCtx = InstrumentationRegistry.getInstrumentation().getTargetContext();
323+
Uri testFileUri = FileProvider.getUriForFile(appCtx, appCtx.getPackageName() + ".provider", testFile);
324+
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> activity.loadUri(testFileUri));
325+
326+
DocumentFragment fragment = waitForDocumentFragment(activity, 10000);
327+
Assert.assertNotNull(fragment);
328+
Assert.assertTrue("Timed out waiting for document to load", waitForLastResult(fragment, 10000));
329+
return fragment;
330+
}
331+
332+
private DocumentFragment waitForDocumentFragment(MainActivity activity, long timeoutMs)
333+
throws InterruptedException {
334+
long startMs = SystemClock.elapsedRealtime();
335+
DocumentFragment fragment;
336+
do {
337+
fragment = (DocumentFragment) activity.getSupportFragmentManager()
338+
.findFragmentByTag("document_fragment");
339+
if (fragment != null) {
340+
return fragment;
341+
}
342+
SystemClock.sleep(100);
343+
} while (SystemClock.elapsedRealtime() - startMs < timeoutMs);
344+
return null;
345+
}
346+
347+
private boolean waitForLastResult(DocumentFragment fragment, long timeoutMs) throws InterruptedException {
348+
long startMs = SystemClock.elapsedRealtime();
349+
while (SystemClock.elapsedRealtime() - startMs < timeoutMs) {
350+
if (fragment.hasLastResult()) {
351+
return true;
352+
}
353+
SystemClock.sleep(100);
354+
}
355+
return false;
356+
}
357+
358+
private void enterEditMode(MainActivity activity, DocumentFragment documentFragment) {
359+
AtomicReference<Boolean> started = new AtomicReference<>(false);
360+
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
361+
started.set(activity.startSupportActionMode(
362+
new EditActionModeCallback(activity, documentFragment)) != null);
363+
});
364+
Assert.assertTrue("Failed to enter edit mode", started.get());
365+
}
366+
367+
private boolean waitForEditableState(PageView pageView, boolean expected, long timeoutMs)
368+
throws InterruptedException {
369+
long startMs = SystemClock.elapsedRealtime();
370+
while (SystemClock.elapsedRealtime() - startMs < timeoutMs) {
371+
if (expected == isEditableDom(pageView)) {
372+
return true;
373+
}
374+
SystemClock.sleep(250);
375+
}
376+
return false;
377+
}
378+
379+
private boolean waitForNonEditableState(PageView pageView, long timeoutMs) throws InterruptedException {
380+
long startMs = SystemClock.elapsedRealtime();
381+
while (SystemClock.elapsedRealtime() - startMs < timeoutMs) {
382+
if (isEditableDom(pageView)) {
383+
return false;
384+
}
385+
SystemClock.sleep(250);
386+
}
387+
return true;
388+
}
389+
390+
private boolean isEditableDom(PageView pageView) throws InterruptedException {
391+
String result = evaluateJavascript(pageView,
392+
"(function(){"
393+
+ "var bodyEditable = document.body && document.body.isContentEditable;"
394+
+ "var editableNode = document.querySelector('[contenteditable=\"true\"], [contenteditable=\"plaintext-only\"]');"
395+
+ "return !!(bodyEditable || editableNode);"
396+
+ "})()");
397+
if (result == null) {
398+
return false;
399+
}
400+
String normalized = result.replace("\"", "");
401+
return "true".equalsIgnoreCase(normalized);
402+
}
403+
404+
private String evaluateJavascript(PageView pageView, String script) throws InterruptedException {
405+
AtomicReference<String> result = new AtomicReference<>();
406+
CountDownLatch latch = new CountDownLatch(1);
407+
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
408+
pageView.evaluateJavascript(script, value -> {
409+
result.set(value);
410+
latch.countDown();
411+
});
412+
});
413+
if (!latch.await(10, TimeUnit.SECONDS)) {
414+
Assert.fail("Timed out waiting for JS evaluation result");
415+
}
416+
return result.get();
417+
}
280418
}

0 commit comments

Comments
 (0)