@ecdt/server-common 1.6.0 → 1.7.0
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/README.md +53 -3
- package/package.json +1 -1
- package/src/index.d.ts +26 -1
- package/src/index.js +3 -2
- package/src/services/cookieService.js +43 -0
- package/src/services/motorEventosService.js +55 -8
- package/test/cookieService.test.js +59 -0
- package/test/motorEventosService.test.js +147 -2
package/README.md
CHANGED
|
@@ -176,14 +176,19 @@ publicarEvento({
|
|
|
176
176
|
|---|---|---|
|
|
177
177
|
| `tipo` | — | Nome do evento, em `snake_case` |
|
|
178
178
|
| `autorizacao` | — | Header `Authorization` da requisição que originou o evento |
|
|
179
|
+
| `idVisitante` | — | Identificador anônimo, para quando não há token |
|
|
179
180
|
| `payload` | `{}` | Campos do evento |
|
|
180
181
|
| `url` | `process.env.MOTOR_EVENTOS_URL` | URL completa do coletor; a função não monta caminho nenhum |
|
|
181
182
|
| `timeoutMs` | `2000` | Aborta a requisição |
|
|
182
183
|
| `aoFalhar` | `console.error` | Recebe a mensagem quando a publicação não acontece |
|
|
183
184
|
|
|
184
|
-
A identidade sai do token, nunca do corpo: o coletor resolve
|
|
185
|
-
repassado.
|
|
186
|
-
`
|
|
185
|
+
A identidade do usuário sai do token, nunca do corpo: o coletor a resolve a partir do `Authorization`
|
|
186
|
+
repassado. Quando não há token — rota pública, visitante anônimo — vale o `idVisitante`, que vai no
|
|
187
|
+
corpo como `id_visitante`. Ele não é identidade autenticada, é um identificador de correlação: forjá-lo
|
|
188
|
+
não atribui nada à conta de ninguém, e por isso pode vir do corpo da requisição. Basta um dos dois.
|
|
189
|
+
|
|
190
|
+
Sem `tipo`, ou sem nenhum dos dois identificadores, a função não faz nada; sem `url` ela ainda registra
|
|
191
|
+
um `console.warn`, porque url ausente é configuração faltando e não um evento que não se aplica.
|
|
187
192
|
|
|
188
193
|
**A função nunca lança e nunca devolve promise.** O evento é secundário ao fluxo que o gerou —
|
|
189
194
|
falha de publicação não pode virar erro de quem chamou, e o retorno `undefined` impede que alguém
|
|
@@ -191,6 +196,51 @@ consiga dar `await` e acoplar a latência do request ao motor.
|
|
|
191
196
|
|
|
192
197
|
---
|
|
193
198
|
|
|
199
|
+
### `publicarEventoDaRequisicao(req, options)`
|
|
200
|
+
|
|
201
|
+
O mesmo publish, montado a partir da requisição que gerou o evento. Resolve o token pelo header
|
|
202
|
+
`Authorization` e o identificador anônimo pelo corpo (`id_visitante`) ou pelo cookie, nessa ordem.
|
|
203
|
+
|
|
204
|
+
```js
|
|
205
|
+
const { publicarEventoDaRequisicao } = require('@ecdt/server-common');
|
|
206
|
+
|
|
207
|
+
publicarEventoDaRequisicao(req, {
|
|
208
|
+
tipo: 'meu_evento',
|
|
209
|
+
payload: { campo: 'valor' },
|
|
210
|
+
});
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
| Opção | Default | Descrição |
|
|
214
|
+
|---|---|---|
|
|
215
|
+
| `tipo`, `payload`, `url`, `timeoutMs`, `aoFalhar` | — | Idênticos ao `publicarEvento` |
|
|
216
|
+
| `cookieVisitante` | `process.env.MOTOR_EVENTOS_COOKIE_VISITANTE` | Nome do cookie que guarda o identificador anônimo |
|
|
217
|
+
|
|
218
|
+
Sem `cookieVisitante` configurado, só o corpo alimenta o `id_visitante`. Também não lança em
|
|
219
|
+
nenhuma hipótese, inclusive com `req` sem `headers` nem `body`.
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
### `lerCookie`, `idDoCookie` e `sanitizarId`
|
|
224
|
+
|
|
225
|
+
Leitura do header `Cookie` no servidor, sem dependência de framework.
|
|
226
|
+
|
|
227
|
+
```js
|
|
228
|
+
const { idDoCookie } = require('@ecdt/server-common');
|
|
229
|
+
|
|
230
|
+
const idVisitante = idDoCookie(req.headers.cookie, 'nome_do_cookie');
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
| Função | Devolve |
|
|
234
|
+
|---|---|
|
|
235
|
+
| `lerCookie(cabecalho, nome)` | Valor cru do cookie, ou `null` |
|
|
236
|
+
| `idDoCookie(cabecalho, nome, { maxLen })` | O identificador: aceita o cookie como string simples ou como JSON com campo `id`, decodifica o valor e corta em `maxLen` (100 por padrão) |
|
|
237
|
+
| `sanitizarId(valor, maxLen)` | O mesmo corte e validação, para identificador que veio de outro lugar |
|
|
238
|
+
|
|
239
|
+
O match do nome é exato, então `nome_antigo` não casa com `nome`. Nenhuma das três lança: entrada
|
|
240
|
+
que não é string vira `null`.
|
|
241
|
+
|
|
242
|
+
---
|
|
243
|
+
|
|
194
244
|
## Instalação
|
|
195
245
|
|
|
196
246
|
```bash
|
package/package.json
CHANGED
package/src/index.d.ts
CHANGED
|
@@ -138,7 +138,8 @@ export declare function renderMetrics(
|
|
|
138
138
|
|
|
139
139
|
export interface PublicarEventoOptions {
|
|
140
140
|
tipo: string;
|
|
141
|
-
autorizacao
|
|
141
|
+
autorizacao?: string;
|
|
142
|
+
idVisitante?: string;
|
|
142
143
|
payload?: Record<string, unknown>;
|
|
143
144
|
url?: string;
|
|
144
145
|
timeoutMs?: number;
|
|
@@ -146,3 +147,27 @@ export interface PublicarEventoOptions {
|
|
|
146
147
|
}
|
|
147
148
|
|
|
148
149
|
export declare function publicarEvento(options?: PublicarEventoOptions): void;
|
|
150
|
+
|
|
151
|
+
export interface PublicarEventoDaRequisicaoOptions
|
|
152
|
+
extends Omit<PublicarEventoOptions, 'autorizacao' | 'idVisitante'> {
|
|
153
|
+
cookieVisitante?: string;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export declare function publicarEventoDaRequisicao(
|
|
157
|
+
req: unknown,
|
|
158
|
+
options?: PublicarEventoDaRequisicaoOptions
|
|
159
|
+
): void;
|
|
160
|
+
|
|
161
|
+
export interface IdDoCookieOptions {
|
|
162
|
+
maxLen?: number;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
export declare function lerCookie(cabecalho: unknown, nome: string): string | null;
|
|
166
|
+
|
|
167
|
+
export declare function idDoCookie(
|
|
168
|
+
cabecalho: unknown,
|
|
169
|
+
nome: string,
|
|
170
|
+
options?: IdDoCookieOptions
|
|
171
|
+
): string | null;
|
|
172
|
+
|
|
173
|
+
export declare function sanitizarId(valor: unknown, maxLen?: number): string | null;
|
package/src/index.js
CHANGED
|
@@ -3,7 +3,8 @@ const { devMktTokenSanitaze } = require("./services/tokenService.js");
|
|
|
3
3
|
const { expressCors } = require("./services/corsService.js");
|
|
4
4
|
const { setupGracefulShutdown } = require("./services/shutdownService.js");
|
|
5
5
|
const { setupRedMetrics, initRedMetrics, redMetricsMiddleware, metricsHandler, renderMetrics } = require("./services/redMetricsService.js");
|
|
6
|
-
const { publicarEvento } = require("./services/motorEventosService.js");
|
|
6
|
+
const { publicarEvento, publicarEventoDaRequisicao } = require("./services/motorEventosService.js");
|
|
7
|
+
const { lerCookie, idDoCookie, sanitizarId } = require("./services/cookieService.js");
|
|
7
8
|
|
|
8
9
|
function expressCommonMiddlewares({ cookieName } = {}){
|
|
9
10
|
return [bodyParser.text(), bodyParser.json(), bodyParser.urlencoded({extended: false}), devMktTokenSanitaze({ cookieName })];
|
|
@@ -12,4 +13,4 @@ function expressCommonMiddlewares({ cookieName } = {}){
|
|
|
12
13
|
|
|
13
14
|
|
|
14
15
|
|
|
15
|
-
module.exports = { expressCommonMiddlewares, expressCors, setupGracefulShutdown, setupRedMetrics, initRedMetrics, redMetricsMiddleware, metricsHandler, renderMetrics, publicarEvento }
|
|
16
|
+
module.exports = { expressCommonMiddlewares, expressCors, setupGracefulShutdown, setupRedMetrics, initRedMetrics, redMetricsMiddleware, metricsHandler, renderMetrics, publicarEvento, publicarEventoDaRequisicao, lerCookie, idDoCookie, sanitizarId }
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
const TAMANHO_MAXIMO_PADRAO = 100;
|
|
2
|
+
|
|
3
|
+
function sanitizarId(valor, maxLen = TAMANHO_MAXIMO_PADRAO) {
|
|
4
|
+
if (typeof valor !== "string") return null;
|
|
5
|
+
|
|
6
|
+
const limpo = valor.trim();
|
|
7
|
+
return limpo ? limpo.slice(0, maxLen) : null;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function lerCookie(cabecalho, nome) {
|
|
11
|
+
if (typeof cabecalho !== "string" || typeof nome !== "string") return null;
|
|
12
|
+
|
|
13
|
+
for (const parte of cabecalho.split(";")) {
|
|
14
|
+
const separador = parte.indexOf("=");
|
|
15
|
+
if (separador === -1) continue;
|
|
16
|
+
if (parte.slice(0, separador).trim() !== nome) continue;
|
|
17
|
+
return parte.slice(separador + 1).trim();
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function idDoCookie(cabecalho, nome, { maxLen = TAMANHO_MAXIMO_PADRAO } = {}) {
|
|
24
|
+
const bruto = lerCookie(cabecalho, nome);
|
|
25
|
+
if (!bruto) return null;
|
|
26
|
+
|
|
27
|
+
let valor = bruto;
|
|
28
|
+
try {
|
|
29
|
+
valor = decodeURIComponent(bruto);
|
|
30
|
+
} catch (_erroDeEncoding) {
|
|
31
|
+
valor = bruto;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
try {
|
|
35
|
+
const conteudo = JSON.parse(valor);
|
|
36
|
+
const id = conteudo && typeof conteudo === "object" ? conteudo.id : conteudo;
|
|
37
|
+
return sanitizarId(typeof id === "string" ? id : String(id ?? ""), maxLen);
|
|
38
|
+
} catch (_naoEhJson) {
|
|
39
|
+
return sanitizarId(valor, maxLen);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
module.exports = { lerCookie, idDoCookie, sanitizarId };
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
const { idDoCookie, sanitizarId } = require("./cookieService.js");
|
|
2
|
+
|
|
1
3
|
const TIMEOUT_PADRAO_MS = 2000;
|
|
2
4
|
|
|
3
5
|
function urlConfigurada(url) {
|
|
@@ -11,9 +13,14 @@ function urlConfigurada(url) {
|
|
|
11
13
|
return configurada.trim();
|
|
12
14
|
}
|
|
13
15
|
|
|
16
|
+
function textoNaoVazio(valor) {
|
|
17
|
+
return typeof valor === "string" && valor.trim() !== "" ? valor.trim() : null;
|
|
18
|
+
}
|
|
19
|
+
|
|
14
20
|
function publicarEvento({
|
|
15
21
|
tipo,
|
|
16
22
|
autorizacao,
|
|
23
|
+
idVisitante,
|
|
17
24
|
payload,
|
|
18
25
|
url,
|
|
19
26
|
timeoutMs = TIMEOUT_PADRAO_MS,
|
|
@@ -21,19 +28,30 @@ function publicarEvento({
|
|
|
21
28
|
} = {}) {
|
|
22
29
|
try {
|
|
23
30
|
const destino = urlConfigurada(url);
|
|
31
|
+
const visitante = textoNaoVazio(idVisitante);
|
|
24
32
|
|
|
25
|
-
if (!destino || !tipo || !autorizacao) {
|
|
33
|
+
if (!destino || !tipo || (!autorizacao && !visitante)) {
|
|
26
34
|
return;
|
|
27
35
|
}
|
|
28
36
|
|
|
37
|
+
const cabecalhos = { "Content-Type": "application/json" };
|
|
38
|
+
if (autorizacao) {
|
|
39
|
+
cabecalhos.Authorization = autorizacao;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const corpo = {
|
|
43
|
+
tipo,
|
|
44
|
+
dt_evento: new Date().toISOString(),
|
|
45
|
+
payload: payload ?? {},
|
|
46
|
+
};
|
|
47
|
+
if (visitante) {
|
|
48
|
+
corpo.id_visitante = visitante;
|
|
49
|
+
}
|
|
50
|
+
|
|
29
51
|
fetch(destino, {
|
|
30
52
|
method: "POST",
|
|
31
|
-
headers:
|
|
32
|
-
body: JSON.stringify(
|
|
33
|
-
tipo,
|
|
34
|
-
dt_evento: new Date().toISOString(),
|
|
35
|
-
payload: payload ?? {},
|
|
36
|
-
}),
|
|
53
|
+
headers: cabecalhos,
|
|
54
|
+
body: JSON.stringify(corpo),
|
|
37
55
|
signal: AbortSignal.timeout(timeoutMs),
|
|
38
56
|
})
|
|
39
57
|
.then((resposta) => {
|
|
@@ -53,4 +71,33 @@ function publicarEvento({
|
|
|
53
71
|
}
|
|
54
72
|
}
|
|
55
73
|
|
|
56
|
-
|
|
74
|
+
/**
|
|
75
|
+
* Publica o evento a partir da requisicao que o gerou: tira o token do header
|
|
76
|
+
* Authorization e o identificador anonimo do corpo ou do cookie, nessa ordem.
|
|
77
|
+
* Nunca lanca, nem quando `req` nao tem headers nem corpo — o evento e
|
|
78
|
+
* secundario ao fluxo, e boa parte das chamadas acontece depois de uma escrita
|
|
79
|
+
* ja efetivada.
|
|
80
|
+
*/
|
|
81
|
+
function publicarEventoDaRequisicao(req, {
|
|
82
|
+
tipo,
|
|
83
|
+
payload,
|
|
84
|
+
cookieVisitante = process.env.MOTOR_EVENTOS_COOKIE_VISITANTE,
|
|
85
|
+
...resto
|
|
86
|
+
} = {}) {
|
|
87
|
+
try {
|
|
88
|
+
const doCorpo = sanitizarId(req?.body?.id_visitante);
|
|
89
|
+
const doCookie = cookieVisitante ? idDoCookie(req?.headers?.cookie, cookieVisitante) : null;
|
|
90
|
+
|
|
91
|
+
publicarEvento({
|
|
92
|
+
tipo,
|
|
93
|
+
payload,
|
|
94
|
+
autorizacao: req?.headers?.authorization,
|
|
95
|
+
idVisitante: doCorpo ?? doCookie,
|
|
96
|
+
...resto,
|
|
97
|
+
});
|
|
98
|
+
} catch (erro) {
|
|
99
|
+
console.error(`motorEventos: ${tipo} nao publicado (${erro?.message})`);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
module.exports = { publicarEvento, publicarEventoDaRequisicao };
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
const { test, describe } = require('node:test');
|
|
2
|
+
const assert = require('node:assert/strict');
|
|
3
|
+
|
|
4
|
+
const { lerCookie, idDoCookie, sanitizarId } = require('../src/services/cookieService.js');
|
|
5
|
+
|
|
6
|
+
const comCookie = (nome, valor) => `_ga=GA1.1.9; ${nome}=${encodeURIComponent(valor)}; outro=x`;
|
|
7
|
+
|
|
8
|
+
describe('sanitizarId', () => {
|
|
9
|
+
test('devolve null para vazio, espaco em branco ou valor que nao e string', () => {
|
|
10
|
+
assert.equal(sanitizarId(''), null);
|
|
11
|
+
assert.equal(sanitizarId(' '), null);
|
|
12
|
+
assert.equal(sanitizarId(undefined), null);
|
|
13
|
+
assert.equal(sanitizarId(42), null);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
test('corta no tamanho maximo', () => {
|
|
17
|
+
assert.equal(sanitizarId('a'.repeat(300)).length, 100);
|
|
18
|
+
assert.equal(sanitizarId('a'.repeat(300), 10).length, 10);
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
describe('lerCookie', () => {
|
|
23
|
+
test('acha o cookie no meio do header', () => {
|
|
24
|
+
assert.equal(lerCookie('a=1; alvo=valor; b=2', 'alvo'), 'valor');
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
test('nao casa com cookie de nome parecido', () => {
|
|
28
|
+
assert.equal(lerCookie('alvo_antigo=valor', 'alvo'), null);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
test('devolve null sem header, sem o cookie ou com header que nao e string', () => {
|
|
32
|
+
assert.equal(lerCookie(undefined, 'alvo'), null);
|
|
33
|
+
assert.equal(lerCookie('a=1', 'alvo'), null);
|
|
34
|
+
assert.equal(lerCookie({}, 'alvo'), null);
|
|
35
|
+
assert.equal(lerCookie('a=1', undefined), null);
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
describe('idDoCookie', () => {
|
|
40
|
+
test('extrai o id quando o cookie guarda JSON', () => {
|
|
41
|
+
assert.equal(idDoCookie(comCookie('trk', '{"id":"visitante-1"}'), 'trk'), 'visitante-1');
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
test('aceita o cookie como string simples', () => {
|
|
45
|
+
assert.equal(idDoCookie(comCookie('trk', 'visitante-2'), 'trk'), 'visitante-2');
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
test('devolve null quando o JSON nao tem id', () => {
|
|
49
|
+
assert.equal(idDoCookie(comCookie('trk', '{"outro":"x"}'), 'trk'), null);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
test('devolve null quando o cookie nao existe', () => {
|
|
53
|
+
assert.equal(idDoCookie('a=1', 'trk'), null);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
test('respeita o maxLen', () => {
|
|
57
|
+
assert.equal(idDoCookie(comCookie('trk', 'a'.repeat(300)), 'trk', { maxLen: 5 }).length, 5);
|
|
58
|
+
});
|
|
59
|
+
});
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
const { test, describe, beforeEach, afterEach } = require('node:test');
|
|
2
2
|
const assert = require('node:assert/strict');
|
|
3
3
|
|
|
4
|
-
const {
|
|
4
|
+
const {
|
|
5
|
+
publicarEvento,
|
|
6
|
+
publicarEventoDaRequisicao,
|
|
7
|
+
} = require('../src/services/motorEventosService.js');
|
|
5
8
|
|
|
6
9
|
const URL = 'http://coletor.interno/eventos';
|
|
7
10
|
|
|
@@ -101,9 +104,10 @@ describe('publicarEvento', () => {
|
|
|
101
104
|
assert.equal(avisos.length, 2);
|
|
102
105
|
});
|
|
103
106
|
|
|
104
|
-
test('nao publica sem tipo
|
|
107
|
+
test('nao publica sem tipo, nem sem identidade nenhuma', async () => {
|
|
105
108
|
publicarEvento({ autorizacao: 'Bearer jwt', url: URL, aoFalhar });
|
|
106
109
|
publicarEvento({ tipo: 'meu_evento', url: URL, aoFalhar });
|
|
110
|
+
publicarEvento({ tipo: 'meu_evento', url: URL, idVisitante: ' ', aoFalhar });
|
|
107
111
|
await esperarMicrotasks();
|
|
108
112
|
|
|
109
113
|
assert.equal(chamadas.length, 0);
|
|
@@ -111,6 +115,36 @@ describe('publicarEvento', () => {
|
|
|
111
115
|
assert.deepEqual(avisos, []);
|
|
112
116
|
});
|
|
113
117
|
|
|
118
|
+
test('publica so com idVisitante, sem header de autorizacao', async () => {
|
|
119
|
+
publicarEvento({ tipo: 'meu_evento', idVisitante: 'visitante-1', url: URL, aoFalhar });
|
|
120
|
+
await esperarMicrotasks();
|
|
121
|
+
|
|
122
|
+
assert.equal(chamadas.length, 1);
|
|
123
|
+
assert.equal(chamadas[0].opcoes.headers.Authorization, undefined);
|
|
124
|
+
assert.equal(JSON.parse(chamadas[0].opcoes.body).id_visitante, 'visitante-1');
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
test('manda os dois quando tem token e visitante', async () => {
|
|
128
|
+
publicarEvento({
|
|
129
|
+
tipo: 'meu_evento',
|
|
130
|
+
autorizacao: 'Bearer jwt',
|
|
131
|
+
idVisitante: 'visitante-1',
|
|
132
|
+
url: URL,
|
|
133
|
+
aoFalhar,
|
|
134
|
+
});
|
|
135
|
+
await esperarMicrotasks();
|
|
136
|
+
|
|
137
|
+
assert.equal(chamadas[0].opcoes.headers.Authorization, 'Bearer jwt');
|
|
138
|
+
assert.equal(JSON.parse(chamadas[0].opcoes.body).id_visitante, 'visitante-1');
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
test('omite id_visitante do corpo quando nao ha visitante', async () => {
|
|
142
|
+
publicarEvento({ tipo: 'meu_evento', autorizacao: 'Bearer jwt', url: URL, aoFalhar });
|
|
143
|
+
await esperarMicrotasks();
|
|
144
|
+
|
|
145
|
+
assert.ok(!('id_visitante' in JSON.parse(chamadas[0].opcoes.body)));
|
|
146
|
+
});
|
|
147
|
+
|
|
114
148
|
test('nao quebra quando chamado sem argumento nenhum', () => {
|
|
115
149
|
delete process.env.MOTOR_EVENTOS_URL;
|
|
116
150
|
|
|
@@ -163,3 +197,114 @@ describe('publicarEvento', () => {
|
|
|
163
197
|
assert.equal(retorno, undefined);
|
|
164
198
|
});
|
|
165
199
|
});
|
|
200
|
+
|
|
201
|
+
describe('publicarEventoDaRequisicao', () => {
|
|
202
|
+
let fetchOriginal;
|
|
203
|
+
let warnOriginal;
|
|
204
|
+
let errorOriginal;
|
|
205
|
+
let urlOriginal;
|
|
206
|
+
let cookieOriginal;
|
|
207
|
+
let chamadas;
|
|
208
|
+
|
|
209
|
+
beforeEach(() => {
|
|
210
|
+
fetchOriginal = global.fetch;
|
|
211
|
+
warnOriginal = console.warn;
|
|
212
|
+
errorOriginal = console.error;
|
|
213
|
+
urlOriginal = process.env.MOTOR_EVENTOS_URL;
|
|
214
|
+
cookieOriginal = process.env.MOTOR_EVENTOS_COOKIE_VISITANTE;
|
|
215
|
+
chamadas = [];
|
|
216
|
+
console.warn = () => {};
|
|
217
|
+
console.error = () => {};
|
|
218
|
+
process.env.MOTOR_EVENTOS_URL = URL;
|
|
219
|
+
global.fetch = (url, opcoes) => {
|
|
220
|
+
chamadas.push({ url, opcoes });
|
|
221
|
+
return Promise.resolve({ ok: true, status: 201 });
|
|
222
|
+
};
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
afterEach(() => {
|
|
226
|
+
global.fetch = fetchOriginal;
|
|
227
|
+
console.warn = warnOriginal;
|
|
228
|
+
console.error = errorOriginal;
|
|
229
|
+
for (const [chave, valor] of [
|
|
230
|
+
['MOTOR_EVENTOS_URL', urlOriginal],
|
|
231
|
+
['MOTOR_EVENTOS_COOKIE_VISITANTE', cookieOriginal],
|
|
232
|
+
]) {
|
|
233
|
+
if (valor === undefined) delete process.env[chave];
|
|
234
|
+
else process.env[chave] = valor;
|
|
235
|
+
}
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
const corpoEnviado = () => JSON.parse(chamadas[0].opcoes.body);
|
|
239
|
+
|
|
240
|
+
test('tira o token do header da requisicao', async () => {
|
|
241
|
+
publicarEventoDaRequisicao(
|
|
242
|
+
{ headers: { authorization: 'Bearer jwt' }, body: {} },
|
|
243
|
+
{ tipo: 'meu_evento', payload: { campo: 'valor' } }
|
|
244
|
+
);
|
|
245
|
+
await esperarMicrotasks();
|
|
246
|
+
|
|
247
|
+
assert.equal(chamadas[0].opcoes.headers.Authorization, 'Bearer jwt');
|
|
248
|
+
assert.deepEqual(corpoEnviado().payload, { campo: 'valor' });
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
test('tira o visitante do cookie quando nao ha token', async () => {
|
|
252
|
+
publicarEventoDaRequisicao(
|
|
253
|
+
{ headers: { cookie: 'trk=%7B%22id%22%3A%22visitante-1%22%7D' }, body: {} },
|
|
254
|
+
{ tipo: 'meu_evento', cookieVisitante: 'trk' }
|
|
255
|
+
);
|
|
256
|
+
await esperarMicrotasks();
|
|
257
|
+
|
|
258
|
+
assert.equal(corpoEnviado().id_visitante, 'visitante-1');
|
|
259
|
+
assert.equal(chamadas[0].opcoes.headers.Authorization, undefined);
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
test('o corpo tem precedencia sobre o cookie', async () => {
|
|
263
|
+
publicarEventoDaRequisicao(
|
|
264
|
+
{
|
|
265
|
+
headers: { cookie: 'trk=%7B%22id%22%3A%22do-cookie%22%7D' },
|
|
266
|
+
body: { id_visitante: 'do-corpo' },
|
|
267
|
+
},
|
|
268
|
+
{ tipo: 'meu_evento', cookieVisitante: 'trk' }
|
|
269
|
+
);
|
|
270
|
+
await esperarMicrotasks();
|
|
271
|
+
|
|
272
|
+
assert.equal(corpoEnviado().id_visitante, 'do-corpo');
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
test('cai na MOTOR_EVENTOS_COOKIE_VISITANTE quando o nome nao e passado', async () => {
|
|
276
|
+
process.env.MOTOR_EVENTOS_COOKIE_VISITANTE = 'trk';
|
|
277
|
+
|
|
278
|
+
publicarEventoDaRequisicao(
|
|
279
|
+
{ headers: { cookie: 'trk=visitante-2' }, body: {} },
|
|
280
|
+
{ tipo: 'meu_evento' }
|
|
281
|
+
);
|
|
282
|
+
await esperarMicrotasks();
|
|
283
|
+
|
|
284
|
+
assert.equal(corpoEnviado().id_visitante, 'visitante-2');
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
test('nao publica quando a requisicao nao traz identidade nenhuma', async () => {
|
|
288
|
+
delete process.env.MOTOR_EVENTOS_COOKIE_VISITANTE;
|
|
289
|
+
|
|
290
|
+
publicarEventoDaRequisicao({ headers: {}, body: {} }, { tipo: 'meu_evento' });
|
|
291
|
+
await esperarMicrotasks();
|
|
292
|
+
|
|
293
|
+
assert.equal(chamadas.length, 0);
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
test('nao quebra com requisicao sem headers, sem corpo, ou sem argumento nenhum', () => {
|
|
297
|
+
assert.doesNotThrow(() => publicarEventoDaRequisicao({}, { tipo: 'meu_evento' }));
|
|
298
|
+
assert.doesNotThrow(() => publicarEventoDaRequisicao());
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
test('repassa as demais opcoes para o publicarEvento', async () => {
|
|
302
|
+
publicarEventoDaRequisicao(
|
|
303
|
+
{ headers: { authorization: 'Bearer jwt' }, body: {} },
|
|
304
|
+
{ tipo: 'meu_evento', url: 'http://outro.interno/eventos' }
|
|
305
|
+
);
|
|
306
|
+
await esperarMicrotasks();
|
|
307
|
+
|
|
308
|
+
assert.equal(chamadas[0].url, 'http://outro.interno/eventos');
|
|
309
|
+
});
|
|
310
|
+
});
|