@controleonline/ui-customers 1.0.81 → 1.0.82
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/workflows/integration-source-gate.yml +68 -0
- package/.github/workflows/publish-npm.yml +91 -0
- package/AGENTS.md +12 -6
- package/docs/technical/Client-Details-Criar-Usuario.md +113 -0
- package/package.json +5 -4
- package/src/react/components/tabs/AddressesTab.js +240 -335
- package/src/react/components/tabs/DocumentAttachments.js +270 -0
- package/src/react/components/tabs/DocumentsTab.js +355 -463
- package/src/react/components/tabs/DocumentsTab.styles.js +123 -0
- package/src/react/components/tabs/EmployeeCreateFormFields.js +203 -0
- package/src/react/components/tabs/EmployeesTab.js +17 -171
- package/src/react/components/tabs/EmployeesTab.styles.js +220 -172
- package/src/react/components/tabs/GeneralTab.js +84 -46
- package/src/react/components/tabs/GeneralTab.styles.js +81 -77
- package/src/react/components/tabs/MediaTab.js +50 -5
- package/src/react/components/tabs/PeopleCategoriesPanel.js +161 -78
- package/src/react/components/tabs/SalesmanTab.js +1 -1
- package/src/react/components/tabs/UserFormModal.js +26 -2
- package/src/react/components/tabs/UsersTab.js +30 -19
- package/src/react/components/tabs/UsersTab.styles.js +257 -257
- package/src/react/components/tabs/UsersTabApiKeyModal.js +115 -0
- package/src/react/components/tabs/UsersTabUserModal.js +222 -0
- package/src/react/components/tabs/addressesTabHelpers.js +190 -0
- package/src/react/components/tabs/documentsTabHelpers.js +142 -0
- package/src/react/components/tabs/employeeContacts.js +3 -23
- package/src/react/components/tabs/employeeUnlink.js +7 -4
- package/src/react/components/tabs/employeesTabHelpers.js +33 -9
- package/src/react/components/tabs/generalTabHelpers.js +30 -8
- package/src/react/components/tabs/useGeneralTabPeopleLink.js +68 -0
- package/src/react/components/tabs/usersTabHelpers.js +24 -23
- package/src/react/pages/details.page.styles.js +114 -100
- package/src/react/utils/humanCompanyLinkTypes.js +28 -0
- package/src/tests/browser/manager/client-details-add-user-modal.spec.js +281 -0
- package/src/tests/browser/manager/client-details-address-create-coords.spec.js +414 -0
- package/src/tests/browser/manager/client-details-address-edit.spec.js +331 -0
- package/src/tests/browser/manager/client-details-contact-edit.spec.js +198 -0
- package/src/tests/browser/manager/client-details-create-contact.spec.js +306 -0
- package/src/tests/browser/manager/client-details-documents.spec.js +346 -0
- package/src/tests/browser/manager/client-details-identity-case.spec.js +227 -0
- package/src/tests/browser/manager/client-details-people-type.manifest.md +18 -0
- package/src/tests/browser/manager/client-details-people-type.spec.js +345 -0
- package/src/tests/browser/manager/client-details-supplier-product-create.spec.js +334 -0
- package/src/tests/browser/manager/client-details-users-tab-load.spec.js +194 -0
- package/src/tests/browser/manager/employees-salesman-after-sales.spec.js +441 -0
- package/src/tests/react/components/SalesmanTab.company.test.js +40 -0
- package/src/tests/react/components/tabs/UsersTab.styles.test.js +39 -0
- package/src/tests/react/components/tabs/addressesTabHelpers.test.js +78 -0
- package/src/tests/react/components/tabs/documentsTabContract.test.mjs +37 -0
- package/src/tests/react/components/tabs/documentsTabHelpers.test.mjs +93 -0
- package/src/tests/react/components/tabs/employeeContacts.test.js +46 -4
- package/src/tests/react/components/tabs/employeeLinkTypes.contract.test.mjs +52 -0
- package/src/tests/react/components/tabs/employeeUnlink.test.js +11 -11
- package/src/tests/react/components/tabs/employeesTabHelpers.media.test.js +2 -23
- package/src/tests/react/components/tabs/employeesTabHelpers.test.js +59 -0
- package/src/tests/react/components/tabs/generalTabHelpers.test.js +35 -0
- package/src/tests/react/components/tabs/peopleMediaTabs.test.js +217 -217
- package/src/tests/react/components/tabs/peopleType.contract.test.mjs +47 -0
- package/src/tests/react/components/tabs/resolveSeededLinkType.test.mjs +20 -0
- package/src/tests/react/components/tabs/salesmanTabMedia.no-redeclare.test.mjs +33 -0
- package/src/tests/react/components/tabs/usersTabHelpers.test.js +20 -0
- package/src/tests/react/components/tabs/usersTabHelpers.test.mjs +63 -0
- package/src/tests/react/utils/humanCompanyLinkTypes.test.js +50 -0
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browser smoke for app-community#376:
|
|
3
|
+
* GeneralTab name/alias inputs must keep exact mixed case on the value
|
|
4
|
+
* submitted via PUT/PATCH (no forced uppercase on the input → persist path).
|
|
5
|
+
*/
|
|
6
|
+
const {expect, test} = require('playwright/test');
|
|
7
|
+
const {API_ORIGIN} = require('../../../../../../../src/tests/browser/apiOrigin');
|
|
8
|
+
const {version: appVersion} = require('../../../../../../../package.json');
|
|
9
|
+
|
|
10
|
+
const CORS_HEADERS = {
|
|
11
|
+
'access-control-allow-origin': '*',
|
|
12
|
+
'access-control-allow-headers':
|
|
13
|
+
'API-TOKEN, APP-DOMAIN, DEVICE, ACCEPT, CONTENT-TYPE, X-Requested-With',
|
|
14
|
+
'access-control-allow-methods': 'GET,POST,PUT,PATCH,DELETE,OPTIONS',
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const collection = (member = [], summary = {}) => ({
|
|
18
|
+
member,
|
|
19
|
+
'hydra:member': member,
|
|
20
|
+
totalItems: member.length,
|
|
21
|
+
'hydra:totalItems': member.length,
|
|
22
|
+
summary,
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
const jsonHeaders = () => ({
|
|
26
|
+
...CORS_HEADERS,
|
|
27
|
+
'content-type': 'application/ld+json; charset=utf-8',
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
const textHeaders = () => ({
|
|
31
|
+
...CORS_HEADERS,
|
|
32
|
+
'content-type': 'text/css; charset=utf-8',
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
const createCompany = () => ({
|
|
36
|
+
id: 3,
|
|
37
|
+
name: 'Controle Online',
|
|
38
|
+
alias: 'CONTROLE ONLINE',
|
|
39
|
+
panel_enabled: true,
|
|
40
|
+
enabled: true,
|
|
41
|
+
commercial_enabled: true,
|
|
42
|
+
theme: {
|
|
43
|
+
colors: {
|
|
44
|
+
primary: '#0EA5E9',
|
|
45
|
+
secondary: '#F97316',
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
configs: {},
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
const mockApi = async page => {
|
|
52
|
+
const company = createCompany();
|
|
53
|
+
const peopleWrites = [];
|
|
54
|
+
|
|
55
|
+
await page.route(`${API_ORIGIN}/**`, async route => {
|
|
56
|
+
const request = route.request();
|
|
57
|
+
const url = new URL(request.url());
|
|
58
|
+
const pathname = url.pathname.replace(/^\/+/, '');
|
|
59
|
+
const method = request.method().toUpperCase();
|
|
60
|
+
|
|
61
|
+
if (method === 'OPTIONS') {
|
|
62
|
+
return route.fulfill({status: 204, headers: CORS_HEADERS, body: ''});
|
|
63
|
+
}
|
|
64
|
+
if (pathname === 'themes-colors.css') {
|
|
65
|
+
return route.fulfill({
|
|
66
|
+
status: 200,
|
|
67
|
+
headers: textHeaders(),
|
|
68
|
+
body: ':root { --primary: #0ea5e9; --secondary: #f97316; }',
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
if (pathname === 'runtime/ip') {
|
|
72
|
+
return route.fulfill({
|
|
73
|
+
status: 200,
|
|
74
|
+
headers: jsonHeaders(),
|
|
75
|
+
body: JSON.stringify({ip: '127.0.0.1'}),
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
if (pathname === 'people/company/default') {
|
|
79
|
+
return route.fulfill({status: 200, headers: jsonHeaders(), body: JSON.stringify(company)});
|
|
80
|
+
}
|
|
81
|
+
if (pathname === 'people/companies/my') {
|
|
82
|
+
return route.fulfill({
|
|
83
|
+
status: 200,
|
|
84
|
+
headers: jsonHeaders(),
|
|
85
|
+
body: JSON.stringify(collection([company])),
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
if (pathname === 'people/30') {
|
|
89
|
+
if (method === 'PUT' || method === 'PATCH') {
|
|
90
|
+
const body = await request.postDataJSON().catch(() => ({}));
|
|
91
|
+
peopleWrites.push({method, body});
|
|
92
|
+
return route.fulfill({
|
|
93
|
+
status: 200,
|
|
94
|
+
headers: jsonHeaders(),
|
|
95
|
+
body: JSON.stringify({
|
|
96
|
+
'@id': '/people/30',
|
|
97
|
+
id: 30,
|
|
98
|
+
peopleType: 'F',
|
|
99
|
+
enable: true,
|
|
100
|
+
...body,
|
|
101
|
+
}),
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
return route.fulfill({
|
|
105
|
+
status: 200,
|
|
106
|
+
headers: jsonHeaders(),
|
|
107
|
+
body: JSON.stringify({
|
|
108
|
+
'@id': '/people/30',
|
|
109
|
+
id: 30,
|
|
110
|
+
name: 'Joao Silva',
|
|
111
|
+
alias: 'Joao',
|
|
112
|
+
peopleType: 'F',
|
|
113
|
+
enable: true,
|
|
114
|
+
}),
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
if (pathname === 'people_links' || pathname.startsWith('people_links')) {
|
|
118
|
+
return route.fulfill({
|
|
119
|
+
status: 200,
|
|
120
|
+
headers: jsonHeaders(),
|
|
121
|
+
body: JSON.stringify(collection([])),
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
if (pathname === 'menus-people') {
|
|
125
|
+
return route.fulfill({
|
|
126
|
+
status: 200,
|
|
127
|
+
headers: jsonHeaders(),
|
|
128
|
+
body: JSON.stringify({modules: {}}),
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
if (pathname === 'configs/discovery-configs') {
|
|
132
|
+
return route.fulfill({
|
|
133
|
+
status: 200,
|
|
134
|
+
headers: jsonHeaders(),
|
|
135
|
+
body: JSON.stringify({configs: {}}),
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
return route.fulfill({
|
|
139
|
+
status: 200,
|
|
140
|
+
headers: jsonHeaders(),
|
|
141
|
+
body: JSON.stringify(collection([])),
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
await page.addInitScript(
|
|
146
|
+
({appVersion: ver}) => {
|
|
147
|
+
const set = (k, v) => {
|
|
148
|
+
try {
|
|
149
|
+
localStorage.setItem(k, v);
|
|
150
|
+
} catch {
|
|
151
|
+
// ignore
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
set(
|
|
155
|
+
'session',
|
|
156
|
+
JSON.stringify({
|
|
157
|
+
id: 7,
|
|
158
|
+
people: '/people/7',
|
|
159
|
+
api_key: 'test-api-key',
|
|
160
|
+
active: 1,
|
|
161
|
+
mycompany: 3,
|
|
162
|
+
roles: ['ROLE_SUPER'],
|
|
163
|
+
}),
|
|
164
|
+
);
|
|
165
|
+
set('config', JSON.stringify({language: 'pt-br'}));
|
|
166
|
+
set('app-type', 'MANAGER');
|
|
167
|
+
set(
|
|
168
|
+
'device',
|
|
169
|
+
JSON.stringify({
|
|
170
|
+
id: 'web-manager',
|
|
171
|
+
device: 'web-manager',
|
|
172
|
+
type: 'WEB',
|
|
173
|
+
appName: 'Browser Manager',
|
|
174
|
+
appVersion: ver,
|
|
175
|
+
buildNumber: ver,
|
|
176
|
+
systemName: 'web',
|
|
177
|
+
systemVersion: 'web',
|
|
178
|
+
deviceType: 'web',
|
|
179
|
+
metadata: {},
|
|
180
|
+
}),
|
|
181
|
+
);
|
|
182
|
+
},
|
|
183
|
+
{appVersion},
|
|
184
|
+
);
|
|
185
|
+
|
|
186
|
+
return {peopleWrites};
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
test.describe('client-details identity case preservation (#376)', () => {
|
|
190
|
+
test('GeneralTab keeps exact mixed case on name/alias in people PUT body', async ({page}) => {
|
|
191
|
+
const api = await mockApi(page);
|
|
192
|
+
|
|
193
|
+
await page.goto('/client-details?clientId=30&contextKey=contacts&parentCompanyId=29');
|
|
194
|
+
|
|
195
|
+
await expect(page.getByText('Dados Cadastrais', {exact: true})).toBeVisible({
|
|
196
|
+
timeout: 15000,
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
const MIXED_NAME = 'Cláudia Mixed Case';
|
|
200
|
+
const MIXED_ALIAS = 'Claudia Alias';
|
|
201
|
+
|
|
202
|
+
const nameInput = page.getByPlaceholder(/nome|name/i).first();
|
|
203
|
+
const aliasInput = page.getByPlaceholder(/apelido|alias|nome fantasia/i).first();
|
|
204
|
+
|
|
205
|
+
if ((await nameInput.count()) > 0) {
|
|
206
|
+
await nameInput.fill(MIXED_NAME);
|
|
207
|
+
} else {
|
|
208
|
+
await page.locator('input[type="text"], input:not([type])').nth(0).fill(MIXED_NAME);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
if ((await aliasInput.count()) > 0) {
|
|
212
|
+
await aliasInput.fill(MIXED_ALIAS);
|
|
213
|
+
} else {
|
|
214
|
+
await page.locator('input[type="text"], input:not([type])').nth(1).fill(MIXED_ALIAS);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
await page.getByText(/Save Changes|Salvar alterações/i).click();
|
|
218
|
+
|
|
219
|
+
await expect.poll(() => api.peopleWrites.length, {timeout: 15000}).toBeGreaterThanOrEqual(1);
|
|
220
|
+
|
|
221
|
+
const body = api.peopleWrites[0].body || {};
|
|
222
|
+
expect(String(body.name)).toBe(MIXED_NAME);
|
|
223
|
+
if (body.alias != null && body.alias !== '') {
|
|
224
|
+
expect(String(body.alias)).toBe(MIXED_ALIAS);
|
|
225
|
+
}
|
|
226
|
+
});
|
|
227
|
+
});
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Smoke manifesto — client-details peopleType
|
|
2
|
+
|
|
3
|
+
- **Issue:** ControleOnline/app-community#625
|
|
4
|
+
- **fluxo:** outros
|
|
5
|
+
- **flowchartIds:** [1](https://admin.controleonline.com/admin/flowcharts/1)
|
|
6
|
+
- **Spec:** `src/tests/browser/manager/client-details-people-type.spec.js`
|
|
7
|
+
- **Modelo canônico:** `People.peopleType` = `F` | `J` (contrato não é peopleType)
|
|
8
|
+
|
|
9
|
+
## Etapas (prints gerados em runtime)
|
|
10
|
+
|
|
11
|
+
| # | Arquivo | Etapa |
|
|
12
|
+
| --- | --- | --- |
|
|
13
|
+
| 01 | `01-client-details-dados-cadastrais.png` | Abrir client-details → Dados Cadastrais |
|
|
14
|
+
| 02 | `02-tipo-pf-sem-contrato.png` | Picker Tipo PF; sem opção inventada "contrato" |
|
|
15
|
+
| 03 | `03-tipo-pj-selecionado.png` | Selecionar PJ (`J`) |
|
|
16
|
+
| 04 | `04-pj-persistido-sem-f5.png` | Salvar; tipo permanece `J` sem F5; PUT `/people/30` com `peopleType: "J"` |
|
|
17
|
+
|
|
18
|
+
Os PNGs e `manifest.json` são gravados em `testInfo.outputDir/client-details-people-type/` e anexados ao relatório Playwright (`testInfo.attach`).
|
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* fluxo: outros
|
|
3
|
+
* flowchartIds: [1]
|
|
4
|
+
* app-community#625 — persist People.peopleType F/J on client-details.
|
|
5
|
+
*/
|
|
6
|
+
const fs = require('fs');
|
|
7
|
+
const path = require('path');
|
|
8
|
+
const {expect, test} = require('playwright/test');
|
|
9
|
+
const {API_ORIGIN} = require('../../../../../../../src/tests/browser/apiOrigin');
|
|
10
|
+
const {version: appVersion} = require('../../../../../../../package.json');
|
|
11
|
+
|
|
12
|
+
const FLOW_ID = 'outros';
|
|
13
|
+
const FLOWCHART_IDS = [1];
|
|
14
|
+
const FLOWCHART_LINKS = FLOWCHART_IDS.map(
|
|
15
|
+
id => `https://admin.controleonline.com/admin/flowcharts/${id}`,
|
|
16
|
+
);
|
|
17
|
+
|
|
18
|
+
const evidenceSteps = [];
|
|
19
|
+
|
|
20
|
+
const writeEvidence = async (page, outputDir, stepId, title) => {
|
|
21
|
+
fs.mkdirSync(outputDir, {recursive: true});
|
|
22
|
+
const fileName = `${stepId}.png`;
|
|
23
|
+
const filePath = path.join(outputDir, fileName);
|
|
24
|
+
await page.screenshot({path: filePath, fullPage: true});
|
|
25
|
+
evidenceSteps.push({
|
|
26
|
+
id: stepId,
|
|
27
|
+
title,
|
|
28
|
+
screenshot: fileName,
|
|
29
|
+
url: page.url(),
|
|
30
|
+
});
|
|
31
|
+
return filePath;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const writeManifest = outputDir => {
|
|
35
|
+
const manifest = {
|
|
36
|
+
fluxo: FLOW_ID,
|
|
37
|
+
flowchartIds: FLOWCHART_IDS,
|
|
38
|
+
flowchartLinks: FLOWCHART_LINKS,
|
|
39
|
+
title: 'client-details peopleType F/J persist without invented contrato',
|
|
40
|
+
issue: 'ControleOnline/app-community#625',
|
|
41
|
+
steps: evidenceSteps,
|
|
42
|
+
};
|
|
43
|
+
fs.writeFileSync(
|
|
44
|
+
path.join(outputDir, 'manifest.json'),
|
|
45
|
+
`${JSON.stringify(manifest, null, 2)}\n`,
|
|
46
|
+
);
|
|
47
|
+
return manifest;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const CORS_HEADERS = {
|
|
51
|
+
'access-control-allow-origin': '*',
|
|
52
|
+
'access-control-allow-headers':
|
|
53
|
+
'API-TOKEN, APP-DOMAIN, DEVICE, ACCEPT, CONTENT-TYPE, X-Requested-With',
|
|
54
|
+
'access-control-allow-methods': 'GET,POST,PUT,PATCH,DELETE,OPTIONS',
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const collection = (member = []) => ({
|
|
58
|
+
member,
|
|
59
|
+
'hydra:member': member,
|
|
60
|
+
totalItems: member.length,
|
|
61
|
+
'hydra:totalItems': member.length,
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
const jsonHeaders = () => ({
|
|
65
|
+
...CORS_HEADERS,
|
|
66
|
+
'content-type': 'application/ld+json; charset=utf-8',
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
const textHeaders = () => ({
|
|
70
|
+
...CORS_HEADERS,
|
|
71
|
+
'content-type': 'text/css; charset=utf-8',
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
const createCompany = () => ({
|
|
75
|
+
id: 3,
|
|
76
|
+
name: 'Controle Online',
|
|
77
|
+
alias: 'CONTROLE ONLINE',
|
|
78
|
+
panel_enabled: true,
|
|
79
|
+
enabled: true,
|
|
80
|
+
commercial_enabled: true,
|
|
81
|
+
theme: {
|
|
82
|
+
colors: {
|
|
83
|
+
primary: '#0EA5E9',
|
|
84
|
+
secondary: '#F97316',
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
configs: {},
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
const mockClientDetailsPeopleTypeApi = async page => {
|
|
91
|
+
const company = createCompany();
|
|
92
|
+
let peopleType = 'F';
|
|
93
|
+
const peopleWrites = [];
|
|
94
|
+
|
|
95
|
+
await page.route(`${API_ORIGIN}/**`, async route => {
|
|
96
|
+
const request = route.request();
|
|
97
|
+
const url = new URL(request.url());
|
|
98
|
+
const pathname = url.pathname.replace(/^\/+/, '');
|
|
99
|
+
const method = request.method().toUpperCase();
|
|
100
|
+
|
|
101
|
+
if (method === 'OPTIONS') {
|
|
102
|
+
return route.fulfill({
|
|
103
|
+
status: 204,
|
|
104
|
+
headers: CORS_HEADERS,
|
|
105
|
+
body: '',
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (pathname === 'themes-colors.css') {
|
|
110
|
+
return route.fulfill({
|
|
111
|
+
status: 200,
|
|
112
|
+
headers: textHeaders(),
|
|
113
|
+
body: ':root { --primary: #0ea5e9; --secondary: #f97316; }',
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (pathname === 'runtime/ip') {
|
|
118
|
+
return route.fulfill({
|
|
119
|
+
status: 200,
|
|
120
|
+
headers: jsonHeaders(),
|
|
121
|
+
body: JSON.stringify({ip: '127.0.0.1'}),
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (pathname === 'people/company/default') {
|
|
126
|
+
return route.fulfill({
|
|
127
|
+
status: 200,
|
|
128
|
+
headers: jsonHeaders(),
|
|
129
|
+
body: JSON.stringify(company),
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if (pathname === 'people/companies/my') {
|
|
134
|
+
return route.fulfill({
|
|
135
|
+
status: 200,
|
|
136
|
+
headers: jsonHeaders(),
|
|
137
|
+
body: JSON.stringify(collection([company])),
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
if (pathname === 'people/30') {
|
|
142
|
+
if (method === 'PUT' || method === 'PATCH') {
|
|
143
|
+
const body = await request.postDataJSON().catch(() => ({}));
|
|
144
|
+
peopleWrites.push({method, body});
|
|
145
|
+
if (body.peopleType === 'F' || body.peopleType === 'J') {
|
|
146
|
+
peopleType = body.peopleType;
|
|
147
|
+
}
|
|
148
|
+
return route.fulfill({
|
|
149
|
+
status: 200,
|
|
150
|
+
headers: jsonHeaders(),
|
|
151
|
+
body: JSON.stringify({
|
|
152
|
+
'@id': '/people/30',
|
|
153
|
+
id: 30,
|
|
154
|
+
name: 'JOAO SILVA',
|
|
155
|
+
alias: 'JOAO SILVA',
|
|
156
|
+
peopleType,
|
|
157
|
+
enable: true,
|
|
158
|
+
}),
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
return route.fulfill({
|
|
163
|
+
status: 200,
|
|
164
|
+
headers: jsonHeaders(),
|
|
165
|
+
body: JSON.stringify({
|
|
166
|
+
'@id': '/people/30',
|
|
167
|
+
id: 30,
|
|
168
|
+
name: 'JOAO SILVA',
|
|
169
|
+
alias: 'JOAO SILVA',
|
|
170
|
+
peopleType,
|
|
171
|
+
enable: true,
|
|
172
|
+
}),
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
if (pathname === 'people_links' || pathname.startsWith('people_links')) {
|
|
177
|
+
return route.fulfill({
|
|
178
|
+
status: 200,
|
|
179
|
+
headers: jsonHeaders(),
|
|
180
|
+
body: JSON.stringify(
|
|
181
|
+
collection([
|
|
182
|
+
{
|
|
183
|
+
id: 8,
|
|
184
|
+
linkType: 'employee',
|
|
185
|
+
company: {'@id': '/people/29', id: 29},
|
|
186
|
+
people: {
|
|
187
|
+
'@id': '/people/30',
|
|
188
|
+
id: 30,
|
|
189
|
+
name: 'JOAO SILVA',
|
|
190
|
+
alias: 'JOAO SILVA',
|
|
191
|
+
peopleType,
|
|
192
|
+
},
|
|
193
|
+
},
|
|
194
|
+
]),
|
|
195
|
+
),
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
if (pathname === 'menus-people') {
|
|
200
|
+
return route.fulfill({
|
|
201
|
+
status: 200,
|
|
202
|
+
headers: jsonHeaders(),
|
|
203
|
+
body: JSON.stringify({modules: {}}),
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
if (pathname === 'configs/discovery-configs') {
|
|
208
|
+
return route.fulfill({
|
|
209
|
+
status: 200,
|
|
210
|
+
headers: jsonHeaders(),
|
|
211
|
+
body: JSON.stringify({configs: {}}),
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
return route.fulfill({
|
|
216
|
+
status: 200,
|
|
217
|
+
headers: jsonHeaders(),
|
|
218
|
+
body: JSON.stringify(collection([])),
|
|
219
|
+
});
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
await page.addInitScript(
|
|
223
|
+
({appVersion}) => {
|
|
224
|
+
const setLocalStorageItem = (key, value) => {
|
|
225
|
+
try {
|
|
226
|
+
localStorage.setItem(key, value);
|
|
227
|
+
} catch {
|
|
228
|
+
// ignore
|
|
229
|
+
}
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
setLocalStorageItem(
|
|
233
|
+
'session',
|
|
234
|
+
JSON.stringify({
|
|
235
|
+
id: 7,
|
|
236
|
+
people: '/people/7',
|
|
237
|
+
api_key: 'test-api-key',
|
|
238
|
+
active: 1,
|
|
239
|
+
mycompany: 3,
|
|
240
|
+
roles: ['ROLE_SUPER'],
|
|
241
|
+
}),
|
|
242
|
+
);
|
|
243
|
+
setLocalStorageItem('config', JSON.stringify({language: 'pt-br'}));
|
|
244
|
+
setLocalStorageItem('app-type', 'MANAGER');
|
|
245
|
+
setLocalStorageItem(
|
|
246
|
+
'device',
|
|
247
|
+
JSON.stringify({
|
|
248
|
+
id: 'web-manager',
|
|
249
|
+
device: 'web-manager',
|
|
250
|
+
type: 'WEB',
|
|
251
|
+
appName: 'Browser Manager',
|
|
252
|
+
appVersion,
|
|
253
|
+
buildNumber: appVersion,
|
|
254
|
+
systemName: 'web',
|
|
255
|
+
systemVersion: 'web',
|
|
256
|
+
deviceType: 'web',
|
|
257
|
+
metadata: {},
|
|
258
|
+
}),
|
|
259
|
+
);
|
|
260
|
+
},
|
|
261
|
+
{appVersion},
|
|
262
|
+
);
|
|
263
|
+
|
|
264
|
+
return {getPeopleWrites: () => peopleWrites};
|
|
265
|
+
};
|
|
266
|
+
|
|
267
|
+
test.describe('client details peopleType browser smoke', () => {
|
|
268
|
+
test('selects PJ and persists peopleType without inventing contrato', async ({
|
|
269
|
+
page,
|
|
270
|
+
}, testInfo) => {
|
|
271
|
+
const api = await mockClientDetailsPeopleTypeApi(page);
|
|
272
|
+
const outputDir = path.join(
|
|
273
|
+
testInfo.outputDir,
|
|
274
|
+
'client-details-people-type',
|
|
275
|
+
);
|
|
276
|
+
|
|
277
|
+
await page.goto(
|
|
278
|
+
'/client-details?clientId=30&contextKey=contacts&parentCompanyId=29&initialTab=general',
|
|
279
|
+
);
|
|
280
|
+
|
|
281
|
+
await expect(page.getByText('Dados Cadastrais', {exact: true})).toBeVisible({
|
|
282
|
+
timeout: 15000,
|
|
283
|
+
});
|
|
284
|
+
await writeEvidence(
|
|
285
|
+
page,
|
|
286
|
+
outputDir,
|
|
287
|
+
'01-client-details-dados-cadastrais',
|
|
288
|
+
'Abrir client-details na aba Dados Cadastrais',
|
|
289
|
+
);
|
|
290
|
+
|
|
291
|
+
const typePicker = page.getByLabel('Tipo de colaborador');
|
|
292
|
+
await expect(typePicker).toBeVisible();
|
|
293
|
+
await expect(typePicker).toHaveValue('F');
|
|
294
|
+
await expect(page.getByText('Pessoa Física')).toBeVisible();
|
|
295
|
+
await expect(page.getByText('contrato', {exact: true})).toHaveCount(0);
|
|
296
|
+
await writeEvidence(
|
|
297
|
+
page,
|
|
298
|
+
outputDir,
|
|
299
|
+
'02-tipo-pf-sem-contrato',
|
|
300
|
+
'Tipo PF visível; opção inventada contrato ausente',
|
|
301
|
+
);
|
|
302
|
+
|
|
303
|
+
await typePicker.selectOption('J');
|
|
304
|
+
await expect(typePicker).toHaveValue('J');
|
|
305
|
+
await writeEvidence(
|
|
306
|
+
page,
|
|
307
|
+
outputDir,
|
|
308
|
+
'03-tipo-pj-selecionado',
|
|
309
|
+
'Selecionar Pessoa Jurídica no picker F|J',
|
|
310
|
+
);
|
|
311
|
+
|
|
312
|
+
await page.getByText(/Save Changes|Salvar alterações/i).click();
|
|
313
|
+
|
|
314
|
+
await expect.poll(() => api.getPeopleWrites().length).toBeGreaterThan(0);
|
|
315
|
+
const lastWrite = api.getPeopleWrites().at(-1);
|
|
316
|
+
expect(lastWrite.body.peopleType).toBe('J');
|
|
317
|
+
expect(lastWrite.body.peopleType).not.toBe('contrato');
|
|
318
|
+
|
|
319
|
+
await expect(typePicker).toHaveValue('J');
|
|
320
|
+
await writeEvidence(
|
|
321
|
+
page,
|
|
322
|
+
outputDir,
|
|
323
|
+
'04-pj-persistido-sem-f5',
|
|
324
|
+
'Após Salvar, tipo permanece J sem F5 (PUT peopleType=J)',
|
|
325
|
+
);
|
|
326
|
+
|
|
327
|
+
const manifest = writeManifest(outputDir);
|
|
328
|
+
expect(manifest.fluxo).toBe(FLOW_ID);
|
|
329
|
+
expect(manifest.flowchartIds).toEqual(FLOWCHART_IDS);
|
|
330
|
+
expect(manifest.steps).toHaveLength(4);
|
|
331
|
+
await testInfo.attach('smoke-manifest', {
|
|
332
|
+
body: Buffer.from(JSON.stringify(manifest, null, 2)),
|
|
333
|
+
contentType: 'application/json',
|
|
334
|
+
});
|
|
335
|
+
for (const step of evidenceSteps) {
|
|
336
|
+
const pngPath = path.join(outputDir, step.screenshot);
|
|
337
|
+
if (fs.existsSync(pngPath)) {
|
|
338
|
+
await testInfo.attach(step.id, {
|
|
339
|
+
path: pngPath,
|
|
340
|
+
contentType: 'image/png',
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
});
|
|
345
|
+
});
|