-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathindex.test.js
More file actions
224 lines (172 loc) · 7.71 KB
/
index.test.js
File metadata and controls
224 lines (172 loc) · 7.71 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
'use strict';
jest.mock('node-fetch');
const fetch = require('node-fetch');
const pensador = require('./index');
// Helpers ─────────────────────────────────────────────────────────────────────
function toArrayBuffer(buf) {
const ab = new ArrayBuffer(buf.length);
const view = new Uint8Array(ab);
for (let i = 0; i < buf.length; i++) view[i] = buf[i];
return ab;
}
function buildCard({ text = 'Frase teste.', author = 'Autor Teste' } = {}) {
return `
<div class="thought-card">
<p class="frase fr">${text}</p>
<div class="autor">
<a href="/autor/test/"><span class="author-name">${author}</span></a>
</div>
</div>`;
}
function mockPage(cards = [], hasNext = false) {
const pagination = hasNext
? `<div id="paginacao"><a class="nav">Próxima</a></div>`
: '';
const html = `<html><body>${cards.map(buildCard).join('')}${pagination}</body></html>`;
fetch.mockResolvedValueOnce({
arrayBuffer: () => Promise.resolve(toArrayBuffer(Buffer.from(html, 'utf-8'))),
});
}
// ─────────────────────────────────────────────────────────────────────────────
beforeEach(() => fetch.mockClear());
// Estrutura de retorno ────────────────────────────────────────────────────────
describe('estrutura de retorno', () => {
test('retorna total, searchTerm e phrases', async () => {
mockPage([{ text: 'Uma frase.', author: 'Autor' }]);
const result = await pensador({ term: 'Teste', max: 5 });
expect(result).toHaveProperty('total');
expect(result).toHaveProperty('searchTerm');
expect(result).toHaveProperty('phrases');
expect(Array.isArray(result.phrases)).toBe(true);
});
test('total reflete o número de frases retornadas', async () => {
mockPage([
{ text: 'Frase 1', author: 'A' },
{ text: 'Frase 2', author: 'B' },
]);
const result = await pensador({ term: 'Teste', max: 10 });
expect(result.total).toBe(result.phrases.length);
});
});
// Slugificação do termo ───────────────────────────────────────────────────────
describe('slugificação do term', () => {
test('gera o searchTerm correto para um termo simples', async () => {
mockPage([]);
const result = await pensador({ term: 'Elon Musk', max: 1 });
expect(result.searchTerm).toBe('frases_de_elon_musk');
});
test('gera o searchTerm correto para término com caracteres especiais', async () => {
mockPage([]);
const result = await pensador({ term: 'Papa Francisco', max: 1 });
expect(result.searchTerm).toBe('frases_de_papa_francisco');
});
test('usa "frases_curtas" quando nenhum term é fornecido', async () => {
mockPage([]);
const result = await pensador({ max: 1 });
expect(result.searchTerm).toBe('frases_curtas');
});
test('usa "frases_curtas" quando options é omitido por completo', async () => {
mockPage([]);
const result = await pensador();
expect(result.searchTerm).toBe('frases_curtas');
});
});
// Limite máximo ───────────────────────────────────────────────────────────────
describe('opção max', () => {
test('limita o número de frases retornadas', async () => {
const cards = Array.from({ length: 8 }, (_, i) => ({
text: `Frase ${i + 1}`,
author: 'Autor',
}));
mockPage(cards);
const result = await pensador({ term: 'Teste', max: 3 });
expect(result.phrases).toHaveLength(3);
expect(result.total).toBe(3);
});
test('retorna todas as frases quando max não é fornecido', async () => {
mockPage([
{ text: 'Frase 1', author: 'A' },
{ text: 'Frase 2', author: 'B' },
{ text: 'Frase 3', author: 'C' },
]);
const result = await pensador({ term: 'Teste' });
expect(result.total).toBe(3);
});
});
// Extração de conteúdo ────────────────────────────────────────────────────────
describe('extração de conteúdo', () => {
test('extrai author e text corretamente', async () => {
mockPage([{ text: 'A vida é bela.', author: 'Fernando Pessoa' }]);
const result = await pensador({ term: 'Pessoa', max: 1 });
expect(result.phrases[0]).toEqual({
author: 'Fernando Pessoa',
text: 'A vida é bela.',
});
});
test('remove espaços em branco extras do nome do autor', async () => {
const html = `<html><body>
<div class="thought-card">
<p class="frase fr">Uma frase.</p>
<div class="autor">
<a href="/autor/test/">
<span class="author-name">
Autor Com Espacos
</span>
</a>
</div>
</div>
</body></html>`;
fetch.mockResolvedValueOnce({
arrayBuffer: () => Promise.resolve(toArrayBuffer(Buffer.from(html, 'utf-8'))),
});
const result = await pensador({ term: 'Teste', max: 1 });
expect(result.phrases[0].author).toBe('Autor Com Espacos');
});
test('ignora thought-cards sem texto', async () => {
const html = `<html><body>
<div class="thought-card">
<p class="frase fr"></p>
<div class="autor"><a href="/"><span class="author-name">Autor</span></a></div>
</div>
<div class="thought-card">
<p class="frase fr">Frase válida.</p>
<div class="autor"><a href="/"><span class="author-name">Autor</span></a></div>
</div>
</body></html>`;
fetch.mockResolvedValueOnce({
arrayBuffer: () => Promise.resolve(toArrayBuffer(Buffer.from(html, 'utf-8'))),
});
const result = await pensador({ term: 'Teste', max: 5 });
expect(result.total).toBe(1);
expect(result.phrases[0].text).toBe('Frase válida.');
});
test('retorna lista vazia quando não há thought-cards na página', async () => {
mockPage([]);
const result = await pensador({ term: 'Inexistente', max: 5 });
expect(result.total).toBe(0);
expect(result.phrases).toEqual([]);
});
});
// Paginação ───────────────────────────────────────────────────────────────────
describe('paginação', () => {
test('busca a próxima página quando "Próxima" está presente', async () => {
mockPage([{ text: 'Frase 1', author: 'A' }], true); // página 1 com next
mockPage([{ text: 'Frase 2', author: 'B' }], false); // página 2 sem next
const result = await pensador({ term: 'Teste', max: 10 });
expect(fetch).toHaveBeenCalledTimes(2);
expect(result.total).toBe(2);
});
test('para de paginar quando não há próxima página', async () => {
mockPage([{ text: 'Frase 1', author: 'A' }], false);
await pensador({ term: 'Teste', max: 10 });
expect(fetch).toHaveBeenCalledTimes(1);
});
test('para de paginar ao atingir o max, mesmo que haja próxima página', async () => {
// Página com 5 frases e há próxima página
const cards = Array.from({ length: 5 }, (_, i) => ({ text: `Frase ${i + 1}`, author: 'A' }));
mockPage(cards, true);
const result = await pensador({ term: 'Teste', max: 3 });
expect(fetch).toHaveBeenCalledTimes(1);
expect(result.total).toBe(3);
});
});