Skip to content

Commit 59cd97e

Browse files
rtibblesbotclaude
andcommitted
Cover the onStart thaw, and put robolectric.properties where Gradle looks
The freeze suite passed with the onStart thaw deleted, so the branch of it that matters was untested: ShadowWebView's pause/resume flags are sticky, so `onStart_thawsTheWebView_whenTheServerIsAlreadyReady` set serverReady after stopping the activity and was served by the observer re-delivering a changed value — the same path the test below it already covered. The case only onStart can reach is an *unchanged* value, which LiveData does not re-deliver. A shadow subclass records the pause/resume order, so that case now asserts resume, pause, resume: the observer's thaw when the server first came up, the freeze, then the thaw from onStart with serverReady untouched throughout. Verified to fail when the onStart branch is removed. robolectric.properties moves to src/test/resources, the source set Gradle already puts on the test runtime classpath, so it needs no build.gradle entry. Nothing under src/test/resources reads as a test. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent 0437f02 commit 59cd97e

3 files changed

Lines changed: 47 additions & 17 deletions

File tree

platforms/android/app/build.gradle

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -260,11 +260,6 @@ android {
260260
exclude "tests/**"
261261
}
262262
}
263-
test {
264-
// Robolectric reads robolectric.properties off the test runtime classpath, so its
265-
// configuration can live outside src/test — where it would read as a test itself.
266-
resources.srcDir "robolectric"
267-
}
268263
}
269264
}
270265

platforms/android/app/src/test/java/org/learningequality/Kolibri/WebViewActivityTest.java

Lines changed: 47 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
package org.learningequality.Kolibri;
22

3+
import static java.util.Arrays.asList;
34
import static org.junit.Assert.assertEquals;
4-
import static org.junit.Assert.assertFalse;
5-
import static org.junit.Assert.assertTrue;
65
import static org.mockito.Mockito.mock;
76
import static org.mockito.Mockito.when;
87
import static org.robolectric.Shadows.shadowOf;
@@ -12,15 +11,22 @@
1211
import android.webkit.WebResourceRequest;
1312
import android.webkit.WebView;
1413
import android.webkit.WebViewClient;
14+
import java.util.ArrayList;
15+
import java.util.List;
1516
import org.junit.After;
1617
import org.junit.Before;
1718
import org.junit.Test;
1819
import org.junit.runner.RunWith;
1920
import org.robolectric.Robolectric;
2021
import org.robolectric.RobolectricTestRunner;
2122
import org.robolectric.android.controller.ActivityController;
23+
import org.robolectric.annotation.Config;
24+
import org.robolectric.annotation.Implementation;
25+
import org.robolectric.annotation.Implements;
26+
import org.robolectric.shadows.ShadowWebView;
2227

2328
@RunWith(RobolectricTestRunner.class)
29+
@Config(shadows = WebViewActivityTest.FreezeRecordingWebView.class)
2430
public class WebViewActivityTest {
2531
private static final String PAGE_URL = "http://127.0.0.1:46655/en/facility/#/data/import";
2632
private static final String SAME_ORIGIN_INITIALIZE_URL =
@@ -33,6 +39,7 @@ public class WebViewActivityTest {
3339

3440
@Before
3541
public void setUp() {
42+
FreezeRecordingWebView.freezeCalls.clear();
3643
controller = Robolectric.buildActivity(WebViewActivity.class).setup();
3744
webView = controller.get().findViewById(R.id.webview);
3845
}
@@ -47,21 +54,26 @@ public void tearDown() {
4754
}
4855

4956
@Test
50-
public void onStop_pausesTheWebView() {
57+
public void onStop_freezesTheWebView() {
5158
controller.stop();
5259

53-
assertTrue(shadowOf(webView).wasOnPauseCalled());
60+
assertEquals(asList("pause"), FreezeRecordingWebView.freezeCalls);
5461
}
5562

63+
/**
64+
* The common case, and the one the idle stop does not reach: the app was backgrounded for less
65+
* than the idle timeout, so serverReady never changed. LiveData does not re-deliver an unchanged
66+
* value to an observer returning to STARTED, so onStart itself has to thaw the page — the leading
67+
* resume here is the observer's, at the point the server first came up.
68+
*/
5669
@Test
57-
public void onStart_thawsTheWebView_whenTheServerIsAlreadyReady() {
58-
controller.stop();
59-
70+
public void onStart_thawsTheWebView_whenTheServerNeverWentAway() {
6071
KolibriServerViewModel.getInstance().setServerReady(true);
6172
shadowOf(Looper.getMainLooper()).idle();
62-
controller.start();
6373

64-
assertTrue(shadowOf(webView).wasOnResumeCalled());
74+
controller.stop().start();
75+
76+
assertEquals(asList("resume", "pause", "resume"), FreezeRecordingWebView.freezeCalls);
6577
}
6678

6779
/**
@@ -71,12 +83,12 @@ public void onStart_thawsTheWebView_whenTheServerIsAlreadyReady() {
7183
@Test
7284
public void theObserver_thawsTheWebView_whenTheServerComesBackAfterTheActivityHasStarted() {
7385
controller.stop().start();
74-
assertFalse(shadowOf(webView).wasOnResumeCalled());
86+
assertEquals(asList("pause"), FreezeRecordingWebView.freezeCalls);
7587

7688
KolibriServerViewModel.getInstance().setServerReady(true);
7789
shadowOf(Looper.getMainLooper()).idle();
7890

79-
assertTrue(shadowOf(webView).wasOnResumeCalled());
91+
assertEquals(asList("pause", "resume"), FreezeRecordingWebView.freezeCalls);
8092
}
8193

8294
@Test
@@ -145,4 +157,28 @@ private void failLoad(String url) {
145157
client.onReceivedError(webView, request, mock(WebResourceError.class));
146158
client.onPageFinished(webView, url);
147159
}
160+
161+
/**
162+
* ShadowWebView's pause/resume flags are sticky, so they cannot tell a thaw that happened before
163+
* the freeze from one that happened after — which is the whole question for the onStart gate.
164+
* Record the order instead.
165+
*/
166+
@Implements(WebView.class)
167+
public static class FreezeRecordingWebView extends ShadowWebView {
168+
static final List<String> freezeCalls = new ArrayList<>();
169+
170+
@Implementation
171+
@Override
172+
protected void onPause() {
173+
super.onPause();
174+
freezeCalls.add("pause");
175+
}
176+
177+
@Implementation
178+
@Override
179+
protected void onResume() {
180+
super.onResume();
181+
freezeCalls.add("resume");
182+
}
183+
}
148184
}

platforms/android/app/robolectric/robolectric.properties renamed to platforms/android/app/src/test/resources/robolectric.properties

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
# Robolectric configuration for the JVM unit tests, not a test itself.
21
# includeAndroidResources makes Robolectric honour android:name=".App" from the merged manifest,
32
# and App.onCreate calls Python.start(...), which throws UnsatisfiedLinkError on the JVM.
43
application=android.app.Application

0 commit comments

Comments
 (0)