@controleonline/ui-common 1.2.71 → 1.2.76

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 (150) hide show
  1. package/.github/actions/workers/manager/action.yml +147 -0
  2. package/.github/actions/workers/qa/action.yml +44 -0
  3. package/.github/actions/workers/security/action.yml +44 -0
  4. package/.github/actions/workers/technical-documenter/action.yml +51 -0
  5. package/.github/workflows/manager-worker.yml +168 -0
  6. package/.github/workflows/publish-npm.yml +45 -0
  7. package/.gitmodules +3 -0
  8. package/AGENTS.md +6 -0
  9. package/README.md +14 -0
  10. package/package.json +3 -2
  11. package/src/api/fetch.js +1 -1
  12. package/src/api/index.js +92 -22
  13. package/src/react/components/AddImportModal.js +94 -110
  14. package/src/react/components/BottomNavigationBar.config.js +211 -231
  15. package/src/react/components/CategoryForm.js +52 -35
  16. package/src/react/components/DefaultProvider.native.js +131 -95
  17. package/src/react/components/DefaultProvider.web.js +148 -74
  18. package/src/react/components/NetworkPrinterPreviewModal.js +249 -0
  19. package/src/react/components/NetworkPrinterPreviewModal.styles.js +159 -0
  20. package/src/react/components/RuntimeInfoFooter.js +164 -104
  21. package/src/react/components/RuntimeInfoFooter.styles.js +3 -0
  22. package/src/react/components/UnifiedPaymentBar.js +7 -4
  23. package/src/react/components/UserAvatar.js +160 -0
  24. package/src/react/components/integrations/IntegrationHero/index.js +48 -0
  25. package/src/react/components/integrations/IntegrationHero/styles.js +57 -0
  26. package/src/react/components/integrations/IntegrationTabs/index.js +89 -0
  27. package/src/react/components/integrations/IntegrationTabs/styles.js +44 -0
  28. package/src/react/config/deviceConfigBootstrap.js +5 -3
  29. package/src/react/pages/Connections.js +229 -0
  30. package/src/react/pages/Connections.styles.js +222 -0
  31. package/src/react/pages/DeviceDetailPage.js +2865 -0
  32. package/src/react/pages/DeviceDetailPage.styles.js +308 -0
  33. package/src/react/pages/Devices/currentDevice.js +194 -0
  34. package/src/react/pages/Devices/deviceTypes/DeviceGroupCard.js +257 -0
  35. package/src/react/pages/Devices/deviceTypes/all.js +23 -0
  36. package/src/react/pages/Devices/deviceTypes/device.js +25 -0
  37. package/src/react/pages/Devices/deviceTypes/deviceListHelpers.js +178 -0
  38. package/src/react/pages/Devices/deviceTypes/display.js +26 -0
  39. package/src/react/pages/Devices/deviceTypes/index.js +145 -0
  40. package/src/react/pages/Devices/deviceTypes/ipCamera.js +35 -0
  41. package/src/react/pages/Devices/deviceTypes/pdv.js +88 -0
  42. package/src/react/pages/Devices/deviceTypes/printer.js +37 -0
  43. package/src/react/pages/Devices/deviceTypes/shared.js +453 -0
  44. package/src/react/pages/Devices/deviceTypes/useDeviceNetworkConnectivity.js +145 -0
  45. package/src/react/pages/Devices.js +183 -0
  46. package/src/react/pages/Devices.styles.js +353 -0
  47. package/src/react/pages/Food99IntegrationPage/components/Food99CatalogTab.js +219 -0
  48. package/src/react/pages/Food99IntegrationPage/components/Food99OverviewTab.js +134 -0
  49. package/src/react/pages/Food99IntegrationPage/components/Food99PreviewModal.js +173 -0
  50. package/src/react/pages/Food99IntegrationPage/components/Food99ProductCard.js +1 -0
  51. package/src/react/pages/Food99IntegrationPage/components/Food99QuickWalletModal.js +181 -0
  52. package/src/react/pages/Food99IntegrationPage/components/Food99SettingsTab.js +306 -0
  53. package/src/react/pages/Food99IntegrationPage/components/Food99StoreTab.js +417 -0
  54. package/src/react/pages/Food99IntegrationPage/index.js +1530 -0
  55. package/src/react/pages/Food99IntegrationPage/styles.js +792 -0
  56. package/src/react/pages/Food99IntegrationPage/utils.js +155 -0
  57. package/src/react/pages/Food99IntegrationPage.js +1 -0
  58. package/src/react/pages/Food99IntegrationPage.styles.js +1 -0
  59. package/src/react/pages/GenericLogPage.js +42 -167
  60. package/src/react/pages/IFoodIntegrationPage/components/IFoodCatalogTab.js +8 -0
  61. package/src/react/pages/IFoodIntegrationPage/components/IFoodOperationsTab.js +420 -0
  62. package/src/react/pages/IFoodIntegrationPage/components/IFoodOverviewTab.js +118 -0
  63. package/src/react/pages/IFoodIntegrationPage/components/IFoodPreviewModal.js +103 -0
  64. package/src/react/pages/IFoodIntegrationPage/components/IFoodProductCard.js +1 -0
  65. package/src/react/pages/IFoodIntegrationPage/components/IFoodStoreTab.js +150 -0
  66. package/src/react/pages/IFoodIntegrationPage/index.js +1298 -0
  67. package/src/react/pages/IFoodIntegrationPage/styles.js +764 -0
  68. package/src/react/pages/IFoodIntegrationPage/utils.js +91 -0
  69. package/src/react/pages/IFoodIntegrationPage.js +1 -0
  70. package/src/react/pages/IFoodIntegrationPage.styles.js +1 -0
  71. package/src/react/pages/Imports.js +214 -166
  72. package/src/react/pages/IntegrationConfigPage.js +744 -0
  73. package/src/react/pages/IntegrationConfigPage.styles.js +269 -0
  74. package/src/react/pages/Integrations.js +299 -0
  75. package/src/react/pages/Integrations.styles.js +130 -0
  76. package/src/react/pages/ManagerOrderNotificationsPage.js +642 -0
  77. package/src/react/pages/MarketplaceIntegrationPage/components/MarketplaceProductCard.js +205 -0
  78. package/src/react/pages/MarketplaceIntegrationPage/components/RemoteMarketplaceMenuTab.js +335 -0
  79. package/src/react/pages/MarketplaceIntegrationPage/index.js +60 -0
  80. package/src/react/pages/MarketplaceIntegrationPage/utils.js +137 -0
  81. package/src/react/pages/MercadoLivreIntegrationPage.js +538 -0
  82. package/src/react/pages/PrinterDeviceDetailPage.js +1916 -0
  83. package/src/react/pages/PrinterDeviceDetailPage.styles.js +223 -0
  84. package/src/react/pages/PrinterDeviceFormPage.js +521 -0
  85. package/src/react/pages/PrinterDeviceFormPage.styles.js +159 -0
  86. package/src/react/pages/WhatsAppConnectionPage.js +459 -0
  87. package/src/react/pages/WhatsAppConnectionPage.styles.js +284 -0
  88. package/src/react/pages/integrationsCatalog.js +399 -0
  89. package/src/react/services/Cielo/Cielo.js +193 -193
  90. package/src/react/utils/categoryContexts.js +46 -0
  91. package/src/react/utils/entityDisplay.js +222 -217
  92. package/src/react/utils/fileUrl.js +39 -20
  93. package/src/react/utils/integrationPage.js +16 -0
  94. package/src/react/utils/runtimeFooter.js +40 -22
  95. package/src/react/utils/runtimeLanguage.js +50 -9
  96. package/src/react/utils/runtimeMenu.js +191 -131
  97. package/src/react/utils/runtimeZoom.js +43 -0
  98. package/src/react/utils/shopConfig.js +27 -15
  99. package/src/react/utils/shopFranchises.js +126 -1
  100. package/src/react/utils/storeColumns.js +23 -4
  101. package/src/react/utils/userAvatar.js +104 -0
  102. package/src/store/categories/index.js +48 -20
  103. package/src/store/device_config/index.js +62 -21
  104. package/src/store/entity_log/index.js +22 -1
  105. package/src/store/imports/customActions.js +51 -0
  106. package/src/store/imports/index.js +89 -88
  107. package/src/store/status/index.js +11 -11
  108. package/src/store/themes/index.js +22 -0
  109. package/src/store/timezones/index.js +3 -1
  110. package/src/tests/browser/manager/connections.spec.js +143 -0
  111. package/src/tests/browser/manager/devices-current.spec.js +343 -0
  112. package/src/tests/browser/manager/mercado-livre-integration.spec.js +268 -0
  113. package/src/tests/react/api/deviceHeaders.test.js +114 -0
  114. package/src/tests/react/components/AddImportModal.test.js +166 -0
  115. package/src/tests/react/components/BottomNavigationBar.config.test.js +20 -0
  116. package/src/tests/react/components/UserAvatar.test.js +52 -0
  117. package/src/tests/react/pages/DevicePickerStyles.test.js +47 -0
  118. package/src/tests/react/pages/Devices/deviceListHelpers.test.js +39 -0
  119. package/src/tests/react/pages/DevicesCurrentDevice.test.js +198 -0
  120. package/src/tests/react/pages/connectionsHelpers.test.js +34 -0
  121. package/src/tests/react/pages/mercadoLivreIntegrationPageContract.test.mjs +16 -0
  122. package/src/tests/react/services/Cielo.test.js +190 -190
  123. package/src/tests/react/store/categoriesOrdering.test.js +26 -0
  124. package/src/tests/react/utils/appDomain.test.js +62 -0
  125. package/src/tests/react/utils/entityDisplay.test.js +2 -2
  126. package/src/tests/react/utils/fileUrl.test.js +3 -3
  127. package/src/tests/react/utils/formatter.test.mjs +33 -0
  128. package/src/tests/react/utils/runtimeFooter.test.js +29 -4
  129. package/src/tests/react/utils/runtimeLanguage.test.js +79 -9
  130. package/src/tests/react/utils/runtimeMenu.test.js +198 -134
  131. package/src/tests/react/utils/runtimeZoom.test.js +38 -0
  132. package/src/tests/react/utils/shopConfig.test.js +10 -9
  133. package/src/tests/react/utils/shopFranchises.test.js +43 -0
  134. package/src/tests/react/utils/translate.discovery.test.mjs +170 -0
  135. package/src/tests/react/utils/translate.test.helpers.mjs +152 -0
  136. package/src/tests/react/utils/translate.test.mjs +141 -349
  137. package/src/tests/react/utils/userAvatar.test.js +63 -0
  138. package/src/utils/appDomain.js +15 -4
  139. package/src/utils/formatter.js +104 -16
  140. package/src/utils/integrationConfigs.js +80 -80
  141. package/src/utils/translate.js +222 -438
  142. package/src/utils/translateDiscovery.js +96 -0
  143. package/src/utils/translateNormalize.js +33 -0
  144. package/src/utils/translatePending.js +92 -0
  145. package/src/utils/translateStorage.js +142 -0
  146. package/.github/agents/developer.agent.md +0 -30
  147. package/.github/agents/devops.agent.md +0 -30
  148. package/.github/agents/qa.agent.md +0 -30
  149. package/.github/agents/security.agent.md +0 -30
  150. package/.github/workflows/npmjs.yml +0 -35
@@ -0,0 +1,343 @@
1
+ const {expect, test} = require('playwright/test');
2
+ const packageJson = require('../../../../../../../package.json');
3
+ const {API_ORIGIN} = require('../../../../../../../src/tests/browser/apiOrigin');
4
+
5
+ const APP_VERSION = packageJson?.version || '1.0.0';
6
+ const CURRENT_DEVICE_ID = 'web-7';
7
+
8
+ const CORS_HEADERS = {
9
+ 'access-control-allow-origin': '*',
10
+ 'access-control-allow-headers':
11
+ 'API-TOKEN, APP-DOMAIN, DEVICE, ACCEPT, CONTENT-TYPE, X-Requested-With',
12
+ 'access-control-allow-methods': 'GET,POST,PUT,PATCH,DELETE,OPTIONS',
13
+ };
14
+
15
+ const jsonHeaders = () => ({
16
+ ...CORS_HEADERS,
17
+ 'content-type': 'application/ld+json; charset=utf-8',
18
+ });
19
+
20
+ const collection = member => ({
21
+ member,
22
+ 'hydra:member': member,
23
+ totalItems: member.length,
24
+ 'hydra:totalItems': member.length,
25
+ summary: {},
26
+ });
27
+
28
+ const currentDevice = {
29
+ '@id': '/devices/396',
30
+ '@type': 'Device',
31
+ id: 396,
32
+ device: CURRENT_DEVICE_ID,
33
+ alias: 'Caixa atual',
34
+ metadata: {
35
+ runtime: 'web',
36
+ network: {
37
+ publicIp: '127.0.0.1',
38
+ },
39
+ },
40
+ };
41
+
42
+ const remoteDevice = {
43
+ '@id': '/devices/410',
44
+ '@type': 'Device',
45
+ id: 410,
46
+ device: 'remote-pdv',
47
+ alias: 'Caixa remoto',
48
+ metadata: {
49
+ runtime: 'android',
50
+ },
51
+ };
52
+
53
+ const createDeviceConfig = ({
54
+ id,
55
+ type,
56
+ device = currentDevice,
57
+ }) => ({
58
+ '@id': `/device_configs/${id}`,
59
+ '@type': 'DeviceConfig',
60
+ id,
61
+ type,
62
+ people: '/people/3',
63
+ device,
64
+ configs: JSON.stringify({
65
+ 'config-version': APP_VERSION,
66
+ 'pos-gateway': 'infinite-pay',
67
+ }),
68
+ });
69
+
70
+ const mockDevicesApi = async (page, {includeCurrentPdv}) => {
71
+ const company = {
72
+ id: 3,
73
+ name: 'Teste',
74
+ alias: 'TESTE',
75
+ panel_enabled: true,
76
+ enabled: true,
77
+ commercial_enabled: true,
78
+ theme: {
79
+ colors: {
80
+ primary: '#0EA5E9',
81
+ cardBackground: '#FFFFFF',
82
+ cardBorder: '#D8E0EA',
83
+ cardSelectedBackground: '#E8F8FD',
84
+ cardSelectedBorder: '#0284C7',
85
+ cardSelectedText: '#0F172A',
86
+ badgeSelectedBackground: '#CDEFFA',
87
+ badgeSelectedText: '#075985',
88
+ },
89
+ },
90
+ };
91
+ const managerConfig = createDeviceConfig({id: 487, type: 'MANAGER'});
92
+ const currentPdvConfig = createDeviceConfig({id: 488, type: 'PDV'});
93
+ const remotePdvConfig = createDeviceConfig({
94
+ id: 410,
95
+ type: 'PDV',
96
+ device: remoteDevice,
97
+ });
98
+ const deviceConfigs = [
99
+ remotePdvConfig,
100
+ managerConfig,
101
+ ...(includeCurrentPdv ? [currentPdvConfig] : []),
102
+ ];
103
+ const savedPdvRequests = [];
104
+
105
+ await page.route(`${API_ORIGIN}/**`, async route => {
106
+ const request = route.request();
107
+ const url = new URL(request.url());
108
+ const pathname = url.pathname.replace(/^\/+/, '');
109
+ const method = request.method().toUpperCase();
110
+
111
+ if (method === 'OPTIONS') {
112
+ return route.fulfill({
113
+ status: 204,
114
+ headers: CORS_HEADERS,
115
+ body: '',
116
+ });
117
+ }
118
+
119
+ if (pathname === 'themes-colors.css') {
120
+ return route.fulfill({
121
+ status: 200,
122
+ headers: {
123
+ ...CORS_HEADERS,
124
+ 'content-type': 'text/css; charset=utf-8',
125
+ },
126
+ body: ':root { --primary: #0ea5e9; }',
127
+ });
128
+ }
129
+
130
+ if (pathname === 'runtime/ip') {
131
+ return route.fulfill({
132
+ status: 200,
133
+ headers: jsonHeaders(),
134
+ body: JSON.stringify({ip: '127.0.0.1'}),
135
+ });
136
+ }
137
+
138
+ if (pathname === 'menus-people') {
139
+ return route.fulfill({
140
+ status: 200,
141
+ headers: jsonHeaders(),
142
+ body: JSON.stringify({modules: {}}),
143
+ });
144
+ }
145
+
146
+ if (pathname === 'people/companies/my') {
147
+ return route.fulfill({
148
+ status: 200,
149
+ headers: jsonHeaders(),
150
+ body: JSON.stringify(collection([company])),
151
+ });
152
+ }
153
+
154
+ if (pathname === 'people/company/default') {
155
+ return route.fulfill({
156
+ status: 200,
157
+ headers: jsonHeaders(),
158
+ body: JSON.stringify(company),
159
+ });
160
+ }
161
+
162
+ if (pathname === 'configs/discovery-configs') {
163
+ return route.fulfill({
164
+ status: 200,
165
+ headers: jsonHeaders(),
166
+ body: JSON.stringify({configs: {}}),
167
+ });
168
+ }
169
+
170
+ if (pathname === 'devices' && method === 'GET') {
171
+ return route.fulfill({
172
+ status: 200,
173
+ headers: jsonHeaders(),
174
+ body: JSON.stringify(collection([currentDevice])),
175
+ });
176
+ }
177
+
178
+ if (pathname === 'devices' && method === 'POST') {
179
+ return route.fulfill({
180
+ status: 200,
181
+ headers: jsonHeaders(),
182
+ body: JSON.stringify(currentDevice),
183
+ });
184
+ }
185
+
186
+ if (pathname === 'device_configs' && method === 'GET') {
187
+ const requestedDevice = url.searchParams.get('device.device');
188
+ const requestedType = url.searchParams.get('type');
189
+ const filtered = deviceConfigs.filter(deviceConfig => {
190
+ if (
191
+ requestedDevice &&
192
+ deviceConfig.device.device !== requestedDevice
193
+ ) {
194
+ return false;
195
+ }
196
+
197
+ if (requestedType && deviceConfig.type !== requestedType) {
198
+ return false;
199
+ }
200
+
201
+ return true;
202
+ });
203
+
204
+ return route.fulfill({
205
+ status: 200,
206
+ headers: jsonHeaders(),
207
+ body: JSON.stringify(collection(filtered)),
208
+ });
209
+ }
210
+
211
+ if (pathname === 'device_configs/add-configs' && method === 'POST') {
212
+ const payload = request.postDataJSON();
213
+ const type = String(payload?.type || '').toUpperCase();
214
+ const savedDeviceConfig = createDeviceConfig({
215
+ id: type === 'PDV' ? 489 : 490,
216
+ type: type || 'MANAGER',
217
+ });
218
+
219
+ if (type === 'PDV') {
220
+ savedPdvRequests.push(payload);
221
+ deviceConfigs.push(savedDeviceConfig);
222
+ }
223
+
224
+ return route.fulfill({
225
+ status: 200,
226
+ headers: jsonHeaders(),
227
+ body: JSON.stringify(savedDeviceConfig),
228
+ });
229
+ }
230
+
231
+ return route.fulfill({
232
+ status: 200,
233
+ headers: jsonHeaders(),
234
+ body: JSON.stringify(collection([])),
235
+ });
236
+ });
237
+
238
+ await page.addInitScript(
239
+ ({appVersion}) => {
240
+ localStorage.setItem(
241
+ 'session',
242
+ JSON.stringify({
243
+ id: 7,
244
+ people: '/people/7',
245
+ api_key: 'test-api-key',
246
+ active: 1,
247
+ mycompany: 3,
248
+ roles: ['ROLE_SUPER'],
249
+ }),
250
+ );
251
+ localStorage.setItem('config', JSON.stringify({language: 'pt-br'}));
252
+ localStorage.setItem(
253
+ 'device',
254
+ JSON.stringify({
255
+ id: 'web-7',
256
+ device: 'web-7',
257
+ type: 'MANAGER',
258
+ appName: 'Browser Manager',
259
+ appVersion,
260
+ buildNumber: appVersion,
261
+ systemName: 'web',
262
+ systemVersion: 'web',
263
+ deviceType: 'web',
264
+ metadata: {
265
+ runtime: 'web',
266
+ },
267
+ }),
268
+ );
269
+ },
270
+ {appVersion: APP_VERSION},
271
+ );
272
+
273
+ return {savedPdvRequests};
274
+ };
275
+
276
+ test.describe('current device browser smoke', () => {
277
+ test('groups every profile under one highlighted current Device', async ({
278
+ page,
279
+ }) => {
280
+ await mockDevicesApi(page, {includeCurrentPdv: true});
281
+
282
+ await page.goto('/devices-index?store=device_config');
283
+
284
+ await expect(page.getByTestId('current-device-badge')).toHaveCount(1);
285
+ await expect(page.getByTestId('device-config-487')).toBeVisible();
286
+ await expect(page.getByTestId('device-config-488')).toBeVisible();
287
+ await expect(page.getByTestId('device-config-410')).toBeVisible();
288
+ await expect(page.getByTestId('device-config-488')).toContainText(
289
+ 'PDV · Infinite Pay',
290
+ );
291
+ await expect(
292
+ page.getByTestId('configure-current-device-pdv'),
293
+ ).toHaveCount(0);
294
+
295
+ const groups = page.locator('[data-testid^="device-group-"]');
296
+ await expect(groups).toHaveCount(2);
297
+ await expect(groups.first()).toContainText('Caixa atual');
298
+ await expect(page.getByTestId('device-config-487')).toHaveAttribute(
299
+ 'data-session-config',
300
+ 'true',
301
+ );
302
+ });
303
+
304
+ test('opens the detail for the selected configuration profile', async ({
305
+ page,
306
+ }) => {
307
+ await mockDevicesApi(page, {includeCurrentPdv: true});
308
+
309
+ await page.goto('/devices-index?store=device_config');
310
+
311
+ await page.getByTestId('device-config-487').click();
312
+ await expect(page).toHaveURL(/device-detail/);
313
+ await expect(page.getByText('Configuração do PDV')).toHaveCount(0);
314
+
315
+ await page.goBack();
316
+ await expect(page.getByTestId('device-config-488')).toBeVisible();
317
+ await page.getByTestId('device-config-488').click();
318
+
319
+ await expect(page).toHaveURL(/device-detail/);
320
+ await expect(page.getByText('Configuração do PDV')).toBeVisible();
321
+ });
322
+
323
+ test('creates the missing PDV profile for the current device', async ({
324
+ page,
325
+ }) => {
326
+ const api = await mockDevicesApi(page, {includeCurrentPdv: false});
327
+
328
+ await page.goto('/devices-index?store=device_config');
329
+
330
+ const setupButton = page.getByTestId('configure-current-device-pdv');
331
+ await expect(setupButton).toBeVisible();
332
+ await setupButton.click();
333
+
334
+ await expect.poll(() => api.savedPdvRequests.length).toBe(1);
335
+ expect(api.savedPdvRequests[0]).toEqual(
336
+ expect.objectContaining({
337
+ device: CURRENT_DEVICE_ID,
338
+ people: '/people/3',
339
+ type: 'PDV',
340
+ }),
341
+ );
342
+ });
343
+ });
@@ -0,0 +1,268 @@
1
+ const {expect, test} = require('playwright/test');
2
+ const packageJson = require('../../../../../../../package.json');
3
+ const {API_ORIGIN} = require('../../../../../../../src/tests/browser/apiOrigin');
4
+
5
+ const APP_VERSION = packageJson?.version || '1.0.0';
6
+
7
+ const CORS_HEADERS = {
8
+ 'access-control-allow-origin': '*',
9
+ 'access-control-allow-headers':
10
+ 'API-TOKEN, APP-DOMAIN, DEVICE, ACCEPT, CONTENT-TYPE, X-Requested-With',
11
+ 'access-control-allow-methods': 'GET,POST,PUT,PATCH,DELETE,OPTIONS',
12
+ };
13
+
14
+ const collection = (member = []) => ({
15
+ member,
16
+ 'hydra:member': member,
17
+ totalItems: member.length,
18
+ 'hydra:totalItems': member.length,
19
+ summary: {},
20
+ });
21
+
22
+ const jsonHeaders = () => ({
23
+ ...CORS_HEADERS,
24
+ 'content-type': 'application/ld+json; charset=utf-8',
25
+ });
26
+
27
+ const textHeaders = () => ({
28
+ ...CORS_HEADERS,
29
+ 'content-type': 'text/css; charset=utf-8',
30
+ });
31
+
32
+ const company = {
33
+ id: 1,
34
+ '@id': '/people/1',
35
+ name: 'Jagunços',
36
+ alias: 'JAGUNCOS',
37
+ panel_enabled: true,
38
+ enabled: true,
39
+ commercial_enabled: true,
40
+ theme: {
41
+ colors: {
42
+ primary: '#6B3924',
43
+ secondary: '#D9A441',
44
+ },
45
+ },
46
+ };
47
+
48
+ const detail = {
49
+ integration: {
50
+ id: 12,
51
+ connected: true,
52
+ user_id: 222,
53
+ },
54
+ oauth: {
55
+ client_configured: true,
56
+ },
57
+ webhook: {
58
+ url: 'https://api.controleonline.com/oauth/mercadolivre/notifications',
59
+ },
60
+ showcases: [
61
+ {
62
+ id: 91,
63
+ name: 'Loja Jagunços',
64
+ domain: 'loja.jaguncos.com.br',
65
+ integration_key: 'shop',
66
+ },
67
+ {
68
+ id: 92,
69
+ name: 'Cardápio Jagunços',
70
+ domain: 'cardapio.jaguncos.com.br',
71
+ integration_key: 'menu',
72
+ },
73
+ ],
74
+ };
75
+
76
+ const setupMercadoLivreApi = async page => {
77
+ const requests = [];
78
+ const errors = [];
79
+
80
+ page.on('pageerror', error => {
81
+ errors.push(error);
82
+ });
83
+
84
+ await page.route(`${API_ORIGIN}/**`, async route => {
85
+ const request = route.request();
86
+ const url = new URL(request.url());
87
+ const pathname = url.pathname.replace(/^\/+/, '');
88
+ const method = request.method().toUpperCase();
89
+
90
+ if (method === 'OPTIONS') {
91
+ return route.fulfill({
92
+ status: 204,
93
+ headers: CORS_HEADERS,
94
+ body: '',
95
+ });
96
+ }
97
+
98
+ if (method !== 'OPTIONS') {
99
+ requests.push({
100
+ pathname,
101
+ method,
102
+ body: method === 'POST' ? request.postDataJSON() : null,
103
+ });
104
+ }
105
+
106
+ if (pathname === 'themes-colors.css') {
107
+ return route.fulfill({
108
+ status: 200,
109
+ headers: textHeaders(),
110
+ body: ':root { --primary: #6b3924; --secondary: #d9a441; }',
111
+ });
112
+ }
113
+
114
+ if (pathname === 'runtime/ip') {
115
+ return route.fulfill({
116
+ status: 200,
117
+ headers: jsonHeaders(),
118
+ body: JSON.stringify({ip: '127.0.0.1'}),
119
+ });
120
+ }
121
+
122
+ if (pathname === 'menus-people') {
123
+ return route.fulfill({
124
+ status: 200,
125
+ headers: jsonHeaders(),
126
+ body: JSON.stringify({modules: {}}),
127
+ });
128
+ }
129
+
130
+ if (pathname === 'people/companies/my') {
131
+ return route.fulfill({
132
+ status: 200,
133
+ headers: jsonHeaders(),
134
+ body: JSON.stringify(collection([company])),
135
+ });
136
+ }
137
+
138
+ if (pathname === 'people/company/default') {
139
+ return route.fulfill({
140
+ status: 200,
141
+ headers: jsonHeaders(),
142
+ body: JSON.stringify(company),
143
+ });
144
+ }
145
+
146
+ if (pathname === 'configs/discovery-configs') {
147
+ return route.fulfill({
148
+ status: 200,
149
+ headers: jsonHeaders(),
150
+ body: JSON.stringify({configs: {}}),
151
+ });
152
+ }
153
+
154
+ if (pathname === 'marketplace/integrations/mercadolivre/detail') {
155
+ return route.fulfill({
156
+ status: 200,
157
+ headers: jsonHeaders(),
158
+ body: JSON.stringify(detail),
159
+ });
160
+ }
161
+
162
+ if (pathname === 'marketplace/integrations/mercadolivre/authorization-page') {
163
+ return route.fulfill({
164
+ status: 200,
165
+ headers: jsonHeaders(),
166
+ body: JSON.stringify({
167
+ authorization_url: 'https://auth.mercadolivre.com.br/authorization',
168
+ }),
169
+ });
170
+ }
171
+
172
+ if (pathname === 'marketplace/integrations/mercadolivre/products/import') {
173
+ return route.fulfill({
174
+ status: 200,
175
+ headers: jsonHeaders(),
176
+ body: JSON.stringify({integration_id: 77}),
177
+ });
178
+ }
179
+
180
+ return route.fulfill({
181
+ status: 200,
182
+ headers: jsonHeaders(),
183
+ body: JSON.stringify({}),
184
+ });
185
+ });
186
+
187
+ await page.addInitScript(
188
+ ({appVersion}) => {
189
+ localStorage.setItem(
190
+ 'session',
191
+ JSON.stringify({
192
+ id: 7,
193
+ people: '/people/7',
194
+ api_key: 'test-api-key',
195
+ active: 1,
196
+ mycompany: 1,
197
+ name: 'Test User',
198
+ realname: 'Test User',
199
+ username: 'tester',
200
+ roles: ['ROLE_SUPER'],
201
+ }),
202
+ );
203
+ localStorage.setItem('config', JSON.stringify({language: 'pt-br'}));
204
+ localStorage.setItem('app-type', 'MANAGER');
205
+ localStorage.setItem(
206
+ 'device',
207
+ JSON.stringify({
208
+ id: 'web-mercadolivre',
209
+ device: 'web-mercadolivre',
210
+ type: 'MANAGER',
211
+ appName: 'ControleOnline',
212
+ appVersion,
213
+ buildNumber: appVersion,
214
+ systemName: 'web',
215
+ systemVersion: 'web',
216
+ deviceType: 'MANAGER',
217
+ metadata: {},
218
+ }),
219
+ );
220
+ },
221
+ {appVersion: APP_VERSION},
222
+ );
223
+
224
+ return {requests, errors};
225
+ };
226
+
227
+ test.describe('Mercado Livre browser smoke', () => {
228
+ test('loads the integration page and queues product import for the selected showcase', async ({
229
+ page,
230
+ }) => {
231
+ const {requests, errors} = await setupMercadoLivreApi(page);
232
+
233
+ await page.goto('/marketplace-integration-page?providerKey=mercadolivre');
234
+
235
+ await expect(page.getByRole('heading', {name: 'Mercado Livre'})).toBeVisible();
236
+ await expect(page.getByText('Webhook')).toBeVisible();
237
+ await expect(page.getByText('Loja Jagunços')).toBeVisible();
238
+ await expect(page.getByRole('button', {name: 'Queue Product Import'})).toBeVisible();
239
+
240
+ const importRequestPromise = page.waitForRequest(request => {
241
+ if (request.method().toUpperCase() !== 'POST') return false;
242
+ return request.url().includes('/marketplace/integrations/mercadolivre/products/import');
243
+ });
244
+
245
+ await page.getByRole('button', {name: 'Queue Product Import'}).click();
246
+ const importRequest = await importRequestPromise;
247
+ const payload = importRequest.postDataJSON();
248
+
249
+ expect(payload).toMatchObject({
250
+ provider_id: 1,
251
+ showcase_id: 91,
252
+ limit: 50,
253
+ });
254
+
255
+ const importCall = requests.find(
256
+ entry =>
257
+ entry.pathname === 'marketplace/integrations/mercadolivre/products/import' &&
258
+ entry.method === 'POST',
259
+ );
260
+ expect(importCall).toBeTruthy();
261
+ expect(importCall.body).toMatchObject({
262
+ provider_id: 1,
263
+ showcase_id: 91,
264
+ limit: 50,
265
+ });
266
+ expect(errors.map(error => error.message)).toEqual([]);
267
+ });
268
+ });