mattermost-mobile/app/components/formatted_date/index.test.tsx
Felipe Martin 714c3dc769
feat: AI rewrite (#9280)
* feat: ai rewrite

* feat: allow crating content apart from editing it

* feat: feature parity with webapp

* feat: feature parity with webapp

* chore: fixed padding

* map ux to webapp

* refactored ai rewrite logic to separate package

* chore: tests and lint

* Update app/products/ai/rewrite/screens/options/options.tsx

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* rewrite post editor animation

* i18n

* ui feedback, centered icon and less top padding

* chore: lint

* Consolidate @ai product into @agents

Move all rewrite functionality from app/products/ai/ into
app/products/agents/ to unify under a single namespace.

- Add rewrite types, store, hooks, components, and screens to agents
- Merge AI client methods into agents client
- Update screen constants (AI_* -> AGENTS_*)
- Update all consumer imports
- Remove AI state from EphemeralStore
- Remove @ai path alias from config
- Delete app/products/ai/ directory

* refactor: load screens from product package

* refactor: move detection logic to the agents pacakge

* refactor: remove "backwards compatibility"

* refactor: move hooks to proper package

* refactor: styles

* refactor: remove unneedd position attribute

* refactor: remove unneeded cancel animation calls

* refactor: "backwards compat"

* refactor: optimize renderContent with useCallback for performance

* refactor: rename variable to avoid confusion

* refactor: update handleRewrite to use async/await for better error handling

* refactor: simplify handleRewrite by always dismissing keyboard

* refactor: use hook, always all keyboard.dismiss

* chore: enhance AgentSelector component with FlatList support

* feat: add rewriteMessage function for AI message rewriting and integrate it into useRewrite hook

* refactor: simplify message length calculation in useHandleSendMessage hook

* refactor: consolidate agent screen constants and integrate with existing screens

* fix: update dependency array in useMemo for isUnrevealedPost to include post expiration metadata

* refactor: remove unused variable to clean up Typing component

* refactor: simplify logic for atDisabled and slashDisabled flags in QuickActions component

* feat: add AIRewriteAction component for AI message rewriting functionality

* revert: thread.ts changes manually

* refactor: integrate useSafeAreaInsets

* refactor: cleanup unused methods

* chore: add comment to clarify casting

* refactor: use_agents

* chore: lint and test

* fix: trim

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-02-16 16:48:57 +01:00

144 lines
4.4 KiB
TypeScript

// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
import timezones from 'timezones.json';
import {renderWithIntl} from '@test/intl-test-helper';
import {logDebug} from '@utils/log';
import locales from '../../i18n/languages';
import FormattedDate, {type FormattedDateFormat} from './index';
jest.mock('@utils/log', () => ({
logDebug: jest.fn(),
logError: jest.fn(),
logInfo: jest.fn(),
logWarning: jest.fn(),
}));
const DATE = new Date('2024-10-26T10:01:04.653Z');
const FORMATS = [
undefined,
{weekday: 'long'},
{dateStyle: 'medium'},
{month: 'short', day: 'numeric'},
{
month: 'short',
day: 'numeric',
hour: 'numeric',
minute: 'numeric',
},
{
year: 'numeric',
month: 'short',
day: 'numeric',
hour: 'numeric',
minute: 'numeric',
},
] satisfies Array<FormattedDateFormat | undefined>;
const TEST_MATRIX = Object.keys(locales).
map((locale) => FORMATS.map<[string, FormattedDateFormat | undefined]>((format) => [locale, format])).
flat(1);
function getTimezoneTestsCases() {
// Mimics the logic for the timezones offered by the web app
// in webapp/channels/src/components/user_settings/display/manage_timezones/manage_timezones.tsx
let index = 0;
const testCases = [];
let previousTimezone = '';
for (const timezone of timezones) {
if (timezone.utc[index] === previousTimezone) {
index++;
} else {
index = 0;
}
testCases.push([timezone.utc[index]]);
previousTimezone = timezone.utc[index];
}
return testCases;
}
describe('<FormattedDate/>', () => {
it.each(TEST_MATRIX)("should match snapshot for '%s' locale and '%p' format", (locale, format) => {
const wrapper = renderWithIntl(
<FormattedDate
format={format}
value={DATE}
timezone='UTC'
/>,
{locale},
);
expect(wrapper.toJSON()).toMatchSnapshot();
});
it('should render with a manual user time', () => {
const wrapper = renderWithIntl(
<FormattedDate
value={DATE}
timezone={{
automaticTimezone: '',
manualTimezone: 'Indian/Mauritius',
useAutomaticTimezone: '',
}}
/>,
);
expect(wrapper.toJSON()).toMatchSnapshot();
});
it('should render with an automatic user time', () => {
const wrapper = renderWithIntl(
<FormattedDate
value={DATE}
timezone={{
automaticTimezone: 'Indian/Mauritius',
manualTimezone: '',
useAutomaticTimezone: 'true',
}}
/>,
);
// Just check that the component render as automatic timezone is environment dependant
expect(wrapper.toJSON()).toBeTruthy();
});
it.each(getTimezoneTestsCases())('should render with timezone %s', (timezone) => {
const wrapper = renderWithIntl(
<FormattedDate
value={DATE}
timezone={timezone}
format={{hour: 'numeric', minute: 'numeric'}}
/>,
);
expect(wrapper.queryByText('Unknown')).not.toBeTruthy();
expect(logDebug).not.toHaveBeenCalled();
expect(wrapper.toJSON()).toMatchSnapshot();
});
it('should default when timezone is not found', () => {
const wrapper = renderWithIntl(
<FormattedDate
value={DATE}
timezone={'not valid timezone'}
format={{hour: 'numeric', minute: 'numeric'}}
/>,
);
expect(wrapper.queryByText('Unknown')).not.toBeTruthy();
expect(logDebug).toHaveBeenCalledTimes(1);
expect(wrapper.toJSON()).toMatchSnapshot();
});
it('should show unknown on other errors', () => {
const wrapper = renderWithIntl(
<FormattedDate
value={DATE}
timezone={undefined}
format={{hour: 'numeric', minute: 'invalid' as any}}
/>,
);
expect(wrapper.queryByText('Unknown')).toBeTruthy();
expect(logDebug).toHaveBeenCalledTimes(2);
});
});