@@ -38,201 +38,142 @@ internal class FullEnd2EndTest {
3838 @get:Rule
3939 val repeatRule = RepeatRule ()
4040
41+ private lateinit var device: UiDevice
42+
4143 @Before
4244 fun setUp () {
4345 logger.info(" Setting up test" )
44-
4546 Intents .init ()
47+ device = UiDevice .getInstance(InstrumentationRegistry .getInstrumentation())
4648
4749 val automation = InstrumentationRegistry .getInstrumentation().uiAutomation
4850 val info = automation.serviceInfo
4951 info.flags = info.flags or AccessibilityServiceInfo .FLAG_RETRIEVE_INTERACTIVE_WINDOWS
5052 automation.serviceInfo = info
5153 }
5254
53- /* *
54- * Executes an end-to-end test for the login functionality.
55- *
56- * It performs the following steps:
57- *
58- * 1. Clicks the login button.
59- * 2. Wait for the login form to appear.
60- * 3. Sets the username and password on the login form.
61- * 4. Submits the form by pressing the enter key.
62- * 5. Wait for the token activity to be displayed.
63- * 6. Checks the refresh token functionality.
64- * 7. Checks if the token was refreshed.
65- * 8. Clicks the sign-out button.
66- * 9. Wait for the login activity to be displayed.
67- *
68- * This test is repeated twice to ensure logout was successful and the login form is displayed again.
69- */
7055 @Test
7156 @Repeat(2 )
7257 fun e2eTest () {
73- logger.info(" Click login button" )
74- onView(withId(R .id.start_auth)).perform(click())
75- logger.info(" Login button clicked" )
76-
77- logger.info(" Waiting for login form to appear" )
78- val device = UiDevice .getInstance(InstrumentationRegistry .getInstrumentation())
79-
80- handleFALoginForm(device, USERNAME , PASSWORD )
81-
82- // Check that the token activity is displayed
83- device.wait(Until .findObject(By .res(" io.fusionauth.app:id/sign_out" )), TIMEOUT_MILLIS )
84- onView(withId(R .id.sign_out)).check(matches(isDisplayed()))
85-
86- logger.info(" Token activity displayed" )
87-
88- // Check refresh token functionality
89- val expirationTime = runBlocking { AuthorizationManager .getAccessTokenExpirationTime()!! }
90- logger.info(" Check refresh token" )
91- onView(withId(R .id.refresh_token))
92- .check(matches(isDisplayed()))
93- .perform(click())
94-
95- val newExpirationTime = runBlocking { AuthorizationManager .getAccessTokenExpirationTime()!! }
96-
97- logger.info(" Token was refreshed (${expirationTime} to ${newExpirationTime} )" )
98- check(newExpirationTime > expirationTime) { " Token was not refreshed" }
99-
100- Thread .sleep(1000 )
101-
102- // Click the sign-out button
103- logger.info(" Click sign out button" )
104- onView(withId(R .id.sign_out)).perform(click())
105-
106- // Check that the login activity is displayed
107- logger.info(" Check that the login activity is displayed" )
108- device.wait(Until .findObject(By .res(" io.fusionauth.app:id/start_auth" )), TIMEOUT_MILLIS )
109- onView(withId(R .id.start_auth)).check(matches(isDisplayed()))
110-
111- logger.info(" Click login button for second user login" )
112- onView(withId(R .id.start_auth)).perform(click())
113- logger.info(" Login button clicked" )
114-
115- logger.info(" Waiting for login form to appear" )
116-
117- handleFALoginForm(device, USERNAME2 , PASSWORD2 )
118-
119- // Check that the token activity is displayed
120- device.wait(Until .findObject(By .res(" io.fusionauth.app:id/sign_out" )), TIMEOUT_MILLIS )
121- onView(withId(R .id.sign_out)).check(matches(isDisplayed()))
122-
123- logger.info(" Token activity displayed for second user" )
58+ login(USERNAME , PASSWORD )
59+ performAndVerifyTokenRefresh()
60+ logout()
61+ login(USERNAME2 , PASSWORD2 )
62+ logout()
63+ }
12464
125- // Click the sign-out button
126- logger.info(" Click sign out button for second user" )
127- onView(withId(R .id.sign_out)).perform(click())
65+ @Test
66+ fun e2eTestSwitchFromPrimaryToAlternative () {
67+ login(USERNAME , PASSWORD )
68+ switchToAlternative()
69+ login(USERNAME_RESET_CONFIGURATION , PASSWORD_RESET_CONFIGURATION )
70+ logout()
71+ loginSessionExists(USERNAME )
72+ logout()
73+ }
12874
129- // Check that the login activity is displayed
130- logger.info(" Check that the login activity is displayed" )
131- device.wait(Until .findObject(By .res(" io.fusionauth.app:id/start_auth" )), TIMEOUT_MILLIS )
132- onView(withId(R .id.start_auth)).check(matches(isDisplayed()))
75+ @Test
76+ fun e2eTestSwitchFromAlternativeToPrimary () {
77+ login(USERNAME , PASSWORD )
78+ switchToAlternative()
79+ login(USERNAME_RESET_CONFIGURATION , PASSWORD_RESET_CONFIGURATION )
80+ switchToPrimary()
81+ loginSessionExists(USERNAME )
82+ switchToAlternative()
83+ loginSessionExists(USERNAME_RESET_CONFIGURATION )
84+ logout()
85+ loginSessionExists(USERNAME )
86+ logout()
13387 }
13488
135- /* *
136- * Executes an end-to-end test for the login functionality where the configuration is reset to login
137- * to a different tenant. It performs the following steps:
138- * 1. Clicks the login button.
139- * 2. Waits for the login form to appear.
140- * 3. Sets the username and password on the login form.
141- * 4. Submits the form by pressing the enter key.
142- * 5. Waits for the token activity to be displayed.
143- * 6. Checks the reset configuration functionality.
144- * 7. Waits for the login activity to be displayed.
145- * 8. Clicks the login button.
146- * 9. Waits for the login form to appear.
147- * 10. Sets the username and password on the login form.
148- * 11. Submits the form by pressing the enter key.
149- * 12. Checks the refresh token functionality.
150- * 13. Checks if the token was refreshed.
151- * 14. Clicks the sign-out button.
152- * 15. Waits for the login activity to be displayed.
153- */
15489 @Test
155- fun e2eTestResetConfiguration () {
156- logger.info(" Click login button" )
157- onView(withId(R .id.start_auth)).perform(click())
158- logger.info(" Login button clicked" )
90+ fun e2eTestCancelConfigurationSwitch () {
91+ login(USERNAME , PASSWORD )
15992
160- logger.info(" Waiting for login form to appear" )
161- val device = UiDevice .getInstance(InstrumentationRegistry .getInstrumentation())
93+ val expirationTimeBefore = runBlocking { AuthorizationManager .getAccessTokenExpirationTime()!! }
16294
163- handleFALoginForm(device, USERNAME , PASSWORD )
95+ logger.info(" Click reset configuration" )
96+ onView(withId(R .id.reset_configuration)).perform(click())
97+ logger.info(" Click cancel button on dialog" )
98+ onView(withId(R .id.cancel_button)).perform(click())
16499
165- // Check that the token activity is displayed
166- device.wait(Until .findObject(By .res(" io.fusionauth.app:id/sign_out" )), TIMEOUT_MILLIS )
167- onView(withId(R .id.sign_out)).check(matches(isDisplayed()))
100+ verifyOnTokenActivity()
168101
169- logger.info(" Token activity displayed" )
102+ logger.info(" Click refresh token to confirm session is active" )
103+ onView(withId(R .id.refresh_token)).perform(click())
104+ val expirationTimeAfter = runBlocking { AuthorizationManager .getAccessTokenExpirationTime()!! }
105+ check(expirationTimeAfter > expirationTimeBefore) { " Token was not refreshed after canceling config switch" }
170106
171- // Check reset configuration functionality
172- logger.info(" Check reset configuration" )
173- onView(withId(R .id.reset_configuration))
174- .check(matches(isDisplayed()))
175- .perform(click())
107+ logout()
108+ }
176109
177- // Check that the login activity is displayed
178- logger.info(" Check that the login activity is displayed" )
179- device.wait(Until .findObject(By .res(" io.fusionauth.app:id/start_auth" )), TIMEOUT_MILLIS )
180- onView(withId(R .id.start_auth)).check(matches(isDisplayed()))
110+ // Helper Functions
181111
182- logger.info(" Click login button for user login" )
112+ private fun login (username : String , password : String ) {
113+ logger.info(" --> login(username: $username )" )
183114 onView(withId(R .id.start_auth)).perform(click())
184- logger.info(" Login button clicked" )
185-
186- logger.info(" Waiting for login form to appear" )
187-
188- handleFALoginForm(device, USERNAME_RESET_CONFIGURATION , PASSWORD_RESET_CONFIGURATION )
189-
190- // Check that the token activity is displayed
191- device.wait(Until .findObject(By .res(" io.fusionauth.app:id/sign_out" )), TIMEOUT_MILLIS )
192- onView(withId(R .id.sign_out)).check(matches(isDisplayed()))
115+ handleFALoginForm(username, password)
116+ verifyOnTokenActivity()
117+ logger.info(" <-- login" )
118+ }
193119
194- logger.info(" Token activity displayed for user in reset configuration tenant" )
120+ private fun loginSessionExists (username : String ) {
121+ logger.info(" --> login(username: $username )" )
122+ onView(withId(R .id.start_auth)).perform(click())
123+ verifyOnTokenActivity()
124+ logger.info(" <-- login" )
125+ }
126+ private fun logout () {
127+ logger.info(" --> logout()" )
128+ onView(withId(R .id.sign_out)).perform(click())
129+ verifyOnLoginActivity()
130+ logger.info(" <-- logout()" )
131+ }
195132
196- // Check refresh token functionality
133+ private fun performAndVerifyTokenRefresh () {
134+ logger.info(" --> performAndVerifyTokenRefresh()" )
197135 val expirationTime = runBlocking { AuthorizationManager .getAccessTokenExpirationTime()!! }
198- logger.info(" Check refresh token" )
199136 onView(withId(R .id.refresh_token))
200137 .check(matches(isDisplayed()))
201138 .perform(click())
202-
203139 val newExpirationTime = runBlocking { AuthorizationManager .getAccessTokenExpirationTime()!! }
204-
205140 logger.info(" Token was refreshed (${expirationTime} to ${newExpirationTime} )" )
206141 check(newExpirationTime > expirationTime) { " Token was not refreshed" }
142+ Thread .sleep(1000 ) // Wait a bit for UI to settle
143+ logger.info(" <-- performAndVerifyTokenRefresh()" )
144+ }
207145
208- Thread .sleep(1000 )
146+ private fun switchToAlternative () {
147+ logger.info(" --> switchToAlternative()" )
148+ onView(withId(R .id.reset_configuration)).perform(click())
149+ onView(withId(R .id.switch_to_alternative_button)).perform(click())
150+ verifyOnLoginActivity()
151+ logger.info(" <-- switchToAlternative()" )
152+ }
209153
210- // Click the sign-out button
211- logger.info(" Click sign out button for user" )
212- onView(withId(R .id.sign_out)).perform(click())
154+ private fun switchToPrimary () {
155+ logger.info(" --> switchToPrimary()" )
156+ onView(withId(R .id.reset_configuration)).perform(click())
157+ onView(withId(R .id.switch_to_primary_button)).perform(click())
158+ verifyOnLoginActivity()
159+ logger.info(" <-- switchToPrimary()" )
160+ }
161+
162+ private fun verifyOnTokenActivity () {
163+ device.wait(Until .findObject(By .res(" io.fusionauth.app:id/sign_out" )), TIMEOUT_MILLIS )
164+ onView(withId(R .id.sign_out)).check(matches(isDisplayed()))
165+ logger.info(" Verified on TokenActivity" )
166+ }
213167
214- // Check that the login activity is displayed
215- logger.info(" Check that the login activity is displayed" )
168+ private fun verifyOnLoginActivity () {
216169 device.wait(Until .findObject(By .res(" io.fusionauth.app:id/start_auth" )), TIMEOUT_MILLIS )
217170 onView(withId(R .id.start_auth)).check(matches(isDisplayed()))
171+ logger.info(" Verified on LoginActivity" )
218172 }
219173
220- /* *
221- * Sets the username and password on the login form.
222- *
223- * @param device The UiDevice used to interact with the UI.
224- * @param username The username to set on the login form.
225- * @param password The password to set on the login form.
226- */
227- private fun handleFALoginForm (
228- device : UiDevice ,
229- username : String ,
230- password : String
231- ) {
232- device.wait(
233- Until .findObject(By .clazz(" android.webkit.WebView" )),
234- TIMEOUT_MILLIS
235- )
174+ private fun handleFALoginForm (username : String , password : String ) {
175+ device.wait(Until .findObject(By .clazz(" android.webkit.WebView" )),
176+ TIMEOUT_MILLIS )
236177
237178 val textFields = device.findObjects(By .clazz(" android.widget.EditText" ))
238179
@@ -246,25 +187,16 @@ internal class FullEnd2EndTest {
246187 val passwordInputObject = textFields[1 ]
247188 passwordInputObject.setText(password)
248189
249- // Submit the form by pressing the enter key
250190 logger.info(" Submit form by pressing enter key" )
251191 passwordInputObject.click()
252192 device.pressEnter()
253193 }
254194
255- /* *
256- * Closes the keyboard if it is open on the screen.
257- *
258- * When the (automated test) device has a small vertical resolution, the keyboard may be open and cover the login
259- * form, thus preventing the UISelector from targeting the form fields.
260- *
261- * @throws IllegalStateException if the keyboard cannot be closed.
262- */
263195 private fun closeKeyboardIfOpen () {
264196 val automation = InstrumentationRegistry .getInstrumentation().uiAutomation
265197 for (window in automation.windows) {
266198 if (window.type == AccessibilityWindowInfo .TYPE_INPUT_METHOD ) {
267- UiDevice .getInstance( InstrumentationRegistry .getInstrumentation()) .pressBack()
199+ device .pressBack()
268200 return
269201 }
270202 }
@@ -273,7 +205,7 @@ internal class FullEnd2EndTest {
273205 @After
274206 fun tearDown () {
275207 logger.info(" Tearing down test" )
276-
208+ runBlocking { AuthorizationManager .clearState() }
277209 Intents .release()
278210 }
279211
0 commit comments