@sproutsocial/seeds-react-duration 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintignore +6 -0
- package/.eslintrc.js +4 -0
- package/.turbo/turbo-build.log +21 -0
- package/CHANGELOG.md +7 -0
- package/dist/esm/index.js +176 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/index.d.mts +37 -0
- package/dist/index.d.ts +37 -0
- package/dist/index.js +215 -0
- package/dist/index.js.map +1 -0
- package/jest.config.js +13 -0
- package/package.json +45 -0
- package/src/Duration.stories.tsx +82 -0
- package/src/Duration.tsx +151 -0
- package/src/DurationTypes.ts +34 -0
- package/src/__tests__/Duration.typetest.tsx +29 -0
- package/src/__tests__/features/A11y.test.tsx +11 -0
- package/src/__tests__/features/defaults.test.ts +116 -0
- package/src/__tests__/features/display.test.ts +102 -0
- package/src/__tests__/features/displayUnits.test.ts +548 -0
- package/src/__tests__/features/invalid.test.ts +32 -0
- package/src/__tests__/features/locale.test.ts +87 -0
- package/src/__tests__/features/negative.test.ts +82 -0
- package/src/__tests__/features/testDuration.tsx +37 -0
- package/src/__tests__/features/utils.test.ts +260 -0
- package/src/__tests__/features/zero.test.ts +82 -0
- package/src/constants.ts +41 -0
- package/src/index.ts +12 -0
- package/src/styles.ts +6 -0
- package/src/utils.ts +89 -0
- package/tsconfig.json +9 -0
- package/tsup.config.ts +12 -0
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import type { Meta, StoryObj } from "@storybook/react";
|
|
3
|
+
import Duration from "./Duration";
|
|
4
|
+
|
|
5
|
+
const localeOptions = [
|
|
6
|
+
"English (en-US)",
|
|
7
|
+
"Spanish (es-LA)",
|
|
8
|
+
"French (fr-FR)",
|
|
9
|
+
"Italian (it-IT)",
|
|
10
|
+
"Portuguese (pt-BR)",
|
|
11
|
+
];
|
|
12
|
+
|
|
13
|
+
const localeMapping = {
|
|
14
|
+
"English (en-US)": "en-US",
|
|
15
|
+
"Spanish (es-LA)": "es-LA",
|
|
16
|
+
"French (fr-FR)": "fr-FR",
|
|
17
|
+
"Italian (it-IT)": "it-IT",
|
|
18
|
+
"Portuguese (pt-BR)": "pt-BR",
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const displayOptions = ["Long", "Narrow"];
|
|
22
|
+
|
|
23
|
+
const displayMapping = {
|
|
24
|
+
Long: "long",
|
|
25
|
+
Narrow: "narrow",
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const meta: Meta<typeof Duration> = {
|
|
29
|
+
title: "Components/Duration",
|
|
30
|
+
component: Duration,
|
|
31
|
+
argTypes: {
|
|
32
|
+
locale: {
|
|
33
|
+
control: "select",
|
|
34
|
+
options: localeOptions,
|
|
35
|
+
mapping: localeMapping,
|
|
36
|
+
},
|
|
37
|
+
display: {
|
|
38
|
+
control: "select",
|
|
39
|
+
options: displayOptions,
|
|
40
|
+
mapping: displayMapping,
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
args: {
|
|
44
|
+
milliseconds: 123456789,
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
export default meta;
|
|
48
|
+
|
|
49
|
+
type Story = StoryObj<typeof Duration>;
|
|
50
|
+
|
|
51
|
+
export const Default: Story = {
|
|
52
|
+
args: {
|
|
53
|
+
milliseconds: 123456789,
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
export const Invalid: Story = {
|
|
58
|
+
args: {
|
|
59
|
+
milliseconds: null,
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
export const DisplayLong: Story = {
|
|
64
|
+
args: {
|
|
65
|
+
display: "long",
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
export const Negative: Story = {
|
|
70
|
+
args: {
|
|
71
|
+
milliseconds: -123456789,
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
export const DisplayUnits: Story = {
|
|
76
|
+
args: {
|
|
77
|
+
displayUnits: {
|
|
78
|
+
hours: true,
|
|
79
|
+
minutes: true,
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
};
|
package/src/Duration.tsx
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
// @ts-expect-error lru-memoize is not typed
|
|
3
|
+
import memoize from "lru-memoize";
|
|
4
|
+
import { EM_DASH } from "./constants";
|
|
5
|
+
import { VisuallyHidden } from "@sproutsocial/seeds-react-visually-hidden";
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
COMPARE_OBJECTS,
|
|
9
|
+
DEFAULT_DISPLAY,
|
|
10
|
+
DEFAULT_DISPLAY_UNITS,
|
|
11
|
+
DEFAULT_LOCALE,
|
|
12
|
+
DEFAULT_MILLISECONDS,
|
|
13
|
+
MEMO_CACHE_SIZE,
|
|
14
|
+
ORDERED_UNITS,
|
|
15
|
+
UNITS,
|
|
16
|
+
} from "./constants";
|
|
17
|
+
import { Container } from "./styles";
|
|
18
|
+
import type {
|
|
19
|
+
TypeDurationProps,
|
|
20
|
+
TypeDurationLocale,
|
|
21
|
+
TypeDurationDisplay,
|
|
22
|
+
TypeDurationDisplayUnits,
|
|
23
|
+
} from "./DurationTypes";
|
|
24
|
+
import {
|
|
25
|
+
isValidNumber,
|
|
26
|
+
getLowestUnit,
|
|
27
|
+
splitMillisecondsIntoUnits,
|
|
28
|
+
} from "./utils";
|
|
29
|
+
|
|
30
|
+
const _createDurationFormatter = (
|
|
31
|
+
locale: TypeDurationLocale,
|
|
32
|
+
unitDisplay: TypeDurationDisplay,
|
|
33
|
+
displayUnits: TypeDurationDisplayUnits
|
|
34
|
+
) => {
|
|
35
|
+
const timeUnitFormatter = (
|
|
36
|
+
locale: TypeDurationProps["locale"],
|
|
37
|
+
unit: string,
|
|
38
|
+
unitDisplay: TypeDurationProps["display"]
|
|
39
|
+
) => Intl.NumberFormat(locale, { style: "unit", unit, unitDisplay }).format;
|
|
40
|
+
|
|
41
|
+
const formatterByUnit = {
|
|
42
|
+
[UNITS.days]: timeUnitFormatter(locale, "day", unitDisplay),
|
|
43
|
+
[UNITS.hours]: timeUnitFormatter(locale, "hour", unitDisplay),
|
|
44
|
+
[UNITS.minutes]: timeUnitFormatter(locale, "minute", unitDisplay),
|
|
45
|
+
[UNITS.seconds]: timeUnitFormatter(locale, "second", unitDisplay),
|
|
46
|
+
[UNITS.milliseconds]: timeUnitFormatter(locale, "millisecond", unitDisplay),
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const formatList = new Intl.ListFormat(locale, {
|
|
50
|
+
style: "narrow",
|
|
51
|
+
type: "unit",
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
return (value: number) => {
|
|
55
|
+
const lowestUnit = getLowestUnit(displayUnits);
|
|
56
|
+
|
|
57
|
+
// if the value is zero or negative, we just want to return 0 for the lowest unit (ex "0 minutes")
|
|
58
|
+
if (value <= 0) {
|
|
59
|
+
// @ts-ignore TS error later
|
|
60
|
+
return formatterByUnit[lowestUnit](0);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const millisecondsByUnit = splitMillisecondsIntoUnits(value, displayUnits);
|
|
64
|
+
const list: string[] = [];
|
|
65
|
+
|
|
66
|
+
ORDERED_UNITS.forEach((unit) => {
|
|
67
|
+
if (unit in millisecondsByUnit) {
|
|
68
|
+
// @ts-ignore TS error later
|
|
69
|
+
const unitValue = millisecondsByUnit[unit];
|
|
70
|
+
|
|
71
|
+
// we want to add to the list if one of two conditions are met:
|
|
72
|
+
// 1) the unit has a value greater than 0 OR
|
|
73
|
+
// 2) the unit has value 0 AND the unit is the lowest unit AND the list is already empty
|
|
74
|
+
if (
|
|
75
|
+
unitValue !== 0 ||
|
|
76
|
+
(unitValue === 0 && unit === lowestUnit && list.length === 0)
|
|
77
|
+
) {
|
|
78
|
+
// @ts-ignore TS error later
|
|
79
|
+
list.push(formatterByUnit[unit](millisecondsByUnit[unit]));
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
return formatList.format(list);
|
|
85
|
+
};
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
// Memoize to reduce the energy of creating new instances of Intl.NumberFormat
|
|
89
|
+
const memoizer = memoize(MEMO_CACHE_SIZE, COMPARE_OBJECTS);
|
|
90
|
+
const createDurationFormatter = memoizer(_createDurationFormatter);
|
|
91
|
+
|
|
92
|
+
const getDuration = ({
|
|
93
|
+
returnType,
|
|
94
|
+
props,
|
|
95
|
+
}: {
|
|
96
|
+
returnType: "string" | "component";
|
|
97
|
+
props: TypeDurationProps;
|
|
98
|
+
}): string | React.ReactNode => {
|
|
99
|
+
const {
|
|
100
|
+
display = DEFAULT_DISPLAY,
|
|
101
|
+
displayUnits = DEFAULT_DISPLAY_UNITS,
|
|
102
|
+
invalidMillisecondsLabel,
|
|
103
|
+
locale = DEFAULT_LOCALE,
|
|
104
|
+
milliseconds = DEFAULT_MILLISECONDS,
|
|
105
|
+
qa,
|
|
106
|
+
} = props;
|
|
107
|
+
const isReturnTypeString = returnType === "string";
|
|
108
|
+
|
|
109
|
+
if (!isValidNumber(milliseconds)) {
|
|
110
|
+
return isReturnTypeString ? (
|
|
111
|
+
EM_DASH
|
|
112
|
+
) : (
|
|
113
|
+
<>
|
|
114
|
+
{invalidMillisecondsLabel ? (
|
|
115
|
+
// Give screen readers something useful to read off + hide the em dash
|
|
116
|
+
<VisuallyHidden>{invalidMillisecondsLabel}</VisuallyHidden>
|
|
117
|
+
) : null}
|
|
118
|
+
<Container aria-hidden {...qa}>
|
|
119
|
+
{EM_DASH}
|
|
120
|
+
</Container>
|
|
121
|
+
</>
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const validatedDisplayUnits =
|
|
126
|
+
Object.keys(displayUnits).length === 0
|
|
127
|
+
? DEFAULT_DISPLAY_UNITS
|
|
128
|
+
: displayUnits;
|
|
129
|
+
|
|
130
|
+
const fullText = createDurationFormatter(
|
|
131
|
+
locale,
|
|
132
|
+
display,
|
|
133
|
+
validatedDisplayUnits
|
|
134
|
+
)(milliseconds);
|
|
135
|
+
|
|
136
|
+
return isReturnTypeString ? (
|
|
137
|
+
fullText
|
|
138
|
+
) : (
|
|
139
|
+
<Container {...qa}>{fullText}</Container>
|
|
140
|
+
);
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
export const formatDuration = (props: TypeDurationProps): string => {
|
|
144
|
+
return getDuration({ returnType: "string", props }) as string;
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
const Duration = (props: TypeDurationProps) => {
|
|
148
|
+
return getDuration({ returnType: "component", props });
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
export default Duration;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { TypeTextProps } from "@sproutsocial/seeds-react-text";
|
|
2
|
+
|
|
3
|
+
export type TypeDurationMilliseconds = number | null;
|
|
4
|
+
|
|
5
|
+
export type TypeDurationLocale = Intl.LocalesArgument;
|
|
6
|
+
|
|
7
|
+
export type TypeDurationDisplay = "long" | "narrow";
|
|
8
|
+
|
|
9
|
+
export interface TypeDurationDisplayUnits {
|
|
10
|
+
days?: boolean;
|
|
11
|
+
hours?: boolean;
|
|
12
|
+
minutes?: boolean;
|
|
13
|
+
seconds?: boolean;
|
|
14
|
+
milliseconds?: boolean;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface TypeDurationProps extends Omit<TypeTextProps, "children"> {
|
|
18
|
+
/** The milliseconds to be formatted */
|
|
19
|
+
milliseconds: TypeDurationMilliseconds;
|
|
20
|
+
|
|
21
|
+
/** Locale to format. See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl#locales_argument */
|
|
22
|
+
locale?: TypeDurationLocale;
|
|
23
|
+
|
|
24
|
+
/** The style of the formatted duration */
|
|
25
|
+
display?: TypeDurationDisplay;
|
|
26
|
+
|
|
27
|
+
/** The units of the duration to render */
|
|
28
|
+
displayUnits?: TypeDurationDisplayUnits;
|
|
29
|
+
|
|
30
|
+
/** Text to be read off by screen readers for invalid values (i.e., any value rendered as '—' (em dash)) */
|
|
31
|
+
invalidMillisecondsLabel?: string;
|
|
32
|
+
|
|
33
|
+
qa?: object;
|
|
34
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import Duration from "../Duration";
|
|
3
|
+
|
|
4
|
+
const defaultProps = {
|
|
5
|
+
color: "text.headline",
|
|
6
|
+
milliseconds: 12345,
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export const DurationTypeTest = () => (
|
|
10
|
+
<>
|
|
11
|
+
<Duration {...defaultProps} />
|
|
12
|
+
<Duration
|
|
13
|
+
{...defaultProps}
|
|
14
|
+
milliseconds={100}
|
|
15
|
+
fontWeight="semibold"
|
|
16
|
+
fontSize={500}
|
|
17
|
+
/>
|
|
18
|
+
<Duration {...defaultProps} milliseconds={100} color="teal.500" />
|
|
19
|
+
<Duration {...defaultProps} milliseconds={100} locale="it-IT" />
|
|
20
|
+
<Duration {...defaultProps} milliseconds={123.4} display="narrow" />
|
|
21
|
+
<Duration
|
|
22
|
+
{...defaultProps}
|
|
23
|
+
milliseconds={null}
|
|
24
|
+
invalidMillisecondsLabel="Not available"
|
|
25
|
+
/>
|
|
26
|
+
{/* @ts-expect-error - test that invalid display is rejected */}
|
|
27
|
+
<Duration {...defaultProps} display="short" />
|
|
28
|
+
</>
|
|
29
|
+
);
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { render } from "@sproutsocial/seeds-react-testing-library";
|
|
3
|
+
import Duration from "../../Duration";
|
|
4
|
+
|
|
5
|
+
describe("When rendering...", () => {
|
|
6
|
+
it("should handle A11y", async () => {
|
|
7
|
+
const { container, runA11yCheck } = render(<Duration milliseconds={0} />);
|
|
8
|
+
expect(container).toBeTruthy();
|
|
9
|
+
await runA11yCheck();
|
|
10
|
+
});
|
|
11
|
+
});
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import testDuration from "./testDuration";
|
|
2
|
+
|
|
3
|
+
describe("When using the default props...", () => {
|
|
4
|
+
describe("... it renders properly", () => {
|
|
5
|
+
testDuration(1, {}, { text: "0s" });
|
|
6
|
+
testDuration(2, {}, { text: "0s" });
|
|
7
|
+
testDuration(1000, {}, { text: "1s" });
|
|
8
|
+
testDuration(2000, {}, { text: "2s" });
|
|
9
|
+
testDuration(1001, {}, { text: "1s" });
|
|
10
|
+
testDuration(2002, {}, { text: "2s" });
|
|
11
|
+
testDuration(60000, {}, { text: "1m" });
|
|
12
|
+
testDuration(120000, {}, { text: "2m" });
|
|
13
|
+
testDuration(61000, {}, { text: "1m 1s" });
|
|
14
|
+
testDuration(122000, {}, { text: "2m 2s" });
|
|
15
|
+
testDuration(60001, {}, { text: "1m" });
|
|
16
|
+
testDuration(120002, {}, { text: "2m" });
|
|
17
|
+
testDuration(61001, {}, { text: "1m 1s" });
|
|
18
|
+
testDuration(
|
|
19
|
+
122002,
|
|
20
|
+
{},
|
|
21
|
+
{
|
|
22
|
+
text: "2m 2s",
|
|
23
|
+
}
|
|
24
|
+
);
|
|
25
|
+
testDuration(3600000, {}, { text: "1h" });
|
|
26
|
+
testDuration(7200000, {}, { text: "2h" });
|
|
27
|
+
testDuration(3660000, {}, { text: "1h 1m" });
|
|
28
|
+
testDuration(7320000, {}, { text: "2h 2m" });
|
|
29
|
+
testDuration(3601000, {}, { text: "1h 1s" });
|
|
30
|
+
testDuration(7202000, {}, { text: "2h 2s" });
|
|
31
|
+
testDuration(3600001, {}, { text: "1h" });
|
|
32
|
+
testDuration(7200002, {}, { text: "2h" });
|
|
33
|
+
testDuration(3661000, {}, { text: "1h 1m 1s" });
|
|
34
|
+
testDuration(7322000, {}, { text: "2h 2m 2s" });
|
|
35
|
+
testDuration(3601001, {}, { text: "1h 1s" });
|
|
36
|
+
testDuration(
|
|
37
|
+
7202002,
|
|
38
|
+
{},
|
|
39
|
+
{
|
|
40
|
+
text: "2h 2s",
|
|
41
|
+
}
|
|
42
|
+
);
|
|
43
|
+
testDuration(3660001, {}, { text: "1h 1m" });
|
|
44
|
+
testDuration(
|
|
45
|
+
7320002,
|
|
46
|
+
{},
|
|
47
|
+
{
|
|
48
|
+
text: "2h 2m",
|
|
49
|
+
}
|
|
50
|
+
);
|
|
51
|
+
testDuration(3661001, {}, { text: "1h 1m 1s" });
|
|
52
|
+
testDuration(7322002, {}, { text: "2h 2m 2s" });
|
|
53
|
+
testDuration(86400000, {}, { text: "1d" });
|
|
54
|
+
testDuration(172800000, {}, { text: "2d" });
|
|
55
|
+
testDuration(90000000, {}, { text: "1d 1h" });
|
|
56
|
+
testDuration(180000000, {}, { text: "2d 2h" });
|
|
57
|
+
testDuration(86460000, {}, { text: "1d 1m" });
|
|
58
|
+
testDuration(172920000, {}, { text: "2d 2m" });
|
|
59
|
+
testDuration(86401000, {}, { text: "1d 1s" });
|
|
60
|
+
testDuration(172802000, {}, { text: "2d 2s" });
|
|
61
|
+
testDuration(86400001, {}, { text: "1d" });
|
|
62
|
+
testDuration(172800002, {}, { text: "2d" });
|
|
63
|
+
testDuration(90060000, {}, { text: "1d 1h 1m" });
|
|
64
|
+
testDuration(180120000, {}, { text: "2d 2h 2m" });
|
|
65
|
+
testDuration(90001000, {}, { text: "1d 1h 1s" });
|
|
66
|
+
testDuration(180002000, {}, { text: "2d 2h 2s" });
|
|
67
|
+
testDuration(90000001, {}, { text: "1d 1h" });
|
|
68
|
+
testDuration(180000002, {}, { text: "2d 2h" });
|
|
69
|
+
testDuration(86461000, {}, { text: "1d 1m 1s" });
|
|
70
|
+
testDuration(172922000, {}, { text: "2d 2m 2s" });
|
|
71
|
+
testDuration(86460001, {}, { text: "1d 1m" });
|
|
72
|
+
testDuration(
|
|
73
|
+
172920002,
|
|
74
|
+
{},
|
|
75
|
+
{
|
|
76
|
+
text: "2d 2m",
|
|
77
|
+
}
|
|
78
|
+
);
|
|
79
|
+
testDuration(86401001, {}, { text: "1d 1s" });
|
|
80
|
+
testDuration(
|
|
81
|
+
172802002,
|
|
82
|
+
{},
|
|
83
|
+
{
|
|
84
|
+
text: "2d 2s",
|
|
85
|
+
}
|
|
86
|
+
);
|
|
87
|
+
testDuration(90061000, {}, { text: "1d 1h 1m 1s" });
|
|
88
|
+
testDuration(
|
|
89
|
+
180122000,
|
|
90
|
+
{},
|
|
91
|
+
{
|
|
92
|
+
text: "2d 2h 2m 2s",
|
|
93
|
+
}
|
|
94
|
+
);
|
|
95
|
+
testDuration(86461001, {}, { text: "1d 1m 1s" });
|
|
96
|
+
testDuration(172922002, {}, { text: "2d 2m 2s" });
|
|
97
|
+
testDuration(
|
|
98
|
+
90001001,
|
|
99
|
+
{},
|
|
100
|
+
{
|
|
101
|
+
text: "1d 1h 1s",
|
|
102
|
+
}
|
|
103
|
+
);
|
|
104
|
+
testDuration(180002002, {}, { text: "2d 2h 2s" });
|
|
105
|
+
testDuration(
|
|
106
|
+
90060001,
|
|
107
|
+
{},
|
|
108
|
+
{
|
|
109
|
+
text: "1d 1h 1m",
|
|
110
|
+
}
|
|
111
|
+
);
|
|
112
|
+
testDuration(180120002, {}, { text: "2d 2h 2m" });
|
|
113
|
+
testDuration(90061001, {}, { text: "1d 1h 1m 1s" });
|
|
114
|
+
testDuration(180122002, {}, { text: "2d 2h 2m 2s" });
|
|
115
|
+
});
|
|
116
|
+
});
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import testDuration from "./testDuration";
|
|
2
|
+
|
|
3
|
+
const options = { display: "long" };
|
|
4
|
+
|
|
5
|
+
describe("When setting display long...", () => {
|
|
6
|
+
describe("... it renders properly", () => {
|
|
7
|
+
testDuration(1, options, { text: "0 seconds" });
|
|
8
|
+
testDuration(2, options, { text: "0 seconds" });
|
|
9
|
+
testDuration(1000, options, { text: "1 second" });
|
|
10
|
+
testDuration(2000, options, { text: "2 seconds" });
|
|
11
|
+
testDuration(1001, options, { text: "1 second" });
|
|
12
|
+
testDuration(2002, options, { text: "2 seconds" });
|
|
13
|
+
testDuration(60000, options, { text: "1 minute" });
|
|
14
|
+
testDuration(120000, options, { text: "2 minutes" });
|
|
15
|
+
testDuration(61000, options, { text: "1 minute 1 second" });
|
|
16
|
+
testDuration(122000, options, { text: "2 minutes 2 seconds" });
|
|
17
|
+
testDuration(60001, options, { text: "1 minute" });
|
|
18
|
+
testDuration(120002, options, { text: "2 minutes" });
|
|
19
|
+
testDuration(61001, options, { text: "1 minute 1 second" });
|
|
20
|
+
testDuration(122002, options, {
|
|
21
|
+
text: "2 minutes 2 seconds",
|
|
22
|
+
});
|
|
23
|
+
testDuration(3600000, options, { text: "1 hour" });
|
|
24
|
+
testDuration(7200000, options, { text: "2 hours" });
|
|
25
|
+
testDuration(3660000, options, { text: "1 hour 1 minute" });
|
|
26
|
+
testDuration(7320000, options, { text: "2 hours 2 minutes" });
|
|
27
|
+
testDuration(3601000, options, { text: "1 hour 1 second" });
|
|
28
|
+
testDuration(7202000, options, { text: "2 hours 2 seconds" });
|
|
29
|
+
testDuration(3600001, options, { text: "1 hour" });
|
|
30
|
+
testDuration(7200002, options, { text: "2 hours" });
|
|
31
|
+
testDuration(3661000, options, { text: "1 hour 1 minute 1 second" });
|
|
32
|
+
testDuration(7322000, options, { text: "2 hours 2 minutes 2 seconds" });
|
|
33
|
+
testDuration(3601001, options, { text: "1 hour 1 second" });
|
|
34
|
+
testDuration(7202002, options, {
|
|
35
|
+
text: "2 hours 2 seconds",
|
|
36
|
+
});
|
|
37
|
+
testDuration(3660001, options, { text: "1 hour 1 minute" });
|
|
38
|
+
testDuration(7320002, options, {
|
|
39
|
+
text: "2 hours 2 minutes",
|
|
40
|
+
});
|
|
41
|
+
testDuration(3661001, options, {
|
|
42
|
+
text: "1 hour 1 minute 1 second",
|
|
43
|
+
});
|
|
44
|
+
testDuration(7322002, options, {
|
|
45
|
+
text: "2 hours 2 minutes 2 seconds",
|
|
46
|
+
});
|
|
47
|
+
testDuration(86400000, options, { text: "1 day" });
|
|
48
|
+
testDuration(172800000, options, { text: "2 days" });
|
|
49
|
+
testDuration(90000000, options, { text: "1 day 1 hour" });
|
|
50
|
+
testDuration(180000000, options, { text: "2 days 2 hours" });
|
|
51
|
+
testDuration(86460000, options, { text: "1 day 1 minute" });
|
|
52
|
+
testDuration(172920000, options, { text: "2 days 2 minutes" });
|
|
53
|
+
testDuration(86401000, options, { text: "1 day 1 second" });
|
|
54
|
+
testDuration(172802000, options, { text: "2 days 2 seconds" });
|
|
55
|
+
testDuration(86400001, options, { text: "1 day" });
|
|
56
|
+
testDuration(172800002, options, { text: "2 days" });
|
|
57
|
+
testDuration(90060000, options, { text: "1 day 1 hour 1 minute" });
|
|
58
|
+
testDuration(180120000, options, { text: "2 days 2 hours 2 minutes" });
|
|
59
|
+
testDuration(90001000, options, { text: "1 day 1 hour 1 second" });
|
|
60
|
+
testDuration(180002000, options, { text: "2 days 2 hours 2 seconds" });
|
|
61
|
+
testDuration(90000001, options, { text: "1 day 1 hour" });
|
|
62
|
+
testDuration(180000002, options, { text: "2 days 2 hours" });
|
|
63
|
+
testDuration(86461000, options, { text: "1 day 1 minute 1 second" });
|
|
64
|
+
testDuration(172922000, options, { text: "2 days 2 minutes 2 seconds" });
|
|
65
|
+
testDuration(86460001, options, { text: "1 day 1 minute" });
|
|
66
|
+
testDuration(172920002, options, {
|
|
67
|
+
text: "2 days 2 minutes",
|
|
68
|
+
});
|
|
69
|
+
testDuration(86401001, options, { text: "1 day 1 second" });
|
|
70
|
+
testDuration(172802002, options, {
|
|
71
|
+
text: "2 days 2 seconds",
|
|
72
|
+
});
|
|
73
|
+
testDuration(90061000, options, { text: "1 day 1 hour 1 minute 1 second" });
|
|
74
|
+
testDuration(180122000, options, {
|
|
75
|
+
text: "2 days 2 hours 2 minutes 2 seconds",
|
|
76
|
+
});
|
|
77
|
+
testDuration(86461001, options, {
|
|
78
|
+
text: "1 day 1 minute 1 second",
|
|
79
|
+
});
|
|
80
|
+
testDuration(172922002, options, {
|
|
81
|
+
text: "2 days 2 minutes 2 seconds",
|
|
82
|
+
});
|
|
83
|
+
testDuration(90001001, options, {
|
|
84
|
+
text: "1 day 1 hour 1 second",
|
|
85
|
+
});
|
|
86
|
+
testDuration(180002002, options, {
|
|
87
|
+
text: "2 days 2 hours 2 seconds",
|
|
88
|
+
});
|
|
89
|
+
testDuration(90060001, options, {
|
|
90
|
+
text: "1 day 1 hour 1 minute",
|
|
91
|
+
});
|
|
92
|
+
testDuration(180120002, options, {
|
|
93
|
+
text: "2 days 2 hours 2 minutes",
|
|
94
|
+
});
|
|
95
|
+
testDuration(90061001, options, {
|
|
96
|
+
text: "1 day 1 hour 1 minute 1 second",
|
|
97
|
+
});
|
|
98
|
+
testDuration(180122002, options, {
|
|
99
|
+
text: "2 days 2 hours 2 minutes 2 seconds",
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
});
|