DM: Last active timestamp UI (#1793)
This commit is contained in:
@@ -15,23 +15,14 @@
|
||||
// @vitest-environment happy-dom
|
||||
|
||||
import { render, cleanup } from "@testing-library/react";
|
||||
import { describe, expect, it, afterEach, vi } from "vitest";
|
||||
import { describe, expect, it, afterEach } from "vitest";
|
||||
|
||||
import { makeFragmentData } from "../../gql/fragment-masking";
|
||||
import DateTime from "../DateTime";
|
||||
|
||||
import OAuth2ClientDetail, {
|
||||
OAUTH2_CLIENT_FRAGMENT,
|
||||
} from "./OAuth2ClientDetail";
|
||||
|
||||
// Mock out datetime to avoid timezones/date formatting
|
||||
vi.mock("./DateTime", () => {
|
||||
const MockDateTime: typeof DateTime = ({ datetime }) => (
|
||||
<code>{datetime.toString()}</code>
|
||||
);
|
||||
return { default: MockDateTime };
|
||||
});
|
||||
|
||||
describe("<OAuth2ClientDetail>", () => {
|
||||
const baseClient = {
|
||||
id: "test-id",
|
||||
|
||||
@@ -15,21 +15,13 @@
|
||||
// @vitest-environment happy-dom
|
||||
|
||||
import { create } from "react-test-renderer";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { describe, expect, it, beforeAll } from "vitest";
|
||||
|
||||
import { FragmentType } from "../gql/fragment-masking";
|
||||
import { WithLocation } from "../test-utils/WithLocation";
|
||||
import { mockLocale } from "../test-utils/mockLocale";
|
||||
|
||||
import CompatSession, { COMPAT_SESSION_FRAGMENT } from "./CompatSession";
|
||||
import DateTime from "./DateTime";
|
||||
|
||||
// Mock out datetime to avoid timezones/date formatting
|
||||
vi.mock("./DateTime", () => {
|
||||
const MockDateTime: typeof DateTime = ({ datetime }) => (
|
||||
<code>{datetime.toString()}</code>
|
||||
);
|
||||
return { default: MockDateTime };
|
||||
});
|
||||
|
||||
describe("<CompatSession />", () => {
|
||||
const session = {
|
||||
@@ -44,6 +36,8 @@ describe("<CompatSession />", () => {
|
||||
|
||||
const finishedAt = "2023-06-29T03:35:19.451292+00:00";
|
||||
|
||||
beforeAll(() => mockLocale());
|
||||
|
||||
it("renders an active session", () => {
|
||||
const component = create(
|
||||
<WithLocation>
|
||||
|
||||
@@ -26,6 +26,26 @@ type Props = {
|
||||
now?: Date;
|
||||
};
|
||||
|
||||
export const formatDate = (datetime: Date): string =>
|
||||
intlFormat(datetime, {
|
||||
year: "numeric",
|
||||
month: "short",
|
||||
day: "numeric",
|
||||
weekday: "short",
|
||||
hour: "numeric",
|
||||
minute: "numeric",
|
||||
});
|
||||
|
||||
/**
|
||||
* Formats a datetime
|
||||
* Uses distance when less than an hour ago
|
||||
* Else internationalised `Fri, 21 Jul 2023, 16:14`
|
||||
*/
|
||||
export const formatReadableDate = (datetime: Date, now: Date): string =>
|
||||
Math.abs(differenceInHours(now, datetime, { roundingMethod: "round" })) > 1
|
||||
? formatDate(datetime)
|
||||
: intlFormatDistance(datetime, now);
|
||||
|
||||
const DateTime: React.FC<Props> = ({
|
||||
datetime: datetimeProps,
|
||||
now: nowProps,
|
||||
@@ -34,17 +54,8 @@ const DateTime: React.FC<Props> = ({
|
||||
const datetime =
|
||||
typeof datetimeProps === "string" ? parseISO(datetimeProps) : datetimeProps;
|
||||
const now = nowProps || new Date();
|
||||
const text =
|
||||
Math.abs(differenceInHours(now, datetime, { roundingMethod: "round" })) > 1
|
||||
? intlFormat(datetime, {
|
||||
year: "numeric",
|
||||
month: "short",
|
||||
day: "numeric",
|
||||
weekday: "short",
|
||||
hour: "numeric",
|
||||
minute: "numeric",
|
||||
})
|
||||
: intlFormatDistance(datetime, now);
|
||||
const text = formatReadableDate(datetime, now);
|
||||
|
||||
return (
|
||||
<time className={className} dateTime={formatISO(datetime)}>
|
||||
{text}
|
||||
|
||||
@@ -15,22 +15,14 @@
|
||||
// @vitest-environment happy-dom
|
||||
|
||||
import { create } from "react-test-renderer";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { describe, expect, it, beforeAll } from "vitest";
|
||||
|
||||
import { FragmentType } from "../gql/fragment-masking";
|
||||
import { WithLocation } from "../test-utils/WithLocation";
|
||||
import { mockLocale } from "../test-utils/mockLocale";
|
||||
|
||||
import DateTime from "./DateTime";
|
||||
import OAuth2Session, { OAUTH2_SESSION_FRAGMENT } from "./OAuth2Session";
|
||||
|
||||
// Mock out datetime to avoid timezones/date formatting
|
||||
vi.mock("./DateTime", () => {
|
||||
const MockDateTime: typeof DateTime = ({ datetime }) => (
|
||||
<code>{datetime.toString()}</code>
|
||||
);
|
||||
return { default: MockDateTime };
|
||||
});
|
||||
|
||||
describe("<OAuth2Session />", () => {
|
||||
const defaultProps = {
|
||||
session: {
|
||||
@@ -49,6 +41,8 @@ describe("<OAuth2Session />", () => {
|
||||
|
||||
const finishedAt = "2023-06-29T03:35:19.451292+00:00";
|
||||
|
||||
beforeAll(() => mockLocale());
|
||||
|
||||
it("renders an active session", () => {
|
||||
const component = create(
|
||||
<WithLocation>
|
||||
|
||||
18
frontend/src/components/Session/LastActive.module.css
Normal file
18
frontend/src/components/Session/LastActive.module.css
Normal file
@@ -0,0 +1,18 @@
|
||||
/* Copyright 2023 The Matrix.org Foundation C.I.C.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
.active {
|
||||
color: var(--cpd-color-text-success-primary);
|
||||
}
|
||||
60
frontend/src/components/Session/LastActive.stories.tsx
Normal file
60
frontend/src/components/Session/LastActive.stories.tsx
Normal file
@@ -0,0 +1,60 @@
|
||||
// Copyright 2023 The Matrix.org Foundation C.I.C.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import type { Meta, StoryObj } from "@storybook/react";
|
||||
|
||||
import LastActive from "./LastActive";
|
||||
|
||||
type Props = {
|
||||
lastActiveTimestamp: number;
|
||||
now: number;
|
||||
};
|
||||
const Template: React.FC<Props> = ({ lastActiveTimestamp, now }) => {
|
||||
return <LastActive lastActiveTimestamp={lastActiveTimestamp} now={now} />;
|
||||
};
|
||||
|
||||
const meta = {
|
||||
title: "UI/Session/Last active time",
|
||||
component: Template,
|
||||
tags: ["autodocs"],
|
||||
} satisfies Meta<typeof Template>;
|
||||
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof Template>;
|
||||
|
||||
const now = 1694999531800;
|
||||
const ONE_DAY_MS = 24 * 60 * 60 * 1000;
|
||||
|
||||
export const Basic: Story = {
|
||||
args: {
|
||||
// yesterday
|
||||
lastActiveTimestamp: now - ONE_DAY_MS,
|
||||
now,
|
||||
},
|
||||
};
|
||||
|
||||
export const ActiveNow: Story = {
|
||||
args: {
|
||||
lastActiveTimestamp: now - 1000,
|
||||
now,
|
||||
},
|
||||
};
|
||||
|
||||
export const Inactive: Story = {
|
||||
args: {
|
||||
// 91 days ago
|
||||
lastActiveTimestamp: now - 91 * ONE_DAY_MS,
|
||||
now,
|
||||
},
|
||||
};
|
||||
46
frontend/src/components/Session/LastActive.test.tsx
Normal file
46
frontend/src/components/Session/LastActive.test.tsx
Normal file
@@ -0,0 +1,46 @@
|
||||
// Copyright 2023 The Matrix.org Foundation C.I.C.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// @vitest-environment happy-dom
|
||||
|
||||
import { composeStory } from "@storybook/react";
|
||||
import { render, cleanup } from "@testing-library/react";
|
||||
import { describe, afterEach, expect, it, beforeAll } from "vitest";
|
||||
|
||||
import { mockLocale } from "../../test-utils/mockLocale";
|
||||
|
||||
import Meta, { ActiveNow, Basic, Inactive } from "./LastActive.stories";
|
||||
|
||||
describe("<LastActive", () => {
|
||||
beforeAll(() => mockLocale());
|
||||
afterEach(cleanup);
|
||||
|
||||
it("renders an 'active now' timestamp", () => {
|
||||
const Component = composeStory(ActiveNow, { ...Meta });
|
||||
const { container } = render(<Component />);
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("renders a default timestamp", () => {
|
||||
const Component = composeStory(Basic, Meta);
|
||||
const { container } = render(<Component />);
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("renders an inactive timestamp", () => {
|
||||
const Component = composeStory(Inactive, Meta);
|
||||
const { container } = render(<Component />);
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
47
frontend/src/components/Session/LastActive.tsx
Normal file
47
frontend/src/components/Session/LastActive.tsx
Normal file
@@ -0,0 +1,47 @@
|
||||
// Copyright 2023 The Matrix.org Foundation C.I.C.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { formatDate, formatReadableDate } from "../DateTime";
|
||||
|
||||
import styles from "./LastActive.module.css";
|
||||
|
||||
// 3 minutes
|
||||
const ACTIVE_NOW_MAX_AGE = 1000 * 60 * 3;
|
||||
/// 90 days
|
||||
const INACTIVE_MIN_AGE = 1000 * 60 * 60 * 24 * 90;
|
||||
|
||||
const LastActive: React.FC<{ lastActiveTimestamp: number; now?: number }> = ({
|
||||
lastActiveTimestamp,
|
||||
now: nowProps,
|
||||
}) => {
|
||||
const now = nowProps || Date.now();
|
||||
const formattedDate = formatDate(new Date(lastActiveTimestamp));
|
||||
if (lastActiveTimestamp >= now - ACTIVE_NOW_MAX_AGE) {
|
||||
return (
|
||||
<span title={formattedDate} className={styles.active}>
|
||||
Active now
|
||||
</span>
|
||||
);
|
||||
}
|
||||
if (lastActiveTimestamp < now - INACTIVE_MIN_AGE) {
|
||||
return <span title={formattedDate}>Inactive for 90+ days</span>;
|
||||
}
|
||||
const relativeDate = formatReadableDate(
|
||||
new Date(lastActiveTimestamp),
|
||||
new Date(now),
|
||||
);
|
||||
return <span title={formattedDate}>{`Active ${relativeDate}`}</span>;
|
||||
};
|
||||
|
||||
export default LastActive;
|
||||
@@ -15,11 +15,14 @@
|
||||
// @vitest-environment happy-dom
|
||||
|
||||
import { render, cleanup, fireEvent } from "@testing-library/react";
|
||||
import { describe, it, vi, expect, afterEach } from "vitest";
|
||||
import { describe, it, vi, expect, afterEach, beforeAll } from "vitest";
|
||||
|
||||
import { mockLocale } from "../../test-utils/mockLocale";
|
||||
|
||||
import SelectableSession from "./SelectableSession";
|
||||
|
||||
describe("<SelectableSession />", () => {
|
||||
beforeAll(() => mockLocale());
|
||||
afterEach(cleanup);
|
||||
|
||||
it("renders an unselected session", () => {
|
||||
|
||||
@@ -13,20 +13,12 @@
|
||||
// limitations under the License.
|
||||
|
||||
import { create } from "react-test-renderer";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { describe, expect, it, beforeAll } from "vitest";
|
||||
|
||||
import DateTime from "../DateTime";
|
||||
import { mockLocale } from "../../test-utils/mockLocale";
|
||||
|
||||
import Session from "./Session";
|
||||
|
||||
// Mock out datetime to avoid timezones/date formatting
|
||||
vi.mock("../DateTime", () => {
|
||||
const MockDateTime: typeof DateTime = ({ datetime }) => (
|
||||
<code>{datetime.toString()}</code>
|
||||
);
|
||||
return { default: MockDateTime };
|
||||
});
|
||||
|
||||
describe("<Session />", () => {
|
||||
const defaultProps = {
|
||||
id: "session-id",
|
||||
@@ -35,6 +27,8 @@ describe("<Session />", () => {
|
||||
|
||||
const finishedAt = "2023-06-29T03:35:19.451292+00:00";
|
||||
|
||||
beforeAll(() => mockLocale());
|
||||
|
||||
it("renders an active session", () => {
|
||||
const component = create(<Session {...defaultProps} />);
|
||||
expect(component.toJSON()).toMatchSnapshot();
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||
|
||||
exports[`<LastActive > renders a default timestamp 1`] = `
|
||||
<div>
|
||||
<span
|
||||
title="Sun, 17 Sept 2023, 01:12"
|
||||
>
|
||||
Active Sun, 17 Sept 2023, 01:12
|
||||
</span>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`<LastActive > renders an 'active now' timestamp 1`] = `
|
||||
<div>
|
||||
<span
|
||||
class="_active_04756f"
|
||||
title="Mon, 18 Sept 2023, 01:12"
|
||||
>
|
||||
Active now
|
||||
</span>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`<LastActive > renders an inactive timestamp 1`] = `
|
||||
<div>
|
||||
<span
|
||||
title="Mon, 19 Jun 2023, 01:12"
|
||||
>
|
||||
Inactive for 90+ days
|
||||
</span>
|
||||
</div>
|
||||
`;
|
||||
@@ -14,18 +14,22 @@ exports[`<Session /> > renders a finished session 1`] = `
|
||||
className="_font-body-sm-semibold_1jx6b_45 _sessionMetadata_634806"
|
||||
>
|
||||
Signed in
|
||||
<code>
|
||||
2023-06-29T03:35:17.451292+00:00
|
||||
</code>
|
||||
<time
|
||||
dateTime="2023-06-29T03:35:17Z"
|
||||
>
|
||||
Thu, 29 Jun 2023, 03:35
|
||||
</time>
|
||||
</p>
|
||||
<p
|
||||
className="_font-body-sm-semibold_1jx6b_45 _sessionMetadata_634806"
|
||||
data-finished={true}
|
||||
>
|
||||
Finished
|
||||
<code>
|
||||
2023-06-29T03:35:19.451292+00:00
|
||||
</code>
|
||||
<time
|
||||
dateTime="2023-06-29T03:35:19Z"
|
||||
>
|
||||
Thu, 29 Jun 2023, 03:35
|
||||
</time>
|
||||
</p>
|
||||
</div>
|
||||
`;
|
||||
@@ -44,9 +48,11 @@ exports[`<Session /> > renders an active session 1`] = `
|
||||
className="_font-body-sm-semibold_1jx6b_45 _sessionMetadata_634806"
|
||||
>
|
||||
Signed in
|
||||
<code>
|
||||
2023-06-29T03:35:17.451292+00:00
|
||||
</code>
|
||||
<time
|
||||
dateTime="2023-06-29T03:35:17Z"
|
||||
>
|
||||
Thu, 29 Jun 2023, 03:35
|
||||
</time>
|
||||
</p>
|
||||
</div>
|
||||
`;
|
||||
@@ -65,18 +71,22 @@ exports[`<Session /> > uses client name when truthy 1`] = `
|
||||
className="_font-body-sm-semibold_1jx6b_45 _sessionMetadata_634806"
|
||||
>
|
||||
Signed in
|
||||
<code>
|
||||
2023-06-29T03:35:17.451292+00:00
|
||||
</code>
|
||||
<time
|
||||
dateTime="2023-06-29T03:35:17Z"
|
||||
>
|
||||
Thu, 29 Jun 2023, 03:35
|
||||
</time>
|
||||
</p>
|
||||
<p
|
||||
className="_font-body-sm-semibold_1jx6b_45 _sessionMetadata_634806"
|
||||
data-finished={true}
|
||||
>
|
||||
Finished
|
||||
<code>
|
||||
2023-06-29T03:35:19.451292+00:00
|
||||
</code>
|
||||
<time
|
||||
dateTime="2023-06-29T03:35:19Z"
|
||||
>
|
||||
Thu, 29 Jun 2023, 03:35
|
||||
</time>
|
||||
</p>
|
||||
<p
|
||||
className="_font-body-sm-regular_1jx6b_40 _sessionMetadata_634806"
|
||||
@@ -105,18 +115,22 @@ exports[`<Session /> > uses session name when truthy 1`] = `
|
||||
className="_font-body-sm-semibold_1jx6b_45 _sessionMetadata_634806"
|
||||
>
|
||||
Signed in
|
||||
<code>
|
||||
2023-06-29T03:35:17.451292+00:00
|
||||
</code>
|
||||
<time
|
||||
dateTime="2023-06-29T03:35:17Z"
|
||||
>
|
||||
Thu, 29 Jun 2023, 03:35
|
||||
</time>
|
||||
</p>
|
||||
<p
|
||||
className="_font-body-sm-semibold_1jx6b_45 _sessionMetadata_634806"
|
||||
data-finished={true}
|
||||
>
|
||||
Finished
|
||||
<code>
|
||||
2023-06-29T03:35:19.451292+00:00
|
||||
</code>
|
||||
<time
|
||||
dateTime="2023-06-29T03:35:19Z"
|
||||
>
|
||||
Thu, 29 Jun 2023, 03:35
|
||||
</time>
|
||||
</p>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@@ -15,23 +15,15 @@
|
||||
// @vitest-environment happy-dom
|
||||
|
||||
import { render, cleanup } from "@testing-library/react";
|
||||
import { describe, expect, it, afterEach, vi } from "vitest";
|
||||
import { describe, expect, it, afterEach, beforeAll } from "vitest";
|
||||
|
||||
import { makeFragmentData } from "../../gql/fragment-masking";
|
||||
import { WithLocation } from "../../test-utils/WithLocation";
|
||||
import { mockLocale } from "../../test-utils/mockLocale";
|
||||
import { COMPAT_SESSION_FRAGMENT } from "../CompatSession";
|
||||
import DateTime from "../DateTime";
|
||||
|
||||
import CompatSessionDetail from "./CompatSessionDetail";
|
||||
|
||||
// Mock out datetime to avoid timezones/date formatting
|
||||
vi.mock("../DateTime", () => {
|
||||
const MockDateTime: typeof DateTime = ({ datetime }) => (
|
||||
<code>{datetime.toString()}</code>
|
||||
);
|
||||
return { default: MockDateTime };
|
||||
});
|
||||
|
||||
describe("<CompatSessionDetail>", () => {
|
||||
const baseSession = {
|
||||
id: "session-id",
|
||||
@@ -42,6 +34,8 @@ describe("<CompatSessionDetail>", () => {
|
||||
redirectUri: "https://element.io",
|
||||
},
|
||||
};
|
||||
|
||||
beforeAll(() => mockLocale());
|
||||
afterEach(cleanup);
|
||||
|
||||
it("renders a compatability session details", () => {
|
||||
|
||||
@@ -15,23 +15,15 @@
|
||||
// @vitest-environment happy-dom
|
||||
|
||||
import { render, cleanup } from "@testing-library/react";
|
||||
import { describe, expect, it, afterEach, vi } from "vitest";
|
||||
import { describe, expect, it, afterEach, beforeAll } from "vitest";
|
||||
|
||||
import { makeFragmentData } from "../../gql/fragment-masking";
|
||||
import { WithLocation } from "../../test-utils/WithLocation";
|
||||
import DateTime from "../DateTime";
|
||||
import { mockLocale } from "../../test-utils/mockLocale";
|
||||
import { OAUTH2_SESSION_FRAGMENT } from "../OAuth2Session";
|
||||
|
||||
import OAuth2SessionDetail from "./OAuth2SessionDetail";
|
||||
|
||||
// Mock out datetime to avoid timezones/date formatting
|
||||
vi.mock("../DateTime", () => {
|
||||
const MockDateTime: typeof DateTime = ({ datetime }) => (
|
||||
<code>{datetime.toString()}</code>
|
||||
);
|
||||
return { default: MockDateTime };
|
||||
});
|
||||
|
||||
describe("<OAuth2SessionDetail>", () => {
|
||||
const baseSession = {
|
||||
id: "session-id",
|
||||
@@ -45,6 +37,8 @@ describe("<OAuth2SessionDetail>", () => {
|
||||
clientUri: "https://element.io",
|
||||
},
|
||||
};
|
||||
|
||||
beforeAll(() => mockLocale());
|
||||
afterEach(cleanup);
|
||||
|
||||
it("renders session details", () => {
|
||||
|
||||
@@ -87,9 +87,11 @@ exports[`<CompatSessionDetail> > renders a compatability session details 1`] = `
|
||||
<p
|
||||
class="_font-body-sm-regular_1jx6b_40 _detailValue_040867"
|
||||
>
|
||||
<code>
|
||||
2023-06-29T03:35:17.451292+00:00
|
||||
</code>
|
||||
<time
|
||||
datetime="2023-06-29T03:35:17Z"
|
||||
>
|
||||
Thu, 29 Jun 2023, 03:35
|
||||
</time>
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
@@ -248,9 +250,11 @@ exports[`<CompatSessionDetail> > renders a compatability session without an ssoL
|
||||
<p
|
||||
class="_font-body-sm-regular_1jx6b_40 _detailValue_040867"
|
||||
>
|
||||
<code>
|
||||
2023-06-29T03:35:17.451292+00:00
|
||||
</code>
|
||||
<time
|
||||
datetime="2023-06-29T03:35:17Z"
|
||||
>
|
||||
Thu, 29 Jun 2023, 03:35
|
||||
</time>
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -87,9 +87,11 @@ exports[`<OAuth2SessionDetail> > renders session details 1`] = `
|
||||
<p
|
||||
class="_font-body-sm-regular_1jx6b_40 _detailValue_040867"
|
||||
>
|
||||
<code>
|
||||
2023-06-29T03:35:17.451292+00:00
|
||||
</code>
|
||||
<time
|
||||
datetime="2023-06-29T03:35:17Z"
|
||||
>
|
||||
Thu, 29 Jun 2023, 03:35
|
||||
</time>
|
||||
</p>
|
||||
</li>
|
||||
<li
|
||||
|
||||
@@ -20,18 +20,22 @@ exports[`<CompatSession /> > renders a finished session 1`] = `
|
||||
className="_font-body-sm-semibold_1jx6b_45 _sessionMetadata_634806"
|
||||
>
|
||||
Signed in
|
||||
<code>
|
||||
2023-06-29T03:35:17.451292+00:00
|
||||
</code>
|
||||
<time
|
||||
dateTime="2023-06-29T03:35:17Z"
|
||||
>
|
||||
Thu, 29 Jun 2023, 03:35
|
||||
</time>
|
||||
</p>
|
||||
<p
|
||||
className="_font-body-sm-semibold_1jx6b_45 _sessionMetadata_634806"
|
||||
data-finished={true}
|
||||
>
|
||||
Finished
|
||||
<code>
|
||||
2023-06-29T03:35:19.451292+00:00
|
||||
</code>
|
||||
<time
|
||||
dateTime="2023-06-29T03:35:19Z"
|
||||
>
|
||||
Thu, 29 Jun 2023, 03:35
|
||||
</time>
|
||||
</p>
|
||||
<p
|
||||
className="_font-body-sm-regular_1jx6b_40 _sessionMetadata_634806"
|
||||
@@ -66,9 +70,11 @@ exports[`<CompatSession /> > renders an active session 1`] = `
|
||||
className="_font-body-sm-semibold_1jx6b_45 _sessionMetadata_634806"
|
||||
>
|
||||
Signed in
|
||||
<code>
|
||||
2023-06-29T03:35:17.451292+00:00
|
||||
</code>
|
||||
<time
|
||||
dateTime="2023-06-29T03:35:17Z"
|
||||
>
|
||||
Thu, 29 Jun 2023, 03:35
|
||||
</time>
|
||||
</p>
|
||||
<p
|
||||
className="_font-body-sm-regular_1jx6b_40 _sessionMetadata_634806"
|
||||
|
||||
@@ -20,18 +20,22 @@ exports[`<OAuth2Session /> > renders a finished session 1`] = `
|
||||
className="_font-body-sm-semibold_1jx6b_45 _sessionMetadata_634806"
|
||||
>
|
||||
Signed in
|
||||
<code>
|
||||
2023-06-29T03:35:17.451292+00:00
|
||||
</code>
|
||||
<time
|
||||
dateTime="2023-06-29T03:35:17Z"
|
||||
>
|
||||
Thu, 29 Jun 2023, 03:35
|
||||
</time>
|
||||
</p>
|
||||
<p
|
||||
className="_font-body-sm-semibold_1jx6b_45 _sessionMetadata_634806"
|
||||
data-finished={true}
|
||||
>
|
||||
Finished
|
||||
<code>
|
||||
2023-06-29T03:35:19.451292+00:00
|
||||
</code>
|
||||
<time
|
||||
dateTime="2023-06-29T03:35:19Z"
|
||||
>
|
||||
Thu, 29 Jun 2023, 03:35
|
||||
</time>
|
||||
</p>
|
||||
<p
|
||||
className="_font-body-sm-regular_1jx6b_40 _sessionMetadata_634806"
|
||||
@@ -66,9 +70,11 @@ exports[`<OAuth2Session /> > renders an active session 1`] = `
|
||||
className="_font-body-sm-semibold_1jx6b_45 _sessionMetadata_634806"
|
||||
>
|
||||
Signed in
|
||||
<code>
|
||||
2023-06-29T03:35:17.451292+00:00
|
||||
</code>
|
||||
<time
|
||||
dateTime="2023-06-29T03:35:17Z"
|
||||
>
|
||||
Thu, 29 Jun 2023, 03:35
|
||||
</time>
|
||||
</p>
|
||||
<p
|
||||
className="_font-body-sm-regular_1jx6b_40 _sessionMetadata_634806"
|
||||
|
||||
30
frontend/src/test-utils/mockLocale.ts
Normal file
30
frontend/src/test-utils/mockLocale.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
// Copyright 2023 The Matrix.org Foundation C.I.C.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { vi } from "vitest";
|
||||
|
||||
/**
|
||||
* Mock the locale on Intl.DateTimeFormat
|
||||
* To achieve stable formatted dates across environments
|
||||
* Defaults to `en-GB`
|
||||
*/
|
||||
export const mockLocale = (defaultLocale = "en-GB"): void => {
|
||||
const { DateTimeFormat } = Intl;
|
||||
vi.spyOn(Intl, "DateTimeFormat").mockImplementation(
|
||||
(
|
||||
locales?: string | string[] | undefined,
|
||||
options?: Intl.DateTimeFormatOptions | undefined,
|
||||
) => new DateTimeFormat(locales || defaultLocale, options),
|
||||
);
|
||||
};
|
||||
@@ -9,6 +9,7 @@
|
||||
"include": [
|
||||
".storybook/main.ts",
|
||||
"vite.config.ts",
|
||||
"vitest.global-setup.ts",
|
||||
".eslintrc.cjs",
|
||||
"postcss.config.cjs",
|
||||
"tailwind.config.cjs",
|
||||
|
||||
@@ -122,11 +122,12 @@ export default defineConfig((env) => ({
|
||||
proxy: {
|
||||
// Routes mostly extracted from crates/router/src/endpoints.rs
|
||||
"^/(|graphql.*|assets.*|\\.well-known.*|oauth2.*|login.*|logout.*|register.*|reauth.*|add-email.*|verify-email.*|change-password.*|consent.*|_matrix.*|complete-compat-sso.*)$":
|
||||
"http://127.0.0.1:8080",
|
||||
"https://auth-oidc.lab.element.dev",
|
||||
},
|
||||
},
|
||||
|
||||
test: {
|
||||
globalSetup: "./vitest.global-setup.ts",
|
||||
coverage: {
|
||||
provider: "v8",
|
||||
src: ["./src/"],
|
||||
|
||||
17
frontend/vitest.global-setup.ts
Normal file
17
frontend/vitest.global-setup.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
// Copyright 2023 The Matrix.org Foundation C.I.C.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
export const setup = (): void => {
|
||||
process.env.TZ = "UTC";
|
||||
};
|
||||
Reference in New Issue
Block a user