mattermost-mobile/app/screens/user_profile/user_info.test.tsx
Guillermo Vayá 972bd34da6
[MM-62700] User Attribute types (#8903)
* add basic types to user_profile

* fix storing multiselect in DB

* fix storing multi-select on db

* add tests

* add tests for select-multiselect

* imporove testing

* improve intl, add tests

* address comments and tests

* review comments

* more test refactoring

* remove styling tests

* remove styling tests

* small improvements

* nitpick

* improve messaging

* safer stringify

* fix tests
2025-06-12 10:59:13 +02:00

252 lines
7.5 KiB
TypeScript

// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
import * as CustomProfileActions from '@actions/remote/custom_profile';
import * as CustomProfileQueries from '@queries/servers/custom_profile';
import {renderWithIntlAndTheme, waitFor} from '@test/intl-test-helper';
import UserInfo from './user_info';
import type UserModel from '@database/models/server/user';
import type {CustomAttributeSet} from '@typings/api/custom_profile_attributes';
const localhost = 'http://localhost:8065';
// Create test attribute sets
const serverAttributes: CustomAttributeSet = {
attr1: {
id: 'attr1',
name: 'Department',
value: 'Engineering',
type: 'text',
sort_order: 1,
},
attr2: {
id: 'attr2',
name: 'Location',
value: 'Remote',
type: 'text',
sort_order: 0,
},
};
const updatedAttributes: CustomAttributeSet = {
attr1: {
id: 'attr1',
name: 'Department',
value: 'Engineering Updated',
type: 'text',
sort_order: 1,
},
attr2: {
id: 'attr2',
name: 'Location',
value: 'Office',
type: 'text',
sort_order: 0,
},
attr3: {
id: 'attr3',
name: 'Team',
value: 'Mobile',
type: 'text',
sort_order: 2,
},
};
jest.mock('@actions/remote/custom_profile', () => ({
fetchCustomProfileAttributes: jest.fn().mockResolvedValue({
attributes: {},
error: undefined,
}),
}));
jest.mock('@context/server', () => ({
useServerUrl: jest.fn().mockReturnValue(localhost),
}));
jest.mock('@database/manager', () => {
const mockDatabase = {
get: jest.fn().mockReturnValue({
query: jest.fn().mockReturnValue({
fetch: jest.fn().mockResolvedValue([]),
}),
}),
};
return {
getServerDatabaseAndOperator: jest.fn().mockReturnValue({
database: mockDatabase,
operator: {},
}),
};
});
const mockQueryFetch = jest.fn().mockResolvedValue([]);
const mockQueryAttributesByUserId = jest.fn().mockReturnValue({
fetch: mockQueryFetch,
});
const mockAttributesCallback = jest.fn();
const mockFieldsCallback = jest.fn();
const mockAttributesObservable = {
subscribe: jest.fn().mockImplementation((callback) => {
mockAttributesCallback.mockImplementation(callback);
return {unsubscribe: jest.fn()};
}),
};
const mockFieldsObservable = {
subscribe: jest.fn().mockImplementation((callback) => {
mockFieldsCallback.mockImplementation(callback);
return {unsubscribe: jest.fn()};
}),
};
const mockConvertAttributes = jest.fn().mockResolvedValue([]);
jest.mock('@queries/servers/custom_profile', () => {
return {
queryCustomProfileAttributesByUserId: jest.fn().mockImplementation((...args) =>
mockQueryAttributesByUserId(...args),
),
observeCustomProfileAttributesByUserId: jest.fn().mockReturnValue(mockAttributesObservable),
observeCustomProfileFields: jest.fn().mockReturnValue(mockFieldsObservable),
convertProfileAttributesToCustomAttributes: jest.fn().mockImplementation((...args) =>
mockConvertAttributes(...args),
),
};
});
describe('screens/user_profile/UserInfo', () => {
beforeEach(() => {
jest.clearAllMocks();
(CustomProfileActions.fetchCustomProfileAttributes as jest.Mock).mockResolvedValue({
attributes: {},
error: undefined,
});
mockQueryFetch.mockResolvedValue([]);
mockConvertAttributes.mockResolvedValue([]);
});
const baseProps = {
user: {
id: 'user1',
firstName: 'First',
lastName: 'Last',
username: 'username',
nickname: 'nick',
position: 'Developer',
} as UserModel,
showCustomStatus: false,
showLocalTime: true,
showNickname: true,
showPosition: true,
enableCustomAttributes: true,
};
test('should load attributes from database before fetching from server', async () => {
// Mock fetch to return server attributes
const fetchMock = CustomProfileActions.fetchCustomProfileAttributes as jest.Mock;
fetchMock.mockResolvedValue({
attributes: serverAttributes,
error: undefined,
});
// Render with initial customAttributesSet
const {queryByText, rerender} = renderWithIntlAndTheme(
<UserInfo
{...baseProps}
customAttributesSet={{}}
/>,
);
// Initially there should be no custom attributes displayed
expect(queryByText('Engineering')).toBeNull();
expect(queryByText('Remote')).toBeNull();
// Verify fetch was called
await waitFor(() => {
expect(fetchMock).toHaveBeenCalledWith(localhost, 'user1', true);
});
// Simulate receiving custom attributes from props
rerender(
<UserInfo
{...baseProps}
customAttributesSet={serverAttributes}
/>,
);
// Custom attributes should now be displayed
await waitFor(() => {
expect(queryByText('Engineering')).not.toBeNull();
expect(queryByText('Remote')).not.toBeNull();
});
});
test('should update UI when database changes via observables', async () => {
// Set up component with initial empty attributes
const {queryByText, rerender} = renderWithIntlAndTheme(
<UserInfo
{...baseProps}
customAttributesSet={{}}
/>,
);
// Initially there should be no custom attributes
expect(queryByText('Engineering')).toBeNull();
// Simulate receiving attributes from props (as would happen from parent observable)
rerender(
<UserInfo
{...baseProps}
customAttributesSet={serverAttributes}
/>,
);
// Now the attributes should be displayed
await waitFor(() => {
expect(queryByText('Engineering')).not.toBeNull();
expect(queryByText('Remote')).not.toBeNull();
});
// Simulate a database update via changed props
rerender(
<UserInfo
{...baseProps}
customAttributesSet={updatedAttributes}
/>,
);
// Updated values should be displayed
await waitFor(() => {
expect(queryByText('Engineering Updated')).not.toBeNull();
expect(queryByText('Office')).not.toBeNull();
expect(queryByText('Mobile')).not.toBeNull();
});
});
test('should not fetch data if custom attributes are disabled', async () => {
const fetchMock = CustomProfileActions.fetchCustomProfileAttributes as jest.Mock;
renderWithIntlAndTheme(
<UserInfo
{...baseProps}
enableCustomAttributes={false}
/>,
);
await new Promise((resolve) => setTimeout(resolve, 100));
expect(fetchMock).not.toHaveBeenCalled();
expect(mockQueryAttributesByUserId).not.toHaveBeenCalled();
expect(CustomProfileQueries.observeCustomProfileAttributesByUserId).not.toHaveBeenCalled();
expect(CustomProfileQueries.observeCustomProfileFields).not.toHaveBeenCalled();
});
});