From 171ea4d287ba2d2224be274e47a95717f8ab18c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Dudfield?= Date: Fri, 7 Jan 2022 19:47:25 +0100 Subject: [PATCH] frontend i18n/dateTime: Add default locale+TZ under test This is because different systems have different default locales and different timezones - which makes testing more difficult. Moved date/time formatting functions out of helpers into src/i18n/dateTime. The cross-env package is for cross platform setting of env vars. --- frontend/package-lock.json | 8 +++ frontend/package.json | 5 +- frontend/src/__tests__/Activity/List.spec.js | 2 +- frontend/src/components/Activity/List.tsx | 2 +- frontend/src/components/Groups/Charts.tsx | 9 +--- frontend/src/components/Instances/Details.tsx | 2 +- frontend/src/components/Instances/Item.tsx | 3 +- .../Instances/StatusHistoryItem.tsx | 2 +- frontend/src/i18n/dateTime.ts | 51 +++++++++++++++++++ frontend/src/utils/helpers.ts | 22 -------- 10 files changed, 70 insertions(+), 36 deletions(-) create mode 100644 frontend/src/i18n/dateTime.ts diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 62f941d80..6eebbaba9 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -10669,6 +10669,14 @@ "warning": "^4.0.3" } }, + "cross-env": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", + "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==", + "requires": { + "cross-spawn": "^7.0.1" + } + }, "cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", diff --git a/frontend/package.json b/frontend/package.json index 68245e123..34467245b 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -24,6 +24,7 @@ "@types/react-window": "^1.8.2", "@types/semver": "^7.3.6", "@types/yup": "^0.29.12", + "cross-env": "^7.0.3", "dompurify": "^2.2.9", "downshift": "^6.1.3", "formik": "^2.2.9", @@ -79,8 +80,8 @@ "build-icons": "node tools/build-icons.js ./src/img ./src/icons && npm run format", "start": "react-scripts start", "build": "react-scripts build", - "test": "react-scripts test --silent", - "test:coverage": "react-scripts test --silent --watchAll=false --env=jsdom --coverage --reporters=default --coverageDirectory=coverage/report", + "test": "cross-env TEST_TZ=true react-scripts test --silent", + "test:coverage": "cross-env TEST_TZ=true react-scripts test --silent --watchAll=false --env=jsdom --coverage --reporters=default --coverageDirectory=coverage/report", "eject": "react-scripts eject", "lint": "eslint -c package.json 'src/**/*.{js,jsx,ts,tsx}' && prettier --config package.json --check src/", "format": "prettier --config package.json --write src/", diff --git a/frontend/src/__tests__/Activity/List.spec.js b/frontend/src/__tests__/Activity/List.spec.js index 55482aaff..96e68651c 100644 --- a/frontend/src/__tests__/Activity/List.spec.js +++ b/frontend/src/__tests__/Activity/List.spec.js @@ -2,7 +2,7 @@ import { render } from '@testing-library/react'; import React from 'react'; import { BrowserRouter } from 'react-router-dom'; import List from '../../components/Activity/List'; -import { makeLocaleTime } from '../../utils/helpers'; +import { makeLocaleTime } from '../../i18n/dateTime'; describe('Activity List', () => { it('should render correct entries and timestamp for Activity list', () => { diff --git a/frontend/src/components/Activity/List.tsx b/frontend/src/components/Activity/List.tsx index 4a3318c30..6445fe833 100644 --- a/frontend/src/components/Activity/List.tsx +++ b/frontend/src/components/Activity/List.tsx @@ -3,7 +3,7 @@ import { makeStyles } from '@material-ui/core/styles'; import Typography from '@material-ui/core/Typography'; import React from 'react'; import { Activity } from '../../api/apiDataTypes'; -import { makeLocaleTime } from '../../utils/helpers'; +import { makeLocaleTime } from '../../i18n/dateTime'; import Item from './Item'; const useStyles = makeStyles({ diff --git a/frontend/src/components/Groups/Charts.tsx b/frontend/src/components/Groups/Charts.tsx index fdf9df005..b5f6bd4f2 100644 --- a/frontend/src/components/Groups/Charts.tsx +++ b/frontend/src/components/Groups/Charts.tsx @@ -11,14 +11,9 @@ import { Area, AreaChart, AreaProps, CartesianGrid, Tooltip, XAxis, YAxis } from import semver from 'semver'; import _ from 'underscore'; import { Group } from '../../api/apiDataTypes'; +import { getMinuteDifference, makeLocaleTime } from '../../i18n/dateTime'; import { groupChartStore } from '../../stores/Stores'; -import { - cleanSemverVersion, - getInstanceStatus, - getMinuteDifference, - makeColorsForVersions, - makeLocaleTime, -} from '../../utils/helpers'; +import { cleanSemverVersion, getInstanceStatus, makeColorsForVersions } from '../../utils/helpers'; import Loader from '../Common/Loader'; import SimpleTable from '../Common/SimpleTable'; import makeStatusDefs from '../Instances/StatusDefs'; diff --git a/frontend/src/components/Instances/Details.tsx b/frontend/src/components/Instances/Details.tsx index 644f5d049..bc5d85b11 100644 --- a/frontend/src/components/Instances/Details.tsx +++ b/frontend/src/components/Instances/Details.tsx @@ -29,11 +29,11 @@ import { Link as RouterLink } from 'react-router-dom'; import * as Yup from 'yup'; import API from '../../api/API'; import { Application, Group, Instance, InstanceStatusHistory } from '../../api/apiDataTypes'; +import { makeLocaleTime } from '../../i18n/dateTime'; import { ERROR_STATUS_CODE, getErrorAndFlags, getInstanceStatus, - makeLocaleTime, prepareErrorMessage, } from '../../utils/helpers'; import ChannelItem from '../Channels/ChannelItem'; diff --git a/frontend/src/components/Instances/Item.tsx b/frontend/src/components/Instances/Item.tsx index f9c70a558..770ddfc61 100644 --- a/frontend/src/components/Instances/Item.tsx +++ b/frontend/src/components/Instances/Item.tsx @@ -13,7 +13,8 @@ import semver from 'semver'; import _ from 'underscore'; import API from '../../api/API'; import { Instance } from '../../api/apiDataTypes'; -import { cleanSemverVersion, makeLocaleTime } from '../../utils/helpers'; +import { makeLocaleTime } from '../../i18n/dateTime'; +import { cleanSemverVersion } from '../../utils/helpers'; import StatusHistoryContainer from './StatusHistoryContainer'; const TableLabel = function (props: PropsWithChildren<{ bgColor?: string; textColor?: string }>) { diff --git a/frontend/src/components/Instances/StatusHistoryItem.tsx b/frontend/src/components/Instances/StatusHistoryItem.tsx index c1d73cab0..98be2e0ef 100644 --- a/frontend/src/components/Instances/StatusHistoryItem.tsx +++ b/frontend/src/components/Instances/StatusHistoryItem.tsx @@ -3,11 +3,11 @@ import TableCell from '@material-ui/core/TableCell'; import TableRow from '@material-ui/core/TableRow'; import React from 'react'; import { InstanceStatusHistory } from '../../api/apiDataTypes'; +import { makeLocaleTime } from '../../i18n/dateTime'; import { ERROR_STATUS_CODE, getErrorAndFlags, getInstanceStatus, - makeLocaleTime, prepareErrorMessage, } from '../../utils/helpers'; diff --git a/frontend/src/i18n/dateTime.ts b/frontend/src/i18n/dateTime.ts new file mode 100644 index 000000000..3002a8902 --- /dev/null +++ b/frontend/src/i18n/dateTime.ts @@ -0,0 +1,51 @@ +type DateParam = string | number | Date; + +export function toLocaleString( + date: DateParam, + locales?: string | string[], + options?: Intl.DateTimeFormatOptions +) { + // Locales and timezones can be different, so we set a default when under test. + if (process.env.TEST_TZ) { + const newOptions = options ? options : {}; + return new Date(date).toLocaleString('en-US', { ...newOptions, timeZone: 'UTC' }); + } else { + return new Date(date).toLocaleString(locales, options); + } +} + +export function toLocaleDateString( + date: DateParam, + locales?: string | string[], + options?: Intl.DateTimeFormatOptions +) { + if (process.env.TEST_TZ) { + // Locales and timezones can be different, so we set a default when under test. + const newOptions = options ? options : {}; + return new Date(date).toLocaleDateString('en-US', { ...newOptions, timeZone: 'UTC' }); + } else { + return new Date(date).toLocaleDateString(locales, options); + } +} + +export function getMinuteDifference(date1: number, date2: number) { + return (date1 - date2) / 1000 / 60; +} + +export function makeLocaleTime( + timestamp: string | Date | number, + opts: { useDate?: boolean; showTime?: boolean; dateFormat?: Intl.DateTimeFormatOptions } = {} +) { + const { useDate = true, showTime = true, dateFormat = {} } = opts; + const date = new Date(timestamp); + const formattedDate = toLocaleDateString(date, undefined, dateFormat); + const timeFormat = toLocaleString(date, undefined, { hour: '2-digit', minute: '2-digit' }); + + if (useDate && showTime) { + return `${formattedDate} ${timeFormat}`; + } + if (useDate) { + return formattedDate; + } + return timeFormat; +} diff --git a/frontend/src/utils/helpers.ts b/frontend/src/utils/helpers.ts index 39d599ed6..b50b9db13 100644 --- a/frontend/src/utils/helpers.ts +++ b/frontend/src/utils/helpers.ts @@ -91,28 +91,6 @@ export function cleanSemverVersion(version: string) { return shortVersion; } -export function getMinuteDifference(date1: number, date2: number) { - return (date1 - date2) / 1000 / 60; -} - -export function makeLocaleTime( - timestamp: string | Date | number, - opts: { useDate?: boolean; showTime?: boolean; dateFormat?: Intl.DateTimeFormatOptions } = {} -) { - const { useDate = true, showTime = true, dateFormat = {} } = opts; - const date = new Date(timestamp); - const formattedDate = date.toLocaleDateString('default', dateFormat); - const timeFormat = date.toLocaleString('default', { hour: '2-digit', minute: '2-digit' }); - - if (useDate && showTime) { - return `${formattedDate} ${timeFormat}`; - } - if (useDate) { - return formattedDate; - } - return timeFormat; -} - export function makeColorsForVersions( theme: Theme, versions: string[],