Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[No QA] Migrate 'OptionsListUtilsTest.js', 'DateUtilsTest.js', 'SidebarLinks.perf-test.js', 'markdown.js' and 'ReportUtilsTest.js' to Typescript #37206

Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
79d9495
refactor(typescript): migrate multiple tests and utils
pac-guerreiro Feb 26, 2024
1b2af89
Merge branch 'main' into pac-guerreiro/refactor/migrate-25309-25310-2…
pac-guerreiro Feb 26, 2024
0bd0ce5
Merge branch 'main' into pac-guerreiro/refactor/migrate-25309-25310-2…
pac-guerreiro Feb 28, 2024
c66339c
refactor(typescript): apply pull request suggestions
pac-guerreiro Feb 29, 2024
947c99f
Merge branch 'main' into pac-guerreiro/refactor/migrate-25309-25310-2…
pac-guerreiro Feb 29, 2024
2a76abb
refactor(typescript): resolve type error
pac-guerreiro Feb 29, 2024
76f4e2e
Merge branch 'main' into pac-guerreiro/refactor/migrate-25309-25310-2…
pac-guerreiro Mar 11, 2024
a5131ed
refactor(typescript): resolve type issues
pac-guerreiro Mar 12, 2024
d78e9d1
Merge branch 'main' into pac-guerreiro/refactor/migrate-25309-25310-2…
pac-guerreiro Mar 13, 2024
e5d3ef0
fix: wrong data type conversion
pac-guerreiro Mar 13, 2024
16854a9
Merge branch 'main' into pac-guerreiro/refactor/migrate-25309-25310-2…
pac-guerreiro Mar 14, 2024
c5b2ada
refactor(typescript): apply pull request suggestions
pac-guerreiro Mar 14, 2024
104f838
Merge branch 'main' into pac-guerreiro/refactor/migrate-25309-25310-2…
pac-guerreiro Mar 18, 2024
f051c2e
refactor(typescript): apply pull request suggestion
pac-guerreiro Mar 18, 2024
3e40a53
refactor(typescript): apply pull request feedback
pac-guerreiro Mar 20, 2024
5685095
Merge branch 'main' into pac-guerreiro/refactor/migrate-25309-25310-2…
pac-guerreiro Mar 22, 2024
ba09987
refactor(typescript): apply pull request suggestion
pac-guerreiro Mar 22, 2024
9ab0ea3
refactor(typescript): apply pull request feedback
pac-guerreiro Mar 22, 2024
dc6ede9
Merge branch 'main' into pac-guerreiro/refactor/migrate-25309-25310-2…
pac-guerreiro Mar 26, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/libs/DateUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ function formatToLongDateWithWeekday(datetime: string | Date): string {
*
* @returns Sunday
*/
function formatToDayOfWeek(datetime: Date): string {
function formatToDayOfWeek(datetime: string | Date): string {
pac-guerreiro marked this conversation as resolved.
Show resolved Hide resolved
return format(new Date(datetime), CONST.DATE.WEEKDAY_TIME_FORMAT);
pac-guerreiro marked this conversation as resolved.
Show resolved Hide resolved
}

Expand Down
2 changes: 1 addition & 1 deletion src/libs/OptionsListUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2077,4 +2077,4 @@ export {
getTaxRatesSection,
};

export type {MemberForList, CategorySection, GetOptions, PayeePersonalDetails, Category};
export type {MemberForList, CategorySection, CategoryTreeSection, GetOptions, PayeePersonalDetails, Category, Tag};
6 changes: 5 additions & 1 deletion src/libs/ReportUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import type {
ReportMetadata,
Session,
Task,
TaxRate,
Transaction,
TransactionViolation,
UserWallet,
Expand Down Expand Up @@ -404,6 +405,9 @@ type OptionData = {
isDisabled?: boolean | null;
name?: string | null;
isSelfDM?: boolean | null;
reportID?: string;
enabled?: boolean;
data?: Partial<TaxRate>;
} & Report;

type OnyxDataTaskAssigneeChat = {
Expand Down Expand Up @@ -958,7 +962,7 @@ function filterReportsByPolicyIDAndMemberAccountIDs(reports: Report[], policyMem
/**
* Given an array of reports, return them sorted by the last read timestamp.
*/
function sortReportsByLastRead(reports: Report[], reportMetadata: OnyxCollection<ReportMetadata>): Array<OnyxEntry<Report>> {
function sortReportsByLastRead(reports: Array<OnyxEntry<Report>>, reportMetadata: OnyxCollection<ReportMetadata>): Array<OnyxEntry<Report>> {
return reports
.filter((report) => !!report?.reportID && !!(reportMetadata?.[`${ONYXKEYS.COLLECTION.REPORT_METADATA}${report.reportID}`]?.lastVisitTime ?? report?.lastReadTime))
.sort((a, b) => {
Expand Down
4 changes: 3 additions & 1 deletion tests/e2e/compare/output/console.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ type Entry = {
type Data = {
significance: Entry[];
meaningless: Entry[];
errors: string[];
warnings: string[];
};

const printRegularLine = (entry: Entry) => {
Expand All @@ -36,4 +38,4 @@ export default (data: Data) => {
console.debug('');
};

export type {Entry};
export type {Data, Entry};
Original file line number Diff line number Diff line change
@@ -1,80 +1,80 @@
// From: https://raw.githubusercontent.com/callstack/reassure/main/packages/reassure-compare/src/output/markdown.ts
import fs from 'node:fs/promises';
import path from 'path';
import _ from 'underscore';
import type {Stats} from 'tests/e2e/measure/math';
import * as Logger from '../../utils/logger';
import type {Data, Entry} from './console';
import * as format from './format';
import markdownTable from './markdownTable';

const tableHeader = ['Name', 'Duration'];

const collapsibleSection = (title, content) => `<details>\n<summary>${title}</summary>\n\n${content}\n</details>\n\n`;
const collapsibleSection = (title: string, content: string) => `<details>\n<summary>${title}</summary>\n\n${content}\n</details>\n\n`;

const buildDurationDetails = (title, entry) => {
const buildDurationDetails = (title: string, entry: Stats) => {
const relativeStdev = entry.stdev / entry.mean;

return _.filter(
[
`**${title}**`,
`Mean: ${format.formatDuration(entry.mean)}`,
`Stdev: ${format.formatDuration(entry.stdev)} (${format.formatPercent(relativeStdev)})`,
entry.entries ? `Runs: ${entry.entries.join(' ')}` : '',
],
Boolean,
).join('<br/>');
return [
`**${title}**`,
`Mean: ${format.formatDuration(entry.mean)}`,
`Stdev: ${format.formatDuration(entry.stdev)} (${format.formatPercent(relativeStdev)})`,
entry.entries ? `Runs: ${entry.entries.join(' ')}` : '',
]
.filter(Boolean)
.join('<br/>');
};

const buildDurationDetailsEntry = (entry) =>
_.filter(['baseline' in entry ? buildDurationDetails('Baseline', entry.baseline) : '', 'current' in entry ? buildDurationDetails('Current', entry.current) : ''], Boolean).join(
'<br/><br/>',
);
const buildDurationDetailsEntry = (entry: Entry) =>
['baseline' in entry ? buildDurationDetails('Baseline', entry.baseline) : '', 'current' in entry ? buildDurationDetails('Current', entry.current) : '']
.filter(Boolean)
.join('<br/><br/>');

const formatEntryDuration = (entry) => {
if ('baseline' in entry && 'current' in entry) {
const formatEntryDuration = (entry: Entry) => {
if (entry.baseline && entry.current) {
return format.formatDurationDiffChange(entry);
}
if ('baseline' in entry) {
if (entry.baseline) {
return format.formatDuration(entry.baseline.mean);
}
if ('current' in entry) {
if (entry.current) {
pac-guerreiro marked this conversation as resolved.
Show resolved Hide resolved
return format.formatDuration(entry.current.mean);
}
return '';
};

const buildDetailsTable = (entries) => {
const buildDetailsTable = (entries: Entry[]) => {
if (!entries.length) {
return '';
}

const rows = _.map(entries, (entry) => [entry.name, buildDurationDetailsEntry(entry)]);
const rows = entries.map((entry) => [entry.name, buildDurationDetailsEntry(entry)]);
const content = markdownTable([tableHeader, ...rows]);

return collapsibleSection('Show details', content);
};

const buildSummaryTable = (entries, collapse = false) => {
const buildSummaryTable = (entries: Entry[], collapse = false) => {
if (!entries.length) {
return '_There are no entries_';
}

const rows = _.map(entries, (entry) => [entry.name, formatEntryDuration(entry)]);
const rows = entries.map((entry) => [entry.name, formatEntryDuration(entry)]);
const content = markdownTable([tableHeader, ...rows]);

return collapse ? collapsibleSection('Show entries', content) : content;
};

const buildMarkdown = (data) => {
const buildMarkdown = (data: Data) => {
let result = '## Performance Comparison Report 📊';

if (data.errors && data.errors.length) {
if (data.errors?.length) {
result += '\n\n### Errors\n';
data.errors.forEach((message) => {
result += ` 1. 🛑 ${message}\n`;
});
}

if (data.warnings && data.warnings.length) {
if (data.warnings?.length) {
result += '\n\n### Warnings\n';
data.warnings.forEach((message) => {
result += ` 1. 🟡 ${message}\n`;
Expand All @@ -92,7 +92,7 @@ const buildMarkdown = (data) => {
return result;
};

const writeToFile = (filePath, content) =>
const writeToFile = (filePath: string, content: string) =>
fs
.writeFile(filePath, content)
.then(() => {
Expand All @@ -106,7 +106,7 @@ const writeToFile = (filePath, content) =>
throw error;
});

const writeToMarkdown = (filePath, data) => {
const writeToMarkdown = (filePath: string, data: Data) => {
const markdown = buildMarkdown(data);
return writeToFile(filePath, markdown).catch((error) => {
console.error(error);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,32 +1,33 @@
import {fireEvent, screen} from '@testing-library/react-native';
import Onyx from 'react-native-onyx';
import {measurePerformance} from 'reassure';
import _ from 'underscore';
import CONST from '../../src/CONST';
import ONYXKEYS from '../../src/ONYXKEYS';
import variables from '../../src/styles/variables';
import variables from '@styles/variables';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import * as LHNTestUtils from '../utils/LHNTestUtils';
import waitForBatchedUpdates from '../utils/waitForBatchedUpdates';
import wrapOnyxWithWaitForBatchedUpdates from '../utils/wrapOnyxWithWaitForBatchedUpdates';

jest.mock('../../src/libs/Permissions');
jest.mock('../../src/hooks/usePermissions.ts');
jest.mock('../../src/libs/Navigation/Navigation');
jest.mock('../../src/components/Icon/Expensicons');
jest.mock('@libs/Permissions');
jest.mock('@hooks/usePermissions.ts');
jest.mock('@libs/Navigation/Navigation');
jest.mock('@components/Icon/Expensicons');

jest.mock('@react-navigation/native');

const getMockedReportsMap = (length = 100) => {
const mockReports = Array.from({length}, (__, i) => {
const reportID = i + 1;
const participants = [1, 2];
const reportKey = `${ONYXKEYS.COLLECTION.REPORT}${reportID}`;
const report = LHNTestUtils.getFakeReport(participants, 1, true);

return {[reportKey]: report};
});

return _.assign({}, ...mockReports);
const mockReports = Object.fromEntries(
Array.from({length}, (value, index) => {
const reportID = index + 1;
const participants = [1, 2];
const reportKey = `${ONYXKEYS.COLLECTION.REPORT}${reportID}`;
const report = LHNTestUtils.getFakeReport(participants, 1, true);

return [reportKey, report];
}),
);

return mockReports;
};

const mockedResponseMap = getMockedReportsMap(500);
Expand All @@ -36,11 +37,9 @@ describe('SidebarLinks', () => {
Onyx.init({
keys: ONYXKEYS,
safeEvictionKeys: [ONYXKEYS.COLLECTION.REPORT_ACTIONS],
registerStorageEventListener: () => {},
});

Onyx.multiSet({
[ONYXKEYS.NVP_PRIORITY_MODE]: CONST.PRIORITY_MODE.DEFAULT,
[ONYXKEYS.PERSONAL_DETAILS_LIST]: LHNTestUtils.fakePersonalDetails,
[ONYXKEYS.BETAS]: [CONST.BETAS.DEFAULT_ROOMS],
[ONYXKEYS.NVP_PRIORITY_MODE]: CONST.PRIORITY_MODE.GSD,
Expand Down
55 changes: 32 additions & 23 deletions tests/unit/DateUtilsTest.js → tests/unit/DateUtilsTest.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
/* eslint-disable @typescript-eslint/naming-convention */
import {addDays, addMinutes, format, setHours, setMinutes, subDays, subHours, subMinutes, subSeconds} from 'date-fns';
import {format as tzFormat, utcToZonedTime} from 'date-fns-tz';
import Onyx from 'react-native-onyx';
import CONST from '../../src/CONST';
import DateUtils from '../../src/libs/DateUtils';
import ONYXKEYS from '../../src/ONYXKEYS';
import DateUtils from '@libs/DateUtils';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import type {SelectedTimezone} from '@src/types/onyx/PersonalDetails';
import waitForBatchedUpdates from '../utils/waitForBatchedUpdates';

const LOCALE = CONST.LOCALES.EN;
Expand All @@ -14,13 +16,14 @@ describe('DateUtils', () => {
keys: ONYXKEYS,
initialKeyStates: {
[ONYXKEYS.SESSION]: {accountID: 999},
[ONYXKEYS.PERSONAL_DETAILS_LIST]: {999: {timezone: {selected: UTC}}},
[ONYXKEYS.PERSONAL_DETAILS_LIST]: {'999': {accountID: 999, timezone: {selected: 'Europe/London'}}},
pac-guerreiro marked this conversation as resolved.
Show resolved Hide resolved
},
});
return waitForBatchedUpdates();
});

afterEach(() => {
jest.restoreAllMocks();
jest.useRealTimers();
Onyx.clear();
});
Expand Down Expand Up @@ -53,32 +56,35 @@ describe('DateUtils', () => {
});

it('should fallback to current date when getLocalDateFromDatetime is failing', () => {
const localDate = DateUtils.getLocalDateFromDatetime(LOCALE, undefined, 'InvalidTimezone');
const localDate = DateUtils.getLocalDateFromDatetime(LOCALE, undefined, 'InvalidTimezone' as SelectedTimezone);
expect(localDate.getTime()).not.toBeNaN();
});

it('should return the date in calendar time when calling datetimeToCalendarTime', () => {
const today = setMinutes(setHours(new Date(), 14), 32);
const today = setMinutes(setHours(new Date(), 14), 32).toString();
expect(DateUtils.datetimeToCalendarTime(LOCALE, today)).toBe('Today at 2:32 PM');

const tomorrow = addDays(setMinutes(setHours(new Date(), 14), 32), 1);
const tomorrow = addDays(setMinutes(setHours(new Date(), 14), 32), 1).toString();
expect(DateUtils.datetimeToCalendarTime(LOCALE, tomorrow)).toBe('Tomorrow at 2:32 PM');

const yesterday = setMinutes(setHours(subDays(new Date(), 1), 7), 43);
const yesterday = setMinutes(setHours(subDays(new Date(), 1), 7), 43).toString();
expect(DateUtils.datetimeToCalendarTime(LOCALE, yesterday)).toBe('Yesterday at 7:43 AM');

const date = setMinutes(setHours(new Date('2022-11-05'), 10), 17);
const date = setMinutes(setHours(new Date('2022-11-05'), 10), 17).toString();
expect(DateUtils.datetimeToCalendarTime(LOCALE, date)).toBe('Nov 5, 2022 at 10:17 AM');

const todayLowercaseDate = setMinutes(setHours(new Date(), 14), 32);
const todayLowercaseDate = setMinutes(setHours(new Date(), 14), 32).toString();
expect(DateUtils.datetimeToCalendarTime(LOCALE, todayLowercaseDate, false, undefined, true)).toBe('today at 2:32 PM');
});

it('should update timezone if automatic and selected timezone do not match', () => {
Intl.DateTimeFormat = jest.fn(() => ({
resolvedOptions: () => ({timeZone: 'America/Chicago'}),
}));
Onyx.set(ONYXKEYS.PERSONAL_DETAILS_LIST, {999: {timezone: {selected: UTC, automatic: true}}}).then(() => {
jest.spyOn(Intl, 'DateTimeFormat').mockImplementation(
() =>
({
resolvedOptions: () => ({timeZone: 'America/Chicago'}),
} as Intl.DateTimeFormat),
);
Onyx.set(ONYXKEYS.PERSONAL_DETAILS_LIST, {'999': {accountID: 999, timezone: {selected: 'Europe/London', automatic: true}}}).then(() => {
const result = DateUtils.getCurrentTimezone();
expect(result).toEqual({
selected: 'America/Chicago',
Expand All @@ -88,10 +94,13 @@ describe('DateUtils', () => {
});

it('should not update timezone if automatic and selected timezone match', () => {
Intl.DateTimeFormat = jest.fn(() => ({
resolvedOptions: () => ({timeZone: UTC}),
}));
Onyx.set(ONYXKEYS.PERSONAL_DETAILS_LIST, {999: {timezone: {selected: UTC, automatic: true}}}).then(() => {
jest.spyOn(Intl, 'DateTimeFormat').mockImplementation(
() =>
({
resolvedOptions: () => ({timeZone: UTC}),
} as Intl.DateTimeFormat),
);
Onyx.set(ONYXKEYS.PERSONAL_DETAILS_LIST, {'999': {accountID: 999, timezone: {selected: 'Europe/London', automatic: true}}}).then(() => {
pac-guerreiro marked this conversation as resolved.
Show resolved Hide resolved
const result = DateUtils.getCurrentTimezone();
expect(result).toEqual({
selected: UTC,
Expand All @@ -102,28 +111,28 @@ describe('DateUtils', () => {

it('canUpdateTimezone should return true when lastUpdatedTimezoneTime is more than 5 minutes ago', () => {
// Use fake timers to control the current time
jest.useFakeTimers('modern');
jest.useFakeTimers();
jest.setSystemTime(addMinutes(new Date(), 6));
const isUpdateTimezoneAllowed = DateUtils.canUpdateTimezone();
expect(isUpdateTimezoneAllowed).toBe(true);
});

it('canUpdateTimezone should return false when lastUpdatedTimezoneTime is less than 5 minutes ago', () => {
// Use fake timers to control the current time
jest.useFakeTimers('modern');
jest.useFakeTimers();
jest.setSystemTime(addMinutes(new Date(), 4));
const isUpdateTimezoneAllowed = DateUtils.canUpdateTimezone();
expect(isUpdateTimezoneAllowed).toBe(false);
});

it('should return the date in calendar time when calling datetimeToRelative', () => {
const aFewSecondsAgo = subSeconds(new Date(), 10);
const aFewSecondsAgo = subSeconds(new Date(), 10).toString();
expect(DateUtils.datetimeToRelative(LOCALE, aFewSecondsAgo)).toBe('less than a minute ago');

const aMinuteAgo = subMinutes(new Date(), 1);
const aMinuteAgo = subMinutes(new Date(), 1).toString();
expect(DateUtils.datetimeToRelative(LOCALE, aMinuteAgo)).toBe('1 minute ago');

const anHourAgo = subHours(new Date(), 1);
const anHourAgo = subHours(new Date(), 1).toString();
expect(DateUtils.datetimeToRelative(LOCALE, anHourAgo)).toBe('about 1 hour ago');
});

Expand Down
Loading
Loading