@@ -19,8 +19,17 @@ export async function createRandomUser(): Promise<User> {
1919
2020/**
2121 * Helper to login on the Nextcloud instance
22+ *
23+ * Throws if the login did not actually succeed. A rejected Nextcloud login does
24+ * not return an error status: it answers `303` and redirects back to `./login`,
25+ * whereas a successful login redirects to the default app. Following the
26+ * redirect (the default) would collapse both cases into a `200`, letting a
27+ * failed login pass silently and only surface much later as a confusing `403`
28+ * on the first authenticated request. So we stop at the redirect and inspect it.
29+ *
2230 * @param request API request object
2331 * @param user The user to login
32+ * @throws If the credentials are rejected or the login redirect is unexpected
2433 */
2534export async function login (
2635 request : APIRequestContext ,
@@ -40,10 +49,15 @@ export async function login(
4049 headers : {
4150 Origin : tokenResponse . url ( ) . replace ( / i n d e x .p h p .* / , '' ) ,
4251 } ,
43- failOnStatusCode : true ,
52+ // Do not follow the redirect — its target tells us whether login succeeded
53+ maxRedirects : 0 ,
4454 } )
4555
46- const response = await request . get ( 'apps/files' , {
47- failOnStatusCode : true ,
48- } )
56+ const location = loginResponse . headers ( ) [ 'location' ] ?? ''
57+ if ( loginResponse . status ( ) !== 303 || / \/ l o g i n ( \? | $ ) / . test ( location ) ) {
58+ throw new Error (
59+ `Failed to login as "${ user . userId } ": expected a redirect away from the login page `
60+ + `but got status ${ loginResponse . status ( ) } redirecting to "${ location || '<none>' } "` ,
61+ )
62+ }
4963}
0 commit comments