blob: ea0ce61b0a7d47811f4e1ec6ed664f7f6ebdedea [file] [log] [blame]
Copybara854996b2021-09-07 19:36:02 +00001// Copyright 2020 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5import {assert} from 'chai';
6import sinon from 'sinon';
7
8import * as users from './users.js';
9import * as example from 'shared/test/constants-users.js';
10
11import {prpcClient} from 'prpc-client-instance.js';
12
13let dispatch;
14
15describe('user reducers', () => {
16 it('root reducer initial state', () => {
17 const actual = users.reducer(undefined, {type: null});
18 const expected = {
19 currentUserName: null,
20 byName: {},
21 projectMemberships: {},
22 requests: {
23 batchGet: {},
24 fetch: {},
25 gatherProjectMemberships: {},
26 },
27 };
28 assert.deepEqual(actual, expected);
29 });
30
31 it('currentUserName updates on LOG_IN', () => {
32 const action = {type: users.LOG_IN, user: example.USER};
33 const actual = users.currentUserNameReducer(null, action);
34 assert.deepEqual(actual, example.NAME);
35 });
36
37 it('byName updates on BATCH_GET_SUCCESS', () => {
38 const action = {type: users.BATCH_GET_SUCCESS, users: [example.USER]};
39 const actual = users.byNameReducer({}, action);
40 assert.deepEqual(actual, {[example.NAME]: example.USER});
41 });
42
43 describe('projectMembershipsReducer', () => {
44 it('updates on GATHER_PROJECT_MEMBERSHIPS_SUCCESS', () => {
45 const action = {type: users.GATHER_PROJECT_MEMBERSHIPS_SUCCESS,
46 userName: example.NAME, projectMemberships: [example.PROJECT_MEMBER]};
47 const actual = users.projectMembershipsReducer({}, action);
48 assert.deepEqual(actual, {[example.NAME]: [example.PROJECT_MEMBER]});
49 });
50
51 it('sets empty on GATHER_PROJECT_MEMBERSHIPS_SUCCESS', () => {
52 const action = {type: users.GATHER_PROJECT_MEMBERSHIPS_SUCCESS,
53 userName: example.NAME, projectMemberships: undefined};
54 const actual = users.projectMembershipsReducer({}, action);
55 assert.deepEqual(actual, {[example.NAME]: []});
56 });
57 });
58});
59
60describe('user selectors', () => {
61 it('currentUserName', () => {
62 const state = {users: {currentUserName: example.NAME}};
63 assert.deepEqual(users.currentUserName(state), example.NAME);
64 });
65
66 it('byName', () => {
67 const state = {users: {byName: example.BY_NAME}};
68 assert.deepEqual(users.byName(state), example.BY_NAME);
69 });
70
71 it('projectMemberships', () => {
72 const membershipsByName = {[example.NAME]: [example.PROJECT_MEMBER]};
73 const state = {users: {projectMemberships: membershipsByName}};
74 assert.deepEqual(users.projectMemberships(state), membershipsByName);
75 });
76});
77
78describe('user action creators', () => {
79 beforeEach(() => {
80 sinon.stub(prpcClient, 'call');
81 dispatch = sinon.stub();
82 });
83
84 afterEach(() => {
85 prpcClient.call.restore();
86 });
87
88 describe('batchGet', () => {
89 it('success', async () => {
90 prpcClient.call.returns(Promise.resolve({users: [example.USER]}));
91
92 await users.batchGet([example.NAME])(dispatch);
93
94 sinon.assert.calledWith(dispatch, {type: users.BATCH_GET_START});
95
96 const args = {names: [example.NAME]};
97 sinon.assert.calledWith(
98 prpcClient.call, 'monorail.v3.Users', 'BatchGetUsers', args);
99
100 const action = {type: users.BATCH_GET_SUCCESS, users: [example.USER]};
101 sinon.assert.calledWith(dispatch, action);
102 });
103
104 it('failure', async () => {
105 prpcClient.call.throws();
106
107 await users.batchGet([example.NAME])(dispatch);
108
109 const action = {type: users.BATCH_GET_FAILURE, error: sinon.match.any};
110 sinon.assert.calledWith(dispatch, action);
111 });
112 });
113
114 describe('fetch', () => {
115 it('success', async () => {
116 prpcClient.call.returns(Promise.resolve(example.USER));
117
118 await users.fetch(example.NAME)(dispatch);
119
120 sinon.assert.calledWith(dispatch, {type: users.FETCH_START});
121
122 const args = {name: example.NAME};
123 sinon.assert.calledWith(
124 prpcClient.call, 'monorail.v3.Users', 'GetUser', args);
125
126 const fetchAction = {type: users.FETCH_SUCCESS, user: example.USER};
127 sinon.assert.calledWith(dispatch, fetchAction);
128
129 const logInAction = {type: users.LOG_IN, user: example.USER};
130 sinon.assert.calledWith(dispatch, logInAction);
131 });
132
133 it('failure', async () => {
134 prpcClient.call.throws();
135
136 await users.fetch(example.NAME)(dispatch);
137
138 const action = {type: users.FETCH_FAILURE, error: sinon.match.any};
139 sinon.assert.calledWith(dispatch, action);
140 });
141 });
142
143 describe('gatherProjectMemberships', () => {
144 it('success', async () => {
145 prpcClient.call.returns(Promise.resolve({projectMemberships: [
146 example.PROJECT_MEMBER,
147 ]}));
148
149 await users.gatherProjectMemberships(
150 example.NAME)(dispatch);
151
152 sinon.assert.calledWith(dispatch,
153 {type: users.GATHER_PROJECT_MEMBERSHIPS_START});
154
155 const args = {user: example.NAME};
156 sinon.assert.calledWith(
157 prpcClient.call, 'monorail.v3.Frontend',
158 'GatherProjectMembershipsForUser', args);
159
160 const action = {
161 type: users.GATHER_PROJECT_MEMBERSHIPS_SUCCESS,
162 projectMemberships: [example.PROJECT_MEMBER],
163 userName: example.NAME,
164 };
165 sinon.assert.calledWith(dispatch, action);
166 });
167
168 it('failure', async () => {
169 prpcClient.call.throws(new Error());
170
171 await users.batchGet([example.NAME])(dispatch);
172
173 const action = {type: users.BATCH_GET_FAILURE,
174 error: sinon.match.instanceOf(Error)};
175 sinon.assert.calledWith(dispatch, action);
176 });
177 });
178});