湯本 開 7421203bc4 Merged PR 567: テスト用Attributeを追加
## 概要
[Task3060: テスト用Attributeを追加](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/3060)

- E2Eテストから指定しやすいように代表的な要素(ログアウトボタン等)に一意の名前を付ける実装を追加
  - `data-*` はカスタムデータ属性と呼ばれるもので、「標準的な取り扱い方」が存在しない属性
    - https://developer.mozilla.org/ja/docs/Learn/HTML/Howto/Use_data_attributes
  - 一般的に、E2Eテストで「このボタン」とか「このラベル」とかを指定したい時に使われる
    - https://docs.cypress.io/guides/references/best-practices
  - 本番環境などでも属性としては残したままにする想定だが、`data-test-id` 等の見るからにテスト用の名前を指定すると、テスト処理が入っているような変な誤解を招きそうなので名前は `data-tag` とした
    - 実際にはテストにも使える、副作用が特にない属性

## レビューポイント
- 動作が変わるような変更が入り込んでしまっていないか
- タグ名は妥当か

## UIの変更
- なし

## 動作確認状況
- ローカルで確認
2023-11-10 03:50:33 +00:00

117 lines
4.1 KiB
TypeScript

import React, { useCallback, useEffect } from "react";
import styles from "styles/app.module.scss";
import { useDispatch, useSelector } from "react-redux";
import { AppDispatch } from "app/store";
import { useMsal } from "@azure/msal-react";
import { clearToken, loadAccessToken } from "features/auth";
import { useTranslation } from "react-i18next";
import {
getUserInfoAsync,
selectUserName,
selectIsUserNameEmpty,
clearUserInfo,
} from "features/login";
import { useNavigate } from "react-router-dom";
import { selectDelegationAccessToken } from "features/auth/selectors";
import { getFilteredMenus } from "./utils";
import logo from "../../assets/images/OMS_logo_black.svg";
import ac from "../../assets/images/account_circle.svg";
import { LoginedPaths } from "./types";
import { HEADER_NAME } from "./constants";
import logout from "../../assets/images/logout.svg";
import { getTranslationID } from "../../translation";
interface HeaderProps {
activePath: LoginedPaths;
}
// ログイン後のヘッダー
const LoginedHeader: React.FC<HeaderProps> = (props: HeaderProps) => {
const { activePath } = props;
const dispatch: AppDispatch = useDispatch();
const { instance } = useMsal();
const { t } = useTranslation();
const navigate = useNavigate();
// メニューの代行操作表示制御
const isDelegation = useSelector(selectDelegationAccessToken) !== null;
const accessToken = loadAccessToken();
const filterMenus = getFilteredMenus(isDelegation);
// Headerのユーザー情報を取得する
const isUserNameEmpty = useSelector(selectIsUserNameEmpty);
const userName = useSelector(selectUserName);
useEffect(() => {
// ユーザー情報が空の場合、ユーザー情報を取得する(アクセストークンがある場合のみ)
// ログアウト時にユーザー情報とアクセストークンをクリアするため、失敗するそのタイミングでユーザー情報を取得しないようにする
if (accessToken !== null && isUserNameEmpty) {
dispatch(getUserInfoAsync());
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [dispatch, isUserNameEmpty]);
// ログアウト
const onSignoutButton = useCallback(
async () => {
// ダイアログ確認
if (
!isDelegation &&
// eslint-disable-next-line no-alert
window.confirm(t(getTranslationID("common.message.displayDialog")))
) {
dispatch(clearToken());
dispatch(clearUserInfo());
instance.logoutRedirect({ postLogoutRedirectUri: "/" });
}
},
// eslint-disable-next-line react-hooks/exhaustive-deps
[dispatch]
);
return (
<header className={styles.header}>
<div className={styles.headerLogo}>
<img src={logo} alt="OM System" />
</div>
<div className={styles.headerSub}>{t(HEADER_NAME)}</div>
<div className={styles.headerMenu}>
<ul>
{filterMenus.map((x) => (
<li key={x.key}>
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions */}
<a
onClick={() => navigate(x.path)}
className={
activePath.toUpperCase() === x.path.toUpperCase()
? styles.isActive
: ""
}
data-tag={`menu-${x.key}`}
>
{t(x.label)}
</a>
</li>
))}
</ul>
<p className={styles.accountInfo}>
<img src={ac} alt="" className={styles.accountIcon} />
<span>{userName}</span>
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions */}
<span
className={styles.accountSignout}
onClick={onSignoutButton}
data-tag="logout"
style={{ pointerEvents: isDelegation ? "none" : "auto" }}
>
<img src={logout} alt="" className={styles.accountIcon} />
{t(getTranslationID("common.label.signOutButton"))}
</span>
</p>
</div>
</header>
);
};
export default LoginedHeader;