@controleonline/ui-customers 1.0.81
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/.github/agents/developer.agent.md +30 -0
- package/.github/agents/devops.agent.md +30 -0
- package/.github/agents/qa.agent.md +30 -0
- package/.github/agents/security.agent.md +30 -0
- package/.scrutinizer.yml +20 -0
- package/AGENTS.md +50 -0
- package/FUNDING.yml +1 -0
- package/README.md +23 -0
- package/docs/technical/Client-Details-Franquia-Filial.md +18 -0
- package/docs/technical/Client-Details-People-Name-Case.md +103 -0
- package/docs/technical/Cliente-Vendedor-Vinculo-e-Permissoes.md +152 -0
- package/docs/wiki.md +1 -0
- package/package.json +32 -0
- package/scripts/validate-wiki-pointer.cjs +13 -0
- package/src/react/components/tabs/AddressesTab.js +494 -0
- package/src/react/components/tabs/CategoriesTab.js +196 -0
- package/src/react/components/tabs/ClassificationChips.js +494 -0
- package/src/react/components/tabs/ContactTab.js +621 -0
- package/src/react/components/tabs/ContactTab.styles.js +119 -0
- package/src/react/components/tabs/ContractsTab.js +13 -0
- package/src/react/components/tabs/DocumentsTab.js +463 -0
- package/src/react/components/tabs/DocumentsTab.styles.js +133 -0
- package/src/react/components/tabs/EmployeeContactRow.js +83 -0
- package/src/react/components/tabs/EmployeesTab.js +454 -0
- package/src/react/components/tabs/EmployeesTab.styles.js +172 -0
- package/src/react/components/tabs/FiscalTab.js +6 -0
- package/src/react/components/tabs/FranchiseCommissionSection.js +307 -0
- package/src/react/components/tabs/FranchiseLinksManageModal.js +215 -0
- package/src/react/components/tabs/FranchiseLinksTab.js +282 -0
- package/src/react/components/tabs/GeneralTab.js +466 -0
- package/src/react/components/tabs/GeneralTab.styles.js +101 -0
- package/src/react/components/tabs/MediaTab.js +356 -0
- package/src/react/components/tabs/PeopleCategoriesPanel.js +601 -0
- package/src/react/components/tabs/ProductsTab.js +236 -0
- package/src/react/components/tabs/ProductsTab.styles.js +143 -0
- package/src/react/components/tabs/SalesmanCommissionBlock.js +120 -0
- package/src/react/components/tabs/SalesmanManageModal.js +208 -0
- package/src/react/components/tabs/SalesmanTab.js +436 -0
- package/src/react/components/tabs/SalesmanTab.styles.js +4 -0
- package/src/react/components/tabs/UserApiKeyModal.js +90 -0
- package/src/react/components/tabs/UserFormModal.js +301 -0
- package/src/react/components/tabs/UsersTab.js +426 -0
- package/src/react/components/tabs/UsersTab.styles.js +283 -0
- package/src/react/components/tabs/UsersTab.styles.test.js +42 -0
- package/src/react/components/tabs/contactMutationMessage.js +18 -0
- package/src/react/components/tabs/employeeContacts.js +214 -0
- package/src/react/components/tabs/employeeUnlink.js +68 -0
- package/src/react/components/tabs/employeesTabHelpers.js +227 -0
- package/src/react/components/tabs/franchiseCommissionHelpers.js +134 -0
- package/src/react/components/tabs/franchiseLinksTab.helpers.js +247 -0
- package/src/react/components/tabs/generalTabHelpers.js +120 -0
- package/src/react/components/tabs/salesmanTab.helpers.js +114 -0
- package/src/react/components/tabs/salesmanTabHelpers.js +173 -0
- package/src/react/components/tabs/salesmanTabMedia.js +55 -0
- package/src/react/components/tabs/salesmanTabSession.js +39 -0
- package/src/react/components/tabs/useEmployeeUnlink.js +58 -0
- package/src/react/components/tabs/useFranchiseLinksManage.js +215 -0
- package/src/react/components/tabs/useSalesmanManage.js +222 -0
- package/src/react/components/tabs/usersTabHelpers.js +221 -0
- package/src/react/domain/productSupplierFlow.js +37 -0
- package/src/react/index.js +4 -0
- package/src/react/pages/ClientDetailsSkeleton.js +84 -0
- package/src/react/pages/clientDetailsHelpers.js +17 -0
- package/src/react/pages/clients.js +27 -0
- package/src/react/pages/details.js +529 -0
- package/src/react/pages/details.page.styles.js +105 -0
- package/src/react/pages/details.styles.js +15 -0
- package/src/react/pages/employees.js +69 -0
- package/src/react/pages/franchisees.js +30 -0
- package/src/react/pages/prospects.js +21 -0
- package/src/react/pages/provider.js +21 -0
- package/src/react/router/routes.js +104 -0
- package/src/react/styles/details.js +571 -0
- package/src/store/people_categories/index.js +72 -0
- package/src/tests/browser/manager/client-details-create-user.spec.js +321 -0
- package/src/tests/browser/manager/client-details-employee-unlink.spec.js +215 -0
- package/src/tests/browser/manager/client-details-employees-refresh.spec.js +271 -0
- package/src/tests/browser/manager/client-details-enable.spec.js +241 -0
- package/src/tests/browser/manager/client-details-fiscal-tabs.spec.js +410 -0
- package/src/tests/browser/manager/client-details-franchise-commission.spec.js +318 -0
- package/src/tests/browser/manager/client-details-franchise-links.spec.js +365 -0
- package/src/tests/browser/manager/client-details-media.spec.js +405 -0
- package/src/tests/browser/manager/client-details-relationships.spec.js +313 -0
- package/src/tests/browser/manager/client-details-salesman-commission.spec.js +291 -0
- package/src/tests/browser/manager/client-details-salesman-manage.spec.js +448 -0
- package/src/tests/react/components/tabs/contactMutationMessage.test.js +25 -0
- package/src/tests/react/components/tabs/employeeContacts.test.js +266 -0
- package/src/tests/react/components/tabs/employeeUnlink.test.js +67 -0
- package/src/tests/react/components/tabs/employeesTabHelpers.media.test.js +78 -0
- package/src/tests/react/components/tabs/employeesTabHelpers.test.js +64 -0
- package/src/tests/react/components/tabs/fiscalTabContract.test.mjs +29 -0
- package/src/tests/react/components/tabs/franchiseCommissionHelpers.test.js +128 -0
- package/src/tests/react/components/tabs/franchiseLinksTab.helpers.test.mjs +166 -0
- package/src/tests/react/components/tabs/generalTabHelpers.test.js +130 -0
- package/src/tests/react/components/tabs/peopleMediaTabs.test.js +322 -0
- package/src/tests/react/components/tabs/salesmanTab.helpers.test.mjs +75 -0
- package/src/tests/react/components/tabs/salesmanTabHelpers.test.js +142 -0
- package/src/tests/react/components/tabs/salesmanTabHelpers.test.mjs +92 -0
- package/src/tests/react/components/tabs/usersTabHelpers.test.js +59 -0
- package/src/tests/react/domain/productSupplierFlow.test.mjs +55 -0
- package/src/tests/react/pages/clientDetailsHelpers.test.js +98 -0
- package/src/tests/react/pages/employees.test.js +44 -0
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
const {expect, test} = require('playwright/test');
|
|
2
|
+
const {API_ORIGIN} = require('../../../../../../../src/tests/browser/apiOrigin');
|
|
3
|
+
const {version: appVersion} = require('../../../../../../../package.json');
|
|
4
|
+
|
|
5
|
+
const CORS_HEADERS = {
|
|
6
|
+
'access-control-allow-origin': '*',
|
|
7
|
+
'access-control-allow-headers':
|
|
8
|
+
'API-TOKEN, APP-DOMAIN, DEVICE, ACCEPT, CONTENT-TYPE, X-Requested-With',
|
|
9
|
+
'access-control-allow-methods': 'GET,POST,PUT,PATCH,DELETE,OPTIONS',
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
const collection = (member = [], summary = {}) => ({
|
|
13
|
+
member,
|
|
14
|
+
'hydra:member': member,
|
|
15
|
+
totalItems: member.length,
|
|
16
|
+
'hydra:totalItems': member.length,
|
|
17
|
+
summary,
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
const jsonHeaders = () => ({
|
|
21
|
+
...CORS_HEADERS,
|
|
22
|
+
'content-type': 'application/ld+json; charset=utf-8',
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
const textHeaders = () => ({
|
|
26
|
+
...CORS_HEADERS,
|
|
27
|
+
'content-type': 'text/css; charset=utf-8',
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
const createCompany = () => ({
|
|
31
|
+
id: 3,
|
|
32
|
+
name: 'Controle Online',
|
|
33
|
+
alias: 'CONTROLE ONLINE',
|
|
34
|
+
panel_enabled: true,
|
|
35
|
+
enabled: true,
|
|
36
|
+
commercial_enabled: true,
|
|
37
|
+
theme: {
|
|
38
|
+
colors: {
|
|
39
|
+
primary: '#0EA5E9',
|
|
40
|
+
secondary: '#F97316',
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
configs: {},
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Browser smoke for ControleOnline/app-community#369:
|
|
48
|
+
* create user on Client Details with contextKey=employee without
|
|
49
|
+
* HTTP 500 "Authentication required".
|
|
50
|
+
*/
|
|
51
|
+
const mockClientDetailsCreateUserApi = async page => {
|
|
52
|
+
const company = createCompany();
|
|
53
|
+
const createdUsers = [];
|
|
54
|
+
const postUsersRequests = [];
|
|
55
|
+
|
|
56
|
+
const employee = {
|
|
57
|
+
'@id': '/people/106218',
|
|
58
|
+
id: 106218,
|
|
59
|
+
name: 'Funcionario Teste',
|
|
60
|
+
alias: 'FUNC TESTE',
|
|
61
|
+
peopleType: 'F',
|
|
62
|
+
enabled: true,
|
|
63
|
+
user: [],
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
await page.route(`${API_ORIGIN}/**`, async route => {
|
|
67
|
+
const request = route.request();
|
|
68
|
+
const url = new URL(request.url());
|
|
69
|
+
const pathname = url.pathname.replace(/^\/+/, '');
|
|
70
|
+
const method = request.method().toUpperCase();
|
|
71
|
+
|
|
72
|
+
if (method === 'OPTIONS') {
|
|
73
|
+
return route.fulfill({
|
|
74
|
+
status: 204,
|
|
75
|
+
headers: CORS_HEADERS,
|
|
76
|
+
body: '',
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (pathname === 'themes-colors.css') {
|
|
81
|
+
return route.fulfill({
|
|
82
|
+
status: 200,
|
|
83
|
+
headers: textHeaders(),
|
|
84
|
+
body: ':root { --primary: #0ea5e9; --secondary: #f97316; }',
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (pathname === 'runtime/ip') {
|
|
89
|
+
return route.fulfill({
|
|
90
|
+
status: 200,
|
|
91
|
+
headers: jsonHeaders(),
|
|
92
|
+
body: JSON.stringify({ip: '127.0.0.1'}),
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (pathname === 'people/company/default') {
|
|
97
|
+
return route.fulfill({
|
|
98
|
+
status: 200,
|
|
99
|
+
headers: jsonHeaders(),
|
|
100
|
+
body: JSON.stringify(company),
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (pathname === 'people/companies/my') {
|
|
105
|
+
return route.fulfill({
|
|
106
|
+
status: 200,
|
|
107
|
+
headers: jsonHeaders(),
|
|
108
|
+
body: JSON.stringify(collection([company])),
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (pathname === 'people/106218') {
|
|
113
|
+
return route.fulfill({
|
|
114
|
+
status: 200,
|
|
115
|
+
headers: jsonHeaders(),
|
|
116
|
+
body: JSON.stringify({
|
|
117
|
+
...employee,
|
|
118
|
+
user: createdUsers.map(u => ({
|
|
119
|
+
'@id': `/users/${u.id}`,
|
|
120
|
+
id: u.id,
|
|
121
|
+
username: u.username,
|
|
122
|
+
apiKey: u.apiKey || '',
|
|
123
|
+
})),
|
|
124
|
+
}),
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// POST /users — must receive API-TOKEN (auth) and not return 500
|
|
129
|
+
if (pathname === 'users' && method === 'POST') {
|
|
130
|
+
const headers = request.headers();
|
|
131
|
+
const apiToken =
|
|
132
|
+
headers['api-token'] || headers['API-TOKEN'] || headers['api_token'] || '';
|
|
133
|
+
let body = {};
|
|
134
|
+
try {
|
|
135
|
+
body = request.postDataJSON() || {};
|
|
136
|
+
} catch {
|
|
137
|
+
body = {};
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
postUsersRequests.push({
|
|
141
|
+
apiToken,
|
|
142
|
+
body,
|
|
143
|
+
method,
|
|
144
|
+
pathname,
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
// Simulate the fixed backend: ROLE_HUMAN + valid token → 201
|
|
148
|
+
if (!apiToken) {
|
|
149
|
+
return route.fulfill({
|
|
150
|
+
status: 401,
|
|
151
|
+
headers: jsonHeaders(),
|
|
152
|
+
body: JSON.stringify({message: 'Authentication required'}),
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const newUser = {
|
|
157
|
+
'@id': `/users/${9000 + createdUsers.length}`,
|
|
158
|
+
id: 9000 + createdUsers.length,
|
|
159
|
+
username: body.username || 'new-user',
|
|
160
|
+
apiKey: 'ak-test-' + Date.now(),
|
|
161
|
+
people: body.people || '/people/106218',
|
|
162
|
+
};
|
|
163
|
+
createdUsers.push(newUser);
|
|
164
|
+
|
|
165
|
+
return route.fulfill({
|
|
166
|
+
status: 201,
|
|
167
|
+
headers: jsonHeaders(),
|
|
168
|
+
body: JSON.stringify(newUser),
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
if (pathname === 'users' || pathname.startsWith('users/')) {
|
|
173
|
+
return route.fulfill({
|
|
174
|
+
status: 200,
|
|
175
|
+
headers: jsonHeaders(),
|
|
176
|
+
body: JSON.stringify(collection(createdUsers)),
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
if (pathname === 'people_links') {
|
|
181
|
+
return route.fulfill({
|
|
182
|
+
status: 200,
|
|
183
|
+
headers: jsonHeaders(),
|
|
184
|
+
body: JSON.stringify(collection([])),
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (pathname.startsWith('statuses') || pathname.startsWith('categories')) {
|
|
189
|
+
return route.fulfill({
|
|
190
|
+
status: 200,
|
|
191
|
+
headers: jsonHeaders(),
|
|
192
|
+
body: JSON.stringify(collection([])),
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Default empty collection for other GETs
|
|
197
|
+
return route.fulfill({
|
|
198
|
+
status: 200,
|
|
199
|
+
headers: jsonHeaders(),
|
|
200
|
+
body: JSON.stringify(collection([])),
|
|
201
|
+
});
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
await page.addInitScript(
|
|
205
|
+
({appVersion}) => {
|
|
206
|
+
const setLocalStorageItem = (key, value) => {
|
|
207
|
+
try {
|
|
208
|
+
localStorage.setItem(key, value);
|
|
209
|
+
} catch {
|
|
210
|
+
// ignore
|
|
211
|
+
}
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
setLocalStorageItem(
|
|
215
|
+
'session',
|
|
216
|
+
JSON.stringify({
|
|
217
|
+
id: 7,
|
|
218
|
+
people: '/people/7',
|
|
219
|
+
api_key: 'test-api-key',
|
|
220
|
+
token: 'test-api-key',
|
|
221
|
+
active: 1,
|
|
222
|
+
mycompany: 3,
|
|
223
|
+
roles: ['ROLE_SUPER', 'ROLE_HUMAN'],
|
|
224
|
+
}),
|
|
225
|
+
);
|
|
226
|
+
setLocalStorageItem('config', JSON.stringify({language: 'pt-br'}));
|
|
227
|
+
setLocalStorageItem('app-type', 'MANAGER');
|
|
228
|
+
setLocalStorageItem(
|
|
229
|
+
'device',
|
|
230
|
+
JSON.stringify({
|
|
231
|
+
id: 'web-manager',
|
|
232
|
+
device: 'web-manager',
|
|
233
|
+
type: 'WEB',
|
|
234
|
+
appName: 'Browser Manager',
|
|
235
|
+
appVersion,
|
|
236
|
+
buildNumber: appVersion,
|
|
237
|
+
systemName: 'web',
|
|
238
|
+
systemVersion: 'web',
|
|
239
|
+
deviceType: 'web',
|
|
240
|
+
metadata: {},
|
|
241
|
+
}),
|
|
242
|
+
);
|
|
243
|
+
},
|
|
244
|
+
{appVersion},
|
|
245
|
+
);
|
|
246
|
+
|
|
247
|
+
return {
|
|
248
|
+
getPostUsersRequests: () => postUsersRequests,
|
|
249
|
+
getCreatedUsers: () => createdUsers,
|
|
250
|
+
};
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
test.describe('client details create user browser smoke (#369)', () => {
|
|
254
|
+
test('creates user on contextKey=employee without Authentication required 500', async ({
|
|
255
|
+
page,
|
|
256
|
+
}) => {
|
|
257
|
+
const api = await mockClientDetailsCreateUserApi(page);
|
|
258
|
+
|
|
259
|
+
await page.goto(
|
|
260
|
+
'/client-details?clientId=106218&contextKey=employee&initialTab=users',
|
|
261
|
+
);
|
|
262
|
+
|
|
263
|
+
// Page / tab shell should load
|
|
264
|
+
await expect(
|
|
265
|
+
page.getByText(/Dados Cadastrais|Usuários|Users|Geral/i).first(),
|
|
266
|
+
).toBeVisible({timeout: 15000});
|
|
267
|
+
|
|
268
|
+
// Open create-user modal (Users tab with isEditing=true always in details)
|
|
269
|
+
const addUserTrigger = page
|
|
270
|
+
.getByText(/Adicionar Usuário|Adicionar|Add user|Novo usuário/i)
|
|
271
|
+
.first();
|
|
272
|
+
await expect(addUserTrigger).toBeVisible({timeout: 15000});
|
|
273
|
+
await addUserTrigger.click();
|
|
274
|
+
|
|
275
|
+
await expect(page.getByText(/Adicionar Usuário/i)).toBeVisible({
|
|
276
|
+
timeout: 10000,
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
// Fill form — username + password + confirm
|
|
280
|
+
const usernameInput = page.locator('input').first();
|
|
281
|
+
await usernameInput.fill('employee.user.369');
|
|
282
|
+
|
|
283
|
+
const passwordInputs = page.locator('input[type="password"], input');
|
|
284
|
+
// Prefer password-type fields; fall back to remaining inputs
|
|
285
|
+
const count = await passwordInputs.count();
|
|
286
|
+
if (count >= 3) {
|
|
287
|
+
await passwordInputs.nth(1).fill('Secret123!');
|
|
288
|
+
await passwordInputs.nth(2).fill('Secret123!');
|
|
289
|
+
} else {
|
|
290
|
+
// Modal fields: username already filled; next two are password/confirm
|
|
291
|
+
const allInputs = page.locator('input');
|
|
292
|
+
const inputCount = await allInputs.count();
|
|
293
|
+
if (inputCount >= 3) {
|
|
294
|
+
await allInputs.nth(1).fill('Secret123!');
|
|
295
|
+
await allInputs.nth(2).fill('Secret123!');
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// Save
|
|
300
|
+
await page.getByText(/^Salvar$/i).click();
|
|
301
|
+
|
|
302
|
+
// Success path: no 500 Authentication required; user appears or success toast
|
|
303
|
+
await expect(
|
|
304
|
+
page.getByText(/Usuário criado com sucesso|employee\.user\.369|sucesso/i),
|
|
305
|
+
).toBeVisible({timeout: 15000});
|
|
306
|
+
|
|
307
|
+
const posts = api.getPostUsersRequests();
|
|
308
|
+
expect(posts.length).toBeGreaterThanOrEqual(1);
|
|
309
|
+
|
|
310
|
+
const lastPost = posts[posts.length - 1];
|
|
311
|
+
// Auth header must be present (session api_key injected by ui-common)
|
|
312
|
+
expect(String(lastPost.apiToken || '').length).toBeGreaterThan(0);
|
|
313
|
+
// people IRI must be sent
|
|
314
|
+
expect(String(lastPost.body?.people || '')).toMatch(/people\/106218/);
|
|
315
|
+
expect(lastPost.body?.username).toBe('employee.user.369');
|
|
316
|
+
|
|
317
|
+
// Created user should be in mock store / list
|
|
318
|
+
const created = api.getCreatedUsers();
|
|
319
|
+
expect(created.some(u => u.username === 'employee.user.369')).toBeTruthy();
|
|
320
|
+
});
|
|
321
|
+
});
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browser smoke — client-details Contatos: remover colaborador.
|
|
3
|
+
* fluxo: outros
|
|
4
|
+
* flowchartIds: [1]
|
|
5
|
+
* app-community#624
|
|
6
|
+
*
|
|
7
|
+
* Steps:
|
|
8
|
+
* 1. Open Client Details contacts tab
|
|
9
|
+
* 2. Active employee is listed; disabled link is hidden
|
|
10
|
+
* 3. Trash → confirmation dialog
|
|
11
|
+
* 4. Confirm → DELETE /people/{id} → row disappears without F5
|
|
12
|
+
*/
|
|
13
|
+
const {expect, test} = require('playwright/test');
|
|
14
|
+
const {API_ORIGIN} = require('../../../../../../../src/tests/browser/apiOrigin');
|
|
15
|
+
const {version: appVersion} = require('../../../../../../../package.json');
|
|
16
|
+
|
|
17
|
+
const CORS_HEADERS = {
|
|
18
|
+
'access-control-allow-origin': '*',
|
|
19
|
+
'access-control-allow-headers':
|
|
20
|
+
'API-TOKEN, APP-DOMAIN, DEVICE, ACCEPT, CONTENT-TYPE, X-Requested-With',
|
|
21
|
+
'access-control-allow-methods': 'GET,POST,PUT,PATCH,DELETE,OPTIONS',
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const jsonHeaders = () => ({
|
|
25
|
+
...CORS_HEADERS,
|
|
26
|
+
'content-type': 'application/ld+json; charset=utf-8',
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
const collection = (member = []) => ({
|
|
30
|
+
member,
|
|
31
|
+
'hydra:member': member,
|
|
32
|
+
totalItems: member.length,
|
|
33
|
+
'hydra:totalItems': member.length,
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
const company = {
|
|
37
|
+
'@id': '/people/2',
|
|
38
|
+
id: 2,
|
|
39
|
+
name: 'CONTROLE ONLINE',
|
|
40
|
+
alias: 'CONTROLE ONLINE',
|
|
41
|
+
panel_enabled: true,
|
|
42
|
+
enabled: true,
|
|
43
|
+
commercial_enabled: true,
|
|
44
|
+
theme: {colors: {primary: '#0EA5E9', secondary: '#F97316'}},
|
|
45
|
+
configs: {},
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const client = {
|
|
49
|
+
'@id': '/people/31487',
|
|
50
|
+
id: 31487,
|
|
51
|
+
name: 'CLIENTE TESTE LTDA',
|
|
52
|
+
alias: 'CLIENTE TESTE',
|
|
53
|
+
peopleType: 'J',
|
|
54
|
+
enable: true,
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const employeeActive = {
|
|
58
|
+
'@id': '/people/90010',
|
|
59
|
+
id: 90010,
|
|
60
|
+
name: 'COLABORADOR ATIVO',
|
|
61
|
+
alias: 'ATIVO',
|
|
62
|
+
peopleType: 'F',
|
|
63
|
+
enable: true,
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
const employeeDisabled = {
|
|
67
|
+
'@id': '/people/90011',
|
|
68
|
+
id: 90011,
|
|
69
|
+
name: 'COLABORADOR INATIVO',
|
|
70
|
+
alias: 'INATIVO',
|
|
71
|
+
peopleType: 'F',
|
|
72
|
+
enable: true,
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
const mockUnlinkApi = async page => {
|
|
76
|
+
const deletedPeople = new Set();
|
|
77
|
+
|
|
78
|
+
await page.route(`${API_ORIGIN}/**`, async route => {
|
|
79
|
+
const request = route.request();
|
|
80
|
+
const url = new URL(request.url());
|
|
81
|
+
const pathname = url.pathname.replace(/^\/+/, '');
|
|
82
|
+
const method = request.method().toUpperCase();
|
|
83
|
+
|
|
84
|
+
if (method === 'OPTIONS') {
|
|
85
|
+
return route.fulfill({status: 204, headers: CORS_HEADERS, body: ''});
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (pathname === 'people/company/default') {
|
|
89
|
+
return route.fulfill({
|
|
90
|
+
status: 200,
|
|
91
|
+
headers: jsonHeaders(),
|
|
92
|
+
body: JSON.stringify(company),
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (pathname === 'people/31487' && method === 'GET') {
|
|
97
|
+
return route.fulfill({
|
|
98
|
+
status: 200,
|
|
99
|
+
headers: jsonHeaders(),
|
|
100
|
+
body: JSON.stringify(client),
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (pathname === 'people/90010' && method === 'DELETE') {
|
|
105
|
+
deletedPeople.add(90010);
|
|
106
|
+
return route.fulfill({status: 204, headers: CORS_HEADERS, body: ''});
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (
|
|
110
|
+
(pathname === 'people_links' || pathname === 'people-links') &&
|
|
111
|
+
method === 'GET'
|
|
112
|
+
) {
|
|
113
|
+
const links = [
|
|
114
|
+
{
|
|
115
|
+
'@id': '/people_links/501',
|
|
116
|
+
id: 501,
|
|
117
|
+
enable: 1,
|
|
118
|
+
linkType: 'employee',
|
|
119
|
+
people: employeeActive,
|
|
120
|
+
company: client,
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
'@id': '/people_links/502',
|
|
124
|
+
id: 502,
|
|
125
|
+
enable: 0,
|
|
126
|
+
linkType: 'employee',
|
|
127
|
+
people: employeeDisabled,
|
|
128
|
+
company: client,
|
|
129
|
+
},
|
|
130
|
+
].filter(link => !deletedPeople.has(Number(link.people.id)));
|
|
131
|
+
|
|
132
|
+
return route.fulfill({
|
|
133
|
+
status: 200,
|
|
134
|
+
headers: jsonHeaders(),
|
|
135
|
+
body: JSON.stringify(collection(links)),
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (method === 'GET') {
|
|
140
|
+
return route.fulfill({
|
|
141
|
+
status: 200,
|
|
142
|
+
headers: jsonHeaders(),
|
|
143
|
+
body: JSON.stringify(collection([])),
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return route.fulfill({
|
|
148
|
+
status: 200,
|
|
149
|
+
headers: jsonHeaders(),
|
|
150
|
+
body: JSON.stringify({}),
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
await page.addInitScript(
|
|
155
|
+
({version}) => {
|
|
156
|
+
localStorage.setItem(
|
|
157
|
+
'session',
|
|
158
|
+
JSON.stringify({
|
|
159
|
+
id: 19,
|
|
160
|
+
people: '/people/19',
|
|
161
|
+
api_key: 'test-api-key',
|
|
162
|
+
active: 1,
|
|
163
|
+
mycompany: 2,
|
|
164
|
+
roles: ['ROLE_SUPER'],
|
|
165
|
+
}),
|
|
166
|
+
);
|
|
167
|
+
localStorage.setItem('app-type', 'MANAGER');
|
|
168
|
+
localStorage.setItem('config', JSON.stringify({language: 'pt-br'}));
|
|
169
|
+
localStorage.setItem(
|
|
170
|
+
'device',
|
|
171
|
+
JSON.stringify({
|
|
172
|
+
id: 'web-manager',
|
|
173
|
+
device: 'web-manager',
|
|
174
|
+
type: 'WEB',
|
|
175
|
+
appName: 'Browser Manager',
|
|
176
|
+
appVersion: version,
|
|
177
|
+
buildNumber: version,
|
|
178
|
+
systemName: 'web',
|
|
179
|
+
systemVersion: 'web',
|
|
180
|
+
deviceType: 'web',
|
|
181
|
+
metadata: {},
|
|
182
|
+
}),
|
|
183
|
+
);
|
|
184
|
+
},
|
|
185
|
+
{version: appVersion},
|
|
186
|
+
);
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
test.describe('client-details employee unlink (#624)', () => {
|
|
190
|
+
test('hides inactive links and removes employee after confirmation', async ({
|
|
191
|
+
page,
|
|
192
|
+
}) => {
|
|
193
|
+
await mockUnlinkApi(page);
|
|
194
|
+
await page.goto(
|
|
195
|
+
'/client-details?clientId=31487&contextKey=client&initialTab=contacts',
|
|
196
|
+
);
|
|
197
|
+
|
|
198
|
+
await expect(page.getByText(/COLABORADOR ATIVO/i).first()).toBeVisible({
|
|
199
|
+
timeout: 15000,
|
|
200
|
+
});
|
|
201
|
+
await expect(page.getByText(/COLABORADOR INATIVO/i)).toHaveCount(0);
|
|
202
|
+
|
|
203
|
+
await expect(page.getByTestId('employee-unlink-501')).toBeVisible();
|
|
204
|
+
await page.getByTestId('employee-unlink-501').click();
|
|
205
|
+
await expect(
|
|
206
|
+
page.getByText(/marcado como removido e o vínculo/i),
|
|
207
|
+
).toBeVisible({timeout: 10000});
|
|
208
|
+
await page.getByText('Remover', {exact: true}).last().click();
|
|
209
|
+
|
|
210
|
+
await expect(page.getByTestId('employee-unlink-501')).toHaveCount(0, {
|
|
211
|
+
timeout: 10000,
|
|
212
|
+
});
|
|
213
|
+
await expect(page.getByText(/COLABORADOR ATIVO/i)).toHaveCount(0);
|
|
214
|
+
});
|
|
215
|
+
});
|