44 */
55
66import { randomString } from '../../support/utils/randomString.ts'
7+ import { handlePasswordConfirmation } from '../core-utils.ts'
8+
9+ type RecommendedAppsMode = 'skip' | 'install-success' | 'install-failure'
710
811/**
912 * DO NOT RENAME THIS FILE to .cy.ts ⚠️
@@ -30,6 +33,22 @@ describe('Can install Nextcloud', { testIsolation: true, retries: 0 }, () => {
3033 sharedSetup ( )
3134 } )
3235
36+ it ( 'Sqlite - Install recommended apps (success)' , ( ) => {
37+ cy . visit ( '/' )
38+ cy . get ( '[data-cy-setup-form]' ) . should ( 'be.visible' )
39+ cy . get ( '[data-cy-setup-form-field="dbtype-sqlite"] input' ) . check ( { force : true } )
40+
41+ sharedSetup ( 'install-success' )
42+ } )
43+
44+ it ( 'Sqlite - Install recommended apps (failure)' , ( ) => {
45+ cy . visit ( '/' )
46+ cy . get ( '[data-cy-setup-form]' ) . should ( 'be.visible' )
47+ cy . get ( '[data-cy-setup-form-field="dbtype-sqlite"] input' ) . check ( { force : true } )
48+
49+ sharedSetup ( 'install-failure' )
50+ } )
51+
3352 it ( 'MySQL' , ( ) => {
3453 cy . visit ( '/' )
3554 cy . get ( '[data-cy-setup-form]' ) . should ( 'be.visible' )
@@ -110,8 +129,12 @@ describe('Can install Nextcloud', { testIsolation: true, retries: 0 }, () => {
110129
111130/**
112131 * Shared admin setup function for the Nextcloud setup
132+ *
133+ * @param mode How to handle the recommended apps screen at the end of the
134+ * install assistant: skip it, exercise the install button with a
135+ * stubbed success response, or stub a failure response.
113136 */
114- function sharedSetup ( ) {
137+ function sharedSetup ( mode : RecommendedAppsMode = 'skip' ) {
115138 const randAdmin = 'admin-' + randomString ( 10 )
116139
117140 // mock appstore
@@ -140,10 +163,41 @@ function sharedSetup() {
140163 . should ( 'be.visible' )
141164 } )
142165
143- // Skip the setup apps
144- cy . get ( '[data-cy-setup-recommended-apps-skip]' ) . click ( )
166+ if ( mode === 'skip' ) {
167+ // Skip the setup apps
168+ cy . get ( '[data-cy-setup-recommended-apps-skip]' ) . click ( )
145169
146- // Go to files
147- cy . visit ( '/apps/files/' )
148- cy . get ( '[data-cy-files-content]' ) . should ( 'be.visible' )
170+ // Go to files
171+ cy . visit ( '/apps/files/' )
172+ cy . get ( '[data-cy-files-content]' ) . should ( 'be.visible' )
173+ return
174+ }
175+
176+ // Stub the bulk enable endpoint so we exercise the frontend flow without
177+ // hitting the real app store.
178+ cy . intercept ( 'POST' , '**/settings/apps/enable' , mode === 'install-success'
179+ ? { statusCode : 200 , body : { data : { update_required : false } } }
180+ : { statusCode : 500 , body : { data : { message : 'Forced failure' } } } ) . as ( 'enableApps' )
181+
182+ cy . get ( '[data-cy-setup-recommended-apps-install]' ) . click ( )
183+
184+ // The strict password-confirmation dialog must appear and must result in a
185+ // Basic auth header on the enable request.
186+ cy . findByRole ( 'dialog' , { name : 'Authentication required' } )
187+ . should ( 'be.visible' )
188+ handlePasswordConfirmation ( randAdmin )
189+ cy . wait ( '@enableApps' )
190+ . its ( 'request.headers.authorization' )
191+ . should ( 'match' , / ^ B a s i c / )
192+
193+ if ( mode === 'install-success' ) {
194+ // Frontend redirects via window.location to the default page.
195+ cy . location ( 'pathname' , { timeout : 10000 } )
196+ . should ( 'not.include' , '/core/apps/recommended' )
197+ } else {
198+ // Stay on the recommended-apps page and surface the per-app error state.
199+ cy . location ( 'pathname' ) . should ( 'include' , '/core/apps/recommended' )
200+ cy . get ( '[data-cy-setup-recommended-apps]' )
201+ . should ( 'contain.text' , 'App download or installation failed' )
202+ }
149203}
0 commit comments