firecrawl-cli 1.16.2 → 1.17.1
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 +15 -37
- package/dist/__tests__/commands/init.test.js +4 -2
- package/dist/__tests__/commands/init.test.js.map +1 -1
- package/dist/__tests__/commands/search.test.js +134 -179
- package/dist/__tests__/commands/search.test.js.map +1 -1
- package/dist/__tests__/commands/setup.test.js +6 -2
- package/dist/__tests__/commands/setup.test.js.map +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +27 -4
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/search-feedback.d.ts +44 -0
- package/dist/commands/search-feedback.d.ts.map +1 -0
- package/dist/commands/search-feedback.js +357 -0
- package/dist/commands/search-feedback.js.map +1 -0
- package/dist/commands/search.d.ts.map +1 -1
- package/dist/commands/search.js +19 -28
- package/dist/commands/search.js.map +1 -1
- package/dist/commands/setup.d.ts +1 -1
- package/dist/commands/setup.d.ts.map +1 -1
- package/dist/commands/setup.js +9 -5
- package/dist/commands/setup.js.map +1 -1
- package/dist/commands/skills-install.d.ts +9 -1
- package/dist/commands/skills-install.d.ts.map +1 -1
- package/dist/commands/skills-install.js +13 -2
- package/dist/commands/skills-install.js.map +1 -1
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/status.js +4 -0
- package/dist/commands/status.js.map +1 -1
- package/dist/index.js +68 -8
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/commands/experimental/backends.d.ts +0 -19
- package/dist/commands/experimental/backends.d.ts.map +0 -1
- package/dist/commands/experimental/backends.js +0 -74
- package/dist/commands/experimental/backends.js.map +0 -1
- package/dist/commands/experimental/index.d.ts +0 -13
- package/dist/commands/experimental/index.d.ts.map +0 -1
- package/dist/commands/experimental/index.js +0 -200
- package/dist/commands/experimental/index.js.map +0 -1
- package/dist/commands/experimental/shared.d.ts +0 -17
- package/dist/commands/experimental/shared.d.ts.map +0 -1
- package/dist/commands/experimental/shared.js +0 -152
- package/dist/commands/experimental/shared.js.map +0 -1
- package/dist/commands/experimental/workflows/company-directories.d.ts +0 -11
- package/dist/commands/experimental/workflows/company-directories.d.ts.map +0 -1
- package/dist/commands/experimental/workflows/company-directories.js +0 -245
- package/dist/commands/experimental/workflows/company-directories.js.map +0 -1
- package/dist/commands/experimental/workflows/competitive-intel.d.ts +0 -11
- package/dist/commands/experimental/workflows/competitive-intel.d.ts.map +0 -1
- package/dist/commands/experimental/workflows/competitive-intel.js +0 -226
- package/dist/commands/experimental/workflows/competitive-intel.js.map +0 -1
- package/dist/commands/experimental/workflows/competitor-analysis.d.ts +0 -10
- package/dist/commands/experimental/workflows/competitor-analysis.d.ts.map +0 -1
- package/dist/commands/experimental/workflows/competitor-analysis.js +0 -196
- package/dist/commands/experimental/workflows/competitor-analysis.js.map +0 -1
- package/dist/commands/experimental/workflows/dashboard-reporting.d.ts +0 -11
- package/dist/commands/experimental/workflows/dashboard-reporting.d.ts.map +0 -1
- package/dist/commands/experimental/workflows/dashboard-reporting.js +0 -254
- package/dist/commands/experimental/workflows/dashboard-reporting.js.map +0 -1
- package/dist/commands/experimental/workflows/deep-research.d.ts +0 -11
- package/dist/commands/experimental/workflows/deep-research.d.ts.map +0 -1
- package/dist/commands/experimental/workflows/deep-research.js +0 -159
- package/dist/commands/experimental/workflows/deep-research.js.map +0 -1
- package/dist/commands/experimental/workflows/demo.d.ts +0 -11
- package/dist/commands/experimental/workflows/demo.d.ts.map +0 -1
- package/dist/commands/experimental/workflows/demo.js +0 -190
- package/dist/commands/experimental/workflows/demo.js.map +0 -1
- package/dist/commands/experimental/workflows/knowledge-base.d.ts +0 -11
- package/dist/commands/experimental/workflows/knowledge-base.d.ts.map +0 -1
- package/dist/commands/experimental/workflows/knowledge-base.js +0 -319
- package/dist/commands/experimental/workflows/knowledge-base.js.map +0 -1
- package/dist/commands/experimental/workflows/knowledge-ingest.d.ts +0 -12
- package/dist/commands/experimental/workflows/knowledge-ingest.d.ts.map +0 -1
- package/dist/commands/experimental/workflows/knowledge-ingest.js +0 -251
- package/dist/commands/experimental/workflows/knowledge-ingest.js.map +0 -1
- package/dist/commands/experimental/workflows/lead-gen.d.ts +0 -11
- package/dist/commands/experimental/workflows/lead-gen.d.ts.map +0 -1
- package/dist/commands/experimental/workflows/lead-gen.js +0 -257
- package/dist/commands/experimental/workflows/lead-gen.js.map +0 -1
- package/dist/commands/experimental/workflows/lead-research.d.ts +0 -11
- package/dist/commands/experimental/workflows/lead-research.d.ts.map +0 -1
- package/dist/commands/experimental/workflows/lead-research.js +0 -146
- package/dist/commands/experimental/workflows/lead-research.js.map +0 -1
- package/dist/commands/experimental/workflows/market-research.d.ts +0 -11
- package/dist/commands/experimental/workflows/market-research.d.ts.map +0 -1
- package/dist/commands/experimental/workflows/market-research.js +0 -260
- package/dist/commands/experimental/workflows/market-research.js.map +0 -1
- package/dist/commands/experimental/workflows/qa.d.ts +0 -11
- package/dist/commands/experimental/workflows/qa.d.ts.map +0 -1
- package/dist/commands/experimental/workflows/qa.js +0 -184
- package/dist/commands/experimental/workflows/qa.js.map +0 -1
- package/dist/commands/experimental/workflows/research-papers.d.ts +0 -11
- package/dist/commands/experimental/workflows/research-papers.d.ts.map +0 -1
- package/dist/commands/experimental/workflows/research-papers.js +0 -151
- package/dist/commands/experimental/workflows/research-papers.js.map +0 -1
- package/dist/commands/experimental/workflows/seo-audit.d.ts +0 -11
- package/dist/commands/experimental/workflows/seo-audit.d.ts.map +0 -1
- package/dist/commands/experimental/workflows/seo-audit.js +0 -155
- package/dist/commands/experimental/workflows/seo-audit.js.map +0 -1
- package/dist/commands/experimental/workflows/shop.d.ts +0 -11
- package/dist/commands/experimental/workflows/shop.d.ts.map +0 -1
- package/dist/commands/experimental/workflows/shop.js +0 -155
- package/dist/commands/experimental/workflows/shop.js.map +0 -1
|
@@ -18,18 +18,30 @@ vitest_1.vi.mock('../../utils/client', async () => {
|
|
|
18
18
|
});
|
|
19
19
|
(0, vitest_1.describe)('executeSearch', () => {
|
|
20
20
|
let mockClient;
|
|
21
|
+
let mockHttpPost;
|
|
22
|
+
// Wrap a payload in the axios envelope returned by `client.http.post`.
|
|
23
|
+
// Mirrors the `/v2/search` response shape:
|
|
24
|
+
// { success, data: { web?, news?, images? }, id?, creditsUsed?, warning? }
|
|
25
|
+
const mockSearchResponse = (payload, extras = {}) => {
|
|
26
|
+
const inner = {
|
|
27
|
+
success: true,
|
|
28
|
+
data: Array.isArray(payload) ? { web: payload } : payload,
|
|
29
|
+
...extras,
|
|
30
|
+
};
|
|
31
|
+
return { data: inner };
|
|
32
|
+
};
|
|
21
33
|
(0, vitest_1.beforeEach)(() => {
|
|
22
34
|
(0, mock_client_1.setupTest)();
|
|
23
|
-
// Initialize config with test API key
|
|
24
35
|
(0, config_1.initializeConfig)({
|
|
25
36
|
apiKey: 'test-api-key',
|
|
26
37
|
apiUrl: 'https://api.firecrawl.dev',
|
|
27
38
|
});
|
|
28
|
-
|
|
39
|
+
mockHttpPost = vitest_1.vi.fn();
|
|
29
40
|
mockClient = {
|
|
30
|
-
|
|
41
|
+
http: {
|
|
42
|
+
post: mockHttpPost,
|
|
43
|
+
},
|
|
31
44
|
};
|
|
32
|
-
// Mock getClient to return our mock
|
|
33
45
|
vitest_1.vi.mocked(client_1.getClient).mockReturnValue(mockClient);
|
|
34
46
|
});
|
|
35
47
|
(0, vitest_1.afterEach)(() => {
|
|
@@ -37,25 +49,28 @@ vitest_1.vi.mock('../../utils/client', async () => {
|
|
|
37
49
|
vitest_1.vi.clearAllMocks();
|
|
38
50
|
});
|
|
39
51
|
(0, vitest_1.describe)('API call generation', () => {
|
|
40
|
-
(0, vitest_1.it)('should call search with correct query and default options', async () => {
|
|
41
|
-
|
|
52
|
+
(0, vitest_1.it)('should call /v2/search with correct query and default options', async () => {
|
|
53
|
+
mockHttpPost.mockResolvedValue(mockSearchResponse({
|
|
42
54
|
web: [
|
|
43
|
-
{
|
|
55
|
+
{
|
|
56
|
+
url: 'https://example.com',
|
|
57
|
+
title: 'Example',
|
|
58
|
+
description: 'Test',
|
|
59
|
+
},
|
|
44
60
|
],
|
|
45
|
-
};
|
|
46
|
-
mockClient.search.mockResolvedValue(mockResponse);
|
|
61
|
+
}));
|
|
47
62
|
await (0, search_1.executeSearch)({
|
|
48
63
|
query: 'test query',
|
|
49
64
|
});
|
|
50
|
-
(0, vitest_1.expect)(
|
|
51
|
-
(0, vitest_1.expect)(
|
|
65
|
+
(0, vitest_1.expect)(mockHttpPost).toHaveBeenCalledTimes(1);
|
|
66
|
+
(0, vitest_1.expect)(mockHttpPost).toHaveBeenCalledWith('/v2/search', {
|
|
67
|
+
query: 'test query',
|
|
52
68
|
limit: undefined,
|
|
53
69
|
integration: 'cli',
|
|
54
70
|
});
|
|
55
71
|
});
|
|
56
72
|
(0, vitest_1.it)('should pass apiUrl to getClient when provided', async () => {
|
|
57
|
-
|
|
58
|
-
mockClient.search.mockResolvedValue(mockResponse);
|
|
73
|
+
mockHttpPost.mockResolvedValue(mockSearchResponse({ web: [] }));
|
|
59
74
|
await (0, search_1.executeSearch)({
|
|
60
75
|
query: 'test query',
|
|
61
76
|
apiUrl: 'http://localhost:3002',
|
|
@@ -66,8 +81,7 @@ vitest_1.vi.mock('../../utils/client', async () => {
|
|
|
66
81
|
});
|
|
67
82
|
});
|
|
68
83
|
(0, vitest_1.it)('should pass both apiKey and apiUrl to getClient when provided', async () => {
|
|
69
|
-
|
|
70
|
-
mockClient.search.mockResolvedValue(mockResponse);
|
|
84
|
+
mockHttpPost.mockResolvedValue(mockSearchResponse({ web: [] }));
|
|
71
85
|
await (0, search_1.executeSearch)({
|
|
72
86
|
query: 'test query',
|
|
73
87
|
apiKey: 'fc-custom-key',
|
|
@@ -79,157 +93,157 @@ vitest_1.vi.mock('../../utils/client', async () => {
|
|
|
79
93
|
});
|
|
80
94
|
});
|
|
81
95
|
(0, vitest_1.it)('should include limit option when provided', async () => {
|
|
82
|
-
|
|
83
|
-
mockClient.search.mockResolvedValue(mockResponse);
|
|
96
|
+
mockHttpPost.mockResolvedValue(mockSearchResponse({ web: [] }));
|
|
84
97
|
await (0, search_1.executeSearch)({
|
|
85
98
|
query: 'AI news',
|
|
86
99
|
limit: 10,
|
|
87
100
|
});
|
|
88
|
-
(0, vitest_1.expect)(
|
|
101
|
+
(0, vitest_1.expect)(mockHttpPost).toHaveBeenCalledWith('/v2/search', vitest_1.expect.objectContaining({
|
|
102
|
+
query: 'AI news',
|
|
89
103
|
limit: 10,
|
|
90
104
|
}));
|
|
91
105
|
});
|
|
92
106
|
(0, vitest_1.it)('should include sources option when provided', async () => {
|
|
93
|
-
|
|
94
|
-
mockClient.search.mockResolvedValue(mockResponse);
|
|
107
|
+
mockHttpPost.mockResolvedValue(mockSearchResponse({ web: [], images: [], news: [] }));
|
|
95
108
|
await (0, search_1.executeSearch)({
|
|
96
109
|
query: 'test query',
|
|
97
110
|
sources: ['web', 'images', 'news'],
|
|
98
111
|
});
|
|
99
|
-
(0, vitest_1.expect)(
|
|
112
|
+
(0, vitest_1.expect)(mockHttpPost).toHaveBeenCalledWith('/v2/search', vitest_1.expect.objectContaining({
|
|
113
|
+
query: 'test query',
|
|
100
114
|
sources: [{ type: 'web' }, { type: 'images' }, { type: 'news' }],
|
|
101
115
|
}));
|
|
102
116
|
});
|
|
103
117
|
(0, vitest_1.it)('should include single source correctly', async () => {
|
|
104
|
-
|
|
105
|
-
mockClient.search.mockResolvedValue(mockResponse);
|
|
118
|
+
mockHttpPost.mockResolvedValue(mockSearchResponse({ news: [] }));
|
|
106
119
|
await (0, search_1.executeSearch)({
|
|
107
120
|
query: 'tech news',
|
|
108
121
|
sources: ['news'],
|
|
109
122
|
});
|
|
110
|
-
(0, vitest_1.expect)(
|
|
123
|
+
(0, vitest_1.expect)(mockHttpPost).toHaveBeenCalledWith('/v2/search', vitest_1.expect.objectContaining({
|
|
124
|
+
query: 'tech news',
|
|
111
125
|
sources: [{ type: 'news' }],
|
|
112
126
|
}));
|
|
113
127
|
});
|
|
114
128
|
(0, vitest_1.it)('should include categories option when provided', async () => {
|
|
115
|
-
|
|
116
|
-
mockClient.search.mockResolvedValue(mockResponse);
|
|
129
|
+
mockHttpPost.mockResolvedValue(mockSearchResponse({ web: [] }));
|
|
117
130
|
await (0, search_1.executeSearch)({
|
|
118
131
|
query: 'web scraping python',
|
|
119
132
|
categories: ['github'],
|
|
120
133
|
});
|
|
121
|
-
(0, vitest_1.expect)(
|
|
134
|
+
(0, vitest_1.expect)(mockHttpPost).toHaveBeenCalledWith('/v2/search', vitest_1.expect.objectContaining({
|
|
135
|
+
query: 'web scraping python',
|
|
122
136
|
categories: [{ type: 'github' }],
|
|
123
137
|
}));
|
|
124
138
|
});
|
|
125
139
|
(0, vitest_1.it)('should include multiple categories correctly', async () => {
|
|
126
|
-
|
|
127
|
-
mockClient.search.mockResolvedValue(mockResponse);
|
|
140
|
+
mockHttpPost.mockResolvedValue(mockSearchResponse({ web: [] }));
|
|
128
141
|
await (0, search_1.executeSearch)({
|
|
129
142
|
query: 'transformer architecture',
|
|
130
143
|
categories: ['research', 'pdf'],
|
|
131
144
|
});
|
|
132
|
-
(0, vitest_1.expect)(
|
|
145
|
+
(0, vitest_1.expect)(mockHttpPost).toHaveBeenCalledWith('/v2/search', vitest_1.expect.objectContaining({
|
|
146
|
+
query: 'transformer architecture',
|
|
133
147
|
categories: [{ type: 'research' }, { type: 'pdf' }],
|
|
134
148
|
}));
|
|
135
149
|
});
|
|
136
150
|
(0, vitest_1.it)('should include tbs (time-based search) option when provided', async () => {
|
|
137
|
-
|
|
138
|
-
mockClient.search.mockResolvedValue(mockResponse);
|
|
151
|
+
mockHttpPost.mockResolvedValue(mockSearchResponse({ web: [] }));
|
|
139
152
|
await (0, search_1.executeSearch)({
|
|
140
153
|
query: 'AI announcements',
|
|
141
154
|
tbs: 'qdr:d', // Past day
|
|
142
155
|
});
|
|
143
|
-
(0, vitest_1.expect)(
|
|
156
|
+
(0, vitest_1.expect)(mockHttpPost).toHaveBeenCalledWith('/v2/search', vitest_1.expect.objectContaining({
|
|
157
|
+
query: 'AI announcements',
|
|
144
158
|
tbs: 'qdr:d',
|
|
145
159
|
}));
|
|
146
160
|
});
|
|
147
161
|
(0, vitest_1.it)('should include location option when provided', async () => {
|
|
148
|
-
|
|
149
|
-
mockClient.search.mockResolvedValue(mockResponse);
|
|
162
|
+
mockHttpPost.mockResolvedValue(mockSearchResponse({ web: [] }));
|
|
150
163
|
await (0, search_1.executeSearch)({
|
|
151
164
|
query: 'restaurants',
|
|
152
165
|
location: 'San Francisco,California,United States',
|
|
153
166
|
});
|
|
154
|
-
(0, vitest_1.expect)(
|
|
167
|
+
(0, vitest_1.expect)(mockHttpPost).toHaveBeenCalledWith('/v2/search', vitest_1.expect.objectContaining({
|
|
168
|
+
query: 'restaurants',
|
|
155
169
|
location: 'San Francisco,California,United States',
|
|
156
170
|
}));
|
|
157
171
|
});
|
|
158
172
|
(0, vitest_1.it)('should include country option when provided', async () => {
|
|
159
|
-
|
|
160
|
-
mockClient.search.mockResolvedValue(mockResponse);
|
|
173
|
+
mockHttpPost.mockResolvedValue(mockSearchResponse({ web: [] }));
|
|
161
174
|
await (0, search_1.executeSearch)({
|
|
162
175
|
query: 'local news',
|
|
163
176
|
country: 'DE',
|
|
164
177
|
});
|
|
165
|
-
(0, vitest_1.expect)(
|
|
178
|
+
(0, vitest_1.expect)(mockHttpPost).toHaveBeenCalledWith('/v2/search', vitest_1.expect.objectContaining({
|
|
179
|
+
query: 'local news',
|
|
166
180
|
country: 'DE',
|
|
167
181
|
}));
|
|
168
182
|
});
|
|
169
183
|
(0, vitest_1.it)('should include timeout option when provided', async () => {
|
|
170
|
-
|
|
171
|
-
mockClient.search.mockResolvedValue(mockResponse);
|
|
184
|
+
mockHttpPost.mockResolvedValue(mockSearchResponse({ web: [] }));
|
|
172
185
|
await (0, search_1.executeSearch)({
|
|
173
186
|
query: 'test query',
|
|
174
187
|
timeout: 30000,
|
|
175
188
|
});
|
|
176
|
-
(0, vitest_1.expect)(
|
|
189
|
+
(0, vitest_1.expect)(mockHttpPost).toHaveBeenCalledWith('/v2/search', vitest_1.expect.objectContaining({
|
|
190
|
+
query: 'test query',
|
|
177
191
|
timeout: 30000,
|
|
178
192
|
}));
|
|
179
193
|
});
|
|
180
194
|
(0, vitest_1.it)('should include ignoreInvalidUrls option when provided', async () => {
|
|
181
|
-
|
|
182
|
-
mockClient.search.mockResolvedValue(mockResponse);
|
|
195
|
+
mockHttpPost.mockResolvedValue(mockSearchResponse({ web: [] }));
|
|
183
196
|
await (0, search_1.executeSearch)({
|
|
184
197
|
query: 'test query',
|
|
185
198
|
ignoreInvalidUrls: true,
|
|
186
199
|
});
|
|
187
|
-
(0, vitest_1.expect)(
|
|
200
|
+
(0, vitest_1.expect)(mockHttpPost).toHaveBeenCalledWith('/v2/search', vitest_1.expect.objectContaining({
|
|
201
|
+
query: 'test query',
|
|
188
202
|
ignoreInvalidURLs: true,
|
|
189
203
|
}));
|
|
190
204
|
});
|
|
191
205
|
(0, vitest_1.it)('should include scrape options when scrape is enabled', async () => {
|
|
192
|
-
|
|
206
|
+
mockHttpPost.mockResolvedValue(mockSearchResponse({
|
|
193
207
|
web: [{ url: 'https://example.com', markdown: '# Test' }],
|
|
194
|
-
};
|
|
195
|
-
mockClient.search.mockResolvedValue(mockResponse);
|
|
208
|
+
}));
|
|
196
209
|
await (0, search_1.executeSearch)({
|
|
197
210
|
query: 'firecrawl tutorials',
|
|
198
211
|
scrape: true,
|
|
199
212
|
});
|
|
200
|
-
(0, vitest_1.expect)(
|
|
213
|
+
(0, vitest_1.expect)(mockHttpPost).toHaveBeenCalledWith('/v2/search', vitest_1.expect.objectContaining({
|
|
214
|
+
query: 'firecrawl tutorials',
|
|
201
215
|
scrapeOptions: {
|
|
202
216
|
formats: [{ type: 'markdown' }],
|
|
203
217
|
},
|
|
204
218
|
}));
|
|
205
219
|
});
|
|
206
220
|
(0, vitest_1.it)('should include custom scrape formats when provided', async () => {
|
|
207
|
-
|
|
221
|
+
mockHttpPost.mockResolvedValue(mockSearchResponse({
|
|
208
222
|
web: [{ url: 'https://example.com', markdown: '# Test', links: [] }],
|
|
209
|
-
};
|
|
210
|
-
mockClient.search.mockResolvedValue(mockResponse);
|
|
223
|
+
}));
|
|
211
224
|
await (0, search_1.executeSearch)({
|
|
212
225
|
query: 'API docs',
|
|
213
226
|
scrape: true,
|
|
214
227
|
scrapeFormats: ['markdown', 'links'],
|
|
215
228
|
});
|
|
216
|
-
(0, vitest_1.expect)(
|
|
229
|
+
(0, vitest_1.expect)(mockHttpPost).toHaveBeenCalledWith('/v2/search', vitest_1.expect.objectContaining({
|
|
230
|
+
query: 'API docs',
|
|
217
231
|
scrapeOptions: {
|
|
218
232
|
formats: [{ type: 'markdown' }, { type: 'links' }],
|
|
219
233
|
},
|
|
220
234
|
}));
|
|
221
235
|
});
|
|
222
236
|
(0, vitest_1.it)('should include onlyMainContent in scrape options when provided', async () => {
|
|
223
|
-
|
|
237
|
+
mockHttpPost.mockResolvedValue(mockSearchResponse({
|
|
224
238
|
web: [{ url: 'https://example.com', markdown: '# Test' }],
|
|
225
|
-
};
|
|
226
|
-
mockClient.search.mockResolvedValue(mockResponse);
|
|
239
|
+
}));
|
|
227
240
|
await (0, search_1.executeSearch)({
|
|
228
241
|
query: 'test query',
|
|
229
242
|
scrape: true,
|
|
230
243
|
onlyMainContent: true,
|
|
231
244
|
});
|
|
232
|
-
(0, vitest_1.expect)(
|
|
245
|
+
(0, vitest_1.expect)(mockHttpPost).toHaveBeenCalledWith('/v2/search', vitest_1.expect.objectContaining({
|
|
246
|
+
query: 'test query',
|
|
233
247
|
scrapeOptions: {
|
|
234
248
|
formats: [{ type: 'markdown' }],
|
|
235
249
|
onlyMainContent: true,
|
|
@@ -237,11 +251,10 @@ vitest_1.vi.mock('../../utils/client', async () => {
|
|
|
237
251
|
}));
|
|
238
252
|
});
|
|
239
253
|
(0, vitest_1.it)('should combine all options correctly', async () => {
|
|
240
|
-
|
|
254
|
+
mockHttpPost.mockResolvedValue(mockSearchResponse({
|
|
241
255
|
web: [{ url: 'https://example.com', markdown: '# Test' }],
|
|
242
256
|
news: [{ url: 'https://news.example.com', title: 'News' }],
|
|
243
|
-
};
|
|
244
|
-
mockClient.search.mockResolvedValue(mockResponse);
|
|
257
|
+
}));
|
|
245
258
|
await (0, search_1.executeSearch)({
|
|
246
259
|
query: 'comprehensive test',
|
|
247
260
|
limit: 20,
|
|
@@ -255,7 +268,8 @@ vitest_1.vi.mock('../../utils/client', async () => {
|
|
|
255
268
|
scrapeFormats: ['markdown', 'links'],
|
|
256
269
|
onlyMainContent: true,
|
|
257
270
|
});
|
|
258
|
-
(0, vitest_1.expect)(
|
|
271
|
+
(0, vitest_1.expect)(mockHttpPost).toHaveBeenCalledWith('/v2/search', {
|
|
272
|
+
query: 'comprehensive test',
|
|
259
273
|
limit: 20,
|
|
260
274
|
integration: 'cli',
|
|
261
275
|
sources: [{ type: 'web' }, { type: 'news' }],
|
|
@@ -273,74 +287,62 @@ vitest_1.vi.mock('../../utils/client', async () => {
|
|
|
273
287
|
});
|
|
274
288
|
(0, vitest_1.describe)('Response handling', () => {
|
|
275
289
|
(0, vitest_1.it)('should return success result with web results', async () => {
|
|
276
|
-
const
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
};
|
|
290
|
-
mockClient.search.mockResolvedValue(mockResponse);
|
|
290
|
+
const web = [
|
|
291
|
+
{
|
|
292
|
+
url: 'https://example.com',
|
|
293
|
+
title: 'Example',
|
|
294
|
+
description: 'Test description',
|
|
295
|
+
},
|
|
296
|
+
{
|
|
297
|
+
url: 'https://example2.com',
|
|
298
|
+
title: 'Example 2',
|
|
299
|
+
description: 'Another test',
|
|
300
|
+
},
|
|
301
|
+
];
|
|
302
|
+
mockHttpPost.mockResolvedValue(mockSearchResponse({ web }));
|
|
291
303
|
const result = await (0, search_1.executeSearch)({
|
|
292
304
|
query: 'test query',
|
|
293
305
|
});
|
|
294
306
|
(0, vitest_1.expect)(result.success).toBe(true);
|
|
295
|
-
(0, vitest_1.expect)(result.data).toEqual({
|
|
296
|
-
web: mockResponse.web,
|
|
297
|
-
});
|
|
307
|
+
(0, vitest_1.expect)(result.data).toEqual({ web });
|
|
298
308
|
});
|
|
299
309
|
(0, vitest_1.it)('should return success result with image results', async () => {
|
|
300
|
-
const
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
};
|
|
311
|
-
mockClient.search.mockResolvedValue(mockResponse);
|
|
310
|
+
const images = [
|
|
311
|
+
{
|
|
312
|
+
imageUrl: 'https://example.com/image.jpg',
|
|
313
|
+
url: 'https://example.com',
|
|
314
|
+
title: 'Image 1',
|
|
315
|
+
imageWidth: 800,
|
|
316
|
+
imageHeight: 600,
|
|
317
|
+
},
|
|
318
|
+
];
|
|
319
|
+
mockHttpPost.mockResolvedValue(mockSearchResponse({ images }));
|
|
312
320
|
const result = await (0, search_1.executeSearch)({
|
|
313
321
|
query: 'landscapes',
|
|
314
322
|
sources: ['images'],
|
|
315
323
|
});
|
|
316
324
|
(0, vitest_1.expect)(result.success).toBe(true);
|
|
317
|
-
(0, vitest_1.expect)(result.data).toEqual({
|
|
318
|
-
images: mockResponse.images,
|
|
319
|
-
});
|
|
325
|
+
(0, vitest_1.expect)(result.data).toEqual({ images });
|
|
320
326
|
});
|
|
321
327
|
(0, vitest_1.it)('should return success result with news results', async () => {
|
|
322
|
-
const
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
};
|
|
332
|
-
mockClient.search.mockResolvedValue(mockResponse);
|
|
328
|
+
const news = [
|
|
329
|
+
{
|
|
330
|
+
url: 'https://news.example.com',
|
|
331
|
+
title: 'Breaking News',
|
|
332
|
+
snippet: 'Something happened',
|
|
333
|
+
date: '2024-01-15',
|
|
334
|
+
},
|
|
335
|
+
];
|
|
336
|
+
mockHttpPost.mockResolvedValue(mockSearchResponse({ news }));
|
|
333
337
|
const result = await (0, search_1.executeSearch)({
|
|
334
338
|
query: 'tech news',
|
|
335
339
|
sources: ['news'],
|
|
336
340
|
});
|
|
337
341
|
(0, vitest_1.expect)(result.success).toBe(true);
|
|
338
|
-
(0, vitest_1.expect)(result.data).toEqual({
|
|
339
|
-
news: mockResponse.news,
|
|
340
|
-
});
|
|
342
|
+
(0, vitest_1.expect)(result.data).toEqual({ news });
|
|
341
343
|
});
|
|
342
344
|
(0, vitest_1.it)('should handle combined results from multiple sources', async () => {
|
|
343
|
-
const
|
|
345
|
+
const payload = {
|
|
344
346
|
web: [{ url: 'https://example.com', title: 'Web Result' }],
|
|
345
347
|
images: [
|
|
346
348
|
{
|
|
@@ -350,20 +352,16 @@ vitest_1.vi.mock('../../utils/client', async () => {
|
|
|
350
352
|
],
|
|
351
353
|
news: [{ url: 'https://news.example.com', title: 'News' }],
|
|
352
354
|
};
|
|
353
|
-
|
|
355
|
+
mockHttpPost.mockResolvedValue(mockSearchResponse(payload));
|
|
354
356
|
const result = await (0, search_1.executeSearch)({
|
|
355
357
|
query: 'machine learning',
|
|
356
358
|
sources: ['web', 'images', 'news'],
|
|
357
359
|
});
|
|
358
360
|
(0, vitest_1.expect)(result.success).toBe(true);
|
|
359
|
-
(0, vitest_1.expect)(result.data).toEqual(
|
|
360
|
-
web: mockResponse.web,
|
|
361
|
-
images: mockResponse.images,
|
|
362
|
-
news: mockResponse.news,
|
|
363
|
-
});
|
|
361
|
+
(0, vitest_1.expect)(result.data).toEqual(payload);
|
|
364
362
|
});
|
|
365
363
|
(0, vitest_1.it)('should handle response with scraped content', async () => {
|
|
366
|
-
|
|
364
|
+
mockHttpPost.mockResolvedValue(mockSearchResponse({
|
|
367
365
|
web: [
|
|
368
366
|
{
|
|
369
367
|
url: 'https://example.com',
|
|
@@ -371,8 +369,7 @@ vitest_1.vi.mock('../../utils/client', async () => {
|
|
|
371
369
|
markdown: '# Page Content\n\nThis is the content.',
|
|
372
370
|
},
|
|
373
371
|
],
|
|
374
|
-
};
|
|
375
|
-
mockClient.search.mockResolvedValue(mockResponse);
|
|
372
|
+
}));
|
|
376
373
|
const result = await (0, search_1.executeSearch)({
|
|
377
374
|
query: 'test',
|
|
378
375
|
scrape: true,
|
|
@@ -380,39 +377,8 @@ vitest_1.vi.mock('../../utils/client', async () => {
|
|
|
380
377
|
(0, vitest_1.expect)(result.success).toBe(true);
|
|
381
378
|
(0, vitest_1.expect)(result.data?.web?.[0].markdown).toBe('# Page Content\n\nThis is the content.');
|
|
382
379
|
});
|
|
383
|
-
(0, vitest_1.it)('should handle nested data response format', async () => {
|
|
384
|
-
const mockResponse = {
|
|
385
|
-
data: {
|
|
386
|
-
web: [{ url: 'https://example.com', title: 'Test' }],
|
|
387
|
-
},
|
|
388
|
-
};
|
|
389
|
-
mockClient.search.mockResolvedValue(mockResponse);
|
|
390
|
-
const result = await (0, search_1.executeSearch)({
|
|
391
|
-
query: 'test',
|
|
392
|
-
});
|
|
393
|
-
(0, vitest_1.expect)(result.success).toBe(true);
|
|
394
|
-
(0, vitest_1.expect)(result.data?.web).toEqual([
|
|
395
|
-
{ url: 'https://example.com', title: 'Test' },
|
|
396
|
-
]);
|
|
397
|
-
});
|
|
398
|
-
(0, vitest_1.it)('should handle array response format (legacy)', async () => {
|
|
399
|
-
const mockResponse = [
|
|
400
|
-
{ url: 'https://example.com', title: 'Test 1' },
|
|
401
|
-
{ url: 'https://example2.com', title: 'Test 2' },
|
|
402
|
-
];
|
|
403
|
-
mockClient.search.mockResolvedValue(mockResponse);
|
|
404
|
-
const result = await (0, search_1.executeSearch)({
|
|
405
|
-
query: 'test',
|
|
406
|
-
});
|
|
407
|
-
(0, vitest_1.expect)(result.success).toBe(true);
|
|
408
|
-
(0, vitest_1.expect)(result.data?.web).toEqual(mockResponse);
|
|
409
|
-
});
|
|
410
380
|
(0, vitest_1.it)('should include warning in result when present', async () => {
|
|
411
|
-
|
|
412
|
-
web: [{ url: 'https://example.com', title: 'Test' }],
|
|
413
|
-
warning: 'Some warning message',
|
|
414
|
-
};
|
|
415
|
-
mockClient.search.mockResolvedValue(mockResponse);
|
|
381
|
+
mockHttpPost.mockResolvedValue(mockSearchResponse({ web: [{ url: 'https://example.com', title: 'Test' }] }, { warning: 'Some warning message' }));
|
|
416
382
|
const result = await (0, search_1.executeSearch)({
|
|
417
383
|
query: 'test',
|
|
418
384
|
});
|
|
@@ -420,11 +386,7 @@ vitest_1.vi.mock('../../utils/client', async () => {
|
|
|
420
386
|
(0, vitest_1.expect)(result.warning).toBe('Some warning message');
|
|
421
387
|
});
|
|
422
388
|
(0, vitest_1.it)('should include id in result when present', async () => {
|
|
423
|
-
|
|
424
|
-
web: [{ url: 'https://example.com', title: 'Test' }],
|
|
425
|
-
id: 'search-123',
|
|
426
|
-
};
|
|
427
|
-
mockClient.search.mockResolvedValue(mockResponse);
|
|
389
|
+
mockHttpPost.mockResolvedValue(mockSearchResponse({ web: [{ url: 'https://example.com', title: 'Test' }] }, { id: 'search-123' }));
|
|
428
390
|
const result = await (0, search_1.executeSearch)({
|
|
429
391
|
query: 'test',
|
|
430
392
|
});
|
|
@@ -432,11 +394,7 @@ vitest_1.vi.mock('../../utils/client', async () => {
|
|
|
432
394
|
(0, vitest_1.expect)(result.id).toBe('search-123');
|
|
433
395
|
});
|
|
434
396
|
(0, vitest_1.it)('should include creditsUsed in result when present', async () => {
|
|
435
|
-
|
|
436
|
-
web: [{ url: 'https://example.com', title: 'Test' }],
|
|
437
|
-
creditsUsed: 5,
|
|
438
|
-
};
|
|
439
|
-
mockClient.search.mockResolvedValue(mockResponse);
|
|
397
|
+
mockHttpPost.mockResolvedValue(mockSearchResponse({ web: [{ url: 'https://example.com', title: 'Test' }] }, { creditsUsed: 5 }));
|
|
440
398
|
const result = await (0, search_1.executeSearch)({
|
|
441
399
|
query: 'test',
|
|
442
400
|
});
|
|
@@ -444,8 +402,7 @@ vitest_1.vi.mock('../../utils/client', async () => {
|
|
|
444
402
|
(0, vitest_1.expect)(result.creditsUsed).toBe(5);
|
|
445
403
|
});
|
|
446
404
|
(0, vitest_1.it)('should handle empty results', async () => {
|
|
447
|
-
|
|
448
|
-
mockClient.search.mockResolvedValue(mockResponse);
|
|
405
|
+
mockHttpPost.mockResolvedValue(mockSearchResponse({}));
|
|
449
406
|
const result = await (0, search_1.executeSearch)({
|
|
450
407
|
query: 'nonexistent content xyz123',
|
|
451
408
|
});
|
|
@@ -454,7 +411,7 @@ vitest_1.vi.mock('../../utils/client', async () => {
|
|
|
454
411
|
});
|
|
455
412
|
(0, vitest_1.it)('should return error result when search fails', async () => {
|
|
456
413
|
const errorMessage = 'API Error: Rate limit exceeded';
|
|
457
|
-
|
|
414
|
+
mockHttpPost.mockRejectedValue(new Error(errorMessage));
|
|
458
415
|
const result = await (0, search_1.executeSearch)({
|
|
459
416
|
query: 'test query',
|
|
460
417
|
});
|
|
@@ -464,7 +421,7 @@ vitest_1.vi.mock('../../utils/client', async () => {
|
|
|
464
421
|
});
|
|
465
422
|
});
|
|
466
423
|
(0, vitest_1.it)('should handle non-Error exceptions', async () => {
|
|
467
|
-
|
|
424
|
+
mockHttpPost.mockRejectedValue('String error');
|
|
468
425
|
const result = await (0, search_1.executeSearch)({
|
|
469
426
|
query: 'test query',
|
|
470
427
|
});
|
|
@@ -474,44 +431,44 @@ vitest_1.vi.mock('../../utils/client', async () => {
|
|
|
474
431
|
});
|
|
475
432
|
(0, vitest_1.describe)('Time-based search parameters', () => {
|
|
476
433
|
(0, vitest_1.it)('should support qdr:h for past hour', async () => {
|
|
477
|
-
|
|
434
|
+
mockHttpPost.mockResolvedValue(mockSearchResponse({ web: [] }));
|
|
478
435
|
await (0, search_1.executeSearch)({
|
|
479
436
|
query: 'breaking news',
|
|
480
437
|
tbs: 'qdr:h',
|
|
481
438
|
});
|
|
482
|
-
(0, vitest_1.expect)(
|
|
439
|
+
(0, vitest_1.expect)(mockHttpPost).toHaveBeenCalledWith('/v2/search', vitest_1.expect.objectContaining({ tbs: 'qdr:h' }));
|
|
483
440
|
});
|
|
484
441
|
(0, vitest_1.it)('should support qdr:d for past day', async () => {
|
|
485
|
-
|
|
442
|
+
mockHttpPost.mockResolvedValue(mockSearchResponse({ web: [] }));
|
|
486
443
|
await (0, search_1.executeSearch)({
|
|
487
444
|
query: 'AI announcements',
|
|
488
445
|
tbs: 'qdr:d',
|
|
489
446
|
});
|
|
490
|
-
(0, vitest_1.expect)(
|
|
447
|
+
(0, vitest_1.expect)(mockHttpPost).toHaveBeenCalledWith('/v2/search', vitest_1.expect.objectContaining({ tbs: 'qdr:d' }));
|
|
491
448
|
});
|
|
492
449
|
(0, vitest_1.it)('should support qdr:w for past week', async () => {
|
|
493
|
-
|
|
450
|
+
mockHttpPost.mockResolvedValue(mockSearchResponse({ web: [] }));
|
|
494
451
|
await (0, search_1.executeSearch)({
|
|
495
452
|
query: 'tech news',
|
|
496
453
|
tbs: 'qdr:w',
|
|
497
454
|
});
|
|
498
|
-
(0, vitest_1.expect)(
|
|
455
|
+
(0, vitest_1.expect)(mockHttpPost).toHaveBeenCalledWith('/v2/search', vitest_1.expect.objectContaining({ tbs: 'qdr:w' }));
|
|
499
456
|
});
|
|
500
457
|
(0, vitest_1.it)('should support qdr:m for past month', async () => {
|
|
501
|
-
|
|
458
|
+
mockHttpPost.mockResolvedValue(mockSearchResponse({ web: [] }));
|
|
502
459
|
await (0, search_1.executeSearch)({
|
|
503
460
|
query: 'startup funding',
|
|
504
461
|
tbs: 'qdr:m',
|
|
505
462
|
});
|
|
506
|
-
(0, vitest_1.expect)(
|
|
463
|
+
(0, vitest_1.expect)(mockHttpPost).toHaveBeenCalledWith('/v2/search', vitest_1.expect.objectContaining({ tbs: 'qdr:m' }));
|
|
507
464
|
});
|
|
508
465
|
(0, vitest_1.it)('should support qdr:y for past year', async () => {
|
|
509
|
-
|
|
466
|
+
mockHttpPost.mockResolvedValue(mockSearchResponse({ web: [] }));
|
|
510
467
|
await (0, search_1.executeSearch)({
|
|
511
468
|
query: 'yearly review',
|
|
512
469
|
tbs: 'qdr:y',
|
|
513
470
|
});
|
|
514
|
-
(0, vitest_1.expect)(
|
|
471
|
+
(0, vitest_1.expect)(mockHttpPost).toHaveBeenCalledWith('/v2/search', vitest_1.expect.objectContaining({ tbs: 'qdr:y' }));
|
|
515
472
|
});
|
|
516
473
|
});
|
|
517
474
|
(0, vitest_1.describe)('Type safety', () => {
|
|
@@ -521,7 +478,7 @@ vitest_1.vi.mock('../../utils/client', async () => {
|
|
|
521
478
|
'images',
|
|
522
479
|
'news',
|
|
523
480
|
];
|
|
524
|
-
|
|
481
|
+
mockHttpPost.mockResolvedValue(mockSearchResponse({ web: [], images: [], news: [] }));
|
|
525
482
|
for (const source of sourceList) {
|
|
526
483
|
const result = await (0, search_1.executeSearch)({
|
|
527
484
|
query: 'test',
|
|
@@ -536,7 +493,7 @@ vitest_1.vi.mock('../../utils/client', async () => {
|
|
|
536
493
|
'research',
|
|
537
494
|
'pdf',
|
|
538
495
|
];
|
|
539
|
-
|
|
496
|
+
mockHttpPost.mockResolvedValue(mockSearchResponse({ web: [] }));
|
|
540
497
|
for (const category of categoryList) {
|
|
541
498
|
const result = await (0, search_1.executeSearch)({
|
|
542
499
|
query: 'test',
|
|
@@ -553,9 +510,7 @@ vitest_1.vi.mock('../../utils/client', async () => {
|
|
|
553
510
|
'links',
|
|
554
511
|
];
|
|
555
512
|
for (const format of formatList) {
|
|
556
|
-
|
|
557
|
-
web: [{ url: 'https://example.com' }],
|
|
558
|
-
});
|
|
513
|
+
mockHttpPost.mockResolvedValue(mockSearchResponse({ web: [{ url: 'https://example.com' }] }));
|
|
559
514
|
const result = await (0, search_1.executeSearch)({
|
|
560
515
|
query: 'test',
|
|
561
516
|
scrape: true,
|