* feat: enhance navigation overlay management - Add overlay tracking to NavigationStore with exception handling - Implement dismissAllOverlays with individual overlay dismissal - Add overlay management methods (add, remove, filter exceptions) - Preserve floating-banner-overlay when dismissing other overlays - Add comprehensive tests for overlay stack management - Update navigation command listeners for overlay events This improves overlay management by tracking overlays in the store and providing fine-grained control over which overlays to dismiss, particularly preserving floating banners during navigation cleanup. * make tests more meaningful in navigation * ChatGPT review fix * revert changes to dismissAllOverlays * create a new function dismissAllOverlaysWithExceptions * add new function removeAllOverlaysFromStack to clear the entire overlays * added a mock to dismissAllOverlays * update thread to call dismissAllOverlays with exceptions instead. * remove unneeded removeAllOverlaysWithExceptions() * silly ai * use set instead of array.
214 lines
8.7 KiB
TypeScript
214 lines
8.7 KiB
TypeScript
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
// See LICENSE.txt for license information.
|
|
|
|
import {Screens} from '@constants';
|
|
|
|
import NavigationStore from './navigation_store';
|
|
|
|
describe('NavigationStore', () => {
|
|
beforeEach(() => {
|
|
NavigationStore.reset();
|
|
});
|
|
|
|
describe('screen management', () => {
|
|
it('should add and get screens correctly', () => {
|
|
NavigationStore.addScreenToStack(Screens.ABOUT);
|
|
NavigationStore.addScreenToStack(Screens.ACCOUNT);
|
|
|
|
expect(NavigationStore.getScreensInStack()).toEqual([Screens.ACCOUNT, Screens.ABOUT]);
|
|
expect(NavigationStore.getVisibleScreen()).toBe(Screens.ACCOUNT);
|
|
});
|
|
|
|
it('should remove screens correctly', () => {
|
|
NavigationStore.addScreenToStack(Screens.ABOUT);
|
|
NavigationStore.addScreenToStack(Screens.ACCOUNT);
|
|
NavigationStore.removeScreenFromStack(Screens.ACCOUNT);
|
|
|
|
expect(NavigationStore.getScreensInStack()).toEqual([Screens.ABOUT]);
|
|
expect(NavigationStore.getVisibleScreen()).toBe(Screens.ABOUT);
|
|
});
|
|
|
|
it('should clear screens correctly', () => {
|
|
NavigationStore.addScreenToStack(Screens.ABOUT);
|
|
NavigationStore.addScreenToStack(Screens.ACCOUNT);
|
|
NavigationStore.clearScreensFromStack();
|
|
|
|
expect(NavigationStore.getScreensInStack()).toEqual([]);
|
|
expect(NavigationStore.getVisibleScreen()).toBeUndefined();
|
|
});
|
|
|
|
it('should pop to screen correctly', () => {
|
|
NavigationStore.addScreenToStack(Screens.ABOUT);
|
|
NavigationStore.addScreenToStack(Screens.ACCOUNT);
|
|
NavigationStore.addScreenToStack(Screens.CHANNEL);
|
|
NavigationStore.popTo(Screens.ABOUT);
|
|
|
|
expect(NavigationStore.getScreensInStack()).toEqual([Screens.ABOUT]);
|
|
expect(NavigationStore.getVisibleScreen()).toBe(Screens.ABOUT);
|
|
});
|
|
});
|
|
|
|
describe('modal management', () => {
|
|
it('should add and get modals correctly', () => {
|
|
NavigationStore.addModalToStack(Screens.EDIT_POST);
|
|
NavigationStore.addModalToStack(Screens.EDIT_PROFILE);
|
|
|
|
expect(NavigationStore.getModalsInStack()).toEqual([Screens.EDIT_PROFILE, Screens.EDIT_POST]);
|
|
expect(NavigationStore.getVisibleModal()).toBe(Screens.EDIT_PROFILE);
|
|
expect(NavigationStore.hasModalsOpened()).toBe(true);
|
|
});
|
|
|
|
it('should remove modals correctly', () => {
|
|
NavigationStore.addModalToStack(Screens.EDIT_POST);
|
|
NavigationStore.addModalToStack(Screens.EDIT_PROFILE);
|
|
NavigationStore.removeModalFromStack(Screens.EDIT_PROFILE);
|
|
|
|
expect(NavigationStore.getModalsInStack()).toEqual([Screens.EDIT_POST]);
|
|
expect(NavigationStore.getVisibleModal()).toBe(Screens.EDIT_POST);
|
|
});
|
|
|
|
it('should handle duplicate modal additions', () => {
|
|
NavigationStore.addModalToStack(Screens.EDIT_POST);
|
|
NavigationStore.addModalToStack(Screens.EDIT_POST);
|
|
|
|
expect(NavigationStore.getModalsInStack()).toEqual([Screens.EDIT_POST]);
|
|
});
|
|
});
|
|
|
|
describe('tab management', () => {
|
|
it('should manage visible tab correctly', () => {
|
|
expect(NavigationStore.getVisibleTab()).toBe('Home');
|
|
|
|
NavigationStore.setVisibleTap('Channel');
|
|
expect(NavigationStore.getVisibleTab()).toBe('Channel');
|
|
});
|
|
});
|
|
|
|
describe('ToS management', () => {
|
|
it('should manage ToS state correctly', () => {
|
|
expect(NavigationStore.isToSOpen()).toBe(false);
|
|
|
|
NavigationStore.setToSOpen(true);
|
|
expect(NavigationStore.isToSOpen()).toBe(true);
|
|
|
|
NavigationStore.setToSOpen(false);
|
|
expect(NavigationStore.isToSOpen()).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe('subject management', () => {
|
|
it('should notify subscribers of screen changes', () => {
|
|
const mockNext = jest.fn();
|
|
const subscription = NavigationStore.getSubject().subscribe({
|
|
next: mockNext,
|
|
});
|
|
|
|
NavigationStore.addScreenToStack(Screens.ABOUT);
|
|
expect(mockNext).toHaveBeenCalledWith(Screens.ABOUT);
|
|
|
|
NavigationStore.removeScreenFromStack(Screens.ABOUT);
|
|
expect(mockNext).toHaveBeenCalledWith(undefined);
|
|
|
|
subscription.unsubscribe();
|
|
});
|
|
});
|
|
|
|
describe('overlay management', () => {
|
|
it('should add and remove overlays correctly', () => {
|
|
NavigationStore.addOverlayToStack('test-overlay');
|
|
NavigationStore.addOverlayToStack('another-overlay');
|
|
|
|
expect(NavigationStore.getOverlaysInStack()).toEqual(['another-overlay', 'test-overlay']);
|
|
});
|
|
|
|
it('should handle duplicate overlay additions', () => {
|
|
NavigationStore.addOverlayToStack('test-overlay');
|
|
NavigationStore.addOverlayToStack('test-overlay');
|
|
|
|
expect(NavigationStore.getOverlaysInStack()).toEqual(['test-overlay']);
|
|
});
|
|
|
|
it('should remove specific overlays from stack', () => {
|
|
NavigationStore.addOverlayToStack('overlay1');
|
|
NavigationStore.addOverlayToStack('overlay2');
|
|
NavigationStore.addOverlayToStack('overlay3');
|
|
|
|
NavigationStore.removeOverlayFromStack('overlay2');
|
|
|
|
expect(NavigationStore.getOverlaysInStack()).toEqual(['overlay3', 'overlay1']);
|
|
});
|
|
|
|
it('should return overlays other than exceptions', () => {
|
|
NavigationStore.addOverlayToStack('regular-overlay');
|
|
NavigationStore.addOverlayToStack('floating-banner-overlay');
|
|
NavigationStore.addOverlayToStack('another-overlay');
|
|
|
|
const overlaysToRemove = NavigationStore.getAllOverlaysOtherThanExceptions();
|
|
|
|
expect(overlaysToRemove).toEqual(['another-overlay', 'regular-overlay']);
|
|
expect(overlaysToRemove).not.toContain('floating-banner-overlay');
|
|
});
|
|
|
|
it('should return empty array when only exception overlays exist', () => {
|
|
NavigationStore.addOverlayToStack('floating-banner-overlay');
|
|
|
|
const overlaysToRemove = NavigationStore.getAllOverlaysOtherThanExceptions();
|
|
|
|
expect(overlaysToRemove).toEqual([]);
|
|
});
|
|
|
|
it('should return all overlays when no exceptions exist in stack', () => {
|
|
NavigationStore.addOverlayToStack('overlay1');
|
|
NavigationStore.addOverlayToStack('overlay2');
|
|
|
|
const overlaysToRemove = NavigationStore.getAllOverlaysOtherThanExceptions();
|
|
|
|
expect(overlaysToRemove).toEqual(['overlay2', 'overlay1']);
|
|
});
|
|
|
|
it('should handle empty overlay stack gracefully when getting overlays to remove', () => {
|
|
const overlaysToRemove = NavigationStore.getAllOverlaysOtherThanExceptions();
|
|
expect(overlaysToRemove).toEqual([]);
|
|
expect(NavigationStore.getOverlaysInStack()).toEqual([]);
|
|
});
|
|
|
|
it('should maintain overlay order when filtering', () => {
|
|
NavigationStore.addOverlayToStack('first-overlay');
|
|
NavigationStore.addOverlayToStack('floating-banner-overlay');
|
|
NavigationStore.addOverlayToStack('second-overlay');
|
|
NavigationStore.addOverlayToStack('third-overlay');
|
|
|
|
const overlaysToRemove = NavigationStore.getAllOverlaysOtherThanExceptions();
|
|
|
|
expect(overlaysToRemove).toEqual(['third-overlay', 'second-overlay', 'first-overlay']);
|
|
});
|
|
});
|
|
|
|
describe('screen loading and visibility', () => {
|
|
it('should handle waitUntilScreenHasLoaded', async () => {
|
|
const promise = NavigationStore.waitUntilScreenHasLoaded(Screens.ABOUT);
|
|
NavigationStore.addScreenToStack(Screens.ABOUT);
|
|
|
|
await promise;
|
|
expect(NavigationStore.getScreensInStack()).toContain(Screens.ABOUT);
|
|
});
|
|
|
|
it('should handle waitUntilScreenIsTop', async () => {
|
|
const promise = NavigationStore.waitUntilScreenIsTop(Screens.ABOUT);
|
|
NavigationStore.addScreenToStack(Screens.CHANNEL);
|
|
NavigationStore.addScreenToStack(Screens.ABOUT);
|
|
|
|
await promise;
|
|
expect(NavigationStore.getVisibleScreen()).toBe(Screens.ABOUT);
|
|
});
|
|
|
|
it('should handle waitUntilScreensIsRemoved', async () => {
|
|
NavigationStore.addScreenToStack(Screens.ABOUT);
|
|
const promise = NavigationStore.waitUntilScreensIsRemoved(Screens.ABOUT);
|
|
NavigationStore.removeScreenFromStack(Screens.ABOUT);
|
|
|
|
await promise;
|
|
expect(NavigationStore.getScreensInStack()).not.toContain(Screens.ABOUT);
|
|
});
|
|
});
|
|
});
|