diff --git a/webapp/channels/src/components/root/root_redirect/index.ts b/webapp/channels/src/components/root/root_redirect/index.ts
index d361a82c98ec2..1309717653c09 100644
--- a/webapp/channels/src/components/root/root_redirect/index.ts
+++ b/webapp/channels/src/components/root/root_redirect/index.ts
@@ -7,6 +7,7 @@ import type {Dispatch} from 'redux';
import {getFirstAdminSetupComplete} from 'mattermost-redux/actions/general';
import {getIsOnboardingFlowEnabled} from 'mattermost-redux/selectors/entities/preferences';
+import {getActiveTeamsList} from 'mattermost-redux/selectors/entities/teams';
import {getCurrentUserId, isCurrentUserSystemAdmin, isFirstAdmin} from 'mattermost-redux/selectors/entities/users';
import type {GlobalState} from 'types/store';
@@ -15,6 +16,7 @@ import RootRedirect from './root_redirect';
function mapStateToProps(state: GlobalState) {
const onboardingFlowEnabled = getIsOnboardingFlowEnabled(state);
+ const teams = getActiveTeamsList(state);
let isElegibleForFirstAdmingOnboarding = onboardingFlowEnabled;
if (isElegibleForFirstAdmingOnboarding) {
isElegibleForFirstAdmingOnboarding = isCurrentUserSystemAdmin(state);
@@ -23,6 +25,7 @@ function mapStateToProps(state: GlobalState) {
currentUserId: getCurrentUserId(state),
isElegibleForFirstAdmingOnboarding,
isFirstAdmin: isFirstAdmin(state),
+ areThereTeams: Boolean(teams.length),
};
}
diff --git a/webapp/channels/src/components/root/root_redirect/root_redirect.test.tsx b/webapp/channels/src/components/root/root_redirect/root_redirect.test.tsx
new file mode 100644
index 0000000000000..8bb5278ec9647
--- /dev/null
+++ b/webapp/channels/src/components/root/root_redirect/root_redirect.test.tsx
@@ -0,0 +1,173 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
+
+import {createMemoryHistory} from 'history';
+import React from 'react';
+import type {RouteComponentProps} from 'react-router-dom';
+import {Redirect} from 'react-router-dom';
+
+import {getFirstAdminSetupComplete as getFirstAdminSetupCompleteAction} from 'mattermost-redux/actions/general';
+
+import * as GlobalActions from 'actions/global_actions';
+
+import {renderWithContext, waitFor} from 'tests/react_testing_utils';
+
+import RootRedirect from './root_redirect';
+import type {Props} from './root_redirect';
+
+jest.mock('actions/global_actions', () => ({
+ redirectUserToDefaultTeam: jest.fn(),
+}));
+
+jest.mock('mattermost-redux/actions/general', () => ({
+ getFirstAdminSetupComplete: jest.fn(() =>
+ Promise.resolve({
+ data: true,
+ }),
+ ),
+}));
+
+jest.mock('react-router-dom', () => {
+ const actual = jest.requireActual('react-router-dom');
+ return {
+ ...actual,
+ Redirect: jest.fn(() => null),
+ };
+});
+
+describe('components/RootRedirect', () => {
+ const baseProps: Props = {
+ currentUserId: '',
+ isElegibleForFirstAdmingOnboarding: false,
+ isFirstAdmin: false,
+ areThereTeams: false,
+ actions: {
+ getFirstAdminSetupComplete: getFirstAdminSetupCompleteAction as jest.Mock,
+ },
+ };
+
+ const defaultProps = {
+ ...baseProps,
+ location: {
+ pathname: '/',
+ },
+ } as Props & RouteComponentProps;
+
+ afterEach(() => {
+ jest.clearAllMocks();
+ });
+
+ test('should redirect to /login when currentUserId is empty', () => {
+ renderWithContext();
+
+ expect(Redirect).toHaveBeenCalledTimes(1);
+ expect(Redirect).toHaveBeenCalledWith(
+ expect.objectContaining({
+ to: expect.objectContaining({
+ pathname: '/login',
+ }),
+ }),
+ {},
+ );
+ });
+
+ test('should call GlobalActions.redirectUserToDefaultTeam when user is logged in and not eligible for first admin onboarding', () => {
+ const props = {
+ ...defaultProps,
+ currentUserId: 'test-user-id',
+ isElegibleForFirstAdmingOnboarding: false,
+ };
+
+ renderWithContext();
+
+ expect(GlobalActions.redirectUserToDefaultTeam).toHaveBeenCalledTimes(1);
+ });
+
+ test('should redirect to preparing-workspace when eligible for first admin onboarding and no teams created', async () => {
+ const history = createMemoryHistory({initialEntries: ['/']});
+ const mockHistoryPush = jest.spyOn(history, 'push');
+
+ const props = {
+ currentUserId: 'test-user-id',
+ isElegibleForFirstAdmingOnboarding: true,
+ isFirstAdmin: true,
+ areThereTeams: false,
+ actions: {
+ getFirstAdminSetupComplete: jest.fn().mockResolvedValue({data: false}),
+ },
+ };
+
+ renderWithContext(, {}, {history});
+
+ expect(props.actions.getFirstAdminSetupComplete).toHaveBeenCalledTimes(1);
+
+ await waitFor(() => {
+ expect(mockHistoryPush).toHaveBeenCalledWith('/preparing-workspace');
+ });
+ });
+
+ test('should NOT redirect to preparing-workspace when there are teams created, even if system value for first admin onboarding complete is false', async () => {
+ const history = createMemoryHistory({initialEntries: ['/']});
+
+ const props = {
+ ...defaultProps,
+ currentUserId: 'test-user-id',
+ isElegibleForFirstAdmingOnboarding: true,
+ isFirstAdmin: true,
+ areThereTeams: true,
+ actions: {
+ getFirstAdminSetupComplete: jest.fn().mockResolvedValue({data: false}),
+ },
+ };
+
+ renderWithContext(, {}, {history});
+
+ expect(props.actions.getFirstAdminSetupComplete).toHaveBeenCalledTimes(1);
+
+ await waitFor(() => {
+ expect(GlobalActions.redirectUserToDefaultTeam).toHaveBeenCalledTimes(1);
+ });
+ });
+
+ test('should redirect to default team when first admin setup is complete', async () => {
+ const props = {
+ ...defaultProps,
+ currentUserId: 'test-user-id',
+ isElegibleForFirstAdmingOnboarding: true,
+ isFirstAdmin: true,
+ areThereTeams: false,
+ actions: {
+ getFirstAdminSetupComplete: jest.fn().mockResolvedValue({data: true}),
+ },
+ };
+
+ renderWithContext();
+
+ expect(props.actions.getFirstAdminSetupComplete).toHaveBeenCalledTimes(1);
+
+ await waitFor(() => {
+ expect(GlobalActions.redirectUserToDefaultTeam).toHaveBeenCalledTimes(1);
+ });
+ });
+
+ test('should redirect to default team when not first admin or teams exist', async () => {
+ const props = {
+ ...defaultProps,
+ currentUserId: 'test-user-id',
+ isElegibleForFirstAdmingOnboarding: true,
+ isFirstAdmin: false,
+ areThereTeams: true,
+ actions: {
+ getFirstAdminSetupComplete: jest.fn().mockResolvedValue({data: false}),
+ },
+ };
+
+ renderWithContext();
+
+ expect(props.actions.getFirstAdminSetupComplete).toHaveBeenCalledTimes(1);
+
+ await waitFor(() => {
+ expect(GlobalActions.redirectUserToDefaultTeam).toHaveBeenCalledTimes(1);
+ });
+ });
+});
diff --git a/webapp/channels/src/components/root/root_redirect/root_redirect.tsx b/webapp/channels/src/components/root/root_redirect/root_redirect.tsx
index c528a91c3aeb9..3a1db8624e92c 100644
--- a/webapp/channels/src/components/root/root_redirect/root_redirect.tsx
+++ b/webapp/channels/src/components/root/root_redirect/root_redirect.tsx
@@ -13,6 +13,7 @@ export type Props = {
currentUserId: string;
location?: Location;
isFirstAdmin: boolean;
+ areThereTeams: boolean;
actions: {
getFirstAdminSetupComplete: () => Promise;
};
@@ -26,7 +27,7 @@ export default function RootRedirect(props: Props) {
if (props.isElegibleForFirstAdmingOnboarding) {
props.actions.getFirstAdminSetupComplete().then((firstAdminCompletedSignup) => {
// root.tsx ensures admin profiles are eventually loaded
- if (firstAdminCompletedSignup.data === false && props.isFirstAdmin) {
+ if (firstAdminCompletedSignup.data === false && props.isFirstAdmin && !props.areThereTeams) {
history.push('/preparing-workspace');
} else {
GlobalActions.redirectUserToDefaultTeam();