@@ -47,6 +47,13 @@ vi.mock("@src/components/settings/SettingsView", () => ({
4747 } ,
4848} ) )
4949
50+ vi . mock ( "@src/components/welcome/WelcomeViewProvider" , ( ) => ( {
51+ __esModule : true ,
52+ default : function WelcomeView ( ) {
53+ return < div data-testid = "welcome-view" > Welcome View</ div >
54+ } ,
55+ } ) )
56+
5057vi . mock ( "@src/components/history/HistoryView" , ( ) => ( {
5158 __esModule : true ,
5259 default : function HistoryView ( { onDone } : { onDone : ( ) => void } ) {
@@ -181,6 +188,15 @@ describe("App", () => {
181188 window . dispatchEvent ( messageEvent )
182189 }
183190
191+ const createSetupIncompleteState = ( ) => ( {
192+ didHydrateState : true ,
193+ showWelcome : true ,
194+ shouldShowAnnouncement : false ,
195+ experiments : { } ,
196+ language : "en" ,
197+ telemetrySetting : "enabled" ,
198+ } )
199+
184200 it ( "shows chat view by default" , ( ) => {
185201 render ( < AppWithProviders /> )
186202
@@ -189,6 +205,22 @@ describe("App", () => {
189205 expect ( chatView . getAttribute ( "data-hidden" ) ) . toBe ( "false" )
190206 } , 10000 )
191207
208+ it ( "shows welcome view when setup is incomplete" , ( ) => {
209+ mockUseExtensionState . mockReturnValue ( {
210+ didHydrateState : true ,
211+ showWelcome : true ,
212+ shouldShowAnnouncement : false ,
213+ experiments : { } ,
214+ language : "en" ,
215+ telemetrySetting : "enabled" ,
216+ } )
217+
218+ render ( < AppWithProviders /> )
219+
220+ expect ( screen . getByTestId ( "welcome-view" ) ) . toBeInTheDocument ( )
221+ expect ( screen . queryByTestId ( "settings-view" ) ) . not . toBeInTheDocument ( )
222+ } )
223+
192224 it ( "switches to settings view when receiving settingsButtonClicked action" , async ( ) => {
193225 render ( < AppWithProviders /> )
194226
@@ -203,6 +235,166 @@ describe("App", () => {
203235 expect ( chatView . getAttribute ( "data-hidden" ) ) . toBe ( "true" )
204236 } )
205237
238+ it . each ( [
239+ [ "settings" , "settings-view" ] ,
240+ [ "marketplace" , "marketplace-view" ] ,
241+ ] ) ( "still switches to %s while welcome gating is active" , async ( action , testId ) => {
242+ mockUseExtensionState . mockReturnValue ( {
243+ didHydrateState : true ,
244+ showWelcome : true ,
245+ shouldShowAnnouncement : false ,
246+ experiments : { } ,
247+ language : "en" ,
248+ telemetrySetting : "enabled" ,
249+ } )
250+
251+ render ( < AppWithProviders /> )
252+
253+ act ( ( ) => {
254+ triggerMessage ( `${ action } ButtonClicked` )
255+ } )
256+
257+ expect ( await screen . findByTestId ( testId ) ) . toBeInTheDocument ( )
258+ expect ( screen . queryByTestId ( "welcome-view" ) ) . not . toBeInTheDocument ( )
259+ } )
260+
261+ it ( "keeps history behind the welcome gate while setup is incomplete" , ( ) => {
262+ mockUseExtensionState . mockReturnValue ( {
263+ didHydrateState : true ,
264+ showWelcome : true ,
265+ shouldShowAnnouncement : false ,
266+ experiments : { } ,
267+ language : "en" ,
268+ telemetrySetting : "enabled" ,
269+ } )
270+
271+ render ( < AppWithProviders /> )
272+
273+ act ( ( ) => {
274+ triggerMessage ( "historyButtonClicked" )
275+ } )
276+
277+ expect ( screen . getByTestId ( "welcome-view" ) ) . toBeInTheDocument ( )
278+ expect ( screen . queryByTestId ( "history-view" ) ) . not . toBeInTheDocument ( )
279+ } )
280+
281+ it . each ( [
282+ { label : "chat" , action : undefined } ,
283+ { label : "history" , action : "historyButtonClicked" } ,
284+ ] ) ( "redirects to providers settings when an import fires from the $label tab" , async ( { action } ) => {
285+ const state = {
286+ ...createSetupIncompleteState ( ) ,
287+ settingsImportedAt : undefined as number | undefined ,
288+ }
289+
290+ mockUseExtensionState . mockImplementation ( ( ) => state )
291+
292+ const { rerender } = render ( < AppWithProviders /> )
293+
294+ if ( action ) {
295+ act ( ( ) => {
296+ triggerMessage ( action )
297+ } )
298+ }
299+
300+ if ( action === "historyButtonClicked" ) {
301+ expect ( screen . getByTestId ( "welcome-view" ) ) . toBeInTheDocument ( )
302+ }
303+
304+ state . settingsImportedAt = Date . now ( )
305+ rerender ( < AppWithProviders /> )
306+
307+ expect ( await screen . findByTestId ( "settings-view" ) ) . toBeInTheDocument ( )
308+ expect ( screen . queryByTestId ( "welcome-view" ) ) . not . toBeInTheDocument ( )
309+ } )
310+
311+ it . each ( [
312+ {
313+ label : "settings before returning to chat" ,
314+ action : "settingsButtonClicked" ,
315+ viewId : "settings-view" ,
316+ nextAction : undefined ,
317+ } ,
318+ {
319+ label : "settings before switching to history" ,
320+ action : "settingsButtonClicked" ,
321+ viewId : "settings-view" ,
322+ nextAction : "historyButtonClicked" ,
323+ } ,
324+ {
325+ label : "marketplace before returning to chat" ,
326+ action : "marketplaceButtonClicked" ,
327+ viewId : "marketplace-view" ,
328+ nextAction : undefined ,
329+ } ,
330+ {
331+ label : "marketplace before switching to history" ,
332+ action : "marketplaceButtonClicked" ,
333+ viewId : "marketplace-view" ,
334+ nextAction : "historyButtonClicked" ,
335+ } ,
336+ ] ) (
337+ "consumes imported settings without a later redirect when already on $label" ,
338+ async ( { action, viewId, nextAction } ) => {
339+ const state = {
340+ ...createSetupIncompleteState ( ) ,
341+ settingsImportedAt : undefined as number | undefined ,
342+ }
343+
344+ mockUseExtensionState . mockImplementation ( ( ) => state )
345+
346+ const { rerender } = render ( < AppWithProviders /> )
347+
348+ act ( ( ) => {
349+ triggerMessage ( action )
350+ } )
351+
352+ expect ( await screen . findByTestId ( viewId ) ) . toBeInTheDocument ( )
353+ expect ( screen . queryByTestId ( "welcome-view" ) ) . not . toBeInTheDocument ( )
354+
355+ state . settingsImportedAt = Date . now ( )
356+ rerender ( < AppWithProviders /> )
357+
358+ const currentView = await screen . findByTestId ( viewId )
359+ expect ( currentView ) . toBeInTheDocument ( )
360+
361+ if ( nextAction ) {
362+ act ( ( ) => {
363+ triggerMessage ( nextAction )
364+ } )
365+ } else {
366+ act ( ( ) => {
367+ currentView . click ( )
368+ } )
369+ }
370+
371+ expect ( screen . getByTestId ( "welcome-view" ) ) . toBeInTheDocument ( )
372+ expect ( screen . queryByTestId ( "settings-view" ) ) . not . toBeInTheDocument ( )
373+ expect ( screen . queryByTestId ( "marketplace-view" ) ) . not . toBeInTheDocument ( )
374+ } ,
375+ )
376+
377+ it ( "does not bounce back to settings after the import redirect has already fired" , async ( ) => {
378+ const importedAt = Date . now ( )
379+
380+ mockUseExtensionState . mockReturnValue ( {
381+ ...createSetupIncompleteState ( ) ,
382+ settingsImportedAt : importedAt ,
383+ } )
384+
385+ render ( < AppWithProviders /> )
386+
387+ const settingsView = await screen . findByTestId ( "settings-view" )
388+ expect ( settingsView ) . toBeInTheDocument ( )
389+
390+ act ( ( ) => {
391+ settingsView . click ( )
392+ } )
393+
394+ expect ( screen . getByTestId ( "welcome-view" ) ) . toBeInTheDocument ( )
395+ expect ( screen . queryByTestId ( "settings-view" ) ) . not . toBeInTheDocument ( )
396+ } )
397+
206398 it ( "switches to history view when receiving historyButtonClicked action" , async ( ) => {
207399 render ( < AppWithProviders /> )
208400
0 commit comments