@truedat/auth 8.14.3 → 8.14.4

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.
Files changed (66) hide show
  1. package/package.json +4 -4
  2. package/src/messages/en.js +6 -5
  3. package/src/messages/es.js +8 -7
  4. package/src/styles/UserCard.less +582 -0
  5. package/src/styles/UserModals.less +826 -0
  6. package/src/styles/Users.less +280 -0
  7. package/src/users/components/AdminUserRoutes.js +7 -20
  8. package/src/users/components/EditUser.js +7 -34
  9. package/src/users/components/EditUserModal.js +150 -0
  10. package/src/users/components/NewUser.js +128 -17
  11. package/src/users/components/Password.js +11 -189
  12. package/src/users/components/UserAcls.js +56 -6
  13. package/src/users/components/UserActions.js +99 -34
  14. package/src/users/components/UserCard.js +168 -22
  15. package/src/users/components/UserCards.js +273 -35
  16. package/src/users/components/UserFormFields.js +206 -0
  17. package/src/users/components/UserGroupAclRow.js +8 -2
  18. package/src/users/components/UserGroupAcls.js +2 -2
  19. package/src/users/components/UserGroupLink.js +21 -0
  20. package/src/users/components/UserInfoModal.js +268 -0
  21. package/src/users/components/UserPasswordField.js +66 -0
  22. package/src/users/components/UserPasswordModal.js +210 -0
  23. package/src/users/components/UserRoutes.js +4 -13
  24. package/src/users/components/UserTabs.js +5 -2
  25. package/src/users/components/UserTypeSelector.js +109 -0
  26. package/src/users/components/UsersAndGroups.js +39 -5
  27. package/src/users/components/UsersTable.js +234 -0
  28. package/src/users/components/__tests__/EditUser.spec.js +84 -10
  29. package/src/users/components/__tests__/NewUser.spec.js +34 -4
  30. package/src/users/components/__tests__/Password.spec.js +53 -146
  31. package/src/users/components/__tests__/UserAcls.spec.js +23 -2
  32. package/src/users/components/__tests__/UserCard.spec.js +111 -5
  33. package/src/users/components/__tests__/UserCards.spec.js +194 -0
  34. package/src/users/components/__tests__/UserGroupAclRow.spec.js +19 -1
  35. package/src/users/components/__tests__/UserModals.spec.js +507 -0
  36. package/src/users/components/__tests__/UserRoutes.spec.js +8 -3
  37. package/src/users/components/__tests__/UserTypeSelector.spec.js +32 -0
  38. package/src/users/components/__tests__/UsersAndGroups.spec.js +17 -0
  39. package/src/users/components/__tests__/__snapshots__/UserCard.spec.js.snap +64 -37
  40. package/src/users/components/__tests__/__snapshots__/UserCards.spec.js.snap +424 -75
  41. package/src/users/components/__tests__/__snapshots__/UserGroupAclRow.spec.js.snap +7 -3
  42. package/src/users/components/__tests__/__snapshots__/UserRoutes.spec.js.snap +4 -13
  43. package/src/users/hooks/useSortedGroups.js +13 -0
  44. package/src/users/hooks/useUserModalOperation.js +55 -0
  45. package/src/users/reducers/__tests__/userRedirect.spec.js +14 -3
  46. package/src/users/reducers/index.js +1 -0
  47. package/src/users/reducers/userModalOperation.js +29 -0
  48. package/src/users/reducers/userRedirect.js +5 -4
  49. package/src/users/sagas/__tests__/updateUser.spec.js +19 -1
  50. package/src/users/sagas/createUser.js +12 -5
  51. package/src/users/sagas/deleteUser.js +12 -5
  52. package/src/users/sagas/updateUser.js +19 -8
  53. package/src/users/selectors/__tests__/filterUsers.spec.js +11 -0
  54. package/src/users/selectors/__tests__/getUserAcls.spec.js +1 -0
  55. package/src/users/selectors/__tests__/getUserGroupAcls.spec.js +2 -0
  56. package/src/users/selectors/filterUsers.js +9 -1
  57. package/src/users/selectors/getUserGroupAcls.js +1 -0
  58. package/src/users/components/User.js +0 -68
  59. package/src/users/components/UserPassword.js +0 -24
  60. package/src/users/components/__tests__/User.spec.js +0 -20
  61. package/src/users/components/__tests__/UserPassword.spec.js +0 -24
  62. package/src/users/components/__tests__/__snapshots__/EditUser.spec.js.snap +0 -281
  63. package/src/users/components/__tests__/__snapshots__/NewUser.spec.js.snap +0 -321
  64. package/src/users/components/__tests__/__snapshots__/Password.spec.js.snap +0 -128
  65. package/src/users/components/__tests__/__snapshots__/User.spec.js.snap +0 -129
  66. package/src/users/components/__tests__/__snapshots__/UserPassword.spec.js.snap +0 -124
@@ -71,10 +71,7 @@ exports[`<UserRoutes /> renders correctly with users/:id route 1`] = `
71
71
  UsersLoader
72
72
  </div>
73
73
  <div>
74
- UserLoader
75
- </div>
76
- <div>
77
- User
74
+ UsersAndGroups
78
75
  </div>
79
76
  </div>
80
77
  `;
@@ -85,10 +82,7 @@ exports[`<UserRoutes /> renders correctly with users/:id/edit route 1`] = `
85
82
  UsersLoader
86
83
  </div>
87
84
  <div>
88
- UserLoader
89
- </div>
90
- <div>
91
- EditUser
85
+ UsersAndGroups
92
86
  </div>
93
87
  </div>
94
88
  `;
@@ -99,10 +93,7 @@ exports[`<UserRoutes /> renders correctly with users/:id/password route 1`] = `
99
93
  UsersLoader
100
94
  </div>
101
95
  <div>
102
- UserLoader
103
- </div>
104
- <div>
105
- UserPassword
96
+ UsersAndGroups
106
97
  </div>
107
98
  </div>
108
99
  `;
@@ -113,7 +104,7 @@ exports[`<UserRoutes /> renders correctly with users/new route 1`] = `
113
104
  UsersLoader
114
105
  </div>
115
106
  <div>
116
- NewUser
107
+ UsersAndGroups
117
108
  </div>
118
109
  </div>
119
110
  `;
@@ -0,0 +1,13 @@
1
+ import _ from "lodash/fp";
2
+ import { useMemo } from "react";
3
+ import { useGroups } from "../../groups/hooks/useGroups";
4
+
5
+ const caseInsensitiveName = ({ name }) => _.lowerCase(name);
6
+
7
+ // Group options for the user forms, sorted as the former Redux `groups` state was.
8
+ export const useSortedGroups = () => {
9
+ const { groups } = useGroups();
10
+ return useMemo(() => _.sortBy(caseInsensitiveName)(groups), [groups]);
11
+ };
12
+
13
+ export default useSortedGroups;
@@ -0,0 +1,55 @@
1
+ import { useEffect, useId, useRef } from "react";
2
+ import { useDispatch, useSelector } from "react-redux";
3
+ import { useIntl } from "react-intl";
4
+ import { clearUserModalOperation } from "../reducers/userModalOperation";
5
+
6
+ export default function useUserModalOperation(
7
+ routine,
8
+ onClose,
9
+ onSuccess = onClose,
10
+ ) {
11
+ const id = useId();
12
+ const dispatch = useDispatch();
13
+ const { formatMessage } = useIntl();
14
+ const request = useRef(0);
15
+ const pending = useRef(false);
16
+ const operation = useSelector((state) => state.userModalOperation?.[id]);
17
+ const isSubmitting = operation?.status === "pending";
18
+
19
+ useEffect(() => () => dispatch(clearUserModalOperation(id)), [dispatch, id]);
20
+
21
+ useEffect(() => {
22
+ if (operation?.requestId !== request.current || !pending.current) return;
23
+ if (operation.status === "error") pending.current = false;
24
+ if (operation.status === "success") {
25
+ pending.current = false;
26
+ onSuccess();
27
+ }
28
+ }, [operation, onSuccess]);
29
+
30
+ const submit = (payload) => {
31
+ if (pending.current) return;
32
+ pending.current = true;
33
+ request.current += 1;
34
+ dispatch({
35
+ ...routine(payload),
36
+ meta: { userModalId: id, requestId: request.current },
37
+ });
38
+ };
39
+
40
+ return {
41
+ submit,
42
+ isSubmitting,
43
+ onClose: () => {
44
+ if (!pending.current) onClose();
45
+ },
46
+ error:
47
+ operation?.status === "error"
48
+ ? formatMessage({
49
+ id: "user.modal.operation.error",
50
+ defaultMessage:
51
+ "The operation could not be completed. Please try again.",
52
+ })
53
+ : null,
54
+ };
55
+ }
@@ -1,4 +1,3 @@
1
- import { linkTo } from "@truedat/core/routes";
2
1
  import { clearRedirect } from "@truedat/core/routines";
3
2
  import { createUser, deleteUser, updateUser } from "../../routines";
4
3
  import { userRedirect } from "..";
@@ -27,12 +26,24 @@ describe("reducers: userRedirect", () => {
27
26
 
28
27
  it("should handle the updateUser.SUCCESS action", () => {
29
28
  const payload = { data: { id: "1" } };
30
- const url = linkTo.USER({ id: "1" });
31
29
  expect(userRedirect("foo", { type: updateUser.SUCCESS, payload })).toBe(
32
- url,
30
+ "/users/1",
33
31
  );
34
32
  });
35
33
 
34
+ it.each([createUser.SUCCESS, updateUser.SUCCESS])(
35
+ "preserves the redirect for modal operation %s",
36
+ (type) => {
37
+ expect(
38
+ userRedirect("foo", {
39
+ type,
40
+ payload: { data: { id: "1" } },
41
+ meta: { userModalId: "modal", requestId: 1 },
42
+ }),
43
+ ).toBe("foo");
44
+ },
45
+ );
46
+
36
47
  it("should ignore unknown actions", () => {
37
48
  expect(userRedirect("foo", { type: "bar", payload })).toEqual("foo");
38
49
  });
@@ -3,3 +3,4 @@ export * from "./users";
3
3
  export * from "./usersSearch";
4
4
  export * from "./userRedirect";
5
5
  export * from "./canInit";
6
+ export { userModalOperation } from "./userModalOperation";
@@ -0,0 +1,29 @@
1
+ import _ from "lodash/fp";
2
+ import {
3
+ createUser,
4
+ updateUser,
5
+ updatePassword,
6
+ deleteUser,
7
+ } from "../routines";
8
+
9
+ export const clearUserModalOperation = (id) => ({
10
+ type: "CLEAR_USER_MODAL_OPERATION",
11
+ payload: id,
12
+ });
13
+
14
+ export const userModalOperation = (state = {}, { type, meta, payload }) => {
15
+ if (type === "CLEAR_USER_MODAL_OPERATION") return _.omit([payload])(state);
16
+ if (!meta?.userModalId) return state;
17
+ const { userModalId, requestId } = meta;
18
+ const routines = [createUser, updateUser, updatePassword, deleteUser];
19
+ if (routines.some((routine) => routine.TRIGGER === type)) {
20
+ return { ...state, [userModalId]: { requestId, status: "pending" } };
21
+ }
22
+ if (state[userModalId]?.requestId !== requestId) return state;
23
+ const status = routines.some((routine) => routine.SUCCESS === type)
24
+ ? "success"
25
+ : routines.some((routine) => routine.FAILURE === type)
26
+ ? "error"
27
+ : null;
28
+ return status ? { ...state, [userModalId]: { requestId, status } } : state;
29
+ };
@@ -5,15 +5,16 @@ import { createUser, deleteUser, updateUser } from "../routines";
5
5
 
6
6
  const initialState = "";
7
7
 
8
- export const userRedirect = (state = initialState, { type, payload }) => {
8
+ export const userRedirect = (state = initialState, { type, payload, meta }) => {
9
9
  switch (type) {
10
10
  case clearRedirect.TRIGGER:
11
11
  return initialState;
12
12
  case createUser.SUCCESS:
13
- return USERS;
13
+ return meta?.userModalId ? state : USERS;
14
14
  case updateUser.SUCCESS:
15
- const data = _.get("data")(payload);
16
- return linkTo.USER({ ...data });
15
+ return meta?.userModalId
16
+ ? state
17
+ : linkTo.USER({ ..._.get("data")(payload) });
17
18
  case deleteUser.SUCCESS:
18
19
  return state;
19
20
  default:
@@ -7,7 +7,7 @@ import {
7
7
  updatePasswordSaga,
8
8
  } from "../updateUser";
9
9
  import { updateUser, updatePassword } from "../../routines";
10
- import { API_USER } from "../../api";
10
+ import { API_USER, API_USER_CHANGE_PASSWORD } from "../../api";
11
11
 
12
12
  describe("sagas: updateUserRequestSaga", () => {
13
13
  it("should invoke updateUserSaga on updateUser.TRIGGER", () => {
@@ -94,3 +94,21 @@ describe("sagas: updateUserSaga", () => {
94
94
  }).not.toThrow();
95
95
  });
96
96
  });
97
+
98
+ it("changes the current password without requesting the administrative user list", () => {
99
+ const payload = {
100
+ user: { old_password: "old-example", new_password: "new-example" },
101
+ };
102
+ const meta = { userModalId: "self-password", requestId: 1 };
103
+ testSaga(updatePasswordSaga, { payload, meta })
104
+ .next()
105
+ .put(updatePassword.request())
106
+ .next()
107
+ .call(apiJsonPut, API_USER_CHANGE_PASSWORD, payload, JSON_OPTS)
108
+ .next({ data: {} })
109
+ .put({ ...updatePassword.success({}), meta })
110
+ .next()
111
+ .put(updatePassword.fulfill())
112
+ .next()
113
+ .isDone();
114
+ });
@@ -1,21 +1,28 @@
1
1
  import { call, put, takeLatest } from "redux-saga/effects";
2
2
  import { apiJsonPost, JSON_OPTS } from "@truedat/core/services/api";
3
- import { createUser } from "../routines";
3
+ import { createUser, fetchUsers } from "../routines";
4
4
  import { API_USERS } from "../api";
5
5
 
6
- export function* createUserSaga({ payload: user }) {
6
+ export function* createUserSaga({ payload: user, meta }) {
7
7
  try {
8
8
  const url = API_USERS;
9
9
  const requestData = { user };
10
10
  yield put(createUser.request());
11
11
  const { data } = yield call(apiJsonPost, url, requestData, JSON_OPTS);
12
- yield put(createUser.success(data));
12
+ yield put({ ...createUser.success(data), ...(meta ? { meta } : {}) });
13
+ if (meta?.userModalId) yield put(fetchUsers());
13
14
  } catch (error) {
14
15
  if (error.response) {
15
16
  const { status, data } = error.response;
16
- yield put(createUser.failure({ status, data }));
17
+ yield put({
18
+ ...createUser.failure({ status, data }),
19
+ ...(meta ? { meta } : {}),
20
+ });
17
21
  } else {
18
- yield put(createUser.failure(error.message));
22
+ yield put({
23
+ ...createUser.failure(error.message),
24
+ ...(meta ? { meta } : {}),
25
+ });
19
26
  }
20
27
  } finally {
21
28
  yield put(createUser.fulfill());
@@ -1,24 +1,31 @@
1
1
  import { compile } from "path-to-regexp";
2
2
  import { call, put, takeLatest } from "redux-saga/effects";
3
3
  import { apiJsonDelete, JSON_OPTS } from "@truedat/core/services/api";
4
- import { deleteUser } from "../routines";
4
+ import { deleteUser, fetchUsers } from "../routines";
5
5
  import { API_USER } from "../api";
6
6
 
7
7
  const toApiPath = compile(API_USER);
8
8
 
9
- export function* deleteUserSaga({ payload }) {
9
+ export function* deleteUserSaga({ payload, meta }) {
10
10
  try {
11
11
  const user = payload;
12
12
  const url = toApiPath({ id: `${user.id}` });
13
13
  yield put(deleteUser.request());
14
14
  const { data } = yield call(apiJsonDelete, url, JSON_OPTS);
15
- yield put(deleteUser.success(data));
15
+ yield put({ ...deleteUser.success(data), ...(meta ? { meta } : {}) });
16
+ if (meta?.userModalId) yield put(fetchUsers());
16
17
  } catch (error) {
17
18
  if (error.response) {
18
19
  const { status, data } = error.response;
19
- yield put(deleteUser.failure({ status, data }));
20
+ yield put({
21
+ ...deleteUser.failure({ status, data }),
22
+ ...(meta ? { meta } : {}),
23
+ });
20
24
  } else {
21
- yield put(deleteUser.failure(error.message));
25
+ yield put({
26
+ ...deleteUser.failure(error.message),
27
+ ...(meta ? { meta } : {}),
28
+ });
22
29
  }
23
30
  } finally {
24
31
  yield put(deleteUser.fulfill());
@@ -1,36 +1,47 @@
1
1
  import { compile } from "path-to-regexp";
2
2
  import { all, call, put, takeLatest } from "redux-saga/effects";
3
3
  import { apiJsonPut, JSON_OPTS } from "@truedat/core/services/api";
4
- import { updateUser, updatePassword } from "../routines";
4
+ import { updateUser, updatePassword, fetchUsers } from "../routines";
5
5
  import { API_USER, API_USER_CHANGE_PASSWORD } from "../api";
6
6
 
7
- export function* updateUserSaga({ payload: user }) {
7
+ export function* updateUserSaga({ payload: user, meta }) {
8
8
  try {
9
9
  const url = compile(API_USER)({ id: `${user.id}` });
10
10
  const requestData = { user };
11
11
  yield put(updateUser.request());
12
12
  const { data } = yield call(apiJsonPut, url, requestData, JSON_OPTS);
13
- yield put(updateUser.success(data));
13
+ yield put({ ...updateUser.success(data), ...(meta ? { meta } : {}) });
14
+ if (meta?.userModalId) yield put(fetchUsers());
14
15
  } catch (error) {
15
16
  if (error.response) {
16
17
  const { status, data } = error.response;
17
- yield put(updateUser.failure({ status, data }));
18
+ yield put({
19
+ ...updateUser.failure({ status, data }),
20
+ ...(meta ? { meta } : {}),
21
+ });
18
22
  } else {
19
- yield put(updateUser.failure(error.message));
23
+ yield put({
24
+ ...updateUser.failure(error.message),
25
+ ...(meta ? { meta } : {}),
26
+ });
20
27
  }
21
28
  } finally {
22
29
  yield put(updateUser.fulfill());
23
30
  }
24
31
  }
25
32
 
26
- export function* updatePasswordSaga({ payload }) {
33
+ export function* updatePasswordSaga({ payload, meta }) {
27
34
  try {
28
35
  const url = API_USER_CHANGE_PASSWORD;
29
36
  yield put(updatePassword.request());
30
37
  const { data } = yield call(apiJsonPut, url, payload, JSON_OPTS);
31
- yield put(updatePassword.success(data));
38
+ yield put({ ...updatePassword.success(data), ...(meta ? { meta } : {}) });
39
+ if (meta?.userModalId && payload.user.id) yield put(fetchUsers());
32
40
  } catch (error) {
33
- yield put(updatePassword.failure(error.message));
41
+ yield put({
42
+ ...updatePassword.failure(error.message),
43
+ ...(meta ? { meta } : {}),
44
+ });
34
45
  } finally {
35
46
  yield put(updatePassword.fulfill());
36
47
  }
@@ -42,3 +42,14 @@ describe("selectors: filterUsers", () => {
42
42
  expect(filteredUsers).toEqual(expect.arrayContaining([miguel]));
43
43
  });
44
44
  });
45
+
46
+ it.each([" ext-1 ", "calidad", "data"])(
47
+ "searches external IDs and group names/aliases: %s",
48
+ (query) => {
49
+ const user = {
50
+ external_id: "EXT-1",
51
+ groups: [{ name: "data", alias: "Calidád" }],
52
+ };
53
+ expect(filterUsers(query)([user, { user_name: "other" }])).toEqual([user]);
54
+ },
55
+ );
@@ -30,6 +30,7 @@ describe("selectors: getUserGroupAcls", () => {
30
30
  resource: acl3.resource,
31
31
  role: acl3.role.name,
32
32
  group: acl3.group.name,
33
+ groupId: acl3.group.id,
33
34
  },
34
35
  ]),
35
36
  );
@@ -28,11 +28,13 @@ describe("selectors: getUserGroupAcls", () => {
28
28
  resource: aclWithAlias.resource,
29
29
  role: aclWithAlias.role.name,
30
30
  group: aclWithAlias.group.alias,
31
+ groupId: aclWithAlias.group.id,
31
32
  },
32
33
  {
33
34
  resource: aclWithoutAlias.resource,
34
35
  role: aclWithoutAlias.role.name,
35
36
  group: aclWithoutAlias.group.name,
37
+ groupId: aclWithoutAlias.group.id,
36
38
  },
37
39
  ]);
38
40
  });
@@ -5,7 +5,15 @@ export const filterUsers = (usersFilter) =>
5
5
  lowerDeburrTrim(usersFilter)
6
6
  ? _.filter(
7
7
  _.flow(
8
- _.at(["user_name", "full_name", "email"]),
8
+ (user) => [
9
+ user.user_name,
10
+ user.full_name,
11
+ user.email,
12
+ user.external_id,
13
+ ...(user.groups || []).flatMap((group) =>
14
+ typeof group === "string" ? [group] : [group.name, group.alias],
15
+ ),
16
+ ],
9
17
  _.map(lowerDeburrTrim),
10
18
  _.some(_.includes(lowerDeburrTrim(usersFilter))),
11
19
  ),
@@ -8,6 +8,7 @@ const buildGroupAcl = (m) => ({
8
8
  resource: m.resource,
9
9
  role: m.role.name,
10
10
  group: m.group.alias || m.group.name,
11
+ groupId: m.group.id,
11
12
  });
12
13
 
13
14
  export const getUserGroupAcls = createSelector([getUser], (user) =>
@@ -1,68 +0,0 @@
1
- import _ from "lodash/fp";
2
- import PropTypes from "prop-types";
3
- import { Divider, Header, Grid, Icon, Segment } from "semantic-ui-react";
4
- import { connect } from "react-redux";
5
- import { FormattedMessage, useIntl } from "react-intl";
6
- import UserActions from "./UserActions";
7
- import UserAcls from "./UserAcls";
8
- import UserBreadcrumbs from "./UserBreadcrumbs";
9
- import UserGroupAcls from "./UserGroupAcls";
10
-
11
- export const User = ({ user }) => {
12
- const { formatMessage } = useIntl();
13
- return _.isEmpty(user) ? null : (
14
- <>
15
- <UserBreadcrumbs name={user.user_name} />
16
- <Segment>
17
- <Grid>
18
- <Grid.Column width={8}>
19
- <Header floated="left" as="h2">
20
- <Icon
21
- circular
22
- name={formatMessage({
23
- id: "users.header.icon",
24
- defaultMessage: "users",
25
- })}
26
- />
27
- <Header.Content>
28
- {user.user_name}
29
- <Header.Subheader>
30
- <FormattedMessage id={`user.type.${user?.role}`} />
31
- </Header.Subheader>
32
- </Header.Content>
33
- </Header>
34
- </Grid.Column>
35
- <Grid.Column width={8} textAlign="right">
36
- <UserActions />
37
- </Grid.Column>
38
- <Grid.Column width={8}>
39
- {user.external_id == null ? (
40
- user.external_id
41
- ) : (
42
- <>
43
- {user.external_id}
44
- <br />
45
- </>
46
- )}
47
- {user.full_name}
48
- <br />
49
- {user.email}
50
- <br />
51
- {_.join(" ")(user.groups)}
52
- <Divider hidden />
53
- <UserAcls />
54
- <UserGroupAcls />
55
- </Grid.Column>
56
- </Grid>
57
- </Segment>
58
- </>
59
- );
60
- };
61
-
62
- User.propTypes = {
63
- user: PropTypes.object,
64
- };
65
-
66
- const mapStateToProps = ({ user }) => ({ user });
67
-
68
- export default connect(mapStateToProps)(User);
@@ -1,24 +0,0 @@
1
- import _ from "lodash/fp";
2
- import { connect } from "react-redux";
3
- import PropTypes from "prop-types";
4
- import { useIntl } from "react-intl";
5
- import UserBreadcrumbs from "./UserBreadcrumbs";
6
- import Password from "./Password";
7
-
8
- export const UserPassword = ({ user }) => {
9
- const { formatMessage } = useIntl();
10
- return (
11
- <>
12
- <UserBreadcrumbs name={formatMessage({ id: "user.password.change" })} />
13
- <Password id={_.get("id")(user)} userName={_.get("user_name")(user)} />
14
- </>
15
- );
16
- };
17
-
18
- UserPassword.propTypes = {
19
- user: PropTypes.object,
20
- };
21
-
22
- const mapStateToProps = ({ user }) => ({ user });
23
-
24
- export default connect(mapStateToProps)(UserPassword);
@@ -1,20 +0,0 @@
1
- import { render } from "@truedat/test/render";
2
- import User from "../User";
3
-
4
- describe("<User />", () => {
5
- const user = {
6
- id: "1",
7
- user_name: "joe",
8
- role: "admin",
9
- full_name: "Joe Bloggs",
10
- email: "joe@bloggs.net",
11
- };
12
- const renderOpts = {
13
- state: { user },
14
- };
15
-
16
- it("matches the latest snapshot", () => {
17
- const { container } = render(<User />, renderOpts);
18
- expect(container).toMatchSnapshot();
19
- });
20
- });
@@ -1,24 +0,0 @@
1
- import { render, waitForLoad } from "@truedat/test/render";
2
- import { UserPassword } from "../UserPassword";
3
-
4
- const renderOpts = {
5
- state: {
6
- authentication: {
7
- user_name: "foo",
8
- },
9
- },
10
- };
11
-
12
- describe("<UserPassword />", () => {
13
- const user = {
14
- id: 1,
15
- user_name: "joe",
16
- };
17
- const props = { user };
18
-
19
- it("matches the latest snapshot", async () => {
20
- const rendered = render(<UserPassword {...props} />, renderOpts);
21
- await waitForLoad(rendered);
22
- expect(rendered.container).toMatchSnapshot();
23
- });
24
- });