diff --git a/android/app/src/androidTest/java/ai/elizaresearch/alphaphone/AppNavigation.java b/android/app/src/androidTest/java/ai/elizaresearch/alphaphone/AppNavigation.java index 5227d40cc..0a71309c2 100644 --- a/android/app/src/androidTest/java/ai/elizaresearch/alphaphone/AppNavigation.java +++ b/android/app/src/androidTest/java/ai/elizaresearch/alphaphone/AppNavigation.java @@ -6,7 +6,7 @@ final class AppNavigation { private AppNavigation() {} /** Decision P-43: there is no offline choice. The connection dialog's close button carries this * accessible name in every build. Signed out on a flag-off phone (or with a sign-in Cloud rejected) - * the dialog has no close button once the start settles: the Eliza Cloud sign-in is required. */ + * the dialog has no close button once the start settles: the Eliza Cloud sign-in page is required. */ static final String CLOSE_CONNECTION = "Close connection settings"; static String closeConnection() { return "document.querySelector('.alpha-connection-scrim button[aria-label=\"" + CLOSE_CONNECTION + "\"]')?.click()"; } static void liveMode() throws Exception { @@ -47,8 +47,8 @@ static void declineStartupAccess() throws Exception { } } /** - * Decision P-43: a flag-off build signed out of Eliza Cloud opens the "Your agent" sign-in dialog by - * itself, and it cannot be dismissed (connection-ui.tsx residentSignInRequired); it covers every view + * Decision P-43: a flag-off build signed out of Eliza Cloud opens the full-page sign-in screen by + * itself, and it cannot be dismissed (connection-ui.tsx productionCloudSignInRequired); it covers every view * and withdraws the native browser page. Tests never enter credentials, so a journey that needs the * views runs on the test-mocks pair, or on a flag-off phone its owner already signed in. Skips with * that reason instead of timing out behind the dialog. @@ -56,7 +56,7 @@ static void declineStartupAccess() throws Exception { static void assumeNoRequiredSignIn(String journey) throws Exception { if (BuildConfig.ELIZA_DEV_ALLOW_TEST_MOCKS) return; android.content.Context context = androidx.test.platform.app.InstrumentationRegistry.getInstrumentation().getTargetContext(); - org.junit.Assume.assumeTrue(journey + " needs the views: this flag-off build is signed out of Eliza Cloud, so P-43's sign-in dialog opens by itself and cannot be dismissed (tests never sign in). Run it on the test-mocks pair or on a flag-off phone its owner signed in.", + org.junit.Assume.assumeTrue(journey + " needs the views: this flag-off build is signed out of Eliza Cloud, so P-43's sign-in screen opens by itself and cannot be dismissed (tests never sign in). Run it on the test-mocks pair or on a flag-off phone its owner signed in.", new AlphaCredentialStore(context).readCredentialSlot("cloud:production") != null); } static String selected(String view) { return "document.documentElement.dataset.activeView==="+JSONObject.quote(view.toLowerCase()); } diff --git a/android/app/src/androidTest/java/ai/elizaresearch/alphaphone/BrowserFlowInstrumentedTest.java b/android/app/src/androidTest/java/ai/elizaresearch/alphaphone/BrowserFlowInstrumentedTest.java index b1cd6420c..9bb4de18f 100644 --- a/android/app/src/androidTest/java/ai/elizaresearch/alphaphone/BrowserFlowInstrumentedTest.java +++ b/android/app/src/androidTest/java/ai/elizaresearch/alphaphone/BrowserFlowInstrumentedTest.java @@ -17,6 +17,9 @@ /** Public HTTPS flow with real child WebViews. TLS verification is never bypassed. */ @RunWith(AndroidJUnit4.class) public class BrowserFlowInstrumentedTest { + @org.junit.Before public void requireSignedInViews() throws Exception { + AppNavigation.assumeNoRequiredSignIn("BrowserFlow journey"); + } private String host(String js)throws Exception{return WebViewTestDriver.evaluate(js);} private void until(String js)throws Exception{for(int i=0;i<150;i++){if("true".equals(host("Boolean("+js+")")))return;SystemClock.sleep(100);}fail("Browser control missing: "+js);} private void click(String label)throws Exception{String q="[...document.querySelectorAll('[data-screen] button')].find(e=>e.getAttribute('aria-label')==="+JSONObject.quote(label)+")";until(q);host("("+q+").click()");} diff --git a/android/app/src/androidTest/java/ai/elizaresearch/alphaphone/LauncherHomeInstrumentedTest.java b/android/app/src/androidTest/java/ai/elizaresearch/alphaphone/LauncherHomeInstrumentedTest.java index f1d7558da..2f3571c39 100644 --- a/android/app/src/androidTest/java/ai/elizaresearch/alphaphone/LauncherHomeInstrumentedTest.java +++ b/android/app/src/androidTest/java/ai/elizaresearch/alphaphone/LauncherHomeInstrumentedTest.java @@ -35,6 +35,9 @@ * emergency calling need a phone. */ @RunWith(AndroidJUnit4.class) public class LauncherHomeInstrumentedTest { + @org.junit.Before public void requireSignedInViews() throws Exception { + AppNavigation.assumeNoRequiredSignIn("LauncherHome journey"); + } private static final Pattern TOP = Pattern.compile("(?:topResumedActivity|mResumedActivity)[=:][^\\n]*?\\s([A-Za-z0-9_.]+)/"); private static void assumeAlphaIsHome() { diff --git a/android/app/src/androidTest/java/ai/elizaresearch/alphaphone/NoMockProductInstrumentedTest.java b/android/app/src/androidTest/java/ai/elizaresearch/alphaphone/NoMockProductInstrumentedTest.java index 17f7d5020..eff815a1a 100644 --- a/android/app/src/androidTest/java/ai/elizaresearch/alphaphone/NoMockProductInstrumentedTest.java +++ b/android/app/src/androidTest/java/ai/elizaresearch/alphaphone/NoMockProductInstrumentedTest.java @@ -32,18 +32,19 @@ private static void assertNoMockEntry()throws Exception{ until("document.querySelector('[data-screen]')"); String saved=NotesSecureFixture.evaluate("localStorage.getItem('"+SELECTION+"')"); try{ - // Open the connection chooser explicitly so every choice is rendered and inspected. + // A signed-out production install must render the required sign-in page. String previousDocument=NotesSecureFixture.evaluate("performance.timeOrigin"); WebViewTestDriver.navigateHostDocument("localStorage.removeItem('"+SELECTION+"');location.replace(location.origin+location.pathname)",true); - until("performance.timeOrigin!=="+previousDocument+"&&document.querySelector('.alpha-connection-scrim')"); + until("performance.timeOrigin!=="+previousDocument+"&&document.querySelector('.alpha-auth-page [role=main]')"); NotesSecureFixture.evaluate("document.querySelectorAll('.alpha-connection details').forEach(d=>d.open=true)"); + assertEquals("Required sign-in cannot be dismissed","false",NotesSecureFixture.evaluate("!!document.querySelector('.alpha-auth-page button[aria-label=\"Close connection settings\"]')")); assertNoMockEntry(); }finally{ WebViewTestDriver.navigateHostDocument("localStorage."+("null".equals(saved)?"removeItem('"+SELECTION+"')":"setItem('"+SELECTION+"',"+saved+")")+";location.replace(location.origin+location.pathname)",true); } } } - @Test public void legacyMockSelectionOpensTheChooser()throws Exception{ + @Test public void legacyMockSelectionRequiresSignIn()throws Exception{ Assume.assumeFalse("Test-mocks builds intentionally honour a mock selection",BuildConfig.ELIZA_DEV_ALLOW_TEST_MOCKS); try(BoundedActivityScenario scenario=BoundedActivityScenario.launch(MainActivity.class)){ until("document.querySelector('[data-screen]')"); @@ -51,9 +52,10 @@ private static void assertNoMockEntry()throws Exception{ try{ String previousDocument=NotesSecureFixture.evaluate("performance.timeOrigin"); WebViewTestDriver.navigateHostDocument("localStorage.setItem('"+SELECTION+"',JSON.stringify({kind:'mock'}));location.replace(location.origin+location.pathname)",true); - until("performance.timeOrigin!=="+previousDocument+"&&document.querySelector('.alpha-connection-scrim')"); - assertEquals("Underlying phone is inert while choosing","true",NotesSecureFixture.evaluate("document.querySelector('.os').inert")); + until("performance.timeOrigin!=="+previousDocument+"&&document.querySelector('.alpha-auth-page [role=main]')"); + assertEquals("Underlying phone is inert while sign-in is required","true",NotesSecureFixture.evaluate("document.querySelector('.os').inert")); assertNotEquals("Legacy mock selection is retired","\"mock\"",NotesSecureFixture.evaluate("JSON.parse(localStorage.getItem('"+SELECTION+"')||'null')?.kind??null")); + assertEquals("Required sign-in cannot be dismissed","false",NotesSecureFixture.evaluate("!!document.querySelector('.alpha-auth-page button[aria-label=\"Close connection settings\"]')")); assertNoMockEntry(); }finally{ WebViewTestDriver.navigateHostDocument("localStorage."+("null".equals(saved)?"removeItem('"+SELECTION+"')":"setItem('"+SELECTION+"',"+saved+")")+";location.replace(location.origin+location.pathname)",true); diff --git a/android/app/src/androidTest/java/ai/elizaresearch/alphaphone/SettingsRolesInstrumentedTest.java b/android/app/src/androidTest/java/ai/elizaresearch/alphaphone/SettingsRolesInstrumentedTest.java index 550b43e89..6b90db40c 100644 --- a/android/app/src/androidTest/java/ai/elizaresearch/alphaphone/SettingsRolesInstrumentedTest.java +++ b/android/app/src/androidTest/java/ai/elizaresearch/alphaphone/SettingsRolesInstrumentedTest.java @@ -23,6 +23,9 @@ */ @RunWith(AndroidJUnit4.class) public final class SettingsRolesInstrumentedTest { + @org.junit.Before public void requireSignedInViews() throws Exception { + AppNavigation.assumeNoRequiredSignIn("SettingsRoles journey"); + } private static final String HOME="android.app.role.HOME"; private final Context context=InstrumentationRegistry.getInstrumentation().getTargetContext(); private UiAutomation ui(){return InstrumentationRegistry.getInstrumentation().getUiAutomation();} diff --git a/android/app/src/androidTest/java/ai/elizaresearch/alphaphone/ShellInstrumentedTest.java b/android/app/src/androidTest/java/ai/elizaresearch/alphaphone/ShellInstrumentedTest.java index 0d8c2f09b..943fbc1f0 100644 --- a/android/app/src/androidTest/java/ai/elizaresearch/alphaphone/ShellInstrumentedTest.java +++ b/android/app/src/androidTest/java/ai/elizaresearch/alphaphone/ShellInstrumentedTest.java @@ -38,6 +38,11 @@ private String evaluate(BoundedActivityScenario scenario, String j Intent home = new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME).setPackage("ai.elizaresearch.alphaphone"); boolean qualifies = InstrumentationRegistry.getInstrumentation().getTargetContext().getPackageManager().queryIntentActivities(home,0).size()>0; assertEquals("HOME qualification follows variant",BuildConfig.IS_LAUNCHER,qualifies); + } + } + @Test public void signedInComposerAndNativeAppHandoffWork() throws Exception { + AppNavigation.assumeNoRequiredSignIn("Shell composer and native app handoff"); + try (BoundedActivityScenario scenario = BoundedActivityScenario.launch(MainActivity.class)) { AppNavigation.liveMode(); evaluate(scenario,AppNavigation.request("Home")); String homeReady="document.documentElement.dataset.activeView==='home'&&!document.querySelector('.alpha-connection-scrim')&&!document.querySelector('.os')?.inert";