@@ -169,9 +169,21 @@ public function testViewApps(): void {
169169 ->method ('setActiveEntry ' )
170170 ->with ('core_apps ' );
171171
172+ // Test that developer docs link is generated correctly
173+ $ this ->urlGenerator
174+ ->expects ($ this ->once ())
175+ ->method ('linkToDocs ' )
176+ ->with ('developer-manual ' )
177+ ->willReturn ('https://docs.nextcloud.com/server/latest/developer_manual/ ' );
178+
172179 $ this ->initialState
173180 ->expects ($ this ->exactly (4 ))
174- ->method ('provideInitialState ' );
181+ ->method ('provideInitialState ' )
182+ ->willReturnCallback (function ($ key , $ value ) {
183+ if ($ key === 'appstoreDeveloperDocs ' ) {
184+ $ this ->assertEquals ('https://docs.nextcloud.com/server/latest/developer_manual/ ' , $ value );
185+ }
186+ });
175187
176188 $ policy = new ContentSecurityPolicy ();
177189 $ policy ->addAllowedImageDomain ('https://usercontent.apps.nextcloud.com ' );
@@ -202,9 +214,21 @@ public function testViewAppsAppstoreNotEnabled(): void {
202214 ->method ('setActiveEntry ' )
203215 ->with ('core_apps ' );
204216
217+ // Test that developer docs link is still generated even when appstore is disabled
218+ $ this ->urlGenerator
219+ ->expects ($ this ->once ())
220+ ->method ('linkToDocs ' )
221+ ->with ('developer-manual ' )
222+ ->willReturn ('https://docs.nextcloud.com/server/latest/developer_manual/ ' );
223+
205224 $ this ->initialState
206225 ->expects ($ this ->exactly (4 ))
207- ->method ('provideInitialState ' );
226+ ->method ('provideInitialState ' )
227+ ->willReturnCallback (function ($ key , $ value ) {
228+ if ($ key === 'appstoreDeveloperDocs ' ) {
229+ $ this ->assertEquals ('https://docs.nextcloud.com/server/latest/developer_manual/ ' , $ value );
230+ }
231+ });
208232
209233 $ policy = new ContentSecurityPolicy ();
210234 $ policy ->addAllowedImageDomain ('https://usercontent.apps.nextcloud.com ' );
@@ -219,4 +243,93 @@ public function testViewAppsAppstoreNotEnabled(): void {
219243
220244 $ this ->assertEquals ($ expected , $ this ->appSettingsController ->viewApps ());
221245 }
246+
247+ public function testDeveloperDocumentationLinkIsProvided (): void {
248+ $ this ->installer ->expects ($ this ->any ())
249+ ->method ('isUpdateAvailable ' )
250+ ->willReturn (false );
251+ $ this ->bundleFetcher ->expects ($ this ->once ())->method ('getBundles ' )->willReturn ([]);
252+ $ this ->config
253+ ->expects ($ this ->once ())
254+ ->method ('getSystemValueBool ' )
255+ ->with ('appstoreenabled ' , true )
256+ ->willReturn (true );
257+ $ this ->navigationManager
258+ ->expects ($ this ->once ())
259+ ->method ('setActiveEntry ' )
260+ ->with ('core_apps ' );
261+
262+ $ developerDocsUrl = 'https://docs.nextcloud.com/server/latest/developer_manual/ ' ;
263+
264+ // Verify that linkToDocs is called with 'developer-manual'
265+ $ this ->urlGenerator
266+ ->expects ($ this ->once ())
267+ ->method ('linkToDocs ' )
268+ ->with ('developer-manual ' )
269+ ->willReturn ($ developerDocsUrl );
270+
271+ // Verify that the developer docs URL is provided to initial state
272+ $ providedStates = [];
273+ $ this ->initialState
274+ ->expects ($ this ->exactly (4 ))
275+ ->method ('provideInitialState ' )
276+ ->willReturnCallback (function ($ key , $ value ) use (&$ providedStates ) {
277+ $ providedStates [$ key ] = $ value ;
278+ });
279+
280+ $ this ->appSettingsController ->viewApps ();
281+
282+ // Assert that the developer docs state was provided with the correct URL
283+ $ this ->assertArrayHasKey ('appstoreDeveloperDocs ' , $ providedStates );
284+ $ this ->assertEquals ($ developerDocsUrl , $ providedStates ['appstoreDeveloperDocs ' ]);
285+ }
286+
287+ /**
288+ * @dataProvider developerDocsUrlProvider
289+ */
290+ public function testDeveloperDocumentationLinkWithDifferentUrls (string $ expectedUrl ): void {
291+ $ this ->installer ->expects ($ this ->any ())
292+ ->method ('isUpdateAvailable ' )
293+ ->willReturn (false );
294+ $ this ->bundleFetcher ->expects ($ this ->once ())->method ('getBundles ' )->willReturn ([]);
295+ $ this ->config
296+ ->expects ($ this ->once ())
297+ ->method ('getSystemValueBool ' )
298+ ->with ('appstoreenabled ' , true )
299+ ->willReturn (true );
300+ $ this ->navigationManager
301+ ->expects ($ this ->once ())
302+ ->method ('setActiveEntry ' )
303+ ->with ('core_apps ' );
304+
305+ // Test with different potential URL formats
306+ $ this ->urlGenerator
307+ ->expects ($ this ->once ())
308+ ->method ('linkToDocs ' )
309+ ->with ('developer-manual ' )
310+ ->willReturn ($ expectedUrl );
311+
312+ $ providedStates = [];
313+ $ this ->initialState
314+ ->expects ($ this ->exactly (4 ))
315+ ->method ('provideInitialState ' )
316+ ->willReturnCallback (function ($ key , $ value ) use (&$ providedStates ) {
317+ $ providedStates [$ key ] = $ value ;
318+ });
319+
320+ $ this ->appSettingsController ->viewApps ();
321+
322+ $ this ->assertArrayHasKey ('appstoreDeveloperDocs ' , $ providedStates );
323+ $ this ->assertEquals ($ expectedUrl , $ providedStates ['appstoreDeveloperDocs ' ]);
324+ }
325+
326+ public function developerDocsUrlProvider (): array {
327+ return [
328+ 'standard URL ' => ['https://docs.nextcloud.com/server/latest/developer_manual/ ' ],
329+ 'versioned URL ' => ['https://docs.nextcloud.com/server/28/developer_manual/ ' ],
330+ 'custom domain ' => ['https://custom-docs.example.com/developer/ ' ],
331+ 'relative URL ' => ['/docs/developer-manual ' ],
332+ 'with anchor ' => ['https://docs.nextcloud.com/server/latest/developer_manual/#getting-started ' ],
333+ ];
334+ }
222335}
0 commit comments